Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
| Comment: | Sync with trunk. |
|---|---|
| Downloads: | Tarball | ZIP archive |
| Timelines: | family | ancestors | descendants | both | timeline-keyboard-navigation |
| Files: | files | file ages | folders |
| SHA3-256: |
f05b04a6253022ec2b3f30413f62eb47 |
| User & Date: | florian 2024-01-22 13:39:00.000 |
Context
|
2024-09-06
| ||
| 10:47 | Sync with trunk. ... (check-in: 00f7466add user: florian tags: timeline-keyboard-navigation) | |
|
2024-01-22
| ||
| 13:39 | Sync with trunk. ... (check-in: f05b04a625 user: florian tags: timeline-keyboard-navigation) | |
| 13:37 | Hide the timeline graph tooltip in the `pagehide' handler, as Chromium-based browsers (but not Firefox) are deprecating the `unload' handler. ... (check-in: f97a29dd58 user: florian tags: trunk) | |
|
2022-10-30
| ||
| 12:53 | Fix a bug when handling timeline data blocks not containing any check-ins. ... (check-in: d3f9b8ab78 user: florian tags: timeline-keyboard-navigation) | |
Changes
Changes to .fossil-settings/ignore-glob.
1 2 3 4 5 6 7 | compat/openssl* compat/tcl* fossil fossil.exe win/fossil.exe *shell-see.* *sqlite3-see.* | > > | 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.* |
Changes to Dockerfile.
1 2 3 | # See www/containers.md for documentation on how to use this file. ## --------------------------------------------------------------------- | > | > > > > > | | | | < < < < | | < < < < < < < < < < < < | < < > < | > | | | < | > > | | | > | < < | < | < < < < < < < > | | < | | | | | > > < > | | < < | | | < < | > | | | | | | 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 |
# syntax=docker/dockerfile:1.3
# See www/containers.md for documentation on how to use this file.
## ---------------------------------------------------------------------
## STAGE 1: Build static Fossil binary
## ---------------------------------------------------------------------
### We aren't pinning to a more stable version of Alpine because we want
### to build with the latest tools and libraries available in case they
### fixed something that matters to us since the last build. Everything
### below depends on this layer, and so, alas, we toss this container's
### cache on Alpine's release schedule, roughly once a month.
FROM alpine:latest AS bld
WORKDIR /fsl
### Bake the basic Alpine Linux into a base layer so it only changes
### when the upstream image is updated or we change the package set.
RUN set -x \
&& apk update \
&& apk upgrade --no-cache \
&& apk add --no-cache \
gcc make \
linux-headers musl-dev \
openssl-dev openssl-libs-static \
zlib-dev zlib-static
### Build Fossil as a separate layer so we don't have to rebuild the
### Alpine environment for each iteration of Fossil's dev cycle.
###
### We must cope with a bizarre ADD misfeature here: it unpacks tarballs
### automatically when you give it a local file name but not if you give
### it a /tarball URL! It matters because we default to a URL in case
### you're building outside a Fossil checkout, but when building via the
### container-image target, we avoid a costly hit on fossil-scm.org
### by leveraging its DVCS nature via the "tarball" command and passing
### the resulting file's name in.
ARG FSLCFG=""
ARG FSLVER="trunk"
ARG FSLURL="https://fossil-scm.org/home/tarball/src?r=${FSLVER}"
ENV FSLSTB=/fsl/src.tar.gz
ADD $FSLURL $FSLSTB
RUN set -x \
&& if [ -d $FSLSTB ] ; \
then mv $FSLSTB/src . ; \
else tar -xf src.tar.gz ; fi \
&& src/configure --static CFLAGS='-Os -s' $FSLCFG && make -j16
## ---------------------------------------------------------------------
## STAGE 2: Pare that back to the bare essentials.
## ---------------------------------------------------------------------
FROM busybox AS os
ARG UID=499
### Set up that base OS for our specific use without tying it to
### anything likely to change often. So long as the user leaves
### UID alone, this layer will be durable.
RUN set -x \
&& mkdir e log museum \
&& echo "root:x:0:0:Admin:/:/false" > /e/passwd \
&& echo "root:x:0:root" > /e/group \
&& echo "fossil:x:${UID}:${UID}:User:/museum:/false" >> /e/passwd \
&& echo "fossil:x:${UID}:fossil" >> /e/group
## ---------------------------------------------------------------------
## STAGE 3: Drop BusyBox, too, now that we're done with its /bin/sh &c
## ---------------------------------------------------------------------
FROM scratch AS run
COPY --from=bld --chmod=755 /fsl/fossil /bin/
COPY --from=os --chmod=600 /e/* /etc/
COPY --from=os --chmod=1777 /tmp /tmp/
COPY --from=os --chown=fossil:fossil /log /log/
COPY --from=os --chown=fossil:fossil /museum /museum/
## ---------------------------------------------------------------------
## RUN!
## ---------------------------------------------------------------------
ENV PATH "/bin"
EXPOSE 8080/tcp
USER fossil
ENTRYPOINT [ "fossil", "server" ]
CMD [ \
"--create", \
"--jsmode", "bundled", \
"--user", "admin", \
"museum/repo.fossil" ]
|
Changes to Makefile.in.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | #!/usr/bin/make # # This is the top-level makefile for Fossil when the build is occurring # on a unix platform. This works out-of-the-box on most unix platforms. # But you are free to vary some of the definitions if desired. # #### The toplevel directory of the source tree. Fossil can be built # in a directory that is separate from the source tree. Just change # the following to point from the build directory to the src/ folder. # SRCDIR = @srcdir@/src #### Upstream source files included directly in this repository. # SRCDIR_extsrc = @srcdir@/extsrc #### In-tree tools such as code generators and translators: # SRCDIR_tools = @srcdir@/tools | > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | #!/usr/bin/make # # This is the top-level makefile for Fossil when the build is occurring # on a unix platform. This works out-of-the-box on most unix platforms. # But you are free to vary some of the definitions if desired. # #### The toplevel directory of the source tree. Fossil can be built # in a directory that is separate from the source tree. Just change # the following to point from the build directory to the src/ folder. # SRCDIR = @srcdir@/src TOPDIR = @srcdir@ #### Upstream source files included directly in this repository. # SRCDIR_extsrc = @srcdir@/extsrc #### In-tree tools such as code generators and translators: # SRCDIR_tools = @srcdir@/tools |
| ︙ | ︙ | |||
44 45 46 47 48 49 50 | # TCLSH = @TCLSH@ CFLAGS = @CFLAGS@ CFLAGS_INCLUDE = @CFLAGS_INCLUDE@ LIB = @LDFLAGS@ @EXTRA_LDFLAGS@ @LIBS@ BCCFLAGS = @CPPFLAGS@ $(CFLAGS) | | | 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | # TCLSH = @TCLSH@ CFLAGS = @CFLAGS@ CFLAGS_INCLUDE = @CFLAGS_INCLUDE@ LIB = @LDFLAGS@ @EXTRA_LDFLAGS@ @LIBS@ BCCFLAGS = @CPPFLAGS@ $(CFLAGS) TCCFLAGS = @EXTRA_CFLAGS@ @CPPFLAGS@ $(CFLAGS) -DHAVE_AUTOCONFIG_H # # Fuzzing may be enable by appending -fsanitize=fuzzer -DFOSSIL_FUZZ # to the TCCFLAGS variable. # For more thorouth (but also slower) investigation # -fsanitize=fuzzer,undefined,address # might be more useful. |
| ︙ | ︙ | |||
82 83 84 85 86 87 88 89 90 91 92 93 94 95 | # with the Emscripten SDK package: # https://emscripten.org/docs/getting_started/downloads.html EMSDK_HOME = @EMSDK_HOME@ EMSDK_ENV = @EMSDK_ENV@ EMCC_OPT = @EMCC_OPT@ EMCC_WRAPPER = $(SRCDIR_tools)/emcc.sh .PHONY: all tags include $(SRCDIR)/main.mk distclean: clean -rm -f autoconfig.h config.log Makefile -rm -f cscope.out tags | > > > > | 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 | # with the Emscripten SDK package: # https://emscripten.org/docs/getting_started/downloads.html EMSDK_HOME = @EMSDK_HOME@ EMSDK_ENV = @EMSDK_ENV@ EMCC_OPT = @EMCC_OPT@ EMCC_WRAPPER = $(SRCDIR_tools)/emcc.sh # MAKE_COMPILATION_DB (yes/no) determines whether or not the # compile_commands.json file will be generated. MAKE_COMPILATION_DB = @MAKE_COMPILATION_DB@ .PHONY: all tags include $(SRCDIR)/main.mk distclean: clean -rm -f autoconfig.h config.log Makefile -rm -f cscope.out tags |
| ︙ | ︙ | |||
117 118 119 120 121 122 123 124 125 | # around interfering makes this failure mode even worse. Makefile: @srcdir@/Makefile.in $(SRCDIR)/main.mk @AUTODEPS@ @AUTOREMAKE@ touch @builddir@/Makefile # Container stuff SRCTB := src-@FOSSIL_CI_PFX@.tar.gz container-image: $(APPNAME) tarball --name src @FOSSIL_CI_PFX@ $(SRCTB) | > > > > > > > > > > > > > > > > > > > > > > > > > > | > | | > > | | < | < | | < < < < < < | > | 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 | # around interfering makes this failure mode even worse. Makefile: @srcdir@/Makefile.in $(SRCDIR)/main.mk @AUTODEPS@ @AUTOREMAKE@ touch @builddir@/Makefile # Container stuff SRCTB := src-@FOSSIL_CI_PFX@.tar.gz IMGVER := fossil:@FOSSIL_CI_PFX@ CNTVER := fossil-@FOSSIL_CI_PFX@ CENGINE := docker container: $(CENGINE) image inspect $(IMGVER) > /dev/null 2>&1 || \ $(MAKE) container-image $(CENGINE) container inspect $(CNTVER) > /dev/null 2>&1 || \ $(CENGINE) create \ --name $(CNTVER) \ --cap-drop AUDIT_WRITE \ --cap-drop CHOWN \ --cap-drop FSETID \ --cap-drop KILL \ --cap-drop MKNOD \ --cap-drop NET_BIND_SERVICE \ --cap-drop NET_RAW \ --cap-drop SETFCAP \ --cap-drop SETPCAP \ --publish 8080:8080 \ $(DCFLAGS) $(IMGVER) $(DCCMD) container-clean: -$(CENGINE) container kill $(CNTVER) -$(CENGINE) container rm $(CNTVER) -$(CENGINE) image rm $(IMGVER) container-image: $(APPNAME) tarball --name src @FOSSIL_CI_PFX@ $(SRCTB) $(CENGINE) buildx build \ --load \ --tag $(IMGVER) \ --build-arg FSLURL=$(SRCTB) \ $(DBFLAGS) @srcdir@ rm -f $(SRCTB) container-run container-start: container $(CENGINE) start $(DSFLAGS) $(CNTVER) @sleep 1 # decrease likelihood of logging race condition $(CENGINE) container logs $(CNTVER) container-stop: $(CENGINE) stop $(CNTVER) container-version: @echo $(CNTVER) |
Changes to VERSION.
|
| | | 1 | 2.24 |
Changes to auto.def.
| ︙ | ︙ | |||
27 28 29 30 31 32 33 34 35 36 37 38 |
internal-sqlite=1 => {Don't use the internal SQLite, use the system one}
static=0 => {Link a static executable}
fusefs=1 => {Disable the Fuse Filesystem}
fossil-debug=0 => {Build with fossil debugging enabled}
no-opt=0 => {Build without optimization}
json=0 => {Build with fossil JSON API enabled}
with-emsdk:path => {Directory containing the Emscripten SDK}
}
# 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!
| > > | > > > > > > | 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 |
internal-sqlite=1 => {Don't use the internal SQLite, use the system one}
static=0 => {Link a static executable}
fusefs=1 => {Disable the Fuse Filesystem}
fossil-debug=0 => {Build with fossil debugging enabled}
no-opt=0 => {Build without optimization}
json=0 => {Build with fossil JSON API enabled}
with-emsdk:path => {Directory containing the Emscripten SDK}
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.43.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
}
set outOfTreeBuild 0
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
|
| ︙ | ︙ | |||
176 177 178 179 180 181 182 |
}
user-error "system sqlite3 not found"
}
find_system_sqlite
proc test_system_sqlite {} {
| | | | > | 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 |
}
user-error "system sqlite3 not found"
}
find_system_sqlite
proc test_system_sqlite {} {
# Check compatibility of the system SQLite library by running the
# sqlcompttest.c program in the source tree passes
# MINIMUM_SQLITE_VERSION set at the top of this file to
# sqlcompttest.c
#
set cmdline {}
lappend cmdline {*}[get-define CCACHE]
lappend cmdline {*}[get-define CC] {*}[get-define CFLAGS]
lappend cmdline $::autosetup(dir)/../tools/sqlcompattest.c -o conftest__
lappend cmdline {*}[get-define LDFLAGS]
lappend cmdline {*}[get-define LIBS]
|
| ︙ | ︙ | |||
356 357 358 359 360 361 362 363 |
}
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 {
if {$zlibpath ni {auto ""}} {
| > > > > > > > > > > > | > > > | > > > > > > > > > > > > > > | | | < < > > | 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 |
}
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"
}
break
}
}
set ::zlib_lib -lz
}
set ssldirs [opt-val with-openssl]
if {$ssldirs ne "none"} {
set found 0
|
| ︙ | ︙ | |||
416 417 418 419 420 421 422 423 424 425 426 427 428 429 |
}
}
}
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
| > > | 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 |
}
}
}
if {$found} {
define FOSSIL_ENABLE_SSL
define-append EXTRA_CFLAGS $cflags
define-append EXTRA_LDFLAGS $ldflags
define-append CFLAGS $cflags
define-append 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
|
| ︙ | ︙ | |||
616 617 618 619 620 621 622 623 624 625 626 627 628 629 |
}
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
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)]
| > | 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 |
}
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)]
|
| ︙ | ︙ | |||
726 727 728 729 730 731 732 733 734 735 736 737 738 739 |
} elseif {[cc-check-function-in-lib fuse_mount fuse]} {
define-append EXTRA_CFLAGS -DFOSSIL_HAVE_FUSEFS
define FOSSIL_HAVE_FUSEFS 1
define-append LIBS -lfuse
msg-result "FuseFS support enabled"
}
}
# 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
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 |
} elseif {[cc-check-function-in-lib fuse_mount fuse]} {
define-append EXTRA_CFLAGS -DFOSSIL_HAVE_FUSEFS
define FOSSIL_HAVE_FUSEFS 1
define-append LIBS -lfuse
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
|
| ︙ | ︙ |
Changes to autosetup/autosetup-find-tclsh.
1 2 3 4 5 6 7 8 9 10 11 12 |
#!/bin/sh
# Looks for a suitable tclsh or jimsh in the PATH
# If not found, builds a bootstrap jimsh from source
# Prefer $autosetup_tclsh if is set in the environment
d=`dirname "$0"`
{ "$d/jimsh0" "$d/autosetup-test-tclsh"; } 2>/dev/null && exit 0
PATH="$PATH:$d"; export PATH
for tclsh in $autosetup_tclsh jimsh tclsh tclsh8.5 tclsh8.6; do
{ $tclsh "$d/autosetup-test-tclsh"; } 2>/dev/null && exit 0
done
echo 1>&2 "No installed jimsh or tclsh, building local bootstrap jimsh0"
for cc in ${CC_FOR_BUILD:-cc} gcc; do
| | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
#!/bin/sh
# Looks for a suitable tclsh or jimsh in the PATH
# If not found, builds a bootstrap jimsh from source
# Prefer $autosetup_tclsh if is set in the environment
d=`dirname "$0"`
{ "$d/jimsh0" "$d/autosetup-test-tclsh"; } 2>/dev/null && exit 0
PATH="$PATH:$d"; export PATH
for tclsh in $autosetup_tclsh jimsh tclsh tclsh8.5 tclsh8.6; do
{ $tclsh "$d/autosetup-test-tclsh"; } 2>/dev/null && exit 0
done
echo 1>&2 "No installed jimsh or tclsh, building local bootstrap jimsh0"
for cc in ${CC_FOR_BUILD:-cc} gcc; do
{ $cc -o "$d/jimsh0" "$d/jimsh0.c"; } >/dev/null 2>&1 || continue
"$d/jimsh0" "$d/autosetup-test-tclsh" && exit 0
done
echo 1>&2 "No working C compiler found. Tried ${CC_FOR_BUILD:-cc} and gcc."
echo false
|
Changes to compat/zlib/CMakeLists.txt.
|
| | | < < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 |
cmake_minimum_required(VERSION 2.4.4...3.15.0)
set(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS ON)
project(zlib C)
set(VERSION "1.3")
set(INSTALL_BIN_DIR "${CMAKE_INSTALL_PREFIX}/bin" CACHE PATH "Installation directory for executables")
set(INSTALL_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib" CACHE PATH "Installation directory for libraries")
set(INSTALL_INC_DIR "${CMAKE_INSTALL_PREFIX}/include" CACHE PATH "Installation directory for headers")
set(INSTALL_MAN_DIR "${CMAKE_INSTALL_PREFIX}/share/man" CACHE PATH "Installation directory for manual pages")
set(INSTALL_PKGCONFIG_DIR "${CMAKE_INSTALL_PREFIX}/share/pkgconfig" CACHE PATH "Installation directory for pkgconfig (.pc) files")
|
| ︙ | ︙ | |||
125 126 127 128 129 130 131 |
if(NOT MINGW)
set(ZLIB_DLL_SRCS
win32/zlib1.rc # If present will override custom build rule below.
)
endif()
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 122 123 124 125 126 127 128 129 130 131 132 133 134 135 |
if(NOT MINGW)
set(ZLIB_DLL_SRCS
win32/zlib1.rc # If present will override custom build rule below.
)
endif()
# parse the full version number from zlib.h and include in ZLIB_FULL_VERSION
file(READ ${CMAKE_CURRENT_SOURCE_DIR}/zlib.h _zlib_h_contents)
string(REGEX REPLACE ".*#define[ \t]+ZLIB_VERSION[ \t]+\"([-0-9A-Za-z.]+)\".*"
"\\1" ZLIB_FULL_VERSION ${_zlib_h_contents})
if(MINGW)
# This gets us DLL resource information when compiling on MinGW.
|
| ︙ | ︙ | |||
179 180 181 182 183 184 185 |
-I ${CMAKE_CURRENT_SOURCE_DIR}
-I ${CMAKE_CURRENT_BINARY_DIR}
-o ${CMAKE_CURRENT_BINARY_DIR}/zlib1rc.obj
-i ${CMAKE_CURRENT_SOURCE_DIR}/win32/zlib1.rc)
set(ZLIB_DLL_SRCS ${CMAKE_CURRENT_BINARY_DIR}/zlib1rc.obj)
endif(MINGW)
| | | | 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 |
-I ${CMAKE_CURRENT_SOURCE_DIR}
-I ${CMAKE_CURRENT_BINARY_DIR}
-o ${CMAKE_CURRENT_BINARY_DIR}/zlib1rc.obj
-i ${CMAKE_CURRENT_SOURCE_DIR}/win32/zlib1.rc)
set(ZLIB_DLL_SRCS ${CMAKE_CURRENT_BINARY_DIR}/zlib1rc.obj)
endif(MINGW)
add_library(zlib SHARED ${ZLIB_SRCS} ${ZLIB_DLL_SRCS} ${ZLIB_PUBLIC_HDRS} ${ZLIB_PRIVATE_HDRS})
add_library(zlibstatic STATIC ${ZLIB_SRCS} ${ZLIB_PUBLIC_HDRS} ${ZLIB_PRIVATE_HDRS})
set_target_properties(zlib PROPERTIES DEFINE_SYMBOL ZLIB_DLL)
set_target_properties(zlib PROPERTIES SOVERSION 1)
if(NOT CYGWIN)
# This property causes shared libraries on Linux to have the full version
# encoded into their final filename. We disable this on Cygwin because
# it causes cygz-${ZLIB_FULL_VERSION}.dll to be created when cygz.dll
|
| ︙ | ︙ |
Changes to compat/zlib/ChangeLog.
1 2 3 4 5 6 7 8 9 10 |
ChangeLog file for zlib
Changes in 1.2.12 (27 Mar 2022)
- Cygwin does not have _wopen(), so do not create gzopen_w() there
- Permit a deflateParams() parameter change as soon as possible
- Limit hash table inserts after switch from stored deflate
- Fix bug when window full in deflate_stored()
- Fix CLEAR_HASH macro to be usable as a single statement
- Avoid a conversion error in gzseek when off_t type too small
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 |
ChangeLog file for zlib
Changes in 1.3 (18 Aug 2023)
- Remove K&R function definitions and zlib2ansi
- Fix bug in deflateBound() for level 0 and memLevel 9
- Fix bug when gzungetc() is used immediately after gzopen()
- Fix bug when using gzflush() with a very small buffer
- Fix crash when gzsetparams() attempted for transparent write
- Fix test/example.c to work with FORCE_STORED
- Rewrite of zran in examples (see zran.c version history)
- Fix minizip to allow it to open an empty zip file
- Fix reading disk number start on zip64 files in minizip
- Fix logic error in minizip argument processing
- Add minizip testing to Makefile
- Read multiple bytes instead of byte-by-byte in minizip unzip.c
- Add memory sanitizer to configure (--memory)
- Various portability improvements
- Various documentation improvements
- Various spelling and typo corrections
Changes in 1.2.13 (13 Oct 2022)
- Fix configure issue that discarded provided CC definition
- Correct incorrect inputs provided to the CRC functions
- Repair prototypes and exporting of new CRC functions
- Fix inflateBack to detect invalid input with distances too far
- Have infback() deliver all of the available output up to any error
- Fix a bug when getting a gzip header extra field with inflate()
- Fix bug in block type selection when Z_FIXED used
- Tighten deflateBound bounds
- Remove deleted assembler code references
- Various portability and appearance improvements
Changes in 1.2.12 (27 Mar 2022)
- Cygwin does not have _wopen(), so do not create gzopen_w() there
- Permit a deflateParams() parameter change as soon as possible
- Limit hash table inserts after switch from stored deflate
- Fix bug when window full in deflate_stored()
- Fix CLEAR_HASH macro to be usable as a single statement
- Avoid a conversion error in gzseek when off_t type too small
|
| ︙ | ︙ | |||
155 156 157 158 159 160 161 | - Add contrib/vstudio/vc10 pre-build step for static only - Quote --version-script argument in CMakeLists.txt - Don't specify --version-script on Apple platforms in CMakeLists.txt - Fix casting error in contrib/testzlib/testzlib.c - Fix types in contrib/minizip to match result of get_crc_table() - Simplify contrib/vstudio/vc10 with 'd' suffix - Add TOP support to win32/Makefile.msc | | | 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 | - Add contrib/vstudio/vc10 pre-build step for static only - Quote --version-script argument in CMakeLists.txt - Don't specify --version-script on Apple platforms in CMakeLists.txt - Fix casting error in contrib/testzlib/testzlib.c - Fix types in contrib/minizip to match result of get_crc_table() - Simplify contrib/vstudio/vc10 with 'd' suffix - Add TOP support to win32/Makefile.msc - Support i686 and amd64 assembler builds in CMakeLists.txt - Fix typos in the use of _LARGEFILE64_SOURCE in zconf.h - Add vc11 and vc12 build files to contrib/vstudio - Add gzvprintf() as an undocumented function in zlib - Fix configure for Sun shell - Remove runtime check in configure for four-byte integer type - Add casts and consts to ease user conversion to C++ - Add man pages for minizip and miniunzip |
| ︙ | ︙ | |||
355 356 357 358 359 360 361 | - Avoid deflate sensitivity to volatile input data - Avoid division in adler32_combine for NO_DIVIDE - Clarify the use of Z_FINISH with deflateBound() amount of space - Set binary for output file in puff.c - Use u4 type for crc_table to avoid conversion warnings - Apply casts in zlib.h to avoid conversion warnings - Add OF to prototypes for adler32_combine_ and crc32_combine_ [Miller] | | | | 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 | - Avoid deflate sensitivity to volatile input data - Avoid division in adler32_combine for NO_DIVIDE - Clarify the use of Z_FINISH with deflateBound() amount of space - Set binary for output file in puff.c - Use u4 type for crc_table to avoid conversion warnings - Apply casts in zlib.h to avoid conversion warnings - Add OF to prototypes for adler32_combine_ and crc32_combine_ [Miller] - Improve inflateSync() documentation to note indeterminacy - Add deflatePending() function to return the amount of pending output - Correct the spelling of "specification" in FAQ [Randers-Pehrson] - Add a check in configure for stdarg.h, use for gzprintf() - Check that pointers fit in ints when gzprint() compiled old style - Add dummy name before $(SHAREDLIBV) in Makefile [Bar-Lev, Bowler] - Delete line in configure that adds -L. libz.a to LDFLAGS [Weigelt] - Add debug records in assembler code [Londer] - Update RFC references to use http://tools.ietf.org/html/... [Li] - Add --archs option, use of libtool to configure for Mac OS X [Borstel] Changes in 1.2.5 (19 Apr 2010) - Disable visibility attribute in win32/Makefile.gcc [Bar-Lev] - Default to libdir as sharedlibdir in configure [Nieder] - Update copyright dates on modified source files |
| ︙ | ︙ | |||
1029 1030 1031 1032 1033 1034 1035 |
- Clean up what gets compiled for FASTEST
- Incorporate changes to zconf.in.h [Vollant]
- Refine detection of Turbo C need for dummy returns
- Refine ZLIB_DLL compilation
- Include additional header file on VMS for off_t typedef
- Try to use _vsnprintf where it supplants vsprintf [Vollant]
- Add some casts in inffast.c
| | | 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 |
- Clean up what gets compiled for FASTEST
- Incorporate changes to zconf.in.h [Vollant]
- Refine detection of Turbo C need for dummy returns
- Refine ZLIB_DLL compilation
- Include additional header file on VMS for off_t typedef
- Try to use _vsnprintf where it supplants vsprintf [Vollant]
- Add some casts in inffast.c
- Enhance comments in zlib.h on what happens if gzprintf() tries to
write more than 4095 bytes before compression
- Remove unused state from inflateBackEnd()
- Remove exit(0) from minigzip.c, example.c
- Get rid of all those darn tabs
- Add "check" target to Makefile.in that does the same thing as "test"
- Add "mostlyclean" and "maintainer-clean" targets to Makefile.in
- Update contrib/inflate86 [Anderson]
|
| ︙ | ︙ | |||
1207 1208 1209 1210 1211 1212 1213 | . ZALLOC the length list in inflate_trees_fixed() instead of using stack . ZALLOC the value area for huft_build() instead of using stack . Simplify Z_FINISH check in inflate() - Avoid gcc 2.8.0 comparison bug a little differently than zlib 1.0.8 - in inftrees.c, avoid cc -O bug on HP (Farshid Elahi) - in zconf.h move the ZLIB_DLL stuff earlier to avoid problems with | | | 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 | . ZALLOC the length list in inflate_trees_fixed() instead of using stack . ZALLOC the value area for huft_build() instead of using stack . Simplify Z_FINISH check in inflate() - Avoid gcc 2.8.0 comparison bug a little differently than zlib 1.0.8 - in inftrees.c, avoid cc -O bug on HP (Farshid Elahi) - in zconf.h move the ZLIB_DLL stuff earlier to avoid problems with the declaration of FAR (Gilles Vollant) - install libz.so* with mode 755 (executable) instead of 644 (Marc Lehmann) - read_buf buf parameter of type Bytef* instead of charf* - zmemcpy parameters are of type Bytef*, not charf* (Joseph Strout) - do not redeclare unlink in minigzip.c for WIN32 (John Bowler) - fix check for presence of directories in "make install" (Ian Willis) Changes in 1.0.8 (27 Jan 1998) |
| ︙ | ︙ | |||
1429 1430 1431 1432 1433 1434 1435 | - clear z->msg in inflateInit2 before any error return - initialize opaque in example.c, gzio.c, deflate.c and inflate.c - fixed typo in zconf.h (_GNUC__ => __GNUC__) - check for WIN32 in zconf.h and zutil.c (avoid farmalloc in 32-bit mode) - fix typo in Make_vms.com (f$trnlnm -> f$getsyi) - in fcalloc, normalize pointer if size > 65520 bytes - don't use special fcalloc for 32 bit Borland C++ | | | 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 | - clear z->msg in inflateInit2 before any error return - initialize opaque in example.c, gzio.c, deflate.c and inflate.c - fixed typo in zconf.h (_GNUC__ => __GNUC__) - check for WIN32 in zconf.h and zutil.c (avoid farmalloc in 32-bit mode) - fix typo in Make_vms.com (f$trnlnm -> f$getsyi) - in fcalloc, normalize pointer if size > 65520 bytes - don't use special fcalloc for 32 bit Borland C++ - use STDC instead of __GO32__ to avoid redeclaring exit, calloc, etc. - use Z_BINARY instead of BINARY - document that gzclose after gzdopen will close the file - allow "a" as mode in gzopen - fix error checking in gzread - allow skipping .gz extra-field on pipes - added reference to Perl interface in README - put the crc table in FAR data (I dislike more and more the medium model :) |
| ︙ | ︙ | |||
1563 1564 1565 1566 1567 1568 1569 | - avoid "zip" everywhere, use zlib instead of ziplib - suppress Z_BLOCK_FLUSH, interpret Z_PARTIAL_FLUSH as block flush if compression method == 8 - added adler32 and crc32 - renamed deflateOptions as deflateInit2, call one or the other but not both - added the method parameter for deflateInit2 - added inflateInit2 | | | 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 | - avoid "zip" everywhere, use zlib instead of ziplib - suppress Z_BLOCK_FLUSH, interpret Z_PARTIAL_FLUSH as block flush if compression method == 8 - added adler32 and crc32 - renamed deflateOptions as deflateInit2, call one or the other but not both - added the method parameter for deflateInit2 - added inflateInit2 - simplified considerably deflateInit and inflateInit by not supporting user-provided history buffer. This is supported only in deflateInit2 and inflateInit2 Changes in 0.3: - prefix all macro names with Z_ - use Z_FINISH instead of deflateEnd to finish compression - added Z_HUFFMAN_ONLY - added gzerror() |
Changes to compat/zlib/FAQ.
1 2 3 4 5 6 |
Frequently Asked Questions about zlib
If your question is not there, please check the zlib home page
http://zlib.net/ which may have more recent information.
| | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
Frequently Asked Questions about zlib
If your question is not there, please check the zlib home page
http://zlib.net/ which may have more recent information.
The latest zlib FAQ is at http://zlib.net/zlib_faq.html
1. Is zlib Y2K-compliant?
Yes. zlib doesn't handle dates.
2. Where can I get a Windows DLL version?
|
| ︙ | ︙ |
Added compat/zlib/LICENSE.
> > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
Copyright notice:
(C) 1995-2022 Jean-loup Gailly and Mark Adler
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
Jean-loup Gailly Mark Adler
jloup@gzip.org madler@alumni.caltech.edu
|
Changes to compat/zlib/Makefile.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < | 1 2 3 4 5 | all: -@echo "Please use ./configure first. Thank you." distclean: make -f Makefile.in distclean |
Changes to compat/zlib/Makefile.in.
1 2 3 4 5 6 7 8 9 | # Makefile for zlib # Copyright (C) 1995-2017 Jean-loup Gailly, Mark Adler # For conditions of distribution and use, see copyright notice in zlib.h # To compile and test, type: # ./configure; make test # Normally configure builds both a static and a shared library. # If you want to build just a static library, use: ./configure --static | < < < < | | | 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 | # Makefile for zlib # Copyright (C) 1995-2017 Jean-loup Gailly, Mark Adler # For conditions of distribution and use, see copyright notice in zlib.h # To compile and test, type: # ./configure; make test # Normally configure builds both a static and a shared library. # If you want to build just a static library, use: ./configure --static # To install /usr/local/lib/libz.* and /usr/local/include/zlib.h, type: # make install # To install in $HOME instead of /usr/local, use: # make install prefix=$HOME CC=cc CFLAGS=-O #CFLAGS=-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7 #CFLAGS=-g -DZLIB_DEBUG #CFLAGS=-O3 -Wall -Wwrite-strings -Wpointer-arith -Wconversion \ # -Wstrict-prototypes -Wmissing-prototypes SFLAGS=-O LDFLAGS= TEST_LDFLAGS=$(LDFLAGS) -L. libz.a LDSHARED=$(CC) CPP=$(CC) -E STATICLIB=libz.a SHAREDLIB=libz.so SHAREDLIBV=libz.so.1.3 SHAREDLIBM=libz.so.1 LIBS=$(STATICLIB) $(SHAREDLIBV) AR=ar ARFLAGS=rc RANLIB=ranlib LDCONFIG=ldconfig |
| ︙ | ︙ | |||
83 84 85 86 87 88 89 | check: test test: all teststatic testshared teststatic: static @TMPST=tmpst_$$; \ | | | | | | 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 |
check: test
test: all teststatic testshared
teststatic: static
@TMPST=tmpst_$$; \
if echo hello world | ${QEMU_RUN} ./minigzip | ${QEMU_RUN} ./minigzip -d && ${QEMU_RUN} ./example $$TMPST ; then \
echo ' *** zlib test OK ***'; \
else \
echo ' *** zlib test FAILED ***'; false; \
fi
@rm -f tmpst_$$
testshared: shared
@LD_LIBRARY_PATH=`pwd`:$(LD_LIBRARY_PATH) ; export LD_LIBRARY_PATH; \
LD_LIBRARYN32_PATH=`pwd`:$(LD_LIBRARYN32_PATH) ; export LD_LIBRARYN32_PATH; \
DYLD_LIBRARY_PATH=`pwd`:$(DYLD_LIBRARY_PATH) ; export DYLD_LIBRARY_PATH; \
SHLIB_PATH=`pwd`:$(SHLIB_PATH) ; export SHLIB_PATH; \
TMPSH=tmpsh_$$; \
if echo hello world | ${QEMU_RUN} ./minigzipsh | ${QEMU_RUN} ./minigzipsh -d && ${QEMU_RUN} ./examplesh $$TMPSH; then \
echo ' *** zlib shared test OK ***'; \
else \
echo ' *** zlib shared test FAILED ***'; false; \
fi
@rm -f tmpsh_$$
test64: all64
@TMP64=tmp64_$$; \
if echo hello world | ${QEMU_RUN} ./minigzip64 | ${QEMU_RUN} ./minigzip64 -d && ${QEMU_RUN} ./example64 $$TMP64; then \
echo ' *** zlib 64-bit test OK ***'; \
else \
echo ' *** zlib 64-bit test FAILED ***'; false; \
fi
@rm -f tmp64_$$
infcover.o: $(SRCDIR)test/infcover.c $(SRCDIR)zlib.h zconf.h
$(CC) $(CFLAGS) $(ZINCOUT) -c -o $@ $(SRCDIR)test/infcover.c
infcover: infcover.o libz.a
$(CC) $(CFLAGS) -o $@ infcover.o libz.a
cover: infcover
rm -f *.gcda
${QEMU_RUN} ./infcover
gcov inf*.c
libz.a: $(OBJS)
$(AR) $(ARFLAGS) $@ $(OBJS)
-@ ($(RANLIB) $@ || true) >/dev/null 2>&1
match.o: match.S
|
| ︙ | ︙ | |||
288 289 290 291 292 293 294 | example$(EXE): example.o $(STATICLIB) $(CC) $(CFLAGS) -o $@ example.o $(TEST_LDFLAGS) minigzip$(EXE): minigzip.o $(STATICLIB) $(CC) $(CFLAGS) -o $@ minigzip.o $(TEST_LDFLAGS) examplesh$(EXE): example.o $(SHAREDLIBV) | | | | 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 | example$(EXE): example.o $(STATICLIB) $(CC) $(CFLAGS) -o $@ example.o $(TEST_LDFLAGS) minigzip$(EXE): minigzip.o $(STATICLIB) $(CC) $(CFLAGS) -o $@ minigzip.o $(TEST_LDFLAGS) examplesh$(EXE): example.o $(SHAREDLIBV) $(CC) $(CFLAGS) -o $@ example.o $(LDFLAGS) -L. $(SHAREDLIBV) minigzipsh$(EXE): minigzip.o $(SHAREDLIBV) $(CC) $(CFLAGS) -o $@ minigzip.o $(LDFLAGS) -L. $(SHAREDLIBV) example64$(EXE): example64.o $(STATICLIB) $(CC) $(CFLAGS) -o $@ example64.o $(TEST_LDFLAGS) minigzip64$(EXE): minigzip64.o $(STATICLIB) $(CC) $(CFLAGS) -o $@ minigzip64.o $(TEST_LDFLAGS) |
| ︙ | ︙ | |||
359 360 361 362 363 364 365 366 | sed -f $$TEMPFILE $(SRCDIR)zconf.h.in > $@ &&\ touch -r $(SRCDIR)zconf.h.in $@ &&\ rm $$TEMPFILE zconf: $(SRCDIR)zconf.h.in cp -p $(SRCDIR)zconf.h.in zconf.h mostlyclean: clean | > > > > > > | | 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 |
sed -f $$TEMPFILE $(SRCDIR)zconf.h.in > $@ &&\
touch -r $(SRCDIR)zconf.h.in $@ &&\
rm $$TEMPFILE
zconf: $(SRCDIR)zconf.h.in
cp -p $(SRCDIR)zconf.h.in zconf.h
minizip-test: static
cd contrib/minizip && { CFLAGS="$(CFLAGS)" $(MAKE) test ; cd ../.. ; }
minizip-clean:
cd contrib/minizip && { $(MAKE) clean ; cd ../.. ; }
mostlyclean: clean
clean: minizip-clean
rm -f *.o *.lo *~ \
example$(EXE) minigzip$(EXE) examplesh$(EXE) minigzipsh$(EXE) \
example64$(EXE) minigzip64$(EXE) \
infcover \
libz.* foo.gz so_locations \
_match.s maketree contrib/infback9/*.o
rm -rf objs
|
| ︙ | ︙ |
Changes to compat/zlib/README.
1 2 | ZLIB DATA COMPRESSION LIBRARY | | | 1 2 3 4 5 6 7 8 9 10 | ZLIB DATA COMPRESSION LIBRARY zlib 1.3 is a general purpose data compression library. All the code is thread safe. The data format used by the zlib library is described by RFCs (Request for Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950 (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format). All functions of the compression library are documented in the file zlib.h (volunteer to write man pages welcome, contact zlib@gzip.org). A usage example |
| ︙ | ︙ | |||
25 26 27 28 29 30 31 | verify that you have the latest version of zlib; otherwise get the latest version and check whether the problem still exists or not. PLEASE read the zlib FAQ http://zlib.net/zlib_faq.html before asking for help. Mark Nelson <markn@ieee.org> wrote an article about zlib for the Jan. 1997 issue of Dr. Dobb's Journal; a copy of the article is available at | | | | | | < | | 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 | verify that you have the latest version of zlib; otherwise get the latest version and check whether the problem still exists or not. PLEASE read the zlib FAQ http://zlib.net/zlib_faq.html before asking for help. Mark Nelson <markn@ieee.org> wrote an article about zlib for the Jan. 1997 issue of Dr. Dobb's Journal; a copy of the article is available at https://marknelson.us/posts/1997/01/01/zlib-engine.html . The changes made in version 1.3 are documented in the file ChangeLog. Unsupported third party contributions are provided in directory contrib/ . zlib is available in Java using the java.util.zip package. Follow the API Documentation link at: https://docs.oracle.com/search/?q=java.util.zip . A Perl interface to zlib and bzip2 written by Paul Marquess <pmqs@cpan.org> can be found at https://github.com/pmqs/IO-Compress . A Python interface to zlib written by A.M. Kuchling <amk@amk.ca> is available in Python 1.5 and later versions, see http://docs.python.org/library/zlib.html . zlib is built into tcl: http://wiki.tcl.tk/4610 . |
| ︙ | ︙ | |||
60 61 62 63 64 65 66 | - For 64-bit Irix, deflate.c must be compiled without any optimization. With -O, one libpng test fails. The test works in 32 bit mode (with the -n32 compiler flag). The compiler bug has been reported to SGI. - zlib doesn't work with gcc 2.6.3 on a DEC 3000/300LX under OSF/1 2.1 it works when compiled with cc. | | | | 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 | - For 64-bit Irix, deflate.c must be compiled without any optimization. With -O, one libpng test fails. The test works in 32 bit mode (with the -n32 compiler flag). The compiler bug has been reported to SGI. - zlib doesn't work with gcc 2.6.3 on a DEC 3000/300LX under OSF/1 2.1 it works when compiled with cc. - On Digital Unix 4.0D (formerly OSF/1) on AlphaServer, the cc option -std1 is necessary to get gzprintf working correctly. This is done by configure. - zlib doesn't work on HP-UX 9.05 with some versions of /bin/cc. It works with other compilers. Use "make test" to check your compiler. - gzdopen is not supported on RISCOS or BEOS. - For PalmOs, see http://palmzlib.sourceforge.net/ Acknowledgments: The deflate format used by zlib was defined by Phil Katz. The deflate and zlib specifications were written by L. Peter Deutsch. Thanks to all the people who reported problems and suggested various improvements in zlib; they are too numerous to cite here. Copyright notice: (C) 1995-2023 Jean-loup Gailly and Mark Adler This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it |
| ︙ | ︙ |
Changes to compat/zlib/adler32.c.
1 2 3 4 5 6 7 8 9 | /* adler32.c -- compute the Adler-32 checksum of a data stream * Copyright (C) 1995-2011, 2016 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* @(#) $Id$ */ #include "zutil.h" | < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
/* adler32.c -- compute the Adler-32 checksum of a data stream
* Copyright (C) 1995-2011, 2016 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
/* @(#) $Id$ */
#include "zutil.h"
#define BASE 65521U /* largest prime smaller than 65536 */
#define NMAX 5552
/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
#define DO1(buf,i) {adler += (buf)[i]; sum2 += adler;}
#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1);
#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2);
|
| ︙ | ︙ | |||
56 57 58 59 60 61 62 | #else # define MOD(a) a %= BASE # define MOD28(a) a %= BASE # define MOD63(a) a %= BASE #endif /* ========================================================================= */ | | < < < < | 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
#else
# define MOD(a) a %= BASE
# define MOD28(a) a %= BASE
# define MOD63(a) a %= BASE
#endif
/* ========================================================================= */
uLong ZEXPORT adler32_z(uLong adler, const Bytef *buf, z_size_t len) {
unsigned long sum2;
unsigned n;
/* split Adler-32 into component sums */
sum2 = (adler >> 16) & 0xffff;
adler &= 0xffff;
|
| ︙ | ︙ | |||
127 128 129 130 131 132 133 |
}
/* return recombined sums */
return adler | (sum2 << 16);
}
/* ========================================================================= */
| | < < < < | < < < < | 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 |
}
/* return recombined sums */
return adler | (sum2 << 16);
}
/* ========================================================================= */
uLong ZEXPORT adler32(uLong adler, const Bytef *buf, uInt len) {
return adler32_z(adler, buf, len);
}
/* ========================================================================= */
local uLong adler32_combine_(uLong adler1, uLong adler2, z_off64_t len2) {
unsigned long sum1;
unsigned long sum2;
unsigned rem;
/* for negative len, return invalid adler32 as a clue for debugging */
if (len2 < 0)
return 0xffffffffUL;
|
| ︙ | ︙ | |||
165 166 167 168 169 170 171 |
if (sum1 >= BASE) sum1 -= BASE;
if (sum2 >= ((unsigned long)BASE << 1)) sum2 -= ((unsigned long)BASE << 1);
if (sum2 >= BASE) sum2 -= BASE;
return sum1 | (sum2 << 16);
}
/* ========================================================================= */
| | < < < < | < < < < | 151 152 153 154 155 156 157 158 159 160 161 162 163 164 |
if (sum1 >= BASE) sum1 -= BASE;
if (sum2 >= ((unsigned long)BASE << 1)) sum2 -= ((unsigned long)BASE << 1);
if (sum2 >= BASE) sum2 -= BASE;
return sum1 | (sum2 << 16);
}
/* ========================================================================= */
uLong ZEXPORT adler32_combine(uLong adler1, uLong adler2, z_off_t len2) {
return adler32_combine_(adler1, adler2, len2);
}
uLong ZEXPORT adler32_combine64(uLong adler1, uLong adler2, z_off64_t len2) {
return adler32_combine_(adler1, adler2, len2);
}
|
Changes to compat/zlib/compress.c.
| ︙ | ︙ | |||
15 16 17 18 19 20 21 |
destination buffer, which must be at least 0.1% larger than sourceLen plus
12 bytes. Upon exit, destLen is the actual size of the compressed buffer.
compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
memory, Z_BUF_ERROR if there was not enough room in the output buffer,
Z_STREAM_ERROR if the level parameter is invalid.
*/
| < < < | | < < | 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
destination buffer, which must be at least 0.1% larger than sourceLen plus
12 bytes. Upon exit, destLen is the actual size of the compressed buffer.
compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
memory, Z_BUF_ERROR if there was not enough room in the output buffer,
Z_STREAM_ERROR if the level parameter is invalid.
*/
int ZEXPORT compress2(Bytef *dest, uLongf *destLen, const Bytef *source,
uLong sourceLen, int level) {
z_stream stream;
int err;
const uInt max = (uInt)-1;
uLong left;
left = *destLen;
*destLen = 0;
|
| ︙ | ︙ | |||
61 62 63 64 65 66 67 |
*destLen = stream.total_out;
deflateEnd(&stream);
return err == Z_STREAM_END ? Z_OK : err;
}
/* ===========================================================================
*/
| < < < | | < | < < | 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
*destLen = stream.total_out;
deflateEnd(&stream);
return err == Z_STREAM_END ? Z_OK : err;
}
/* ===========================================================================
*/
int ZEXPORT compress(Bytef *dest, uLongf *destLen, const Bytef *source,
uLong sourceLen) {
return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION);
}
/* ===========================================================================
If the default memLevel or windowBits for deflateInit() is changed, then
this function needs to be updated.
*/
uLong ZEXPORT compressBound(uLong sourceLen) {
return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) +
(sourceLen >> 25) + 13;
}
|
Changes to compat/zlib/configure.
| ︙ | ︙ | |||
28 29 30 31 32 33 34 |
ZINC='-include zconf.h'
ZINCOUT='-I. -I$(SRCDIR)'
SRCDIR="$SRCDIR/"
fi
# set command prefix for cross-compilation
if [ -n "${CHOST}" ]; then
| | > > > < < | 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 |
ZINC='-include zconf.h'
ZINCOUT='-I. -I$(SRCDIR)'
SRCDIR="$SRCDIR/"
fi
# set command prefix for cross-compilation
if [ -n "${CHOST}" ]; then
uname=${CHOST}
mname=${CHOST}
CROSS_PREFIX="${CHOST}-"
else
mname=`(uname -a || echo unknown) 2>/dev/null`
fi
# destination name for static library
STATICLIB=libz.a
# extract zlib version numbers from zlib.h
VER=`sed -n -e '/VERSION "/s/.*"\(.*\)".*/\1/p' < ${SRCDIR}zlib.h`
VER1=`sed -n -e '/VERSION "/s/.*"\([0-9]*\)\\..*/\1/p' < ${SRCDIR}zlib.h`
# establish commands for library building
if "${CROSS_PREFIX}ar" --version >/dev/null 2>/dev/null || test $? -lt 126; then
AR=${AR-"${CROSS_PREFIX}ar"}
test -n "${CROSS_PREFIX}" && echo Using ${AR} | tee -a configure.log
else
|
| ︙ | ︙ | |||
83 84 85 86 87 88 89 | cover=0 zprefix=0 zconst=0 build64=0 gcc=0 warn=0 debug=0 | | > | | 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 |
cover=0
zprefix=0
zconst=0
build64=0
gcc=0
warn=0
debug=0
address=0
memory=0
old_cc="$CC"
old_cflags="$CFLAGS"
OBJC='$(OBJZ) $(OBJG)'
PIC_OBJC='$(PIC_OBJZ) $(PIC_OBJG)'
# leave this script, optionally in a bad way
leave()
{
if test "$*" != "0"; then
echo "** $0 aborting." | tee -a configure.log
fi
rm -rf $test.[co] $test $test$shared_ext $test.gcno $test.dSYM ./--version
echo -------------------- >> configure.log
echo >> configure.log
echo >> configure.log
exit $1
}
# process command line options
|
| ︙ | ︙ | |||
134 135 136 137 138 139 140 |
-6* | --64) build64=1; shift ;;
-a*=* | --archs=*) ARCHS=`echo $1 | sed 's/.*=//'`; shift ;;
--sysconfdir=*) echo "ignored option: --sysconfdir" | tee -a configure.log; shift ;;
--localstatedir=*) echo "ignored option: --localstatedir" | tee -a configure.log; shift ;;
-c* | --const) zconst=1; shift ;;
-w* | --warn) warn=1; shift ;;
-d* | --debug) debug=1; shift ;;
| > > | | 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 |
-6* | --64) build64=1; shift ;;
-a*=* | --archs=*) ARCHS=`echo $1 | sed 's/.*=//'`; shift ;;
--sysconfdir=*) echo "ignored option: --sysconfdir" | tee -a configure.log; shift ;;
--localstatedir=*) echo "ignored option: --localstatedir" | tee -a configure.log; shift ;;
-c* | --const) zconst=1; shift ;;
-w* | --warn) warn=1; shift ;;
-d* | --debug) debug=1; shift ;;
--sanitize) address=1; shift ;;
--address) address=1; shift ;;
--memory) memory=1; shift ;;
*)
echo "unknown option: $1" | tee -a configure.log
echo "$0 --help for help" | tee -a configure.log
leave 1;;
esac
done
|
| ︙ | ︙ | |||
170 171 172 173 174 175 176 177 |
if test -z "$CC"; then
echo Checking for ${CROSS_PREFIX}gcc... | tee -a configure.log
if ${CROSS_PREFIX}gcc -v >/dev/null 2>&1; then
cc=${CROSS_PREFIX}gcc
else
cc=${CROSS_PREFIX}cc
fi
fi
| > > | < | 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 |
if test -z "$CC"; then
echo Checking for ${CROSS_PREFIX}gcc... | tee -a configure.log
if ${CROSS_PREFIX}gcc -v >/dev/null 2>&1; then
cc=${CROSS_PREFIX}gcc
else
cc=${CROSS_PREFIX}cc
fi
else
cc=${CC}
fi
case "$cc" in
*gcc*) gcc=1 ;;
*clang*) gcc=1 ;;
esac
case `$cc -v 2>&1` in
*gcc*) gcc=1 ;;
*clang*) gcc=1 ;;
|
| ︙ | ︙ | |||
198 199 200 201 202 203 204 |
fi
if test $build64 -eq 1; then
CFLAGS="${CFLAGS} -m64"
SFLAGS="${SFLAGS} -m64"
fi
if test "$warn" -eq 1; then
if test "$zconst" -eq 1; then
| | | | | > > > | > > > > | | < | < | | | | | | | | | | | | > > | | | | | | > > | | | | | | > | | 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 |
fi
if test $build64 -eq 1; then
CFLAGS="${CFLAGS} -m64"
SFLAGS="${SFLAGS} -m64"
fi
if test "$warn" -eq 1; then
if test "$zconst" -eq 1; then
CFLAGS="${CFLAGS} -Wall -Wextra -Wcast-qual -DZLIB_CONST"
else
CFLAGS="${CFLAGS} -Wall -Wextra"
fi
fi
if test $address -eq 1; then
CFLAGS="${CFLAGS} -g -fsanitize=address -fno-omit-frame-pointer"
fi
if test $memory -eq 1; then
CFLAGS="${CFLAGS} -g -fsanitize=memory -fno-omit-frame-pointer"
fi
if test $debug -eq 1; then
CFLAGS="${CFLAGS} -DZLIB_DEBUG"
SFLAGS="${SFLAGS} -DZLIB_DEBUG"
fi
if test -z "$uname"; then
uname=`(uname -s || echo unknown) 2>/dev/null`
fi
case "$uname" in
Linux* | linux* | *-linux* | GNU | GNU/* | solaris*)
case "$mname" in
*sparc*)
LDFLAGS="${LDFLAGS} -Wl,--no-warn-rwx-segments" ;;
esac
LDSHARED=${LDSHARED-"$cc -shared -Wl,-soname,libz.so.1,--version-script,${SRCDIR}zlib.map"} ;;
*BSD | *bsd* | DragonFly)
LDSHARED=${LDSHARED-"$cc -shared -Wl,-soname,libz.so.1,--version-script,${SRCDIR}zlib.map"}
LDCONFIG="ldconfig -m" ;;
CYGWIN* | Cygwin* | cygwin* | *-cygwin* | OS/2*)
EXE='.exe' ;;
MINGW* | mingw* | *-mingw*)
rm -f $test.[co] $test $test$shared_ext
echo "If this doesn't work for you, try win32/Makefile.gcc." | tee -a configure.log
LDSHARED=${LDSHARED-"$cc -shared"}
LDSHAREDLIBC=""
EXE='.exe' ;;
QNX*) # This is for QNX6. I suppose that the QNX rule below is for QNX2,QNX4
# (alain.bonnefoy@icbt.com)
LDSHARED=${LDSHARED-"$cc -shared -Wl,-hlibz.so.1"} ;;
HP-UX*)
LDSHARED=${LDSHARED-"$cc -shared $SFLAGS"}
case `(uname -m || echo unknown) 2>/dev/null` in
ia64)
shared_ext='.so'
SHAREDLIB='libz.so' ;;
*)
shared_ext='.sl'
SHAREDLIB='libz.sl' ;;
esac ;;
AIX*)
LDFLAGS="${LDFLAGS} -Wl,-brtl" ;;
Darwin* | darwin* | *-darwin*)
shared_ext='.dylib'
SHAREDLIB=libz$shared_ext
SHAREDLIBV=libz.$VER$shared_ext
SHAREDLIBM=libz.$VER1$shared_ext
LDSHARED=${LDSHARED-"$cc -dynamiclib -install_name $libdir/$SHAREDLIBM -compatibility_version $VER1 -current_version $VER"}
if "${CROSS_PREFIX}libtool" -V 2>&1 | grep Apple > /dev/null; then
AR="${CROSS_PREFIX}libtool"
elif libtool -V 2>&1 | grep Apple > /dev/null; then
AR="libtool"
else
AR="/usr/bin/libtool"
fi
ARFLAGS="-o" ;;
*)
LDSHARED=${LDSHARED-"$cc -shared"} ;;
esac
else
# find system name and corresponding cc options
CC=${CC-cc}
gcc=0
echo ... using $CC >> configure.log
if test -z "$uname"; then
|
| ︙ | ︙ | |||
446 447 448 449 450 451 452 | SHAREDLIBM="" echo Building static library $STATICLIB version $VER with $CC. | tee -a configure.log else ALL="static shared" TEST="all teststatic testshared" fi | < < < < < < < < < < < < < < | 461 462 463 464 465 466 467 468 469 470 471 472 473 474 | SHAREDLIBM="" echo Building static library $STATICLIB version $VER with $CC. | tee -a configure.log else ALL="static shared" TEST="all teststatic testshared" fi echo >> configure.log # check for size_t cat > $test.c <<EOF #include <stdio.h> #include <stdlib.h> size_t dummy = 0; |
| ︙ | ︙ | |||
861 862 863 864 865 866 867 | echo includedir = $includedir >> configure.log echo libdir = $libdir >> configure.log echo mandir = $mandir >> configure.log echo prefix = $prefix >> configure.log echo sharedlibdir = $sharedlibdir >> configure.log echo uname = $uname >> configure.log | | | 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 |
echo includedir = $includedir >> configure.log
echo libdir = $libdir >> configure.log
echo mandir = $mandir >> configure.log
echo prefix = $prefix >> configure.log
echo sharedlibdir = $sharedlibdir >> configure.log
echo uname = $uname >> configure.log
# update Makefile with the configure results
sed < ${SRCDIR}Makefile.in "
/^CC *=/s#=.*#=$CC#
/^CFLAGS *=/s#=.*#=$CFLAGS#
/^SFLAGS *=/s#=.*#=$SFLAGS#
/^LDFLAGS *=/s#=.*#=$LDFLAGS#
/^LDSHARED *=/s#=.*#=$LDSHARED#
/^CPP *=/s#=.*#=$CPP#
|
| ︙ | ︙ |
Changes to compat/zlib/contrib/README.contrib.
|
| | | 1 2 3 4 5 6 7 8 |
All files under this contrib directory are UNSUPPORTED. They were
provided by users of zlib and were not tested by the authors of zlib.
Use at your own risk. Please contact the authors of the contributions
for help about these, not the zlib authors. Thanks.
ada/ by Dmitriy Anisimkov <anisimkov@yahoo.com>
Support for Ada
|
| ︙ | ︙ |
Deleted compat/zlib/contrib/ada/buffer_demo.adb.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted compat/zlib/contrib/ada/mtest.adb.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted compat/zlib/contrib/ada/read.adb.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted compat/zlib/contrib/ada/readme.txt.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted compat/zlib/contrib/ada/test.adb.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted compat/zlib/contrib/ada/zlib-streams.adb.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted compat/zlib/contrib/ada/zlib-streams.ads.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted compat/zlib/contrib/ada/zlib-thin.adb.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted compat/zlib/contrib/ada/zlib-thin.ads.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted compat/zlib/contrib/ada/zlib.adb.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted compat/zlib/contrib/ada/zlib.ads.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted compat/zlib/contrib/ada/zlib.gpr.
|
| < < < < < < < < < < < < < < < < < < < < |
Deleted compat/zlib/contrib/amd64/amd64-match.S.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted compat/zlib/contrib/asm686/README.686.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted compat/zlib/contrib/asm686/match.S.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to compat/zlib/contrib/delphi/ZLib.pas.
| ︙ | ︙ | |||
148 149 150 151 152 153 154 |
InBytes = number of bytes in InBuf
Out: OutBuf = ptr to user-allocated buffer to contain decompressed data
BufSize = number of bytes in OutBuf }
procedure DecompressToUserBuf(const InBuf: Pointer; InBytes: Integer;
const OutBuf: Pointer; BufSize: Integer);
const
| | | 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 |
InBytes = number of bytes in InBuf
Out: OutBuf = ptr to user-allocated buffer to contain decompressed data
BufSize = number of bytes in OutBuf }
procedure DecompressToUserBuf(const InBuf: Pointer; InBytes: Integer;
const OutBuf: Pointer; BufSize: Integer);
const
zlib_version = '1.3.0';
type
EZlibError = class(Exception);
ECompressionError = class(EZlibError);
EDecompressionError = class(EZlibError);
implementation
|
| ︙ | ︙ |
Changes to compat/zlib/contrib/dotzlib/DotZLib/ChecksumImpl.cs.
| ︙ | ︙ | |||
57 58 59 60 61 62 63 |
/// </summary>
/// <param name="data">The data to update the checksum with</param>
/// <param name="offset">Where in <c>data</c> to start updating</param>
/// <param name="count">The number of bytes from <c>data</c> to use</param>
/// <exception cref="ArgumentException">The sum of offset and count is larger than the length of <c>data</c></exception>
/// <exception cref="NullReferenceException"><c>data</c> is a null reference</exception>
/// <exception cref="ArgumentOutOfRangeException">Offset or count is negative.</exception>
| | | 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
/// </summary>
/// <param name="data">The data to update the checksum with</param>
/// <param name="offset">Where in <c>data</c> to start updating</param>
/// <param name="count">The number of bytes from <c>data</c> to use</param>
/// <exception cref="ArgumentException">The sum of offset and count is larger than the length of <c>data</c></exception>
/// <exception cref="NullReferenceException"><c>data</c> is a null reference</exception>
/// <exception cref="ArgumentOutOfRangeException">Offset or count is negative.</exception>
/// <remarks>All the other <c>Update</c> methods are implemented in terms of this one.
/// This is therefore the only method a derived class has to implement</remarks>
public abstract void Update(byte[] data, int offset, int count);
/// <summary>
/// Updates the current checksum with an array of bytes.
/// </summary>
/// <param name="data">The data to update the checksum with</param>
|
| ︙ | ︙ |
Changes to compat/zlib/contrib/dotzlib/DotZLib/CodecBase.cs.
| ︙ | ︙ | |||
135 136 137 138 139 140 141 |
/// <summary>
/// Performs any codec specific cleanup
/// </summary>
/// <remarks>This must be implemented by a derived class</remarks>
protected abstract void CleanUp();
| | | | 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 |
/// <summary>
/// Performs any codec specific cleanup
/// </summary>
/// <remarks>This must be implemented by a derived class</remarks>
protected abstract void CleanUp();
// performs the release of the handles and calls the derived CleanUp()
private void CleanUp(bool isDisposing)
{
if (!_isDisposed)
{
CleanUp();
if (_hInput.IsAllocated)
_hInput.Free();
if (_hOutput.IsAllocated)
_hOutput.Free();
_isDisposed = true;
}
}
#endregion
#region Helper methods
/// <summary>
/// Copies a number of bytes to the internal codec buffer - ready for processing
/// </summary>
/// <param name="data">The byte array that contains the data to copy</param>
/// <param name="startIndex">The index of the first byte to copy</param>
/// <param name="count">The number of bytes to copy from <c>data</c></param>
protected void copyInput(byte[] data, int startIndex, int count)
{
Array.Copy(data, startIndex, _inBuffer,0, count);
|
| ︙ | ︙ |
Changes to compat/zlib/contrib/dotzlib/DotZLib/GZipStream.cs.
| ︙ | ︙ | |||
242 243 244 245 246 247 248 |
/// <exception cref="NotSupportedException">Always thrown</exception>
public override void SetLength(long value)
{
throw new NotSupportedException();
}
/// <summary>
| | | 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 |
/// <exception cref="NotSupportedException">Always thrown</exception>
public override void SetLength(long value)
{
throw new NotSupportedException();
}
/// <summary>
/// Not supported.
/// </summary>
/// <param name="offset"></param>
/// <param name="origin"></param>
/// <returns></returns>
/// <exception cref="NotSupportedException">Always thrown</exception>
public override long Seek(long offset, SeekOrigin origin)
{
|
| ︙ | ︙ | |||
264 265 266 267 268 269 270 |
/// flushing may degrade the achievable compression rates.</remarks>
public override void Flush()
{
// left empty on purpose
}
/// <summary>
| | | | 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 |
/// flushing may degrade the achievable compression rates.</remarks>
public override void Flush()
{
// left empty on purpose
}
/// <summary>
/// Gets/sets the current position in the <c>GZipStream</c>. Not supported.
/// </summary>
/// <remarks>In this implementation this property is not supported</remarks>
/// <exception cref="NotSupportedException">Always thrown</exception>
public override long Position
{
get
{
throw new NotSupportedException();
}
set
{
throw new NotSupportedException();
}
}
/// <summary>
/// Gets the size of the stream. Not supported.
/// </summary>
/// <remarks>In this implementation this property is not supported</remarks>
/// <exception cref="NotSupportedException">Always thrown</exception>
public override long Length
{
get
{
throw new NotSupportedException();
}
}
#endregion
}
}
|
Changes to compat/zlib/contrib/dotzlib/DotZLib/UnitTests.cs.
| ︙ | ︙ | |||
152 153 154 155 156 157 158 |
public class InfoTests
{
#region Info tests
[Test]
public void Info_Version()
{
Info info = new Info();
| | | 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 |
public class InfoTests
{
#region Info tests
[Test]
public void Info_Version()
{
Info info = new Info();
Assert.AreEqual("1.3.0", Info.Version);
Assert.AreEqual(32, info.SizeOfUInt);
Assert.AreEqual(32, info.SizeOfULong);
Assert.AreEqual(32, info.SizeOfPointer);
Assert.AreEqual(32, info.SizeOfOffset);
}
#endregion
}
|
| ︙ | ︙ |
Changes to compat/zlib/contrib/dotzlib/readme.txt.
| ︙ | ︙ | |||
32 33 34 35 36 37 38 |
build.
2. Using NAnt:
Open a command prompt with access to the build environment and run nant
in the same directory as the DotZLib.build file.
You can define 2 properties on the nant command-line to control the build:
debug={true|false} to toggle between release/debug builds (default=true).
| | | 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
build.
2. Using NAnt:
Open a command prompt with access to the build environment and run nant
in the same directory as the DotZLib.build file.
You can define 2 properties on the nant command-line to control the build:
debug={true|false} to toggle between release/debug builds (default=true).
nunit={true|false} to include or exclude unit tests (default=true).
Also the target clean will remove binaries.
Output file (DotZLib.dll) will be found in either ./DotZLib/bin/release
or ./DotZLib/bin/debug, depending on whether you are building the release
or debug version of the library.
Examples:
nant -D:debug=false -D:nunit=false
|
| ︙ | ︙ |
Changes to compat/zlib/contrib/infback9/infback9.c.
| ︙ | ︙ | |||
12 13 14 15 16 17 18 | /* strm provides memory allocation functions in zalloc and zfree, or Z_NULL to use the library memory allocation functions. window is a user-supplied window and output buffer that is 64K bytes. */ | < < | | < < | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
/*
strm provides memory allocation functions in zalloc and zfree, or
Z_NULL to use the library memory allocation functions.
window is a user-supplied window and output buffer that is 64K bytes.
*/
int ZEXPORT inflateBack9Init_(z_stream FAR *strm, unsigned char FAR *window,
const char *version, int stream_size) {
struct inflate_state FAR *state;
if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
stream_size != (int)(sizeof(z_stream)))
return Z_VERSION_ERROR;
if (strm == Z_NULL || window == Z_NULL)
return Z_STREAM_ERROR;
|
| ︙ | ︙ | |||
47 48 49 50 51 52 53 | /* Build and output length and distance decoding tables for fixed code decoding. */ #ifdef MAKEFIXED #include <stdio.h> | | < | 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
/*
Build and output length and distance decoding tables for fixed code
decoding.
*/
#ifdef MAKEFIXED
#include <stdio.h>
void makefixed9(void) {
unsigned sym, bits, low, size;
code *next, *lenfix, *distfix;
struct inflate_state state;
code fixed[544];
/* literal/length table */
sym = 0;
|
| ︙ | ︙ | |||
210 211 212 213 214 215 216 | Z_BUF_ERROR. strm->next_in can be checked for Z_NULL to see whether it was in() or out() that caused in the error. Otherwise, inflateBack() returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format error, or Z_MEM_ERROR if it could not allocate memory for the state. inflateBack() can also return Z_STREAM_ERROR if the input parameters are not correct, i.e. strm is Z_NULL or the state was not initialized. */ | < | < < | < < | 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 |
Z_BUF_ERROR. strm->next_in can be checked for Z_NULL to see whether it
was in() or out() that caused in the error. Otherwise, inflateBack()
returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format
error, or Z_MEM_ERROR if it could not allocate memory for the state.
inflateBack() can also return Z_STREAM_ERROR if the input parameters
are not correct, i.e. strm is Z_NULL or the state was not initialized.
*/
int ZEXPORT inflateBack9(z_stream FAR *strm, in_func in, void FAR *in_desc,
out_func out, void FAR *out_desc) {
struct inflate_state FAR *state;
z_const unsigned char FAR *next; /* next input */
unsigned char FAR *put; /* next output */
unsigned have; /* available input */
unsigned long left; /* available output */
inflate_mode mode; /* current inflate mode */
int lastblock; /* true if processing last block */
|
| ︙ | ︙ | |||
599 600 601 602 603 604 605 |
/* Return unused input */
inf_leave:
strm->next_in = next;
strm->avail_in = have;
return ret;
}
| | < < | 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 |
/* Return unused input */
inf_leave:
strm->next_in = next;
strm->avail_in = have;
return ret;
}
int ZEXPORT inflateBack9End(z_stream FAR *strm) {
if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0)
return Z_STREAM_ERROR;
ZFREE(strm, strm->state);
strm->state = Z_NULL;
Tracev((stderr, "inflate: end\n"));
return Z_OK;
}
|
Changes to compat/zlib/contrib/infback9/infback9.h.
| ︙ | ︙ | |||
16 17 18 19 20 21 22 |
* zlib.h must be included before this header file.
*/
#ifdef __cplusplus
extern "C" {
#endif
| | | | | | | | | | 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
* zlib.h must be included before this header file.
*/
#ifdef __cplusplus
extern "C" {
#endif
ZEXTERN int ZEXPORT inflateBack9(z_stream FAR *strm,
in_func in, void FAR *in_desc,
out_func out, void FAR *out_desc);
ZEXTERN int ZEXPORT inflateBack9End(z_stream FAR *strm);
ZEXTERN int ZEXPORT inflateBack9Init_(z_stream FAR *strm,
unsigned char FAR *window,
const char *version,
int stream_size);
#define inflateBack9Init(strm, window) \
inflateBack9Init_((strm), (window), \
ZLIB_VERSION, sizeof(z_stream))
#ifdef __cplusplus
}
#endif
|
Changes to compat/zlib/contrib/infback9/inftree9.c.
1 | /* inftree9.c -- generate Huffman trees for efficient decoding | | | < < | < | < | < | 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 |
/* inftree9.c -- generate Huffman trees for efficient decoding
* Copyright (C) 1995-2023 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#include "zutil.h"
#include "inftree9.h"
#define MAXBITS 15
const char inflate9_copyright[] =
" inflate9 1.3 Copyright 1995-2023 Mark Adler ";
/*
If you use the zlib library in a product, an acknowledgment is welcome
in the documentation of your product. If for some reason you cannot
include such an acknowledgment, I would appreciate that you keep this
copyright string in the executable of your product.
*/
/*
Build a set of tables to decode the provided canonical Huffman code.
The code lengths are lens[0..codes-1]. The result starts at *table,
whose indices are 0..2^bits-1. work is a writable array of at least
lens shorts, which is used as a work area. type is the type of code
to be generated, CODES, LENS, or DISTS. On return, zero is success,
-1 is an invalid code, and +1 means that ENOUGH isn't enough. table
on return points to the next available entry's address. bits is the
requested root table index bits, and on return it is the actual root
table index bits. It will differ if the request is greater than the
longest code or if it is less than the shortest code.
*/
int inflate_table9(codetype type, unsigned short FAR *lens, unsigned codes,
code FAR * FAR *table, unsigned FAR *bits,
unsigned short FAR *work) {
unsigned len; /* a code's length in bits */
unsigned sym; /* index of code symbols */
unsigned min, max; /* minimum and maximum code lengths */
unsigned root; /* number of index bits for root table */
unsigned curr; /* number of index bits for current table */
unsigned drop; /* code bits to drop for sub-table */
int left; /* number of prefix codes available */
|
| ︙ | ︙ | |||
60 61 62 63 64 65 66 |
static const unsigned short lbase[31] = { /* Length codes 257..285 base */
3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17,
19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115,
131, 163, 195, 227, 3, 0, 0};
static const unsigned short lext[31] = { /* Length codes 257..285 extra */
128, 128, 128, 128, 128, 128, 128, 128, 129, 129, 129, 129,
130, 130, 130, 130, 131, 131, 131, 131, 132, 132, 132, 132,
| | | 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
static const unsigned short lbase[31] = { /* Length codes 257..285 base */
3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17,
19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115,
131, 163, 195, 227, 3, 0, 0};
static const unsigned short lext[31] = { /* Length codes 257..285 extra */
128, 128, 128, 128, 128, 128, 128, 128, 129, 129, 129, 129,
130, 130, 130, 130, 131, 131, 131, 131, 132, 132, 132, 132,
133, 133, 133, 133, 144, 198, 203};
static const unsigned short dbase[32] = { /* Distance codes 0..31 base */
1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49,
65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073,
4097, 6145, 8193, 12289, 16385, 24577, 32769, 49153};
static const unsigned short dext[32] = { /* Distance codes 0..31 extra */
128, 128, 128, 128, 129, 129, 130, 130, 131, 131, 132, 132,
133, 133, 134, 134, 135, 135, 136, 136, 137, 137, 138, 138,
|
| ︙ | ︙ |
Changes to compat/zlib/contrib/infback9/inftree9.h.
| ︙ | ︙ | |||
34 35 36 37 38 39 40 |
01100000 - end of block
01000000 - invalid code
*/
/* Maximum size of the dynamic table. The maximum number of code structures is
1446, which is the sum of 852 for literal/length codes and 594 for distance
codes. These values were found by exhaustive searches using the program
| | | | | | 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 |
01100000 - end of block
01000000 - invalid code
*/
/* Maximum size of the dynamic table. The maximum number of code structures is
1446, which is the sum of 852 for literal/length codes and 594 for distance
codes. These values were found by exhaustive searches using the program
examples/enough.c found in the zlib distribution. The arguments to that
program are the number of symbols, the initial root table size, and the
maximum bit length of a code. "enough 286 9 15" for literal/length codes
returns returns 852, and "enough 32 6 15" for distance codes returns 594.
The initial root table size (9 or 6) is found in the fifth argument of the
inflate_table() calls in infback9.c. If the root table size is changed,
then these maximum sizes would be need to be recalculated and updated. */
#define ENOUGH_LENS 852
#define ENOUGH_DISTS 594
#define ENOUGH (ENOUGH_LENS+ENOUGH_DISTS)
/* Type of code to build for inflate_table9() */
typedef enum {
CODES,
LENS,
DISTS
} codetype;
extern int inflate_table9(codetype type, unsigned short FAR *lens,
unsigned codes, code FAR * FAR *table,
unsigned FAR *bits, unsigned short FAR *work);
|
Deleted compat/zlib/contrib/inflate86/inffas86.c.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted compat/zlib/contrib/inflate86/inffast.S.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted compat/zlib/contrib/masmx64/bld_ml64.bat.
|
| < < |
Deleted compat/zlib/contrib/masmx64/gvmat64.asm.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted compat/zlib/contrib/masmx64/inffas8664.c.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted compat/zlib/contrib/masmx64/inffasx64.asm.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted compat/zlib/contrib/masmx64/readme.txt.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted compat/zlib/contrib/masmx86/bld_ml32.bat.
|
| < < |
Deleted compat/zlib/contrib/masmx86/inffas32.asm.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted compat/zlib/contrib/masmx86/match686.asm.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted compat/zlib/contrib/masmx86/readme.txt.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to compat/zlib/contrib/minizip/MiniZip64_Changes.txt.
1 |
| | | 1 2 3 4 5 6 | MiniZip 1.1 was derived from MiniZip at version 1.01f Change in 1.0 (Okt 2009) - **TODO - Add history** |
Changes to compat/zlib/contrib/minizip/configure.ac.
1 2 3 | # -*- Autoconf -*- # Process this file with autoconf to produce a configure script. | | | 1 2 3 4 5 6 7 8 9 10 11 | # -*- Autoconf -*- # Process this file with autoconf to produce a configure script. AC_INIT([minizip], [1.3.0], [bugzilla.redhat.com]) AC_CONFIG_SRCDIR([minizip.c]) AM_INIT_AUTOMAKE([foreign]) LT_INIT AC_MSG_CHECKING([whether to build example programs]) AC_ARG_ENABLE([demos], AC_HELP_STRING([--enable-demos], [build example programs])) AM_CONDITIONAL([COND_DEMOS], [test "$enable_demos" = yes]) |
| ︙ | ︙ |
Changes to compat/zlib/contrib/minizip/crypt.h.
| ︙ | ︙ | |||
28 29 30 31 32 33 34 | */ #define CRC32(c, b) ((*(pcrc_32_tab+(((int)(c) ^ (b)) & 0xff))) ^ ((c) >> 8)) /*********************************************************************** * Return the next byte in the pseudo-random sequence */ | | < | < | < | | < | 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 |
*/
#define CRC32(c, b) ((*(pcrc_32_tab+(((int)(c) ^ (b)) & 0xff))) ^ ((c) >> 8))
/***********************************************************************
* Return the next byte in the pseudo-random sequence
*/
static int decrypt_byte(unsigned long* pkeys, const z_crc_t* pcrc_32_tab) {
unsigned temp; /* POTENTIAL BUG: temp*(temp^1) may overflow in an
* unpredictable manner on 16-bit systems; not a problem
* with any known compiler so far, though */
(void)pcrc_32_tab;
temp = ((unsigned)(*(pkeys+2)) & 0xffff) | 2;
return (int)(((temp * (temp ^ 1)) >> 8) & 0xff);
}
/***********************************************************************
* Update the encryption keys with the next byte of plain text
*/
static int update_keys(unsigned long* pkeys, const z_crc_t* pcrc_32_tab, int c) {
(*(pkeys+0)) = CRC32((*(pkeys+0)), c);
(*(pkeys+1)) += (*(pkeys+0)) & 0xff;
(*(pkeys+1)) = (*(pkeys+1)) * 134775813L + 1;
{
register int keyshift = (int)((*(pkeys+1)) >> 24);
(*(pkeys+2)) = CRC32((*(pkeys+2)), keyshift);
}
return c;
}
/***********************************************************************
* Initialize the encryption keys and the random header according to
* the given password.
*/
static void init_keys(const char* passwd, unsigned long* pkeys, const z_crc_t* pcrc_32_tab) {
*(pkeys+0) = 305419896L;
*(pkeys+1) = 591751049L;
*(pkeys+2) = 878082192L;
while (*passwd != '\0') {
update_keys(pkeys,pcrc_32_tab,(int)*passwd);
passwd++;
}
}
#define zdecode(pkeys,pcrc_32_tab,c) \
(update_keys(pkeys,pcrc_32_tab,c ^= decrypt_byte(pkeys,pcrc_32_tab)))
#define zencode(pkeys,pcrc_32_tab,c,t) \
(t=decrypt_byte(pkeys,pcrc_32_tab), update_keys(pkeys,pcrc_32_tab,c), (Byte)t^(c))
#ifdef INCLUDECRYPTINGCODE_IFCRYPTALLOWED
#define RAND_HEAD_LEN 12
/* "last resort" source for second part of crypt seed pattern */
# ifndef ZCR_SEED2
# define ZCR_SEED2 3141592654UL /* use PI as default pattern */
# endif
static unsigned crypthead(const char* passwd, /* password string */
unsigned char* buf, /* where to write header */
int bufSize,
unsigned long* pkeys,
const z_crc_t* pcrc_32_tab,
unsigned long crcForCrypting) {
unsigned n; /* index in random header */
int t; /* temporary */
int c; /* random byte */
unsigned char header[RAND_HEAD_LEN-2]; /* random header */
static unsigned calls = 0; /* ensure different random header each time */
if (bufSize<RAND_HEAD_LEN)
|
| ︙ | ︙ |
Changes to compat/zlib/contrib/minizip/ioapi.c.
| ︙ | ︙ | |||
10 11 12 13 14 15 16 |
*/
#if defined(_WIN32) && (!(defined(_CRT_SECURE_NO_WARNINGS)))
#define _CRT_SECURE_NO_WARNINGS
#endif
| | | < | < | < | < < < < < < < < < < | < < > | < < > | < < > | < < > | < < > | < < > | < < > | < < > | | < < > | < < > < | < | < | 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 |
*/
#if defined(_WIN32) && (!(defined(_CRT_SECURE_NO_WARNINGS)))
#define _CRT_SECURE_NO_WARNINGS
#endif
#if defined(__APPLE__) || defined(IOAPI_NO_64) || defined(__HAIKU__) || defined(MINIZIP_FOPEN_NO_64)
// In darwin and perhaps other BSD variants off_t is a 64 bit value, hence no need for specific 64 bit functions
#define FOPEN_FUNC(filename, mode) fopen(filename, mode)
#define FTELLO_FUNC(stream) ftello(stream)
#define FSEEKO_FUNC(stream, offset, origin) fseeko(stream, offset, origin)
#else
#define FOPEN_FUNC(filename, mode) fopen64(filename, mode)
#define FTELLO_FUNC(stream) ftello64(stream)
#define FSEEKO_FUNC(stream, offset, origin) fseeko64(stream, offset, origin)
#endif
#include "ioapi.h"
voidpf call_zopen64 (const zlib_filefunc64_32_def* pfilefunc, const void*filename, int mode) {
if (pfilefunc->zfile_func64.zopen64_file != NULL)
return (*(pfilefunc->zfile_func64.zopen64_file)) (pfilefunc->zfile_func64.opaque,filename,mode);
else
{
return (*(pfilefunc->zopen32_file))(pfilefunc->zfile_func64.opaque,(const char*)filename,mode);
}
}
long call_zseek64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin) {
if (pfilefunc->zfile_func64.zseek64_file != NULL)
return (*(pfilefunc->zfile_func64.zseek64_file)) (pfilefunc->zfile_func64.opaque,filestream,offset,origin);
else
{
uLong offsetTruncated = (uLong)offset;
if (offsetTruncated != offset)
return -1;
else
return (*(pfilefunc->zseek32_file))(pfilefunc->zfile_func64.opaque,filestream,offsetTruncated,origin);
}
}
ZPOS64_T call_ztell64 (const zlib_filefunc64_32_def* pfilefunc, voidpf filestream) {
if (pfilefunc->zfile_func64.zseek64_file != NULL)
return (*(pfilefunc->zfile_func64.ztell64_file)) (pfilefunc->zfile_func64.opaque,filestream);
else
{
uLong tell_uLong = (uLong)(*(pfilefunc->ztell32_file))(pfilefunc->zfile_func64.opaque,filestream);
if ((tell_uLong) == MAXU32)
return (ZPOS64_T)-1;
else
return tell_uLong;
}
}
void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32, const zlib_filefunc_def* p_filefunc32) {
p_filefunc64_32->zfile_func64.zopen64_file = NULL;
p_filefunc64_32->zopen32_file = p_filefunc32->zopen_file;
p_filefunc64_32->zfile_func64.zread_file = p_filefunc32->zread_file;
p_filefunc64_32->zfile_func64.zwrite_file = p_filefunc32->zwrite_file;
p_filefunc64_32->zfile_func64.ztell64_file = NULL;
p_filefunc64_32->zfile_func64.zseek64_file = NULL;
p_filefunc64_32->zfile_func64.zclose_file = p_filefunc32->zclose_file;
p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file;
p_filefunc64_32->zfile_func64.opaque = p_filefunc32->opaque;
p_filefunc64_32->zseek32_file = p_filefunc32->zseek_file;
p_filefunc64_32->ztell32_file = p_filefunc32->ztell_file;
}
static voidpf ZCALLBACK fopen_file_func(voidpf opaque, const char* filename, int mode) {
FILE* file = NULL;
const char* mode_fopen = NULL;
(void)opaque;
if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ)
mode_fopen = "rb";
else
if (mode & ZLIB_FILEFUNC_MODE_EXISTING)
mode_fopen = "r+b";
else
if (mode & ZLIB_FILEFUNC_MODE_CREATE)
mode_fopen = "wb";
if ((filename!=NULL) && (mode_fopen != NULL))
file = fopen(filename, mode_fopen);
return file;
}
static voidpf ZCALLBACK fopen64_file_func(voidpf opaque, const void* filename, int mode) {
FILE* file = NULL;
const char* mode_fopen = NULL;
(void)opaque;
if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ)
mode_fopen = "rb";
else
if (mode & ZLIB_FILEFUNC_MODE_EXISTING)
mode_fopen = "r+b";
else
if (mode & ZLIB_FILEFUNC_MODE_CREATE)
mode_fopen = "wb";
if ((filename!=NULL) && (mode_fopen != NULL))
file = FOPEN_FUNC((const char*)filename, mode_fopen);
return file;
}
static uLong ZCALLBACK fread_file_func(voidpf opaque, voidpf stream, void* buf, uLong size) {
uLong ret;
(void)opaque;
ret = (uLong)fread(buf, 1, (size_t)size, (FILE *)stream);
return ret;
}
static uLong ZCALLBACK fwrite_file_func(voidpf opaque, voidpf stream, const void* buf, uLong size) {
uLong ret;
(void)opaque;
ret = (uLong)fwrite(buf, 1, (size_t)size, (FILE *)stream);
return ret;
}
static long ZCALLBACK ftell_file_func(voidpf opaque, voidpf stream) {
long ret;
(void)opaque;
ret = ftell((FILE *)stream);
return ret;
}
static ZPOS64_T ZCALLBACK ftell64_file_func(voidpf opaque, voidpf stream) {
ZPOS64_T ret;
(void)opaque;
ret = (ZPOS64_T)FTELLO_FUNC((FILE *)stream);
return ret;
}
static long ZCALLBACK fseek_file_func(voidpf opaque, voidpf stream, uLong offset, int origin) {
int fseek_origin=0;
long ret;
(void)opaque;
switch (origin)
{
case ZLIB_FILEFUNC_SEEK_CUR :
fseek_origin = SEEK_CUR;
break;
case ZLIB_FILEFUNC_SEEK_END :
fseek_origin = SEEK_END;
break;
case ZLIB_FILEFUNC_SEEK_SET :
fseek_origin = SEEK_SET;
break;
default: return -1;
}
ret = 0;
if (fseek((FILE *)stream, (long)offset, fseek_origin) != 0)
ret = -1;
return ret;
}
static long ZCALLBACK fseek64_file_func(voidpf opaque, voidpf stream, ZPOS64_T offset, int origin) {
int fseek_origin=0;
long ret;
(void)opaque;
switch (origin)
{
case ZLIB_FILEFUNC_SEEK_CUR :
fseek_origin = SEEK_CUR;
break;
case ZLIB_FILEFUNC_SEEK_END :
fseek_origin = SEEK_END;
break;
case ZLIB_FILEFUNC_SEEK_SET :
fseek_origin = SEEK_SET;
break;
default: return -1;
}
ret = 0;
if(FSEEKO_FUNC((FILE *)stream, (z_off64_t)offset, fseek_origin) != 0)
ret = -1;
return ret;
}
static int ZCALLBACK fclose_file_func(voidpf opaque, voidpf stream) {
int ret;
(void)opaque;
ret = fclose((FILE *)stream);
return ret;
}
static int ZCALLBACK ferror_file_func(voidpf opaque, voidpf stream) {
int ret;
(void)opaque;
ret = ferror((FILE *)stream);
return ret;
}
void fill_fopen_filefunc(zlib_filefunc_def* pzlib_filefunc_def) {
pzlib_filefunc_def->zopen_file = fopen_file_func;
pzlib_filefunc_def->zread_file = fread_file_func;
pzlib_filefunc_def->zwrite_file = fwrite_file_func;
pzlib_filefunc_def->ztell_file = ftell_file_func;
pzlib_filefunc_def->zseek_file = fseek_file_func;
pzlib_filefunc_def->zclose_file = fclose_file_func;
pzlib_filefunc_def->zerror_file = ferror_file_func;
pzlib_filefunc_def->opaque = NULL;
}
void fill_fopen64_filefunc(zlib_filefunc64_def* pzlib_filefunc_def) {
pzlib_filefunc_def->zopen64_file = fopen64_file_func;
pzlib_filefunc_def->zread_file = fread_file_func;
pzlib_filefunc_def->zwrite_file = fwrite_file_func;
pzlib_filefunc_def->ztell64_file = ftell64_file_func;
pzlib_filefunc_def->zseek64_file = fseek64_file_func;
pzlib_filefunc_def->zclose_file = fclose_file_func;
pzlib_filefunc_def->zerror_file = ferror_file_func;
pzlib_filefunc_def->opaque = NULL;
}
|
Changes to compat/zlib/contrib/minizip/ioapi.h.
| ︙ | ︙ | |||
46 47 48 49 50 51 52 | #include "zlib.h" #if defined(USE_FILE32API) #define fopen64 fopen #define ftello64 ftell #define fseeko64 fseek #else | | | 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | #include "zlib.h" #if defined(USE_FILE32API) #define fopen64 fopen #define ftello64 ftell #define fseeko64 fseek #else #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__HAIKU__) || defined(MINIZIP_FOPEN_NO_64) #define fopen64 fopen #define ftello64 ftello #define fseeko64 fseeko #endif #ifdef _MSC_VER #define fopen64 fopen #if (_MSC_VER >= 1400) && (!(defined(NO_MSCVER_FILE64_FUNC))) |
| ︙ | ︙ | |||
78 79 80 81 82 83 84 | #endif */ #ifdef HAVE_MINIZIP64_CONF_H #include "mz64conf.h" #endif | | | 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 | #endif */ #ifdef HAVE_MINIZIP64_CONF_H #include "mz64conf.h" #endif /* a type chosen by DEFINE */ #ifdef HAVE_64BIT_INT_CUSTOM typedef 64BIT_INT_CUSTOM_TYPE ZPOS64_T; #else #ifdef HAS_STDINT_H #include "stdint.h" typedef uint64_t ZPOS64_T; #else |
| ︙ | ︙ | |||
130 131 132 133 134 135 136 | #define ZCALLBACK #endif #endif | | | | | | | | | | | | | | | | | | 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 |
#define ZCALLBACK
#endif
#endif
typedef voidpf (ZCALLBACK *open_file_func) (voidpf opaque, const char* filename, int mode);
typedef uLong (ZCALLBACK *read_file_func) (voidpf opaque, voidpf stream, void* buf, uLong size);
typedef uLong (ZCALLBACK *write_file_func) (voidpf opaque, voidpf stream, const void* buf, uLong size);
typedef int (ZCALLBACK *close_file_func) (voidpf opaque, voidpf stream);
typedef int (ZCALLBACK *testerror_file_func) (voidpf opaque, voidpf stream);
typedef long (ZCALLBACK *tell_file_func) (voidpf opaque, voidpf stream);
typedef long (ZCALLBACK *seek_file_func) (voidpf opaque, voidpf stream, uLong offset, int origin);
/* here is the "old" 32 bits structure structure */
typedef struct zlib_filefunc_def_s
{
open_file_func zopen_file;
read_file_func zread_file;
write_file_func zwrite_file;
tell_file_func ztell_file;
seek_file_func zseek_file;
close_file_func zclose_file;
testerror_file_func zerror_file;
voidpf opaque;
} zlib_filefunc_def;
typedef ZPOS64_T (ZCALLBACK *tell64_file_func) (voidpf opaque, voidpf stream);
typedef long (ZCALLBACK *seek64_file_func) (voidpf opaque, voidpf stream, ZPOS64_T offset, int origin);
typedef voidpf (ZCALLBACK *open64_file_func) (voidpf opaque, const void* filename, int mode);
typedef struct zlib_filefunc64_def_s
{
open64_file_func zopen64_file;
read_file_func zread_file;
write_file_func zwrite_file;
tell64_file_func ztell64_file;
seek64_file_func zseek64_file;
close_file_func zclose_file;
testerror_file_func zerror_file;
voidpf opaque;
} zlib_filefunc64_def;
void fill_fopen64_filefunc(zlib_filefunc64_def* pzlib_filefunc_def);
void fill_fopen_filefunc(zlib_filefunc_def* pzlib_filefunc_def);
/* now internal definition, only for zip.c and unzip.h */
typedef struct zlib_filefunc64_32_def_s
{
zlib_filefunc64_def zfile_func64;
open_file_func zopen32_file;
tell_file_func ztell32_file;
seek_file_func zseek32_file;
} zlib_filefunc64_32_def;
#define ZREAD64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zread_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size))
#define ZWRITE64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zwrite_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size))
//#define ZTELL64(filefunc,filestream) ((*((filefunc).ztell64_file)) ((filefunc).opaque,filestream))
//#define ZSEEK64(filefunc,filestream,pos,mode) ((*((filefunc).zseek64_file)) ((filefunc).opaque,filestream,pos,mode))
#define ZCLOSE64(filefunc,filestream) ((*((filefunc).zfile_func64.zclose_file)) ((filefunc).zfile_func64.opaque,filestream))
#define ZERROR64(filefunc,filestream) ((*((filefunc).zfile_func64.zerror_file)) ((filefunc).zfile_func64.opaque,filestream))
voidpf call_zopen64(const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode);
long call_zseek64(const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin);
ZPOS64_T call_ztell64(const zlib_filefunc64_32_def* pfilefunc,voidpf filestream);
void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32);
#define ZOPEN64(filefunc,filename,mode) (call_zopen64((&(filefunc)),(filename),(mode)))
#define ZTELL64(filefunc,filestream) (call_ztell64((&(filefunc)),(filestream)))
#define ZSEEK64(filefunc,filestream,pos,mode) (call_zseek64((&(filefunc)),(filestream),(pos),(mode)))
#ifdef __cplusplus
}
#endif
#endif
|
Changes to compat/zlib/contrib/minizip/iowin32.c.
| ︙ | ︙ | |||
24 25 26 27 28 29 30 31 32 33 34 35 | #ifndef INVALID_SET_FILE_POINTER #define INVALID_SET_FILE_POINTER ((DWORD)-1) #endif // see Include/shared/winapifamily.h in the Windows Kit #if defined(WINAPI_FAMILY_PARTITION) && (!(defined(IOWIN32_USING_WINRT_API))) #if WINAPI_FAMILY_ONE_PARTITION(WINAPI_FAMILY, WINAPI_PARTITION_APP) #define IOWIN32_USING_WINRT_API 1 #endif #endif | > > > > > < < < < < < < < | < | < | < | 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 |
#ifndef INVALID_SET_FILE_POINTER
#define INVALID_SET_FILE_POINTER ((DWORD)-1)
#endif
// see Include/shared/winapifamily.h in the Windows Kit
#if defined(WINAPI_FAMILY_PARTITION) && (!(defined(IOWIN32_USING_WINRT_API)))
#if !defined(WINAPI_FAMILY_ONE_PARTITION)
#define WINAPI_FAMILY_ONE_PARTITION(PartitionSet, Partition) ((WINAPI_FAMILY & PartitionSet) == Partition)
#endif
#if WINAPI_FAMILY_ONE_PARTITION(WINAPI_FAMILY, WINAPI_PARTITION_APP)
#define IOWIN32_USING_WINRT_API 1
#endif
#endif
typedef struct
{
HANDLE hf;
int error;
} WIN32FILE_IOWIN;
static void win32_translate_open_mode(int mode,
DWORD* lpdwDesiredAccess,
DWORD* lpdwCreationDisposition,
DWORD* lpdwShareMode,
DWORD* lpdwFlagsAndAttributes) {
*lpdwDesiredAccess = *lpdwShareMode = *lpdwFlagsAndAttributes = *lpdwCreationDisposition = 0;
if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ)
{
*lpdwDesiredAccess = GENERIC_READ;
*lpdwCreationDisposition = OPEN_EXISTING;
*lpdwShareMode = FILE_SHARE_READ;
}
else if (mode & ZLIB_FILEFUNC_MODE_EXISTING)
{
*lpdwDesiredAccess = GENERIC_WRITE | GENERIC_READ;
*lpdwCreationDisposition = OPEN_EXISTING;
}
else if (mode & ZLIB_FILEFUNC_MODE_CREATE)
{
*lpdwDesiredAccess = GENERIC_WRITE | GENERIC_READ;
*lpdwCreationDisposition = CREATE_ALWAYS;
}
}
static voidpf win32_build_iowin(HANDLE hFile) {
voidpf ret=NULL;
if ((hFile != NULL) && (hFile != INVALID_HANDLE_VALUE))
{
WIN32FILE_IOWIN w32fiow;
w32fiow.hf = hFile;
w32fiow.error = 0;
ret = malloc(sizeof(WIN32FILE_IOWIN));
if (ret==NULL)
CloseHandle(hFile);
else
*((WIN32FILE_IOWIN*)ret) = w32fiow;
}
return ret;
}
voidpf ZCALLBACK win32_open64_file_func(voidpf opaque, const void* filename, int mode) {
const char* mode_fopen = NULL;
DWORD dwDesiredAccess,dwCreationDisposition,dwShareMode,dwFlagsAndAttributes ;
HANDLE hFile = NULL;
win32_translate_open_mode(mode,&dwDesiredAccess,&dwCreationDisposition,&dwShareMode,&dwFlagsAndAttributes);
#ifdef IOWIN32_USING_WINRT_API
|
| ︙ | ︙ | |||
118 119 120 121 122 123 124 |
hFile = CreateFile((LPCTSTR)filename, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwFlagsAndAttributes, NULL);
#endif
return win32_build_iowin(hFile);
}
| | < | 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 |
hFile = CreateFile((LPCTSTR)filename, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwFlagsAndAttributes, NULL);
#endif
return win32_build_iowin(hFile);
}
voidpf ZCALLBACK win32_open64_file_funcA(voidpf opaque, const void* filename, int mode) {
const char* mode_fopen = NULL;
DWORD dwDesiredAccess,dwCreationDisposition,dwShareMode,dwFlagsAndAttributes ;
HANDLE hFile = NULL;
win32_translate_open_mode(mode,&dwDesiredAccess,&dwCreationDisposition,&dwShareMode,&dwFlagsAndAttributes);
#ifdef IOWIN32_USING_WINRT_API
|
| ︙ | ︙ | |||
142 143 144 145 146 147 148 |
hFile = CreateFileA((LPCSTR)filename, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwFlagsAndAttributes, NULL);
#endif
return win32_build_iowin(hFile);
}
| | < | < | 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 |
hFile = CreateFileA((LPCSTR)filename, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwFlagsAndAttributes, NULL);
#endif
return win32_build_iowin(hFile);
}
voidpf ZCALLBACK win32_open64_file_funcW(voidpf opaque, const void* filename, int mode) {
const char* mode_fopen = NULL;
DWORD dwDesiredAccess,dwCreationDisposition,dwShareMode,dwFlagsAndAttributes ;
HANDLE hFile = NULL;
win32_translate_open_mode(mode,&dwDesiredAccess,&dwCreationDisposition,&dwShareMode,&dwFlagsAndAttributes);
#ifdef IOWIN32_USING_WINRT_API
if ((filename!=NULL) && (dwDesiredAccess != 0))
hFile = CreateFile2((LPCWSTR)filename, dwDesiredAccess, dwShareMode, dwCreationDisposition,NULL);
#else
if ((filename!=NULL) && (dwDesiredAccess != 0))
hFile = CreateFileW((LPCWSTR)filename, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwFlagsAndAttributes, NULL);
#endif
return win32_build_iowin(hFile);
}
voidpf ZCALLBACK win32_open_file_func(voidpf opaque, const char* filename, int mode) {
const char* mode_fopen = NULL;
DWORD dwDesiredAccess,dwCreationDisposition,dwShareMode,dwFlagsAndAttributes ;
HANDLE hFile = NULL;
win32_translate_open_mode(mode,&dwDesiredAccess,&dwCreationDisposition,&dwShareMode,&dwFlagsAndAttributes);
#ifdef IOWIN32_USING_WINRT_API
|
| ︙ | ︙ | |||
191 192 193 194 195 196 197 |
hFile = CreateFile((LPCTSTR)filename, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwFlagsAndAttributes, NULL);
#endif
return win32_build_iowin(hFile);
}
| | < | < | < | < | 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 |
hFile = CreateFile((LPCTSTR)filename, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwFlagsAndAttributes, NULL);
#endif
return win32_build_iowin(hFile);
}
uLong ZCALLBACK win32_read_file_func(voidpf opaque, voidpf stream, void* buf,uLong size) {
uLong ret=0;
HANDLE hFile = NULL;
if (stream!=NULL)
hFile = ((WIN32FILE_IOWIN*)stream) -> hf;
if (hFile != NULL)
{
if (!ReadFile(hFile, buf, size, &ret, NULL))
{
DWORD dwErr = GetLastError();
if (dwErr == ERROR_HANDLE_EOF)
dwErr = 0;
((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr;
}
}
return ret;
}
uLong ZCALLBACK win32_write_file_func(voidpf opaque, voidpf stream, const void* buf, uLong size) {
uLong ret=0;
HANDLE hFile = NULL;
if (stream!=NULL)
hFile = ((WIN32FILE_IOWIN*)stream) -> hf;
if (hFile != NULL)
{
if (!WriteFile(hFile, buf, size, &ret, NULL))
{
DWORD dwErr = GetLastError();
if (dwErr == ERROR_HANDLE_EOF)
dwErr = 0;
((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr;
}
}
return ret;
}
static BOOL MySetFilePointerEx(HANDLE hFile, LARGE_INTEGER pos, LARGE_INTEGER *newPos, DWORD dwMoveMethod) {
#ifdef IOWIN32_USING_WINRT_API
return SetFilePointerEx(hFile, pos, newPos, dwMoveMethod);
#else
LONG lHigh = pos.HighPart;
DWORD dwNewPos = SetFilePointer(hFile, pos.LowPart, &lHigh, dwMoveMethod);
BOOL fOk = TRUE;
if (dwNewPos == 0xFFFFFFFF)
if (GetLastError() != NO_ERROR)
fOk = FALSE;
if ((newPos != NULL) && (fOk))
{
newPos->LowPart = dwNewPos;
newPos->HighPart = lHigh;
}
return fOk;
#endif
}
long ZCALLBACK win32_tell_file_func(voidpf opaque, voidpf stream) {
long ret=-1;
HANDLE hFile = NULL;
if (stream!=NULL)
hFile = ((WIN32FILE_IOWIN*)stream) -> hf;
if (hFile != NULL)
{
LARGE_INTEGER pos;
|
| ︙ | ︙ | |||
277 278 279 280 281 282 283 |
}
else
ret=(long)pos.LowPart;
}
return ret;
}
| | < | 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 |
}
else
ret=(long)pos.LowPart;
}
return ret;
}
ZPOS64_T ZCALLBACK win32_tell64_file_func(voidpf opaque, voidpf stream) {
ZPOS64_T ret= (ZPOS64_T)-1;
HANDLE hFile = NULL;
if (stream!=NULL)
hFile = ((WIN32FILE_IOWIN*)stream)->hf;
if (hFile)
{
|
| ︙ | ︙ | |||
302 303 304 305 306 307 308 |
else
ret=pos.QuadPart;
}
return ret;
}
| | < | 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 |
else
ret=pos.QuadPart;
}
return ret;
}
long ZCALLBACK win32_seek_file_func(voidpf opaque, voidpf stream, uLong offset, int origin) {
DWORD dwMoveMethod=0xFFFFFFFF;
HANDLE hFile = NULL;
long ret=-1;
if (stream!=NULL)
hFile = ((WIN32FILE_IOWIN*)stream) -> hf;
switch (origin)
|
| ︙ | ︙ | |||
340 341 342 343 344 345 346 |
}
else
ret=0;
}
return ret;
}
| | < | 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 |
}
else
ret=0;
}
return ret;
}
long ZCALLBACK win32_seek64_file_func(voidpf opaque, voidpf stream, ZPOS64_T offset, int origin) {
DWORD dwMoveMethod=0xFFFFFFFF;
HANDLE hFile = NULL;
long ret=-1;
if (stream!=NULL)
hFile = ((WIN32FILE_IOWIN*)stream)->hf;
|
| ︙ | ︙ | |||
379 380 381 382 383 384 385 |
}
else
ret=0;
}
return ret;
}
| | < | < | < | < | < | < | 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 |
}
else
ret=0;
}
return ret;
}
int ZCALLBACK win32_close_file_func(voidpf opaque, voidpf stream) {
int ret=-1;
if (stream!=NULL)
{
HANDLE hFile;
hFile = ((WIN32FILE_IOWIN*)stream) -> hf;
if (hFile != NULL)
{
CloseHandle(hFile);
ret=0;
}
free(stream);
}
return ret;
}
int ZCALLBACK win32_error_file_func(voidpf opaque, voidpf stream) {
int ret=-1;
if (stream!=NULL)
{
ret = ((WIN32FILE_IOWIN*)stream) -> error;
}
return ret;
}
void fill_win32_filefunc(zlib_filefunc_def* pzlib_filefunc_def) {
pzlib_filefunc_def->zopen_file = win32_open_file_func;
pzlib_filefunc_def->zread_file = win32_read_file_func;
pzlib_filefunc_def->zwrite_file = win32_write_file_func;
pzlib_filefunc_def->ztell_file = win32_tell_file_func;
pzlib_filefunc_def->zseek_file = win32_seek_file_func;
pzlib_filefunc_def->zclose_file = win32_close_file_func;
pzlib_filefunc_def->zerror_file = win32_error_file_func;
pzlib_filefunc_def->opaque = NULL;
}
void fill_win32_filefunc64(zlib_filefunc64_def* pzlib_filefunc_def) {
pzlib_filefunc_def->zopen64_file = win32_open64_file_func;
pzlib_filefunc_def->zread_file = win32_read_file_func;
pzlib_filefunc_def->zwrite_file = win32_write_file_func;
pzlib_filefunc_def->ztell64_file = win32_tell64_file_func;
pzlib_filefunc_def->zseek64_file = win32_seek64_file_func;
pzlib_filefunc_def->zclose_file = win32_close_file_func;
pzlib_filefunc_def->zerror_file = win32_error_file_func;
pzlib_filefunc_def->opaque = NULL;
}
void fill_win32_filefunc64A(zlib_filefunc64_def* pzlib_filefunc_def) {
pzlib_filefunc_def->zopen64_file = win32_open64_file_funcA;
pzlib_filefunc_def->zread_file = win32_read_file_func;
pzlib_filefunc_def->zwrite_file = win32_write_file_func;
pzlib_filefunc_def->ztell64_file = win32_tell64_file_func;
pzlib_filefunc_def->zseek64_file = win32_seek64_file_func;
pzlib_filefunc_def->zclose_file = win32_close_file_func;
pzlib_filefunc_def->zerror_file = win32_error_file_func;
pzlib_filefunc_def->opaque = NULL;
}
void fill_win32_filefunc64W(zlib_filefunc64_def* pzlib_filefunc_def) {
pzlib_filefunc_def->zopen64_file = win32_open64_file_funcW;
pzlib_filefunc_def->zread_file = win32_read_file_func;
pzlib_filefunc_def->zwrite_file = win32_write_file_func;
pzlib_filefunc_def->ztell64_file = win32_tell64_file_func;
pzlib_filefunc_def->zseek64_file = win32_seek64_file_func;
pzlib_filefunc_def->zclose_file = win32_close_file_func;
pzlib_filefunc_def->zerror_file = win32_error_file_func;
pzlib_filefunc_def->opaque = NULL;
}
|
Changes to compat/zlib/contrib/minizip/iowin32.h.
| ︙ | ︙ | |||
14 15 16 17 18 19 20 |
#include <windows.h>
#ifdef __cplusplus
extern "C" {
#endif
| | | | | | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
#include <windows.h>
#ifdef __cplusplus
extern "C" {
#endif
void fill_win32_filefunc(zlib_filefunc_def* pzlib_filefunc_def);
void fill_win32_filefunc64(zlib_filefunc64_def* pzlib_filefunc_def);
void fill_win32_filefunc64A(zlib_filefunc64_def* pzlib_filefunc_def);
void fill_win32_filefunc64W(zlib_filefunc64_def* pzlib_filefunc_def);
#ifdef __cplusplus
}
#endif
|
Changes to compat/zlib/contrib/minizip/miniunz.c.
| ︙ | ︙ | |||
23 24 25 26 27 28 29 |
#define _LARGEFILE64_SOURCE
#endif
#ifndef _FILE_OFFSET_BIT
#define _FILE_OFFSET_BIT 64
#endif
#endif
| | | 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
#define _LARGEFILE64_SOURCE
#endif
#ifndef _FILE_OFFSET_BIT
#define _FILE_OFFSET_BIT 64
#endif
#endif
#if defined(__APPLE__) || defined(__HAIKU__) || defined(MINIZIP_FOPEN_NO_64)
// In darwin and perhaps other BSD variants off_t is a 64 bit value, hence no need for specific 64 bit functions
#define FOPEN_FUNC(filename, mode) fopen(filename, mode)
#define FTELLO_FUNC(stream) ftello(stream)
#define FSEEKO_FUNC(stream, offset, origin) fseeko(stream, offset, origin)
#else
#define FOPEN_FUNC(filename, mode) fopen64(filename, mode)
#define FTELLO_FUNC(stream) ftello64(stream)
|
| ︙ | ︙ | |||
77 78 79 80 81 82 83 |
*/
/* change_file_date : change the date/time of a file
filename : the filename of the file where date/time must be modified
dosdate : the new date at the MSDos format (4 bytes)
tmu_date : the SAME new date at the tm_unz format */
| | < < < < | 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
*/
/* change_file_date : change the date/time of a file
filename : the filename of the file where date/time must be modified
dosdate : the new date at the MSDos format (4 bytes)
tmu_date : the SAME new date at the tm_unz format */
static void change_file_date(const char *filename, uLong dosdate, tm_unz tmu_date) {
#ifdef _WIN32
HANDLE hFile;
FILETIME ftm,ftLocal,ftCreate,ftLastAcc,ftLastWrite;
hFile = CreateFileA(filename,GENERIC_READ | GENERIC_WRITE,
0,NULL,OPEN_EXISTING,0,NULL);
GetFileTime(hFile,&ftCreate,&ftLastAcc,&ftLastWrite);
|
| ︙ | ︙ | |||
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 |
newdate.tm_year=tmu_date.tm_year - 1900;
else
newdate.tm_year=tmu_date.tm_year ;
newdate.tm_isdst=-1;
ut.actime=ut.modtime=mktime(&newdate);
utime(filename,&ut);
#endif
#endif
}
/* mymkdir and change_file_date are not 100 % portable
As I don't know well Unix, I wait feedback for the unix portion */
| > > > > | < < > > | < < | 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 |
newdate.tm_year=tmu_date.tm_year - 1900;
else
newdate.tm_year=tmu_date.tm_year ;
newdate.tm_isdst=-1;
ut.actime=ut.modtime=mktime(&newdate);
utime(filename,&ut);
#else
(void)filename;
(void)dosdate;
(void)tmu_date;
#endif
#endif
}
/* mymkdir and change_file_date are not 100 % portable
As I don't know well Unix, I wait feedback for the unix portion */
static int mymkdir(const char* dirname) {
int ret=0;
#ifdef _WIN32
ret = _mkdir(dirname);
#elif unix
ret = mkdir (dirname,0775);
#elif __APPLE__
ret = mkdir (dirname,0775);
#else
(void)dirname;
#endif
return ret;
}
static int makedir(const char *newdir) {
char *buffer ;
char *p;
size_t len = strlen(newdir);
if (len == 0)
return 0;
|
| ︙ | ︙ | |||
183 184 185 186 187 188 189 |
break;
*p++ = hold;
}
free(buffer);
return 1;
}
| | < | < | | < | 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 |
break;
*p++ = hold;
}
free(buffer);
return 1;
}
static void do_banner(void) {
printf("MiniUnz 1.01b, demo of zLib + Unz package written by Gilles Vollant\n");
printf("more info at http://www.winimage.com/zLibDll/unzip.html\n\n");
}
static void do_help(void) {
printf("Usage : miniunz [-e] [-x] [-v] [-l] [-o] [-p password] file.zip [file_to_extr.] [-d extractdir]\n\n" \
" -e Extract without pathname (junk paths)\n" \
" -x Extract with pathname\n" \
" -v list files\n" \
" -l list files\n" \
" -d directory to extract into\n" \
" -o overwrite files without prompting\n" \
" -p extract encrypted file using password\n\n");
}
static void Display64BitsSize(ZPOS64_T n, int size_char) {
/* to avoid compatibility problem , we do here the conversion */
char number[21];
int offset=19;
int pos_string = 19;
number[20]=0;
for (;;) {
number[offset]=(char)((n%10)+'0');
|
| ︙ | ︙ | |||
229 230 231 232 233 234 235 |
printf(" ");
}
}
printf("%s",&number[pos_string]);
}
| | < < | | | 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 |
printf(" ");
}
}
printf("%s",&number[pos_string]);
}
static int do_list(unzFile uf) {
uLong i;
unz_global_info64 gi;
int err;
err = unzGetGlobalInfo64(uf,&gi);
if (err!=UNZ_OK)
printf("error %d with zipfile in unzGetGlobalInfo \n",err);
printf(" Length Method Size Ratio Date Time CRC-32 Name\n");
printf(" ------ ------ ---- ----- ---- ---- ------ ----\n");
for (i=0;i<gi.number_entry;i++)
{
char filename_inzip[256];
unz_file_info64 file_info;
uLong ratio=0;
const char *string_method = "";
char charCrypt=' ';
err = unzGetCurrentFileInfo64(uf,&file_info,filename_inzip,sizeof(filename_inzip),NULL,0,NULL,0);
if (err!=UNZ_OK)
{
printf("error %d with zipfile in unzGetCurrentFileInfo\n",err);
break;
}
if (file_info.uncompressed_size>0)
ratio = (uLong)((file_info.compressed_size*100)/file_info.uncompressed_size);
/* display a '*' if the file is encrypted */
if ((file_info.flag & 1) != 0)
charCrypt='*';
if (file_info.compression_method==0)
string_method="Stored";
else
if (file_info.compression_method==Z_DEFLATED)
|
| ︙ | ︙ | |||
307 308 309 310 311 312 313 |
}
}
return 0;
}
| < < | < < < | 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 |
}
}
return 0;
}
static int do_extract_currentfile(unzFile uf, const int* popt_extract_without_path, int* popt_overwrite, const char* password) {
char filename_inzip[256];
char* filename_withoutpath;
char* p;
int err=UNZ_OK;
FILE *fout=NULL;
void* buf;
uInt size_buf;
|
| ︙ | ︙ | |||
469 470 471 472 473 474 475 |
}
free(buf);
return err;
}
| < < | < < < | 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 |
}
free(buf);
return err;
}
static int do_extract(unzFile uf, int opt_extract_without_path, int opt_overwrite, const char* password) {
uLong i;
unz_global_info64 gi;
int err;
err = unzGetGlobalInfo64(uf,&gi);
if (err!=UNZ_OK)
printf("error %d with zipfile in unzGetGlobalInfo \n",err);
|
| ︙ | ︙ | |||
504 505 506 507 508 509 510 |
}
}
}
return 0;
}
| | < < < < < < < < | < | 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 |
}
}
}
return 0;
}
static int do_extract_onefile(unzFile uf, const char* filename, int opt_extract_without_path, int opt_overwrite, const char* password) {
if (unzLocateFile(uf,filename,CASESENSITIVITY)!=UNZ_OK)
{
printf("file %s not found in the zipfile\n",filename);
return 2;
}
if (do_extract_currentfile(uf,&opt_extract_without_path,
&opt_overwrite,
password) == UNZ_OK)
return 0;
else
return 1;
}
int main(int argc, char *argv[]) {
const char *zipfilename=NULL;
const char *filename_to_extract=NULL;
const char *password=NULL;
char filename_try[MAXFILENAME+16] = "";
int i;
int ret_value=0;
int opt_do_list=0;
|
| ︙ | ︙ | |||
560 561 562 563 564 565 566 |
{
if ((*argv[i])=='-')
{
const char *p=argv[i]+1;
while ((*p)!='\0')
{
| | | 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 |
{
if ((*argv[i])=='-')
{
const char *p=argv[i]+1;
while ((*p)!='\0')
{
char c=*(p++);
if ((c=='l') || (c=='L'))
opt_do_list = 1;
if ((c=='v') || (c=='V'))
opt_do_list = 1;
if ((c=='x') || (c=='X'))
opt_do_extract = 1;
if ((c=='e') || (c=='E'))
|
| ︙ | ︙ | |||
602 603 604 605 606 607 608 |
{
# ifdef USEWIN32IOAPI
zlib_filefunc64_def ffunc;
# endif
strncpy(filename_try, zipfilename,MAXFILENAME-1);
| | | 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 |
{
# ifdef USEWIN32IOAPI
zlib_filefunc64_def ffunc;
# endif
strncpy(filename_try, zipfilename,MAXFILENAME-1);
/* strncpy doesn't append the trailing NULL, of the string is too long. */
filename_try[ MAXFILENAME ] = '\0';
# ifdef USEWIN32IOAPI
fill_win32_filefunc64A(&ffunc);
uf = unzOpen2_64(zipfilename,&ffunc);
# else
uf = unzOpen64(zipfilename);
|
| ︙ | ︙ |
Changes to compat/zlib/contrib/minizip/minizip.c.
| ︙ | ︙ | |||
24 25 26 27 28 29 30 |
#define _LARGEFILE64_SOURCE
#endif
#ifndef _FILE_OFFSET_BIT
#define _FILE_OFFSET_BIT 64
#endif
#endif
| | | 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
#define _LARGEFILE64_SOURCE
#endif
#ifndef _FILE_OFFSET_BIT
#define _FILE_OFFSET_BIT 64
#endif
#endif
#if defined(__APPLE__) || defined(__HAIKU__) || defined(MINIZIP_FOPEN_NO_64)
// In darwin and perhaps other BSD variants off_t is a 64 bit value, hence no need for specific 64 bit functions
#define FOPEN_FUNC(filename, mode) fopen(filename, mode)
#define FTELLO_FUNC(stream) ftello(stream)
#define FSEEKO_FUNC(stream, offset, origin) fseeko(stream, offset, origin)
#else
#define FOPEN_FUNC(filename, mode) fopen64(filename, mode)
#define FTELLO_FUNC(stream) ftello64(stream)
|
| ︙ | ︙ | |||
67 68 69 70 71 72 73 | #define WRITEBUFFERSIZE (16384) #define MAXFILENAME (256) #ifdef _WIN32 | < | | | < < | | | < | | 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 |
#define WRITEBUFFERSIZE (16384)
#define MAXFILENAME (256)
#ifdef _WIN32
/* f: name of file to get info on, tmzip: return value: access,
modification and creation times, dt: dostime */
static int filetime(const char *f, tm_zip *tmzip, uLong *dt) {
int ret = 0;
{
FILETIME ftLocal;
HANDLE hFind;
WIN32_FIND_DATAA ff32;
hFind = FindFirstFileA(f,&ff32);
if (hFind != INVALID_HANDLE_VALUE)
{
FileTimeToLocalFileTime(&(ff32.ftLastWriteTime),&ftLocal);
FileTimeToDosDateTime(&ftLocal,((LPWORD)dt)+1,((LPWORD)dt)+0);
FindClose(hFind);
ret = 1;
}
}
return ret;
}
#else
#if defined(unix) || defined(__APPLE__)
/* f: name of file to get info on, tmzip: return value: access,
modification and creation times, dt: dostime */
static int filetime(const char *f, tm_zip *tmzip, uLong *dt) {
(void)dt;
int ret=0;
struct stat s; /* results of stat() */
struct tm* filedate;
time_t tm_t=0;
if (strcmp(f,"-")!=0)
{
char name[MAXFILENAME+1];
size_t len = strlen(f);
if (len > MAXFILENAME)
len = MAXFILENAME;
strncpy(name, f,MAXFILENAME-1);
/* strncpy doesn't append the trailing NULL, of the string is too long. */
name[ MAXFILENAME ] = '\0';
if (name[len - 1] == '/')
name[len - 1] = '\0';
/* not all systems allow stat'ing a file with / appended */
if (stat(name,&s)==0)
{
|
| ︙ | ︙ | |||
134 135 136 137 138 139 140 | tmzip->tm_mday = filedate->tm_mday; tmzip->tm_mon = filedate->tm_mon ; tmzip->tm_year = filedate->tm_year; return ret; } #else | < | | | < > > > | < < | < | < | < | | | < | < < | < | 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 |
tmzip->tm_mday = filedate->tm_mday;
tmzip->tm_mon = filedate->tm_mon ;
tmzip->tm_year = filedate->tm_year;
return ret;
}
#else
/* f: name of file to get info on, tmzip: return value: access,
modification and creation times, dt: dostime */
static int filetime(const char *f, tm_zip *tmzip, uLong *dt) {
(void)f;
(void)tmzip;
(void)dt;
return 0;
}
#endif
#endif
static int check_exist_file(const char* filename) {
FILE* ftestexist;
int ret = 1;
ftestexist = FOPEN_FUNC(filename,"rb");
if (ftestexist==NULL)
ret = 0;
else
fclose(ftestexist);
return ret;
}
static void do_banner(void) {
printf("MiniZip 1.1, demo of zLib + MiniZip64 package, written by Gilles Vollant\n");
printf("more info on MiniZip at http://www.winimage.com/zLibDll/minizip.html\n\n");
}
static void do_help(void) {
printf("Usage : minizip [-o] [-a] [-0 to -9] [-p password] [-j] file.zip [files_to_add]\n\n" \
" -o Overwrite existing file.zip\n" \
" -a Append to existing file.zip\n" \
" -0 Store only\n" \
" -1 Compress faster\n" \
" -9 Compress better\n\n" \
" -j exclude path. store only the file name.\n\n");
}
/* calculate the CRC32 of a file,
because to encrypt a file, we need known the CRC32 of the file before */
static int getFileCrc(const char* filenameinzip, void* buf, unsigned long size_buf, unsigned long* result_crc) {
unsigned long calculate_crc=0;
int err=ZIP_OK;
FILE * fin = FOPEN_FUNC(filenameinzip,"rb");
unsigned long size_read = 0;
/* unsigned long total_read = 0; */
if (fin==NULL)
{
err = ZIP_ERRNO;
}
if (err == ZIP_OK)
do
{
err = ZIP_OK;
size_read = fread(buf,1,size_buf,fin);
if (size_read < size_buf)
if (feof(fin)==0)
{
printf("error in reading %s\n",filenameinzip);
err = ZIP_ERRNO;
}
if (size_read>0)
calculate_crc = crc32_z(calculate_crc,buf,size_read);
/* total_read += size_read; */
} while ((err == ZIP_OK) && (size_read>0));
if (fin)
fclose(fin);
*result_crc=calculate_crc;
printf("file %s crc %lx\n", filenameinzip, calculate_crc);
return err;
}
static int isLargeFile(const char* filename) {
int largeFile = 0;
ZPOS64_T pos = 0;
FILE* pFile = FOPEN_FUNC(filename, "rb");
if(pFile != NULL)
{
FSEEKO_FUNC(pFile, 0, SEEK_END);
pos = (ZPOS64_T)FTELLO_FUNC(pFile);
printf("File : %s is %llu bytes\n", filename, pos);
if(pos >= 0xffffffff)
largeFile = 1;
fclose(pFile);
}
return largeFile;
}
int main(int argc, char *argv[]) {
int i;
int opt_overwrite=0;
int opt_compress_level=Z_DEFAULT_COMPRESSION;
int opt_exclude_path=0;
int zipfilenamearg = 0;
char filename_try[MAXFILENAME+16];
int zipok;
|
| ︙ | ︙ | |||
273 274 275 276 277 278 279 |
{
if ((*argv[i])=='-')
{
const char *p=argv[i]+1;
while ((*p)!='\0')
{
| | | 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 |
{
if ((*argv[i])=='-')
{
const char *p=argv[i]+1;
while ((*p)!='\0')
{
char c=*(p++);
if ((c=='o') || (c=='O'))
opt_overwrite = 1;
if ((c=='a') || (c=='A'))
opt_overwrite = 2;
if ((c>='0') && (c<='9'))
opt_compress_level = c-'0';
if ((c=='j') || (c=='J'))
|
| ︙ | ︙ | |||
319 320 321 322 323 324 325 |
else
{
int i,len;
int dot_found=0;
zipok = 1 ;
strncpy(filename_try, argv[zipfilenamearg],MAXFILENAME-1);
| | | 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 |
else
{
int i,len;
int dot_found=0;
zipok = 1 ;
strncpy(filename_try, argv[zipfilenamearg],MAXFILENAME-1);
/* strncpy doesn't append the trailing NULL, of the string is too long. */
filename_try[ MAXFILENAME ] = '\0';
len=(int)strlen(filename_try);
for (i=0;i<len;i++)
if (filename_try[i]=='.')
dot_found=1;
|
| ︙ | ︙ | |||
389 390 391 392 393 394 395 |
for (i=zipfilenamearg+1;(i<argc) && (err==ZIP_OK);i++)
{
if (!((((*(argv[i]))=='-') || ((*(argv[i]))=='/')) &&
((argv[i][1]=='o') || (argv[i][1]=='O') ||
(argv[i][1]=='a') || (argv[i][1]=='A') ||
(argv[i][1]=='p') || (argv[i][1]=='P') ||
| | | | 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 |
for (i=zipfilenamearg+1;(i<argc) && (err==ZIP_OK);i++)
{
if (!((((*(argv[i]))=='-') || ((*(argv[i]))=='/')) &&
((argv[i][1]=='o') || (argv[i][1]=='O') ||
(argv[i][1]=='a') || (argv[i][1]=='A') ||
(argv[i][1]=='p') || (argv[i][1]=='P') ||
((argv[i][1]>='0') && (argv[i][1]<='9'))) &&
(strlen(argv[i]) == 2)))
{
FILE * fin = NULL;
size_t size_read;
const char* filenameinzip = argv[i];
const char *savefilenameinzip;
zip_fileinfo zi;
unsigned long crcFile=0;
int zip64 = 0;
|
| ︙ | ︙ |
Changes to compat/zlib/contrib/minizip/mztools.c.
| ︙ | ︙ | |||
23 24 25 26 27 28 29 |
WRITE_8(((unsigned char*)(buff)) + 1, (n) >> 8); \
} while(0)
#define WRITE_32(buff, n) do { \
WRITE_16((unsigned char*)(buff), (n) & 0xffff); \
WRITE_16((unsigned char*)(buff) + 2, (n) >> 16); \
} while(0)
| | < < < < < < | 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
WRITE_8(((unsigned char*)(buff)) + 1, (n) >> 8); \
} while(0)
#define WRITE_32(buff, n) do { \
WRITE_16((unsigned char*)(buff), (n) & 0xffff); \
WRITE_16((unsigned char*)(buff) + 2, (n) >> 16); \
} while(0)
extern int ZEXPORT unzRepair(const char* file, const char* fileOut, const char* fileOutTmp, uLong* nRecovered, uLong* bytesRecovered) {
int err = Z_OK;
FILE* fpZip = fopen(file, "rb");
FILE* fpOut = fopen(fileOut, "wb");
FILE* fpOutCD = fopen(fileOutTmp, "wb");
if (fpZip != NULL && fpOut != NULL) {
int entries = 0;
uLong totalBytes = 0;
|
| ︙ | ︙ |
Changes to compat/zlib/contrib/minizip/unzip.c.
| ︙ | ︙ | |||
45 46 47 48 49 50 51 |
2007-2008 - Even Rouault - Decoration of symbol names unz* -> cpl_unz*
2007-2008 - Even Rouault - Remove old C style function prototypes
2007-2008 - Even Rouault - Add unzip support for ZIP64
Copyright (C) 2007-2008 Even Rouault
| | | | | 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
2007-2008 - Even Rouault - Decoration of symbol names unz* -> cpl_unz*
2007-2008 - Even Rouault - Remove old C style function prototypes
2007-2008 - Even Rouault - Add unzip support for ZIP64
Copyright (C) 2007-2008 Even Rouault
Oct-2009 - Mathias Svensson - Removed cpl_* from symbol names (Even Rouault added them but since this is now moved to a new project (minizip64) I renamed them again).
Oct-2009 - Mathias Svensson - Fixed problem if uncompressed size was > 4G and compressed size was <4G
should only read the compressed/uncompressed size from the Zip64 format if
the size from normal header was 0xFFFFFFFF
Oct-2009 - Mathias Svensson - Applied some bug fixes from patches received from Gilles Vollant
Oct-2009 - Mathias Svensson - Applied support to unzip files with compression method BZIP2 (bzip2 lib is required)
Patch created by Daniel Borca
Jan-2010 - back to unzip and minizip 1.0 name scheme, with compatibility layer
Copyright (C) 1998 - 2010 Gilles Vollant, Even Rouault, Mathias Svensson
*/
|
| ︙ | ︙ | |||
73 74 75 76 77 78 79 | #endif #include "zlib.h" #include "unzip.h" #ifdef STDC # include <stddef.h> | < < | 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
#endif
#include "zlib.h"
#include "unzip.h"
#ifdef STDC
# include <stddef.h>
#endif
#ifdef NO_ERRNO_H
extern int errno;
#else
# include <errno.h>
#endif
|
| ︙ | ︙ | |||
107 108 109 110 111 112 113 | #ifndef UNZ_MAXFILENAMEINZIP #define UNZ_MAXFILENAMEINZIP (256) #endif #ifndef ALLOC # define ALLOC(size) (malloc(size)) #endif | < < < | 105 106 107 108 109 110 111 112 113 114 115 116 117 118 | #ifndef UNZ_MAXFILENAMEINZIP #define UNZ_MAXFILENAMEINZIP (256) #endif #ifndef ALLOC # define ALLOC(size) (malloc(size)) #endif #define SIZECENTRALDIRITEM (0x2e) #define SIZEZIPLOCALHEADER (0x1e) const char unz_copyright[] = " unzip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll"; |
| ︙ | ︙ | |||
149 150 151 152 153 154 155 |
ZPOS64_T total_out_64;
uLong crc32; /* crc32 of all data uncompressed */
uLong crc32_wait; /* crc32 we must obtain after decompress all */
ZPOS64_T rest_read_compressed; /* number of byte to be decompressed */
ZPOS64_T rest_read_uncompressed;/*number of byte to be obtained after decomp*/
zlib_filefunc64_32_def z_filefunc;
| | | | 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 |
ZPOS64_T total_out_64;
uLong crc32; /* crc32 of all data uncompressed */
uLong crc32_wait; /* crc32 we must obtain after decompress all */
ZPOS64_T rest_read_compressed; /* number of byte to be decompressed */
ZPOS64_T rest_read_uncompressed;/*number of byte to be obtained after decomp*/
zlib_filefunc64_32_def z_filefunc;
voidpf filestream; /* io structure of the zipfile */
uLong compression_method; /* compression method (0==store) */
ZPOS64_T byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/
int raw;
} file_in_zip64_read_info_s;
/* unz64_s contain internal information about the zipfile
*/
typedef struct
{
zlib_filefunc64_32_def z_filefunc;
int is64bitOpenFunction;
voidpf filestream; /* io structure of the zipfile */
unz_global_info64 gi; /* public global information */
ZPOS64_T byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/
ZPOS64_T num_file; /* number of the current file in the zipfile*/
ZPOS64_T pos_in_central_dir; /* pos of the current file in the central dir*/
ZPOS64_T current_file_ok; /* flag about the usability of the current file*/
ZPOS64_T central_pos; /* position of the beginning of the central dir*/
|
| ︙ | ︙ | |||
192 193 194 195 196 197 198 199 200 | # endif } unz64_s; #ifndef NOUNCRYPT #include "crypt.h" #endif /* =========================================================================== | > | < < > > > > > > | > > > > > > > > > > > > | | | | > > > | > > > > > > > > > > > > | | > > > | | | < > > > < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < | 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 |
# endif
} unz64_s;
#ifndef NOUNCRYPT
#include "crypt.h"
#endif
/* ===========================================================================
Reads a long in LSB order from the given gz_stream. Sets
*/
local int unz64local_getShort(const zlib_filefunc64_32_def* pzlib_filefunc_def,
voidpf filestream,
uLong *pX) {
unsigned char c[2];
int err = (int)ZREAD64(*pzlib_filefunc_def,filestream,c,2);
if (err==2)
{
*pX = c[0] | ((uLong)c[1] << 8);
return UNZ_OK;
}
else
{
*pX = 0;
if (ZERROR64(*pzlib_filefunc_def,filestream))
return UNZ_ERRNO;
else
return UNZ_EOF;
}
}
local int unz64local_getLong(const zlib_filefunc64_32_def* pzlib_filefunc_def,
voidpf filestream,
uLong *pX) {
unsigned char c[4];
int err = (int)ZREAD64(*pzlib_filefunc_def,filestream,c,4);
if (err==4)
{
*pX = c[0] | ((uLong)c[1] << 8) | ((uLong)c[2] << 16) | ((uLong)c[3] << 24);
return UNZ_OK;
}
else
{
*pX = 0;
if (ZERROR64(*pzlib_filefunc_def,filestream))
return UNZ_ERRNO;
else
return UNZ_EOF;
}
}
local int unz64local_getLong64(const zlib_filefunc64_32_def* pzlib_filefunc_def,
voidpf filestream,
ZPOS64_T *pX) {
unsigned char c[8];
int err = (int)ZREAD64(*pzlib_filefunc_def,filestream,c,8);
if (err==8)
{
*pX = c[0] | ((ZPOS64_T)c[1] << 8) | ((ZPOS64_T)c[2] << 16) | ((ZPOS64_T)c[3] << 24)
| ((ZPOS64_T)c[4] << 32) | ((ZPOS64_T)c[5] << 40) | ((ZPOS64_T)c[6] << 48) | ((ZPOS64_T)c[7] << 56);
return UNZ_OK;
}
else
{
*pX = 0;
if (ZERROR64(*pzlib_filefunc_def,filestream))
return UNZ_ERRNO;
else
return UNZ_EOF;
}
}
/* My own strcmpi / strcasecmp */
local int strcmpcasenosensitive_internal(const char* fileName1, const char* fileName2) {
for (;;)
{
char c1=*(fileName1++);
char c2=*(fileName2++);
if ((c1>='a') && (c1<='z'))
c1 -= 0x20;
if ((c2>='a') && (c2<='z'))
|
| ︙ | ︙ | |||
375 376 377 378 379 380 381 | #endif #ifndef STRCMPCASENOSENTIVEFUNCTION #define STRCMPCASENOSENTIVEFUNCTION strcmpcasenosensitive_internal #endif /* | | | | | | | < < > > > > < | < | | | | 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 |
#endif
#ifndef STRCMPCASENOSENTIVEFUNCTION
#define STRCMPCASENOSENTIVEFUNCTION strcmpcasenosensitive_internal
#endif
/*
Compare two filenames (fileName1,fileName2).
If iCaseSensitivity = 1, comparison is case sensitive (like strcmp)
If iCaseSensitivity = 2, comparison is not case sensitive (like strcmpi
or strcasecmp)
If iCaseSensitivity = 0, case sensitivity is default of your operating system
(like 1 on Unix, 2 on Windows)
*/
extern int ZEXPORT unzStringFileNameCompare (const char* fileName1,
const char* fileName2,
int iCaseSensitivity) {
if (iCaseSensitivity==0)
iCaseSensitivity=CASESENSITIVITYDEFAULTVALUE;
if (iCaseSensitivity==1)
return strcmp(fileName1,fileName2);
return STRCMPCASENOSENTIVEFUNCTION(fileName1,fileName2);
}
#ifndef BUFREADCOMMENT
#define BUFREADCOMMENT (0x400)
#endif
#ifndef CENTRALDIRINVALID
#define CENTRALDIRINVALID ((ZPOS64_T)(-1))
#endif
/*
Locate the Central directory of a zipfile (at the end, just before
the global comment)
*/
local ZPOS64_T unz64local_SearchCentralDir(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream) {
unsigned char* buf;
ZPOS64_T uSizeFile;
ZPOS64_T uBackRead;
ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */
ZPOS64_T uPosFound=CENTRALDIRINVALID;
if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0)
return CENTRALDIRINVALID;
uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream);
if (uMaxBack>uSizeFile)
uMaxBack = uSizeFile;
buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4);
if (buf==NULL)
return CENTRALDIRINVALID;
uBackRead = 4;
while (uBackRead<uMaxBack)
{
uLong uReadSize;
ZPOS64_T uReadPos ;
int i;
|
| ︙ | ︙ | |||
455 456 457 458 459 460 461 |
if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) &&
((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06))
{
uPosFound = uReadPos+(unsigned)i;
break;
}
| | | < < < < | < | | | | 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 |
if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) &&
((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06))
{
uPosFound = uReadPos+(unsigned)i;
break;
}
if (uPosFound!=CENTRALDIRINVALID)
break;
}
free(buf);
return uPosFound;
}
/*
Locate the Central directory 64 of a zipfile (at the end, just before
the global comment)
*/
local ZPOS64_T unz64local_SearchCentralDir64(const zlib_filefunc64_32_def* pzlib_filefunc_def,
voidpf filestream) {
unsigned char* buf;
ZPOS64_T uSizeFile;
ZPOS64_T uBackRead;
ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */
ZPOS64_T uPosFound=CENTRALDIRINVALID;
uLong uL;
ZPOS64_T relativeOffset;
if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0)
return CENTRALDIRINVALID;
uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream);
if (uMaxBack>uSizeFile)
uMaxBack = uSizeFile;
buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4);
if (buf==NULL)
return CENTRALDIRINVALID;
uBackRead = 4;
while (uBackRead<uMaxBack)
{
uLong uReadSize;
ZPOS64_T uReadPos;
int i;
|
| ︙ | ︙ | |||
523 524 525 526 527 528 529 |
if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) &&
((*(buf+i+2))==0x06) && ((*(buf+i+3))==0x07))
{
uPosFound = uReadPos+(unsigned)i;
break;
}
| | | | | | | | | | | | | | | | | | < | | | 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 |
if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) &&
((*(buf+i+2))==0x06) && ((*(buf+i+3))==0x07))
{
uPosFound = uReadPos+(unsigned)i;
break;
}
if (uPosFound!=CENTRALDIRINVALID)
break;
}
free(buf);
if (uPosFound == CENTRALDIRINVALID)
return CENTRALDIRINVALID;
/* Zip64 end of central directory locator */
if (ZSEEK64(*pzlib_filefunc_def,filestream, uPosFound,ZLIB_FILEFUNC_SEEK_SET)!=0)
return CENTRALDIRINVALID;
/* the signature, already checked */
if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK)
return CENTRALDIRINVALID;
/* number of the disk with the start of the zip64 end of central directory */
if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK)
return CENTRALDIRINVALID;
if (uL != 0)
return CENTRALDIRINVALID;
/* relative offset of the zip64 end of central directory record */
if (unz64local_getLong64(pzlib_filefunc_def,filestream,&relativeOffset)!=UNZ_OK)
return CENTRALDIRINVALID;
/* total number of disks */
if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK)
return CENTRALDIRINVALID;
if (uL != 1)
return CENTRALDIRINVALID;
/* Goto end of central directory record */
if (ZSEEK64(*pzlib_filefunc_def,filestream, relativeOffset,ZLIB_FILEFUNC_SEEK_SET)!=0)
return CENTRALDIRINVALID;
/* the signature */
if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK)
return CENTRALDIRINVALID;
if (uL != 0x06064b50)
return CENTRALDIRINVALID;
return relativeOffset;
}
/*
Open a Zip file. path contain the full pathname (by example,
on a Windows NT computer "c:\\test\\zlib114.zip" or on an Unix computer
"zlib/zlib114.zip".
If the zipfile cannot be opened (file doesn't exist or in not valid), the
return value is NULL.
Else, the return value is a unzFile Handle, usable with other function
of this unzip package.
*/
local unzFile unzOpenInternal(const void *path,
zlib_filefunc64_32_def* pzlib_filefunc64_32_def,
int is64bitOpenFunction) {
unz64_s us;
unz64_s *s;
ZPOS64_T central_pos;
uLong uL;
uLong number_disk; /* number of the current dist, used for
spanning ZIP, unsupported, always 0*/
uLong number_disk_with_CD; /* number the the disk with central dir, used
for spanning ZIP, unsupported, always 0*/
ZPOS64_T number_entry_CD; /* total number of entries in
the central dir
(same than number_entry on nospan) */
int err=UNZ_OK;
if (unz_copyright[0]!=' ')
|
| ︙ | ︙ | |||
617 618 619 620 621 622 623 |
path,
ZLIB_FILEFUNC_MODE_READ |
ZLIB_FILEFUNC_MODE_EXISTING);
if (us.filestream==NULL)
return NULL;
central_pos = unz64local_SearchCentralDir64(&us.z_filefunc,us.filestream);
| | | 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 |
path,
ZLIB_FILEFUNC_MODE_READ |
ZLIB_FILEFUNC_MODE_EXISTING);
if (us.filestream==NULL)
return NULL;
central_pos = unz64local_SearchCentralDir64(&us.z_filefunc,us.filestream);
if (central_pos!=CENTRALDIRINVALID)
{
uLong uS;
ZPOS64_T uL64;
us.isZip64 = 1;
if (ZSEEK64(us.z_filefunc, us.filestream,
|
| ︙ | ︙ | |||
679 680 681 682 683 684 685 |
err=UNZ_ERRNO;
us.gi.size_comment = 0;
}
else
{
central_pos = unz64local_SearchCentralDir(&us.z_filefunc,us.filestream);
| | | 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 |
err=UNZ_ERRNO;
us.gi.size_comment = 0;
}
else
{
central_pos = unz64local_SearchCentralDir(&us.z_filefunc,us.filestream);
if (central_pos==CENTRALDIRINVALID)
err=UNZ_ERRNO;
us.isZip64 = 0;
if (ZSEEK64(us.z_filefunc, us.filestream,
central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0)
err=UNZ_ERRNO;
|
| ︙ | ︙ | |||
758 759 760 761 762 763 764 |
*s=us;
unzGoToFirstFile((unzFile)s);
}
return (unzFile)s;
}
| | | < | | < | < | < | < | | < | < | | < | | | | | | | | | < < < < < < < < < < < | < | 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 |
*s=us;
unzGoToFirstFile((unzFile)s);
}
return (unzFile)s;
}
extern unzFile ZEXPORT unzOpen2(const char *path,
zlib_filefunc_def* pzlib_filefunc32_def) {
if (pzlib_filefunc32_def != NULL)
{
zlib_filefunc64_32_def zlib_filefunc64_32_def_fill;
fill_zlib_filefunc64_32_def_from_filefunc32(&zlib_filefunc64_32_def_fill,pzlib_filefunc32_def);
return unzOpenInternal(path, &zlib_filefunc64_32_def_fill, 0);
}
else
return unzOpenInternal(path, NULL, 0);
}
extern unzFile ZEXPORT unzOpen2_64(const void *path,
zlib_filefunc64_def* pzlib_filefunc_def) {
if (pzlib_filefunc_def != NULL)
{
zlib_filefunc64_32_def zlib_filefunc64_32_def_fill;
zlib_filefunc64_32_def_fill.zfile_func64 = *pzlib_filefunc_def;
zlib_filefunc64_32_def_fill.ztell32_file = NULL;
zlib_filefunc64_32_def_fill.zseek32_file = NULL;
return unzOpenInternal(path, &zlib_filefunc64_32_def_fill, 1);
}
else
return unzOpenInternal(path, NULL, 1);
}
extern unzFile ZEXPORT unzOpen(const char *path) {
return unzOpenInternal(path, NULL, 0);
}
extern unzFile ZEXPORT unzOpen64(const void *path) {
return unzOpenInternal(path, NULL, 1);
}
/*
Close a ZipFile opened with unzOpen.
If there is files inside the .Zip opened with unzOpenCurrentFile (see later),
these files MUST be closed with unzCloseCurrentFile before call unzClose.
return UNZ_OK if there is no problem. */
extern int ZEXPORT unzClose(unzFile file) {
unz64_s* s;
if (file==NULL)
return UNZ_PARAMERROR;
s=(unz64_s*)file;
if (s->pfile_in_zip_read!=NULL)
unzCloseCurrentFile(file);
ZCLOSE64(s->z_filefunc, s->filestream);
free(s);
return UNZ_OK;
}
/*
Write info about the ZipFile in the *pglobal_info structure.
No preparation of the structure is needed
return UNZ_OK if there is no problem. */
extern int ZEXPORT unzGetGlobalInfo64(unzFile file, unz_global_info64* pglobal_info) {
unz64_s* s;
if (file==NULL)
return UNZ_PARAMERROR;
s=(unz64_s*)file;
*pglobal_info=s->gi;
return UNZ_OK;
}
extern int ZEXPORT unzGetGlobalInfo(unzFile file, unz_global_info* pglobal_info32) {
unz64_s* s;
if (file==NULL)
return UNZ_PARAMERROR;
s=(unz64_s*)file;
/* to do : check if number_entry is not truncated */
pglobal_info32->number_entry = (uLong)s->gi.number_entry;
pglobal_info32->size_comment = s->gi.size_comment;
return UNZ_OK;
}
/*
Translate date/time from Dos format to tm_unz (readable more easily)
*/
local void unz64local_DosDateToTmuDate(ZPOS64_T ulDosDate, tm_unz* ptm) {
ZPOS64_T uDate;
uDate = (ZPOS64_T)(ulDosDate>>16);
ptm->tm_mday = (int)(uDate&0x1f) ;
ptm->tm_mon = (int)((((uDate)&0x1E0)/0x20)-1) ;
ptm->tm_year = (int)(((uDate&0x0FE00)/0x0200)+1980) ;
ptm->tm_hour = (int) ((ulDosDate &0xF800)/0x800);
ptm->tm_min = (int) ((ulDosDate&0x7E0)/0x20) ;
ptm->tm_sec = (int) (2*(ulDosDate&0x1f)) ;
}
/*
Get Info about the current file in the zipfile, with internal only info
*/
local int unz64local_GetCurrentFileInfoInternal(unzFile file,
unz_file_info64 *pfile_info,
unz_file_info64_internal
*pfile_info_internal,
char *szFileName,
uLong fileNameBufferSize,
void *extraField,
uLong extraFieldBufferSize,
char *szComment,
uLong commentBufferSize) {
unz64_s* s;
unz_file_info64 file_info;
unz_file_info64_internal file_info_internal;
int err=UNZ_OK;
uLong uMagic;
long lSeek=0;
uLong uL;
|
| ︙ | ︙ | |||
1034 1035 1036 1037 1038 1039 1040 |
if (unz64local_getShort(&s->z_filefunc, s->filestream,&dataSize) != UNZ_OK)
err=UNZ_ERRNO;
/* ZIP64 extra fields */
if (headerId == 0x0001)
{
| < < | | | | | | | | | | | | | | | | | | | | | | | 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 |
if (unz64local_getShort(&s->z_filefunc, s->filestream,&dataSize) != UNZ_OK)
err=UNZ_ERRNO;
/* ZIP64 extra fields */
if (headerId == 0x0001)
{
if(file_info.uncompressed_size == MAXU32)
{
if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info.uncompressed_size) != UNZ_OK)
err=UNZ_ERRNO;
}
if(file_info.compressed_size == MAXU32)
{
if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info.compressed_size) != UNZ_OK)
err=UNZ_ERRNO;
}
if(file_info_internal.offset_curfile == MAXU32)
{
/* Relative Header offset */
if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info_internal.offset_curfile) != UNZ_OK)
err=UNZ_ERRNO;
}
if(file_info.disk_num_start == 0xffff)
{
/* Disk Start Number */
if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.disk_num_start) != UNZ_OK)
err=UNZ_ERRNO;
}
}
else
{
if (ZSEEK64(s->z_filefunc, s->filestream,dataSize,ZLIB_FILEFUNC_SEEK_CUR)!=0)
err=UNZ_ERRNO;
}
|
| ︙ | ︙ | |||
1117 1118 1119 1120 1121 1122 1123 | /* Write info about the ZipFile in the *pglobal_info structure. No preparation of the structure is needed return UNZ_OK if there is no problem. */ | | | | | | < | | | | | | | | < | 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 |
/*
Write info about the ZipFile in the *pglobal_info structure.
No preparation of the structure is needed
return UNZ_OK if there is no problem.
*/
extern int ZEXPORT unzGetCurrentFileInfo64(unzFile file,
unz_file_info64 * pfile_info,
char * szFileName, uLong fileNameBufferSize,
void *extraField, uLong extraFieldBufferSize,
char* szComment, uLong commentBufferSize) {
return unz64local_GetCurrentFileInfoInternal(file,pfile_info,NULL,
szFileName,fileNameBufferSize,
extraField,extraFieldBufferSize,
szComment,commentBufferSize);
}
extern int ZEXPORT unzGetCurrentFileInfo(unzFile file,
unz_file_info * pfile_info,
char * szFileName, uLong fileNameBufferSize,
void *extraField, uLong extraFieldBufferSize,
char* szComment, uLong commentBufferSize) {
int err;
unz_file_info64 file_info64;
err = unz64local_GetCurrentFileInfoInternal(file,&file_info64,NULL,
szFileName,fileNameBufferSize,
extraField,extraFieldBufferSize,
szComment,commentBufferSize);
if ((err==UNZ_OK) && (pfile_info != NULL))
|
| ︙ | ︙ | |||
1158 1159 1160 1161 1162 1163 1164 |
pfile_info->size_file_extra = file_info64.size_file_extra;
pfile_info->size_file_comment = file_info64.size_file_comment;
pfile_info->disk_num_start = file_info64.disk_num_start;
pfile_info->internal_fa = file_info64.internal_fa;
pfile_info->external_fa = file_info64.external_fa;
| | | < | < | 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 |
pfile_info->size_file_extra = file_info64.size_file_extra;
pfile_info->size_file_comment = file_info64.size_file_comment;
pfile_info->disk_num_start = file_info64.disk_num_start;
pfile_info->internal_fa = file_info64.internal_fa;
pfile_info->external_fa = file_info64.external_fa;
pfile_info->tmu_date = file_info64.tmu_date;
pfile_info->compressed_size = (uLong)file_info64.compressed_size;
pfile_info->uncompressed_size = (uLong)file_info64.uncompressed_size;
}
return err;
}
/*
Set the current file of the zipfile to the first file.
return UNZ_OK if there is no problem
*/
extern int ZEXPORT unzGoToFirstFile(unzFile file) {
int err=UNZ_OK;
unz64_s* s;
if (file==NULL)
return UNZ_PARAMERROR;
s=(unz64_s*)file;
s->pos_in_central_dir=s->offset_central_dir;
s->num_file=0;
err=unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info,
&s->cur_file_info_internal,
NULL,0,NULL,0,NULL,0);
s->current_file_ok = (err == UNZ_OK);
return err;
}
/*
Set the current file of the zipfile to the next file.
return UNZ_OK if there is no problem
return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest.
*/
extern int ZEXPORT unzGoToNextFile(unzFile file) {
unz64_s* s;
int err;
if (file==NULL)
return UNZ_PARAMERROR;
s=(unz64_s*)file;
if (!s->current_file_ok)
|
| ︙ | ︙ | |||
1225 1226 1227 1228 1229 1230 1231 | Try locate the file szFileName in the zipfile. For the iCaseSensitivity signification, see unzStringFileNameCompare return value : UNZ_OK if the file is found. It becomes the current file. UNZ_END_OF_LIST_OF_FILE if the file is not found */ | | < | 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 |
Try locate the file szFileName in the zipfile.
For the iCaseSensitivity signification, see unzStringFileNameCompare
return value :
UNZ_OK if the file is found. It becomes the current file.
UNZ_END_OF_LIST_OF_FILE if the file is not found
*/
extern int ZEXPORT unzLocateFile(unzFile file, const char *szFileName, int iCaseSensitivity) {
unz64_s* s;
int err;
/* We remember the 'current' position in the file so that we can jump
* back there if we fail.
*/
unz_file_info64 cur_file_infoSaved;
|
| ︙ | ︙ | |||
1301 1302 1303 1304 1305 1306 1307 |
typedef struct unz_file_pos_s
{
ZPOS64_T pos_in_zip_directory; // offset in file
ZPOS64_T num_of_file; // # of file
} unz_file_pos;
*/
| | < | < < < | < | < < < | 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 |
typedef struct unz_file_pos_s
{
ZPOS64_T pos_in_zip_directory; // offset in file
ZPOS64_T num_of_file; // # of file
} unz_file_pos;
*/
extern int ZEXPORT unzGetFilePos64(unzFile file, unz64_file_pos* file_pos) {
unz64_s* s;
if (file==NULL || file_pos==NULL)
return UNZ_PARAMERROR;
s=(unz64_s*)file;
if (!s->current_file_ok)
return UNZ_END_OF_LIST_OF_FILE;
file_pos->pos_in_zip_directory = s->pos_in_central_dir;
file_pos->num_of_file = s->num_file;
return UNZ_OK;
}
extern int ZEXPORT unzGetFilePos(unzFile file, unz_file_pos* file_pos) {
unz64_file_pos file_pos64;
int err = unzGetFilePos64(file,&file_pos64);
if (err==UNZ_OK)
{
file_pos->pos_in_zip_directory = (uLong)file_pos64.pos_in_zip_directory;
file_pos->num_of_file = (uLong)file_pos64.num_of_file;
}
return err;
}
extern int ZEXPORT unzGoToFilePos64(unzFile file, const unz64_file_pos* file_pos) {
unz64_s* s;
int err;
if (file==NULL || file_pos==NULL)
return UNZ_PARAMERROR;
s=(unz64_s*)file;
/* jump to the right spot */
s->pos_in_central_dir = file_pos->pos_in_zip_directory;
s->num_file = file_pos->num_of_file;
/* set the current file */
err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info,
&s->cur_file_info_internal,
NULL,0,NULL,0,NULL,0);
/* return results */
s->current_file_ok = (err == UNZ_OK);
return err;
}
extern int ZEXPORT unzGoToFilePos(unzFile file, unz_file_pos* file_pos) {
unz64_file_pos file_pos64;
if (file_pos == NULL)
return UNZ_PARAMERROR;
file_pos64.pos_in_zip_directory = file_pos->pos_in_zip_directory;
file_pos64.num_of_file = file_pos->num_of_file;
return unzGoToFilePos64(file,&file_pos64);
|
| ︙ | ︙ | |||
1378 1379 1380 1381 1382 1383 1384 |
/*
Read the local header of the current zipfile
Check the coherency of the local header and info in the end of central
directory about this file
store in *piSizeVar the size of extra info in local header
(filename and size of extra field data)
*/
| | | | < | 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 |
/*
Read the local header of the current zipfile
Check the coherency of the local header and info in the end of central
directory about this file
store in *piSizeVar the size of extra info in local header
(filename and size of extra field data)
*/
local int unz64local_CheckCurrentFileCoherencyHeader(unz64_s* s, uInt* piSizeVar,
ZPOS64_T * poffset_local_extrafield,
uInt * psize_local_extrafield) {
uLong uMagic,uData,uFlags;
uLong size_filename;
uLong size_extra_field;
int err=UNZ_OK;
*piSizeVar = 0;
*poffset_local_extrafield = 0;
|
| ︙ | ︙ | |||
1465 1466 1467 1468 1469 1470 1471 |
return err;
}
/*
Open for reading data the current file in the zipfile.
If there is no error and the file is opened, the return value is UNZ_OK.
*/
| | | < | 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 |
return err;
}
/*
Open for reading data the current file in the zipfile.
If there is no error and the file is opened, the return value is UNZ_OK.
*/
extern int ZEXPORT unzOpenCurrentFile3(unzFile file, int* method,
int* level, int raw, const char* password) {
int err=UNZ_OK;
uInt iSizeVar;
unz64_s* s;
file_in_zip64_read_info_s* pfile_in_zip_read_info;
ZPOS64_T offset_local_extrafield; /* offset of the local extra field */
uInt size_local_extrafield; /* size of the local extra field */
# ifndef NOUNCRYPT
|
| ︙ | ︙ | |||
1505 1506 1507 1508 1509 1510 1511 |
pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield;
pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield;
pfile_in_zip_read_info->pos_local_extrafield=0;
pfile_in_zip_read_info->raw=raw;
if (pfile_in_zip_read_info->read_buffer==NULL)
{
| | | 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 |
pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield;
pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield;
pfile_in_zip_read_info->pos_local_extrafield=0;
pfile_in_zip_read_info->raw=raw;
if (pfile_in_zip_read_info->read_buffer==NULL)
{
free(pfile_in_zip_read_info);
return UNZ_INTERNALERROR;
}
pfile_in_zip_read_info->stream_initialised=0;
if (method!=NULL)
*method = (int)s->cur_file_info.compression_method;
|
| ︙ | ︙ | |||
1562 1563 1564 1565 1566 1567 1568 |
pfile_in_zip_read_info->stream.avail_in = 0;
err=BZ2_bzDecompressInit(&pfile_in_zip_read_info->bstream, 0, 0);
if (err == Z_OK)
pfile_in_zip_read_info->stream_initialised=Z_BZIP2ED;
else
{
| > | > | | 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 |
pfile_in_zip_read_info->stream.avail_in = 0;
err=BZ2_bzDecompressInit(&pfile_in_zip_read_info->bstream, 0, 0);
if (err == Z_OK)
pfile_in_zip_read_info->stream_initialised=Z_BZIP2ED;
else
{
free(pfile_in_zip_read_info->read_buffer);
free(pfile_in_zip_read_info);
return err;
}
#else
pfile_in_zip_read_info->raw=1;
#endif
}
else if ((s->cur_file_info.compression_method==Z_DEFLATED) && (!raw))
{
pfile_in_zip_read_info->stream.zalloc = (alloc_func)0;
pfile_in_zip_read_info->stream.zfree = (free_func)0;
pfile_in_zip_read_info->stream.opaque = (voidpf)0;
pfile_in_zip_read_info->stream.next_in = 0;
pfile_in_zip_read_info->stream.avail_in = 0;
err=inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS);
if (err == Z_OK)
pfile_in_zip_read_info->stream_initialised=Z_DEFLATED;
else
{
free(pfile_in_zip_read_info->read_buffer);
free(pfile_in_zip_read_info);
return err;
}
/* windowBits is passed < 0 to tell that there is no zlib header.
* Note that in this case inflate *requires* an extra "dummy" byte
* after the compressed stream in order to complete decompression and
* return Z_STREAM_END.
* In unzip, i don't wait absolutely Z_STREAM_END because I known the
|
| ︙ | ︙ | |||
1634 1635 1636 1637 1638 1639 1640 |
}
# endif
return UNZ_OK;
}
| | < | < | < | < | | < | 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 |
}
# endif
return UNZ_OK;
}
extern int ZEXPORT unzOpenCurrentFile(unzFile file) {
return unzOpenCurrentFile3(file, NULL, NULL, 0, NULL);
}
extern int ZEXPORT unzOpenCurrentFilePassword(unzFile file, const char* password) {
return unzOpenCurrentFile3(file, NULL, NULL, 0, password);
}
extern int ZEXPORT unzOpenCurrentFile2(unzFile file, int* method, int* level, int raw) {
return unzOpenCurrentFile3(file, method, level, raw, NULL);
}
/** Addition for GDAL : START */
extern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64(unzFile file) {
unz64_s* s;
file_in_zip64_read_info_s* pfile_in_zip_read_info;
s=(unz64_s*)file;
if (file==NULL)
return 0; //UNZ_PARAMERROR;
pfile_in_zip_read_info=s->pfile_in_zip_read;
if (pfile_in_zip_read_info==NULL)
return 0; //UNZ_PARAMERROR;
return pfile_in_zip_read_info->pos_in_zipfile +
pfile_in_zip_read_info->byte_before_the_zipfile;
}
/** Addition for GDAL : END */
/*
Read bytes from the current file.
buf contain buffer where data must be copied
len the size of buf.
return the number of byte copied if some bytes are copied
return 0 if the end of file was reached
return <0 with error code if there is an error
(UNZ_ERRNO for IO error, or zLib error for uncompress error)
*/
extern int ZEXPORT unzReadCurrentFile(unzFile file, voidp buf, unsigned len) {
int err=UNZ_OK;
uInt iRead = 0;
unz64_s* s;
file_in_zip64_read_info_s* pfile_in_zip_read_info;
if (file==NULL)
return UNZ_PARAMERROR;
s=(unz64_s*)file;
|
| ︙ | ︙ | |||
1885 1886 1887 1888 1889 1890 1891 |
return err;
}
/*
Give the current position in uncompressed data
*/
| | < | < | < | 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 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 |
return err;
}
/*
Give the current position in uncompressed data
*/
extern z_off_t ZEXPORT unztell(unzFile file) {
unz64_s* s;
file_in_zip64_read_info_s* pfile_in_zip_read_info;
if (file==NULL)
return UNZ_PARAMERROR;
s=(unz64_s*)file;
pfile_in_zip_read_info=s->pfile_in_zip_read;
if (pfile_in_zip_read_info==NULL)
return UNZ_PARAMERROR;
return (z_off_t)pfile_in_zip_read_info->stream.total_out;
}
extern ZPOS64_T ZEXPORT unztell64(unzFile file) {
unz64_s* s;
file_in_zip64_read_info_s* pfile_in_zip_read_info;
if (file==NULL)
return (ZPOS64_T)-1;
s=(unz64_s*)file;
pfile_in_zip_read_info=s->pfile_in_zip_read;
if (pfile_in_zip_read_info==NULL)
return (ZPOS64_T)-1;
return pfile_in_zip_read_info->total_out_64;
}
/*
return 1 if the end of file was reached, 0 elsewhere
*/
extern int ZEXPORT unzeof(unzFile file) {
unz64_s* s;
file_in_zip64_read_info_s* pfile_in_zip_read_info;
if (file==NULL)
return UNZ_PARAMERROR;
s=(unz64_s*)file;
pfile_in_zip_read_info=s->pfile_in_zip_read;
|
| ︙ | ︙ | |||
1952 1953 1954 1955 1956 1957 1958 |
if buf==NULL, it return the size of the local extra field that can be read
if buf!=NULL, len is the size of the buffer, the extra header is copied in
buf.
the return value is the number of bytes copied in buf, or (if <0)
the error code
*/
| | < | 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 |
if buf==NULL, it return the size of the local extra field that can be read
if buf!=NULL, len is the size of the buffer, the extra header is copied in
buf.
the return value is the number of bytes copied in buf, or (if <0)
the error code
*/
extern int ZEXPORT unzGetLocalExtrafield(unzFile file, voidp buf, unsigned len) {
unz64_s* s;
file_in_zip64_read_info_s* pfile_in_zip_read_info;
uInt read_now;
ZPOS64_T size_to_read;
if (file==NULL)
return UNZ_PARAMERROR;
|
| ︙ | ︙ | |||
2000 2001 2002 2003 2004 2005 2006 |
return (int)read_now;
}
/*
Close the file in zip opened with unzOpenCurrentFile
Return UNZ_CRCERROR if all the file was read but the CRC is not good
*/
| | < | 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 |
return (int)read_now;
}
/*
Close the file in zip opened with unzOpenCurrentFile
Return UNZ_CRCERROR if all the file was read but the CRC is not good
*/
extern int ZEXPORT unzCloseCurrentFile(unzFile file) {
int err=UNZ_OK;
unz64_s* s;
file_in_zip64_read_info_s* pfile_in_zip_read_info;
if (file==NULL)
return UNZ_PARAMERROR;
s=(unz64_s*)file;
|
| ︙ | ︙ | |||
2023 2024 2025 2026 2027 2028 2029 |
(!pfile_in_zip_read_info->raw))
{
if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait)
err=UNZ_CRCERROR;
}
| | | | < | 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 |
(!pfile_in_zip_read_info->raw))
{
if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait)
err=UNZ_CRCERROR;
}
free(pfile_in_zip_read_info->read_buffer);
pfile_in_zip_read_info->read_buffer = NULL;
if (pfile_in_zip_read_info->stream_initialised == Z_DEFLATED)
inflateEnd(&pfile_in_zip_read_info->stream);
#ifdef HAVE_BZIP2
else if (pfile_in_zip_read_info->stream_initialised == Z_BZIP2ED)
BZ2_bzDecompressEnd(&pfile_in_zip_read_info->bstream);
#endif
pfile_in_zip_read_info->stream_initialised = 0;
free(pfile_in_zip_read_info);
s->pfile_in_zip_read=NULL;
return err;
}
/*
Get the global comment string of the ZipFile, in the szComment buffer.
uSizeBuf is the size of the szComment buffer.
return the number of byte copied or an error code <0
*/
extern int ZEXPORT unzGetGlobalComment(unzFile file, char * szComment, uLong uSizeBuf) {
unz64_s* s;
uLong uReadThis ;
if (file==NULL)
return (int)UNZ_PARAMERROR;
s=(unz64_s*)file;
uReadThis = uSizeBuf;
|
| ︙ | ︙ | |||
2075 2076 2077 2078 2079 2080 2081 |
if ((szComment != NULL) && (uSizeBuf > s->gi.size_comment))
*(szComment+s->gi.size_comment)='\0';
return (int)uReadThis;
}
/* Additions by RX '2004 */
| | < | < | < | < | 1936 1937 1938 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 |
if ((szComment != NULL) && (uSizeBuf > s->gi.size_comment))
*(szComment+s->gi.size_comment)='\0';
return (int)uReadThis;
}
/* Additions by RX '2004 */
extern ZPOS64_T ZEXPORT unzGetOffset64(unzFile file) {
unz64_s* s;
if (file==NULL)
return 0; //UNZ_PARAMERROR;
s=(unz64_s*)file;
if (!s->current_file_ok)
return 0;
if (s->gi.number_entry != 0 && s->gi.number_entry != 0xffff)
if (s->num_file==s->gi.number_entry)
return 0;
return s->pos_in_central_dir;
}
extern uLong ZEXPORT unzGetOffset(unzFile file) {
ZPOS64_T offset64;
if (file==NULL)
return 0; //UNZ_PARAMERROR;
offset64 = unzGetOffset64(file);
return (uLong)offset64;
}
extern int ZEXPORT unzSetOffset64(unzFile file, ZPOS64_T pos) {
unz64_s* s;
int err;
if (file==NULL)
return UNZ_PARAMERROR;
s=(unz64_s*)file;
s->pos_in_central_dir = pos;
s->num_file = s->gi.number_entry; /* hack */
err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info,
&s->cur_file_info_internal,
NULL,0,NULL,0,NULL,0);
s->current_file_ok = (err == UNZ_OK);
return err;
}
extern int ZEXPORT unzSetOffset (unzFile file, uLong pos) {
return unzSetOffset64(file,pos);
}
|
Changes to compat/zlib/contrib/minizip/unzip.h.
| ︙ | ︙ | |||
146 147 148 149 150 151 152 |
uLong disk_num_start; /* disk number start 2 bytes */
uLong internal_fa; /* internal file attributes 2 bytes */
uLong external_fa; /* external file attributes 4 bytes */
tm_unz tmu_date;
} unz_file_info;
| | | | | | | | | | | | | | | | | | | | | | | | | | | | 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 |
uLong disk_num_start; /* disk number start 2 bytes */
uLong internal_fa; /* internal file attributes 2 bytes */
uLong external_fa; /* external file attributes 4 bytes */
tm_unz tmu_date;
} unz_file_info;
extern int ZEXPORT unzStringFileNameCompare(const char* fileName1,
const char* fileName2,
int iCaseSensitivity);
/*
Compare two filenames (fileName1,fileName2).
If iCaseSensitivity = 1, comparison is case sensitive (like strcmp)
If iCaseSensitivity = 2, comparison is not case sensitive (like strcmpi
or strcasecmp)
If iCaseSensitivity = 0, case sensitivity is default of your operating system
(like 1 on Unix, 2 on Windows)
*/
extern unzFile ZEXPORT unzOpen(const char *path);
extern unzFile ZEXPORT unzOpen64(const void *path);
/*
Open a Zip file. path contain the full pathname (by example,
on a Windows XP computer "c:\\zlib\\zlib113.zip" or on an Unix computer
"zlib/zlib113.zip".
If the zipfile cannot be opened (file don't exist or in not valid), the
return value is NULL.
Else, the return value is a unzFile Handle, usable with other function
of this unzip package.
the "64" function take a const void* pointer, because the path is just the
value passed to the open64_file_func callback.
Under Windows, if UNICODE is defined, using fill_fopen64_filefunc, the path
is a pointer to a wide unicode string (LPCTSTR is LPCWSTR), so const char*
does not describe the reality
*/
extern unzFile ZEXPORT unzOpen2(const char *path,
zlib_filefunc_def* pzlib_filefunc_def);
/*
Open a Zip file, like unzOpen, but provide a set of file low level API
for read/write the zip file (see ioapi.h)
*/
extern unzFile ZEXPORT unzOpen2_64(const void *path,
zlib_filefunc64_def* pzlib_filefunc_def);
/*
Open a Zip file, like unz64Open, but provide a set of file low level API
for read/write the zip file (see ioapi.h)
*/
extern int ZEXPORT unzClose(unzFile file);
/*
Close a ZipFile opened with unzOpen.
If there is files inside the .Zip opened with unzOpenCurrentFile (see later),
these files MUST be closed with unzCloseCurrentFile before call unzClose.
return UNZ_OK if there is no problem. */
extern int ZEXPORT unzGetGlobalInfo(unzFile file,
unz_global_info *pglobal_info);
extern int ZEXPORT unzGetGlobalInfo64(unzFile file,
unz_global_info64 *pglobal_info);
/*
Write info about the ZipFile in the *pglobal_info structure.
No preparation of the structure is needed
return UNZ_OK if there is no problem. */
extern int ZEXPORT unzGetGlobalComment(unzFile file,
char *szComment,
uLong uSizeBuf);
/*
Get the global comment string of the ZipFile, in the szComment buffer.
uSizeBuf is the size of the szComment buffer.
return the number of byte copied or an error code <0
*/
/***************************************************************************/
/* Unzip package allow you browse the directory of the zipfile */
extern int ZEXPORT unzGoToFirstFile(unzFile file);
/*
Set the current file of the zipfile to the first file.
return UNZ_OK if there is no problem
*/
extern int ZEXPORT unzGoToNextFile(unzFile file);
/*
Set the current file of the zipfile to the next file.
return UNZ_OK if there is no problem
return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest.
*/
extern int ZEXPORT unzLocateFile(unzFile file,
const char *szFileName,
int iCaseSensitivity);
/*
Try locate the file szFileName in the zipfile.
For the iCaseSensitivity signification, see unzStringFileNameCompare
return value :
UNZ_OK if the file is found. It becomes the current file.
UNZ_END_OF_LIST_OF_FILE if the file is not found
|
| ︙ | ︙ | |||
281 282 283 284 285 286 287 |
extern int ZEXPORT unzGoToFilePos64(
unzFile file,
const unz64_file_pos* file_pos);
/* ****************************************** */
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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 |
extern int ZEXPORT unzGoToFilePos64(
unzFile file,
const unz64_file_pos* file_pos);
/* ****************************************** */
extern int ZEXPORT unzGetCurrentFileInfo64(unzFile file,
unz_file_info64 *pfile_info,
char *szFileName,
uLong fileNameBufferSize,
void *extraField,
uLong extraFieldBufferSize,
char *szComment,
uLong commentBufferSize);
extern int ZEXPORT unzGetCurrentFileInfo(unzFile file,
unz_file_info *pfile_info,
char *szFileName,
uLong fileNameBufferSize,
void *extraField,
uLong extraFieldBufferSize,
char *szComment,
uLong commentBufferSize);
/*
Get Info about the current file
if pfile_info!=NULL, the *pfile_info structure will contain some info about
the current file
if szFileName!=NULL, the filemane string will be copied in szFileName
(fileNameBufferSize is the size of the buffer)
if extraField!=NULL, the extra field information will be copied in extraField
(extraFieldBufferSize is the size of the buffer).
This is the Central-header version of the extra field
if szComment!=NULL, the comment string of the file will be copied in szComment
(commentBufferSize is the size of the buffer)
*/
/** Addition for GDAL : START */
extern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64(unzFile file);
/** Addition for GDAL : END */
/***************************************************************************/
/* for reading the content of the current zipfile, you can open it, read data
from it, and close it (you can close it before reading all the file)
*/
extern int ZEXPORT unzOpenCurrentFile(unzFile file);
/*
Open for reading data the current file in the zipfile.
If there is no error, the return value is UNZ_OK.
*/
extern int ZEXPORT unzOpenCurrentFilePassword(unzFile file,
const char* password);
/*
Open for reading data the current file in the zipfile.
password is a crypting password
If there is no error, the return value is UNZ_OK.
*/
extern int ZEXPORT unzOpenCurrentFile2(unzFile file,
int* method,
int* level,
int raw);
/*
Same than unzOpenCurrentFile, but open for read raw the file (not uncompress)
if raw==1
*method will receive method of compression, *level will receive level of
compression
note : you can set level parameter as NULL (if you did not want known level,
but you CANNOT set method parameter as NULL
*/
extern int ZEXPORT unzOpenCurrentFile3(unzFile file,
int* method,
int* level,
int raw,
const char* password);
/*
Same than unzOpenCurrentFile, but open for read raw the file (not uncompress)
if raw==1
*method will receive method of compression, *level will receive level of
compression
note : you can set level parameter as NULL (if you did not want known level,
but you CANNOT set method parameter as NULL
*/
extern int ZEXPORT unzCloseCurrentFile(unzFile file);
/*
Close the file in zip opened with unzOpenCurrentFile
Return UNZ_CRCERROR if all the file was read but the CRC is not good
*/
extern int ZEXPORT unzReadCurrentFile(unzFile file,
voidp buf,
unsigned len);
/*
Read bytes from the current file (opened by unzOpenCurrentFile)
buf contain buffer where data must be copied
len the size of buf.
return the number of byte copied if some bytes are copied
return 0 if the end of file was reached
return <0 with error code if there is an error
(UNZ_ERRNO for IO error, or zLib error for uncompress error)
*/
extern z_off_t ZEXPORT unztell(unzFile file);
extern ZPOS64_T ZEXPORT unztell64(unzFile file);
/*
Give the current position in uncompressed data
*/
extern int ZEXPORT unzeof(unzFile file);
/*
return 1 if the end of file was reached, 0 elsewhere
*/
extern int ZEXPORT unzGetLocalExtrafield(unzFile file,
voidp buf,
unsigned len);
/*
Read extra field from the current file (opened by unzOpenCurrentFile)
This is the local-header version of the extra field (sometimes, there is
more info in the local-header version than in the central-header)
if buf==NULL, it return the size of the local extra field
|
| ︙ | ︙ |
Changes to compat/zlib/contrib/minizip/zip.c.
| ︙ | ︙ | |||
10 11 12 13 14 15 16 |
For more info read MiniZip_info.txt
Changes
Oct-2009 - Mathias Svensson - Remove old C style function prototypes
Oct-2009 - Mathias Svensson - Added Zip64 Support when creating new file archives
Oct-2009 - Mathias Svensson - Did some code cleanup and refactoring to get better overview of some functions.
Oct-2009 - Mathias Svensson - Added zipRemoveExtraInfoBlock to strip extra field data from its ZIP64 data
| | > < < | < < < | 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 |
For more info read MiniZip_info.txt
Changes
Oct-2009 - Mathias Svensson - Remove old C style function prototypes
Oct-2009 - Mathias Svensson - Added Zip64 Support when creating new file archives
Oct-2009 - Mathias Svensson - Did some code cleanup and refactoring to get better overview of some functions.
Oct-2009 - Mathias Svensson - Added zipRemoveExtraInfoBlock to strip extra field data from its ZIP64 data
It is used when recreating zip archive with RAW when deleting items from a zip.
ZIP64 data is automatically added to items that needs it, and existing ZIP64 data need to be removed.
Oct-2009 - Mathias Svensson - Added support for BZIP2 as compression mode (bzip2 lib is required)
Jan-2010 - back to unzip and minizip 1.0 name scheme, with compatibility layer
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <time.h>
#include "zlib.h"
#include "zip.h"
#ifdef STDC
# include <stddef.h>
#endif
#ifdef NO_ERRNO_H
extern int errno;
#else
# include <errno.h>
#endif
#ifndef local
# define local static
#endif
/* compile with -Dlocal if your debugger can't find static symbols */
#ifndef VERSIONMADEBY
# define VERSIONMADEBY (0x0) /* platform dependent */
#endif
#ifndef Z_BUFSIZE
#define Z_BUFSIZE (64*1024) //(16384)
#endif
#ifndef Z_MAXFILENAMEINZIP
#define Z_MAXFILENAMEINZIP (256)
#endif
#ifndef ALLOC
# define ALLOC(size) (malloc(size))
#endif
/*
#define SIZECENTRALDIRITEM (0x2e)
#define SIZEZIPLOCALHEADER (0x1e)
*/
/* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */
|
| ︙ | ︙ | |||
134 135 136 137 138 139 140 |
bz_stream bstream; /* bzLib stream structure for bziped */
#endif
int stream_initialised; /* 1 is stream is initialised */
uInt pos_in_buffered_data; /* last written byte in buffered_data */
ZPOS64_T pos_local_header; /* offset of the local header of the file
| | | | | | | < | < | | < | < | < | | 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 |
bz_stream bstream; /* bzLib stream structure for bziped */
#endif
int stream_initialised; /* 1 is stream is initialised */
uInt pos_in_buffered_data; /* last written byte in buffered_data */
ZPOS64_T pos_local_header; /* offset of the local header of the file
currently writing */
char* central_header; /* central header data for the current file */
uLong size_centralExtra;
uLong size_centralheader; /* size of the central header for cur file */
uLong size_centralExtraFree; /* Extra bytes allocated to the centralheader but that are not used */
uLong flag; /* flag of the file currently writing */
int method; /* compression method of file currently wr.*/
int raw; /* 1 for directly writing raw data */
Byte buffered_data[Z_BUFSIZE];/* buffer contain compressed data to be writ*/
uLong dosDate;
uLong crc32;
int encrypt;
int zip64; /* Add ZIP64 extended information in the extra field */
ZPOS64_T pos_zip64extrainfo;
ZPOS64_T totalCompressedData;
ZPOS64_T totalUncompressedData;
#ifndef NOCRYPT
unsigned long keys[3]; /* keys defining the pseudo-random sequence */
const z_crc_t* pcrc_32_tab;
unsigned crypt_header_size;
#endif
} curfile64_info;
typedef struct
{
zlib_filefunc64_32_def z_filefunc;
voidpf filestream; /* io structure of the zipfile */
linkedlist_data central_dir;/* datablock with central dir in construction*/
int in_opened_file_inzip; /* 1 if a file in the zip is currently writ.*/
curfile64_info ci; /* info on the file currently writing */
ZPOS64_T begin_pos; /* position of the beginning of the zipfile */
ZPOS64_T add_position_when_writing_offset;
ZPOS64_T number_entry;
#ifndef NO_ADDFILEINEXISTINGZIP
char *globalcomment;
#endif
} zip64_internal;
#ifndef NOCRYPT
#define INCLUDECRYPTINGCODE_IFCRYPTALLOWED
#include "crypt.h"
#endif
local linkedlist_datablock_internal* allocate_new_datablock(void) {
linkedlist_datablock_internal* ldi;
ldi = (linkedlist_datablock_internal*)
ALLOC(sizeof(linkedlist_datablock_internal));
if (ldi!=NULL)
{
ldi->next_datablock = NULL ;
ldi->filled_in_this_block = 0 ;
ldi->avail_in_this_block = SIZEDATA_INDATABLOCK ;
}
return ldi;
}
local void free_datablock(linkedlist_datablock_internal* ldi) {
while (ldi!=NULL)
{
linkedlist_datablock_internal* ldinext = ldi->next_datablock;
free(ldi);
ldi = ldinext;
}
}
local void init_linkedlist(linkedlist_data* ll) {
ll->first_block = ll->last_block = NULL;
}
local void free_linkedlist(linkedlist_data* ll) {
free_datablock(ll->first_block);
ll->first_block = ll->last_block = NULL;
}
local int add_data_in_datablock(linkedlist_data* ll, const void* buf, uLong len) {
linkedlist_datablock_internal* ldi;
const unsigned char* from_copy;
if (ll==NULL)
return ZIP_INTERNALERROR;
if (ll->last_block == NULL)
{
ll->first_block = ll->last_block = allocate_new_datablock();
if (ll->first_block == NULL)
return ZIP_INTERNALERROR;
}
ldi = ll->last_block;
from_copy = (const unsigned char*)buf;
while (len>0)
{
uInt copy_this;
uInt i;
unsigned char* to_copy;
|
| ︙ | ︙ | |||
279 280 281 282 283 284 285 | #ifndef NO_ADDFILEINEXISTINGZIP /* =========================================================================== Inputs a long in LSB order to the given file nbByte == 1, 2 ,4 or 8 (byte, short or long, ZPOS64_T) */ | < | < | 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 |
#ifndef NO_ADDFILEINEXISTINGZIP
/* ===========================================================================
Inputs a long in LSB order to the given file
nbByte == 1, 2 ,4 or 8 (byte, short or long, ZPOS64_T)
*/
local int zip64local_putValue(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T x, int nbByte) {
unsigned char buf[8];
int n;
for (n = 0; n < nbByte; n++)
{
buf[n] = (unsigned char)(x & 0xff);
x >>= 8;
}
|
| ︙ | ︙ | |||
303 304 305 306 307 308 309 |
if (ZWRITE64(*pzlib_filefunc_def,filestream,buf,(uLong)nbByte)!=(uLong)nbByte)
return ZIP_ERRNO;
else
return ZIP_OK;
}
| < | < | < < < | < < < | < < < | < | 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 |
if (ZWRITE64(*pzlib_filefunc_def,filestream,buf,(uLong)nbByte)!=(uLong)nbByte)
return ZIP_ERRNO;
else
return ZIP_OK;
}
local void zip64local_putValue_inmemory (void* dest, ZPOS64_T x, int nbByte) {
unsigned char* buf=(unsigned char*)dest;
int n;
for (n = 0; n < nbByte; n++) {
buf[n] = (unsigned char)(x & 0xff);
x >>= 8;
}
if (x != 0)
{ /* data overflow - hack for ZIP64 */
for (n = 0; n < nbByte; n++)
{
buf[n] = 0xff;
}
}
}
/****************************************************************************/
local uLong zip64local_TmzDateToDosDate(const tm_zip* ptm) {
uLong year = (uLong)ptm->tm_year;
if (year>=1980)
year-=1980;
else if (year>=80)
year-=80;
return
(uLong) (((uLong)(ptm->tm_mday) + (32 * (uLong)(ptm->tm_mon+1)) + (512 * year)) << 16) |
(((uLong)ptm->tm_sec/2) + (32 * (uLong)ptm->tm_min) + (2048 * (uLong)ptm->tm_hour));
}
/****************************************************************************/
local int zip64local_getByte(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, int* pi) {
unsigned char c;
int err = (int)ZREAD64(*pzlib_filefunc_def,filestream,&c,1);
if (err==1)
{
*pi = (int)c;
return ZIP_OK;
}
else
{
if (ZERROR64(*pzlib_filefunc_def,filestream))
return ZIP_ERRNO;
else
return ZIP_EOF;
}
}
/* ===========================================================================
Reads a long in LSB order from the given gz_stream. Sets
*/
local int zip64local_getShort(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong* pX) {
uLong x ;
int i = 0;
int err;
err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);
x = (uLong)i;
if (err==ZIP_OK)
err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);
x += ((uLong)i)<<8;
if (err==ZIP_OK)
*pX = x;
else
*pX = 0;
return err;
}
local int zip64local_getLong(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong* pX) {
uLong x ;
int i = 0;
int err;
err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);
x = (uLong)i;
|
| ︙ | ︙ | |||
416 417 418 419 420 421 422 |
if (err==ZIP_OK)
*pX = x;
else
*pX = 0;
return err;
}
| < < | < | 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 |
if (err==ZIP_OK)
*pX = x;
else
*pX = 0;
return err;
}
local int zip64local_getLong64(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T *pX) {
ZPOS64_T x;
int i = 0;
int err;
err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);
x = (ZPOS64_T)i;
|
| ︙ | ︙ | |||
471 472 473 474 475 476 477 |
#ifndef BUFREADCOMMENT
#define BUFREADCOMMENT (0x400)
#endif
/*
Locate the Central directory of a zipfile (at the end, just before
the global comment)
*/
| < < | < | 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 |
#ifndef BUFREADCOMMENT
#define BUFREADCOMMENT (0x400)
#endif
/*
Locate the Central directory of a zipfile (at the end, just before
the global comment)
*/
local ZPOS64_T zip64local_SearchCentralDir(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream) {
unsigned char* buf;
ZPOS64_T uSizeFile;
ZPOS64_T uBackRead;
ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */
ZPOS64_T uPosFound=0;
if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0)
|
| ︙ | ︙ | |||
525 526 527 528 529 530 531 |
uPosFound = uReadPos+(unsigned)i;
break;
}
if (uPosFound!=0)
break;
}
| | < < | < | 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 |
uPosFound = uReadPos+(unsigned)i;
break;
}
if (uPosFound!=0)
break;
}
free(buf);
return uPosFound;
}
/*
Locate the End of Zip64 Central directory locator and from there find the CD of a zipfile (at the end, just before
the global comment)
*/
local ZPOS64_T zip64local_SearchCentralDir64(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream) {
unsigned char* buf;
ZPOS64_T uSizeFile;
ZPOS64_T uBackRead;
ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */
ZPOS64_T uPosFound=0;
uLong uL;
ZPOS64_T relativeOffset;
|
| ︙ | ︙ | |||
591 592 593 594 595 596 597 |
}
}
if (uPosFound!=0)
break;
}
| | | 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 |
}
}
if (uPosFound!=0)
break;
}
free(buf);
if (uPosFound == 0)
return 0;
/* Zip64 end of central directory locator */
if (ZSEEK64(*pzlib_filefunc_def,filestream, uPosFound,ZLIB_FILEFUNC_SEEK_SET)!=0)
return 0;
|
| ︙ | ︙ | |||
633 634 635 636 637 638 639 |
if (uL != 0x06064b50) // signature of 'Zip64 end of central directory'
return 0;
return relativeOffset;
}
| | < | | | 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 |
if (uL != 0x06064b50) // signature of 'Zip64 end of central directory'
return 0;
return relativeOffset;
}
local int LoadCentralDirectoryRecord(zip64_internal* pziinit) {
int err=ZIP_OK;
ZPOS64_T byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/
ZPOS64_T size_central_dir; /* size of the central directory */
ZPOS64_T offset_central_dir; /* offset of start of central directory */
ZPOS64_T central_pos;
uLong uL;
uLong number_disk; /* number of the current dist, used for
spanning ZIP, unsupported, always 0*/
uLong number_disk_with_CD; /* number the the disk with central dir, used
for spanning ZIP, unsupported, always 0*/
ZPOS64_T number_entry;
ZPOS64_T number_entry_CD; /* total number of entries in
the central dir
(same than number_entry on nospan) */
uLong VersionMadeBy;
uLong VersionNeeded;
uLong size_comment;
|
| ︙ | ︙ | |||
826 827 828 829 830 831 832 |
err=ZIP_ERRNO;
if (err==ZIP_OK)
err = add_data_in_datablock(&pziinit->central_dir,buf_read, (uLong)read_this);
size_central_dir_to_read-=read_this;
}
| | | < | 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 |
err=ZIP_ERRNO;
if (err==ZIP_OK)
err = add_data_in_datablock(&pziinit->central_dir,buf_read, (uLong)read_this);
size_central_dir_to_read-=read_this;
}
free(buf_read);
}
pziinit->begin_pos = byte_before_the_zipfile;
pziinit->number_entry = number_entry_CD;
if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, offset_central_dir+byte_before_the_zipfile,ZLIB_FILEFUNC_SEEK_SET) != 0)
err=ZIP_ERRNO;
return err;
}
#endif /* !NO_ADDFILEINEXISTINGZIP*/
/************************************************************/
extern zipFile ZEXPORT zipOpen3(const void *pathname, int append, zipcharpc* globalcomment, zlib_filefunc64_32_def* pzlib_filefunc64_32_def) {
zip64_internal ziinit;
zip64_internal* zi;
int err=ZIP_OK;
ziinit.z_filefunc.zseek32_file = NULL;
ziinit.z_filefunc.ztell32_file = NULL;
if (pzlib_filefunc64_32_def==NULL)
|
| ︙ | ︙ | |||
901 902 903 904 905 906 907 |
*globalcomment = ziinit.globalcomment;
}
# endif /* !NO_ADDFILEINEXISTINGZIP*/
if (err != ZIP_OK)
{
# ifndef NO_ADDFILEINEXISTINGZIP
| | | | < | < | < | < | < | 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 |
*globalcomment = ziinit.globalcomment;
}
# endif /* !NO_ADDFILEINEXISTINGZIP*/
if (err != ZIP_OK)
{
# ifndef NO_ADDFILEINEXISTINGZIP
free(ziinit.globalcomment);
# endif /* !NO_ADDFILEINEXISTINGZIP*/
free(zi);
return NULL;
}
else
{
*zi = ziinit;
return (zipFile)zi;
}
}
extern zipFile ZEXPORT zipOpen2(const char *pathname, int append, zipcharpc* globalcomment, zlib_filefunc_def* pzlib_filefunc32_def) {
if (pzlib_filefunc32_def != NULL)
{
zlib_filefunc64_32_def zlib_filefunc64_32_def_fill;
fill_zlib_filefunc64_32_def_from_filefunc32(&zlib_filefunc64_32_def_fill,pzlib_filefunc32_def);
return zipOpen3(pathname, append, globalcomment, &zlib_filefunc64_32_def_fill);
}
else
return zipOpen3(pathname, append, globalcomment, NULL);
}
extern zipFile ZEXPORT zipOpen2_64(const void *pathname, int append, zipcharpc* globalcomment, zlib_filefunc64_def* pzlib_filefunc_def) {
if (pzlib_filefunc_def != NULL)
{
zlib_filefunc64_32_def zlib_filefunc64_32_def_fill;
zlib_filefunc64_32_def_fill.zfile_func64 = *pzlib_filefunc_def;
zlib_filefunc64_32_def_fill.ztell32_file = NULL;
zlib_filefunc64_32_def_fill.zseek32_file = NULL;
return zipOpen3(pathname, append, globalcomment, &zlib_filefunc64_32_def_fill);
}
else
return zipOpen3(pathname, append, globalcomment, NULL);
}
extern zipFile ZEXPORT zipOpen(const char* pathname, int append) {
return zipOpen3((const void*)pathname,append,NULL,NULL);
}
extern zipFile ZEXPORT zipOpen64(const void* pathname, int append) {
return zipOpen3(pathname,append,NULL,NULL);
}
local int Write_LocalFileHeader(zip64_internal* zi, const char* filename, uInt size_extrafield_local, const void* extrafield_local) {
/* write the local header */
int err;
uInt size_filename = (uInt)strlen(filename);
uInt size_extrafield = size_extrafield_local;
err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)LOCALHEADERMAGIC, 4);
|
| ︙ | ︙ | |||
1048 1049 1050 1051 1052 1053 1054 | NOTE. When writing RAW the ZIP64 extended information in extrafield_local and extrafield_global needs to be stripped before calling this function it can be done with zipRemoveExtraInfoBlock It is not done here because then we need to realloc a new buffer since parameters are 'const' and I want to minimize unnecessary allocations. */ | | | | | | | | < | 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 |
NOTE.
When writing RAW the ZIP64 extended information in extrafield_local and extrafield_global needs to be stripped
before calling this function it can be done with zipRemoveExtraInfoBlock
It is not done here because then we need to realloc a new buffer since parameters are 'const' and I want to minimize
unnecessary allocations.
*/
extern int ZEXPORT zipOpenNewFileInZip4_64(zipFile file, const char* filename, const zip_fileinfo* zipfi,
const void* extrafield_local, uInt size_extrafield_local,
const void* extrafield_global, uInt size_extrafield_global,
const char* comment, int method, int level, int raw,
int windowBits,int memLevel, int strategy,
const char* password, uLong crcForCrypting,
uLong versionMadeBy, uLong flagBase, int zip64) {
zip64_internal* zi;
uInt size_filename;
uInt size_comment;
uInt i;
int err = ZIP_OK;
# ifdef NOCRYPT
|
| ︙ | ︙ | |||
1258 1259 1260 1261 1262 1263 1264 |
# endif
if (err==Z_OK)
zi->in_opened_file_inzip = 1;
return err;
}
| | | | | | | | < | | | | | | | | | | | | < | | | | | | | < | | | | | | | < | | | | | | | | | < | | | | | | | | | | < | | | | | | | | | | < | | | | | | | < | 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 |
# endif
if (err==Z_OK)
zi->in_opened_file_inzip = 1;
return err;
}
extern int ZEXPORT zipOpenNewFileInZip4(zipFile file, const char* filename, const zip_fileinfo* zipfi,
const void* extrafield_local, uInt size_extrafield_local,
const void* extrafield_global, uInt size_extrafield_global,
const char* comment, int method, int level, int raw,
int windowBits,int memLevel, int strategy,
const char* password, uLong crcForCrypting,
uLong versionMadeBy, uLong flagBase) {
return zipOpenNewFileInZip4_64(file, filename, zipfi,
extrafield_local, size_extrafield_local,
extrafield_global, size_extrafield_global,
comment, method, level, raw,
windowBits, memLevel, strategy,
password, crcForCrypting, versionMadeBy, flagBase, 0);
}
extern int ZEXPORT zipOpenNewFileInZip3(zipFile file, const char* filename, const zip_fileinfo* zipfi,
const void* extrafield_local, uInt size_extrafield_local,
const void* extrafield_global, uInt size_extrafield_global,
const char* comment, int method, int level, int raw,
int windowBits,int memLevel, int strategy,
const char* password, uLong crcForCrypting) {
return zipOpenNewFileInZip4_64(file, filename, zipfi,
extrafield_local, size_extrafield_local,
extrafield_global, size_extrafield_global,
comment, method, level, raw,
windowBits, memLevel, strategy,
password, crcForCrypting, VERSIONMADEBY, 0, 0);
}
extern int ZEXPORT zipOpenNewFileInZip3_64(zipFile file, const char* filename, const zip_fileinfo* zipfi,
const void* extrafield_local, uInt size_extrafield_local,
const void* extrafield_global, uInt size_extrafield_global,
const char* comment, int method, int level, int raw,
int windowBits,int memLevel, int strategy,
const char* password, uLong crcForCrypting, int zip64) {
return zipOpenNewFileInZip4_64(file, filename, zipfi,
extrafield_local, size_extrafield_local,
extrafield_global, size_extrafield_global,
comment, method, level, raw,
windowBits, memLevel, strategy,
password, crcForCrypting, VERSIONMADEBY, 0, zip64);
}
extern int ZEXPORT zipOpenNewFileInZip2(zipFile file, const char* filename, const zip_fileinfo* zipfi,
const void* extrafield_local, uInt size_extrafield_local,
const void* extrafield_global, uInt size_extrafield_global,
const char* comment, int method, int level, int raw) {
return zipOpenNewFileInZip4_64(file, filename, zipfi,
extrafield_local, size_extrafield_local,
extrafield_global, size_extrafield_global,
comment, method, level, raw,
-MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY,
NULL, 0, VERSIONMADEBY, 0, 0);
}
extern int ZEXPORT zipOpenNewFileInZip2_64(zipFile file, const char* filename, const zip_fileinfo* zipfi,
const void* extrafield_local, uInt size_extrafield_local,
const void* extrafield_global, uInt size_extrafield_global,
const char* comment, int method, int level, int raw, int zip64) {
return zipOpenNewFileInZip4_64(file, filename, zipfi,
extrafield_local, size_extrafield_local,
extrafield_global, size_extrafield_global,
comment, method, level, raw,
-MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY,
NULL, 0, VERSIONMADEBY, 0, zip64);
}
extern int ZEXPORT zipOpenNewFileInZip64(zipFile file, const char* filename, const zip_fileinfo* zipfi,
const void* extrafield_local, uInt size_extrafield_local,
const void*extrafield_global, uInt size_extrafield_global,
const char* comment, int method, int level, int zip64) {
return zipOpenNewFileInZip4_64(file, filename, zipfi,
extrafield_local, size_extrafield_local,
extrafield_global, size_extrafield_global,
comment, method, level, 0,
-MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY,
NULL, 0, VERSIONMADEBY, 0, zip64);
}
extern int ZEXPORT zipOpenNewFileInZip(zipFile file, const char* filename, const zip_fileinfo* zipfi,
const void* extrafield_local, uInt size_extrafield_local,
const void*extrafield_global, uInt size_extrafield_global,
const char* comment, int method, int level) {
return zipOpenNewFileInZip4_64(file, filename, zipfi,
extrafield_local, size_extrafield_local,
extrafield_global, size_extrafield_global,
comment, method, level, 0,
-MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY,
NULL, 0, VERSIONMADEBY, 0, 0);
}
local int zip64FlushWriteBuffer(zip64_internal* zi) {
int err=ZIP_OK;
if (zi->ci.encrypt != 0)
{
#ifndef NOCRYPT
uInt i;
int t;
|
| ︙ | ︙ | |||
1395 1396 1397 1398 1399 1400 1401 |
zi->ci.pos_in_buffered_data = 0;
return err;
}
| | < | 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 |
zi->ci.pos_in_buffered_data = 0;
return err;
}
extern int ZEXPORT zipWriteInFileInZip(zipFile file, const void* buf, unsigned int len) {
zip64_internal* zi;
int err=ZIP_OK;
if (file == NULL)
return ZIP_PARAMERROR;
zi = (zip64_internal*)file;
|
| ︙ | ︙ | |||
1446 1447 1448 1449 1450 1451 1452 |
if(err == BZ_RUN_OK)
err = ZIP_OK;
}
else
#endif
{
| | < < < < < | 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 |
if(err == BZ_RUN_OK)
err = ZIP_OK;
}
else
#endif
{
zi->ci.stream.next_in = (Bytef*)(uintptr_t)buf;
zi->ci.stream.avail_in = len;
while ((err==ZIP_OK) && (zi->ci.stream.avail_in>0))
{
if (zi->ci.stream.avail_out == 0)
{
if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO)
err = ZIP_ERRNO;
zi->ci.stream.avail_out = (uInt)Z_BUFSIZE;
zi->ci.stream.next_out = zi->ci.buffered_data;
}
if(err != ZIP_OK)
break;
if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw))
{
uLong uTotalOutBefore = zi->ci.stream.total_out;
err=deflate(&zi->ci.stream, Z_NO_FLUSH);
zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - uTotalOutBefore) ;
}
else
{
uInt copy_this,i;
if (zi->ci.stream.avail_in < zi->ci.stream.avail_out)
|
| ︙ | ︙ | |||
1502 1503 1504 1505 1506 1507 1508 |
}
}// while(...)
}
return err;
}
| | < | < | 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 |
}
}// while(...)
}
return err;
}
extern int ZEXPORT zipCloseFileInZipRaw(zipFile file, uLong uncompressed_size, uLong crc32) {
return zipCloseFileInZipRaw64 (file, uncompressed_size, crc32);
}
extern int ZEXPORT zipCloseFileInZipRaw64(zipFile file, ZPOS64_T uncompressed_size, uLong crc32) {
zip64_internal* zi;
ZPOS64_T compressed_size;
uLong invalidValue = 0xffffffff;
unsigned datasize = 0;
int err=ZIP_OK;
if (file == NULL)
|
| ︙ | ︙ | |||
1743 1744 1745 1746 1747 1748 1749 |
zi->number_entry ++;
zi->in_opened_file_inzip = 0;
return err;
}
| | < | < | < | 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 1720 1721 1722 1723 1724 1725 1726 |
zi->number_entry ++;
zi->in_opened_file_inzip = 0;
return err;
}
extern int ZEXPORT zipCloseFileInZip(zipFile file) {
return zipCloseFileInZipRaw (file,0,0);
}
local int Write_Zip64EndOfCentralDirectoryLocator(zip64_internal* zi, ZPOS64_T zip64eocd_pos_inzip) {
int err = ZIP_OK;
ZPOS64_T pos = zip64eocd_pos_inzip - zi->add_position_when_writing_offset;
err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)ZIP64ENDLOCHEADERMAGIC,4);
/*num disks*/
if (err==ZIP_OK) /* number of the disk with the start of the central directory */
err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4);
/*relative offset*/
if (err==ZIP_OK) /* Relative offset to the Zip64EndOfCentralDirectory */
err = zip64local_putValue(&zi->z_filefunc,zi->filestream, pos,8);
/*total disks*/ /* Do not support spawning of disk so always say 1 here*/
if (err==ZIP_OK) /* number of the disk with the start of the central directory */
err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)1,4);
return err;
}
local int Write_Zip64EndOfCentralDirectoryRecord(zip64_internal* zi, uLong size_centraldir, ZPOS64_T centraldir_pos_inzip) {
int err = ZIP_OK;
uLong Zip64DataSize = 44;
err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)ZIP64ENDHEADERMAGIC,4);
if (err==ZIP_OK) /* size of this 'zip64 end of central directory' */
|
| ︙ | ︙ | |||
1809 1810 1811 1812 1813 1814 1815 |
if (err==ZIP_OK) /* offset of start of central directory with respect to the starting disk number */
{
ZPOS64_T pos = centraldir_pos_inzip - zi->add_position_when_writing_offset;
err = zip64local_putValue(&zi->z_filefunc,zi->filestream, (ZPOS64_T)pos,8);
}
return err;
}
| < | > | 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 |
if (err==ZIP_OK) /* offset of start of central directory with respect to the starting disk number */
{
ZPOS64_T pos = centraldir_pos_inzip - zi->add_position_when_writing_offset;
err = zip64local_putValue(&zi->z_filefunc,zi->filestream, (ZPOS64_T)pos,8);
}
return err;
}
local int Write_EndOfCentralDirectoryRecord(zip64_internal* zi, uLong size_centraldir, ZPOS64_T centraldir_pos_inzip) {
int err = ZIP_OK;
/*signature*/
err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)ENDHEADERMAGIC,4);
if (err==ZIP_OK) /* number of this disk */
err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,2);
|
| ︙ | ︙ | |||
1857 1858 1859 1860 1861 1862 1863 |
else
err = zip64local_putValue(&zi->z_filefunc,zi->filestream, (uLong)(centraldir_pos_inzip - zi->add_position_when_writing_offset),4);
}
return err;
}
| | < | < | 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 |
else
err = zip64local_putValue(&zi->z_filefunc,zi->filestream, (uLong)(centraldir_pos_inzip - zi->add_position_when_writing_offset),4);
}
return err;
}
local int Write_GlobalComment(zip64_internal* zi, const char* global_comment) {
int err = ZIP_OK;
uInt size_global_comment = 0;
if(global_comment != NULL)
size_global_comment = (uInt)strlen(global_comment);
err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_global_comment,2);
if (err == ZIP_OK && size_global_comment > 0)
{
if (ZWRITE64(zi->z_filefunc,zi->filestream, global_comment, size_global_comment) != size_global_comment)
err = ZIP_ERRNO;
}
return err;
}
extern int ZEXPORT zipClose(zipFile file, const char* global_comment) {
zip64_internal* zi;
int err = 0;
uLong size_centraldir = 0;
ZPOS64_T centraldir_pos_inzip;
ZPOS64_T pos;
if (file == NULL)
|
| ︙ | ︙ | |||
1937 1938 1939 1940 1941 1942 1943 |
err = Write_GlobalComment(zi, global_comment);
if (ZCLOSE64(zi->z_filefunc,zi->filestream) != 0)
if (err == ZIP_OK)
err = ZIP_ERRNO;
#ifndef NO_ADDFILEINEXISTINGZIP
| | | | < | | 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 |
err = Write_GlobalComment(zi, global_comment);
if (ZCLOSE64(zi->z_filefunc,zi->filestream) != 0)
if (err == ZIP_OK)
err = ZIP_ERRNO;
#ifndef NO_ADDFILEINEXISTINGZIP
free(zi->globalcomment);
#endif
free(zi);
return err;
}
extern int ZEXPORT zipRemoveExtraInfoBlock(char* pData, int* dataLen, short sHeader) {
char* p = pData;
int size = 0;
char* pNewHeader;
char* pTmp;
short header;
short dataSize;
int retVal = ZIP_OK;
if(pData == NULL || dataLen == NULL || *dataLen < 4)
return ZIP_PARAMERROR;
pNewHeader = (char*)ALLOC((unsigned)*dataLen);
pTmp = pNewHeader;
while(p < (pData + *dataLen))
{
|
| ︙ | ︙ | |||
1997 1998 1999 2000 2001 2002 2003 |
*dataLen = size;
retVal = ZIP_OK;
}
else
retVal = ZIP_ERRNO;
| | | 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 |
*dataLen = size;
retVal = ZIP_OK;
}
else
retVal = ZIP_ERRNO;
free(pNewHeader);
return retVal;
}
|
Changes to compat/zlib/contrib/minizip/zip.h.
| ︙ | ︙ | |||
109 110 111 112 113 114 115 | typedef const char* zipcharpc; #define APPEND_STATUS_CREATE (0) #define APPEND_STATUS_CREATEAFTER (1) #define APPEND_STATUS_ADDINZIP (2) | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | < | | | | | | | | | | | | | | | | | | < | | | | | | | | | | | | | | | | | | | < | | | | | | | | | | | | | | 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 |
typedef const char* zipcharpc;
#define APPEND_STATUS_CREATE (0)
#define APPEND_STATUS_CREATEAFTER (1)
#define APPEND_STATUS_ADDINZIP (2)
extern zipFile ZEXPORT zipOpen(const char *pathname, int append);
extern zipFile ZEXPORT zipOpen64(const void *pathname, int append);
/*
Create a zipfile.
pathname contain on Windows XP a filename like "c:\\zlib\\zlib113.zip" or on
an Unix computer "zlib/zlib113.zip".
if the file pathname exist and append==APPEND_STATUS_CREATEAFTER, the zip
will be created at the end of the file.
(useful if the file contain a self extractor code)
if the file pathname exist and append==APPEND_STATUS_ADDINZIP, we will
add files in existing zip (be sure you don't add file that doesn't exist)
If the zipfile cannot be opened, the return value is NULL.
Else, the return value is a zipFile Handle, usable with other function
of this zip package.
*/
/* Note : there is no delete function into a zipfile.
If you want delete file into a zipfile, you must open a zipfile, and create another
Of course, you can use RAW reading and writing to copy the file you did not want delete
*/
extern zipFile ZEXPORT zipOpen2(const char *pathname,
int append,
zipcharpc* globalcomment,
zlib_filefunc_def* pzlib_filefunc_def);
extern zipFile ZEXPORT zipOpen2_64(const void *pathname,
int append,
zipcharpc* globalcomment,
zlib_filefunc64_def* pzlib_filefunc_def);
extern zipFile ZEXPORT zipOpen3(const void *pathname,
int append,
zipcharpc* globalcomment,
zlib_filefunc64_32_def* pzlib_filefunc64_32_def);
extern int ZEXPORT zipOpenNewFileInZip(zipFile file,
const char* filename,
const zip_fileinfo* zipfi,
const void* extrafield_local,
uInt size_extrafield_local,
const void* extrafield_global,
uInt size_extrafield_global,
const char* comment,
int method,
int level);
extern int ZEXPORT zipOpenNewFileInZip64(zipFile file,
const char* filename,
const zip_fileinfo* zipfi,
const void* extrafield_local,
uInt size_extrafield_local,
const void* extrafield_global,
uInt size_extrafield_global,
const char* comment,
int method,
int level,
int zip64);
/*
Open a file in the ZIP for writing.
filename : the filename in zip (if NULL, '-' without quote will be used
*zipfi contain supplemental information
if extrafield_local!=NULL and size_extrafield_local>0, extrafield_local
contains the extrafield data the the local header
if extrafield_global!=NULL and size_extrafield_global>0, extrafield_global
contains the extrafield data the the local header
if comment != NULL, comment contain the comment string
method contain the compression method (0 for store, Z_DEFLATED for deflate)
level contain the level of compression (can be Z_DEFAULT_COMPRESSION)
zip64 is set to 1 if a zip64 extended information block should be added to the local file header.
this MUST be '1' if the uncompressed size is >= 0xffffffff.
*/
extern int ZEXPORT zipOpenNewFileInZip2(zipFile file,
const char* filename,
const zip_fileinfo* zipfi,
const void* extrafield_local,
uInt size_extrafield_local,
const void* extrafield_global,
uInt size_extrafield_global,
const char* comment,
int method,
int level,
int raw);
extern int ZEXPORT zipOpenNewFileInZip2_64(zipFile file,
const char* filename,
const zip_fileinfo* zipfi,
const void* extrafield_local,
uInt size_extrafield_local,
const void* extrafield_global,
uInt size_extrafield_global,
const char* comment,
int method,
int level,
int raw,
int zip64);
/*
Same than zipOpenNewFileInZip, except if raw=1, we write raw file
*/
extern int ZEXPORT zipOpenNewFileInZip3(zipFile file,
const char* filename,
const zip_fileinfo* zipfi,
const void* extrafield_local,
uInt size_extrafield_local,
const void* extrafield_global,
uInt size_extrafield_global,
const char* comment,
int method,
int level,
int raw,
int windowBits,
int memLevel,
int strategy,
const char* password,
uLong crcForCrypting);
extern int ZEXPORT zipOpenNewFileInZip3_64(zipFile file,
const char* filename,
const zip_fileinfo* zipfi,
const void* extrafield_local,
uInt size_extrafield_local,
const void* extrafield_global,
uInt size_extrafield_global,
const char* comment,
int method,
int level,
int raw,
int windowBits,
int memLevel,
int strategy,
const char* password,
uLong crcForCrypting,
int zip64);
/*
Same than zipOpenNewFileInZip2, except
windowBits,memLevel,,strategy : see parameter strategy in deflateInit2
password : crypting password (NULL for no crypting)
crcForCrypting : crc of file to compress (needed for crypting)
*/
extern int ZEXPORT zipOpenNewFileInZip4(zipFile file,
const char* filename,
const zip_fileinfo* zipfi,
const void* extrafield_local,
uInt size_extrafield_local,
const void* extrafield_global,
uInt size_extrafield_global,
const char* comment,
int method,
int level,
int raw,
int windowBits,
int memLevel,
int strategy,
const char* password,
uLong crcForCrypting,
uLong versionMadeBy,
uLong flagBase);
extern int ZEXPORT zipOpenNewFileInZip4_64(zipFile file,
const char* filename,
const zip_fileinfo* zipfi,
const void* extrafield_local,
uInt size_extrafield_local,
const void* extrafield_global,
uInt size_extrafield_global,
const char* comment,
int method,
int level,
int raw,
int windowBits,
int memLevel,
int strategy,
const char* password,
uLong crcForCrypting,
uLong versionMadeBy,
uLong flagBase,
int zip64);
/*
Same than zipOpenNewFileInZip4, except
versionMadeBy : value for Version made by field
flag : value for flag field (compression level info will be added)
*/
extern int ZEXPORT zipWriteInFileInZip(zipFile file,
const void* buf,
unsigned len);
/*
Write data in the zipfile
*/
extern int ZEXPORT zipCloseFileInZip(zipFile file);
/*
Close the current file in the zipfile
*/
extern int ZEXPORT zipCloseFileInZipRaw(zipFile file,
uLong uncompressed_size,
uLong crc32);
extern int ZEXPORT zipCloseFileInZipRaw64(zipFile file,
ZPOS64_T uncompressed_size,
uLong crc32);
/*
Close the current file in the zipfile, for file opened with
parameter raw=1 in zipOpenNewFileInZip2
uncompressed_size and crc32 are value for the uncompressed size
*/
extern int ZEXPORT zipClose(zipFile file,
const char* global_comment);
/*
Close the zipfile
*/
extern int ZEXPORT zipRemoveExtraInfoBlock(char* pData, int* dataLen, short sHeader);
/*
zipRemoveExtraInfoBlock - Added by Mathias Svensson
Remove extra information block from a extra information data for the local file header or central directory header
It is needed to remove ZIP64 extra information blocks when before data is written if using RAW mode.
|
| ︙ | ︙ |
Changes to compat/zlib/contrib/pascal/zlibpas.pas.
1 2 3 4 5 6 7 8 9 10 11 12 | (* zlibpas -- Pascal interface to the zlib data compression library * * Copyright (C) 2003 Cosmin Truta. * Derived from original sources by Bob Dellaca. * For conditions of distribution and use, see copyright notice in readme.txt *) unit zlibpas; interface const | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
(* zlibpas -- Pascal interface to the zlib data compression library
*
* Copyright (C) 2003 Cosmin Truta.
* Derived from original sources by Bob Dellaca.
* For conditions of distribution and use, see copyright notice in readme.txt
*)
unit zlibpas;
interface
const
ZLIB_VERSION = '1.3.0';
ZLIB_VERNUM = $12a0;
type
alloc_func = function(opaque: Pointer; items, size: Integer): Pointer;
cdecl;
free_func = procedure(opaque, address: Pointer);
cdecl;
|
| ︙ | ︙ |
Changes to compat/zlib/contrib/puff/README.
| ︙ | ︙ | |||
34 35 36 37 38 39 40 |
unsigned char *source, /* pointer to source data pointer */
unsigned long *sourcelen); /* amount of input available */
Then you can call puff() to decompress a deflate stream that is in memory in
its entirety at source, to a sufficiently sized block of memory for the
decompressed data at dest. puff() is the only external symbol in puff.c The
only C library functions that puff.c needs are setjmp() and longjmp(), which
| | | 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
unsigned char *source, /* pointer to source data pointer */
unsigned long *sourcelen); /* amount of input available */
Then you can call puff() to decompress a deflate stream that is in memory in
its entirety at source, to a sufficiently sized block of memory for the
decompressed data at dest. puff() is the only external symbol in puff.c The
only C library functions that puff.c needs are setjmp() and longjmp(), which
are used to simplify error checking in the code to improve readability. puff.c
does no memory allocation, and uses less than 2K bytes off of the stack.
If destlen is not enough space for the uncompressed data, then inflate will
return an error without writing more than destlen bytes. Note that this means
that in order to decompress the deflate data successfully, you need to know
the size of the uncompressed data ahead of time.
|
| ︙ | ︙ |
Changes to compat/zlib/contrib/puff/puff.c.
| ︙ | ︙ | |||
39 40 41 42 43 44 45 | * - Simplify offs[] index in construct() * - Add input size and checking, using longjmp() to * maintain easy readability * - Use short data type for large arrays * - Use pointers instead of long to specify source and * destination sizes to avoid arbitrary 4 GB limits * 1.2 17 Mar 2002 - Add faster version of decode(), doubles speed (!), | | | 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | * - Simplify offs[] index in construct() * - Add input size and checking, using longjmp() to * maintain easy readability * - Use short data type for large arrays * - Use pointers instead of long to specify source and * destination sizes to avoid arbitrary 4 GB limits * 1.2 17 Mar 2002 - Add faster version of decode(), doubles speed (!), * but leave simple version for readability * - Make sure invalid distances detected if pointers * are 16 bits * - Fix fixed codes table error * - Provide a scanning mode for determining size of * uncompressed data * 1.3 20 Mar 2002 - Go back to lengths for puff() parameters [Gailly] * - Add a puff.h file for the interface |
| ︙ | ︙ | |||
620 621 622 623 624 625 626 | * - If there are only literal codes and no lengths, then there are no distance * codes. This is represented by one distance code with zero bits. * * - The list of up to 286 length/literal lengths and up to 30 distance lengths * are themselves compressed using Huffman codes and run-length encoding. In * the list of code lengths, a 0 symbol means no code, a 1..15 symbol means * that length, and the symbols 16, 17, and 18 are run-length instructions. | | | 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 | * - If there are only literal codes and no lengths, then there are no distance * codes. This is represented by one distance code with zero bits. * * - The list of up to 286 length/literal lengths and up to 30 distance lengths * are themselves compressed using Huffman codes and run-length encoding. In * the list of code lengths, a 0 symbol means no code, a 1..15 symbol means * that length, and the symbols 16, 17, and 18 are run-length instructions. * Each of 16, 17, and 18 are followed by extra bits to define the length of * the run. 16 copies the last length 3 to 6 times. 17 represents 3 to 10 * zero lengths, and 18 represents 11 to 138 zero lengths. Unused symbols * are common, hence the special coding for zero lengths. * * - The symbols for 0..18 are Huffman coded, and so that code must be * described first. This is simply a sequence of up to 19 three-bit values * representing no code (0) or the code length for that symbol (1..7). |
| ︙ | ︙ |
Changes to compat/zlib/contrib/puff/pufftest.c.
| ︙ | ︙ | |||
139 140 141 142 143 144 145 |
fprintf(stderr, "puff() failed with return code %d\n", ret);
else {
fprintf(stderr, "puff() succeeded uncompressing %lu bytes\n", destlen);
if (sourcelen < len) fprintf(stderr, "%lu compressed bytes unused\n",
len - sourcelen);
}
| | | 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 |
fprintf(stderr, "puff() failed with return code %d\n", ret);
else {
fprintf(stderr, "puff() succeeded uncompressing %lu bytes\n", destlen);
if (sourcelen < len) fprintf(stderr, "%lu compressed bytes unused\n",
len - sourcelen);
}
/* if requested, inflate again and write decompressed data to stdout */
if (put && ret == 0) {
if (fail)
destlen >>= 1;
dest = malloc(destlen);
if (dest == NULL) {
fprintf(stderr, "memory allocation failure\n");
free(source);
|
| ︙ | ︙ |
Changes to compat/zlib/contrib/testzlib/testzlib.c.
| ︙ | ︙ | |||
165 166 167 168 169 170 171 |
}
if (ReadFileMemory(argv[1],&lFileSize,&FilePtr)==0)
{
printf("error reading %s\n",argv[1]);
return 1;
}
| | | 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 |
}
if (ReadFileMemory(argv[1],&lFileSize,&FilePtr)==0)
{
printf("error reading %s\n",argv[1]);
return 1;
}
else printf("file %s read, %ld bytes\n",argv[1],lFileSize);
if (argc>=3)
BlockSizeCompress=atol(argv[2]);
if (argc>=4)
BlockSizeUncompress=atol(argv[3]);
|
| ︙ | ︙ |
Changes to compat/zlib/contrib/untgz/untgz.c.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | /* * untgz.c -- Display contents and extract files from a gzip'd TAR file * * written by Pedro A. Aranda Gutierrez <paag@tid.es> * adaptation to Unix by Jean-loup Gailly <jloup@gzip.org> * various fixes by Cosmin Truta <cosmint@cs.ubbcluj.ro> */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #include <errno.h> #include "zlib.h" | > > > > > > > > > > > > > > > > | < < < < < | > > | 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 | /* * untgz.c -- Display contents and extract files from a gzip'd TAR file * * written by Pedro A. Aranda Gutierrez <paag@tid.es> * adaptation to Unix by Jean-loup Gailly <jloup@gzip.org> * various fixes by Cosmin Truta <cosmint@cs.ubbcluj.ro> * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #include <errno.h> #include "zlib.h" #ifdef _WIN32 # include <direct.h> # include <io.h> # include <windows.h> # ifndef F_OK # define F_OK 0 # endif # define mkdir(dirname,mode) _mkdir(dirname) # ifdef _MSC_VER # define access(path,mode) _access(path,mode) # define chmod(path,mode) _chmod(path,mode) # define strdup(str) _strdup(str) # endif #else # include <sys/stat.h> # include <unistd.h> # include <utime.h> #endif /* values used in typeflag field */ #define REGTYPE '0' /* regular file */ |
| ︙ | ︙ | |||
98 99 100 101 102 103 104 |
char *fname;
int mode;
time_t time;
};
enum { TGZ_EXTRACT, TGZ_LIST, TGZ_INVALID };
| | < < < < < < | < | < < | < < | < < | < | 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 |
char *fname;
int mode;
time_t time;
};
enum { TGZ_EXTRACT, TGZ_LIST, TGZ_INVALID };
char *prog;
void error(const char *msg)
{
fprintf(stderr, "%s: %s\n", prog, msg);
exit(1);
}
const char *TGZsuffix[] = { "\0", ".tar", ".tar.gz", ".taz", ".tgz", NULL };
/* return the file name of the TGZ archive */
/* or NULL if it does not exist */
char *TGZfname (const char *arcname)
|
| ︙ | ︙ | |||
201 202 203 204 205 206 207 |
}
/* set file time */
int setfiletime (char *fname,time_t ftime)
{
| | | 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 |
}
/* set file time */
int setfiletime (char *fname,time_t ftime)
{
#ifdef _WIN32
static int isWinNT = -1;
SYSTEMTIME st;
FILETIME locft, modft;
struct tm *loctm;
HANDLE hFile;
int result;
|
| ︙ | ︙ | |||
586 587 588 589 590 591 592 |
printf("Usage: untgz file.tgz extract all files\n"
" untgz file.tgz fname ... extract selected files\n"
" untgz -l file.tgz list archive contents\n"
" untgz -h display this help\n");
exit(exitval);
}
| < < < < < < | | 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 |
printf("Usage: untgz file.tgz extract all files\n"
" untgz file.tgz fname ... extract selected files\n"
" untgz -l file.tgz list archive contents\n"
" untgz -h display this help\n");
exit(exitval);
}
/* ============================================================ */
#if defined(WIN32) && defined(__GNUC__)
int _CRT_glob = 0; /* disable argument globbing in MinGW */
#endif
int main(int argc,char **argv)
{
int action = TGZ_EXTRACT;
int arg = 1;
char *TGZfile;
gzFile f;
prog = strrchr(argv[0],'\\');
if (prog == NULL)
{
prog = strrchr(argv[0],'/');
if (prog == NULL)
{
|
| ︙ | ︙ |
Changes to compat/zlib/contrib/vstudio/readme.txt.
|
| | < < < | 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 | Building instructions for the DLL versions of Zlib 1.3.0 ======================================================== This directory contains projects that build zlib and minizip using Microsoft Visual C++ 9.0/10.0. You don't need to build these projects yourself. You can download the binaries from: http://www.winimage.com/zLibDll More information can be found at this site. Build instructions for Visual Studio 2008 (32 bits or 64 bits) -------------------------------------------------------------- - Decompress current zlib, including all contrib/* files - Open contrib\vstudio\vc9\zlibvc.sln with Microsoft Visual C++ 2008 - Or run: vcbuild /rebuild contrib\vstudio\vc9\zlibvc.sln "Release|Win32" Build instructions for Visual Studio 2010 (32 bits or 64 bits) -------------------------------------------------------------- - Decompress current zlib, including all contrib/* files - Open contrib\vstudio\vc10\zlibvc.sln with Microsoft Visual C++ 2010 |
| ︙ | ︙ |
Changes to compat/zlib/contrib/vstudio/vc10/miniunz.vcxproj.filters.
1 2 3 4 5 |
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{048af943-022b-4db6-beeb-a54c34774ee2}</UniqueIdentifier>
| | | 1 2 3 4 5 6 7 8 9 10 11 12 13 |
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{048af943-022b-4db6-beeb-a54c34774ee2}</UniqueIdentifier>
<Extensions>cpp;c;cxx;def;odl;idl;hpj;bat</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{c1d600d2-888f-4aea-b73e-8b0dd9befa0c}</UniqueIdentifier>
<Extensions>h;hpp;hxx;hm;inl;inc</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{0844199a-966b-4f19-81db-1e0125e141b9}</UniqueIdentifier>
|
| ︙ | ︙ |
Changes to compat/zlib/contrib/vstudio/vc10/minizip.vcxproj.filters.
1 2 3 4 5 |
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{c0419b40-bf50-40da-b153-ff74215b79de}</UniqueIdentifier>
| | | 1 2 3 4 5 6 7 8 9 10 11 12 13 |
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{c0419b40-bf50-40da-b153-ff74215b79de}</UniqueIdentifier>
<Extensions>cpp;c;cxx;def;odl;idl;hpj;bat</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{bb87b070-735b-478e-92ce-7383abb2f36c}</UniqueIdentifier>
<Extensions>h;hpp;hxx;hm;inl;inc</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{f46ab6a6-548f-43cb-ae96-681abb5bd5db}</UniqueIdentifier>
|
| ︙ | ︙ |
Changes to compat/zlib/contrib/vstudio/vc10/testzlib.vcxproj.
| ︙ | ︙ | |||
177 178 179 180 181 182 183 |
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
| | | | 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 |
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;ZLIB_WINAPI;_DEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>true</MinimalRebuild>
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<PrecompiledHeader>
</PrecompiledHeader>
<AssemblerOutput>AssemblyAndSourceCode</AssemblerOutput>
<AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
</ClCompile>
<Link>
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)testzlib.exe</OutputFile>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>$(OutDir)testzlib.pdb</ProgramDatabaseFile>
<SubSystem>Console</SubSystem>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention>
</DataExecutionPrevention>
|
| ︙ | ︙ | |||
237 238 239 240 241 242 243 |
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<Optimization>MaxSpeed</Optimization>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<OmitFramePointers>true</OmitFramePointers>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
| | | | | | 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 |
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<Optimization>MaxSpeed</Optimization>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<OmitFramePointers>true</OmitFramePointers>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;ZLIB_WINAPI;NDEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking>
<PrecompiledHeader>
</PrecompiledHeader>
<AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<Link>
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)testzlib.exe</OutputFile>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention>
</DataExecutionPrevention>
<TargetMachine>MachineX86</TargetMachine>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;ZLIB_WINAPI;_DEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
</ClCompile>
<Link>
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Itanium'">
<Midl>
<TargetEnvironment>Itanium</TargetEnvironment>
</Midl>
<ClCompile>
|
| ︙ | ︙ | |||
348 349 350 351 352 353 354 |
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<TargetMachine>MachineIA64</TargetMachine>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
| | | | 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 |
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<TargetMachine>MachineIA64</TargetMachine>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;ZLIB_WINAPI;NDEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
</ClCompile>
<Link>
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Itanium'">
<Midl>
<TargetEnvironment>Itanium</TargetEnvironment>
</Midl>
<ClCompile>
|
| ︙ | ︙ | |||
394 395 396 397 398 399 400 |
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\..\adler32.c" />
<ClCompile Include="..\..\..\compress.c" />
<ClCompile Include="..\..\..\crc32.c" />
<ClCompile Include="..\..\..\deflate.c" />
<ClCompile Include="..\..\..\infback.c" />
| < < < < < < < < | 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 |
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\..\adler32.c" />
<ClCompile Include="..\..\..\compress.c" />
<ClCompile Include="..\..\..\crc32.c" />
<ClCompile Include="..\..\..\deflate.c" />
<ClCompile Include="..\..\..\infback.c" />
<ClCompile Include="..\..\..\inffast.c" />
<ClCompile Include="..\..\..\inflate.c" />
<ClCompile Include="..\..\..\inftrees.c" />
<ClCompile Include="..\..\testzlib\testzlib.c" />
<ClCompile Include="..\..\..\trees.c" />
<ClCompile Include="..\..\..\uncompr.c" />
<ClCompile Include="..\..\..\zutil.c" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
|
Changes to compat/zlib/contrib/vstudio/vc10/testzlib.vcxproj.filters.
1 2 3 4 5 |
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{c1f6a2e3-5da5-4955-8653-310d3efe05a9}</UniqueIdentifier>
| | | 1 2 3 4 5 6 7 8 9 10 11 12 13 |
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{c1f6a2e3-5da5-4955-8653-310d3efe05a9}</UniqueIdentifier>
<Extensions>cpp;c;cxx;def;odl;idl;hpj;bat</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{c2aaffdc-2c95-4d6f-8466-4bec5890af2c}</UniqueIdentifier>
<Extensions>h;hpp;hxx;hm;inl;inc</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{c274fe07-05f2-461c-964b-f6341e4e7eb5}</UniqueIdentifier>
|
| ︙ | ︙ | |||
26 27 28 29 30 31 32 |
</ClCompile>
<ClCompile Include="..\..\..\deflate.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\infback.c">
<Filter>Source Files</Filter>
</ClCompile>
| < < < | 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
</ClCompile>
<ClCompile Include="..\..\..\deflate.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\infback.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\inffast.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\inflate.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\inftrees.c">
|
| ︙ | ︙ |
Changes to compat/zlib/contrib/vstudio/vc10/testzlibdll.vcxproj.filters.
1 2 3 4 5 |
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{fa61a89f-93fc-4c89-b29e-36224b7592f4}</UniqueIdentifier>
| | | 1 2 3 4 5 6 7 8 9 10 11 12 13 |
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{fa61a89f-93fc-4c89-b29e-36224b7592f4}</UniqueIdentifier>
<Extensions>cpp;c;cxx;def;odl;idl;hpj;bat</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{d4b85da0-2ba2-4934-b57f-e2584e3848ee}</UniqueIdentifier>
<Extensions>h;hpp;hxx;hm;inl;inc</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{e573e075-00bd-4a7d-bd67-a8cc9bfc5aca}</UniqueIdentifier>
|
| ︙ | ︙ |
Changes to compat/zlib/contrib/vstudio/vc10/zlib.rc.
1 2 3 4 | #include <windows.h> #define IDR_VERSION1 1 IDR_VERSION1 VERSIONINFO MOVEABLE IMPURE LOADONCALL DISCARDABLE | | | | | | 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 |
#include <windows.h>
#define IDR_VERSION1 1
IDR_VERSION1 VERSIONINFO MOVEABLE IMPURE LOADONCALL DISCARDABLE
FILEVERSION 1, 3, 0, 0
PRODUCTVERSION 1, 3, 0, 0
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
FILEFLAGS 0
FILEOS VOS_DOS_WINDOWS32
FILETYPE VFT_DLL
FILESUBTYPE 0 // not used
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904E4"
//language ID = U.S. English, char set = Windows, Multilingual
BEGIN
VALUE "FileDescription", "zlib data compression and ZIP file I/O library\0"
VALUE "FileVersion", "1.3.0\0"
VALUE "InternalName", "zlib\0"
VALUE "OriginalFilename", "zlibwapi.dll\0"
VALUE "ProductName", "ZLib.DLL\0"
VALUE "Comments","DLL support by Alessandro Iacopetti & Gilles Vollant\0"
VALUE "LegalCopyright", "(C) 1995-2023 Jean-loup Gailly & Mark Adler\0"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x0409, 1252
END
END
|
Changes to compat/zlib/contrib/vstudio/vc10/zlibstat.vcxproj.
| ︙ | ︙ | |||
156 157 158 159 160 161 162 |
<CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Release|x64'">AllRules.ruleset</CodeAnalysisRuleSet>
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<Optimization>Disabled</Optimization>
| | | 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 |
<CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Release|x64'">AllRules.ruleset</CodeAnalysisRuleSet>
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ExceptionHandling>
</ExceptionHandling>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<PrecompiledHeaderOutputFile>$(IntDir)zlibstat.pch</PrecompiledHeaderOutputFile>
<AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
|
| ︙ | ︙ | |||
178 179 180 181 182 183 184 |
<Culture>0x040c</Culture>
</ResourceCompile>
<Lib>
<AdditionalOptions>/MACHINE:X86 /NODEFAULTLIB %(AdditionalOptions)</AdditionalOptions>
<OutputFile>$(OutDir)zlibstat.lib</OutputFile>
<SuppressStartupBanner>true</SuppressStartupBanner>
</Lib>
| < < < < | | | < < < < | | 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 |
<Culture>0x040c</Culture>
</ResourceCompile>
<Lib>
<AdditionalOptions>/MACHINE:X86 /NODEFAULTLIB %(AdditionalOptions)</AdditionalOptions>
<OutputFile>$(OutDir)zlibstat.lib</OutputFile>
<SuppressStartupBanner>true</SuppressStartupBanner>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<ExceptionHandling>
</ExceptionHandling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking>
<PrecompiledHeaderOutputFile>$(IntDir)zlibstat.pch</PrecompiledHeaderOutputFile>
<AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
<ObjectFileName>$(IntDir)</ObjectFileName>
<ProgramDataBaseFileName>$(OutDir)</ProgramDataBaseFileName>
<WarningLevel>Level3</WarningLevel>
<SuppressStartupBanner>true</SuppressStartupBanner>
</ClCompile>
<ResourceCompile>
<Culture>0x040c</Culture>
</ResourceCompile>
<Lib>
<AdditionalOptions>/MACHINE:X86 /NODEFAULTLIB %(AdditionalOptions)</AdditionalOptions>
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)zlibstat.lib</OutputFile>
<SuppressStartupBanner>true</SuppressStartupBanner>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseWithoutAsm|Win32'">
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<ExceptionHandling>
</ExceptionHandling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking>
|
| ︙ | ︙ | |||
248 249 250 251 252 253 254 |
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Midl>
<TargetEnvironment>X64</TargetEnvironment>
</Midl>
<ClCompile>
<Optimization>Disabled</Optimization>
| | | 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 |
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Midl>
<TargetEnvironment>X64</TargetEnvironment>
</Midl>
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ExceptionHandling>
</ExceptionHandling>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<PrecompiledHeaderOutputFile>$(IntDir)zlibstat.pch</PrecompiledHeaderOutputFile>
<AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
|
| ︙ | ︙ | |||
270 271 272 273 274 275 276 |
<Culture>0x040c</Culture>
</ResourceCompile>
<Lib>
<AdditionalOptions>/MACHINE:AMD64 /NODEFAULTLIB %(AdditionalOptions)</AdditionalOptions>
<OutputFile>$(OutDir)zlibstat.lib</OutputFile>
<SuppressStartupBanner>true</SuppressStartupBanner>
</Lib>
| < < < < | | 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 |
<Culture>0x040c</Culture>
</ResourceCompile>
<Lib>
<AdditionalOptions>/MACHINE:AMD64 /NODEFAULTLIB %(AdditionalOptions)</AdditionalOptions>
<OutputFile>$(OutDir)zlibstat.lib</OutputFile>
<SuppressStartupBanner>true</SuppressStartupBanner>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Itanium'">
<Midl>
<TargetEnvironment>Itanium</TargetEnvironment>
</Midl>
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ExceptionHandling>
</ExceptionHandling>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<PrecompiledHeaderOutputFile>$(IntDir)zlibstat.pch</PrecompiledHeaderOutputFile>
<AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
|
| ︙ | ︙ | |||
310 311 312 313 314 315 316 |
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Midl>
<TargetEnvironment>X64</TargetEnvironment>
</Midl>
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
| | | | < < < < | | 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 |
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Midl>
<TargetEnvironment>X64</TargetEnvironment>
</Midl>
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<ExceptionHandling>
</ExceptionHandling>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking>
<PrecompiledHeaderOutputFile>$(IntDir)zlibstat.pch</PrecompiledHeaderOutputFile>
<AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
<ObjectFileName>$(IntDir)</ObjectFileName>
<ProgramDataBaseFileName>$(OutDir)</ProgramDataBaseFileName>
<WarningLevel>Level3</WarningLevel>
<SuppressStartupBanner>true</SuppressStartupBanner>
</ClCompile>
<ResourceCompile>
<Culture>0x040c</Culture>
</ResourceCompile>
<Lib>
<AdditionalOptions>/MACHINE:AMD64 /NODEFAULTLIB %(AdditionalOptions)</AdditionalOptions>
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)zlibstat.lib</OutputFile>
<SuppressStartupBanner>true</SuppressStartupBanner>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Itanium'">
<Midl>
<TargetEnvironment>Itanium</TargetEnvironment>
</Midl>
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<ExceptionHandling>
</ExceptionHandling>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking>
|
| ︙ | ︙ | |||
375 376 377 378 379 380 381 |
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseWithoutAsm|x64'">
<Midl>
<TargetEnvironment>X64</TargetEnvironment>
</Midl>
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
| | | 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 |
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseWithoutAsm|x64'">
<Midl>
<TargetEnvironment>X64</TargetEnvironment>
</Midl>
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<ExceptionHandling>
</ExceptionHandling>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking>
|
| ︙ | ︙ | |||
405 406 407 408 409 410 411 |
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseWithoutAsm|Itanium'">
<Midl>
<TargetEnvironment>Itanium</TargetEnvironment>
</Midl>
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
| | | 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 |
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseWithoutAsm|Itanium'">
<Midl>
<TargetEnvironment>Itanium</TargetEnvironment>
</Midl>
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<ExceptionHandling>
</ExceptionHandling>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking>
|
| ︙ | ︙ | |||
439 440 441 442 443 444 445 |
<ClCompile Include="..\..\..\crc32.c" />
<ClCompile Include="..\..\..\deflate.c" />
<ClCompile Include="..\..\..\gzclose.c" />
<ClCompile Include="..\..\..\gzlib.c" />
<ClCompile Include="..\..\..\gzread.c" />
<ClCompile Include="..\..\..\gzwrite.c" />
<ClCompile Include="..\..\..\infback.c" />
| < < < < < < < < | 423 424 425 426 427 428 429 430 431 432 433 434 435 436 |
<ClCompile Include="..\..\..\crc32.c" />
<ClCompile Include="..\..\..\deflate.c" />
<ClCompile Include="..\..\..\gzclose.c" />
<ClCompile Include="..\..\..\gzlib.c" />
<ClCompile Include="..\..\..\gzread.c" />
<ClCompile Include="..\..\..\gzwrite.c" />
<ClCompile Include="..\..\..\infback.c" />
<ClCompile Include="..\..\..\inffast.c" />
<ClCompile Include="..\..\..\inflate.c" />
<ClCompile Include="..\..\..\inftrees.c" />
<ClCompile Include="..\..\minizip\ioapi.c" />
<ClCompile Include="..\..\..\trees.c" />
<ClCompile Include="..\..\..\uncompr.c" />
<ClCompile Include="..\..\minizip\unzip.c" />
|
| ︙ | ︙ |
Changes to compat/zlib/contrib/vstudio/vc10/zlibstat.vcxproj.filters.
| ︙ | ︙ | |||
29 30 31 32 33 34 35 |
</ClCompile>
<ClCompile Include="..\..\..\gzwrite.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\infback.c">
<Filter>Source Files</Filter>
</ClCompile>
| < < < | 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
</ClCompile>
<ClCompile Include="..\..\..\gzwrite.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\infback.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\inffast.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\inflate.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\inftrees.c">
|
| ︙ | ︙ |
Changes to compat/zlib/contrib/vstudio/vc10/zlibvc.def.
1 2 3 | LIBRARY ; zlib data compression and ZIP file I/O library | | | 1 2 3 4 5 6 7 8 9 10 11 |
LIBRARY
; zlib data compression and ZIP file I/O library
VERSION 1.3
EXPORTS
adler32 @1
compress @2
crc32 @3
deflate @4
deflateCopy @5
|
| ︙ | ︙ |
Changes to compat/zlib/contrib/vstudio/vc10/zlibvc.vcxproj.
| ︙ | ︙ | |||
193 194 195 196 197 198 199 |
<MkTypLibCompatible>true</MkTypLibCompatible>
<SuppressStartupBanner>true</SuppressStartupBanner>
<TargetEnvironment>Win32</TargetEnvironment>
<TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName>
</Midl>
<ClCompile>
<Optimization>Disabled</Optimization>
| | | | < < < < | | 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 |
<MkTypLibCompatible>true</MkTypLibCompatible>
<SuppressStartupBanner>true</SuppressStartupBanner>
<TargetEnvironment>Win32</TargetEnvironment>
<TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName>
</Midl>
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ExceptionHandling>
</ExceptionHandling>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<PrecompiledHeaderOutputFile>$(IntDir)zlibvc.pch</PrecompiledHeaderOutputFile>
<AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
<ObjectFileName>$(IntDir)</ObjectFileName>
<ProgramDataBaseFileName>$(OutDir)</ProgramDataBaseFileName>
<BrowseInformation>
</BrowseInformation>
<WarningLevel>Level3</WarningLevel>
<SuppressStartupBanner>true</SuppressStartupBanner>
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x040c</Culture>
</ResourceCompile>
<Link>
<AdditionalOptions>/MACHINE:I386 %(AdditionalOptions)</AdditionalOptions>
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
<SuppressStartupBanner>true</SuppressStartupBanner>
<ModuleDefinitionFile>.\zlibvc.def</ModuleDefinitionFile>
<GenerateDebugInformation>true</GenerateDebugInformation>
<GenerateMapFile>true</GenerateMapFile>
<SubSystem>Windows</SubSystem>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention>
</DataExecutionPrevention>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseWithoutAsm|Win32'">
<Midl>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MkTypLibCompatible>true</MkTypLibCompatible>
<SuppressStartupBanner>true</SuppressStartupBanner>
<TargetEnvironment>Win32</TargetEnvironment>
<TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName>
</Midl>
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<ExceptionHandling>
</ExceptionHandling>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking>
|
| ︙ | ︙ | |||
284 285 286 287 288 289 290 |
<MkTypLibCompatible>true</MkTypLibCompatible>
<SuppressStartupBanner>true</SuppressStartupBanner>
<TargetEnvironment>Win32</TargetEnvironment>
<TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName>
</Midl>
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
| | | | 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 |
<MkTypLibCompatible>true</MkTypLibCompatible>
<SuppressStartupBanner>true</SuppressStartupBanner>
<TargetEnvironment>Win32</TargetEnvironment>
<TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName>
</Midl>
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<ExceptionHandling>
</ExceptionHandling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking>
<PrecompiledHeaderOutputFile>$(IntDir)zlibvc.pch</PrecompiledHeaderOutputFile>
|
| ︙ | ︙ | |||
308 309 310 311 312 313 314 |
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x040c</Culture>
</ResourceCompile>
<Link>
<AdditionalOptions>/MACHINE:I386 %(AdditionalOptions)</AdditionalOptions>
| | < < < < | | | < < < < | | 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 |
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x040c</Culture>
</ResourceCompile>
<Link>
<AdditionalOptions>/MACHINE:I386 %(AdditionalOptions)</AdditionalOptions>
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
<SuppressStartupBanner>true</SuppressStartupBanner>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<ModuleDefinitionFile>.\zlibvc.def</ModuleDefinitionFile>
<GenerateMapFile>true</GenerateMapFile>
<SubSystem>Windows</SubSystem>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention>
</DataExecutionPrevention>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Midl>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MkTypLibCompatible>true</MkTypLibCompatible>
<SuppressStartupBanner>true</SuppressStartupBanner>
<TargetEnvironment>X64</TargetEnvironment>
<TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName>
</Midl>
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ExceptionHandling>
</ExceptionHandling>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<PrecompiledHeaderOutputFile>$(IntDir)zlibvc.pch</PrecompiledHeaderOutputFile>
<AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
<ObjectFileName>$(IntDir)</ObjectFileName>
<ProgramDataBaseFileName>$(OutDir)</ProgramDataBaseFileName>
<BrowseInformation>
</BrowseInformation>
<WarningLevel>Level3</WarningLevel>
<SuppressStartupBanner>true</SuppressStartupBanner>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x040c</Culture>
</ResourceCompile>
<Link>
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
<SuppressStartupBanner>true</SuppressStartupBanner>
<ModuleDefinitionFile>.\zlibvc.def</ModuleDefinitionFile>
<GenerateDebugInformation>true</GenerateDebugInformation>
<GenerateMapFile>true</GenerateMapFile>
<SubSystem>Windows</SubSystem>
<TargetMachine>MachineX64</TargetMachine>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Itanium'">
<Midl>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MkTypLibCompatible>true</MkTypLibCompatible>
<SuppressStartupBanner>true</SuppressStartupBanner>
<TargetEnvironment>Itanium</TargetEnvironment>
<TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName>
</Midl>
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ExceptionHandling>
</ExceptionHandling>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<PrecompiledHeaderOutputFile>$(IntDir)zlibvc.pch</PrecompiledHeaderOutputFile>
<AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
|
| ︙ | ︙ | |||
420 421 422 423 424 425 426 |
<MkTypLibCompatible>true</MkTypLibCompatible>
<SuppressStartupBanner>true</SuppressStartupBanner>
<TargetEnvironment>X64</TargetEnvironment>
<TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName>
</Midl>
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
| | | 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 |
<MkTypLibCompatible>true</MkTypLibCompatible>
<SuppressStartupBanner>true</SuppressStartupBanner>
<TargetEnvironment>X64</TargetEnvironment>
<TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName>
</Midl>
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<ExceptionHandling>
</ExceptionHandling>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking>
|
| ︙ | ︙ | |||
461 462 463 464 465 466 467 |
<MkTypLibCompatible>true</MkTypLibCompatible>
<SuppressStartupBanner>true</SuppressStartupBanner>
<TargetEnvironment>Itanium</TargetEnvironment>
<TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName>
</Midl>
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
| | | 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 |
<MkTypLibCompatible>true</MkTypLibCompatible>
<SuppressStartupBanner>true</SuppressStartupBanner>
<TargetEnvironment>Itanium</TargetEnvironment>
<TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName>
</Midl>
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<ExceptionHandling>
</ExceptionHandling>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking>
|
| ︙ | ︙ | |||
506 507 508 509 510 511 512 |
<MkTypLibCompatible>true</MkTypLibCompatible>
<SuppressStartupBanner>true</SuppressStartupBanner>
<TargetEnvironment>X64</TargetEnvironment>
<TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName>
</Midl>
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
| | | | 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 |
<MkTypLibCompatible>true</MkTypLibCompatible>
<SuppressStartupBanner>true</SuppressStartupBanner>
<TargetEnvironment>X64</TargetEnvironment>
<TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName>
</Midl>
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<ExceptionHandling>
</ExceptionHandling>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking>
<PrecompiledHeaderOutputFile>$(IntDir)zlibvc.pch</PrecompiledHeaderOutputFile>
|
| ︙ | ︙ | |||
529 530 531 532 533 534 535 |
<SuppressStartupBanner>true</SuppressStartupBanner>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x040c</Culture>
</ResourceCompile>
<Link>
| | < < < < | | 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 |
<SuppressStartupBanner>true</SuppressStartupBanner>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x040c</Culture>
</ResourceCompile>
<Link>
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
<SuppressStartupBanner>true</SuppressStartupBanner>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<ModuleDefinitionFile>.\zlibvc.def</ModuleDefinitionFile>
<GenerateMapFile>true</GenerateMapFile>
<SubSystem>Windows</SubSystem>
<TargetMachine>MachineX64</TargetMachine>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Itanium'">
<Midl>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MkTypLibCompatible>true</MkTypLibCompatible>
<SuppressStartupBanner>true</SuppressStartupBanner>
<TargetEnvironment>Itanium</TargetEnvironment>
<TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName>
</Midl>
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<ExceptionHandling>
</ExceptionHandling>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking>
|
| ︙ | ︙ | |||
597 598 599 600 601 602 603 |
<ClCompile Include="..\..\..\crc32.c" />
<ClCompile Include="..\..\..\deflate.c" />
<ClCompile Include="..\..\..\gzclose.c" />
<ClCompile Include="..\..\..\gzlib.c" />
<ClCompile Include="..\..\..\gzread.c" />
<ClCompile Include="..\..\..\gzwrite.c" />
<ClCompile Include="..\..\..\infback.c" />
| < < < < < < < < | 581 582 583 584 585 586 587 588 589 590 591 592 593 594 |
<ClCompile Include="..\..\..\crc32.c" />
<ClCompile Include="..\..\..\deflate.c" />
<ClCompile Include="..\..\..\gzclose.c" />
<ClCompile Include="..\..\..\gzlib.c" />
<ClCompile Include="..\..\..\gzread.c" />
<ClCompile Include="..\..\..\gzwrite.c" />
<ClCompile Include="..\..\..\infback.c" />
<ClCompile Include="..\..\..\inffast.c" />
<ClCompile Include="..\..\..\inflate.c" />
<ClCompile Include="..\..\..\inftrees.c" />
<ClCompile Include="..\..\minizip\ioapi.c" />
<ClCompile Include="..\..\minizip\iowin32.c" />
<ClCompile Include="..\..\..\trees.c" />
<ClCompile Include="..\..\..\uncompr.c" />
|
| ︙ | ︙ |
Changes to compat/zlib/contrib/vstudio/vc10/zlibvc.vcxproj.filters.
| ︙ | ︙ | |||
38 39 40 41 42 43 44 |
</ClCompile>
<ClCompile Include="..\..\..\gzwrite.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\infback.c">
<Filter>Source Files</Filter>
</ClCompile>
| < < < | 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
</ClCompile>
<ClCompile Include="..\..\..\gzwrite.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\infback.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\inffast.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\inflate.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\inftrees.c">
|
| ︙ | ︙ |
Changes to compat/zlib/contrib/vstudio/vc11/testzlib.vcxproj.
| ︙ | ︙ | |||
183 184 185 186 187 188 189 |
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
| | | | 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 |
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;ZLIB_WINAPI;_DEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>true</MinimalRebuild>
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<PrecompiledHeader>
</PrecompiledHeader>
<AssemblerOutput>AssemblyAndSourceCode</AssemblerOutput>
<AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<Link>
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)testzlib.exe</OutputFile>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>$(OutDir)testzlib.pdb</ProgramDatabaseFile>
<SubSystem>Console</SubSystem>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention>
</DataExecutionPrevention>
|
| ︙ | ︙ | |||
243 244 245 246 247 248 249 |
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<Optimization>MaxSpeed</Optimization>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<OmitFramePointers>true</OmitFramePointers>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
| | | | | | 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 |
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<Optimization>MaxSpeed</Optimization>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<OmitFramePointers>true</OmitFramePointers>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;ZLIB_WINAPI;NDEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking>
<PrecompiledHeader>
</PrecompiledHeader>
<AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<Link>
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)testzlib.exe</OutputFile>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention>
</DataExecutionPrevention>
<TargetMachine>MachineX86</TargetMachine>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;ZLIB_WINAPI;_DEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
</ClCompile>
<Link>
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Itanium'">
<Midl>
<TargetEnvironment>Itanium</TargetEnvironment>
</Midl>
<ClCompile>
|
| ︙ | ︙ | |||
354 355 356 357 358 359 360 |
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<TargetMachine>MachineIA64</TargetMachine>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
| | | | 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 |
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<TargetMachine>MachineIA64</TargetMachine>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;ZLIB_WINAPI;NDEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
</ClCompile>
<Link>
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Itanium'">
<Midl>
<TargetEnvironment>Itanium</TargetEnvironment>
</Midl>
<ClCompile>
|
| ︙ | ︙ | |||
400 401 402 403 404 405 406 |
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\..\adler32.c" />
<ClCompile Include="..\..\..\compress.c" />
<ClCompile Include="..\..\..\crc32.c" />
<ClCompile Include="..\..\..\deflate.c" />
<ClCompile Include="..\..\..\infback.c" />
| < < < < < < < < | 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 |
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\..\adler32.c" />
<ClCompile Include="..\..\..\compress.c" />
<ClCompile Include="..\..\..\crc32.c" />
<ClCompile Include="..\..\..\deflate.c" />
<ClCompile Include="..\..\..\infback.c" />
<ClCompile Include="..\..\..\inffast.c" />
<ClCompile Include="..\..\..\inflate.c" />
<ClCompile Include="..\..\..\inftrees.c" />
<ClCompile Include="..\..\testzlib\testzlib.c" />
<ClCompile Include="..\..\..\trees.c" />
<ClCompile Include="..\..\..\uncompr.c" />
<ClCompile Include="..\..\..\zutil.c" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
|
Changes to compat/zlib/contrib/vstudio/vc11/zlib.rc.
1 2 3 4 | #include <windows.h> #define IDR_VERSION1 1 IDR_VERSION1 VERSIONINFO MOVEABLE IMPURE LOADONCALL DISCARDABLE | | | | | | 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 |
#include <windows.h>
#define IDR_VERSION1 1
IDR_VERSION1 VERSIONINFO MOVEABLE IMPURE LOADONCALL DISCARDABLE
FILEVERSION 1, 3, 0, 0
PRODUCTVERSION 1, 3, 0, 0
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
FILEFLAGS 0
FILEOS VOS_DOS_WINDOWS32
FILETYPE VFT_DLL
FILESUBTYPE 0 // not used
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904E4"
//language ID = U.S. English, char set = Windows, Multilingual
BEGIN
VALUE "FileDescription", "zlib data compression and ZIP file I/O library\0"
VALUE "FileVersion", "1.3.0\0"
VALUE "InternalName", "zlib\0"
VALUE "OriginalFilename", "zlibwapi.dll\0"
VALUE "ProductName", "ZLib.DLL\0"
VALUE "Comments","DLL support by Alessandro Iacopetti & Gilles Vollant\0"
VALUE "LegalCopyright", "(C) 1995-2023 Jean-loup Gailly & Mark Adler\0"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x0409, 1252
END
END
|
Changes to compat/zlib/contrib/vstudio/vc11/zlibstat.vcxproj.
| ︙ | ︙ | |||
163 164 165 166 167 168 169 |
<CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Release|x64'">AllRules.ruleset</CodeAnalysisRuleSet>
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<Optimization>Disabled</Optimization>
| | | 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 |
<CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Release|x64'">AllRules.ruleset</CodeAnalysisRuleSet>
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ExceptionHandling>
</ExceptionHandling>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<PrecompiledHeaderOutputFile>$(IntDir)zlibstat.pch</PrecompiledHeaderOutputFile>
<AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
|
| ︙ | ︙ | |||
189 190 191 192 193 194 195 |
<OutputFile>$(OutDir)zlibstat.lib</OutputFile>
<SuppressStartupBanner>true</SuppressStartupBanner>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
| | | | | | 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 |
<OutputFile>$(OutDir)zlibstat.lib</OutputFile>
<SuppressStartupBanner>true</SuppressStartupBanner>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<ExceptionHandling>
</ExceptionHandling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking>
<PrecompiledHeaderOutputFile>$(IntDir)zlibstat.pch</PrecompiledHeaderOutputFile>
<AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
<ObjectFileName>$(IntDir)</ObjectFileName>
<ProgramDataBaseFileName>$(OutDir)</ProgramDataBaseFileName>
<WarningLevel>Level3</WarningLevel>
<SuppressStartupBanner>true</SuppressStartupBanner>
</ClCompile>
<ResourceCompile>
<Culture>0x040c</Culture>
</ResourceCompile>
<Lib>
<AdditionalOptions>/MACHINE:X86 /NODEFAULTLIB %(AdditionalOptions)</AdditionalOptions>
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)zlibstat.lib</OutputFile>
<SuppressStartupBanner>true</SuppressStartupBanner>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseWithoutAsm|Win32'">
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<ExceptionHandling>
</ExceptionHandling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking>
|
| ︙ | ︙ | |||
247 248 249 250 251 252 253 |
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Midl>
<TargetEnvironment>X64</TargetEnvironment>
</Midl>
<ClCompile>
<Optimization>Disabled</Optimization>
| | | 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 |
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Midl>
<TargetEnvironment>X64</TargetEnvironment>
</Midl>
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ExceptionHandling>
</ExceptionHandling>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<PrecompiledHeaderOutputFile>$(IntDir)zlibstat.pch</PrecompiledHeaderOutputFile>
<AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
|
| ︙ | ︙ | |||
276 277 278 279 280 281 282 |
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Itanium'">
<Midl>
<TargetEnvironment>Itanium</TargetEnvironment>
</Midl>
<ClCompile>
<Optimization>Disabled</Optimization>
| | | 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 |
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Itanium'">
<Midl>
<TargetEnvironment>Itanium</TargetEnvironment>
</Midl>
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ExceptionHandling>
</ExceptionHandling>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<PrecompiledHeaderOutputFile>$(IntDir)zlibstat.pch</PrecompiledHeaderOutputFile>
<AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
|
| ︙ | ︙ | |||
305 306 307 308 309 310 311 |
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Midl>
<TargetEnvironment>X64</TargetEnvironment>
</Midl>
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
| | | | | | 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 |
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Midl>
<TargetEnvironment>X64</TargetEnvironment>
</Midl>
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<ExceptionHandling>
</ExceptionHandling>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking>
<PrecompiledHeaderOutputFile>$(IntDir)zlibstat.pch</PrecompiledHeaderOutputFile>
<AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
<ObjectFileName>$(IntDir)</ObjectFileName>
<ProgramDataBaseFileName>$(OutDir)</ProgramDataBaseFileName>
<WarningLevel>Level3</WarningLevel>
<SuppressStartupBanner>true</SuppressStartupBanner>
</ClCompile>
<ResourceCompile>
<Culture>0x040c</Culture>
</ResourceCompile>
<Lib>
<AdditionalOptions>/MACHINE:AMD64 /NODEFAULTLIB %(AdditionalOptions)</AdditionalOptions>
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)zlibstat.lib</OutputFile>
<SuppressStartupBanner>true</SuppressStartupBanner>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Itanium'">
<Midl>
<TargetEnvironment>Itanium</TargetEnvironment>
</Midl>
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<ExceptionHandling>
</ExceptionHandling>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking>
|
| ︙ | ︙ | |||
366 367 368 369 370 371 372 |
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseWithoutAsm|x64'">
<Midl>
<TargetEnvironment>X64</TargetEnvironment>
</Midl>
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
| | | 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 |
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseWithoutAsm|x64'">
<Midl>
<TargetEnvironment>X64</TargetEnvironment>
</Midl>
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<ExceptionHandling>
</ExceptionHandling>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking>
|
| ︙ | ︙ | |||
396 397 398 399 400 401 402 |
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseWithoutAsm|Itanium'">
<Midl>
<TargetEnvironment>Itanium</TargetEnvironment>
</Midl>
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
| | | 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 |
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseWithoutAsm|Itanium'">
<Midl>
<TargetEnvironment>Itanium</TargetEnvironment>
</Midl>
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<ExceptionHandling>
</ExceptionHandling>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking>
|
| ︙ | ︙ | |||
430 431 432 433 434 435 436 |
<ClCompile Include="..\..\..\crc32.c" />
<ClCompile Include="..\..\..\deflate.c" />
<ClCompile Include="..\..\..\gzclose.c" />
<ClCompile Include="..\..\..\gzlib.c" />
<ClCompile Include="..\..\..\gzread.c" />
<ClCompile Include="..\..\..\gzwrite.c" />
<ClCompile Include="..\..\..\infback.c" />
| < < < < < < < < | 430 431 432 433 434 435 436 437 438 439 440 441 442 443 |
<ClCompile Include="..\..\..\crc32.c" />
<ClCompile Include="..\..\..\deflate.c" />
<ClCompile Include="..\..\..\gzclose.c" />
<ClCompile Include="..\..\..\gzlib.c" />
<ClCompile Include="..\..\..\gzread.c" />
<ClCompile Include="..\..\..\gzwrite.c" />
<ClCompile Include="..\..\..\infback.c" />
<ClCompile Include="..\..\..\inffast.c" />
<ClCompile Include="..\..\..\inflate.c" />
<ClCompile Include="..\..\..\inftrees.c" />
<ClCompile Include="..\..\minizip\ioapi.c" />
<ClCompile Include="..\..\..\trees.c" />
<ClCompile Include="..\..\..\uncompr.c" />
<ClCompile Include="..\..\minizip\unzip.c" />
|
| ︙ | ︙ |
Changes to compat/zlib/contrib/vstudio/vc11/zlibvc.def.
1 2 3 | LIBRARY ; zlib data compression and ZIP file I/O library | | | 1 2 3 4 5 6 7 8 9 10 11 |
LIBRARY
; zlib data compression and ZIP file I/O library
VERSION 1.3
EXPORTS
adler32 @1
compress @2
crc32 @3
deflate @4
deflateCopy @5
|
| ︙ | ︙ |
Changes to compat/zlib/contrib/vstudio/vc11/zlibvc.vcxproj.
| ︙ | ︙ | |||
200 201 202 203 204 205 206 |
<MkTypLibCompatible>true</MkTypLibCompatible>
<SuppressStartupBanner>true</SuppressStartupBanner>
<TargetEnvironment>Win32</TargetEnvironment>
<TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName>
</Midl>
<ClCompile>
<Optimization>Disabled</Optimization>
| | | | < < < < | | 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 |
<MkTypLibCompatible>true</MkTypLibCompatible>
<SuppressStartupBanner>true</SuppressStartupBanner>
<TargetEnvironment>Win32</TargetEnvironment>
<TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName>
</Midl>
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ExceptionHandling>
</ExceptionHandling>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<PrecompiledHeaderOutputFile>$(IntDir)zlibvc.pch</PrecompiledHeaderOutputFile>
<AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
<ObjectFileName>$(IntDir)</ObjectFileName>
<ProgramDataBaseFileName>$(OutDir)</ProgramDataBaseFileName>
<BrowseInformation>
</BrowseInformation>
<WarningLevel>Level3</WarningLevel>
<SuppressStartupBanner>true</SuppressStartupBanner>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x040c</Culture>
</ResourceCompile>
<Link>
<AdditionalOptions>/MACHINE:I386 %(AdditionalOptions)</AdditionalOptions>
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)zlibwapi.dll</OutputFile>
<SuppressStartupBanner>true</SuppressStartupBanner>
<ModuleDefinitionFile>.\zlibvc.def</ModuleDefinitionFile>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>$(OutDir)zlibwapi.pdb</ProgramDatabaseFile>
<GenerateMapFile>true</GenerateMapFile>
<MapFileName>$(OutDir)zlibwapi.map</MapFileName>
<SubSystem>Windows</SubSystem>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention>
</DataExecutionPrevention>
<ImportLibrary>$(OutDir)zlibwapi.lib</ImportLibrary>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseWithoutAsm|Win32'">
<Midl>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MkTypLibCompatible>true</MkTypLibCompatible>
<SuppressStartupBanner>true</SuppressStartupBanner>
<TargetEnvironment>Win32</TargetEnvironment>
<TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName>
</Midl>
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<ExceptionHandling>
</ExceptionHandling>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking>
|
| ︙ | ︙ | |||
299 300 301 302 303 304 305 |
<MkTypLibCompatible>true</MkTypLibCompatible>
<SuppressStartupBanner>true</SuppressStartupBanner>
<TargetEnvironment>Win32</TargetEnvironment>
<TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName>
</Midl>
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
| | | | 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 |
<MkTypLibCompatible>true</MkTypLibCompatible>
<SuppressStartupBanner>true</SuppressStartupBanner>
<TargetEnvironment>Win32</TargetEnvironment>
<TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName>
</Midl>
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<ExceptionHandling>
</ExceptionHandling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking>
<PrecompiledHeaderOutputFile>$(IntDir)zlibvc.pch</PrecompiledHeaderOutputFile>
|
| ︙ | ︙ | |||
323 324 325 326 327 328 329 |
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x040c</Culture>
</ResourceCompile>
<Link>
<AdditionalOptions>/MACHINE:I386 %(AdditionalOptions)</AdditionalOptions>
| | < < < < | | | < < < < | | 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 |
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x040c</Culture>
</ResourceCompile>
<Link>
<AdditionalOptions>/MACHINE:I386 %(AdditionalOptions)</AdditionalOptions>
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)zlibwapi.dll</OutputFile>
<SuppressStartupBanner>true</SuppressStartupBanner>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<ModuleDefinitionFile>.\zlibvc.def</ModuleDefinitionFile>
<ProgramDatabaseFile>$(OutDir)zlibwapi.pdb</ProgramDatabaseFile>
<GenerateMapFile>true</GenerateMapFile>
<MapFileName>$(OutDir)zlibwapi.map</MapFileName>
<SubSystem>Windows</SubSystem>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention>
</DataExecutionPrevention>
<ImportLibrary>$(OutDir)zlibwapi.lib</ImportLibrary>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Midl>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MkTypLibCompatible>true</MkTypLibCompatible>
<SuppressStartupBanner>true</SuppressStartupBanner>
<TargetEnvironment>X64</TargetEnvironment>
<TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName>
</Midl>
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ExceptionHandling>
</ExceptionHandling>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<PrecompiledHeaderOutputFile>$(IntDir)zlibvc.pch</PrecompiledHeaderOutputFile>
<AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
<ObjectFileName>$(IntDir)</ObjectFileName>
<ProgramDataBaseFileName>$(OutDir)</ProgramDataBaseFileName>
<BrowseInformation>
</BrowseInformation>
<WarningLevel>Level3</WarningLevel>
<SuppressStartupBanner>true</SuppressStartupBanner>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x040c</Culture>
</ResourceCompile>
<Link>
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)zlibwapi.dll</OutputFile>
<SuppressStartupBanner>true</SuppressStartupBanner>
<ModuleDefinitionFile>.\zlibvc.def</ModuleDefinitionFile>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>$(OutDir)zlibwapi.pdb</ProgramDatabaseFile>
<GenerateMapFile>true</GenerateMapFile>
<MapFileName>$(OutDir)zlibwapi.map</MapFileName>
<SubSystem>Windows</SubSystem>
<ImportLibrary>$(OutDir)zlibwapi.lib</ImportLibrary>
<TargetMachine>MachineX64</TargetMachine>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Itanium'">
<Midl>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MkTypLibCompatible>true</MkTypLibCompatible>
<SuppressStartupBanner>true</SuppressStartupBanner>
<TargetEnvironment>Itanium</TargetEnvironment>
<TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName>
</Midl>
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ExceptionHandling>
</ExceptionHandling>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<PrecompiledHeaderOutputFile>$(IntDir)zlibvc.pch</PrecompiledHeaderOutputFile>
<AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
|
| ︙ | ︙ | |||
443 444 445 446 447 448 449 |
<MkTypLibCompatible>true</MkTypLibCompatible>
<SuppressStartupBanner>true</SuppressStartupBanner>
<TargetEnvironment>X64</TargetEnvironment>
<TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName>
</Midl>
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
| | | 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 |
<MkTypLibCompatible>true</MkTypLibCompatible>
<SuppressStartupBanner>true</SuppressStartupBanner>
<TargetEnvironment>X64</TargetEnvironment>
<TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName>
</Midl>
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<ExceptionHandling>
</ExceptionHandling>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking>
|
| ︙ | ︙ | |||
488 489 490 491 492 493 494 |
<MkTypLibCompatible>true</MkTypLibCompatible>
<SuppressStartupBanner>true</SuppressStartupBanner>
<TargetEnvironment>Itanium</TargetEnvironment>
<TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName>
</Midl>
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
| | | 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 |
<MkTypLibCompatible>true</MkTypLibCompatible>
<SuppressStartupBanner>true</SuppressStartupBanner>
<TargetEnvironment>Itanium</TargetEnvironment>
<TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName>
</Midl>
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<ExceptionHandling>
</ExceptionHandling>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking>
|
| ︙ | ︙ | |||
533 534 535 536 537 538 539 |
<MkTypLibCompatible>true</MkTypLibCompatible>
<SuppressStartupBanner>true</SuppressStartupBanner>
<TargetEnvironment>X64</TargetEnvironment>
<TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName>
</Midl>
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
| | | | 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 |
<MkTypLibCompatible>true</MkTypLibCompatible>
<SuppressStartupBanner>true</SuppressStartupBanner>
<TargetEnvironment>X64</TargetEnvironment>
<TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName>
</Midl>
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<ExceptionHandling>
</ExceptionHandling>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking>
<PrecompiledHeaderOutputFile>$(IntDir)zlibvc.pch</PrecompiledHeaderOutputFile>
|
| ︙ | ︙ | |||
556 557 558 559 560 561 562 |
<SuppressStartupBanner>true</SuppressStartupBanner>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x040c</Culture>
</ResourceCompile>
<Link>
| | < < < < | | 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 |
<SuppressStartupBanner>true</SuppressStartupBanner>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x040c</Culture>
</ResourceCompile>
<Link>
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)zlibwapi.dll</OutputFile>
<SuppressStartupBanner>true</SuppressStartupBanner>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<ModuleDefinitionFile>.\zlibvc.def</ModuleDefinitionFile>
<ProgramDatabaseFile>$(OutDir)zlibwapi.pdb</ProgramDatabaseFile>
<GenerateMapFile>true</GenerateMapFile>
<MapFileName>$(OutDir)zlibwapi.map</MapFileName>
<SubSystem>Windows</SubSystem>
<ImportLibrary>$(OutDir)zlibwapi.lib</ImportLibrary>
<TargetMachine>MachineX64</TargetMachine>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Itanium'">
<Midl>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MkTypLibCompatible>true</MkTypLibCompatible>
<SuppressStartupBanner>true</SuppressStartupBanner>
<TargetEnvironment>Itanium</TargetEnvironment>
<TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName>
</Midl>
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<ExceptionHandling>
</ExceptionHandling>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking>
|
| ︙ | ︙ | |||
628 629 630 631 632 633 634 |
<ClCompile Include="..\..\..\crc32.c" />
<ClCompile Include="..\..\..\deflate.c" />
<ClCompile Include="..\..\..\gzclose.c" />
<ClCompile Include="..\..\..\gzlib.c" />
<ClCompile Include="..\..\..\gzread.c" />
<ClCompile Include="..\..\..\gzwrite.c" />
<ClCompile Include="..\..\..\infback.c" />
| < < < < < < < < | 612 613 614 615 616 617 618 619 620 621 622 623 624 625 |
<ClCompile Include="..\..\..\crc32.c" />
<ClCompile Include="..\..\..\deflate.c" />
<ClCompile Include="..\..\..\gzclose.c" />
<ClCompile Include="..\..\..\gzlib.c" />
<ClCompile Include="..\..\..\gzread.c" />
<ClCompile Include="..\..\..\gzwrite.c" />
<ClCompile Include="..\..\..\infback.c" />
<ClCompile Include="..\..\..\inffast.c" />
<ClCompile Include="..\..\..\inflate.c" />
<ClCompile Include="..\..\..\inftrees.c" />
<ClCompile Include="..\..\minizip\ioapi.c" />
<ClCompile Include="..\..\minizip\iowin32.c" />
<ClCompile Include="..\..\..\trees.c" />
<ClCompile Include="..\..\..\uncompr.c" />
|
| ︙ | ︙ |
Changes to compat/zlib/contrib/vstudio/vc12/testzlib.vcxproj.
| ︙ | ︙ | |||
186 187 188 189 190 191 192 |
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
| | | | 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 |
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;ZLIB_WINAPI;_DEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>true</MinimalRebuild>
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<PrecompiledHeader>
</PrecompiledHeader>
<AssemblerOutput>AssemblyAndSourceCode</AssemblerOutput>
<AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<Link>
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)testzlib.exe</OutputFile>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>$(OutDir)testzlib.pdb</ProgramDatabaseFile>
<SubSystem>Console</SubSystem>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention>
</DataExecutionPrevention>
|
| ︙ | ︙ | |||
246 247 248 249 250 251 252 |
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<Optimization>MaxSpeed</Optimization>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<OmitFramePointers>true</OmitFramePointers>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
| | | | | | 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 |
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<Optimization>MaxSpeed</Optimization>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<OmitFramePointers>true</OmitFramePointers>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;ZLIB_WINAPI;NDEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking>
<PrecompiledHeader>
</PrecompiledHeader>
<AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<Link>
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)testzlib.exe</OutputFile>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention>
</DataExecutionPrevention>
<TargetMachine>MachineX86</TargetMachine>
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;ZLIB_WINAPI;_DEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
</ClCompile>
<Link>
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Itanium'">
<Midl>
<TargetEnvironment>Itanium</TargetEnvironment>
</Midl>
<ClCompile>
|
| ︙ | ︙ | |||
358 359 360 361 362 363 364 |
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<TargetMachine>MachineIA64</TargetMachine>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
| | | | 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 |
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<TargetMachine>MachineIA64</TargetMachine>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;ZLIB_WINAPI;NDEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
</ClCompile>
<Link>
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Itanium'">
<Midl>
<TargetEnvironment>Itanium</TargetEnvironment>
</Midl>
<ClCompile>
|
| ︙ | ︙ | |||
404 405 406 407 408 409 410 |
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\..\adler32.c" />
<ClCompile Include="..\..\..\compress.c" />
<ClCompile Include="..\..\..\crc32.c" />
<ClCompile Include="..\..\..\deflate.c" />
<ClCompile Include="..\..\..\infback.c" />
| < < < < < < < < | 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 |
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\..\adler32.c" />
<ClCompile Include="..\..\..\compress.c" />
<ClCompile Include="..\..\..\crc32.c" />
<ClCompile Include="..\..\..\deflate.c" />
<ClCompile Include="..\..\..\infback.c" />
<ClCompile Include="..\..\..\inffast.c" />
<ClCompile Include="..\..\..\inflate.c" />
<ClCompile Include="..\..\..\inftrees.c" />
<ClCompile Include="..\..\testzlib\testzlib.c" />
<ClCompile Include="..\..\..\trees.c" />
<ClCompile Include="..\..\..\uncompr.c" />
<ClCompile Include="..\..\..\zutil.c" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
|
Changes to compat/zlib/contrib/vstudio/vc12/zlib.rc.
1 2 3 4 | #include <windows.h> #define IDR_VERSION1 1 IDR_VERSION1 VERSIONINFO MOVEABLE IMPURE LOADONCALL DISCARDABLE | | | | | | 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 |
#include <windows.h>
#define IDR_VERSION1 1
IDR_VERSION1 VERSIONINFO MOVEABLE IMPURE LOADONCALL DISCARDABLE
FILEVERSION 1, 3, 0, 0
PRODUCTVERSION 1, 3, 0, 0
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
FILEFLAGS 0
FILEOS VOS_DOS_WINDOWS32
FILETYPE VFT_DLL
FILESUBTYPE 0 // not used
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904E4"
//language ID = U.S. English, char set = Windows, Multilingual
BEGIN
VALUE "FileDescription", "zlib data compression and ZIP file I/O library\0"
VALUE "FileVersion", "1.3.0\0"
VALUE "InternalName", "zlib\0"
VALUE "OriginalFilename", "zlibwapi.dll\0"
VALUE "ProductName", "ZLib.DLL\0"
VALUE "Comments","DLL support by Alessandro Iacopetti & Gilles Vollant\0"
VALUE "LegalCopyright", "(C) 1995-2023 Jean-loup Gailly & Mark Adler\0"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x0409, 1252
END
END
|
Changes to compat/zlib/contrib/vstudio/vc12/zlibstat.vcxproj.
| ︙ | ︙ | |||
166 167 168 169 170 171 172 |
<CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Release|x64'">AllRules.ruleset</CodeAnalysisRuleSet>
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<Optimization>Disabled</Optimization>
| | | 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 |
<CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Release|x64'">AllRules.ruleset</CodeAnalysisRuleSet>
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ExceptionHandling>
</ExceptionHandling>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<PrecompiledHeaderOutputFile>$(IntDir)zlibstat.pch</PrecompiledHeaderOutputFile>
<AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
|
| ︙ | ︙ | |||
192 193 194 195 196 197 198 |
<OutputFile>$(OutDir)zlibstat.lib</OutputFile>
<SuppressStartupBanner>true</SuppressStartupBanner>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
| | | | | | 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 |
<OutputFile>$(OutDir)zlibstat.lib</OutputFile>
<SuppressStartupBanner>true</SuppressStartupBanner>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<ExceptionHandling>
</ExceptionHandling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking>
<PrecompiledHeaderOutputFile>$(IntDir)zlibstat.pch</PrecompiledHeaderOutputFile>
<AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
<ObjectFileName>$(IntDir)</ObjectFileName>
<ProgramDataBaseFileName>$(OutDir)</ProgramDataBaseFileName>
<WarningLevel>Level3</WarningLevel>
<SuppressStartupBanner>true</SuppressStartupBanner>
</ClCompile>
<ResourceCompile>
<Culture>0x040c</Culture>
</ResourceCompile>
<Lib>
<AdditionalOptions>/MACHINE:X86 /NODEFAULTLIB %(AdditionalOptions)</AdditionalOptions>
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)zlibstat.lib</OutputFile>
<SuppressStartupBanner>true</SuppressStartupBanner>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseWithoutAsm|Win32'">
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<ExceptionHandling>
</ExceptionHandling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking>
|
| ︙ | ︙ | |||
250 251 252 253 254 255 256 |
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Midl>
<TargetEnvironment>X64</TargetEnvironment>
</Midl>
<ClCompile>
<Optimization>Disabled</Optimization>
| | | 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 |
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Midl>
<TargetEnvironment>X64</TargetEnvironment>
</Midl>
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ExceptionHandling>
</ExceptionHandling>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<PrecompiledHeaderOutputFile>$(IntDir)zlibstat.pch</PrecompiledHeaderOutputFile>
<AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
|
| ︙ | ︙ | |||
279 280 281 282 283 284 285 |
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Itanium'">
<Midl>
<TargetEnvironment>Itanium</TargetEnvironment>
</Midl>
<ClCompile>
<Optimization>Disabled</Optimization>
| | | 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 |
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Itanium'">
<Midl>
<TargetEnvironment>Itanium</TargetEnvironment>
</Midl>
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ExceptionHandling>
</ExceptionHandling>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<PrecompiledHeaderOutputFile>$(IntDir)zlibstat.pch</PrecompiledHeaderOutputFile>
<AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
|
| ︙ | ︙ | |||
308 309 310 311 312 313 314 |
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Midl>
<TargetEnvironment>X64</TargetEnvironment>
</Midl>
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
| | | | | | 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 |
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Midl>
<TargetEnvironment>X64</TargetEnvironment>
</Midl>
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<ExceptionHandling>
</ExceptionHandling>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking>
<PrecompiledHeaderOutputFile>$(IntDir)zlibstat.pch</PrecompiledHeaderOutputFile>
<AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
<ObjectFileName>$(IntDir)</ObjectFileName>
<ProgramDataBaseFileName>$(OutDir)</ProgramDataBaseFileName>
<WarningLevel>Level3</WarningLevel>
<SuppressStartupBanner>true</SuppressStartupBanner>
</ClCompile>
<ResourceCompile>
<Culture>0x040c</Culture>
</ResourceCompile>
<Lib>
<AdditionalOptions>/MACHINE:AMD64 /NODEFAULTLIB %(AdditionalOptions)</AdditionalOptions>
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)zlibstat.lib</OutputFile>
<SuppressStartupBanner>true</SuppressStartupBanner>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Itanium'">
<Midl>
<TargetEnvironment>Itanium</TargetEnvironment>
</Midl>
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<ExceptionHandling>
</ExceptionHandling>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking>
|
| ︙ | ︙ | |||
369 370 371 372 373 374 375 |
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseWithoutAsm|x64'">
<Midl>
<TargetEnvironment>X64</TargetEnvironment>
</Midl>
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
| | | 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 |
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseWithoutAsm|x64'">
<Midl>
<TargetEnvironment>X64</TargetEnvironment>
</Midl>
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<ExceptionHandling>
</ExceptionHandling>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking>
|
| ︙ | ︙ | |||
399 400 401 402 403 404 405 |
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseWithoutAsm|Itanium'">
<Midl>
<TargetEnvironment>Itanium</TargetEnvironment>
</Midl>
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
| | | 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 |
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseWithoutAsm|Itanium'">
<Midl>
<TargetEnvironment>Itanium</TargetEnvironment>
</Midl>
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<ExceptionHandling>
</ExceptionHandling>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking>
|
| ︙ | ︙ | |||
433 434 435 436 437 438 439 |
<ClCompile Include="..\..\..\crc32.c" />
<ClCompile Include="..\..\..\deflate.c" />
<ClCompile Include="..\..\..\gzclose.c" />
<ClCompile Include="..\..\..\gzlib.c" />
<ClCompile Include="..\..\..\gzread.c" />
<ClCompile Include="..\..\..\gzwrite.c" />
<ClCompile Include="..\..\..\infback.c" />
| < < < < < < < < | 433 434 435 436 437 438 439 440 441 442 443 444 445 446 |
<ClCompile Include="..\..\..\crc32.c" />
<ClCompile Include="..\..\..\deflate.c" />
<ClCompile Include="..\..\..\gzclose.c" />
<ClCompile Include="..\..\..\gzlib.c" />
<ClCompile Include="..\..\..\gzread.c" />
<ClCompile Include="..\..\..\gzwrite.c" />
<ClCompile Include="..\..\..\infback.c" />
<ClCompile Include="..\..\..\inffast.c" />
<ClCompile Include="..\..\..\inflate.c" />
<ClCompile Include="..\..\..\inftrees.c" />
<ClCompile Include="..\..\minizip\ioapi.c" />
<ClCompile Include="..\..\..\trees.c" />
<ClCompile Include="..\..\..\uncompr.c" />
<ClCompile Include="..\..\minizip\unzip.c" />
|
| ︙ | ︙ |
Changes to compat/zlib/contrib/vstudio/vc12/zlibvc.def.
1 2 3 | LIBRARY ; zlib data compression and ZIP file I/O library | | | 1 2 3 4 5 6 7 8 9 10 11 |
LIBRARY
; zlib data compression and ZIP file I/O library
VERSION 1.3
EXPORTS
adler32 @1
compress @2
crc32 @3
deflate @4
deflateCopy @5
|
| ︙ | ︙ |
Changes to compat/zlib/contrib/vstudio/vc12/zlibvc.vcxproj.
| ︙ | ︙ | |||
203 204 205 206 207 208 209 |
<MkTypLibCompatible>true</MkTypLibCompatible>
<SuppressStartupBanner>true</SuppressStartupBanner>
<TargetEnvironment>Win32</TargetEnvironment>
<TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName>
</Midl>
<ClCompile>
<Optimization>Disabled</Optimization>
| | | | < < < < | | 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 |
<MkTypLibCompatible>true</MkTypLibCompatible>
<SuppressStartupBanner>true</SuppressStartupBanner>
<TargetEnvironment>Win32</TargetEnvironment>
<TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName>
</Midl>
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ExceptionHandling>
</ExceptionHandling>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<PrecompiledHeaderOutputFile>$(IntDir)zlibvc.pch</PrecompiledHeaderOutputFile>
<AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
<ObjectFileName>$(IntDir)</ObjectFileName>
<ProgramDataBaseFileName>$(OutDir)</ProgramDataBaseFileName>
<BrowseInformation>
</BrowseInformation>
<WarningLevel>Level3</WarningLevel>
<SuppressStartupBanner>true</SuppressStartupBanner>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x040c</Culture>
</ResourceCompile>
<Link>
<AdditionalOptions>/MACHINE:I386 %(AdditionalOptions)</AdditionalOptions>
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)zlibwapi.dll</OutputFile>
<SuppressStartupBanner>true</SuppressStartupBanner>
<ModuleDefinitionFile>.\zlibvc.def</ModuleDefinitionFile>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>$(OutDir)zlibwapi.pdb</ProgramDatabaseFile>
<GenerateMapFile>true</GenerateMapFile>
<MapFileName>$(OutDir)zlibwapi.map</MapFileName>
<SubSystem>Windows</SubSystem>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention>
</DataExecutionPrevention>
<ImportLibrary>$(OutDir)zlibwapi.lib</ImportLibrary>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseWithoutAsm|Win32'">
<Midl>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MkTypLibCompatible>true</MkTypLibCompatible>
<SuppressStartupBanner>true</SuppressStartupBanner>
<TargetEnvironment>Win32</TargetEnvironment>
<TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName>
</Midl>
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<ExceptionHandling>
</ExceptionHandling>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking>
|
| ︙ | ︙ | |||
302 303 304 305 306 307 308 |
<MkTypLibCompatible>true</MkTypLibCompatible>
<SuppressStartupBanner>true</SuppressStartupBanner>
<TargetEnvironment>Win32</TargetEnvironment>
<TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName>
</Midl>
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
| | | | 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 |
<MkTypLibCompatible>true</MkTypLibCompatible>
<SuppressStartupBanner>true</SuppressStartupBanner>
<TargetEnvironment>Win32</TargetEnvironment>
<TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName>
</Midl>
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<ExceptionHandling>
</ExceptionHandling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking>
<PrecompiledHeaderOutputFile>$(IntDir)zlibvc.pch</PrecompiledHeaderOutputFile>
|
| ︙ | ︙ | |||
326 327 328 329 330 331 332 |
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x040c</Culture>
</ResourceCompile>
<Link>
<AdditionalOptions>/MACHINE:I386 %(AdditionalOptions)</AdditionalOptions>
| | < < < < | | | < < < < | | 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 |
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x040c</Culture>
</ResourceCompile>
<Link>
<AdditionalOptions>/MACHINE:I386 %(AdditionalOptions)</AdditionalOptions>
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)zlibwapi.dll</OutputFile>
<SuppressStartupBanner>true</SuppressStartupBanner>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<ModuleDefinitionFile>.\zlibvc.def</ModuleDefinitionFile>
<ProgramDatabaseFile>$(OutDir)zlibwapi.pdb</ProgramDatabaseFile>
<GenerateMapFile>true</GenerateMapFile>
<MapFileName>$(OutDir)zlibwapi.map</MapFileName>
<SubSystem>Windows</SubSystem>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention>
</DataExecutionPrevention>
<ImportLibrary>$(OutDir)zlibwapi.lib</ImportLibrary>
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Midl>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MkTypLibCompatible>true</MkTypLibCompatible>
<SuppressStartupBanner>true</SuppressStartupBanner>
<TargetEnvironment>X64</TargetEnvironment>
<TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName>
</Midl>
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ExceptionHandling>
</ExceptionHandling>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<PrecompiledHeaderOutputFile>$(IntDir)zlibvc.pch</PrecompiledHeaderOutputFile>
<AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
<ObjectFileName>$(IntDir)</ObjectFileName>
<ProgramDataBaseFileName>$(OutDir)</ProgramDataBaseFileName>
<BrowseInformation>
</BrowseInformation>
<WarningLevel>Level3</WarningLevel>
<SuppressStartupBanner>true</SuppressStartupBanner>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x040c</Culture>
</ResourceCompile>
<Link>
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)zlibwapi.dll</OutputFile>
<SuppressStartupBanner>true</SuppressStartupBanner>
<ModuleDefinitionFile>.\zlibvc.def</ModuleDefinitionFile>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>$(OutDir)zlibwapi.pdb</ProgramDatabaseFile>
<GenerateMapFile>true</GenerateMapFile>
<MapFileName>$(OutDir)zlibwapi.map</MapFileName>
<SubSystem>Windows</SubSystem>
<ImportLibrary>$(OutDir)zlibwapi.lib</ImportLibrary>
<TargetMachine>MachineX64</TargetMachine>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Itanium'">
<Midl>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MkTypLibCompatible>true</MkTypLibCompatible>
<SuppressStartupBanner>true</SuppressStartupBanner>
<TargetEnvironment>Itanium</TargetEnvironment>
<TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName>
</Midl>
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ExceptionHandling>
</ExceptionHandling>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<PrecompiledHeaderOutputFile>$(IntDir)zlibvc.pch</PrecompiledHeaderOutputFile>
<AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
|
| ︙ | ︙ | |||
447 448 449 450 451 452 453 |
<MkTypLibCompatible>true</MkTypLibCompatible>
<SuppressStartupBanner>true</SuppressStartupBanner>
<TargetEnvironment>X64</TargetEnvironment>
<TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName>
</Midl>
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
| | | 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 |
<MkTypLibCompatible>true</MkTypLibCompatible>
<SuppressStartupBanner>true</SuppressStartupBanner>
<TargetEnvironment>X64</TargetEnvironment>
<TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName>
</Midl>
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<ExceptionHandling>
</ExceptionHandling>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking>
|
| ︙ | ︙ | |||
492 493 494 495 496 497 498 |
<MkTypLibCompatible>true</MkTypLibCompatible>
<SuppressStartupBanner>true</SuppressStartupBanner>
<TargetEnvironment>Itanium</TargetEnvironment>
<TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName>
</Midl>
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
| | | 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 |
<MkTypLibCompatible>true</MkTypLibCompatible>
<SuppressStartupBanner>true</SuppressStartupBanner>
<TargetEnvironment>Itanium</TargetEnvironment>
<TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName>
</Midl>
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<ExceptionHandling>
</ExceptionHandling>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking>
|
| ︙ | ︙ | |||
537 538 539 540 541 542 543 |
<MkTypLibCompatible>true</MkTypLibCompatible>
<SuppressStartupBanner>true</SuppressStartupBanner>
<TargetEnvironment>X64</TargetEnvironment>
<TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName>
</Midl>
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
| | | | 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 |
<MkTypLibCompatible>true</MkTypLibCompatible>
<SuppressStartupBanner>true</SuppressStartupBanner>
<TargetEnvironment>X64</TargetEnvironment>
<TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName>
</Midl>
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<ExceptionHandling>
</ExceptionHandling>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking>
<PrecompiledHeaderOutputFile>$(IntDir)zlibvc.pch</PrecompiledHeaderOutputFile>
|
| ︙ | ︙ | |||
560 561 562 563 564 565 566 |
<SuppressStartupBanner>true</SuppressStartupBanner>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x040c</Culture>
</ResourceCompile>
<Link>
| | < < < < | | 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 |
<SuppressStartupBanner>true</SuppressStartupBanner>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x040c</Culture>
</ResourceCompile>
<Link>
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)zlibwapi.dll</OutputFile>
<SuppressStartupBanner>true</SuppressStartupBanner>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<ModuleDefinitionFile>.\zlibvc.def</ModuleDefinitionFile>
<ProgramDatabaseFile>$(OutDir)zlibwapi.pdb</ProgramDatabaseFile>
<GenerateMapFile>true</GenerateMapFile>
<MapFileName>$(OutDir)zlibwapi.map</MapFileName>
<SubSystem>Windows</SubSystem>
<ImportLibrary>$(OutDir)zlibwapi.lib</ImportLibrary>
<TargetMachine>MachineX64</TargetMachine>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Itanium'">
<Midl>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MkTypLibCompatible>true</MkTypLibCompatible>
<SuppressStartupBanner>true</SuppressStartupBanner>
<TargetEnvironment>Itanium</TargetEnvironment>
<TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName>
</Midl>
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<ExceptionHandling>
</ExceptionHandling>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking>
|
| ︙ | ︙ | |||
632 633 634 635 636 637 638 |
<ClCompile Include="..\..\..\crc32.c" />
<ClCompile Include="..\..\..\deflate.c" />
<ClCompile Include="..\..\..\gzclose.c" />
<ClCompile Include="..\..\..\gzlib.c" />
<ClCompile Include="..\..\..\gzread.c" />
<ClCompile Include="..\..\..\gzwrite.c" />
<ClCompile Include="..\..\..\infback.c" />
| < < < < < < < < | 616 617 618 619 620 621 622 623 624 625 626 627 628 629 |
<ClCompile Include="..\..\..\crc32.c" />
<ClCompile Include="..\..\..\deflate.c" />
<ClCompile Include="..\..\..\gzclose.c" />
<ClCompile Include="..\..\..\gzlib.c" />
<ClCompile Include="..\..\..\gzread.c" />
<ClCompile Include="..\..\..\gzwrite.c" />
<ClCompile Include="..\..\..\infback.c" />
<ClCompile Include="..\..\..\inffast.c" />
<ClCompile Include="..\..\..\inflate.c" />
<ClCompile Include="..\..\..\inftrees.c" />
<ClCompile Include="..\..\minizip\ioapi.c" />
<ClCompile Include="..\..\minizip\iowin32.c" />
<ClCompile Include="..\..\..\trees.c" />
<ClCompile Include="..\..\..\uncompr.c" />
|
| ︙ | ︙ |
Changes to compat/zlib/contrib/vstudio/vc14/testzlib.vcxproj.
| ︙ | ︙ | |||
186 187 188 189 190 191 192 |
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
| | | | 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 |
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;ZLIB_WINAPI;_DEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>true</MinimalRebuild>
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<PrecompiledHeader>
</PrecompiledHeader>
<AssemblerOutput>AssemblyAndSourceCode</AssemblerOutput>
<AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<Link>
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)testzlib.exe</OutputFile>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>$(OutDir)testzlib.pdb</ProgramDatabaseFile>
<SubSystem>Console</SubSystem>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention>
</DataExecutionPrevention>
|
| ︙ | ︙ | |||
246 247 248 249 250 251 252 |
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<Optimization>MaxSpeed</Optimization>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<OmitFramePointers>true</OmitFramePointers>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
| | | | | | 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 |
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<Optimization>MaxSpeed</Optimization>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<OmitFramePointers>true</OmitFramePointers>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;ZLIB_WINAPI;NDEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking>
<PrecompiledHeader>
</PrecompiledHeader>
<AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<Link>
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)testzlib.exe</OutputFile>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention>
</DataExecutionPrevention>
<TargetMachine>MachineX86</TargetMachine>
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;ZLIB_WINAPI;_DEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
</ClCompile>
<Link>
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Itanium'">
<Midl>
<TargetEnvironment>Itanium</TargetEnvironment>
</Midl>
<ClCompile>
|
| ︙ | ︙ | |||
358 359 360 361 362 363 364 |
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<TargetMachine>MachineIA64</TargetMachine>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
| | | | 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 |
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<TargetMachine>MachineIA64</TargetMachine>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;ZLIB_WINAPI;NDEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
</ClCompile>
<Link>
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Itanium'">
<Midl>
<TargetEnvironment>Itanium</TargetEnvironment>
</Midl>
<ClCompile>
|
| ︙ | ︙ | |||
404 405 406 407 408 409 410 |
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\..\adler32.c" />
<ClCompile Include="..\..\..\compress.c" />
<ClCompile Include="..\..\..\crc32.c" />
<ClCompile Include="..\..\..\deflate.c" />
<ClCompile Include="..\..\..\infback.c" />
| < < < < < < < < | 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 |
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\..\adler32.c" />
<ClCompile Include="..\..\..\compress.c" />
<ClCompile Include="..\..\..\crc32.c" />
<ClCompile Include="..\..\..\deflate.c" />
<ClCompile Include="..\..\..\infback.c" />
<ClCompile Include="..\..\..\inffast.c" />
<ClCompile Include="..\..\..\inflate.c" />
<ClCompile Include="..\..\..\inftrees.c" />
<ClCompile Include="..\..\testzlib\testzlib.c" />
<ClCompile Include="..\..\..\trees.c" />
<ClCompile Include="..\..\..\uncompr.c" />
<ClCompile Include="..\..\..\zutil.c" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
|
Changes to compat/zlib/contrib/vstudio/vc14/zlib.rc.
1 2 3 4 | #include <windows.h> #define IDR_VERSION1 1 IDR_VERSION1 VERSIONINFO MOVEABLE IMPURE LOADONCALL DISCARDABLE | | | | | | 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 |
#include <windows.h>
#define IDR_VERSION1 1
IDR_VERSION1 VERSIONINFO MOVEABLE IMPURE LOADONCALL DISCARDABLE
FILEVERSION 1, 3, 0, 0
PRODUCTVERSION 1, 3, 0, 0
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
FILEFLAGS 0
FILEOS VOS_DOS_WINDOWS32
FILETYPE VFT_DLL
FILESUBTYPE 0 // not used
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904E4"
//language ID = U.S. English, char set = Windows, Multilingual
BEGIN
VALUE "FileDescription", "zlib data compression and ZIP file I/O library\0"
VALUE "FileVersion", "1.3.0\0"
VALUE "InternalName", "zlib\0"
VALUE "OriginalFilename", "zlibwapi.dll\0"
VALUE "ProductName", "ZLib.DLL\0"
VALUE "Comments","DLL support by Alessandro Iacopetti & Gilles Vollant\0"
VALUE "LegalCopyright", "(C) 1995-2023 Jean-loup Gailly & Mark Adler\0"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x0409, 1252
END
END
|
Changes to compat/zlib/contrib/vstudio/vc14/zlibstat.vcxproj.
| ︙ | ︙ | |||
166 167 168 169 170 171 172 |
<CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Release|x64'">AllRules.ruleset</CodeAnalysisRuleSet>
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<Optimization>Disabled</Optimization>
| | | 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 |
<CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Release|x64'">AllRules.ruleset</CodeAnalysisRuleSet>
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ExceptionHandling>
</ExceptionHandling>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<PrecompiledHeaderOutputFile>$(IntDir)zlibstat.pch</PrecompiledHeaderOutputFile>
<AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
|
| ︙ | ︙ | |||
192 193 194 195 196 197 198 |
<OutputFile>$(OutDir)zlibstat.lib</OutputFile>
<SuppressStartupBanner>true</SuppressStartupBanner>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
| | | | | | 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 |
<OutputFile>$(OutDir)zlibstat.lib</OutputFile>
<SuppressStartupBanner>true</SuppressStartupBanner>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<ExceptionHandling>
</ExceptionHandling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking>
<PrecompiledHeaderOutputFile>$(IntDir)zlibstat.pch</PrecompiledHeaderOutputFile>
<AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
<ObjectFileName>$(IntDir)</ObjectFileName>
<ProgramDataBaseFileName>$(OutDir)</ProgramDataBaseFileName>
<WarningLevel>Level3</WarningLevel>
<SuppressStartupBanner>true</SuppressStartupBanner>
</ClCompile>
<ResourceCompile>
<Culture>0x040c</Culture>
</ResourceCompile>
<Lib>
<AdditionalOptions>/MACHINE:X86 /NODEFAULTLIB %(AdditionalOptions)</AdditionalOptions>
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)zlibstat.lib</OutputFile>
<SuppressStartupBanner>true</SuppressStartupBanner>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseWithoutAsm|Win32'">
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<ExceptionHandling>
</ExceptionHandling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking>
|
| ︙ | ︙ | |||
250 251 252 253 254 255 256 |
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Midl>
<TargetEnvironment>X64</TargetEnvironment>
</Midl>
<ClCompile>
<Optimization>Disabled</Optimization>
| | | 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 |
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Midl>
<TargetEnvironment>X64</TargetEnvironment>
</Midl>
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ExceptionHandling>
</ExceptionHandling>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<PrecompiledHeaderOutputFile>$(IntDir)zlibstat.pch</PrecompiledHeaderOutputFile>
<AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
|
| ︙ | ︙ | |||
279 280 281 282 283 284 285 |
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Itanium'">
<Midl>
<TargetEnvironment>Itanium</TargetEnvironment>
</Midl>
<ClCompile>
<Optimization>Disabled</Optimization>
| | | 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 |
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Itanium'">
<Midl>
<TargetEnvironment>Itanium</TargetEnvironment>
</Midl>
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ExceptionHandling>
</ExceptionHandling>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<PrecompiledHeaderOutputFile>$(IntDir)zlibstat.pch</PrecompiledHeaderOutputFile>
<AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
|
| ︙ | ︙ | |||
308 309 310 311 312 313 314 |
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Midl>
<TargetEnvironment>X64</TargetEnvironment>
</Midl>
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
| | | | | | 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 |
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Midl>
<TargetEnvironment>X64</TargetEnvironment>
</Midl>
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<ExceptionHandling>
</ExceptionHandling>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking>
<PrecompiledHeaderOutputFile>$(IntDir)zlibstat.pch</PrecompiledHeaderOutputFile>
<AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
<ObjectFileName>$(IntDir)</ObjectFileName>
<ProgramDataBaseFileName>$(OutDir)</ProgramDataBaseFileName>
<WarningLevel>Level3</WarningLevel>
<SuppressStartupBanner>true</SuppressStartupBanner>
</ClCompile>
<ResourceCompile>
<Culture>0x040c</Culture>
</ResourceCompile>
<Lib>
<AdditionalOptions>/MACHINE:AMD64 /NODEFAULTLIB %(AdditionalOptions)</AdditionalOptions>
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)zlibstat.lib</OutputFile>
<SuppressStartupBanner>true</SuppressStartupBanner>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Itanium'">
<Midl>
<TargetEnvironment>Itanium</TargetEnvironment>
</Midl>
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<ExceptionHandling>
</ExceptionHandling>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking>
|
| ︙ | ︙ | |||
369 370 371 372 373 374 375 |
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseWithoutAsm|x64'">
<Midl>
<TargetEnvironment>X64</TargetEnvironment>
</Midl>
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
| | | 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 |
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseWithoutAsm|x64'">
<Midl>
<TargetEnvironment>X64</TargetEnvironment>
</Midl>
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<ExceptionHandling>
</ExceptionHandling>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking>
|
| ︙ | ︙ | |||
399 400 401 402 403 404 405 |
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseWithoutAsm|Itanium'">
<Midl>
<TargetEnvironment>Itanium</TargetEnvironment>
</Midl>
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
| | | 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 |
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseWithoutAsm|Itanium'">
<Midl>
<TargetEnvironment>Itanium</TargetEnvironment>
</Midl>
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<ExceptionHandling>
</ExceptionHandling>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking>
|
| ︙ | ︙ | |||
433 434 435 436 437 438 439 |
<ClCompile Include="..\..\..\crc32.c" />
<ClCompile Include="..\..\..\deflate.c" />
<ClCompile Include="..\..\..\gzclose.c" />
<ClCompile Include="..\..\..\gzlib.c" />
<ClCompile Include="..\..\..\gzread.c" />
<ClCompile Include="..\..\..\gzwrite.c" />
<ClCompile Include="..\..\..\infback.c" />
| < < < < < < < < | 433 434 435 436 437 438 439 440 441 442 443 444 445 446 |
<ClCompile Include="..\..\..\crc32.c" />
<ClCompile Include="..\..\..\deflate.c" />
<ClCompile Include="..\..\..\gzclose.c" />
<ClCompile Include="..\..\..\gzlib.c" />
<ClCompile Include="..\..\..\gzread.c" />
<ClCompile Include="..\..\..\gzwrite.c" />
<ClCompile Include="..\..\..\infback.c" />
<ClCompile Include="..\..\..\inffast.c" />
<ClCompile Include="..\..\..\inflate.c" />
<ClCompile Include="..\..\..\inftrees.c" />
<ClCompile Include="..\..\minizip\ioapi.c" />
<ClCompile Include="..\..\..\trees.c" />
<ClCompile Include="..\..\..\uncompr.c" />
<ClCompile Include="..\..\minizip\unzip.c" />
|
| ︙ | ︙ |
Changes to compat/zlib/contrib/vstudio/vc14/zlibvc.def.
1 2 3 | LIBRARY ; zlib data compression and ZIP file I/O library | | | 1 2 3 4 5 6 7 8 9 10 11 |
LIBRARY
; zlib data compression and ZIP file I/O library
VERSION 1.3
EXPORTS
adler32 @1
compress @2
crc32 @3
deflate @4
deflateCopy @5
|
| ︙ | ︙ |
Changes to compat/zlib/contrib/vstudio/vc14/zlibvc.vcxproj.
| ︙ | ︙ | |||
203 204 205 206 207 208 209 |
<MkTypLibCompatible>true</MkTypLibCompatible>
<SuppressStartupBanner>true</SuppressStartupBanner>
<TargetEnvironment>Win32</TargetEnvironment>
<TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName>
</Midl>
<ClCompile>
<Optimization>Disabled</Optimization>
| | | | < < < < | | 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 |
<MkTypLibCompatible>true</MkTypLibCompatible>
<SuppressStartupBanner>true</SuppressStartupBanner>
<TargetEnvironment>Win32</TargetEnvironment>
<TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName>
</Midl>
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ExceptionHandling>
</ExceptionHandling>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<PrecompiledHeaderOutputFile>$(IntDir)zlibvc.pch</PrecompiledHeaderOutputFile>
<AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
<ObjectFileName>$(IntDir)</ObjectFileName>
<ProgramDataBaseFileName>$(OutDir)</ProgramDataBaseFileName>
<BrowseInformation>
</BrowseInformation>
<WarningLevel>Level3</WarningLevel>
<SuppressStartupBanner>true</SuppressStartupBanner>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x040c</Culture>
</ResourceCompile>
<Link>
<AdditionalOptions>/MACHINE:I386 %(AdditionalOptions)</AdditionalOptions>
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)zlibwapi.dll</OutputFile>
<SuppressStartupBanner>true</SuppressStartupBanner>
<ModuleDefinitionFile>.\zlibvc.def</ModuleDefinitionFile>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>$(OutDir)zlibwapi.pdb</ProgramDatabaseFile>
<GenerateMapFile>true</GenerateMapFile>
<MapFileName>$(OutDir)zlibwapi.map</MapFileName>
<SubSystem>Windows</SubSystem>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention>
</DataExecutionPrevention>
<ImportLibrary>$(OutDir)zlibwapi.lib</ImportLibrary>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseWithoutAsm|Win32'">
<Midl>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MkTypLibCompatible>true</MkTypLibCompatible>
<SuppressStartupBanner>true</SuppressStartupBanner>
<TargetEnvironment>Win32</TargetEnvironment>
<TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName>
</Midl>
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<ExceptionHandling>
</ExceptionHandling>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking>
|
| ︙ | ︙ | |||
302 303 304 305 306 307 308 |
<MkTypLibCompatible>true</MkTypLibCompatible>
<SuppressStartupBanner>true</SuppressStartupBanner>
<TargetEnvironment>Win32</TargetEnvironment>
<TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName>
</Midl>
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
| | | | 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 |
<MkTypLibCompatible>true</MkTypLibCompatible>
<SuppressStartupBanner>true</SuppressStartupBanner>
<TargetEnvironment>Win32</TargetEnvironment>
<TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName>
</Midl>
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<ExceptionHandling>
</ExceptionHandling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking>
<PrecompiledHeaderOutputFile>$(IntDir)zlibvc.pch</PrecompiledHeaderOutputFile>
|
| ︙ | ︙ | |||
326 327 328 329 330 331 332 |
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x040c</Culture>
</ResourceCompile>
<Link>
<AdditionalOptions>/MACHINE:I386 %(AdditionalOptions)</AdditionalOptions>
| | < < < < | | | < < < < | | 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 |
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x040c</Culture>
</ResourceCompile>
<Link>
<AdditionalOptions>/MACHINE:I386 %(AdditionalOptions)</AdditionalOptions>
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)zlibwapi.dll</OutputFile>
<SuppressStartupBanner>true</SuppressStartupBanner>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<ModuleDefinitionFile>.\zlibvc.def</ModuleDefinitionFile>
<ProgramDatabaseFile>$(OutDir)zlibwapi.pdb</ProgramDatabaseFile>
<GenerateMapFile>true</GenerateMapFile>
<MapFileName>$(OutDir)zlibwapi.map</MapFileName>
<SubSystem>Windows</SubSystem>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention>
</DataExecutionPrevention>
<ImportLibrary>$(OutDir)zlibwapi.lib</ImportLibrary>
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Midl>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MkTypLibCompatible>true</MkTypLibCompatible>
<SuppressStartupBanner>true</SuppressStartupBanner>
<TargetEnvironment>X64</TargetEnvironment>
<TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName>
</Midl>
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ExceptionHandling>
</ExceptionHandling>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<PrecompiledHeaderOutputFile>$(IntDir)zlibvc.pch</PrecompiledHeaderOutputFile>
<AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
<ObjectFileName>$(IntDir)</ObjectFileName>
<ProgramDataBaseFileName>$(OutDir)</ProgramDataBaseFileName>
<BrowseInformation>
</BrowseInformation>
<WarningLevel>Level3</WarningLevel>
<SuppressStartupBanner>true</SuppressStartupBanner>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x040c</Culture>
</ResourceCompile>
<Link>
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)zlibwapi.dll</OutputFile>
<SuppressStartupBanner>true</SuppressStartupBanner>
<ModuleDefinitionFile>.\zlibvc.def</ModuleDefinitionFile>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>$(OutDir)zlibwapi.pdb</ProgramDatabaseFile>
<GenerateMapFile>true</GenerateMapFile>
<MapFileName>$(OutDir)zlibwapi.map</MapFileName>
<SubSystem>Windows</SubSystem>
<ImportLibrary>$(OutDir)zlibwapi.lib</ImportLibrary>
<TargetMachine>MachineX64</TargetMachine>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Itanium'">
<Midl>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MkTypLibCompatible>true</MkTypLibCompatible>
<SuppressStartupBanner>true</SuppressStartupBanner>
<TargetEnvironment>Itanium</TargetEnvironment>
<TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName>
</Midl>
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ExceptionHandling>
</ExceptionHandling>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<PrecompiledHeaderOutputFile>$(IntDir)zlibvc.pch</PrecompiledHeaderOutputFile>
<AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
|
| ︙ | ︙ | |||
447 448 449 450 451 452 453 |
<MkTypLibCompatible>true</MkTypLibCompatible>
<SuppressStartupBanner>true</SuppressStartupBanner>
<TargetEnvironment>X64</TargetEnvironment>
<TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName>
</Midl>
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
| | | 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 |
<MkTypLibCompatible>true</MkTypLibCompatible>
<SuppressStartupBanner>true</SuppressStartupBanner>
<TargetEnvironment>X64</TargetEnvironment>
<TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName>
</Midl>
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<ExceptionHandling>
</ExceptionHandling>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking>
|
| ︙ | ︙ | |||
492 493 494 495 496 497 498 |
<MkTypLibCompatible>true</MkTypLibCompatible>
<SuppressStartupBanner>true</SuppressStartupBanner>
<TargetEnvironment>Itanium</TargetEnvironment>
<TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName>
</Midl>
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
| | | 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 |
<MkTypLibCompatible>true</MkTypLibCompatible>
<SuppressStartupBanner>true</SuppressStartupBanner>
<TargetEnvironment>Itanium</TargetEnvironment>
<TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName>
</Midl>
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<ExceptionHandling>
</ExceptionHandling>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking>
|
| ︙ | ︙ | |||
537 538 539 540 541 542 543 |
<MkTypLibCompatible>true</MkTypLibCompatible>
<SuppressStartupBanner>true</SuppressStartupBanner>
<TargetEnvironment>X64</TargetEnvironment>
<TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName>
</Midl>
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
| | | | 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 |
<MkTypLibCompatible>true</MkTypLibCompatible>
<SuppressStartupBanner>true</SuppressStartupBanner>
<TargetEnvironment>X64</TargetEnvironment>
<TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName>
</Midl>
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<ExceptionHandling>
</ExceptionHandling>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking>
<PrecompiledHeaderOutputFile>$(IntDir)zlibvc.pch</PrecompiledHeaderOutputFile>
|
| ︙ | ︙ | |||
560 561 562 563 564 565 566 |
<SuppressStartupBanner>true</SuppressStartupBanner>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x040c</Culture>
</ResourceCompile>
<Link>
| | < < < < | | 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 |
<SuppressStartupBanner>true</SuppressStartupBanner>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x040c</Culture>
</ResourceCompile>
<Link>
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)zlibwapi.dll</OutputFile>
<SuppressStartupBanner>true</SuppressStartupBanner>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<ModuleDefinitionFile>.\zlibvc.def</ModuleDefinitionFile>
<ProgramDatabaseFile>$(OutDir)zlibwapi.pdb</ProgramDatabaseFile>
<GenerateMapFile>true</GenerateMapFile>
<MapFileName>$(OutDir)zlibwapi.map</MapFileName>
<SubSystem>Windows</SubSystem>
<ImportLibrary>$(OutDir)zlibwapi.lib</ImportLibrary>
<TargetMachine>MachineX64</TargetMachine>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Itanium'">
<Midl>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MkTypLibCompatible>true</MkTypLibCompatible>
<SuppressStartupBanner>true</SuppressStartupBanner>
<TargetEnvironment>Itanium</TargetEnvironment>
<TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName>
</Midl>
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<ExceptionHandling>
</ExceptionHandling>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking>
|
| ︙ | ︙ | |||
632 633 634 635 636 637 638 |
<ClCompile Include="..\..\..\crc32.c" />
<ClCompile Include="..\..\..\deflate.c" />
<ClCompile Include="..\..\..\gzclose.c" />
<ClCompile Include="..\..\..\gzlib.c" />
<ClCompile Include="..\..\..\gzread.c" />
<ClCompile Include="..\..\..\gzwrite.c" />
<ClCompile Include="..\..\..\infback.c" />
| < < < < < < < < | 616 617 618 619 620 621 622 623 624 625 626 627 628 629 |
<ClCompile Include="..\..\..\crc32.c" />
<ClCompile Include="..\..\..\deflate.c" />
<ClCompile Include="..\..\..\gzclose.c" />
<ClCompile Include="..\..\..\gzlib.c" />
<ClCompile Include="..\..\..\gzread.c" />
<ClCompile Include="..\..\..\gzwrite.c" />
<ClCompile Include="..\..\..\infback.c" />
<ClCompile Include="..\..\..\inffast.c" />
<ClCompile Include="..\..\..\inflate.c" />
<ClCompile Include="..\..\..\inftrees.c" />
<ClCompile Include="..\..\minizip\ioapi.c" />
<ClCompile Include="..\..\minizip\iowin32.c" />
<ClCompile Include="..\..\..\trees.c" />
<ClCompile Include="..\..\..\uncompr.c" />
|
| ︙ | ︙ |
Changes to compat/zlib/contrib/vstudio/vc9/miniunz.vcproj.
| ︙ | ︙ | |||
538 539 540 541 542 543 544 | </Configuration> </Configurations> <References> </References> <Files> <Filter Name="Source Files" | | | 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 | </Configuration> </Configurations> <References> </References> <Files> <Filter Name="Source Files" Filter="cpp;c;cxx;def;odl;idl;hpj;bat" > <File RelativePath="..\..\minizip\miniunz.c" > </File> </Filter> <Filter |
| ︙ | ︙ |
Changes to compat/zlib/contrib/vstudio/vc9/minizip.vcproj.
| ︙ | ︙ | |||
535 536 537 538 539 540 541 | </Configuration> </Configurations> <References> </References> <Files> <Filter Name="Source Files" | | | 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 | </Configuration> </Configurations> <References> </References> <Files> <Filter Name="Source Files" Filter="cpp;c;cxx;def;odl;idl;hpj;bat" > <File RelativePath="..\..\minizip\minizip.c" > </File> </Filter> <Filter |
| ︙ | ︙ |
Changes to compat/zlib/contrib/vstudio/vc9/testzlib.vcproj.
| ︙ | ︙ | |||
44 45 46 47 48 49 50 | <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories="..\..\.." | | | 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories="..\..\.." PreprocessorDefinitions="WIN32;ZLIB_WINAPI;_DEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS" MinimalRebuild="true" BasicRuntimeChecks="0" RuntimeLibrary="1" BufferSecurityCheck="false" UsePrecompiledHeader="0" AssemblerOutput="4" AssemblerListingLocation="$(IntDir)\" |
| ︙ | ︙ | |||
67 68 69 70 71 72 73 | Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" | < | 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" OutputFile="$(OutDir)/testzlib.exe" LinkIncremental="2" GenerateManifest="false" GenerateDebugInformation="true" ProgramDatabaseFile="$(OutDir)/testzlib.pdb" SubSystem="1" RandomizedBaseAddress="1" |
| ︙ | ︙ | |||
124 125 126 127 128 129 130 | /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" AdditionalIncludeDirectories="..\..\.." | | < | 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 | /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" AdditionalIncludeDirectories="..\..\.." PreprocessorDefinitions="WIN32;ZLIB_WINAPI;_DEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS" BasicRuntimeChecks="0" RuntimeLibrary="3" BufferSecurityCheck="false" AssemblerListingLocation="$(IntDir)\" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" GenerateManifest="false" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" |
| ︙ | ︙ | |||
513 514 515 516 517 518 519 | /> <Tool Name="VCCLCompilerTool" Optimization="2" InlineFunctionExpansion="1" OmitFramePointers="true" AdditionalIncludeDirectories="..\..\.." | | | 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 | /> <Tool Name="VCCLCompilerTool" Optimization="2" InlineFunctionExpansion="1" OmitFramePointers="true" AdditionalIncludeDirectories="..\..\.." PreprocessorDefinitions="WIN32;ZLIB_WINAPI;NDEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS" StringPooling="true" BasicRuntimeChecks="0" RuntimeLibrary="0" BufferSecurityCheck="false" EnableFunctionLevelLinking="true" UsePrecompiledHeader="0" AssemblerListingLocation="$(IntDir)\" |
| ︙ | ︙ | |||
536 537 538 539 540 541 542 | Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" | < | 534 535 536 537 538 539 540 541 542 543 544 545 546 547 | Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" OutputFile="$(OutDir)/testzlib.exe" LinkIncremental="1" GenerateManifest="false" GenerateDebugInformation="true" SubSystem="1" OptimizeReferences="2" EnableCOMDATFolding="2" |
| ︙ | ︙ | |||
596 597 598 599 600 601 602 | /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" AdditionalIncludeDirectories="..\..\.." | | < | 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 | /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" AdditionalIncludeDirectories="..\..\.." PreprocessorDefinitions="WIN32;ZLIB_WINAPI;NDEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS" BasicRuntimeChecks="0" RuntimeLibrary="0" BufferSecurityCheck="false" AssemblerListingLocation="$(IntDir)\" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" GenerateManifest="false" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" |
| ︙ | ︙ | |||
729 730 731 732 733 734 735 | </Configuration> </Configurations> <References> </References> <Files> <Filter Name="Source Files" | | | 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 | </Configuration> </Configurations> <References> </References> <Files> <Filter Name="Source Files" Filter="cpp;c;cxx;def;odl;idl;hpj;bat" > <File RelativePath="..\..\..\adler32.c" > </File> <File RelativePath="..\..\..\compress.c" |
| ︙ | ︙ | |||
752 753 754 755 756 757 758 | > </File> <File RelativePath="..\..\..\infback.c" > </File> <File | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 748 749 750 751 752 753 754 755 756 757 758 759 760 761 | > </File> <File RelativePath="..\..\..\infback.c" > </File> <File RelativePath="..\..\..\inffast.c" > </File> <File RelativePath="..\..\..\inflate.c" > </File> |
| ︙ | ︙ |
Changes to compat/zlib/contrib/vstudio/vc9/testzlibdll.vcproj.
| ︙ | ︙ | |||
538 539 540 541 542 543 544 | </Configuration> </Configurations> <References> </References> <Files> <Filter Name="Source Files" | | | 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 | </Configuration> </Configurations> <References> </References> <Files> <Filter Name="Source Files" Filter="cpp;c;cxx;def;odl;idl;hpj;bat" > <File RelativePath="..\..\testzlib\testzlib.c" > </File> </Filter> <Filter |
| ︙ | ︙ |
Changes to compat/zlib/contrib/vstudio/vc9/zlib.rc.
1 2 3 4 | #include <windows.h> #define IDR_VERSION1 1 IDR_VERSION1 VERSIONINFO MOVEABLE IMPURE LOADONCALL DISCARDABLE | | | | | | 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 |
#include <windows.h>
#define IDR_VERSION1 1
IDR_VERSION1 VERSIONINFO MOVEABLE IMPURE LOADONCALL DISCARDABLE
FILEVERSION 1, 3, 0, 0
PRODUCTVERSION 1, 3, 0, 0
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
FILEFLAGS 0
FILEOS VOS_DOS_WINDOWS32
FILETYPE VFT_DLL
FILESUBTYPE 0 // not used
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904E4"
//language ID = U.S. English, char set = Windows, Multilingual
BEGIN
VALUE "FileDescription", "zlib data compression and ZIP file I/O library\0"
VALUE "FileVersion", "1.3.0\0"
VALUE "InternalName", "zlib\0"
VALUE "OriginalFilename", "zlibwapi.dll\0"
VALUE "ProductName", "ZLib.DLL\0"
VALUE "Comments","DLL support by Alessandro Iacopetti & Gilles Vollant\0"
VALUE "LegalCopyright", "(C) 1995-2023 Jean-loup Gailly & Mark Adler\0"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x0409, 1252
END
END
|
Changes to compat/zlib/contrib/vstudio/vc9/zlibstat.vcproj.
| ︙ | ︙ | |||
43 44 45 46 47 48 49 | /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" Optimization="0" | | | 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories="..\..\.." PreprocessorDefinitions="WIN32;ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS" ExceptionHandling="0" RuntimeLibrary="1" BufferSecurityCheck="false" PrecompiledHeaderFile="$(IntDir)/zlibstat.pch" AssemblerListingLocation="$(IntDir)\" ObjectFile="$(IntDir)\" |
| ︙ | ︙ | |||
117 118 119 120 121 122 123 | <Tool Name="VCMIDLTool" TargetEnvironment="3" /> <Tool Name="VCCLCompilerTool" Optimization="0" | | | 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 | <Tool Name="VCMIDLTool" TargetEnvironment="3" /> <Tool Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories="..\..\.." PreprocessorDefinitions="ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64" ExceptionHandling="0" RuntimeLibrary="3" BufferSecurityCheck="false" PrecompiledHeaderFile="$(IntDir)/zlibstat.pch" AssemblerListingLocation="$(IntDir)\" ObjectFile="$(IntDir)\" |
| ︙ | ︙ | |||
191 192 193 194 195 196 197 | <Tool Name="VCMIDLTool" TargetEnvironment="2" /> <Tool Name="VCCLCompilerTool" Optimization="0" | | | 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 | <Tool Name="VCMIDLTool" TargetEnvironment="2" /> <Tool Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories="..\..\.." PreprocessorDefinitions="ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64" ExceptionHandling="0" RuntimeLibrary="3" BufferSecurityCheck="false" PrecompiledHeaderFile="$(IntDir)/zlibstat.pch" AssemblerListingLocation="$(IntDir)\" ObjectFile="$(IntDir)\" |
| ︙ | ︙ | |||
264 265 266 267 268 269 270 | /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" InlineFunctionExpansion="1" | | | | 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 | /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" InlineFunctionExpansion="1" AdditionalIncludeDirectories="..\..\.." PreprocessorDefinitions="WIN32;ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS" StringPooling="true" ExceptionHandling="0" RuntimeLibrary="0" BufferSecurityCheck="false" EnableFunctionLevelLinking="true" PrecompiledHeaderFile="$(IntDir)/zlibstat.pch" AssemblerListingLocation="$(IntDir)\" |
| ︙ | ︙ | |||
291 292 293 294 295 296 297 | /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLibrarianTool" AdditionalOptions="/MACHINE:X86 /NODEFAULTLIB" | < | 291 292 293 294 295 296 297 298 299 300 301 302 303 304 | /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLibrarianTool" AdditionalOptions="/MACHINE:X86 /NODEFAULTLIB" OutputFile="$(OutDir)\zlibstat.lib" SuppressStartupBanner="true" /> <Tool Name="VCALinkTool" /> <Tool |
| ︙ | ︙ | |||
339 340 341 342 343 344 345 | <Tool Name="VCMIDLTool" TargetEnvironment="3" /> <Tool Name="VCCLCompilerTool" InlineFunctionExpansion="1" | | | | 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 | <Tool Name="VCMIDLTool" TargetEnvironment="3" /> <Tool Name="VCCLCompilerTool" InlineFunctionExpansion="1" AdditionalIncludeDirectories="..\..\.." PreprocessorDefinitions="ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64" StringPooling="true" ExceptionHandling="0" RuntimeLibrary="2" BufferSecurityCheck="false" EnableFunctionLevelLinking="true" PrecompiledHeaderFile="$(IntDir)/zlibstat.pch" AssemblerListingLocation="$(IntDir)\" |
| ︙ | ︙ | |||
366 367 368 369 370 371 372 | /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLibrarianTool" AdditionalOptions="/MACHINE:AMD64 /NODEFAULTLIB" | < | 365 366 367 368 369 370 371 372 373 374 375 376 377 378 | /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLibrarianTool" AdditionalOptions="/MACHINE:AMD64 /NODEFAULTLIB" OutputFile="$(OutDir)\zlibstat.lib" SuppressStartupBanner="true" /> <Tool Name="VCALinkTool" /> <Tool |
| ︙ | ︙ | |||
414 415 416 417 418 419 420 | <Tool Name="VCMIDLTool" TargetEnvironment="2" /> <Tool Name="VCCLCompilerTool" InlineFunctionExpansion="1" | | | 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 | <Tool Name="VCMIDLTool" TargetEnvironment="2" /> <Tool Name="VCCLCompilerTool" InlineFunctionExpansion="1" AdditionalIncludeDirectories="..\..\.." PreprocessorDefinitions="ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64" StringPooling="true" ExceptionHandling="0" RuntimeLibrary="2" BufferSecurityCheck="false" EnableFunctionLevelLinking="true" PrecompiledHeaderFile="$(IntDir)/zlibstat.pch" |
| ︙ | ︙ | |||
487 488 489 490 491 492 493 | /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" InlineFunctionExpansion="1" | | | 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 | /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" InlineFunctionExpansion="1" AdditionalIncludeDirectories="..\..\.." PreprocessorDefinitions="WIN32;ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS" StringPooling="true" ExceptionHandling="0" RuntimeLibrary="0" BufferSecurityCheck="false" EnableFunctionLevelLinking="true" PrecompiledHeaderFile="$(IntDir)/zlibstat.pch" |
| ︙ | ︙ | |||
561 562 563 564 565 566 567 | <Tool Name="VCMIDLTool" TargetEnvironment="3" /> <Tool Name="VCCLCompilerTool" InlineFunctionExpansion="1" | | | 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 | <Tool Name="VCMIDLTool" TargetEnvironment="3" /> <Tool Name="VCCLCompilerTool" InlineFunctionExpansion="1" AdditionalIncludeDirectories="..\..\.." PreprocessorDefinitions="ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64" StringPooling="true" ExceptionHandling="0" RuntimeLibrary="2" BufferSecurityCheck="false" EnableFunctionLevelLinking="true" PrecompiledHeaderFile="$(IntDir)/zlibstat.pch" |
| ︙ | ︙ | |||
635 636 637 638 639 640 641 | <Tool Name="VCMIDLTool" TargetEnvironment="2" /> <Tool Name="VCCLCompilerTool" InlineFunctionExpansion="1" | | | 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 | <Tool Name="VCMIDLTool" TargetEnvironment="2" /> <Tool Name="VCCLCompilerTool" InlineFunctionExpansion="1" AdditionalIncludeDirectories="..\..\.." PreprocessorDefinitions="ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64" StringPooling="true" ExceptionHandling="0" RuntimeLibrary="2" BufferSecurityCheck="false" EnableFunctionLevelLinking="true" PrecompiledHeaderFile="$(IntDir)/zlibstat.pch" |
| ︙ | ︙ | |||
729 730 731 732 733 734 735 | > </File> <File RelativePath="..\..\..\infback.c" > </File> <File | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 727 728 729 730 731 732 733 734 735 736 737 738 739 740 | > </File> <File RelativePath="..\..\..\infback.c" > </File> <File RelativePath="..\..\..\inffast.c" > </File> <File RelativePath="..\..\..\inflate.c" > </File> |
| ︙ | ︙ |
Changes to compat/zlib/contrib/vstudio/vc9/zlibvc.def.
1 2 3 | LIBRARY ; zlib data compression and ZIP file I/O library | | | 1 2 3 4 5 6 7 8 9 10 11 |
LIBRARY
; zlib data compression and ZIP file I/O library
VERSION 1.3
EXPORTS
adler32 @1
compress @2
crc32 @3
deflate @4
deflateCopy @5
|
| ︙ | ︙ |
Changes to compat/zlib/contrib/vstudio/vc9/zlibvc.vcproj.
| ︙ | ︙ | |||
49 50 51 52 53 54 55 | SuppressStartupBanner="true" TargetEnvironment="1" TypeLibraryName="$(OutDir)/zlibvc.tlb" /> <Tool Name="VCCLCompilerTool" Optimization="0" | | | | 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | SuppressStartupBanner="true" TargetEnvironment="1" TypeLibraryName="$(OutDir)/zlibvc.tlb" /> <Tool Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories="..\..\.." PreprocessorDefinitions="WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI" ExceptionHandling="0" RuntimeLibrary="1" BufferSecurityCheck="false" PrecompiledHeaderFile="$(IntDir)/zlibvc.pch" AssemblerListingLocation="$(IntDir)\" ObjectFile="$(IntDir)\" ProgramDataBaseFileName="$(OutDir)\" |
| ︙ | ︙ | |||
77 78 79 80 81 82 83 | /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalOptions="/MACHINE:I386" | < | 77 78 79 80 81 82 83 84 85 86 87 88 89 90 | /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalOptions="/MACHINE:I386" OutputFile="$(OutDir)\zlibwapi.dll" LinkIncremental="2" SuppressStartupBanner="true" GenerateManifest="false" ModuleDefinitionFile=".\zlibvc.def" GenerateDebugInformation="true" ProgramDatabaseFile="$(OutDir)/zlibwapi.pdb" |
| ︙ | ︙ | |||
146 147 148 149 150 151 152 | SuppressStartupBanner="true" TargetEnvironment="3" TypeLibraryName="$(OutDir)/zlibvc.tlb" /> <Tool Name="VCCLCompilerTool" Optimization="0" | | | | 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 | SuppressStartupBanner="true" TargetEnvironment="3" TypeLibraryName="$(OutDir)/zlibvc.tlb" /> <Tool Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories="..\..\.." PreprocessorDefinitions="WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;WIN64" ExceptionHandling="0" RuntimeLibrary="3" BufferSecurityCheck="false" PrecompiledHeaderFile="$(IntDir)/zlibvc.pch" AssemblerListingLocation="$(IntDir)\" ObjectFile="$(IntDir)\" ProgramDataBaseFileName="$(OutDir)\" |
| ︙ | ︙ | |||
173 174 175 176 177 178 179 | Culture="1036" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" | < | 172 173 174 175 176 177 178 179 180 181 182 183 184 185 | Culture="1036" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" OutputFile="$(OutDir)\zlibwapi.dll" LinkIncremental="2" SuppressStartupBanner="true" GenerateManifest="false" ModuleDefinitionFile=".\zlibvc.def" GenerateDebugInformation="true" ProgramDatabaseFile="$(OutDir)/zlibwapi.pdb" |
| ︙ | ︙ | |||
241 242 243 244 245 246 247 | SuppressStartupBanner="true" TargetEnvironment="2" TypeLibraryName="$(OutDir)/zlibvc.tlb" /> <Tool Name="VCCLCompilerTool" Optimization="0" | | | 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 | SuppressStartupBanner="true" TargetEnvironment="2" TypeLibraryName="$(OutDir)/zlibvc.tlb" /> <Tool Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories="..\..\.." PreprocessorDefinitions="WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;WIN64" ExceptionHandling="0" RuntimeLibrary="3" BufferSecurityCheck="false" PrecompiledHeaderFile="$(IntDir)/zlibvc.pch" AssemblerListingLocation="$(IntDir)\" ObjectFile="$(IntDir)\" |
| ︙ | ︙ | |||
336 337 338 339 340 341 342 | SuppressStartupBanner="true" TargetEnvironment="1" TypeLibraryName="$(OutDir)/zlibvc.tlb" /> <Tool Name="VCCLCompilerTool" InlineFunctionExpansion="1" | | | 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 | SuppressStartupBanner="true" TargetEnvironment="1" TypeLibraryName="$(OutDir)/zlibvc.tlb" /> <Tool Name="VCCLCompilerTool" InlineFunctionExpansion="1" AdditionalIncludeDirectories="..\..\.." PreprocessorDefinitions="WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI" StringPooling="true" ExceptionHandling="0" RuntimeLibrary="2" BufferSecurityCheck="false" EnableFunctionLevelLinking="true" PrecompiledHeaderFile="$(IntDir)/zlibvc.pch" |
| ︙ | ︙ | |||
436 437 438 439 440 441 442 | SuppressStartupBanner="true" TargetEnvironment="3" TypeLibraryName="$(OutDir)/zlibvc.tlb" /> <Tool Name="VCCLCompilerTool" InlineFunctionExpansion="1" | | | 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 | SuppressStartupBanner="true" TargetEnvironment="3" TypeLibraryName="$(OutDir)/zlibvc.tlb" /> <Tool Name="VCCLCompilerTool" InlineFunctionExpansion="1" AdditionalIncludeDirectories="..\..\.." PreprocessorDefinitions="WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;WIN64" StringPooling="true" ExceptionHandling="0" RuntimeLibrary="2" BufferSecurityCheck="false" EnableFunctionLevelLinking="true" PrecompiledHeaderFile="$(IntDir)/zlibvc.pch" |
| ︙ | ︙ | |||
534 535 536 537 538 539 540 | SuppressStartupBanner="true" TargetEnvironment="2" TypeLibraryName="$(OutDir)/zlibvc.tlb" /> <Tool Name="VCCLCompilerTool" InlineFunctionExpansion="1" | | | 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 | SuppressStartupBanner="true" TargetEnvironment="2" TypeLibraryName="$(OutDir)/zlibvc.tlb" /> <Tool Name="VCCLCompilerTool" InlineFunctionExpansion="1" AdditionalIncludeDirectories="..\..\.." PreprocessorDefinitions="WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;WIN64" StringPooling="true" ExceptionHandling="0" RuntimeLibrary="2" BufferSecurityCheck="false" EnableFunctionLevelLinking="true" PrecompiledHeaderFile="$(IntDir)/zlibvc.pch" |
| ︙ | ︙ | |||
632 633 634 635 636 637 638 | SuppressStartupBanner="true" TargetEnvironment="1" TypeLibraryName="$(OutDir)/zlibvc.tlb" /> <Tool Name="VCCLCompilerTool" InlineFunctionExpansion="1" | | | | 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 | SuppressStartupBanner="true" TargetEnvironment="1" TypeLibraryName="$(OutDir)/zlibvc.tlb" /> <Tool Name="VCCLCompilerTool" InlineFunctionExpansion="1" AdditionalIncludeDirectories="..\..\.." PreprocessorDefinitions="WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI" StringPooling="true" ExceptionHandling="0" RuntimeLibrary="0" BufferSecurityCheck="false" EnableFunctionLevelLinking="true" PrecompiledHeaderFile="$(IntDir)/zlibvc.pch" AssemblerOutput="2" |
| ︙ | ︙ | |||
662 663 664 665 666 667 668 | /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalOptions="/MACHINE:I386" | < | 660 661 662 663 664 665 666 667 668 669 670 671 672 673 | /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalOptions="/MACHINE:I386" OutputFile="$(OutDir)\zlibwapi.dll" LinkIncremental="1" SuppressStartupBanner="true" GenerateManifest="false" IgnoreAllDefaultLibraries="false" ModuleDefinitionFile=".\zlibvc.def" ProgramDatabaseFile="$(OutDir)/zlibwapi.pdb" |
| ︙ | ︙ | |||
733 734 735 736 737 738 739 | SuppressStartupBanner="true" TargetEnvironment="3" TypeLibraryName="$(OutDir)/zlibvc.tlb" /> <Tool Name="VCCLCompilerTool" InlineFunctionExpansion="1" | | | | 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 | SuppressStartupBanner="true" TargetEnvironment="3" TypeLibraryName="$(OutDir)/zlibvc.tlb" /> <Tool Name="VCCLCompilerTool" InlineFunctionExpansion="1" AdditionalIncludeDirectories="..\..\.." PreprocessorDefinitions="_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;WIN64" StringPooling="true" ExceptionHandling="0" RuntimeLibrary="2" BufferSecurityCheck="false" EnableFunctionLevelLinking="true" PrecompiledHeaderFile="$(IntDir)/zlibvc.pch" AssemblerOutput="2" |
| ︙ | ︙ | |||
762 763 764 765 766 767 768 | Culture="1036" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" | < | 759 760 761 762 763 764 765 766 767 768 769 770 771 772 | Culture="1036" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" OutputFile="$(OutDir)\zlibwapi.dll" LinkIncremental="1" SuppressStartupBanner="true" GenerateManifest="false" IgnoreAllDefaultLibraries="false" ModuleDefinitionFile=".\zlibvc.def" ProgramDatabaseFile="$(OutDir)/zlibwapi.pdb" |
| ︙ | ︙ | |||
832 833 834 835 836 837 838 | SuppressStartupBanner="true" TargetEnvironment="2" TypeLibraryName="$(OutDir)/zlibvc.tlb" /> <Tool Name="VCCLCompilerTool" InlineFunctionExpansion="1" | | | 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 | SuppressStartupBanner="true" TargetEnvironment="2" TypeLibraryName="$(OutDir)/zlibvc.tlb" /> <Tool Name="VCCLCompilerTool" InlineFunctionExpansion="1" AdditionalIncludeDirectories="..\..\.." PreprocessorDefinitions="_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;WIN64" StringPooling="true" ExceptionHandling="0" RuntimeLibrary="2" BufferSecurityCheck="false" EnableFunctionLevelLinking="true" PrecompiledHeaderFile="$(IntDir)/zlibvc.pch" |
| ︙ | ︙ | |||
946 947 948 949 950 951 952 | > </File> <File RelativePath="..\..\..\infback.c" > </File> <File | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 942 943 944 945 946 947 948 949 950 951 952 953 954 955 | > </File> <File RelativePath="..\..\..\infback.c" > </File> <File RelativePath="..\..\..\inffast.c" > </File> <File RelativePath="..\..\..\inflate.c" > </File> |
| ︙ | ︙ |
Changes to compat/zlib/crc32.c.
| ︙ | ︙ | |||
94 95 96 97 98 99 100 |
# define W 4
typedef Z_U4 z_word_t;
# else
# undef W
# endif
#endif
| < < < < | < < > > > > > > > > > > > > > > > > > > > > | > > > > > > > | > > > > > > > > > > > | > > > > > > > > > > > > > > > > | < | | | | < | < < < | 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 |
# define W 4
typedef Z_U4 z_word_t;
# else
# undef W
# endif
#endif
/* If available, use the ARM processor CRC32 instruction. */
#if defined(__aarch64__) && defined(__ARM_FEATURE_CRC32) && W == 8
# define ARMCRC32
#endif
#if defined(W) && (!defined(ARMCRC32) || defined(DYNAMIC_CRC_TABLE))
/*
Swap the bytes in a z_word_t to convert between little and big endian. Any
self-respecting compiler will optimize this to a single machine byte-swap
instruction, if one is available. This assumes that word_t is either 32 bits
or 64 bits.
*/
local z_word_t byte_swap(z_word_t word) {
# if W == 8
return
(word & 0xff00000000000000) >> 56 |
(word & 0xff000000000000) >> 40 |
(word & 0xff0000000000) >> 24 |
(word & 0xff00000000) >> 8 |
(word & 0xff000000) << 8 |
(word & 0xff0000) << 24 |
(word & 0xff00) << 40 |
(word & 0xff) << 56;
# else /* W == 4 */
return
(word & 0xff000000) >> 24 |
(word & 0xff0000) >> 8 |
(word & 0xff00) << 8 |
(word & 0xff) << 24;
# endif
}
#endif
#ifdef DYNAMIC_CRC_TABLE
/* =========================================================================
* Table of powers of x for combining CRC-32s, filled in by make_crc_table()
* below.
*/
local z_crc_t FAR x2n_table[32];
#else
/* =========================================================================
* Tables for byte-wise and braided CRC-32 calculations, and a table of powers
* of x for combining CRC-32s, all made by make_crc_table().
*/
# include "crc32.h"
#endif
/* CRC polynomial. */
#define POLY 0xedb88320 /* p(x) reflected, with x^32 implied */
/*
Return a(x) multiplied by b(x) modulo p(x), where p(x) is the CRC polynomial,
reflected. For speed, this requires that a not be zero.
*/
local z_crc_t multmodp(z_crc_t a, z_crc_t b) {
z_crc_t m, p;
m = (z_crc_t)1 << 31;
p = 0;
for (;;) {
if (a & m) {
p ^= b;
if ((a & (m - 1)) == 0)
break;
}
m >>= 1;
b = b & 1 ? (b >> 1) ^ POLY : b >> 1;
}
return p;
}
/*
Return x^(n * 2^k) modulo p(x). Requires that x2n_table[] has been
initialized.
*/
local z_crc_t x2nmodp(z_off64_t n, unsigned k) {
z_crc_t p;
p = (z_crc_t)1 << 31; /* x^0 == 1 */
while (n) {
if (n & 1)
p = multmodp(x2n_table[k & 31], p);
n >>= 1;
k++;
}
return p;
}
#ifdef DYNAMIC_CRC_TABLE
/* =========================================================================
* Build the tables for byte-wise and braided CRC-32 calculations, and a table
* of powers of x for combining CRC-32s.
*/
local z_crc_t FAR crc_table[256];
#ifdef W
local z_word_t FAR crc_big_table[256];
local z_crc_t FAR crc_braid_table[W][256];
local z_word_t FAR crc_braid_big_table[W][256];
local void braid(z_crc_t [][256], z_word_t [][256], int, int);
#endif
#ifdef MAKECRCH
local void write_table(FILE *, const z_crc_t FAR *, int);
local void write_table32hi(FILE *, const z_word_t FAR *, int);
local void write_table64(FILE *, const z_word_t FAR *, int);
#endif /* MAKECRCH */
/*
Define a once() function depending on the availability of atomics. If this is
compiled with DYNAMIC_CRC_TABLE defined, and if CRCs will be computed in
multiple threads, and if atomics are not available, then get_crc_table() must
be called to initialize the tables and must return before any threads are
allowed to compute or combine CRCs.
*/
/* Definition of once functionality. */
typedef struct once_s once_t;
/* Check for the availability of atomics. */
#if defined(__STDC__) && __STDC_VERSION__ >= 201112L && \
!defined(__STDC_NO_ATOMICS__)
#include <stdatomic.h>
/* Structure for once(), which must be initialized with ONCE_INIT. */
struct once_s {
atomic_flag begun;
atomic_int done;
};
#define ONCE_INIT {ATOMIC_FLAG_INIT, 0}
/*
Run the provided init() function exactly once, even if multiple threads
invoke once() at the same time. The state must be a once_t initialized with
ONCE_INIT.
*/
local void once(once_t *state, void (*init)(void)) {
if (!atomic_load(&state->done)) {
if (atomic_flag_test_and_set(&state->begun))
while (!atomic_load(&state->done))
;
else {
init();
atomic_store(&state->done, 1);
|
| ︙ | ︙ | |||
209 210 211 212 213 214 215 |
volatile int begun;
volatile int done;
};
#define ONCE_INIT {0, 0}
/* Test and set. Alas, not atomic, but tries to minimize the period of
vulnerability. */
| < | < < | < < < | 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 |
volatile int begun;
volatile int done;
};
#define ONCE_INIT {0, 0}
/* Test and set. Alas, not atomic, but tries to minimize the period of
vulnerability. */
local int test_and_set(int volatile *flag) {
int was;
was = *flag;
*flag = 1;
return was;
}
/* Run the provided init() function once. This is not thread-safe. */
local void once(once_t *state, void (*init)(void)) {
if (!state->done) {
if (test_and_set(&state->begun))
while (!state->done)
;
else {
init();
state->done = 1;
|
| ︙ | ︙ | |||
266 267 268 269 270 271 272 | repeat for all eight bits of q. The table is simply the CRC of all possible eight bit values. This is all the information needed to generate CRCs on data a byte at a time for all combinations of CRC register values and incoming bytes. */ | | < | 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 |
repeat for all eight bits of q.
The table is simply the CRC of all possible eight bit values. This is all the
information needed to generate CRCs on data a byte at a time for all
combinations of CRC register values and incoming bytes.
*/
local void make_crc_table(void) {
unsigned i, j, n;
z_crc_t p;
/* initialize the CRC of bytes tables */
for (i = 0; i < 256; i++) {
p = i;
for (j = 0; j < 8; j++)
|
| ︙ | ︙ | |||
434 435 436 437 438 439 440 | #ifdef MAKECRCH /* Write the 32-bit values in table[0..k-1] to out, five per line in hexadecimal separated by commas. */ | | < < < < | < < < < | < < < < | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < | 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 |
#ifdef MAKECRCH
/*
Write the 32-bit values in table[0..k-1] to out, five per line in
hexadecimal separated by commas.
*/
local void write_table(FILE *out, const z_crc_t FAR *table, int k) {
int n;
for (n = 0; n < k; n++)
fprintf(out, "%s0x%08lx%s", n == 0 || n % 5 ? "" : " ",
(unsigned long)(table[n]),
n == k - 1 ? "" : (n % 5 == 4 ? ",\n" : ", "));
}
/*
Write the high 32-bits of each value in table[0..k-1] to out, five per line
in hexadecimal separated by commas.
*/
local void write_table32hi(FILE *out, const z_word_t FAR *table, int k) {
int n;
for (n = 0; n < k; n++)
fprintf(out, "%s0x%08lx%s", n == 0 || n % 5 ? "" : " ",
(unsigned long)(table[n] >> 32),
n == k - 1 ? "" : (n % 5 == 4 ? ",\n" : ", "));
}
/*
Write the 64-bit values in table[0..k-1] to out, three per line in
hexadecimal separated by commas. This assumes that if there is a 64-bit
type, then there is also a long long integer type, and it is at least 64
bits. If not, then the type cast and format string can be adjusted
accordingly.
*/
local void write_table64(FILE *out, const z_word_t FAR *table, int k) {
int n;
for (n = 0; n < k; n++)
fprintf(out, "%s0x%016llx%s", n == 0 || n % 3 ? "" : " ",
(unsigned long long)(table[n]),
n == k - 1 ? "" : (n % 3 == 2 ? ",\n" : ", "));
}
/* Actually do the deed. */
int main(void) {
make_crc_table();
return 0;
}
#endif /* MAKECRCH */
#ifdef W
/*
Generate the little and big-endian braid tables for the given n and z_word_t
size w. Each array must have room for w blocks of 256 elements.
*/
local void braid(z_crc_t ltl[][256], z_word_t big[][256], int n, int w) {
int k;
z_crc_t i, p, q;
for (k = 0; k < w; k++) {
p = x2nmodp((n * w + 3 - k) << 3, 0);
ltl[k][0] = 0;
big[w - 1 - k][0] = 0;
for (i = 1; i < 256; i++) {
ltl[k][i] = q = multmodp(i << 24, p);
big[w - 1 - k][i] = byte_swap(q);
}
}
}
#endif
#endif /* DYNAMIC_CRC_TABLE */
/* =========================================================================
* This function can be used by asm versions of crc32(), and to force the
* generation of the CRC tables in a threaded application.
*/
const z_crc_t FAR * ZEXPORT get_crc_table(void) {
#ifdef DYNAMIC_CRC_TABLE
once(&made, make_crc_table);
#endif /* DYNAMIC_CRC_TABLE */
return (const z_crc_t FAR *)crc_table;
}
/* =========================================================================
|
| ︙ | ︙ | |||
606 607 608 609 610 611 612 | Constants empirically determined to maximize speed. These values are from measurements on a Cortex-A57. Your mileage may vary. */ #define Z_BATCH 3990 /* number of words in a batch */ #define Z_BATCH_ZEROS 0xa10d3d0c /* computed from Z_BATCH = 3990 */ #define Z_BATCH_MIN 800 /* fewest words in a final batch */ | | < < | < | | | | 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 |
Constants empirically determined to maximize speed. These values are from
measurements on a Cortex-A57. Your mileage may vary.
*/
#define Z_BATCH 3990 /* number of words in a batch */
#define Z_BATCH_ZEROS 0xa10d3d0c /* computed from Z_BATCH = 3990 */
#define Z_BATCH_MIN 800 /* fewest words in a final batch */
unsigned long ZEXPORT crc32_z(unsigned long crc, const unsigned char FAR *buf,
z_size_t len) {
z_crc_t val;
z_word_t crc1, crc2;
const z_word_t *word;
z_word_t val0, val1, val2;
z_size_t last, last2, i;
z_size_t num;
/* Return initial CRC, if requested. */
if (buf == Z_NULL) return 0;
#ifdef DYNAMIC_CRC_TABLE
once(&made, make_crc_table);
#endif /* DYNAMIC_CRC_TABLE */
/* Pre-condition the CRC */
crc = (~crc) & 0xffffffff;
/* Compute the CRC up to a word boundary. */
while (len && ((z_size_t)buf & 7) != 0) {
len--;
val = *buf++;
__asm__ volatile("crc32b %w0, %w0, %w1" : "+r"(crc) : "r"(val));
}
/* Prepare to compute the CRC on full 64-bit words word[0..num-1]. */
word = (z_word_t const *)buf;
num = len >> 3;
len &= 7;
/* Do three interleaved CRCs to realize the throughput of one crc32x
instruction per cycle. Each CRC is calculated on Z_BATCH words. The
three CRCs are combined into a single CRC after each set of batches. */
while (num >= 3 * Z_BATCH) {
crc1 = 0;
crc2 = 0;
for (i = 0; i < Z_BATCH; i++) {
val0 = word[i];
val1 = word[i + Z_BATCH];
val2 = word[i + 2 * Z_BATCH];
|
| ︙ | ︙ | |||
710 711 712 713 714 715 716 | #ifdef W /* Return the CRC of the W bytes in the word_t data, taking the least-significant byte of the word as the first byte of data, without any pre or post conditioning. This is used to combine the CRCs of each braid. */ | | < < | < < | < < | < | | 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 |
#ifdef W
/*
Return the CRC of the W bytes in the word_t data, taking the
least-significant byte of the word as the first byte of data, without any pre
or post conditioning. This is used to combine the CRCs of each braid.
*/
local z_crc_t crc_word(z_word_t data) {
int k;
for (k = 0; k < W; k++)
data = (data >> 8) ^ crc_table[data & 0xff];
return (z_crc_t)data;
}
local z_word_t crc_word_big(z_word_t data) {
int k;
for (k = 0; k < W; k++)
data = (data << 8) ^
crc_big_table[(data >> ((W - 1) << 3)) & 0xff];
return data;
}
#endif
/* ========================================================================= */
unsigned long ZEXPORT crc32_z(unsigned long crc, const unsigned char FAR *buf,
z_size_t len) {
/* Return initial CRC, if requested. */
if (buf == Z_NULL) return 0;
#ifdef DYNAMIC_CRC_TABLE
once(&made, make_crc_table);
#endif /* DYNAMIC_CRC_TABLE */
/* Pre-condition the CRC */
crc = (~crc) & 0xffffffff;
#ifdef W
/* If provided enough bytes, do a braided CRC calculation. */
if (len >= N * W + W - 1) {
z_size_t blks;
z_word_t const *words;
|
| ︙ | ︙ | |||
768 769 770 771 772 773 774 |
/* Compute the CRC on as many N z_word_t blocks as are available. */
blks = len / (N * W);
len -= blks * N * W;
words = (z_word_t const *)buf;
/* Do endian check at execution time instead of compile time, since ARM
| | | | 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 |
/* Compute the CRC on as many N z_word_t blocks as are available. */
blks = len / (N * W);
len -= blks * N * W;
words = (z_word_t const *)buf;
/* Do endian check at execution time instead of compile time, since ARM
processors can change the endianness at execution time. If the
compiler knows what the endianness will be, it can optimize out the
check and the unused branch. */
endian = 1;
if (*(unsigned char *)&endian) {
/* Little endian. */
z_crc_t crc0;
z_word_t word0;
|
| ︙ | ︙ | |||
1056 1057 1058 1059 1060 1061 1062 |
/* Return the CRC, post-conditioned. */
return crc ^ 0xffffffff;
}
#endif
/* ========================================================================= */
| | < < | < | < < < < | | < < < < | | < < | < < | | < < < < | | 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 |
/* Return the CRC, post-conditioned. */
return crc ^ 0xffffffff;
}
#endif
/* ========================================================================= */
unsigned long ZEXPORT crc32(unsigned long crc, const unsigned char FAR *buf,
uInt len) {
return crc32_z(crc, buf, len);
}
/* ========================================================================= */
uLong ZEXPORT crc32_combine64(uLong crc1, uLong crc2, z_off64_t len2) {
#ifdef DYNAMIC_CRC_TABLE
once(&made, make_crc_table);
#endif /* DYNAMIC_CRC_TABLE */
return multmodp(x2nmodp(len2, 3), crc1) ^ (crc2 & 0xffffffff);
}
/* ========================================================================= */
uLong ZEXPORT crc32_combine(uLong crc1, uLong crc2, z_off_t len2) {
return crc32_combine64(crc1, crc2, (z_off64_t)len2);
}
/* ========================================================================= */
uLong ZEXPORT crc32_combine_gen64(z_off64_t len2) {
#ifdef DYNAMIC_CRC_TABLE
once(&made, make_crc_table);
#endif /* DYNAMIC_CRC_TABLE */
return x2nmodp(len2, 3);
}
/* ========================================================================= */
uLong ZEXPORT crc32_combine_gen(z_off_t len2) {
return crc32_combine_gen64((z_off64_t)len2);
}
/* ========================================================================= */
uLong ZEXPORT crc32_combine_op(uLong crc1, uLong crc2, uLong op) {
return multmodp(op, crc1) ^ (crc2 & 0xffffffff);
}
|
Changes to compat/zlib/deflate.c.
1 | /* deflate.c -- compress data using the deflation algorithm | | | 1 2 3 4 5 6 7 8 9 | /* deflate.c -- compress data using the deflation algorithm * Copyright (C) 1995-2023 Jean-loup Gailly and Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* * ALGORITHM * * The "deflation" process depends on being able to identify portions |
| ︙ | ︙ | |||
48 49 50 51 52 53 54 | */ /* @(#) $Id$ */ #include "deflate.h" const char deflate_copyright[] = | | < < < | < < < | | | | | < < < < < < < < < < < < < < < < | 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 |
*/
/* @(#) $Id$ */
#include "deflate.h"
const char deflate_copyright[] =
" deflate 1.3 Copyright 1995-2023 Jean-loup Gailly and Mark Adler ";
/*
If you use the zlib library in a product, an acknowledgment is welcome
in the documentation of your product. If for some reason you cannot
include such an acknowledgment, I would appreciate that you keep this
copyright string in the executable of your product.
*/
typedef enum {
need_more, /* block not completed, need more input or more output */
block_done, /* block flush performed */
finish_started, /* finish started, need only more output at next deflate */
finish_done /* finish done, accept no more input or output */
} block_state;
typedef block_state (*compress_func)(deflate_state *s, int flush);
/* Compression function. Returns the block state after the call. */
local block_state deflate_stored(deflate_state *s, int flush);
local block_state deflate_fast(deflate_state *s, int flush);
#ifndef FASTEST
local block_state deflate_slow(deflate_state *s, int flush);
#endif
local block_state deflate_rle(deflate_state *s, int flush);
local block_state deflate_huff(deflate_state *s, int flush);
/* ===========================================================================
* Local data
*/
#define NIL 0
/* Tail of hash chains */
|
| ︙ | ︙ | |||
156 157 158 159 160 161 162 | /* =========================================================================== * Update a hash value with the given input byte * IN assertion: all calls to UPDATE_HASH are made with consecutive input * characters, so that a running hash key can be computed from the previous * key instead of complete recalculation each time. */ | | | 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 | /* =========================================================================== * Update a hash value with the given input byte * IN assertion: all calls to UPDATE_HASH are made with consecutive input * characters, so that a running hash key can be computed from the previous * key instead of complete recalculation each time. */ #define UPDATE_HASH(s,h,c) (h = (((h) << s->hash_shift) ^ (c)) & s->hash_mask) /* =========================================================================== * Insert string str in the dictionary and set match_head to the previous head * of the hash chain (the most recent string with same hash key). Return * the previous length of the hash chain. * If this file is compiled with -DFASTEST, the compression level is forced |
| ︙ | ︙ | |||
187 188 189 190 191 192 193 |
/* ===========================================================================
* Initialize the hash table (avoiding 64K overflow for 16 bit systems).
* prev[] will be initialized on the fly.
*/
#define CLEAR_HASH(s) \
do { \
| | | > > > > > | < < | 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 |
/* ===========================================================================
* Initialize the hash table (avoiding 64K overflow for 16 bit systems).
* prev[] will be initialized on the fly.
*/
#define CLEAR_HASH(s) \
do { \
s->head[s->hash_size - 1] = NIL; \
zmemzero((Bytef *)s->head, \
(unsigned)(s->hash_size - 1)*sizeof(*s->head)); \
} while (0)
/* ===========================================================================
* Slide the hash table when sliding the window down (could be avoided with 32
* bit values at the expense of memory usage). We slide even when level == 0 to
* keep the hash table consistent if we switch back to level > 0 later.
*/
#if defined(__has_feature)
# if __has_feature(memory_sanitizer)
__attribute__((no_sanitize("memory")))
# endif
#endif
local void slide_hash(deflate_state *s) {
unsigned n, m;
Posf *p;
uInt wsize = s->w_size;
n = s->hash_size;
p = &s->head[n];
do {
|
| ︙ | ︙ | |||
222 223 224 225 226 227 228 229 230 |
*p = (Pos)(m >= wsize ? m - wsize : NIL);
/* If n is not on any hash chain, prev[n] is garbage but
* its value will never be used.
*/
} while (--n);
#endif
}
/* ========================================================================= */
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > < < < | | < | < < < < | < < | < < | 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 |
*p = (Pos)(m >= wsize ? m - wsize : NIL);
/* If n is not on any hash chain, prev[n] is garbage but
* its value will never be used.
*/
} while (--n);
#endif
}
/* ===========================================================================
* Read a new buffer from the current input stream, update the adler32
* and total number of bytes read. All deflate() input goes through
* this function so some applications may wish to modify it to avoid
* allocating a large strm->next_in buffer and copying from it.
* (See also flush_pending()).
*/
local unsigned read_buf(z_streamp strm, Bytef *buf, unsigned size) {
unsigned len = strm->avail_in;
if (len > size) len = size;
if (len == 0) return 0;
strm->avail_in -= len;
zmemcpy(buf, strm->next_in, len);
if (strm->state->wrap == 1) {
strm->adler = adler32(strm->adler, buf, len);
}
#ifdef GZIP
else if (strm->state->wrap == 2) {
strm->adler = crc32(strm->adler, buf, len);
}
#endif
strm->next_in += len;
strm->total_in += len;
return len;
}
/* ===========================================================================
* Fill the window when the lookahead becomes insufficient.
* Updates strstart and lookahead.
*
* IN assertion: lookahead < MIN_LOOKAHEAD
* OUT assertions: strstart <= window_size-MIN_LOOKAHEAD
* At least one byte has been read, or avail_in == 0; reads are
* performed for at least two bytes (required for the zip translate_eol
* option -- not supported here).
*/
local void fill_window(deflate_state *s) {
unsigned n;
unsigned more; /* Amount of free space at the end of the window. */
uInt wsize = s->w_size;
Assert(s->lookahead < MIN_LOOKAHEAD, "already enough lookahead");
do {
more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart);
/* Deal with !@#$% 64K limit: */
if (sizeof(int) <= 2) {
if (more == 0 && s->strstart == 0 && s->lookahead == 0) {
more = wsize;
} else if (more == (unsigned)(-1)) {
/* Very unlikely, but possible on 16 bit machine if
* strstart == 0 && lookahead == 1 (input done a byte at time)
*/
more--;
}
}
/* If the window is almost full and there is insufficient lookahead,
* move the upper half to the lower one to make room in the upper half.
*/
if (s->strstart >= wsize + MAX_DIST(s)) {
zmemcpy(s->window, s->window + wsize, (unsigned)wsize - more);
s->match_start -= wsize;
s->strstart -= wsize; /* we now have strstart >= MAX_DIST */
s->block_start -= (long) wsize;
if (s->insert > s->strstart)
s->insert = s->strstart;
slide_hash(s);
more += wsize;
}
if (s->strm->avail_in == 0) break;
/* If there was no sliding:
* strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&
* more == window_size - lookahead - strstart
* => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
* => more >= window_size - 2*WSIZE + 2
* In the BIG_MEM or MMAP case (not yet supported),
* window_size == input_size + MIN_LOOKAHEAD &&
* strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.
* Otherwise, window_size == 2*WSIZE so more >= 2.
* If there was sliding, more >= WSIZE. So in all cases, more >= 2.
*/
Assert(more >= 2, "more < 2");
n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more);
s->lookahead += n;
/* Initialize the hash value now that we have some input: */
if (s->lookahead + s->insert >= MIN_MATCH) {
uInt str = s->strstart - s->insert;
s->ins_h = s->window[str];
UPDATE_HASH(s, s->ins_h, s->window[str + 1]);
#if MIN_MATCH != 3
Call UPDATE_HASH() MIN_MATCH-3 more times
#endif
while (s->insert) {
UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]);
#ifndef FASTEST
s->prev[str & s->w_mask] = s->head[s->ins_h];
#endif
s->head[s->ins_h] = (Pos)str;
str++;
s->insert--;
if (s->lookahead + s->insert < MIN_MATCH)
break;
}
}
/* If the whole input has less than MIN_MATCH bytes, ins_h is garbage,
* but this is not important since only literal bytes will be emitted.
*/
} while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0);
/* If the WIN_INIT bytes after the end of the current data have never been
* written, then zero those bytes in order to avoid memory check reports of
* the use of uninitialized (or uninitialised as Julian writes) bytes by
* the longest match routines. Update the high water mark for the next
* time through here. WIN_INIT is set to MAX_MATCH since the longest match
* routines allow scanning to strstart + MAX_MATCH, ignoring lookahead.
*/
if (s->high_water < s->window_size) {
ulg curr = s->strstart + (ulg)(s->lookahead);
ulg init;
if (s->high_water < curr) {
/* Previous high water mark below current data -- zero WIN_INIT
* bytes or up to end of window, whichever is less.
*/
init = s->window_size - curr;
if (init > WIN_INIT)
init = WIN_INIT;
zmemzero(s->window + curr, (unsigned)init);
s->high_water = curr + init;
}
else if (s->high_water < (ulg)curr + WIN_INIT) {
/* High water mark at or above current data, but below current data
* plus WIN_INIT -- zero out to current data plus WIN_INIT, or up
* to end of window, whichever is less.
*/
init = (ulg)curr + WIN_INIT - s->high_water;
if (init > s->window_size - s->high_water)
init = s->window_size - s->high_water;
zmemzero(s->window + s->high_water, (unsigned)init);
s->high_water += init;
}
}
Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD,
"not enough room for search");
}
/* ========================================================================= */
int ZEXPORT deflateInit_(z_streamp strm, int level, const char *version,
int stream_size) {
return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL,
Z_DEFAULT_STRATEGY, version, stream_size);
/* To do: ignore strm->next_in if we use it as window */
}
/* ========================================================================= */
int ZEXPORT deflateInit2_(z_streamp strm, int level, int method,
int windowBits, int memLevel, int strategy,
const char *version, int stream_size) {
deflate_state *s;
int wrap = 1;
static const char my_version[] = ZLIB_VERSION;
if (version == Z_NULL || version[0] != my_version[0] ||
stream_size != sizeof(z_stream)) {
return Z_VERSION_ERROR;
|
| ︙ | ︙ | |||
281 282 283 284 285 286 287 288 289 290 291 292 293 294 |
if (level != 0) level = 1;
#else
if (level == Z_DEFAULT_COMPRESSION) level = 6;
#endif
if (windowBits < 0) { /* suppress zlib wrapper */
wrap = 0;
windowBits = -windowBits;
}
#ifdef GZIP
else if (windowBits > 15) {
wrap = 2; /* write gzip wrapper instead */
windowBits -= 16;
}
| > > | 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 |
if (level != 0) level = 1;
#else
if (level == Z_DEFAULT_COMPRESSION) level = 6;
#endif
if (windowBits < 0) { /* suppress zlib wrapper */
wrap = 0;
if (windowBits < -15)
return Z_STREAM_ERROR;
windowBits = -windowBits;
}
#ifdef GZIP
else if (windowBits > 15) {
wrap = 2; /* write gzip wrapper instead */
windowBits -= 16;
}
|
| ︙ | ︙ | |||
310 311 312 313 314 315 316 |
s->w_bits = (uInt)windowBits;
s->w_size = 1 << s->w_bits;
s->w_mask = s->w_size - 1;
s->hash_bits = (uInt)memLevel + 7;
s->hash_size = 1 << s->hash_bits;
s->hash_mask = s->hash_size - 1;
| | | 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 |
s->w_bits = (uInt)windowBits;
s->w_size = 1 << s->w_bits;
s->w_mask = s->w_size - 1;
s->hash_bits = (uInt)memLevel + 7;
s->hash_size = 1 << s->hash_bits;
s->hash_mask = s->hash_size - 1;
s->hash_shift = ((s->hash_bits + MIN_MATCH-1) / MIN_MATCH);
s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte));
s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos));
s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos));
s->high_water = 0; /* nothing written to s->window yet */
|
| ︙ | ︙ | |||
336 337 338 339 340 341 342 |
* sym_buf starts one-fourth of the way into pending_buf. So there are
* three bytes in sym_buf for every four bytes in pending_buf. Each symbol
* in sym_buf is three bytes -- two for the distance and one for the
* literal/length. As each symbol is consumed, the pointer to the next
* sym_buf value to read moves forward three bytes. From that symbol, up to
* 31 bits are written to pending_buf. The closest the written pending_buf
* bits gets to the next sym_buf symbol to read is just before the last
| | | | | | 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 |
* sym_buf starts one-fourth of the way into pending_buf. So there are
* three bytes in sym_buf for every four bytes in pending_buf. Each symbol
* in sym_buf is three bytes -- two for the distance and one for the
* literal/length. As each symbol is consumed, the pointer to the next
* sym_buf value to read moves forward three bytes. From that symbol, up to
* 31 bits are written to pending_buf. The closest the written pending_buf
* bits gets to the next sym_buf symbol to read is just before the last
* code is written. At that time, 31*(n - 2) bits have been written, just
* after 24*(n - 2) bits have been consumed from sym_buf. sym_buf starts at
* 8*n bits into pending_buf. (Note that the symbol buffer fills when n - 1
* symbols are written.) The closest the writing gets to what is unread is
* then n + 14 bits. Here n is lit_bufsize, which is 16384 by default, and
* can range from 128 to 32768.
*
* Therefore, at a minimum, there are 142 bits of space between what is
* written and what is read in the overlain buffers, so the symbols cannot
* be overwritten by the compressed data. That space is actually 139 bits,
* due to the three-bit fixed-code block header.
*
|
| ︙ | ︙ | |||
386 387 388 389 390 391 392 |
return deflateReset(strm);
}
/* =========================================================================
* Check for a valid deflate stream state. Return 0 if ok, 1 if not.
*/
| | < < | < < | < | 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 |
return deflateReset(strm);
}
/* =========================================================================
* Check for a valid deflate stream state. Return 0 if ok, 1 if not.
*/
local int deflateStateCheck(z_streamp strm) {
deflate_state *s;
if (strm == Z_NULL ||
strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0)
return 1;
s = strm->state;
if (s == Z_NULL || s->strm != strm || (s->status != INIT_STATE &&
#ifdef GZIP
s->status != GZIP_STATE &&
#endif
s->status != EXTRA_STATE &&
s->status != NAME_STATE &&
s->status != COMMENT_STATE &&
s->status != HCRC_STATE &&
s->status != BUSY_STATE &&
s->status != FINISH_STATE))
return 1;
return 0;
}
/* ========================================================================= */
int ZEXPORT deflateSetDictionary(z_streamp strm, const Bytef *dictionary,
uInt dictLength) {
deflate_state *s;
uInt str, n;
int wrap;
unsigned avail;
z_const unsigned char *next;
if (deflateStateCheck(strm) || dictionary == Z_NULL)
|
| ︙ | ︙ | |||
478 479 480 481 482 483 484 |
strm->next_in = next;
strm->avail_in = avail;
s->wrap = wrap;
return Z_OK;
}
/* ========================================================================= */
| | < < | < | < < | 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 |
strm->next_in = next;
strm->avail_in = avail;
s->wrap = wrap;
return Z_OK;
}
/* ========================================================================= */
int ZEXPORT deflateGetDictionary(z_streamp strm, Bytef *dictionary,
uInt *dictLength) {
deflate_state *s;
uInt len;
if (deflateStateCheck(strm))
return Z_STREAM_ERROR;
s = strm->state;
len = s->strstart + s->lookahead;
if (len > s->w_size)
len = s->w_size;
if (dictionary != Z_NULL && len)
zmemcpy(dictionary, s->window + s->strstart + s->lookahead - len, len);
if (dictLength != Z_NULL)
*dictLength = len;
return Z_OK;
}
/* ========================================================================= */
int ZEXPORT deflateResetKeep(z_streamp strm) {
deflate_state *s;
if (deflateStateCheck(strm)) {
return Z_STREAM_ERROR;
}
strm->total_in = strm->total_out = 0;
|
| ︙ | ︙ | |||
536 537 538 539 540 541 542 543 |
adler32(0L, Z_NULL, 0);
s->last_flush = -2;
_tr_init(s);
return Z_OK;
}
| | > > > > | > | > > > > > > | > > > > > > > > > > > | < < < | < < < < | < < < < | 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 |
adler32(0L, Z_NULL, 0);
s->last_flush = -2;
_tr_init(s);
return Z_OK;
}
/* ===========================================================================
* Initialize the "longest match" routines for a new zlib stream
*/
local void lm_init(deflate_state *s) {
s->window_size = (ulg)2L*s->w_size;
CLEAR_HASH(s);
/* Set the default configuration parameters:
*/
s->max_lazy_match = configuration_table[s->level].max_lazy;
s->good_match = configuration_table[s->level].good_length;
s->nice_match = configuration_table[s->level].nice_length;
s->max_chain_length = configuration_table[s->level].max_chain;
s->strstart = 0;
s->block_start = 0L;
s->lookahead = 0;
s->insert = 0;
s->match_length = s->prev_length = MIN_MATCH-1;
s->match_available = 0;
s->ins_h = 0;
}
/* ========================================================================= */
int ZEXPORT deflateReset(z_streamp strm) {
int ret;
ret = deflateResetKeep(strm);
if (ret == Z_OK)
lm_init(strm->state);
return ret;
}
/* ========================================================================= */
int ZEXPORT deflateSetHeader(z_streamp strm, gz_headerp head) {
if (deflateStateCheck(strm) || strm->state->wrap != 2)
return Z_STREAM_ERROR;
strm->state->gzhead = head;
return Z_OK;
}
/* ========================================================================= */
int ZEXPORT deflatePending(z_streamp strm, unsigned *pending, int *bits) {
if (deflateStateCheck(strm)) return Z_STREAM_ERROR;
if (pending != Z_NULL)
*pending = strm->state->pending;
if (bits != Z_NULL)
*bits = strm->state->bi_valid;
return Z_OK;
}
/* ========================================================================= */
int ZEXPORT deflatePrime(z_streamp strm, int bits, int value) {
deflate_state *s;
int put;
if (deflateStateCheck(strm)) return Z_STREAM_ERROR;
s = strm->state;
if (bits < 0 || bits > 16 ||
s->sym_buf < s->pending_out + ((Buf_size + 7) >> 3))
|
| ︙ | ︙ | |||
602 603 604 605 606 607 608 |
value >>= put;
bits -= put;
} while (bits);
return Z_OK;
}
/* ========================================================================= */
| | < < < < | 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 |
value >>= put;
bits -= put;
} while (bits);
return Z_OK;
}
/* ========================================================================= */
int ZEXPORT deflateParams(z_streamp strm, int level, int strategy) {
deflate_state *s;
compress_func func;
if (deflateStateCheck(strm)) return Z_STREAM_ERROR;
s = strm->state;
#ifdef FASTEST
|
| ︙ | ︙ | |||
651 652 653 654 655 656 657 |
s->max_chain_length = configuration_table[level].max_chain;
}
s->strategy = strategy;
return Z_OK;
}
/* ========================================================================= */
| < < | < | < < | | | < < | | > > | | > > < > | > > | < > > > > | | | | > > | < > > | > | | | | | 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 |
s->max_chain_length = configuration_table[level].max_chain;
}
s->strategy = strategy;
return Z_OK;
}
/* ========================================================================= */
int ZEXPORT deflateTune(z_streamp strm, int good_length, int max_lazy,
int nice_length, int max_chain) {
deflate_state *s;
if (deflateStateCheck(strm)) return Z_STREAM_ERROR;
s = strm->state;
s->good_match = (uInt)good_length;
s->max_lazy_match = (uInt)max_lazy;
s->nice_match = nice_length;
s->max_chain_length = (uInt)max_chain;
return Z_OK;
}
/* =========================================================================
* For the default windowBits of 15 and memLevel of 8, this function returns a
* close to exact, as well as small, upper bound on the compressed size. This
* is an expansion of ~0.03%, plus a small constant.
*
* For any setting other than those defaults for windowBits and memLevel, one
* of two worst case bounds is returned. This is at most an expansion of ~4% or
* ~13%, plus a small constant.
*
* Both the 0.03% and 4% derive from the overhead of stored blocks. The first
* one is for stored blocks of 16383 bytes (memLevel == 8), whereas the second
* is for stored blocks of 127 bytes (the worst case memLevel == 1). The
* expansion results from five bytes of header for each stored block.
*
* The larger expansion of 13% results from a window size less than or equal to
* the symbols buffer size (windowBits <= memLevel + 7). In that case some of
* the data being compressed may have slid out of the sliding window, impeding
* a stored block from being emitted. Then the only choice is a fixed or
* dynamic block, where a fixed block limits the maximum expansion to 9 bits
* per 8-bit byte, plus 10 bits for every block. The smallest block size for
* which this can occur is 255 (memLevel == 2).
*
* Shifts are used to approximate divisions, for speed.
*/
uLong ZEXPORT deflateBound(z_streamp strm, uLong sourceLen) {
deflate_state *s;
uLong fixedlen, storelen, wraplen;
/* upper bound for fixed blocks with 9-bit literals and length 255
(memLevel == 2, which is the lowest that may not use stored blocks) --
~13% overhead plus a small constant */
fixedlen = sourceLen + (sourceLen >> 3) + (sourceLen >> 8) +
(sourceLen >> 9) + 4;
/* upper bound for stored blocks with length 127 (memLevel == 1) --
~4% overhead plus a small constant */
storelen = sourceLen + (sourceLen >> 5) + (sourceLen >> 7) +
(sourceLen >> 11) + 7;
/* if can't get parameters, return larger bound plus a zlib wrapper */
if (deflateStateCheck(strm))
return (fixedlen > storelen ? fixedlen : storelen) + 6;
/* compute wrapper length */
s = strm->state;
switch (s->wrap) {
case 0: /* raw deflate */
wraplen = 0;
break;
|
| ︙ | ︙ | |||
736 737 738 739 740 741 742 |
}
break;
#endif
default: /* for compiler happiness */
wraplen = 6;
}
| | > | | > | < < < | < < | 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 |
}
break;
#endif
default: /* for compiler happiness */
wraplen = 6;
}
/* if not default parameters, return one of the conservative bounds */
if (s->w_bits != 15 || s->hash_bits != 8 + 7)
return (s->w_bits <= s->hash_bits && s->level ? fixedlen : storelen) +
wraplen;
/* default settings: return tight bound for that case -- ~0.03% overhead
plus a small constant */
return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) +
(sourceLen >> 25) + 13 - 6 + wraplen;
}
/* =========================================================================
* Put a short in the pending buffer. The 16-bit value is put in MSB order.
* IN assertion: the stream state is correct and there is enough room in
* pending_buf.
*/
local void putShortMSB(deflate_state *s, uInt b) {
put_byte(s, (Byte)(b >> 8));
put_byte(s, (Byte)(b & 0xff));
}
/* =========================================================================
* Flush as much pending output as possible. All deflate() output, except for
* some deflate_stored() output, goes through this function so some
* applications may wish to modify it to avoid allocating a large
* strm->next_out buffer and copying into it. (See also read_buf()).
*/
local void flush_pending(z_streamp strm) {
unsigned len;
deflate_state *s = strm->state;
_tr_flush_bits(s);
len = s->pending;
if (len > strm->avail_out) len = strm->avail_out;
if (len == 0) return;
|
| ︙ | ︙ | |||
797 798 799 800 801 802 803 |
do { \
if (s->gzhead->hcrc && s->pending > (beg)) \
strm->adler = crc32(strm->adler, s->pending_buf + (beg), \
s->pending - (beg)); \
} while (0)
/* ========================================================================= */
| | < < < | 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 |
do { \
if (s->gzhead->hcrc && s->pending > (beg)) \
strm->adler = crc32(strm->adler, s->pending_buf + (beg), \
s->pending - (beg)); \
} while (0)
/* ========================================================================= */
int ZEXPORT deflate(z_streamp strm, int flush) {
int old_flush; /* value of flush param for previous deflate call */
deflate_state *s;
if (deflateStateCheck(strm) || flush > Z_BLOCK || flush < 0) {
return Z_STREAM_ERROR;
}
s = strm->state;
|
| ︙ | ︙ | |||
852 853 854 855 856 857 858 |
}
/* Write the header */
if (s->status == INIT_STATE && s->wrap == 0)
s->status = BUSY_STATE;
if (s->status == INIT_STATE) {
/* zlib header */
| | | 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 |
}
/* Write the header */
if (s->status == INIT_STATE && s->wrap == 0)
s->status = BUSY_STATE;
if (s->status == INIT_STATE) {
/* zlib header */
uInt header = (Z_DEFLATED + ((s->w_bits - 8) << 4)) << 8;
uInt level_flags;
if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2)
level_flags = 0;
else if (s->level < 6)
level_flags = 1;
else if (s->level == 6)
|
| ︙ | ︙ | |||
1112 1113 1114 1115 1116 1117 1118 |
* to flush the rest.
*/
if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */
return s->pending != 0 ? Z_OK : Z_STREAM_END;
}
/* ========================================================================= */
| | < < | 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 |
* to flush the rest.
*/
if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */
return s->pending != 0 ? Z_OK : Z_STREAM_END;
}
/* ========================================================================= */
int ZEXPORT deflateEnd(z_streamp strm) {
int status;
if (deflateStateCheck(strm)) return Z_STREAM_ERROR;
status = strm->state->status;
/* Deallocate in reverse order of allocations: */
|
| ︙ | ︙ | |||
1138 1139 1140 1141 1142 1143 1144 | } /* ========================================================================= * Copy the source state to the destination state. * To simplify the source, this is not supported for 16-bit MSDOS (which * doesn't have enough memory anyway to duplicate compression states). */ | | < < < > > | 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 |
}
/* =========================================================================
* Copy the source state to the destination state.
* To simplify the source, this is not supported for 16-bit MSDOS (which
* doesn't have enough memory anyway to duplicate compression states).
*/
int ZEXPORT deflateCopy(z_streamp dest, z_streamp source) {
#ifdef MAXSEG_64K
(void)dest;
(void)source;
return Z_STREAM_ERROR;
#else
deflate_state *ds;
deflate_state *ss;
if (deflateStateCheck(source) || dest == Z_NULL) {
|
| ︙ | ︙ | |||
1190 1191 1192 1193 1194 1195 1196 |
ds->d_desc.dyn_tree = ds->dyn_dtree;
ds->bl_desc.dyn_tree = ds->bl_tree;
return Z_OK;
#endif /* MAXSEG_64K */
}
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < | | | > | | | | | | | | | > | | | | | | | | > | | < | < < < | > | | | | < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 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 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 |
ds->d_desc.dyn_tree = ds->dyn_dtree;
ds->bl_desc.dyn_tree = ds->bl_tree;
return Z_OK;
#endif /* MAXSEG_64K */
}
#ifndef FASTEST
/* ===========================================================================
* Set match_start to the longest match starting at the given string and
* return its length. Matches shorter or equal to prev_length are discarded,
* in which case the result is equal to prev_length and match_start is
* garbage.
* IN assertions: cur_match is the head of the hash chain for the current
* string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
* OUT assertion: the match length is not greater than s->lookahead.
*/
local uInt longest_match(deflate_state *s, IPos cur_match) {
unsigned chain_length = s->max_chain_length;/* max hash chain length */
register Bytef *scan = s->window + s->strstart; /* current string */
register Bytef *match; /* matched string */
register int len; /* length of current match */
int best_len = (int)s->prev_length; /* best match length so far */
int nice_match = s->nice_match; /* stop if match long enough */
IPos limit = s->strstart > (IPos)MAX_DIST(s) ?
s->strstart - (IPos)MAX_DIST(s) : NIL;
/* Stop when cur_match becomes <= limit. To simplify the code,
* we prevent matches with the string of window index 0.
*/
Posf *prev = s->prev;
uInt wmask = s->w_mask;
#ifdef UNALIGNED_OK
/* Compare two bytes at a time. Note: this is not always beneficial.
* Try with and without -DUNALIGNED_OK to check.
*/
register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1;
register ush scan_start = *(ushf*)scan;
register ush scan_end = *(ushf*)(scan + best_len - 1);
#else
register Bytef *strend = s->window + s->strstart + MAX_MATCH;
register Byte scan_end1 = scan[best_len - 1];
register Byte scan_end = scan[best_len];
#endif
/* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
* It is easy to get rid of this optimization if necessary.
*/
Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
/* Do not waste too much time if we already have a good match: */
if (s->prev_length >= s->good_match) {
chain_length >>= 2;
}
/* Do not look for matches beyond the end of the input. This is necessary
* to make deflate deterministic.
*/
if ((uInt)nice_match > s->lookahead) nice_match = (int)s->lookahead;
Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD,
"need lookahead");
do {
Assert(cur_match < s->strstart, "no future");
match = s->window + cur_match;
/* Skip to next match if the match length cannot increase
* or if the match length is less than 2. Note that the checks below
* for insufficient lookahead only occur occasionally for performance
* reasons. Therefore uninitialized memory will be accessed, and
* conditional jumps will be made that depend on those values.
* However the length of the match is limited to the lookahead, so
* the output of deflate is not affected by the uninitialized values.
*/
#if (defined(UNALIGNED_OK) && MAX_MATCH == 258)
/* This code assumes sizeof(unsigned short) == 2. Do not use
* UNALIGNED_OK if your compiler uses a different size.
*/
if (*(ushf*)(match + best_len - 1) != scan_end ||
*(ushf*)match != scan_start) continue;
/* It is not necessary to compare scan[2] and match[2] since they are
* always equal when the other bytes match, given that the hash keys
* are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at
* strstart + 3, + 5, up to strstart + 257. We check for insufficient
* lookahead only every 4th comparison; the 128th check will be made
* at strstart + 257. If MAX_MATCH-2 is not a multiple of 8, it is
* necessary to put more guard bytes at the end of the window, or
* to check more often for insufficient lookahead.
*/
Assert(scan[2] == match[2], "scan[2]?");
scan++, match++;
do {
} while (*(ushf*)(scan += 2) == *(ushf*)(match += 2) &&
*(ushf*)(scan += 2) == *(ushf*)(match += 2) &&
*(ushf*)(scan += 2) == *(ushf*)(match += 2) &&
*(ushf*)(scan += 2) == *(ushf*)(match += 2) &&
scan < strend);
/* The funny "do {}" generates better code on most compilers */
/* Here, scan <= window + strstart + 257 */
Assert(scan <= s->window + (unsigned)(s->window_size - 1),
"wild scan");
if (*scan == *match) scan++;
len = (MAX_MATCH - 1) - (int)(strend - scan);
scan = strend - (MAX_MATCH-1);
#else /* UNALIGNED_OK */
if (match[best_len] != scan_end ||
match[best_len - 1] != scan_end1 ||
*match != *scan ||
*++match != scan[1]) continue;
/* The check at best_len - 1 can be removed because it will be made
* again later. (This heuristic is not always a win.)
* It is not necessary to compare scan[2] and match[2] since they
* are always equal when the other bytes match, given that
* the hash keys are equal and that HASH_BITS >= 8.
*/
scan += 2, match++;
Assert(*scan == *match, "match[2]?");
/* We check for insufficient lookahead only every 8th comparison;
* the 256th check will be made at strstart + 258.
*/
do {
} while (*++scan == *++match && *++scan == *++match &&
*++scan == *++match && *++scan == *++match &&
*++scan == *++match && *++scan == *++match &&
*++scan == *++match && *++scan == *++match &&
scan < strend);
Assert(scan <= s->window + (unsigned)(s->window_size - 1),
"wild scan");
len = MAX_MATCH - (int)(strend - scan);
scan = strend - MAX_MATCH;
#endif /* UNALIGNED_OK */
if (len > best_len) {
s->match_start = cur_match;
best_len = len;
if (len >= nice_match) break;
#ifdef UNALIGNED_OK
scan_end = *(ushf*)(scan + best_len - 1);
#else
scan_end1 = scan[best_len - 1];
scan_end = scan[best_len];
#endif
}
} while ((cur_match = prev[cur_match & wmask]) > limit
&& --chain_length != 0);
if ((uInt)best_len <= s->lookahead) return (uInt)best_len;
return s->lookahead;
}
#else /* FASTEST */
/* ---------------------------------------------------------------------------
* Optimized version for FASTEST only
*/
local uInt longest_match(deflate_state *s, IPos cur_match) {
register Bytef *scan = s->window + s->strstart; /* current string */
register Bytef *match; /* matched string */
register int len; /* length of current match */
register Bytef *strend = s->window + s->strstart + MAX_MATCH;
/* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
* It is easy to get rid of this optimization if necessary.
*/
Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD,
"need lookahead");
Assert(cur_match < s->strstart, "no future");
match = s->window + cur_match;
/* Return failure if the match length is less than 2:
*/
if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1;
/* The check at best_len - 1 can be removed because it will be made
* again later. (This heuristic is not always a win.)
* It is not necessary to compare scan[2] and match[2] since they
* are always equal when the other bytes match, given that
* the hash keys are equal and that HASH_BITS >= 8.
*/
scan += 2, match += 2;
Assert(*scan == *match, "match[2]?");
/* We check for insufficient lookahead only every 8th comparison;
* the 256th check will be made at strstart + 258.
*/
do {
} while (*++scan == *++match && *++scan == *++match &&
*++scan == *++match && *++scan == *++match &&
*++scan == *++match && *++scan == *++match &&
*++scan == *++match && *++scan == *++match &&
scan < strend);
Assert(scan <= s->window + (unsigned)(s->window_size - 1), "wild scan");
len = MAX_MATCH - (int)(strend - scan);
if (len < MIN_MATCH) return MIN_MATCH - 1;
s->match_start = cur_match;
return (uInt)len <= s->lookahead ? (uInt)len : s->lookahead;
}
#endif /* FASTEST */
#ifdef ZLIB_DEBUG
#define EQUAL 0
/* result of memcmp for equal strings */
/* ===========================================================================
* Check that the match at match_start is indeed a match.
*/
local void check_match(deflate_state *s, IPos start, IPos match, int length) {
/* check that the match is indeed a match */
if (zmemcmp(s->window + match,
s->window + start, length) != EQUAL) {
fprintf(stderr, " start %u, match %u, length %d\n",
start, match, length);
do {
fprintf(stderr, "%c%c", s->window[match++], s->window[start++]);
} while (--length != 0);
z_error("invalid match");
}
if (z_verbose > 1) {
fprintf(stderr,"\\[%d,%d]", start - match, length);
do { putc(s->window[start++], stderr); } while (--length != 0);
}
}
#else
# define check_match(s, start, match, length)
#endif /* ZLIB_DEBUG */
/* ===========================================================================
* Flush the current block, with given end-of-file flag.
* IN assertion: strstart is set to the end of the current match.
*/
#define FLUSH_BLOCK_ONLY(s, last) { \
_tr_flush_block(s, (s->block_start >= 0L ? \
(charf *)&s->window[(unsigned)s->block_start] : \
|
| ︙ | ︙ | |||
1676 1677 1678 1679 1680 1681 1682 | * of hash table slides to perform. If s->matches is 1, then one hash table * slide will be done when switching. If s->matches is 2, the maximum value * allowed here, then the hash table will be cleared, since two or more slides * is the same as a clear. * * deflate_stored() is written to minimize the number of times an input byte is * copied. It is most efficient with large input and output buffers, which | | | < < < | 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 |
* of hash table slides to perform. If s->matches is 1, then one hash table
* slide will be done when switching. If s->matches is 2, the maximum value
* allowed here, then the hash table will be cleared, since two or more slides
* is the same as a clear.
*
* deflate_stored() is written to minimize the number of times an input byte is
* copied. It is most efficient with large input and output buffers, which
* maximizes the opportunities to have a single copy from next_in to next_out.
*/
local block_state deflate_stored(deflate_state *s, int flush) {
/* Smallest worthy block size when not flushing or finishing. By default
* this is 32K. This can be as small as 507 bytes for memLevel == 1. For
* large input and output buffers, the stored block size will be larger.
*/
unsigned min_block = MIN(s->pending_buf_size - 5, s->w_size);
/* Copy as many min_block or larger stored blocks directly to next_out as
|
| ︙ | ︙ | |||
1865 1866 1867 1868 1869 1870 1871 | /* =========================================================================== * Compress as much as possible from the input stream, return the current * block state. * This function does not perform lazy evaluation of matches and inserts * new strings in the dictionary only for unmatched strings or for short * matches. It is used only for the fast compression options. */ | | < < < | | 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 1806 1807 1808 1809 1810 1811 |
/* ===========================================================================
* Compress as much as possible from the input stream, return the current
* block state.
* This function does not perform lazy evaluation of matches and inserts
* new strings in the dictionary only for unmatched strings or for short
* matches. It is used only for the fast compression options.
*/
local block_state deflate_fast(deflate_state *s, int flush) {
IPos hash_head; /* head of the hash chain */
int bflush; /* set if current block must be flushed */
for (;;) {
/* Make sure that we always have enough lookahead, except
* at the end of the input file. We need MAX_MATCH bytes
* for the next match, plus MIN_MATCH bytes to insert the
* string following the next match.
*/
if (s->lookahead < MIN_LOOKAHEAD) {
fill_window(s);
if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
return need_more;
}
if (s->lookahead == 0) break; /* flush the current block */
}
/* Insert the string window[strstart .. strstart + 2] in the
* dictionary, and set hash_head to the head of the hash chain:
*/
hash_head = NIL;
if (s->lookahead >= MIN_MATCH) {
INSERT_STRING(s, s->strstart, hash_head);
}
|
| ︙ | ︙ | |||
1934 1935 1936 1937 1938 1939 1940 |
s->strstart++;
} else
#endif
{
s->strstart += s->match_length;
s->match_length = 0;
s->ins_h = s->window[s->strstart];
| | | | 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 |
s->strstart++;
} else
#endif
{
s->strstart += s->match_length;
s->match_length = 0;
s->ins_h = s->window[s->strstart];
UPDATE_HASH(s, s->ins_h, s->window[s->strstart + 1]);
#if MIN_MATCH != 3
Call UPDATE_HASH() MIN_MATCH-3 more times
#endif
/* If lookahead < MIN_MATCH, ins_h is garbage, but it does not
* matter since it will be recomputed at next deflate call.
*/
}
} else {
/* No match, output a literal byte */
Tracevv((stderr,"%c", s->window[s->strstart]));
_tr_tally_lit(s, s->window[s->strstart], bflush);
s->lookahead--;
s->strstart++;
}
if (bflush) FLUSH_BLOCK(s, 0);
}
s->insert = s->strstart < MIN_MATCH-1 ? s->strstart : MIN_MATCH-1;
if (flush == Z_FINISH) {
|
| ︙ | ︙ | |||
1967 1968 1969 1970 1971 1972 1973 | #ifndef FASTEST /* =========================================================================== * Same as above, but achieves better compression. We use a lazy * evaluation for matches: a match is finally adopted only if there is * no better match at the next window position. */ | | < < < | | 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 |
#ifndef FASTEST
/* ===========================================================================
* Same as above, but achieves better compression. We use a lazy
* evaluation for matches: a match is finally adopted only if there is
* no better match at the next window position.
*/
local block_state deflate_slow(deflate_state *s, int flush) {
IPos hash_head; /* head of hash chain */
int bflush; /* set if current block must be flushed */
/* Process the input block. */
for (;;) {
/* Make sure that we always have enough lookahead, except
* at the end of the input file. We need MAX_MATCH bytes
* for the next match, plus MIN_MATCH bytes to insert the
* string following the next match.
*/
if (s->lookahead < MIN_LOOKAHEAD) {
fill_window(s);
if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
return need_more;
}
if (s->lookahead == 0) break; /* flush the current block */
}
/* Insert the string window[strstart .. strstart + 2] in the
* dictionary, and set hash_head to the head of the hash chain:
*/
hash_head = NIL;
if (s->lookahead >= MIN_MATCH) {
INSERT_STRING(s, s->strstart, hash_head);
}
|
| ︙ | ︙ | |||
2031 2032 2033 2034 2035 2036 2037 |
/* If there was a match at the previous step and the current
* match is not better, output the previous match:
*/
if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) {
uInt max_insert = s->strstart + s->lookahead - MIN_MATCH;
/* Do not insert strings in hash table beyond this. */
| | | | | | | | | | < < < | 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 |
/* If there was a match at the previous step and the current
* match is not better, output the previous match:
*/
if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) {
uInt max_insert = s->strstart + s->lookahead - MIN_MATCH;
/* Do not insert strings in hash table beyond this. */
check_match(s, s->strstart - 1, s->prev_match, s->prev_length);
_tr_tally_dist(s, s->strstart - 1 - s->prev_match,
s->prev_length - MIN_MATCH, bflush);
/* Insert in hash table all strings up to the end of the match.
* strstart - 1 and strstart are already inserted. If there is not
* enough lookahead, the last two strings are not inserted in
* the hash table.
*/
s->lookahead -= s->prev_length - 1;
s->prev_length -= 2;
do {
if (++s->strstart <= max_insert) {
INSERT_STRING(s, s->strstart, hash_head);
}
} while (--s->prev_length != 0);
s->match_available = 0;
s->match_length = MIN_MATCH-1;
s->strstart++;
if (bflush) FLUSH_BLOCK(s, 0);
} else if (s->match_available) {
/* If there was no match at the previous position, output a
* single literal. If there was a match but the current match
* is longer, truncate the previous match to a single literal.
*/
Tracevv((stderr,"%c", s->window[s->strstart - 1]));
_tr_tally_lit(s, s->window[s->strstart - 1], bflush);
if (bflush) {
FLUSH_BLOCK_ONLY(s, 0);
}
s->strstart++;
s->lookahead--;
if (s->strm->avail_out == 0) return need_more;
} else {
/* There is no previous match to compare with, wait for
* the next step to decide.
*/
s->match_available = 1;
s->strstart++;
s->lookahead--;
}
}
Assert (flush != Z_NO_FLUSH, "no flush?");
if (s->match_available) {
Tracevv((stderr,"%c", s->window[s->strstart - 1]));
_tr_tally_lit(s, s->window[s->strstart - 1], bflush);
s->match_available = 0;
}
s->insert = s->strstart < MIN_MATCH-1 ? s->strstart : MIN_MATCH-1;
if (flush == Z_FINISH) {
FLUSH_BLOCK(s, 1);
return finish_done;
}
if (s->sym_next)
FLUSH_BLOCK(s, 0);
return block_done;
}
#endif /* FASTEST */
/* ===========================================================================
* For Z_RLE, simply look for runs of bytes, generate matches only of distance
* one. Do not maintain a hash table. (It will be regenerated if this run of
* deflate switches away from Z_RLE.)
*/
local block_state deflate_rle(deflate_state *s, int flush) {
int bflush; /* set if current block must be flushed */
uInt prev; /* byte at distance one to match */
Bytef *scan, *strend; /* scan goes up to strend for length of run */
for (;;) {
/* Make sure that we always have enough lookahead, except
* at the end of the input file. We need MAX_MATCH bytes
|
| ︙ | ︙ | |||
2136 2137 2138 2139 2140 2141 2142 |
prev == *++scan && prev == *++scan &&
prev == *++scan && prev == *++scan &&
scan < strend);
s->match_length = MAX_MATCH - (uInt)(strend - scan);
if (s->match_length > s->lookahead)
s->match_length = s->lookahead;
}
| | > | | < < < | | 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 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 |
prev == *++scan && prev == *++scan &&
prev == *++scan && prev == *++scan &&
scan < strend);
s->match_length = MAX_MATCH - (uInt)(strend - scan);
if (s->match_length > s->lookahead)
s->match_length = s->lookahead;
}
Assert(scan <= s->window + (uInt)(s->window_size - 1),
"wild scan");
}
/* Emit match if have run of MIN_MATCH or longer, else emit literal */
if (s->match_length >= MIN_MATCH) {
check_match(s, s->strstart, s->strstart - 1, s->match_length);
_tr_tally_dist(s, 1, s->match_length - MIN_MATCH, bflush);
s->lookahead -= s->match_length;
s->strstart += s->match_length;
s->match_length = 0;
} else {
/* No match, output a literal byte */
Tracevv((stderr,"%c", s->window[s->strstart]));
_tr_tally_lit(s, s->window[s->strstart], bflush);
s->lookahead--;
s->strstart++;
}
if (bflush) FLUSH_BLOCK(s, 0);
}
s->insert = 0;
if (flush == Z_FINISH) {
FLUSH_BLOCK(s, 1);
return finish_done;
}
if (s->sym_next)
FLUSH_BLOCK(s, 0);
return block_done;
}
/* ===========================================================================
* For Z_HUFFMAN_ONLY, do not look for matches. Do not maintain a hash table.
* (It will be regenerated if this run of deflate switches away from Huffman.)
*/
local block_state deflate_huff(deflate_state *s, int flush) {
int bflush; /* set if current block must be flushed */
for (;;) {
/* Make sure that we have a literal to write. */
if (s->lookahead == 0) {
fill_window(s);
if (s->lookahead == 0) {
if (flush == Z_NO_FLUSH)
return need_more;
break; /* flush the current block */
}
}
/* Output a literal byte */
s->match_length = 0;
Tracevv((stderr,"%c", s->window[s->strstart]));
_tr_tally_lit(s, s->window[s->strstart], bflush);
s->lookahead--;
s->strstart++;
if (bflush) FLUSH_BLOCK(s, 0);
}
s->insert = 0;
if (flush == Z_FINISH) {
FLUSH_BLOCK(s, 1);
return finish_done;
}
if (s->sym_next)
FLUSH_BLOCK(s, 0);
return block_done;
}
|
Changes to compat/zlib/deflate.h.
| ︙ | ︙ | |||
287 288 289 290 291 292 293 |
*/
#define WIN_INIT MAX_MATCH
/* Number of bytes after end of data in window to initialize in order to avoid
memory checker errors from longest match routines */
/* in trees.c */
| | | | | | | | | | 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 |
*/
#define WIN_INIT MAX_MATCH
/* Number of bytes after end of data in window to initialize in order to avoid
memory checker errors from longest match routines */
/* in trees.c */
void ZLIB_INTERNAL _tr_init(deflate_state *s);
int ZLIB_INTERNAL _tr_tally(deflate_state *s, unsigned dist, unsigned lc);
void ZLIB_INTERNAL _tr_flush_block(deflate_state *s, charf *buf,
ulg stored_len, int last);
void ZLIB_INTERNAL _tr_flush_bits(deflate_state *s);
void ZLIB_INTERNAL _tr_align(deflate_state *s);
void ZLIB_INTERNAL _tr_stored_block(deflate_state *s, charf *buf,
ulg stored_len, int last);
#define d_code(dist) \
((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)])
/* Mapping from a distance to a distance code. dist is the distance - 1 and
* must not have side effects. _dist_code[256] and _dist_code[257] are never
* used.
*/
|
| ︙ | ︙ | |||
325 326 327 328 329 330 331 |
s->sym_buf[s->sym_next++] = cc; \
s->dyn_ltree[cc].Freq++; \
flush = (s->sym_next == s->sym_end); \
}
# define _tr_tally_dist(s, distance, length, flush) \
{ uch len = (uch)(length); \
ush dist = (ush)(distance); \
| | | | 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 |
s->sym_buf[s->sym_next++] = cc; \
s->dyn_ltree[cc].Freq++; \
flush = (s->sym_next == s->sym_end); \
}
# define _tr_tally_dist(s, distance, length, flush) \
{ uch len = (uch)(length); \
ush dist = (ush)(distance); \
s->sym_buf[s->sym_next++] = (uch)dist; \
s->sym_buf[s->sym_next++] = (uch)(dist >> 8); \
s->sym_buf[s->sym_next++] = len; \
dist--; \
s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \
s->dyn_dtree[d_code(dist)].Freq++; \
flush = (s->sym_next == s->sym_end); \
}
#else
# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c)
# define _tr_tally_dist(s, distance, length, flush) \
flush = _tr_tally(s, distance, length)
#endif
#endif /* DEFLATE_H */
|
Changes to compat/zlib/examples/enough.c.
| ︙ | ︙ | |||
482 483 484 485 486 487 488 | // Examine and show the total number of possible prefix codes for a given // maximum number of symbols, initial root table size, and maximum code length // in bits -- those are the command arguments in that order. The default values // are 286, 9, and 15 respectively, for the deflate literal/length code. The // possible codes are counted for each number of coded symbols from two to the // maximum. The counts for each of those and the total number of codes are | | | 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 | // Examine and show the total number of possible prefix codes for a given // maximum number of symbols, initial root table size, and maximum code length // in bits -- those are the command arguments in that order. The default values // are 286, 9, and 15 respectively, for the deflate literal/length code. The // possible codes are counted for each number of coded symbols from two to the // maximum. The counts for each of those and the total number of codes are // shown. The maximum number of inflate table entries is then calculated across // all possible codes. Each new maximum number of table entries and the // associated sub-code (starting at root + 1 == 10 bits) is shown. // // To count and examine prefix codes that are not length-limited, provide a // maximum length equal to the number of symbols minus one. // // For the deflate literal/length code, use "enough". For the deflate distance |
| ︙ | ︙ |
Changes to compat/zlib/examples/fitblk.c.
| ︙ | ︙ | |||
13 14 15 16 17 18 19 | /* Approach to just fitting a requested compressed size: fitblk performs three compression passes on a portion of the input data in order to determine how much of that input will compress to nearly the requested output block size. The first pass generates enough deflate blocks to produce output to fill the requested | | | 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | /* Approach to just fitting a requested compressed size: fitblk performs three compression passes on a portion of the input data in order to determine how much of that input will compress to nearly the requested output block size. The first pass generates enough deflate blocks to produce output to fill the requested output size plus a specified excess amount (see the EXCESS define below). The last deflate block may go quite a bit past that, but is discarded. The second pass decompresses and recompresses just the compressed data that fit in the requested plus excess sized buffer. The deflate process is terminated after that amount of input, which is less than the amount consumed on the first pass. The last deflate block of the result will be of a comparable size to the final product, so that the header for that deflate block and |
| ︙ | ︙ | |||
105 106 107 108 109 110 111 |
inf->next_out = raw;
ret = inflate(inf, Z_NO_FLUSH);
assert(ret != Z_STREAM_ERROR && ret != Z_DATA_ERROR &&
ret != Z_NEED_DICT);
if (ret == Z_MEM_ERROR)
return ret;
| | | 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 |
inf->next_out = raw;
ret = inflate(inf, Z_NO_FLUSH);
assert(ret != Z_STREAM_ERROR && ret != Z_DATA_ERROR &&
ret != Z_NEED_DICT);
if (ret == Z_MEM_ERROR)
return ret;
/* compress what was decompressed until done or no room */
def->avail_in = RAWLEN - inf->avail_out;
def->next_in = raw;
if (inf->avail_out != 0)
flush = Z_FINISH;
ret = deflate(def, flush);
assert(ret != Z_STREAM_ERROR);
} while (ret != Z_STREAM_END && def->avail_out != 0);
|
| ︙ | ︙ | |||
194 195 196 197 198 199 200 |
inf.next_in = blk;
def.avail_out = size + EXCESS;
def.next_out = tmp;
ret = recompress(&inf, &def);
if (ret == Z_MEM_ERROR)
quit("out of memory");
| | | 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 |
inf.next_in = blk;
def.avail_out = size + EXCESS;
def.next_out = tmp;
ret = recompress(&inf, &def);
if (ret == Z_MEM_ERROR)
quit("out of memory");
/* set up for next recompression */
ret = inflateReset(&inf);
assert(ret != Z_STREAM_ERROR);
ret = deflateReset(&def);
assert(ret != Z_STREAM_ERROR);
/* do second and final recompression (third compression) */
inf.avail_in = size - MARGIN; /* assure stream will complete */
|
| ︙ | ︙ |
Changes to compat/zlib/examples/gun.c.
| ︙ | ︙ | |||
39 40 41 42 43 44 45 | writing all of the uncompressed data to the output. Unlike gzip, gun allows an empty file on input, and will produce no error writing an empty output file. gun will also decompress files made by Unix compress, which uses LZW compression. These files are automatically detected by virtue of their magic header bytes. Since the end of Unix compress stream is marked by the | | | 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | writing all of the uncompressed data to the output. Unlike gzip, gun allows an empty file on input, and will produce no error writing an empty output file. gun will also decompress files made by Unix compress, which uses LZW compression. These files are automatically detected by virtue of their magic header bytes. Since the end of Unix compress stream is marked by the end-of-file, they cannot be concatenated. If a Unix compress stream is encountered in an input file, it is the last stream in that file. Like gunzip and uncompress, the file attributes of the original compressed file are maintained in the final uncompressed file, to the extent that the user permissions allow it. On my Mac OS X PowerPC G4, gun is almost twice as fast as gunzip (version |
| ︙ | ︙ |
Changes to compat/zlib/examples/gzappend.c.
| ︙ | ︙ | |||
29 30 31 32 33 34 35 | * 1.1 4 Nov 2003 - Expand and clarify some comments and notes * - Add version and copyright to help * - Send help to stdout instead of stderr * - Add some preemptive typecasts * - Add L to constants in lseek() calls * - Remove some debugging information in error messages * - Use new data_type definition for zlib 1.2.1 | | | | 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 | * 1.1 4 Nov 2003 - Expand and clarify some comments and notes * - Add version and copyright to help * - Send help to stdout instead of stderr * - Add some preemptive typecasts * - Add L to constants in lseek() calls * - Remove some debugging information in error messages * - Use new data_type definition for zlib 1.2.1 * - Simplify and unify file operations * - Finish off gzip file in gztack() * - Use deflatePrime() instead of adding empty blocks * - Keep gzip file clean on appended file read errors * - Use in-place rotate instead of auxiliary buffer * (Why you ask? Because it was fun to write!) * 1.2 11 Oct 2012 - Fix for proper z_const usage * - Check for input buffer malloc failure */ /* gzappend takes a gzip file and appends to it, compressing files from the command line or data from stdin. The gzip file is written to directly, to avoid copying that file, in case it's large. Note that this results in the unfriendly behavior that if gzappend fails, the gzip file is corrupted. This program was written to illustrate the use of the new Z_BLOCK option of zlib 1.2.x's inflate() function. This option returns from inflate() at each block boundary to facilitate locating and modifying the last block bit at the start of the final deflate block. Also whether using Z_BLOCK or not, another required feature of zlib 1.2.x is that inflate() now provides the number of unused bits in the last input byte used. gzappend will not work with versions of zlib earlier than 1.2.1. gzappend first decompresses the gzip file internally, discarding all but the last 32K of uncompressed data, and noting the location of the last block bit and the number of unused bits in the last byte of the compressed data. The gzip trailer containing the CRC-32 and length of the uncompressed data is verified. This trailer will be later overwritten. |
| ︙ | ︙ |
Changes to compat/zlib/examples/gzlog.h.
| ︙ | ︙ | |||
36 37 38 39 40 41 42 | opening the log file locked for small bursts, and then closing it. The log object works by appending stored (uncompressed) data to the gzip file until 1 MB has been accumulated. At that time, the stored data is compressed, and replaces the uncompressed data in the file. The log file is truncated to its new size at that time. After each write operation, the log file is a valid gzip file that can decompressed to recover what was written. | | | 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | opening the log file locked for small bursts, and then closing it. The log object works by appending stored (uncompressed) data to the gzip file until 1 MB has been accumulated. At that time, the stored data is compressed, and replaces the uncompressed data in the file. The log file is truncated to its new size at that time. After each write operation, the log file is a valid gzip file that can decompressed to recover what was written. The gzlog operations can be interrupted at any point due to an application or system crash, and the log file will be recovered the next time the log is opened with gzlog_open(). */ #ifndef GZLOG_H #define GZLOG_H |
| ︙ | ︙ |
Changes to compat/zlib/examples/zlib_how.html.
|
| | | | | | 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 | <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> <title>zlib Usage Example</title> <!-- Copyright (c) 2004-2023 Mark Adler. --> </head> <body bgcolor="#FFFFFF" text="#000000" link="#0000FF" vlink="#00A000"> <h2 align="center"> zlib Usage Example </h2> We often get questions about how the <tt>deflate()</tt> and <tt>inflate()</tt> functions should be used. Users wonder when they should provide more input, when they should use more output, what to do with a <tt>Z_BUF_ERROR</tt>, how to make sure the process terminates properly, and so on. So for those who have read <tt>zlib.h</tt> (a few times), and would like further edification, below is an annotated example in C of simple routines to compress and decompress from an input file to an output file using <tt>deflate()</tt> and <tt>inflate()</tt> respectively. The annotations are interspersed between lines of the code. So please read between the lines. We hope this helps explain some of the intricacies of <em>zlib</em>. <p> Without further ado, here is the program <a href="zpipe.c"><tt>zpipe.c</tt></a>: <pre><b> /* zpipe.c: example of proper use of zlib's inflate() and deflate() Not copyrighted -- provided to the public domain Version 1.4 11 December 2005 Mark Adler */ /* Version history: 1.0 30 Oct 2004 First version |
| ︙ | ︙ | |||
151 152 153 154 155 156 157 |
before we fall out of the loop at the bottom.
<pre><b>
/* compress until end of file */
do {
</b></pre>
We start off by reading data from the input file. The number of bytes read is put directly
into <tt>avail_in</tt>, and a pointer to those bytes is put into <tt>next_in</tt>. We also
| | > | < < < | | 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 |
before we fall out of the loop at the bottom.
<pre><b>
/* compress until end of file */
do {
</b></pre>
We start off by reading data from the input file. The number of bytes read is put directly
into <tt>avail_in</tt>, and a pointer to those bytes is put into <tt>next_in</tt>. We also
check to see if end-of-file on the input has been reached using feof().
If we are at the end of file, then <tt>flush</tt> is set to the
<em>zlib</em> constant <tt>Z_FINISH</tt>, which is later passed to <tt>deflate()</tt> to
indicate that this is the last chunk of input data to compress.
If we are not yet at the end of the input, then the <em>zlib</em>
constant <tt>Z_NO_FLUSH</tt> will be passed to <tt>deflate</tt> to indicate that we are still
in the middle of the uncompressed data.
<p>
If there is an error in reading from the input file, the process is aborted with
<tt>deflateEnd()</tt> being called to free the allocated <em>zlib</em> state before returning
the error. We wouldn't want a memory leak, now would we? <tt>deflateEnd()</tt> can be called
at any time after the state has been initialized. Once that's done, <tt>deflateInit()</tt> (or
|
| ︙ | ︙ | |||
536 537 538 539 540 541 542 |
else {
fputs("zpipe usage: zpipe [-d] < source > dest\n", stderr);
return 1;
}
}
</b></pre>
<hr>
| | > > > > > > | 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 |
else {
fputs("zpipe usage: zpipe [-d] < source > dest\n", stderr);
return 1;
}
}
</b></pre>
<hr>
<i>Last modified 24 January 2023<br>
Copyright © 2004-2023 Mark Adler</i><br>
<a rel="license" href="http://creativecommons.org/licenses/by-nd/4.0/">
<img alt="Creative Commons License" style="border-width:0"
src="https://i.creativecommons.org/l/by-nd/4.0/88x31.png"></a>
<a rel="license" href="http://creativecommons.org/licenses/by-nd/4.0/">
Creative Commons Attribution-NoDerivatives 4.0 International License</a>.
</body>
</html>
|
Changes to compat/zlib/examples/zran.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 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 |
/* zran.c -- example of deflate stream indexing and random access
* Copyright (C) 2005, 2012, 2018, 2023 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
* Version 1.4 13 Apr 2023 Mark Adler */
/* Version History:
1.0 29 May 2005 First version
1.1 29 Sep 2012 Fix memory reallocation error
1.2 14 Oct 2018 Handle gzip streams with multiple members
Add a header file to facilitate usage in applications
1.3 18 Feb 2023 Permit raw deflate streams as well as zlib and gzip
Permit crossing gzip member boundaries when extracting
Support a size_t size when extracting (was an int)
Do a binary search over the index for an access point
Expose the access point type to enable save and load
1.4 13 Apr 2023 Add a NOPRIME define to not use inflatePrime()
*/
// Illustrate the use of Z_BLOCK, inflatePrime(), and inflateSetDictionary()
// for random access of a compressed file. A file containing a raw deflate
// stream is provided on the command line. The compressed stream is decoded in
// its entirety, and an index built with access points about every SPAN bytes
// in the uncompressed output. The compressed file is left open, and can then
// be read randomly, having to decompress on the average SPAN/2 uncompressed
// bytes before getting to the desired block of data.
//
// An access point can be created at the start of any deflate block, by saving
// the starting file offset and bit of that block, and the 32K bytes of
// uncompressed data that precede that block. Also the uncompressed offset of
// that block is saved to provide a reference for locating a desired starting
// point in the uncompressed stream. deflate_index_build() decompresses the
// input raw deflate stream a block at a time, and at the end of each block
// decides if enough uncompressed data has gone by to justify the creation of a
// new access point. If so, that point is saved in a data structure that grows
// as needed to accommodate the points.
//
// To use the index, an offset in the uncompressed data is provided, for which
// the latest access point at or preceding that offset is located in the index.
// The input file is positioned to the specified location in the index, and if
// necessary the first few bits of the compressed data is read from the file.
// inflate is initialized with those bits and the 32K of uncompressed data, and
// decompression then proceeds until the desired offset in the file is reached.
// Then decompression continues to read the requested uncompressed data from
// the file.
//
// There is some fair bit of overhead to starting inflation for the random
// access, mainly copying the 32K byte dictionary. If small pieces of the file
// are being accessed, it would make sense to implement a cache to hold some
// lookahead to avoid many calls to deflate_index_extract() for small lengths.
//
// Another way to build an index would be to use inflateCopy(). That would not
// be constrained to have access points at block boundaries, but would require
// more memory per access point, and could not be saved to a file due to the
// use of pointers in the state. The approach here allows for storage of the
// index in a file.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include "zlib.h"
#include "zran.h"
#define WINSIZE 32768U // sliding window size
#define CHUNK 16384 // file input buffer size
// See comments in zran.h.
void deflate_index_free(struct deflate_index *index) {
if (index != NULL) {
free(index->list);
free(index);
}
}
// Add an access point to the list. If out of memory, deallocate the existing
// list and return NULL. index->mode is temporarily the allocated number of
// access points, until it is time for deflate_index_build() to return. Then
// index->mode is set to the mode of inflation.
static struct deflate_index *add_point(struct deflate_index *index, int bits,
off_t in, off_t out, unsigned left,
unsigned char *window) {
if (index == NULL) {
// The list is empty. Create it, starting with eight access points.
index = malloc(sizeof(struct deflate_index));
if (index == NULL)
return NULL;
index->have = 0;
index->mode = 8;
index->list = malloc(sizeof(point_t) * index->mode);
if (index->list == NULL) {
free(index);
return NULL;
}
}
else if (index->have == index->mode) {
// The list is full. Make it bigger.
index->mode <<= 1;
point_t *next = realloc(index->list, sizeof(point_t) * index->mode);
if (next == NULL) {
deflate_index_free(index);
return NULL;
}
index->list = next;
}
// Fill in the access point and increment how many we have.
point_t *next = (point_t *)(index->list) + index->have++;
if (index->have < 0) {
// Overflowed the int!
deflate_index_free(index);
return NULL;
}
next->out = out;
next->in = in;
next->bits = bits;
if (left)
memcpy(next->window, window + WINSIZE - left, left);
if (left < WINSIZE)
memcpy(next->window + left, window, WINSIZE - left);
// Return the index, which may have been newly allocated or destroyed.
return index;
}
// Decompression modes. These are the inflateInit2() windowBits parameter.
#define RAW -15
#define ZLIB 15
#define GZIP 31
// See comments in zran.h.
int deflate_index_build(FILE *in, off_t span, struct deflate_index **built) {
// Set up inflation state.
z_stream strm = {0}; // inflate engine (gets fired up later)
unsigned char buf[CHUNK]; // input buffer
unsigned char win[WINSIZE] = {0}; // output sliding window
off_t totin = 0; // total bytes read from input
off_t totout = 0; // total bytes uncompressed
int mode = 0; // mode: RAW, ZLIB, or GZIP (0 => not set yet)
// Decompress from in, generating access points along the way.
int ret; // the return value from zlib, or Z_ERRNO
off_t last; // last access point uncompressed offset
struct deflate_index *index = NULL; // list of access points
do {
// Assure available input, at least until reaching EOF.
if (strm.avail_in == 0) {
strm.avail_in = fread(buf, 1, sizeof(buf), in);
totin += strm.avail_in;
strm.next_in = buf;
if (strm.avail_in < sizeof(buf) && ferror(in)) {
ret = Z_ERRNO;
break;
}
if (mode == 0) {
// At the start of the input -- determine the type. Assume raw
// if it is neither zlib nor gzip. This could in theory result
// in a false positive for zlib, but in practice the fill bits
// after a stored block are always zeros, so a raw stream won't
// start with an 8 in the low nybble.
mode = strm.avail_in == 0 ? RAW : // empty -- will fail
(strm.next_in[0] & 0xf) == 8 ? ZLIB :
strm.next_in[0] == 0x1f ? GZIP :
/* else */ RAW;
ret = inflateInit2(&strm, mode);
if (ret != Z_OK)
break;
}
}
// Assure available output. This rotates the output through, for use as
// a sliding window on the uncompressed data.
if (strm.avail_out == 0) {
strm.avail_out = sizeof(win);
strm.next_out = win;
}
if (mode == RAW && index == NULL)
// We skip the inflate() call at the start of raw deflate data in
// order generate an access point there. Set data_type to imitate
// the end of a header.
strm.data_type = 0x80;
else {
// Inflate and update the number of uncompressed bytes.
unsigned before = strm.avail_out;
ret = inflate(&strm, Z_BLOCK);
totout += before - strm.avail_out;
}
if ((strm.data_type & 0xc0) == 0x80 &&
(index == NULL || totout - last >= span)) {
// We are at the end of a header or a non-last deflate block, so we
// can add an access point here. Furthermore, we are either at the
// very start for the first access point, or there has been span or
// more uncompressed bytes since the last access point, so we want
// to add an access point here.
index = add_point(index, strm.data_type & 7, totin - strm.avail_in,
totout, strm.avail_out, win);
if (index == NULL) {
ret = Z_MEM_ERROR;
break;
}
last = totout;
}
if (ret == Z_STREAM_END && mode == GZIP &&
(strm.avail_in || ungetc(getc(in), in) != EOF))
// There is more input after the end of a gzip member. Reset the
// inflate state to read another gzip member. On success, this will
// set ret to Z_OK to continue decompressing.
ret = inflateReset2(&strm, GZIP);
// Keep going until Z_STREAM_END or error. If the compressed data ends
// prematurely without a file read error, Z_BUF_ERROR is returned.
} while (ret == Z_OK);
inflateEnd(&strm);
if (ret != Z_STREAM_END) {
// An error was encountered. Discard the index and return a negative
// error code.
deflate_index_free(index);
return ret == Z_NEED_DICT ? Z_DATA_ERROR : ret;
}
// Shrink the index to only the occupied access points and return it.
index->mode = mode;
index->length = totout;
point_t *list = realloc(index->list, sizeof(point_t) * index->have);
if (list == NULL) {
// Seems like a realloc() to make something smaller should always work,
// but just in case.
deflate_index_free(index);
return Z_MEM_ERROR;
}
index->list = list;
*built = index;
return index->have;
}
#ifdef NOPRIME
// Support zlib versions before 1.2.3 (July 2005), or incomplete zlib clones
// that do not have inflatePrime().
# define INFLATEPRIME inflatePreface
// Append the low bits bits of value to in[] at bit position *have, updating
// *have. value must be zero above its low bits bits. bits must be positive.
// This assumes that any bits above the *have bits in the last byte are zeros.
// That assumption is preserved on return, as any bits above *have + bits in
// the last byte written will be set to zeros.
static inline void append_bits(unsigned value, int bits,
unsigned char *in, int *have) {
in += *have >> 3; // where the first bits from value will go
int k = *have & 7; // the number of bits already there
*have += bits;
if (k)
*in |= value << k; // write value above the low k bits
else
*in = value;
k = 8 - k; // the number of bits just appended
while (bits > k) {
value >>= k; // drop the bits appended
bits -= k;
k = 8; // now at a byte boundary
*++in = value;
}
}
// Insert enough bits in the form of empty deflate blocks in front of the the
// low bits bits of value, in order to bring the sequence to a byte boundary.
// Then feed that to inflate(). This does what inflatePrime() does, except that
// a negative value of bits is not supported. bits must be in 0..16. If the
// arguments are invalid, Z_STREAM_ERROR is returned. Otherwise the return
// value from inflate() is returned.
static int inflatePreface(z_stream *strm, int bits, int value) {
// Check input.
if (strm == Z_NULL || bits < 0 || bits > 16)
return Z_STREAM_ERROR;
if (bits == 0)
return Z_OK;
value &= (2 << (bits - 1)) - 1;
// An empty dynamic block with an odd number of bits (95). The high bit of
// the last byte is unused.
static const unsigned char dyn[] = {
4, 0xe0, 0x81, 8, 0, 0, 0, 0, 0x20, 0xa8, 0xab, 0x1f
};
const int dynlen = 95; // number of bits in the block
// Build an input buffer for inflate that is a multiple of eight bits in
// length, and that ends with the low bits bits of value.
unsigned char in[(dynlen + 3 * 10 + 16 + 7) / 8];
int have = 0;
if (bits & 1) {
// Insert an empty dynamic block to get to an odd number of bits, so
// when bits bits from value are appended, we are at an even number of
// bits.
memcpy(in, dyn, sizeof(dyn));
have = dynlen;
}
while ((have + bits) & 7)
// Insert empty fixed blocks until appending bits bits would put us on
// a byte boundary. This will insert at most three fixed blocks.
append_bits(2, 10, in, &have);
// Append the bits bits from value, which takes us to a byte boundary.
append_bits(value, bits, in, &have);
// Deliver the input to inflate(). There is no output space provided, but
// inflate() can't get stuck waiting on output not ingesting all of the
// provided input. The reason is that there will be at most 16 bits of
// input from value after the empty deflate blocks (which themselves
// generate no output). At least ten bits are needed to generate the first
// output byte from a fixed block. The last two bytes of the buffer have to
// be ingested in order to get ten bits, which is the most that value can
// occupy.
strm->avail_in = have >> 3;
strm->next_in = in;
strm->avail_out = 0;
strm->next_out = in; // not used, but can't be NULL
return inflate(strm, Z_NO_FLUSH);
}
#else
# define INFLATEPRIME inflatePrime
#endif
// See comments in zran.h.
ptrdiff_t deflate_index_extract(FILE *in, struct deflate_index *index,
off_t offset, unsigned char *buf, size_t len) {
// Do a quick sanity check on the index.
if (index == NULL || index->have < 1 || index->list[0].out != 0)
return Z_STREAM_ERROR;
// If nothing to extract, return zero bytes extracted.
if (len == 0 || offset < 0 || offset >= index->length)
return 0;
// Find the access point closest to but not after offset.
int lo = -1, hi = index->have;
point_t *point = index->list;
while (hi - lo > 1) {
int mid = (lo + hi) >> 1;
if (offset < point[mid].out)
hi = mid;
else
lo = mid;
}
point += lo;
// Initialize the input file and prime the inflate engine to start there.
int ret = fseeko(in, point->in - (point->bits ? 1 : 0), SEEK_SET);
if (ret == -1)
return Z_ERRNO;
int ch = 0;
if (point->bits && (ch = getc(in)) == EOF)
return ferror(in) ? Z_ERRNO : Z_BUF_ERROR;
z_stream strm = {0};
ret = inflateInit2(&strm, RAW);
if (ret != Z_OK)
return ret;
if (point->bits)
INFLATEPRIME(&strm, point->bits, ch >> (8 - point->bits));
inflateSetDictionary(&strm, point->window, WINSIZE);
// Skip uncompressed bytes until offset reached, then satisfy request.
unsigned char input[CHUNK];
unsigned char discard[WINSIZE];
offset -= point->out; // number of bytes to skip to get to offset
size_t left = len; // number of bytes left to read after offset
do {
if (offset) {
// Discard up to offset uncompressed bytes.
strm.avail_out = offset < WINSIZE ? (unsigned)offset : WINSIZE;
strm.next_out = discard;
}
else {
// Uncompress up to left bytes into buf.
strm.avail_out = left < UINT_MAX ? (unsigned)left : UINT_MAX;
strm.next_out = buf + len - left;
}
// Uncompress, setting got to the number of bytes uncompressed.
if (strm.avail_in == 0) {
// Assure available input.
strm.avail_in = fread(input, 1, CHUNK, in);
if (strm.avail_in < CHUNK && ferror(in)) {
ret = Z_ERRNO;
break;
}
strm.next_in = input;
}
unsigned got = strm.avail_out;
ret = inflate(&strm, Z_NO_FLUSH);
got -= strm.avail_out;
// Update the appropriate count.
if (offset)
offset -= got;
else
left -= got;
// If we're at the end of a gzip member and there's more to read,
// continue to the next gzip member.
if (ret == Z_STREAM_END && index->mode == GZIP) {
// Discard the gzip trailer.
unsigned drop = 8; // length of gzip trailer
if (strm.avail_in >= drop) {
strm.avail_in -= drop;
strm.next_in += drop;
}
else {
// Read and discard the remainder of the gzip trailer.
drop -= strm.avail_in;
strm.avail_in = 0;
do {
if (getc(in) == EOF)
// The input does not have a complete trailer.
return ferror(in) ? Z_ERRNO : Z_BUF_ERROR;
} while (--drop);
}
if (strm.avail_in || ungetc(getc(in), in) != EOF) {
// There's more after the gzip trailer. Use inflate to skip the
// gzip header and resume the raw inflate there.
inflateReset2(&strm, GZIP);
do {
if (strm.avail_in == 0) {
strm.avail_in = fread(input, 1, CHUNK, in);
if (strm.avail_in < CHUNK && ferror(in)) {
ret = Z_ERRNO;
break;
}
strm.next_in = input;
}
strm.avail_out = WINSIZE;
strm.next_out = discard;
ret = inflate(&strm, Z_BLOCK); // stop at end of header
} while (ret == Z_OK && (strm.data_type & 0x80) == 0);
if (ret != Z_OK)
break;
inflateReset2(&strm, RAW);
}
}
// Continue until we have the requested data, the deflate data has
// ended, or an error is encountered.
} while (ret == Z_OK && left);
inflateEnd(&strm);
// Return the number of uncompressed bytes read into buf, or the error.
return ret == Z_OK || ret == Z_STREAM_END ? len - left : ret;
}
#ifdef TEST
#define SPAN 1048576L // desired distance between access points
#define LEN 16384 // number of bytes to extract
// Demonstrate the use of deflate_index_build() and deflate_index_extract() by
// processing the file provided on the command line, and extracting LEN bytes
// from 2/3rds of the way through the uncompressed output, writing that to
// stdout. An offset can be provided as the second argument, in which case the
// data is extracted from there instead.
int main(int argc, char **argv) {
// Open the input file.
if (argc < 2 || argc > 3) {
fprintf(stderr, "usage: zran file.raw [offset]\n");
return 1;
}
FILE *in = fopen(argv[1], "rb");
if (in == NULL) {
fprintf(stderr, "zran: could not open %s for reading\n", argv[1]);
return 1;
}
// Get optional offset.
off_t offset = -1;
if (argc == 3) {
char *end;
offset = strtoll(argv[2], &end, 10);
if (*end || offset < 0) {
fprintf(stderr, "zran: %s is not a valid offset\n", argv[2]);
return 1;
}
}
// Build index.
struct deflate_index *index = NULL;
int len = deflate_index_build(in, SPAN, &index);
if (len < 0) {
fclose(in);
switch (len) {
case Z_MEM_ERROR:
fprintf(stderr, "zran: out of memory\n");
break;
case Z_BUF_ERROR:
fprintf(stderr, "zran: %s ended prematurely\n", argv[1]);
break;
case Z_DATA_ERROR:
fprintf(stderr, "zran: compressed data error in %s\n", argv[1]);
break;
case Z_ERRNO:
fprintf(stderr, "zran: read error on %s\n", argv[1]);
break;
default:
fprintf(stderr, "zran: error %d while building index\n", len);
}
return 1;
}
fprintf(stderr, "zran: built index with %d access points\n", len);
// Use index by reading some bytes from an arbitrary offset.
unsigned char buf[LEN];
if (offset == -1)
offset = ((index->length + 1) << 1) / 3;
ptrdiff_t got = deflate_index_extract(in, index, offset, buf, LEN);
if (got < 0)
fprintf(stderr, "zran: extraction failed: %s error\n",
got == Z_MEM_ERROR ? "out of memory" : "input corrupted");
else {
fwrite(buf, 1, got, stdout);
fprintf(stderr, "zran: extracted %ld bytes at %lld\n", got, offset);
}
// Clean up and exit.
deflate_index_free(index);
fclose(in);
return 0;
}
#endif
|
Changes to compat/zlib/examples/zran.h.
|
| | | | > > > > > > > > | | | < | | | | | | | | > | | < < < | | | | | | > > > | | | | > > > | 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 |
/* zran.h -- example of deflated stream indexing and random access
* Copyright (C) 2005, 2012, 2018, 2023 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
* Version 1.3 18 Feb 2023 Mark Adler */
#include <stdio.h>
#include "zlib.h"
// Access point.
typedef struct point {
off_t out; // offset in uncompressed data
off_t in; // offset in compressed file of first full byte
int bits; // 0, or number of bits (1-7) from byte at in-1
unsigned char window[32768]; // preceding 32K of uncompressed data
} point_t;
// Access point list.
struct deflate_index {
int have; // number of access points in list
int mode; // -15 for raw, 15 for zlib, or 31 for gzip
off_t length; // total length of uncompressed data
point_t *list; // allocated list of access points
};
// Make one pass through a zlib, gzip, or raw deflate compressed stream and
// build an index, with access points about every span bytes of uncompressed
// output. gzip files with multiple members are fully indexed. span should be
// chosen to balance the speed of random access against the memory requirements
// of the list, which is about 32K bytes per access point. The return value is
// the number of access points on success (>= 1), Z_MEM_ERROR for out of
// memory, Z_BUF_ERROR for a premature end of input, Z_DATA_ERROR for a format
// or verification error in the input file, or Z_ERRNO for a file read error.
// On success, *built points to the resulting index.
int deflate_index_build(FILE *in, off_t span, struct deflate_index **built);
// Use the index to read len bytes from offset into buf. Return the number of
// bytes read or a negative error code. If data is requested past the end of
// the uncompressed data, then deflate_index_extract() will return a value less
// than len, indicating how much was actually read into buf. If given a valid
// index, this function should not return an error unless the file was modified
// somehow since the index was generated, given that deflate_index_build() had
// validated all of the input. If nevertheless there is a failure, Z_BUF_ERROR
// is returned if the compressed data ends prematurely, Z_DATA_ERROR if the
// deflate compressed data is not valid, Z_MEM_ERROR if out of memory,
// Z_STREAM_ERROR if the index is not valid, or Z_ERRNO if there is an error
// reading or seeking on the input file.
ptrdiff_t deflate_index_extract(FILE *in, struct deflate_index *index,
off_t offset, unsigned char *buf, size_t len);
// Deallocate an index built by deflate_index_build().
void deflate_index_free(struct deflate_index *index);
|
Changes to compat/zlib/gzclose.c.
1 2 3 4 5 6 7 8 9 10 | /* gzclose.c -- zlib gzclose() function * Copyright (C) 2004, 2010 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ #include "gzguts.h" /* gzclose() is in a separate file so that it is linked in only if it is used. That way the other gzclose functions can be used instead to avoid linking in unneeded compression or decompression routines. */ | | < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
/* gzclose.c -- zlib gzclose() function
* Copyright (C) 2004, 2010 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#include "gzguts.h"
/* gzclose() is in a separate file so that it is linked in only if it is used.
That way the other gzclose functions can be used instead to avoid linking in
unneeded compression or decompression routines. */
int ZEXPORT gzclose(gzFile file) {
#ifndef NO_GZCOMPRESS
gz_statep state;
if (file == NULL)
return Z_STREAM_ERROR;
state = (gz_statep)file;
|
| ︙ | ︙ |
Changes to compat/zlib/gzguts.h.
1 2 3 4 5 6 7 8 9 | /* gzguts.h -- zlib internal header definitions for gz* operations * Copyright (C) 2004-2019 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ #ifdef _LARGEFILE64_SOURCE # ifndef _LARGEFILE_SOURCE # define _LARGEFILE_SOURCE 1 # endif | | | < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
/* gzguts.h -- zlib internal header definitions for gz* operations
* Copyright (C) 2004-2019 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#ifdef _LARGEFILE64_SOURCE
# ifndef _LARGEFILE_SOURCE
# define _LARGEFILE_SOURCE 1
# endif
# undef _FILE_OFFSET_BITS
# undef _TIME_BITS
#endif
#ifdef HAVE_HIDDEN
# define ZLIB_INTERNAL __attribute__((visibility ("hidden")))
#else
# define ZLIB_INTERNAL
#endif
|
| ︙ | ︙ | |||
115 116 117 118 119 120 121 | #endif /* since "static" is used to mean two completely different things in C, we define "local" for the non-static meaning of "static", for readability (compile with -Dlocal if your debugger can't find static symbols) */ /* gz* functions always use library allocation functions */ #ifndef STDC | | | | | | | | 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 |
#endif
/* since "static" is used to mean two completely different things in C, we
define "local" for the non-static meaning of "static", for readability
(compile with -Dlocal if your debugger can't find static symbols) */
/* gz* functions always use library allocation functions */
#ifndef STDC
extern voidp malloc(uInt size);
extern void free(voidpf ptr);
#endif
/* get errno and strerror definition */
#if defined UNDER_CE
# include <windows.h>
# define zstrerror() gz_strwinerror((DWORD)GetLastError())
#else
# ifndef NO_STRERROR
# include <errno.h>
# define zstrerror() strerror(errno)
# else
# define zstrerror() "stdio error (consult errno)"
# endif
#endif
/* provide prototypes for these when building zlib without LFS */
#if !defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0
ZEXTERN gzFile ZEXPORT gzopen64(const char *, const char *);
ZEXTERN z_off64_t ZEXPORT gzseek64(gzFile, z_off64_t, int);
ZEXTERN z_off64_t ZEXPORT gztell64(gzFile);
ZEXTERN z_off64_t ZEXPORT gzoffset64(gzFile);
#endif
/* default memLevel */
#if MAX_MEM_LEVEL >= 8
# define DEF_MEM_LEVEL 8
#else
# define DEF_MEM_LEVEL MAX_MEM_LEVEL
|
| ︙ | ︙ | |||
199 200 201 202 203 204 205 |
char *msg; /* error message */
/* zlib inflate or deflate stream */
z_stream strm; /* stream structure in-place (not a pointer) */
} gz_state;
typedef gz_state FAR *gz_statep;
/* shared functions */
| | | | | 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 |
char *msg; /* error message */
/* zlib inflate or deflate stream */
z_stream strm; /* stream structure in-place (not a pointer) */
} gz_state;
typedef gz_state FAR *gz_statep;
/* shared functions */
void ZLIB_INTERNAL gz_error(gz_statep, int, const char *);
#if defined UNDER_CE
char ZLIB_INTERNAL *gz_strwinerror(DWORD error);
#endif
/* GT_OFF(x), where x is an unsigned value, is true if x > maximum z_off64_t
value -- needed when comparing unsigned to z_off64_t, which is signed
(possible z_off64_t types off_t, off64_t, and long are all signed) */
#ifdef INT_MAX
# define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > INT_MAX)
#else
unsigned ZLIB_INTERNAL gz_intmax(void);
# define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > gz_intmax())
#endif
|
Changes to compat/zlib/gzlib.c.
| ︙ | ︙ | |||
11 12 13 14 15 16 17 | #if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0 # define LSEEK lseek64 #else # define LSEEK lseek #endif #endif | < < < < | < < | 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 |
#if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0
# define LSEEK lseek64
#else
# define LSEEK lseek
#endif
#endif
#if defined UNDER_CE
/* Map the Windows error number in ERROR to a locale-dependent error message
string and return a pointer to it. Typically, the values for ERROR come
from GetLastError.
The string pointed to shall not be modified by the application, but may be
overwritten by a subsequent call to gz_strwinerror
The gz_strwinerror function does not change the current setting of
GetLastError. */
char ZLIB_INTERNAL *gz_strwinerror(DWORD error) {
static char buf[1024];
wchar_t *msgbuf;
DWORD lasterr = GetLastError();
DWORD chars = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM
| FORMAT_MESSAGE_ALLOCATE_BUFFER,
NULL,
|
| ︙ | ︙ | |||
68 69 70 71 72 73 74 |
SetLastError(lasterr);
return buf;
}
#endif /* UNDER_CE */
/* Reset gzip file state */
| | < < | < < < < | 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 |
SetLastError(lasterr);
return buf;
}
#endif /* UNDER_CE */
/* Reset gzip file state */
local void gz_reset(gz_statep state) {
state->x.have = 0; /* no output data available */
if (state->mode == GZ_READ) { /* for reading ... */
state->eof = 0; /* not at end of file */
state->past = 0; /* have not read past end yet */
state->how = LOOK; /* look for gzip header */
}
else /* for writing ... */
state->reset = 0; /* no deflateReset pending */
state->seek = 0; /* no seek request pending */
gz_error(state, Z_OK, NULL); /* clear error */
state->x.pos = 0; /* no uncompressed data yet */
state->strm.avail_in = 0; /* no input data yet */
}
/* Open a gzip file either by name or file descriptor. */
local gzFile gz_open(const void *path, int fd, const char *mode) {
gz_statep state;
z_size_t len;
int oflag;
#ifdef O_CLOEXEC
int cloexec = 0;
#endif
#ifdef O_EXCL
|
| ︙ | ︙ | |||
265 266 267 268 269 270 271 |
gz_reset(state);
/* return stream */
return (gzFile)state;
}
/* -- see zlib.h -- */
| | | < > | > > < < < < < < < < | < < < | < < < | < < < | | | < < | < < < < | 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 |
gz_reset(state);
/* return stream */
return (gzFile)state;
}
/* -- see zlib.h -- */
gzFile ZEXPORT gzopen(const char *path, const char *mode) {
return gz_open(path, -1, mode);
}
/* -- see zlib.h -- */
gzFile ZEXPORT gzopen64(const char *path, const char *mode) {
return gz_open(path, -1, mode);
}
/* -- see zlib.h -- */
gzFile ZEXPORT gzdopen(int fd, const char *mode) {
char *path; /* identifier for error messages */
gzFile gz;
if (fd == -1 || (path = (char *)malloc(7 + 3 * sizeof(int))) == NULL)
return NULL;
#if !defined(NO_snprintf) && !defined(NO_vsnprintf)
(void)snprintf(path, 7 + 3 * sizeof(int), "<fd:%d>", fd);
#else
sprintf(path, "<fd:%d>", fd); /* for debugging */
#endif
gz = gz_open(path, fd, mode);
free(path);
return gz;
}
/* -- see zlib.h -- */
#ifdef WIDECHAR
gzFile ZEXPORT gzopen_w(const wchar_t *path, const char *mode) {
return gz_open(path, -2, mode);
}
#endif
/* -- see zlib.h -- */
int ZEXPORT gzbuffer(gzFile file, unsigned size) {
gz_statep state;
/* get internal structure and check integrity */
if (file == NULL)
return -1;
state = (gz_statep)file;
if (state->mode != GZ_READ && state->mode != GZ_WRITE)
return -1;
/* make sure we haven't already allocated memory */
if (state->size != 0)
return -1;
/* check and set requested size */
if ((size << 1) < size)
return -1; /* need to be able to double it */
if (size < 8)
size = 8; /* needed to behave well with flushing */
state->want = size;
return 0;
}
/* -- see zlib.h -- */
int ZEXPORT gzrewind(gzFile file) {
gz_statep state;
/* get internal structure */
if (file == NULL)
return -1;
state = (gz_statep)file;
/* check that we're reading and that there's no error */
if (state->mode != GZ_READ ||
(state->err != Z_OK && state->err != Z_BUF_ERROR))
return -1;
/* back up and start over */
if (LSEEK(state->fd, state->start, SEEK_SET) == -1)
return -1;
gz_reset(state);
return 0;
}
/* -- see zlib.h -- */
z_off64_t ZEXPORT gzseek64(gzFile file, z_off64_t offset, int whence) {
unsigned n;
z_off64_t ret;
gz_statep state;
/* get internal structure and check integrity */
if (file == NULL)
return -1;
|
| ︙ | ︙ | |||
438 439 440 441 442 443 444 |
state->seek = 1;
state->skip = offset;
}
return state->x.pos + offset;
}
/* -- see zlib.h -- */
| | < < < < | < < | < < | < < | < < | < < | < < < | < < | 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 |
state->seek = 1;
state->skip = offset;
}
return state->x.pos + offset;
}
/* -- see zlib.h -- */
z_off_t ZEXPORT gzseek(gzFile file, z_off_t offset, int whence) {
z_off64_t ret;
ret = gzseek64(file, (z_off64_t)offset, whence);
return ret == (z_off_t)ret ? (z_off_t)ret : -1;
}
/* -- see zlib.h -- */
z_off64_t ZEXPORT gztell64(gzFile file) {
gz_statep state;
/* get internal structure and check integrity */
if (file == NULL)
return -1;
state = (gz_statep)file;
if (state->mode != GZ_READ && state->mode != GZ_WRITE)
return -1;
/* return position */
return state->x.pos + (state->seek ? state->skip : 0);
}
/* -- see zlib.h -- */
z_off_t ZEXPORT gztell(gzFile file) {
z_off64_t ret;
ret = gztell64(file);
return ret == (z_off_t)ret ? (z_off_t)ret : -1;
}
/* -- see zlib.h -- */
z_off64_t ZEXPORT gzoffset64(gzFile file) {
z_off64_t offset;
gz_statep state;
/* get internal structure and check integrity */
if (file == NULL)
return -1;
state = (gz_statep)file;
if (state->mode != GZ_READ && state->mode != GZ_WRITE)
return -1;
/* compute and return effective offset in file */
offset = LSEEK(state->fd, 0, SEEK_CUR);
if (offset == -1)
return -1;
if (state->mode == GZ_READ) /* reading */
offset -= state->strm.avail_in; /* don't count buffered input */
return offset;
}
/* -- see zlib.h -- */
z_off_t ZEXPORT gzoffset(gzFile file) {
z_off64_t ret;
ret = gzoffset64(file);
return ret == (z_off_t)ret ? (z_off_t)ret : -1;
}
/* -- see zlib.h -- */
int ZEXPORT gzeof(gzFile file) {
gz_statep state;
/* get internal structure and check integrity */
if (file == NULL)
return 0;
state = (gz_statep)file;
if (state->mode != GZ_READ && state->mode != GZ_WRITE)
return 0;
/* return end-of-file state */
return state->mode == GZ_READ ? state->past : 0;
}
/* -- see zlib.h -- */
const char * ZEXPORT gzerror(gzFile file, int *errnum) {
gz_statep state;
/* get internal structure and check integrity */
if (file == NULL)
return NULL;
state = (gz_statep)file;
if (state->mode != GZ_READ && state->mode != GZ_WRITE)
return NULL;
/* return error information */
if (errnum != NULL)
*errnum = state->err;
return state->err == Z_MEM_ERROR ? "out of memory" :
(state->msg == NULL ? "" : state->msg);
}
/* -- see zlib.h -- */
void ZEXPORT gzclearerr(gzFile file) {
gz_statep state;
/* get internal structure and check integrity */
if (file == NULL)
return;
state = (gz_statep)file;
if (state->mode != GZ_READ && state->mode != GZ_WRITE)
|
| ︙ | ︙ | |||
574 575 576 577 578 579 580 | /* Create an error message in allocated memory and set state->err and state->msg accordingly. Free any previous error message already there. Do not try to free or allocate space if the error is Z_MEM_ERROR (out of memory). Simply save the error message as a static string. If there is an allocation failure constructing the error message, then convert the error to out of memory. */ | | < < < < | 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 |
/* Create an error message in allocated memory and set state->err and
state->msg accordingly. Free any previous error message already there. Do
not try to free or allocate space if the error is Z_MEM_ERROR (out of
memory). Simply save the error message as a static string. If there is an
allocation failure constructing the error message, then convert the error to
out of memory. */
void ZLIB_INTERNAL gz_error(gz_statep state, int err, const char *msg) {
/* free previously allocated message and clear */
if (state->msg != NULL) {
if (state->err != Z_MEM_ERROR)
free(state->msg);
state->msg = NULL;
}
|
| ︙ | ︙ | |||
620 621 622 623 624 625 626 | } #ifndef INT_MAX /* portably return maximum value for an int (when limits.h presumed not available) -- we need to do this to cover cases where 2's complement not used, since C standard permits 1's complement and sign-bit representations, otherwise we could just use ((unsigned)-1) >> 1 */ | | < | 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 |
}
#ifndef INT_MAX
/* portably return maximum value for an int (when limits.h presumed not
available) -- we need to do this to cover cases where 2's complement not
used, since C standard permits 1's complement and sign-bit representations,
otherwise we could just use ((unsigned)-1) >> 1 */
unsigned ZLIB_INTERNAL gz_intmax(void) {
unsigned p, q;
p = 1;
do {
q = p;
p <<= 1;
p++;
} while (p > q);
return q >> 1;
}
#endif
|
Changes to compat/zlib/gzread.c.
1 2 3 4 5 6 7 | /* gzread.c -- zlib functions for reading gzip files * Copyright (C) 2004-2017 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ #include "gzguts.h" | < < < < < < < < < < < | < | < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
/* gzread.c -- zlib functions for reading gzip files
* Copyright (C) 2004-2017 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#include "gzguts.h"
/* Use read() to load a buffer -- return -1 on error, otherwise 0. Read from
state->fd, and update state->eof, state->err, and state->msg as appropriate.
This function needs to loop on read(), since read() is not guaranteed to
read the number of bytes requested, depending on the type of descriptor. */
local int gz_load(gz_statep state, unsigned char *buf, unsigned len,
unsigned *have) {
int ret;
unsigned get, max = ((unsigned)-1 >> 2) + 1;
*have = 0;
do {
get = len - *have;
if (get > max)
|
| ︙ | ︙ | |||
49 50 51 52 53 54 55 | /* Load up input buffer and set eof flag if last data loaded -- return -1 on error, 0 otherwise. Note that the eof flag is set when the end of the input file is reached, even though there may be unused data in the buffer. Once that data has been used, no more attempts will be made to read the file. If strm->avail_in != 0, then the current data is moved to the beginning of the input buffer, and then the remainder of the buffer is loaded with the available data from the input file. */ | | < < | 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
/* Load up input buffer and set eof flag if last data loaded -- return -1 on
error, 0 otherwise. Note that the eof flag is set when the end of the input
file is reached, even though there may be unused data in the buffer. Once
that data has been used, no more attempts will be made to read the file.
If strm->avail_in != 0, then the current data is moved to the beginning of
the input buffer, and then the remainder of the buffer is loaded with the
available data from the input file. */
local int gz_avail(gz_statep state) {
unsigned got;
z_streamp strm = &(state->strm);
if (state->err != Z_OK && state->err != Z_BUF_ERROR)
return -1;
if (state->eof == 0) {
if (strm->avail_in) { /* copy what's there to the start */
|
| ︙ | ︙ | |||
84 85 86 87 88 89 90 | left unchanged if there is no more input data available, will be set to COPY if there is no gzip header and direct copying will be performed, or it will be set to GZIP for decompression. If direct copying, then leftover input data from the input buffer will be copied to the output buffer. In that case, all further file reads will be directly to either the output buffer or a user buffer. If decompressing, the inflate state will be initialized. gz_look() will return 0 on success or -1 on failure. */ | | < < | 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
left unchanged if there is no more input data available, will be set to COPY
if there is no gzip header and direct copying will be performed, or it will
be set to GZIP for decompression. If direct copying, then leftover input
data from the input buffer will be copied to the output buffer. In that
case, all further file reads will be directly to either the output buffer or
a user buffer. If decompressing, the inflate state will be initialized.
gz_look() will return 0 on success or -1 on failure. */
local int gz_look(gz_statep state) {
z_streamp strm = &(state->strm);
/* allocate read buffers and inflate memory */
if (state->size == 0) {
/* allocate buffers */
state->in = (unsigned char *)malloc(state->want);
state->out = (unsigned char *)malloc(state->want << 1);
|
| ︙ | ︙ | |||
153 154 155 156 157 158 159 |
return 0;
}
/* doing raw i/o, copy any leftover input to output -- this assumes that
the output buffer is larger than the input buffer, which also assures
space for gzungetc() */
state->x.next = state->out;
| < | | | < | < < | 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 |
return 0;
}
/* doing raw i/o, copy any leftover input to output -- this assumes that
the output buffer is larger than the input buffer, which also assures
space for gzungetc() */
state->x.next = state->out;
memcpy(state->x.next, strm->next_in, strm->avail_in);
state->x.have = strm->avail_in;
strm->avail_in = 0;
state->how = COPY;
state->direct = 1;
return 0;
}
/* Decompress from input to the provided next_out and avail_out in the state.
On return, state->x.have and state->x.next point to the just decompressed
data. If the gzip stream completes, state->how is reset to LOOK to look for
the next gzip stream or raw data, once state->x.have is depleted. Returns 0
on success, -1 on failure. */
local int gz_decomp(gz_statep state) {
int ret = Z_OK;
unsigned had;
z_streamp strm = &(state->strm);
/* fill output buffer up to end of deflate stream */
had = strm->avail_out;
do {
|
| ︙ | ︙ | |||
222 223 224 225 226 227 228 | /* Fetch data and put it in the output buffer. Assumes state->x.have is 0. Data is either copied from the input file or decompressed from the input file depending on state->how. If state->how is LOOK, then a gzip header is looked for to determine whether to copy or decompress. Returns -1 on error, otherwise 0. gz_fetch() will leave state->how as COPY or GZIP unless the end of the input file has been reached and all data has been processed. */ | | < < | 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 |
/* Fetch data and put it in the output buffer. Assumes state->x.have is 0.
Data is either copied from the input file or decompressed from the input
file depending on state->how. If state->how is LOOK, then a gzip header is
looked for to determine whether to copy or decompress. Returns -1 on error,
otherwise 0. gz_fetch() will leave state->how as COPY or GZIP unless the
end of the input file has been reached and all data has been processed. */
local int gz_fetch(gz_statep state) {
z_streamp strm = &(state->strm);
do {
switch(state->how) {
case LOOK: /* -> LOOK, COPY (only if never GZIP), or GZIP */
if (gz_look(state) == -1)
return -1;
|
| ︙ | ︙ | |||
252 253 254 255 256 257 258 |
return -1;
}
} while (state->x.have == 0 && (!state->eof || strm->avail_in));
return 0;
}
/* Skip len uncompressed bytes of output. Return -1 on error, 0 on success. */
| | < < < | 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 |
return -1;
}
} while (state->x.have == 0 && (!state->eof || strm->avail_in));
return 0;
}
/* Skip len uncompressed bytes of output. Return -1 on error, 0 on success. */
local int gz_skip(gz_statep state, z_off64_t len) {
unsigned n;
/* skip over len bytes or reach end-of-file, whichever comes first */
while (len)
/* skip over whatever is in output buffer */
if (state->x.have) {
n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > len ?
|
| ︙ | ︙ | |||
287 288 289 290 291 292 293 |
return 0;
}
/* Read len bytes into buf from file, or less than len up to the end of the
input. Return the number of bytes read. If zero is returned, either the
end of file was reached, or there was an error. state->err must be
consulted in that case to determine which. */
| | < < < < | 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 |
return 0;
}
/* Read len bytes into buf from file, or less than len up to the end of the
input. Return the number of bytes read. If zero is returned, either the
end of file was reached, or there was an error. state->err must be
consulted in that case to determine which. */
local z_size_t gz_read(gz_statep state, voidp buf, z_size_t len) {
z_size_t got;
unsigned n;
/* if len is zero, avoid unnecessary operations */
if (len == 0)
return 0;
|
| ︙ | ︙ | |||
368 369 370 371 372 373 374 |
} while (len);
/* return number of bytes read into user buffer */
return got;
}
/* -- see zlib.h -- */
| | < < < < | 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 |
} while (len);
/* return number of bytes read into user buffer */
return got;
}
/* -- see zlib.h -- */
int ZEXPORT gzread(gzFile file, voidp buf, unsigned len) {
gz_statep state;
/* get internal structure */
if (file == NULL)
return -1;
state = (gz_statep)file;
|
| ︙ | ︙ | |||
404 405 406 407 408 409 410 |
return -1;
/* return the number of bytes read (this is assured to fit in an int) */
return (int)len;
}
/* -- see zlib.h -- */
| | < < < < < | 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 |
return -1;
/* return the number of bytes read (this is assured to fit in an int) */
return (int)len;
}
/* -- see zlib.h -- */
z_size_t ZEXPORT gzfread(voidp buf, z_size_t size, z_size_t nitems, gzFile file) {
z_size_t len;
gz_statep state;
/* get internal structure */
if (file == NULL)
return 0;
state = (gz_statep)file;
|
| ︙ | ︙ | |||
440 441 442 443 444 445 446 | /* -- see zlib.h -- */ #ifdef Z_PREFIX_SET # undef z_gzgetc #else # undef gzgetc #endif | | < < | 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 |
/* -- see zlib.h -- */
#ifdef Z_PREFIX_SET
# undef z_gzgetc
#else
# undef gzgetc
#endif
int ZEXPORT gzgetc(gzFile file) {
unsigned char buf[1];
gz_statep state;
/* get internal structure */
if (file == NULL)
return -1;
state = (gz_statep)file;
|
| ︙ | ︙ | |||
467 468 469 470 471 472 473 |
return *(state->x.next)++;
}
/* nothing there -- try gz_read() */
return gz_read(state, buf, 1) < 1 ? -1 : buf[0];
}
| | < < | < < < > > > > | 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 |
return *(state->x.next)++;
}
/* nothing there -- try gz_read() */
return gz_read(state, buf, 1) < 1 ? -1 : buf[0];
}
int ZEXPORT gzgetc_(gzFile file) {
return gzgetc(file);
}
/* -- see zlib.h -- */
int ZEXPORT gzungetc(int c, gzFile file) {
gz_statep state;
/* get internal structure */
if (file == NULL)
return -1;
state = (gz_statep)file;
/* in case this was just opened, set up the input buffer */
if (state->mode == GZ_READ && state->how == LOOK && state->x.have == 0)
(void)gz_look(state);
/* check that we're reading and that there's no (serious) error */
if (state->mode != GZ_READ ||
(state->err != Z_OK && state->err != Z_BUF_ERROR))
return -1;
/* process a skip request */
|
| ︙ | ︙ | |||
534 535 536 537 538 539 540 |
state->x.next[0] = (unsigned char)c;
state->x.pos--;
state->past = 0;
return c;
}
/* -- see zlib.h -- */
| | < < < < | 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 |
state->x.next[0] = (unsigned char)c;
state->x.pos--;
state->past = 0;
return c;
}
/* -- see zlib.h -- */
char * ZEXPORT gzgets(gzFile file, char *buf, int len) {
unsigned left, n;
char *str;
unsigned char *eol;
gz_statep state;
/* check parameters and get internal structure */
if (file == NULL || buf == NULL || len < 1)
|
| ︙ | ︙ | |||
598 599 600 601 602 603 604 |
if (buf == str)
return NULL;
buf[0] = 0;
return str;
}
/* -- see zlib.h -- */
| | < < | < < | 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 |
if (buf == str)
return NULL;
buf[0] = 0;
return str;
}
/* -- see zlib.h -- */
int ZEXPORT gzdirect(gzFile file) {
gz_statep state;
/* get internal structure */
if (file == NULL)
return 0;
state = (gz_statep)file;
/* if the state is not known, but we can find out, then do so (this is
mainly for right after a gzopen() or gzdopen()) */
if (state->mode == GZ_READ && state->how == LOOK && state->x.have == 0)
(void)gz_look(state);
/* return 1 if transparent, 0 if processing a gzip stream */
return state->direct;
}
/* -- see zlib.h -- */
int ZEXPORT gzclose_r(gzFile file) {
int ret, err;
gz_statep state;
/* get internal structure */
if (file == NULL)
return Z_STREAM_ERROR;
state = (gz_statep)file;
|
| ︙ | ︙ |
Changes to compat/zlib/gzwrite.c.
1 2 3 4 5 6 7 | /* gzwrite.c -- zlib functions for writing gzip files * Copyright (C) 2004-2019 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ #include "gzguts.h" | < < < < < < | < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
/* gzwrite.c -- zlib functions for writing gzip files
* Copyright (C) 2004-2019 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#include "gzguts.h"
/* Initialize state for writing a gzip file. Mark initialization by setting
state->size to non-zero. Return -1 on a memory allocation failure, or 0 on
success. */
local int gz_init(gz_statep state) {
int ret;
z_streamp strm = &(state->strm);
/* allocate input buffer (double size for gzprintf) */
state->in = (unsigned char *)malloc(state->want << 1);
if (state->in == NULL) {
gz_error(state, Z_MEM_ERROR, "out of memory");
|
| ︙ | ︙ | |||
66 67 68 69 70 71 72 | /* Compress whatever is at avail_in and next_in and write to the output file. Return -1 if there is an error writing to the output file or if gz_init() fails to allocate memory, otherwise 0. flush is assumed to be a valid deflate() flush value. If flush is Z_FINISH, then the deflate() state is reset to start a new gzip stream. If gz->direct is true, then simply write to the output file without compressing, and ignore flush. */ | | < < < | 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
/* Compress whatever is at avail_in and next_in and write to the output file.
Return -1 if there is an error writing to the output file or if gz_init()
fails to allocate memory, otherwise 0. flush is assumed to be a valid
deflate() flush value. If flush is Z_FINISH, then the deflate() state is
reset to start a new gzip stream. If gz->direct is true, then simply write
to the output file without compressing, and ignore flush. */
local int gz_comp(gz_statep state, int flush) {
int ret, writ;
unsigned have, put, max = ((unsigned)-1 >> 2) + 1;
z_streamp strm = &(state->strm);
/* allocate memory if this is the first time through */
if (state->size == 0 && gz_init(state) == -1)
return -1;
|
| ︙ | ︙ | |||
147 148 149 150 151 152 153 |
/* all done, no errors */
return 0;
}
/* Compress len zeros to output. Return -1 on a write error or memory
allocation failure by gz_comp(), or 0 on success. */
| | < < < | 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 |
/* all done, no errors */
return 0;
}
/* Compress len zeros to output. Return -1 on a write error or memory
allocation failure by gz_comp(), or 0 on success. */
local int gz_zero(gz_statep state, z_off64_t len) {
int first;
unsigned n;
z_streamp strm = &(state->strm);
/* consume whatever's left in the input buffer */
if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1)
return -1;
|
| ︙ | ︙ | |||
180 181 182 183 184 185 186 |
len -= n;
}
return 0;
}
/* Write len bytes from buf to file. Return the number of bytes written. If
the returned value is less than len, then there was an error. */
| | < < < < | 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 |
len -= n;
}
return 0;
}
/* Write len bytes from buf to file. Return the number of bytes written. If
the returned value is less than len, then there was an error. */
local z_size_t gz_write(gz_statep state, voidpc buf, z_size_t len) {
z_size_t put = len;
/* if len is zero, avoid unnecessary operations */
if (len == 0)
return 0;
/* allocate memory if this is the first time through */
|
| ︙ | ︙ | |||
248 249 250 251 252 253 254 |
}
/* input was all buffered or compressed */
return put;
}
/* -- see zlib.h -- */
| | < < < < | 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 |
}
/* input was all buffered or compressed */
return put;
}
/* -- see zlib.h -- */
int ZEXPORT gzwrite(gzFile file, voidpc buf, unsigned len) {
gz_statep state;
/* get internal structure */
if (file == NULL)
return 0;
state = (gz_statep)file;
|
| ︙ | ︙ | |||
276 277 278 279 280 281 282 |
}
/* write len bytes from buf (the return value will fit in an int) */
return (int)gz_write(state, buf, len);
}
/* -- see zlib.h -- */
| | < < < | < | 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 |
}
/* write len bytes from buf (the return value will fit in an int) */
return (int)gz_write(state, buf, len);
}
/* -- see zlib.h -- */
z_size_t ZEXPORT gzfwrite(voidpc buf, z_size_t size, z_size_t nitems,
gzFile file) {
z_size_t len;
gz_statep state;
/* get internal structure */
if (file == NULL)
return 0;
state = (gz_statep)file;
|
| ︙ | ︙ | |||
306 307 308 309 310 311 312 |
}
/* write len bytes to buf, return the number of full items written */
return len ? gz_write(state, buf, len) / size : 0;
}
/* -- see zlib.h -- */
| | < < < | 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 |
}
/* write len bytes to buf, return the number of full items written */
return len ? gz_write(state, buf, len) / size : 0;
}
/* -- see zlib.h -- */
int ZEXPORT gzputc(gzFile file, int c) {
unsigned have;
unsigned char buf[1];
gz_statep state;
z_streamp strm;
/* get internal structure */
if (file == NULL)
|
| ︙ | ︙ | |||
354 355 356 357 358 359 360 |
buf[0] = (unsigned char)c;
if (gz_write(state, buf, 1) != 1)
return -1;
return c & 0xff;
}
/* -- see zlib.h -- */
| | < < < | 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 |
buf[0] = (unsigned char)c;
if (gz_write(state, buf, 1) != 1)
return -1;
return c & 0xff;
}
/* -- see zlib.h -- */
int ZEXPORT gzputs(gzFile file, const char *s) {
z_size_t len, put;
gz_statep state;
/* get internal structure */
if (file == NULL)
return -1;
state = (gz_statep)file;
|
| ︙ | ︙ | |||
384 385 386 387 388 389 390 |
return put < len ? -1 : (int)len;
}
#if defined(STDC) || defined(Z_HAVE_STDARG_H)
#include <stdarg.h>
/* -- see zlib.h -- */
| | < | 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 |
return put < len ? -1 : (int)len;
}
#if defined(STDC) || defined(Z_HAVE_STDARG_H)
#include <stdarg.h>
/* -- see zlib.h -- */
int ZEXPORTVA gzvprintf(gzFile file, const char *format, va_list va) {
int len;
unsigned left;
char *next;
gz_statep state;
z_streamp strm;
/* get internal structure */
|
| ︙ | ︙ | |||
456 457 458 459 460 461 462 |
memmove(state->in, state->in + state->size, left);
strm->next_in = state->in;
strm->avail_in = left;
}
return len;
}
| | < < < < | | > | < | 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 |
memmove(state->in, state->in + state->size, left);
strm->next_in = state->in;
strm->avail_in = left;
}
return len;
}
int ZEXPORTVA gzprintf(gzFile file, const char *format, ...) {
va_list va;
int ret;
va_start(va, format);
ret = gzvprintf(file, format, va);
va_end(va);
return ret;
}
#else /* !STDC && !Z_HAVE_STDARG_H */
/* -- see zlib.h -- */
int ZEXPORTVA gzprintf(gzFile file, const char *format, int a1, int a2, int a3,
int a4, int a5, int a6, int a7, int a8, int a9, int a10,
int a11, int a12, int a13, int a14, int a15, int a16,
int a17, int a18, int a19, int a20) {
unsigned len, left;
char *next;
gz_statep state;
z_streamp strm;
/* get internal structure */
if (file == NULL)
|
| ︙ | ︙ | |||
558 559 560 561 562 563 564 |
}
return (int)len;
}
#endif
/* -- see zlib.h -- */
| | < < < | 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 |
}
return (int)len;
}
#endif
/* -- see zlib.h -- */
int ZEXPORT gzflush(gzFile file, int flush) {
gz_statep state;
/* get internal structure */
if (file == NULL)
return Z_STREAM_ERROR;
state = (gz_statep)file;
|
| ︙ | ︙ | |||
590 591 592 593 594 595 596 |
/* compress remaining data with requested flush */
(void)gz_comp(state, flush);
return state->err;
}
/* -- see zlib.h -- */
| | < < < < | | 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 |
/* compress remaining data with requested flush */
(void)gz_comp(state, flush);
return state->err;
}
/* -- see zlib.h -- */
int ZEXPORT gzsetparams(gzFile file, int level, int strategy) {
gz_statep state;
z_streamp strm;
/* get internal structure */
if (file == NULL)
return Z_STREAM_ERROR;
state = (gz_statep)file;
strm = &(state->strm);
/* check that we're writing and that there's no error */
if (state->mode != GZ_WRITE || state->err != Z_OK || state->direct)
return Z_STREAM_ERROR;
/* if no change is requested, then do nothing */
if (level == state->level && strategy == state->strategy)
return Z_OK;
/* check for seek request */
|
| ︙ | ︙ | |||
632 633 634 635 636 637 638 |
}
state->level = level;
state->strategy = strategy;
return Z_OK;
}
/* -- see zlib.h -- */
| | < < | 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 |
}
state->level = level;
state->strategy = strategy;
return Z_OK;
}
/* -- see zlib.h -- */
int ZEXPORT gzclose_w(gzFile file) {
int ret = Z_OK;
gz_statep state;
/* get internal structure */
if (file == NULL)
return Z_STREAM_ERROR;
state = (gz_statep)file;
|
| ︙ | ︙ |
Changes to compat/zlib/infback.c.
| ︙ | ︙ | |||
11 12 13 14 15 16 17 | */ #include "zutil.h" #include "inftrees.h" #include "inflate.h" #include "inffast.h" | < < < | < < | < | < | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
*/
#include "zutil.h"
#include "inftrees.h"
#include "inflate.h"
#include "inffast.h"
/*
strm provides memory allocation functions in zalloc and zfree, or
Z_NULL to use the library memory allocation functions.
windowBits is in the range 8..15, and window is a user-supplied
window and output buffer that is 2**windowBits bytes.
*/
int ZEXPORT inflateBackInit_(z_streamp strm, int windowBits,
unsigned char FAR *window, const char *version,
int stream_size) {
struct inflate_state FAR *state;
if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
stream_size != (int)(sizeof(z_stream)))
return Z_VERSION_ERROR;
if (strm == Z_NULL || window == Z_NULL ||
windowBits < 8 || windowBits > 15)
|
| ︙ | ︙ | |||
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
strm->state = (struct internal_state FAR *)state;
state->dmax = 32768U;
state->wbits = (uInt)windowBits;
state->wsize = 1U << windowBits;
state->window = window;
state->wnext = 0;
state->whave = 0;
return Z_OK;
}
/*
Return state with length and distance decoding tables and index sizes set to
fixed code decoding. Normally this returns fixed tables from inffixed.h.
If BUILDFIXED is defined, then instead this routine builds the tables the
first time it's called, and returns those tables the first time and
thereafter. This reduces the size of the code by about 2K bytes, in
exchange for a little execution time. However, BUILDFIXED should not be
used for threaded applications, since the rewriting of the tables and virgin
may not be thread-safe.
*/
| > | < < | 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 |
strm->state = (struct internal_state FAR *)state;
state->dmax = 32768U;
state->wbits = (uInt)windowBits;
state->wsize = 1U << windowBits;
state->window = window;
state->wnext = 0;
state->whave = 0;
state->sane = 1;
return Z_OK;
}
/*
Return state with length and distance decoding tables and index sizes set to
fixed code decoding. Normally this returns fixed tables from inffixed.h.
If BUILDFIXED is defined, then instead this routine builds the tables the
first time it's called, and returns those tables the first time and
thereafter. This reduces the size of the code by about 2K bytes, in
exchange for a little execution time. However, BUILDFIXED should not be
used for threaded applications, since the rewriting of the tables and virgin
may not be thread-safe.
*/
local void fixedtables(struct inflate_state FAR *state) {
#ifdef BUILDFIXED
static int virgin = 1;
static code *lenfix, *distfix;
static code fixed[544];
/* build fixed huffman tables if first call (may not be thread safe) */
if (virgin) {
|
| ︙ | ︙ | |||
243 244 245 246 247 248 249 | Z_BUF_ERROR. strm->next_in can be checked for Z_NULL to see whether it was in() or out() that caused in the error. Otherwise, inflateBack() returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format error, or Z_MEM_ERROR if it could not allocate memory for the state. inflateBack() can also return Z_STREAM_ERROR if the input parameters are not correct, i.e. strm is Z_NULL or the state was not initialized. */ | | < < < | < < | 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 |
Z_BUF_ERROR. strm->next_in can be checked for Z_NULL to see whether it
was in() or out() that caused in the error. Otherwise, inflateBack()
returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format
error, or Z_MEM_ERROR if it could not allocate memory for the state.
inflateBack() can also return Z_STREAM_ERROR if the input parameters
are not correct, i.e. strm is Z_NULL or the state was not initialized.
*/
int ZEXPORT inflateBack(z_streamp strm, in_func in, void FAR *in_desc,
out_func out, void FAR *out_desc) {
struct inflate_state FAR *state;
z_const unsigned char FAR *next; /* next input */
unsigned char FAR *put; /* next output */
unsigned have, left; /* available input and output */
unsigned long hold; /* bit buffer */
unsigned bits; /* bits in bit buffer */
unsigned copy; /* number of stored or match bytes to copy */
|
| ︙ | ︙ | |||
601 602 603 604 605 606 607 |
do {
*put++ = *from++;
} while (--copy);
} while (state->length != 0);
break;
case DONE:
| | < < < < > | | > > > > > | < < | 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 |
do {
*put++ = *from++;
} while (--copy);
} while (state->length != 0);
break;
case DONE:
/* inflate stream terminated properly */
ret = Z_STREAM_END;
goto inf_leave;
case BAD:
ret = Z_DATA_ERROR;
goto inf_leave;
default:
/* can't happen, but makes compilers happy */
ret = Z_STREAM_ERROR;
goto inf_leave;
}
/* Write leftover output and return unused input */
inf_leave:
if (left < state->wsize) {
if (out(out_desc, state->window, state->wsize - left) &&
ret == Z_STREAM_END)
ret = Z_BUF_ERROR;
}
strm->next_in = next;
strm->avail_in = have;
return ret;
}
int ZEXPORT inflateBackEnd(z_streamp strm) {
if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0)
return Z_STREAM_ERROR;
ZFREE(strm, strm->state);
strm->state = Z_NULL;
Tracev((stderr, "inflate: end\n"));
return Z_OK;
}
|
Changes to compat/zlib/inffast.c.
| ︙ | ︙ | |||
43 44 45 46 47 48 49 |
checking for available input while decoding.
- The maximum bytes that a single length/distance pair can output is 258
bytes, which is the maximum length that can be coded. inflate_fast()
requires strm->avail_out >= 258 for each loop to avoid checking for
output space.
*/
| | < < < | 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
checking for available input while decoding.
- The maximum bytes that a single length/distance pair can output is 258
bytes, which is the maximum length that can be coded. inflate_fast()
requires strm->avail_out >= 258 for each loop to avoid checking for
output space.
*/
void ZLIB_INTERNAL inflate_fast(z_streamp strm, unsigned start) {
struct inflate_state FAR *state;
z_const unsigned char FAR *in; /* local strm->next_in */
z_const unsigned char FAR *last; /* have enough input while in < last */
unsigned char FAR *out; /* local strm->next_out */
unsigned char FAR *beg; /* inflate()'s initial strm->next_out */
unsigned char FAR *end; /* while out < end, enough space available */
#ifdef INFLATE_STRICT
|
| ︙ | ︙ |
Changes to compat/zlib/inffast.h.
1 2 3 4 5 6 7 8 9 10 | /* inffast.h -- header to use inffast.c * Copyright (C) 1995-2003, 2010 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* WARNING: this file should *not* be used by applications. It is part of the implementation of the compression library and is subject to change. Applications should only use zlib.h. */ | | | 1 2 3 4 5 6 7 8 9 10 11 | /* inffast.h -- header to use inffast.c * Copyright (C) 1995-2003, 2010 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* WARNING: this file should *not* be used by applications. It is part of the implementation of the compression library and is subject to change. Applications should only use zlib.h. */ void ZLIB_INTERNAL inflate_fast(z_streamp strm, unsigned start); |
Changes to compat/zlib/inflate.c.
| ︙ | ︙ | |||
87 88 89 90 91 92 93 | #ifdef MAKEFIXED # ifndef BUILDFIXED # define BUILDFIXED # endif #endif | < < < < < < < < < < < | < < | < < | 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 |
#ifdef MAKEFIXED
# ifndef BUILDFIXED
# define BUILDFIXED
# endif
#endif
local int inflateStateCheck(z_streamp strm) {
struct inflate_state FAR *state;
if (strm == Z_NULL ||
strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0)
return 1;
state = (struct inflate_state FAR *)strm->state;
if (state == Z_NULL || state->strm != strm ||
state->mode < HEAD || state->mode > SYNC)
return 1;
return 0;
}
int ZEXPORT inflateResetKeep(z_streamp strm) {
struct inflate_state FAR *state;
if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
state = (struct inflate_state FAR *)strm->state;
strm->total_in = strm->total_out = state->total = 0;
strm->msg = Z_NULL;
if (state->wrap) /* to support ill-conceived Java test suite */
|
| ︙ | ︙ | |||
138 139 140 141 142 143 144 |
state->lencode = state->distcode = state->next = state->codes;
state->sane = 1;
state->back = -1;
Tracev((stderr, "inflate: reset\n"));
return Z_OK;
}
| | < < | < < < > > | 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 |
state->lencode = state->distcode = state->next = state->codes;
state->sane = 1;
state->back = -1;
Tracev((stderr, "inflate: reset\n"));
return Z_OK;
}
int ZEXPORT inflateReset(z_streamp strm) {
struct inflate_state FAR *state;
if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
state = (struct inflate_state FAR *)strm->state;
state->wsize = 0;
state->whave = 0;
state->wnext = 0;
return inflateResetKeep(strm);
}
int ZEXPORT inflateReset2(z_streamp strm, int windowBits) {
int wrap;
struct inflate_state FAR *state;
/* get the state */
if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
state = (struct inflate_state FAR *)strm->state;
/* extract wrap request from windowBits parameter */
if (windowBits < 0) {
if (windowBits < -15)
return Z_STREAM_ERROR;
wrap = 0;
windowBits = -windowBits;
}
else {
wrap = (windowBits >> 4) + 5;
#ifdef GUNZIP
if (windowBits < 48)
|
| ︙ | ︙ | |||
189 190 191 192 193 194 195 |
/* update state and reset the rest of it */
state->wrap = wrap;
state->wbits = (unsigned)windowBits;
return inflateReset(strm);
}
| | < < | < < | 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 |
/* update state and reset the rest of it */
state->wrap = wrap;
state->wbits = (unsigned)windowBits;
return inflateReset(strm);
}
int ZEXPORT inflateInit2_(z_streamp strm, int windowBits,
const char *version, int stream_size) {
int ret;
struct inflate_state FAR *state;
if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
stream_size != (int)(sizeof(z_stream)))
return Z_VERSION_ERROR;
if (strm == Z_NULL) return Z_STREAM_ERROR;
|
| ︙ | ︙ | |||
233 234 235 236 237 238 239 |
if (ret != Z_OK) {
ZFREE(strm, state);
strm->state = Z_NULL;
}
return ret;
}
| < < | | < | < < < < > > | 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 |
if (ret != Z_OK) {
ZFREE(strm, state);
strm->state = Z_NULL;
}
return ret;
}
int ZEXPORT inflateInit_(z_streamp strm, const char *version,
int stream_size) {
return inflateInit2_(strm, DEF_WBITS, version, stream_size);
}
int ZEXPORT inflatePrime(z_streamp strm, int bits, int value) {
struct inflate_state FAR *state;
if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
if (bits == 0)
return Z_OK;
state = (struct inflate_state FAR *)strm->state;
if (bits < 0) {
state->hold = 0;
state->bits = 0;
return Z_OK;
}
if (bits > 16 || state->bits + (uInt)bits > 32) return Z_STREAM_ERROR;
|
| ︙ | ︙ | |||
272 273 274 275 276 277 278 | If BUILDFIXED is defined, then instead this routine builds the tables the first time it's called, and returns those tables the first time and thereafter. This reduces the size of the code by about 2K bytes, in exchange for a little execution time. However, BUILDFIXED should not be used for threaded applications, since the rewriting of the tables and virgin may not be thread-safe. */ | | < < | 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 |
If BUILDFIXED is defined, then instead this routine builds the tables the
first time it's called, and returns those tables the first time and
thereafter. This reduces the size of the code by about 2K bytes, in
exchange for a little execution time. However, BUILDFIXED should not be
used for threaded applications, since the rewriting of the tables and virgin
may not be thread-safe.
*/
local void fixedtables(struct inflate_state FAR *state) {
#ifdef BUILDFIXED
static int virgin = 1;
static code *lenfix, *distfix;
static code fixed[544];
/* build fixed huffman tables if first call (may not be thread safe) */
if (virgin) {
|
| ︙ | ︙ | |||
336 337 338 339 340 341 342 |
return 0;
}
Then that can be linked with zlib built with MAKEFIXED defined and run:
a.out > inffixed.h
*/
| | | 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 |
return 0;
}
Then that can be linked with zlib built with MAKEFIXED defined and run:
a.out > inffixed.h
*/
void makefixed(void)
{
unsigned low, size;
struct inflate_state state;
fixedtables(&state);
puts(" /* inffixed.h -- table for decoding fixed codes");
puts(" * Generated automatically by makefixed().");
|
| ︙ | ︙ | |||
390 391 392 393 394 395 396 | Providing output buffers larger than 32K to inflate() should provide a speed advantage, since only the last 32K of output is copied to the sliding window upon return from inflate(), and since all distances after the first 32K of output will fall in the output data, making match copies simpler and faster. The advantage may be dependent on the size of the processor's data caches. */ | | < < < < | 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 |
Providing output buffers larger than 32K to inflate() should provide a speed
advantage, since only the last 32K of output is copied to the sliding window
upon return from inflate(), and since all distances after the first 32K of
output will fall in the output data, making match copies simpler and faster.
The advantage may be dependent on the size of the processor's data caches.
*/
local int updatewindow(z_streamp strm, const Bytef *end, unsigned copy) {
struct inflate_state FAR *state;
unsigned dist;
state = (struct inflate_state FAR *)strm->state;
/* if it hasn't been done already, allocate space for the window */
if (state->window == Z_NULL) {
|
| ︙ | ︙ | |||
616 617 618 619 620 621 622 | the allocation of and copying into a sliding window until necessary, which provides the effect documented in zlib.h for Z_FINISH when the entire input stream available. So the only thing the flush parameter actually does is: when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it will return Z_BUF_ERROR if it has not reached the end of the stream. */ | | < < < | 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 |
the allocation of and copying into a sliding window until necessary, which
provides the effect documented in zlib.h for Z_FINISH when the entire input
stream available. So the only thing the flush parameter actually does is:
when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it
will return Z_BUF_ERROR if it has not reached the end of the stream.
*/
int ZEXPORT inflate(z_streamp strm, int flush) {
struct inflate_state FAR *state;
z_const unsigned char FAR *next; /* next input */
unsigned char FAR *put; /* next output */
unsigned have, left; /* available input and output */
unsigned long hold; /* bit buffer */
unsigned bits; /* bits in bit buffer */
unsigned in, out; /* save starting available input and output */
|
| ︙ | ︙ | |||
760 761 762 763 764 765 766 |
/* fallthrough */
case EXTRA:
if (state->flags & 0x0400) {
copy = state->length;
if (copy > have) copy = have;
if (copy) {
if (state->head != Z_NULL &&
| | | > | 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 |
/* fallthrough */
case EXTRA:
if (state->flags & 0x0400) {
copy = state->length;
if (copy > have) copy = have;
if (copy) {
if (state->head != Z_NULL &&
state->head->extra != Z_NULL &&
(len = state->head->extra_len - state->length) <
state->head->extra_max) {
zmemcpy(state->head->extra + len, next,
len + copy > state->head->extra_max ?
state->head->extra_max - len : copy);
}
if ((state->flags & 0x0200) && (state->wrap & 4))
state->check = crc32(state->check, next, copy);
have -= copy;
|
| ︙ | ︙ | |||
1294 1295 1296 1297 1298 1299 1300 |
(state->mode == TYPE ? 128 : 0) +
(state->mode == LEN_ || state->mode == COPY_ ? 256 : 0);
if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK)
ret = Z_BUF_ERROR;
return ret;
}
| | < < | < < | < | < < | < | 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 |
(state->mode == TYPE ? 128 : 0) +
(state->mode == LEN_ || state->mode == COPY_ ? 256 : 0);
if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK)
ret = Z_BUF_ERROR;
return ret;
}
int ZEXPORT inflateEnd(z_streamp strm) {
struct inflate_state FAR *state;
if (inflateStateCheck(strm))
return Z_STREAM_ERROR;
state = (struct inflate_state FAR *)strm->state;
if (state->window != Z_NULL) ZFREE(strm, state->window);
ZFREE(strm, strm->state);
strm->state = Z_NULL;
Tracev((stderr, "inflate: end\n"));
return Z_OK;
}
int ZEXPORT inflateGetDictionary(z_streamp strm, Bytef *dictionary,
uInt *dictLength) {
struct inflate_state FAR *state;
/* check state */
if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
state = (struct inflate_state FAR *)strm->state;
/* copy dictionary */
if (state->whave && dictionary != Z_NULL) {
zmemcpy(dictionary, state->window + state->wnext,
state->whave - state->wnext);
zmemcpy(dictionary + state->whave - state->wnext,
state->window, state->wnext);
}
if (dictLength != Z_NULL)
*dictLength = state->whave;
return Z_OK;
}
int ZEXPORT inflateSetDictionary(z_streamp strm, const Bytef *dictionary,
uInt dictLength) {
struct inflate_state FAR *state;
unsigned long dictid;
int ret;
/* check state */
if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
state = (struct inflate_state FAR *)strm->state;
|
| ︙ | ︙ | |||
1366 1367 1368 1369 1370 1371 1372 |
return Z_MEM_ERROR;
}
state->havedict = 1;
Tracev((stderr, "inflate: dictionary set\n"));
return Z_OK;
}
| | < < < | 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 |
return Z_MEM_ERROR;
}
state->havedict = 1;
Tracev((stderr, "inflate: dictionary set\n"));
return Z_OK;
}
int ZEXPORT inflateGetHeader(z_streamp strm, gz_headerp head) {
struct inflate_state FAR *state;
/* check state */
if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
state = (struct inflate_state FAR *)strm->state;
if ((state->wrap & 2) == 0) return Z_STREAM_ERROR;
|
| ︙ | ︙ | |||
1394 1395 1396 1397 1398 1399 1400 | state. If on return *have equals four, then the pattern was found and the return value is how many bytes were read including the last byte of the pattern. If *have is less than four, then the pattern has not been found yet and the return value is len. In the latter case, syncsearch() can be called again with more data and the *have state. *have is initialized to zero for the first call. */ | | < < | < | < < | 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 |
state. If on return *have equals four, then the pattern was found and the
return value is how many bytes were read including the last byte of the
pattern. If *have is less than four, then the pattern has not been found
yet and the return value is len. In the latter case, syncsearch() can be
called again with more data and the *have state. *have is initialized to
zero for the first call.
*/
local unsigned syncsearch(unsigned FAR *have, const unsigned char FAR *buf,
unsigned len) {
unsigned got;
unsigned next;
got = *have;
next = 0;
while (next < len && got < 4) {
if ((int)(buf[next]) == (got < 2 ? 0 : 0xff))
got++;
else if (buf[next])
got = 0;
else
got = 4 - got;
next++;
}
*have = got;
return next;
}
int ZEXPORT inflateSync(z_streamp strm) {
unsigned len; /* number of bytes to look at or looked at */
int flags; /* temporary to save header status */
unsigned long in, out; /* temporary to save total_in and total_out */
unsigned char buf[4]; /* to restore bit buffer to byte string */
struct inflate_state FAR *state;
/* check parameters */
|
| ︙ | ︙ | |||
1475 1476 1477 1478 1479 1480 1481 | Returns true if inflate is currently at the end of a block generated by Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP implementation to provide an additional safety check. PPP uses Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored block. When decompressing, PPP checks that at the end of input packet, inflate is waiting for these length bytes. */ | | < < | < < < | 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 |
Returns true if inflate is currently at the end of a block generated by
Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP
implementation to provide an additional safety check. PPP uses
Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored
block. When decompressing, PPP checks that at the end of input packet,
inflate is waiting for these length bytes.
*/
int ZEXPORT inflateSyncPoint(z_streamp strm) {
struct inflate_state FAR *state;
if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
state = (struct inflate_state FAR *)strm->state;
return state->mode == STORED && state->bits == 0;
}
int ZEXPORT inflateCopy(z_streamp dest, z_streamp source) {
struct inflate_state FAR *state;
struct inflate_state FAR *copy;
unsigned char FAR *window;
unsigned wsize;
/* check input */
if (inflateStateCheck(source) || dest == Z_NULL)
|
| ︙ | ︙ | |||
1532 1533 1534 1535 1536 1537 1538 |
zmemcpy(window, state->window, wsize);
}
copy->window = window;
dest->state = (struct internal_state FAR *)copy;
return Z_OK;
}
| | < < < | < < < | < < | < < | 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 1522 1523 1524 1525 1526 |
zmemcpy(window, state->window, wsize);
}
copy->window = window;
dest->state = (struct internal_state FAR *)copy;
return Z_OK;
}
int ZEXPORT inflateUndermine(z_streamp strm, int subvert) {
struct inflate_state FAR *state;
if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
state = (struct inflate_state FAR *)strm->state;
#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
state->sane = !subvert;
return Z_OK;
#else
(void)subvert;
state->sane = 1;
return Z_DATA_ERROR;
#endif
}
int ZEXPORT inflateValidate(z_streamp strm, int check) {
struct inflate_state FAR *state;
if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
state = (struct inflate_state FAR *)strm->state;
if (check && state->wrap)
state->wrap |= 4;
else
state->wrap &= ~4;
return Z_OK;
}
long ZEXPORT inflateMark(z_streamp strm) {
struct inflate_state FAR *state;
if (inflateStateCheck(strm))
return -(1L << 16);
state = (struct inflate_state FAR *)strm->state;
return (long)(((unsigned long)((long)state->back)) << 16) +
(state->mode == COPY ? state->length :
(state->mode == MATCH ? state->was - state->length : 0));
}
unsigned long ZEXPORT inflateCodesUsed(z_streamp strm) {
struct inflate_state FAR *state;
if (inflateStateCheck(strm)) return (unsigned long)-1;
state = (struct inflate_state FAR *)strm->state;
return (unsigned long)(state->next - state->codes);
}
|
Changes to compat/zlib/inftrees.c.
1 | /* inftrees.c -- generate Huffman trees for efficient decoding | | | < < | | < | < < | 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 |
/* inftrees.c -- generate Huffman trees for efficient decoding
* Copyright (C) 1995-2023 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#include "zutil.h"
#include "inftrees.h"
#define MAXBITS 15
const char inflate_copyright[] =
" inflate 1.3 Copyright 1995-2023 Mark Adler ";
/*
If you use the zlib library in a product, an acknowledgment is welcome
in the documentation of your product. If for some reason you cannot
include such an acknowledgment, I would appreciate that you keep this
copyright string in the executable of your product.
*/
/*
Build a set of tables to decode the provided canonical Huffman code.
The code lengths are lens[0..codes-1]. The result starts at *table,
whose indices are 0..2^bits-1. work is a writable array of at least
lens shorts, which is used as a work area. type is the type of code
to be generated, CODES, LENS, or DISTS. On return, zero is success,
-1 is an invalid code, and +1 means that ENOUGH isn't enough. table
on return points to the next available entry's address. bits is the
requested root table index bits, and on return it is the actual root
table index bits. It will differ if the request is greater than the
longest code or if it is less than the shortest code.
*/
int ZLIB_INTERNAL inflate_table(codetype type, unsigned short FAR *lens,
unsigned codes, code FAR * FAR *table,
unsigned FAR *bits, unsigned short FAR *work) {
unsigned len; /* a code's length in bits */
unsigned sym; /* index of code symbols */
unsigned min, max; /* minimum and maximum code lengths */
unsigned root; /* number of index bits for root table */
unsigned curr; /* number of index bits for current table */
unsigned drop; /* code bits to drop for sub-table */
int left; /* number of prefix codes available */
|
| ︙ | ︙ | |||
58 59 60 61 62 63 64 |
unsigned short count[MAXBITS+1]; /* number of codes of each length */
unsigned short offs[MAXBITS+1]; /* offsets in table for each length */
static const unsigned short lbase[31] = { /* Length codes 257..285 base */
3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
static const unsigned short lext[31] = { /* Length codes 257..285 extra */
16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18,
| | | 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
unsigned short count[MAXBITS+1]; /* number of codes of each length */
unsigned short offs[MAXBITS+1]; /* offsets in table for each length */
static const unsigned short lbase[31] = { /* Length codes 257..285 base */
3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
static const unsigned short lext[31] = { /* Length codes 257..285 extra */
16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18,
19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 198, 203};
static const unsigned short dbase[32] = { /* Distance codes 0..29 base */
1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
8193, 12289, 16385, 24577, 0, 0};
static const unsigned short dext[32] = { /* Distance codes 0..29 extra */
16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22,
23, 23, 24, 24, 25, 25, 26, 26, 27, 27,
|
| ︙ | ︙ |
Changes to compat/zlib/inftrees.h.
| ︙ | ︙ | |||
34 35 36 37 38 39 40 |
01100000 - end of block
01000000 - invalid code
*/
/* Maximum size of the dynamic table. The maximum number of code structures is
1444, which is the sum of 852 for literal/length codes and 592 for distance
codes. These values were found by exhaustive searches using the program
| | | | | | 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 |
01100000 - end of block
01000000 - invalid code
*/
/* Maximum size of the dynamic table. The maximum number of code structures is
1444, which is the sum of 852 for literal/length codes and 592 for distance
codes. These values were found by exhaustive searches using the program
examples/enough.c found in the zlib distribution. The arguments to that
program are the number of symbols, the initial root table size, and the
maximum bit length of a code. "enough 286 9 15" for literal/length codes
returns returns 852, and "enough 30 6 15" for distance codes returns 592.
The initial root table size (9 or 6) is found in the fifth argument of the
inflate_table() calls in inflate.c and infback.c. If the root table size is
changed, then these maximum sizes would be need to be recalculated and
updated. */
#define ENOUGH_LENS 852
#define ENOUGH_DISTS 592
#define ENOUGH (ENOUGH_LENS+ENOUGH_DISTS)
/* Type of code to build for inflate_table() */
typedef enum {
CODES,
LENS,
DISTS
} codetype;
int ZLIB_INTERNAL inflate_table(codetype type, unsigned short FAR *lens,
unsigned codes, code FAR * FAR *table,
unsigned FAR *bits, unsigned short FAR *work);
|
Changes to compat/zlib/make_vms.com.
| ︙ | ︙ | |||
10 11 12 13 14 15 16 | $!------------------------------------------------------------------------------ $! Version history $! 0.01 20060120 First version to receive a number $! 0.02 20061008 Adapt to new Makefile.in $! 0.03 20091224 Add support for large file check $! 0.04 20100110 Add new gzclose, gzlib, gzread, gzwrite $! 0.05 20100221 Exchange zlibdefs.h by zconf.h.in | | | | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
$!------------------------------------------------------------------------------
$! Version history
$! 0.01 20060120 First version to receive a number
$! 0.02 20061008 Adapt to new Makefile.in
$! 0.03 20091224 Add support for large file check
$! 0.04 20100110 Add new gzclose, gzlib, gzread, gzwrite
$! 0.05 20100221 Exchange zlibdefs.h by zconf.h.in
$! 0.06 20120111 Fix missing amiss_err, update zconf_h.in, fix new examples
$! subdir path, update module search in makefile.in
$! 0.07 20120115 Triggered by work done by Alexey Chupahin completely redesigned
$! shared image creation
$! 0.08 20120219 Make it work on VAX again, pre-load missing symbols to shared
$! image
$! 0.09 20120305 SMS. P1 sets builder ("MMK", "MMS", " " (built-in)).
$! "" -> automatic, preference: MMK, MMS, built-in.
$!
$ on error then goto err_exit
|
| ︙ | ︙ |
Changes to compat/zlib/os400/README400.
|
| | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 |
ZLIB version 1.3.0 for OS/400 installation instructions
1) Download and unpack the zlib tarball to some IFS directory.
(i.e.: /path/to/the/zlib/ifs/source/directory)
If the installed IFS command supports gzip format, this is straightforward,
else you have to unpack first to some directory on a system supporting it,
then move the whole directory to the IFS via the network (via SMB or FTP).
2) Edit the configuration parameters in the compilation script.
EDTF STMF('/path/to/the/zlib/ifs/source/directory/os400/make.sh')
|
| ︙ | ︙ | |||
39 40 41 42 43 44 45 |
In the ILE environment, the same definitions are available from
file zlib.inc located in the same IFS include directory as the
C/C++ header files.
Please read comments in this member for more information.
Remember that most foreign textual data are ASCII coded: this
implementation does not handle conversion from/to ASCII, so
| | | 39 40 41 42 43 44 45 46 47 48 |
In the ILE environment, the same definitions are available from
file zlib.inc located in the same IFS include directory as the
C/C++ header files.
Please read comments in this member for more information.
Remember that most foreign textual data are ASCII coded: this
implementation does not handle conversion from/to ASCII, so
text data code conversions must be done explicitly.
Mainly for the reason above, always open zipped files in binary mode.
|
Changes to compat/zlib/os400/bndsrc.
| ︙ | ︙ | |||
111 112 113 114 115 116 117 118 119 |
EXPORT SYMBOL("crc32_z")
EXPORT SYMBOL("deflateGetDictionary")
EXPORT SYMBOL("gzfread")
EXPORT SYMBOL("gzfwrite")
EXPORT SYMBOL("inflateCodesUsed")
EXPORT SYMBOL("inflateValidate")
EXPORT SYMBOL("uncompress2")
ENDPGMEXP
| > > > > > > > > | 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 |
EXPORT SYMBOL("crc32_z")
EXPORT SYMBOL("deflateGetDictionary")
EXPORT SYMBOL("gzfread")
EXPORT SYMBOL("gzfwrite")
EXPORT SYMBOL("inflateCodesUsed")
EXPORT SYMBOL("inflateValidate")
EXPORT SYMBOL("uncompress2")
/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
/* Version 1.2.12 additional entry points. */
/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
EXPORT SYMBOL("crc32_combine_gen64")
EXPORT SYMBOL("crc32_combine_gen")
EXPORT SYMBOL("crc32_combine_op")
ENDPGMEXP
|
Changes to compat/zlib/os400/zlib.inc.
1 2 3 |
* ZLIB.INC - Interface to the general purpose compression library
*
* ILE RPG400 version by Patrick Monnerat, DATASPHERE.
| | | | | | 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 |
* ZLIB.INC - Interface to the general purpose compression library
*
* ILE RPG400 version by Patrick Monnerat, DATASPHERE.
* Version 1.3.0
*
*
* WARNING:
* Procedures inflateInit(), inflateInit2(), deflateInit(),
* deflateInit2() and inflateBackInit() need to be called with
* two additional arguments:
* the package version string and the stream control structure.
* size. This is needed because RPG lacks some macro feature.
* Call these procedures as:
* inflateInit(...: ZLIB_VERSION: %size(z_stream))
*
/if not defined(ZLIB_H_)
/define ZLIB_H_
*
**************************************************************************
* Constants
**************************************************************************
*
* Versioning information.
*
D ZLIB_VERSION C '1.3.0'
D ZLIB_VERNUM C X'12a0'
D ZLIB_VER_MAJOR C 1
D ZLIB_VER_MINOR C 3
D ZLIB_VER_REVISION...
D C 0
D ZLIB_VER_SUBREVISION...
D C 0
*
* Other equates.
*
D Z_NO_FLUSH C 0
D Z_PARTIAL_FLUSH...
|
| ︙ | ︙ |
Changes to compat/zlib/qnx/package.qpg.
| ︙ | ︙ | |||
21 22 23 24 25 26 27 |
<QPG:EmailAddress></QPG:EmailAddress>
</QPG:Responsible>
<QPG:Values>
<QPG:Files>
<QPG:Add file="../zconf.h" install="/opt/include/" user="root:sys" permission="644"/>
<QPG:Add file="../zlib.h" install="/opt/include/" user="root:sys" permission="644"/>
| | | | | | 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
<QPG:EmailAddress></QPG:EmailAddress>
</QPG:Responsible>
<QPG:Values>
<QPG:Files>
<QPG:Add file="../zconf.h" install="/opt/include/" user="root:sys" permission="644"/>
<QPG:Add file="../zlib.h" install="/opt/include/" user="root:sys" permission="644"/>
<QPG:Add file="../libz.so.1.3.0" install="/opt/lib/" user="root:bin" permission="644"/>
<QPG:Add file="libz.so" install="/opt/lib/" component="dev" filetype="symlink" linkto="libz.so.1.3.0"/>
<QPG:Add file="libz.so.1" install="/opt/lib/" filetype="symlink" linkto="libz.so.1.3.0"/>
<QPG:Add file="../libz.so.1.3.0" install="/opt/lib/" component="slib"/>
</QPG:Files>
<QPG:PackageFilter>
<QPM:PackageManifest>
<QPM:PackageDescription>
<QPM:PackageType>Library</QPM:PackageType>
<QPM:PackageReleaseNotes></QPM:PackageReleaseNotes>
|
| ︙ | ︙ | |||
59 60 61 62 63 64 65 |
<QPM:ProductDescriptionShort>A massively spiffy yet delicately unobtrusive compression library.</QPM:ProductDescriptionShort>
<QPM:ProductDescriptionLong>zlib is designed to be a free, general-purpose, legally unencumbered, lossless data compression library for use on virtually any computer hardware and operating system.</QPM:ProductDescriptionLong>
<QPM:ProductDescriptionURL>http://www.gzip.org/zlib</QPM:ProductDescriptionURL>
<QPM:ProductDescriptionEmbedURL></QPM:ProductDescriptionEmbedURL>
</QPM:ProductDescription>
<QPM:ReleaseDescription>
| | | 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
<QPM:ProductDescriptionShort>A massively spiffy yet delicately unobtrusive compression library.</QPM:ProductDescriptionShort>
<QPM:ProductDescriptionLong>zlib is designed to be a free, general-purpose, legally unencumbered, lossless data compression library for use on virtually any computer hardware and operating system.</QPM:ProductDescriptionLong>
<QPM:ProductDescriptionURL>http://www.gzip.org/zlib</QPM:ProductDescriptionURL>
<QPM:ProductDescriptionEmbedURL></QPM:ProductDescriptionEmbedURL>
</QPM:ProductDescription>
<QPM:ReleaseDescription>
<QPM:ReleaseVersion>1.3.0</QPM:ReleaseVersion>
<QPM:ReleaseUrgency>Medium</QPM:ReleaseUrgency>
<QPM:ReleaseStability>Stable</QPM:ReleaseStability>
<QPM:ReleaseNoteMinor></QPM:ReleaseNoteMinor>
<QPM:ReleaseNoteMajor></QPM:ReleaseNoteMajor>
<QPM:ExcludeCountries>
<QPM:Country></QPM:Country>
</QPM:ExcludeCountries>
|
| ︙ | ︙ |
Changes to compat/zlib/test/example.c.
| ︙ | ︙ | |||
29 30 31 32 33 34 35 36 | static z_const char hello[] = "hello, hello!"; /* "hello world" would be more standard, but the repeated "hello" * stresses the compression code better, sorry... */ static const char dictionary[] = "hello"; static uLong dictId; /* Adler32 value of the dictionary */ | < < < < < < < < < < < < < < < < < < < | < < < | < < < < < < | < | < | 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 |
static z_const char hello[] = "hello, hello!";
/* "hello world" would be more standard, but the repeated "hello"
* stresses the compression code better, sorry...
*/
static const char dictionary[] = "hello";
static uLong dictId; /* Adler32 value of the dictionary */
#ifdef Z_SOLO
void *myalloc(void *q, unsigned n, unsigned m) {
(void)q;
return calloc(n, m);
}
void myfree(void *q, void *p) {
(void)q;
free(p);
}
static alloc_func zalloc = myalloc;
static free_func zfree = myfree;
#else /* !Z_SOLO */
static alloc_func zalloc = (alloc_func)0;
static free_func zfree = (free_func)0;
/* ===========================================================================
* Test compress() and uncompress()
*/
void test_compress(Byte *compr, uLong comprLen, Byte *uncompr,
uLong uncomprLen) {
int err;
uLong len = (uLong)strlen(hello)+1;
err = compress(compr, &comprLen, (const Bytef*)hello, len);
CHECK_ERR(err, "compress");
strcpy((char*)uncompr, "garbage");
|
| ︙ | ︙ | |||
107 108 109 110 111 112 113 |
printf("uncompress(): %s\n", (char *)uncompr);
}
}
/* ===========================================================================
* Test read/write of .gz files
*/
| < < < | < | 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
printf("uncompress(): %s\n", (char *)uncompr);
}
}
/* ===========================================================================
* Test read/write of .gz files
*/
void test_gzio(const char *fname, Byte *uncompr, uLong uncomprLen) {
#ifdef NO_GZCOMPRESS
fprintf(stderr, "NO_GZCOMPRESS -- gz* functions cannot compress\n");
#else
int err;
int len = (int)strlen(hello)+1;
gzFile file;
z_off_t pos;
|
| ︙ | ︙ | |||
193 194 195 196 197 198 199 | } #endif /* Z_SOLO */ /* =========================================================================== * Test deflate() with small buffers */ | | < < < | 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 |
}
#endif /* Z_SOLO */
/* ===========================================================================
* Test deflate() with small buffers
*/
void test_deflate(Byte *compr, uLong comprLen) {
z_stream c_stream; /* compression stream */
int err;
uLong len = (uLong)strlen(hello)+1;
c_stream.zalloc = zalloc;
c_stream.zfree = zfree;
c_stream.opaque = (voidpf)0;
|
| ︙ | ︙ | |||
231 232 233 234 235 236 237 |
err = deflateEnd(&c_stream);
CHECK_ERR(err, "deflateEnd");
}
/* ===========================================================================
* Test inflate() with small buffers
*/
| < | | < | 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 |
err = deflateEnd(&c_stream);
CHECK_ERR(err, "deflateEnd");
}
/* ===========================================================================
* Test inflate() with small buffers
*/
void test_inflate(Byte *compr, uLong comprLen, Byte *uncompr,
uLong uncomprLen) {
int err;
z_stream d_stream; /* decompression stream */
strcpy((char*)uncompr, "garbage");
d_stream.zalloc = zalloc;
d_stream.zfree = zfree;
|
| ︙ | ︙ | |||
272 273 274 275 276 277 278 |
printf("inflate(): %s\n", (char *)uncompr);
}
}
/* ===========================================================================
* Test deflate() with large buffers and dynamic change of compression level
*/
| | < | < | 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 |
printf("inflate(): %s\n", (char *)uncompr);
}
}
/* ===========================================================================
* Test deflate() with large buffers and dynamic change of compression level
*/
void test_large_deflate(Byte *compr, uLong comprLen, Byte *uncompr,
uLong uncomprLen) {
z_stream c_stream; /* compression stream */
int err;
c_stream.zalloc = zalloc;
c_stream.zfree = zfree;
c_stream.opaque = (voidpf)0;
|
| ︙ | ︙ | |||
304 305 306 307 308 309 310 |
fprintf(stderr, "deflate not greedy\n");
exit(1);
}
/* Feed in already compressed data and switch to no compression: */
deflateParams(&c_stream, Z_NO_COMPRESSION, Z_DEFAULT_STRATEGY);
c_stream.next_in = compr;
| | | 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 |
fprintf(stderr, "deflate not greedy\n");
exit(1);
}
/* Feed in already compressed data and switch to no compression: */
deflateParams(&c_stream, Z_NO_COMPRESSION, Z_DEFAULT_STRATEGY);
c_stream.next_in = compr;
c_stream.avail_in = (uInt)uncomprLen/2;
err = deflate(&c_stream, Z_NO_FLUSH);
CHECK_ERR(err, "deflate");
/* Switch back to compressing mode: */
deflateParams(&c_stream, Z_BEST_COMPRESSION, Z_FILTERED);
c_stream.next_in = uncompr;
c_stream.avail_in = (uInt)uncomprLen;
|
| ︙ | ︙ | |||
327 328 329 330 331 332 333 |
err = deflateEnd(&c_stream);
CHECK_ERR(err, "deflateEnd");
}
/* ===========================================================================
* Test inflate() with large buffers
*/
| | < | < | 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 |
err = deflateEnd(&c_stream);
CHECK_ERR(err, "deflateEnd");
}
/* ===========================================================================
* Test inflate() with large buffers
*/
void test_large_inflate(Byte *compr, uLong comprLen, Byte *uncompr,
uLong uncomprLen) {
int err;
z_stream d_stream; /* decompression stream */
strcpy((char*)uncompr, "garbage");
d_stream.zalloc = zalloc;
d_stream.zfree = zfree;
|
| ︙ | ︙ | |||
357 358 359 360 361 362 363 |
if (err == Z_STREAM_END) break;
CHECK_ERR(err, "large inflate");
}
err = inflateEnd(&d_stream);
CHECK_ERR(err, "inflateEnd");
| | < < | < | 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 |
if (err == Z_STREAM_END) break;
CHECK_ERR(err, "large inflate");
}
err = inflateEnd(&d_stream);
CHECK_ERR(err, "inflateEnd");
if (d_stream.total_out != 2*uncomprLen + uncomprLen/2) {
fprintf(stderr, "bad large inflate: %ld\n", d_stream.total_out);
exit(1);
} else {
printf("large_inflate(): OK\n");
}
}
/* ===========================================================================
* Test deflate() with full flush
*/
void test_flush(Byte *compr, uLong *comprLen) {
z_stream c_stream; /* compression stream */
int err;
uInt len = (uInt)strlen(hello)+1;
c_stream.zalloc = zalloc;
c_stream.zfree = zfree;
c_stream.opaque = (voidpf)0;
|
| ︙ | ︙ | |||
406 407 408 409 410 411 412 |
*comprLen = c_stream.total_out;
}
/* ===========================================================================
* Test inflateSync()
*/
| < < | < | 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 |
*comprLen = c_stream.total_out;
}
/* ===========================================================================
* Test inflateSync()
*/
void test_sync(Byte *compr, uLong comprLen, Byte *uncompr, uLong uncomprLen) {
int err;
z_stream d_stream; /* decompression stream */
strcpy((char*)uncompr, "garbage");
d_stream.zalloc = zalloc;
d_stream.zfree = zfree;
|
| ︙ | ︙ | |||
449 450 451 452 453 454 455 |
printf("after inflateSync(): hel%s\n", (char *)uncompr);
}
/* ===========================================================================
* Test deflate() with preset dictionary
*/
| | < < < | 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 |
printf("after inflateSync(): hel%s\n", (char *)uncompr);
}
/* ===========================================================================
* Test deflate() with preset dictionary
*/
void test_dict_deflate(Byte *compr, uLong comprLen) {
z_stream c_stream; /* compression stream */
int err;
c_stream.zalloc = zalloc;
c_stream.zfree = zfree;
c_stream.opaque = (voidpf)0;
|
| ︙ | ︙ | |||
486 487 488 489 490 491 492 |
err = deflateEnd(&c_stream);
CHECK_ERR(err, "deflateEnd");
}
/* ===========================================================================
* Test inflate() with a preset dictionary
*/
| | < | < | 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 |
err = deflateEnd(&c_stream);
CHECK_ERR(err, "deflateEnd");
}
/* ===========================================================================
* Test inflate() with a preset dictionary
*/
void test_dict_inflate(Byte *compr, uLong comprLen, Byte *uncompr,
uLong uncomprLen) {
int err;
z_stream d_stream; /* decompression stream */
strcpy((char*)uncompr, "garbage");
d_stream.zalloc = zalloc;
d_stream.zfree = zfree;
|
| ︙ | ︙ | |||
537 538 539 540 541 542 543 |
}
}
/* ===========================================================================
* Usage: example [output.gz [input.gz]]
*/
| < < | < < | > | > | 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 |
}
}
/* ===========================================================================
* Usage: example [output.gz [input.gz]]
*/
int main(int argc, char *argv[]) {
Byte *compr, *uncompr;
uLong uncomprLen = 20000;
uLong comprLen = 3 * uncomprLen;
static const char* myVersion = ZLIB_VERSION;
if (zlibVersion()[0] != myVersion[0]) {
fprintf(stderr, "incompatible zlib version\n");
exit(1);
} else if (strcmp(zlibVersion(), ZLIB_VERSION) != 0) {
fprintf(stderr, "warning: different zlib version linked: %s\n",
zlibVersion());
}
printf("zlib version %s = 0x%04x, compile flags = 0x%lx\n",
ZLIB_VERSION, ZLIB_VERNUM, zlibCompileFlags());
compr = (Byte*)calloc((uInt)comprLen, 1);
uncompr = (Byte*)calloc((uInt)uncomprLen, 1);
|
| ︙ | ︙ | |||
585 586 587 588 589 590 591 |
test_inflate(compr, comprLen, uncompr, uncomprLen);
test_large_deflate(compr, comprLen, uncompr, uncomprLen);
test_large_inflate(compr, comprLen, uncompr, uncomprLen);
test_flush(compr, &comprLen);
test_sync(compr, comprLen, uncompr, uncomprLen);
| | | 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 |
test_inflate(compr, comprLen, uncompr, uncomprLen);
test_large_deflate(compr, comprLen, uncompr, uncomprLen);
test_large_inflate(compr, comprLen, uncompr, uncomprLen);
test_flush(compr, &comprLen);
test_sync(compr, comprLen, uncompr, uncomprLen);
comprLen = 3 * uncomprLen;
test_dict_deflate(compr, comprLen);
test_dict_inflate(compr, comprLen, uncompr, uncomprLen);
free(compr);
free(uncompr);
return 0;
}
|
Changes to compat/zlib/test/infcover.c.
| ︙ | ︙ | |||
369 370 371 372 373 374 375 |
inf("63 18 68 30 d0 0 0", "force split window update", 4, -8, 259, Z_OK);
inf("3 0", "use fixed blocks", 0, -15, 1, Z_STREAM_END);
inf("", "bad window size", 0, 1, 0, Z_STREAM_ERROR);
mem_setup(&strm);
strm.avail_in = 0;
strm.next_in = Z_NULL;
| | | 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 |
inf("63 18 68 30 d0 0 0", "force split window update", 4, -8, 259, Z_OK);
inf("3 0", "use fixed blocks", 0, -15, 1, Z_STREAM_END);
inf("", "bad window size", 0, 1, 0, Z_STREAM_ERROR);
mem_setup(&strm);
strm.avail_in = 0;
strm.next_in = Z_NULL;
ret = inflateInit_(&strm, "!", (int)sizeof(z_stream));
assert(ret == Z_VERSION_ERROR);
mem_done(&strm, "wrong version");
strm.avail_in = 0;
strm.next_in = Z_NULL;
ret = inflateInit(&strm); assert(ret == Z_OK);
ret = inflateEnd(&strm); assert(ret == Z_OK);
|
| ︙ | ︙ | |||
458 459 460 461 462 463 464 |
if (state != Z_NULL)
state->mode = SYNC; /* force an otherwise impossible situation */
return next < sizeof(dat) ? (*buf = dat + next++, 1) : 0;
}
local int push(void *desc, unsigned char *buf, unsigned len)
{
| > | | 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 |
if (state != Z_NULL)
state->mode = SYNC; /* force an otherwise impossible situation */
return next < sizeof(dat) ? (*buf = dat + next++, 1) : 0;
}
local int push(void *desc, unsigned char *buf, unsigned len)
{
(void)buf;
(void)len;
return desc != Z_NULL; /* force error if desc not null */
}
/* cover inflateBack() up to common deflate data cases and after those */
local void cover_back(void)
{
int ret;
|
| ︙ | ︙ |
Changes to compat/zlib/test/minigzip.c.
| ︙ | ︙ | |||
55 56 57 58 59 60 61 | #endif #if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os # include <unix.h> /* for fileno */ #endif #if !defined(Z_HAVE_UNISTD_H) && !defined(_LARGEFILE64_SOURCE) #ifndef WIN32 /* unlink already in stdio.h for WIN32 */ | | | 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | #endif #if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os # include <unix.h> /* for fileno */ #endif #if !defined(Z_HAVE_UNISTD_H) && !defined(_LARGEFILE64_SOURCE) #ifndef WIN32 /* unlink already in stdio.h for WIN32 */ extern int unlink(const char *); #endif #endif #if defined(UNDER_CE) # include <windows.h> # define perror(s) pwinerror(s) |
| ︙ | ︙ | |||
145 146 147 148 149 150 151 | #ifdef Z_SOLO /* for Z_SOLO, create simplified gz* functions using deflate and inflate */ #if defined(Z_HAVE_UNISTD_H) || defined(Z_LARGE) # include <unistd.h> /* for unlink() */ #endif | < < < | < < < | < < < < < < < | < < < < < < < < < < < < < < < < < | 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 |
#ifdef Z_SOLO
/* for Z_SOLO, create simplified gz* functions using deflate and inflate */
#if defined(Z_HAVE_UNISTD_H) || defined(Z_LARGE)
# include <unistd.h> /* for unlink() */
#endif
void *myalloc(void *q, unsigned n, unsigned m) {
(void)q;
return calloc(n, m);
}
void myfree(void *q, void *p) {
(void)q;
free(p);
}
typedef struct gzFile_s {
FILE *file;
int write;
int err;
char *msg;
z_stream strm;
} *gzFile;
gzFile gz_open(const char *path, int fd, const char *mode) {
gzFile gz;
int ret;
gz = malloc(sizeof(struct gzFile_s));
if (gz == NULL)
return NULL;
gz->write = strchr(mode, 'w') != NULL;
|
| ︙ | ︙ | |||
227 228 229 230 231 232 233 |
return NULL;
}
gz->err = 0;
gz->msg = "";
return gz;
}
| | > | | | < | > | > < < | < < < < | 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 |
return NULL;
}
gz->err = 0;
gz->msg = "";
return gz;
}
gzFile gzopen(const char *path, const char *mode) {
return gz_open(path, -1, mode);
}
gzFile gzdopen(int fd, const char *mode) {
return gz_open(NULL, fd, mode);
}
int gzwrite(gzFile gz, const void *buf, unsigned len) {
z_stream *strm;
unsigned char out[BUFLEN];
if (gz == NULL || !gz->write)
return 0;
strm = &(gz->strm);
strm->next_in = (void *)buf;
strm->avail_in = len;
do {
strm->next_out = out;
strm->avail_out = BUFLEN;
(void)deflate(strm, Z_NO_FLUSH);
fwrite(out, 1, BUFLEN - strm->avail_out, gz->file);
} while (strm->avail_out == 0);
return len;
}
int gzread(gzFile gz, void *buf, unsigned len) {
int ret;
unsigned got;
unsigned char in[1];
z_stream *strm;
if (gz == NULL || gz->write)
return 0;
|
| ︙ | ︙ | |||
288 289 290 291 292 293 294 |
}
if (ret == Z_STREAM_END)
inflateReset(strm);
} while (strm->avail_out);
return len - strm->avail_out;
}
| < < | < < | 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 |
}
if (ret == Z_STREAM_END)
inflateReset(strm);
} while (strm->avail_out);
return len - strm->avail_out;
}
int gzclose(gzFile gz) {
z_stream *strm;
unsigned char out[BUFLEN];
if (gz == NULL)
return Z_STREAM_ERROR;
strm = &(gz->strm);
if (gz->write) {
|
| ︙ | ︙ | |||
317 318 319 320 321 322 323 |
else
inflateEnd(strm);
fclose(gz->file);
free(gz);
return Z_OK;
}
| < < | < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < | 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 |
else
inflateEnd(strm);
fclose(gz->file);
free(gz);
return Z_OK;
}
const char *gzerror(gzFile gz, int *err) {
*err = gz->err;
return gz->msg;
}
#endif
static char *prog;
/* ===========================================================================
* Display error message and exit
*/
void error(const char *msg) {
fprintf(stderr, "%s: %s\n", prog, msg);
exit(1);
}
#ifdef USE_MMAP /* MMAP version, Miguel Albrecht <malbrech@eso.org> */
/* Try compressing the input file at once using mmap. Return Z_OK if
* if success, Z_ERRNO otherwise.
*/
int gz_compress_mmap(FILE *in, gzFile out) {
int len;
int err;
int ifd = fileno(in);
caddr_t buf; /* mmap'ed buffer for the entire input file */
off_t buf_len; /* length of the input file */
struct stat sb;
|
| ︙ | ︙ | |||
419 420 421 422 423 424 425 426 427 |
munmap(buf, buf_len);
fclose(in);
if (gzclose(out) != Z_OK) error("failed gzclose");
return Z_OK;
}
#endif /* USE_MMAP */
/* ===========================================================================
| | | > > > > | > > > > > > > > > > > > > | > > > > > | > > > > | 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 |
munmap(buf, buf_len);
fclose(in);
if (gzclose(out) != Z_OK) error("failed gzclose");
return Z_OK;
}
#endif /* USE_MMAP */
/* ===========================================================================
* Compress input to output then close both files.
*/
void gz_compress(FILE *in, gzFile out) {
local char buf[BUFLEN];
int len;
int err;
#ifdef USE_MMAP
/* Try first compressing with mmap. If mmap fails (minigzip used in a
* pipe), use the normal fread loop.
*/
if (gz_compress_mmap(in, out) == Z_OK) return;
#endif
for (;;) {
len = (int)fread(buf, 1, sizeof(buf), in);
if (ferror(in)) {
perror("fread");
exit(1);
}
if (len == 0) break;
if (gzwrite(out, buf, (unsigned)len) != len) error(gzerror(out, &err));
}
fclose(in);
if (gzclose(out) != Z_OK) error("failed gzclose");
}
/* ===========================================================================
* Uncompress input to output then close both files.
*/
void gz_uncompress(gzFile in, FILE *out) {
local char buf[BUFLEN];
int len;
int err;
for (;;) {
len = gzread(in, buf, sizeof(buf));
if (len < 0) error (gzerror(in, &err));
|
| ︙ | ︙ | |||
450 451 452 453 454 455 456 | } /* =========================================================================== * Compress the given file: create a corresponding .gz file and remove the * original. */ | | < < < | 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 |
}
/* ===========================================================================
* Compress the given file: create a corresponding .gz file and remove the
* original.
*/
void file_compress(char *file, char *mode) {
local char outfile[MAX_NAME_LEN];
FILE *in;
gzFile out;
if (strlen(file) + strlen(GZ_SUFFIX) >= sizeof(outfile)) {
fprintf(stderr, "%s: filename too long\n", prog);
exit(1);
|
| ︙ | ︙ | |||
489 490 491 492 493 494 495 |
unlink(file);
}
/* ===========================================================================
* Uncompress the given file and remove the original.
*/
| | < < | | 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 |
unlink(file);
}
/* ===========================================================================
* Uncompress the given file and remove the original.
*/
void file_uncompress(char *file) {
local char buf[MAX_NAME_LEN];
char *infile, *outfile;
FILE *out;
gzFile in;
z_size_t len = strlen(file);
if (len + strlen(GZ_SUFFIX) >= sizeof(buf)) {
fprintf(stderr, "%s: filename too long\n", prog);
exit(1);
}
#if !defined(NO_snprintf) && !defined(NO_vsnprintf)
|
| ︙ | ︙ | |||
549 550 551 552 553 554 555 | * -d : decompress * -f : compress with Z_FILTERED * -h : compress with Z_HUFFMAN_ONLY * -r : compress with Z_RLE * -1 to -9 : compression level */ | < < | < | 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 |
* -d : decompress
* -f : compress with Z_FILTERED
* -h : compress with Z_HUFFMAN_ONLY
* -r : compress with Z_RLE
* -1 to -9 : compression level
*/
int main(int argc, char *argv[]) {
int copyout = 0;
int uncompr = 0;
gzFile file;
char *bname, outmode[20];
#if !defined(NO_snprintf) && !defined(NO_vsnprintf)
snprintf(outmode, sizeof(outmode), "%s", "wb6 ");
|
| ︙ | ︙ |
Changes to compat/zlib/treebuild.xml.
1 | <?xml version="1.0" ?> | | | | 1 2 3 4 5 6 7 8 9 10 |
<?xml version="1.0" ?>
<package name="zlib" version="1.3">
<library name="zlib" dlversion="1.3" dlname="z">
<property name="description"> zip compression library </property>
<property name="include-target-dir" value="$(@PACKAGE/install-includedir)" />
<!-- fixme: not implemented yet -->
<property name="compiler/c/inline" value="yes" />
<include-file name="zlib.h" scope="public" mode="644" />
|
| ︙ | ︙ |
Changes to compat/zlib/trees.c.
| ︙ | ︙ | |||
118 119 120 121 122 123 124 |
const ct_data *static_tree; /* static tree or NULL */
const intf *extra_bits; /* extra bits for each code or NULL */
int extra_base; /* base index for extra_bits */
int elems; /* max number of elements in the tree */
int max_length; /* max bit length for the codes */
};
| > > > > > > | | | > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | < < < > > | > > > > > > > > | | < < < | < | < | > | < > > | > > | < < < < < < < < < | < < < < < < | | 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 |
const ct_data *static_tree; /* static tree or NULL */
const intf *extra_bits; /* extra bits for each code or NULL */
int extra_base; /* base index for extra_bits */
int elems; /* max number of elements in the tree */
int max_length; /* max bit length for the codes */
};
#ifdef NO_INIT_GLOBAL_POINTERS
# define TCONST
#else
# define TCONST const
#endif
local TCONST static_tree_desc static_l_desc =
{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS};
local TCONST static_tree_desc static_d_desc =
{static_dtree, extra_dbits, 0, D_CODES, MAX_BITS};
local TCONST static_tree_desc static_bl_desc =
{(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS};
/* ===========================================================================
* Output a short LSB first on the stream.
* IN assertion: there is enough room in pendingBuf.
*/
#define put_short(s, w) { \
put_byte(s, (uch)((w) & 0xff)); \
put_byte(s, (uch)((ush)(w) >> 8)); \
}
/* ===========================================================================
* Reverse the first len bits of a code, using straightforward code (a faster
* method would use a table)
* IN assertion: 1 <= len <= 15
*/
local unsigned bi_reverse(unsigned code, int len) {
register unsigned res = 0;
do {
res |= code & 1;
code >>= 1, res <<= 1;
} while (--len > 0);
return res >> 1;
}
/* ===========================================================================
* Flush the bit buffer, keeping at most 7 bits in it.
*/
local void bi_flush(deflate_state *s) {
if (s->bi_valid == 16) {
put_short(s, s->bi_buf);
s->bi_buf = 0;
s->bi_valid = 0;
} else if (s->bi_valid >= 8) {
put_byte(s, (Byte)s->bi_buf);
s->bi_buf >>= 8;
s->bi_valid -= 8;
}
}
/* ===========================================================================
* Flush the bit buffer and align the output on a byte boundary
*/
local void bi_windup(deflate_state *s) {
if (s->bi_valid > 8) {
put_short(s, s->bi_buf);
} else if (s->bi_valid > 0) {
put_byte(s, (Byte)s->bi_buf);
}
s->bi_buf = 0;
s->bi_valid = 0;
#ifdef ZLIB_DEBUG
s->bits_sent = (s->bits_sent + 7) & ~7;
#endif
}
/* ===========================================================================
* Generate the codes for a given tree and bit counts (which need not be
* optimal).
* IN assertion: the array bl_count contains the bit length statistics for
* the given tree and the field len is set for all tree elements.
* OUT assertion: the field code is set for all tree elements of non
* zero code length.
*/
local void gen_codes(ct_data *tree, int max_code, ushf *bl_count) {
ush next_code[MAX_BITS+1]; /* next code value for each bit length */
unsigned code = 0; /* running code value */
int bits; /* bit index */
int n; /* code index */
/* The distribution counts are first used to generate the code values
* without bit reversal.
*/
for (bits = 1; bits <= MAX_BITS; bits++) {
code = (code + bl_count[bits - 1]) << 1;
next_code[bits] = (ush)code;
}
/* Check that the bit counts in bl_count are consistent. The last code
* must be all ones.
*/
Assert (code + bl_count[MAX_BITS] - 1 == (1 << MAX_BITS) - 1,
"inconsistent bit counts");
Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
for (n = 0; n <= max_code; n++) {
int len = tree[n].Len;
if (len == 0) continue;
/* Now reverse the bits */
tree[n].Code = (ush)bi_reverse(next_code[len]++, len);
Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ",
n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len] - 1));
}
}
#ifdef GEN_TREES_H
local void gen_trees_header(void);
#endif
#ifndef ZLIB_DEBUG
# define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len)
/* Send a code of the given tree. c and tree must not have side effects */
#else /* !ZLIB_DEBUG */
# define send_code(s, c, tree) \
{ if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \
send_bits(s, tree[c].Code, tree[c].Len); }
#endif
/* ===========================================================================
* Send a value on a given number of bits.
* IN assertion: length <= 16 and value fits in length bits.
*/
#ifdef ZLIB_DEBUG
local void send_bits(deflate_state *s, int value, int length) {
Tracevv((stderr," l %2d v %4x ", length, value));
Assert(length > 0 && length <= 15, "invalid length");
s->bits_sent += (ulg)length;
/* If not enough room in bi_buf, use (valid) bits from bi_buf and
* (16 - bi_valid) bits from value, leaving (width - (16 - bi_valid))
* unused bits in value.
*/
if (s->bi_valid > (int)Buf_size - length) {
s->bi_buf |= (ush)value << s->bi_valid;
put_short(s, s->bi_buf);
s->bi_buf = (ush)value >> (Buf_size - s->bi_valid);
s->bi_valid += length - Buf_size;
|
| ︙ | ︙ | |||
225 226 227 228 229 230 231 | /* the arguments must not have side effects */ /* =========================================================================== * Initialize the various 'constant' tables. */ | | < | 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 |
/* the arguments must not have side effects */
/* ===========================================================================
* Initialize the various 'constant' tables.
*/
local void tr_static_init(void) {
#if defined(GEN_TREES_H) || !defined(STDC)
static int static_init_done = 0;
int n; /* iterates over tree elements */
int bits; /* bit counter */
int length; /* length value */
int code; /* code value */
int dist; /* distance index */
|
| ︙ | ︙ | |||
252 253 254 255 256 257 258 |
static_bl_desc.extra_bits = extra_blbits;
#endif
/* Initialize the mapping length (0..255) -> length code (0..28) */
length = 0;
for (code = 0; code < LENGTH_CODES-1; code++) {
base_length[code] = length;
| | | | | | | 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 |
static_bl_desc.extra_bits = extra_blbits;
#endif
/* Initialize the mapping length (0..255) -> length code (0..28) */
length = 0;
for (code = 0; code < LENGTH_CODES-1; code++) {
base_length[code] = length;
for (n = 0; n < (1 << extra_lbits[code]); n++) {
_length_code[length++] = (uch)code;
}
}
Assert (length == 256, "tr_static_init: length != 256");
/* Note that the length 255 (match length 258) can be represented
* in two different ways: code 284 + 5 bits or code 285, so we
* overwrite length_code[255] to use the best encoding:
*/
_length_code[length - 1] = (uch)code;
/* Initialize the mapping dist (0..32K) -> dist code (0..29) */
dist = 0;
for (code = 0 ; code < 16; code++) {
base_dist[code] = dist;
for (n = 0; n < (1 << extra_dbits[code]); n++) {
_dist_code[dist++] = (uch)code;
}
}
Assert (dist == 256, "tr_static_init: dist != 256");
dist >>= 7; /* from now on, all distances are divided by 128 */
for ( ; code < D_CODES; code++) {
base_dist[code] = dist << 7;
for (n = 0; n < (1 << (extra_dbits[code] - 7)); n++) {
_dist_code[256 + dist++] = (uch)code;
}
}
Assert (dist == 256, "tr_static_init: 256 + dist != 512");
/* Construct the codes of the static literal tree */
for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0;
n = 0;
while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++;
while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++;
while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++;
|
| ︙ | ︙ | |||
308 309 310 311 312 313 314 |
# ifdef GEN_TREES_H
gen_trees_header();
# endif
#endif /* defined(GEN_TREES_H) || !defined(STDC) */
}
/* ===========================================================================
| | | | < | 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 |
# ifdef GEN_TREES_H
gen_trees_header();
# endif
#endif /* defined(GEN_TREES_H) || !defined(STDC) */
}
/* ===========================================================================
* Generate the file trees.h describing the static trees.
*/
#ifdef GEN_TREES_H
# ifndef ZLIB_DEBUG
# include <stdio.h>
# endif
# define SEPARATOR(i, last, width) \
((i) == (last)? "\n};\n\n" : \
((i) % (width) == (width) - 1 ? ",\n" : ", "))
void gen_trees_header(void) {
FILE *header = fopen("trees.h", "w");
int i;
Assert (header != NULL, "Can't open trees.h");
fprintf(header,
"/* header created automatically with -DGEN_TREES_H */\n\n");
|
| ︙ | ︙ | |||
368 369 370 371 372 373 374 375 376 377 378 |
fprintf(header, "%5u%s", base_dist[i],
SEPARATOR(i, D_CODES-1, 10));
}
fclose(header);
}
#endif /* GEN_TREES_H */
/* ===========================================================================
* Initialize the tree data structures for a new zlib stream.
*/
| > > > > > > > > > > > > > > > > | < < | 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 |
fprintf(header, "%5u%s", base_dist[i],
SEPARATOR(i, D_CODES-1, 10));
}
fclose(header);
}
#endif /* GEN_TREES_H */
/* ===========================================================================
* Initialize a new block.
*/
local void init_block(deflate_state *s) {
int n; /* iterates over tree elements */
/* Initialize the trees. */
for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0;
for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0;
for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0;
s->dyn_ltree[END_BLOCK].Freq = 1;
s->opt_len = s->static_len = 0L;
s->sym_next = s->matches = 0;
}
/* ===========================================================================
* Initialize the tree data structures for a new zlib stream.
*/
void ZLIB_INTERNAL _tr_init(deflate_state *s) {
tr_static_init();
s->l_desc.dyn_tree = s->dyn_ltree;
s->l_desc.stat_desc = &static_l_desc;
s->d_desc.dyn_tree = s->dyn_dtree;
s->d_desc.stat_desc = &static_d_desc;
|
| ︙ | ︙ | |||
397 398 399 400 401 402 403 |
s->bits_sent = 0L;
#endif
/* Initialize the first block of the first file: */
init_block(s);
}
| < < < < < < < < < < < < < < < < < < | 471 472 473 474 475 476 477 478 479 480 481 482 483 484 |
s->bits_sent = 0L;
#endif
/* Initialize the first block of the first file: */
init_block(s);
}
#define SMALLEST 1
/* Index within the heap array of least frequent node in the Huffman tree */
/* ===========================================================================
* Remove the smallest element from the heap and recreate the heap with
* one less element. Updates heap and heap_len.
|
| ︙ | ︙ | |||
444 445 446 447 448 449 450 | /* =========================================================================== * Restore the heap property by moving down the tree starting at node k, * exchanging a node with the smallest of its two sons if necessary, stopping * when the heap property is re-established (each father smaller than its * two sons). */ | | < < < < | | 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 |
/* ===========================================================================
* Restore the heap property by moving down the tree starting at node k,
* exchanging a node with the smallest of its two sons if necessary, stopping
* when the heap property is re-established (each father smaller than its
* two sons).
*/
local void pqdownheap(deflate_state *s, ct_data *tree, int k) {
int v = s->heap[k];
int j = k << 1; /* left son of k */
while (j <= s->heap_len) {
/* Set j to the smallest of the two sons: */
if (j < s->heap_len &&
smaller(tree, s->heap[j + 1], s->heap[j], s->depth)) {
j++;
}
/* Exit if v is smaller than both sons */
if (smaller(tree, v, s->heap[j], s->depth)) break;
/* Exchange v with the smallest son */
s->heap[k] = s->heap[j]; k = j;
|
| ︙ | ︙ | |||
479 480 481 482 483 484 485 | * IN assertion: the fields freq and dad are set, heap[heap_max] and * above are the tree nodes sorted by increasing frequency. * OUT assertions: the field len is set to the optimal bit length, the * array bl_count contains the frequencies for each bit length. * The length opt_len is updated; static_len is also updated if stree is * not null. */ | | < < < | | | | | | 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 |
* IN assertion: the fields freq and dad are set, heap[heap_max] and
* above are the tree nodes sorted by increasing frequency.
* OUT assertions: the field len is set to the optimal bit length, the
* array bl_count contains the frequencies for each bit length.
* The length opt_len is updated; static_len is also updated if stree is
* not null.
*/
local void gen_bitlen(deflate_state *s, tree_desc *desc) {
ct_data *tree = desc->dyn_tree;
int max_code = desc->max_code;
const ct_data *stree = desc->stat_desc->static_tree;
const intf *extra = desc->stat_desc->extra_bits;
int base = desc->stat_desc->extra_base;
int max_length = desc->stat_desc->max_length;
int h; /* heap index */
int n, m; /* iterate over the tree elements */
int bits; /* bit length */
int xbits; /* extra bits */
ush f; /* frequency */
int overflow = 0; /* number of elements with bit length too large */
for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0;
/* In a first pass, compute the optimal bit lengths (which may
* overflow in the case of the bit length tree).
*/
tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */
for (h = s->heap_max + 1; h < HEAP_SIZE; h++) {
n = s->heap[h];
bits = tree[tree[n].Dad].Len + 1;
if (bits > max_length) bits = max_length, overflow++;
tree[n].Len = (ush)bits;
/* We overwrite tree[n].Dad which is no longer needed */
if (n > max_code) continue; /* not a leaf node */
s->bl_count[bits]++;
xbits = 0;
if (n >= base) xbits = extra[n - base];
f = tree[n].Freq;
s->opt_len += (ulg)f * (unsigned)(bits + xbits);
if (stree) s->static_len += (ulg)f * (unsigned)(stree[n].Len + xbits);
}
if (overflow == 0) return;
Tracev((stderr,"\nbit length overflow\n"));
/* This happens for example on obj2 and pic of the Calgary corpus */
/* Find the first bit length which could increase: */
do {
bits = max_length - 1;
while (s->bl_count[bits] == 0) bits--;
s->bl_count[bits]--; /* move one leaf down the tree */
s->bl_count[bits + 1] += 2; /* move one overflow item as its brother */
s->bl_count[max_length]--;
/* The brother of the overflow item also moves one step up,
* but this does not affect bl_count[max_length]
*/
overflow -= 2;
} while (overflow > 0);
|
| ︙ | ︙ | |||
557 558 559 560 561 562 563 |
tree[m].Len = (ush)bits;
}
n--;
}
}
}
| < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < | < < < < < | < < < < | < < < | | 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 |
tree[m].Len = (ush)bits;
}
n--;
}
}
}
#ifdef DUMP_BL_TREE
# include <stdio.h>
#endif
/* ===========================================================================
* Construct one Huffman tree and assigns the code bit strings and lengths.
* Update the total bit length for the current block.
* IN assertion: the field freq is set for all tree elements.
* OUT assertions: the fields len and code are set to the optimal bit length
* and corresponding code. The length opt_len is updated; static_len is
* also updated if stree is not null. The field max_code is set.
*/
local void build_tree(deflate_state *s, tree_desc *desc) {
ct_data *tree = desc->dyn_tree;
const ct_data *stree = desc->stat_desc->static_tree;
int elems = desc->stat_desc->elems;
int n, m; /* iterate over heap elements */
int max_code = -1; /* largest code with non zero frequency */
int node; /* new node being created */
/* Construct the initial heap, with least frequent element in
* heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n + 1].
* heap[0] is not used.
*/
s->heap_len = 0, s->heap_max = HEAP_SIZE;
for (n = 0; n < elems; n++) {
if (tree[n].Freq != 0) {
s->heap[++(s->heap_len)] = max_code = n;
|
| ︙ | ︙ | |||
648 649 650 651 652 653 654 |
tree[node].Freq = 1;
s->depth[node] = 0;
s->opt_len--; if (stree) s->static_len -= stree[node].Len;
/* node is 0 or 1 so it does not have extra bits */
}
desc->max_code = max_code;
| | | 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 |
tree[node].Freq = 1;
s->depth[node] = 0;
s->opt_len--; if (stree) s->static_len -= stree[node].Len;
/* node is 0 or 1 so it does not have extra bits */
}
desc->max_code = max_code;
/* The elements heap[heap_len/2 + 1 .. heap_len] are leaves of the tree,
* establish sub-heaps of increasing lengths:
*/
for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n);
/* Construct the Huffman tree by repeatedly combining the least two
* frequent nodes.
*/
|
| ︙ | ︙ | |||
696 697 698 699 700 701 702 |
gen_codes ((ct_data *)tree, max_code, s->bl_count);
}
/* ===========================================================================
* Scan a literal or distance tree to determine the frequencies of the codes
* in the bit length tree.
*/
| | < < < < | | | 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 |
gen_codes ((ct_data *)tree, max_code, s->bl_count);
}
/* ===========================================================================
* Scan a literal or distance tree to determine the frequencies of the codes
* in the bit length tree.
*/
local void scan_tree(deflate_state *s, ct_data *tree, int max_code) {
int n; /* iterates over all tree elements */
int prevlen = -1; /* last emitted length */
int curlen; /* length of current code */
int nextlen = tree[0].Len; /* length of next code */
int count = 0; /* repeat count of the current code */
int max_count = 7; /* max repeat count */
int min_count = 4; /* min repeat count */
if (nextlen == 0) max_count = 138, min_count = 3;
tree[max_code + 1].Len = (ush)0xffff; /* guard */
for (n = 0; n <= max_code; n++) {
curlen = nextlen; nextlen = tree[n + 1].Len;
if (++count < max_count && curlen == nextlen) {
continue;
} else if (count < min_count) {
s->bl_tree[curlen].Freq += count;
} else if (curlen != 0) {
if (curlen != prevlen) s->bl_tree[curlen].Freq++;
s->bl_tree[REP_3_6].Freq++;
|
| ︙ | ︙ | |||
741 742 743 744 745 746 747 |
}
}
/* ===========================================================================
* Send a literal or distance tree in compressed form, using the codes in
* bl_tree.
*/
| | < < < < | | | | | | < < | | | | < | < | | | | | | < < | < < | | | < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < | < | | 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 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 |
}
}
/* ===========================================================================
* Send a literal or distance tree in compressed form, using the codes in
* bl_tree.
*/
local void send_tree(deflate_state *s, ct_data *tree, int max_code) {
int n; /* iterates over all tree elements */
int prevlen = -1; /* last emitted length */
int curlen; /* length of current code */
int nextlen = tree[0].Len; /* length of next code */
int count = 0; /* repeat count of the current code */
int max_count = 7; /* max repeat count */
int min_count = 4; /* min repeat count */
/* tree[max_code + 1].Len = -1; */ /* guard already set */
if (nextlen == 0) max_count = 138, min_count = 3;
for (n = 0; n <= max_code; n++) {
curlen = nextlen; nextlen = tree[n + 1].Len;
if (++count < max_count && curlen == nextlen) {
continue;
} else if (count < min_count) {
do { send_code(s, curlen, s->bl_tree); } while (--count != 0);
} else if (curlen != 0) {
if (curlen != prevlen) {
send_code(s, curlen, s->bl_tree); count--;
}
Assert(count >= 3 && count <= 6, " 3_6?");
send_code(s, REP_3_6, s->bl_tree); send_bits(s, count - 3, 2);
} else if (count <= 10) {
send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count - 3, 3);
} else {
send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count - 11, 7);
}
count = 0; prevlen = curlen;
if (nextlen == 0) {
max_count = 138, min_count = 3;
} else if (curlen == nextlen) {
max_count = 6, min_count = 3;
} else {
max_count = 7, min_count = 4;
}
}
}
/* ===========================================================================
* Construct the Huffman tree for the bit lengths and return the index in
* bl_order of the last bit length code to send.
*/
local int build_bl_tree(deflate_state *s) {
int max_blindex; /* index of last bit length code of non zero freq */
/* Determine the bit length frequencies for literal and distance trees */
scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code);
scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code);
/* Build the bit length tree: */
build_tree(s, (tree_desc *)(&(s->bl_desc)));
/* opt_len now includes the length of the tree representations, except the
* lengths of the bit lengths codes and the 5 + 5 + 4 bits for the counts.
*/
/* Determine the number of bit length codes to send. The pkzip format
* requires that at least 4 bit length codes be sent. (appnote.txt says
* 3 but the actual value used is 4.)
*/
for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) {
if (s->bl_tree[bl_order[max_blindex]].Len != 0) break;
}
/* Update opt_len to include the bit length tree and counts */
s->opt_len += 3*((ulg)max_blindex + 1) + 5 + 5 + 4;
Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld",
s->opt_len, s->static_len));
return max_blindex;
}
/* ===========================================================================
* Send the header for a block using dynamic Huffman trees: the counts, the
* lengths of the bit length codes, the literal tree and the distance tree.
* IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
*/
local void send_all_trees(deflate_state *s, int lcodes, int dcodes,
int blcodes) {
int rank; /* index in bl_order */
Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes");
Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,
"too many codes");
Tracev((stderr, "\nbl counts: "));
send_bits(s, lcodes - 257, 5); /* not +255 as stated in appnote.txt */
send_bits(s, dcodes - 1, 5);
send_bits(s, blcodes - 4, 4); /* not -3 as stated in appnote.txt */
for (rank = 0; rank < blcodes; rank++) {
Tracev((stderr, "\nbl code %2d ", bl_order[rank]));
send_bits(s, s->bl_tree[bl_order[rank]].Len, 3);
}
Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent));
send_tree(s, (ct_data *)s->dyn_ltree, lcodes - 1); /* literal tree */
Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent));
send_tree(s, (ct_data *)s->dyn_dtree, dcodes - 1); /* distance tree */
Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent));
}
/* ===========================================================================
* Send a stored block
*/
void ZLIB_INTERNAL _tr_stored_block(deflate_state *s, charf *buf,
ulg stored_len, int last) {
send_bits(s, (STORED_BLOCK<<1) + last, 3); /* send block type */
bi_windup(s); /* align on byte boundary */
put_short(s, (ush)stored_len);
put_short(s, (ush)~stored_len);
if (stored_len)
zmemcpy(s->pending_buf + s->pending, (Bytef *)buf, stored_len);
s->pending += stored_len;
#ifdef ZLIB_DEBUG
s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L;
s->compressed_len += (stored_len + 4) << 3;
s->bits_sent += 2*16;
s->bits_sent += stored_len << 3;
#endif
}
/* ===========================================================================
* Flush the bits in the bit buffer to pending output (leaves at most 7 bits)
*/
void ZLIB_INTERNAL _tr_flush_bits(deflate_state *s) {
bi_flush(s);
}
/* ===========================================================================
* Send one empty static block to give enough lookahead for inflate.
* This takes 10 bits, of which 7 may remain in the bit buffer.
*/
void ZLIB_INTERNAL _tr_align(deflate_state *s) {
send_bits(s, STATIC_TREES<<1, 3);
send_code(s, END_BLOCK, static_ltree);
#ifdef ZLIB_DEBUG
s->compressed_len += 10L; /* 3 for block type, 7 for EOB */
#endif
bi_flush(s);
}
/* ===========================================================================
* Send the block data compressed using the given Huffman trees
*/
local void compress_block(deflate_state *s, const ct_data *ltree,
const ct_data *dtree) {
unsigned dist; /* distance of matched string */
int lc; /* match length or unmatched char (if dist == 0) */
unsigned sx = 0; /* running index in sym_buf */
unsigned code; /* the code to send */
int extra; /* number of extra bits to send */
if (s->sym_next != 0) do {
dist = s->sym_buf[sx++] & 0xff;
dist += (unsigned)(s->sym_buf[sx++] & 0xff) << 8;
lc = s->sym_buf[sx++];
if (dist == 0) {
send_code(s, lc, ltree); /* send a literal byte */
Tracecv(isgraph(lc), (stderr," '%c' ", lc));
} else {
/* Here, lc is the match length - MIN_MATCH */
code = _length_code[lc];
send_code(s, code + LITERALS + 1, ltree); /* send length code */
extra = extra_lbits[code];
if (extra != 0) {
lc -= base_length[code];
send_bits(s, lc, extra); /* send the extra length bits */
}
dist--; /* dist is now the match distance - 1 */
code = d_code(dist);
|
| ︙ | ︙ | |||
1096 1097 1098 1099 1100 1101 1102 |
* "allow list" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255).
* - BINARY otherwise.
* - The following partially-portable control characters form a
* "gray list" that is ignored in this detection algorithm:
* (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}).
* IN assertion: the fields Freq of dyn_ltree are set.
*/
| | < < | 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 |
* "allow list" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255).
* - BINARY otherwise.
* - The following partially-portable control characters form a
* "gray list" that is ignored in this detection algorithm:
* (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}).
* IN assertion: the fields Freq of dyn_ltree are set.
*/
local int detect_data_type(deflate_state *s) {
/* block_mask is the bit mask of block-listed bytes
* set bits 0..6, 14..25, and 28..31
* 0xf3ffc07f = binary 11110011111111111100000001111111
*/
unsigned long block_mask = 0xf3ffc07fUL;
int n;
|
| ︙ | ︙ | |||
1126 1127 1128 1129 1130 1131 1132 |
/* There are no "block-listed" or "allow-listed" bytes:
* this stream either is empty or has tolerated ("gray-listed") bytes only.
*/
return Z_BINARY;
}
/* ===========================================================================
| | | < > | | | | | | | > > > | > > > | | > > > > > > | > > > > < | < < > | | > > | | > > > | | | < | < > | > > > > > > > > > > | < < | < < > | | > > > > | > | | > > > > > > > > > > > > | > | < > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 |
/* There are no "block-listed" or "allow-listed" bytes:
* this stream either is empty or has tolerated ("gray-listed") bytes only.
*/
return Z_BINARY;
}
/* ===========================================================================
* Determine the best encoding for the current block: dynamic trees, static
* trees or store, and write out the encoded block.
*/
void ZLIB_INTERNAL _tr_flush_block(deflate_state *s, charf *buf,
ulg stored_len, int last) {
ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */
int max_blindex = 0; /* index of last bit length code of non zero freq */
/* Build the Huffman trees unless a stored block is forced */
if (s->level > 0) {
/* Check if the file is binary or text */
if (s->strm->data_type == Z_UNKNOWN)
s->strm->data_type = detect_data_type(s);
/* Construct the literal and distance trees */
build_tree(s, (tree_desc *)(&(s->l_desc)));
Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len,
s->static_len));
build_tree(s, (tree_desc *)(&(s->d_desc)));
Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len,
s->static_len));
/* At this point, opt_len and static_len are the total bit lengths of
* the compressed block data, excluding the tree representations.
*/
/* Build the bit length tree for the above two trees, and get the index
* in bl_order of the last bit length code to send.
*/
max_blindex = build_bl_tree(s);
/* Determine the best encoding. Compute the block lengths in bytes. */
opt_lenb = (s->opt_len + 3 + 7) >> 3;
static_lenb = (s->static_len + 3 + 7) >> 3;
Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ",
opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len,
s->sym_next / 3));
#ifndef FORCE_STATIC
if (static_lenb <= opt_lenb || s->strategy == Z_FIXED)
#endif
opt_lenb = static_lenb;
} else {
Assert(buf != (char*)0, "lost buf");
opt_lenb = static_lenb = stored_len + 5; /* force a stored block */
}
#ifdef FORCE_STORED
if (buf != (char*)0) { /* force stored block */
#else
if (stored_len + 4 <= opt_lenb && buf != (char*)0) {
/* 4: two words for the lengths */
#endif
/* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
* Otherwise we can't have processed more than WSIZE input bytes since
* the last block flush, because compression would have been
* successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
* transform a block into a stored block.
*/
_tr_stored_block(s, buf, stored_len, last);
} else if (static_lenb == opt_lenb) {
send_bits(s, (STATIC_TREES<<1) + last, 3);
compress_block(s, (const ct_data *)static_ltree,
(const ct_data *)static_dtree);
#ifdef ZLIB_DEBUG
s->compressed_len += 3 + s->static_len;
#endif
} else {
send_bits(s, (DYN_TREES<<1) + last, 3);
send_all_trees(s, s->l_desc.max_code + 1, s->d_desc.max_code + 1,
max_blindex + 1);
compress_block(s, (const ct_data *)s->dyn_ltree,
(const ct_data *)s->dyn_dtree);
#ifdef ZLIB_DEBUG
s->compressed_len += 3 + s->opt_len;
#endif
}
Assert (s->compressed_len == s->bits_sent, "bad compressed size");
/* The above check is made mod 2^32, for files larger than 512 MB
* and uLong implemented on 32 bits.
*/
init_block(s);
if (last) {
bi_windup(s);
#ifdef ZLIB_DEBUG
s->compressed_len += 7; /* align on byte boundary */
#endif
}
Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len >> 3,
s->compressed_len - 7*last));
}
/* ===========================================================================
* Save the match info and tally the frequency counts. Return true if
* the current block must be flushed.
*/
int ZLIB_INTERNAL _tr_tally(deflate_state *s, unsigned dist, unsigned lc) {
s->sym_buf[s->sym_next++] = (uch)dist;
s->sym_buf[s->sym_next++] = (uch)(dist >> 8);
s->sym_buf[s->sym_next++] = (uch)lc;
if (dist == 0) {
/* lc is the unmatched char */
s->dyn_ltree[lc].Freq++;
} else {
s->matches++;
/* Here, lc is the match length - MIN_MATCH */
dist--; /* dist = match distance - 1 */
Assert((ush)dist < (ush)MAX_DIST(s) &&
(ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) &&
(ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match");
s->dyn_ltree[_length_code[lc] + LITERALS + 1].Freq++;
s->dyn_dtree[d_code(dist)].Freq++;
}
return (s->sym_next == s->sym_end);
}
|
Changes to compat/zlib/uncompr.c.
| ︙ | ︙ | |||
20 21 22 23 24 25 26 |
first unused input byte.
uncompress returns Z_OK if success, Z_MEM_ERROR if there was not enough
memory, Z_BUF_ERROR if there was not enough room in the output buffer, or
Z_DATA_ERROR if the input data was corrupted, including if the input data is
an incomplete zlib stream.
*/
| < < < | | < | 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
first unused input byte.
uncompress returns Z_OK if success, Z_MEM_ERROR if there was not enough
memory, Z_BUF_ERROR if there was not enough room in the output buffer, or
Z_DATA_ERROR if the input data was corrupted, including if the input data is
an incomplete zlib stream.
*/
int ZEXPORT uncompress2(Bytef *dest, uLongf *destLen, const Bytef *source,
uLong *sourceLen) {
z_stream stream;
int err;
const uInt max = (uInt)-1;
uLong len, left;
Byte buf[1]; /* for detection of incomplete stream when *destLen == 0 */
len = *sourceLen;
|
| ︙ | ︙ | |||
79 80 81 82 83 84 85 |
inflateEnd(&stream);
return err == Z_STREAM_END ? Z_OK :
err == Z_NEED_DICT ? Z_DATA_ERROR :
err == Z_BUF_ERROR && left + stream.avail_out ? Z_DATA_ERROR :
err;
}
| < < < | | < | 75 76 77 78 79 80 81 82 83 84 85 |
inflateEnd(&stream);
return err == Z_STREAM_END ? Z_OK :
err == Z_NEED_DICT ? Z_DATA_ERROR :
err == Z_BUF_ERROR && left + stream.avail_out ? Z_DATA_ERROR :
err;
}
int ZEXPORT uncompress(Bytef *dest, uLongf *destLen, const Bytef *source,
uLong sourceLen) {
return uncompress2(dest, destLen, source, &sourceLen);
}
|
Changes to compat/zlib/win32/README-WIN32.txt.
1 2 | ZLIB DATA COMPRESSION LIBRARY | | | 1 2 3 4 5 6 7 8 9 10 | ZLIB DATA COMPRESSION LIBRARY zlib 1.3.0 is a general purpose data compression library. All the code is thread safe. The data format used by the zlib library is described by RFCs (Request for Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). All functions of the compression library are documented in the file zlib.h (volunteer to write man pages welcome, contact zlib@gzip.org). Two compiled |
| ︙ | ︙ | |||
18 19 20 21 22 23 24 | PLEASE read DLL_FAQ.txt, and the the zlib FAQ http://zlib.net/zlib_faq.html before asking for help. Manifest: | | | 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | PLEASE read DLL_FAQ.txt, and the the zlib FAQ http://zlib.net/zlib_faq.html before asking for help. Manifest: The package zlib-1.3.0-win32-x86.zip will contain the following files: README-WIN32.txt This document ChangeLog Changes since previous zlib packages DLL_FAQ.txt Frequently asked questions about zlib1.dll zlib.3.pdf Documentation of this library in Adobe Acrobat format example.exe A statically-bound example (using zlib.lib, not the dll) |
| ︙ | ︙ |
Changes to compat/zlib/win32/zlib1.rc.
| ︙ | ︙ | |||
22 23 24 25 26 27 28 |
BEGIN
BLOCK "040904E4"
//language ID = U.S. English, char set = Windows, Multilingual
BEGIN
VALUE "FileDescription", "zlib data compression library\0"
VALUE "FileVersion", ZLIB_VERSION "\0"
VALUE "InternalName", "zlib1.dll\0"
| | | 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
BEGIN
BLOCK "040904E4"
//language ID = U.S. English, char set = Windows, Multilingual
BEGIN
VALUE "FileDescription", "zlib data compression library\0"
VALUE "FileVersion", ZLIB_VERSION "\0"
VALUE "InternalName", "zlib1.dll\0"
VALUE "LegalCopyright", "(C) 1995-2022 Jean-loup Gailly & Mark Adler\0"
VALUE "OriginalFilename", "zlib1.dll\0"
VALUE "ProductName", "zlib\0"
VALUE "ProductVersion", ZLIB_VERSION "\0"
VALUE "Comments", "For more information visit http://www.zlib.net/\0"
END
END
BLOCK "VarFileInfo"
|
| ︙ | ︙ |
Changes to compat/zlib/zconf.h.
| ︙ | ︙ | |||
34 35 36 37 38 39 40 41 42 43 44 45 46 47 | # define compress z_compress # define compress2 z_compress2 # define compressBound z_compressBound # endif # define crc32 z_crc32 # define crc32_combine z_crc32_combine # define crc32_combine64 z_crc32_combine64 # define crc32_z z_crc32_z # define deflate z_deflate # define deflateBound z_deflateBound # define deflateCopy z_deflateCopy # define deflateEnd z_deflateEnd # define deflateGetDictionary z_deflateGetDictionary # define deflateInit z_deflateInit | > > > | 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | # define compress z_compress # define compress2 z_compress2 # define compressBound z_compressBound # endif # define crc32 z_crc32 # define crc32_combine z_crc32_combine # define crc32_combine64 z_crc32_combine64 # define crc32_combine_gen z_crc32_combine_gen # define crc32_combine_gen64 z_crc32_combine_gen64 # define crc32_combine_op z_crc32_combine_op # define crc32_z z_crc32_z # define deflate z_deflate # define deflateBound z_deflateBound # define deflateCopy z_deflateCopy # define deflateEnd z_deflateEnd # define deflateGetDictionary z_deflateGetDictionary # define deflateInit z_deflateInit |
| ︙ | ︙ | |||
234 235 236 237 238 239 240 | #if defined(ZLIB_CONST) && !defined(z_const) # define z_const const #else # define z_const #endif #ifdef Z_SOLO | > > > | > | 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 |
#if defined(ZLIB_CONST) && !defined(z_const)
# define z_const const
#else
# define z_const
#endif
#ifdef Z_SOLO
# ifdef _WIN64
typedef unsigned long long z_size_t;
# else
typedef unsigned long z_size_t;
# endif
#else
# define z_longlong long long
# if defined(NO_SIZE_T)
typedef unsigned NO_SIZE_T z_size_t;
# elif defined(STDC)
# include <stddef.h>
typedef size_t z_size_t;
|
| ︙ | ︙ | |||
345 346 347 348 349 350 351 352 353 354 355 356 357 358 |
* define ZLIB_WINAPI.
* Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI.
*/
# ifdef ZLIB_WINAPI
# ifdef FAR
# undef FAR
# endif
# include <windows.h>
/* No need for _export, use ZLIB.DEF instead. */
/* For complete Windows compatibility, use WINAPI, not __stdcall. */
# define ZEXPORT WINAPI
# ifdef WIN32
# define ZEXPORTVA WINAPIV
# else
| > > > | 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 |
* define ZLIB_WINAPI.
* Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI.
*/
# ifdef ZLIB_WINAPI
# ifdef FAR
# undef FAR
# endif
# ifndef WIN32_LEAN_AND_MEAN
# define WIN32_LEAN_AND_MEAN
# endif
# include <windows.h>
/* No need for _export, use ZLIB.DEF instead. */
/* For complete Windows compatibility, use WINAPI, not __stdcall. */
# define ZEXPORT WINAPI
# ifdef WIN32
# define ZEXPORTVA WINAPIV
# else
|
| ︙ | ︙ | |||
427 428 429 430 431 432 433 | #ifdef Z_U4 typedef Z_U4 z_crc_t; #else typedef unsigned long z_crc_t; #endif | | | | 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 | #ifdef Z_U4 typedef Z_U4 z_crc_t; #else typedef unsigned long z_crc_t; #endif #ifdef HAVE_UNISTD_H /* may be set to #if 1 by ./configure */ # define Z_HAVE_UNISTD_H #endif #ifdef HAVE_STDARG_H /* may be set to #if 1 by ./configure */ # define Z_HAVE_STDARG_H #endif #ifdef STDC # ifndef Z_SOLO # include <sys/types.h> /* for off_t */ # endif |
| ︙ | ︙ | |||
463 464 465 466 467 468 469 | * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as * equivalently requesting no 64-bit operations */ #if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1 # undef _LARGEFILE64_SOURCE #endif | | > | > > > > > > | | 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 | * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as * equivalently requesting no 64-bit operations */ #if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1 # undef _LARGEFILE64_SOURCE #endif #ifndef Z_HAVE_UNISTD_H # ifdef __WATCOMC__ # define Z_HAVE_UNISTD_H # endif #endif #ifndef Z_HAVE_UNISTD_H # if defined(_LARGEFILE64_SOURCE) && !defined(_WIN32) # define Z_HAVE_UNISTD_H # endif #endif #ifndef Z_SOLO # if defined(Z_HAVE_UNISTD_H) # include <unistd.h> /* for SEEK_*, off_t, and _LFS64_LARGEFILE */ # ifdef VMS # include <unixio.h> /* for off_t */ # endif # ifndef z_off_t # define z_off_t off_t # endif |
| ︙ | ︙ | |||
503 504 505 506 507 508 509 | #ifndef z_off_t # define z_off_t long #endif #if !defined(_WIN32) && defined(Z_LARGE64) # define z_off64_t off64_t #else | | | 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 | #ifndef z_off_t # define z_off_t long #endif #if !defined(_WIN32) && defined(Z_LARGE64) # define z_off64_t off64_t #else # if defined(_WIN32) && !defined(__GNUC__) # define z_off64_t __int64 # else # define z_off64_t z_off_t # endif #endif /* MVS linker does not support external names larger than 8 bytes */ |
| ︙ | ︙ |
Changes to compat/zlib/zconf.h.cmakein.
| ︙ | ︙ | |||
36 37 38 39 40 41 42 43 44 45 46 47 48 49 | # define compress z_compress # define compress2 z_compress2 # define compressBound z_compressBound # endif # define crc32 z_crc32 # define crc32_combine z_crc32_combine # define crc32_combine64 z_crc32_combine64 # define crc32_z z_crc32_z # define deflate z_deflate # define deflateBound z_deflateBound # define deflateCopy z_deflateCopy # define deflateEnd z_deflateEnd # define deflateGetDictionary z_deflateGetDictionary # define deflateInit z_deflateInit | > > > | 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | # define compress z_compress # define compress2 z_compress2 # define compressBound z_compressBound # endif # define crc32 z_crc32 # define crc32_combine z_crc32_combine # define crc32_combine64 z_crc32_combine64 # define crc32_combine_gen z_crc32_combine_gen # define crc32_combine_gen64 z_crc32_combine_gen64 # define crc32_combine_op z_crc32_combine_op # define crc32_z z_crc32_z # define deflate z_deflate # define deflateBound z_deflateBound # define deflateCopy z_deflateCopy # define deflateEnd z_deflateEnd # define deflateGetDictionary z_deflateGetDictionary # define deflateInit z_deflateInit |
| ︙ | ︙ | |||
236 237 238 239 240 241 242 | #if defined(ZLIB_CONST) && !defined(z_const) # define z_const const #else # define z_const #endif #ifdef Z_SOLO | > > > | > | 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 |
#if defined(ZLIB_CONST) && !defined(z_const)
# define z_const const
#else
# define z_const
#endif
#ifdef Z_SOLO
# ifdef _WIN64
typedef unsigned long long z_size_t;
# else
typedef unsigned long z_size_t;
# endif
#else
# define z_longlong long long
# if defined(NO_SIZE_T)
typedef unsigned NO_SIZE_T z_size_t;
# elif defined(STDC)
# include <stddef.h>
typedef size_t z_size_t;
|
| ︙ | ︙ | |||
347 348 349 350 351 352 353 354 355 356 357 358 359 360 |
* define ZLIB_WINAPI.
* Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI.
*/
# ifdef ZLIB_WINAPI
# ifdef FAR
# undef FAR
# endif
# include <windows.h>
/* No need for _export, use ZLIB.DEF instead. */
/* For complete Windows compatibility, use WINAPI, not __stdcall. */
# define ZEXPORT WINAPI
# ifdef WIN32
# define ZEXPORTVA WINAPIV
# else
| > > > | 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 |
* define ZLIB_WINAPI.
* Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI.
*/
# ifdef ZLIB_WINAPI
# ifdef FAR
# undef FAR
# endif
# ifndef WIN32_LEAN_AND_MEAN
# define WIN32_LEAN_AND_MEAN
# endif
# include <windows.h>
/* No need for _export, use ZLIB.DEF instead. */
/* For complete Windows compatibility, use WINAPI, not __stdcall. */
# define ZEXPORT WINAPI
# ifdef WIN32
# define ZEXPORTVA WINAPIV
# else
|
| ︙ | ︙ | |||
465 466 467 468 469 470 471 | * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as * equivalently requesting no 64-bit operations */ #if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1 # undef _LARGEFILE64_SOURCE #endif | | > | > > > > > > | | 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 | * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as * equivalently requesting no 64-bit operations */ #if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1 # undef _LARGEFILE64_SOURCE #endif #ifndef Z_HAVE_UNISTD_H # ifdef __WATCOMC__ # define Z_HAVE_UNISTD_H # endif #endif #ifndef Z_HAVE_UNISTD_H # if defined(_LARGEFILE64_SOURCE) && !defined(_WIN32) # define Z_HAVE_UNISTD_H # endif #endif #ifndef Z_SOLO # if defined(Z_HAVE_UNISTD_H) # include <unistd.h> /* for SEEK_*, off_t, and _LFS64_LARGEFILE */ # ifdef VMS # include <unixio.h> /* for off_t */ # endif # ifndef z_off_t # define z_off_t off_t # endif |
| ︙ | ︙ | |||
505 506 507 508 509 510 511 | #ifndef z_off_t # define z_off_t long #endif #if !defined(_WIN32) && defined(Z_LARGE64) # define z_off64_t off64_t #else | | | 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 | #ifndef z_off_t # define z_off_t long #endif #if !defined(_WIN32) && defined(Z_LARGE64) # define z_off64_t off64_t #else # if defined(_WIN32) && !defined(__GNUC__) # define z_off64_t __int64 # else # define z_off64_t z_off_t # endif #endif /* MVS linker does not support external names larger than 8 bytes */ |
| ︙ | ︙ |
Changes to compat/zlib/zconf.h.in.
| ︙ | ︙ | |||
34 35 36 37 38 39 40 41 42 43 44 45 46 47 | # define compress z_compress # define compress2 z_compress2 # define compressBound z_compressBound # endif # define crc32 z_crc32 # define crc32_combine z_crc32_combine # define crc32_combine64 z_crc32_combine64 # define crc32_z z_crc32_z # define deflate z_deflate # define deflateBound z_deflateBound # define deflateCopy z_deflateCopy # define deflateEnd z_deflateEnd # define deflateGetDictionary z_deflateGetDictionary # define deflateInit z_deflateInit | > > > | 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | # define compress z_compress # define compress2 z_compress2 # define compressBound z_compressBound # endif # define crc32 z_crc32 # define crc32_combine z_crc32_combine # define crc32_combine64 z_crc32_combine64 # define crc32_combine_gen z_crc32_combine_gen # define crc32_combine_gen64 z_crc32_combine_gen64 # define crc32_combine_op z_crc32_combine_op # define crc32_z z_crc32_z # define deflate z_deflate # define deflateBound z_deflateBound # define deflateCopy z_deflateCopy # define deflateEnd z_deflateEnd # define deflateGetDictionary z_deflateGetDictionary # define deflateInit z_deflateInit |
| ︙ | ︙ | |||
234 235 236 237 238 239 240 | #if defined(ZLIB_CONST) && !defined(z_const) # define z_const const #else # define z_const #endif #ifdef Z_SOLO | > > > | > | 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 |
#if defined(ZLIB_CONST) && !defined(z_const)
# define z_const const
#else
# define z_const
#endif
#ifdef Z_SOLO
# ifdef _WIN64
typedef unsigned long long z_size_t;
# else
typedef unsigned long z_size_t;
# endif
#else
# define z_longlong long long
# if defined(NO_SIZE_T)
typedef unsigned NO_SIZE_T z_size_t;
# elif defined(STDC)
# include <stddef.h>
typedef size_t z_size_t;
|
| ︙ | ︙ | |||
345 346 347 348 349 350 351 352 353 354 355 356 357 358 |
* define ZLIB_WINAPI.
* Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI.
*/
# ifdef ZLIB_WINAPI
# ifdef FAR
# undef FAR
# endif
# include <windows.h>
/* No need for _export, use ZLIB.DEF instead. */
/* For complete Windows compatibility, use WINAPI, not __stdcall. */
# define ZEXPORT WINAPI
# ifdef WIN32
# define ZEXPORTVA WINAPIV
# else
| > > > | 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 |
* define ZLIB_WINAPI.
* Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI.
*/
# ifdef ZLIB_WINAPI
# ifdef FAR
# undef FAR
# endif
# ifndef WIN32_LEAN_AND_MEAN
# define WIN32_LEAN_AND_MEAN
# endif
# include <windows.h>
/* No need for _export, use ZLIB.DEF instead. */
/* For complete Windows compatibility, use WINAPI, not __stdcall. */
# define ZEXPORT WINAPI
# ifdef WIN32
# define ZEXPORTVA WINAPIV
# else
|
| ︙ | ︙ | |||
463 464 465 466 467 468 469 | * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as * equivalently requesting no 64-bit operations */ #if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1 # undef _LARGEFILE64_SOURCE #endif | | > | > > > > > > | | 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 | * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as * equivalently requesting no 64-bit operations */ #if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1 # undef _LARGEFILE64_SOURCE #endif #ifndef Z_HAVE_UNISTD_H # ifdef __WATCOMC__ # define Z_HAVE_UNISTD_H # endif #endif #ifndef Z_HAVE_UNISTD_H # if defined(_LARGEFILE64_SOURCE) && !defined(_WIN32) # define Z_HAVE_UNISTD_H # endif #endif #ifndef Z_SOLO # if defined(Z_HAVE_UNISTD_H) # include <unistd.h> /* for SEEK_*, off_t, and _LFS64_LARGEFILE */ # ifdef VMS # include <unixio.h> /* for off_t */ # endif # ifndef z_off_t # define z_off_t off_t # endif |
| ︙ | ︙ | |||
503 504 505 506 507 508 509 | #ifndef z_off_t # define z_off_t long #endif #if !defined(_WIN32) && defined(Z_LARGE64) # define z_off64_t off64_t #else | | | 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 | #ifndef z_off_t # define z_off_t long #endif #if !defined(_WIN32) && defined(Z_LARGE64) # define z_off64_t off64_t #else # if defined(_WIN32) && !defined(__GNUC__) # define z_off64_t __int64 # else # define z_off64_t z_off_t # endif #endif /* MVS linker does not support external names larger than 8 bytes */ |
| ︙ | ︙ |
Changes to compat/zlib/zlib.3.
|
| | | 1 2 3 4 5 6 7 8 | .TH ZLIB 3 "18 Aug 2023" .SH NAME zlib \- compression/decompression library .SH SYNOPSIS [see .I zlib.h for full description] .SH DESCRIPTION |
| ︙ | ︙ | |||
101 102 103 104 105 106 107 | .IP http://zlib.net/zlib_faq.html .LP before asking for help. Send questions and/or comments to zlib@gzip.org, or (for the Windows DLL version) to Gilles Vollant (info@winimage.com). .SH AUTHORS AND LICENSE | | | | 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 | .IP http://zlib.net/zlib_faq.html .LP before asking for help. Send questions and/or comments to zlib@gzip.org, or (for the Windows DLL version) to Gilles Vollant (info@winimage.com). .SH AUTHORS AND LICENSE Version 1.3 .LP Copyright (C) 1995-2023 Jean-loup Gailly and Mark Adler .LP This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. .LP Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it |
| ︙ | ︙ |
Changes to compat/zlib/zlib.3.pdf.
cannot compute difference between binary files
Changes to compat/zlib/zlib.h.
1 | /* zlib.h -- interface of the 'zlib' general purpose compression library | | | | 1 2 3 4 5 6 7 8 9 10 11 | /* zlib.h -- interface of the 'zlib' general purpose compression library version 1.3, August 18th, 2023 Copyright (C) 1995-2023 Jean-loup Gailly and Mark Adler This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it |
| ︙ | ︙ | |||
33 34 35 36 37 38 39 |
#include "zconf.h"
#ifdef __cplusplus
extern "C" {
#endif
| | | | | | 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
#include "zconf.h"
#ifdef __cplusplus
extern "C" {
#endif
#define ZLIB_VERSION "1.3"
#define ZLIB_VERNUM 0x1300
#define ZLIB_VER_MAJOR 1
#define ZLIB_VER_MINOR 3
#define ZLIB_VER_REVISION 0
#define ZLIB_VER_SUBREVISION 0
/*
The 'zlib' compression library provides in-memory compression and
decompression functions, including integrity checks of the uncompressed data.
This version of the library supports only one compression method (deflation)
but other algorithms will be added later and will have the same stream
|
| ︙ | ︙ | |||
74 75 76 77 78 79 80 |
directory information, and uses a different, slower check method than zlib.
The library does not install any signal handler. The decoder checks
the consistency of the compressed data, so the library should never crash
even in the case of corrupted input.
*/
| | | | 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
directory information, and uses a different, slower check method than zlib.
The library does not install any signal handler. The decoder checks
the consistency of the compressed data, so the library should never crash
even in the case of corrupted input.
*/
typedef voidpf (*alloc_func)(voidpf opaque, uInt items, uInt size);
typedef void (*free_func)(voidpf opaque, voidpf address);
struct internal_state;
typedef struct z_stream_s {
z_const Bytef *next_in; /* next input byte */
uInt avail_in; /* number of bytes available at next_in */
uLong total_in; /* total number of input bytes read so far */
|
| ︙ | ︙ | |||
213 214 215 216 217 218 219 |
#define zlib_version zlibVersion()
/* for compatibility with versions < 1.0.2 */
/* basic functions */
| | | | | | 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 |
#define zlib_version zlibVersion()
/* for compatibility with versions < 1.0.2 */
/* basic functions */
ZEXTERN const char * ZEXPORT zlibVersion(void);
/* The application can compare zlibVersion and ZLIB_VERSION for consistency.
If the first character differs, the library code actually used is not
compatible with the zlib.h header file used by the application. This check
is automatically made by deflateInit and inflateInit.
*/
/*
ZEXTERN int ZEXPORT deflateInit(z_streamp strm, int level);
Initializes the internal stream state for compression. The fields
zalloc, zfree and opaque must be initialized before by the caller. If
zalloc and zfree are set to Z_NULL, deflateInit updates them to use default
allocation functions. total_in, total_out, adler, and msg are initialized.
The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9:
1 gives best speed, 9 gives best compression, 0 gives no compression at all
(the input data is simply copied a block at a time). Z_DEFAULT_COMPRESSION
requests a default compromise between speed and compression (currently
equivalent to level 6).
deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough
memory, Z_STREAM_ERROR if level is not a valid compression level, or
Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible
with the version assumed by the caller (ZLIB_VERSION). msg is set to null
if there is no error message. deflateInit does not perform any compression:
this will be done by deflate().
*/
ZEXTERN int ZEXPORT deflate(z_streamp strm, int flush);
/*
deflate compresses as much data as possible, and stops when the input
buffer becomes empty or the output buffer becomes full. It may introduce
some output latency (reading input without producing any output) except when
forced to flush.
The detailed semantics are as follows. deflate performs one or both of the
|
| ︙ | ︙ | |||
272 273 274 275 276 277 278 | one of the actions is possible, by providing more input and/or consuming more output, and updating avail_in or avail_out accordingly; avail_out should never be zero before the call. The application can consume the compressed output when it wants, for example when the output buffer is full (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK and with zero avail_out, it must be called again after making room in the output buffer because there might be more output pending. See deflatePending(), | | | 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 |
one of the actions is possible, by providing more input and/or consuming more
output, and updating avail_in or avail_out accordingly; avail_out should
never be zero before the call. The application can consume the compressed
output when it wants, for example when the output buffer is full (avail_out
== 0), or after each call of deflate(). If deflate returns Z_OK and with
zero avail_out, it must be called again after making room in the output
buffer because there might be more output pending. See deflatePending(),
which can be used if desired to determine whether or not there is more output
in that case.
Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to
decide how much data to accumulate before producing output, in order to
maximize compression.
If the parameter flush is set to Z_SYNC_FLUSH, all pending output is
|
| ︙ | ︙ | |||
316 317 318 319 320 321 322 |
random access is desired. Using Z_FULL_FLUSH too often can seriously degrade
compression.
If deflate returns with avail_out == 0, this function must be called again
with the same value of the flush parameter and more output space (updated
avail_out), until the flush is complete (deflate returns with non-zero
avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that
| | | | 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 |
random access is desired. Using Z_FULL_FLUSH too often can seriously degrade
compression.
If deflate returns with avail_out == 0, this function must be called again
with the same value of the flush parameter and more output space (updated
avail_out), until the flush is complete (deflate returns with non-zero
avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that
avail_out is greater than six when the flush marker begins, in order to avoid
repeated flush markers upon calling deflate() again when avail_out == 0.
If the parameter flush is set to Z_FINISH, pending input is processed,
pending output is flushed and deflate returns with Z_STREAM_END if there was
enough output space. If deflate returns with Z_OK or Z_BUF_ERROR, this
function must be called again with Z_FINISH and more output space (updated
avail_out) but no more input data, until it returns with Z_STREAM_END or an
error. After deflate has returned Z_STREAM_END, the only possible operations
|
| ︙ | ︙ | |||
356 357 358 359 360 361 362 | by the application), or Z_BUF_ERROR if no progress is possible (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not fatal, and deflate() can be called again with more input and more output space to continue compressing. */ | | | | > | | 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 |
by the application), or Z_BUF_ERROR if no progress is possible (for example
avail_in or avail_out was zero). Note that Z_BUF_ERROR is not fatal, and
deflate() can be called again with more input and more output space to
continue compressing.
*/
ZEXTERN int ZEXPORT deflateEnd(z_streamp strm);
/*
All dynamically allocated data structures for this stream are freed.
This function discards any unprocessed input and does not flush any pending
output.
deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the
stream state was inconsistent, Z_DATA_ERROR if the stream was freed
prematurely (some input or output was discarded). In the error case, msg
may be set but then points to a static string (which must not be
deallocated).
*/
/*
ZEXTERN int ZEXPORT inflateInit(z_streamp strm);
Initializes the internal stream state for decompression. The fields
next_in, avail_in, zalloc, zfree and opaque must be initialized before by
the caller. In the current version of inflate, the provided input is not
read or consumed. The allocation of a sliding window will be deferred to
the first call of inflate (if the decompression does not complete on the
first call). If zalloc and zfree are set to Z_NULL, inflateInit updates
them to use default allocation functions. total_in, total_out, adler, and
msg are initialized.
inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough
memory, Z_VERSION_ERROR if the zlib library version is incompatible with the
version assumed by the caller, or Z_STREAM_ERROR if the parameters are
invalid, such as a null pointer to the structure. msg is set to null if
there is no error message. inflateInit does not perform any decompression.
Actual decompression will be done by inflate(). So next_in, and avail_in,
next_out, and avail_out are unused and unchanged. The current
implementation of inflateInit() does not process any header information --
that is deferred until inflate() is called.
*/
ZEXTERN int ZEXPORT inflate(z_streamp strm, int flush);
/*
inflate decompresses as much data as possible, and stops when the input
buffer becomes empty or the output buffer becomes full. It may introduce
some output latency (reading input without producing any output) except when
forced to flush.
The detailed semantics are as follows. inflate performs one or both of the
|
| ︙ | ︙ | |||
513 514 515 516 517 518 519 | inflate() can be called again with more input and more output space to continue decompressing. If Z_DATA_ERROR is returned, the application may then call inflateSync() to look for a good compression block if a partial recovery of the data is to be attempted. */ | | | | | | | | | 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 |
inflate() can be called again with more input and more output space to
continue decompressing. If Z_DATA_ERROR is returned, the application may
then call inflateSync() to look for a good compression block if a partial
recovery of the data is to be attempted.
*/
ZEXTERN int ZEXPORT inflateEnd(z_streamp strm);
/*
All dynamically allocated data structures for this stream are freed.
This function discards any unprocessed input and does not flush any pending
output.
inflateEnd returns Z_OK if success, or Z_STREAM_ERROR if the stream state
was inconsistent.
*/
/* Advanced functions */
/*
The following functions are needed only in some special applications.
*/
/*
ZEXTERN int ZEXPORT deflateInit2(z_streamp strm,
int level,
int method,
int windowBits,
int memLevel,
int strategy);
This is another version of deflateInit with more compression options. The
fields zalloc, zfree and opaque must be initialized before by the caller.
The method parameter is the compression method. It must be Z_DEFLATED in
this version of the library.
|
| ︙ | ︙ | |||
603 604 605 606 607 608 609 | memory, Z_STREAM_ERROR if any parameter is invalid (such as an invalid method), or Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible with the version assumed by the caller (ZLIB_VERSION). msg is set to null if there is no error message. deflateInit2 does not perform any compression: this will be done by deflate(). */ | | | | | 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 |
memory, Z_STREAM_ERROR if any parameter is invalid (such as an invalid
method), or Z_VERSION_ERROR if the zlib library version (zlib_version) is
incompatible with the version assumed by the caller (ZLIB_VERSION). msg is
set to null if there is no error message. deflateInit2 does not perform any
compression: this will be done by deflate().
*/
ZEXTERN int ZEXPORT deflateSetDictionary(z_streamp strm,
const Bytef *dictionary,
uInt dictLength);
/*
Initializes the compression dictionary from the given byte sequence
without producing any compressed output. When using the zlib format, this
function must be called immediately after deflateInit, deflateInit2 or
deflateReset, and before any call of deflate. When doing raw deflate, this
function must be called either before any call of deflate, or immediately
after the completion of a deflate block, i.e. after all input has been
|
| ︙ | ︙ | |||
647 648 649 650 651 652 653 |
deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a
parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is
inconsistent (for example if deflate has already been called for this stream
or if not at a block boundary for raw deflate). deflateSetDictionary does
not perform any compression: this will be done by deflate().
*/
| | | | | | | | | | | | | 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 |
deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a
parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is
inconsistent (for example if deflate has already been called for this stream
or if not at a block boundary for raw deflate). deflateSetDictionary does
not perform any compression: this will be done by deflate().
*/
ZEXTERN int ZEXPORT deflateGetDictionary(z_streamp strm,
Bytef *dictionary,
uInt *dictLength);
/*
Returns the sliding dictionary being maintained by deflate. dictLength is
set to the number of bytes in the dictionary, and that many bytes are copied
to dictionary. dictionary must have enough space, where 32768 bytes is
always enough. If deflateGetDictionary() is called with dictionary equal to
Z_NULL, then only the dictionary length is returned, and nothing is copied.
Similarly, if dictLength is Z_NULL, then it is not set.
deflateGetDictionary() may return a length less than the window size, even
when more than the window size in input has been provided. It may return up
to 258 bytes less in that case, due to how zlib's implementation of deflate
manages the sliding window and lookahead for matches, where matches can be
up to 258 bytes long. If the application needs the last window-size bytes of
input, then that would need to be saved by the application outside of zlib.
deflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the
stream state is inconsistent.
*/
ZEXTERN int ZEXPORT deflateCopy(z_streamp dest,
z_streamp source);
/*
Sets the destination stream as a complete copy of the source stream.
This function can be useful when several compression strategies will be
tried, for example when there are several ways of pre-processing the input
data with a filter. The streams that will be discarded should then be freed
by calling deflateEnd. Note that deflateCopy duplicates the internal
compression state which can be quite large, so this strategy is slow and can
consume lots of memory.
deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
(such as zalloc being Z_NULL). msg is left unchanged in both source and
destination.
*/
ZEXTERN int ZEXPORT deflateReset(z_streamp strm);
/*
This function is equivalent to deflateEnd followed by deflateInit, but
does not free and reallocate the internal compression state. The stream
will leave the compression level and any other attributes that may have been
set unchanged. total_in, total_out, adler, and msg are initialized.
deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
stream state was inconsistent (such as zalloc or state being Z_NULL).
*/
ZEXTERN int ZEXPORT deflateParams(z_streamp strm,
int level,
int strategy);
/*
Dynamically update the compression level and compression strategy. The
interpretation of level and strategy is as in deflateInit2(). This can be
used to switch between compression and straight copy of the input data, or
to switch to a different kind of input data requiring a different strategy.
If the compression approach (which is a function of the level) or the
strategy is changed, and if there have been any deflate() calls since the
|
| ︙ | ︙ | |||
725 726 727 728 729 730 731 |
In order to assure a change in the parameters on the first try, the
deflate stream should be flushed using deflate() with Z_BLOCK or other flush
request until strm.avail_out is not zero, before calling deflateParams().
Then no more input data should be provided before the deflateParams() call.
If this is done, the old level and strategy will be applied to the data
compressed before deflateParams(), and the new level and strategy will be
| | | | | | | | | | | | | | | | | | | > | | | 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 |
In order to assure a change in the parameters on the first try, the
deflate stream should be flushed using deflate() with Z_BLOCK or other flush
request until strm.avail_out is not zero, before calling deflateParams().
Then no more input data should be provided before the deflateParams() call.
If this is done, the old level and strategy will be applied to the data
compressed before deflateParams(), and the new level and strategy will be
applied to the data compressed after deflateParams().
deflateParams returns Z_OK on success, Z_STREAM_ERROR if the source stream
state was inconsistent or if a parameter was invalid, or Z_BUF_ERROR if
there was not enough output space to complete the compression of the
available input data before a change in the strategy or approach. Note that
in the case of a Z_BUF_ERROR, the parameters are not changed. A return
value of Z_BUF_ERROR is not fatal, in which case deflateParams() can be
retried with more output space.
*/
ZEXTERN int ZEXPORT deflateTune(z_streamp strm,
int good_length,
int max_lazy,
int nice_length,
int max_chain);
/*
Fine tune deflate's internal compression parameters. This should only be
used by someone who understands the algorithm used by zlib's deflate for
searching for the best matching string, and even then only by the most
fanatic optimizer trying to squeeze out the last compressed bit for their
specific input data. Read the deflate.c source code for the meaning of the
max_lazy, good_length, nice_length, and max_chain parameters.
deflateTune() can be called after deflateInit() or deflateInit2(), and
returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream.
*/
ZEXTERN uLong ZEXPORT deflateBound(z_streamp strm,
uLong sourceLen);
/*
deflateBound() returns an upper bound on the compressed size after
deflation of sourceLen bytes. It must be called after deflateInit() or
deflateInit2(), and after deflateSetHeader(), if used. This would be used
to allocate an output buffer for deflation in a single pass, and so would be
called before deflate(). If that first deflate() call is provided the
sourceLen input bytes, an output buffer allocated to the size returned by
deflateBound(), and the flush value Z_FINISH, then deflate() is guaranteed
to return Z_STREAM_END. Note that it is possible for the compressed size to
be larger than the value returned by deflateBound() if flush options other
than Z_FINISH or Z_NO_FLUSH are used.
*/
ZEXTERN int ZEXPORT deflatePending(z_streamp strm,
unsigned *pending,
int *bits);
/*
deflatePending() returns the number of bytes and bits of output that have
been generated, but not yet provided in the available output. The bytes not
provided would be due to the available output space having being consumed.
The number of bits of output not provided are between 0 and 7, where they
await more bits to join them in order to fill out a full byte. If pending
or bits are Z_NULL, then those values are not set.
deflatePending returns Z_OK if success, or Z_STREAM_ERROR if the source
stream state was inconsistent.
*/
ZEXTERN int ZEXPORT deflatePrime(z_streamp strm,
int bits,
int value);
/*
deflatePrime() inserts bits in the deflate output stream. The intent
is that this function is used to start off the deflate output with the bits
leftover from a previous deflate stream when appending to it. As such, this
function can only be used for raw deflate, and must be used before the first
deflate() call after a deflateInit2() or deflateReset(). bits must be less
than or equal to 16, and that many of the least significant bits of value
will be inserted in the output.
deflatePrime returns Z_OK if success, Z_BUF_ERROR if there was not enough
room in the internal buffer to insert the bits, or Z_STREAM_ERROR if the
source stream state was inconsistent.
*/
ZEXTERN int ZEXPORT deflateSetHeader(z_streamp strm,
gz_headerp head);
/*
deflateSetHeader() provides gzip header information for when a gzip
stream is requested by deflateInit2(). deflateSetHeader() may be called
after deflateInit2() or deflateReset() and before the first call of
deflate(). The text, time, os, extra field, name, and comment information
in the provided gz_header structure are written to the gzip header (xflag is
ignored -- the extra flags are set according to the compression level). The
caller must assure that, if not Z_NULL, name and comment are terminated with
a zero byte, and that if extra is not Z_NULL, that extra_len bytes are
available there. If hcrc is true, a gzip header crc is included. Note that
the current versions of the command-line version of gzip (up through version
1.3.x) do not support header crc's, and will report that it is a "multi-part
gzip file" and give up.
If deflateSetHeader is not used, the default gzip header has text false,
the time set to zero, and os set to the current operating system, with no
extra, name, or comment fields. The gzip header is returned to the default
state by deflateReset().
deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source
stream state was inconsistent.
*/
/*
ZEXTERN int ZEXPORT inflateInit2(z_streamp strm,
int windowBits);
This is another version of inflateInit with an extra parameter. The
fields next_in, avail_in, zalloc, zfree and opaque must be initialized
before by the caller.
The windowBits parameter is the base two logarithm of the maximum window
size (the size of the history buffer). It should be in the range 8..15 for
|
| ︙ | ︙ | |||
879 880 881 882 883 884 885 | apart from possibly reading the zlib header if present: actual decompression will be done by inflate(). (So next_in and avail_in may be modified, but next_out and avail_out are unused and unchanged.) The current implementation of inflateInit2() does not process any header information -- that is deferred until inflate() is called. */ | | | | | | | | | | | | > | | | | | | | 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 |
apart from possibly reading the zlib header if present: actual decompression
will be done by inflate(). (So next_in and avail_in may be modified, but
next_out and avail_out are unused and unchanged.) The current implementation
of inflateInit2() does not process any header information -- that is
deferred until inflate() is called.
*/
ZEXTERN int ZEXPORT inflateSetDictionary(z_streamp strm,
const Bytef *dictionary,
uInt dictLength);
/*
Initializes the decompression dictionary from the given uncompressed byte
sequence. This function must be called immediately after a call of inflate,
if that call returned Z_NEED_DICT. The dictionary chosen by the compressor
can be determined from the Adler-32 value returned by that call of inflate.
The compressor and decompressor must use exactly the same dictionary (see
deflateSetDictionary). For raw inflate, this function can be called at any
time to set the dictionary. If the provided dictionary is smaller than the
window and there is already data in the window, then the provided dictionary
will amend what's there. The application must insure that the dictionary
that was used for compression is provided.
inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a
parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is
inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the
expected one (incorrect Adler-32 value). inflateSetDictionary does not
perform any decompression: this will be done by subsequent calls of
inflate().
*/
ZEXTERN int ZEXPORT inflateGetDictionary(z_streamp strm,
Bytef *dictionary,
uInt *dictLength);
/*
Returns the sliding dictionary being maintained by inflate. dictLength is
set to the number of bytes in the dictionary, and that many bytes are copied
to dictionary. dictionary must have enough space, where 32768 bytes is
always enough. If inflateGetDictionary() is called with dictionary equal to
Z_NULL, then only the dictionary length is returned, and nothing is copied.
Similarly, if dictLength is Z_NULL, then it is not set.
inflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the
stream state is inconsistent.
*/
ZEXTERN int ZEXPORT inflateSync(z_streamp strm);
/*
Skips invalid compressed data until a possible full flush point (see above
for the description of deflate with Z_FULL_FLUSH) can be found, or until all
available input is skipped. No output is provided.
inflateSync searches for a 00 00 FF FF pattern in the compressed data.
All full flush points have this pattern, but not all occurrences of this
pattern are full flush points.
inflateSync returns Z_OK if a possible full flush point has been found,
Z_BUF_ERROR if no more input was provided, Z_DATA_ERROR if no flush point
has been found, or Z_STREAM_ERROR if the stream structure was inconsistent.
In the success case, the application may save the current current value of
total_in which indicates where valid compressed data was found. In the
error case, the application may repeatedly call inflateSync, providing more
input each time, until success or end of the input data.
*/
ZEXTERN int ZEXPORT inflateCopy(z_streamp dest,
z_streamp source);
/*
Sets the destination stream as a complete copy of the source stream.
This function can be useful when randomly accessing a large stream. The
first pass through the stream can periodically record the inflate state,
allowing restarting inflate at those points when randomly accessing the
stream.
inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
(such as zalloc being Z_NULL). msg is left unchanged in both source and
destination.
*/
ZEXTERN int ZEXPORT inflateReset(z_streamp strm);
/*
This function is equivalent to inflateEnd followed by inflateInit,
but does not free and reallocate the internal decompression state. The
stream will keep attributes that may have been set by inflateInit2.
total_in, total_out, adler, and msg are initialized.
inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
stream state was inconsistent (such as zalloc or state being Z_NULL).
*/
ZEXTERN int ZEXPORT inflateReset2(z_streamp strm,
int windowBits);
/*
This function is the same as inflateReset, but it also permits changing
the wrap and window size requests. The windowBits parameter is interpreted
the same as it is for inflateInit2. If the window size is changed, then the
memory allocated for the window is freed, and the window will be reallocated
by inflate() if needed.
inflateReset2 returns Z_OK if success, or Z_STREAM_ERROR if the source
stream state was inconsistent (such as zalloc or state being Z_NULL), or if
the windowBits parameter is invalid.
*/
ZEXTERN int ZEXPORT inflatePrime(z_streamp strm,
int bits,
int value);
/*
This function inserts bits in the inflate input stream. The intent is
that this function is used to start inflating at a bit position in the
middle of a byte. The provided bits will be used before any bytes are used
from next_in. This function should only be used with raw inflate, and
should be used before the first inflate() call after inflateInit2() or
inflateReset(). bits must be less than or equal to 16, and that many of the
least significant bits of value will be inserted in the input.
If bits is negative, then the input stream bit buffer is emptied. Then
inflatePrime() can be called again to put bits in the buffer. This is used
to clear out bits leftover after feeding inflate a block description prior
to feeding inflate codes.
inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source
stream state was inconsistent.
*/
ZEXTERN long ZEXPORT inflateMark(z_streamp strm);
/*
This function returns two values, one in the lower 16 bits of the return
value, and the other in the remaining upper bits, obtained by shifting the
return value down 16 bits. If the upper value is -1 and the lower value is
zero, then inflate() is currently decoding information outside of a block.
If the upper value is -1 and the lower value is non-zero, then inflate is in
the middle of a stored block, with the lower value equaling the number of
|
| ︙ | ︙ | |||
1025 1026 1027 1028 1029 1030 1031 |
location in the input stream can be determined from avail_in and data_type
as noted in the description for the Z_BLOCK flush parameter for inflate.
inflateMark returns the value noted above, or -65536 if the provided
source stream state was inconsistent.
*/
| | | | 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 |
location in the input stream can be determined from avail_in and data_type
as noted in the description for the Z_BLOCK flush parameter for inflate.
inflateMark returns the value noted above, or -65536 if the provided
source stream state was inconsistent.
*/
ZEXTERN int ZEXPORT inflateGetHeader(z_streamp strm,
gz_headerp head);
/*
inflateGetHeader() requests that gzip header information be stored in the
provided gz_header structure. inflateGetHeader() may be called after
inflateInit2() or inflateReset(), and before the first call of inflate().
As inflate() processes the gzip stream, head->done is zero until the header
is completed, at which time head->done is set to one. If a zlib stream is
being decoded, then head->done is set to -1 to indicate that there will be
|
| ︙ | ︙ | |||
1066 1067 1068 1069 1070 1071 1072 |
retrieve the header from the next gzip stream.
inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source
stream state was inconsistent.
*/
/*
| | | | | | | | | | 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 |
retrieve the header from the next gzip stream.
inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source
stream state was inconsistent.
*/
/*
ZEXTERN int ZEXPORT inflateBackInit(z_streamp strm, int windowBits,
unsigned char FAR *window);
Initialize the internal stream state for decompression using inflateBack()
calls. The fields zalloc, zfree and opaque in strm must be initialized
before the call. If zalloc and zfree are Z_NULL, then the default library-
derived memory allocation routines are used. windowBits is the base two
logarithm of the window size, in the range 8..15. window is a caller
supplied buffer of that size. Except for special applications where it is
assured that deflate was used with small window sizes, windowBits must be 15
and a 32K byte window must be supplied to be able to decompress general
deflate streams.
See inflateBack() for the usage of these routines.
inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of
the parameters are invalid, Z_MEM_ERROR if the internal state could not be
allocated, or Z_VERSION_ERROR if the version of the library does not match
the version of the header file.
*/
typedef unsigned (*in_func)(void FAR *,
z_const unsigned char FAR * FAR *);
typedef int (*out_func)(void FAR *, unsigned char FAR *, unsigned);
ZEXTERN int ZEXPORT inflateBack(z_streamp strm,
in_func in, void FAR *in_desc,
out_func out, void FAR *out_desc);
/*
inflateBack() does a raw inflate with a single call using a call-back
interface for input and output. This is potentially more efficient than
inflate() for file i/o applications, in that it avoids copying between the
output and the sliding window by simply making the window itself the output
buffer. inflate() can be faster on modern CPUs when used with large
buffers. inflateBack() trusts the application to not change the output
|
| ︙ | ︙ | |||
1161 1162 1163 1164 1165 1166 1167 | using strm->next_in which will be Z_NULL only if in() returned an error. If strm->next_in is not Z_NULL, then the Z_BUF_ERROR was due to out() returning non-zero. (in() will always be called before out(), so strm->next_in is assured to be defined if out() returns non-zero.) Note that inflateBack() cannot return Z_OK. */ | | | | 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 |
using strm->next_in which will be Z_NULL only if in() returned an error. If
strm->next_in is not Z_NULL, then the Z_BUF_ERROR was due to out() returning
non-zero. (in() will always be called before out(), so strm->next_in is
assured to be defined if out() returns non-zero.) Note that inflateBack()
cannot return Z_OK.
*/
ZEXTERN int ZEXPORT inflateBackEnd(z_streamp strm);
/*
All memory allocated by inflateBackInit() is freed.
inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream
state was inconsistent.
*/
ZEXTERN uLong ZEXPORT zlibCompileFlags(void);
/* Return flags indicating compile-time options.
Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other:
1.0: size of uInt
3.2: size of uLong
5.4: size of voidpf (pointer)
7.6: size of z_off_t
|
| ︙ | ︙ | |||
1222 1223 1224 1225 1226 1227 1228 |
The following utility functions are implemented on top of the basic
stream-oriented functions. To simplify the interface, some default options
are assumed (compression level and memory usage, standard memory allocation
functions). The source code of these utility functions can be modified if
you need special options.
*/
| | | | | | | | | | | | | 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 |
The following utility functions are implemented on top of the basic
stream-oriented functions. To simplify the interface, some default options
are assumed (compression level and memory usage, standard memory allocation
functions). The source code of these utility functions can be modified if
you need special options.
*/
ZEXTERN int ZEXPORT compress(Bytef *dest, uLongf *destLen,
const Bytef *source, uLong sourceLen);
/*
Compresses the source buffer into the destination buffer. sourceLen is
the byte length of the source buffer. Upon entry, destLen is the total size
of the destination buffer, which must be at least the value returned by
compressBound(sourceLen). Upon exit, destLen is the actual size of the
compressed data. compress() is equivalent to compress2() with a level
parameter of Z_DEFAULT_COMPRESSION.
compress returns Z_OK if success, Z_MEM_ERROR if there was not
enough memory, Z_BUF_ERROR if there was not enough room in the output
buffer.
*/
ZEXTERN int ZEXPORT compress2(Bytef *dest, uLongf *destLen,
const Bytef *source, uLong sourceLen,
int level);
/*
Compresses the source buffer into the destination buffer. The level
parameter has the same meaning as in deflateInit. sourceLen is the byte
length of the source buffer. Upon entry, destLen is the total size of the
destination buffer, which must be at least the value returned by
compressBound(sourceLen). Upon exit, destLen is the actual size of the
compressed data.
compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
memory, Z_BUF_ERROR if there was not enough room in the output buffer,
Z_STREAM_ERROR if the level parameter is invalid.
*/
ZEXTERN uLong ZEXPORT compressBound(uLong sourceLen);
/*
compressBound() returns an upper bound on the compressed size after
compress() or compress2() on sourceLen bytes. It would be used before a
compress() or compress2() call to allocate the destination buffer.
*/
ZEXTERN int ZEXPORT uncompress(Bytef *dest, uLongf *destLen,
const Bytef *source, uLong sourceLen);
/*
Decompresses the source buffer into the destination buffer. sourceLen is
the byte length of the source buffer. Upon entry, destLen is the total size
of the destination buffer, which must be large enough to hold the entire
uncompressed data. (The size of the uncompressed data must have been saved
previously by the compressor and transmitted to the decompressor by some
mechanism outside the scope of this compression library.) Upon exit, destLen
is the actual size of the uncompressed data.
uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
enough memory, Z_BUF_ERROR if there was not enough room in the output
buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. In
the case where there is not enough room, uncompress() will fill the output
buffer with the uncompressed data up to that point.
*/
ZEXTERN int ZEXPORT uncompress2(Bytef *dest, uLongf *destLen,
const Bytef *source, uLong *sourceLen);
/*
Same as uncompress, except that sourceLen is a pointer, where the
length of the source is *sourceLen. On return, *sourceLen is the number of
source bytes consumed.
*/
/* gzip file access functions */
/*
This library supports reading and writing files in gzip (.gz) format with
an interface similar to that of stdio, using the functions that start with
"gz". The gzip format is different from the zlib format. gzip is a gzip
wrapper, documented in RFC 1952, wrapped around a deflate stream.
*/
typedef struct gzFile_s *gzFile; /* semi-opaque gzip file descriptor */
/*
ZEXTERN gzFile ZEXPORT gzopen(const char *path, const char *mode);
Open the gzip (.gz) file at path for reading and decompressing, or
compressing and writing. The mode parameter is as in fopen ("rb" or "wb")
but can also include a compression level ("wb9") or a strategy: 'f' for
filtered data as in "wb6f", 'h' for Huffman-only compression as in "wb1h",
'R' for run-length encoding as in "wb1R", or 'F' for fixed code compression
as in "wb9F". (See the description of deflateInit2 for more information
|
| ︙ | ︙ | |||
1335 1336 1337 1338 1339 1340 1341 |
gzopen returns NULL if the file could not be opened, if there was
insufficient memory to allocate the gzFile state, or if an invalid mode was
specified (an 'r', 'w', or 'a' was not provided, or '+' was provided).
errno can be checked to determine if the reason gzopen failed was that the
file could not be opened.
*/
| | | 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 |
gzopen returns NULL if the file could not be opened, if there was
insufficient memory to allocate the gzFile state, or if an invalid mode was
specified (an 'r', 'w', or 'a' was not provided, or '+' was provided).
errno can be checked to determine if the reason gzopen failed was that the
file could not be opened.
*/
ZEXTERN gzFile ZEXPORT gzdopen(int fd, const char *mode);
/*
Associate a gzFile with the file descriptor fd. File descriptors are
obtained from calls like open, dup, creat, pipe or fileno (if the file has
been previously opened with fopen). The mode parameter is as in gzopen.
The next call of gzclose on the returned gzFile will also close the file
descriptor fd, just like fclose(fdopen(fd, mode)) closes the file descriptor
|
| ︙ | ︙ | |||
1358 1359 1360 1361 1362 1363 1364 |
gzdopen returns NULL if there was insufficient memory to allocate the
gzFile state, if an invalid mode was specified (an 'r', 'w', or 'a' was not
provided, or '+' was provided), or if fd is -1. The file descriptor is not
used until the next gz* read, write, seek, or close operation, so gzdopen
will not detect if fd is invalid (unless fd is -1).
*/
| | | | | 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 |
gzdopen returns NULL if there was insufficient memory to allocate the
gzFile state, if an invalid mode was specified (an 'r', 'w', or 'a' was not
provided, or '+' was provided), or if fd is -1. The file descriptor is not
used until the next gz* read, write, seek, or close operation, so gzdopen
will not detect if fd is invalid (unless fd is -1).
*/
ZEXTERN int ZEXPORT gzbuffer(gzFile file, unsigned size);
/*
Set the internal buffer size used by this library's functions for file to
size. The default buffer size is 8192 bytes. This function must be called
after gzopen() or gzdopen(), and before any other calls that read or write
the file. The buffer memory allocation is always deferred to the first read
or write. Three times that size in buffer space is allocated. A larger
buffer size of, for example, 64K or 128K bytes will noticeably increase the
speed of decompression (reading).
The new buffer size also affects the maximum length for gzprintf().
gzbuffer() returns 0 on success, or -1 on failure, such as being called
too late.
*/
ZEXTERN int ZEXPORT gzsetparams(gzFile file, int level, int strategy);
/*
Dynamically update the compression level and strategy for file. See the
description of deflateInit2 for the meaning of these parameters. Previously
provided data is flushed before applying the parameter changes.
gzsetparams returns Z_OK if success, Z_STREAM_ERROR if the file was not
opened for writing, Z_ERRNO if there is an error writing the flushed data,
or Z_MEM_ERROR if there is a memory allocation error.
*/
ZEXTERN int ZEXPORT gzread(gzFile file, voidp buf, unsigned len);
/*
Read and decompress up to len uncompressed bytes from file into buf. If
the input file is not in gzip format, gzread copies the given number of
bytes into the buffer directly from the file.
After reaching the end of a gzip stream in the input, gzread will continue
to read, looking for another gzip stream. Any number of gzip streams may be
|
| ︙ | ︙ | |||
1415 1416 1417 1418 1419 1420 1421 |
gzread returns the number of uncompressed bytes actually read, less than
len for end of file, or -1 for error. If len is too large to fit in an int,
then nothing is read, -1 is returned, and the error state is set to
Z_STREAM_ERROR.
*/
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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 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 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 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 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 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 |
gzread returns the number of uncompressed bytes actually read, less than
len for end of file, or -1 for error. If len is too large to fit in an int,
then nothing is read, -1 is returned, and the error state is set to
Z_STREAM_ERROR.
*/
ZEXTERN z_size_t ZEXPORT gzfread(voidp buf, z_size_t size, z_size_t nitems,
gzFile file);
/*
Read and decompress up to nitems items of size size from file into buf,
otherwise operating as gzread() does. This duplicates the interface of
stdio's fread(), with size_t request and return types. If the library
defines size_t, then z_size_t is identical to size_t. If not, then z_size_t
is an unsigned integer type that can contain a pointer.
gzfread() returns the number of full items read of size size, or zero if
the end of the file was reached and a full item could not be read, or if
there was an error. gzerror() must be consulted if zero is returned in
order to determine if there was an error. If the multiplication of size and
nitems overflows, i.e. the product does not fit in a z_size_t, then nothing
is read, zero is returned, and the error state is set to Z_STREAM_ERROR.
In the event that the end of file is reached and only a partial item is
available at the end, i.e. the remaining uncompressed data length is not a
multiple of size, then the final partial item is nevertheless read into buf
and the end-of-file flag is set. The length of the partial item read is not
provided, but could be inferred from the result of gztell(). This behavior
is the same as the behavior of fread() implementations in common libraries,
but it prevents the direct use of gzfread() to read a concurrently written
file, resetting and retrying on end-of-file, when size is not 1.
*/
ZEXTERN int ZEXPORT gzwrite(gzFile file, voidpc buf, unsigned len);
/*
Compress and write the len uncompressed bytes at buf to file. gzwrite
returns the number of uncompressed bytes written or 0 in case of error.
*/
ZEXTERN z_size_t ZEXPORT gzfwrite(voidpc buf, z_size_t size,
z_size_t nitems, gzFile file);
/*
Compress and write nitems items of size size from buf to file, duplicating
the interface of stdio's fwrite(), with size_t request and return types. If
the library defines size_t, then z_size_t is identical to size_t. If not,
then z_size_t is an unsigned integer type that can contain a pointer.
gzfwrite() returns the number of full items written of size size, or zero
if there was an error. If the multiplication of size and nitems overflows,
i.e. the product does not fit in a z_size_t, then nothing is written, zero
is returned, and the error state is set to Z_STREAM_ERROR.
*/
ZEXTERN int ZEXPORTVA gzprintf(gzFile file, const char *format, ...);
/*
Convert, format, compress, and write the arguments (...) to file under
control of the string format, as in fprintf. gzprintf returns the number of
uncompressed bytes actually written, or a negative zlib error code in case
of error. The number of uncompressed bytes written is limited to 8191, or
one less than the buffer size given to gzbuffer(). The caller should assure
that this limit is not exceeded. If it is exceeded, then gzprintf() will
return an error (0) with nothing written. In this case, there may also be a
buffer overflow with unpredictable consequences, which is possible only if
zlib was compiled with the insecure functions sprintf() or vsprintf(),
because the secure snprintf() or vsnprintf() functions were not available.
This can be determined using zlibCompileFlags().
*/
ZEXTERN int ZEXPORT gzputs(gzFile file, const char *s);
/*
Compress and write the given null-terminated string s to file, excluding
the terminating null character.
gzputs returns the number of characters written, or -1 in case of error.
*/
ZEXTERN char * ZEXPORT gzgets(gzFile file, char *buf, int len);
/*
Read and decompress bytes from file into buf, until len-1 characters are
read, or until a newline character is read and transferred to buf, or an
end-of-file condition is encountered. If any characters are read or if len
is one, the string is terminated with a null character. If no characters
are read due to an end-of-file or len is less than one, then the buffer is
left untouched.
gzgets returns buf which is a null-terminated string, or it returns NULL
for end-of-file or in case of error. If there was an error, the contents at
buf are indeterminate.
*/
ZEXTERN int ZEXPORT gzputc(gzFile file, int c);
/*
Compress and write c, converted to an unsigned char, into file. gzputc
returns the value that was written, or -1 in case of error.
*/
ZEXTERN int ZEXPORT gzgetc(gzFile file);
/*
Read and decompress one byte from file. gzgetc returns this byte or -1
in case of end of file or error. This is implemented as a macro for speed.
As such, it does not do all of the checking the other functions do. I.e.
it does not check to see if file is NULL, nor whether the structure file
points to has been clobbered or not.
*/
ZEXTERN int ZEXPORT gzungetc(int c, gzFile file);
/*
Push c back onto the stream for file to be read as the first character on
the next read. At least one character of push-back is always allowed.
gzungetc() returns the character pushed, or -1 on failure. gzungetc() will
fail if c is -1, and may fail if a character has been pushed but not read
yet. If gzungetc is used immediately after gzopen or gzdopen, at least the
output buffer size of pushed characters is allowed. (See gzbuffer above.)
The pushed character will be discarded if the stream is repositioned with
gzseek() or gzrewind().
*/
ZEXTERN int ZEXPORT gzflush(gzFile file, int flush);
/*
Flush all pending output to file. The parameter flush is as in the
deflate() function. The return value is the zlib error number (see function
gzerror below). gzflush is only permitted when writing.
If the flush parameter is Z_FINISH, the remaining data is written and the
gzip stream is completed in the output. If gzwrite() is called again, a new
gzip stream will be started in the output. gzread() is able to read such
concatenated gzip streams.
gzflush should be called only when strictly necessary because it will
degrade compression if called too often.
*/
/*
ZEXTERN z_off_t ZEXPORT gzseek(gzFile file,
z_off_t offset, int whence);
Set the starting position to offset relative to whence for the next gzread
or gzwrite on file. The offset represents a number of bytes in the
uncompressed data stream. The whence parameter is defined as in lseek(2);
the value SEEK_END is not supported.
If the file is opened for reading, this function is emulated but can be
extremely slow. If the file is opened for writing, only forward seeks are
supported; gzseek then compresses a sequence of zeroes up to the new
starting position.
gzseek returns the resulting offset location as measured in bytes from
the beginning of the uncompressed stream, or -1 in case of error, in
particular if the file is opened for writing and the new starting position
would be before the current position.
*/
ZEXTERN int ZEXPORT gzrewind(gzFile file);
/*
Rewind file. This function is supported only for reading.
gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET).
*/
/*
ZEXTERN z_off_t ZEXPORT gztell(gzFile file);
Return the starting position for the next gzread or gzwrite on file.
This position represents a number of bytes in the uncompressed data stream,
and is zero when starting, even if appending or reading a gzip stream from
the middle of a file using gzdopen().
gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR)
*/
/*
ZEXTERN z_off_t ZEXPORT gzoffset(gzFile file);
Return the current compressed (actual) read or write offset of file. This
offset includes the count of bytes that precede the gzip stream, for example
when appending or when using gzdopen() for reading. When reading, the
offset does not include as yet unused buffered input. This information can
be used for a progress indicator. On error, gzoffset() returns -1.
*/
ZEXTERN int ZEXPORT gzeof(gzFile file);
/*
Return true (1) if the end-of-file indicator for file has been set while
reading, false (0) otherwise. Note that the end-of-file indicator is set
only if the read tried to go past the end of the input, but came up short.
Therefore, just like feof(), gzeof() may return false even if there is no
more data to read, in the event that the last read request was for the exact
number of bytes remaining in the input file. This will happen if the input
file size is an exact multiple of the buffer size.
If gzeof() returns true, then the read functions will return no more data,
unless the end-of-file indicator is reset by gzclearerr() and the input file
has grown since the previous end of file was detected.
*/
ZEXTERN int ZEXPORT gzdirect(gzFile file);
/*
Return true (1) if file is being copied directly while reading, or false
(0) if file is a gzip stream being decompressed.
If the input file is empty, gzdirect() will return true, since the input
does not contain a gzip stream.
If gzdirect() is used immediately after gzopen() or gzdopen() it will
cause buffers to be allocated to allow reading the file to determine if it
is a gzip file. Therefore if gzbuffer() is used, it should be called before
gzdirect().
When writing, gzdirect() returns true (1) if transparent writing was
requested ("wT" for the gzopen() mode), or false (0) otherwise. (Note:
gzdirect() is not needed when writing. Transparent writing must be
explicitly requested, so the application already knows the answer. When
linking statically, using gzdirect() will include all of the zlib code for
gzip file reading and decompression, which may not be desired.)
*/
ZEXTERN int ZEXPORT gzclose(gzFile file);
/*
Flush all pending output for file, if necessary, close file and
deallocate the (de)compression state. Note that once file is closed, you
cannot call gzerror with file, since its structures have been deallocated.
gzclose must not be called more than once on the same file, just as free
must not be called more than once on the same allocation.
gzclose will return Z_STREAM_ERROR if file is not valid, Z_ERRNO on a
file operation error, Z_MEM_ERROR if out of memory, Z_BUF_ERROR if the
last read ended in the middle of a gzip stream, or Z_OK on success.
*/
ZEXTERN int ZEXPORT gzclose_r(gzFile file);
ZEXTERN int ZEXPORT gzclose_w(gzFile file);
/*
Same as gzclose(), but gzclose_r() is only for use when reading, and
gzclose_w() is only for use when writing or appending. The advantage to
using these instead of gzclose() is that they avoid linking in zlib
compression or decompression code that is not used when only reading or only
writing respectively. If gzclose() is used, then both compression and
decompression code will be included the application when linking to a static
zlib library.
*/
ZEXTERN const char * ZEXPORT gzerror(gzFile file, int *errnum);
/*
Return the error message for the last error which occurred on file.
errnum is set to zlib error number. If an error occurred in the file system
and not in the compression library, errnum is set to Z_ERRNO and the
application may consult errno to get the exact error code.
The application must not modify the returned string. Future calls to
this function may invalidate the previously returned string. If file is
closed, then the string previously returned by gzerror will no longer be
available.
gzerror() should be used to distinguish errors from end-of-file for those
functions above that do not distinguish those cases in their return values.
*/
ZEXTERN void ZEXPORT gzclearerr(gzFile file);
/*
Clear the error and end-of-file flags for file. This is analogous to the
clearerr() function in stdio. This is useful for continuing to read a gzip
file that is being written concurrently.
*/
#endif /* !Z_SOLO */
/* checksum functions */
/*
These functions are not related to compression but are exported
anyway because they might be useful in applications using the compression
library.
*/
ZEXTERN uLong ZEXPORT adler32(uLong adler, const Bytef *buf, uInt len);
/*
Update a running Adler-32 checksum with the bytes buf[0..len-1] and
return the updated checksum. An Adler-32 value is in the range of a 32-bit
unsigned integer. If buf is Z_NULL, this function returns the required
initial value for the checksum.
An Adler-32 checksum is almost as reliable as a CRC-32 but can be computed
much faster.
Usage example:
uLong adler = adler32(0L, Z_NULL, 0);
while (read_buffer(buffer, length) != EOF) {
adler = adler32(adler, buffer, length);
}
if (adler != original_adler) error();
*/
ZEXTERN uLong ZEXPORT adler32_z(uLong adler, const Bytef *buf,
z_size_t len);
/*
Same as adler32(), but with a size_t length.
*/
/*
ZEXTERN uLong ZEXPORT adler32_combine(uLong adler1, uLong adler2,
z_off_t len2);
Combine two Adler-32 checksums into one. For two sequences of bytes, seq1
and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for
each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of
seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. Note
that the z_off_t type (like off_t) is a signed integer. If len2 is
negative, the result has no meaning or utility.
*/
ZEXTERN uLong ZEXPORT crc32(uLong crc, const Bytef *buf, uInt len);
/*
Update a running CRC-32 with the bytes buf[0..len-1] and return the
updated CRC-32. A CRC-32 value is in the range of a 32-bit unsigned integer.
If buf is Z_NULL, this function returns the required initial value for the
crc. Pre- and post-conditioning (one's complement) is performed within this
function so it shouldn't be done by the application.
Usage example:
uLong crc = crc32(0L, Z_NULL, 0);
while (read_buffer(buffer, length) != EOF) {
crc = crc32(crc, buffer, length);
}
if (crc != original_crc) error();
*/
ZEXTERN uLong ZEXPORT crc32_z(uLong crc, const Bytef *buf,
z_size_t len);
/*
Same as crc32(), but with a size_t length.
*/
/*
ZEXTERN uLong ZEXPORT crc32_combine(uLong crc1, uLong crc2, z_off_t len2);
Combine two CRC-32 check values into one. For two sequences of bytes,
seq1 and seq2 with lengths len1 and len2, CRC-32 check values were
calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32
check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and
len2.
*/
/*
ZEXTERN uLong ZEXPORT crc32_combine_gen(z_off_t len2);
Return the operator corresponding to length len2, to be used with
crc32_combine_op().
*/
ZEXTERN uLong ZEXPORT crc32_combine_op(uLong crc1, uLong crc2, uLong op);
/*
Give the same result as crc32_combine(), using op in place of len2. op is
is generated from len2 by crc32_combine_gen(). This will be faster than
crc32_combine() if the generated op is used more than once.
*/
/* various hacks, don't look :) */
/* deflateInit and inflateInit are macros to allow checking the zlib version
* and the compiler's view of z_stream:
*/
ZEXTERN int ZEXPORT deflateInit_(z_streamp strm, int level,
const char *version, int stream_size);
ZEXTERN int ZEXPORT inflateInit_(z_streamp strm,
const char *version, int stream_size);
ZEXTERN int ZEXPORT deflateInit2_(z_streamp strm, int level, int method,
int windowBits, int memLevel,
int strategy, const char *version,
int stream_size);
ZEXTERN int ZEXPORT inflateInit2_(z_streamp strm, int windowBits,
const char *version, int stream_size);
ZEXTERN int ZEXPORT inflateBackInit_(z_streamp strm, int windowBits,
unsigned char FAR *window,
const char *version,
int stream_size);
#ifdef Z_PREFIX_SET
# define z_deflateInit(strm, level) \
deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream))
# define z_inflateInit(strm) \
inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream))
# define z_deflateInit2(strm, level, method, windowBits, memLevel, strategy) \
deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\
|
| ︙ | ︙ | |||
1832 1833 1834 1835 1836 1837 1838 |
* only be used by the gzgetc() macro. You have been warned.
*/
struct gzFile_s {
unsigned have;
unsigned char *next;
z_off64_t pos;
};
| | | | | | | | | | 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 |
* only be used by the gzgetc() macro. You have been warned.
*/
struct gzFile_s {
unsigned have;
unsigned char *next;
z_off64_t pos;
};
ZEXTERN int ZEXPORT gzgetc_(gzFile file); /* backward compatibility */
#ifdef Z_PREFIX_SET
# undef z_gzgetc
# define z_gzgetc(g) \
((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : (gzgetc)(g))
#else
# define gzgetc(g) \
((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : (gzgetc)(g))
#endif
/* provide 64-bit offset functions if _LARGEFILE64_SOURCE defined, and/or
* change the regular functions to 64 bits if _FILE_OFFSET_BITS is 64 (if
* both are true, the application gets the *64 functions, and the regular
* functions are changed to 64 bits) -- in case these are set on systems
* without large file support, _LFS64_LARGEFILE must also be true
*/
#ifdef Z_LARGE64
ZEXTERN gzFile ZEXPORT gzopen64(const char *, const char *);
ZEXTERN z_off64_t ZEXPORT gzseek64(gzFile, z_off64_t, int);
ZEXTERN z_off64_t ZEXPORT gztell64(gzFile);
ZEXTERN z_off64_t ZEXPORT gzoffset64(gzFile);
ZEXTERN uLong ZEXPORT adler32_combine64(uLong, uLong, z_off64_t);
ZEXTERN uLong ZEXPORT crc32_combine64(uLong, uLong, z_off64_t);
ZEXTERN uLong ZEXPORT crc32_combine_gen64(z_off64_t);
#endif
#if !defined(ZLIB_INTERNAL) && defined(Z_WANT64)
# ifdef Z_PREFIX_SET
# define z_gzopen z_gzopen64
# define z_gzseek z_gzseek64
# define z_gztell z_gztell64
|
| ︙ | ︙ | |||
1877 1878 1879 1880 1881 1882 1883 | # define gztell gztell64 # define gzoffset gzoffset64 # define adler32_combine adler32_combine64 # define crc32_combine crc32_combine64 # define crc32_combine_gen crc32_combine_gen64 # endif # ifndef Z_LARGE64 | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 |
# define gztell gztell64
# define gzoffset gzoffset64
# define adler32_combine adler32_combine64
# define crc32_combine crc32_combine64
# define crc32_combine_gen crc32_combine_gen64
# endif
# ifndef Z_LARGE64
ZEXTERN gzFile ZEXPORT gzopen64(const char *, const char *);
ZEXTERN z_off_t ZEXPORT gzseek64(gzFile, z_off_t, int);
ZEXTERN z_off_t ZEXPORT gztell64(gzFile);
ZEXTERN z_off_t ZEXPORT gzoffset64(gzFile);
ZEXTERN uLong ZEXPORT adler32_combine64(uLong, uLong, z_off_t);
ZEXTERN uLong ZEXPORT crc32_combine64(uLong, uLong, z_off_t);
ZEXTERN uLong ZEXPORT crc32_combine_gen64(z_off_t);
# endif
#else
ZEXTERN gzFile ZEXPORT gzopen(const char *, const char *);
ZEXTERN z_off_t ZEXPORT gzseek(gzFile, z_off_t, int);
ZEXTERN z_off_t ZEXPORT gztell(gzFile);
ZEXTERN z_off_t ZEXPORT gzoffset(gzFile);
ZEXTERN uLong ZEXPORT adler32_combine(uLong, uLong, z_off_t);
ZEXTERN uLong ZEXPORT crc32_combine(uLong, uLong, z_off_t);
ZEXTERN uLong ZEXPORT crc32_combine_gen(z_off_t);
#endif
#else /* Z_SOLO */
ZEXTERN uLong ZEXPORT adler32_combine(uLong, uLong, z_off_t);
ZEXTERN uLong ZEXPORT crc32_combine(uLong, uLong, z_off_t);
ZEXTERN uLong ZEXPORT crc32_combine_gen(z_off_t);
#endif /* !Z_SOLO */
/* undocumented functions */
ZEXTERN const char * ZEXPORT zError(int);
ZEXTERN int ZEXPORT inflateSyncPoint(z_streamp);
ZEXTERN const z_crc_t FAR * ZEXPORT get_crc_table(void);
ZEXTERN int ZEXPORT inflateUndermine(z_streamp, int);
ZEXTERN int ZEXPORT inflateValidate(z_streamp, int);
ZEXTERN unsigned long ZEXPORT inflateCodesUsed(z_streamp);
ZEXTERN int ZEXPORT inflateResetKeep(z_streamp);
ZEXTERN int ZEXPORT deflateResetKeep(z_streamp);
#if defined(_WIN32) && !defined(Z_SOLO)
ZEXTERN gzFile ZEXPORT gzopen_w(const wchar_t *path,
const char *mode);
#endif
#if defined(STDC) || defined(Z_HAVE_STDARG_H)
# ifndef Z_SOLO
ZEXTERN int ZEXPORTVA gzvprintf(gzFile file,
const char *format,
va_list va);
# endif
#endif
#ifdef __cplusplus
}
#endif
#endif /* ZLIB_H */
|
Deleted compat/zlib/zlib2ansi.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to compat/zlib/zutil.c.
| ︙ | ︙ | |||
20 21 22 23 24 25 26 |
(z_const char *)"insufficient memory", /* Z_MEM_ERROR (-4) */
(z_const char *)"buffer error", /* Z_BUF_ERROR (-5) */
(z_const char *)"incompatible version",/* Z_VERSION_ERROR (-6) */
(z_const char *)""
};
| | < | < | 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
(z_const char *)"insufficient memory", /* Z_MEM_ERROR (-4) */
(z_const char *)"buffer error", /* Z_BUF_ERROR (-5) */
(z_const char *)"incompatible version",/* Z_VERSION_ERROR (-6) */
(z_const char *)""
};
const char * ZEXPORT zlibVersion(void) {
return ZLIB_VERSION;
}
uLong ZEXPORT zlibCompileFlags(void) {
uLong flags;
flags = 0;
switch ((int)(sizeof(uInt))) {
case 2: break;
case 4: flags += 1; break;
case 8: flags += 2; break;
|
| ︙ | ︙ | |||
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
case 4: flags += 1 << 6; break;
case 8: flags += 2 << 6; break;
default: flags += 3 << 6;
}
#ifdef ZLIB_DEBUG
flags += 1 << 8;
#endif
#if defined(ASMV) || defined(ASMINF)
flags += 1 << 9;
#endif
#ifdef ZLIB_WINAPI
flags += 1 << 10;
#endif
#ifdef BUILDFIXED
flags += 1 << 12;
#endif
#ifdef DYNAMIC_CRC_TABLE
| > > | 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
case 4: flags += 1 << 6; break;
case 8: flags += 2 << 6; break;
default: flags += 3 << 6;
}
#ifdef ZLIB_DEBUG
flags += 1 << 8;
#endif
/*
#if defined(ASMV) || defined(ASMINF)
flags += 1 << 9;
#endif
*/
#ifdef ZLIB_WINAPI
flags += 1 << 10;
#endif
#ifdef BUILDFIXED
flags += 1 << 12;
#endif
#ifdef DYNAMIC_CRC_TABLE
|
| ︙ | ︙ | |||
115 116 117 118 119 120 121 | #ifdef ZLIB_DEBUG #include <stdlib.h> # ifndef verbose # define verbose 0 # endif int ZLIB_INTERNAL z_verbose = verbose; | | < < | < < | < < < < | < < < < | < < < | 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 |
#ifdef ZLIB_DEBUG
#include <stdlib.h>
# ifndef verbose
# define verbose 0
# endif
int ZLIB_INTERNAL z_verbose = verbose;
void ZLIB_INTERNAL z_error(char *m) {
fprintf(stderr, "%s\n", m);
exit(1);
}
#endif
/* exported to allow conversion of error code to string for compress() and
* uncompress()
*/
const char * ZEXPORT zError(int err) {
return ERR_MSG(err);
}
#if defined(_WIN32_WCE) && _WIN32_WCE < 0x800
/* The older Microsoft C Run-Time Library for Windows CE doesn't have
* errno. We define it as a global variable to simplify porting.
* Its value is always 0 and should not be used.
*/
int errno = 0;
#endif
#ifndef HAVE_MEMCPY
void ZLIB_INTERNAL zmemcpy(Bytef* dest, const Bytef* source, uInt len) {
if (len == 0) return;
do {
*dest++ = *source++; /* ??? to be unrolled */
} while (--len != 0);
}
int ZLIB_INTERNAL zmemcmp(const Bytef* s1, const Bytef* s2, uInt len) {
uInt j;
for (j = 0; j < len; j++) {
if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1;
}
return 0;
}
void ZLIB_INTERNAL zmemzero(Bytef* dest, uInt len) {
if (len == 0) return;
do {
*dest++ = 0; /* ??? to be unrolled */
} while (--len != 0);
}
#endif
|
| ︙ | ︙ | |||
210 211 212 213 214 215 216 | /* This table is used to remember the original form of pointers * to large buffers (64K). Such pointers are normalized with a zero offset. * Since MSDOS is not a preemptive multitasking OS, this table is not * protected from concurrent access. This hack doesn't work anyway on * a protected system like OS/2. Use Microsoft C instead. */ | | < | 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 |
/* This table is used to remember the original form of pointers
* to large buffers (64K). Such pointers are normalized with a zero offset.
* Since MSDOS is not a preemptive multitasking OS, this table is not
* protected from concurrent access. This hack doesn't work anyway on
* a protected system like OS/2. Use Microsoft C instead.
*/
voidpf ZLIB_INTERNAL zcalloc(voidpf opaque, unsigned items, unsigned size) {
voidpf buf;
ulg bsize = (ulg)items*size;
(void)opaque;
/* If we allocate less than 65520 bytes, we assume that farmalloc
* will return a usable pointer which doesn't have to be normalized.
|
| ︙ | ︙ | |||
236 237 238 239 240 241 242 |
/* Normalize the pointer to seg:0 */
*((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4;
*(ush*)&buf = 0;
table[next_ptr++].new_ptr = buf;
return buf;
}
| | < | 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 |
/* Normalize the pointer to seg:0 */
*((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4;
*(ush*)&buf = 0;
table[next_ptr++].new_ptr = buf;
return buf;
}
void ZLIB_INTERNAL zcfree(voidpf opaque, voidpf ptr) {
int n;
(void)opaque;
if (*(ush*)&ptr != 0) { /* object < 64K */
farfree(ptr);
return;
|
| ︙ | ︙ | |||
273 274 275 276 277 278 279 | # define MY_ZCALLOC #if (!defined(_MSC_VER) || (_MSC_VER <= 600)) # define _halloc halloc # define _hfree hfree #endif | | < | < | | | | < < < < | < < < | 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 |
# define MY_ZCALLOC
#if (!defined(_MSC_VER) || (_MSC_VER <= 600))
# define _halloc halloc
# define _hfree hfree
#endif
voidpf ZLIB_INTERNAL zcalloc(voidpf opaque, uInt items, uInt size) {
(void)opaque;
return _halloc((long)items, size);
}
void ZLIB_INTERNAL zcfree(voidpf opaque, voidpf ptr) {
(void)opaque;
_hfree(ptr);
}
#endif /* M_I86 */
#endif /* SYS16BIT */
#ifndef MY_ZCALLOC /* Any system without a special alloc function */
#ifndef STDC
extern voidp malloc(uInt size);
extern voidp calloc(uInt items, uInt size);
extern void free(voidpf ptr);
#endif
voidpf ZLIB_INTERNAL zcalloc(voidpf opaque, unsigned items, unsigned size) {
(void)opaque;
return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) :
(voidpf)calloc(items, size);
}
void ZLIB_INTERNAL zcfree(voidpf opaque, voidpf ptr) {
(void)opaque;
free(ptr);
}
#endif /* MY_ZCALLOC */
#endif /* !Z_SOLO */
|
Changes to compat/zlib/zutil.h.
| ︙ | ︙ | |||
187 188 189 190 191 192 193 |
#pragma warn -8008
#pragma warn -8066
#endif
/* provide prototypes for these when building zlib without LFS */
#if !defined(_WIN32) && \
(!defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0)
| | > | | 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 |
#pragma warn -8008
#pragma warn -8066
#endif
/* provide prototypes for these when building zlib without LFS */
#if !defined(_WIN32) && \
(!defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0)
ZEXTERN uLong ZEXPORT adler32_combine64(uLong, uLong, z_off_t);
ZEXTERN uLong ZEXPORT crc32_combine64(uLong, uLong, z_off_t);
ZEXTERN uLong ZEXPORT crc32_combine_gen64(z_off_t);
#endif
/* common defaults */
#ifndef OS_CODE
# define OS_CODE 3 /* assume Unix */
#endif
|
| ︙ | ︙ | |||
227 228 229 230 231 232 233 | # define zmemzero(dest, len) _fmemset(dest, 0, len) # else # define zmemcpy memcpy # define zmemcmp memcmp # define zmemzero(dest, len) memset(dest, 0, len) # endif #else | | | | | | | | | 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 |
# define zmemzero(dest, len) _fmemset(dest, 0, len)
# else
# define zmemcpy memcpy
# define zmemcmp memcmp
# define zmemzero(dest, len) memset(dest, 0, len)
# endif
#else
void ZLIB_INTERNAL zmemcpy(Bytef* dest, const Bytef* source, uInt len);
int ZLIB_INTERNAL zmemcmp(const Bytef* s1, const Bytef* s2, uInt len);
void ZLIB_INTERNAL zmemzero(Bytef* dest, uInt len);
#endif
/* Diagnostic functions */
#ifdef ZLIB_DEBUG
# include <stdio.h>
extern int ZLIB_INTERNAL z_verbose;
extern void ZLIB_INTERNAL z_error(char *m);
# define Assert(cond,msg) {if(!(cond)) z_error(msg);}
# define Trace(x) {if (z_verbose>=0) fprintf x ;}
# define Tracev(x) {if (z_verbose>0) fprintf x ;}
# define Tracevv(x) {if (z_verbose>1) fprintf x ;}
# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;}
# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;}
#else
# define Assert(cond,msg)
# define Trace(x)
# define Tracev(x)
# define Tracevv(x)
# define Tracec(c,x)
# define Tracecv(c,x)
#endif
#ifndef Z_SOLO
voidpf ZLIB_INTERNAL zcalloc(voidpf opaque, unsigned items,
unsigned size);
void ZLIB_INTERNAL zcfree(voidpf opaque, voidpf ptr);
#endif
#define ZALLOC(strm, items, size) \
(*((strm)->zalloc))((strm)->opaque, (items), (size))
#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr))
#define TRY_FREE(s, p) {if (p) ZFREE(s, p);}
/* Reverse the bytes in a 32-bit value */
#define ZSWAP32(q) ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \
(((q) & 0xff00) << 8) + (((q) & 0xff) << 24))
#endif /* ZUTIL_H */
|
Deleted containers/Dockerfile-nojail.patch.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted containers/busybox-config.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to extsrc/cson_amalgamation.c.
| ︙ | ︙ | |||
5387 5388 5389 5390 5391 5392 5393 |
cson_value * rootV = NULL;
cson_object * root = NULL;
cson_string * colName = NULL;
int i = 0;
int rc = 0;
cson_value * currentValue = NULL;
int const colCount = sqlite3_column_count(st);
| | | 5387 5388 5389 5390 5391 5392 5393 5394 5395 5396 5397 5398 5399 5400 5401 |
cson_value * rootV = NULL;
cson_object * root = NULL;
cson_string * colName = NULL;
int i = 0;
int rc = 0;
cson_value * currentValue = NULL;
int const colCount = sqlite3_column_count(st);
if( !colCount || (colCount>(int)cson_array_length_get(colNames)) ) {
return NULL;
}
rootV = cson_value_new_object();
if(!rootV) return NULL;
root = cson_value_get_object(rootV);
for( i = 0; i < colCount; ++i )
{
|
| ︙ | ︙ |
Changes to extsrc/pikchr.c.
| ︙ | ︙ | |||
57 58 59 60 61 62 63 | ** ** lemon pikchr.y ** cc pikchr.c -o pikchr.o ** ** Add -DPIKCHR_SHELL to add a main() routine that reads input files ** and sends them through Pikchr, for testing. Add -DPIKCHR_FUZZ for ** -fsanitizer=fuzzer testing. | | | 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | ** ** lemon pikchr.y ** cc pikchr.c -o pikchr.o ** ** Add -DPIKCHR_SHELL to add a main() routine that reads input files ** and sends them through Pikchr, for testing. Add -DPIKCHR_FUZZ for ** -fsanitizer=fuzzer testing. ** **************************************************************************** ** IMPLEMENTATION NOTES (for people who want to understand the internal ** operation of this software, perhaps to extend the code or to fix bugs): ** ** Each call to pikchr() uses a single instance of the Pik structure to ** track its internal state. The Pik structure lives for the duration ** of the pikchr() call. |
| ︙ | ︙ | |||
201 202 203 204 205 206 207 | #define TP_VMASK 0x007c /* Mask for text positioning flags */ #define TP_BIG 0x0100 /* Larger font */ #define TP_SMALL 0x0200 /* Smaller font */ #define TP_XTRA 0x0400 /* Amplify TP_BIG or TP_SMALL */ #define TP_SZMASK 0x0700 /* Font size mask */ #define TP_ITALIC 0x1000 /* Italic font */ #define TP_BOLD 0x2000 /* Bold font */ | > | | | 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 |
#define TP_VMASK 0x007c /* Mask for text positioning flags */
#define TP_BIG 0x0100 /* Larger font */
#define TP_SMALL 0x0200 /* Smaller font */
#define TP_XTRA 0x0400 /* Amplify TP_BIG or TP_SMALL */
#define TP_SZMASK 0x0700 /* Font size mask */
#define TP_ITALIC 0x1000 /* Italic font */
#define TP_BOLD 0x2000 /* Bold font */
#define TP_MONO 0x4000 /* Monospace font family */
#define TP_FMASK 0x7000 /* Mask for font style */
#define TP_ALIGN 0x8000 /* Rotate to align with the line */
/* An object to hold a position in 2-D space */
struct PPoint {
PNum x, y; /* X and Y coordinates */
};
static const PPoint cZeroPoint = {0.0,0.0};
|
| ︙ | ︙ | |||
468 469 470 471 472 473 474 | static int pik_bbox_isempty(PBox*); 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); | | | | 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 | static int pik_bbox_isempty(PBox*); 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*,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 521 "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 |
| ︙ | ︙ | |||
562 563 564 565 566 567 568 | #define T_CENTER 64 #define T_LJUST 65 #define T_RJUST 66 #define T_ABOVE 67 #define T_BELOW 68 #define T_ITALIC 69 #define T_BOLD 70 | > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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 | #define T_CENTER 64 #define T_LJUST 65 #define T_RJUST 66 #define T_ABOVE 67 #define T_BELOW 68 #define T_ITALIC 69 #define T_BOLD 70 #define T_MONO 71 #define T_ALIGNED 72 #define T_BIG 73 #define T_SMALL 74 #define T_AND 75 #define T_LT 76 #define T_GT 77 #define T_ON 78 #define T_WAY 79 #define T_BETWEEN 80 #define T_THE 81 #define T_NTH 82 #define T_VERTEX 83 #define T_TOP 84 #define T_BOTTOM 85 #define T_START 86 #define T_END 87 #define T_IN 88 #define T_THIS 89 #define T_DOT_U 90 #define T_LAST 91 #define T_NUMBER 92 #define T_FUNC1 93 #define T_FUNC2 94 #define T_DIST 95 #define T_DOT_XY 96 #define T_X 97 #define T_Y 98 #define T_DOT_L 99 #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. |
| ︙ | ︙ | |||
649 650 651 652 653 654 655 | ** YY_MAX_REDUCE Maximum value for reduce actions */ #ifndef INTERFACE # define INTERFACE 1 #endif /************* Begin control #defines *****************************************/ #define YYCODETYPE unsigned char | | > > | | < < | | | | 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 |
** YY_MAX_REDUCE Maximum value for reduce actions
*/
#ifndef INTERFACE
# define INTERFACE 1
#endif
/************* Begin control #defines *****************************************/
#define YYCODETYPE unsigned char
#define YYNOCODE 136
#define YYACTIONTYPE unsigned short int
#define pik_parserTOKENTYPE PToken
typedef union {
int yyinit;
pik_parserTOKENTYPE yy0;
PNum yy21;
PPoint yy63;
PRel yy72;
PObj* yy162;
short int yy188;
PList* yy235;
} YYMINORTYPE;
#ifndef YYSTACKDEPTH
#define YYSTACKDEPTH 100
#endif
#define pik_parserARG_SDECL
#define pik_parserARG_PDECL
#define pik_parserARG_PARAM
#define pik_parserARG_FETCH
#define pik_parserARG_STORE
#define pik_parserCTX_SDECL Pik *p;
#define pik_parserCTX_PDECL ,Pik *p
#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 100
#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
|
| ︙ | ︙ | |||
754 755 756 757 758 759 760 | ** 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 **********************************************/ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | < > | | | | | | | | | < | | | | > > > | | | | | | < < < | | | | > | | | < | | > | | | | | | | | | | | | | | | | > > | | | | > > > | | | | | | | > | | | | | | | | | | | | < < | | | | < | < | | | | < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | < | > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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 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 |
** 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 (1313)
static const YYACTIONTYPE yy_action[] = {
/* 0 */ 575, 495, 161, 119, 25, 452, 29, 74, 129, 148,
/* 10 */ 575, 492, 161, 119, 453, 113, 120, 161, 119, 530,
/* 20 */ 427, 428, 339, 559, 81, 30, 560, 561, 575, 64,
/* 30 */ 63, 62, 61, 322, 323, 9, 8, 33, 149, 32,
/* 40 */ 7, 71, 127, 38, 335, 66, 48, 37, 28, 339,
/* 50 */ 339, 339, 339, 425, 426, 340, 341, 342, 343, 344,
/* 60 */ 345, 346, 347, 348, 474, 528, 161, 119, 577, 77,
/* 70 */ 577, 73, 306, 148, 474, 533, 161, 119, 112, 113,
/* 80 */ 120, 161, 119, 128, 427, 428, 339, 31, 81, 531,
/* 90 */ 161, 119, 474, 35, 330, 378, 158, 322, 323, 9,
/* 100 */ 8, 33, 149, 32, 7, 71, 127, 328, 335, 66,
/* 110 */ 579, 378, 158, 339, 339, 339, 339, 425, 426, 340,
/* 120 */ 341, 342, 343, 344, 345, 346, 347, 348, 394, 435,
/* 130 */ 46, 59, 60, 64, 63, 62, 61, 357, 36, 376,
/* 140 */ 54, 51, 2, 47, 403, 13, 297, 411, 412, 413,
/* 150 */ 414, 80, 162, 308, 79, 133, 310, 126, 441, 440,
/* 160 */ 118, 123, 83, 404, 405, 406, 408, 80, 84, 308,
/* 170 */ 79, 299, 411, 412, 413, 414, 118, 69, 350, 350,
/* 180 */ 350, 350, 350, 350, 350, 350, 350, 350, 350, 62,
/* 190 */ 61, 434, 64, 63, 62, 61, 313, 398, 399, 427,
/* 200 */ 428, 339, 380, 157, 64, 63, 62, 61, 122, 106,
/* 210 */ 535, 436, 437, 438, 439, 298, 375, 391, 117, 393,
/* 220 */ 155, 154, 153, 394, 435, 49, 59, 60, 339, 339,
/* 230 */ 339, 339, 425, 426, 376, 3, 4, 2, 64, 63,
/* 240 */ 62, 61, 156, 156, 156, 394, 379, 159, 59, 60,
/* 250 */ 76, 67, 535, 441, 440, 5, 102, 6, 535, 42,
/* 260 */ 131, 535, 69, 107, 301, 302, 303, 394, 305, 15,
/* 270 */ 59, 60, 120, 161, 119, 446, 463, 424, 376, 423,
/* 280 */ 1, 42, 397, 78, 78, 36, 434, 11, 394, 435,
/* 290 */ 356, 59, 60, 12, 152, 139, 432, 14, 16, 376,
/* 300 */ 18, 65, 2, 138, 106, 430, 436, 437, 438, 439,
/* 310 */ 44, 375, 19, 117, 393, 155, 154, 153, 441, 440,
/* 320 */ 142, 140, 64, 63, 62, 61, 106, 20, 68, 376,
/* 330 */ 359, 107, 23, 375, 45, 117, 393, 155, 154, 153,
/* 340 */ 120, 161, 119, 55, 463, 114, 26, 57, 106, 147,
/* 350 */ 146, 434, 569, 58, 392, 375, 43, 117, 393, 155,
/* 360 */ 154, 153, 152, 384, 64, 63, 62, 61, 382, 106,
/* 370 */ 383, 436, 437, 438, 439, 377, 375, 70, 117, 393,
/* 380 */ 155, 154, 153, 160, 39, 22, 21, 445, 142, 140,
/* 390 */ 64, 63, 62, 61, 24, 17, 145, 141, 431, 108,
/* 400 */ 445, 445, 445, 391, 445, 445, 375, 445, 117, 445,
/* 410 */ 445, 55, 74, 445, 148, 445, 445, 147, 146, 124,
/* 420 */ 113, 120, 161, 119, 43, 445, 445, 142, 140, 64,
/* 430 */ 63, 62, 61, 445, 394, 445, 445, 59, 60, 64,
/* 440 */ 63, 62, 61, 149, 445, 376, 445, 445, 42, 445,
/* 450 */ 55, 445, 391, 22, 21, 445, 147, 146, 445, 445,
/* 460 */ 52, 445, 24, 43, 145, 141, 431, 394, 445, 445,
/* 470 */ 59, 60, 64, 63, 62, 61, 445, 445, 376, 132,
/* 480 */ 130, 42, 445, 445, 445, 355, 156, 156, 156, 445,
/* 490 */ 445, 445, 22, 21, 445, 394, 473, 445, 59, 60,
/* 500 */ 445, 24, 445, 145, 141, 431, 376, 445, 107, 42,
/* 510 */ 64, 63, 62, 61, 445, 106, 445, 120, 161, 119,
/* 520 */ 445, 478, 375, 354, 117, 393, 155, 154, 153, 445,
/* 530 */ 394, 143, 473, 59, 60, 64, 63, 62, 61, 152,
/* 540 */ 445, 376, 445, 445, 42, 445, 445, 445, 106, 64,
/* 550 */ 63, 62, 61, 445, 445, 375, 50, 117, 393, 155,
/* 560 */ 154, 153, 445, 394, 144, 445, 59, 60, 445, 445,
/* 570 */ 53, 72, 445, 148, 376, 445, 106, 42, 125, 113,
/* 580 */ 120, 161, 119, 375, 445, 117, 393, 155, 154, 153,
/* 590 */ 394, 445, 445, 59, 60, 445, 445, 445, 445, 445,
/* 600 */ 445, 102, 149, 445, 42, 445, 74, 445, 148, 445,
/* 610 */ 445, 106, 445, 497, 113, 120, 161, 119, 375, 445,
/* 620 */ 117, 393, 155, 154, 153, 394, 445, 445, 59, 60,
/* 630 */ 445, 445, 88, 445, 445, 445, 376, 149, 445, 40,
/* 640 */ 445, 120, 161, 119, 106, 445, 445, 435, 110, 110,
/* 650 */ 445, 375, 445, 117, 393, 155, 154, 153, 394, 445,
/* 660 */ 445, 59, 60, 152, 85, 445, 445, 445, 445, 376,
/* 670 */ 445, 106, 41, 120, 161, 119, 441, 440, 375, 445,
/* 680 */ 117, 393, 155, 154, 153, 448, 454, 29, 445, 445,
/* 690 */ 74, 450, 148, 75, 88, 152, 445, 496, 113, 120,
/* 700 */ 161, 119, 163, 120, 161, 119, 106, 27, 445, 434,
/* 710 */ 111, 111, 445, 375, 445, 117, 393, 155, 154, 153,
/* 720 */ 445, 149, 445, 445, 445, 152, 74, 445, 148, 436,
/* 730 */ 437, 438, 439, 490, 113, 120, 161, 119, 445, 106,
/* 740 */ 121, 447, 454, 29, 445, 445, 375, 450, 117, 393,
/* 750 */ 155, 154, 153, 445, 445, 445, 445, 149, 163, 74,
/* 760 */ 445, 148, 444, 27, 445, 445, 484, 113, 120, 161,
/* 770 */ 119, 445, 445, 445, 74, 445, 148, 445, 445, 445,
/* 780 */ 445, 483, 113, 120, 161, 119, 74, 445, 148, 86,
/* 790 */ 149, 445, 445, 480, 113, 120, 161, 119, 120, 161,
/* 800 */ 119, 445, 74, 445, 148, 149, 445, 445, 445, 134,
/* 810 */ 113, 120, 161, 119, 74, 445, 148, 149, 445, 445,
/* 820 */ 152, 517, 113, 120, 161, 119, 88, 64, 63, 62,
/* 830 */ 61, 445, 445, 149, 445, 120, 161, 119, 445, 74,
/* 840 */ 396, 148, 475, 445, 445, 149, 137, 113, 120, 161,
/* 850 */ 119, 74, 445, 148, 445, 445, 445, 152, 525, 113,
/* 860 */ 120, 161, 119, 445, 74, 445, 148, 445, 445, 445,
/* 870 */ 149, 527, 113, 120, 161, 119, 445, 445, 445, 74,
/* 880 */ 445, 148, 149, 445, 445, 445, 524, 113, 120, 161,
/* 890 */ 119, 74, 445, 148, 98, 149, 445, 445, 526, 113,
/* 900 */ 120, 161, 119, 120, 161, 119, 445, 74, 445, 148,
/* 910 */ 149, 445, 445, 445, 523, 113, 120, 161, 119, 74,
/* 920 */ 445, 148, 149, 445, 445, 152, 522, 113, 120, 161,
/* 930 */ 119, 89, 64, 63, 62, 61, 445, 445, 149, 445,
/* 940 */ 120, 161, 119, 445, 74, 395, 148, 445, 445, 445,
/* 950 */ 149, 521, 113, 120, 161, 119, 74, 445, 148, 445,
/* 960 */ 445, 445, 152, 520, 113, 120, 161, 119, 445, 74,
/* 970 */ 445, 148, 445, 445, 445, 149, 519, 113, 120, 161,
/* 980 */ 119, 445, 445, 445, 74, 445, 148, 149, 445, 445,
/* 990 */ 445, 150, 113, 120, 161, 119, 74, 445, 148, 90,
/* 1000 */ 149, 445, 445, 151, 113, 120, 161, 119, 120, 161,
/* 1010 */ 119, 445, 74, 445, 148, 149, 445, 435, 445, 136,
/* 1020 */ 113, 120, 161, 119, 74, 445, 148, 149, 445, 445,
/* 1030 */ 152, 135, 113, 120, 161, 119, 64, 63, 62, 61,
/* 1040 */ 445, 445, 445, 149, 445, 445, 441, 440, 445, 88,
/* 1050 */ 445, 445, 445, 445, 445, 149, 445, 56, 120, 161,
/* 1060 */ 119, 88, 445, 445, 10, 479, 479, 445, 445, 445,
/* 1070 */ 120, 161, 119, 445, 445, 445, 445, 82, 445, 434,
/* 1080 */ 152, 445, 445, 445, 466, 445, 34, 109, 447, 454,
/* 1090 */ 29, 445, 152, 445, 450, 445, 445, 445, 107, 436,
/* 1100 */ 437, 438, 439, 87, 445, 163, 445, 120, 161, 119,
/* 1110 */ 27, 451, 120, 161, 119, 99, 445, 64, 63, 62,
/* 1120 */ 61, 445, 100, 445, 120, 161, 119, 101, 445, 152,
/* 1130 */ 391, 120, 161, 119, 152, 445, 120, 161, 119, 91,
/* 1140 */ 445, 445, 445, 445, 445, 445, 152, 445, 120, 161,
/* 1150 */ 119, 103, 445, 152, 92, 445, 445, 445, 152, 445,
/* 1160 */ 120, 161, 119, 120, 161, 119, 93, 445, 445, 104,
/* 1170 */ 152, 445, 445, 445, 445, 120, 161, 119, 120, 161,
/* 1180 */ 119, 445, 152, 445, 94, 152, 445, 445, 445, 445,
/* 1190 */ 445, 445, 105, 120, 161, 119, 445, 152, 445, 95,
/* 1200 */ 152, 120, 161, 119, 445, 445, 445, 96, 120, 161,
/* 1210 */ 119, 445, 445, 445, 445, 152, 120, 161, 119, 445,
/* 1220 */ 445, 445, 445, 152, 445, 445, 445, 445, 445, 445,
/* 1230 */ 152, 97, 445, 445, 549, 445, 445, 548, 152, 445,
/* 1240 */ 120, 161, 119, 120, 161, 119, 120, 161, 119, 445,
/* 1250 */ 445, 445, 445, 445, 445, 445, 445, 445, 445, 445,
/* 1260 */ 445, 445, 152, 547, 445, 152, 546, 445, 152, 115,
/* 1270 */ 445, 445, 120, 161, 119, 120, 161, 119, 120, 161,
/* 1280 */ 119, 116, 445, 445, 445, 445, 445, 445, 445, 445,
/* 1290 */ 120, 161, 119, 445, 152, 445, 445, 152, 445, 445,
/* 1300 */ 152, 445, 445, 445, 445, 445, 445, 445, 445, 445,
/* 1310 */ 445, 445, 152,
};
static const YYCODETYPE yy_lookahead[] = {
/* 0 */ 0, 113, 114, 115, 134, 102, 103, 104, 106, 106,
/* 10 */ 10, 113, 114, 115, 111, 112, 113, 114, 115, 106,
/* 20 */ 20, 21, 22, 105, 24, 126, 108, 109, 28, 4,
/* 30 */ 5, 6, 7, 33, 34, 35, 36, 37, 135, 39,
/* 40 */ 40, 41, 42, 105, 44, 45, 108, 109, 107, 49,
/* 50 */ 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
/* 60 */ 60, 61, 62, 63, 0, 113, 114, 115, 130, 131,
/* 70 */ 132, 104, 25, 106, 10, 113, 114, 115, 111, 112,
/* 80 */ 113, 114, 115, 106, 20, 21, 22, 128, 24, 113,
/* 90 */ 114, 115, 28, 129, 2, 26, 27, 33, 34, 35,
/* 100 */ 36, 37, 135, 39, 40, 41, 42, 2, 44, 45,
/* 110 */ 133, 26, 27, 49, 50, 51, 52, 53, 54, 55,
/* 120 */ 56, 57, 58, 59, 60, 61, 62, 63, 1, 2,
/* 130 */ 38, 4, 5, 4, 5, 6, 7, 17, 10, 12,
/* 140 */ 4, 5, 15, 38, 1, 25, 17, 29, 30, 31,
/* 150 */ 32, 24, 83, 26, 27, 12, 28, 14, 31, 32,
/* 160 */ 91, 18, 116, 20, 21, 22, 23, 24, 116, 26,
/* 170 */ 27, 19, 29, 30, 31, 32, 91, 3, 64, 65,
/* 180 */ 66, 67, 68, 69, 70, 71, 72, 73, 74, 6,
/* 190 */ 7, 64, 4, 5, 6, 7, 8, 97, 98, 20,
/* 200 */ 21, 22, 26, 27, 4, 5, 6, 7, 1, 82,
/* 210 */ 48, 84, 85, 86, 87, 17, 89, 17, 91, 92,
/* 220 */ 93, 94, 95, 1, 2, 25, 4, 5, 49, 50,
/* 230 */ 51, 52, 53, 54, 12, 16, 15, 15, 4, 5,
/* 240 */ 6, 7, 20, 21, 22, 1, 26, 27, 4, 5,
/* 250 */ 48, 43, 90, 31, 32, 40, 12, 40, 96, 15,
/* 260 */ 47, 99, 88, 104, 20, 21, 22, 1, 24, 35,
/* 270 */ 4, 5, 113, 114, 115, 0, 117, 41, 12, 41,
/* 280 */ 13, 15, 17, 124, 125, 10, 64, 25, 1, 2,
/* 290 */ 17, 4, 5, 75, 135, 81, 80, 3, 3, 12,
/* 300 */ 3, 99, 15, 79, 82, 80, 84, 85, 86, 87,
/* 310 */ 38, 89, 3, 91, 92, 93, 94, 95, 31, 32,
/* 320 */ 2, 3, 4, 5, 6, 7, 82, 3, 3, 12,
/* 330 */ 77, 104, 25, 89, 16, 91, 92, 93, 94, 95,
/* 340 */ 113, 114, 115, 25, 117, 96, 15, 15, 82, 31,
/* 350 */ 32, 64, 125, 15, 17, 89, 38, 91, 92, 93,
/* 360 */ 94, 95, 135, 28, 4, 5, 6, 7, 28, 82,
/* 370 */ 28, 84, 85, 86, 87, 12, 89, 3, 91, 92,
/* 380 */ 93, 94, 95, 90, 11, 67, 68, 136, 2, 3,
/* 390 */ 4, 5, 6, 7, 76, 35, 78, 79, 80, 82,
/* 400 */ 136, 136, 136, 17, 136, 136, 89, 136, 91, 136,
/* 410 */ 136, 25, 104, 136, 106, 136, 136, 31, 32, 111,
/* 420 */ 112, 113, 114, 115, 38, 136, 136, 2, 3, 4,
/* 430 */ 5, 6, 7, 136, 1, 136, 136, 4, 5, 4,
/* 440 */ 5, 6, 7, 135, 136, 12, 136, 136, 15, 136,
/* 450 */ 25, 136, 17, 67, 68, 136, 31, 32, 136, 136,
/* 460 */ 25, 136, 76, 38, 78, 79, 80, 1, 136, 136,
/* 470 */ 4, 5, 4, 5, 6, 7, 136, 136, 12, 46,
/* 480 */ 47, 15, 136, 136, 136, 17, 20, 21, 22, 136,
/* 490 */ 136, 136, 67, 68, 136, 1, 2, 136, 4, 5,
/* 500 */ 136, 76, 136, 78, 79, 80, 12, 136, 104, 15,
/* 510 */ 4, 5, 6, 7, 136, 82, 136, 113, 114, 115,
/* 520 */ 136, 117, 89, 17, 91, 92, 93, 94, 95, 136,
/* 530 */ 1, 2, 38, 4, 5, 4, 5, 6, 7, 135,
/* 540 */ 136, 12, 136, 136, 15, 136, 136, 136, 82, 4,
/* 550 */ 5, 6, 7, 136, 136, 89, 25, 91, 92, 93,
/* 560 */ 94, 95, 136, 1, 2, 136, 4, 5, 136, 136,
/* 570 */ 25, 104, 136, 106, 12, 136, 82, 15, 111, 112,
/* 580 */ 113, 114, 115, 89, 136, 91, 92, 93, 94, 95,
/* 590 */ 1, 136, 136, 4, 5, 136, 136, 136, 136, 136,
/* 600 */ 136, 12, 135, 136, 15, 136, 104, 136, 106, 136,
/* 610 */ 136, 82, 136, 111, 112, 113, 114, 115, 89, 136,
/* 620 */ 91, 92, 93, 94, 95, 1, 136, 136, 4, 5,
/* 630 */ 136, 136, 104, 136, 136, 136, 12, 135, 136, 15,
/* 640 */ 136, 113, 114, 115, 82, 136, 136, 2, 120, 121,
/* 650 */ 136, 89, 136, 91, 92, 93, 94, 95, 1, 136,
/* 660 */ 136, 4, 5, 135, 104, 136, 136, 136, 136, 12,
/* 670 */ 136, 82, 15, 113, 114, 115, 31, 32, 89, 136,
/* 680 */ 91, 92, 93, 94, 95, 101, 102, 103, 136, 136,
/* 690 */ 104, 107, 106, 48, 104, 135, 136, 111, 112, 113,
/* 700 */ 114, 115, 118, 113, 114, 115, 82, 123, 136, 64,
/* 710 */ 120, 121, 136, 89, 136, 91, 92, 93, 94, 95,
/* 720 */ 136, 135, 136, 136, 136, 135, 104, 136, 106, 84,
/* 730 */ 85, 86, 87, 111, 112, 113, 114, 115, 136, 82,
/* 740 */ 100, 101, 102, 103, 136, 136, 89, 107, 91, 92,
/* 750 */ 93, 94, 95, 136, 136, 136, 136, 135, 118, 104,
/* 760 */ 136, 106, 122, 123, 136, 136, 111, 112, 113, 114,
/* 770 */ 115, 136, 136, 136, 104, 136, 106, 136, 136, 136,
/* 780 */ 136, 111, 112, 113, 114, 115, 104, 136, 106, 104,
/* 790 */ 135, 136, 136, 111, 112, 113, 114, 115, 113, 114,
/* 800 */ 115, 136, 104, 136, 106, 135, 136, 136, 136, 111,
/* 810 */ 112, 113, 114, 115, 104, 136, 106, 135, 136, 136,
/* 820 */ 135, 111, 112, 113, 114, 115, 104, 4, 5, 6,
/* 830 */ 7, 136, 136, 135, 136, 113, 114, 115, 136, 104,
/* 840 */ 17, 106, 120, 136, 136, 135, 111, 112, 113, 114,
/* 850 */ 115, 104, 136, 106, 136, 136, 136, 135, 111, 112,
/* 860 */ 113, 114, 115, 136, 104, 136, 106, 136, 136, 136,
/* 870 */ 135, 111, 112, 113, 114, 115, 136, 136, 136, 104,
/* 880 */ 136, 106, 135, 136, 136, 136, 111, 112, 113, 114,
/* 890 */ 115, 104, 136, 106, 104, 135, 136, 136, 111, 112,
/* 900 */ 113, 114, 115, 113, 114, 115, 136, 104, 136, 106,
/* 910 */ 135, 136, 136, 136, 111, 112, 113, 114, 115, 104,
/* 920 */ 136, 106, 135, 136, 136, 135, 111, 112, 113, 114,
/* 930 */ 115, 104, 4, 5, 6, 7, 136, 136, 135, 136,
/* 940 */ 113, 114, 115, 136, 104, 17, 106, 136, 136, 136,
/* 950 */ 135, 111, 112, 113, 114, 115, 104, 136, 106, 136,
/* 960 */ 136, 136, 135, 111, 112, 113, 114, 115, 136, 104,
/* 970 */ 136, 106, 136, 136, 136, 135, 111, 112, 113, 114,
/* 980 */ 115, 136, 136, 136, 104, 136, 106, 135, 136, 136,
/* 990 */ 136, 111, 112, 113, 114, 115, 104, 136, 106, 104,
/* 1000 */ 135, 136, 136, 111, 112, 113, 114, 115, 113, 114,
/* 1010 */ 115, 136, 104, 136, 106, 135, 136, 2, 136, 111,
/* 1020 */ 112, 113, 114, 115, 104, 136, 106, 135, 136, 136,
/* 1030 */ 135, 111, 112, 113, 114, 115, 4, 5, 6, 7,
/* 1040 */ 136, 136, 136, 135, 136, 136, 31, 32, 136, 104,
/* 1050 */ 136, 136, 136, 136, 136, 135, 136, 25, 113, 114,
/* 1060 */ 115, 104, 136, 136, 119, 120, 121, 136, 136, 136,
/* 1070 */ 113, 114, 115, 136, 136, 136, 136, 120, 136, 64,
/* 1080 */ 135, 136, 136, 136, 127, 136, 129, 100, 101, 102,
/* 1090 */ 103, 136, 135, 136, 107, 136, 136, 136, 104, 84,
/* 1100 */ 85, 86, 87, 104, 136, 118, 136, 113, 114, 115,
/* 1110 */ 123, 117, 113, 114, 115, 104, 136, 4, 5, 6,
/* 1120 */ 7, 136, 104, 136, 113, 114, 115, 104, 136, 135,
/* 1130 */ 17, 113, 114, 115, 135, 136, 113, 114, 115, 104,
/* 1140 */ 136, 136, 136, 136, 136, 136, 135, 136, 113, 114,
/* 1150 */ 115, 104, 136, 135, 104, 136, 136, 136, 135, 136,
/* 1160 */ 113, 114, 115, 113, 114, 115, 104, 136, 136, 104,
/* 1170 */ 135, 136, 136, 136, 136, 113, 114, 115, 113, 114,
/* 1180 */ 115, 136, 135, 136, 104, 135, 136, 136, 136, 136,
/* 1190 */ 136, 136, 104, 113, 114, 115, 136, 135, 136, 104,
/* 1200 */ 135, 113, 114, 115, 136, 136, 136, 104, 113, 114,
/* 1210 */ 115, 136, 136, 136, 136, 135, 113, 114, 115, 136,
/* 1220 */ 136, 136, 136, 135, 136, 136, 136, 136, 136, 136,
/* 1230 */ 135, 104, 136, 136, 104, 136, 136, 104, 135, 136,
/* 1240 */ 113, 114, 115, 113, 114, 115, 113, 114, 115, 136,
/* 1250 */ 136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
/* 1260 */ 136, 136, 135, 104, 136, 135, 104, 136, 135, 104,
/* 1270 */ 136, 136, 113, 114, 115, 113, 114, 115, 113, 114,
/* 1280 */ 115, 104, 136, 136, 136, 136, 136, 136, 136, 136,
/* 1290 */ 113, 114, 115, 136, 135, 136, 136, 135, 136, 136,
/* 1300 */ 135, 136, 136, 136, 136, 136, 136, 136, 136, 136,
/* 1310 */ 136, 136, 135, 100, 100, 100, 100, 100, 100, 100,
/* 1320 */ 100, 100, 100, 100, 100, 100, 100, 100, 100, 100,
/* 1330 */ 100, 100, 100, 100, 100, 100, 100, 100, 100, 100,
/* 1340 */ 100, 100, 100, 100, 100, 100, 100, 100, 100, 100,
/* 1350 */ 100, 100, 100, 100, 100, 100, 100, 100, 100, 100,
/* 1360 */ 100, 100, 100, 100, 100, 100, 100, 100, 100, 100,
/* 1370 */ 100, 100, 100, 100, 100, 100, 100, 100, 100, 100,
/* 1380 */ 100, 100, 100, 100, 100, 100, 100, 100, 100, 100,
/* 1390 */ 100, 100, 100, 100, 100, 100, 100, 100, 100, 100,
/* 1400 */ 100, 100, 100, 100, 100, 100, 100, 100, 100, 100,
/* 1410 */ 100, 100, 100,
};
#define YY_SHIFT_COUNT (163)
#define YY_SHIFT_MIN (0)
#define YY_SHIFT_MAX (1113)
static const unsigned short int yy_shift_ofst[] = {
/* 0 */ 143, 127, 222, 287, 287, 287, 287, 287, 287, 287,
/* 10 */ 287, 287, 287, 287, 287, 287, 287, 287, 287, 287,
/* 20 */ 287, 287, 287, 287, 287, 287, 287, 244, 433, 266,
/* 30 */ 244, 143, 494, 494, 0, 64, 143, 589, 266, 589,
/* 40 */ 466, 466, 466, 529, 562, 266, 266, 266, 266, 266,
/* 50 */ 266, 624, 266, 266, 657, 266, 266, 266, 266, 266,
/* 60 */ 266, 266, 266, 266, 266, 179, 317, 317, 317, 317,
/* 70 */ 317, 645, 318, 386, 425, 1015, 1015, 118, 47, 1313,
/* 80 */ 1313, 1313, 1313, 114, 114, 200, 435, 129, 188, 234,
/* 90 */ 360, 468, 531, 506, 545, 823, 1032, 928, 1113, 25,
/* 100 */ 25, 25, 162, 25, 25, 25, 69, 25, 85, 128,
/* 110 */ 92, 105, 120, 136, 100, 183, 183, 176, 220, 174,
/* 120 */ 202, 275, 152, 207, 198, 219, 221, 208, 215, 217,
/* 130 */ 236, 238, 213, 267, 265, 262, 218, 273, 216, 224,
/* 140 */ 214, 225, 294, 295, 297, 272, 309, 324, 325, 249,
/* 150 */ 253, 307, 249, 331, 332, 338, 337, 335, 340, 342,
/* 160 */ 363, 293, 374, 373,
};
#define YY_REDUCE_COUNT (82)
#define YY_REDUCE_MIN (-130)
#define YY_REDUCE_MAX (1177)
static const short yy_reduce_ofst[] = {
/* 0 */ 640, -97, -33, 308, 467, 502, 586, 622, 655, 670,
/* 10 */ 682, 698, 710, 735, 747, 760, 775, 787, 803, 815,
/* 20 */ 840, 852, 865, 880, 892, 908, 920, 159, 945, 957,
/* 30 */ 227, 987, 528, 590, -62, -62, 584, 404, 722, 994,
/* 40 */ 560, 685, 790, 827, 895, 999, 1011, 1018, 1023, 1035,
/* 50 */ 1047, 1050, 1062, 1065, 1080, 1088, 1095, 1103, 1127, 1130,
/* 60 */ 1133, 1159, 1162, 1165, 1177, -82, -112, -102, -48, -38,
/* 70 */ -24, -23, -130, -130, -130, -98, -87, -59, -101, -41,
/* 80 */ 46, 52, -36,
};
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,
|
| ︙ | ︙ | |||
1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 |
0, /* CENTER => nothing */
0, /* LJUST => nothing */
0, /* RJUST => nothing */
0, /* ABOVE => nothing */
0, /* BELOW => nothing */
0, /* ITALIC => nothing */
0, /* BOLD => nothing */
0, /* ALIGNED => nothing */
0, /* BIG => nothing */
0, /* SMALL => nothing */
0, /* AND => nothing */
0, /* LT => nothing */
0, /* GT => nothing */
0, /* ON => nothing */
| > | 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 |
0, /* CENTER => nothing */
0, /* LJUST => nothing */
0, /* RJUST => nothing */
0, /* ABOVE => nothing */
0, /* BELOW => nothing */
0, /* ITALIC => nothing */
0, /* BOLD => nothing */
0, /* MONO => nothing */
0, /* ALIGNED => nothing */
0, /* BIG => nothing */
0, /* SMALL => nothing */
0, /* AND => nothing */
0, /* LT => nothing */
0, /* GT => nothing */
0, /* ON => nothing */
|
| ︙ | ︙ | |||
1254 1255 1256 1257 1258 1259 1260 1261 1262 | #else yyStackEntry yystack[YYSTACKDEPTH]; /* The parser's stack */ yyStackEntry *yystackEnd; /* Last entry in the stack */ #endif }; typedef struct yyParser yyParser; #ifndef NDEBUG #include <stdio.h> | > < | 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 | #else yyStackEntry yystack[YYSTACKDEPTH]; /* The parser's stack */ yyStackEntry *yystackEnd; /* Last entry in the stack */ #endif }; typedef struct yyParser yyParser; #include <assert.h> #ifndef NDEBUG #include <stdio.h> static FILE *yyTraceFILE = 0; static char *yyTracePrompt = 0; #endif /* NDEBUG */ #ifndef NDEBUG /* ** Turn parser tracing on by giving a stream to which to write the trace |
| ︙ | ︙ | |||
1362 1363 1364 1365 1366 1367 1368 | /* 64 */ "CENTER", /* 65 */ "LJUST", /* 66 */ "RJUST", /* 67 */ "ABOVE", /* 68 */ "BELOW", /* 69 */ "ITALIC", /* 70 */ "BOLD", | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > | 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 |
/* 64 */ "CENTER",
/* 65 */ "LJUST",
/* 66 */ "RJUST",
/* 67 */ "ABOVE",
/* 68 */ "BELOW",
/* 69 */ "ITALIC",
/* 70 */ "BOLD",
/* 71 */ "MONO",
/* 72 */ "ALIGNED",
/* 73 */ "BIG",
/* 74 */ "SMALL",
/* 75 */ "AND",
/* 76 */ "LT",
/* 77 */ "GT",
/* 78 */ "ON",
/* 79 */ "WAY",
/* 80 */ "BETWEEN",
/* 81 */ "THE",
/* 82 */ "NTH",
/* 83 */ "VERTEX",
/* 84 */ "TOP",
/* 85 */ "BOTTOM",
/* 86 */ "START",
/* 87 */ "END",
/* 88 */ "IN",
/* 89 */ "THIS",
/* 90 */ "DOT_U",
/* 91 */ "LAST",
/* 92 */ "NUMBER",
/* 93 */ "FUNC1",
/* 94 */ "FUNC2",
/* 95 */ "DIST",
/* 96 */ "DOT_XY",
/* 97 */ "X",
/* 98 */ "Y",
/* 99 */ "DOT_L",
/* 100 */ "statement_list",
/* 101 */ "statement",
/* 102 */ "unnamed_statement",
/* 103 */ "basetype",
/* 104 */ "expr",
/* 105 */ "numproperty",
/* 106 */ "edge",
/* 107 */ "direction",
/* 108 */ "dashproperty",
/* 109 */ "colorproperty",
/* 110 */ "locproperty",
/* 111 */ "position",
/* 112 */ "place",
/* 113 */ "object",
/* 114 */ "objectname",
/* 115 */ "nth",
/* 116 */ "textposition",
/* 117 */ "rvalue",
/* 118 */ "lvalue",
/* 119 */ "even",
/* 120 */ "relexpr",
/* 121 */ "optrelexpr",
/* 122 */ "document",
/* 123 */ "print",
/* 124 */ "prlist",
/* 125 */ "pritem",
/* 126 */ "prsep",
/* 127 */ "attribute_list",
/* 128 */ "savelist",
/* 129 */ "alist",
/* 130 */ "attribute",
/* 131 */ "go",
/* 132 */ "boolproperty",
/* 133 */ "withclause",
/* 134 */ "between",
/* 135 */ "place2",
};
#endif /* defined(YYCOVERAGE) || !defined(NDEBUG) */
#ifndef NDEBUG
/* For tracing reduce actions, the names of all rules are required.
*/
static const char *const yyRuleName[] = {
|
| ︙ | ︙ | |||
1496 1497 1498 1499 1500 1501 1502 | /* 56 */ "boolproperty ::= RARROW", /* 57 */ "boolproperty ::= LRARROW", /* 58 */ "boolproperty ::= INVIS", /* 59 */ "boolproperty ::= THICK", /* 60 */ "boolproperty ::= THIN", /* 61 */ "boolproperty ::= SOLID", /* 62 */ "textposition ::=", | | | 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 | /* 56 */ "boolproperty ::= RARROW", /* 57 */ "boolproperty ::= LRARROW", /* 58 */ "boolproperty ::= INVIS", /* 59 */ "boolproperty ::= THICK", /* 60 */ "boolproperty ::= THIN", /* 61 */ "boolproperty ::= SOLID", /* 62 */ "textposition ::=", /* 63 */ "textposition ::= textposition CENTER|LJUST|RJUST|ABOVE|BELOW|ITALIC|BOLD|MONO|ALIGNED|BIG|SMALL", /* 64 */ "position ::= expr COMMA expr", /* 65 */ "position ::= place PLUS expr COMMA expr", /* 66 */ "position ::= place MINUS expr COMMA expr", /* 67 */ "position ::= place PLUS LP expr COMMA expr RP", /* 68 */ "position ::= place MINUS LP expr COMMA expr RP", /* 69 */ "position ::= LP position COMMA position RP", /* 70 */ "position ::= LP position RP", |
| ︙ | ︙ | |||
1714 1715 1716 1717 1718 1719 1720 |
** 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 ***************************************/
| | | | | | | | | | | | 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 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 ***************************************/
case 100: /* statement_list */
{
#line 510 "pikchr.y"
pik_elist_free(p,(yypminor->yy235));
#line 1756 "pikchr.c"
}
break;
case 101: /* statement */
case 102: /* unnamed_statement */
case 103: /* basetype */
{
#line 512 "pikchr.y"
pik_elem_free(p,(yypminor->yy162));
#line 1765 "pikchr.c"
}
break;
/********* End destructor definitions *****************************************/
default: break; /* If no destructor action specified: do nothing */
}
}
|
| ︙ | ︙ | |||
1945 1946 1947 1948 1949 1950 1951 |
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 ******************************************/
| | | | 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 |
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 544 "pikchr.y"
pik_error(p, 0, "parser stack overflow");
#line 1986 "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
|
| ︙ | ︙ | |||
2020 2021 2022 2023 2024 2025 2026 |
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[] = {
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 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 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 |
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[] = {
122, /* (0) document ::= statement_list */
100, /* (1) statement_list ::= statement */
100, /* (2) statement_list ::= statement_list EOL statement */
101, /* (3) statement ::= */
101, /* (4) statement ::= direction */
101, /* (5) statement ::= lvalue ASSIGN rvalue */
101, /* (6) statement ::= PLACENAME COLON unnamed_statement */
101, /* (7) statement ::= PLACENAME COLON position */
101, /* (8) statement ::= unnamed_statement */
101, /* (9) statement ::= print prlist */
101, /* (10) statement ::= ASSERT LP expr EQ expr RP */
101, /* (11) statement ::= ASSERT LP position EQ position RP */
101, /* (12) statement ::= DEFINE ID CODEBLOCK */
117, /* (13) rvalue ::= PLACENAME */
125, /* (14) pritem ::= FILL */
125, /* (15) pritem ::= COLOR */
125, /* (16) pritem ::= THICKNESS */
125, /* (17) pritem ::= rvalue */
125, /* (18) pritem ::= STRING */
126, /* (19) prsep ::= COMMA */
102, /* (20) unnamed_statement ::= basetype attribute_list */
103, /* (21) basetype ::= CLASSNAME */
103, /* (22) basetype ::= STRING textposition */
103, /* (23) basetype ::= LB savelist statement_list RB */
128, /* (24) savelist ::= */
120, /* (25) relexpr ::= expr */
120, /* (26) relexpr ::= expr PERCENT */
121, /* (27) optrelexpr ::= */
127, /* (28) attribute_list ::= relexpr alist */
130, /* (29) attribute ::= numproperty relexpr */
130, /* (30) attribute ::= dashproperty expr */
130, /* (31) attribute ::= dashproperty */
130, /* (32) attribute ::= colorproperty rvalue */
130, /* (33) attribute ::= go direction optrelexpr */
130, /* (34) attribute ::= go direction even position */
130, /* (35) attribute ::= CLOSE */
130, /* (36) attribute ::= CHOP */
130, /* (37) attribute ::= FROM position */
130, /* (38) attribute ::= TO position */
130, /* (39) attribute ::= THEN */
130, /* (40) attribute ::= THEN optrelexpr HEADING expr */
130, /* (41) attribute ::= THEN optrelexpr EDGEPT */
130, /* (42) attribute ::= GO optrelexpr HEADING expr */
130, /* (43) attribute ::= GO optrelexpr EDGEPT */
130, /* (44) attribute ::= AT position */
130, /* (45) attribute ::= SAME */
130, /* (46) attribute ::= SAME AS object */
130, /* (47) attribute ::= STRING textposition */
130, /* (48) attribute ::= FIT */
130, /* (49) attribute ::= BEHIND object */
133, /* (50) withclause ::= DOT_E edge AT position */
133, /* (51) withclause ::= edge AT position */
105, /* (52) numproperty ::= HEIGHT|WIDTH|RADIUS|DIAMETER|THICKNESS */
132, /* (53) boolproperty ::= CW */
132, /* (54) boolproperty ::= CCW */
132, /* (55) boolproperty ::= LARROW */
132, /* (56) boolproperty ::= RARROW */
132, /* (57) boolproperty ::= LRARROW */
132, /* (58) boolproperty ::= INVIS */
132, /* (59) boolproperty ::= THICK */
132, /* (60) boolproperty ::= THIN */
132, /* (61) boolproperty ::= SOLID */
116, /* (62) textposition ::= */
116, /* (63) textposition ::= textposition CENTER|LJUST|RJUST|ABOVE|BELOW|ITALIC|BOLD|MONO|ALIGNED|BIG|SMALL */
111, /* (64) position ::= expr COMMA expr */
111, /* (65) position ::= place PLUS expr COMMA expr */
111, /* (66) position ::= place MINUS expr COMMA expr */
111, /* (67) position ::= place PLUS LP expr COMMA expr RP */
111, /* (68) position ::= place MINUS LP expr COMMA expr RP */
111, /* (69) position ::= LP position COMMA position RP */
111, /* (70) position ::= LP position RP */
111, /* (71) position ::= expr between position AND position */
111, /* (72) position ::= expr LT position COMMA position GT */
111, /* (73) position ::= expr ABOVE position */
111, /* (74) position ::= expr BELOW position */
111, /* (75) position ::= expr LEFT OF position */
111, /* (76) position ::= expr RIGHT OF position */
111, /* (77) position ::= expr ON HEADING EDGEPT OF position */
111, /* (78) position ::= expr HEADING EDGEPT OF position */
111, /* (79) position ::= expr EDGEPT OF position */
111, /* (80) position ::= expr ON HEADING expr FROM position */
111, /* (81) position ::= expr HEADING expr FROM position */
112, /* (82) place ::= edge OF object */
135, /* (83) place2 ::= object */
135, /* (84) place2 ::= object DOT_E edge */
135, /* (85) place2 ::= NTH VERTEX OF object */
113, /* (86) object ::= nth */
113, /* (87) object ::= nth OF|IN object */
114, /* (88) objectname ::= THIS */
114, /* (89) objectname ::= PLACENAME */
114, /* (90) objectname ::= objectname DOT_U PLACENAME */
115, /* (91) nth ::= NTH CLASSNAME */
115, /* (92) nth ::= NTH LAST CLASSNAME */
115, /* (93) nth ::= LAST CLASSNAME */
115, /* (94) nth ::= LAST */
115, /* (95) nth ::= NTH LB RB */
115, /* (96) nth ::= NTH LAST LB RB */
115, /* (97) nth ::= LAST LB RB */
104, /* (98) expr ::= expr PLUS expr */
104, /* (99) expr ::= expr MINUS expr */
104, /* (100) expr ::= expr STAR expr */
104, /* (101) expr ::= expr SLASH expr */
104, /* (102) expr ::= MINUS expr */
104, /* (103) expr ::= PLUS expr */
104, /* (104) expr ::= LP expr RP */
104, /* (105) expr ::= LP FILL|COLOR|THICKNESS RP */
104, /* (106) expr ::= NUMBER */
104, /* (107) expr ::= ID */
104, /* (108) expr ::= FUNC1 LP expr RP */
104, /* (109) expr ::= FUNC2 LP expr COMMA expr RP */
104, /* (110) expr ::= DIST LP position COMMA position RP */
104, /* (111) expr ::= place2 DOT_XY X */
104, /* (112) expr ::= place2 DOT_XY Y */
104, /* (113) expr ::= object DOT_L numproperty */
104, /* (114) expr ::= object DOT_L dashproperty */
104, /* (115) expr ::= object DOT_L colorproperty */
118, /* (116) lvalue ::= ID */
118, /* (117) lvalue ::= FILL */
118, /* (118) lvalue ::= COLOR */
118, /* (119) lvalue ::= THICKNESS */
117, /* (120) rvalue ::= expr */
123, /* (121) print ::= PRINT */
124, /* (122) prlist ::= pritem */
124, /* (123) prlist ::= prlist prsep pritem */
107, /* (124) direction ::= UP */
107, /* (125) direction ::= DOWN */
107, /* (126) direction ::= LEFT */
107, /* (127) direction ::= RIGHT */
121, /* (128) optrelexpr ::= relexpr */
127, /* (129) attribute_list ::= alist */
129, /* (130) alist ::= */
129, /* (131) alist ::= alist attribute */
130, /* (132) attribute ::= boolproperty */
130, /* (133) attribute ::= WITH withclause */
131, /* (134) go ::= GO */
131, /* (135) go ::= */
119, /* (136) even ::= UNTIL EVEN WITH */
119, /* (137) even ::= EVEN WITH */
108, /* (138) dashproperty ::= DOTTED */
108, /* (139) dashproperty ::= DASHED */
109, /* (140) colorproperty ::= FILL */
109, /* (141) colorproperty ::= COLOR */
111, /* (142) position ::= place */
134, /* (143) between ::= WAY BETWEEN */
134, /* (144) between ::= BETWEEN */
134, /* (145) between ::= OF THE WAY BETWEEN */
112, /* (146) place ::= place2 */
106, /* (147) edge ::= CENTER */
106, /* (148) edge ::= EDGEPT */
106, /* (149) edge ::= TOP */
106, /* (150) edge ::= BOTTOM */
106, /* (151) edge ::= START */
106, /* (152) edge ::= END */
106, /* (153) edge ::= RIGHT */
106, /* (154) edge ::= LEFT */
113, /* (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 */
|
| ︙ | ︙ | |||
2244 2245 2246 2247 2248 2249 2250 |
-1, /* (56) boolproperty ::= RARROW */
-1, /* (57) boolproperty ::= LRARROW */
-1, /* (58) boolproperty ::= INVIS */
-1, /* (59) boolproperty ::= THICK */
-1, /* (60) boolproperty ::= THIN */
-1, /* (61) boolproperty ::= SOLID */
0, /* (62) textposition ::= */
| | | 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 |
-1, /* (56) boolproperty ::= RARROW */
-1, /* (57) boolproperty ::= LRARROW */
-1, /* (58) boolproperty ::= INVIS */
-1, /* (59) boolproperty ::= THICK */
-1, /* (60) boolproperty ::= THIN */
-1, /* (61) boolproperty ::= SOLID */
0, /* (62) textposition ::= */
-2, /* (63) textposition ::= textposition CENTER|LJUST|RJUST|ABOVE|BELOW|ITALIC|BOLD|MONO|ALIGNED|BIG|SMALL */
-3, /* (64) position ::= expr COMMA expr */
-5, /* (65) position ::= place PLUS expr COMMA expr */
-5, /* (66) position ::= place MINUS expr COMMA expr */
-7, /* (67) position ::= place PLUS LP expr COMMA expr RP */
-7, /* (68) position ::= place MINUS LP expr COMMA expr RP */
-5, /* (69) position ::= LP position COMMA position RP */
-3, /* (70) position ::= LP position RP */
|
| ︙ | ︙ | |||
2366 2367 2368 2369 2370 2371 2372 | YYACTIONTYPE yyact; /* The next action */ yyStackEntry *yymsp; /* The top of the parser's stack */ int yysize; /* Amount to pop the stack */ pik_parserARG_FETCH (void)yyLookahead; (void)yyLookaheadToken; yymsp = yypParser->yytos; | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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 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 |
YYACTIONTYPE yyact; /* The next action */
yyStackEntry *yymsp; /* The top of the parser's stack */
int yysize; /* Amount to pop the stack */
pik_parserARG_FETCH
(void)yyLookahead;
(void)yyLookaheadToken;
yymsp = yypParser->yytos;
switch( yyruleno ){
/* Beginning here are the reduction cases. A typical example
** follows:
** case 0:
** #line <lineno> <grammarfile>
** { ... } // User supplied code
** #line <lineno> <thisfile>
** break;
*/
/********** Begin reduce actions **********************************************/
YYMINORTYPE yylhsminor;
case 0: /* document ::= statement_list */
#line 548 "pikchr.y"
{pik_render(p,yymsp[0].minor.yy235);}
#line 2419 "pikchr.c"
break;
case 1: /* statement_list ::= statement */
#line 551 "pikchr.y"
{ yylhsminor.yy235 = pik_elist_append(p,0,yymsp[0].minor.yy162); }
#line 2424 "pikchr.c"
yymsp[0].minor.yy235 = yylhsminor.yy235;
break;
case 2: /* statement_list ::= statement_list EOL statement */
#line 553 "pikchr.y"
{ yylhsminor.yy235 = pik_elist_append(p,yymsp[-2].minor.yy235,yymsp[0].minor.yy162); }
#line 2430 "pikchr.c"
yymsp[-2].minor.yy235 = yylhsminor.yy235;
break;
case 3: /* statement ::= */
#line 556 "pikchr.y"
{ yymsp[1].minor.yy162 = 0; }
#line 2436 "pikchr.c"
break;
case 4: /* statement ::= direction */
#line 557 "pikchr.y"
{ pik_set_direction(p,yymsp[0].minor.yy0.eCode); yylhsminor.yy162=0; }
#line 2441 "pikchr.c"
yymsp[0].minor.yy162 = yylhsminor.yy162;
break;
case 5: /* statement ::= lvalue ASSIGN rvalue */
#line 558 "pikchr.y"
{pik_set_var(p,&yymsp[-2].minor.yy0,yymsp[0].minor.yy21,&yymsp[-1].minor.yy0); yylhsminor.yy162=0;}
#line 2447 "pikchr.c"
yymsp[-2].minor.yy162 = yylhsminor.yy162;
break;
case 6: /* statement ::= PLACENAME COLON unnamed_statement */
#line 560 "pikchr.y"
{ yylhsminor.yy162 = yymsp[0].minor.yy162; pik_elem_setname(p,yymsp[0].minor.yy162,&yymsp[-2].minor.yy0); }
#line 2453 "pikchr.c"
yymsp[-2].minor.yy162 = yylhsminor.yy162;
break;
case 7: /* statement ::= PLACENAME COLON position */
#line 562 "pikchr.y"
{ yylhsminor.yy162 = pik_elem_new(p,0,0,0);
if(yylhsminor.yy162){ yylhsminor.yy162->ptAt = yymsp[0].minor.yy63; pik_elem_setname(p,yylhsminor.yy162,&yymsp[-2].minor.yy0); }}
#line 2460 "pikchr.c"
yymsp[-2].minor.yy162 = yylhsminor.yy162;
break;
case 8: /* statement ::= unnamed_statement */
#line 564 "pikchr.y"
{yylhsminor.yy162 = yymsp[0].minor.yy162;}
#line 2466 "pikchr.c"
yymsp[0].minor.yy162 = yylhsminor.yy162;
break;
case 9: /* statement ::= print prlist */
#line 565 "pikchr.y"
{pik_append(p,"<br>\n",5); yymsp[-1].minor.yy162=0;}
#line 2472 "pikchr.c"
break;
case 10: /* statement ::= ASSERT LP expr EQ expr RP */
#line 570 "pikchr.y"
{yymsp[-5].minor.yy162=pik_assert(p,yymsp[-3].minor.yy21,&yymsp[-2].minor.yy0,yymsp[-1].minor.yy21);}
#line 2477 "pikchr.c"
break;
case 11: /* statement ::= ASSERT LP position EQ position RP */
#line 572 "pikchr.y"
{yymsp[-5].minor.yy162=pik_position_assert(p,&yymsp[-3].minor.yy63,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy63);}
#line 2482 "pikchr.c"
break;
case 12: /* statement ::= DEFINE ID CODEBLOCK */
#line 573 "pikchr.y"
{yymsp[-2].minor.yy162=0; pik_add_macro(p,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0);}
#line 2487 "pikchr.c"
break;
case 13: /* rvalue ::= PLACENAME */
#line 584 "pikchr.y"
{yylhsminor.yy21 = pik_lookup_color(p,&yymsp[0].minor.yy0);}
#line 2492 "pikchr.c"
yymsp[0].minor.yy21 = yylhsminor.yy21;
break;
case 14: /* pritem ::= FILL */
case 15: /* pritem ::= COLOR */ yytestcase(yyruleno==15);
case 16: /* pritem ::= THICKNESS */ yytestcase(yyruleno==16);
#line 589 "pikchr.y"
{pik_append_num(p,"",pik_value(p,yymsp[0].minor.yy0.z,yymsp[0].minor.yy0.n,0));}
#line 2500 "pikchr.c"
break;
case 17: /* pritem ::= rvalue */
#line 592 "pikchr.y"
{pik_append_num(p,"",yymsp[0].minor.yy21);}
#line 2505 "pikchr.c"
break;
case 18: /* pritem ::= STRING */
#line 593 "pikchr.y"
{pik_append_text(p,yymsp[0].minor.yy0.z+1,yymsp[0].minor.yy0.n-2,0);}
#line 2510 "pikchr.c"
break;
case 19: /* prsep ::= COMMA */
#line 594 "pikchr.y"
{pik_append(p, " ", 1);}
#line 2515 "pikchr.c"
break;
case 20: /* unnamed_statement ::= basetype attribute_list */
#line 597 "pikchr.y"
{yylhsminor.yy162 = yymsp[-1].minor.yy162; pik_after_adding_attributes(p,yylhsminor.yy162);}
#line 2520 "pikchr.c"
yymsp[-1].minor.yy162 = yylhsminor.yy162;
break;
case 21: /* basetype ::= CLASSNAME */
#line 599 "pikchr.y"
{yylhsminor.yy162 = pik_elem_new(p,&yymsp[0].minor.yy0,0,0); }
#line 2526 "pikchr.c"
yymsp[0].minor.yy162 = yylhsminor.yy162;
break;
case 22: /* basetype ::= STRING textposition */
#line 601 "pikchr.y"
{yymsp[-1].minor.yy0.eCode = yymsp[0].minor.yy188; yylhsminor.yy162 = pik_elem_new(p,0,&yymsp[-1].minor.yy0,0); }
#line 2532 "pikchr.c"
yymsp[-1].minor.yy162 = yylhsminor.yy162;
break;
case 23: /* basetype ::= LB savelist statement_list RB */
#line 603 "pikchr.y"
{ p->list = yymsp[-2].minor.yy235; yymsp[-3].minor.yy162 = pik_elem_new(p,0,0,yymsp[-1].minor.yy235); if(yymsp[-3].minor.yy162) yymsp[-3].minor.yy162->errTok = yymsp[0].minor.yy0; }
#line 2538 "pikchr.c"
break;
case 24: /* savelist ::= */
#line 608 "pikchr.y"
{yymsp[1].minor.yy235 = p->list; p->list = 0;}
#line 2543 "pikchr.c"
break;
case 25: /* relexpr ::= expr */
#line 615 "pikchr.y"
{yylhsminor.yy72.rAbs = yymsp[0].minor.yy21; yylhsminor.yy72.rRel = 0;}
#line 2548 "pikchr.c"
yymsp[0].minor.yy72 = yylhsminor.yy72;
break;
case 26: /* relexpr ::= expr PERCENT */
#line 616 "pikchr.y"
{yylhsminor.yy72.rAbs = 0; yylhsminor.yy72.rRel = yymsp[-1].minor.yy21/100;}
#line 2554 "pikchr.c"
yymsp[-1].minor.yy72 = yylhsminor.yy72;
break;
case 27: /* optrelexpr ::= */
#line 618 "pikchr.y"
{yymsp[1].minor.yy72.rAbs = 0; yymsp[1].minor.yy72.rRel = 1.0;}
#line 2560 "pikchr.c"
break;
case 28: /* attribute_list ::= relexpr alist */
#line 620 "pikchr.y"
{pik_add_direction(p,0,&yymsp[-1].minor.yy72);}
#line 2565 "pikchr.c"
break;
case 29: /* attribute ::= numproperty relexpr */
#line 624 "pikchr.y"
{ pik_set_numprop(p,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy72); }
#line 2570 "pikchr.c"
break;
case 30: /* attribute ::= dashproperty expr */
#line 625 "pikchr.y"
{ pik_set_dashed(p,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy21); }
#line 2575 "pikchr.c"
break;
case 31: /* attribute ::= dashproperty */
#line 626 "pikchr.y"
{ pik_set_dashed(p,&yymsp[0].minor.yy0,0); }
#line 2580 "pikchr.c"
break;
case 32: /* attribute ::= colorproperty rvalue */
#line 627 "pikchr.y"
{ pik_set_clrprop(p,&yymsp[-1].minor.yy0,yymsp[0].minor.yy21); }
#line 2585 "pikchr.c"
break;
case 33: /* attribute ::= go direction optrelexpr */
#line 628 "pikchr.y"
{ pik_add_direction(p,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy72);}
#line 2590 "pikchr.c"
break;
case 34: /* attribute ::= go direction even position */
#line 629 "pikchr.y"
{pik_evenwith(p,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy63);}
#line 2595 "pikchr.c"
break;
case 35: /* attribute ::= CLOSE */
#line 630 "pikchr.y"
{ pik_close_path(p,&yymsp[0].minor.yy0); }
#line 2600 "pikchr.c"
break;
case 36: /* attribute ::= CHOP */
#line 631 "pikchr.y"
{ p->cur->bChop = 1; }
#line 2605 "pikchr.c"
break;
case 37: /* attribute ::= FROM position */
#line 632 "pikchr.y"
{ pik_set_from(p,p->cur,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy63); }
#line 2610 "pikchr.c"
break;
case 38: /* attribute ::= TO position */
#line 633 "pikchr.y"
{ pik_add_to(p,p->cur,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy63); }
#line 2615 "pikchr.c"
break;
case 39: /* attribute ::= THEN */
#line 634 "pikchr.y"
{ pik_then(p, &yymsp[0].minor.yy0, p->cur); }
#line 2620 "pikchr.c"
break;
case 40: /* attribute ::= THEN optrelexpr HEADING expr */
case 42: /* attribute ::= GO optrelexpr HEADING expr */ yytestcase(yyruleno==42);
#line 636 "pikchr.y"
{pik_move_hdg(p,&yymsp[-2].minor.yy72,&yymsp[-1].minor.yy0,yymsp[0].minor.yy21,0,&yymsp[-3].minor.yy0);}
#line 2626 "pikchr.c"
break;
case 41: /* attribute ::= THEN optrelexpr EDGEPT */
case 43: /* attribute ::= GO optrelexpr EDGEPT */ yytestcase(yyruleno==43);
#line 637 "pikchr.y"
{pik_move_hdg(p,&yymsp[-1].minor.yy72,0,0,&yymsp[0].minor.yy0,&yymsp[-2].minor.yy0);}
#line 2632 "pikchr.c"
break;
case 44: /* attribute ::= AT position */
#line 642 "pikchr.y"
{ pik_set_at(p,0,&yymsp[0].minor.yy63,&yymsp[-1].minor.yy0); }
#line 2637 "pikchr.c"
break;
case 45: /* attribute ::= SAME */
#line 644 "pikchr.y"
{pik_same(p,0,&yymsp[0].minor.yy0);}
#line 2642 "pikchr.c"
break;
case 46: /* attribute ::= SAME AS object */
#line 645 "pikchr.y"
{pik_same(p,yymsp[0].minor.yy162,&yymsp[-2].minor.yy0);}
#line 2647 "pikchr.c"
break;
case 47: /* attribute ::= STRING textposition */
#line 646 "pikchr.y"
{pik_add_txt(p,&yymsp[-1].minor.yy0,yymsp[0].minor.yy188);}
#line 2652 "pikchr.c"
break;
case 48: /* attribute ::= FIT */
#line 647 "pikchr.y"
{pik_size_to_fit(p,&yymsp[0].minor.yy0,3); }
#line 2657 "pikchr.c"
break;
case 49: /* attribute ::= BEHIND object */
#line 648 "pikchr.y"
{pik_behind(p,yymsp[0].minor.yy162);}
#line 2662 "pikchr.c"
break;
case 50: /* withclause ::= DOT_E edge AT position */
case 51: /* withclause ::= edge AT position */ yytestcase(yyruleno==51);
#line 656 "pikchr.y"
{ pik_set_at(p,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy63,&yymsp[-1].minor.yy0); }
#line 2668 "pikchr.c"
break;
case 52: /* numproperty ::= HEIGHT|WIDTH|RADIUS|DIAMETER|THICKNESS */
#line 660 "pikchr.y"
{yylhsminor.yy0 = yymsp[0].minor.yy0;}
#line 2673 "pikchr.c"
yymsp[0].minor.yy0 = yylhsminor.yy0;
break;
case 53: /* boolproperty ::= CW */
#line 671 "pikchr.y"
{p->cur->cw = 1;}
#line 2679 "pikchr.c"
break;
case 54: /* boolproperty ::= CCW */
#line 672 "pikchr.y"
{p->cur->cw = 0;}
#line 2684 "pikchr.c"
break;
case 55: /* boolproperty ::= LARROW */
#line 673 "pikchr.y"
{p->cur->larrow=1; p->cur->rarrow=0; }
#line 2689 "pikchr.c"
break;
case 56: /* boolproperty ::= RARROW */
#line 674 "pikchr.y"
{p->cur->larrow=0; p->cur->rarrow=1; }
#line 2694 "pikchr.c"
break;
case 57: /* boolproperty ::= LRARROW */
#line 675 "pikchr.y"
{p->cur->larrow=1; p->cur->rarrow=1; }
#line 2699 "pikchr.c"
break;
case 58: /* boolproperty ::= INVIS */
#line 676 "pikchr.y"
{p->cur->sw = -0.00001;}
#line 2704 "pikchr.c"
break;
case 59: /* boolproperty ::= THICK */
#line 677 "pikchr.y"
{p->cur->sw *= 1.5;}
#line 2709 "pikchr.c"
break;
case 60: /* boolproperty ::= THIN */
#line 678 "pikchr.y"
{p->cur->sw *= 0.67;}
#line 2714 "pikchr.c"
break;
case 61: /* boolproperty ::= SOLID */
#line 679 "pikchr.y"
{p->cur->sw = pik_value(p,"thickness",9,0);
p->cur->dotted = p->cur->dashed = 0.0;}
#line 2720 "pikchr.c"
break;
case 62: /* textposition ::= */
#line 682 "pikchr.y"
{yymsp[1].minor.yy188 = 0;}
#line 2725 "pikchr.c"
break;
case 63: /* textposition ::= textposition CENTER|LJUST|RJUST|ABOVE|BELOW|ITALIC|BOLD|MONO|ALIGNED|BIG|SMALL */
#line 685 "pikchr.y"
{yylhsminor.yy188 = (short int)pik_text_position(yymsp[-1].minor.yy188,&yymsp[0].minor.yy0);}
#line 2730 "pikchr.c"
yymsp[-1].minor.yy188 = yylhsminor.yy188;
break;
case 64: /* position ::= expr COMMA expr */
#line 688 "pikchr.y"
{yylhsminor.yy63.x=yymsp[-2].minor.yy21; yylhsminor.yy63.y=yymsp[0].minor.yy21;}
#line 2736 "pikchr.c"
yymsp[-2].minor.yy63 = yylhsminor.yy63;
break;
case 65: /* position ::= place PLUS expr COMMA expr */
#line 690 "pikchr.y"
{yylhsminor.yy63.x=yymsp[-4].minor.yy63.x+yymsp[-2].minor.yy21; yylhsminor.yy63.y=yymsp[-4].minor.yy63.y+yymsp[0].minor.yy21;}
#line 2742 "pikchr.c"
yymsp[-4].minor.yy63 = yylhsminor.yy63;
break;
case 66: /* position ::= place MINUS expr COMMA expr */
#line 691 "pikchr.y"
{yylhsminor.yy63.x=yymsp[-4].minor.yy63.x-yymsp[-2].minor.yy21; yylhsminor.yy63.y=yymsp[-4].minor.yy63.y-yymsp[0].minor.yy21;}
#line 2748 "pikchr.c"
yymsp[-4].minor.yy63 = yylhsminor.yy63;
break;
case 67: /* position ::= place PLUS LP expr COMMA expr RP */
#line 693 "pikchr.y"
{yylhsminor.yy63.x=yymsp[-6].minor.yy63.x+yymsp[-3].minor.yy21; yylhsminor.yy63.y=yymsp[-6].minor.yy63.y+yymsp[-1].minor.yy21;}
#line 2754 "pikchr.c"
yymsp[-6].minor.yy63 = yylhsminor.yy63;
break;
case 68: /* position ::= place MINUS LP expr COMMA expr RP */
#line 695 "pikchr.y"
{yylhsminor.yy63.x=yymsp[-6].minor.yy63.x-yymsp[-3].minor.yy21; yylhsminor.yy63.y=yymsp[-6].minor.yy63.y-yymsp[-1].minor.yy21;}
#line 2760 "pikchr.c"
yymsp[-6].minor.yy63 = yylhsminor.yy63;
break;
case 69: /* position ::= LP position COMMA position RP */
#line 696 "pikchr.y"
{yymsp[-4].minor.yy63.x=yymsp[-3].minor.yy63.x; yymsp[-4].minor.yy63.y=yymsp[-1].minor.yy63.y;}
#line 2766 "pikchr.c"
break;
case 70: /* position ::= LP position RP */
#line 697 "pikchr.y"
{yymsp[-2].minor.yy63=yymsp[-1].minor.yy63;}
#line 2771 "pikchr.c"
break;
case 71: /* position ::= expr between position AND position */
#line 699 "pikchr.y"
{yylhsminor.yy63 = pik_position_between(yymsp[-4].minor.yy21,yymsp[-2].minor.yy63,yymsp[0].minor.yy63);}
#line 2776 "pikchr.c"
yymsp[-4].minor.yy63 = yylhsminor.yy63;
break;
case 72: /* position ::= expr LT position COMMA position GT */
#line 701 "pikchr.y"
{yylhsminor.yy63 = pik_position_between(yymsp[-5].minor.yy21,yymsp[-3].minor.yy63,yymsp[-1].minor.yy63);}
#line 2782 "pikchr.c"
yymsp[-5].minor.yy63 = yylhsminor.yy63;
break;
case 73: /* position ::= expr ABOVE position */
#line 702 "pikchr.y"
{yylhsminor.yy63=yymsp[0].minor.yy63; yylhsminor.yy63.y += yymsp[-2].minor.yy21;}
#line 2788 "pikchr.c"
yymsp[-2].minor.yy63 = yylhsminor.yy63;
break;
case 74: /* position ::= expr BELOW position */
#line 703 "pikchr.y"
{yylhsminor.yy63=yymsp[0].minor.yy63; yylhsminor.yy63.y -= yymsp[-2].minor.yy21;}
#line 2794 "pikchr.c"
yymsp[-2].minor.yy63 = yylhsminor.yy63;
break;
case 75: /* position ::= expr LEFT OF position */
#line 704 "pikchr.y"
{yylhsminor.yy63=yymsp[0].minor.yy63; yylhsminor.yy63.x -= yymsp[-3].minor.yy21;}
#line 2800 "pikchr.c"
yymsp[-3].minor.yy63 = yylhsminor.yy63;
break;
case 76: /* position ::= expr RIGHT OF position */
#line 705 "pikchr.y"
{yylhsminor.yy63=yymsp[0].minor.yy63; yylhsminor.yy63.x += yymsp[-3].minor.yy21;}
#line 2806 "pikchr.c"
yymsp[-3].minor.yy63 = yylhsminor.yy63;
break;
case 77: /* position ::= expr ON HEADING EDGEPT OF position */
#line 707 "pikchr.y"
{yylhsminor.yy63 = pik_position_at_hdg(yymsp[-5].minor.yy21,&yymsp[-2].minor.yy0,yymsp[0].minor.yy63);}
#line 2812 "pikchr.c"
yymsp[-5].minor.yy63 = yylhsminor.yy63;
break;
case 78: /* position ::= expr HEADING EDGEPT OF position */
#line 709 "pikchr.y"
{yylhsminor.yy63 = pik_position_at_hdg(yymsp[-4].minor.yy21,&yymsp[-2].minor.yy0,yymsp[0].minor.yy63);}
#line 2818 "pikchr.c"
yymsp[-4].minor.yy63 = yylhsminor.yy63;
break;
case 79: /* position ::= expr EDGEPT OF position */
#line 711 "pikchr.y"
{yylhsminor.yy63 = pik_position_at_hdg(yymsp[-3].minor.yy21,&yymsp[-2].minor.yy0,yymsp[0].minor.yy63);}
#line 2824 "pikchr.c"
yymsp[-3].minor.yy63 = yylhsminor.yy63;
break;
case 80: /* position ::= expr ON HEADING expr FROM position */
#line 713 "pikchr.y"
{yylhsminor.yy63 = pik_position_at_angle(yymsp[-5].minor.yy21,yymsp[-2].minor.yy21,yymsp[0].minor.yy63);}
#line 2830 "pikchr.c"
yymsp[-5].minor.yy63 = yylhsminor.yy63;
break;
case 81: /* position ::= expr HEADING expr FROM position */
#line 715 "pikchr.y"
{yylhsminor.yy63 = pik_position_at_angle(yymsp[-4].minor.yy21,yymsp[-2].minor.yy21,yymsp[0].minor.yy63);}
#line 2836 "pikchr.c"
yymsp[-4].minor.yy63 = yylhsminor.yy63;
break;
case 82: /* place ::= edge OF object */
#line 727 "pikchr.y"
{yylhsminor.yy63 = pik_place_of_elem(p,yymsp[0].minor.yy162,&yymsp[-2].minor.yy0);}
#line 2842 "pikchr.c"
yymsp[-2].minor.yy63 = yylhsminor.yy63;
break;
case 83: /* place2 ::= object */
#line 728 "pikchr.y"
{yylhsminor.yy63 = pik_place_of_elem(p,yymsp[0].minor.yy162,0);}
#line 2848 "pikchr.c"
yymsp[0].minor.yy63 = yylhsminor.yy63;
break;
case 84: /* place2 ::= object DOT_E edge */
#line 729 "pikchr.y"
{yylhsminor.yy63 = pik_place_of_elem(p,yymsp[-2].minor.yy162,&yymsp[0].minor.yy0);}
#line 2854 "pikchr.c"
yymsp[-2].minor.yy63 = yylhsminor.yy63;
break;
case 85: /* place2 ::= NTH VERTEX OF object */
#line 730 "pikchr.y"
{yylhsminor.yy63 = pik_nth_vertex(p,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,yymsp[0].minor.yy162);}
#line 2860 "pikchr.c"
yymsp[-3].minor.yy63 = yylhsminor.yy63;
break;
case 86: /* object ::= nth */
#line 742 "pikchr.y"
{yylhsminor.yy162 = pik_find_nth(p,0,&yymsp[0].minor.yy0);}
#line 2866 "pikchr.c"
yymsp[0].minor.yy162 = yylhsminor.yy162;
break;
case 87: /* object ::= nth OF|IN object */
#line 743 "pikchr.y"
{yylhsminor.yy162 = pik_find_nth(p,yymsp[0].minor.yy162,&yymsp[-2].minor.yy0);}
#line 2872 "pikchr.c"
yymsp[-2].minor.yy162 = yylhsminor.yy162;
break;
case 88: /* objectname ::= THIS */
#line 745 "pikchr.y"
{yymsp[0].minor.yy162 = p->cur;}
#line 2878 "pikchr.c"
break;
case 89: /* objectname ::= PLACENAME */
#line 746 "pikchr.y"
{yylhsminor.yy162 = pik_find_byname(p,0,&yymsp[0].minor.yy0);}
#line 2883 "pikchr.c"
yymsp[0].minor.yy162 = yylhsminor.yy162;
break;
case 90: /* objectname ::= objectname DOT_U PLACENAME */
#line 748 "pikchr.y"
{yylhsminor.yy162 = pik_find_byname(p,yymsp[-2].minor.yy162,&yymsp[0].minor.yy0);}
#line 2889 "pikchr.c"
yymsp[-2].minor.yy162 = yylhsminor.yy162;
break;
case 91: /* nth ::= NTH CLASSNAME */
#line 750 "pikchr.y"
{yylhsminor.yy0=yymsp[0].minor.yy0; yylhsminor.yy0.eCode = pik_nth_value(p,&yymsp[-1].minor.yy0); }
#line 2895 "pikchr.c"
yymsp[-1].minor.yy0 = yylhsminor.yy0;
break;
case 92: /* nth ::= NTH LAST CLASSNAME */
#line 751 "pikchr.y"
{yylhsminor.yy0=yymsp[0].minor.yy0; yylhsminor.yy0.eCode = -pik_nth_value(p,&yymsp[-2].minor.yy0); }
#line 2901 "pikchr.c"
yymsp[-2].minor.yy0 = yylhsminor.yy0;
break;
case 93: /* nth ::= LAST CLASSNAME */
#line 752 "pikchr.y"
{yymsp[-1].minor.yy0=yymsp[0].minor.yy0; yymsp[-1].minor.yy0.eCode = -1;}
#line 2907 "pikchr.c"
break;
case 94: /* nth ::= LAST */
#line 753 "pikchr.y"
{yylhsminor.yy0=yymsp[0].minor.yy0; yylhsminor.yy0.eCode = -1;}
#line 2912 "pikchr.c"
yymsp[0].minor.yy0 = yylhsminor.yy0;
break;
case 95: /* nth ::= NTH LB RB */
#line 754 "pikchr.y"
{yylhsminor.yy0=yymsp[-1].minor.yy0; yylhsminor.yy0.eCode = pik_nth_value(p,&yymsp[-2].minor.yy0);}
#line 2918 "pikchr.c"
yymsp[-2].minor.yy0 = yylhsminor.yy0;
break;
case 96: /* nth ::= NTH LAST LB RB */
#line 755 "pikchr.y"
{yylhsminor.yy0=yymsp[-1].minor.yy0; yylhsminor.yy0.eCode = -pik_nth_value(p,&yymsp[-3].minor.yy0);}
#line 2924 "pikchr.c"
yymsp[-3].minor.yy0 = yylhsminor.yy0;
break;
case 97: /* nth ::= LAST LB RB */
#line 756 "pikchr.y"
{yymsp[-2].minor.yy0=yymsp[-1].minor.yy0; yymsp[-2].minor.yy0.eCode = -1; }
#line 2930 "pikchr.c"
break;
case 98: /* expr ::= expr PLUS expr */
#line 758 "pikchr.y"
{yylhsminor.yy21=yymsp[-2].minor.yy21+yymsp[0].minor.yy21;}
#line 2935 "pikchr.c"
yymsp[-2].minor.yy21 = yylhsminor.yy21;
break;
case 99: /* expr ::= expr MINUS expr */
#line 759 "pikchr.y"
{yylhsminor.yy21=yymsp[-2].minor.yy21-yymsp[0].minor.yy21;}
#line 2941 "pikchr.c"
yymsp[-2].minor.yy21 = yylhsminor.yy21;
break;
case 100: /* expr ::= expr STAR expr */
#line 760 "pikchr.y"
{yylhsminor.yy21=yymsp[-2].minor.yy21*yymsp[0].minor.yy21;}
#line 2947 "pikchr.c"
yymsp[-2].minor.yy21 = yylhsminor.yy21;
break;
case 101: /* expr ::= expr SLASH expr */
#line 761 "pikchr.y"
{
if( yymsp[0].minor.yy21==0.0 ){ pik_error(p, &yymsp[-1].minor.yy0, "division by zero"); yylhsminor.yy21 = 0.0; }
else{ yylhsminor.yy21 = yymsp[-2].minor.yy21/yymsp[0].minor.yy21; }
}
#line 2956 "pikchr.c"
yymsp[-2].minor.yy21 = yylhsminor.yy21;
break;
case 102: /* expr ::= MINUS expr */
#line 765 "pikchr.y"
{yymsp[-1].minor.yy21=-yymsp[0].minor.yy21;}
#line 2962 "pikchr.c"
break;
case 103: /* expr ::= PLUS expr */
#line 766 "pikchr.y"
{yymsp[-1].minor.yy21=yymsp[0].minor.yy21;}
#line 2967 "pikchr.c"
break;
case 104: /* expr ::= LP expr RP */
#line 767 "pikchr.y"
{yymsp[-2].minor.yy21=yymsp[-1].minor.yy21;}
#line 2972 "pikchr.c"
break;
case 105: /* expr ::= LP FILL|COLOR|THICKNESS RP */
#line 768 "pikchr.y"
{yymsp[-2].minor.yy21=pik_get_var(p,&yymsp[-1].minor.yy0);}
#line 2977 "pikchr.c"
break;
case 106: /* expr ::= NUMBER */
#line 769 "pikchr.y"
{yylhsminor.yy21=pik_atof(&yymsp[0].minor.yy0);}
#line 2982 "pikchr.c"
yymsp[0].minor.yy21 = yylhsminor.yy21;
break;
case 107: /* expr ::= ID */
#line 770 "pikchr.y"
{yylhsminor.yy21=pik_get_var(p,&yymsp[0].minor.yy0);}
#line 2988 "pikchr.c"
yymsp[0].minor.yy21 = yylhsminor.yy21;
break;
case 108: /* expr ::= FUNC1 LP expr RP */
#line 771 "pikchr.y"
{yylhsminor.yy21 = pik_func(p,&yymsp[-3].minor.yy0,yymsp[-1].minor.yy21,0.0);}
#line 2994 "pikchr.c"
yymsp[-3].minor.yy21 = yylhsminor.yy21;
break;
case 109: /* expr ::= FUNC2 LP expr COMMA expr RP */
#line 772 "pikchr.y"
{yylhsminor.yy21 = pik_func(p,&yymsp[-5].minor.yy0,yymsp[-3].minor.yy21,yymsp[-1].minor.yy21);}
#line 3000 "pikchr.c"
yymsp[-5].minor.yy21 = yylhsminor.yy21;
break;
case 110: /* expr ::= DIST LP position COMMA position RP */
#line 773 "pikchr.y"
{yymsp[-5].minor.yy21 = pik_dist(&yymsp[-3].minor.yy63,&yymsp[-1].minor.yy63);}
#line 3006 "pikchr.c"
break;
case 111: /* expr ::= place2 DOT_XY X */
#line 774 "pikchr.y"
{yylhsminor.yy21 = yymsp[-2].minor.yy63.x;}
#line 3011 "pikchr.c"
yymsp[-2].minor.yy21 = yylhsminor.yy21;
break;
case 112: /* expr ::= place2 DOT_XY Y */
#line 775 "pikchr.y"
{yylhsminor.yy21 = yymsp[-2].minor.yy63.y;}
#line 3017 "pikchr.c"
yymsp[-2].minor.yy21 = yylhsminor.yy21;
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 776 "pikchr.y"
{yylhsminor.yy21=pik_property_of(yymsp[-2].minor.yy162,&yymsp[0].minor.yy0);}
#line 3025 "pikchr.c"
yymsp[-2].minor.yy21 = yylhsminor.yy21;
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);
|
| ︙ | ︙ | |||
3139 3140 3141 3142 3143 3144 3145 |
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 ****************************************/
| | | | 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 |
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 536 "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 3136 "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
|
| ︙ | ︙ | |||
3233 3234 3235 3236 3237 3238 3239 |
}else{
fprintf(yyTraceFILE,"%sInput '%s' with pending reduce %d\n",
yyTracePrompt,yyTokenName[yymajor],yyact-YY_MIN_REDUCE);
}
}
#endif
| | > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > | | 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 |
}else{
fprintf(yyTraceFILE,"%sInput '%s' with pending reduce %d\n",
yyTracePrompt,yyTokenName[yymajor],yyact-YY_MIN_REDUCE);
}
}
#endif
while(1){ /* Exit by "break" */
assert( yypParser->yytos>=yypParser->yystack );
assert( yyact==yypParser->yytos->stateno );
yyact = yy_find_shift_action((YYCODETYPE)yymajor,yyact);
if( yyact >= YY_MIN_REDUCE ){
unsigned int yyruleno = yyact - YY_MIN_REDUCE; /* Reduce by this rule */
#ifndef NDEBUG
assert( yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) );
if( yyTraceFILE ){
int yysize = yyRuleInfoNRhs[yyruleno];
if( yysize ){
fprintf(yyTraceFILE, "%sReduce %d [%s]%s, pop back to state %d.\n",
yyTracePrompt,
yyruleno, yyRuleName[yyruleno],
yyruleno<YYNRULE_WITH_ACTION ? "" : " without external action",
yypParser->yytos[yysize].stateno);
}else{
fprintf(yyTraceFILE, "%sReduce %d [%s]%s.\n",
yyTracePrompt, yyruleno, yyRuleName[yyruleno],
yyruleno<YYNRULE_WITH_ACTION ? "" : " without external action");
}
}
#endif /* NDEBUG */
/* Check that the stack is large enough to grow by a single entry
** if the RHS of the rule is empty. This ensures that there is room
** enough on the stack to push the LHS value */
if( yyRuleInfoNRhs[yyruleno]==0 ){
#ifdef YYTRACKMAXSTACKDEPTH
if( (int)(yypParser->yytos - yypParser->yystack)>yypParser->yyhwm ){
yypParser->yyhwm++;
assert( yypParser->yyhwm ==
(int)(yypParser->yytos - yypParser->yystack));
}
#endif
#if YYSTACKDEPTH>0
if( yypParser->yytos>=yypParser->yystackEnd ){
yyStackOverflow(yypParser);
break;
}
#else
if( yypParser->yytos>=&yypParser->yystack[yypParser->yystksz-1] ){
if( yyGrowStack(yypParser) ){
yyStackOverflow(yypParser);
break;
}
}
#endif
}
yyact = yy_reduce(yypParser,yyruleno,yymajor,yyminor pik_parserCTX_PARAM);
}else if( yyact <= YY_MAX_SHIFTREDUCE ){
yy_shift(yypParser,yyact,(YYCODETYPE)yymajor,yyminor);
#ifndef YYNOERRORRECOVERY
yypParser->yyerrcnt--;
#endif
break;
}else if( yyact==YY_ACCEPT_ACTION ){
|
| ︙ | ︙ | |||
3294 3295 3296 3297 3298 3299 3300 |
fprintf(yyTraceFILE,"%sDiscard input token %s\n",
yyTracePrompt,yyTokenName[yymajor]);
}
#endif
yy_destructor(yypParser, (YYCODETYPE)yymajor, &yyminorunion);
yymajor = YYNOCODE;
}else{
| | | < | < > | | 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 |
fprintf(yyTraceFILE,"%sDiscard input token %s\n",
yyTracePrompt,yyTokenName[yymajor]);
}
#endif
yy_destructor(yypParser, (YYCODETYPE)yymajor, &yyminorunion);
yymajor = YYNOCODE;
}else{
while( yypParser->yytos > yypParser->yystack ){
yyact = yy_find_reduce_action(yypParser->yytos->stateno,
YYERRORSYMBOL);
if( yyact<=YY_MAX_SHIFTREDUCE ) break;
yy_pop_parser_stack(yypParser);
}
if( yypParser->yytos <= yypParser->yystack || yymajor==0 ){
yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion);
yy_parse_failed(yypParser);
#ifndef YYNOERRORRECOVERY
yypParser->yyerrcnt = -1;
#endif
yymajor = YYNOCODE;
}else if( yymx!=YYERRORSYMBOL ){
|
| ︙ | ︙ | |||
3351 3352 3353 3354 3355 3356 3357 |
#ifndef YYNOERRORRECOVERY
yypParser->yyerrcnt = -1;
#endif
}
break;
#endif
}
| < > | 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 |
#ifndef YYNOERRORRECOVERY
yypParser->yyerrcnt = -1;
#endif
}
break;
#endif
}
}
#ifndef NDEBUG
if( yyTraceFILE ){
yyStackEntry *i;
char cDiv = '[';
fprintf(yyTraceFILE,"%sReturn. Stack=",yyTracePrompt);
for(i=&yypParser->yystack[1]; i<=yypParser->yytos; i++){
fprintf(yyTraceFILE,"%c%s", cDiv, yyTokenName[i->major]);
|
| ︙ | ︙ | |||
3380 3381 3382 3383 3384 3385 3386 | assert( iToken<(int)(sizeof(yyFallback)/sizeof(yyFallback[0])) ); return yyFallback[iToken]; #else (void)iToken; return 0; #endif } | | | 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 | assert( iToken<(int)(sizeof(yyFallback)/sizeof(yyFallback[0])) ); return yyFallback[iToken]; #else (void)iToken; return 0; #endif } #line 781 "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 ** |
| ︙ | ︙ | |||
3633 3634 3635 3636 3637 3638 3639 |
}
m = arcControlPoint(pObj->cw, p->aTPath[0], p->aTPath[1], 0.5);
pik_bbox_add_xy(&pObj->bbox, m.x, m.y);
}
static void arcRender(Pik *p, PObj *pObj){
PPoint f, m, t;
if( pObj->nPath<2 ) return;
| | | 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 |
}
m = arcControlPoint(pObj->cw, p->aTPath[0], p->aTPath[1], 0.5);
pik_bbox_add_xy(&pObj->bbox, m.x, m.y);
}
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,1.0);
if( pObj->larrow ){
pik_draw_arrowhead(p,&m,&f,pObj);
}
if( pObj->rarrow ){
|
| ︙ | ︙ | |||
3746 3747 3748 3749 3750 3751 3752 |
UNUSED_PARAMETER(p);
}
static void boxRender(Pik *p, PObj *pObj){
PNum w2 = 0.5*pObj->w;
PNum h2 = 0.5*pObj->h;
PNum rad = pObj->rad;
PPoint pt = pObj->ptAt;
| | | 3746 3747 3748 3749 3750 3751 3752 3753 3754 3755 3756 3757 3758 3759 3760 |
UNUSED_PARAMETER(p);
}
static void boxRender(Pik *p, PObj *pObj){
PNum w2 = 0.5*pObj->w;
PNum h2 = 0.5*pObj->h;
PNum rad = pObj->rad;
PPoint pt = pObj->ptAt;
if( pObj->sw>=0.0 ){
if( rad<=0.0 ){
pik_append_xy(p,"<path d=\"M", pt.x-w2,pt.y-h2);
pik_append_xy(p,"L", pt.x+w2,pt.y-h2);
pik_append_xy(p,"L", pt.x+w2,pt.y+h2);
pik_append_xy(p,"L", pt.x-w2,pt.y+h2);
pik_append(p,"Z\" ",-1);
}else{
|
| ︙ | ︙ | |||
3848 3849 3850 3851 3852 3853 3854 |
}
UNUSED_PARAMETER(p);
}
static void circleRender(Pik *p, PObj *pObj){
PNum r = pObj->rad;
PPoint pt = pObj->ptAt;
| | | 3848 3849 3850 3851 3852 3853 3854 3855 3856 3857 3858 3859 3860 3861 3862 |
}
UNUSED_PARAMETER(p);
}
static void circleRender(Pik *p, PObj *pObj){
PNum r = pObj->rad;
PPoint pt = pObj->ptAt;
if( pObj->sw>=0.0 ){
pik_append_x(p,"<circle cx=\"", pt.x, "\"");
pik_append_y(p," cy=\"", pt.y, "\"");
pik_append_dis(p," r=\"", r, "\" ");
pik_append_style(p,pObj,3);
pik_append(p,"\" />\n", -1);
}
pik_append_txt(p, pObj, 0);
|
| ︙ | ︙ | |||
3874 3875 3876 3877 3878 3879 3880 |
UNUSED_PARAMETER(p);
}
static void cylinderRender(Pik *p, PObj *pObj){
PNum w2 = 0.5*pObj->w;
PNum h2 = 0.5*pObj->h;
PNum rad = pObj->rad;
PPoint pt = pObj->ptAt;
| | | 3874 3875 3876 3877 3878 3879 3880 3881 3882 3883 3884 3885 3886 3887 3888 |
UNUSED_PARAMETER(p);
}
static void cylinderRender(Pik *p, PObj *pObj){
PNum w2 = 0.5*pObj->w;
PNum h2 = 0.5*pObj->h;
PNum rad = pObj->rad;
PPoint pt = pObj->ptAt;
if( pObj->sw>=0.0 ){
if( rad>h2 ){
rad = h2;
}else if( rad<0 ){
rad = 0;
}
pik_append_xy(p,"<path d=\"M", pt.x-w2,pt.y+h2-rad);
pik_append_xy(p,"L", pt.x-w2,pt.y-h2+rad);
|
| ︙ | ︙ | |||
3945 3946 3947 3948 3949 3950 3951 |
UNUSED_PARAMETER(pObj);
UNUSED_PARAMETER(cp);
return cZeroPoint;
}
static void dotRender(Pik *p, PObj *pObj){
PNum r = pObj->rad;
PPoint pt = pObj->ptAt;
| | | 3945 3946 3947 3948 3949 3950 3951 3952 3953 3954 3955 3956 3957 3958 3959 |
UNUSED_PARAMETER(pObj);
UNUSED_PARAMETER(cp);
return cZeroPoint;
}
static void dotRender(Pik *p, PObj *pObj){
PNum r = pObj->rad;
PPoint pt = pObj->ptAt;
if( pObj->sw>=0.0 ){
pik_append_x(p,"<circle cx=\"", pt.x, "\"");
pik_append_y(p," cy=\"", pt.y, "\"");
pik_append_dis(p," r=\"", r, "\"");
pik_append_style(p,pObj,2);
pik_append(p,"\" />\n", -1);
}
pik_append_txt(p, pObj, 0);
|
| ︙ | ︙ | |||
4003 4004 4005 4006 4007 4008 4009 |
UNUSED_PARAMETER(p);
return pt;
}
static void ellipseRender(Pik *p, PObj *pObj){
PNum w = pObj->w;
PNum h = pObj->h;
PPoint pt = pObj->ptAt;
| | | 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 |
UNUSED_PARAMETER(p);
return pt;
}
static void ellipseRender(Pik *p, PObj *pObj){
PNum w = pObj->w;
PNum h = pObj->h;
PPoint pt = pObj->ptAt;
if( pObj->sw>=0.0 ){
pik_append_x(p,"<ellipse cx=\"", pt.x, "\"");
pik_append_y(p," cy=\"", pt.y, "\"");
pik_append_dis(p," rx=\"", w/2.0, "\"");
pik_append_dis(p," ry=\"", h/2.0, "\" ");
pik_append_style(p,pObj,3);
pik_append(p,"\" />\n", -1);
}
|
| ︙ | ︙ | |||
4060 4061 4062 4063 4064 4065 4066 | PNum w2 = 0.5*pObj->w; PNum h2 = 0.5*pObj->h; PNum rad = pObj->rad; PPoint pt = pObj->ptAt; PNum mn = w2<h2 ? w2 : h2; if( rad>mn ) rad = mn; if( rad<mn*0.25 ) rad = mn*0.25; | | | 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 |
PNum w2 = 0.5*pObj->w;
PNum h2 = 0.5*pObj->h;
PNum rad = pObj->rad;
PPoint pt = pObj->ptAt;
PNum mn = w2<h2 ? w2 : h2;
if( rad>mn ) rad = mn;
if( rad<mn*0.25 ) rad = mn*0.25;
if( pObj->sw>=0.0 ){
pik_append_xy(p,"<path d=\"M", pt.x-w2,pt.y-h2);
pik_append_xy(p,"L", pt.x+w2,pt.y-h2);
pik_append_xy(p,"L", pt.x+w2,pt.y+(h2-rad));
pik_append_xy(p,"L", pt.x+(w2-rad),pt.y+h2);
pik_append_xy(p,"L", pt.x-w2,pt.y+h2);
pik_append(p,"Z\" ",-1);
pik_append_style(p,pObj,1);
|
| ︙ | ︙ | |||
4257 4258 4259 4260 4261 4262 4263 4264 4265 4266 4267 4268 4269 4270 |
/* 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->errTok,3);
return boxOffset(p, pObj, cp);
}
/* Methods for the "sublist" class */
static void sublistInit(Pik *p, PObj *pObj){
PList *pList = pObj->pSublist;
int i;
UNUSED_PARAMETER(p);
pik_bbox_init(&pObj->bbox);
| > > > > | 4257 4258 4259 4260 4261 4262 4263 4264 4265 4266 4267 4268 4269 4270 4271 4272 4273 4274 |
/* 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->errTok,3);
return boxOffset(p, pObj, cp);
}
static void textRender(Pik *p, PObj *pObj){
pik_append_txt(p, pObj, 0);
}
/* Methods for the "sublist" class */
static void sublistInit(Pik *p, PObj *pObj){
PList *pList = pObj->pSublist;
int i;
UNUSED_PARAMETER(p);
pik_bbox_init(&pObj->bbox);
|
| ︙ | ︙ | |||
4421 4422 4423 4424 4425 4426 4427 |
/* eJust */ 0,
/* xInit */ textInit,
/* xNumProp */ 0,
/* xCheck */ 0,
/* xChop */ boxChop,
/* xOffset */ textOffset,
/* xFit */ boxFit,
| | | 4425 4426 4427 4428 4429 4430 4431 4432 4433 4434 4435 4436 4437 4438 4439 |
/* eJust */ 0,
/* xInit */ textInit,
/* xNumProp */ 0,
/* xCheck */ 0,
/* xChop */ boxChop,
/* xOffset */ textOffset,
/* xFit */ boxFit,
/* xRender */ textRender
},
};
static const PClass sublistClass =
{ /* name */ "[]",
/* isline */ 0,
/* eJust */ 0,
/* xInit */ sublistInit,
|
| ︙ | ︙ | |||
4685 4686 4687 4688 4689 4690 4691 |
/* Append a PNum value surrounded by text. Do coordinate transformations
** on the value.
*/
static void pik_append_x(Pik *p, const char *z1, PNum v, const char *z2){
char buf[200];
v -= p->bbox.sw.x;
| | | | < | 4689 4690 4691 4692 4693 4694 4695 4696 4697 4698 4699 4700 4701 4702 4703 4704 4705 4706 4707 4708 4709 4710 4711 4712 4713 4714 4715 4716 4717 4718 |
/* Append a PNum value surrounded by text. Do coordinate transformations
** on the value.
*/
static void pik_append_x(Pik *p, const char *z1, PNum v, const char *z2){
char buf[200];
v -= p->bbox.sw.x;
snprintf(buf, sizeof(buf)-1, "%s%g%s", z1, p->rScale*v, z2);
buf[sizeof(buf)-1] = 0;
pik_append(p, buf, -1);
}
static void pik_append_y(Pik *p, const char *z1, PNum v, const char *z2){
char buf[200];
v = p->bbox.ne.y - v;
snprintf(buf, sizeof(buf)-1, "%s%g%s", z1, p->rScale*v, z2);
buf[sizeof(buf)-1] = 0;
pik_append(p, buf, -1);
}
static void pik_append_xy(Pik *p, const char *z1, PNum x, PNum y){
char buf[200];
x = x - p->bbox.sw.x;
y = p->bbox.ne.y - y;
snprintf(buf, sizeof(buf)-1, "%s%g,%g", z1, p->rScale*x, p->rScale*y);
buf[sizeof(buf)-1] = 0;
pik_append(p, buf, -1);
}
static void pik_append_dis(Pik *p, const char *z1, PNum v, const char *z2){
char buf[200];
snprintf(buf, sizeof(buf)-1, "%s%g%s", z1, p->rScale*v, z2);
buf[sizeof(buf)-1] = 0;
|
| ︙ | ︙ | |||
4746 4747 4748 4749 4750 4751 4752 |
**
** A r1 r2 0 0 0 x y
*/
static void pik_append_arc(Pik *p, PNum r1, PNum r2, PNum x, PNum y){
char buf[200];
x = x - p->bbox.sw.x;
y = p->bbox.ne.y - y;
| | | | | 4749 4750 4751 4752 4753 4754 4755 4756 4757 4758 4759 4760 4761 4762 4763 4764 4765 |
**
** A r1 r2 0 0 0 x y
*/
static void pik_append_arc(Pik *p, PNum r1, PNum r2, PNum x, PNum y){
char buf[200];
x = x - p->bbox.sw.x;
y = p->bbox.ne.y - y;
snprintf(buf, sizeof(buf)-1, "A%g %g 0 0 0 %g %g",
p->rScale*r1, p->rScale*r2,
p->rScale*x, p->rScale*y);
buf[sizeof(buf)-1] = 0;
pik_append(p, buf, -1);
}
/* Append a style="..." text. But, leave the quote unterminated, in case
** the caller wants to add some more.
**
|
| ︙ | ︙ | |||
4777 4778 4779 4780 4781 4782 4783 |
if( eFill==2 ) fillIsBg = 0;
if( eFill==3 ) clrIsBg = 1;
}
pik_append_clr(p, "fill:", pObj->fill, ";", fillIsBg);
}else{
pik_append(p,"fill:none;",-1);
}
| | | 4780 4781 4782 4783 4784 4785 4786 4787 4788 4789 4790 4791 4792 4793 4794 |
if( eFill==2 ) fillIsBg = 0;
if( eFill==3 ) clrIsBg = 1;
}
pik_append_clr(p, "fill:", pObj->fill, ";", fillIsBg);
}else{
pik_append(p,"fill:none;",-1);
}
if( pObj->sw>=0.0 && pObj->color>=0.0 ){
PNum sw = pObj->sw;
pik_append_dis(p, "stroke-width:", sw, ";");
if( pObj->nPath>2 && pObj->rad<=pObj->sw ){
pik_append(p, "stroke-linejoin:round;", -1);
}
pik_append_clr(p, "stroke:",pObj->color,";",clrIsBg);
if( pObj->dotted>0.0 ){
|
| ︙ | ︙ | |||
4904 4905 4906 4907 4908 4909 4910 4911 4912 4913 4914 4915 4916 4917 4918 4919 4920 4921 4922 4923 4924 |
PNum jw; /* Justification margin relative to center */
PNum ha2 = 0.0; /* Height of the top row of text */
PNum ha1 = 0.0; /* Height of the second "above" row */
PNum hc = 0.0; /* Height of the center row */
PNum hb1 = 0.0; /* Height of the first "below" row of text */
PNum hb2 = 0.0; /* Height of the second "below" row */
PNum yBase = 0.0;
int n, i, nz;
PNum x, y, orig_y, s;
const char *z;
PToken *aTxt;
unsigned allMask = 0;
if( p->nErr ) return;
if( pObj->nTxt==0 ) return;
aTxt = pObj->aTxt;
n = pObj->nTxt;
pik_txt_vertical_layout(pObj);
x = pObj->ptAt.x;
for(i=0; i<n; i++) allMask |= pObj->aTxt[i].eCode;
if( pObj->type->isLine ){
| > | | 4907 4908 4909 4910 4911 4912 4913 4914 4915 4916 4917 4918 4919 4920 4921 4922 4923 4924 4925 4926 4927 4928 4929 4930 4931 4932 4933 4934 4935 4936 |
PNum jw; /* Justification margin relative to center */
PNum ha2 = 0.0; /* Height of the top row of text */
PNum ha1 = 0.0; /* Height of the second "above" row */
PNum hc = 0.0; /* Height of the center row */
PNum hb1 = 0.0; /* Height of the first "below" row of text */
PNum hb2 = 0.0; /* Height of the second "below" row */
PNum yBase = 0.0;
PNum sw = pObj->sw>=0.0 ? pObj->sw : 0;
int n, i, nz;
PNum x, y, orig_y, s;
const char *z;
PToken *aTxt;
unsigned allMask = 0;
if( p->nErr ) return;
if( pObj->nTxt==0 ) return;
aTxt = pObj->aTxt;
n = pObj->nTxt;
pik_txt_vertical_layout(pObj);
x = pObj->ptAt.x;
for(i=0; i<n; i++) allMask |= pObj->aTxt[i].eCode;
if( pObj->type->isLine ){
hc = sw*1.5;
}else if( pObj->rad>0.0 && pObj->type->xInit==cylinderInit ){
yBase = -0.75*pObj->rad;
}
if( allMask & TP_CENTER ){
for(i=0; i<n; i++){
if( pObj->aTxt[i].eCode & TP_CENTER ){
s = pik_font_scale(pObj->aTxt+i);
|
| ︙ | ︙ | |||
4963 4964 4965 4966 4967 4968 4969 |
s = pik_font_scale(pObj->aTxt+i)*p->charHeight;
if( hb2<s ) hb2 = s;
}
}
}
}
if( pObj->type->eJust==1 ){
| | | > | > | 4967 4968 4969 4970 4971 4972 4973 4974 4975 4976 4977 4978 4979 4980 4981 4982 4983 4984 4985 4986 4987 4988 4989 4990 4991 4992 4993 4994 4995 4996 4997 4998 4999 5000 5001 5002 5003 5004 5005 5006 |
s = pik_font_scale(pObj->aTxt+i)*p->charHeight;
if( hb2<s ) hb2 = s;
}
}
}
}
if( pObj->type->eJust==1 ){
jw = 0.5*(pObj->w - 0.5*(p->charWidth + sw));
}else{
jw = 0.0;
}
for(i=0; i<n; i++){
PToken *t = &aTxt[i];
PNum xtraFontScale = pik_font_scale(t);
PNum nx = 0;
orig_y = pObj->ptAt.y;
y = yBase;
if( t->eCode & TP_ABOVE2 ) y += 0.5*hc + ha1 + 0.5*ha2;
if( t->eCode & TP_ABOVE ) y += 0.5*hc + 0.5*ha1;
if( t->eCode & TP_BELOW ) y -= 0.5*hc + 0.5*hb1;
if( t->eCode & TP_BELOW2 ) y -= 0.5*hc + hb1 + 0.5*hb2;
if( t->eCode & TP_LJUST ) nx -= jw;
if( t->eCode & TP_RJUST ) nx += jw;
if( pBox!=0 ){
/* If pBox is not NULL, do not draw any <text>. Instead, just expand
** pBox to include the text */
PNum cw = pik_text_length(t, t->eCode & TP_MONO)*p->charWidth*xtraFontScale*0.01;
PNum ch = p->charHeight*0.5*xtraFontScale;
PNum x0, y0, x1, y1; /* Boundary of text relative to pObj->ptAt */
if( (t->eCode & (TP_BOLD|TP_MONO))==TP_BOLD ){
cw *= 1.1;
}
if( t->eCode & TP_RJUST ){
x0 = nx;
y0 = y-ch;
x1 = nx-cw;
y1 = y+ch;
}else if( t->eCode & TP_LJUST ){
x0 = nx;
|
| ︙ | ︙ | |||
5042 5043 5044 5045 5046 5047 5048 5049 5050 5051 5052 5053 5054 5055 |
}
if( t->eCode & TP_ITALIC ){
pik_append(p, " font-style=\"italic\"", -1);
}
if( t->eCode & TP_BOLD ){
pik_append(p, " font-weight=\"bold\"", -1);
}
if( pObj->color>=0.0 ){
pik_append_clr(p, " fill=\"", pObj->color, "\"",0);
}
xtraFontScale *= p->fontScale;
if( xtraFontScale<=0.99 || xtraFontScale>=1.01 ){
pik_append_num(p, " font-size=\"", xtraFontScale*100.0);
pik_append(p, "%\"", 2);
| > > > | 5048 5049 5050 5051 5052 5053 5054 5055 5056 5057 5058 5059 5060 5061 5062 5063 5064 |
}
if( t->eCode & TP_ITALIC ){
pik_append(p, " font-style=\"italic\"", -1);
}
if( t->eCode & TP_BOLD ){
pik_append(p, " font-weight=\"bold\"", -1);
}
if( t->eCode & TP_MONO ){
pik_append(p, " font-family=\"monospace\"", -1);
}
if( pObj->color>=0.0 ){
pik_append_clr(p, " fill=\"", pObj->color, "\"",0);
}
xtraFontScale *= p->fontScale;
if( xtraFontScale<=0.99 || xtraFontScale>=1.01 ){
pik_append_num(p, " font-size=\"", xtraFontScale*100.0);
pik_append(p, "%\"", 2);
|
| ︙ | ︙ | |||
5097 5098 5099 5100 5101 5102 5103 | int iErrCol; /* Column of the error token on its line */ int iStart; /* Start position of the error context */ int iEnd; /* End position of the error context */ int iLineno; /* Line number of the error */ int iFirstLineno; /* Line number of start of error context */ int i; /* Loop counter */ int iBump = 0; /* Bump the location of the error cursor */ | | | 5106 5107 5108 5109 5110 5111 5112 5113 5114 5115 5116 5117 5118 5119 5120 |
int iErrCol; /* Column of the error token on its line */
int iStart; /* Start position of the error context */
int iEnd; /* End position of the error context */
int iLineno; /* Line number of the error */
int iFirstLineno; /* Line number of start of error context */
int i; /* Loop counter */
int iBump = 0; /* Bump the location of the error cursor */
char zLineno[24]; /* Buffer in which to generate line numbers */
iErrPt = (int)(pErr->z - p->sIn.z);
if( iErrPt>=(int)p->sIn.n ){
iErrPt = p->sIn.n-1;
iBump = 1;
}else{
while( iErrPt>0 && (p->sIn.z[iErrPt]=='\n' || p->sIn.z[iErrPt]=='\r') ){
|
| ︙ | ︙ | |||
6049 6050 6051 6052 6053 6054 6055 |
int iRes = iPrev;
switch( pFlag->eType ){
case T_LJUST: iRes = (iRes&~TP_JMASK) | TP_LJUST; break;
case T_RJUST: iRes = (iRes&~TP_JMASK) | TP_RJUST; break;
case T_ABOVE: iRes = (iRes&~TP_VMASK) | TP_ABOVE; break;
case T_CENTER: iRes = (iRes&~TP_VMASK) | TP_CENTER; break;
case T_BELOW: iRes = (iRes&~TP_VMASK) | TP_BELOW; break;
| | | > | 6058 6059 6060 6061 6062 6063 6064 6065 6066 6067 6068 6069 6070 6071 6072 6073 6074 |
int iRes = iPrev;
switch( pFlag->eType ){
case T_LJUST: iRes = (iRes&~TP_JMASK) | TP_LJUST; break;
case T_RJUST: iRes = (iRes&~TP_JMASK) | TP_RJUST; break;
case T_ABOVE: iRes = (iRes&~TP_VMASK) | TP_ABOVE; break;
case T_CENTER: iRes = (iRes&~TP_VMASK) | TP_CENTER; break;
case T_BELOW: iRes = (iRes&~TP_VMASK) | TP_BELOW; break;
case T_ITALIC: iRes |= TP_ITALIC; break;
case T_BOLD: iRes |= TP_BOLD; break;
case T_MONO: iRes |= TP_MONO; break;
case T_ALIGNED: iRes |= TP_ALIGN; break;
case T_BIG: if( iRes & TP_BIG ) iRes |= TP_XTRA;
else iRes = (iRes &~TP_SZMASK)|TP_BIG; break;
case T_SMALL: if( iRes & TP_SMALL ) iRes |= TP_XTRA;
else iRes = (iRes &~TP_SZMASK)|TP_SMALL; break;
}
return iRes;
|
| ︙ | ︙ | |||
6185 6186 6187 6188 6189 6190 6191 | ** in a character string. The returned value is 100 times the ** average character width. ** ** Omit "\" used to escape characters. And count entities like ** "<" as a single character. Multi-byte UTF8 characters count ** as a single character. ** | > | | | | > | | > > | | | 6195 6196 6197 6198 6199 6200 6201 6202 6203 6204 6205 6206 6207 6208 6209 6210 6211 6212 6213 6214 6215 6216 6217 6218 6219 6220 6221 6222 6223 6224 6225 6226 6227 6228 6229 6230 6231 6232 6233 6234 6235 6236 6237 6238 6239 6240 |
** in a character string. The returned value is 100 times the
** average character width.
**
** Omit "\" used to escape characters. And count entities like
** "<" as a single character. Multi-byte UTF8 characters count
** as a single character.
**
** Unless using a monospaced font, attempt to scale the answer by
** the actual characters seen. Wide characters count more than
** narrow characters. But the widths are only guesses.
**
*/
static int pik_text_length(const PToken *pToken, const int isMonospace){
const int stdAvg=100, monoAvg=82;
int n = pToken->n;
const char *z = pToken->z;
int cnt, j;
for(j=1, cnt=0; j<n-1; j++){
char c = z[j];
if( c=='\\' && z[j+1]!='&' ){
c = z[++j];
}else if( c=='&' ){
int k;
for(k=j+1; k<j+7 && z[k]!=0 && z[k]!=';'; k++){}
if( z[k]==';' ) j = k;
cnt += (isMonospace ? monoAvg : stdAvg) * 3 / 2;
continue;
}
if( (c & 0xc0)==0xc0 ){
while( j+1<n-1 && (z[j+1]&0xc0)==0x80 ){ j++; }
cnt += isMonospace ? monoAvg : stdAvg;
continue;
}
if( isMonospace ){
cnt += monoAvg;
}else if( c >= 0x20 && c <= 0x7e ){
cnt += awChar[c-0x20];
}else{
cnt += stdAvg;
}
}
return cnt;
}
/* Adjust the width, height, and/or radius of the object so that
** it fits around the text that has been added so far.
|
| ︙ | ︙ | |||
6579 6580 6581 6582 6583 6584 6585 | pObj->fill = pOther->fill; pObj->color = pOther->color; pObj->cw = pOther->cw; pObj->larrow = pOther->larrow; pObj->rarrow = pOther->rarrow; pObj->bClose = pOther->bClose; pObj->bChop = pOther->bChop; | < < | 6593 6594 6595 6596 6597 6598 6599 6600 6601 6602 6603 6604 6605 6606 | pObj->fill = pOther->fill; pObj->color = pOther->color; pObj->cw = pOther->cw; pObj->larrow = pOther->larrow; pObj->rarrow = pOther->rarrow; pObj->bClose = pOther->bClose; pObj->bChop = pOther->bChop; pObj->iLayer = pOther->iLayer; } /* Return a "Place" associated with object pObj. If pEdge is NULL ** return the center of the object. Otherwise, return the corner ** described by pEdge. |
| ︙ | ︙ | |||
7012 7013 7014 7015 7016 7017 7018 |
/* Add all objects of the list pList to the bounding box
*/
static void pik_bbox_add_elist(Pik *p, PList *pList, PNum wArrow){
int i;
for(i=0; i<pList->n; i++){
PObj *pObj = pList->a[i];
| | | 7024 7025 7026 7027 7028 7029 7030 7031 7032 7033 7034 7035 7036 7037 7038 |
/* Add all objects of the list pList to the bounding box
*/
static void pik_bbox_add_elist(Pik *p, PList *pList, PNum wArrow){
int i;
for(i=0; i<pList->n; i++){
PObj *pObj = pList->a[i];
if( pObj->sw>=0.0 ) pik_bbox_addbox(&p->bbox, &pObj->bbox);
pik_append_txt(p, pObj, &p->bbox);
if( pObj->pSublist ) pik_bbox_add_elist(p, pObj->pSublist, wArrow);
/* Expand the bounding box to account for arrowheads on lines */
if( pObj->type->isLine && pObj->nPath>0 ){
if( pObj->larrow ){
|
| ︙ | ︙ | |||
7200 7201 7202 7203 7204 7205 7206 7207 7208 7209 7210 7211 7212 7213 |
{ "invisible", 9, T_INVIS, 0, 0 },
{ "italic", 6, T_ITALIC, 0, 0 },
{ "last", 4, T_LAST, 0, 0 },
{ "left", 4, T_LEFT, DIR_LEFT, CP_W },
{ "ljust", 5, T_LJUST, 0, 0 },
{ "max", 3, T_FUNC2, FN_MAX, 0 },
{ "min", 3, T_FUNC2, FN_MIN, 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 },
| > > | 7212 7213 7214 7215 7216 7217 7218 7219 7220 7221 7222 7223 7224 7225 7226 7227 |
{ "invisible", 9, T_INVIS, 0, 0 },
{ "italic", 6, T_ITALIC, 0, 0 },
{ "last", 4, T_LAST, 0, 0 },
{ "left", 4, T_LEFT, DIR_LEFT, CP_W },
{ "ljust", 5, T_LJUST, 0, 0 },
{ "max", 3, T_FUNC2, FN_MAX, 0 },
{ "min", 3, T_FUNC2, FN_MIN, 0 },
{ "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 },
|
| ︙ | ︙ | |||
8127 8128 8129 8130 8131 8132 8133 | return TCL_OK; } #endif /* PIKCHR_TCL */ | | | 8141 8142 8143 8144 8145 8146 8147 8148 | return TCL_OK; } #endif /* PIKCHR_TCL */ #line 8173 "pikchr.c" |
Changes to extsrc/pikchr.js.
1 2 3 4 5 |
var initPikchrModule = (() => {
var _scriptDir = typeof document !== 'undefined' && document.currentScript ? document.currentScript.src : undefined;
return (
| | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
var initPikchrModule = (() => {
var _scriptDir = typeof document !== 'undefined' && document.currentScript ? document.currentScript.src : undefined;
return (
function(config) {
var initPikchrModule = config || {};
var Module = typeof initPikchrModule != "undefined" ? initPikchrModule : {};
var readyPromiseResolve, readyPromiseReject;
Module["ready"] = new Promise(function(resolve, reject) {
readyPromiseResolve = resolve;
|
| ︙ | ︙ | |||
114 115 116 117 118 119 120 | var wasmMemory; var ABORT = false; var EXITSTATUS; | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < > | | | | | | | | | | | | | | | | | | | | | | | < | 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 |
var wasmMemory;
var ABORT = false;
var EXITSTATUS;
var UTF8Decoder = typeof TextDecoder != "undefined" ? new TextDecoder("utf8") : undefined;
function UTF8ArrayToString(heapOrArray, idx, maxBytesToRead) {
var endIdx = idx + maxBytesToRead;
var endPtr = idx;
while (heapOrArray[endPtr] && !(endPtr >= endIdx)) ++endPtr;
if (endPtr - idx > 16 && heapOrArray.buffer && UTF8Decoder) {
return UTF8Decoder.decode(heapOrArray.subarray(idx, endPtr));
}
var str = "";
while (idx < endPtr) {
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;
}
function UTF8ToString(ptr, maxBytesToRead) {
return ptr ? UTF8ArrayToString(HEAPU8, ptr, maxBytesToRead) : "";
|
| ︙ | ︙ | |||
260 261 262 263 264 265 266 |
return outIdx - startIdx;
}
function stringToUTF8(str, outPtr, maxBytesToWrite) {
return stringToUTF8Array(str, HEAPU8, outPtr, maxBytesToWrite);
}
| < < < < | | | | | | | | | | | | 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 |
return outIdx - startIdx;
}
function stringToUTF8(str, outPtr, maxBytesToWrite) {
return stringToUTF8Array(str, HEAPU8, outPtr, maxBytesToWrite);
}
var HEAP8, HEAPU8, HEAP16, HEAPU16, HEAP32, HEAPU32, HEAPF32, HEAPF64;
function updateMemoryViews() {
var b = wasmMemory.buffer;
Module["HEAP8"] = HEAP8 = new Int8Array(b);
Module["HEAP16"] = HEAP16 = new Int16Array(b);
Module["HEAP32"] = HEAP32 = new Int32Array(b);
Module["HEAPU8"] = HEAPU8 = new Uint8Array(b);
Module["HEAPU16"] = HEAPU16 = new Uint16Array(b);
Module["HEAPU32"] = HEAPU32 = new Uint32Array(b);
Module["HEAPF32"] = HEAPF32 = new Float32Array(b);
Module["HEAPF64"] = HEAPF64 = new Float64Array(b);
}
var INITIAL_MEMORY = Module["INITIAL_MEMORY"] || 16777216;
var wasmTable;
var __ATPRERUN__ = [];
|
| ︙ | ︙ | |||
363 364 365 366 367 368 369 |
dependenciesFulfilled = null;
callback();
}
}
}
function abort(what) {
| < | | < | 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 |
dependenciesFulfilled = null;
callback();
}
}
}
function abort(what) {
if (Module["onAbort"]) {
Module["onAbort"](what);
}
what = "Aborted(" + what + ")";
err(what);
ABORT = true;
EXITSTATUS = 1;
what += ". Build with -sASSERTIONS for more info.";
var e = new WebAssembly.RuntimeError(what);
|
| ︙ | ︙ | |||
399 400 401 402 403 404 405 |
function getBinary(file) {
try {
if (file == wasmBinaryFile && wasmBinary) {
return new Uint8Array(wasmBinary);
}
if (readBinary) {
return readBinary(file);
| < < > | 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 |
function getBinary(file) {
try {
if (file == wasmBinaryFile && wasmBinary) {
return new Uint8Array(wasmBinary);
}
if (readBinary) {
return readBinary(file);
}
throw "both async and sync fetching of the wasm failed";
} catch (err) {
abort(err);
}
}
function getBinaryPromise() {
if (!wasmBinary && (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER)) {
|
| ︙ | ︙ | |||
435 436 437 438 439 440 441 |
var info = {
"a": asmLibraryArg
};
function receiveInstance(instance, module) {
var exports = instance.exports;
Module["asm"] = exports;
wasmMemory = Module["asm"]["d"];
| | | 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 |
var info = {
"a": asmLibraryArg
};
function receiveInstance(instance, module) {
var exports = instance.exports;
Module["asm"] = exports;
wasmMemory = Module["asm"]["d"];
updateMemoryViews();
wasmTable = Module["asm"]["g"];
addOnInit(Module["asm"]["e"]);
removeRunDependency("wasm-instantiate");
}
addRunDependency("wasm-instantiate");
function receiveInstantiationResult(result) {
receiveInstance(result["instance"]);
|
| ︙ | ︙ | |||
476 477 478 479 480 481 482 |
}
if (Module["instantiateWasm"]) {
try {
var exports = Module["instantiateWasm"](info, receiveInstance);
return exports;
} catch (e) {
err("Module.instantiateWasm callback failed with error: " + e);
| | > > > > > > | < < < < < < < < < < < < < < | | > > > < < < < | | 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 |
}
if (Module["instantiateWasm"]) {
try {
var exports = Module["instantiateWasm"](info, receiveInstance);
return exports;
} catch (e) {
err("Module.instantiateWasm callback failed with error: " + e);
readyPromiseReject(e);
}
}
instantiateAsync().catch(readyPromiseReject);
return {};
}
var tempDouble;
var tempI64;
function ExitStatus(status) {
this.name = "ExitStatus";
this.message = "Program terminated with exit(" + status + ")";
this.status = status;
}
function callRuntimeCallbacks(callbacks) {
while (callbacks.length > 0) {
callbacks.shift()(Module);
}
}
function getValue(ptr, type = "i8") {
if (type.endsWith("*")) type = "*";
switch (type) {
case "i1":
return HEAP8[ptr >> 0];
case "i8":
return HEAP8[ptr >> 0];
case "i16":
return HEAP16[ptr >> 1];
case "i32":
return HEAP32[ptr >> 2];
case "i64":
return HEAP32[ptr >> 2];
case "float":
return HEAPF32[ptr >> 2];
case "double":
return HEAPF64[ptr >> 3];
case "*":
return HEAPU32[ptr >> 2];
default:
abort("invalid type for getValue: " + type);
}
return null;
}
function setValue(ptr, value, type = "i8") {
if (type.endsWith("*")) type = "*";
switch (type) {
case "i1":
HEAP8[ptr >> 0] = value;
break;
case "i8":
HEAP8[ptr >> 0] = value;
|
| ︙ | ︙ | |||
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 |
case "float":
HEAPF32[ptr >> 2] = value;
break;
case "double":
HEAPF64[ptr >> 3] = value;
break;
default:
abort("invalid type for setValue: " + type);
}
}
function ___assert_fail(condition, filename, line, func) {
abort("Assertion failed: " + UTF8ToString(condition) + ", at: " + [ filename ? UTF8ToString(filename) : "unknown filename", line, func ? UTF8ToString(func) : "unknown function" ]);
}
function abortOnCannotGrowMemory(requestedSize) {
abort("OOM");
}
function _emscripten_resize_heap(requestedSize) {
var oldSize = HEAPU8.length;
requestedSize = requestedSize >>> 0;
abortOnCannotGrowMemory(requestedSize);
}
| > > > > > > | > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 |
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);
}
}
function ___assert_fail(condition, filename, line, func) {
abort("Assertion failed: " + UTF8ToString(condition) + ", at: " + [ filename ? UTF8ToString(filename) : "unknown filename", line, func ? UTF8ToString(func) : "unknown function" ]);
}
function abortOnCannotGrowMemory(requestedSize) {
abort("OOM");
}
function _emscripten_resize_heap(requestedSize) {
var oldSize = HEAPU8.length;
requestedSize = requestedSize >>> 0;
abortOnCannotGrowMemory(requestedSize);
}
var SYSCALLS = {
varargs: undefined,
get: function() {
SYSCALLS.varargs += 4;
var ret = HEAP32[SYSCALLS.varargs - 4 >> 2];
return ret;
},
getStr: function(ptr) {
var ret = UTF8ToString(ptr);
return ret;
}
};
function _proc_exit(code) {
EXITSTATUS = code;
if (!keepRuntimeAlive()) {
if (Module["onExit"]) Module["onExit"](code);
ABORT = true;
}
quit_(code, new ExitStatus(code));
}
function exitJS(status, implicit) {
EXITSTATUS = status;
_proc_exit(status);
}
var _exit = exitJS;
function getCFunc(ident) {
var func = Module["_" + ident];
return func;
}
function writeArrayToMemory(array, buffer) {
HEAP8.set(array, buffer);
}
function ccall(ident, returnType, argTypes, args, opts) {
var toC = {
"string": str => {
var ret = 0;
if (str !== null && str !== undefined && str !== 0) {
var len = (str.length << 2) + 1;
ret = stackAlloc(len);
stringToUTF8(str, ret, len);
}
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.apply(null, cArgs);
function onDone(ret) {
if (stack !== 0) stackRestore(stack);
return convertReturnValue(ret);
}
ret = onDone(ret);
return ret;
}
function cwrap(ident, returnType, argTypes, opts) {
argTypes = argTypes || [];
var numericArgs = argTypes.every(type => type === "number" || type === "boolean");
var numericRet = returnType !== "string";
if (numericRet && numericArgs && !opts) {
return getCFunc(ident);
}
return function() {
return ccall(ident, returnType, argTypes, arguments, opts);
};
}
var asmLibraryArg = {
"a": ___assert_fail,
"b": _emscripten_resize_heap,
"c": _exit
};
|
| ︙ | ︙ | |||
624 625 626 627 628 629 630 |
return (stackRestore = Module["stackRestore"] = Module["asm"]["i"]).apply(null, arguments);
};
var stackAlloc = Module["stackAlloc"] = function() {
return (stackAlloc = Module["stackAlloc"] = Module["asm"]["j"]).apply(null, arguments);
};
| < < > > < < < < < < | 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 |
return (stackRestore = Module["stackRestore"] = Module["asm"]["i"]).apply(null, arguments);
};
var stackAlloc = Module["stackAlloc"] = function() {
return (stackAlloc = Module["stackAlloc"] = Module["asm"]["j"]).apply(null, arguments);
};
Module["stackSave"] = stackSave;
Module["stackRestore"] = stackRestore;
Module["cwrap"] = cwrap;
Module["setValue"] = setValue;
Module["getValue"] = getValue;
var calledRun;
dependenciesFulfilled = function runCaller() {
if (!calledRun) run();
if (!calledRun) dependenciesFulfilled = runCaller;
};
function run(args) {
args = args || arguments_;
|
| ︙ | ︙ | |||
679 680 681 682 683 684 685 |
doRun();
}, 1);
} else {
doRun();
}
}
| < < < < < < < < < < < < < < < < | 687 688 689 690 691 692 693 694 695 696 697 698 699 700 |
doRun();
}, 1);
} else {
doRun();
}
}
if (Module["preInit"]) {
if (typeof Module["preInit"] == "function") Module["preInit"] = [ Module["preInit"] ];
while (Module["preInit"].length > 0) {
Module["preInit"].pop()();
}
}
|
| ︙ | ︙ |
Changes to extsrc/pikchr.wasm.
cannot compute difference between binary files
Changes to extsrc/shell.c.
more than 10,000 changes
Changes to extsrc/sqlite3.c.
more than 10,000 changes
Changes to extsrc/sqlite3.h.
| ︙ | ︙ | |||
142 143 144 145 146 147 148 | ** been edited in any way since it was last checked in, then the last ** four hexadecimal digits of the hash may be modified. ** ** See also: [sqlite3_libversion()], ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ | | | | | 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 | ** been edited in any way since it was last checked in, then the last ** four hexadecimal digits of the hash may be modified. ** ** See also: [sqlite3_libversion()], ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ #define SQLITE_VERSION "3.45.0" #define SQLITE_VERSION_NUMBER 3045000 #define SQLITE_SOURCE_ID "2024-01-09 12:28:51 97709ce2a1f5ae05495e412ca27108048e5b8a63a1e3bca4be13933f7527da7b" /* ** 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 |
| ︙ | ︙ | |||
524 525 526 527 528 529 530 531 532 533 534 535 536 537 | #define SQLITE_IOERR_VNODE (SQLITE_IOERR | (27<<8)) #define SQLITE_IOERR_AUTH (SQLITE_IOERR | (28<<8)) #define SQLITE_IOERR_BEGIN_ATOMIC (SQLITE_IOERR | (29<<8)) #define SQLITE_IOERR_COMMIT_ATOMIC (SQLITE_IOERR | (30<<8)) #define SQLITE_IOERR_ROLLBACK_ATOMIC (SQLITE_IOERR | (31<<8)) #define SQLITE_IOERR_DATA (SQLITE_IOERR | (32<<8)) #define SQLITE_IOERR_CORRUPTFS (SQLITE_IOERR | (33<<8)) #define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8)) #define SQLITE_LOCKED_VTAB (SQLITE_LOCKED | (2<<8)) #define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8)) #define SQLITE_BUSY_SNAPSHOT (SQLITE_BUSY | (2<<8)) #define SQLITE_BUSY_TIMEOUT (SQLITE_BUSY | (3<<8)) #define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8)) #define SQLITE_CANTOPEN_ISDIR (SQLITE_CANTOPEN | (2<<8)) | > | 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 | #define SQLITE_IOERR_VNODE (SQLITE_IOERR | (27<<8)) #define SQLITE_IOERR_AUTH (SQLITE_IOERR | (28<<8)) #define SQLITE_IOERR_BEGIN_ATOMIC (SQLITE_IOERR | (29<<8)) #define SQLITE_IOERR_COMMIT_ATOMIC (SQLITE_IOERR | (30<<8)) #define SQLITE_IOERR_ROLLBACK_ATOMIC (SQLITE_IOERR | (31<<8)) #define SQLITE_IOERR_DATA (SQLITE_IOERR | (32<<8)) #define SQLITE_IOERR_CORRUPTFS (SQLITE_IOERR | (33<<8)) #define SQLITE_IOERR_IN_PAGE (SQLITE_IOERR | (34<<8)) #define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8)) #define SQLITE_LOCKED_VTAB (SQLITE_LOCKED | (2<<8)) #define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8)) #define SQLITE_BUSY_SNAPSHOT (SQLITE_BUSY | (2<<8)) #define SQLITE_BUSY_TIMEOUT (SQLITE_BUSY | (3<<8)) #define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8)) #define SQLITE_CANTOPEN_ISDIR (SQLITE_CANTOPEN | (2<<8)) |
| ︙ | ︙ | |||
559 560 561 562 563 564 565 566 567 568 569 570 571 572 | #define SQLITE_CONSTRAINT_UNIQUE (SQLITE_CONSTRAINT | (8<<8)) #define SQLITE_CONSTRAINT_VTAB (SQLITE_CONSTRAINT | (9<<8)) #define SQLITE_CONSTRAINT_ROWID (SQLITE_CONSTRAINT |(10<<8)) #define SQLITE_CONSTRAINT_PINNED (SQLITE_CONSTRAINT |(11<<8)) #define SQLITE_CONSTRAINT_DATATYPE (SQLITE_CONSTRAINT |(12<<8)) #define SQLITE_NOTICE_RECOVER_WAL (SQLITE_NOTICE | (1<<8)) #define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2<<8)) #define SQLITE_WARNING_AUTOINDEX (SQLITE_WARNING | (1<<8)) #define SQLITE_AUTH_USER (SQLITE_AUTH | (1<<8)) #define SQLITE_OK_LOAD_PERMANENTLY (SQLITE_OK | (1<<8)) #define SQLITE_OK_SYMLINK (SQLITE_OK | (2<<8)) /* internal use only */ /* ** CAPI3REF: Flags For File Open Operations | > | 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 | #define SQLITE_CONSTRAINT_UNIQUE (SQLITE_CONSTRAINT | (8<<8)) #define SQLITE_CONSTRAINT_VTAB (SQLITE_CONSTRAINT | (9<<8)) #define SQLITE_CONSTRAINT_ROWID (SQLITE_CONSTRAINT |(10<<8)) #define SQLITE_CONSTRAINT_PINNED (SQLITE_CONSTRAINT |(11<<8)) #define SQLITE_CONSTRAINT_DATATYPE (SQLITE_CONSTRAINT |(12<<8)) #define SQLITE_NOTICE_RECOVER_WAL (SQLITE_NOTICE | (1<<8)) #define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2<<8)) #define SQLITE_NOTICE_RBU (SQLITE_NOTICE | (3<<8)) #define SQLITE_WARNING_AUTOINDEX (SQLITE_WARNING | (1<<8)) #define SQLITE_AUTH_USER (SQLITE_AUTH | (1<<8)) #define SQLITE_OK_LOAD_PERMANENTLY (SQLITE_OK | (1<<8)) #define SQLITE_OK_SYMLINK (SQLITE_OK | (2<<8)) /* internal use only */ /* ** CAPI3REF: Flags For File Open Operations |
| ︙ | ︙ | |||
666 667 668 669 670 671 672 | #define SQLITE_IOCAP_BATCH_ATOMIC 0x00004000 /* ** CAPI3REF: File Locking Levels ** ** SQLite uses one of these integer values as the second ** argument to calls it makes to the xLock() and xUnlock() methods | | > > > > | | | | | | 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 | #define SQLITE_IOCAP_BATCH_ATOMIC 0x00004000 /* ** CAPI3REF: File Locking Levels ** ** SQLite uses one of these integer values as the second ** argument to calls it makes to the xLock() and xUnlock() methods ** of an [sqlite3_io_methods] object. These values are ordered from ** lest restrictive to most restrictive. ** ** The argument to xLock() is always SHARED or higher. The argument to ** xUnlock is either SHARED or NONE. */ #define SQLITE_LOCK_NONE 0 /* xUnlock() only */ #define SQLITE_LOCK_SHARED 1 /* xLock() or xUnlock() */ #define SQLITE_LOCK_RESERVED 2 /* xLock() only */ #define SQLITE_LOCK_PENDING 3 /* xLock() only */ #define SQLITE_LOCK_EXCLUSIVE 4 /* xLock() only */ /* ** CAPI3REF: Synchronization Type Flags ** ** When SQLite invokes the xSync() method of an ** [sqlite3_io_methods] object it uses a combination of ** these integer values as the second argument. |
| ︙ | ︙ | |||
750 751 752 753 754 755 756 | ** <ul> ** <li> [SQLITE_LOCK_NONE], ** <li> [SQLITE_LOCK_SHARED], ** <li> [SQLITE_LOCK_RESERVED], ** <li> [SQLITE_LOCK_PENDING], or ** <li> [SQLITE_LOCK_EXCLUSIVE]. ** </ul> | > > > > > > > | | 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 | ** <ul> ** <li> [SQLITE_LOCK_NONE], ** <li> [SQLITE_LOCK_SHARED], ** <li> [SQLITE_LOCK_RESERVED], ** <li> [SQLITE_LOCK_PENDING], or ** <li> [SQLITE_LOCK_EXCLUSIVE]. ** </ul> ** xLock() upgrades the database file lock. In other words, xLock() moves the ** database file lock in the direction NONE toward EXCLUSIVE. The argument to ** xLock() is always on of SHARED, RESERVED, PENDING, or EXCLUSIVE, never ** SQLITE_LOCK_NONE. If the database file lock is already at or above the ** requested lock, then the call to xLock() is a no-op. ** xUnlock() downgrades the database file lock to either SHARED or NONE. * If the lock is already at or below the requested lock state, then the call ** to xUnlock() is a no-op. ** The xCheckReservedLock() method checks whether any database connection, ** either in this process or in some other process, is holding a RESERVED, ** PENDING, or EXCLUSIVE lock on the file. It returns true ** if such a lock exists and false otherwise. ** ** The xFileControl() method is a generic interface that allows custom ** VFS implementations to directly control an open file using the |
| ︙ | ︙ | |||
855 856 857 858 859 860 861 | ** ** <ul> ** <li>[[SQLITE_FCNTL_LOCKSTATE]] ** The [SQLITE_FCNTL_LOCKSTATE] opcode is used for debugging. This ** opcode causes the xFileControl method to write the current state of ** the lock (one of [SQLITE_LOCK_NONE], [SQLITE_LOCK_SHARED], ** [SQLITE_LOCK_RESERVED], [SQLITE_LOCK_PENDING], or [SQLITE_LOCK_EXCLUSIVE]) | | | < | 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 | ** ** <ul> ** <li>[[SQLITE_FCNTL_LOCKSTATE]] ** The [SQLITE_FCNTL_LOCKSTATE] opcode is used for debugging. This ** opcode causes the xFileControl method to write the current state of ** the lock (one of [SQLITE_LOCK_NONE], [SQLITE_LOCK_SHARED], ** [SQLITE_LOCK_RESERVED], [SQLITE_LOCK_PENDING], or [SQLITE_LOCK_EXCLUSIVE]) ** into an integer that the pArg argument points to. ** This capability is only available if SQLite is compiled with [SQLITE_DEBUG]. ** ** <li>[[SQLITE_FCNTL_SIZE_HINT]] ** The [SQLITE_FCNTL_SIZE_HINT] opcode is used by SQLite to give the VFS ** layer a hint of how large the database file will grow to be during the ** current transaction. This hint is not guaranteed to be accurate but it ** is often close. The underlying VFS might choose to preallocate database ** file space based on this hint in order to help writes to the database |
| ︙ | ︙ | |||
1161 1162 1163 1164 1165 1166 1167 | ** file to the database file. ** ** <li>[[SQLITE_FCNTL_CKPT_DONE]] ** The [SQLITE_FCNTL_CKPT_DONE] opcode is invoked from within a checkpoint ** in wal mode after the client has finished copying pages from the wal ** file to the database file, but before the *-shm file is updated to ** record the fact that the pages have been checkpointed. | < | > > > | < > > > > | 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 | ** file to the database file. ** ** <li>[[SQLITE_FCNTL_CKPT_DONE]] ** The [SQLITE_FCNTL_CKPT_DONE] opcode is invoked from within a checkpoint ** in wal mode after the client has finished copying pages from the wal ** file to the database file, but before the *-shm file is updated to ** record the fact that the pages have been checkpointed. ** ** <li>[[SQLITE_FCNTL_EXTERNAL_READER]] ** The EXPERIMENTAL [SQLITE_FCNTL_EXTERNAL_READER] opcode is used to detect ** whether or not there is a database client in another process with a wal-mode ** transaction open on the database or not. It is only available on unix.The ** (void*) argument passed with this file-control should be a pointer to a ** value of type (int). The integer value is set to 1 if the database is a wal ** mode database and there exists at least one client in another process that ** currently has an SQL transaction open on the database. It is set to 0 if ** the database is not a wal-mode db, or if there is no such connection in any ** other process. This opcode cannot be used to detect transactions opened ** by clients within the current process, only within other processes. ** ** <li>[[SQLITE_FCNTL_CKSM_FILE]] ** The [SQLITE_FCNTL_CKSM_FILE] opcode is for use internally by the ** [checksum VFS shim] only. ** ** <li>[[SQLITE_FCNTL_RESET_CACHE]] ** If there is currently no transaction open on the database, and the ** database is not a temp db, then the [SQLITE_FCNTL_RESET_CACHE] file-control ** purges the contents of the in-memory page cache. If there is an open ** transaction, or if the db is a temp-db, this opcode is a no-op, not an error. ** </ul> */ #define SQLITE_FCNTL_LOCKSTATE 1 #define SQLITE_FCNTL_GET_LOCKPROXYFILE 2 #define SQLITE_FCNTL_SET_LOCKPROXYFILE 3 #define SQLITE_FCNTL_LAST_ERRNO 4 #define SQLITE_FCNTL_SIZE_HINT 5 |
| ︙ | ︙ | |||
1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 | #define SQLITE_FCNTL_DATA_VERSION 35 #define SQLITE_FCNTL_SIZE_LIMIT 36 #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 /* 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 | > | 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 | #define SQLITE_FCNTL_DATA_VERSION 35 #define SQLITE_FCNTL_SIZE_LIMIT 36 #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 /* 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 |
| ︙ | ︙ | |||
1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 | ** A pointer to the opaque sqlite3_api_routines structure is passed as ** the third parameter to entry points of [loadable extensions]. This ** structure must be typedefed in order to work around compiler warnings ** on some platforms. */ typedef struct sqlite3_api_routines sqlite3_api_routines; /* ** CAPI3REF: OS Interface Object ** ** An instance of the sqlite3_vfs object defines the interface between ** the SQLite core and the underlying operating system. The "vfs" ** in the name of the object stands for "virtual file system". See ** the [VFS | VFS documentation] for further information. | > > > > > > > > > > > > > > > > > > > > | 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 | ** A pointer to the opaque sqlite3_api_routines structure is passed as ** the third parameter to entry points of [loadable extensions]. This ** structure must be typedefed in order to work around compiler warnings ** on some platforms. */ typedef struct sqlite3_api_routines sqlite3_api_routines; /* ** CAPI3REF: File Name ** ** Type [sqlite3_filename] is used by SQLite to pass filenames to the ** xOpen method of a [VFS]. It may be cast to (const char*) and treated ** as a normal, nul-terminated, UTF-8 buffer containing the filename, but ** may also be passed to special APIs such as: ** ** <ul> ** <li> sqlite3_filename_database() ** <li> sqlite3_filename_journal() ** <li> sqlite3_filename_wal() ** <li> sqlite3_uri_parameter() ** <li> sqlite3_uri_boolean() ** <li> sqlite3_uri_int64() ** <li> sqlite3_uri_key() ** </ul> */ typedef const char *sqlite3_filename; /* ** CAPI3REF: OS Interface Object ** ** An instance of the sqlite3_vfs object defines the interface between ** the SQLite core and the underlying operating system. The "vfs" ** in the name of the object stands for "virtual file system". See ** the [VFS | VFS documentation] for further information. |
| ︙ | ︙ | |||
1427 1428 1429 1430 1431 1432 1433 |
struct sqlite3_vfs {
int iVersion; /* Structure version number (currently 3) */
int szOsFile; /* Size of subclassed sqlite3_file */
int mxPathname; /* Maximum file pathname length */
sqlite3_vfs *pNext; /* Next registered VFS */
const char *zName; /* Name of this virtual file system */
void *pAppData; /* Pointer to application-specific data */
| | | 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 |
struct sqlite3_vfs {
int iVersion; /* Structure version number (currently 3) */
int szOsFile; /* Size of subclassed sqlite3_file */
int mxPathname; /* Maximum file pathname length */
sqlite3_vfs *pNext; /* Next registered VFS */
const char *zName; /* Name of this virtual file system */
void *pAppData; /* Pointer to application-specific data */
int (*xOpen)(sqlite3_vfs*, sqlite3_filename zName, sqlite3_file*,
int flags, int *pOutFlags);
int (*xDelete)(sqlite3_vfs*, const char *zName, int syncDir);
int (*xAccess)(sqlite3_vfs*, const char *zName, int flags, int *pResOut);
int (*xFullPathname)(sqlite3_vfs*, const char *zName, int nOut, char *zOut);
void *(*xDlOpen)(sqlite3_vfs*, const char *zFilename);
void (*xDlError)(sqlite3_vfs*, int nByte, char *zErrMsg);
void (*(*xDlSym)(sqlite3_vfs*,void*, const char *zSymbol))(void);
|
| ︙ | ︙ | |||
1614 1615 1616 1617 1618 1619 1620 | ** applications and so this routine is usually not necessary. It is ** provided to support rare applications with unusual needs. ** ** <b>The sqlite3_config() interface is not threadsafe. The application ** must ensure that no other SQLite interfaces are invoked by other ** threads while sqlite3_config() is running.</b> ** | < < < < < < < < > > > > > > > > > > > | 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 | ** applications and so this routine is usually not necessary. It is ** provided to support rare applications with unusual needs. ** ** <b>The sqlite3_config() interface is not threadsafe. The application ** must ensure that no other SQLite interfaces are invoked by other ** threads while sqlite3_config() is running.</b> ** ** The first argument to sqlite3_config() is an integer ** [configuration option] that determines ** what property of SQLite is to be configured. Subsequent arguments ** vary depending on the [configuration option] ** in the first argument. ** ** For most configuration options, the sqlite3_config() interface ** may only be invoked prior to library initialization using ** [sqlite3_initialize()] or after shutdown by [sqlite3_shutdown()]. ** The exceptional configuration options that may be invoked at any time ** are called "anytime configuration options". ** ^If sqlite3_config() is called after [sqlite3_initialize()] and before ** [sqlite3_shutdown()] with a first argument that is not an anytime ** configuration option, then the sqlite3_config() call will return SQLITE_MISUSE. ** Note, however, that ^sqlite3_config() can be called as part of the ** implementation of an application-defined [sqlite3_os_init()]. ** ** ^When a configuration option is set, sqlite3_config() returns [SQLITE_OK]. ** ^If the option is unknown or SQLite is unable to set the option ** then this routine returns a non-zero [error code]. */ SQLITE_API int sqlite3_config(int, ...); |
| ︙ | ︙ | |||
1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 |
/*
** CAPI3REF: Configuration Options
** KEYWORDS: {configuration option}
**
** These constants are the available integer configuration options that
** can be passed as the first argument to the [sqlite3_config()] interface.
**
** New configuration options may be added in future releases of SQLite.
** Existing configuration options might be discontinued. Applications
** should check the return code from [sqlite3_config()] to make sure that
** the call worked. The [sqlite3_config()] interface will return a
** non-zero [error code] if a discontinued or unsupported configuration option
** is invoked.
| > > > > > > > > > > > > > > > > > | 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 |
/*
** CAPI3REF: Configuration Options
** KEYWORDS: {configuration option}
**
** These constants are the available integer configuration options that
** can be passed as the first argument to the [sqlite3_config()] interface.
**
** Most of the configuration options for sqlite3_config()
** will only work if invoked prior to [sqlite3_initialize()] or after
** [sqlite3_shutdown()]. The few exceptions to this rule are called
** "anytime configuration options".
** ^Calling [sqlite3_config()] with a first argument that is not an
** anytime configuration option in between calls to [sqlite3_initialize()] and
** [sqlite3_shutdown()] is a no-op that returns SQLITE_MISUSE.
**
** The set of anytime configuration options can change (by insertions
** and/or deletions) from one release of SQLite to the next.
** As of SQLite version 3.42.0, the complete set of anytime configuration
** options is:
** <ul>
** <li> SQLITE_CONFIG_LOG
** <li> SQLITE_CONFIG_PCACHE_HDRSZ
** </ul>
**
** New configuration options may be added in future releases of SQLite.
** Existing configuration options might be discontinued. Applications
** should check the return code from [sqlite3_config()] to make sure that
** the call worked. The [sqlite3_config()] interface will return a
** non-zero [error code] if a discontinued or unsupported configuration option
** is invoked.
|
| ︙ | ︙ | |||
2065 2066 2067 2068 2069 2070 2071 | ** to an ORDER BY clause, all fields required by the caller are present in the ** sorted records. However, if SQLite determines based on the declared type ** of a table column that its values are likely to be very large - larger ** than the configured sorter-reference size threshold - then a reference ** is stored in each sorted record and the required column values loaded ** from the database as records are returned in sorted order. The default ** value for this option is to never use this optimization. Specifying a | | | | | | | | | | | | | | | | | | | | | | | | 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 | ** to an ORDER BY clause, all fields required by the caller are present in the ** sorted records. However, if SQLite determines based on the declared type ** of a table column that its values are likely to be very large - larger ** than the configured sorter-reference size threshold - then a reference ** is stored in each sorted record and the required column values loaded ** from the database as records are returned in sorted order. The default ** value for this option is to never use this optimization. Specifying a ** negative value for this option restores the default behavior. ** This option is only available if SQLite is compiled with the ** [SQLITE_ENABLE_SORTER_REFERENCES] compile-time option. ** ** [[SQLITE_CONFIG_MEMDB_MAXSIZE]] ** <dt>SQLITE_CONFIG_MEMDB_MAXSIZE ** <dd>The SQLITE_CONFIG_MEMDB_MAXSIZE option accepts a single parameter ** [sqlite3_int64] parameter which is the default maximum size for an in-memory ** database created using [sqlite3_deserialize()]. This default maximum ** size can be adjusted up or down for individual databases using the ** [SQLITE_FCNTL_SIZE_LIMIT] [sqlite3_file_control|file-control]. If this ** configuration setting is never used, then the default maximum is determined ** by the [SQLITE_MEMDB_DEFAULT_MAXSIZE] compile-time option. If that ** compile-time option is not set, then the default maximum is 1073741824. ** </dl> */ #define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */ #define SQLITE_CONFIG_MULTITHREAD 2 /* nil */ #define SQLITE_CONFIG_SERIALIZED 3 /* nil */ #define SQLITE_CONFIG_MALLOC 4 /* sqlite3_mem_methods* */ #define SQLITE_CONFIG_GETMALLOC 5 /* sqlite3_mem_methods* */ #define SQLITE_CONFIG_SCRATCH 6 /* No longer used */ #define SQLITE_CONFIG_PAGECACHE 7 /* void*, int sz, int N */ #define SQLITE_CONFIG_HEAP 8 /* void*, int nByte, int min */ #define SQLITE_CONFIG_MEMSTATUS 9 /* boolean */ #define SQLITE_CONFIG_MUTEX 10 /* sqlite3_mutex_methods* */ #define SQLITE_CONFIG_GETMUTEX 11 /* sqlite3_mutex_methods* */ /* previously SQLITE_CONFIG_CHUNKALLOC 12 which is now unused. */ #define SQLITE_CONFIG_LOOKASIDE 13 /* int int */ #define SQLITE_CONFIG_PCACHE 14 /* no-op */ #define SQLITE_CONFIG_GETPCACHE 15 /* no-op */ #define SQLITE_CONFIG_LOG 16 /* xFunc, void* */ #define SQLITE_CONFIG_URI 17 /* int */ #define SQLITE_CONFIG_PCACHE2 18 /* sqlite3_pcache_methods2* */ #define SQLITE_CONFIG_GETPCACHE2 19 /* sqlite3_pcache_methods2* */ #define SQLITE_CONFIG_COVERING_INDEX_SCAN 20 /* int */ #define SQLITE_CONFIG_SQLLOG 21 /* xSqllog, void* */ #define SQLITE_CONFIG_MMAP_SIZE 22 /* sqlite3_int64, sqlite3_int64 */ #define SQLITE_CONFIG_WIN32_HEAPSIZE 23 /* int nByte */ #define SQLITE_CONFIG_PCACHE_HDRSZ 24 /* int *psz */ #define SQLITE_CONFIG_PMASZ 25 /* unsigned int szPma */ #define SQLITE_CONFIG_STMTJRNL_SPILL 26 /* int nByte */ #define SQLITE_CONFIG_SMALL_MALLOC 27 /* boolean */ #define SQLITE_CONFIG_SORTERREF_SIZE 28 /* int nByte */ #define SQLITE_CONFIG_MEMDB_MAXSIZE 29 /* sqlite3_int64 */ |
| ︙ | ︙ | |||
2143 2144 2145 2146 2147 2148 2149 | ** or equal to the product of the second and third arguments. The buffer ** must be aligned to an 8-byte boundary. ^If the second argument to ** SQLITE_DBCONFIG_LOOKASIDE is not a multiple of 8, it is internally ** rounded down to the next smaller multiple of 8. ^(The lookaside memory ** configuration for a database connection can only be changed when that ** connection is not currently using lookaside memory, or in other words ** when the "current value" returned by | | | 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 | ** or equal to the product of the second and third arguments. The buffer ** must be aligned to an 8-byte boundary. ^If the second argument to ** SQLITE_DBCONFIG_LOOKASIDE is not a multiple of 8, it is internally ** rounded down to the next smaller multiple of 8. ^(The lookaside memory ** configuration for a database connection can only be changed when that ** connection is not currently using lookaside memory, or in other words ** when the "current value" returned by ** [sqlite3_db_status](D,[SQLITE_DBSTATUS_LOOKASIDE_USED],...) is zero. ** Any attempt to change the lookaside memory configuration when lookaside ** memory is in use leaves the configuration unchanged and returns ** [SQLITE_BUSY].)^</dd> ** ** [[SQLITE_DBCONFIG_ENABLE_FKEY]] ** <dt>SQLITE_DBCONFIG_ENABLE_FKEY</dt> ** <dd> ^This option is used to enable or disable the enforcement of |
| ︙ | ︙ | |||
2240 2241 2242 2243 2244 2245 2246 | ** ** [[SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE]] ** <dt>SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE</dt> ** <dd> Usually, when a database in wal mode is closed or detached from a ** database handle, SQLite checks if this will mean that there are now no ** connections at all to the database. If so, it performs a checkpoint ** operation before closing the connection. This option may be used to | | | 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 | ** ** [[SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE]] ** <dt>SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE</dt> ** <dd> Usually, when a database in wal mode is closed or detached from a ** database handle, SQLite checks if this will mean that there are now no ** connections at all to the database. If so, it performs a checkpoint ** operation before closing the connection. This option may be used to ** override this behavior. The first parameter passed to this operation ** is an integer - positive to disable checkpoints-on-close, or zero (the ** default) to enable them, and negative to leave the setting unchanged. ** The second parameter is a pointer to an integer ** into which is written 0 or 1 to indicate whether checkpoints-on-close ** have been disabled - 0 if they are not disabled, 1 if they are. ** </dd> ** |
| ︙ | ︙ | |||
2293 2294 2295 2296 2297 2298 2299 | ** the database in WAL mode after the reset if it was in WAL mode before ** the reset. ** <li> sqlite3_db_config(db, SQLITE_DBCONFIG_RESET_DATABASE, 1, 0); ** <li> [sqlite3_exec](db, "[VACUUM]", 0, 0, 0); ** <li> sqlite3_db_config(db, SQLITE_DBCONFIG_RESET_DATABASE, 0, 0); ** </ol> ** Because resetting a database is destructive and irreversible, the | | | > > > > > | 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 | ** the database in WAL mode after the reset if it was in WAL mode before ** the reset. ** <li> sqlite3_db_config(db, SQLITE_DBCONFIG_RESET_DATABASE, 1, 0); ** <li> [sqlite3_exec](db, "[VACUUM]", 0, 0, 0); ** <li> sqlite3_db_config(db, SQLITE_DBCONFIG_RESET_DATABASE, 0, 0); ** </ol> ** Because resetting a database is destructive and irreversible, the ** process requires the use of this obscure API and multiple steps to ** help ensure that it does not happen by accident. Because this ** feature must be capable of resetting corrupt databases, and ** shutting down virtual tables may require access to that corrupt ** storage, the library must abandon any installed virtual tables ** without calling their xDestroy() methods. ** ** [[SQLITE_DBCONFIG_DEFENSIVE]] <dt>SQLITE_DBCONFIG_DEFENSIVE</dt> ** <dd>The SQLITE_DBCONFIG_DEFENSIVE option activates or deactivates the ** "defensive" flag for a database connection. When the defensive ** flag is enabled, language features that allow ordinary SQL to ** deliberately corrupt the database file are disabled. The disabled ** features include but are not limited to the following: ** <ul> ** <li> The [PRAGMA writable_schema=ON] statement. ** <li> The [PRAGMA journal_mode=OFF] statement. ** <li> The [PRAGMA schema_version=N] statement. ** <li> Writes to the [sqlite_dbpage] virtual table. ** <li> Direct writes to [shadow tables]. ** </ul> ** </dd> ** ** [[SQLITE_DBCONFIG_WRITABLE_SCHEMA]] <dt>SQLITE_DBCONFIG_WRITABLE_SCHEMA</dt> ** <dd>The SQLITE_DBCONFIG_WRITABLE_SCHEMA option activates or deactivates the |
| ︙ | ︙ | |||
2332 2333 2334 2335 2336 2337 2338 | ** behaves as it did prior to [version 3.24.0] (2018-06-04). See the ** "Compatibility Notice" on the [ALTER TABLE RENAME documentation] for ** additional information. This feature can also be turned on and off ** using the [PRAGMA legacy_alter_table] statement. ** </dd> ** ** [[SQLITE_DBCONFIG_DQS_DML]] | | | | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | 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 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 | ** behaves as it did prior to [version 3.24.0] (2018-06-04). See the ** "Compatibility Notice" on the [ALTER TABLE RENAME documentation] for ** additional information. This feature can also be turned on and off ** using the [PRAGMA legacy_alter_table] statement. ** </dd> ** ** [[SQLITE_DBCONFIG_DQS_DML]] ** <dt>SQLITE_DBCONFIG_DQS_DML</dt> ** <dd>The SQLITE_DBCONFIG_DQS_DML option activates or deactivates ** the legacy [double-quoted string literal] misfeature for DML statements ** only, that is DELETE, INSERT, SELECT, and UPDATE statements. The ** default value of this setting is determined by the [-DSQLITE_DQS] ** compile-time option. ** </dd> ** ** [[SQLITE_DBCONFIG_DQS_DDL]] ** <dt>SQLITE_DBCONFIG_DQS_DDL</dt> ** <dd>The SQLITE_DBCONFIG_DQS option activates or deactivates ** the legacy [double-quoted string literal] misfeature for DDL statements, ** such as CREATE TABLE and CREATE INDEX. The ** default value of this setting is determined by the [-DSQLITE_DQS] ** compile-time option. ** </dd> ** ** [[SQLITE_DBCONFIG_TRUSTED_SCHEMA]] ** <dt>SQLITE_DBCONFIG_TRUSTED_SCHEMA</dt> ** <dd>The SQLITE_DBCONFIG_TRUSTED_SCHEMA option tells SQLite to ** assume that database schemas are untainted by malicious content. ** When the SQLITE_DBCONFIG_TRUSTED_SCHEMA option is disabled, SQLite ** takes additional defensive steps to protect the application from harm ** including: ** <ul> ** <li> Prohibit the use of SQL functions inside triggers, views, ** CHECK constraints, DEFAULT clauses, expression indexes, ** partial indexes, or generated columns ** unless those functions are tagged with [SQLITE_INNOCUOUS]. ** <li> Prohibit the use of virtual tables inside of triggers or views ** unless those virtual tables are tagged with [SQLITE_VTAB_INNOCUOUS]. ** </ul> ** This setting defaults to "on" for legacy compatibility, however ** all applications are advised to turn it off if possible. This setting ** can also be controlled using the [PRAGMA trusted_schema] statement. ** </dd> ** ** [[SQLITE_DBCONFIG_LEGACY_FILE_FORMAT]] ** <dt>SQLITE_DBCONFIG_LEGACY_FILE_FORMAT</dt> ** <dd>The SQLITE_DBCONFIG_LEGACY_FILE_FORMAT option activates or deactivates ** the legacy file format flag. When activated, this flag causes all newly ** created database file to have a schema format version number (the 4-byte ** integer found at offset 44 into the database header) of 1. This in turn ** means that the resulting database file will be readable and writable by ** any SQLite version back to 3.0.0 ([dateof:3.0.0]). Without this setting, ** newly created databases are generally not understandable by SQLite versions ** prior to 3.3.0 ([dateof:3.3.0]). As these words are written, there ** is now scarcely any need to generate database files that are compatible ** all the way back to version 3.0.0, and so this setting is of little ** practical use, but is provided so that SQLite can continue to claim the ** ability to generate new database files that are compatible with version ** 3.0.0. ** <p>Note that when the SQLITE_DBCONFIG_LEGACY_FILE_FORMAT setting is on, ** the [VACUUM] command will fail with an obscure error when attempting to ** process a table with generated columns and a descending index. This is ** not considered a bug since SQLite versions 3.3.0 and earlier do not support ** either generated columns or descending indexes. ** </dd> ** ** [[SQLITE_DBCONFIG_STMT_SCANSTATUS]] ** <dt>SQLITE_DBCONFIG_STMT_SCANSTATUS</dt> ** <dd>The SQLITE_DBCONFIG_STMT_SCANSTATUS option is only useful in ** SQLITE_ENABLE_STMT_SCANSTATUS builds. In this case, it sets or clears ** a flag that enables collection of the sqlite3_stmt_scanstatus_v2() ** statistics. For statistics to be collected, the flag must be set on ** the database handle both when the SQL statement is prepared and when it ** is stepped. The flag is set (collection of statistics is enabled) ** by default. This option takes two arguments: an integer and a pointer to ** an integer.. The first argument is 1, 0, or -1 to enable, disable, or ** leave unchanged the statement scanstatus option. If the second argument ** is not NULL, then the value of the statement scanstatus setting after ** processing the first argument is written into the integer that the second ** argument points to. ** </dd> ** ** [[SQLITE_DBCONFIG_REVERSE_SCANORDER]] ** <dt>SQLITE_DBCONFIG_REVERSE_SCANORDER</dt> ** <dd>The SQLITE_DBCONFIG_REVERSE_SCANORDER option changes the default order ** in which tables and indexes are scanned so that the scans start at the end ** and work toward the beginning rather than starting at the beginning and ** working toward the end. Setting SQLITE_DBCONFIG_REVERSE_SCANORDER is the ** same as setting [PRAGMA reverse_unordered_selects]. This option takes ** two arguments which are an integer and a pointer to an integer. The first ** argument is 1, 0, or -1 to enable, disable, or leave unchanged the ** reverse scan order flag, respectively. If the second argument is not NULL, ** then 0 or 1 is written into the integer that the second argument points to ** depending on if the reverse scan order flag is set after processing the ** first argument. ** </dd> ** ** </dl> */ #define SQLITE_DBCONFIG_MAINDBNAME 1000 /* const char* */ #define SQLITE_DBCONFIG_LOOKASIDE 1001 /* void* int int */ #define SQLITE_DBCONFIG_ENABLE_FKEY 1002 /* int int* */ #define SQLITE_DBCONFIG_ENABLE_TRIGGER 1003 /* int int* */ #define SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER 1004 /* int int* */ #define SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION 1005 /* int int* */ #define SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE 1006 /* int int* */ #define SQLITE_DBCONFIG_ENABLE_QPSG 1007 /* int int* */ #define SQLITE_DBCONFIG_TRIGGER_EQP 1008 /* int int* */ #define SQLITE_DBCONFIG_RESET_DATABASE 1009 /* int int* */ #define SQLITE_DBCONFIG_DEFENSIVE 1010 /* int int* */ #define SQLITE_DBCONFIG_WRITABLE_SCHEMA 1011 /* int int* */ #define SQLITE_DBCONFIG_LEGACY_ALTER_TABLE 1012 /* int int* */ #define SQLITE_DBCONFIG_DQS_DML 1013 /* int int* */ #define SQLITE_DBCONFIG_DQS_DDL 1014 /* int int* */ #define SQLITE_DBCONFIG_ENABLE_VIEW 1015 /* int int* */ #define SQLITE_DBCONFIG_LEGACY_FILE_FORMAT 1016 /* int int* */ #define SQLITE_DBCONFIG_TRUSTED_SCHEMA 1017 /* int int* */ #define SQLITE_DBCONFIG_STMT_SCANSTATUS 1018 /* int int* */ #define SQLITE_DBCONFIG_REVERSE_SCANORDER 1019 /* int int* */ #define SQLITE_DBCONFIG_MAX 1019 /* Largest DBCONFIG */ /* ** CAPI3REF: Enable Or Disable Extended Result Codes ** METHOD: sqlite3 ** ** ^The sqlite3_extended_result_codes() routine enables or disables the ** [extended result codes] feature of SQLite. ^The extended result |
| ︙ | ︙ | |||
2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 | ** running statement count reaches zero are interrupted as if they had been ** running prior to the sqlite3_interrupt() call. ^New SQL statements ** that are started after the running statement count reaches zero are ** not effected by the sqlite3_interrupt(). ** ^A call to sqlite3_interrupt(D) that occurs when there are no running ** SQL statements is a no-op and has no effect on SQL statements ** that are started after the sqlite3_interrupt() call returns. */ SQLITE_API void sqlite3_interrupt(sqlite3*); /* ** CAPI3REF: Determine If An SQL Statement Is Complete ** ** These routines are useful during command-line input to determine if the ** currently entered text seems to form a complete SQL statement or ** if additional input is needed before sending the text into | > > > > > | 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 | ** running statement count reaches zero are interrupted as if they had been ** running prior to the sqlite3_interrupt() call. ^New SQL statements ** that are started after the running statement count reaches zero are ** not effected by the sqlite3_interrupt(). ** ^A call to sqlite3_interrupt(D) that occurs when there are no running ** SQL statements is a no-op and has no effect on SQL statements ** that are started after the sqlite3_interrupt() call returns. ** ** ^The [sqlite3_is_interrupted(D)] interface can be used to determine whether ** or not an interrupt is currently in effect for [database connection] D. ** It returns 1 if an interrupt is currently in effect, or 0 otherwise. */ SQLITE_API void sqlite3_interrupt(sqlite3*); SQLITE_API int sqlite3_is_interrupted(sqlite3*); /* ** CAPI3REF: Determine If An SQL Statement Is Complete ** ** These routines are useful during command-line input to determine if the ** currently entered text seems to form a complete SQL statement or ** if additional input is needed before sending the text into |
| ︙ | ︙ | |||
3251 3252 3253 3254 3255 3256 3257 | ** interface by using the X argument when X begins with "--" and invoking ** [sqlite3_expanded_sql(P)] otherwise. ** ** [[SQLITE_TRACE_PROFILE]] <dt>SQLITE_TRACE_PROFILE</dt> ** <dd>^An SQLITE_TRACE_PROFILE callback provides approximately the same ** information as is provided by the [sqlite3_profile()] callback. ** ^The P argument is a pointer to the [prepared statement] and the | | | | 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 | ** interface by using the X argument when X begins with "--" and invoking ** [sqlite3_expanded_sql(P)] otherwise. ** ** [[SQLITE_TRACE_PROFILE]] <dt>SQLITE_TRACE_PROFILE</dt> ** <dd>^An SQLITE_TRACE_PROFILE callback provides approximately the same ** information as is provided by the [sqlite3_profile()] callback. ** ^The P argument is a pointer to the [prepared statement] and the ** X argument points to a 64-bit integer which is approximately ** the number of nanoseconds that the prepared statement took to run. ** ^The SQLITE_TRACE_PROFILE callback is invoked when the statement finishes. ** ** [[SQLITE_TRACE_ROW]] <dt>SQLITE_TRACE_ROW</dt> ** <dd>^An SQLITE_TRACE_ROW callback is invoked whenever a prepared ** statement generates a single row of result. ** ^The P argument is a pointer to the [prepared statement] and the ** X argument is unused. |
| ︙ | ︙ | |||
3284 3285 3286 3287 3288 3289 3290 | ** ^The sqlite3_trace_v2(D,M,X,P) interface registers a trace callback ** function X against [database connection] D, using property mask M ** and context pointer P. ^If the X callback is ** NULL or if the M mask is zero, then tracing is disabled. The ** M argument should be the bitwise OR-ed combination of ** zero or more [SQLITE_TRACE] constants. ** | | | > > | 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 | ** ^The sqlite3_trace_v2(D,M,X,P) interface registers a trace callback ** function X against [database connection] D, using property mask M ** and context pointer P. ^If the X callback is ** NULL or if the M mask is zero, then tracing is disabled. The ** M argument should be the bitwise OR-ed combination of ** zero or more [SQLITE_TRACE] constants. ** ** ^Each call to either sqlite3_trace(D,X,P) or sqlite3_trace_v2(D,M,X,P) ** overrides (cancels) all prior calls to sqlite3_trace(D,X,P) or ** sqlite3_trace_v2(D,M,X,P) for the [database connection] D. Each ** database connection may have at most one trace callback. ** ** ^The X callback is invoked whenever any of the events identified by ** mask M occur. ^The integer return value from the callback is currently ** ignored, though this may change in future releases. Callback ** implementations should return zero to ensure future compatibility. ** ** ^A trace callback is invoked with four arguments: callback(T,C,P,X). |
| ︙ | ︙ | |||
3315 3316 3317 3318 3319 3320 3321 | /* ** CAPI3REF: Query Progress Callbacks ** METHOD: sqlite3 ** ** ^The sqlite3_progress_handler(D,N,X,P) interface causes the callback ** function X to be invoked periodically during long running calls to | | | 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 | /* ** CAPI3REF: Query Progress Callbacks ** METHOD: sqlite3 ** ** ^The sqlite3_progress_handler(D,N,X,P) interface causes the callback ** function X to be invoked periodically during long running calls to ** [sqlite3_step()] and [sqlite3_prepare()] and similar for ** database connection D. An example use for this ** interface is to keep a GUI updated during a large query. ** ** ^The parameter P is passed through as the only parameter to the ** callback function X. ^The parameter N is the approximate number of ** [virtual machine instructions] that are evaluated between successive ** invocations of the callback X. ^If N is less than one then the progress |
| ︙ | ︙ | |||
3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 | ** "Cancel" button on a GUI progress dialog box. ** ** The progress handler callback must not do anything that will modify ** the database connection that invoked the progress handler. ** Note that [sqlite3_prepare_v2()] and [sqlite3_step()] both modify their ** database connections for the meaning of "modify" in this paragraph. ** */ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*); /* ** CAPI3REF: Opening A New Database Connection ** CONSTRUCTOR: sqlite3 ** | > > > > > > > | 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 | ** "Cancel" button on a GUI progress dialog box. ** ** The progress handler callback must not do anything that will modify ** the database connection that invoked the progress handler. ** Note that [sqlite3_prepare_v2()] and [sqlite3_step()] both modify their ** database connections for the meaning of "modify" in this paragraph. ** ** The progress handler callback would originally only be invoked from the ** bytecode engine. It still might be invoked during [sqlite3_prepare()] ** and similar because those routines might force a reparse of the schema ** which involves running the bytecode engine. However, beginning with ** SQLite version 3.41.0, the progress handler callback might also be ** invoked directly from [sqlite3_prepare()] while analyzing and generating ** code for complex queries. */ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*); /* ** CAPI3REF: Opening A New Database Connection ** CONSTRUCTOR: sqlite3 ** |
| ︙ | ︙ | |||
3376 3377 3378 3379 3380 3381 3382 | ** except that it accepts two additional parameters for additional control ** over the new database connection. ^(The flags parameter to ** sqlite3_open_v2() must include, at a minimum, one of the following ** three flag combinations:)^ ** ** <dl> ** ^(<dt>[SQLITE_OPEN_READONLY]</dt> | | | | | | > > > > > | 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 | ** except that it accepts two additional parameters for additional control ** over the new database connection. ^(The flags parameter to ** sqlite3_open_v2() must include, at a minimum, one of the following ** three flag combinations:)^ ** ** <dl> ** ^(<dt>[SQLITE_OPEN_READONLY]</dt> ** <dd>The database is opened in read-only mode. If the database does ** not already exist, an error is returned.</dd>)^ ** ** ^(<dt>[SQLITE_OPEN_READWRITE]</dt> ** <dd>The database is opened for reading and writing if possible, or ** reading only if the file is write protected by the operating ** system. In either case the database must already exist, otherwise ** an error is returned. For historical reasons, if opening in ** read-write mode fails due to OS-level permissions, an attempt is ** made to open it in read-only mode. [sqlite3_db_readonly()] can be ** used to determine whether the database is actually ** read-write.</dd>)^ ** ** ^(<dt>[SQLITE_OPEN_READWRITE] | [SQLITE_OPEN_CREATE]</dt> ** <dd>The database is opened for reading and writing, and is created if ** it does not already exist. This is the behavior that is always used for ** sqlite3_open() and sqlite3_open16().</dd>)^ ** </dl> ** |
| ︙ | ︙ | |||
3642 3643 3644 3645 3646 3647 3648 | ** that check if a database file was a URI that contained a specific query ** parameter, and if so obtains the value of that query parameter. ** ** The first parameter to these interfaces (hereafter referred to ** as F) must be one of: ** <ul> ** <li> A database filename pointer created by the SQLite core and | | | 3758 3759 3760 3761 3762 3763 3764 3765 3766 3767 3768 3769 3770 3771 3772 | ** that check if a database file was a URI that contained a specific query ** parameter, and if so obtains the value of that query parameter. ** ** The first parameter to these interfaces (hereafter referred to ** as F) must be one of: ** <ul> ** <li> A database filename pointer created by the SQLite core and ** passed into the xOpen() method of a VFS implementation, or ** <li> A filename obtained from [sqlite3_db_filename()], or ** <li> A new filename constructed using [sqlite3_create_filename()]. ** </ul> ** If the F parameter is not one of the above, then the behavior is ** undefined and probably undesirable. Older versions of SQLite were ** more tolerant of invalid F parameters than newer versions. ** |
| ︙ | ︙ | |||
3697 3698 3699 3700 3701 3702 3703 | ** routines would only work if F was the name of the main database file. ** When the F parameter is the name of the rollback journal or WAL file, ** it has access to all the same query parameters as were found on the ** main database file. ** ** See the [URI filename] documentation for additional information. */ | | | | | | 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830 | ** routines would only work if F was the name of the main database file. ** When the F parameter is the name of the rollback journal or WAL file, ** it has access to all the same query parameters as were found on the ** main database file. ** ** See the [URI filename] documentation for additional information. */ SQLITE_API const char *sqlite3_uri_parameter(sqlite3_filename z, const char *zParam); SQLITE_API int sqlite3_uri_boolean(sqlite3_filename z, const char *zParam, int bDefault); SQLITE_API sqlite3_int64 sqlite3_uri_int64(sqlite3_filename, const char*, sqlite3_int64); SQLITE_API const char *sqlite3_uri_key(sqlite3_filename z, int N); /* ** CAPI3REF: Translate filenames ** ** These routines are available to [VFS|custom VFS implementations] for ** translating filenames between the main database file, the journal file, ** and the WAL file. |
| ︙ | ︙ | |||
3729 3730 3731 3732 3733 3734 3735 | ** WAL file. ** ** In all of the above, if F is not the name of a database, journal or WAL ** filename passed into the VFS from the SQLite core and F is not the ** return value from [sqlite3_db_filename()], then the result is ** undefined and is likely a memory access violation. */ | | | | | 3845 3846 3847 3848 3849 3850 3851 3852 3853 3854 3855 3856 3857 3858 3859 3860 3861 | ** WAL file. ** ** In all of the above, if F is not the name of a database, journal or WAL ** filename passed into the VFS from the SQLite core and F is not the ** return value from [sqlite3_db_filename()], then the result is ** undefined and is likely a memory access violation. */ SQLITE_API const char *sqlite3_filename_database(sqlite3_filename); SQLITE_API const char *sqlite3_filename_journal(sqlite3_filename); SQLITE_API const char *sqlite3_filename_wal(sqlite3_filename); /* ** CAPI3REF: Database File Corresponding To A Journal ** ** ^If X is the name of a rollback or WAL-mode journal file that is ** passed into the xOpen method of [sqlite3_vfs], then ** sqlite3_database_file_object(X) returns a pointer to the [sqlite3_file] |
| ︙ | ︙ | |||
3755 3756 3757 3758 3759 3760 3761 | ** behavior. */ SQLITE_API sqlite3_file *sqlite3_database_file_object(const char*); /* ** CAPI3REF: Create and Destroy VFS Filenames ** | | | 3871 3872 3873 3874 3875 3876 3877 3878 3879 3880 3881 3882 3883 3884 3885 | ** behavior. */ SQLITE_API sqlite3_file *sqlite3_database_file_object(const char*); /* ** CAPI3REF: Create and Destroy VFS Filenames ** ** These interfaces are provided for use by [VFS shim] implementations and ** are not useful outside of that context. ** ** The sqlite3_create_filename(D,J,W,N,P) allocates memory to hold a version of ** database filename D with corresponding journal file J and WAL file W and ** with N URI parameters key/values pairs in the array P. The result from ** sqlite3_create_filename(D,J,W,N,P) is a pointer to a database filename that ** is safe to pass to routines like: |
| ︙ | ︙ | |||
3797 3798 3799 3800 3801 3802 3803 | ** sqlite3_create_filename(), then bad things such as heap ** corruption or segfaults may occur. The value Y should not be ** used again after sqlite3_free_filename(Y) has been called. This means ** that if the [sqlite3_vfs.xOpen()] method of a VFS has been called using Y, ** then the corresponding [sqlite3_module.xClose() method should also be ** invoked prior to calling sqlite3_free_filename(Y). */ | | | | 3913 3914 3915 3916 3917 3918 3919 3920 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931 3932 3933 3934 | ** sqlite3_create_filename(), then bad things such as heap ** corruption or segfaults may occur. The value Y should not be ** used again after sqlite3_free_filename(Y) has been called. This means ** that if the [sqlite3_vfs.xOpen()] method of a VFS has been called using Y, ** then the corresponding [sqlite3_module.xClose() method should also be ** invoked prior to calling sqlite3_free_filename(Y). */ SQLITE_API sqlite3_filename sqlite3_create_filename( const char *zDatabase, const char *zJournal, const char *zWal, int nParam, const char **azParam ); SQLITE_API void sqlite3_free_filename(sqlite3_filename); /* ** CAPI3REF: Error Codes And Messages ** METHOD: sqlite3 ** ** ^If the most recent sqlite3_* API call associated with ** [database connection] D failed, then the sqlite3_errcode(D) interface |
| ︙ | ︙ | |||
3834 3835 3836 3837 3838 3839 3840 | ** <li> sqlite3_extended_errcode() ** <li> sqlite3_errmsg() ** <li> sqlite3_errmsg16() ** <li> sqlite3_error_offset() ** </ul> ** ** ^The sqlite3_errmsg() and sqlite3_errmsg16() return English-language | | > > | | > | 3950 3951 3952 3953 3954 3955 3956 3957 3958 3959 3960 3961 3962 3963 3964 3965 3966 3967 3968 3969 3970 3971 3972 3973 3974 | ** <li> sqlite3_extended_errcode() ** <li> sqlite3_errmsg() ** <li> sqlite3_errmsg16() ** <li> sqlite3_error_offset() ** </ul> ** ** ^The sqlite3_errmsg() and sqlite3_errmsg16() return English-language ** text that describes the error, as either UTF-8 or UTF-16 respectively, ** or NULL if no error message is available. ** (See how SQLite handles [invalid UTF] for exceptions to this rule.) ** ^(Memory to hold the error message string is managed internally. ** The application does not need to worry about freeing the result. ** However, the error string might be overwritten or deallocated by ** subsequent calls to other SQLite interface functions.)^ ** ** ^The sqlite3_errstr(E) interface returns the English-language text ** that describes the [result code] E, as UTF-8, or NULL if E is not an ** result code for which a text error message is available. ** ^(Memory to hold the error message string is managed internally ** and must not be freed by the application)^. ** ** ^If the most recent error references a specific token in the input ** SQL, the sqlite3_error_offset() interface returns the byte offset ** of the start of that token. ^The byte offset returned by ** sqlite3_error_offset() assumes that the input SQL is UTF8. |
| ︙ | ︙ | |||
4302 4303 4304 4305 4306 4307 4308 4309 4310 4311 4312 4313 4314 4315 | ** prepared statement S is an EXPLAIN statement, or 2 if the ** statement S is an EXPLAIN QUERY PLAN. ** ^The sqlite3_stmt_isexplain(S) interface returns 0 if S is ** an ordinary statement or a NULL pointer. */ SQLITE_API int sqlite3_stmt_isexplain(sqlite3_stmt *pStmt); /* ** CAPI3REF: Determine If A Prepared Statement Has Been Reset ** METHOD: sqlite3_stmt ** ** ^The sqlite3_stmt_busy(S) interface returns true (non-zero) if the ** [prepared statement] S has been stepped at least once using ** [sqlite3_step(S)] but has neither run to completion (returned | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 4421 4422 4423 4424 4425 4426 4427 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 | ** prepared statement S is an EXPLAIN statement, or 2 if the ** statement S is an EXPLAIN QUERY PLAN. ** ^The sqlite3_stmt_isexplain(S) interface returns 0 if S is ** an ordinary statement or a NULL pointer. */ SQLITE_API int sqlite3_stmt_isexplain(sqlite3_stmt *pStmt); /* ** CAPI3REF: Change The EXPLAIN Setting For A Prepared Statement ** METHOD: sqlite3_stmt ** ** The sqlite3_stmt_explain(S,E) interface changes the EXPLAIN ** setting for [prepared statement] S. If E is zero, then S becomes ** a normal prepared statement. If E is 1, then S behaves as if ** its SQL text began with "[EXPLAIN]". If E is 2, then S behaves as if ** its SQL text began with "[EXPLAIN QUERY PLAN]". ** ** Calling sqlite3_stmt_explain(S,E) might cause S to be reprepared. ** SQLite tries to avoid a reprepare, but a reprepare might be necessary ** on the first transition into EXPLAIN or EXPLAIN QUERY PLAN mode. ** ** Because of the potential need to reprepare, a call to ** sqlite3_stmt_explain(S,E) will fail with SQLITE_ERROR if S cannot be ** reprepared because it was created using [sqlite3_prepare()] instead of ** the newer [sqlite3_prepare_v2()] or [sqlite3_prepare_v3()] interfaces and ** hence has no saved SQL text with which to reprepare. ** ** Changing the explain setting for a prepared statement does not change ** the original SQL text for the statement. Hence, if the SQL text originally ** began with EXPLAIN or EXPLAIN QUERY PLAN, but sqlite3_stmt_explain(S,0) ** is called to convert the statement into an ordinary statement, the EXPLAIN ** or EXPLAIN QUERY PLAN keywords will still appear in the sqlite3_sql(S) ** output, even though the statement now acts like a normal SQL statement. ** ** This routine returns SQLITE_OK if the explain mode is successfully ** changed, or an error code if the explain mode could not be changed. ** The explain mode cannot be changed while a statement is active. ** Hence, it is good practice to call [sqlite3_reset(S)] ** immediately prior to calling sqlite3_stmt_explain(S,E). */ SQLITE_API int sqlite3_stmt_explain(sqlite3_stmt *pStmt, int eMode); /* ** CAPI3REF: Determine If A Prepared Statement Has Been Reset ** METHOD: sqlite3_stmt ** ** ^The sqlite3_stmt_busy(S) interface returns true (non-zero) if the ** [prepared statement] S has been stepped at least once using ** [sqlite3_step(S)] but has neither run to completion (returned |
| ︙ | ︙ | |||
4465 4466 4467 4468 4469 4470 4471 | ** ^The fifth argument to the BLOB and string binding interfaces controls ** or indicates the lifetime of the object referenced by the third parameter. ** These three options exist: ** ^ (1) A destructor to dispose of the BLOB or string after SQLite has finished ** with it may be passed. ^It is called to dispose of the BLOB or string even ** if the call to the bind API fails, except the destructor is not called if ** the third parameter is a NULL pointer or the fourth parameter is negative. | | | 4619 4620 4621 4622 4623 4624 4625 4626 4627 4628 4629 4630 4631 4632 4633 | ** ^The fifth argument to the BLOB and string binding interfaces controls ** or indicates the lifetime of the object referenced by the third parameter. ** These three options exist: ** ^ (1) A destructor to dispose of the BLOB or string after SQLite has finished ** with it may be passed. ^It is called to dispose of the BLOB or string even ** if the call to the bind API fails, except the destructor is not called if ** the third parameter is a NULL pointer or the fourth parameter is negative. ** ^ (2) The special constant, [SQLITE_STATIC], may be passed to indicate that ** the application remains responsible for disposing of the object. ^In this ** case, the object and the provided pointer to it must remain valid until ** either the prepared statement is finalized or the same SQL parameter is ** bound to something else, whichever occurs sooner. ** ^ (3) The constant, [SQLITE_TRANSIENT], may be passed to indicate that the ** object is to be copied prior to the return from sqlite3_bind_*(). ^The ** object and pointer to it must remain valid until then. ^SQLite will then |
| ︙ | ︙ | |||
5144 5145 5146 5147 5148 5149 5150 | ** ^Any SQL statement variables that had values bound to them using ** the [sqlite3_bind_blob | sqlite3_bind_*() API] retain their values. ** Use [sqlite3_clear_bindings()] to reset the bindings. ** ** ^The [sqlite3_reset(S)] interface resets the [prepared statement] S ** back to the beginning of its program. ** | | | | > | > > > > > > > > > > > > | 5298 5299 5300 5301 5302 5303 5304 5305 5306 5307 5308 5309 5310 5311 5312 5313 5314 5315 5316 5317 5318 5319 5320 5321 5322 5323 5324 5325 5326 5327 5328 5329 5330 5331 5332 5333 5334 5335 5336 5337 |
** ^Any SQL statement variables that had values bound to them using
** the [sqlite3_bind_blob | sqlite3_bind_*() API] retain their values.
** Use [sqlite3_clear_bindings()] to reset the bindings.
**
** ^The [sqlite3_reset(S)] interface resets the [prepared statement] S
** back to the beginning of its program.
**
** ^The return code from [sqlite3_reset(S)] indicates whether or not
** the previous evaluation of prepared statement S completed successfully.
** ^If [sqlite3_step(S)] has never before been called on S or if
** [sqlite3_step(S)] has not been called since the previous call
** to [sqlite3_reset(S)], then [sqlite3_reset(S)] will return
** [SQLITE_OK].
**
** ^If the most recent call to [sqlite3_step(S)] for the
** [prepared statement] S indicated an error, then
** [sqlite3_reset(S)] returns an appropriate [error code].
** ^The [sqlite3_reset(S)] interface might also return an [error code]
** if there were no prior errors but the process of resetting
** the prepared statement caused a new error. ^For example, if an
** [INSERT] statement with a [RETURNING] clause is only stepped one time,
** that one call to [sqlite3_step(S)] might return SQLITE_ROW but
** the overall statement might still fail and the [sqlite3_reset(S)] call
** might return SQLITE_BUSY if locking constraints prevent the
** database change from committing. Therefore, it is important that
** applications check the return code from [sqlite3_reset(S)] even if
** no prior call to [sqlite3_step(S)] indicated a problem.
**
** ^The [sqlite3_reset(S)] interface does not change the values
** of any [sqlite3_bind_blob|bindings] on the [prepared statement] S.
*/
SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
/*
** CAPI3REF: Create Or Redefine SQL Functions
** KEYWORDS: {function creation routines}
** METHOD: sqlite3
**
** ^These functions (collectively known as "function creation routines")
|
| ︙ | ︙ | |||
5363 5364 5365 5366 5367 5368 5369 | ** </dd> ** ** [[SQLITE_DIRECTONLY]] <dt>SQLITE_DIRECTONLY</dt><dd> ** The SQLITE_DIRECTONLY flag means that the function may only be invoked ** from top-level SQL, and cannot be used in VIEWs or TRIGGERs nor in ** schema structures such as [CHECK constraints], [DEFAULT clauses], ** [expression indexes], [partial indexes], or [generated columns]. | > | | | > > > > | > > > > > > | 5530 5531 5532 5533 5534 5535 5536 5537 5538 5539 5540 5541 5542 5543 5544 5545 5546 5547 5548 5549 5550 5551 5552 5553 5554 5555 5556 5557 5558 | ** </dd> ** ** [[SQLITE_DIRECTONLY]] <dt>SQLITE_DIRECTONLY</dt><dd> ** The SQLITE_DIRECTONLY flag means that the function may only be invoked ** from top-level SQL, and cannot be used in VIEWs or TRIGGERs nor in ** schema structures such as [CHECK constraints], [DEFAULT clauses], ** [expression indexes], [partial indexes], or [generated columns]. ** <p> ** The SQLITE_DIRECTONLY flag is recommended for any ** [application-defined SQL function] ** that has side-effects or that could potentially leak sensitive information. ** This will prevent attacks in which an application is tricked ** into using a database file that has had its schema surreptitiously ** modified to invoke the application-defined function in ways that are ** harmful. ** <p> ** Some people say it is good practice to set SQLITE_DIRECTONLY on all ** [application-defined SQL functions], regardless of whether or not they ** are security sensitive, as doing so prevents those functions from being used ** inside of the database schema, and thus ensures that the database ** can be inspected and modified using generic tools (such as the [CLI]) ** that do not have access to the application-defined functions. ** </dd> ** ** [[SQLITE_INNOCUOUS]] <dt>SQLITE_INNOCUOUS</dt><dd> ** The SQLITE_INNOCUOUS flag means that the function is unlikely ** to cause problems even if misused. An innocuous function should have ** no side effects and should not depend on any values other than its ** input parameters. The [abs|abs() function] is an example of an |
| ︙ | ︙ | |||
5393 5394 5395 5396 5397 5398 5399 | ** are innocuous. Developers are advised to avoid using the ** SQLITE_INNOCUOUS flag for application-defined functions unless the ** function has been carefully audited and found to be free of potentially ** security-adverse side-effects and information-leaks. ** </dd> ** ** [[SQLITE_SUBTYPE]] <dt>SQLITE_SUBTYPE</dt><dd> | | | | | | > | > > > > > > > > > > > > > > | 5571 5572 5573 5574 5575 5576 5577 5578 5579 5580 5581 5582 5583 5584 5585 5586 5587 5588 5589 5590 5591 5592 5593 5594 5595 5596 5597 5598 5599 5600 5601 5602 5603 5604 5605 5606 5607 5608 5609 5610 5611 5612 5613 | ** are innocuous. Developers are advised to avoid using the ** SQLITE_INNOCUOUS flag for application-defined functions unless the ** function has been carefully audited and found to be free of potentially ** security-adverse side-effects and information-leaks. ** </dd> ** ** [[SQLITE_SUBTYPE]] <dt>SQLITE_SUBTYPE</dt><dd> ** The SQLITE_SUBTYPE flag indicates to SQLite that a function might call ** [sqlite3_value_subtype()] to inspect the sub-types of its arguments. ** This flag instructs SQLite to omit some corner-case optimizations that ** might disrupt the operation of the [sqlite3_value_subtype()] function, ** causing it to return zero rather than the correct subtype(). ** SQL functions that invokes [sqlite3_value_subtype()] should have this ** property. If the SQLITE_SUBTYPE property is omitted, then the return ** value from [sqlite3_value_subtype()] might sometimes be zero even though ** a non-zero subtype was specified by the function argument expression. ** ** [[SQLITE_RESULT_SUBTYPE]] <dt>SQLITE_RESULT_SUBTYPE</dt><dd> ** The SQLITE_RESULT_SUBTYPE flag indicates to SQLite that a function might call ** [sqlite3_result_subtype()] to cause a sub-type to be associated with its ** result. ** Every function that invokes [sqlite3_result_subtype()] should have this ** property. If it does not, then the call to [sqlite3_result_subtype()] ** might become a no-op if the function is used as term in an ** [expression index]. On the other hand, SQL functions that never invoke ** [sqlite3_result_subtype()] should avoid setting this property, as the ** purpose of this property is to disable certain optimizations that are ** incompatible with subtypes. ** </dd> ** </dl> */ #define SQLITE_DETERMINISTIC 0x000000800 #define SQLITE_DIRECTONLY 0x000080000 #define SQLITE_SUBTYPE 0x000100000 #define SQLITE_INNOCUOUS 0x000200000 #define SQLITE_RESULT_SUBTYPE 0x001000000 /* ** CAPI3REF: Deprecated Functions ** DEPRECATED ** ** These functions are [deprecated]. In order to maintain ** backwards compatibility with older code, these functions continue |
| ︙ | ︙ | |||
5572 5573 5574 5575 5576 5577 5578 5579 5580 5581 5582 5583 5584 5585 5586 5587 5588 5589 5590 5591 5592 5593 5594 | SQLITE_API int sqlite3_value_bytes(sqlite3_value*); SQLITE_API int sqlite3_value_bytes16(sqlite3_value*); SQLITE_API int sqlite3_value_type(sqlite3_value*); SQLITE_API int sqlite3_value_numeric_type(sqlite3_value*); SQLITE_API int sqlite3_value_nochange(sqlite3_value*); SQLITE_API int sqlite3_value_frombind(sqlite3_value*); /* ** CAPI3REF: Finding The Subtype Of SQL Values ** METHOD: sqlite3_value ** ** The sqlite3_value_subtype(V) function returns the subtype for ** an [application-defined SQL function] argument V. The subtype ** information can be used to pass a limited amount of context from ** one SQL function to another. Use the [sqlite3_result_subtype()] ** routine to set the subtype for the return value of an SQL function. */ SQLITE_API unsigned int sqlite3_value_subtype(sqlite3_value*); /* ** CAPI3REF: Copy And Free SQL Values ** METHOD: sqlite3_value ** | > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 5765 5766 5767 5768 5769 5770 5771 5772 5773 5774 5775 5776 5777 5778 5779 5780 5781 5782 5783 5784 5785 5786 5787 5788 5789 5790 5791 5792 5793 5794 5795 5796 5797 5798 5799 5800 5801 5802 5803 5804 5805 5806 5807 5808 5809 5810 5811 5812 5813 5814 5815 | SQLITE_API int sqlite3_value_bytes(sqlite3_value*); SQLITE_API int sqlite3_value_bytes16(sqlite3_value*); SQLITE_API int sqlite3_value_type(sqlite3_value*); SQLITE_API int sqlite3_value_numeric_type(sqlite3_value*); SQLITE_API int sqlite3_value_nochange(sqlite3_value*); SQLITE_API int sqlite3_value_frombind(sqlite3_value*); /* ** CAPI3REF: Report the internal text encoding state of an sqlite3_value object ** METHOD: sqlite3_value ** ** ^(The sqlite3_value_encoding(X) interface returns one of [SQLITE_UTF8], ** [SQLITE_UTF16BE], or [SQLITE_UTF16LE] according to the current text encoding ** of the value X, assuming that X has type TEXT.)^ If sqlite3_value_type(X) ** returns something other than SQLITE_TEXT, then the return value from ** sqlite3_value_encoding(X) is meaningless. ^Calls to ** [sqlite3_value_text(X)], [sqlite3_value_text16(X)], [sqlite3_value_text16be(X)], ** [sqlite3_value_text16le(X)], [sqlite3_value_bytes(X)], or ** [sqlite3_value_bytes16(X)] might change the encoding of the value X and ** thus change the return from subsequent calls to sqlite3_value_encoding(X). ** ** This routine is intended for used by applications that test and validate ** the SQLite implementation. This routine is inquiring about the opaque ** internal state of an [sqlite3_value] object. Ordinary applications should ** not need to know what the internal state of an sqlite3_value object is and ** hence should not need to use this interface. */ SQLITE_API int sqlite3_value_encoding(sqlite3_value*); /* ** CAPI3REF: Finding The Subtype Of SQL Values ** METHOD: sqlite3_value ** ** The sqlite3_value_subtype(V) function returns the subtype for ** an [application-defined SQL function] argument V. The subtype ** information can be used to pass a limited amount of context from ** one SQL function to another. Use the [sqlite3_result_subtype()] ** routine to set the subtype for the return value of an SQL function. ** ** Every [application-defined SQL function] that invoke this interface ** should include the [SQLITE_SUBTYPE] property in the text ** encoding argument when the function is [sqlite3_create_function|registered]. ** If the [SQLITE_SUBTYPE] property is omitted, then sqlite3_value_subtype() ** might return zero instead of the upstream subtype in some corner cases. */ SQLITE_API unsigned int sqlite3_value_subtype(sqlite3_value*); /* ** CAPI3REF: Copy And Free SQL Values ** METHOD: sqlite3_value ** |
| ︙ | ︙ | |||
5624 5625 5626 5627 5628 5629 5630 | ** an aggregate query, the xStep() callback of the aggregate function ** implementation is never called and xFinal() is called exactly once. ** In those cases, sqlite3_aggregate_context() might be called for the ** first time from within xFinal().)^ ** ** ^The sqlite3_aggregate_context(C,N) routine returns a NULL pointer ** when first called if N is less than or equal to zero or if a memory | | | 5845 5846 5847 5848 5849 5850 5851 5852 5853 5854 5855 5856 5857 5858 5859 | ** an aggregate query, the xStep() callback of the aggregate function ** implementation is never called and xFinal() is called exactly once. ** In those cases, sqlite3_aggregate_context() might be called for the ** first time from within xFinal().)^ ** ** ^The sqlite3_aggregate_context(C,N) routine returns a NULL pointer ** when first called if N is less than or equal to zero or if a memory ** allocation error occurs. ** ** ^(The amount of space allocated by sqlite3_aggregate_context(C,N) is ** determined by the N parameter on first successful call. Changing the ** value of N in any subsequent call to sqlite3_aggregate_context() within ** the same aggregate function instance will not resize the memory ** allocation.)^ Within the xFinal callback, it is customary to set ** N=0 in calls to sqlite3_aggregate_context(C,N) so that no |
| ︙ | ︙ | |||
5679 5680 5681 5682 5683 5684 5685 | SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context*); /* ** CAPI3REF: Function Auxiliary Data ** METHOD: sqlite3_context ** ** These functions may be used by (non-aggregate) SQL functions to | | | | | | | | | | | | | | | | > > > | | > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 5900 5901 5902 5903 5904 5905 5906 5907 5908 5909 5910 5911 5912 5913 5914 5915 5916 5917 5918 5919 5920 5921 5922 5923 5924 5925 5926 5927 5928 5929 5930 5931 5932 5933 5934 5935 5936 5937 5938 5939 5940 5941 5942 5943 5944 5945 5946 5947 5948 5949 5950 5951 5952 5953 5954 5955 5956 5957 5958 5959 5960 5961 5962 5963 5964 5965 5966 5967 5968 5969 5970 5971 5972 5973 5974 5975 5976 5977 5978 5979 5980 5981 5982 5983 5984 5985 5986 5987 5988 5989 5990 5991 5992 5993 5994 5995 5996 5997 5998 5999 6000 6001 6002 6003 6004 6005 6006 6007 6008 6009 6010 6011 6012 6013 6014 6015 6016 6017 6018 6019 6020 6021 6022 6023 6024 6025 6026 6027 6028 6029 6030 6031 6032 6033 | SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context*); /* ** CAPI3REF: Function Auxiliary Data ** METHOD: sqlite3_context ** ** These functions may be used by (non-aggregate) SQL functions to ** associate auxiliary data with argument values. If the same argument ** value is passed to multiple invocations of the same SQL function during ** query execution, under some circumstances the associated auxiliary data ** might be preserved. An example of where this might be useful is in a ** regular-expression matching function. The compiled version of the regular ** expression can be stored as auxiliary data associated with the pattern string. ** Then as long as the pattern string remains the same, ** the compiled regular expression can be reused on multiple ** invocations of the same function. ** ** ^The sqlite3_get_auxdata(C,N) interface returns a pointer to the auxiliary data ** associated by the sqlite3_set_auxdata(C,N,P,X) function with the Nth argument ** value to the application-defined function. ^N is zero for the left-most ** function argument. ^If there is no auxiliary data ** associated with the function argument, the sqlite3_get_auxdata(C,N) interface ** returns a NULL pointer. ** ** ^The sqlite3_set_auxdata(C,N,P,X) interface saves P as auxiliary data for the ** N-th argument of the application-defined function. ^Subsequent ** calls to sqlite3_get_auxdata(C,N) return P from the most recent ** sqlite3_set_auxdata(C,N,P,X) call if the auxiliary data is still valid or ** NULL if the auxiliary data has been discarded. ** ^After each call to sqlite3_set_auxdata(C,N,P,X) where X is not NULL, ** SQLite will invoke the destructor function X with parameter P exactly ** once, when the auxiliary data is discarded. ** SQLite is free to discard the auxiliary data at any time, including: <ul> ** <li> ^(when the corresponding function parameter changes)^, or ** <li> ^(when [sqlite3_reset()] or [sqlite3_finalize()] is called for the ** SQL statement)^, or ** <li> ^(when sqlite3_set_auxdata() is invoked again on the same ** parameter)^, or ** <li> ^(during the original sqlite3_set_auxdata() call when a memory ** allocation error occurs.)^ ** <li> ^(during the original sqlite3_set_auxdata() call if the function ** is evaluated during query planning instead of during query execution, ** as sometimes happens with [SQLITE_ENABLE_STAT4].)^ </ul> ** ** Note the last two bullets in particular. The destructor X in ** sqlite3_set_auxdata(C,N,P,X) might be called immediately, before the ** sqlite3_set_auxdata() interface even returns. Hence sqlite3_set_auxdata() ** should be called near the end of the function implementation and the ** function implementation should not make any use of P after ** sqlite3_set_auxdata() has been called. Furthermore, a call to ** sqlite3_get_auxdata() that occurs immediately after a corresponding call ** to sqlite3_set_auxdata() might still return NULL if an out-of-memory ** condition occurred during the sqlite3_set_auxdata() call or if the ** function is being evaluated during query planning rather than during ** query execution. ** ** ^(In practice, auxiliary data is preserved between function calls for ** function parameters that are compile-time constants, including literal ** values and [parameters] and expressions composed from the same.)^ ** ** The value of the N parameter to these interfaces should be non-negative. ** Future enhancements may make use of negative N values to define new ** kinds of function caching behavior. ** ** These routines must be called from the same thread in which ** the SQL function is running. ** ** See also: [sqlite3_get_clientdata()] and [sqlite3_set_clientdata()]. */ SQLITE_API void *sqlite3_get_auxdata(sqlite3_context*, int N); SQLITE_API void sqlite3_set_auxdata(sqlite3_context*, int N, void*, void (*)(void*)); /* ** CAPI3REF: Database Connection Client Data ** METHOD: sqlite3 ** ** These functions are used to associate one or more named pointers ** with a [database connection]. ** A call to sqlite3_set_clientdata(D,N,P,X) causes the pointer P ** to be attached to [database connection] D using name N. Subsequent ** calls to sqlite3_get_clientdata(D,N) will return a copy of pointer P ** or a NULL pointer if there were no prior calls to ** sqlite3_set_clientdata() with the same values of D and N. ** Names are compared using strcmp() and are thus case sensitive. ** ** If P and X are both non-NULL, then the destructor X is invoked with ** argument P on the first of the following occurrences: ** <ul> ** <li> An out-of-memory error occurs during the call to ** sqlite3_set_clientdata() which attempts to register pointer P. ** <li> A subsequent call to sqlite3_set_clientdata(D,N,P,X) is made ** with the same D and N parameters. ** <li> The database connection closes. SQLite does not make any guarantees ** about the order in which destructors are called, only that all ** destructors will be called exactly once at some point during the ** database connection closing process. ** </ul> ** ** SQLite does not do anything with client data other than invoke ** destructors on the client data at the appropriate time. The intended ** use for client data is to provide a mechanism for wrapper libraries ** to store additional information about an SQLite database connection. ** ** There is no limit (other than available memory) on the number of different ** client data pointers (with different names) that can be attached to a ** single database connection. However, the implementation is optimized ** for the case of having only one or two different client data names. ** Applications and wrapper libraries are discouraged from using more than ** one client data name each. ** ** There is no way to enumerate the client data pointers ** associated with a database connection. The N parameter can be thought ** of as a secret key such that only code that knows the secret key is able ** to access the associated data. ** ** Security Warning: These interfaces should not be exposed in scripting ** languages or in other circumstances where it might be possible for an ** an attacker to invoke them. Any agent that can invoke these interfaces ** can probably also take control of the process. ** ** Database connection client data is only available for SQLite ** version 3.44.0 ([dateof:3.44.0]) and later. ** ** See also: [sqlite3_set_auxdata()] and [sqlite3_get_auxdata()]. */ SQLITE_API void *sqlite3_get_clientdata(sqlite3*,const char*); SQLITE_API int sqlite3_set_clientdata(sqlite3*, const char*, void*, void(*)(void*)); /* ** CAPI3REF: Constants Defining Special Destructor Behavior ** ** These are special values for the destructor that is passed in as the ** final argument to routines like [sqlite3_result_blob()]. ^If the destructor ** argument is SQLITE_STATIC, it means that the content pointer is constant |
| ︙ | ︙ | |||
5829 5830 5831 5832 5833 5834 5835 | ** UTF-16 little endian, or UTF-16 big endian, respectively. ** ^The sqlite3_result_text64() interface sets the return value of an ** application-defined function to be a text string in an encoding ** specified by the fifth (and last) parameter, which must be one ** of [SQLITE_UTF8], [SQLITE_UTF16], [SQLITE_UTF16BE], or [SQLITE_UTF16LE]. ** ^SQLite takes the text result from the application from ** the 2nd parameter of the sqlite3_result_text* interfaces. | | | > | | 6115 6116 6117 6118 6119 6120 6121 6122 6123 6124 6125 6126 6127 6128 6129 6130 6131 6132 | ** UTF-16 little endian, or UTF-16 big endian, respectively. ** ^The sqlite3_result_text64() interface sets the return value of an ** application-defined function to be a text string in an encoding ** specified by the fifth (and last) parameter, which must be one ** of [SQLITE_UTF8], [SQLITE_UTF16], [SQLITE_UTF16BE], or [SQLITE_UTF16LE]. ** ^SQLite takes the text result from the application from ** the 2nd parameter of the sqlite3_result_text* interfaces. ** ^If the 3rd parameter to any of the sqlite3_result_text* interfaces ** other than sqlite3_result_text64() is negative, then SQLite computes ** the string length itself by searching the 2nd parameter for the first ** zero character. ** ^If the 3rd parameter to the sqlite3_result_text* interfaces ** is non-negative, then as many bytes (not characters) of the text ** pointed to by the 2nd parameter are taken as the application-defined ** function result. If the 3rd parameter is non-negative, then it ** must be the byte offset into the string where the NUL terminator would ** appear if the string where NUL terminated. If any NUL characters occur ** in the string at a byte offset that is less than the value of the 3rd |
| ︙ | ︙ | |||
5934 5935 5936 5937 5938 5939 5940 5941 5942 5943 5944 5945 5946 5947 | ** The sqlite3_result_subtype(C,T) function causes the subtype of ** the result from the [application-defined SQL function] with ** [sqlite3_context] C to be the value T. Only the lower 8 bits ** of the subtype T are preserved in current versions of SQLite; ** higher order bits are discarded. ** The number of subtype bytes preserved by SQLite might increase ** in future releases of SQLite. */ SQLITE_API void sqlite3_result_subtype(sqlite3_context*,unsigned int); /* ** CAPI3REF: Define New Collating Sequences ** METHOD: sqlite3 ** | > > > > > > > > > > > > > > | 6221 6222 6223 6224 6225 6226 6227 6228 6229 6230 6231 6232 6233 6234 6235 6236 6237 6238 6239 6240 6241 6242 6243 6244 6245 6246 6247 6248 | ** The sqlite3_result_subtype(C,T) function causes the subtype of ** the result from the [application-defined SQL function] with ** [sqlite3_context] C to be the value T. Only the lower 8 bits ** of the subtype T are preserved in current versions of SQLite; ** higher order bits are discarded. ** The number of subtype bytes preserved by SQLite might increase ** in future releases of SQLite. ** ** Every [application-defined SQL function] that invokes this interface ** should include the [SQLITE_RESULT_SUBTYPE] property in its ** text encoding argument when the SQL function is ** [sqlite3_create_function|registered]. If the [SQLITE_RESULT_SUBTYPE] ** property is omitted from the function that invokes sqlite3_result_subtype(), ** then in some cases the sqlite3_result_subtype() might fail to set ** the result subtype. ** ** If SQLite is compiled with -DSQLITE_STRICT_SUBTYPE=1, then any ** SQL function that invokes the sqlite3_result_subtype() interface ** and that does not have the SQLITE_RESULT_SUBTYPE property will raise ** an error. Future versions of SQLite might enable -DSQLITE_STRICT_SUBTYPE=1 ** by default. */ SQLITE_API void sqlite3_result_subtype(sqlite3_context*,unsigned int); /* ** CAPI3REF: Define New Collating Sequences ** METHOD: sqlite3 ** |
| ︙ | ︙ | |||
6105 6106 6107 6108 6109 6110 6111 6112 6113 6114 6115 6116 6117 6118 | ** requested from the operating system is returned. ** ** ^SQLite implements this interface by calling the xSleep() ** method of the default [sqlite3_vfs] object. If the xSleep() method ** of the default VFS is not implemented correctly, or not implemented at ** all, then the behavior of sqlite3_sleep() may deviate from the description ** in the previous paragraphs. */ SQLITE_API int sqlite3_sleep(int); /* ** CAPI3REF: Name Of The Folder Holding Temporary Files ** ** ^(If this global variable is made to point to a string which is | > > > > > > > | 6406 6407 6408 6409 6410 6411 6412 6413 6414 6415 6416 6417 6418 6419 6420 6421 6422 6423 6424 6425 6426 | ** requested from the operating system is returned. ** ** ^SQLite implements this interface by calling the xSleep() ** method of the default [sqlite3_vfs] object. If the xSleep() method ** of the default VFS is not implemented correctly, or not implemented at ** all, then the behavior of sqlite3_sleep() may deviate from the description ** in the previous paragraphs. ** ** If a negative argument is passed to sqlite3_sleep() the results vary by ** VFS and operating system. Some system treat a negative argument as an ** instruction to sleep forever. Others understand it to mean do not sleep ** at all. ^In SQLite version 3.42.0 and later, a negative ** argument passed into sqlite3_sleep() is changed to zero before it is relayed ** down into the xSleep method of the VFS. */ SQLITE_API int sqlite3_sleep(int); /* ** CAPI3REF: Name Of The Folder Holding Temporary Files ** ** ^(If this global variable is made to point to a string which is |
| ︙ | ︙ | |||
6327 6328 6329 6330 6331 6332 6333 | ** <li> [sqlite3_uri_boolean()] ** <li> [sqlite3_uri_int64()] ** <li> [sqlite3_filename_database()] ** <li> [sqlite3_filename_journal()] ** <li> [sqlite3_filename_wal()] ** </ul> */ | | | 6635 6636 6637 6638 6639 6640 6641 6642 6643 6644 6645 6646 6647 6648 6649 | ** <li> [sqlite3_uri_boolean()] ** <li> [sqlite3_uri_int64()] ** <li> [sqlite3_filename_database()] ** <li> [sqlite3_filename_journal()] ** <li> [sqlite3_filename_wal()] ** </ul> */ SQLITE_API sqlite3_filename sqlite3_db_filename(sqlite3 *db, const char *zDbName); /* ** CAPI3REF: Determine if a database is read-only ** METHOD: sqlite3 ** ** ^The sqlite3_db_readonly(D,N) interface returns 1 if the database N ** of connection D is read-only, 0 if it is read/write, or -1 if N is not |
| ︙ | ︙ | |||
6358 6359 6360 6361 6362 6363 6364 | ** </ol> ** ^If the S argument to sqlite3_txn_state(D,S) is not the name of ** a valid schema, then -1 is returned. */ SQLITE_API int sqlite3_txn_state(sqlite3*,const char *zSchema); /* | | | 6666 6667 6668 6669 6670 6671 6672 6673 6674 6675 6676 6677 6678 6679 6680 |
** </ol>
** ^If the S argument to sqlite3_txn_state(D,S) is not the name of
** a valid schema, then -1 is returned.
*/
SQLITE_API int sqlite3_txn_state(sqlite3*,const char *zSchema);
/*
** CAPI3REF: Allowed return values from sqlite3_txn_state()
** KEYWORDS: {transaction state}
**
** These constants define the current transaction state of a database file.
** ^The [sqlite3_txn_state(D,S)] interface returns one of these
** constants in order to describe the transaction state of schema S
** in [database connection] D.
**
|
| ︙ | ︙ | |||
6490 6491 6492 6493 6494 6495 6496 | ** invoked whenever the database connection closes or when the callback ** is overwritten by another invocation of sqlite3_autovacuum_pages(). ** ** <p>^There is only one autovacuum pages callback per database connection. ** ^Each call to the sqlite3_autovacuum_pages() interface overrides all ** previous invocations for that database connection. ^If the callback ** argument (C) to sqlite3_autovacuum_pages(D,C,P,X) is a NULL pointer, | | | 6798 6799 6800 6801 6802 6803 6804 6805 6806 6807 6808 6809 6810 6811 6812 | ** invoked whenever the database connection closes or when the callback ** is overwritten by another invocation of sqlite3_autovacuum_pages(). ** ** <p>^There is only one autovacuum pages callback per database connection. ** ^Each call to the sqlite3_autovacuum_pages() interface overrides all ** previous invocations for that database connection. ^If the callback ** argument (C) to sqlite3_autovacuum_pages(D,C,P,X) is a NULL pointer, ** then the autovacuum steps callback is canceled. The return value ** from sqlite3_autovacuum_pages() is normally SQLITE_OK, but might ** be some other error code if something goes wrong. The current ** implementation will only return SQLITE_OK or SQLITE_MISUSE, but other ** return codes might be added in future releases. ** ** <p>If no autovacuum pages callback is specified (the usual case) or ** a NULL pointer is provided for the callback, |
| ︙ | ︙ | |||
6949 6950 6951 6952 6953 6954 6955 | ** CAPI3REF: Reset Automatic Extension Loading ** ** ^This interface disables all automatic extensions previously ** registered using [sqlite3_auto_extension()]. */ SQLITE_API void sqlite3_reset_auto_extension(void); | < < < < < < < < < | 7257 7258 7259 7260 7261 7262 7263 7264 7265 7266 7267 7268 7269 7270 | ** CAPI3REF: Reset Automatic Extension Loading ** ** ^This interface disables all automatic extensions previously ** registered using [sqlite3_auto_extension()]. */ SQLITE_API void sqlite3_reset_auto_extension(void); /* ** Structures used by the virtual table interface */ typedef struct sqlite3_vtab sqlite3_vtab; typedef struct sqlite3_index_info sqlite3_index_info; typedef struct sqlite3_vtab_cursor sqlite3_vtab_cursor; typedef struct sqlite3_module sqlite3_module; |
| ︙ | ︙ | |||
7018 7019 7020 7021 7022 7023 7024 7025 7026 7027 7028 7029 7030 7031 | ** below are for version 2 and greater. */ int (*xSavepoint)(sqlite3_vtab *pVTab, int); int (*xRelease)(sqlite3_vtab *pVTab, int); int (*xRollbackTo)(sqlite3_vtab *pVTab, int); /* The methods above are in versions 1 and 2 of the sqlite_module object. ** Those below are for version 3 and greater. */ int (*xShadowName)(const char*); }; /* ** CAPI3REF: Virtual Table Indexing Information ** KEYWORDS: sqlite3_index_info ** ** The sqlite3_index_info structure and its substructures is used as part | > > > > | 7317 7318 7319 7320 7321 7322 7323 7324 7325 7326 7327 7328 7329 7330 7331 7332 7333 7334 |
** below are for version 2 and greater. */
int (*xSavepoint)(sqlite3_vtab *pVTab, int);
int (*xRelease)(sqlite3_vtab *pVTab, int);
int (*xRollbackTo)(sqlite3_vtab *pVTab, int);
/* The methods above are in versions 1 and 2 of the sqlite_module object.
** Those below are for version 3 and greater. */
int (*xShadowName)(const char*);
/* The methods above are in versions 1 through 3 of the sqlite_module object.
** Those below are for version 4 and greater. */
int (*xIntegrity)(sqlite3_vtab *pVTab, const char *zSchema,
const char *zTabName, int mFlags, char **pzErr);
};
/*
** CAPI3REF: Virtual Table Indexing Information
** KEYWORDS: sqlite3_index_info
**
** The sqlite3_index_info structure and its substructures is used as part
|
| ︙ | ︙ | |||
7076 7077 7078 7079 7080 7081 7082 | ** aConstraintUsage[].omit flag is an optimization hint. When the omit flag ** is left in its default setting of false, the constraint will always be ** checked separately in byte code. If the omit flag is change to true, then ** the constraint may or may not be checked in byte code. In other words, ** when the omit flag is true there is no guarantee that the constraint will ** not be checked again using byte code.)^ ** | | | | | 7379 7380 7381 7382 7383 7384 7385 7386 7387 7388 7389 7390 7391 7392 7393 7394 7395 7396 | ** aConstraintUsage[].omit flag is an optimization hint. When the omit flag ** is left in its default setting of false, the constraint will always be ** checked separately in byte code. If the omit flag is change to true, then ** the constraint may or may not be checked in byte code. In other words, ** when the omit flag is true there is no guarantee that the constraint will ** not be checked again using byte code.)^ ** ** ^The idxNum and idxStr values are recorded and passed into the ** [xFilter] method. ** ^[sqlite3_free()] is used to free idxStr if and only if ** needToFreeIdxStr is true. ** ** ^The orderByConsumed means that output from [xFilter]/[xNext] will occur in ** the correct order to satisfy the ORDER BY clause so that no separate ** sorting step is required. ** ** ^The estimatedCost value is an estimate of the cost of a particular ** strategy. A cost of N indicates that the cost of the strategy is similar |
| ︙ | ︙ | |||
7199 7200 7201 7202 7203 7204 7205 | ** and hence calls to sqlite3_vtab_rhs_value() for those operators will ** always return SQLITE_NOTFOUND. ** ** The collating sequence to be used for comparison can be found using ** the [sqlite3_vtab_collation()] interface. For most real-world virtual ** tables, the collating sequence of constraints does not matter (for example ** because the constraints are numeric) and so the sqlite3_vtab_collation() | | | 7502 7503 7504 7505 7506 7507 7508 7509 7510 7511 7512 7513 7514 7515 7516 | ** and hence calls to sqlite3_vtab_rhs_value() for those operators will ** always return SQLITE_NOTFOUND. ** ** The collating sequence to be used for comparison can be found using ** the [sqlite3_vtab_collation()] interface. For most real-world virtual ** tables, the collating sequence of constraints does not matter (for example ** because the constraints are numeric) and so the sqlite3_vtab_collation() ** interface is not commonly needed. */ #define SQLITE_INDEX_CONSTRAINT_EQ 2 #define SQLITE_INDEX_CONSTRAINT_GT 4 #define SQLITE_INDEX_CONSTRAINT_LE 8 #define SQLITE_INDEX_CONSTRAINT_LT 16 #define SQLITE_INDEX_CONSTRAINT_GE 32 #define SQLITE_INDEX_CONSTRAINT_MATCH 64 |
| ︙ | ︙ | |||
7358 7359 7360 7361 7362 7363 7364 | ** of the new function always causes an exception to be thrown. So ** the new function is not good for anything by itself. Its only ** purpose is to be a placeholder function that can be overloaded ** by a [virtual table]. */ SQLITE_API int sqlite3_overload_function(sqlite3*, const char *zFuncName, int nArg); | < < < < < < < < < < | 7661 7662 7663 7664 7665 7666 7667 7668 7669 7670 7671 7672 7673 7674 |
** of the new function always causes an exception to be thrown. So
** the new function is not good for anything by itself. Its only
** purpose is to be a placeholder function that can be overloaded
** by a [virtual table].
*/
SQLITE_API int sqlite3_overload_function(sqlite3*, const char *zFuncName, int nArg);
/*
** CAPI3REF: A Handle To An Open BLOB
** KEYWORDS: {BLOB handle} {BLOB handles}
**
** An instance of this object represents an open BLOB on which
** [sqlite3_blob_open | incremental BLOB I/O] can be performed.
** ^Objects of this type are created by [sqlite3_blob_open()]
|
| ︙ | ︙ | |||
7515 7516 7517 7518 7519 7520 7521 | ** ^If the blob handle being closed was opened for read-write access, and if ** the database is in auto-commit mode and there are no other open read-write ** blob handles or active write statements, the current transaction is ** committed. ^If an error occurs while committing the transaction, an error ** code is returned and the transaction rolled back. ** ** Calling this function with an argument that is not a NULL pointer or an | | | 7808 7809 7810 7811 7812 7813 7814 7815 7816 7817 7818 7819 7820 7821 7822 | ** ^If the blob handle being closed was opened for read-write access, and if ** the database is in auto-commit mode and there are no other open read-write ** blob handles or active write statements, the current transaction is ** committed. ^If an error occurs while committing the transaction, an error ** code is returned and the transaction rolled back. ** ** Calling this function with an argument that is not a NULL pointer or an ** open blob handle results in undefined behavior. ^Calling this routine ** with a null pointer (such as would be returned by a failed call to ** [sqlite3_blob_open()]) is a harmless no-op. ^Otherwise, if this function ** is passed a valid open blob handle, the values returned by the ** sqlite3_errcode() and sqlite3_errmsg() functions are set before returning. */ SQLITE_API int sqlite3_blob_close(sqlite3_blob *); |
| ︙ | ︙ | |||
7742 7743 7744 7745 7746 7747 7748 | ** In such cases, the ** mutex must be exited an equal number of times before another thread ** can enter.)^ If the same thread tries to enter any mutex other ** than an SQLITE_MUTEX_RECURSIVE more than once, the behavior is undefined. ** ** ^(Some systems (for example, Windows 95) do not support the operation ** implemented by sqlite3_mutex_try(). On those systems, sqlite3_mutex_try() | | | | > > | | | | 8035 8036 8037 8038 8039 8040 8041 8042 8043 8044 8045 8046 8047 8048 8049 8050 8051 8052 8053 8054 8055 8056 8057 8058 8059 8060 8061 8062 | ** In such cases, the ** mutex must be exited an equal number of times before another thread ** can enter.)^ If the same thread tries to enter any mutex other ** than an SQLITE_MUTEX_RECURSIVE more than once, the behavior is undefined. ** ** ^(Some systems (for example, Windows 95) do not support the operation ** implemented by sqlite3_mutex_try(). On those systems, sqlite3_mutex_try() ** will always return SQLITE_BUSY. In most cases the SQLite core only uses ** sqlite3_mutex_try() as an optimization, so this is acceptable ** behavior. The exceptions are unix builds that set the ** SQLITE_ENABLE_SETLK_TIMEOUT build option. In that case a working ** sqlite3_mutex_try() is required.)^ ** ** ^The sqlite3_mutex_leave() routine exits a mutex that was ** previously entered by the same thread. The behavior ** is undefined if the mutex is not currently entered by the ** calling thread or is not currently allocated. ** ** ^If the argument to sqlite3_mutex_enter(), sqlite3_mutex_try(), ** sqlite3_mutex_leave(), or sqlite3_mutex_free() is a NULL pointer, ** then any of the four routines behaves as a no-op. ** ** See also: [sqlite3_mutex_held()] and [sqlite3_mutex_notheld()]. */ SQLITE_API sqlite3_mutex *sqlite3_mutex_alloc(int); SQLITE_API void sqlite3_mutex_free(sqlite3_mutex*); SQLITE_API void sqlite3_mutex_enter(sqlite3_mutex*); SQLITE_API int sqlite3_mutex_try(sqlite3_mutex*); |
| ︙ | ︙ | |||
7995 7996 7997 7998 7999 8000 8001 8002 8003 8004 8005 8006 8007 8008 8009 8010 8011 8012 8013 8014 8015 | ** Applications should not use any of these parameters or the ** [sqlite3_test_control()] interface. */ #define SQLITE_TESTCTRL_FIRST 5 #define SQLITE_TESTCTRL_PRNG_SAVE 5 #define SQLITE_TESTCTRL_PRNG_RESTORE 6 #define SQLITE_TESTCTRL_PRNG_RESET 7 /* NOT USED */ #define SQLITE_TESTCTRL_BITVEC_TEST 8 #define SQLITE_TESTCTRL_FAULT_INSTALL 9 #define SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS 10 #define SQLITE_TESTCTRL_PENDING_BYTE 11 #define SQLITE_TESTCTRL_ASSERT 12 #define SQLITE_TESTCTRL_ALWAYS 13 #define SQLITE_TESTCTRL_RESERVE 14 /* NOT USED */ #define SQLITE_TESTCTRL_OPTIMIZATIONS 15 #define SQLITE_TESTCTRL_ISKEYWORD 16 /* NOT USED */ #define SQLITE_TESTCTRL_SCRATCHMALLOC 17 /* NOT USED */ #define SQLITE_TESTCTRL_INTERNAL_FUNCTIONS 17 #define SQLITE_TESTCTRL_LOCALTIME_FAULT 18 #define SQLITE_TESTCTRL_EXPLAIN_STMT 19 /* NOT USED */ #define SQLITE_TESTCTRL_ONCE_RESET_THRESHOLD 19 | > > | 8290 8291 8292 8293 8294 8295 8296 8297 8298 8299 8300 8301 8302 8303 8304 8305 8306 8307 8308 8309 8310 8311 8312 | ** Applications should not use any of these parameters or the ** [sqlite3_test_control()] interface. */ #define SQLITE_TESTCTRL_FIRST 5 #define SQLITE_TESTCTRL_PRNG_SAVE 5 #define SQLITE_TESTCTRL_PRNG_RESTORE 6 #define SQLITE_TESTCTRL_PRNG_RESET 7 /* NOT USED */ #define SQLITE_TESTCTRL_FK_NO_ACTION 7 #define SQLITE_TESTCTRL_BITVEC_TEST 8 #define SQLITE_TESTCTRL_FAULT_INSTALL 9 #define SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS 10 #define SQLITE_TESTCTRL_PENDING_BYTE 11 #define SQLITE_TESTCTRL_ASSERT 12 #define SQLITE_TESTCTRL_ALWAYS 13 #define SQLITE_TESTCTRL_RESERVE 14 /* NOT USED */ #define SQLITE_TESTCTRL_JSON_SELFCHECK 14 #define SQLITE_TESTCTRL_OPTIMIZATIONS 15 #define SQLITE_TESTCTRL_ISKEYWORD 16 /* NOT USED */ #define SQLITE_TESTCTRL_SCRATCHMALLOC 17 /* NOT USED */ #define SQLITE_TESTCTRL_INTERNAL_FUNCTIONS 17 #define SQLITE_TESTCTRL_LOCALTIME_FAULT 18 #define SQLITE_TESTCTRL_EXPLAIN_STMT 19 /* NOT USED */ #define SQLITE_TESTCTRL_ONCE_RESET_THRESHOLD 19 |
| ︙ | ︙ | |||
8023 8024 8025 8026 8027 8028 8029 | #define SQLITE_TESTCTRL_RESULT_INTREAL 27 #define SQLITE_TESTCTRL_PRNG_SEED 28 #define SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS 29 #define SQLITE_TESTCTRL_SEEK_COUNT 30 #define SQLITE_TESTCTRL_TRACEFLAGS 31 #define SQLITE_TESTCTRL_TUNE 32 #define SQLITE_TESTCTRL_LOGEST 33 | > | | 8320 8321 8322 8323 8324 8325 8326 8327 8328 8329 8330 8331 8332 8333 8334 8335 | #define SQLITE_TESTCTRL_RESULT_INTREAL 27 #define SQLITE_TESTCTRL_PRNG_SEED 28 #define SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS 29 #define SQLITE_TESTCTRL_SEEK_COUNT 30 #define SQLITE_TESTCTRL_TRACEFLAGS 31 #define SQLITE_TESTCTRL_TUNE 32 #define SQLITE_TESTCTRL_LOGEST 33 #define SQLITE_TESTCTRL_USELONGDOUBLE 34 #define SQLITE_TESTCTRL_LAST 34 /* Largest TESTCTRL */ /* ** CAPI3REF: SQL Keyword Checking ** ** These routines provide access to the set of SQL language keywords ** recognized by SQLite. Applications can uses these routines to determine ** whether or not a specific identifier needs to be escaped (for example, |
| ︙ | ︙ | |||
9479 9480 9481 9482 9483 9484 9485 | ** SQLITE_CONSTRAINT, in which case SQLite falls back to OR ABORT ** constraint handling. ** </dd> ** ** [[SQLITE_VTAB_DIRECTONLY]]<dt>SQLITE_VTAB_DIRECTONLY</dt> ** <dd>Calls of the form ** [sqlite3_vtab_config](db,SQLITE_VTAB_DIRECTONLY) from within the | | | > > > > > > > > > > | 9777 9778 9779 9780 9781 9782 9783 9784 9785 9786 9787 9788 9789 9790 9791 9792 9793 9794 9795 9796 9797 9798 9799 9800 9801 9802 9803 9804 9805 9806 9807 9808 9809 9810 9811 9812 9813 9814 9815 9816 9817 9818 9819 9820 |
** SQLITE_CONSTRAINT, in which case SQLite falls back to OR ABORT
** constraint handling.
** </dd>
**
** [[SQLITE_VTAB_DIRECTONLY]]<dt>SQLITE_VTAB_DIRECTONLY</dt>
** <dd>Calls of the form
** [sqlite3_vtab_config](db,SQLITE_VTAB_DIRECTONLY) from within the
** the [xConnect] or [xCreate] methods of a [virtual table] implementation
** prohibits that virtual table from being used from within triggers and
** views.
** </dd>
**
** [[SQLITE_VTAB_INNOCUOUS]]<dt>SQLITE_VTAB_INNOCUOUS</dt>
** <dd>Calls of the form
** [sqlite3_vtab_config](db,SQLITE_VTAB_INNOCUOUS) from within the
** the [xConnect] or [xCreate] methods of a [virtual table] implementation
** identify that virtual table as being safe to use from within triggers
** and views. Conceptually, the SQLITE_VTAB_INNOCUOUS tag means that the
** virtual table can do no serious harm even if it is controlled by a
** malicious hacker. Developers should avoid setting the SQLITE_VTAB_INNOCUOUS
** flag unless absolutely necessary.
** </dd>
**
** [[SQLITE_VTAB_USES_ALL_SCHEMAS]]<dt>SQLITE_VTAB_USES_ALL_SCHEMAS</dt>
** <dd>Calls of the form
** [sqlite3_vtab_config](db,SQLITE_VTAB_USES_ALL_SCHEMA) from within the
** the [xConnect] or [xCreate] methods of a [virtual table] implementation
** instruct the query planner to begin at least a read transaction on
** all schemas ("main", "temp", and any ATTACH-ed databases) whenever the
** virtual table is used.
** </dd>
** </dl>
*/
#define SQLITE_VTAB_CONSTRAINT_SUPPORT 1
#define SQLITE_VTAB_INNOCUOUS 2
#define SQLITE_VTAB_DIRECTONLY 3
#define SQLITE_VTAB_USES_ALL_SCHEMAS 4
/*
** CAPI3REF: Determine The Virtual Table Conflict Policy
**
** This function may only be called from within a call to the [xUpdate] method
** of a [virtual table] implementation for an INSERT or UPDATE operation. ^The
** value returned is one of [SQLITE_ROLLBACK], [SQLITE_IGNORE], [SQLITE_FAIL],
|
| ︙ | ︙ | |||
9571 9572 9573 9574 9575 9576 9577 | ** of the constraint specifies an alternative collating sequence via ** a [COLLATE clause] on the column definition within the CREATE TABLE ** statement that was passed into [sqlite3_declare_vtab()], then the ** name of that alternative collating sequence is returned. ** <li><p> Otherwise, "BINARY" is returned. ** </ol> */ | | | 9879 9880 9881 9882 9883 9884 9885 9886 9887 9888 9889 9890 9891 9892 9893 | ** of the constraint specifies an alternative collating sequence via ** a [COLLATE clause] on the column definition within the CREATE TABLE ** statement that was passed into [sqlite3_declare_vtab()], then the ** name of that alternative collating sequence is returned. ** <li><p> Otherwise, "BINARY" is returned. ** </ol> */ SQLITE_API const char *sqlite3_vtab_collation(sqlite3_index_info*,int); /* ** CAPI3REF: Determine if a virtual table query is DISTINCT ** METHOD: sqlite3_index_info ** ** This API may only be used from within an [xBestIndex|xBestIndex method] ** of a [virtual table] implementation. The result of calling this |
| ︙ | ︙ | |||
9659 9660 9661 9662 9663 9664 9665 | ** undefined and probably harmful. ** ** ^(A constraint on a virtual table of the form ** "[IN operator|column IN (...)]" is ** communicated to the xBestIndex method as a ** [SQLITE_INDEX_CONSTRAINT_EQ] constraint.)^ If xBestIndex wants to use ** this constraint, it must set the corresponding | | | 9967 9968 9969 9970 9971 9972 9973 9974 9975 9976 9977 9978 9979 9980 9981 | ** undefined and probably harmful. ** ** ^(A constraint on a virtual table of the form ** "[IN operator|column IN (...)]" is ** communicated to the xBestIndex method as a ** [SQLITE_INDEX_CONSTRAINT_EQ] constraint.)^ If xBestIndex wants to use ** this constraint, it must set the corresponding ** aConstraintUsage[].argvIndex to a positive integer. ^(Then, under ** the usual mode of handling IN operators, SQLite generates [bytecode] ** that invokes the [xFilter|xFilter() method] once for each value ** on the right-hand side of the IN operator.)^ Thus the virtual table ** only sees a single value from the right-hand side of the IN operator ** at a time. ** ** In some cases, however, it would be advantageous for the virtual |
| ︙ | ︙ | |||
9728 9729 9730 9731 9732 9733 9734 | ** ** These interfaces are only useful from within the ** [xFilter|xFilter() method] of a [virtual table] implementation. ** The result of invoking these interfaces from any other context ** is undefined and probably harmful. ** ** The X parameter in a call to sqlite3_vtab_in_first(X,P) or | | | < | | 10036 10037 10038 10039 10040 10041 10042 10043 10044 10045 10046 10047 10048 10049 10050 10051 10052 10053 10054 10055 10056 10057 10058 10059 10060 10061 10062 10063 |
**
** These interfaces are only useful from within the
** [xFilter|xFilter() method] of a [virtual table] implementation.
** The result of invoking these interfaces from any other context
** is undefined and probably harmful.
**
** The X parameter in a call to sqlite3_vtab_in_first(X,P) or
** sqlite3_vtab_in_next(X,P) should be one of the parameters to the
** xFilter method which invokes these routines, and specifically
** a parameter that was previously selected for all-at-once IN constraint
** processing use the [sqlite3_vtab_in()] interface in the
** [xBestIndex|xBestIndex method]. ^(If the X parameter is not
** an xFilter argument that was selected for all-at-once IN constraint
** processing, then these routines return [SQLITE_ERROR].)^
**
** ^(Use these routines to access all values on the right-hand side
** of the IN constraint using code like the following:
**
** <blockquote><pre>
** for(rc=sqlite3_vtab_in_first(pList, &pVal);
** rc==SQLITE_OK && pVal;
** rc=sqlite3_vtab_in_next(pList, &pVal)
** ){
** // do something with pVal
** }
** if( rc!=SQLITE_OK ){
** // an error has occurred
** }
|
| ︙ | ︙ | |||
9840 9841 9842 9843 9844 9845 9846 9847 9848 9849 9850 9851 9852 9853 | ** [sqlite3_stmt_scanstatus(S,X,T,V)] interface. Each constant designates a ** different metric for sqlite3_stmt_scanstatus() to return. ** ** When the value returned to V is a string, space to hold that string is ** managed by the prepared statement S and will be automatically freed when ** S is finalized. ** ** <dl> ** [[SQLITE_SCANSTAT_NLOOP]] <dt>SQLITE_SCANSTAT_NLOOP</dt> ** <dd>^The [sqlite3_int64] variable pointed to by the V parameter will be ** set to the total number of times that the X-th loop has run.</dd> ** ** [[SQLITE_SCANSTAT_NVISIT]] <dt>SQLITE_SCANSTAT_NVISIT</dt> ** <dd>^The [sqlite3_int64] variable pointed to by the V parameter will be set | > > > > | 10147 10148 10149 10150 10151 10152 10153 10154 10155 10156 10157 10158 10159 10160 10161 10162 10163 10164 | ** [sqlite3_stmt_scanstatus(S,X,T,V)] interface. Each constant designates a ** different metric for sqlite3_stmt_scanstatus() to return. ** ** When the value returned to V is a string, space to hold that string is ** managed by the prepared statement S and will be automatically freed when ** S is finalized. ** ** Not all values are available for all query elements. When a value is ** not available, the output variable is set to -1 if the value is numeric, ** or to NULL if it is a string (SQLITE_SCANSTAT_NAME). ** ** <dl> ** [[SQLITE_SCANSTAT_NLOOP]] <dt>SQLITE_SCANSTAT_NLOOP</dt> ** <dd>^The [sqlite3_int64] variable pointed to by the V parameter will be ** set to the total number of times that the X-th loop has run.</dd> ** ** [[SQLITE_SCANSTAT_NVISIT]] <dt>SQLITE_SCANSTAT_NVISIT</dt> ** <dd>^The [sqlite3_int64] variable pointed to by the V parameter will be set |
| ︙ | ︙ | |||
9867 9868 9869 9870 9871 9872 9873 | ** used for the X-th loop. ** ** [[SQLITE_SCANSTAT_EXPLAIN]] <dt>SQLITE_SCANSTAT_EXPLAIN</dt> ** <dd>^The "const char *" variable pointed to by the V parameter will be set ** to a zero-terminated UTF-8 string containing the [EXPLAIN QUERY PLAN] ** description for the X-th loop. ** | | | < | | > > > > > > > > > > > > > > > | | | > > > > > > > > > | > | | > | | | < < < < < > > > > > > > > > > > > > | 10178 10179 10180 10181 10182 10183 10184 10185 10186 10187 10188 10189 10190 10191 10192 10193 10194 10195 10196 10197 10198 10199 10200 10201 10202 10203 10204 10205 10206 10207 10208 10209 10210 10211 10212 10213 10214 10215 10216 10217 10218 10219 10220 10221 10222 10223 10224 10225 10226 10227 10228 10229 10230 10231 10232 10233 10234 10235 10236 10237 10238 10239 10240 10241 10242 10243 10244 10245 10246 10247 10248 10249 10250 10251 10252 10253 10254 10255 10256 10257 10258 10259 10260 10261 10262 10263 10264 10265 10266 10267 10268 10269 10270 10271 10272 10273 10274 10275 10276 |
** used for the X-th loop.
**
** [[SQLITE_SCANSTAT_EXPLAIN]] <dt>SQLITE_SCANSTAT_EXPLAIN</dt>
** <dd>^The "const char *" variable pointed to by the V parameter will be set
** to a zero-terminated UTF-8 string containing the [EXPLAIN QUERY PLAN]
** description for the X-th loop.
**
** [[SQLITE_SCANSTAT_SELECTID]] <dt>SQLITE_SCANSTAT_SELECTID</dt>
** <dd>^The "int" variable pointed to by the V parameter will be set to the
** id for the X-th query plan element. The id value is unique within the
** statement. The select-id is the same value as is output in the first
** column of an [EXPLAIN QUERY PLAN] query.
**
** [[SQLITE_SCANSTAT_PARENTID]] <dt>SQLITE_SCANSTAT_PARENTID</dt>
** <dd>The "int" variable pointed to by the V parameter will be set to the
** the id of the parent of the current query element, if applicable, or
** to zero if the query element has no parent. This is the same value as
** returned in the second column of an [EXPLAIN QUERY PLAN] query.
**
** [[SQLITE_SCANSTAT_NCYCLE]] <dt>SQLITE_SCANSTAT_NCYCLE</dt>
** <dd>The sqlite3_int64 output value is set to the number of cycles,
** according to the processor time-stamp counter, that elapsed while the
** query element was being processed. This value is not available for
** all query elements - if it is unavailable the output variable is
** set to -1.
** </dl>
*/
#define SQLITE_SCANSTAT_NLOOP 0
#define SQLITE_SCANSTAT_NVISIT 1
#define SQLITE_SCANSTAT_EST 2
#define SQLITE_SCANSTAT_NAME 3
#define SQLITE_SCANSTAT_EXPLAIN 4
#define SQLITE_SCANSTAT_SELECTID 5
#define SQLITE_SCANSTAT_PARENTID 6
#define SQLITE_SCANSTAT_NCYCLE 7
/*
** CAPI3REF: Prepared Statement Scan Status
** METHOD: sqlite3_stmt
**
** These interfaces return information about the predicted and measured
** performance for pStmt. Advanced applications can use this
** interface to compare the predicted and the measured performance and
** issue warnings and/or rerun [ANALYZE] if discrepancies are found.
**
** Since this interface is expected to be rarely used, it is only
** available if SQLite is compiled using the [SQLITE_ENABLE_STMT_SCANSTATUS]
** compile-time option.
**
** The "iScanStatusOp" parameter determines which status information to return.
** The "iScanStatusOp" must be one of the [scanstatus options] or the behavior
** of this interface is undefined. ^The requested measurement is written into
** a variable pointed to by the "pOut" parameter.
**
** The "flags" parameter must be passed a mask of flags. At present only
** one flag is defined - SQLITE_SCANSTAT_COMPLEX. If SQLITE_SCANSTAT_COMPLEX
** is specified, then status information is available for all elements
** of a query plan that are reported by "EXPLAIN QUERY PLAN" output. If
** SQLITE_SCANSTAT_COMPLEX is not specified, then only query plan elements
** that correspond to query loops (the "SCAN..." and "SEARCH..." elements of
** the EXPLAIN QUERY PLAN output) are available. Invoking API
** sqlite3_stmt_scanstatus() is equivalent to calling
** sqlite3_stmt_scanstatus_v2() with a zeroed flags parameter.
**
** Parameter "idx" identifies the specific query element to retrieve statistics
** for. Query elements are numbered starting from zero. A value of -1 may be
** to query for statistics regarding the entire query. ^If idx is out of range
** - less than -1 or greater than or equal to the total number of query
** elements used to implement the statement - a non-zero value is returned and
** the variable that pOut points to is unchanged.
**
** See also: [sqlite3_stmt_scanstatus_reset()]
*/
SQLITE_API int sqlite3_stmt_scanstatus(
sqlite3_stmt *pStmt, /* Prepared statement for which info desired */
int idx, /* Index of loop to report on */
int iScanStatusOp, /* Information desired. SQLITE_SCANSTAT_* */
void *pOut /* Result written here */
);
SQLITE_API int sqlite3_stmt_scanstatus_v2(
sqlite3_stmt *pStmt, /* Prepared statement for which info desired */
int idx, /* Index of loop to report on */
int iScanStatusOp, /* Information desired. SQLITE_SCANSTAT_* */
int flags, /* Mask of flags defined below */
void *pOut /* Result written here */
);
/*
** CAPI3REF: Prepared Statement Scan Status
** KEYWORDS: {scan status flags}
*/
#define SQLITE_SCANSTAT_COMPLEX 0x0001
/*
** CAPI3REF: Zero Scan-Status Counters
** METHOD: sqlite3_stmt
**
** ^Zero all [sqlite3_stmt_scanstatus()] related event counters.
**
|
| ︙ | ︙ | |||
10008 10009 10010 10011 10012 10013 10014 10015 10016 10017 10018 10019 10020 10021 | ** row being modified or deleted. For an INSERT operation on a rowid table, ** or any operation on a WITHOUT ROWID table, the value of the sixth ** parameter is undefined. For an INSERT or UPDATE on a rowid table the ** seventh parameter is the final rowid value of the row being inserted ** or updated. The value of the seventh parameter passed to the callback ** function is not defined for operations on WITHOUT ROWID tables, or for ** DELETE operations on rowid tables. ** ** The [sqlite3_preupdate_old()], [sqlite3_preupdate_new()], ** [sqlite3_preupdate_count()], and [sqlite3_preupdate_depth()] interfaces ** provide additional information about a preupdate event. These routines ** may only be called from within a preupdate callback. Invoking any of ** these routines from outside of a preupdate callback or with a ** [database connection] pointer that is different from the one supplied | > > > > | 10352 10353 10354 10355 10356 10357 10358 10359 10360 10361 10362 10363 10364 10365 10366 10367 10368 10369 | ** row being modified or deleted. For an INSERT operation on a rowid table, ** or any operation on a WITHOUT ROWID table, the value of the sixth ** parameter is undefined. For an INSERT or UPDATE on a rowid table the ** seventh parameter is the final rowid value of the row being inserted ** or updated. The value of the seventh parameter passed to the callback ** function is not defined for operations on WITHOUT ROWID tables, or for ** DELETE operations on rowid tables. ** ** ^The sqlite3_preupdate_hook(D,C,P) function returns the P argument from ** the previous call on the same [database connection] D, or NULL for ** the first call on D. ** ** The [sqlite3_preupdate_old()], [sqlite3_preupdate_new()], ** [sqlite3_preupdate_count()], and [sqlite3_preupdate_depth()] interfaces ** provide additional information about a preupdate event. These routines ** may only be called from within a preupdate callback. Invoking any of ** these routines from outside of a preupdate callback or with a ** [database connection] pointer that is different from the one supplied |
| ︙ | ︙ | |||
10048 10049 10050 10051 10052 10053 10054 | ** operation; or 1 for inserts, updates, or deletes invoked by top-level ** triggers; or 2 for changes resulting from triggers called by top-level ** triggers; and so forth. ** ** When the [sqlite3_blob_write()] API is used to update a blob column, ** the pre-update hook is invoked with SQLITE_DELETE. This is because the ** in this case the new values are not available. In this case, when a | | | 10396 10397 10398 10399 10400 10401 10402 10403 10404 10405 10406 10407 10408 10409 10410 | ** operation; or 1 for inserts, updates, or deletes invoked by top-level ** triggers; or 2 for changes resulting from triggers called by top-level ** triggers; and so forth. ** ** When the [sqlite3_blob_write()] API is used to update a blob column, ** the pre-update hook is invoked with SQLITE_DELETE. This is because the ** in this case the new values are not available. In this case, when a ** callback made with op==SQLITE_DELETE is actually a write using the ** sqlite3_blob_write() API, the [sqlite3_preupdate_blobwrite()] returns ** the index of the column being written. In other cases, where the ** pre-update hook is being invoked for some other reason, including a ** regular DELETE, sqlite3_preupdate_blobwrite() returns -1. ** ** See also: [sqlite3_update_hook()] */ |
| ︙ | ︙ | |||
10308 10309 10310 10311 10312 10313 10314 10315 10316 10317 10318 10319 10320 10321 | ** memory representation of the database exists. A contiguous memory ** representation of the database will usually only exist if there has ** been a prior call to [sqlite3_deserialize(D,S,...)] with the same ** values of D and S. ** The size of the database is written into *P even if the ** SQLITE_SERIALIZE_NOCOPY bit is set but no contiguous copy ** of the database exists. ** ** A call to sqlite3_serialize(D,S,P,F) might return NULL even if the ** SQLITE_SERIALIZE_NOCOPY bit is omitted from argument F if a memory ** allocation error occurs. ** ** This interface is omitted if SQLite is compiled with the ** [SQLITE_OMIT_DESERIALIZE] option. | > > > > > > > | 10656 10657 10658 10659 10660 10661 10662 10663 10664 10665 10666 10667 10668 10669 10670 10671 10672 10673 10674 10675 10676 | ** memory representation of the database exists. A contiguous memory ** representation of the database will usually only exist if there has ** been a prior call to [sqlite3_deserialize(D,S,...)] with the same ** values of D and S. ** The size of the database is written into *P even if the ** SQLITE_SERIALIZE_NOCOPY bit is set but no contiguous copy ** of the database exists. ** ** After the call, if the SQLITE_SERIALIZE_NOCOPY bit had been set, ** the returned buffer content will remain accessible and unchanged ** until either the next write operation on the connection or when ** the connection is closed, and applications must not modify the ** buffer. If the bit had been clear, the returned buffer will not ** be accessed by SQLite after the call. ** ** A call to sqlite3_serialize(D,S,P,F) might return NULL even if the ** SQLITE_SERIALIZE_NOCOPY bit is omitted from argument F if a memory ** allocation error occurs. ** ** This interface is omitted if SQLite is compiled with the ** [SQLITE_OMIT_DESERIALIZE] option. |
| ︙ | ︙ | |||
10356 10357 10358 10359 10360 10361 10362 10363 10364 10365 10366 10367 10368 10369 10370 10371 10372 10373 10374 10375 10376 10377 | ** size does not exceed M bytes. ** ** If the SQLITE_DESERIALIZE_FREEONCLOSE bit is set in F, then SQLite will ** invoke sqlite3_free() on the serialization buffer when the database ** connection closes. If the SQLITE_DESERIALIZE_RESIZEABLE bit is set, then ** SQLite will try to increase the buffer size using sqlite3_realloc64() ** if writes on the database cause it to grow larger than M bytes. ** ** The sqlite3_deserialize() interface will fail with SQLITE_BUSY if the ** database is currently in a read transaction or is involved in a backup ** operation. ** ** It is not possible to deserialized into the TEMP database. If the ** S argument to sqlite3_deserialize(D,S,P,N,M,F) is "temp" then the ** function returns SQLITE_ERROR. ** ** If sqlite3_deserialize(D,S,P,N,M,F) fails for any reason and if the ** SQLITE_DESERIALIZE_FREEONCLOSE bit is set in argument F, then ** [sqlite3_free()] is invoked on argument P prior to returning. ** ** This interface is omitted if SQLite is compiled with the ** [SQLITE_OMIT_DESERIALIZE] option. | > > > > > > > > > > | 10711 10712 10713 10714 10715 10716 10717 10718 10719 10720 10721 10722 10723 10724 10725 10726 10727 10728 10729 10730 10731 10732 10733 10734 10735 10736 10737 10738 10739 10740 10741 10742 | ** size does not exceed M bytes. ** ** If the SQLITE_DESERIALIZE_FREEONCLOSE bit is set in F, then SQLite will ** invoke sqlite3_free() on the serialization buffer when the database ** connection closes. If the SQLITE_DESERIALIZE_RESIZEABLE bit is set, then ** SQLite will try to increase the buffer size using sqlite3_realloc64() ** if writes on the database cause it to grow larger than M bytes. ** ** Applications must not modify the buffer P or invalidate it before ** the database connection D is closed. ** ** The sqlite3_deserialize() interface will fail with SQLITE_BUSY if the ** database is currently in a read transaction or is involved in a backup ** operation. ** ** It is not possible to deserialized into the TEMP database. If the ** S argument to sqlite3_deserialize(D,S,P,N,M,F) is "temp" then the ** function returns SQLITE_ERROR. ** ** The deserialized database should not be in [WAL mode]. If the database ** is in WAL mode, then any attempt to use the database file will result ** in an [SQLITE_CANTOPEN] error. The application can set the ** [file format version numbers] (bytes 18 and 19) of the input database P ** to 0x01 prior to invoking sqlite3_deserialize(D,S,P,N,M,F) to force the ** database file into rollback mode and work around this limitation. ** ** If sqlite3_deserialize(D,S,P,N,M,F) fails for any reason and if the ** SQLITE_DESERIALIZE_FREEONCLOSE bit is set in argument F, then ** [sqlite3_free()] is invoked on argument P prior to returning. ** ** This interface is omitted if SQLite is compiled with the ** [SQLITE_OMIT_DESERIALIZE] option. |
| ︙ | ︙ | |||
10413 10414 10415 10416 10417 10418 10419 10420 10421 10422 10423 10424 10425 10426 | /* ** Undo the hack that converts floating point types to integer for ** builds on processors without floating point support. */ #ifdef SQLITE_OMIT_FLOATING_POINT # undef double #endif #ifdef __cplusplus } /* End of the 'extern "C"' block */ #endif #endif /* SQLITE3_H */ /******** Begin file sqlite3rtree.h *********/ | > > > > > > > > > > > > > | 10778 10779 10780 10781 10782 10783 10784 10785 10786 10787 10788 10789 10790 10791 10792 10793 10794 10795 10796 10797 10798 10799 10800 10801 10802 10803 10804 | /* ** Undo the hack that converts floating point types to integer for ** builds on processors without floating point support. */ #ifdef SQLITE_OMIT_FLOATING_POINT # undef double #endif #if defined(__wasi__) # undef SQLITE_WASI # define SQLITE_WASI 1 # undef SQLITE_OMIT_WAL # define SQLITE_OMIT_WAL 1/* because it requires shared memory APIs */ # ifndef SQLITE_OMIT_LOAD_EXTENSION # define SQLITE_OMIT_LOAD_EXTENSION # endif # ifndef SQLITE_THREADSAFE # define SQLITE_THREADSAFE 0 # endif #endif #ifdef __cplusplus } /* End of the 'extern "C"' block */ #endif #endif /* SQLITE3_H */ /******** Begin file sqlite3rtree.h *********/ |
| ︙ | ︙ | |||
10620 10621 10622 10623 10624 10625 10626 | ** Session objects must be deleted before the database handle to which they ** are attached is closed. Refer to the documentation for ** [sqlite3session_create()] for details. */ SQLITE_API void sqlite3session_delete(sqlite3_session *pSession); /* | | | | > > > > | | | | | > | > > > > > > > | > | 10998 10999 11000 11001 11002 11003 11004 11005 11006 11007 11008 11009 11010 11011 11012 11013 11014 11015 11016 11017 11018 11019 11020 11021 11022 11023 11024 11025 11026 11027 11028 11029 11030 11031 11032 11033 11034 11035 11036 11037 11038 11039 11040 11041 11042 11043 11044 11045 11046 11047 11048 11049 11050 11051 11052 11053 11054 11055 | ** Session objects must be deleted before the database handle to which they ** are attached is closed. Refer to the documentation for ** [sqlite3session_create()] for details. */ SQLITE_API void sqlite3session_delete(sqlite3_session *pSession); /* ** CAPI3REF: Configure a Session Object ** METHOD: sqlite3_session ** ** This method is used to configure a session object after it has been ** created. At present the only valid values for the second parameter are ** [SQLITE_SESSION_OBJCONFIG_SIZE] and [SQLITE_SESSION_OBJCONFIG_ROWID]. ** */ SQLITE_API int sqlite3session_object_config(sqlite3_session*, int op, void *pArg); /* ** CAPI3REF: Options for sqlite3session_object_config ** ** The following values may passed as the the 2nd parameter to ** sqlite3session_object_config(). ** ** <dt>SQLITE_SESSION_OBJCONFIG_SIZE <dd> ** This option is used to set, clear or query the flag that enables ** the [sqlite3session_changeset_size()] API. Because it imposes some ** computational overhead, this API is disabled by default. Argument ** pArg must point to a value of type (int). If the value is initially ** 0, then the sqlite3session_changeset_size() API is disabled. If it ** is greater than 0, then the same API is enabled. Or, if the initial ** value is less than zero, no change is made. In all cases the (int) ** variable is set to 1 if the sqlite3session_changeset_size() API is ** enabled following the current call, or 0 otherwise. ** ** It is an error (SQLITE_MISUSE) to attempt to modify this setting after ** the first table has been attached to the session object. ** ** <dt>SQLITE_SESSION_OBJCONFIG_ROWID <dd> ** This option is used to set, clear or query the flag that enables ** collection of data for tables with no explicit PRIMARY KEY. ** ** Normally, tables with no explicit PRIMARY KEY are simply ignored ** by the sessions module. However, if this flag is set, it behaves ** as if such tables have a column "_rowid_ INTEGER PRIMARY KEY" inserted ** as their leftmost columns. ** ** It is an error (SQLITE_MISUSE) to attempt to modify this setting after ** the first table has been attached to the session object. */ #define SQLITE_SESSION_OBJCONFIG_SIZE 1 #define SQLITE_SESSION_OBJCONFIG_ROWID 2 /* ** CAPI3REF: Enable Or Disable A Session Object ** METHOD: sqlite3_session ** ** Enable or disable the recording of changes by a session object. When ** enabled, a session object records changes made to the database. When |
| ︙ | ︙ | |||
11410 11411 11412 11413 11414 11415 11416 11417 11418 11419 11420 11421 11422 11423 | void *pA, /* Pointer to buffer containing changeset A */ int nB, /* Number of bytes in buffer pB */ void *pB, /* Pointer to buffer containing changeset B */ int *pnOut, /* OUT: Number of bytes in output changeset */ void **ppOut /* OUT: Buffer containing output changeset */ ); /* ** CAPI3REF: Changegroup Handle ** ** A changegroup is an object used to combine two or more ** [changesets] or [patchsets] */ | > > > > > > > > > > > > | 11801 11802 11803 11804 11805 11806 11807 11808 11809 11810 11811 11812 11813 11814 11815 11816 11817 11818 11819 11820 11821 11822 11823 11824 11825 11826 | void *pA, /* Pointer to buffer containing changeset A */ int nB, /* Number of bytes in buffer pB */ void *pB, /* Pointer to buffer containing changeset B */ int *pnOut, /* OUT: Number of bytes in output changeset */ void **ppOut /* OUT: Buffer containing output changeset */ ); /* ** CAPI3REF: Upgrade the Schema of a Changeset/Patchset */ SQLITE_API int sqlite3changeset_upgrade( sqlite3 *db, const char *zDb, int nIn, const void *pIn, /* Input changeset */ int *pnOut, void **ppOut /* OUT: Inverse of input */ ); /* ** CAPI3REF: Changegroup Handle ** ** A changegroup is an object used to combine two or more ** [changesets] or [patchsets] */ |
| ︙ | ︙ | |||
11457 11458 11459 11460 11461 11462 11463 11464 11465 11466 11467 11468 11469 11470 | ** ** As well as the regular sqlite3changegroup_add() and ** sqlite3changegroup_output() functions, also available are the streaming ** versions sqlite3changegroup_add_strm() and sqlite3changegroup_output_strm(). */ SQLITE_API int sqlite3changegroup_new(sqlite3_changegroup **pp); /* ** CAPI3REF: Add A Changeset To A Changegroup ** METHOD: sqlite3_changegroup ** ** Add all changes within the changeset (or patchset) in buffer pData (size ** nData bytes) to the changegroup. ** | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 11860 11861 11862 11863 11864 11865 11866 11867 11868 11869 11870 11871 11872 11873 11874 11875 11876 11877 11878 11879 11880 11881 11882 11883 11884 11885 11886 11887 11888 11889 11890 11891 11892 11893 11894 11895 11896 11897 11898 11899 11900 11901 11902 11903 11904 11905 |
**
** As well as the regular sqlite3changegroup_add() and
** sqlite3changegroup_output() functions, also available are the streaming
** versions sqlite3changegroup_add_strm() and sqlite3changegroup_output_strm().
*/
SQLITE_API int sqlite3changegroup_new(sqlite3_changegroup **pp);
/*
** CAPI3REF: Add a Schema to a Changegroup
** METHOD: sqlite3_changegroup_schema
**
** This method may be used to optionally enforce the rule that the changesets
** added to the changegroup handle must match the schema of database zDb
** ("main", "temp", or the name of an attached database). If
** sqlite3changegroup_add() is called to add a changeset that is not compatible
** with the configured schema, SQLITE_SCHEMA is returned and the changegroup
** object is left in an undefined state.
**
** A changeset schema is considered compatible with the database schema in
** the same way as for sqlite3changeset_apply(). Specifically, for each
** table in the changeset, there exists a database table with:
**
** <ul>
** <li> The name identified by the changeset, and
** <li> at least as many columns as recorded in the changeset, and
** <li> the primary key columns in the same position as recorded in
** the changeset.
** </ul>
**
** The output of the changegroup object always has the same schema as the
** database nominated using this function. In cases where changesets passed
** to sqlite3changegroup_add() have fewer columns than the corresponding table
** in the database schema, these are filled in using the default column
** values from the database schema. This makes it possible to combined
** changesets that have different numbers of columns for a single table
** within a changegroup, provided that they are otherwise compatible.
*/
SQLITE_API int sqlite3changegroup_schema(sqlite3_changegroup*, sqlite3*, const char *zDb);
/*
** CAPI3REF: Add A Changeset To A Changegroup
** METHOD: sqlite3_changegroup
**
** Add all changes within the changeset (or patchset) in buffer pData (size
** nData bytes) to the changegroup.
**
|
| ︙ | ︙ | |||
11525 11526 11527 11528 11529 11530 11531 | ** changeset was recorded immediately after the changesets already ** added to the changegroup. ** </table> ** ** If the new changeset contains changes to a table that is already present ** in the changegroup, then the number of columns and the position of the ** primary key columns for the table must be consistent. If this is not the | | > > > > > | | | < > | | 11960 11961 11962 11963 11964 11965 11966 11967 11968 11969 11970 11971 11972 11973 11974 11975 11976 11977 11978 11979 11980 11981 11982 11983 11984 11985 | ** changeset was recorded immediately after the changesets already ** added to the changegroup. ** </table> ** ** If the new changeset contains changes to a table that is already present ** in the changegroup, then the number of columns and the position of the ** primary key columns for the table must be consistent. If this is not the ** case, this function fails with SQLITE_SCHEMA. Except, if the changegroup ** object has been configured with a database schema using the ** sqlite3changegroup_schema() API, then it is possible to combine changesets ** with different numbers of columns for a single table, provided that ** they are otherwise compatible. ** ** If the input changeset appears to be corrupt and the corruption is ** detected, SQLITE_CORRUPT is returned. Or, if an out-of-memory condition ** occurs during processing, this function returns SQLITE_NOMEM. ** ** In all cases, if an error occurs the state of the final contents of the ** changegroup is undefined. If no error occurs, SQLITE_OK is returned. */ SQLITE_API int sqlite3changegroup_add(sqlite3_changegroup*, int nData, void *pData); /* ** CAPI3REF: Obtain A Composite Changeset From A Changegroup ** METHOD: sqlite3_changegroup ** |
| ︙ | ︙ | |||
11783 11784 11785 11786 11787 11788 11789 11790 11791 11792 11793 11794 11795 11796 11797 11798 11799 | ** caller has an open transaction or savepoint when apply_v2() is called, ** it may revert the partially applied changeset by rolling it back. ** ** <dt>SQLITE_CHANGESETAPPLY_INVERT <dd> ** Invert the changeset before applying it. This is equivalent to inverting ** a changeset using sqlite3changeset_invert() before applying it. It is ** an error to specify this flag with a patchset. */ #define SQLITE_CHANGESETAPPLY_NOSAVEPOINT 0x0001 #define SQLITE_CHANGESETAPPLY_INVERT 0x0002 /* ** CAPI3REF: Constants Passed To The Conflict Handler ** ** Values that may be passed as the second argument to a conflict-handler. ** ** <dl> | > > > > > > > > > > > > > > > > > > > > > | 12223 12224 12225 12226 12227 12228 12229 12230 12231 12232 12233 12234 12235 12236 12237 12238 12239 12240 12241 12242 12243 12244 12245 12246 12247 12248 12249 12250 12251 12252 12253 12254 12255 12256 12257 12258 12259 12260 | ** caller has an open transaction or savepoint when apply_v2() is called, ** it may revert the partially applied changeset by rolling it back. ** ** <dt>SQLITE_CHANGESETAPPLY_INVERT <dd> ** Invert the changeset before applying it. This is equivalent to inverting ** a changeset using sqlite3changeset_invert() before applying it. It is ** an error to specify this flag with a patchset. ** ** <dt>SQLITE_CHANGESETAPPLY_IGNORENOOP <dd> ** Do not invoke the conflict handler callback for any changes that ** would not actually modify the database even if they were applied. ** Specifically, this means that the conflict handler is not invoked ** for: ** <ul> ** <li>a delete change if the row being deleted cannot be found, ** <li>an update change if the modified fields are already set to ** their new values in the conflicting row, or ** <li>an insert change if all fields of the conflicting row match ** the row being inserted. ** </ul> ** ** <dt>SQLITE_CHANGESETAPPLY_FKNOACTION <dd> ** If this flag it set, then all foreign key constraints in the target ** database behave as if they were declared with "ON UPDATE NO ACTION ON ** DELETE NO ACTION", even if they are actually CASCADE, RESTRICT, SET NULL ** or SET DEFAULT. */ #define SQLITE_CHANGESETAPPLY_NOSAVEPOINT 0x0001 #define SQLITE_CHANGESETAPPLY_INVERT 0x0002 #define SQLITE_CHANGESETAPPLY_IGNORENOOP 0x0004 #define SQLITE_CHANGESETAPPLY_FKNOACTION 0x0008 /* ** CAPI3REF: Constants Passed To The Conflict Handler ** ** Values that may be passed as the second argument to a conflict-handler. ** ** <dl> |
| ︙ | ︙ | |||
12351 12352 12353 12354 12355 12356 12357 | ** an OOM condition or IO error), an appropriate SQLite error code is ** returned. ** ** This function may be quite inefficient if used with an FTS5 table ** created with the "columnsize=0" option. ** ** xColumnText: | > > > | | > > | | | > | | | | 12812 12813 12814 12815 12816 12817 12818 12819 12820 12821 12822 12823 12824 12825 12826 12827 12828 12829 12830 12831 12832 12833 12834 12835 12836 12837 12838 12839 12840 12841 12842 12843 12844 12845 12846 12847 12848 12849 12850 12851 12852 12853 12854 12855 12856 12857 12858 12859 12860 12861 12862 12863 12864 12865 | ** an OOM condition or IO error), an appropriate SQLite error code is ** returned. ** ** This function may be quite inefficient if used with an FTS5 table ** created with the "columnsize=0" option. ** ** xColumnText: ** If parameter iCol is less than zero, or greater than or equal to the ** number of columns in the table, SQLITE_RANGE is returned. ** ** Otherwise, this function attempts to retrieve the text of column iCol of ** the current document. If successful, (*pz) is set to point to a buffer ** containing the text in utf-8 encoding, (*pn) is set to the size in bytes ** (not characters) of the buffer and SQLITE_OK is returned. Otherwise, ** if an error occurs, an SQLite error code is returned and the final values ** of (*pz) and (*pn) are undefined. ** ** xPhraseCount: ** Returns the number of phrases in the current query expression. ** ** xPhraseSize: ** If parameter iCol is less than zero, or greater than or equal to the ** number of phrases in the current query, as returned by xPhraseCount, ** 0 is returned. Otherwise, this function returns the number of tokens in ** phrase iPhrase of the query. Phrases are numbered starting from zero. ** ** xInstCount: ** Set *pnInst to the total number of occurrences of all phrases within ** the query within the current row. Return SQLITE_OK if successful, or ** an error code (i.e. SQLITE_NOMEM) if an error occurs. ** ** This API can be quite slow if used with an FTS5 table created with the ** "detail=none" or "detail=column" option. If the FTS5 table is created ** with either "detail=none" or "detail=column" and "content=" option ** (i.e. if it is a contentless table), then this API always returns 0. ** ** xInst: ** Query for the details of phrase match iIdx within the current row. ** Phrase matches are numbered starting from zero, so the iIdx argument ** should be greater than or equal to zero and smaller than the value ** output by xInstCount(). If iIdx is less than zero or greater than ** or equal to the value returned by xInstCount(), SQLITE_RANGE is returned. ** ** Otherwise, output parameter *piPhrase is set to the phrase number, *piCol ** to the column in which it occurs and *piOff the token offset of the ** first token of the phrase. SQLITE_OK is returned if successful, or an ** error code (i.e. SQLITE_NOMEM) if an error occurs. ** ** This API can be quite slow if used with an FTS5 table created with the ** "detail=none" or "detail=column" option. ** ** xRowid: ** Returns the rowid of the current row. ** |
| ︙ | ︙ | |||
12409 12410 12411 12412 12413 12414 12415 12416 12417 12418 12419 12420 12421 12422 | ** current query is executed. Any column filter that applies to ** phrase iPhrase of the current query is included in $p. For each ** row visited, the callback function passed as the fourth argument ** is invoked. The context and API objects passed to the callback ** function may be used to access the properties of each matched row. ** Invoking Api.xUserData() returns a copy of the pointer passed as ** the third argument to pUserData. ** ** If the callback function returns any value other than SQLITE_OK, the ** query is abandoned and the xQueryPhrase function returns immediately. ** If the returned value is SQLITE_DONE, xQueryPhrase returns SQLITE_OK. ** Otherwise, the error code is propagated upwards. ** ** If the query runs to completion without incident, SQLITE_OK is returned. | > > > > | 12876 12877 12878 12879 12880 12881 12882 12883 12884 12885 12886 12887 12888 12889 12890 12891 12892 12893 | ** current query is executed. Any column filter that applies to ** phrase iPhrase of the current query is included in $p. For each ** row visited, the callback function passed as the fourth argument ** is invoked. The context and API objects passed to the callback ** function may be used to access the properties of each matched row. ** Invoking Api.xUserData() returns a copy of the pointer passed as ** the third argument to pUserData. ** ** If parameter iPhrase is less than zero, or greater than or equal to ** the number of phrases in the query, as returned by xPhraseCount(), ** this function returns SQLITE_RANGE. ** ** If the callback function returns any value other than SQLITE_OK, the ** query is abandoned and the xQueryPhrase function returns immediately. ** If the returned value is SQLITE_DONE, xQueryPhrase returns SQLITE_OK. ** Otherwise, the error code is propagated upwards. ** ** If the query runs to completion without incident, SQLITE_OK is returned. |
| ︙ | ︙ | |||
12524 12525 12526 12527 12528 12529 12530 12531 12532 12533 12534 12535 12536 12537 |
** xPhraseFirstColumn() may also be obtained using xPhraseFirst/xPhraseNext
** (or xInst/xInstCount). The chief advantage of this API is that it is
** significantly more efficient than those alternatives when used with
** "detail=column" tables.
**
** xPhraseNextColumn()
** See xPhraseFirstColumn above.
*/
struct Fts5ExtensionApi {
int iVersion; /* Currently always set to 3 */
void *(*xUserData)(Fts5Context*);
int (*xColumnCount)(Fts5Context*);
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 12995 12996 12997 12998 12999 13000 13001 13002 13003 13004 13005 13006 13007 13008 13009 13010 13011 13012 13013 13014 13015 13016 13017 13018 13019 13020 13021 13022 13023 13024 13025 13026 13027 13028 13029 13030 13031 13032 13033 13034 13035 13036 13037 13038 13039 13040 13041 |
** xPhraseFirstColumn() may also be obtained using xPhraseFirst/xPhraseNext
** (or xInst/xInstCount). The chief advantage of this API is that it is
** significantly more efficient than those alternatives when used with
** "detail=column" tables.
**
** xPhraseNextColumn()
** See xPhraseFirstColumn above.
**
** xQueryToken(pFts5, iPhrase, iToken, ppToken, pnToken)
** This is used to access token iToken of phrase iPhrase of the current
** query. Before returning, output parameter *ppToken is set to point
** to a buffer containing the requested token, and *pnToken to the
** size of this buffer in bytes.
**
** If iPhrase or iToken are less than zero, or if iPhrase is greater than
** or equal to the number of phrases in the query as reported by
** xPhraseCount(), or if iToken is equal to or greater than the number of
** tokens in the phrase, SQLITE_RANGE is returned and *ppToken and *pnToken
are both zeroed.
**
** The output text is not a copy of the query text that specified the
** token. It is the output of the tokenizer module. For tokendata=1
** tables, this includes any embedded 0x00 and trailing data.
**
** xInstToken(pFts5, iIdx, iToken, ppToken, pnToken)
** This is used to access token iToken of phrase hit iIdx within the
** current row. If iIdx is less than zero or greater than or equal to the
** value returned by xInstCount(), SQLITE_RANGE is returned. Otherwise,
** output variable (*ppToken) is set to point to a buffer containing the
** matching document token, and (*pnToken) to the size of that buffer in
** bytes. This API is not available if the specified token matches a
** prefix query term. In that case both output variables are always set
** to 0.
**
** The output text is not a copy of the document text that was tokenized.
** It is the output of the tokenizer module. For tokendata=1 tables, this
** includes any embedded 0x00 and trailing data.
**
** This API can be quite slow if used with an FTS5 table created with the
** "detail=none" or "detail=column" option.
*/
struct Fts5ExtensionApi {
int iVersion; /* Currently always set to 3 */
void *(*xUserData)(Fts5Context*);
int (*xColumnCount)(Fts5Context*);
|
| ︙ | ︙ | |||
12561 12562 12563 12564 12565 12566 12567 12568 12569 12570 12571 12572 12573 12574 | void *(*xGetAuxdata)(Fts5Context*, int bClear); int (*xPhraseFirst)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*, int*); void (*xPhraseNext)(Fts5Context*, Fts5PhraseIter*, int *piCol, int *piOff); int (*xPhraseFirstColumn)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*); void (*xPhraseNextColumn)(Fts5Context*, Fts5PhraseIter*, int *piCol); }; /* ** CUSTOM AUXILIARY FUNCTIONS *************************************************************************/ /************************************************************************* | > > > > > > > | 13065 13066 13067 13068 13069 13070 13071 13072 13073 13074 13075 13076 13077 13078 13079 13080 13081 13082 13083 13084 13085 |
void *(*xGetAuxdata)(Fts5Context*, int bClear);
int (*xPhraseFirst)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*, int*);
void (*xPhraseNext)(Fts5Context*, Fts5PhraseIter*, int *piCol, int *piOff);
int (*xPhraseFirstColumn)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*);
void (*xPhraseNextColumn)(Fts5Context*, Fts5PhraseIter*, int *piCol);
/* Below this point are iVersion>=3 only */
int (*xQueryToken)(Fts5Context*,
int iPhrase, int iToken,
const char **ppToken, int *pnToken
);
int (*xInstToken)(Fts5Context*, int iIdx, int iToken, const char**, int*);
};
/*
** CUSTOM AUXILIARY FUNCTIONS
*************************************************************************/
/*************************************************************************
|
| ︙ | ︙ | |||
12755 12756 12757 12758 12759 12760 12761 | ** provide synonyms for prefixes). However, a non-prefix query like '1st' ** will match against "1st" and "first". This method does not require ** extra disk space, as no extra entries are added to the FTS index. ** On the other hand, it may require more CPU cycles to run MATCH queries, ** as separate queries of the FTS index are required for each synonym. ** ** When using methods (2) or (3), it is important that the tokenizer only | | | | 13266 13267 13268 13269 13270 13271 13272 13273 13274 13275 13276 13277 13278 13279 13280 13281 |
** provide synonyms for prefixes). However, a non-prefix query like '1st'
** will match against "1st" and "first". This method does not require
** extra disk space, as no extra entries are added to the FTS index.
** On the other hand, it may require more CPU cycles to run MATCH queries,
** as separate queries of the FTS index are required for each synonym.
**
** When using methods (2) or (3), it is important that the tokenizer only
** provide synonyms when tokenizing document text (method (3)) or query
** text (method (2)), not both. Doing so will not cause any errors, but is
** inefficient.
*/
typedef struct Fts5Tokenizer Fts5Tokenizer;
typedef struct fts5_tokenizer fts5_tokenizer;
struct fts5_tokenizer {
int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut);
void (*xDelete)(Fts5Tokenizer*);
|
| ︙ | ︙ | |||
12804 12805 12806 12807 12808 12809 12810 |
struct fts5_api {
int iVersion; /* Currently always set to 2 */
/* Create a new tokenizer */
int (*xCreateTokenizer)(
fts5_api *pApi,
const char *zName,
| | | | | 13315 13316 13317 13318 13319 13320 13321 13322 13323 13324 13325 13326 13327 13328 13329 13330 13331 13332 13333 13334 13335 13336 13337 13338 13339 13340 13341 13342 13343 13344 13345 13346 |
struct fts5_api {
int iVersion; /* Currently always set to 2 */
/* Create a new tokenizer */
int (*xCreateTokenizer)(
fts5_api *pApi,
const char *zName,
void *pUserData,
fts5_tokenizer *pTokenizer,
void (*xDestroy)(void*)
);
/* Find an existing tokenizer */
int (*xFindTokenizer)(
fts5_api *pApi,
const char *zName,
void **ppUserData,
fts5_tokenizer *pTokenizer
);
/* Create a new auxiliary function */
int (*xCreateFunction)(
fts5_api *pApi,
const char *zName,
void *pUserData,
fts5_extension_function xFunction,
void (*xDestroy)(void*)
);
};
/*
** END OF REGISTRATION API
|
| ︙ | ︙ |
Changes to skins/README.md.
| ︙ | ︙ | |||
19 20 21 22 23 24 25 |
called "skins/newskin" below but you should use a new original
name, of course.)
2. Add files skins/newskin/css.txt, skins/newskin/details.txt,
skins/newskin/footer.txt, skins/newskin/header.txt, and
skins/newskin/js.txt. Be sure to "fossil add" these files.
| | | 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
called "skins/newskin" below but you should use a new original
name, of course.)
2. Add files skins/newskin/css.txt, skins/newskin/details.txt,
skins/newskin/footer.txt, skins/newskin/header.txt, and
skins/newskin/js.txt. Be sure to "fossil add" these files.
3. Go to the tools/ directory and rerun "tclsh makemake.tcl". This
step rebuilds the various makefiles so that they have dependencies
on the skin files you just installed.
4. Edit the BuiltinSkin[] array near the top of the src/skins.c source
file so that it describes and references the "newskin" skin.
5. Type "make" to rebuild.
|
| ︙ | ︙ |
Changes to skins/ardoise/css.txt.
| ︙ | ︙ | |||
47 48 49 50 51 52 53 |
.filetree ul ul,
.mainmenu ul,
sub,
sup {
position: relative
}
.filetree .dir > div.filetreeline > a,
| | | 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
.filetree ul ul,
.mainmenu ul,
sub,
sup {
position: relative
}
.filetree .dir > div.filetreeline > a,
ul.browser li.dir > a {
background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIxNiIgdmlld0JveD0iMCAwIDUuMjkyIDQuMjMzIj48cGF0aCBkPSJNLjc5NC41M3YzLjE3NGgzLjcwNFYxLjMyM0gyLjkxVi41Mjl6IiBmaWxsPSIjMWQyMDIxIiBzdHJva2U9IiNmZjgwMDAiIHN0cm9rZS13aWR0aD0iLjUyOSIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIi8+PC9zdmc+)
}
dfn,
span.modpending {
font-style: italic
}
html {
|
| ︙ | ︙ | |||
305 306 307 308 309 310 311 312 313 314 315 316 317 318 |
display: inline-block;
box-sizing: border-box;
text-decoration: none;
text-align: center;
white-space: nowrap;
cursor: pointer
}
@media (min-width:550px) {
.container {
width: 95%
}
.column,
.columns {
margin-left: 4%
| > > > > > | 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 |
display: inline-block;
box-sizing: border-box;
text-decoration: none;
text-align: center;
white-space: nowrap;
cursor: pointer
}
input[type=submit]:disabled {
color: rgb(70,70,70);
background-color: rgb(153,153,153);
}
@media (min-width:550px) {
.container {
width: 95%
}
.column,
.columns {
margin-left: 4%
|
| ︙ | ︙ | |||
788 789 790 791 792 793 794 |
list-style: none;
line-height: 1.6
}
ul.browser li.dir {
background-repeat: no-repeat
}
.filetree a,
| | | 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 |
list-style: none;
line-height: 1.6
}
ul.browser li.dir {
background-repeat: no-repeat
}
.filetree a,
ul.browser li.file > a{
background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIxNiIgdmlld0JveD0iMCAwIDUuMjkyIDQuMjMzIj48cGF0aCBkPSJNMS4zMjMuMjY1djMuNzA0aDIuNjQ2VjEuMzIzTDIuOTEuMjY1eiIgZmlsbD0iIzFkMjAyMSIgc3Ryb2tlPSIjZGRkIiBzdHJva2Utd2lkdGg9Ii41MjkiIHN0cm9rZS1saW5lam9pbj0icm91bmQiLz48cGF0aCBkPSJNMi42NDYuMjY1aC4yNjR2MS4zMjNoMS4wNiIgZmlsbD0iIzFkMjAyMSIgc3Ryb2tlPSIjZGRkIiBzdHJva2Utd2lkdGg9Ii41MjkiIHN0cm9rZS1saW5lam9pbj0icm91bmQiLz48L3N2Zz4=);
background-repeat: no-repeat
}
div.filetreeline:hover *,
ul.browser li.dir:hover,
ul.browser li.dir:hover *,
ul.browser li.file:hover,
|
| ︙ | ︙ | |||
1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 |
content: '';
position: absolute;
top: 3px;
left: 3px;
width: 4px;
height: 4px;
background: #bbb
}
.tl-node.sel:after {
content: '';
position: absolute;
top: 1px;
left: 1px;
width: 8px;
| > > > > > > > > | 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 |
content: '';
position: absolute;
top: 3px;
left: 3px;
width: 4px;
height: 4px;
background: #bbb
}
.tl-node.closed-leaf svg {
position: absolute;
top: 0px;
left: 0px;
width: 10px;
height: 10px;
color: #bbb;
}
.tl-node.sel:after {
content: '';
position: absolute;
top: 1px;
left: 1px;
width: 8px;
|
| ︙ | ︙ | |||
1380 1381 1382 1383 1384 1385 1386 |
.intLink[title=Hyperlink] {
background: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMiIgaGVpZ2h0PSIyMiIgdmlld0JveD0iMCAwIDUuODIxIDUuODIxIj48cGF0aCBkPSJNMS43NTIgMy45NjloLjc5M20tLjc5My0yLjExN2guNzkzTTEuNzUyIDMuOTdjLS4zNDMgMC0uNjU5LS4xMTktLjgzLS40MTUtLjE3MS0uMjk3LS4xNzEtLjk5IDAtMS4yODcuMTcxLS4yOTYuNDg3LS40MTUuODMtLjQxNW0yLjIxNyAyLjExNmgtLjc5NG0uNzk0LTIuMTE3aC0uNzk0bS43OTQgMi4xMTdjLjM0MiAwIC42NTgtLjExOS44My0uNDE1LjE3LS4yOTcuMTctLjk5IDAtMS4yODctLjE3Mi0uMjk2LS40ODgtLjQxNS0uODMtLjQxNU0yLjExNyAyLjkxaDEuNTg3IiBmaWxsPSJub25lIiBzdHJva2U9IiNhYWEiIHN0cm9rZS13aWR0aD0iLjUyOSIvPjwvc3ZnPg==)
}
.intLink[title=Hyperlink]:hover {
background: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMiIgaGVpZ2h0PSIyMiIgdmlld0JveD0iMCAwIDUuODIxIDUuODIxIj48cmVjdCByeT0iLjI2NSIgcng9Ii4yNjUiIHk9Ii0uMDAxIiBoZWlnaHQ9IjUuODIxIiB3aWR0aD0iNS44MjEiIGZpbGw9IiM1NTUiLz48cGF0aCBkPSJNMS43NTIgMy45NjhoLjc5M20tLjc5My0yLjExN2guNzkzbS0uNzkzIDIuMTE3Yy0uMzQzIDAtLjY1OS0uMTE5LS44My0uNDE1LS4xNzEtLjI5Ny0uMTcxLS45OSAwLTEuMjg3LjE3MS0uMjk2LjQ4Ny0uNDE1LjgzLS40MTVtMi4yMTcgMi4xMTdoLS43OTRtLjc5NC0yLjExN2gtLjc5NG0uNzk0IDIuMTE3Yy4zNDIgMCAuNjU4LS4xMTkuODMtLjQxNS4xNy0uMjk3LjE3LS45OSAwLTEuMjg3LS4xNzItLjI5Ni0uNDg4LS40MTUtLjgzLS40MTVNMi4xMTcgMi45MWgxLjU4NyIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjZGRkIiBzdHJva2Utd2lkdGg9Ii41MjkiLz48L3N2Zz4=)
}
.statistics-report-graph-line {
| > | > > > > | 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 |
.intLink[title=Hyperlink] {
background: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMiIgaGVpZ2h0PSIyMiIgdmlld0JveD0iMCAwIDUuODIxIDUuODIxIj48cGF0aCBkPSJNMS43NTIgMy45NjloLjc5M20tLjc5My0yLjExN2guNzkzTTEuNzUyIDMuOTdjLS4zNDMgMC0uNjU5LS4xMTktLjgzLS40MTUtLjE3MS0uMjk3LS4xNzEtLjk5IDAtMS4yODcuMTcxLS4yOTYuNDg3LS40MTUuODMtLjQxNW0yLjIxNyAyLjExNmgtLjc5NG0uNzk0LTIuMTE3aC0uNzk0bS43OTQgMi4xMTdjLjM0MiAwIC42NTgtLjExOS44My0uNDE1LjE3LS4yOTcuMTctLjk5IDAtMS4yODctLjE3Mi0uMjk2LS40ODgtLjQxNS0uODMtLjQxNU0yLjExNyAyLjkxaDEuNTg3IiBmaWxsPSJub25lIiBzdHJva2U9IiNhYWEiIHN0cm9rZS13aWR0aD0iLjUyOSIvPjwvc3ZnPg==)
}
.intLink[title=Hyperlink]:hover {
background: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMiIgaGVpZ2h0PSIyMiIgdmlld0JveD0iMCAwIDUuODIxIDUuODIxIj48cmVjdCByeT0iLjI2NSIgcng9Ii4yNjUiIHk9Ii0uMDAxIiBoZWlnaHQ9IjUuODIxIiB3aWR0aD0iNS44MjEiIGZpbGw9IiM1NTUiLz48cGF0aCBkPSJNMS43NTIgMy45NjhoLjc5M20tLjc5My0yLjExN2guNzkzbS0uNzkzIDIuMTE3Yy0uMzQzIDAtLjY1OS0uMTE5LS44My0uNDE1LS4xNzEtLjI5Ny0uMTcxLS45OSAwLTEuMjg3LjE3MS0uMjk2LjQ4Ny0uNDE1LjgzLS40MTVtMi4yMTcgMi4xMTdoLS43OTRtLjc5NC0yLjExN2gtLjc5NG0uNzk0IDIuMTE3Yy4zNDIgMCAuNjU4LS4xMTkuODMtLjQxNS4xNy0uMjk3LjE3LS45OSAwLTEuMjg3LS4xNzItLjI5Ni0uNDg4LS40MTUtLjgzLS40MTVNMi4xMTcgMi45MWgxLjU4NyIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjZGRkIiBzdHJva2Utd2lkdGg9Ii41MjkiLz48L3N2Zz4=)
}
.statistics-report-graph-line {
border: 2px solid #ff8000;
background-color: #ff8000;
}
.statistics-report-graph-extra {
border: 2px dashed #446979;
border-left-style: none;
}
mark,
p.noMoreShun,
p.shunned,
span.modpending {
color: #ff8000
}
|
| ︙ | ︙ | |||
1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 |
.u-cf {
content: "";
display: table;
clear: both
}
div.forumSel {
background-color: #3a3a3a;
}
.debug {
background-color: #330;
border: 2px solid #aa0;
}
.capsumOff {
| > > > | 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 |
.u-cf {
content: "";
display: table;
clear: both
}
div.forumSel {
background-color: #3a3a3a;
}
body.forum .forumPosts.fileage a:visited {
color: rgb(72, 144, 224);
}
.debug {
background-color: #330;
border: 2px solid #aa0;
}
.capsumOff {
|
| ︙ | ︙ |
Changes to skins/blitz/css.txt.
| ︙ | ︙ | |||
561 562 563 564 565 566 567 568 569 570 571 572 573 574 |
input[type="submit"]:hover,
input[type="submit"]:focus {
color: white !important;
background-color: #648898;
border-color: #648898;
}
/* Forms
––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */
input[type="email"],
input[type="number"],
input[type="search"],
input[type="text"],
| > > > > > | 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 |
input[type="submit"]:hover,
input[type="submit"]:focus {
color: white !important;
background-color: #648898;
border-color: #648898;
}
input[type="submit"]:disabled {
color: rgb(128,128,128);
background-color: rgb(153,153,153);
}
/* Forms
––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */
input[type="email"],
input[type="number"],
input[type="search"],
input[type="text"],
|
| ︙ | ︙ | |||
954 955 956 957 958 959 960 961 962 963 964 |
* Repository tree navigation.
––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */
ul.browser {
list-style: none;
}
ul.browser li.dir {
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QAVQBVAFV4xrLkAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3wMLExABnLjGZQAAAEFJREFUOMtjYKAQMIaGhv4npGj16tWMuORYGBgYGOZW+eDUnNy2Ba/hLMQ4E58rCRpAyHVMlAbiqAGjBhCdmWgKAHp4Dh0ZusP3AAAAAElFTkSuQmCC);
background-repeat: no-repeat;
background-position: 0px center;
padding-left: 22px;
| > > > > < > > > > < | 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 |
* Repository tree navigation.
––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */
ul.browser {
list-style: none;
}
ul.browser li.dir {
padding-top: 2px;
}
ul.browser li.dir > a {
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QAVQBVAFV4xrLkAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3wMLExABnLjGZQAAAEFJREFUOMtjYKAQMIaGhv4npGj16tWMuORYGBgYGOZW+eDUnNy2Ba/hLMQ4E58rCRpAyHVMlAbiqAGjBhCdmWgKAHp4Dh0ZusP3AAAAAElFTkSuQmCC);
background-repeat: no-repeat;
background-position: 0px center;
padding-left: 22px;
}
ul.browser li.file {
padding-top: 2px;
}
ul.browser li.file > a {
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QAVQBVAFV4xrLkAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3wMLExMaPfBcSgAAAFNJREFUOMvtkzEOwDAIA02VL5pHwiOTJZFQmkqFOTex+CwPCCYkAaDjB+4u65ZdYGafQVV9SR4kWQUke0mwS1o2HGcAQKs0R1lpQuQKruD4jVnBAG/cGRqf0U66AAAAAElFTkSuQmCC);
background-repeat: no-repeat;
background-position: 0px center;
padding-left: 22px;
}
div.filetreeline {
display: table;
width: 100%;
white-space: nowrap;
}
|
| ︙ | ︙ | |||
1112 1113 1114 1115 1116 1117 1118 |
}
span.timelineComment {
padding: 0px 5px;
}
| | | 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 |
}
span.timelineComment {
padding: 0px 5px;
}
/* Login/Logout
––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */
table.login_out {
}
table.login_out .login_out_label {
font-weight: 700;
text-align: right;
|
| ︙ | ︙ | |||
1264 1265 1266 1267 1268 1269 1270 |
.mainmenu:after,
.row:after,
.u-cf {
content: "";
display: table;
clear: both;
}
| > > > > | 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 |
.mainmenu:after,
.row:after,
.u-cf {
content: "";
display: table;
clear: both;
}
body.forum .forumPosts.fileage a:visited {
color: #648999;
}
|
Deleted skins/bootstrap/css.txt.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted skins/bootstrap/details.txt.
|
| < < < < |
Deleted skins/bootstrap/footer.txt.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted skins/bootstrap/header.txt.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to skins/darkmode/css.txt.
| ︙ | ︙ | |||
124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
input[type=button]:hover,
input[type=reset]:hover,
input[type=submit]:hover {
background-color: #FF4500f0;
color: rgba(24,24,24,0.8);
outline: 0
}
.button:focus,
button:focus,
input[type=button]:focus,
input[type=reset]:focus,
input[type=submit]:focus {
outline: 2px outset #333;
border-color: #888;
| > > > > | 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 |
input[type=button]:hover,
input[type=reset]:hover,
input[type=submit]:hover {
background-color: #FF4500f0;
color: rgba(24,24,24,0.8);
outline: 0
}
input[type=submit]:disabled {
color: #363636;
background-color: #707070;
}
.button:focus,
button:focus,
input[type=button]:focus,
input[type=reset]:focus,
input[type=submit]:focus {
outline: 2px outset #333;
border-color: #888;
|
| ︙ | ︙ | |||
381 382 383 384 385 386 387 388 389 390 391 392 393 394 |
content: '';
position: absolute;
top: 3px;
left: 3px;
width: 4px;
height: 4px;
background: #bbb
}
.tl-node.sel:after {
content: '';
position: absolute;
top: 1px;
left: 1px;
width: 8px;
| > > > > > > > > | 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 |
content: '';
position: absolute;
top: 3px;
left: 3px;
width: 4px;
height: 4px;
background: #bbb
}
.tl-node.closed-leaf svg {
position: absolute;
top: 0px;
left: 0px;
width: 10px;
height: 10px;
color: #bbb;
}
.tl-node.sel:after {
content: '';
position: absolute;
top: 1px;
left: 1px;
width: 8px;
|
| ︙ | ︙ | |||
554 555 556 557 558 559 560 |
}
body.forum .debug {
background-color: #FF4500f0;
color: rgba(24,24,24,0.8);
}
| | > > > > > > > > > > > > | 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 |
}
body.forum .debug {
background-color: #FF4500f0;
color: rgba(24,24,24,0.8);
}
body.forum .forumPosts.fileage tr:hover {
background-color: #333;
color: rgba(24,24,24,0.8);
}
body.forum .forumPosts.fileage tr:hover {
background-color: #333;
color: rgba(24,24,24,0.8);
}
body.forum .forumPosts.fileage tr:hover > td:nth-child(1),
body.forum .forumPosts.fileage tr:hover > td:nth-child(3) {
color: #ffffffe0;
}
body.forum .forumPostBody > div blockquote {
border: 1px inset;
padding: 0 0.5em;
}
body.forum .forumPosts.fileage a:visited {
color: rgba(98, 150, 205, 0.9);
}
body.report table.report tr td { color: black }
body.report table.report a { color: blue }
body.tkt td.tktDspValue { color: black }
body.tkt td.tktDspValue a { color: blue }
body.branch .brlist > table > tbody > tr:hover:not(.selected),
body.branch .brlist > table > tbody > tr.selected {
background-color: #442800;
}
|
Changes to skins/eagle/css.txt.
| ︙ | ︙ | |||
207 208 209 210 211 212 213 214 215 216 217 218 219 220 |
position: absolute;
top: 3px;
left: 3px;
width: 4px;
height: 4px;
background: #fff;
}
/* up arrow */
.tl-arrow.u {
margin-top: -1px;
border-width: 0 3px;
border-bottom: 7px solid #fff;
}
| > > > > > > > > > > | 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 |
position: absolute;
top: 3px;
left: 3px;
width: 4px;
height: 4px;
background: #fff;
}
/* closed leaf commit marker */
.tl-node.closed-leaf svg {
position: absolute;
top: 0px;
left: 0px;
width: 10px;
height: 10px;
color: #fff;
}
/* up arrow */
.tl-arrow.u {
margin-top: -1px;
border-width: 0 3px;
border-bottom: 7px solid #fff;
}
|
| ︙ | ︙ | |||
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 |
}
div.forumSel {
background-color: #808080;
}
div.forumObs {
color: white;
}
.fileage td {
font-family: "courier new";
}
div.filetreeline:hover {
background-color: #7EA2D9;
}
table.numbered-lines td.line-numbers span.selected-line {
background-color: #7EA2D9;
}
.statistics-report-graph-line {
background-color: #7EA2D9;
}
.timelineModernCell[id], .timelineColumnarCell[id], .timelineDetailCell[id] {
background-color: #455978;
}
.capsumOff {
| > > > > > > > > | 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 |
}
div.forumSel {
background-color: #808080;
}
div.forumObs {
color: white;
}
body.forum .forumPosts.fileage a:visited {
color: rgba(176,176,176,1.0);
}
.fileage td {
font-family: "courier new";
}
div.filetreeline:hover {
background-color: #7EA2D9;
}
table.numbered-lines td.line-numbers span.selected-line {
background-color: #7EA2D9;
}
.statistics-report-graph-line {
border: 2px solid #7EA2D9;
background-color: #7EA2D9;
}
.statistics-report-graph-extra {
border: 2px solid #7EA2D9;
border-left-style: none;
}
.timelineModernCell[id], .timelineColumnarCell[id], .timelineDetailCell[id] {
background-color: #455978;
}
.capsumOff {
|
| ︙ | ︙ |
Changes to skins/xekri/css.txt.
| ︙ | ︙ | |||
511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 |
/**************************************
* Statistics Reports
*/
.statistics-report-graph-line {
background-color: #22e;
}
.statistics-report-table-events th {
padding: 0 1rem;
}
.statistics-report-table-events td {
| > > > > > | 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 |
/**************************************
* Statistics Reports
*/
.statistics-report-graph-line {
border: 2px solid #22e;
background-color: #22e;
}
.statistics-report-graph-extra {
border: 2px dashed #22e;
border-left-style: none;
}
.statistics-report-table-events th {
padding: 0 1rem;
}
.statistics-report-table-events td {
|
| ︙ | ︙ | |||
1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 |
}
div.forumPostBody blockquote {
border-width: 1pt;
border-style: solid;
padding: 0 0.5em;
border-radius: 0.25em;
}
.debug {
color: black;
}
body.branch .brlist > table > tbody > tr:hover:not(.selected),
body.branch .brlist > table > tbody > tr.selected {
| > > > > > > > | 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 |
}
div.forumPostBody blockquote {
border-width: 1pt;
border-style: solid;
padding: 0 0.5em;
border-radius: 0.25em;
}
body.forum .forumPosts.fileage a {
color: #60c0ff;
}
body.forum .forumPosts.fileage a:visited {
color: #40a0ff;
}
.debug {
color: black;
}
body.branch .brlist > table > tbody > tr:hover:not(.selected),
body.branch .brlist > table > tbody > tr.selected {
|
| ︙ | ︙ |
Changes to src/add.c.
| ︙ | ︙ | |||
21 22 23 24 25 26 27 | #include "config.h" #include "add.h" #include <assert.h> #include <dirent.h> #include "cygsup.h" /* | | | | | 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 |
#include "config.h"
#include "add.h"
#include <assert.h>
#include <dirent.h>
#include "cygsup.h"
/*
** This routine returns the names of files in a working check-out that
** are created by Fossil itself, and hence should not be added, deleted,
** or merge, and should be omitted from "clean" and "extras" lists.
**
** Return the N-th name. The first name has N==0. When all names have
** been used, return 0.
*/
const char *fossil_reserved_name(int N, int omitRepo){
/* Possible names of the local per-check-out database file and
** its associated journals
*/
static const char *const azName[] = {
"_FOSSIL_",
"_FOSSIL_-journal",
"_FOSSIL_-wal",
"_FOSSIL_-shm",
".fslckout",
".fslckout-journal",
".fslckout-wal",
".fslckout-shm",
/* The use of ".fos" as the name of the check-out database is
** deprecated. Use ".fslckout" instead. At some point, the following
** entries should be removed. 2012-02-04 */
".fos",
".fos-journal",
".fos-wal",
".fos-shm",
};
|
| ︙ | ︙ | |||
65 66 67 68 69 70 71 |
{ "manifest", MFESTFLG_RAW },
{ "manifest.uuid", MFESTFLG_UUID },
{ "manifest.tags", MFESTFLG_TAGS }
};
static const char *azManifests[3];
/*
| | | 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
{ "manifest", MFESTFLG_RAW },
{ "manifest.uuid", MFESTFLG_UUID },
{ "manifest.tags", MFESTFLG_TAGS }
};
static const char *azManifests[3];
/*
** Names of repository files, if they exist in the check-out.
*/
static const char *azRepo[4] = { 0, 0, 0, 0 };
/* Cached setting "manifest" */
static int cachedManifest = -1;
static int numManifests;
|
| ︙ | ︙ | |||
243 244 245 246 247 248 249 | } db_finalize(&loop); blob_reset(&repoName); return nAdd; } /* | | | | | 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 |
}
db_finalize(&loop);
blob_reset(&repoName);
return nAdd;
}
/*
** Resets the ADDED/DELETED state of a check-out, such that all
** newly-added (but not yet committed) files are no longer added and
** newly-removed (but not yet committed) files are no longer
** removed. If bIsAdd is true, it operates on the "add" state, else it
** operates on the "rm" state.
**
** If bDryRun is true it outputs what it would have done, but does not
** actually do it. In this case it rolls back the transaction it
** starts (so don't start a transaction before calling this).
**
** If bVerbose is true it outputs the name of each reset entry.
**
** This is intended to be called only in the context of the
** add/rm/addremove commands, after a call to verify_all_options().
**
** Un-added files are not modified but any un-rm'd files which are
** missing from the check-out are restored from the repo. un-rm'd files
** which exist in the check-out are left as-is, rather than restoring
** them using vfile_to_disk(), to avoid overwriting any local changes
** made to those files.
*/
static void addremove_reset(int bIsAdd, int bDryRun, int bVerbose){
int nReset = 0; /* # of entries which get reset */
Stmt stmt; /* vfile loop query */
|
| ︙ | ︙ | |||
339 340 341 342 343 344 345 | /* ** COMMAND: add ** ** Usage: %fossil add ?OPTIONS? FILE1 ?FILE2 ...? ** ** Make arrangements to add one or more files or directories to the | | < | | | 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 |
/*
** COMMAND: add
**
** Usage: %fossil add ?OPTIONS? FILE1 ?FILE2 ...?
**
** Make arrangements to add one or more files or directories to the
** current check-out at the next [[commit]].
**
** When adding files or directories recursively, filenames that begin
** with "." are excluded by default. To include such files, add
** the "--dotfiles" option to the command-line.
**
** The --ignore and --clean options are comma-separated lists of glob patterns
** for files to be excluded. Example: '*.o,*.obj,*.exe' If the --ignore
** option does not appear on the command line then the "ignore-glob" setting
** is used. If the --clean option does not appear on the command line then
** the "clean-glob" setting is used.
**
** If files are attempted to be added explicitly on the command line which
** match "ignore-glob", a confirmation is asked first. This can be prevented
** using the -f|--force option.
**
** The --case-sensitive option determines whether or not filenames should
** be treated case sensitive or not. If the option is not given, the default
** depends on the global setting, or the operating system default, if not set.
**
** Options:
** --case-sensitive BOOL Override the case-sensitive setting
** --dotfiles Include files beginning with a dot (".")
** -f|--force Add files without prompting
** --ignore CSG Ignore unmanaged files matching patterns from
** the Comma Separated Glob (CSG) pattern list
** --clean CSG Also ignore files matching patterns from
** the Comma Separated Glob (CSG) list
** --reset Reset the ADDED state of a check-out, such
** that all newly-added (but not yet committed)
** files are no longer added. No flags other
** than --verbose and --dry-run may be used
** with --reset.
** --allow-reserved Permit filenames which are reserved on
** Windows platforms. Such files cannot be
** checked out on Windows, so use with care.
**
** The following options are only valid with --reset:
** -v|--verbose Output information about each --reset file
** -n|--dry-run Display instead of run actions
**
** See also: [[addremove]], [[rm]]
*/
void add_cmd(void){
int i; /* Loop counter */
int vid; /* Currently checked-out version */
int nRoot; /* Full path characters in g.zLocalRoot */
const char *zCleanFlag; /* The --clean option or clean-glob setting */
const char *zIgnoreFlag; /* The --ignore option or ignore-glob setting */
Glob *pIgnore, *pClean; /* Ignore everything matching the glob patterns */
unsigned scanFlags = 0; /* Flags passed to vfile_scan() */
int forceFlag;
int allowReservedFlag = 0; /* --allow-reserved flag */
|
| ︙ | ︙ | |||
435 436 437 438 439 440 441 |
/* Load the names of all files that are to be added into sfile temp table */
for(i=2; i<g.argc; i++){
char *zName;
int isDir;
Blob fullName = empty_blob;
/* file_tree_name() throws a fatal error if g.argv[i] is outside of the
| | | 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 |
/* Load the names of all files that are to be added into sfile temp table */
for(i=2; i<g.argc; i++){
char *zName;
int isDir;
Blob fullName = empty_blob;
/* file_tree_name() throws a fatal error if g.argv[i] is outside of the
** check-out. */
file_tree_name(g.argv[i], &fullName, 0, 1);
blob_reset(&fullName);
file_canonical_name(g.argv[i], &fullName, 0);
zName = blob_str(&fullName);
isDir = file_isdir(zName, RepoFILE);
if( isDir==1 ){
vfile_scan(&fullName, nRoot-1, scanFlags, pClean, pIgnore, RepoFILE);
|
| ︙ | ︙ | |||
528 529 530 531 532 533 534 |
}
file_tree_name(zOldName, &fullOldName, 1, 1);
db_multi_exec("INSERT INTO fremove VALUES('%q');", blob_str(&fullOldName));
blob_reset(&fullOldName);
}
/*
| | | 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 |
}
file_tree_name(zOldName, &fullOldName, 1, 1);
db_multi_exec("INSERT INTO fremove VALUES('%q');", blob_str(&fullOldName));
blob_reset(&fullOldName);
}
/*
** This function deletes files from the check-out, using the file names
** contained in the temporary table "fremove". The temporary table is
** created on demand by the add_file_to_remove() function.
**
** If dryRunFlag is non-zero, no files will be removed; however, their
** names will still be output.
**
** The temporary table "fremove" is dropped after being processed.
|
| ︙ | ︙ | |||
579 580 581 582 583 584 585 | ** to do so. ** ** WARNING: If the "--hard" option is specified -OR- the "mv-rm-files" ** setting is non-zero, files WILL BE removed from disk as well. ** This does NOT apply to the 'forget' command. ** ** Options: | | | | | | 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 | ** to do so. ** ** WARNING: If the "--hard" option is specified -OR- the "mv-rm-files" ** setting is non-zero, files WILL BE removed from disk as well. ** This does NOT apply to the 'forget' command. ** ** Options: ** --soft Skip removing files from the check-out. ** This supersedes the --hard option. ** --hard Remove files from the check-out ** --case-sensitive BOOL Override the case-sensitive setting ** -n|--dry-run If given, display instead of run actions. ** --reset Reset the DELETED state of a check-out, such ** that all newly-rm'd (but not yet committed) ** files are no longer removed. No flags other ** than --verbose or --dry-run may be used with ** --reset. ** -v|--verbose Outputs information about each --reset file. ** Only usable with --reset. ** |
| ︙ | ︙ | |||
741 742 743 744 745 746 747 | /* ** COMMAND: addremove ** ** Usage: %fossil addremove ?OPTIONS? ** ** Do all necessary "[[add]]" and "[[rm]]" commands to synchronize the | | | | | | | | 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 |
/*
** COMMAND: addremove
**
** Usage: %fossil addremove ?OPTIONS?
**
** Do all necessary "[[add]]" and "[[rm]]" commands to synchronize the
** repository with the content of the working check-out:
**
** * All files in the check-out but not in the repository (that is,
** all files displayed using the "extras" command) are added as
** if by the "[[add]]" command.
**
** * All files in the repository but missing from the check-out (that is,
** all files that show as MISSING with the "status" command) are
** removed as if by the "[[rm]]" command.
**
** The command does not "[[commit]]". You must run the "[[commit]]" separately
** as a separate step.
**
** Files and directories whose names begin with "." are ignored unless
** the --dotfiles option is used.
**
** The --ignore option overrides the "ignore-glob" setting, as do the
** --case-sensitive option with the "case-sensitive" setting and the
** --clean option with the "clean-glob" setting. See the documentation
** on the "settings" command for further information.
**
** The -n|--dry-run option shows what would happen without actually doing
** anything.
**
** This command can be used to track third party software.
**
** Options:
** --case-sensitive BOOL Override the case-sensitive setting
** --dotfiles Include files beginning with a dot (".")
** --ignore CSG Ignore unmanaged files matching patterns from
** the Comma Separated Glob (CSG) list
** --clean CSG Also ignore files matching patterns from
** the Comma Separated Glob (CSG) list
** -n|--dry-run If given, display instead of run actions
** --reset Reset the ADDED/DELETED state of a check-out,
** such that all newly-added (but not yet committed)
** files are no longer added and all newly-removed
** (but not yet committed) files are no longer
** removed. No flags other than --verbose and
** --dry-run may be used with --reset.
** -v|--verbose Outputs information about each --reset file.
** Only usable with --reset.
|
| ︙ | ︙ | |||
824 825 826 827 828 829 830 |
verify_all_options();
/* Fail if unprocessed arguments are present, in case user expect the
** addremove command to accept a list of file or directory.
*/
if( g.argc>2 ){
fossil_fatal(
| | | 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 |
verify_all_options();
/* Fail if unprocessed arguments are present, in case user expect the
** addremove command to accept a list of file or directory.
*/
if( g.argc>2 ){
fossil_fatal(
"%s: Can only work on the entire check-out, no arguments supported.",
g.argv[1]);
}
db_must_be_within_tree();
if( zCleanFlag==0 ){
zCleanFlag = db_get("clean-glob", 0);
}
if( zIgnoreFlag==0 ){
|
| ︙ | ︙ | |||
953 954 955 956 957 958 959 |
db_multi_exec("INSERT INTO fmove VALUES('%q','%q');", zOld, zNew);
}
blob_reset(&fullNewName);
blob_reset(&fullOldName);
}
/*
| | | 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 |
db_multi_exec("INSERT INTO fmove VALUES('%q','%q');", zOld, zNew);
}
blob_reset(&fullNewName);
blob_reset(&fullOldName);
}
/*
** This function moves files within the check-out, using the file names
** contained in the temporary table "fmove". The temporary table is
** created on demand by the add_file_to_move() function.
**
** If dryRunFlag is non-zero, no files will be moved; however, their
** names will still be output.
**
** The temporary table "fmove" is dropped after being processed.
|
| ︙ | ︙ | |||
1019 1020 1021 1022 1023 1024 1025 | ** require it to do so. ** ** WARNING: If the "--hard" option is specified -OR- the "mv-rm-files" ** setting is non-zero, files WILL BE renamed or moved on disk ** as well. This does NOT apply to the 'rename' command. ** ** Options: | | | | 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 |
** require it to do so.
**
** WARNING: If the "--hard" option is specified -OR- the "mv-rm-files"
** setting is non-zero, files WILL BE renamed or moved on disk
** as well. This does NOT apply to the 'rename' command.
**
** Options:
** --soft Skip moving files within the check-out.
** This supersedes the --hard option.
** --hard Move files within the check-out
** --case-sensitive BOOL Override the case-sensitive setting
** -n|--dry-run If given, display instead of run actions
**
** See also: [[changes]], [[status]]
*/
void mv_cmd(void){
int i;
|
| ︙ | ︙ | |||
1050 1051 1052 1053 1054 1055 1056 |
hardFlag = find_option("hard",0,0)!=0;
/* We should be done with options.. */
verify_all_options();
vid = db_lget_int("checkout", 0);
if( vid==0 ){
| | | 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 |
hardFlag = find_option("hard",0,0)!=0;
/* We should be done with options.. */
verify_all_options();
vid = db_lget_int("checkout", 0);
if( vid==0 ){
fossil_fatal("no check-out in which to rename files");
}
if( g.argc<4 ){
usage("OLDNAME NEWNAME");
}
zDest = g.argv[g.argc-1];
db_begin_transaction();
if( g.argv[1][0]=='r' ){ /* i.e. "rename" */
|
| ︙ | ︙ |
Changes to src/ajax.c.
| ︙ | ︙ | |||
233 234 235 236 237 238 239 |
"connections).");
return 0;
}
return 1;
}
/*
| | | 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 |
"connections).");
return 0;
}
return 1;
}
/*
** Helper for collecting filename/check-in request parameters.
**
** If zFn is not NULL, it is assigned the value of the first one of
** the "filename" or "fn" CGI parameters which is set.
**
** If zCi is not NULL, it is assigned the value of the first one of
** the "checkin" or "ci" CGI parameters which is set.
**
|
| ︙ | ︙ | |||
321 322 323 324 325 326 327 |
blob_init(&content, zContent, -1);
ajax_render_preview(&content, zFilename,
ln ? AJAX_PREVIEW_LINE_NUMBERS : 0,
&renderMode, iframeHeight);
/*
** Now tell the caller if we did indeed use AJAX_RENDER_WIKI, so that
** they can re-set the <base href> to an appropriate value (which
| | | 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 |
blob_init(&content, zContent, -1);
ajax_render_preview(&content, zFilename,
ln ? AJAX_PREVIEW_LINE_NUMBERS : 0,
&renderMode, iframeHeight);
/*
** Now tell the caller if we did indeed use AJAX_RENDER_WIKI, so that
** they can re-set the <base href> to an appropriate value (which
** requires knowing the content's current check-in version, which we
** don't have here).
*/
switch(renderMode){
/* The strings used here MUST correspond to those used in the JS-side
** fossil.page.previewModes map.
*/
case AJAX_RENDER_WIKI: zRenderMode = "wiki"; break;
|
| ︙ | ︙ | |||
390 391 392 393 394 395 396 |
*/
void ajax_route_dispatcher(void){
const char * zName = P("name");
AjaxRoute routeName = {0,0,0,0};
const AjaxRoute * pRoute = 0;
const AjaxRoute routes[] = {
/* Keep these sorted by zName (for bsearch()) */
| | > > > > > > > > > | | 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 |
*/
void ajax_route_dispatcher(void){
const char * zName = P("name");
AjaxRoute routeName = {0,0,0,0};
const AjaxRoute * pRoute = 0;
const AjaxRoute routes[] = {
/* Keep these sorted by zName (for bsearch()) */
{"preview-text", ajax_route_preview_text, 0, 1
/* Note that this does not require write permissions in the repo.
** It should arguably require write permissions but doing means
** that /chat does not work without checkin permissions:
**
** https://fossil-scm.org/forum/forumpost/ed4a762b3a557898
**
** This particular route is used by /fileedit and /chat, whereas
** /wikiedit uses a simpler wiki-specific route.
*/ }
};
if(zName==0 || zName[0]==0){
ajax_route_error(400,"Missing required [route] 'name' parameter.");
return;
}
routeName.zName = zName;
pRoute = (const AjaxRoute *)bsearch(&routeName, routes,
count(routes), sizeof routes[0],
cmp_ajax_route_name);
if(pRoute==0){
ajax_route_error(404,"Ajax route not found.");
return;
}else if(0==ajax_route_bootstrap(pRoute->bWriteMode, pRoute->bPost)){
return;
}
pRoute->xCallback();
}
|
Changes to src/alerts.c.
| ︙ | ︙ | |||
17 18 19 20 21 22 23 | ** ** Logic for email notification, also known as "alerts" or "subscriptions". ** ** Are you looking for the code that reads and writes the internet ** email protocol? That is not here. See the "smtp.c" file instead. ** Yes, the choice of source code filenames is not the greatest, but ** it is not so bad that changing them seems justified. | | | 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | ** ** Logic for email notification, also known as "alerts" or "subscriptions". ** ** Are you looking for the code that reads and writes the internet ** email protocol? That is not here. See the "smtp.c" file instead. ** Yes, the choice of source code filenames is not the greatest, but ** it is not so bad that changing them seems justified. */ #include "config.h" #include "alerts.h" #include <assert.h> #include <time.h> /* ** Maximum size of the subscriberCode blob, in bytes |
| ︙ | ︙ | |||
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | @ -- to the USER entry. @ -- @ -- The ssub field is a string where each character indicates a particular @ -- type of event to subscribe to. Choices: @ -- a - Announcements @ -- c - Check-ins @ -- f - Forum posts @ -- t - Ticket changes @ -- w - Wiki changes @ -- 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( @ subscriberId INTEGER PRIMARY KEY, -- numeric subscriber ID. Internal use @ subscriberCode BLOB DEFAULT (randomblob(32)) UNIQUE, -- UUID for subscriber @ semail TEXT UNIQUE COLLATE nocase,-- email address @ suname TEXT, -- corresponding USER entry @ sverified BOOLEAN DEFAULT true, -- email address verified | > > > > | | | > > | 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 |
@ -- to the USER entry.
@ --
@ -- The ssub field is a string where each character indicates a particular
@ -- type of event to subscribe to. Choices:
@ -- 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(
@ subscriberId INTEGER PRIMARY KEY, -- numeric subscriber ID. Internal use
@ subscriberCode BLOB DEFAULT (randomblob(32)) UNIQUE, -- UUID for subscriber
@ semail TEXT UNIQUE COLLATE nocase,-- email address
@ suname TEXT, -- corresponding USER entry
@ sverified BOOLEAN DEFAULT true, -- email address verified
@ sdonotcall BOOLEAN, -- true for Do Not Call
@ sdigest BOOLEAN, -- true for daily digests only
@ ssub TEXT, -- baseline subscriptions
@ sctime INTDATE, -- When this entry was created. unixtime
@ mtime INTDATE, -- Last change. unixtime
@ smip TEXT, -- IP address of last change
@ lastContact INT -- Last contact. days since 1970
@ );
@ CREATE INDEX repository.subscriberUname
@ ON subscriber(suname) WHERE suname IS NOT NULL;
@
@ DROP TABLE IF EXISTS repository.pending_alert;
@ -- Email notifications that need to be sent.
@ --
@ -- The first character of the eventid determines the event type.
@ -- Remaining characters determine the specific event. For example,
@ -- 'c4413' means check-in with rid=4413.
@ --
@ CREATE TABLE repository.pending_alert(
@ eventid TEXT PRIMARY KEY, -- Object that changed
@ sentSep BOOLEAN DEFAULT false, -- individual alert sent
@ sentDigest BOOLEAN DEFAULT false, -- digest alert sent
@ sentMod BOOLEAN DEFAULT false -- pending moderation alert sent
@ ) WITHOUT ROWID;
@
@ -- Obsolete table. No longer used.
@ DROP TABLE IF EXISTS repository.alert_bounce;
;
/*
** Return true if the email notification tables exist.
*/
int alert_tables_exist(void){
return db_table_exists("repository", "subscriber");
}
/*
** Record the fact that user zUser has made contact with the repository.
** This resets the subscription timeout on that user.
*/
void alert_user_contact(const char *zUser){
if( db_table_has_column("repository","subscriber","lastContact") ){
db_unprotect(PROTECT_READONLY);
db_multi_exec(
"UPDATE subscriber SET lastContact=now()/86400 WHERE suname=%Q",
zUser
);
db_protect_pop();
}
}
/*
** Make sure the table needed for email notification exist in the repository.
**
** If the bOnlyIfEnabled option is true, then tables are only created
|
| ︙ | ︙ | |||
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 |
}
db_exec_sql(zAlertInit);
return;
}
if( db_table_has_column("repository","subscriber","lastContact") ){
return;
}
db_multi_exec(
"DROP TABLE IF EXISTS repository.alert_bounce;\n"
"ALTER TABLE repository.subscriber ADD COLUMN lastContact INT;\n"
"UPDATE subscriber SET lastContact=mtime/86400;"
);
if( db_table_has_column("repository","pending_alert","sentMod") ){
return;
}
db_multi_exec(
"ALTER TABLE repository.pending_alert"
" ADD COLUMN sentMod BOOLEAN DEFAULT false;"
);
| > > | 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 |
}
db_exec_sql(zAlertInit);
return;
}
if( db_table_has_column("repository","subscriber","lastContact") ){
return;
}
db_unprotect(PROTECT_READONLY);
db_multi_exec(
"DROP TABLE IF EXISTS repository.alert_bounce;\n"
"ALTER TABLE repository.subscriber ADD COLUMN lastContact INT;\n"
"UPDATE subscriber SET lastContact=mtime/86400;"
);
db_protect_pop();
if( db_table_has_column("repository","pending_alert","sentMod") ){
return;
}
db_multi_exec(
"ALTER TABLE repository.pending_alert"
" ADD COLUMN sentMod BOOLEAN DEFAULT false;"
);
|
| ︙ | ︙ | |||
180 181 182 183 184 185 186 |
" INSERT INTO pending_alert(eventid)\n"
" SELECT printf('%%.1c%%d',new.type,new.objid) WHERE true\n"
" ON CONFLICT(eventId) DO NOTHING;\n"
"END;"
);
}
if( db_table_exists("repository","chat")
| | | 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 |
" INSERT INTO pending_alert(eventid)\n"
" SELECT printf('%%.1c%%d',new.type,new.objid) WHERE true\n"
" ON CONFLICT(eventId) DO NOTHING;\n"
"END;"
);
}
if( db_table_exists("repository","chat")
&& db_get("chat-timeline-user", "")[0]!=0
){
/* Record events that will be relayed to chat, but do not relay
** them immediately, as the chat_msg_from_event() function requires
** that TAGXREF be up-to-date, and that has not happened yet when
** the insert into the EVENT table occurs. Make arrangements to
** invoke alert_process_deferred_triggers() when the transaction
** commits. The TAGXREF table will be ready by then. */
|
| ︙ | ︙ | |||
227 228 229 230 231 232 233 234 235 236 237 238 239 240 |
** Return true if email alerts are active.
*/
int alert_enabled(void){
if( !alert_tables_exist() ) return 0;
if( fossil_strcmp(db_get("email-send-method",0),"off")==0 ) return 0;
return 1;
}
/*
** If the subscriber table does not exist, then paint an error message
** web page and return true.
**
** If the subscriber table does exist, return 0 without doing anything.
*/
| > > > > > > > > > > > > > > > > | 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 |
** Return true if email alerts are active.
*/
int alert_enabled(void){
if( !alert_tables_exist() ) return 0;
if( fossil_strcmp(db_get("email-send-method",0),"off")==0 ) return 0;
return 1;
}
/*
** If alerts are enabled, removes the pending_alert entry which
** matches (eventType || rid). Note that pending_alert entries are
** added via the manifest crosslinking process, so this has no effect
** if called before crosslinking is performed. Because alerts are sent
** asynchronously, unqueuing needs to be performed as part of the
** transaction in which crosslinking is performed in order to avoid a
** race condition.
*/
void alert_unqueue(char eventType, int rid){
if( alert_enabled() ){
db_multi_exec("DELETE FROM pending_alert WHERE eventid='%c%d'",
eventType, rid);
}
}
/*
** If the subscriber table does not exist, then paint an error message
** web page and return true.
**
** If the subscriber table does exist, return 0 without doing anything.
*/
|
| ︙ | ︙ | |||
295 296 297 298 299 300 301 |
}else{
@ <th>Disabled</th>
}
@ </table>
@ <hr>
@ <h1> Configuration </h1>
@ <form action="%R/setup_notification" method="post"><div>
| | | 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 |
}else{
@ <th>Disabled</th>
}
@ </table>
@ <hr>
@ <h1> Configuration </h1>
@ <form action="%R/setup_notification" method="post"><div>
@ <input type="submit" name="submit" value="Apply Changes"><hr>
login_insert_csrf_secret();
entry_attribute("Canonical Server URL", 40, "email-url",
"eurl", "", 0);
@ <p><b>Required.</b>
@ This is URL used as the basename for hyperlinks included in
@ email alert text. Omit the trailing "/".
|
| ︙ | ︙ | |||
394 395 396 397 398 399 400 | @ transmitted via the SMTP protocol (rfc5321) to a "Mail Submission @ Agent" or "MSA" (rfc4409) at the hostname shown here. Optionally @ append a colon and TCP port number (ex: smtp.example.com:587). @ The default TCP port number is 25. @ (Property: "email-send-relayhost")</p> @ <hr> | | | 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 | @ transmitted via the SMTP protocol (rfc5321) to a "Mail Submission @ Agent" or "MSA" (rfc4409) at the hostname shown here. Optionally @ append a colon and TCP port number (ex: smtp.example.com:587). @ The default TCP port number is 25. @ (Property: "email-send-relayhost")</p> @ <hr> @ <p><input type="submit" name="submit" value="Apply Changes"></p> @ </div></form> db_end_transaction(0); style_finish_page(); } #if 0 /* |
| ︙ | ︙ | |||
609 610 611 612 613 614 615 |
blob_init(&p->out, 0, 0);
}else if( fossil_strcmp(p->zDest, "relay")==0 ){
const char *zRelay = 0;
emailerGetSetting(p, &zRelay, "email-send-relayhost");
if( zRelay ){
u32 smtpFlags = SMTP_DIRECT;
if( mFlags & ALERT_TRACE ) smtpFlags |= SMTP_TRACE_STDOUT;
| | > | 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 |
blob_init(&p->out, 0, 0);
}else if( fossil_strcmp(p->zDest, "relay")==0 ){
const char *zRelay = 0;
emailerGetSetting(p, &zRelay, "email-send-relayhost");
if( zRelay ){
u32 smtpFlags = SMTP_DIRECT;
if( mFlags & ALERT_TRACE ) smtpFlags |= SMTP_TRACE_STDOUT;
p->pSmtp = smtp_session_new(domain_of_addr(p->zFrom), zRelay,
smtpFlags);
smtp_client_startup(p->pSmtp);
}
}
return p;
}
/*
|
| ︙ | ︙ | |||
708 709 710 711 712 713 714 | return i; } /* ** Make a copy of the input string up to but not including the ** first cTerm character. ** | | | | > > > | | | | < | < | 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 |
return i;
}
/*
** Make a copy of the input string up to but not including the
** first cTerm character.
**
** Verify that the string to be copied really is a valid
** email address. If it is not, then return NULL.
**
** This routine is more restrictive than necessary. It does not
** allow comments, IP address, quoted strings, or certain uncommon
** characters. The only non-alphanumerics allowed in the local
** part are "_", "+", "-" and "+".
*/
char *email_copy_addr(const char *z, char cTerm ){
int i = email_address_is_valid(z, cTerm);
return i==0 ? 0 : mprintf("%.*s", i, z);
}
/*
** Scan the input string for a valid email address that may be
** enclosed in <...>, or delimited by ',' or ':' or '=' or ' '.
** If the string contains one or more email addresses, extract the first
** one into memory obtained from mprintf() and return a pointer to it.
** If no valid email address can be found, return NULL.
*/
char *alert_find_emailaddr(const char *zIn){
char *zOut = 0;
do{
zOut = email_copy_addr(zIn, zIn[strcspn(zIn, ">,:= ")]);
if( zOut!=0 ) break;
zIn = (const char *)strpbrk(zIn, "<,:= ");
if( zIn==0 ) break;
zIn++;
}while( zIn!=0 );
return zOut;
}
/*
** SQL function: find_emailaddr(X)
**
** Return the first valid email address of the form <...> in input string
|
| ︙ | ︙ | |||
848 849 850 851 852 853 854 |
*/
void email_header_to(Blob *pMsg, int *pnTo, char ***pazTo){
int nTo = 0;
char **azTo = 0;
Blob v;
char *z, *zAddr;
int i;
| | | | 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 |
*/
void email_header_to(Blob *pMsg, int *pnTo, char ***pazTo){
int nTo = 0;
char **azTo = 0;
Blob v;
char *z, *zAddr;
int i;
email_header_value(pMsg, "to", &v);
z = blob_str(&v);
for(i=0; z[i]; i++){
if( z[i]=='<' && (zAddr = email_copy_addr(&z[i+1],'>'))!=0 ){
azTo = fossil_realloc(azTo, sizeof(azTo[0])*(nTo+1) );
azTo[nTo++] = zAddr;
}
}
*pnTo = nTo;
*pazTo = azTo;
}
/*
** Free a list of To addresses obtained from a prior call to
** email_header_to()
*/
void email_header_to_free(int nTo, char **azTo){
int i;
for(i=0; i<nTo; i++) fossil_free(azTo[i]);
fossil_free(azTo);
}
|
| ︙ | ︙ | |||
888 889 890 891 892 893 894 | ** From: ** Date: ** Message-Id: ** Content-Type: ** Content-Transfer-Encoding: ** MIME-Version: ** Sender: | | | | 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 | ** From: ** Date: ** Message-Id: ** Content-Type: ** Content-Transfer-Encoding: ** MIME-Version: ** Sender: ** ** The caller maintains ownership of the input Blobs. This routine will ** read the Blobs and send them onward to the email system, but it will ** not free them. ** ** The Message-Id: field is added if there is not already a Message-Id ** in the pHdr parameter. ** ** If the zFromName argument is not NULL, then it should be a human-readable ** name or handle for the sender. In that case, "From:" becomes a made-up ** email address based on a hash of zFromName and the domain of email-self, ** and an additional "Sender:" field is inserted with the email-self ** address. Downstream software might use the Sender header to set ** the envelope-from address of the email. If zFromName is a NULL pointer, ** then the "From:" is set to the email-self value and Sender is ** omitted. */ void alert_send( AlertSender *p, /* Emailer context */ Blob *pHdr, /* Email header (incomplete) */ Blob *pBody, /* Email body */ |
| ︙ | ︙ | |||
1018 1019 1020 1021 1022 1023 1024 | ** the basename for hyperlinks included in email alert text. ** Omit the trailing "/". If the repository is not intended to be ** a long-running server and will not be sending email notifications, ** then leave this setting blank. */ /* ** SETTING: email-admin width=40 | | | 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 | ** the basename for hyperlinks included in email alert text. ** Omit the trailing "/". If the repository is not intended to be ** a long-running server and will not be sending email notifications, ** then leave this setting blank. */ /* ** SETTING: email-admin width=40 ** This is the email address for the human administrator for the system. ** Abuse and trouble reports and password reset requests are send here. */ /* ** SETTING: email-subname width=16 ** This is a short name used to identifies the repository in the Subject: ** line of email alerts. Traditionally this name is included in square ** brackets. Examples: "[fossil-src]", "[sqlite-src]". |
| ︙ | ︙ | |||
1053 1054 1055 1056 1057 1058 1059 | ** a subscription is less than email-renew-cutoff, then now new emails ** are sent to the subscriber. ** ** email-renew-warning is the time (in days since 1970-01-01) when the ** last batch of "your subscription is about to expire" emails were ** sent out. ** | | | | 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 | ** a subscription is less than email-renew-cutoff, then now new emails ** are sent to the subscriber. ** ** email-renew-warning is the time (in days since 1970-01-01) when the ** last batch of "your subscription is about to expire" emails were ** sent out. ** ** email-renew-cutoff is normally 7 days behind email-renew-warning. */ /* ** SETTING: email-send-method width=5 default=off sensitive ** Determine the method used to send email. Allowed values are ** "off", "relay", "pipe", "dir", "db", and "stdout". The "off" value ** means no email is ever sent. The "relay" value means emails are sent ** to an Mail Sending Agent using SMTP located at email-send-relayhost. ** The "pipe" value means email messages are piped into a command ** determined by the email-send-command setting. The "dir" value means ** emails are written to individual files in a directory determined ** by the email-send-dir setting. The "db" value means that emails ** are added to an SQLite database named by the* email-send-db setting. ** The "stdout" value writes email text to standard output, for debugging. */ /* |
| ︙ | ︙ | |||
1106 1107 1108 1109 1110 1111 1112 | ** SMTP server configured as a Mail Submission Agent listening on the ** designated host and port and all times. */ /* ** COMMAND: alerts* | | < > | > | 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 | ** SMTP server configured as a Mail Submission Agent listening on the ** designated host and port and all times. */ /* ** COMMAND: alerts* ** ** Usage: %fossil alerts SUBCOMMAND ARGS... ** ** Subcommands: ** ** pending Show all pending alerts. Useful for debugging. ** ** reset Hard reset of all email notification tables ** in the repository. This erases all subscription ** information. ** Use with extreme care ** ** ** send Compose and send pending email alerts. ** Some installations may want to do this via ** a cron-job to make sure alerts are sent ** in a timely manner. ** ** Options: ** --digest Send digests ** --renewal Send subscription renewal ** notices ** --test Write to standard output ** ** settings [NAME VALUE] With no arguments, list all email settings. ** Or change the value of a single email setting. ** ** status Report on the status of the email alert ** subsystem ** ** subscribers [PATTERN] List all subscribers matching PATTERN. Either ** LIKE or GLOB wildcards can be used in PATTERN. ** ** test-message TO [OPTS] Send a single email message using whatever ** email sending mechanism is currently configured. ** Use this for testing the email notification ** configuration. ** ** Options: ** --body FILENAME Content from FILENAME ** --smtp-trace Trace SMTP processing ** --stdout Send msg to stdout ** -S|--subject SUBJECT Message "subject:" ** ** unsubscribe EMAIL Remove a single subscriber with the given EMAIL. */ |
| ︙ | ︙ | |||
1229 1230 1231 1232 1233 1234 1235 |
}
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;
| | | | 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 |
}
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);
}
}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);
}
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"
|
| ︙ | ︙ | |||
1517 1518 1519 1520 1521 1522 1523 |
register_page();
return;
}
style_set_current_feature("alerts");
alert_submenu_common();
needCaptcha = !login_is_individual();
if( P("submit")
| | > > | 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 |
register_page();
return;
}
style_set_current_feature("alerts");
alert_submenu_common();
needCaptcha = !login_is_individual();
if( P("submit")
&& cgi_csrf_safe(2)
&& subscribe_error_check(&eErr,&zErr,needCaptcha)
){
/* A validated request for a new subscription has been received. */
char ssub[20];
const char *zEAddr = P("e");
const char *zCode; /* New subscriber code (in hex) */
int nsub = 0;
const char *suname = PT("suname");
if( suname==0 && needCaptcha==0 && !g.perm.Admin ) suname = g.zLogin;
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)"
|
| ︙ | ︙ | |||
1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 |
if( P("submit")==0 ){
/* If this is the first visit to this page (if this HTTP request did not
** come from a prior Submit of the form) then default all of the
** 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.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">
| > > | 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 |
if( P("submit")==0 ){
/* If this is the first visit to this page (if this HTTP request did not
** come from a prior Submit of the form) then default all of the
** 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">
|
| ︙ | ︙ | |||
1650 1651 1652 1653 1654 1655 1656 |
@ Announcements</label><br>
if( g.perm.Read ){
@ <label><input type="checkbox" name="sc" %s(PCK("sc"))> \
@ Check-ins</label><br>
}
if( g.perm.RdForum ){
@ <label><input type="checkbox" name="sf" %s(PCK("sf"))> \
| | > > > > | | 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 |
@ Announcements</label><br>
if( g.perm.Read ){
@ <label><input type="checkbox" name="sc" %s(PCK("sc"))> \
@ Check-ins</label><br>
}
if( g.perm.RdForum ){
@ <label><input type="checkbox" name="sf" %s(PCK("sf"))> \
@ All Forum Posts</label><br>
@ <label><input type="checkbox" name="sn" %s(PCK("sn"))> \
@ New Forum Threads</label><br>
@ <label><input type="checkbox" name="sr" %s(PCK("sr"))> \
@ Replies To My Forum Posts</label><br>
@ <label><input type="checkbox" name="sx" %s(PCK("sx"))> \
@ Edits To Forum Posts</label><br>
}
if( g.perm.RdTkt ){
@ <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"))> \
|
| ︙ | ︙ | |||
1706 1707 1708 1709 1710 1711 1712 | } /* ** Either shutdown or completely delete a subscription entry given ** by the hex value zName. Then paint a webpage that explains that ** the entry has been removed. */ | | | > > | | | > > > > > > > > | 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 |
}
/*
** Either shutdown or completely delete a subscription entry given
** by the hex value zName. Then paint a webpage that explains that
** the entry has been removed.
*/
static void alert_unsubscribe(int sid, int bTotal){
const char *zEmail = 0;
const char *zLogin = 0;
int uid = 0;
Stmt q;
db_prepare(&q, "SELECT semail, suname FROM subscriber"
" WHERE subscriberId=%d", sid);
if( db_step(&q)==SQLITE_ROW ){
zEmail = db_column_text(&q, 0);
zLogin = db_column_text(&q, 1);
uid = db_int(0, "SELECT uid FROM user WHERE login=%Q", zLogin);
}
style_set_current_feature("alerts");
if( zEmail==0 ){
style_header("Unsubscribe Fail");
@ <p>Unable to locate a subscriber with the requested key</p>
}else{
db_unprotect(PROTECT_READONLY);
if( bTotal ){
/* Completely delete the subscriber */
db_multi_exec(
"DELETE FROM subscriber WHERE subscriberId=%d", sid
);
}else{
/* Keep the subscriber, but turn off all notifications */
db_multi_exec(
"UPDATE subscriber SET ssub='k', mtime=now() WHERE subscriberId=%d",
sid
);
}
db_protect_pop();
style_header("Unsubscribed");
@ <p>The "%h(zEmail)" email address has been unsubscribed from all
@ notifications. All subscription records for "%h(zEmail)" have
@ been purged. No further emails will be sent to "%h(zEmail)".</p>
if( uid && g.perm.Admin ){
@ <p>You may also want to
@ <a href="%R/setup_uedit?id=%d(uid)">edit or delete
|
| ︙ | ︙ | |||
1758 1759 1760 1761 1762 1763 1764 | ** email and clicks on the link in the email. When a ** compilete subscriberCode is seen on the name= query parameter, ** that constitutes verification of the email address. ** ** * The sid= query parameter contains an integer subscriberId. ** This only works for the administrator. It allows the ** administrator to edit any subscription. | | > | 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 |
** email and clicks on the link in the email. When a
** compilete subscriberCode is seen on the name= query parameter,
** that constitutes verification of the email address.
**
** * The sid= query parameter contains an integer subscriberId.
** This only works for the administrator. It allows the
** administrator to edit any subscription.
**
** * The user is logged into an account other than "nobody" or
** "anonymous". In that case the notification settings
** associated with that account can be edited without needing
** to know the subscriber code.
**
** * The name= query parameter contains a 32-digit prefix of
** subscriber code. (Subscriber codes are normally 64 hex digits
** 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, 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 */
const char *mtime; /* */
|
| ︙ | ︙ | |||
1819 1820 1821 1822 1823 1824 1825 |
}
if( sid==0 ){
db_commit_transaction();
cgi_redirect("subscribe");
/*NOTREACHED*/
}
alert_submenu_common();
| | > > | 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 |
}
if( sid==0 ){
db_commit_transaction();
cgi_redirect("subscribe");
/*NOTREACHED*/
}
alert_submenu_common();
if( P("submit")!=0 && cgi_csrf_safe(2) ){
char newSsub[10];
int nsub = 0;
Blob update;
sdonotcall = PB("sdonotcall");
sdigest = PB("sdigest");
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,
|
| ︙ | ︙ | |||
1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 |
blob_append_sql(&update," WHERE subscriberId=%d", sid);
if( eErr==0 ){
db_exec_sql(blob_str(&update));
ssub = 0;
}
blob_reset(&update);
}else if( keepAlive ){
db_multi_exec(
"UPDATE subscriber SET lastContact=now()/86400"
" WHERE subscriberId=%d", sid
);
}
| > > | | | | 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 |
blob_append_sql(&update," WHERE subscriberId=%d", sid);
if( eErr==0 ){
db_exec_sql(blob_str(&update));
ssub = 0;
}
blob_reset(&update);
}else if( keepAlive ){
db_unprotect(PROTECT_READONLY);
db_multi_exec(
"UPDATE subscriber SET lastContact=now()/86400"
" WHERE subscriberId=%d", sid
);
db_protect_pop();
}
if( P("delete")!=0 && cgi_csrf_safe(2) ){
if( !PB("dodelete") ){
eErr = 9;
zErr = mprintf("Select this checkbox and press \"Unsubscribe\" again to"
" unsubscribe");
}else{
alert_unsubscribe(sid, 1);
db_commit_transaction();
return;
}
}
style_set_current_feature("alerts");
style_header("Update Subscription");
db_prepare(&q,
"SELECT"
" semail," /* 0 */
|
| ︙ | ︙ | |||
1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 |
if( suname==0 ){
suname = db_column_text(&q, 6);
sverified = db_column_int(&q, 1);
}
sa = strchr(ssub,'a')!=0;
sc = strchr(ssub,'c')!=0;
sf = strchr(ssub,'f')!=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 ){
db_multi_exec(
"UPDATE subscriber SET sverified=1"
" WHERE subscriberCode=hextoblob(%Q)",
zName);
if( db_get_boolean("selfreg-verify",0) ){
char *zNewCap = db_get("default-perms","u");
db_unprotect(PROTECT_USER);
db_multi_exec(
"UPDATE user"
" SET cap=%Q"
" WHERE cap='7' AND login=("
| > > > > | 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 |
if( suname==0 ){
suname = db_column_text(&q, 6);
sverified = db_column_int(&q, 1);
}
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 ){
db_unprotect(PROTECT_READONLY);
db_multi_exec(
"UPDATE subscriber SET sverified=1"
" WHERE subscriberCode=hextoblob(%Q)",
zName);
db_protect_pop();
if( db_get_boolean("selfreg-verify",0) ){
char *zNewCap = db_get("default-perms","u");
db_unprotect(PROTECT_USER);
db_multi_exec(
"UPDATE user"
" SET cap=%Q"
" WHERE cap='7' AND login=("
|
| ︙ | ︙ | |||
2027 2028 2029 2030 2031 2032 2033 |
@ Announcements</label><br>
if( g.perm.Read ){
@ <label><input type="checkbox" name="sc" %s(sc?"checked":"")>\
@ Check-ins</label><br>
}
if( g.perm.RdForum ){
@ <label><input type="checkbox" name="sf" %s(sf?"checked":"")>\
| | > > > > | > > > > | 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 |
@ Announcements</label><br>
if( g.perm.Read ){
@ <label><input type="checkbox" name="sc" %s(sc?"checked":"")>\
@ Check-ins</label><br>
}
if( g.perm.RdForum ){
@ <label><input type="checkbox" name="sf" %s(sf?"checked":"")>\
@ All Forum Posts</label><br>
@ <label><input type="checkbox" name="sn" %s(sn?"checked":"")>\
@ New Forum Threads</label><br>
@ <label><input type="checkbox" name="sr" %s(sr?"checked":"")>\
@ Replies To My Posts</label><br>
@ <label><input type="checkbox" name="sx" %s(sx?"checked":"")>\
@ Edits To Forum Posts</label><br>
}
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>
}
@ </td></tr>
if( strchr(ssub,'k')!=0 ){
@ <tr><td></td><td> ↑
@ Note: User did a one-click unsubscribe</td></tr>
}
@ <tr>
@ <td class="form_label">Delivery:</td>
@ <td><select size="1" name="sdigest">
@ <option value="0" %s(sdigest?"":"selected")>Individual Emails</option>
@ <option value="1" %s(sdigest?"selected":"")>Daily Digest</option>
@ </select></td>
@ </tr>
|
| ︙ | ︙ | |||
2110 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 |
){
@ <p>This repository does not expire email notification subscriptions.
@ No renewals are necessary.</p>
style_finish_page();
return;
}
db_prepare(&s,
"UPDATE subscriber"
" SET lastContact=now()/86400"
" WHERE subscriberCode=hextoblob(%Q)"
" RETURNING semail, date('now','+%d days');",
zName, iInterval+1
);
rc = db_step(&s);
if( rc==SQLITE_ROW ){
@ <p>The email notification subscription for %h(db_column_text(&s,0))
@ has been extended until %h(db_column_text(&s,1)) UTC.
}else{
@ <p>No such subscriber-id: %h(zName)</p>
}
db_finalize(&s);
style_finish_page();
}
/* This is the message that gets sent to describe how to change
** or modify a subscription
*/
| > > | > > > > | | | > > | | | | 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 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 |
){
@ <p>This repository does not expire email notification subscriptions.
@ No renewals are necessary.</p>
style_finish_page();
return;
}
db_unprotect(PROTECT_READONLY);
db_prepare(&s,
"UPDATE subscriber"
" SET lastContact=now()/86400"
" WHERE subscriberCode=hextoblob(%Q)"
" RETURNING semail, date('now','+%d days');",
zName, iInterval+1
);
rc = db_step(&s);
if( rc==SQLITE_ROW ){
@ <p>The email notification subscription for %h(db_column_text(&s,0))
@ has been extended until %h(db_column_text(&s,1)) UTC.
}else{
@ <p>No such subscriber-id: %h(zName)</p>
}
db_finalize(&s);
db_protect_pop();
style_finish_page();
}
/* This is the message that gets sent to describe how to change
** or modify a subscription
*/
static const char zUnsubMsg[] =
@ To changes your subscription settings at %s visit this link:
@
@ %s/alerts/%s
@
@ To completely unsubscribe from %s, visit the following link:
@
@ %s/unsubscribe/%s
;
/*
** WEBPAGE: unsubscribe
** WEBPAGE: oneclickunsub
**
** Users visit this page to be delisted from email alerts.
**
** If a valid subscriber code is supplied in the name= query parameter,
** then that subscriber is delisted.
**
** Otherwise, If the users is logged in, then they are redirected
** to the /alerts page where they have an unsubscribe button.
**
** Non-logged-in users with no name= query parameter are invited to enter
** an email address to which will be sent the unsubscribe link that
** contains the correct subscriber code.
**
** The /unsubscribe page requires comfirmation. The /oneclickunsub
** page unsubscribes immediately without any need to confirm.
*/
void unsubscribe_page(void){
const char *zName = P("name");
char *zErr = 0;
int eErr = 0;
unsigned int uSeed = 0;
const char *zDecoded;
char *zCaptcha = 0;
int dx;
int bSubmit;
const char *zEAddr;
char *zCode = 0;
int sid = 0;
if( zName==0 ) zName = P("scode");
/* If a valid subscriber code is supplied, then either present the user
** with a confirmation, or if already confirmed, unsubscribe immediately.
*/
if( zName
&& (sid = db_int(0, "SELECT subscriberId FROM subscriber"
" WHERE subscriberCode=hextoblob(%Q)", zName))!=0
){
char *zUnsubName = mprintf("confirm%04x", sid);
if( P(zUnsubName)!=0 ){
alert_unsubscribe(sid, 1);
}else if( sqlite3_strglob("*oneclick*",g.zPath)==0 ){
alert_unsubscribe(sid, 0);
}else if( P("manage")!=0 ){
cgi_redirectf("%R/alerts/%s", zName);
}else{
style_header("Unsubscribe");
form_begin(0, "%R/unsubscribe");
@ <input type="hidden" name="scode" value="%h(zName)">
@ <table border="0" cellpadding="10" width="100%%">
@ <tr><td align="right">
@ <input type="submit" name="%h(zUnsubName)" value="Unsubscribe">
@ </td><td><big><b>←</b></big></td>
@ <td>Cancel your subscription to %h(g.zBaseURL) notifications
@ </td><tr>
@ <tr><td align="right">
@ <input type="submit" name="manage" \
@ value="Manage Subscription Settings">
@ </td><td><big><b>←</b></big></td>
@ <td>Make other changes to your subscription preferences
@ </td><tr>
@ </table>
@ </form>
style_finish_page();
}
return;
}
/* Logged in users are redirected to the /alerts page */
login_check_credentials();
if( login_is_individual() ){
cgi_redirectf("%R/alerts");
return;
}
style_set_current_feature("alerts");
zEAddr = PD("e","");
dx = atoi(PD("dx","0"));
bSubmit = P("submit")!=0 && P("e")!=0 && cgi_csrf_safe(2);
if( bSubmit ){
if( !captcha_is_correct(1) ){
eErr = 2;
zErr = mprintf("enter the security code shown below");
bSubmit = 0;
}
}
|
| ︙ | ︙ | |||
2262 2263 2264 2265 2266 2267 2268 |
}else{
@ <p>An email has been sent to "%h(zEAddr)" that explains how to
@ unsubscribe and/or modify your subscription settings</p>
}
alert_sender_free(pSender);
style_finish_page();
return;
| | | 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 |
}else{
@ <p>An email has been sent to "%h(zEAddr)" that explains how to
@ unsubscribe and/or modify your subscription settings</p>
}
alert_sender_free(pSender);
style_finish_page();
return;
}
/* Non-logged-in users have to enter an email address to which is
** sent a message containing the unsubscribe link.
*/
style_header("Unsubscribe Request");
@ <p>Fill out the form below to request an email message that will
@ explain how to unsubscribe and/or change your subscription settings.</p>
|
| ︙ | ︙ | |||
2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 |
** A single event that might appear in an alert is recorded as an
** instance of the following object.
**
** type values:
**
** c A new check-in
** f An original forum post
** 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
*/
struct EmailEvent {
| > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 |
** A single event that might appear in an alert is recorded as an
** instance of the following object.
**
** type values:
**
** 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 {
int type; /* 'c', 'f', 'n', 'r', 't', '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 */
};
#endif
/*
** Free a linked list of EmailEvent objects
*/
void alert_free_eventlist(EmailEvent *p){
while( p ){
EmailEvent *pNext = p->pNext;
blob_reset(&p->txt);
blob_reset(&p->hdr);
fossil_free(p->zFromName);
fossil_free(p->zPriors);
fossil_free(p);
p = pNext;
}
}
/*
** Compute a string that is appropriate for the EmailEvent.zPriors field
** for a particular forum post.
**
** This string is an encode list of sender names and rids for all ancestors
** of the fpdi post - the post that fpid answer, the post that that parent
** post answers, and so forth back up to the root post. Duplicates sender
** names are omitted.
**
** The EmailEvent.zPriors field is used to screen events for people who
** only want to see replies to their own posts or to specific posts.
*/
static char *alert_compute_priors(int fpid){
return db_text(0,
"WITH priors(rid,who) AS ("
" SELECT firt, coalesce(euser,user)"
" FROM forumpost LEFT JOIN event ON fpid=objid"
" WHERE fpid=%d"
" UNION ALL"
" SELECT firt, coalesce(euser,user)"
" FROM priors, forumpost LEFT JOIN event ON fpid=objid"
" WHERE fpid=rid"
")"
"SELECT ','||group_concat(DISTINCT 'u'||who)||"
"','||group_concat(rid) FROM priors;",
fpid
);
}
/*
** Compute and return a linked list of EmailEvent objects
** corresponding to the current content of the temp.wantalert
** table which should be defined as follows:
**
** CREATE TEMP TABLE wantalert(eventId TEXT, needMod BOOLEAN);
|
| ︙ | ︙ | |||
2529 2530 2531 2532 2533 2534 2535 |
);
memset(&anchor, 0, sizeof(anchor));
pLast = &anchor;
*pnEvent = 0;
while( db_step(&q)==SQLITE_ROW ){
const char *zType = "";
const char *zComment = db_column_text(&q, 2);
| | | 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 |
);
memset(&anchor, 0, sizeof(anchor));
pLast = &anchor;
*pnEvent = 0;
while( db_step(&q)==SQLITE_ROW ){
const char *zType = "";
const char *zComment = db_column_text(&q, 2);
p = fossil_malloc_zero( sizeof(EmailEvent) );
pLast->pNext = p;
pLast = p;
p->type = db_column_text(&q, 3)[0];
p->needMod = db_column_int(&q, 4);
p->zFromName = 0;
p->pNext = 0;
switch( p->type ){
|
| ︙ | ︙ | |||
2613 2614 2615 2616 2617 2618 2619 |
" AND eventId GLOB 'f*'"
" AND forumpost.fpid=event.objid"
" ORDER BY event.mtime"
);
zFrom = db_get("email-self",0);
zSub = db_get("email-subname","");
while( db_step(&q)==SQLITE_ROW ){
| > | > | | 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 |
" AND eventId GLOB 'f*'"
" AND forumpost.fpid=event.objid"
" ORDER BY event.mtime"
);
zFrom = db_get("email-self",0);
zSub = db_get("email-subname","");
while( db_step(&q)==SQLITE_ROW ){
int fpid = db_column_int(&q,0);
Manifest *pPost = manifest_get(fpid, CFTYPE_FORUM, 0);
const char *zIrt;
const char *zUuid;
const char *zTitle;
const char *z;
if( pPost==0 ) continue;
p = fossil_malloc( sizeof(EmailEvent) );
pLast->pNext = p;
pLast = p;
p->type = db_column_int(&q,7) ? 'f' : 'x';
p->needMod = db_column_int(&q, 5);
z = db_column_text(&q,6);
p->zFromName = z && z[0] ? fossil_strdup(z) : 0;
p->zPriors = alert_compute_priors(fpid);
p->pNext = 0;
blob_init(&p->hdr, 0, 0);
zUuid = db_column_text(&q, 1);
zTitle = db_column_text(&q, 3);
if( p->needMod ){
blob_appendf(&p->hdr, "Subject: %s Pending Moderation: %s\r\n",
zSub, zTitle);
}else{
blob_appendf(&p->hdr, "Subject: %s %s\r\n", zSub, zTitle);
blob_appendf(&p->hdr, "Message-Id: <%.32s@%s>\r\n",
zUuid, alert_hostname(zFrom));
zIrt = db_column_text(&q, 4);
if( zIrt && zIrt[0] ){
blob_appendf(&p->hdr, "In-Reply-To: <%.32s@%s>\r\n",
zIrt, alert_hostname(zFrom));
}
}
|
| ︙ | ︙ | |||
2696 2697 2698 2699 2700 2701 2702 | ** ** EVENTIDs are text. The first character is 'c', 'f', 't', or 'w' ** for check-in, forum, ticket, or wiki. The remaining text is a ** integer that references the EVENT.OBJID value for the event. ** Run /timeline?showid to see these OBJID values. ** ** Options: | < | 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 |
**
** EVENTIDs are text. The first character is 'c', 'f', 't', or 'w'
** for check-in, forum, ticket, or wiki. The remaining text is a
** integer that references the EVENT.OBJID value for the event.
** Run /timeline?showid to see these OBJID values.
**
** Options:
** --digest Generate digest alert text
** --needmod Assume all events are pending moderator approval
*/
void test_alert_cmd(void){
Blob out;
int nEvent;
int needMod;
|
| ︙ | ︙ | |||
2757 2758 2759 2760 2761 2762 2763 | ** ** EVENTIDs are text. The first character is 'c', 'f', 't', or 'w' ** for check-in, forum, ticket, or wiki. The remaining text is a ** integer that references the EVENT.OBJID value for the event. ** Run /timeline?showid to see these OBJID values. ** ** Options: | < < < | 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 |
**
** EVENTIDs are text. The first character is 'c', 'f', 't', or 'w'
** for check-in, forum, ticket, or wiki. The remaining text is a
** integer that references the EVENT.OBJID value for the event.
** Run /timeline?showid to see these OBJID values.
**
** Options:
** --backoffice Run alert_backoffice() after all alerts have
** been added. This will cause the alerts to be
** sent out with the SENDALERT_TRACE option.
** --debug Like --backoffice, but add the SENDALERT_STDOUT
** so that emails are printed to standard output
** rather than being sent.
** --digest Process emails using SENDALERT_DIGEST
*/
void test_add_alert_cmd(void){
int i;
int doAuto = find_option("backoffice",0,0)!=0;
unsigned mFlags = 0;
if( find_option("debug",0,0)!=0 ){
|
| ︙ | ︙ | |||
2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 |
"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
);
}
#if INTERFACE
/*
** Flags for alert_send_alerts()
*/
#define SENDALERT_DIGEST 0x0001 /* Send a digest */
#define SENDALERT_PRESERVE 0x0002 /* Do not mark the task as done */
| > > > > > > > > > > > > > > > | 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 |
"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
);
}
/*
** If zUser is a sender of one of the ancestors of a forum post
** (if zUser appears in zPriors) then return true.
*/
static int alert_in_priors(const char *zUser, const char *zPriors){
int n = (int)strlen(zUser);
char zBuf[200];
if( n>195 ) return 0;
if( zPriors==0 || zPriors[0]==0 ) return 0;
zBuf[0] = ',';
zBuf[1] = 'u';
memcpy(zBuf+2, zUser, n+1);
return strstr(zPriors, zBuf)!=0;
}
#if INTERFACE
/*
** Flags for alert_send_alerts()
*/
#define SENDALERT_DIGEST 0x0001 /* Send a digest */
#define SENDALERT_PRESERVE 0x0002 /* Do not mark the task as done */
|
| ︙ | ︙ | |||
2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 |
" EXISTS(SELECT 1 FROM private WHERE rid=substr(eventid,2)),"
" sentMod"
" FROM pending_alert"
" WHERE sentSep IS FALSE;"
"DELETE FROM wantalert WHERE needMod AND sentMod;"
);
}
/* Step 2: compute EmailEvent objects for every notification that
** needs sending.
*/
pEvents = alert_compute_event_text(&nEvent, (flags & SENDALERT_DIGEST)!=0);
if( nEvent==0 ) goto send_alert_expiration_warnings;
| > > > > > | 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 |
" EXISTS(SELECT 1 FROM private WHERE rid=substr(eventid,2)),"
" sentMod"
" FROM pending_alert"
" WHERE sentSep IS FALSE;"
"DELETE FROM wantalert WHERE needMod AND sentMod;"
);
}
if( g.fSqlTrace ){
fossil_trace("-- wantalert contains %d rows\n",
db_int(0, "SELECT count(*) FROM wantalert")
);
}
/* Step 2: compute EmailEvent objects for every notification that
** needs sending.
*/
pEvents = alert_compute_event_text(&nEvent, (flags & SENDALERT_DIGEST)!=0);
if( nEvent==0 ) goto send_alert_expiration_warnings;
|
| ︙ | ︙ | |||
2980 2981 2982 2983 2984 2985 2986 |
blob_init(&hdr, 0, 0);
blob_init(&body, 0, 0);
db_prepare(&q,
"SELECT"
" hex(subscriberCode)," /* 0 */
" semail," /* 1 */
" ssub," /* 2 */
| | > | > | > > > > > > > > > > | > | > > > > > | 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 |
blob_init(&hdr, 0, 0);
blob_init(&body, 0, 0);
db_prepare(&q,
"SELECT"
" hex(subscriberCode)," /* 0 */
" semail," /* 1 */
" ssub," /* 2 */
" fullcap(user.cap)," /* 3 */
" suname" /* 4 */
" FROM subscriber LEFT JOIN user ON (login=suname)"
" WHERE sverified"
" AND NOT sdonotcall"
" AND sdigest IS %s"
" AND coalesce(subscriber.lastContact*86400,subscriber.mtime)>=%d",
zDigest/*safe-for-%s*/,
db_get_int("email-renew-cutoff",0)
);
while( db_step(&q)==SQLITE_ROW ){
const char *zCode = db_column_text(&q, 0);
const char *zSub = db_column_text(&q, 2);
const char *zEmail = db_column_text(&q, 1);
const char *zCap = db_column_text(&q, 3);
const char *zUser = db_column_text(&q, 4);
int nHit = 0;
for(p=pEvents; p; p=p->pNext){
if( strchr(zSub,p->type)==0 ){
if( p->type!='f' ) continue;
if( strchr(zSub,'n')!=0 && (p->zPriors==0 || p->zPriors[0]==0) ){
/* New post: accepted */
}else if( strchr(zSub,'r')!=0 && zUser!=0
&& alert_in_priors(zUser, p->zPriors) ){
/* A follow-up to a post written by the user: accept */
}else{
continue;
}
}
if( p->needMod ){
/* For events that require moderator approval, only send an alert
** if the recipient is a moderator for that type of event. Setup
** and Admin users always get notified. */
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);
blob_appendf(&fhdr, "To: <%s>\r\n", zEmail);
blob_append(&fhdr, blob_buffer(&p->hdr), blob_size(&p->hdr));
blob_init(&fbody, blob_buffer(&p->txt), blob_size(&p->txt));
blob_appendf(&fhdr, "List-Unsubscribe: <%s/oneclickunsub/%s>\r\n",
zUrl, zCode);
blob_appendf(&fhdr,
"List-Unsubscribe-Post: List-Unsubscribe=One-Click\r\n");
blob_appendf(&fbody, "\n-- \nUnsubscribe: %s/unsubscribe/%s\n",
zUrl, zCode);
/* blob_appendf(&fbody, "Subscription settings: %s/alerts/%s\n",
** zUrl, zCode); */
alert_send(pSender,&fhdr,&fbody,p->zFromName);
nSent++;
blob_reset(&fhdr);
|
| ︙ | ︙ | |||
3058 3059 3060 3061 3062 3063 3064 |
}
nHit++;
blob_append(&body, "\n", 1);
blob_append(&body, blob_buffer(&p->txt), blob_size(&p->txt));
}
}
if( nHit==0 ) continue;
| | | 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 |
}
nHit++;
blob_append(&body, "\n", 1);
blob_append(&body, blob_buffer(&p->txt), blob_size(&p->txt));
}
}
if( nHit==0 ) continue;
blob_appendf(&hdr, "List-Unsubscribe: <%s/oneclickunsub/%s>\r\n",
zUrl, zCode);
blob_appendf(&hdr, "List-Unsubscribe-Post: List-Unsubscribe=One-Click\r\n");
blob_appendf(&body,"\n-- \nSubscription info: %s/alerts/%s\n",
zUrl, zCode);
alert_send(pSender,&hdr,&body,0);
nSent++;
blob_truncate(&hdr, 0);
|
| ︙ | ︙ | |||
3110 3111 3112 3113 3114 3115 3116 |
" AND length(sdigest)>0",
iNewWarn, iOldWarn
);
while( db_step(&q)==SQLITE_ROW ){
Blob hdr, body;
blob_init(&hdr, 0, 0);
blob_init(&body, 0, 0);
| | | 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 |
" AND length(sdigest)>0",
iNewWarn, iOldWarn
);
while( db_step(&q)==SQLITE_ROW ){
Blob hdr, body;
blob_init(&hdr, 0, 0);
blob_init(&body, 0, 0);
alert_renewal_msg(&hdr, &body,
db_column_text(&q,0),
db_column_int(&q,1),
db_column_text(&q,2),
db_column_text(&q,3),
zRepoName, zUrl);
alert_send(pSender,&hdr,&body,0);
blob_reset(&hdr);
|
| ︙ | ︙ | |||
3180 3181 3182 3183 3184 3185 3186 |
style_set_current_feature("alerts");
if( zAdminEmail==0 || zAdminEmail[0]==0 ){
style_header("Outbound Email Disabled");
@ <p>Outbound email is disabled on this repository
style_finish_page();
return;
}
| | | | 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 |
style_set_current_feature("alerts");
if( zAdminEmail==0 || zAdminEmail[0]==0 ){
style_header("Outbound Email Disabled");
@ <p>Outbound email is disabled on this repository
style_finish_page();
return;
}
if( P("submit")!=0
&& P("subject")!=0
&& P("msg")!=0
&& P("from")!=0
&& cgi_csrf_safe(2)
&& captcha_is_correct(0)
){
Blob hdr, body;
AlertSender *pSender = alert_sender_new(0,0);
blob_init(&hdr, 0, 0);
blob_appendf(&hdr, "To: <%s>\r\nSubject: %s administrator message\r\n",
zAdminEmail, db_get("email-subname","Fossil Repo"));
|
| ︙ | ︙ | |||
3359 3360 3361 3362 3363 3364 3365 |
return;
}
style_set_current_feature("alerts");
if( fossil_strcmp(P("name"),"test1")==0 ){
/* Visit the /announce/test1 page to see the CGI variables */
zAction = "announce/test1";
@ <p style='border: 1px solid black; padding: 1ex;'>
| | | | 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 |
return;
}
style_set_current_feature("alerts");
if( fossil_strcmp(P("name"),"test1")==0 ){
/* Visit the /announce/test1 page to see the CGI variables */
zAction = "announce/test1";
@ <p style='border: 1px solid black; padding: 1ex;'>
cgi_print_all(0, 0, 0);
@ </p>
}else if( P("submit")!=0 && cgi_csrf_safe(2) ){
char *zErr = alert_send_announcement();
style_header("Announcement Sent");
if( zErr ){
@ <h1>Internal Error</h1>
@ <p>The following error was reported by the system:
@ <blockquote><pre>
@ %h(zErr)
|
| ︙ | ︙ | |||
3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 |
@ <a href="https://fossil-scm.org/fossil/doc/trunk/www/alerts.md">set up</a>
@ for this repository.</p>
return;
}
style_header("Send Announcement");
@ <form method="POST" action="%R/%s(zAction)">
@ <table class="subscribe">
if( g.perm.Admin ){
int aa = PB("aa");
int all = PB("all");
int aMod = PB("mods");
const char *aack = aa ? "checked" : "";
const char *allck = all ? "checked" : "";
| > | 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 |
@ <a href="https://fossil-scm.org/fossil/doc/trunk/www/alerts.md">set up</a>
@ for this repository.</p>
return;
}
style_header("Send Announcement");
@ <form method="POST" action="%R/%s(zAction)">
login_insert_csrf_secret();
@ <table class="subscribe">
if( g.perm.Admin ){
int aa = PB("aa");
int all = PB("all");
int aMod = PB("mods");
const char *aack = aa ? "checked" : "";
const char *allck = all ? "checked" : "";
|
| ︙ | ︙ |
Changes to src/allrepo.c.
| ︙ | ︙ | |||
19 20 21 22 23 24 25 | */ #include "config.h" #include "allrepo.h" #include <assert.h> /* ** Build a string that contains all of the command-line options | | > | | > > | | 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 |
*/
#include "config.h"
#include "allrepo.h"
#include <assert.h>
/*
** Build a string that contains all of the command-line options
** specified as arguments. collect_argument() is used for stand-alone
** options and collect_argument_value() is used for options that are
** followed by an argument value.
*/
static void collect_argument(Blob *pExtra,const char *zArg,const char *zShort){
const char *z = find_option(zArg, zShort, 0);
if( z!=0 ){
blob_appendf(pExtra, " %s", z);
}
}
static void collect_argument_value(
Blob *pExtra, const char *zArg, const char *zShort
){
const char *zValue = find_option(zArg, zShort, 1);
if( zValue ){
if( zValue[0] ){
blob_appendf(pExtra, " --%s %$", zArg, zValue);
}else{
blob_appendf(pExtra, " --%s \"\"", zArg);
}
}
|
| ︙ | ︙ | |||
67 68 69 70 71 72 73 | ** backup Backup all repositories. The argument must be the name of ** a directory into which all backup repositories are written. ** ** cache Manages the cache used for potentially expensive web ** pages. Any additional arguments are passed on verbatim ** to the cache command. ** | | | | | | | > > > > | | | | > > > | | | | | | 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 |
** backup Backup all repositories. The argument must be the name of
** a directory into which all backup repositories are written.
**
** cache Manages the cache used for potentially expensive web
** pages. Any additional arguments are passed on verbatim
** to the cache command.
**
** changes Shows all local check-outs that have uncommitted changes.
** This operation has no additional options.
**
** clean Delete all "extra" files in all local check-outs. Extreme
** caution should be exercised with this command because its
** effects cannot be undone. Use of the --dry-run option to
** carefully review the local check-outs to be operated upon
** and the --whatif option to carefully review the files to
** be deleted beforehand is highly recommended. The command
** line options supported by the clean command itself, if any
** are present, are passed along verbatim.
**
** config Only the "config pull AREA" command works.
**
** dbstat Run the "dbstat" command on all repositories.
**
** extras Shows "extra" files from all local check-outs. The command
** line options supported by the extra command itself, if any
** are present, are passed along verbatim.
**
** fts-config Run the "fts-config" command on all repositories.
**
** git CMD Do the "git export" or "git status" command (whichever
** is specified by CMD) on all repositories for which
** a Git mirror has been previously established.
**
** info Run the "info" command on all repositories.
**
** pull Run a "pull" operation on all repositories. Only the
** --verbose and --share-links options are supported.
**
** push Run a "push" on all repositories. Only the --verbose
** option is supported.
**
** rebuild Rebuild on all repositories. The command line options
** supported by the rebuild command itself, if any are
** present, are passed along verbatim. The --force option
** is not supported.
**
** remote Show remote hosts for all repositories.
**
** repack Look for extra compression in all repositories.
**
** sync Run a "sync" on all repositories. Only the --verbose
** and --unversioned and --share-links options are supported.
**
** set Run the "setting" or "set" commands on all repositories.
** This command is useful for settings like "max-loadavg" which
** you usually want to be the same across all repositories
** on a server.
**
** unset Run the "unset" command on all repositories
**
** server Run the "server" commands on all repositories.
** The root URI gives a listing of all repos.
**
** ui Run the "ui" command on all repositories. Like "server"
** but bind to the loopback TCP address only, enable
** the --localauth option and automatically launch a
** web-browser
**
** whatis Run the "whatis" command on all repositories. Only
** show output for repositories that have a match.
**
**
** In addition, the following maintenance operations are supported:
**
** add Add all the repositories named to the set of repositories
** tracked by Fossil. Normally Fossil is able to keep up with
** this list by itself, but sometimes it can benefit from this
** hint if you rename repositories.
**
** ignore Arguments are repositories that should be ignored by
** subsequent clean, extras, list, pull, push, rebuild, and
** sync operations. The -c|--ckout option causes the listed
** local check-outs to be ignored instead.
**
** list | ls Display the location of all repositories. The -c|--ckout
** option causes all local check-outs to be listed instead.
**
** Repositories are automatically added to the set of known repositories
** when one of the following commands are run against the repository:
** clone, info, pull, push, or sync. Even previously ignored repositories
** are added back to the list of repositories by these commands.
**
** Options:
** --dry-run If given, display instead of run actions
** --showfile Show the repository or check-out being operated upon
** --stop-on-error Halt immediately if any subprocess fails
*/
void all_cmd(void){
Stmt q;
const char *zCmd;
char *zSyscmd;
Blob extra;
int useCheckouts = 0;
|
| ︙ | ︙ | |||
200 201 202 203 204 205 206 |
if( file_isdir(zDest, ExtFILE)!=1 ){
fossil_fatal("argument to \"fossil all backup\" must be a directory");
}
blob_appendf(&extra, " %$", zDest);
}else if( fossil_strcmp(zCmd, "clean")==0 ){
zCmd = "clean --chdir";
collect_argument(&extra, "allckouts",0);
| | | | | | 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 |
if( file_isdir(zDest, ExtFILE)!=1 ){
fossil_fatal("argument to \"fossil all backup\" must be a directory");
}
blob_appendf(&extra, " %$", zDest);
}else if( fossil_strcmp(zCmd, "clean")==0 ){
zCmd = "clean --chdir";
collect_argument(&extra, "allckouts",0);
collect_argument_value(&extra, "case-sensitive", 0);
collect_argument_value(&extra, "clean", 0);
collect_argument(&extra, "dirsonly",0);
collect_argument(&extra, "disable-undo",0);
collect_argument(&extra, "dotfiles",0);
collect_argument(&extra, "emptydirs",0);
collect_argument(&extra, "force","f");
collect_argument_value(&extra, "ignore", 0);
collect_argument_value(&extra, "keep", 0);
collect_argument(&extra, "no-prompt",0);
collect_argument(&extra, "temp",0);
collect_argument(&extra, "verbose","v");
collect_argument(&extra, "whatif",0);
useCheckouts = 1;
}else if( fossil_strcmp(zCmd, "config")==0 ){
zCmd = "config -R";
|
| ︙ | ︙ | |||
237 238 239 240 241 242 243 |
}else if( fossil_strcmp(zCmd, "extras")==0 ){
if( showFile ){
zCmd = "extras --chdir";
}else{
zCmd = "extras --header --chdir";
}
collect_argument(&extra, "abs-paths",0);
| | | | 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 |
}else if( fossil_strcmp(zCmd, "extras")==0 ){
if( showFile ){
zCmd = "extras --chdir";
}else{
zCmd = "extras --header --chdir";
}
collect_argument(&extra, "abs-paths",0);
collect_argument_value(&extra, "case-sensitive", 0);
collect_argument(&extra, "dotfiles",0);
collect_argument_value(&extra, "ignore", 0);
collect_argument(&extra, "rel-paths",0);
useCheckouts = 1;
stopOnError = 0;
quiet = 1;
}else if( fossil_strcmp(zCmd, "git")==0 ){
if( g.argc<4 ){
usage("git (export|status)");
|
| ︙ | ︙ | |||
266 267 268 269 270 271 272 273 274 275 276 |
collect_argument(&extra, "verbose","v");
}else if( fossil_strcmp(zCmd, "pull")==0 ){
zCmd = "pull -autourl -R";
collect_argument(&extra, "verbose","v");
collect_argument(&extra, "share-links",0);
}else if( fossil_strcmp(zCmd, "rebuild")==0 ){
zCmd = "rebuild";
collect_argument(&extra, "cluster",0);
collect_argument(&extra, "compress",0);
collect_argument(&extra, "compress-only",0);
collect_argument(&extra, "noverify",0);
| > | | > > > > > > > > > > > > > > > > > > > > > > | 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 |
collect_argument(&extra, "verbose","v");
}else if( fossil_strcmp(zCmd, "pull")==0 ){
zCmd = "pull -autourl -R";
collect_argument(&extra, "verbose","v");
collect_argument(&extra, "share-links",0);
}else if( fossil_strcmp(zCmd, "rebuild")==0 ){
zCmd = "rebuild";
collect_argument(&extra, "analyze",0);
collect_argument(&extra, "cluster",0);
collect_argument(&extra, "compress",0);
collect_argument(&extra, "compress-only",0);
collect_argument(&extra, "noverify",0);
collect_argument_value(&extra, "pagesize", 0);
collect_argument(&extra, "vacuum",0);
collect_argument(&extra, "deanalyze",0); /* Deprecated */
collect_argument(&extra, "analyze",0);
collect_argument(&extra, "wal",0);
collect_argument(&extra, "stats",0);
collect_argument(&extra, "index",0);
collect_argument(&extra, "noindex",0);
collect_argument(&extra, "ifneeded", 0);
}else if( fossil_strcmp(zCmd, "remote")==0 ){
showLabel = 1;
quiet = 1;
collect_argument(&extra, "show-passwords", 0);
if( g.argc==3 ){
zCmd = "remote -R";
}else if( g.argc!=4 ){
usage("remote ?config-data|list|ls?");
}else if( fossil_strcmp(g.argv[3],"ls")==0
|| fossil_strcmp(g.argv[3],"list")==0 ){
zCmd = "remote ls -R";
}else if( fossil_strcmp(g.argv[3],"ls")==0
|| fossil_strcmp(g.argv[3],"list")==0 ){
zCmd = "remote ls -R";
}else if( fossil_strcmp(g.argv[3],"config-data")==0 ){
zCmd = "remote config-data -R";
}else{
usage("remote ?config-data|list|ls?");
}
}else if( fossil_strcmp(zCmd, "repack")==0 ){
zCmd = "repack";
}else if( fossil_strcmp(zCmd, "setting")==0 ){
zCmd = "setting -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);
}else if( fossil_strcmp(zCmd, "sync")==0 ){
zCmd = "sync -autourl -R";
collect_argument(&extra, "share-links",0);
collect_argument(&extra, "verbose","v");
collect_argument(&extra, "unversioned","u");
collect_argument(&extra, "all",0);
}else if( fossil_strcmp(zCmd, "test-integrity")==0 ){
collect_argument(&extra, "db-only", "d");
collect_argument(&extra, "parse", 0);
collect_argument(&extra, "quick", "q");
zCmd = "test-integrity";
}else if( fossil_strcmp(zCmd, "test-orphans")==0 ){
zCmd = "test-orphans -R";
|
| ︙ | ︙ | |||
379 380 381 382 383 384 385 386 387 |
zCmd = "info";
showLabel = 1;
quiet = 1;
}else if( fossil_strcmp(zCmd, "cache")==0 ){
zCmd = "cache -R";
showLabel = 1;
collect_argv(&extra, 3);
}else{
fossil_fatal("\"all\" subcommand should be one of: "
| > > > > > > | | > | 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 |
zCmd = "info";
showLabel = 1;
quiet = 1;
}else if( fossil_strcmp(zCmd, "cache")==0 ){
zCmd = "cache -R";
showLabel = 1;
collect_argv(&extra, 3);
}else if( fossil_strcmp(zCmd, "whatis")==0 ){
zCmd = "whatis -q -R";
quiet = 1;
collect_argument(&extra, "file", "f");
collect_argument_value(&extra, "type", 0);
collect_argv(&extra, 3);
}else{
fossil_fatal("\"all\" subcommand should be one of: "
"add cache changes clean dbstat extras fts-config git ignore "
"info list ls pull push rebuild remote "
"server setting sync ui unset whatis");
}
verify_all_options();
db_multi_exec("CREATE TEMP TABLE repolist(name,tag);");
if( useCheckouts ){
db_multi_exec(
"INSERT INTO repolist "
"SELECT DISTINCT substr(name, 7), name COLLATE nocase"
|
| ︙ | ︙ | |||
423 424 425 426 427 428 429 |
nToDel++;
continue;
}
if( zCmd[0]=='l' ){
fossil_print("%s\n", zFilename);
continue;
}else if( showFile ){
| | | 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 |
nToDel++;
continue;
}
if( zCmd[0]=='l' ){
fossil_print("%s\n", zFilename);
continue;
}else if( showFile ){
fossil_print("%s: %s\n", useCheckouts ? "check-out" : "repository",
zFilename);
}
zSyscmd = mprintf("%$ %s %$%s",
g.nameOfExe, zCmd, zFilename, blob_str(&extra));
if( showLabel ){
int len = (int)strlen(zFilename);
int nStar = 80 - (len + 15);
|
| ︙ | ︙ |
Changes to src/attach.c.
| ︙ | ︙ | |||
109 110 111 112 113 114 115 |
zUrlTail = mprintf("technote=%s&file=%t", zTarget, zFilename);
}else{
zUrlTail = mprintf("page=%t&file=%t", zTarget, zFilename);
}
@ <li><p>
@ Attachment %z(href("%R/ainfo/%!S",zUuid))%S(zUuid)</a>
moderation_pending_www(attachid);
| | | | 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 |
zUrlTail = mprintf("technote=%s&file=%t", zTarget, zFilename);
}else{
zUrlTail = mprintf("page=%t&file=%t", zTarget, zFilename);
}
@ <li><p>
@ Attachment %z(href("%R/ainfo/%!S",zUuid))%S(zUuid)</a>
moderation_pending_www(attachid);
@ <br><a href="%R/attachview?%s(zUrlTail)">%h(zFilename)</a>
@ [<a href="%R/attachdownload/%t(zFilename)?%s(zUrlTail)">download</a>]<br>
if( zComment ) while( fossil_isspace(zComment[0]) ) zComment++;
if( zComment && zComment[0] ){
@ %!W(zComment)<br>
}
if( zPage==0 && zTkt==0 && zTechNote==0 ){
if( zSrc==0 || zSrc[0]==0 ){
zSrc = "Deleted from";
}else {
zSrc = "Added to";
}
|
| ︙ | ︙ | |||
242 243 244 245 246 247 248 |
moderation_table_create();
db_multi_exec(
"INSERT INTO modreq(objid,attachRid) VALUES(%d,%d);",
rid, attachRid
);
}else{
rid = content_put(pAttach);
| | | 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 |
moderation_table_create();
db_multi_exec(
"INSERT INTO modreq(objid,attachRid) VALUES(%d,%d);",
rid, attachRid
);
}else{
rid = content_put(pAttach);
db_add_unsent(rid);
db_multi_exec("INSERT OR IGNORE INTO unclustered VALUES(%d);", rid);
}
manifest_crosslink(rid, pAttach, MC_NONE);
}
/*
|
| ︙ | ︙ | |||
395 396 397 398 399 400 401 |
if( !goodCaptcha ){
@ <p class="generalError">Error: Incorrect security code.</p>
}
@ <h2>Add Attachment To %s(zTargetType)</h2>
form_begin("enctype='multipart/form-data'", "%R/attachadd");
@ <div>
@ File to Attach:
| | | | | | | | | | | 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 |
if( !goodCaptcha ){
@ <p class="generalError">Error: Incorrect security code.</p>
}
@ <h2>Add Attachment To %s(zTargetType)</h2>
form_begin("enctype='multipart/form-data'", "%R/attachadd");
@ <div>
@ File to Attach:
@ <input type="file" name="f" size="60"><br>
@ Description:<br>
@ <textarea name="comment" cols="80" rows="5" wrap="virtual"></textarea><br>
if( zTkt ){
@ <input type="hidden" name="tkt" value="%h(zTkt)">
}else if( zTechNote ){
@ <input type="hidden" name="technote" value="%h(zTechNote)">
}else{
@ <input type="hidden" name="page" value="%h(zPage)">
}
@ <input type="hidden" name="from" value="%h(zFrom)">
@ <input type="submit" name="ok" value="Add Attachment">
@ <input type="submit" name="cancel" value="Cancel">
@ </div>
captcha_generate(0);
@ </form>
style_finish_page();
fossil_free(zTargetType);
}
|
| ︙ | ︙ | |||
589 590 591 592 593 594 595 |
@ </table>
if( isModerator && modPending ){
@ <div class="section">Moderation</div>
@ <blockquote>
form_begin(0, "%R/ainfo/%s", zUuid);
@ <label><input type="radio" name="modaction" value="delete">
| | | | 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 |
@ </table>
if( isModerator && modPending ){
@ <div class="section">Moderation</div>
@ <blockquote>
form_begin(0, "%R/ainfo/%s", zUuid);
@ <label><input type="radio" name="modaction" value="delete">
@ Delete this change</label><br>
@ <label><input type="radio" name="modaction" value="approve">
@ Approve this change</label><br>
@ <input type="submit" value="Submit">
@ </form>
@ </blockquote>
}
@ <div class="section">Content Appended</div>
@ <blockquote>
|
| ︙ | ︙ | |||
614 615 616 617 618 619 620 |
}else{
@ <pre>
@ %h(z)
@ </pre>
}
}else if( strncmp(zMime, "image/", 6)==0 ){
int sz = db_int(0, "SELECT size FROM blob WHERE rid=%d", ridSrc);
| | | 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 |
}else{
@ <pre>
@ %h(z)
@ </pre>
}
}else if( strncmp(zMime, "image/", 6)==0 ){
int sz = db_int(0, "SELECT size FROM blob WHERE rid=%d", ridSrc);
@ <i>(file is %d(sz) bytes of image data)</i><br>
@ <img src="%R/raw/%s(zSrc)?m=%s(zMime)"></img>
style_submenu_element("Image", "%R/raw/%s?m=%s", zSrc, zMime);
}else{
int sz = db_int(0, "SELECT size FROM blob WHERE rid=%d", ridSrc);
@ <i>(file is %d(sz) bytes of binary data)</i>
}
@ </blockquote>
|
| ︙ | ︙ | |||
676 677 678 679 680 681 682 | /* ** COMMAND: attachment* ** ** Usage: %fossil attachment add ?PAGENAME? FILENAME ?OPTIONS? ** ** Add an attachment to an existing wiki page or tech note. | < > < | | 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 | /* ** COMMAND: attachment* ** ** Usage: %fossil attachment add ?PAGENAME? FILENAME ?OPTIONS? ** ** Add an attachment to an existing wiki page or tech note. ** ** Options: ** -t|--technote DATETIME Specifies the timestamp of ** the technote to which the attachment ** is to be made. The attachment will be ** to the most recently modified tech note ** with the specified timestamp. ** -t|--technote TECHNOTE-ID Specifies the technote to be ** updated by its technote id ** ** One of PAGENAME, DATETIME or TECHNOTE-ID must be specified. ** ** 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" |
| ︙ | ︙ | |||
790 791 792 793 794 795 796 | ** ** List attachments for one or more attachment targets. The target ** name arguments are glob prefixes for the attachment.target ** field. If no names are provided then a prefix of [a-zA-Z] is used, ** which will match most wiki page names and some ticket hashes. ** ** Options: | < | | 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 |
**
** List attachments for one or more attachment targets. The target
** name arguments are glob prefixes for the attachment.target
** field. If no names are provided then a prefix of [a-zA-Z] is used,
** which will match most wiki page names and some ticket hashes.
**
** Options:
** -latest List only the latest version of a given attachment
**
*/
void test_list_attachments(void){
Stmt q;
int i;
const int fLatest = find_option("latest", 0, 0) != 0;
|
| ︙ | ︙ |
Changes to src/backlink.c.
| ︙ | ︙ | |||
130 131 132 133 134 135 136 |
" WHEN 2 THEN (SELECT substr(tagname,6) FROM tag"
" WHERE tagid=srcid AND tagname GLOB 'wiki-*')"
" ELSE null END FROM backlink"
);
style_table_sorter();
@ <table border="1" cellpadding="2" cellspacing="0" \
@ class='sortable' data-column-types='ttt' data-init-sort='0'>
| | | 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 |
" WHEN 2 THEN (SELECT substr(tagname,6) FROM tag"
" WHERE tagid=srcid AND tagname GLOB 'wiki-*')"
" ELSE null END FROM backlink"
);
style_table_sorter();
@ <table border="1" cellpadding="2" cellspacing="0" \
@ class='sortable' data-column-types='ttt' data-init-sort='0'>
@ <thead><tr><th> Target <th> Source <th> mtime </tr></thead>
@ <tbody>
while( db_step(&q)==SQLITE_ROW ){
const char *zTarget = db_column_text(&q, 0);
int srctype = db_column_int(&q, 1);
int srcid = db_column_int(&q, 2);
const char *zMtime = db_column_text(&q, 3);
@ <tr><td><a href="%R/info/%h(zTarget)">%h(zTarget)</a>
|
| ︙ | ︙ | |||
250 251 252 253 254 255 256 | char *zTarget = blob_buffer(target); int nTarget = blob_size(target); backlink_create(p, zTarget, nTarget); return 1; } | | | > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > | | | | | | | | | | | | | | | | | | | | | | | | | 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 |
char *zTarget = blob_buffer(target);
int nTarget = blob_size(target);
backlink_create(p, zTarget, nTarget);
return 1;
}
/* No-op routines for the rendering callbacks that we do not need */
static void mkdn_noop_prolog(Blob *b, void *v){ return; }
static void (*mkdn_noop_epilog)(Blob*, void*) = mkdn_noop_prolog;
static void mkdn_noop_footnotes(Blob *b1, const Blob *b2, void *v){ return; }
static void mkdn_noop_blockcode(Blob *b1, Blob *b2, void *v){ return; }
static void (*mkdn_noop_blockquote)(Blob*, Blob*, void*) = mkdn_noop_blockcode;
static void (*mkdn_noop_blockhtml)(Blob*, Blob*, void*) = mkdn_noop_blockcode;
static void mkdn_noop_header(Blob *b1, Blob *b2, int i, void *v){ return; }
static void (*mkdn_noop_hrule)(Blob*, void*) = mkdn_noop_prolog;
static void (*mkdn_noop_list)(Blob*, Blob*, int, void*) = mkdn_noop_header;
static void (*mkdn_noop_listitem)(Blob*, Blob*, int, void*) = mkdn_noop_header;
static void (*mkdn_noop_paragraph)(Blob*, Blob*, void*) = mkdn_noop_blockcode;
static void mkdn_noop_table(Blob *b1, Blob *b2, Blob *b3, void *v){ return; }
static void (*mkdn_noop_table_cell)(Blob*, Blob*, int,
void*) = mkdn_noop_header;
static void (*mkdn_noop_table_row)(Blob*, Blob*, int,
void*) = mkdn_noop_header;
static void mkdn_noop_footnoteitm(Blob *b1, const Blob *b2, int i1, int i2,
void *v){ return; }
static int mkdn_noop_autolink(Blob *b1, Blob *b2, enum mkd_autolink e,
void *v){ return 1; }
static int mkdn_noop_codespan(Blob *b1, Blob *b2, int i, void *v){ return 1; }
static int mkdn_noop_emphasis(Blob *b1, Blob *b2, char c, void *v){ return 1; }
static int (*mkdn_noop_dbl_emphas)(Blob*, Blob*, char,
void*) = mkdn_noop_emphasis;
static int mkdn_noop_image(Blob *b1, Blob *b2, Blob *b3, Blob *b4,
void *v){ return 1; }
static int mkdn_noop_linebreak(Blob *b1, void *v){ return 1; }
static int mkdn_noop_r_html_tag(Blob *b1, Blob *b2, void *v){ return 1; }
static int (*mkdn_noop_tri_emphas)(Blob*, Blob*, char,
void*) = mkdn_noop_emphasis;
static int mkdn_noop_footnoteref(Blob *b1, const Blob *b2, const Blob *b3,
int i1, int i2, void *v){ return 1; }
/*
** Scan markdown text and add self-hyperlinks to the BACKLINK table.
*/
void markdown_extract_links(
char *zInputText,
Backlink *p
){
struct mkd_renderer html_renderer = {
/* prolog */ mkdn_noop_prolog,
/* epilog */ mkdn_noop_epilog,
/* footnotes */ mkdn_noop_footnotes,
/* blockcode */ mkdn_noop_blockcode,
/* blockquote */ mkdn_noop_blockquote,
/* blockhtml */ mkdn_noop_blockhtml,
/* header */ mkdn_noop_header,
/* hrule */ mkdn_noop_hrule,
/* list */ mkdn_noop_list,
/* listitem */ mkdn_noop_listitem,
/* paragraph */ mkdn_noop_paragraph,
/* table */ mkdn_noop_table,
/* table_cell */ mkdn_noop_table_cell,
/* table_row */ mkdn_noop_table_row,
/* footnoteitm*/ mkdn_noop_footnoteitm,
/* autolink */ mkdn_noop_autolink,
/* codespan */ mkdn_noop_codespan,
/* dbl_emphas */ mkdn_noop_dbl_emphas,
/* emphasis */ mkdn_noop_emphasis,
/* image */ mkdn_noop_image,
/* linebreak */ mkdn_noop_linebreak,
/* link */ backlink_md_link,
/* r_html_tag */ mkdn_noop_r_html_tag,
/* tri_emphas */ mkdn_noop_tri_emphas,
/* footnoteref*/ mkdn_noop_footnoteref,
0, /* entity */
0, /* normal_text */
"*_", /* emphasis characters */
0 /* client data */
};
Blob out, in;
|
| ︙ | ︙ | |||
356 357 358 359 360 361 362 | ** Read the content of INPUT-FILE and pass it into the backlink_extract() ** routine. But instead of adding backlinks to the backlink table, ** just print them on stdout. SRCID and SRCTYPE are integers. ** ** Options: ** --mtime DATETIME Use an alternative date/time. Defaults to the ** current date/time. | | | 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 |
** Read the content of INPUT-FILE and pass it into the backlink_extract()
** routine. But instead of adding backlinks to the backlink table,
** just print them on stdout. SRCID and SRCTYPE are integers.
**
** Options:
** --mtime DATETIME Use an alternative date/time. Defaults to the
** current date/time.
** --mimetype TYPE Use an alternative mimetype
*/
void test_backlinks_cmd(void){
const char *zMTime = find_option("mtime",0,1);
const char *zMimetype = find_option("mimetype",0,1);
const int mimetype = parse_mimetype(zMimetype);
Blob in;
int srcid;
|
| ︙ | ︙ |
Changes to src/backoffice.c.
| ︙ | ︙ | |||
539 540 541 542 543 544 545 |
if( backofficeSleep(1000*(x.tmCurrent - tmNow + 1)) ){
/* The sleep was interrupted by a signal from another thread. */
backofficeTrace("/***** Backoffice Interrupt %d *****/\n", GETPID());
db_end_transaction(0);
break;
}
}else{
| | | 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 |
if( backofficeSleep(1000*(x.tmCurrent - tmNow + 1)) ){
/* The sleep was interrupted by a signal from another thread. */
backofficeTrace("/***** Backoffice Interrupt %d *****/\n", GETPID());
db_end_transaction(0);
break;
}
}else{
if( (sqlite3_uint64)(lastWarning+warningDelay) < tmNow ){
fossil_warning(
"backoffice process %lld still running after %d seconds",
x.idCurrent, (int)(BKOFCE_LEASE_TIME + tmNow - x.tmCurrent));
lastWarning = tmNow;
warningDelay *= 2;
}
if( backofficeSleep(1000) ){
|
| ︙ | ︙ | |||
664 665 666 667 668 669 670 | /* ** COMMAND: backoffice* ** ** Usage: %fossil backoffice [OPTIONS...] [REPOSITORIES...] ** ** Run backoffice processing on the repositories listed. If no | | | | | 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 | /* ** COMMAND: backoffice* ** ** Usage: %fossil backoffice [OPTIONS...] [REPOSITORIES...] ** ** Run backoffice processing on the repositories listed. If no ** repository is specified, run it on the repository of the local check-out. ** ** This might be done by a cron job or similar to make sure backoffice ** processing happens periodically. Or, the --poll option can be used ** to run this command as a daemon that will periodically invoke backoffice ** on a collection of repositories. ** ** If only a single repository is named and --poll is omitted, then the ** backoffice work is done in-process. But if there are multiple repositories ** or if --poll is used, a separate sub-process is started for each poll of ** each repository. ** ** Standard options: ** ** --debug Show what this command is doing ** ** --logfile FILE Append a log of backoffice actions onto FILE ** ** --min N When polling, invoke backoffice at least ** once every N seconds even if the repository ** never changes. 0 or negative means disable ** this feature. Default: 3600 (once per hour). ** ** --poll N Repeat backoffice calls for repositories that |
| ︙ | ︙ |
Changes to src/bag.c.
| ︙ | ︙ | |||
99 100 101 102 103 104 105 |
memset(p->a, 0, sizeof(p->a[0])*newSize );
for(i=0; i<old.sz; i++){
int e = old.a[i];
if( e>0 ){
unsigned h = bag_hash(e)%newSize;
while( p->a[h] ){
h++;
| | | 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
memset(p->a, 0, sizeof(p->a[0])*newSize );
for(i=0; i<old.sz; i++){
int e = old.a[i];
if( e>0 ){
unsigned h = bag_hash(e)%newSize;
while( p->a[h] ){
h++;
if( (int)h==newSize ) h = 0;
}
p->a[h] = e;
nLive++;
}else if( e<0 ){
nDel++;
}
}
|
| ︙ | ︙ | |||
129 130 131 132 133 134 135 |
if( p->used+1 >= p->sz/2 ){
int n = p->sz*2;
bag_resize(p, n + 20 );
}
h = bag_hash(e)%p->sz;
while( p->a[h]>0 && p->a[h]!=e ){
h++;
| | | 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 |
if( p->used+1 >= p->sz/2 ){
int n = p->sz*2;
bag_resize(p, n + 20 );
}
h = bag_hash(e)%p->sz;
while( p->a[h]>0 && p->a[h]!=e ){
h++;
if( (int)h>=p->sz ) h = 0;
}
if( p->a[h]<=0 ){
if( p->a[h]==0 ) p->used++;
p->a[h] = e;
p->cnt++;
rc = 1;
}
|
| ︙ | ︙ | |||
152 153 154 155 156 157 158 |
assert( e>0 );
if( p->sz==0 ){
return 0;
}
h = bag_hash(e)%p->sz;
while( p->a[h] && p->a[h]!=e ){
h++;
| | | | 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 |
assert( e>0 );
if( p->sz==0 ){
return 0;
}
h = bag_hash(e)%p->sz;
while( p->a[h] && p->a[h]!=e ){
h++;
if( (int)h>=p->sz ) h = 0;
}
return p->a[h]==e;
}
/*
** Remove element e from the bag if it exists in the bag.
** If e is not in the bag, this is a no-op.
*/
void bag_remove(Bag *p, int e){
unsigned h;
assert( e>0 );
if( p->sz==0 ) return;
h = bag_hash(e)%p->sz;
while( p->a[h] && p->a[h]!=e ){
h++;
if( (int)h>=p->sz ) h = 0;
}
if( p->a[h] ){
int nx = h+1;
if( nx>=p->sz ) nx = 0;
if( p->a[nx]==0 ){
p->a[h] = 0;
p->used--;
|
| ︙ | ︙ | |||
215 216 217 218 219 220 221 |
int bag_next(Bag *p, int e){
unsigned h;
assert( p->sz>0 );
assert( e>0 );
h = bag_hash(e)%p->sz;
while( p->a[h] && p->a[h]!=e ){
h++;
| | | | | 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 |
int bag_next(Bag *p, int e){
unsigned h;
assert( p->sz>0 );
assert( e>0 );
h = bag_hash(e)%p->sz;
while( p->a[h] && p->a[h]!=e ){
h++;
if( (int)h>=p->sz ) h = 0;
}
assert( p->a[h] );
h++;
while( (int)h<p->sz && p->a[h]<=0 ){
h++;
}
return (int)h<p->sz ? p->a[h] : 0;
}
/*
** Return the number of elements in the bag.
*/
int bag_count(Bag *p){
return p->cnt;
}
|
Changes to src/bisect.c.
| ︙ | ︙ | |||
200 201 202 203 204 205 206 | ); } /* ** Create a TEMP table named "bilog" that contains the complete history ** of the current bisect. ** | | | 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 | ); } /* ** Create a TEMP table named "bilog" that contains the complete history ** of the current bisect. ** ** If iCurrent>0 then it is the RID of the current check-out and is included ** in the history table. ** ** If zDesc is not NULL, then it is the bid= query parameter to /timeline ** that describes a bisect. Use the information in zDesc rather than in ** the bisect-log variable. ** ** If bDetail is true, then also include information about every node |
| ︙ | ︙ | |||
384 385 386 387 388 389 390 | ); } /* ** fossil bisect run [OPTIONS] COMMAND ** ** Invoke COMMAND (with arguments) repeatedly to perform the bisect. | < > | 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 |
);
}
/*
** fossil bisect run [OPTIONS] COMMAND
**
** Invoke COMMAND (with arguments) repeatedly to perform the bisect.
**
** Options:
** -i|--interactive Prompt user for decisions rather than
** using the return code from COMMAND
*/
static void bisect_run(void){
const char *zCmd;
int isInteractive = 0;
int i;
|
| ︙ | ︙ | |||
467 468 469 470 471 472 473 | /* ** COMMAND: bisect ** ** Usage: %fossil bisect SUBCOMMAND ... ** ** Run various subcommands useful for searching back through the change | | | | | 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 | /* ** COMMAND: bisect ** ** Usage: %fossil bisect SUBCOMMAND ... ** ** Run various subcommands useful for searching back through the change ** history for a particular check-in that causes or fixes a problem. ** ** > fossil bisect bad ?VERSION? ** ** Identify version VERSION as non-working. If VERSION is omitted, ** the current check-out is marked as non-working. ** ** > fossil bisect good ?VERSION? ** ** Identify version VERSION as working. If VERSION is omitted, ** the current check-out is marked as working. ** ** > fossil bisect log ** > fossil bisect chart ** ** Show a log of "good", "bad", and "skip" versions. "bisect log" ** shows the events in the order that they were tested. ** "bisect chart" shows them in order of check-in. |
| ︙ | ︙ | |||
505 506 507 508 509 510 511 | ** Reinitialize a bisect session. This cancels prior bisect history ** and allows a bisect session to start over from the beginning. ** ** > fossil bisect run [OPTIONS] COMMAND ** ** Invoke COMMAND repeatedly to run the bisect. The exit code for ** COMMAND should be 0 for "good", 125 for "skip", and any other value | | > | | 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 | ** Reinitialize a bisect session. This cancels prior bisect history ** and allows a bisect session to start over from the beginning. ** ** > fossil bisect run [OPTIONS] COMMAND ** ** Invoke COMMAND repeatedly to run the bisect. The exit code for ** COMMAND should be 0 for "good", 125 for "skip", and any other value ** for "bad". ** ** Options: ** -i|--interactive Prompt the user for the good/bad/skip decision ** after each step, rather than using the exit ** code from COMMAND ** ** > fossil bisect skip ?VERSION? ** ** Cause VERSION (or the current check-out if VERSION is omitted) to ** be ignored for the purpose of the current bisect. This might ** be done, for example, because VERSION does not compile correctly ** or is otherwise unsuitable to participate in this bisect. ** ** > fossil bisect vlist|ls|status ?-a|--all? ** ** List the versions in between the inner-most "bad" and "good". |
| ︙ | ︙ |
Changes to src/blob.c.
| ︙ | ︙ | |||
51 52 53 54 55 56 57 58 59 60 61 62 63 64 | #define blob_size(X) ((X)->nUsed) /* ** The buffer holding the blob data */ #define blob_buffer(X) ((X)->aData) /* ** Append blob contents to another */ #define blob_appendb(dest, src) \ blob_append((dest), blob_buffer(src), blob_size(src)) /* | > > > > > | 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | #define blob_size(X) ((X)->nUsed) /* ** The buffer holding the blob data */ #define blob_buffer(X) ((X)->aData) /* ** Number of elements that fits into the current blob's size */ #define blob_count(X,elType) (blob_size(X)/sizeof(elType)) /* ** Append blob contents to another */ #define blob_appendb(dest, src) \ blob_append((dest), blob_buffer(src), blob_size(src)) /* |
| ︙ | ︙ | |||
117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
/*
** Other replacements for ctype.h functions.
*/
int fossil_islower(char c){ return c>='a' && c<='z'; }
int fossil_isupper(char c){ return c>='A' && c<='Z'; }
int fossil_isdigit(char c){ return c>='0' && c<='9'; }
int fossil_tolower(char c){
return fossil_isupper(c) ? c - 'A' + 'a' : c;
}
int fossil_toupper(char c){
return fossil_islower(c) ? c - 'a' + 'A' : c;
}
int fossil_isalpha(char c){
| > | 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 |
/*
** Other replacements for ctype.h functions.
*/
int fossil_islower(char c){ return c>='a' && c<='z'; }
int fossil_isupper(char c){ return c>='A' && c<='Z'; }
int fossil_isdigit(char c){ return c>='0' && c<='9'; }
int fossil_isxdigit(char c){ return (c>='0' && c<='9') || (c>='a' && c<='f'); }
int fossil_tolower(char c){
return fossil_isupper(c) ? c - 'A' + 'a' : c;
}
int fossil_toupper(char c){
return fossil_islower(c) ? c - 'a' + 'A' : c;
}
int fossil_isalpha(char c){
|
| ︙ | ︙ | |||
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 |
** have run out of memory.
*/
static void blob_panic(void){
static const char zErrMsg[] = "out of memory\n";
fputs(zErrMsg, stderr);
fossil_exit(1);
}
/*
** A reallocation function that assumes that aData came from malloc().
** This function attempts to resize the buffer of the blob to hold
** newSize bytes.
**
** No attempt is made to recover from an out-of-memory error.
** If an OOM error occurs, an error message is printed on stderr
** and the program exits.
*/
void blobReallocMalloc(Blob *pBlob, unsigned int newSize){
if( newSize==0 ){
free(pBlob->aData);
pBlob->aData = 0;
pBlob->nAlloc = 0;
pBlob->nUsed = 0;
pBlob->iCursor = 0;
pBlob->blobFlags = 0;
}else if( newSize>pBlob->nAlloc || newSize+4000<pBlob->nAlloc ){
| > > > > > > > > > > > > > > > > > > > | | 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 |
** have run out of memory.
*/
static void blob_panic(void){
static const char zErrMsg[] = "out of memory\n";
fputs(zErrMsg, stderr);
fossil_exit(1);
}
/*
** Maximum size of a Blob's managed memory. This is ~2GB, largely for
** historical reasons.
**
*/
#define MAX_BLOB_SIZE 0x7fff0000
/*
** If n >= MAX_BLOB_SIZE, calls blob_panic(),
** else this is a no-op.
*/
static void blob_assert_safe_size(i64 n){
if( n>=(i64)MAX_BLOB_SIZE ){
blob_panic();
}
}
/*
** A reallocation function that assumes that aData came from malloc().
** This function attempts to resize the buffer of the blob to hold
** newSize bytes.
**
** No attempt is made to recover from an out-of-memory error.
** If an OOM error occurs, an error message is printed on stderr
** and the program exits.
*/
void blobReallocMalloc(Blob *pBlob, unsigned int newSize){
if( newSize==0 ){
free(pBlob->aData);
pBlob->aData = 0;
pBlob->nAlloc = 0;
pBlob->nUsed = 0;
pBlob->iCursor = 0;
pBlob->blobFlags = 0;
}else if( newSize>pBlob->nAlloc || newSize+4000<pBlob->nAlloc ){
char *pNew;
blob_assert_safe_size((i64)newSize);
pNew = fossil_realloc(pBlob->aData, newSize);
pBlob->aData = pNew;
pBlob->nAlloc = newSize;
if( pBlob->nUsed>pBlob->nAlloc ){
pBlob->nUsed = pBlob->nAlloc;
}
}
}
|
| ︙ | ︙ | |||
211 212 213 214 215 216 217 |
** A reallocation function for when the initial string is in unmanaged
** space. Copy the string to memory obtained from malloc().
*/
static void blobReallocStatic(Blob *pBlob, unsigned int newSize){
if( newSize==0 ){
*pBlob = empty_blob;
}else{
| > > | | 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 |
** A reallocation function for when the initial string is in unmanaged
** space. Copy the string to memory obtained from malloc().
*/
static void blobReallocStatic(Blob *pBlob, unsigned int newSize){
if( newSize==0 ){
*pBlob = empty_blob;
}else{
char *pNew;
blob_assert_safe_size((i64)newSize);
pNew = fossil_malloc( newSize );
if( pBlob->nUsed>newSize ) pBlob->nUsed = newSize;
memcpy(pNew, pBlob->aData, pBlob->nUsed);
pBlob->aData = pNew;
pBlob->xRealloc = blobReallocMalloc;
pBlob->nAlloc = newSize;
}
}
|
| ︙ | ︙ | |||
321 322 323 324 325 326 327 |
}
}
nNew = pBlob->nUsed;
nNew += nData;
if( nNew >= pBlob->nAlloc ){
nNew += pBlob->nAlloc;
nNew += 100;
| < | < | | 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 |
}
}
nNew = pBlob->nUsed;
nNew += nData;
if( nNew >= pBlob->nAlloc ){
nNew += pBlob->nAlloc;
nNew += 100;
blob_assert_safe_size(nNew);
pBlob->xRealloc(pBlob, (unsigned)nNew);
if( pBlob->nUsed + nData >= pBlob->nAlloc ){
blob_panic();
}
}
memcpy(&pBlob->aData[pBlob->nUsed], aData, nData);
pBlob->nUsed += nData;
pBlob->aData[pBlob->nUsed] = 0; /* Blobs are always nul-terminated */
|
| ︙ | ︙ | |||
597 598 599 600 601 602 603 | /* ** Ensures that the given blob has at least the given amount of memory ** allocated to it. Does not modify pBlob->nUsed nor will it reduce ** the currently-allocated amount of memory. ** ** For semantic compatibility with blob_append_full(), if newSize is | | | | < | | 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 |
/*
** Ensures that the given blob has at least the given amount of memory
** allocated to it. Does not modify pBlob->nUsed nor will it reduce
** the currently-allocated amount of memory.
**
** For semantic compatibility with blob_append_full(), if newSize is
** >=MAX_BLOB_SIZE then this function will trigger blob_panic(). If it
** didn't, it would be possible to bypass that hard-coded limit via
** this function.
**
** We've had at least one report:
** https://fossil-scm.org/forum/forumpost/b7bbd28db4
** which implies that this is unconditionally failing on mingw 32-bit
** builds.
*/
void blob_reserve(Blob *pBlob, unsigned int newSize){
blob_assert_safe_size( (i64)newSize );
if(newSize>pBlob->nAlloc){
pBlob->xRealloc(pBlob, newSize+1);
pBlob->aData[newSize] = 0;
}
}
/*
** Make sure a blob is nul-terminated and is not a pointer to unmanaged
|
| ︙ | ︙ | |||
670 671 672 673 674 675 676 |
p->iCursor = 0;
}
/*
** Truncate a blob back to zero length
*/
void blob_truncate(Blob *p, int sz){
| | | 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 |
p->iCursor = 0;
}
/*
** Truncate a blob back to zero length
*/
void blob_truncate(Blob *p, int sz){
if( sz>=0 && sz<(int)(p->nUsed) ) p->nUsed = sz;
}
/*
** Seek the cursor in a blob to the indicated offset.
*/
int blob_seek(Blob *p, int offset, int whence){
if( whence==BLOB_SEEK_SET ){
|
| ︙ | ︙ | |||
843 844 845 846 847 848 849 850 851 852 853 854 855 856 |
i++;
}
if( pTo ){
blob_append(pTo, &pFrom->aData[pFrom->iCursor], i - pFrom->iCursor);
}
pFrom->iCursor = i;
}
/*
** Ensure that the text in pBlob ends with '\n'
*/
void blob_add_final_newline(Blob *pBlob){
if( pBlob->nUsed<=0 ) return;
if( pBlob->aData[pBlob->nUsed-1]!='\n' ){
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 |
i++;
}
if( pTo ){
blob_append(pTo, &pFrom->aData[pFrom->iCursor], i - pFrom->iCursor);
}
pFrom->iCursor = i;
}
/*
** Remove comment lines (starting with '#') from a blob pIn.
** Keep lines starting with "\#" but remove the initial backslash.
**
** Store the result in pOut. It is ok for pIn and pOut to be the same blob.
**
** pOut must either be the same as pIn or else uninitialized.
*/
void blob_strip_comment_lines(Blob *pIn, Blob *pOut){
char *z = pIn->aData;
unsigned int i = 0;
unsigned int n = pIn->nUsed;
unsigned int lineStart = 0;
unsigned int copyStart = 0;
int doCopy = 1;
Blob temp;
blob_zero(&temp);
while( i<n ){
if( i==lineStart && z[i]=='#' ){
copyStart = i;
doCopy = 0;
}else if( i==lineStart && z[i]=='\\' && z[i+1]=='#' ){
/* keep lines starting with an escaped '#' (and unescape it) */
copyStart = i + 1;
}
if( z[i]=='\n' ){
if( doCopy ) blob_append(&temp,&pIn->aData[copyStart], i - copyStart + 1);
lineStart = copyStart = i + 1;
doCopy = 1;
}
i++;
}
/* Last line */
if( doCopy ) blob_append(&temp, &pIn->aData[copyStart], i - copyStart);
if( pOut==pIn ) blob_reset(pOut);
*pOut = temp;
}
/*
** COMMAND: test-strip-comment-lines
**
** Usage: %fossil test-strip-comment-lines ?OPTIONS? INPUTFILE
**
** Read INPUTFILE and print it without comment lines (starting with '#').
** Keep lines starting with "\\#" but remove the initial backslash.
**
** This is used to test and debug the blob_strip_comment_lines() routine.
**
** Options:
** -y|--side-by-side Show diff of INPUTFILE and output side-by-side
** -W|--width N Width of lines in side-by-side diff
*/
void test_strip_comment_lines_cmd(void){
Blob f, h; /* unitialized */
Blob out;
DiffConfig dCfg;
int sbs = 0;
const char *z;
int w = 0;
memset(&dCfg, 0, sizeof(dCfg));
sbs = find_option("side-by-side","y",0)!=0;
if( (z = find_option("width","W",1))!=0 && (w = atoi(z))>0 ){
dCfg.wColumn = w;
}
verify_all_options();
if( g.argc!=3 ) usage("INPUTFILE");
blob_read_from_file(&f, g.argv[2], ExtFILE);
blob_strip_comment_lines(&f, &h);
if ( !sbs ){
blob_write_to_file(&h, "-");
}else{
blob_zero(&out);
dCfg.nContext = -1; /* whole content */
dCfg.diffFlags = DIFF_SIDEBYSIDE | DIFF_CONTEXT_EX | DIFF_STRIP_EOLCR;
diff_begin(&dCfg);
text_diff(&f, &h, &out, &dCfg);
blob_write_to_file(&out, "-");
diff_end(&dCfg, 0);
}
}
/*
** Ensure that the text in pBlob ends with '\n'
*/
void blob_add_final_newline(Blob *pBlob){
if( pBlob->nUsed<=0 ) return;
if( pBlob->aData[pBlob->nUsed-1]!='\n' ){
|
| ︙ | ︙ | |||
925 926 927 928 929 930 931 932 933 934 935 936 937 938 |
int i;
for(i=0; i<n; i++) blob_zero(&aBlob[i]);
}
void blobarray_reset(Blob *aBlob, int n){
int i;
for(i=0; i<n; i++) blob_reset(&aBlob[i]);
}
/*
** Parse a blob into space-separated tokens. Store each token in
** an element of the blobarray aToken[]. aToken[] is nToken elements in
** size. Return the number of tokens seen.
*/
int blob_tokenize(Blob *pIn, Blob *aToken, int nToken){
| > > > > > > > > > > > > > > > > > > > | 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 |
int i;
for(i=0; i<n; i++) blob_zero(&aBlob[i]);
}
void blobarray_reset(Blob *aBlob, int n){
int i;
for(i=0; i<n; i++) blob_reset(&aBlob[i]);
}
/*
** Allocate array of n blobs and initialize each element with `empty_blob`
*/
Blob* blobarray_new(int n){
int i;
Blob *aBlob = fossil_malloc(sizeof(Blob)*n);
for(i=0; i<n; i++) aBlob[i] = empty_blob;
return aBlob;
}
/*
** Free array of n blobs some of which may be empty (have NULL buffer)
*/
void blobarray_delete(Blob *aBlob, int n){
int i;
for(i=0; i<n; i++){
if( blob_buffer(aBlob+i) ) blob_reset(aBlob+i);
}
fossil_free(aBlob);
}
/*
** Parse a blob into space-separated tokens. Store each token in
** an element of the blobarray aToken[]. aToken[] is nToken elements in
** size. Return the number of tokens seen.
*/
int blob_tokenize(Blob *pIn, Blob *aToken, int nToken){
|
| ︙ | ︙ | |||
1136 1137 1138 1139 1140 1141 1142 |
fossil_fatal_recursive("unable to open file \"%s\" for writing",
zFilename);
return 0;
}
blob_is_init(pBlob);
nWrote = fwrite(blob_buffer(pBlob), 1, blob_size(pBlob), out);
fclose(out);
| | | 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 |
fossil_fatal_recursive("unable to open file \"%s\" for writing",
zFilename);
return 0;
}
blob_is_init(pBlob);
nWrote = fwrite(blob_buffer(pBlob), 1, blob_size(pBlob), out);
fclose(out);
if( nWrote!=(int)blob_size(pBlob) ){
fossil_fatal_recursive("short write: %d of %d bytes to %s", nWrote,
blob_size(pBlob), zFilename);
}
}
return nWrote;
}
|
| ︙ | ︙ | |||
1334 1335 1336 1337 1338 1339 1340 |
char *z = p->aData;
int j = p->nUsed;
int i, n;
for(i=n=0; i<j; i++){
if( z[i]=='\n' ) n++;
}
j += n;
| | | 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 |
char *z = p->aData;
int j = p->nUsed;
int i, n;
for(i=n=0; i<j; i++){
if( z[i]=='\n' ) n++;
}
j += n;
if( j>=(int)(p->nAlloc) ){
blob_resize(p, j);
z = p->aData;
}
p->nUsed = j;
z[j] = 0;
while( j>i ){
if( (z[--j] = z[--i]) =='\n' ){
|
| ︙ | ︙ | |||
1389 1390 1391 1392 1393 1394 1395 |
if( (z[i]<0xa0) && (cp1252[z[i]&0x1f]>=0x800) ){
n++;
}
n++;
}
}
j += n;
| | | 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 |
if( (z[i]<0xa0) && (cp1252[z[i]&0x1f]>=0x800) ){
n++;
}
n++;
}
}
j += n;
if( j>=(int)(p->nAlloc) ){
blob_resize(p, j);
z = (unsigned char *)p->aData;
}
p->nUsed = j;
z[j] = 0;
while( j>i ){
if( z[--i]>=0x80 ){
|
| ︙ | ︙ |
Changes to src/branch.c.
| ︙ | ︙ | |||
103 104 105 106 107 108 109 |
if( db_get_boolean("clearsign", 0)==0 ){ noSign = 1; }
/* fossil branch new name */
zBranch = g.argv[3];
if( zBranch==0 || zBranch[0]==0 ){
fossil_fatal("branch name cannot be empty");
}
| < < < < | | | 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
if( db_get_boolean("clearsign", 0)==0 ){ noSign = 1; }
/* fossil branch new name */
zBranch = g.argv[3];
if( zBranch==0 || zBranch[0]==0 ){
fossil_fatal("branch name cannot be empty");
}
if( branch_is_open(zBranch) ){
fossil_fatal("an open branch named \"%s\" already exists", zBranch);
}
user_select();
db_begin_transaction();
rootid = name_to_typed_rid(g.argv[4], "ci");
if( rootid==0 ){
fossil_fatal("unable to locate check-in off of which to branch");
|
| ︙ | ︙ | |||
195 196 197 198 199 200 201 |
}
}
brid = content_put_ex(&branch, 0, 0, 0, isPrivate);
if( brid==0 ){
fossil_fatal("trouble committing manifest: %s", g.zErrMsg);
}
| | | | 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 |
}
}
brid = content_put_ex(&branch, 0, 0, 0, isPrivate);
if( brid==0 ){
fossil_fatal("trouble committing manifest: %s", g.zErrMsg);
}
db_add_unsent(brid);
if( manifest_crosslink(brid, &branch, MC_PERMIT_HOOKS)==0 ){
fossil_fatal("%s", g.zErrMsg);
}
assert( blob_is_reset(&branch) );
content_deltify(rootid, &brid, 1, 0);
zUuid = rid_to_uuid(brid);
fossil_print("New branch: %s\n", zUuid);
if( g.argc==3 ){
fossil_print(
"\n"
"Note: the local check-out has not been updated to the new\n"
" branch. To begin working on the new branch, do this:\n"
"\n"
|
| ︙ | ︙ | |||
226 227 228 229 230 231 232 | if( !isPrivate ) autosync_loop(SYNC_PUSH, 0, "branch"); } /* ** Create a TEMP table named "tmp_brlist" with 7 columns: ** ** name Name of the branch | | | | 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 | if( !isPrivate ) autosync_loop(SYNC_PUSH, 0, "branch"); } /* ** Create a TEMP table named "tmp_brlist" with 7 columns: ** ** name Name of the branch ** mtime Time of last check-in on this branch ** isclosed True if the branch is closed ** mergeto Another branch this branch was merged into ** nckin Number of checkins on this branch ** ckin Hash of the last check-in on this branch ** isprivate True if the branch is private ** bgclr Background color for this branch */ static const char createBrlistQuery[] = @ CREATE TEMP TABLE IF NOT EXISTS tmp_brlist AS @ SELECT @ tagxref.value AS name, |
| ︙ | ︙ | |||
278 279 280 281 282 283 284 285 286 287 288 289 290 | #define BRL_CLOSED_ONLY 0x001 /* Show only closed branches */ #define BRL_OPEN_ONLY 0x002 /* Show only open branches */ #define BRL_BOTH 0x003 /* Show both open and closed branches */ #define BRL_OPEN_CLOSED_MASK 0x003 #define BRL_ORDERBY_MTIME 0x004 /* Sort by MTIME. (otherwise sort by name)*/ #define BRL_REVERSE 0x008 /* Reverse the sort order */ #define BRL_PRIVATE 0x010 /* Show only private branches */ #endif /* INTERFACE */ /* ** Prepare a query that will list branches. ** | > > > < < < < | > | < | > | > > > > > > > > > > > > > > > | | | > | > > > > > | 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 |
#define BRL_CLOSED_ONLY 0x001 /* Show only closed branches */
#define BRL_OPEN_ONLY 0x002 /* Show only open branches */
#define BRL_BOTH 0x003 /* Show both open and closed branches */
#define BRL_OPEN_CLOSED_MASK 0x003
#define BRL_ORDERBY_MTIME 0x004 /* Sort by MTIME. (otherwise sort by name)*/
#define BRL_REVERSE 0x008 /* Reverse the sort order */
#define BRL_PRIVATE 0x010 /* Show only private branches */
#define BRL_MERGED 0x020 /* Show only merged branches */
#define BRL_UNMERGED 0x040 /* Show only unmerged branches */
#define BRL_LIST_USERS 0x080 /* Populate list of users participating */
#endif /* INTERFACE */
/*
** Prepare a query that will list branches.
**
** If the BRL_ORDERBY_MTIME flag is set and nLimitMRU ("Limit Most Recently Used
** style") is a non-zero number, the result is limited to nLimitMRU entries, and
** the BRL_REVERSE flag is applied in an outer query after processing the limit,
** so that it's possible to generate short lists with the most recently modified
** branches sorted chronologically in either direction, as does the "branch lsh"
** command.
** For other cases, the outer query is also generated, but works as a no-op. The
** code to build the outer query is marked with *//* OUTER QUERY *//* comments.
*/
void branch_prepare_list_query(
Stmt *pQuery,
int brFlags,
const char *zBrNameGlob,
int nLimitMRU,
const char *zUser
){
Blob sql;
blob_init(&sql, 0, 0);
brlist_create_temp_table();
/* Ignore nLimitMRU if no chronological sort requested. */
if( (brFlags & BRL_ORDERBY_MTIME)==0 ) nLimitMRU = 0;
/* Negative values for nLimitMRU also mean "no limit". */
if( nLimitMRU<0 ) nLimitMRU = 0;
/* OUTER QUERY */
blob_append_sql(&sql,"SELECT name, isprivate, mergeto,");
if( brFlags & BRL_LIST_USERS ){
blob_append_sql(&sql,
" (SELECT group_concat(user) FROM ("
" SELECT DISTINCT * FROM ("
" SELECT coalesce(euser,user) AS user"
" FROM event"
" WHERE type='ci' AND objid IN ("
" SELECT rid FROM tagxref WHERE value=name)"
" ORDER BY 1)))"
);
}else{
blob_append_sql(&sql, " NULL");
}
blob_append_sql(&sql," FROM (");
/* INNER QUERY */
switch( brFlags & BRL_OPEN_CLOSED_MASK ){
case BRL_CLOSED_ONLY: {
blob_append_sql(&sql,
"SELECT name, isprivate, mtime, mergeto FROM tmp_brlist WHERE isclosed"
);
break;
}
case BRL_BOTH: {
blob_append_sql(&sql,
"SELECT name, isprivate, mtime, mergeto FROM tmp_brlist WHERE 1"
);
break;
}
case BRL_OPEN_ONLY: {
blob_append_sql(&sql,
"SELECT name, isprivate, mtime, mergeto FROM tmp_brlist WHERE NOT isclosed"
);
break;
}
}
if( brFlags & BRL_PRIVATE ) blob_append_sql(&sql, " AND isprivate");
if( brFlags & BRL_MERGED ) blob_append_sql(&sql, " AND mergeto IS NOT NULL");
if( zBrNameGlob ) blob_append_sql(&sql, " AND (name GLOB %Q)", zBrNameGlob);
if( zUser && zUser[0] ) blob_append_sql(&sql,
" AND EXISTS (SELECT 1 FROM event WHERE type='ci' AND (user=%Q OR euser=%Q)"
" AND objid in (SELECT rid FROM tagxref WHERE value=tmp_brlist.name))",
zUser, zUser
);
if( brFlags & BRL_ORDERBY_MTIME ){
blob_append_sql(&sql, " ORDER BY -mtime");
}else{
blob_append_sql(&sql, " ORDER BY name COLLATE nocase");
}
if( brFlags & BRL_REVERSE && !nLimitMRU ){
blob_append_sql(&sql," DESC");
|
| ︙ | ︙ | |||
462 463 464 465 466 467 468 |
fossil_fatal("Problem saving new artifact: %s\n%b",
g.zErrMsg, &manifest);
}else if(manifest_crosslink(newRid, &manifest, 0)==0){
fossil_fatal("Crosslinking error: %s", g.zErrMsg);
}
fossil_print("Saved new control artifact %z (RID %d).\n",
rid_to_uuid(newRid), newRid);
| | | | | | | | | 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 |
fossil_fatal("Problem saving new artifact: %s\n%b",
g.zErrMsg, &manifest);
}else if(manifest_crosslink(newRid, &manifest, 0)==0){
fossil_fatal("Crosslinking error: %s", g.zErrMsg);
}
fossil_print("Saved new control artifact %z (RID %d).\n",
rid_to_uuid(newRid), newRid);
db_add_unsent(newRid);
if(fDryRun){
fossil_print("Dry-run mode: rolling back new artifact.\n");
assert(0!=doRollback);
}
}
db_multi_exec("DROP TABLE brcmdtag");
blob_reset(&manifest);
db_end_transaction(doRollback);
return 0;
}
/*
** Internal helper for branch_cmd_close() and friends. zName is a
** symbolic check-in name. Returns the blob.rid of the check-in or fails
** fatally if the name does not resolve unambiguously. If zUuid is
** not NULL, *zUuid is set to the resolved blob.uuid and must be freed
** by the caller via fossil_free().
*/
static int branch_resolve_name(char const *zName, char **zUuid){
const int rid = name_to_uuid2(zName, "ci", zUuid);
if(0==rid){
fossil_fatal("Cannot resolve name: %s", zName);
}else if(rid<0){
fossil_fatal("Ambiguous name: %s", zName);
}
return rid;
}
/*
** Implementation of (branch hide/unhide) subcommands. nStartAtArg is
** the g.argv index to start reading branch/check-in names. fHide is
** true for hiding, false for unhiding. Fails fatally on error.
*/
static void branch_cmd_hide(int nStartAtArg, int fHide){
int argPos = nStartAtArg; /* g.argv pos with first branch/ci name */
char * zUuid = 0; /* Resolved branch UUID. */
const int fVerbose = find_option("verbose","v",0)!=0;
const int fDryRun = find_option("dry-run","n",0)!=0;
const char *zDateOvrd = find_option("date-override",0,1);
const char *zUserOvrd = find_option("user-override",0,1);
verify_all_options();
db_begin_transaction();
for( ; argPos < g.argc; fossil_free(zUuid), ++argPos ){
const char * zName = g.argv[argPos];
const int rid = branch_resolve_name(zName, &zUuid);
const int isHidden = rid_has_tag(rid, TAG_HIDDEN);
/* Potential TODO: check for existing 'hidden' flag and skip this
** entry if it already has (if fHide) or does not have (if !fHide)
** that tag. FWIW, /ci_edit does not do so. */
if(fHide && isHidden){
fossil_warning("Skipping hidden check-in %s: %s.", zName, zUuid);
continue;
}else if(!fHide && !isHidden){
fossil_warning("Skipping non-hidden check-in %s: %s.", zName, zUuid);
continue;
}
branch_cmd_tag_add(rid, fHide ? "*hidden" : "-hidden");
if(fVerbose!=0){
fossil_print("%s check-in [%s] %s\n",
fHide ? "Hiding" : "Unhiding",
zName, zUuid);
}
}
branch_cmd_tag_finalize(fDryRun, fVerbose, zDateOvrd, zUserOvrd);
}
/*
** Implementation of (branch close|reopen) subcommands. nStartAtArg is
** the g.argv index to start reading branch/check-in names. The given
** checkins are closed if fClose is true, else their "closed" tag (if
** any) is cancelled. Fails fatally on error.
*/
static void branch_cmd_close(int nStartAtArg, int fClose){
int argPos = nStartAtArg; /* g.argv pos with first branch name */
char * zUuid = 0; /* Resolved branch UUID. */
const int fVerbose = find_option("verbose","v",0)!=0;
|
| ︙ | ︙ | |||
587 588 589 590 591 592 593 | ** 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 | | | > > | | | | > > | | > > | | | > > > > | | | | | < | | 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 |
** 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
** -M|--unmerged List branches not merged into the current branch
** -p List only private branches
** -r Reverse the sort order
** -t Show recently changed branches first
** --self List only branches where you participate
** --username USER List only branches where USER participate
** --users N List up to N users partipiating
**
** The current branch is marked with an asterisk. Private branches are
** marked with a hash sign.
**
** 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
** ("auto" lets Fossil choose it automatically,
** even for private branches)
** --nosign Do not sign contents on this branch
** --date-override DATE DATE to use instead of 'now'
** --user-override USER USER to use instead of the current default
**
** DATE 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.
**
** Options:
** -R|--repository REPO Run commands on repository REPO
*/
void branch_cmd(void){
int n;
const char *zCmd = "list";
db_find_and_open_repository(0, 0);
if( g.argc>=3 ) zCmd = g.argv[2];
n = strlen(zCmd);
if( strncmp(zCmd,"current",n)==0 ){
if( !g.localOpen ){
fossil_fatal("not within an open check-out");
}else{
int vid = db_lget_int("checkout", 0);
char *zCurrent = db_text(0, "SELECT value FROM tagxref"
" WHERE rid=%d AND tagid=%d", vid, TAG_BRANCH);
fossil_print("%s\n", zCurrent);
fossil_free(zCurrent);
}
|
| ︙ | ︙ | |||
686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 |
fossil_print("%s: open as of %s on %.16s\n", zBrName, zDate, zUuid);
}
}
}else if( strncmp(zCmd,"list",n)==0 ||
strncmp(zCmd, "ls", n)==0 ||
strcmp(zCmd, "lsh")==0 ){
Stmt q;
int vid;
char *zCurrent = 0;
const char *zBrNameGlob = 0;
int nLimit = 0;
int brFlags = BRL_OPEN_ONLY;
if( find_option("all","a",0)!=0 ) brFlags = BRL_BOTH;
if( find_option("closed","c",0)!=0 ) brFlags = BRL_CLOSED_ONLY;
if( find_option("t",0,0)!=0 ) brFlags |= BRL_ORDERBY_MTIME;
if( find_option("r",0,0)!=0 ) brFlags |= BRL_REVERSE;
if( find_option("p",0,0)!=0 ) brFlags |= BRL_PRIVATE;
| > > > > > > > > > | > > > > > > > > > > > > | > | > > > > > > > > > | | > > > > > > > > > > > > > > > > > > > > | | | | | 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 |
fossil_print("%s: open as of %s on %.16s\n", zBrName, zDate, zUuid);
}
}
}else if( strncmp(zCmd,"list",n)==0 ||
strncmp(zCmd, "ls", n)==0 ||
strcmp(zCmd, "lsh")==0 ){
Stmt q;
Blob txt = empty_blob;
int vid;
char *zCurrent = 0;
const char *zBrNameGlob = 0;
const char *zUser = find_option("username",0,1);
const char *zUsersOpt = find_option("users",0,1);
int nUsers = zUsersOpt ? atoi(zUsersOpt) : 0;
int nLimit = 0;
int brFlags = BRL_OPEN_ONLY;
if( find_option("all","a",0)!=0 ) brFlags = BRL_BOTH;
if( find_option("closed","c",0)!=0 ) brFlags = BRL_CLOSED_ONLY;
if( find_option("t",0,0)!=0 ) brFlags |= BRL_ORDERBY_MTIME;
if( find_option("r",0,0)!=0 ) brFlags |= BRL_REVERSE;
if( find_option("p",0,0)!=0 ) brFlags |= BRL_PRIVATE;
if( find_option("merged","m",0)!=0 ) brFlags |= BRL_MERGED;
if( find_option("unmerged","M",0)!=0 ) brFlags |= BRL_UNMERGED;
if( find_option("self",0,0)!=0 ){
if( zUser ){
fossil_fatal("flags --username and --self are mutually exclusive");
}
user_select();
zUser = login_name();
}
verify_all_options();
if ( (brFlags & BRL_MERGED) && (brFlags & BRL_UNMERGED) ){
fossil_fatal("flags --merged and --unmerged are mutually exclusive");
}
if( zUsersOpt ){
if( nUsers <= 0) fossil_fatal("With --users, N must be positive");
brFlags |= BRL_LIST_USERS;
}
if( strcmp(zCmd, "lsh")==0 ){
nLimit = 5;
if( g.argc>4 || (g.argc==4 && (nLimit = atoi(g.argv[3]))==0) ){
fossil_fatal("the lsh subcommand allows one optional numeric argument");
}
brFlags |= BRL_ORDERBY_MTIME;
}else{
if( g.argc >= 4 ) zBrNameGlob = g.argv[3];
}
if( g.localOpen ){
vid = db_lget_int("checkout", 0);
zCurrent = db_text(0, "SELECT value FROM tagxref"
" WHERE rid=%d AND tagid=%d", vid, TAG_BRANCH);
}
branch_prepare_list_query(&q, brFlags, zBrNameGlob, nLimit, zUser);
blob_init(&txt, 0, 0);
while( db_step(&q)==SQLITE_ROW ){
const char *zBr = db_column_text(&q, 0);
int isPriv = db_column_int(&q, 1)==1;
const char *zMergeTo = db_column_text(&q, 2);
int isCur = zCurrent!=0 && fossil_strcmp(zCurrent,zBr)==0;
const char *zUsers = db_column_text(&q, 3);
if( (brFlags & BRL_MERGED) && fossil_strcmp(zCurrent,zMergeTo)!=0 ){
continue;
}
if( (brFlags & BRL_UNMERGED) && (fossil_strcmp(zCurrent,zMergeTo)==0
|| isCur) ){
continue;
}
blob_appendf(&txt, "%s%s%s",
( (brFlags & BRL_PRIVATE) ? " " : ( isPriv ? "#" : " ") ),
(isCur ? "* " : " "), zBr);
if( nUsers ){
char c;
const char *cp;
const char *pComma = 0;
int commas = 0;
for( cp = zUsers; ( c = *cp ) != 0; cp++ ){
if( c == ',' ){
commas++;
if( commas == nUsers ) pComma = cp;
}
}
if( pComma ){
blob_appendf(&txt, " (%.*s,... %i more)",
pComma - zUsers, zUsers, commas + 1 - nUsers);
}else{
blob_appendf(&txt, " (%s)", zUsers);
}
}
fossil_print("%s\n", blob_str(&txt));
blob_reset(&txt);
}
db_finalize(&q);
}else if( strncmp(zCmd,"new",n)==0 ){
branch_new();
}else if( strncmp(zCmd,"close",5)==0 ){
if(g.argc<4){
usage("close branch-name(s)...");
}
branch_cmd_close(3, 1);
}else if( strncmp(zCmd,"reopen",6)==0 ){
if(g.argc<4){
usage("reopen branch-name(s)...");
}
branch_cmd_close(3, 0);
}else if( strncmp(zCmd,"hide",4)==0 ){
if(g.argc<4){
usage("hide branch-name(s)...");
}
branch_cmd_hide(3,1);
}else if( strncmp(zCmd,"unhide",6)==0 ){
if(g.argc<4){
usage("unhide branch-name(s)...");
}
branch_cmd_hide(3,0);
}else{
fossil_fatal("branch subcommand should be one of: "
"close current hide info list ls lsh new reopen unhide");
}
}
|
| ︙ | ︙ | |||
860 861 862 863 864 865 866 867 868 869 870 871 872 873 |
if( showClosed==0 && showAll==0 && showOpen==0 && colorTest==0 ){
new_brlist_page();
return;
}
login_check_credentials();
if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
if( colorTest ){
showClosed = 0;
showAll = 1;
}
if( showAll ) brFlags = BRL_BOTH;
if( showClosed ) brFlags = BRL_CLOSED_ONLY;
| > | 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 |
if( showClosed==0 && showAll==0 && showOpen==0 && colorTest==0 ){
new_brlist_page();
return;
}
login_check_credentials();
if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
cgi_check_for_malice();
if( colorTest ){
showClosed = 0;
showAll = 1;
}
if( showAll ) brFlags = BRL_BOTH;
if( showClosed ) brFlags = BRL_CLOSED_ONLY;
|
| ︙ | ︙ | |||
905 906 907 908 909 910 911 | @ closed leaves</a></div>. @ Closed branches are fixed and do not change (unless they are first @ reopened).</li> @ </ol> style_sidebox_end(); #endif | | | 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 |
@ closed leaves</a></div>.
@ Closed branches are fixed and do not change (unless they are first
@ reopened).</li>
@ </ol>
style_sidebox_end();
#endif
branch_prepare_list_query(&q, brFlags, 0, 0, 0);
cnt = 0;
while( db_step(&q)==SQLITE_ROW ){
const char *zBr = db_column_text(&q, 0);
if( cnt==0 ){
if( colorTest ){
@ <h2>Default background colors for all branches:</h2>
}else if( showClosed ){
|
| ︙ | ︙ | |||
988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 |
if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
style_set_current_feature("branch");
style_header("Branches");
style_submenu_element("List", "brlist");
login_anonymous_available();
timeline_ss_submenu();
@ <h2>The initial check-in for each branch:</h2>
blob_append(&sql, timeline_query_for_www(), -1);
blob_append_sql(&sql,
"AND blob.rid IN (SELECT rid FROM tagxref"
" WHERE tagtype>0 AND tagid=%d AND srcid!=0)", TAG_BRANCH);
if( fNoHidden || fOnlyHidden ){
const char* zUnaryOp = fNoHidden ? "NOT" : "";
| > | 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 |
if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
style_set_current_feature("branch");
style_header("Branches");
style_submenu_element("List", "brlist");
login_anonymous_available();
timeline_ss_submenu();
cgi_check_for_malice();
@ <h2>The initial check-in for each branch:</h2>
blob_append(&sql, timeline_query_for_www(), -1);
blob_append_sql(&sql,
"AND blob.rid IN (SELECT rid FROM tagxref"
" WHERE tagtype>0 AND tagid=%d AND srcid!=0)", TAG_BRANCH);
if( fNoHidden || fOnlyHidden ){
const char* zUnaryOp = fNoHidden ? "NOT" : "";
|
| ︙ | ︙ |
Changes to src/browse.c.
| ︙ | ︙ | |||
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 |
zSep, zLink, j-i, &zPath[i]);
}
zSep = "/";
while( zPath[j]=='/' ){ j++; }
}
}
/*
** WEBPAGE: dir
**
** Show the files and subdirectories within a single directory of the
** source tree. Only files for a single check-in are shown if the ci=
** query parameter is present. If ci= is missing, the union of files
** across all check-ins is shown.
**
** Query parameters:
**
** ci=LABEL Show only files in this check-in. Optional.
** name=PATH Directory to display. Optional. Top-level if missing
** re=REGEXP Show only files matching REGEXP
** type=TYPE TYPE=flat: use this display
** TYPE=tree: use the /tree display instead
** noreadme Do not attempt to display the README file.
*/
void page_dir(void){
char *zD = fossil_strdup(P("name"));
int nD = zD ? strlen(zD)+1 : 0;
int mxLen;
char *zPrefix;
Stmt q;
const char *zCI = P("ci");
int rid = 0;
char *zUuid = 0;
Manifest *pM = 0;
const char *zSubdirLink;
int linkTrunk = 1;
int linkTip = 1;
HQuery sURI;
int isSymbolicCI = 0; /* ci= is symbolic name, not a hash prefix */
int isBranchCI = 0; /* True if ci= refers to a branch name */
char *zHeader = 0;
const char *zRegexp; /* The re= query parameter */
char *zMatch; /* Extra title text describing the match */
if( zCI && strlen(zCI)==0 ){ zCI = 0; }
if( strcmp(PD("type","flat"),"tree")==0 ){ page_tree(); return; }
login_check_credentials();
if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
while( nD>1 && zD[nD-2]=='/' ){ zD[(--nD)-1] = 0; }
/* If the name= parameter is an empty string, make it a NULL pointer */
if( zD && strlen(zD)==0 ){ zD = 0; }
/* If a specific check-in is requested, fetch and parse it. If the
** specific check-in does not exist, clear zCI. zCI==0 will cause all
** files from all check-ins to be displayed.
*/
if( zCI ){
pM = manifest_get_by_name(zCI, &rid);
if( pM ){
int trunkRid = symbolic_name_to_rid("tag:trunk", "ci");
linkTrunk = trunkRid && rid != trunkRid;
linkTip = rid != symbolic_name_to_rid("tip", "ci");
zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
isSymbolicCI = (sqlite3_strnicmp(zUuid, zCI, strlen(zCI))!=0);
isBranchCI = branch_includes_uuid(zCI, zUuid);
Th_Store("current_checkin", zCI);
}else{
zCI = 0;
}
}
assert( isSymbolicCI==0 || (zCI!=0 && zCI[0]!=0) );
if( zD==0 ){
if( zCI ){
zHeader = mprintf("Top-level Files of %s", zCI);
}else{
zHeader = mprintf("All Top-level Files");
}
}else{
if( zCI ){
zHeader = mprintf("Files in %s/ of %s", zD, zCI);
}else{
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > | > > | > > > | > | | | | > | | | > < | < < < | | | > > > > | < < < < < < < < < < < < < < < < < < < < < < < | | | | | | | > > > | | > > > > > > > | | > | 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 |
zSep, zLink, j-i, &zPath[i]);
}
zSep = "/";
while( zPath[j]=='/' ){ j++; }
}
}
/*
** WEBPAGE: docdir
**
** Show the files and subdirectories within a single directory of the
** source tree. This works similarly to /dir but with the following
** differences:
**
** * Links to files go to /doc (showing the file content directly,
** depending on mimetype) rather than to /file (which always shows
** the file embedded in a standard Fossil page frame).
**
** * The submenu and the page title is now show. The page is plain.
**
** The /docdir page is a shorthand for /dir with the "dx" query parameter.
**
** Query parameters:
**
** ci=LABEL Show only files in this check-in. If omitted, the
** "trunk" directory is used.
** name=PATH Directory to display. Optional. Top-level if missing
** re=REGEXP Show only files matching REGEXP
** noreadme Do not attempt to display the README file.
** dx File links to go to /doc instead of /file or /finfo.
*/
void page_docdir(void){ page_dir(); }
/*
** WEBPAGE: dir
**
** Show the files and subdirectories within a single directory of the
** source tree. Only files for a single check-in are shown if the ci=
** query parameter is present. If ci= is missing, the union of files
** across all check-ins is shown.
**
** Query parameters:
**
** ci=LABEL Show only files in this check-in. Optional.
** name=PATH Directory to display. Optional. Top-level if missing
** re=REGEXP Show only files matching REGEXP
** type=TYPE TYPE=flat: use this display
** TYPE=tree: use the /tree display instead
** noreadme Do not attempt to display the README file.
** dx Behave like /docdir
*/
void page_dir(void){
char *zD = fossil_strdup(P("name"));
int nD = zD ? strlen(zD)+1 : 0;
int mxLen;
char *zPrefix;
Stmt q;
const char *zCI = P("ci");
int rid = 0;
char *zUuid = 0;
Manifest *pM = 0;
const char *zSubdirLink;
int linkTrunk = 1;
int linkTip = 1;
HQuery sURI;
int isSymbolicCI = 0; /* ci= is symbolic name, not a hash prefix */
int isBranchCI = 0; /* True if ci= refers to a branch name */
char *zHeader = 0;
const char *zRegexp; /* The re= query parameter */
char *zMatch; /* Extra title text describing the match */
int bDocDir = PB("dx") || strncmp(g.zPath, "docdir", 6)==0;
if( zCI && strlen(zCI)==0 ){ zCI = 0; }
if( strcmp(PD("type","flat"),"tree")==0 ){ page_tree(); return; }
login_check_credentials();
if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
while( nD>1 && zD[nD-2]=='/' ){ zD[(--nD)-1] = 0; }
/* If the name= parameter is an empty string, make it a NULL pointer */
if( zD && strlen(zD)==0 ){ zD = 0; }
/* If a specific check-in is requested, fetch and parse it. If the
** specific check-in does not exist, clear zCI. zCI==0 will cause all
** files from all check-ins to be displayed.
*/
if( bDocDir && zCI==0 ) zCI = "trunk";
if( zCI ){
pM = manifest_get_by_name(zCI, &rid);
if( pM ){
int trunkRid = symbolic_name_to_rid("tag:trunk", "ci");
linkTrunk = trunkRid && rid != trunkRid;
linkTip = rid != symbolic_name_to_rid("tip", "ci");
zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
isSymbolicCI = (sqlite3_strnicmp(zUuid, zCI, strlen(zCI))!=0);
isBranchCI = branch_includes_uuid(zCI, zUuid);
if( bDocDir ) zCI = mprintf("%S", zUuid);
Th_Store("current_checkin", zCI);
}else{
zCI = 0;
}
}
assert( isSymbolicCI==0 || (zCI!=0 && zCI[0]!=0) );
if( zD==0 ){
if( zCI ){
zHeader = mprintf("Top-level Files of %s", zCI);
}else{
zHeader = mprintf("All Top-level Files");
}
}else{
if( zCI ){
zHeader = mprintf("Files in %s/ of %s", zD, zCI);
}else{
zHeader = mprintf("All Files in %s/", zD);
}
}
zRegexp = P("re");
if( zRegexp ){
zHeader = mprintf("%z matching \"%s\"", zHeader, zRegexp);
zMatch = mprintf(" matching \"%h\"", zRegexp);
}else{
zMatch = "";
}
style_header("%s", zHeader);
fossil_free(zHeader);
style_adunit_config(ADUNIT_RIGHT_OK);
sqlite3_create_function(g.db, "pathelement", 2, SQLITE_UTF8, 0,
pathelementFunc, 0, 0);
url_initialize(&sURI, "dir");
cgi_check_for_malice();
cgi_query_parameters_to_url(&sURI);
/* Compute the title of the page */
if( bDocDir ){
zPrefix = zD ? mprintf("%s/",zD) : "";
}else if( zD ){
Blob dirname;
blob_init(&dirname, 0, 0);
hyperlinked_path(zD, &dirname, zCI, "dir", "", 0);
@ <h2>Files in directory %s(blob_str(&dirname)) \
blob_reset(&dirname);
zPrefix = mprintf("%s/", zD);
style_submenu_element("Top-Level", "%s",
url_render(&sURI, "name", 0, 0, 0));
}else{
@ <h2>Files in the top-level directory \
zPrefix = "";
}
if( zCI ){
if( bDocDir ){
/* No header for /docdir. Just give the list of files. */
}else if( fossil_strcmp(zCI,"tip")==0 ){
@ from the %z(href("%R/info?name=%T",zCI))latest check-in</a>\
@ %s(zMatch)</h2>
}else if( isBranchCI ){
@ from the %z(href("%R/info?name=%T",zCI))latest check-in</a> \
@ of branch %z(href("%R/timeline?r=%T",zCI))%h(zCI)</a>\
@ %s(zMatch)</h2>
}else {
@ of check-in %z(href("%R/info?name=%T",zCI))%h(zCI)</a>\
@ %s(zMatch)</h2>
}
if( bDocDir ){
zSubdirLink = mprintf("%R/docdir?ci=%T&name=%T", zCI, zPrefix);
}else{
zSubdirLink = mprintf("%R/dir?ci=%T&name=%T", zCI, zPrefix);
}
if( nD==0 && !bDocDir ){
style_submenu_element("File Ages", "%R/fileage?name=%T", zCI);
}
}else{
@ in any check-in</h2>
zSubdirLink = mprintf("%R/dir?name=%T", zPrefix);
}
if( linkTrunk && !bDocDir ){
style_submenu_element("Trunk", "%s",
url_render(&sURI, "ci", "trunk", 0, 0));
}
if( linkTip && !bDocDir ){
style_submenu_element("Tip", "%s", url_render(&sURI, "ci", "tip", 0, 0));
}
if( zD && !bDocDir ){
style_submenu_element("History","%R/timeline?chng=%T/*", zD);
}
if( !bDocDir ){
style_submenu_element("All", "%s", url_render(&sURI, "ci", 0, 0, 0));
style_submenu_element("Tree-View", "%s",
url_render(&sURI, "type", "tree", 0, 0));
}
/* Compute the temporary table "localfiles" containing the names
** of all files and subdirectories in the zD[] directory.
**
** Subdirectory names begin with "/". This causes them to sort
** first and it also gives us an easy way to distinguish files
** from directories in the loop that follows.
*/
db_multi_exec(
"CREATE TEMP TABLE localfiles(x UNIQUE NOT NULL, u);"
);
if( zCI ){
/* Files in the specific checked given by zCI */
if( zD ){
db_multi_exec(
"INSERT OR IGNORE INTO localfiles"
" SELECT pathelement(filename,%d), uuid"
" FROM files_of_checkin(%Q)"
" WHERE filename GLOB '%q/*'",
nD, zCI, zD
);
}else{
db_multi_exec(
"INSERT OR IGNORE INTO localfiles"
" SELECT pathelement(filename,%d), uuid"
" FROM files_of_checkin(%Q)",
nD, zCI
);
}
}else{
/* All files across all check-ins */
if( zD ){
db_multi_exec(
"INSERT OR IGNORE INTO localfiles"
" SELECT pathelement(name,%d), NULL FROM filename"
" WHERE name GLOB '%q/*'",
nD, zD
);
}else{
db_multi_exec(
"INSERT OR IGNORE INTO localfiles"
" SELECT pathelement(name,0), NULL FROM filename"
);
}
}
/* If the re=REGEXP query parameter is present, filter out names that
** do not match the pattern */
if( zRegexp ){
db_multi_exec(
"DELETE FROM localfiles WHERE x NOT REGEXP %Q", zRegexp
|
| ︙ | ︙ | |||
340 341 342 343 344 345 346 |
const char *zFN;
zFN = db_column_text(&q, 0);
if( zFN[0]=='/' ){
zFN++;
@ <li class="dir">%z(href("%s%T",zSubdirLink,zFN))%h(zFN)</a></li>
}else{
const char *zLink;
| > > | | 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 |
const char *zFN;
zFN = db_column_text(&q, 0);
if( zFN[0]=='/' ){
zFN++;
@ <li class="dir">%z(href("%s%T",zSubdirLink,zFN))%h(zFN)</a></li>
}else{
const char *zLink;
if( bDocDir ){
zLink = href("%R/doc/%T/%T%T", zCI, zPrefix, zFN);
}else if( zCI ){
zLink = href("%R/file?name=%T%T&ci=%T",zPrefix,zFN,zCI);
}else{
zLink = href("%R/finfo?name=%T%T",zPrefix,zFN);
}
@ <li class="%z(fileext_class(zFN))">%z(zLink)%h(zFN)</a></li>
}
}
|
| ︙ | ︙ | |||
439 440 441 442 443 444 445 446 447 448 449 450 451 452 | FileTreeNode *pSibling; /* Next element in the same subdirectory */ FileTreeNode *pChild; /* List of child nodes */ FileTreeNode *pLastChild; /* Last child on the pChild list */ char *zName; /* Name of this entry. The "tail" */ char *zFullName; /* Full pathname of this entry */ char *zUuid; /* Artifact hash of this file. May be NULL. */ double mtime; /* Modification time for this entry */ unsigned nFullName; /* Length of zFullName */ unsigned iLevel; /* Levels of parent directories */ }; /* ** A complete file hierarchy */ | > > | 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 | FileTreeNode *pSibling; /* Next element in the same subdirectory */ FileTreeNode *pChild; /* List of child nodes */ FileTreeNode *pLastChild; /* Last child on the pChild list */ char *zName; /* Name of this entry. The "tail" */ char *zFullName; /* Full pathname of this entry */ char *zUuid; /* Artifact hash of this file. May be NULL. */ double mtime; /* Modification time for this entry */ double sortBy; /* Either mtime or size, depending on desired sort order */ int iSize; /* Size for this entry */ unsigned nFullName; /* Length of zFullName */ unsigned iLevel; /* Levels of parent directories */ }; /* ** A complete file hierarchy */ |
| ︙ | ︙ | |||
468 469 470 471 472 473 474 | ** a common directory prefix must be added consecutively in order for ** the tree to be constructed properly. */ static void tree_add_node( FileTree *pTree, /* Tree into which nodes are added */ const char *zPath, /* The full pathname of file to add */ const char *zUuid, /* Hash of the file. Might be NULL. */ | | > > | | 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 |
** a common directory prefix must be added consecutively in order for
** the tree to be constructed properly.
*/
static void tree_add_node(
FileTree *pTree, /* Tree into which nodes are added */
const char *zPath, /* The full pathname of file to add */
const char *zUuid, /* Hash of the file. Might be NULL. */
double mtime, /* Modification time for this entry */
int size, /* Size for this entry */
int sortOrder /* 0: filename, 1: mtime, 2: size */
){
int i;
FileTreeNode *pParent; /* Parent (directory) of the next node to insert */
/* Make pParent point to the most recent ancestor of zPath, or
** NULL if there are no prior entires that are a container for zPath.
*/
pParent = pTree->pLast;
while( pParent!=0 &&
( strncmp(pParent->zFullName, zPath, pParent->nFullName)!=0
|| zPath[pParent->nFullName]!='/' )
|
| ︙ | ︙ | |||
522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 |
pNew->iLevel = pParent->iLevel + 1;
pParent->pLastChild = pNew;
}else{
if( pTree->pLastTop ) pTree->pLastTop->pSibling = pNew;
pTree->pLastTop = pNew;
}
pNew->mtime = mtime;
while( zPath[i]=='/' ){ i++; }
pParent = pNew;
}
while( pParent && pParent->pParent ){
if( pParent->pParent->mtime < pParent->mtime ){
pParent->pParent->mtime = pParent->mtime;
}
pParent = pParent->pParent;
}
}
/* Comparison function for two FileTreeNode objects. Sort first by
| > > > > > > | > > > | | | 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 |
pNew->iLevel = pParent->iLevel + 1;
pParent->pLastChild = pNew;
}else{
if( pTree->pLastTop ) pTree->pLastTop->pSibling = pNew;
pTree->pLastTop = pNew;
}
pNew->mtime = mtime;
pNew->iSize = size;
if( sortOrder ){
pNew->sortBy = sortOrder==1 ? mtime : (double)size;
}else{
pNew->sortBy = 0.0;
}
while( zPath[i]=='/' ){ i++; }
pParent = pNew;
}
while( pParent && pParent->pParent ){
if( pParent->pParent->mtime < pParent->mtime ){
pParent->pParent->mtime = pParent->mtime;
}
pParent = pParent->pParent;
}
}
/* Comparison function for two FileTreeNode objects. Sort first by
** sortBy (larger numbers first) and then by zName (smaller names first).
**
** The sortBy field will be the same as mtime in order to sort by time,
** or the same as iSize to sort by file size.
**
** Return negative if pLeft<pRight.
** Return positive if pLeft>pRight.
** Return zero if pLeft==pRight.
*/
static int compareNodes(FileTreeNode *pLeft, FileTreeNode *pRight){
if( pLeft->sortBy>pRight->sortBy ) return -1;
if( pLeft->sortBy<pRight->sortBy ) return +1;
return fossil_stricmp(pLeft->zName, pRight->zName);
}
/* Merge together two sorted lists of FileTreeNode objects */
static FileTreeNode *mergeNodes(FileTreeNode *pLeft, FileTreeNode *pRight){
FileTreeNode *pEnd;
FileTreeNode base;
|
| ︙ | ︙ | |||
568 569 570 571 572 573 574 |
pEnd->pSibling = pLeft;
}else{
pEnd->pSibling = pRight;
}
return base.pSibling;
}
| | | | 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 |
pEnd->pSibling = pLeft;
}else{
pEnd->pSibling = pRight;
}
return base.pSibling;
}
/* Sort a list of FileTreeNode objects in sortmtime order. */
static FileTreeNode *sortNodes(FileTreeNode *p){
FileTreeNode *a[30];
FileTreeNode *pX;
int i;
memset(a, 0, sizeof(a));
while( p ){
pX = p;
|
| ︙ | ︙ | |||
601 602 603 604 605 606 607 | ** This routine invalidates the following fields: ** ** FileTreeNode.pLastChild ** FileTreeNode.pNext ** ** Use relinkTree to reconnect the pNext pointers. */ | | | | | 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 |
** This routine invalidates the following fields:
**
** FileTreeNode.pLastChild
** FileTreeNode.pNext
**
** Use relinkTree to reconnect the pNext pointers.
*/
static FileTreeNode *sortTree(FileTreeNode *p){
FileTreeNode *pX;
for(pX=p; pX; pX=pX->pSibling){
if( pX->pChild ) pX->pChild = sortTree(pX->pChild);
}
return sortNodes(p);
}
/* Reconstruct the FileTree by reconnecting the FileTreeNode.pNext
** fields in sequential order.
*/
static void relinkTree(FileTree *pTree, FileTreeNode *pRoot){
while( pRoot ){
|
| ︙ | ︙ | |||
645 646 647 648 649 650 651 | ** ** type=tree Required to prevent use of /dir format ** name=PATH Directory to display. Optional ** ci=LABEL Show only files in this check-in. Optional. ** re=REGEXP Show only files matching REGEXP. Optional. ** expand Begin with the tree fully expanded. ** nofiles Show directories (folders) only. Omit files. | | | | 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 |
**
** type=tree Required to prevent use of /dir format
** name=PATH Directory to display. Optional
** ci=LABEL Show only files in this check-in. Optional.
** re=REGEXP Show only files matching REGEXP. Optional.
** expand Begin with the tree fully expanded.
** nofiles Show directories (folders) only. Omit files.
** sort 0: by filename, 1: by mtime, 2: by size
*/
void page_tree(void){
char *zD = fossil_strdup(P("name"));
int nD = zD ? strlen(zD)+1 : 0;
const char *zCI = P("ci");
int rid = 0;
char *zUuid = 0;
Blob dirname;
Manifest *pM = 0;
double rNow = 0;
char *zNow = 0;
int useMtime = atoi(PD("mtime","0"));
int sortOrder = atoi(PD("sort",useMtime?"1":"0"));
int linkTrunk = 1; /* include link to "trunk" */
int linkTip = 1; /* include link to "tip" */
const char *zRE; /* the value for the re=REGEXP query parameter */
const char *zObjType; /* "files" by default or "folders" for "nofiles" */
char *zREx = ""; /* Extra parameters for path hyperlinks */
ReCompiled *pRE = 0; /* Compiled regular expression */
FileTreeNode *p; /* One line of the tree */
|
| ︙ | ︙ | |||
704 705 706 707 708 709 710 711 712 713 714 715 716 717 |
/* If a regular expression is specified, compile it */
zRE = P("re");
if( zRE ){
re_compile(&pRE, zRE, 0);
zREx = mprintf("&re=%T", zRE);
}
/* If the name= parameter is an empty string, make it a NULL pointer */
if( zD && strlen(zD)==0 ){ zD = 0; }
/* If a specific check-in is requested, fetch and parse it. If the
** specific check-in does not exist, clear zCI. zCI==0 will cause all
** files from all check-ins to be displayed.
| > | 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 |
/* If a regular expression is specified, compile it */
zRE = P("re");
if( zRE ){
re_compile(&pRE, zRE, 0);
zREx = mprintf("&re=%T", zRE);
}
cgi_check_for_malice();
/* If the name= parameter is an empty string, make it a NULL pointer */
if( zD && strlen(zD)==0 ){ zD = 0; }
/* If a specific check-in is requested, fetch and parse it. If the
** specific check-in does not exist, clear zCI. zCI==0 will cause all
** files from all check-ins to be displayed.
|
| ︙ | ︙ | |||
745 746 747 748 749 750 751 |
}else{
zHeader = mprintf("All Top-level Files");
}
}else{
if( zCI ){
zHeader = mprintf("Files in %s/ of %s", zD, zCI);
}else{
| | > > | > > > > > | 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 |
}else{
zHeader = mprintf("All Top-level Files");
}
}else{
if( zCI ){
zHeader = mprintf("Files in %s/ of %s", zD, zCI);
}else{
zHeader = mprintf("All Files in %s/", zD);
}
}
style_header("%s", zHeader);
fossil_free(zHeader);
/* Compute the title of the page */
blob_zero(&dirname);
if( zD ){
blob_append(&dirname, "within directory ", -1);
hyperlinked_path(zD, &dirname, zCI, "tree", zREx, 0);
if( zRE ) blob_appendf(&dirname, " matching \"%s\"", zRE);
style_submenu_element("Top-Level", "%s",
url_render(&sURI, "name", 0, 0, 0));
}else if( zRE ){
blob_appendf(&dirname, "matching \"%s\"", zRE);
}
{
static const char *const sort_orders[] = {
"0", "Sort By Filename",
"1", "Sort By Age",
"2", "Sort By Size"
};
style_submenu_multichoice("sort", 3, sort_orders, 0);
}
if( zCI ){
style_submenu_element("All", "%s", url_render(&sURI, "ci", 0, 0, 0));
if( nD==0 && !showDirOnly ){
style_submenu_element("File Ages", "%R/fileage?name=%T", zCI);
}
}
if( linkTrunk ){
|
| ︙ | ︙ | |||
785 786 787 788 789 790 791 |
/* Compute the file hierarchy.
*/
if( zCI ){
Stmt q;
compute_fileage(rid, 0);
db_prepare(&q,
| | > | | < > > | | < < < < | 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 |
/* Compute the file hierarchy.
*/
if( zCI ){
Stmt q;
compute_fileage(rid, 0);
db_prepare(&q,
"SELECT filename.name, blob.uuid, blob.size, fileage.mtime\n"
" FROM fileage, filename, blob\n"
" WHERE filename.fnid=fileage.fnid\n"
" AND blob.rid=fileage.fid\n"
" ORDER BY filename.name COLLATE uintnocase;"
);
while( db_step(&q)==SQLITE_ROW ){
const char *zFile = db_column_text(&q,0);
const char *zUuid = db_column_text(&q,1);
int size = db_column_int(&q,2);
double mtime = db_column_double(&q,3);
if( nD>0 && (fossil_strncmp(zFile, zD, nD-1)!=0 || zFile[nD-1]!='/') ){
continue;
}
if( pRE && re_match(pRE, (const unsigned char*)zFile, -1)==0 ) continue;
tree_add_node(&sTree, zFile, zUuid, mtime, size, sortOrder);
}
db_finalize(&q);
}else{
Stmt q;
db_prepare(&q,
"SELECT\n"
" (SELECT name FROM filename WHERE filename.fnid=mlink.fnid),\n"
" (SELECT uuid FROM blob WHERE blob.rid=mlink.fid),\n"
" (SELECT size FROM blob WHERE blob.rid=mlink.fid),\n"
" max(event.mtime)\n"
" FROM mlink JOIN event ON event.objid=mlink.mid\n"
" GROUP BY mlink.fnid\n"
" ORDER BY 1 COLLATE uintnocase;");
while( db_step(&q)==SQLITE_ROW ){
const char *zName = db_column_text(&q, 0);
const char *zUuid = db_column_text(&q,1);
int size = db_column_int(&q,2);
double mtime = db_column_double(&q,3);
if( nD>0 && (fossil_strncmp(zName, zD, nD-1)!=0 || zName[nD-1]!='/') ){
continue;
}
if( pRE && re_match(pRE, (const u8*)zName, -1)==0 ) continue;
tree_add_node(&sTree, zName, zUuid, mtime, size, sortOrder);
}
db_finalize(&q);
}
style_submenu_checkbox("nofiles", "Folders Only", 0, 0);
if( showDirOnly ){
zObjType = "Folders";
}else{
zObjType = "Files";
}
if( zCI && strcmp(zCI,"tip")==0 ){
@ <h2>%s(zObjType) in the %z(href("%R/info?name=tip"))latest check-in</a>
|
| ︙ | ︙ | |||
855 856 857 858 859 860 861 |
if( blob_size(&dirname) ){
@ and %s(blob_str(&dirname))
}
}else{
int n = db_int(0, "SELECT count(*) FROM plink");
@ <h2>%s(zObjType) from all %d(n) check-ins %s(blob_str(&dirname))
}
| | > > | 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 |
if( blob_size(&dirname) ){
@ and %s(blob_str(&dirname))
}
}else{
int n = db_int(0, "SELECT count(*) FROM plink");
@ <h2>%s(zObjType) from all %d(n) check-ins %s(blob_str(&dirname))
}
if( sortOrder==1 ){
@ sorted by modification time</h2>
}else if( sortOrder==2 ){
@ sorted by size</h2>
}else{
@ sorted by filename</h2>
}
if( zNow ){
@ <p>File ages are expressed relative to the check-in time of
@ %z(href("%R/timeline?c=%t",zNow))%s(zNow)</a>.</p>
|
| ︙ | ︙ | |||
886 887 888 889 890 891 892 |
@ <li class="dir last">
}else{
@ <li class="dir subdir last">
}
@ <div class="filetreeline">
@ %z(href("%s",url_render(&sURI,"name",0,0,0)))%h(zProjectName)</a>
if( zNow ){
| | > | | | > | > | 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 |
@ <li class="dir last">
}else{
@ <li class="dir subdir last">
}
@ <div class="filetreeline">
@ %z(href("%s",url_render(&sURI,"name",0,0,0)))%h(zProjectName)</a>
if( zNow ){
@ <div class="filetreeage">Last Change</div>
@ <div class="filetreesize">Size</div>
}
@ </div>
@ <ul>
if( sortOrder ){
p = sortTree(sTree.pFirst);
memset(&sTree, 0, sizeof(sTree));
relinkTree(&sTree, p);
}
for(p=sTree.pFirst, nDir=0; p; p=p->pNext){
const char *zLastClass = p->pSibling==0 ? " last" : "";
if( p->pChild ){
const char *zSubdirClass = (int)(p->nFullName)==nD-1 ? " subdir" : "";
@ <li class="dir%s(zSubdirClass)%s(zLastClass)"><div class="filetreeline">
@ %z(href("%s",url_render(&sURI,"name",p->zFullName,0,0)))%h(p->zName)</a>
if( p->mtime>0.0 ){
char *zAge = human_readable_age(rNow - p->mtime);
@ <div class="filetreeage">%s(zAge)</div>
@ <div class="filetreesize"></div>
}
@ </div>
if( startExpanded || (int)(p->nFullName)<=nD ){
@ <ul id="dir%d(nDir)">
}else{
@ <ul id="dir%d(nDir)" class="collapsed">
}
nDir++;
}else if( !showDirOnly ){
const char *zFileClass = fileext_class(p->zName);
char *zLink;
if( zCI ){
zLink = href("%R/file?name=%T&ci=%T",p->zFullName,zCI);
}else{
zLink = href("%R/finfo?name=%T",p->zFullName);
}
@ <li class="%z(zFileClass)%s(zLastClass)"><div class="filetreeline">
@ %z(zLink)%h(p->zName)</a>
if( p->mtime>0 ){
char *zAge = human_readable_age(rNow - p->mtime);
@ <div class="filetreeage">%s(zAge)</div>
@ <div class="filetreesize">%s(p->iSize ? mprintf("%,d",p->iSize) : "-")</div>
}
@ </div>
}
if( p->pSibling==0 ){
int nClose = p->iLevel - (p->pNext ? p->pNext->iLevel : 0);
while( nClose-- > 0 ){
@ </ul>
|
| ︙ | ︙ | |||
1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 |
isBranchCI = branch_includes_uuid(zName,zUuid);
baseTime = db_double(0.0,"SELECT mtime FROM event WHERE objid=%d", rid);
zNow = db_text("", "SELECT datetime(mtime,toLocal()) FROM event"
" WHERE objid=%d", rid);
style_submenu_element("Tree-View", "%R/tree?ci=%T&mtime=1&type=tree", zName);
style_header("File Ages");
zGlob = P("glob");
compute_fileage(rid,zGlob);
db_multi_exec("CREATE INDEX fileage_ix1 ON fileage(mid,pathname);");
if( fossil_strcmp(zName,"tip")==0 ){
@ <h1>Files in the %z(href("%R/info?name=tip"))latest check-in</a>
}else if( isBranchCI ){
@ <h1>Files in the %z(href("%R/info?name=%T",zName))latest check-in</a>
| > | 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 |
isBranchCI = branch_includes_uuid(zName,zUuid);
baseTime = db_double(0.0,"SELECT mtime FROM event WHERE objid=%d", rid);
zNow = db_text("", "SELECT datetime(mtime,toLocal()) FROM event"
" WHERE objid=%d", rid);
style_submenu_element("Tree-View", "%R/tree?ci=%T&mtime=1&type=tree", zName);
style_header("File Ages");
zGlob = P("glob");
cgi_check_for_malice();
compute_fileage(rid,zGlob);
db_multi_exec("CREATE INDEX fileage_ix1 ON fileage(mid,pathname);");
if( fossil_strcmp(zName,"tip")==0 ){
@ <h1>Files in the %z(href("%R/info?name=tip"))latest check-in</a>
}else if( isBranchCI ){
@ <h1>Files in the %z(href("%R/info?name=%T",zName))latest check-in</a>
|
| ︙ | ︙ | |||
1168 1169 1170 1171 1172 1173 1174 |
@ <td>
db_bind_int(&q2, ":mid", mid);
while( db_step(&q2)==SQLITE_ROW ){
const char *zFile = db_column_text(&q2,0);
@ %z(href("%R/file?name=%T&ci=%!S",zFile,zUuid))%h(zFile)</a> \
if( showId ){
int fid = db_column_int(&q2,1);
| | | | 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 |
@ <td>
db_bind_int(&q2, ":mid", mid);
while( db_step(&q2)==SQLITE_ROW ){
const char *zFile = db_column_text(&q2,0);
@ %z(href("%R/file?name=%T&ci=%!S",zFile,zUuid))%h(zFile)</a> \
if( showId ){
int fid = db_column_int(&q2,1);
@ (%d(fid))<br>
}else{
@ </a><br>
}
}
db_reset(&q2);
@ </td>
@ <td>
@ %W(zComment)
@ (check-in: %z(href("%R/info/%!S",zUuid))%S(zUuid)</a>,
|
| ︙ | ︙ | |||
1193 1194 1195 1196 1197 1198 1199 |
fossil_free(zAge);
}
@ </table></div>
db_finalize(&q1);
db_finalize(&q2);
style_finish_page();
}
| > > > > > > > > > > > > > > > > > | 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 |
fossil_free(zAge);
}
@ </table></div>
db_finalize(&q1);
db_finalize(&q2);
style_finish_page();
}
/*
** WEBPAGE: files
**
** Show files as a flat table. If the ci=LABEL query parameter is provided,
** then show all the files in the specified check-in. Without the ci= query
** parameter show all files across all check-ins.
**
** Query parameters:
**
** name=PATH Directory to display. Optional
** ci=LABEL Show only files in this check-in. Optional.
** re=REGEXP Show only files matching REGEXP. Optional.
*/
void files_page(void){
return;
}
|
Changes to src/builtin.c.
| ︙ | ︙ | |||
482 483 484 485 486 487 488 |
*/
static int builtinVtabColumn(
sqlite3_vtab_cursor *cur, /* The cursor */
sqlite3_context *ctx, /* First argument to sqlite3_result_...() */
int i /* Which column to return */
){
builtinVtab_cursor *pCur = (builtinVtab_cursor*)cur;
| | | 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 |
*/
static int builtinVtabColumn(
sqlite3_vtab_cursor *cur, /* The cursor */
sqlite3_context *ctx, /* First argument to sqlite3_result_...() */
int i /* Which column to return */
){
builtinVtab_cursor *pCur = (builtinVtab_cursor*)cur;
const struct BuiltinFileTable *pFile = aBuiltinFiles + pCur->iRowid - 1;
switch( i ){
case 0: /* name */
sqlite3_result_text(ctx, pFile->zName, -1, SQLITE_STATIC);
break;
case 1: /* size */
sqlite3_result_int(ctx, pFile->nByte);
break;
|
| ︙ | ︙ | |||
513 514 515 516 517 518 519 |
/*
** Return TRUE if the cursor has been moved off of the last
** row of output.
*/
static int builtinVtabEof(sqlite3_vtab_cursor *cur){
builtinVtab_cursor *pCur = (builtinVtab_cursor*)cur;
| | | 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 |
/*
** Return TRUE if the cursor has been moved off of the last
** row of output.
*/
static int builtinVtabEof(sqlite3_vtab_cursor *cur){
builtinVtab_cursor *pCur = (builtinVtab_cursor*)cur;
return pCur->iRowid>count(aBuiltinFiles);
}
/*
** This method is called to "rewind" the builtinVtab_cursor object back
** to the first row of output. This method is always called at least
** once prior to any call to builtinVtabColumn() or builtinVtabRowid() or
** builtinVtabEof().
|
| ︙ | ︙ | |||
575 576 577 578 579 580 581 | /* xCommit */ 0, /* xRollback */ 0, /* xFindMethod */ 0, /* xRename */ 0, /* xSavepoint */ 0, /* xRelease */ 0, /* xRollbackTo */ 0, | | > | 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 |
/* xCommit */ 0,
/* xRollback */ 0,
/* xFindMethod */ 0,
/* xRename */ 0,
/* xSavepoint */ 0,
/* xRelease */ 0,
/* xRollbackTo */ 0,
/* xShadowName */ 0,
/* xIntegrity */ 0
};
/*
** Register the builtin virtual table
*/
int builtin_vtab_register(sqlite3 *db){
|
| ︙ | ︙ | |||
664 665 666 667 668 669 670 |
CX("};\n"/* fossil.config */);
CX("window.fossil.user = {");
CX("name: %!j,", (g.zLogin&&*g.zLogin) ? g.zLogin : "guest");
CX("isAdmin: %s", (g.perm.Admin || g.perm.Setup) ? "true" : "false");
CX("};\n"/*fossil.user*/);
CX("if(fossil.config.skin.isDark) "
"document.body.classList.add('fossil-dark-style');\n");
| < < < < < < < < | 665 666 667 668 669 670 671 672 673 674 675 676 677 678 |
CX("};\n"/* fossil.config */);
CX("window.fossil.user = {");
CX("name: %!j,", (g.zLogin&&*g.zLogin) ? g.zLogin : "guest");
CX("isAdmin: %s", (g.perm.Admin || g.perm.Setup) ? "true" : "false");
CX("};\n"/*fossil.user*/);
CX("if(fossil.config.skin.isDark) "
"document.body.classList.add('fossil-dark-style');\n");
/*
** fossil.page holds info about the current page. This is also
** where the current page "should" store any of its own
** page-specific state, and it is reserved for that purpose.
*/
CX("window.fossil.page = {"
"name:\"%T\""
|
| ︙ | ︙ |
Changes to src/bundle.c.
| ︙ | ︙ | |||
112 113 114 115 116 117 118 |
fossil_print("%s: %s\n", db_column_text(&q,0), db_column_text(&q,1));
}
db_finalize(&q);
fossil_print("%.78c\n",'-');
if( bDetails ){
db_prepare(&q,
"SELECT blobid, substr(uuid,1,10), coalesce(substr(delta,1,10),''),"
| | | 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 |
fossil_print("%s: %s\n", db_column_text(&q,0), db_column_text(&q,1));
}
db_finalize(&q);
fossil_print("%.78c\n",'-');
if( bDetails ){
db_prepare(&q,
"SELECT blobid, substr(uuid,1,10), coalesce(substr(delta,1,10),''),"
" sz, octet_length(data), notes"
" FROM bblob"
);
while( db_step(&q)==SQLITE_ROW ){
fossil_print("%4d %10s %10s %8d %8d %s\n",
db_column_int(&q,0),
db_column_text(&q,1),
db_column_text(&q,2),
|
| ︙ | ︙ | |||
589 590 591 592 593 594 595 |
/* If the bundle contains deltas with a basis that is external to the
** bundle and those external basis files are missing from the local
** repo, then the delta encodings cannot be decoded and the bundle cannot
** be extracted. */
zMissingDeltas = db_text(0,
"SELECT group_concat(substr(delta,1,10),' ')"
" FROM bblob"
| | | 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 |
/* If the bundle contains deltas with a basis that is external to the
** bundle and those external basis files are missing from the local
** repo, then the delta encodings cannot be decoded and the bundle cannot
** be extracted. */
zMissingDeltas = db_text(0,
"SELECT group_concat(substr(delta,1,10),' ')"
" FROM bblob"
" WHERE typeof(delta)='text' AND octet_length(delta)>=%d"
" AND NOT EXISTS(SELECT 1 FROM blob WHERE uuid=bblob.delta)",
HNAME_MIN);
if( zMissingDeltas && zMissingDeltas[0] ){
fossil_fatal("delta basis artifacts not found in repository: %s",
zMissingDeltas);
}
|
| ︙ | ︙ |
Changes to src/cache.c.
| ︙ | ︙ | |||
421 422 423 424 425 426 427 |
" ORDER BY (tm + 3600*min(nRef,48)) DESC"
);
if( pStmt ){
@ <ol>
while( sqlite3_step(pStmt)==SQLITE_ROW ){
const unsigned char *zName = sqlite3_column_text(pStmt,0);
char *zHash = cache_hash_of_key((const char*)zName);
| | | 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 |
" ORDER BY (tm + 3600*min(nRef,48)) DESC"
);
if( pStmt ){
@ <ol>
while( sqlite3_step(pStmt)==SQLITE_ROW ){
const unsigned char *zName = sqlite3_column_text(pStmt,0);
char *zHash = cache_hash_of_key((const char*)zName);
@ <li><p>%z(href("%R/cacheget?key=%T",zName))%h(zName)</a><br>
@ size: %,lld(sqlite3_column_int64(pStmt,1))
@ hit-count: %d(sqlite3_column_int(pStmt,2))
@ last-access: %s(sqlite3_column_text(pStmt,3)) \
if( zHash ){
@ %z(href("%R/timeline?c=%S",zHash))check-in</a>\
fossil_free(zHash);
}
|
| ︙ | ︙ |
Changes to src/capabilities.c.
| ︙ | ︙ | |||
321 322 323 324 325 326 327 |
static int done = 0;
Stmt q;
if( done ) return;
db_prepare(&q, "SELECT fullcap(cap) FROM user");
while( db_step(&q)==SQLITE_ROW ){
const char *zCap = db_column_text(&q, 0);
if( zCap==0 || zCap[0]==0 ) continue;
| | | | 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 |
static int done = 0;
Stmt q;
if( done ) return;
db_prepare(&q, "SELECT fullcap(cap) FROM user");
while( db_step(&q)==SQLITE_ROW ){
const char *zCap = db_column_text(&q, 0);
if( zCap==0 || zCap[0]==0 ) continue;
for(i=0; i<(int)(sizeof(aCap)/sizeof(aCap[0])); i++){
if( strchr(zCap, aCap[i].cCap) ) aCap[i].nUser++;
}
}
db_finalize(&q);
done = 1;
}
/*
** Generate HTML that lists all of the capability letters together with
** a brief summary of what each letter means.
*/
void capabilities_table(unsigned mClass){
int i;
if( g.perm.Admin ) capabilities_count();
@ <table>
@ <tbody>
for(i=0; i<(int)(sizeof(aCap)/sizeof(aCap[0])); i++){
int n;
if( (aCap[i].eClass & mClass)==0 ) continue;
@ <tr><th valign="top">%c(aCap[i].cCap)</th>
@ <td>%h(aCap[i].zAbbrev)</td><td>%h(aCap[i].zOneLiner)</td>\
n = aCap[i].nUser;
if( n && g.perm.Admin ){
@ <td><a href="%R/setup_ulist?with=%c(aCap[i].cCap)">\
|
| ︙ | ︙ | |||
385 386 387 388 389 390 391 |
" SELECT 'Public Pages', %Q, 100, %d"
" UNION ALL"
" SELECT 'New User Default', %Q, 110, 1"
" UNION ALL"
" SELECT 'Regular User', fullcap(capunion(cap)), 200, count(*) FROM user"
" WHERE cap NOT GLOB '*[as]*' AND login NOT IN (SELECT id FROM t)"
" UNION ALL"
| | | 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 |
" SELECT 'Public Pages', %Q, 100, %d"
" UNION ALL"
" SELECT 'New User Default', %Q, 110, 1"
" UNION ALL"
" SELECT 'Regular User', fullcap(capunion(cap)), 200, count(*) FROM user"
" WHERE cap NOT GLOB '*[as]*' AND login NOT IN (SELECT id FROM t)"
" UNION ALL"
" SELECT 'Administrator', fullcap(capunion(cap)), 300, count(*) FROM user"
" WHERE cap GLOB '*[as]*'"
" ORDER BY 3 ASC",
zSelfCap, hasPubPages, zSelfCap
);
@ <table id='capabilitySummary' cellpadding="0" cellspacing="0" border="1">
@ <tr><th> <th>Code<th>Forum<th>Tickets<th>Wiki<th>Chat\
@ <th>Unversioned Content</th></tr>
|
| ︙ | ︙ |
Changes to src/captcha.c.
| ︙ | ︙ | |||
542 543 544 545 546 547 548 | uSeed = captcha_seed(); zDecoded = captcha_decode(uSeed); zCaptcha = captcha_render(zDecoded); @ <div class="captcha"><table class="captcha"><tr><td><pre class="captcha"> @ %h(zCaptcha) @ </pre> @ Enter security code shown above: | | | | 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 |
uSeed = captcha_seed();
zDecoded = captcha_decode(uSeed);
zCaptcha = captcha_render(zDecoded);
@ <div class="captcha"><table class="captcha"><tr><td><pre class="captcha">
@ %h(zCaptcha)
@ </pre>
@ Enter security code shown above:
@ <input type="hidden" name="captchaseed" value="%u(uSeed)">
@ <input type="text" name="captcha" size=8>
if( showButton ){
@ <input type="submit" value="Submit">
}
@ <br/>\
captcha_speakit_button(uSeed, 0);
@ </td></tr></table></div>
}
|
| ︙ | ︙ | |||
683 684 685 686 687 688 689 |
/*
** WEBPAGE: /captcha-audio
**
** Return a WAV file that pronounces the digits of the captcha that
** is determined by the seed given in the name= query parameter.
*/
void captcha_wav_page(void){
| | | 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 |
/*
** WEBPAGE: /captcha-audio
**
** Return a WAV file that pronounces the digits of the captcha that
** is determined by the seed given in the name= query parameter.
*/
void captcha_wav_page(void){
const char *zSeed = PD("name","0");
const char *zDecode = captcha_decode((unsigned int)atoi(zSeed));
Blob audio;
captcha_wav(zDecode, &audio);
cgi_set_content_type("audio/wav");
cgi_set_content(&audio);
}
|
| ︙ | ︙ |
Changes to src/cgi.c.
| ︙ | ︙ | |||
92 93 94 95 96 97 98 |
#if INTERFACE
/*
** Shortcuts for cgi_parameter. P("x") returns the value of query parameter
** or cookie "x", or NULL if there is no such parameter or cookie. PD("x","y")
** does the same except "y" is returned in place of NULL if there is not match.
*/
| | | | | | | | > > | 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 |
#if INTERFACE
/*
** Shortcuts for cgi_parameter. P("x") returns the value of query parameter
** or cookie "x", or NULL if there is no such parameter or cookie. PD("x","y")
** does the same except "y" is returned in place of NULL if there is not match.
*/
#define P(x) cgi_parameter((x),0)
#define PD(x,y) cgi_parameter((x),(y))
#define PT(x) cgi_parameter_trimmed((x),0)
#define PDT(x,y) cgi_parameter_trimmed((x),(y))
#define PB(x) cgi_parameter_boolean(x)
#define PCK(x) cgi_parameter_checked(x,1)
#define PIF(x,y) cgi_parameter_checked(x,y)
#define P_NoBot(x) cgi_parameter_nosql((x),0)
#define PD_NoBot(x,y) cgi_parameter_nosql((x),(y))
/*
** Shortcut for the cgi_printf() routine. Instead of using the
**
** @ ...
**
** notation provided by the translate.c utility, you can also
|
| ︙ | ︙ | |||
310 311 312 313 314 315 316 |
if( zPath[0]==0 ) zPath = "/";
}
if( g.zBaseURL!=0 && fossil_strncmp(g.zBaseURL, "https:", 6)==0 ){
zSecure = " secure;";
}
if( lifetime!=0 ){
blob_appendf(&extraHeader,
| | < | < | 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 |
if( zPath[0]==0 ) zPath = "/";
}
if( g.zBaseURL!=0 && fossil_strncmp(g.zBaseURL, "https:", 6)==0 ){
zSecure = " secure;";
}
if( lifetime!=0 ){
blob_appendf(&extraHeader,
"Set-Cookie: %s=%t; Path=%s; max-age=%d; HttpOnly; %s\r\n",
zName, lifetime>0 ? zValue : "null", zPath, lifetime, zSecure);
}else{
blob_appendf(&extraHeader,
"Set-Cookie: %s=%t; Path=%s; HttpOnly; %s\r\n",
zName, zValue, zPath, zSecure);
}
}
/*
** Return true if the response should be sent with Content-Encoding: gzip.
|
| ︙ | ︙ | |||
493 494 495 496 497 498 499 |
blob_appendf(&hdr, "Date: %s\r\n", cgi_rfc822_datestamp(time(0)));
blob_appendf(&hdr, "Connection: close\r\n");
blob_appendf(&hdr, "X-UA-Compatible: IE=edge\r\n");
}else{
assert( rangeEnd==0 );
blob_appendf(&hdr, "Status: %d %s\r\n", iReplyStatus, zReplyStatus);
}
| | > > > > > > | < < < | 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 |
blob_appendf(&hdr, "Date: %s\r\n", cgi_rfc822_datestamp(time(0)));
blob_appendf(&hdr, "Connection: close\r\n");
blob_appendf(&hdr, "X-UA-Compatible: IE=edge\r\n");
}else{
assert( rangeEnd==0 );
blob_appendf(&hdr, "Status: %d %s\r\n", iReplyStatus, zReplyStatus);
}
if( etag_tag()[0]!=0
&& iReplyStatus==200
&& strcmp(zContentType,"text/html")!=0
){
/* Do not cache HTML replies as those will have been generated and
** will likely, therefore, contains a nonce and we want that nonce to
** be different every time. */
blob_appendf(&hdr, "ETag: %s\r\n", etag_tag());
blob_appendf(&hdr, "Cache-Control: max-age=%d\r\n", etag_maxage());
if( etag_mtime()>0 ){
blob_appendf(&hdr, "Last-Modified: %s\r\n",
cgi_rfc822_datestamp(etag_mtime()));
}
}else if( g.isConst ){
/* isConst means that the reply is guaranteed to be invariant, even
** after configuration changes and/or Fossil binary recompiles. */
blob_appendf(&hdr, "Cache-Control: max-age=315360000, immutable\r\n");
}else{
blob_appendf(&hdr, "Cache-control: no-cache\r\n");
}
if( blob_size(&extraHeader)>0 ){
blob_appendf(&hdr, "%s", blob_buffer(&extraHeader));
}
/* Add headers to turn on useful security options in browsers. */
blob_appendf(&hdr, "X-Frame-Options: SAMEORIGIN\r\n");
/* The previous stops fossil pages appearing in frames or iframes, preventing
** click-jacking attacks on supporting browsers.
**
** Other good headers would be
** Strict-Transport-Security: max-age=62208000
** if we're using https. However, this would break sites which serve different
** content on http and https protocols. Also,
** X-Content-Security-Policy: allow 'self'
** would help mitigate some XSS and data injection attacks, but will break
** deliberate inclusion of external resources, such as JavaScript syntax
** highlighter scripts.
**
** These headers are probably best added by the web server hosting fossil as
** a CGI script.
*/
if( iReplyStatus!=304 ) {
blob_appendf(&hdr, "Content-Type: %s%s\r\n", zContentType,
content_type_charset(zContentType));
if( fossil_strcmp(zContentType,"application/x-fossil")==0 ){
cgi_combine_header_and_body();
blob_compress(&cgiContent[0], &cgiContent[0]);
}
|
| ︙ | ︙ | |||
677 678 679 680 681 682 683 684 685 |
const char *zRef = P("referer");
if( zRef==0 ){
zRef = P("HTTP_REFERER");
if( zRef==0 ) zRef = zDefault;
}
return zRef;
}
/*
| > | < < < < < | | | < | | < < > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 |
const char *zRef = P("referer");
if( zRef==0 ){
zRef = P("HTTP_REFERER");
if( zRef==0 ) zRef = zDefault;
}
return zRef;
}
/*
** Return true if the current request is coming from the same origin.
*/
int cgi_same_origin(void){
const char *zRef;
int nBase;
if( g.zBaseURL==0 ) return 0;
zRef = P("HTTP_REFERER");
if( zRef==0 ) return 0;
nBase = (int)strlen(g.zBaseURL);
if( fossil_strncmp(g.zBaseURL,zRef,nBase)!=0 ) return 0;
if( zRef[nBase]!=0 && zRef[nBase]!='/' ) return 0;
return 1;
}
/*
** Return true if the current CGI request is a POST request
*/
static int cgi_is_post_request(void){
const char *zMethod = P("REQUEST_METHOD");
if( zMethod==0 ) return 0;
if( strcmp(zMethod,"POST")!=0 ) return 0;
return 1;
}
/*
** Return true if the current request appears to be safe from a
** Cross-Site Request Forgery (CSRF) attack. The level of checking
** is determined by the parameter. The higher the number, the more
** secure we are:
**
** 0: Request must come from the same origin
** 1: Same origin and must be a POST request
** 2: All of the above plus must have a valid CSRF token
**
** Results are cached in the g.okCsrf variable. The g.okCsrf value
** has meaning as follows:
**
** -1: Not a secure request
** 0: Status unknown
** 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() ){
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;
}
}
}
}
return g.okCsrf >= (securityLevel+1);
}
/*
** Verify that CSRF defenses are maximal - that the request comes from
** the same origin, that it is a POST request, and that there is a valid
** "csrf" token. If this is not the case, fail immediately.
*/
void cgi_csrf_verify(void){
if( !cgi_csrf_safe(2) ){
fossil_fatal("Cross-site Request Forgery detected");
}
}
/*
** Information about all query parameters, post parameter, cookies and
** CGI environment variables are stored in a hash table as follows:
*/
static int nAllocQP = 0; /* Space allocated for aParamQP[] */
static int nUsedQP = 0; /* Space actually used in aParamQP[] */
static int sortQP = 0; /* True if aParamQP[] needs sorting */
static int seqQP = 0; /* Sequence numbers */
static struct QParam { /* One entry for each query parameter or cookie */
const char *zName; /* Parameter or cookie name */
const char *zValue; /* Value of the query parameter or cookie */
int seq; /* Order of insertion */
char isQP; /* True for query parameters */
char cTag; /* Tag on query parameters */
char isFetched; /* 1 if the var is requested via P/PD() */
} *aParamQP; /* An array of all parameters and cookies */
/*
** Add another query parameter or cookie to the parameter set.
** zName is the name of the query parameter or cookie and zValue
** is its fully decoded value.
**
|
| ︙ | ︙ | |||
742 743 744 745 746 747 748 749 750 751 752 753 754 755 |
aParamQP[nUsedQP].zValue = zValue;
if( g.fHttpTrace ){
fprintf(stderr, "# cgi: %s = [%s]\n", zName, zValue);
}
aParamQP[nUsedQP].seq = seqQP++;
aParamQP[nUsedQP].isQP = isQP;
aParamQP[nUsedQP].cTag = 0;
nUsedQP++;
sortQP = 1;
}
/*
** Add another query parameter or cookie to the parameter set.
** zName is the name of the query parameter or cookie and zValue
| > | 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 |
aParamQP[nUsedQP].zValue = zValue;
if( g.fHttpTrace ){
fprintf(stderr, "# cgi: %s = [%s]\n", zName, zValue);
}
aParamQP[nUsedQP].seq = seqQP++;
aParamQP[nUsedQP].isQP = isQP;
aParamQP[nUsedQP].cTag = 0;
aParamQP[nUsedQP].isFetched = 0;
nUsedQP++;
sortQP = 1;
}
/*
** Add another query parameter or cookie to the parameter set.
** zName is the name of the query parameter or cookie and zValue
|
| ︙ | ︙ | |||
1197 1198 1199 1200 1201 1202 1203 |
int rc = 0;
char * z = (char*)P("QUERY_STRING");
if( z ){
++rc;
z = fossil_strdup(z);
add_param_list(z, '&');
z = (char*)P("skin");
| | | > > > > | 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 |
int rc = 0;
char * z = (char*)P("QUERY_STRING");
if( z ){
++rc;
z = fossil_strdup(z);
add_param_list(z, '&');
z = (char*)P("skin");
if( z ){
char *zErr = skin_use_alternative(z, 2);
++rc;
if( !zErr && P("once")==0 ){
cookie_write_parameter("skin","skin",z);
/* Per /chat discussion, passing ?skin=... without "once"
** implies the "udc" argument, so we force that into the
** environment here. */
cgi_set_parameter_nocopy("udc", "1", 1);
}
fossil_free(zErr);
}
}
return rc;
}
|
| ︙ | ︙ | |||
1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 |
lo = 0;
hi = nUsedQP-1;
while( lo<=hi ){
mid = (lo+hi)/2;
c = fossil_strcmp(aParamQP[mid].zName, zName);
if( c==0 ){
CGIDEBUG(("mem-match [%s] = [%s]\n", zName, aParamQP[mid].zValue));
return aParamQP[mid].zValue;
}else if( c>0 ){
hi = mid-1;
}else{
lo = mid+1;
}
}
| > | 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 |
lo = 0;
hi = nUsedQP-1;
while( lo<=hi ){
mid = (lo+hi)/2;
c = fossil_strcmp(aParamQP[mid].zName, zName);
if( c==0 ){
CGIDEBUG(("mem-match [%s] = [%s]\n", zName, aParamQP[mid].zValue));
aParamQP[mid].isFetched = 1;
return aParamQP[mid].zValue;
}else if( c>0 ){
hi = mid-1;
}else{
lo = mid+1;
}
}
|
| ︙ | ︙ | |||
1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 |
CGIDEBUG(("env-match [%s] = [%s]\n", zName, zValue));
return zValue;
}
}
CGIDEBUG(("no-match [%s]\n", zName));
return zDefault;
}
/*
** Return the value of the first defined query parameter or cookie whose
** name appears in the list of arguments. Or if no parameter is found,
** return NULL.
*/
const char *cgi_coalesce(const char *zName, ...){
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 |
CGIDEBUG(("env-match [%s] = [%s]\n", zName, zValue));
return zValue;
}
}
CGIDEBUG(("no-match [%s]\n", zName));
return zDefault;
}
/*
** Renders the "begone, spider" page and exits.
*/
static void cgi_begone_spider(const char *zName){
Blob content = empty_blob;
cgi_set_content(&content);
style_set_current_feature("test");
style_submenu_enable(0);
style_header("Malicious Query Detected");
@ <h2>Begone, Knave!</h2>
@ <p>This page was generated because Fossil detected an (unsuccessful)
@ SQL injection attack or other nefarious content in your HTTP request.
@
@ <p>If you believe you are innocent and have reached this page in error,
@ contact the Fossil developers on the Fossil-SCM Forum. Type
@ "fossil-scm forum" into any search engine to locate the Fossil-SCM Forum.
style_finish_page();
cgi_set_status(418,"I'm a teapot");
cgi_reply();
fossil_errorlog("Xpossible hack attempt - 418 response on \"%s\"", zName);
exit(0);
}
/*
** If looks_like_sql_injection() returns true for the given string, calls
** cgi_begone_spider() and does not return, else this function has no
** side effects. The range of checks performed by this function may
** be extended in the future.
**
** Checks are omitted for any logged-in user.
**
** This is NOT a defense against SQL injection. Fossil should easily be
** proof against SQL injection without this routine. Rather, this is an
** attempt to avoid denial-of-service caused by persistent spiders that hammer
** the server with dozens or hundreds of SQL injection attempts per second
** against pages (such as /vdiff) that are expensive to compute. In other
** words, this is an effort to reduce the CPU load imposed by malicious
** spiders. It is not an effect defense against SQL injection vulnerabilities.
*/
void cgi_value_spider_check(const char *zTxt, const char *zName){
if( g.zLogin==0 && looks_like_sql_injection(zTxt) ){
cgi_begone_spider(zName);
}
}
/*
** A variant of cgi_parameter() with the same semantics except that if
** cgi_parameter(zName,zDefault) returns a value other than zDefault
** then it passes that value to cgi_value_spider_check().
*/
const char *cgi_parameter_nosql(const char *zName, const char *zDefault){
const char *zTxt = cgi_parameter(zName, zDefault);
if( zTxt!=zDefault ){
cgi_value_spider_check(zTxt, zName);
}
return zTxt;
}
/*
** Return the value of the first defined query parameter or cookie whose
** name appears in the list of arguments. Or if no parameter is found,
** return NULL.
*/
const char *cgi_coalesce(const char *zName, ...){
|
| ︙ | ︙ | |||
1659 1660 1661 1662 1663 1664 1665 | ** This is used for testing and debugging. ** ** Omit the values of the cookies unless showAll is true. ** ** The eDest parameter determines where the output is shown: ** ** eDest==0: Rendering as HTML into the CGI reply | | > | | | | > > > | | | | > > > > > > > > | 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 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 |
** This is used for testing and debugging.
**
** Omit the values of the cookies unless showAll is true.
**
** The eDest parameter determines where the output is shown:
**
** eDest==0: Rendering as HTML into the CGI reply
** eDest==1: Written to fossil_trace
** eDest==2: Written to cgi_debug
** eDest==3: Written to out (Used only by fossil_errorlog())
*/
void cgi_print_all(int showAll, unsigned int eDest, FILE *out){
int i;
cgi_parameter("",""); /* Force the parameters into sorted order */
for(i=0; i<nUsedQP; i++){
const char *zName = aParamQP[i].zName;
const char *zValue = aParamQP[i].zValue;
if( fossil_stricmp("HTTP_COOKIE",zName)==0
|| fossil_strnicmp("fossil-",zName,7)==0
){
if( !showAll ) continue;
if( eDest==3 ) zValue = "...";
}
switch( eDest ){
case 0: {
cgi_printf("%h = %h <br>\n", zName, zValue);
break;
}
case 1: {
fossil_trace("%s = %s\n", zName, zValue);
break;
}
case 2: {
cgi_debug("%s = %s\n", zName, zValue);
break;
}
case 3: {
if( strlen(zValue)>100 ){
fprintf(out,"%s = %.100s...\n", zName, zValue);
}else{
fprintf(out,"%s = %s\n", zName, zValue);
}
break;
}
}
}
}
/*
|
| ︙ | ︙ | |||
1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 |
cgi_setenv("HTTP_IF_MODIFIED_SINCE", zVal);
}else if( fossil_strcmp(zFieldName,"referer:")==0 ){
cgi_setenv("HTTP_REFERER", zVal);
}else if( fossil_strcmp(zFieldName,"user-agent:")==0 ){
cgi_setenv("HTTP_USER_AGENT", zVal);
}else if( fossil_strcmp(zFieldName,"authorization:")==0 ){
cgi_setenv("HTTP_AUTHORIZATION", zVal);
}else if( fossil_strcmp(zFieldName,"x-forwarded-for:")==0 ){
const char *zIpAddr = cgi_accept_forwarded_for(zVal);
if( zIpAddr!=0 ){
g.zIpAddr = fossil_strdup(zIpAddr);
cgi_replace_parameter("REMOTE_ADDR", g.zIpAddr);
}
}else if( fossil_strcmp(zFieldName,"range:")==0 ){
| > > | 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 |
cgi_setenv("HTTP_IF_MODIFIED_SINCE", zVal);
}else if( fossil_strcmp(zFieldName,"referer:")==0 ){
cgi_setenv("HTTP_REFERER", zVal);
}else if( fossil_strcmp(zFieldName,"user-agent:")==0 ){
cgi_setenv("HTTP_USER_AGENT", zVal);
}else if( fossil_strcmp(zFieldName,"authorization:")==0 ){
cgi_setenv("HTTP_AUTHORIZATION", zVal);
}else if( fossil_strcmp(zFieldName,"accept-language:")==0 ){
cgi_setenv("HTTP_ACCEPT_LANGUAGE", zVal);
}else if( fossil_strcmp(zFieldName,"x-forwarded-for:")==0 ){
const char *zIpAddr = cgi_accept_forwarded_for(zVal);
if( zIpAddr!=0 ){
g.zIpAddr = fossil_strdup(zIpAddr);
cgi_replace_parameter("REMOTE_ADDR", g.zIpAddr);
}
}else if( fossil_strcmp(zFieldName,"range:")==0 ){
|
| ︙ | ︙ | |||
2326 2327 2328 2329 2330 2331 2332 |
int iPort = mnPort;
while( iPort<=mxPort ){
memset(&inaddr, 0, sizeof(inaddr));
inaddr.sin_family = AF_INET;
if( zIpAddr ){
inaddr.sin_addr.s_addr = inet_addr(zIpAddr);
| | | 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 |
int iPort = mnPort;
while( iPort<=mxPort ){
memset(&inaddr, 0, sizeof(inaddr));
inaddr.sin_family = AF_INET;
if( zIpAddr ){
inaddr.sin_addr.s_addr = inet_addr(zIpAddr);
if( inaddr.sin_addr.s_addr == INADDR_NONE ){
fossil_fatal("not a valid IP address: %s", zIpAddr);
}
}else if( flags & HTTP_SERVER_LOCALHOST ){
inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
}else{
inaddr.sin_addr.s_addr = htonl(INADDR_ANY);
}
|
| ︙ | ︙ | |||
2608 2609 2610 2611 2612 2613 2614 |
*/
int cgi_from_mobile(void){
const char *zAgent = P("HTTP_USER_AGENT");
if( zAgent==0 ) return 0;
if( sqlite3_strglob("*iPad*", zAgent)==0 ) return 0;
return sqlite3_strlike("%mobile%", zAgent, 0)==0;
}
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 |
*/
int cgi_from_mobile(void){
const char *zAgent = P("HTTP_USER_AGENT");
if( zAgent==0 ) return 0;
if( sqlite3_strglob("*iPad*", zAgent)==0 ) return 0;
return sqlite3_strlike("%mobile%", zAgent, 0)==0;
}
/*
** Look for query or POST parameters that:
**
** (1) Have not been used
** (2) Appear to be malicious attempts to break into or otherwise
** harm the system, for example via SQL injection
**
** If any such parameters are seen, a 418 ("I'm a teapot") return is
** generated and processing aborts - this routine does not return.
**
** When Fossil is launched via CGI from althttpd, the 418 return signals
** the webserver to put the requestor IP address into "timeout", blocking
** subsequent requests for 5 minutes.
**
** Fossil is not subject to any SQL injections, as far as anybody knows.
** This routine is not necessary for the security of the system (though
** an extra layer of security never hurts). The main purpose here is
** to shutdown malicious attack spiders and prevent them from burning
** lots of CPU cycles and bogging down the website. In other words, the
** objective of this routine is to help prevent denial-of-service.
**
** Usage Hint: Put a call to this routine as late in the webpage
** implementation as possible, ideally just before it begins doing
** potentially CPU-intensive computations and after all query parameters
** have been consulted.
*/
void cgi_check_for_malice(void){
struct QParam * pParam;
int i;
for(i = 0; i < nUsedQP; ++i){
pParam = &aParamQP[i];
if(0 == pParam->isFetched
&& fossil_islower(pParam->zName[0])){
cgi_value_spider_check(pParam->zValue, pParam->zName);
}
}
}
|
Changes to src/chat.c.
| ︙ | ︙ | |||
133 134 135 136 137 138 139 | ** SETTING: chat-timeline-user width=10 ** ** If this setting is defined and is not an empty string, then ** timeline events are posted to the chat as they arrive. The synthesized ** chat messages appear to come from the user identified by this setting, ** not the user on the timeline event. ** | | | | > | 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 | ** SETTING: chat-timeline-user width=10 ** ** If this setting is defined and is not an empty string, then ** timeline events are posted to the chat as they arrive. The synthesized ** chat messages appear to come from the user identified by this setting, ** not the user on the timeline event. ** ** All chat messages that come from the chat-timeline-user are ** interpreted as text/x-fossil-wiki instead of as text/x-markdown. ** For this reason, the chat-timeline-user name should probably not be ** a real user. */ /* ** WEBPAGE: chat loadavg-exempt ** ** Start up a browser-based chat session. ** ** This is the main page that humans use to access the chatroom. Simply |
| ︙ | ︙ | |||
390 391 392 393 394 395 396 397 398 399 400 401 402 403 |
return;
}
chat_create_tables();
zUserName = (g.zLogin && g.zLogin[0]) ? g.zLogin : "nobody";
nByte = atoi(PD("file:bytes","0"));
zMsg = PD("msg","");
db_begin_write();
chat_purge();
if( nByte==0 ){
if( zMsg[0] ){
db_multi_exec(
"INSERT INTO chat(mtime,lmtime,xfrom,xmsg)"
"VALUES(julianday('now'),%Q,%Q,%Q)",
P("lmtime"), zUserName, zMsg
| > | 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 |
return;
}
chat_create_tables();
zUserName = (g.zLogin && g.zLogin[0]) ? g.zLogin : "nobody";
nByte = atoi(PD("file:bytes","0"));
zMsg = PD("msg","");
db_begin_write();
db_unprotect(PROTECT_READONLY);
chat_purge();
if( nByte==0 ){
if( zMsg[0] ){
db_multi_exec(
"INSERT INTO chat(mtime,lmtime,xfrom,xmsg)"
"VALUES(julianday('now'),%Q,%Q,%Q)",
P("lmtime"), zUserName, zMsg
|
| ︙ | ︙ | |||
413 414 415 416 417 418 419 420 421 422 423 |
PD("file:mimetype","application/octet-stream"));
blob_init(&b, P("file"), nByte);
db_bind_blob(&q, ":file", &b);
db_step(&q);
db_finalize(&q);
blob_reset(&b);
}
db_commit_transaction();
}
/*
| > | | | | | | 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 |
PD("file:mimetype","application/octet-stream"));
blob_init(&b, P("file"), nByte);
db_bind_blob(&q, ":file", &b);
db_step(&q);
db_finalize(&q);
blob_reset(&b);
}
db_protect_pop();
db_commit_transaction();
}
/*
** This routine receives raw (user-entered) message text and
** transforms it into HTML that is safe to insert using innerHTML. As
** of 2021-09-19, it does so by using wiki_convert() or
** markdown_to_html() to convert wiki/markdown-formatted zMsg to HTML.
**
** Space to hold the returned string is obtained from fossil_malloc()
** and must be freed by the caller.
*/
static char *chat_format_to_html(const char *zMsg, int isWiki){
Blob out;
blob_init(&out, "", 0);
if( zMsg==0 || zMsg[0]==0 ){
/* No-op */
}else if( isWiki ){
/* Used for chat-timeline-user. The zMsg is text/x-fossil-wiki. */
Blob bIn;
blob_init(&bIn, zMsg, (int)strlen(zMsg));
wiki_convert(&bIn, &out, WIKI_INLINE);
}else{
/* The common case: zMsg is text/x-markdown */
Blob bIn;
blob_init(&bIn, zMsg, (int)strlen(zMsg));
markdown_to_html(&bIn, NULL, &out);
}
return blob_str(&out);
}
|
| ︙ | ︙ | |||
583 584 585 586 587 588 589 |
return;
}
zChatUser = db_get("chat-timeline-user",0);
chat_create_tables();
cgi_set_content_type("application/json");
dataVersion = db_int64(0, "PRAGMA data_version");
blob_append_sql(&sql,
| | | 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 |
return;
}
zChatUser = db_get("chat-timeline-user",0);
chat_create_tables();
cgi_set_content_type("application/json");
dataVersion = db_int64(0, "PRAGMA data_version");
blob_append_sql(&sql,
"SELECT msgid, datetime(mtime), xfrom, xmsg, octet_length(file),"
" fname, fmime, %s, lmtime"
" FROM chat ",
msgBefore>0 ? "0 as mdel" : "mdel");
if( msgid<=0 || msgBefore>0 ){
db_begin_write();
chat_purge();
db_commit_transaction();
|
| ︙ | ︙ | |||
722 723 724 725 726 727 728 |
chat_emit_permissions_error(0);
return;
}
zChatUser = db_get("chat-timeline-user",0);
chat_create_tables();
cgi_set_content_type("application/json");
db_prepare(&q,
| | | 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 |
chat_emit_permissions_error(0);
return;
}
zChatUser = db_get("chat-timeline-user",0);
chat_create_tables();
cgi_set_content_type("application/json");
db_prepare(&q,
"SELECT datetime(mtime), xfrom, xmsg, octet_length(file),"
" fname, fmime, lmtime"
" FROM chat WHERE msgid=%d AND mdel IS NULL",
msgid);
if(SQLITE_ROW==db_step(&q)){
const char *zDate = db_column_text(&q, 0);
const char *zFrom = db_column_text(&q, 1);
const char *zRawMsg = db_column_text(&q, 2);
|
| ︙ | ︙ | |||
779 780 781 782 783 784 785 | /* ** WEBPAGE: chat-download hidden loadavg-exempt ** ** Download the CHAT.FILE attachment associated with a single chat ** entry. The "name" query parameter begins with an integer that ** identifies the particular chat message. The integer may be followed | | | > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 |
/*
** WEBPAGE: chat-download hidden loadavg-exempt
**
** Download the CHAT.FILE attachment associated with a single chat
** entry. The "name" query parameter begins with an integer that
** identifies the particular chat message. The integer may be followed
** by a / and a filename, which will (A) indicate to the browser to
** use the indicated name when saving the file and (B) be used to
** guess the mimetype in some particular cases involving the "render"
** flag.
**
** If the "render" URL parameter is provided, the blob has a size
** greater than zero, and blob meets one of the following conditions
** then the fossil-rendered form of that content is returned, rather
** than the original:
**
** - Mimetype is text/x-markdown or text/markdown: emit HTML.
**
** - Mimetype is text/x-fossil-wiki or P("name") ends with ".wiki":
** emit HTML.
**
** - Mimetype is text/x-pikchr or P("name") ends with ".pikchr": emit
** image/svg+xml if rendering succeeds or text/html if rendering
** fails.
*/
void chat_download_webpage(void){
int msgid;
Blob r;
const char *zMime;
const char *zName = PD("name","0");
login_check_credentials();
if( !g.perm.Chat ){
style_header("Chat Not Authorized");
@ <h1>Not Authorized</h1>
@ <p>You do not have permission to use the chatroom on this
@ repository.</p>
style_finish_page();
return;
}
chat_create_tables();
msgid = atoi(zName);
blob_zero(&r);
zMime = db_text(0, "SELECT fmime FROM chat wHERE msgid=%d", msgid);
if( zMime==0 ) return;
db_blob(&r, "SELECT file FROM chat WHERE msgid=%d", msgid);
if( r.nUsed>0 && P("render")!=0 ){
/* Maybe return fossil-rendered form of the content. */
Blob r2 = BLOB_INITIALIZER; /* output target for rendering */
const char * zMime2 = 0; /* adjusted response mimetype */
if(fossil_strcmp(zMime, "text/x-markdown")==0
/* Firefox uploads md files with the mimetype text/markdown */
|| fossil_strcmp(zMime, "text/markdown")==0){
markdown_to_html(&r, 0, &r2);
safe_html(&r2);
zMime2 = "text/html";
}else if(fossil_strcmp(zMime, "text/x-fossil-wiki")==0
|| sqlite3_strglob("*.wiki", zName)==0){
/* .wiki files get uploaded as application/octet-stream */
wiki_convert(&r, &r2, 0);
zMime2 = "text/html";
}else if(fossil_strcmp(zMime, "text/x-pikchr")==0
|| sqlite3_strglob("*.pikchr",zName)==0){
/* .pikchr files get uploaded as application/octet-stream */
const char *zPikchr = blob_str(&r);
int w = 0, h = 0;
char *zOut = pikchr(zPikchr, "pikchr", 0, &w, &h);
if(zOut){
blob_append(&r2, zOut, -1);
}
zMime2 = w>0 ? "image/svg+xml" : "text/html";
free(zOut);
}
if(r2.aData!=0){
blob_swap(&r, &r2);
blob_reset(&r2);
zMime = zMime2;
}
}
cgi_set_content_type(zMime);
cgi_set_content(&r);
}
/*
** WEBPAGE: chat-delete hidden loadavg-exempt
|
| ︙ | ︙ | |||
985 986 987 988 989 990 991 | ** > fossil chat pull ** ** Copy chat content from the server down into the local clone, ** as a backup or archive. Setup privilege is required on the server. ** ** --all Download all chat content. Normally only ** previously undownloaded content is retrieved. | | | 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 | ** > fossil chat pull ** ** Copy chat content from the server down into the local clone, ** as a backup or archive. Setup privilege is required on the server. ** ** --all Download all chat content. Normally only ** previously undownloaded content is retrieved. ** --debug Additional debugging output ** --out DATABASE Store CHAT table in separate database file ** DATABASE rather that adding to local clone ** --unsafe Allow the use of unencrypted http:// ** ** > fossil chat send [ARGUMENTS] ** ** This command sends a new message to the chatroom. The message |
| ︙ | ︙ |
Changes to src/checkin.c.
| ︙ | ︙ | |||
59 60 61 62 63 64 65 | }; /* ** Create a TEMP table named SFILE and add all unmanaged files named on ** the command-line to that table. If directories are named, then add ** all unmanaged files contained underneath those directories. If there ** are no files or directories named on the command-line, then add all | | | 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | }; /* ** Create a TEMP table named SFILE and add all unmanaged files named on ** the command-line to that table. If directories are named, then add ** all unmanaged files contained underneath those directories. If there ** are no files or directories named on the command-line, then add all ** unmanaged files anywhere in the check-out. ** ** This routine never follows symlinks. It always treats symlinks as ** object unto themselves. */ static void locate_unmanaged_files( int argc, /* Number of command-line arguments to examine */ char **argv, /* values of command-line arguments */ |
| ︙ | ︙ | |||
119 120 121 122 123 124 125 |
*/
static void status_report(
Blob *report, /* Append the status report here */
unsigned flags /* Filter and other configuration flags */
){
Stmt q;
int nErr = 0;
| | | 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 |
*/
static void status_report(
Blob *report, /* Append the status report here */
unsigned flags /* Filter and other configuration flags */
){
Stmt q;
int nErr = 0;
Blob rewrittenOrigName, rewrittenPathname;
Blob sql = BLOB_INITIALIZER, where = BLOB_INITIALIZER;
const char *zName;
int i;
/* Skip the file report if no files are requested at all. */
if( !(flags & (C_ALL | C_EXTRA)) ){
goto skipFiles;
|
| ︙ | ︙ | |||
196 197 198 199 200 201 202 |
db_multi_exec("CREATE TEMP TABLE IF NOT EXISTS ok(rid INTEGER PRIMARY KEY)");
/* Append an ORDER BY clause then compile the query. */
blob_append_sql(&sql, " ORDER BY pathname");
db_prepare(&q, "%s", blob_sql_text(&sql));
blob_reset(&sql);
| | > | 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 |
db_multi_exec("CREATE TEMP TABLE IF NOT EXISTS ok(rid INTEGER PRIMARY KEY)");
/* Append an ORDER BY clause then compile the query. */
blob_append_sql(&sql, " ORDER BY pathname");
db_prepare(&q, "%s", blob_sql_text(&sql));
blob_reset(&sql);
/* Bind the check-out version ID to the query if needed. */
if( (flags & C_ALL) && (flags & C_MTIME) ){
db_bind_int(&q, ":vid", db_lget_int("checkout", 0));
}
/* Execute the query and assemble the report. */
blob_zero(&rewrittenPathname);
blob_zero(&rewrittenOrigName);
while( db_step(&q)==SQLITE_ROW ){
const char *zPathname = db_column_text(&q, 0);
const char *zClass = 0;
int isManaged = db_column_int(&q, 7);
const char *zMtime = db_column_text(&q, 1);
int size = db_column_int(&q, 2);
int isDeleted = db_column_int(&q, 3);
|
| ︙ | ︙ | |||
266 267 268 269 270 271 272 |
zClass = "UNLINK";
}else if( (flags & C_CONFLICT) && isChnged && !file_islink(zFullName)
&& file_contains_merge_marker(zFullName) ){
zClass = "CONFLICT";
}else if( (flags & (C_EDITED | C_CHANGED)) && isChnged
&& (isChnged<2 || isChnged>9) ){
zClass = "EDITED";
| < < < > > > > > > < | | | > > | < | > > | < < > > > | | > | 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 |
zClass = "UNLINK";
}else if( (flags & C_CONFLICT) && isChnged && !file_islink(zFullName)
&& file_contains_merge_marker(zFullName) ){
zClass = "CONFLICT";
}else if( (flags & (C_EDITED | C_CHANGED)) && isChnged
&& (isChnged<2 || isChnged>9) ){
zClass = "EDITED";
}else if( (flags & C_UNCHANGED) && isManaged && !isNew
&& !isChnged && !isRenamed ){
zClass = "UNCHANGED";
}else if( (flags & C_EXTRA) && !isManaged ){
zClass = "EXTRA";
}
if( (flags & C_RENAMED) && isRenamed ){
zOrigName = db_column_text(&q,8);
if( zClass==0 ){
zClass = "RENAMED";
}
}
/* Only report files for which a change classification was determined. */
if( zClass ){
if( flags & C_COMMENT ){
blob_append(report, "# ", 2);
}
if( flags & C_CLASSIFY ){
blob_appendf(report, "%-10s ", zClass);
}
if( flags & C_MTIME ){
blob_append(report, zMtime, -1);
blob_append(report, " ", 2);
}
if( flags & C_SIZE ){
blob_appendf(report, "%7d ", size);
}
if( flags & C_RELPATH ){
/* If C_RELPATH, display paths relative to current directory. */
file_relative_name(zFullName, &rewrittenPathname, 0);
zPathname = blob_str(&rewrittenPathname);
if( zPathname[0]=='.' && zPathname[1]=='/' ){
zPathname += 2; /* no unnecessary ./ prefix */
}
if( (flags & (C_FILTER ^ C_RENAMED)) && zOrigName ){
char *zOrigFullName = mprintf("%s%s", g.zLocalRoot, zOrigName);
file_relative_name(zOrigFullName, &rewrittenOrigName, 0);
zOrigName = blob_str(&rewrittenOrigName);
fossil_free(zOrigFullName);
if( zOrigName[0]=='.' && zOrigName[1]=='/' ){
zOrigName += 2; /* no unnecessary ./ prefix */
}
}
}
if( (flags & (C_FILTER ^ C_RENAMED)) && zOrigName ){
blob_appendf(report, "%s -> ", zOrigName);
}
blob_appendf(report, "%s\n", zPathname);
}
free(zFullName);
}
blob_reset(&rewrittenPathname);
blob_reset(&rewrittenOrigName);
db_finalize(&q);
/* If C_MERGE, put merge contributors at the end of the report. */
skipFiles:
if( flags & C_MERGE ){
db_prepare(&q, "SELECT mhash, id FROM vmerge WHERE id<=0" );
while( db_step(&q)==SQLITE_ROW ){
|
| ︙ | ︙ | |||
365 366 367 368 369 370 371 | /* ** COMMAND: changes ** COMMAND: status ** ** Usage: %fossil changes|status ?OPTIONS? ?PATHS ...? ** | | | | 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 | /* ** COMMAND: changes ** COMMAND: status ** ** Usage: %fossil changes|status ?OPTIONS? ?PATHS ...? ** ** Report the change status of files in the current check-out. If one or ** more PATHS are specified, only changes among the named files and ** directories are reported. Directories are searched recursively. ** ** The status command is similar to the changes command, except it lacks ** several of the options supported by changes and it has its own header ** and footer information. The header information is a subset of that ** shown by the info command, and the footer shows if there are any forks. ** Change type classification is always enabled for the status command. ** ** Each line of output is the name of a changed file, with paths shown ** according to the "relative-paths" setting, unless overridden by the ** --abs-paths or --rel-paths options. ** ** By default, all changed files are selected for display. This behavior ** can be overridden by using one or more filter options (listed below), ** in which case only files with the specified change type(s) are shown. ** As a special case, the --no-merge option does not inhibit this default. ** This default shows exactly the set of changes that would be checked- ** in by the commit command. ** ** If no filter options are used, or if the --merge option is used, the ** artifact hash of each merge contributor check-in version is displayed at ** the end of the report. The --no-merge option is useful to display the ** default set of changed files without the merge contributors. ** |
| ︙ | ︙ | |||
407 408 409 410 411 412 413 | ** change type classification is UPDATED_BY_MERGE or UPDATED_BY_INTEGRATE. ** If the file had to be merged with any other changes, it is considered ** to be merged or conflicted and therefore will be shown by --edited, not ** --updated, with types EDITED or CONFLICT. The --changed option can be ** used to display the union of --edited and --updated. ** ** --differ is so named because it lists all the differences between the | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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 |
** change type classification is UPDATED_BY_MERGE or UPDATED_BY_INTEGRATE.
** If the file had to be merged with any other changes, it is considered
** to be merged or conflicted and therefore will be shown by --edited, not
** --updated, with types EDITED or CONFLICT. The --changed option can be
** used to display the union of --edited and --updated.
**
** --differ is so named because it lists all the differences between the
** checked-out version and the check-out directory. In addition to the
** default changes (excluding --merge), it lists extra files which (if
** ignore-glob is set correctly) may be worth adding. Prior to doing a
** commit, it is good practice to check --differ to see not only which
** changes would be committed but also if any files should be added.
**
** If both --merge and --no-merge are used, --no-merge has priority. The
** same is true of --classify and --no-classify.
**
** The "fossil changes --extra" command is equivalent to "fossil extras".
**
** General options:
** --abs-paths Display absolute pathnames
** --rel-paths Display pathnames relative to the current working
** directory
** --hash Verify file status using hashing rather than
** relying on file mtimes
** --case-sensitive BOOL Override case-sensitive setting
** --dotfiles Include unmanaged files beginning with a dot
** --ignore <CSG> Ignore unmanaged files matching CSG glob patterns
**
** Options specific to the changes command:
** --header Identify the repository if report is non-empty
** -v|--verbose Say "(none)" if the change report is empty
** --classify Start each line with the file's change type
** --no-classify Do not print file change types
**
** Filter options:
** --edited Display edited, merged, and conflicted files
** --updated Display files updated by merge/integrate
** --changed Combination of the above two options
** --missing Display missing files
** --added Display added files
** --deleted Display deleted files
** --renamed Display renamed files
** --conflict Display files having merge conflicts
** --meta Display files with metadata changes
** --unchanged Display unchanged files
** --all Display all managed files, i.e. all of the above
** --extra Display unmanaged files
** --differ Display modified and extra files
** --merge Display merge contributors
** --no-merge Do not display merge contributors
**
** See also: [[extras]], [[ls]]
*/
void status_cmd(void){
/* Affirmative and negative flag option tables. */
static const struct {
const char *option; /* Flag name. */
|
| ︙ | ︙ | |||
515 516 517 518 519 520 521 |
for( i=0; i<count(noFlagDefs); ++i ){
if( (command==CHANGES || !(noFlagDefs[i].mask & C_CLASSIFY))
&& find_option(noFlagDefs[i].option, 0, 0) ){
flags &= ~noFlagDefs[i].mask;
}
}
| | | | 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 |
for( i=0; i<count(noFlagDefs); ++i ){
if( (command==CHANGES || !(noFlagDefs[i].mask & C_CLASSIFY))
&& find_option(noFlagDefs[i].option, 0, 0) ){
flags &= ~noFlagDefs[i].mask;
}
}
/* Confirm current working directory is within check-out. */
db_must_be_within_tree();
/* Get check-out version. l*/
vid = db_lget_int("checkout", 0);
/* Relative path flag determination is done by a shared function. */
if( determine_cwd_relative_option() ){
flags |= C_RELPATH;
}
|
| ︙ | ︙ | |||
660 661 662 663 664 665 666 | } /* ** COMMAND: ls ** ** Usage: %fossil ls ?OPTIONS? ?PATHS ...? ** | | | | | | | | | 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 |
}
/*
** COMMAND: ls
**
** Usage: %fossil ls ?OPTIONS? ?PATHS ...?
**
** List all files in the current check-out. If PATHS is included, only the
** named files (or their children if directories) are shown.
**
** The ls command is essentially two related commands in one, depending on
** whether or not the -r option is given. -r selects a specific check-in
** version to list, in which case -R can be used to select the repository.
** The fine behavior of the --age, -v, and -t options is altered by the -r
** option as well, as explained below.
**
** The --age option displays file commit times. Like -r, --age has the
** side effect of making -t sort by commit time, not modification time.
**
** The -v option provides extra information about each file. Without -r,
** -v displays the change status, in the manner of the changes command.
** With -r, -v shows the commit time and size of the checked-in files.
**
** The -t option changes the sort order. Without -t, files are sorted by
** path and name (case insensitive sort if -r). If neither --age nor -r
** are used, -t sorts by modification time, otherwise by commit time.
**
** Options:
** --age Show when each file was committed
** -v|--verbose Provide extra information about each file
** -t Sort output in time order
** -r VERSION The specific check-in to list
** -R|--repository REPO Extract info from repository REPO
** --hash With -v, verify file status using hashing
** rather than relying on file sizes and mtimes
**
** See also: [[changes]], [[extras]], [[status]]
*/
void ls_cmd(void){
int vid;
Stmt q;
int verboseFlag;
|
| ︙ | ︙ | |||
825 826 827 828 829 830 831 | /* ** COMMAND: extras ** ** Usage: %fossil extras ?OPTIONS? ?PATH1 ...? ** ** Print a list of all files in the source tree that are not part of the | | | 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 | /* ** COMMAND: extras ** ** Usage: %fossil extras ?OPTIONS? ?PATH1 ...? ** ** Print a list of all files in the source tree that are not part of the ** current check-out. See also the "clean" command. If paths are specified, ** only files in the given directories will be listed. ** ** Files and subdirectories whose names begin with "." are normally ** ignored but can be included by adding the --dotfiles option. ** ** Files whose names match any of the glob patterns in the "ignore-glob" ** setting are ignored. This setting can be overridden by the --ignore |
| ︙ | ︙ | |||
894 895 896 897 898 899 900 | /* ** COMMAND: clean ** ** Usage: %fossil clean ?OPTIONS? ?PATH ...? ** ** Delete all "extra" files in the source tree. "Extra" files are files | | | 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 | /* ** COMMAND: clean ** ** Usage: %fossil clean ?OPTIONS? ?PATH ...? ** ** Delete all "extra" files in the source tree. "Extra" files are files ** that are not officially part of the check-out. If one or more PATH ** arguments appear, then only the files named, or files contained with ** directories named, will be removed. ** ** If the --prompt option is used, prompts are issued to confirm the ** permanent removal of each file. Otherwise, files are backed up to the ** undo buffer prior to removal, and prompts are issued only for files ** whose removal cannot be undone due to their large size or due to |
| ︙ | ︙ | |||
923 924 925 926 927 928 929 | ** ** The --verily option ignores the keep-glob and ignore-glob settings and ** turns on --force, --emptydirs, --dotfiles, and --disable-undo. Use the ** --verily option when you really want to clean up everything. Extreme ** care should be exercised when using the --verily option. ** ** Options: | | | 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 | ** ** The --verily option ignores the keep-glob and ignore-glob settings and ** turns on --force, --emptydirs, --dotfiles, and --disable-undo. Use the ** --verily option when you really want to clean up everything. Extreme ** care should be exercised when using the --verily option. ** ** Options: ** --allckouts Check for empty directories within any check-outs ** that may be nested within the current one. This ** option should be used with great care because the ** empty-dirs setting (and other applicable settings) ** belonging to the other repositories, if any, will ** not be checked. ** --case-sensitive BOOL Override case-sensitive setting ** --dirsonly Only remove empty directories. No files will |
| ︙ | ︙ | |||
1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 |
"#\n%.78c\n"
"# The following diff is excluded from the commit message:\n#\n",
'#'
);
diff_options(&DCfg, 0, 1);
DCfg.diffFlags |= DIFF_VERBOSE;
if( g.aCommitFile ){
FileDirList *diffFiles;
int i;
for(i=0; g.aCommitFile[i]!=0; ++i){}
diffFiles = fossil_malloc_zero((i+1) * sizeof(*diffFiles));
for(i=0; g.aCommitFile[i]!=0; ++i){
| > > > > > > > > | < > > > > > > > | 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 |
"#\n%.78c\n"
"# The following diff is excluded from the commit message:\n#\n",
'#'
);
diff_options(&DCfg, 0, 1);
DCfg.diffFlags |= DIFF_VERBOSE;
if( g.aCommitFile ){
Stmt q;
Blob sql = BLOB_INITIALIZER;
FileDirList *diffFiles;
int i;
for(i=0; g.aCommitFile[i]!=0; ++i){}
diffFiles = fossil_malloc_zero((i+1) * sizeof(*diffFiles));
for(i=0; g.aCommitFile[i]!=0; ++i){
blob_append_sql(&sql,
"SELECT pathname, deleted, rid WHERE id=%d",
g.aCommitFile[i]);
db_prepare(&q, "%s", blob_sql_text(&sql));
blob_reset(&sql);
assert( db_step(&q)==SQLITE_ROW );
diffFiles[i].zName = fossil_strdup(db_column_text(&q, 0));
DCfg.diffFlags &= (~DIFF_FILE_MASK);
if( db_column_int(&q, 1) ){
DCfg.diffFlags |= DIFF_FILE_DELETED;
}else if( db_column_int(&q, 2)==0 ){
DCfg.diffFlags |= DIFF_FILE_ADDED;
}
db_finalize(&q);
if( fossil_strcmp(diffFiles[i].zName, "." )==0 ){
diffFiles[0].zName[0] = '.';
diffFiles[0].zName[1] = 0;
break;
}
diffFiles[i].nName = strlen(diffFiles[i].zName);
diffFiles[i].nUsed = 0;
|
| ︙ | ︙ | |||
1513 1514 1515 1516 1517 1518 1519 |
g.aCommitFile[jj] = 0;
bag_clear(&toCommit);
}
return result;
}
/*
| | | | 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 |
g.aCommitFile[jj] = 0;
bag_clear(&toCommit);
}
return result;
}
/*
** Returns true if the check-in identified by the first parameter is
** older than the given (valid) date/time string, else returns false.
** Also returns true if rid does not refer to a check-in, but it is not
** intended to be used for that case.
*/
int checkin_is_younger(
int rid, /* The record ID of the ancestor */
const char *zDate /* Date & time of the current check-in */
){
return db_exists(
|
| ︙ | ︙ | |||
1639 1640 1641 1642 1643 1644 1645 |
blob_zero(pOut);
if( vid ){
zParentUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d AND "
"EXISTS(SELECT 1 FROM event WHERE event.type='ci' and event.objid=%d)",
vid, vid);
if( !zParentUuid ){
fossil_fatal("Could not find a valid check-in for RID %d. "
| | | 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 |
blob_zero(pOut);
if( vid ){
zParentUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d AND "
"EXISTS(SELECT 1 FROM event WHERE event.type='ci' and event.objid=%d)",
vid, vid);
if( !zParentUuid ){
fossil_fatal("Could not find a valid check-in for RID %d. "
"Possible check-out/repo mismatch.", vid);
}
}
if( pBaseline ){
blob_appendf(pOut, "B %s\n", zBaselineUuid);
manifest_file_rewind(pBaseline);
pFile = manifest_file_next(pBaseline, 0);
nFBcard++;
|
| ︙ | ︙ | |||
1767 1768 1769 1770 1771 1772 1773 |
"SELECT CASE vmerge.id WHEN -1 THEN '+' ELSE '-' END || mhash, merge"
" FROM vmerge"
" WHERE (vmerge.id=-1 OR vmerge.id=-2)"
" ORDER BY 1");
while( db_step(&q)==SQLITE_ROW ){
const char *zCherrypickUuid = db_column_text(&q, 0);
int mid = db_column_int(&q, 1);
| | | < | 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 |
"SELECT CASE vmerge.id WHEN -1 THEN '+' ELSE '-' END || mhash, merge"
" FROM vmerge"
" WHERE (vmerge.id=-1 OR vmerge.id=-2)"
" ORDER BY 1");
while( db_step(&q)==SQLITE_ROW ){
const char *zCherrypickUuid = db_column_text(&q, 0);
int mid = db_column_int(&q, 1);
if( (!g.markPrivate && content_is_private(mid)) || (mid == vid) ) continue;
blob_appendf(pOut, "Q %s\n", zCherrypickUuid);
}
db_finalize(&q);
if( p->pCksum ) blob_appendf(pOut, "R %b\n", p->pCksum);
zColor = p->zColor;
if( p->zBranch && p->zBranch[0] ){
/* Set tags for the new branch */
|
| ︙ | ︙ | |||
1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 |
int fUnicode; /* return value of could_be_utf16() */
int fBinary; /* does the blob content appear to be binary? */
int lookFlags; /* output flags from looks_like_utf8/utf16() */
int fHasAnyCr; /* the blob contains one or more CR chars */
int fHasLoneCrOnly; /* all detected line endings are CR only */
int fHasCrLfOnly; /* all detected line endings are CR/LF pairs */
int fHasInvalidUtf8 = 0;/* contains invalid UTF-8 */
char *zMsg; /* Warning message */
Blob fname; /* Relative pathname of the file */
static int allOk = 0; /* Set to true to disable this routine */
if( allOk ) return 0;
if( sizeOk ){
fUnicode = could_be_utf16(pContent, &bReverse);
if( fUnicode ){
lookFlags = looks_like_utf16(pContent, bReverse, LOOK_NUL);
}else{
lookFlags = looks_like_utf8(pContent, LOOK_NUL);
if( !(lookFlags & LOOK_BINARY) && invalid_utf8(pContent) ){
fHasInvalidUtf8 = 1;
}
}
fHasAnyCr = (lookFlags & LOOK_CR);
fBinary = (lookFlags & LOOK_BINARY);
fHasLoneCrOnly = ((lookFlags & LOOK_EOL) == LOOK_LONE_CR);
fHasCrLfOnly = ((lookFlags & LOOK_EOL) == LOOK_CRLF);
}else{
fUnicode = fHasAnyCr = fBinary = fHasInvalidUtf8 = 0;
| > > > > | < < | 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 |
int fUnicode; /* return value of could_be_utf16() */
int fBinary; /* does the blob content appear to be binary? */
int lookFlags; /* output flags from looks_like_utf8/utf16() */
int fHasAnyCr; /* the blob contains one or more CR chars */
int fHasLoneCrOnly; /* all detected line endings are CR only */
int fHasCrLfOnly; /* all detected line endings are CR/LF pairs */
int fHasInvalidUtf8 = 0;/* contains invalid UTF-8 */
int fHasNul; /* contains NUL chars? */
int fHasLong; /* overly long line? */
char *zMsg; /* Warning message */
Blob fname; /* Relative pathname of the file */
static int allOk = 0; /* Set to true to disable this routine */
if( allOk ) return 0;
if( sizeOk ){
fUnicode = could_be_utf16(pContent, &bReverse);
if( fUnicode ){
lookFlags = looks_like_utf16(pContent, bReverse, LOOK_NUL);
}else{
lookFlags = looks_like_utf8(pContent, LOOK_NUL);
if( !(lookFlags & LOOK_BINARY) && invalid_utf8(pContent) ){
fHasInvalidUtf8 = 1;
}
}
fHasAnyCr = (lookFlags & LOOK_CR);
fBinary = (lookFlags & LOOK_BINARY);
fHasLoneCrOnly = ((lookFlags & LOOK_EOL) == LOOK_LONE_CR);
fHasCrLfOnly = ((lookFlags & LOOK_EOL) == LOOK_CRLF);
fHasNul = (lookFlags & LOOK_NUL);
fHasLong = (lookFlags & LOOK_LONG);
}else{
fUnicode = fHasAnyCr = fBinary = fHasInvalidUtf8 = 0;
fHasLoneCrOnly = fHasCrLfOnly = fHasNul = fHasLong = 0;
}
if( !sizeOk || fUnicode || fHasAnyCr || fBinary || fHasInvalidUtf8 ){
const char *zWarning = 0;
const char *zDisable = 0;
const char *zConvert = "c=convert/";
const char *zIn = "in";
Blob ans;
char cReply;
if( fBinary ){
if( binOk ){
return 0; /* We don't want binary warnings for this file. */
}
if( !fHasNul && fHasLong ){
zWarning = "long lines";
zConvert = ""; /* We cannot convert overlong lines. */
}else{
|
| ︙ | ︙ | |||
2021 2022 2023 2024 2025 2026 2027 | } /* ** COMMAND: test-commit-warning ** ** Usage: %fossil test-commit-warning ?OPTIONS? ** | | | 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 | } /* ** COMMAND: test-commit-warning ** ** Usage: %fossil test-commit-warning ?OPTIONS? ** ** Check each file in the check-out, including unmodified ones, using all ** the pre-commit checks. ** ** Options: ** --no-settings Do not consider any glob settings. ** -v|--verbose Show per-file results for all pre-commit checks. ** ** See also: commit, extras |
| ︙ | ︙ | |||
2096 2097 2098 2099 2100 2101 2102 | ** COMMAND: ci# ** COMMAND: commit ** ** Usage: %fossil commit ?OPTIONS? ?FILE...? ** or: %fossil ci ?OPTIONS? ?FILE...? ** ** Create a new version containing all of the changes in the current | | | 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 | ** COMMAND: ci# ** COMMAND: commit ** ** Usage: %fossil commit ?OPTIONS? ?FILE...? ** or: %fossil ci ?OPTIONS? ?FILE...? ** ** Create a new version containing all of the changes in the current ** check-out. You will be prompted to enter a check-in comment unless ** the comment has been specified on the command-line using "-m" or a ** file containing the comment using -M. The editor defined in the ** "editor" fossil option (see %fossil help set) will be used, or from ** the "VISUAL" or "EDITOR" environment variables (in that order) if ** no editor is set. ** ** All files that have changed will be committed unless some subset of |
| ︙ | ︙ | |||
2147 2148 2149 2150 2151 2152 2153 | ** ** The --tag option applies the symbolic tag name to the check-in. ** ** The --hash option detects edited files by computing each file's ** artifact hash rather than just checking for changes to its size or mtime. ** ** Options: | | | | | | | | | | | | | | | | | | | | | | | | 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 |
**
** The --tag option applies the symbolic tag name to the check-in.
**
** The --hash option detects edited files by computing each file's
** artifact hash rather than just checking for changes to its size or mtime.
**
** 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
** ("auto" lets Fossil choose it automatically,
** even for private branches)
** --close Close the branch being committed
** --date-override DATETIME DATE to use instead of 'now'
** --delta Use a delta manifest in the commit process
** --hash Verify file status using hashing rather
** than relying on file mtimes
** --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 warning the user about oversized files
** --integrate Close all merged-in branches
** -m|--comment COMMENT-TEXT Use COMMENT-TEXT as commit comment
** -M|--message-file FILE Read the commit comment from given file
** --mimetype MIMETYPE Mimetype of check-in comment
** -n|--dry-run If given, display instead of run actions
** -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
** --nosign Do not attempt to sign this commit with gpg
** --override-lock Allow a check-in even though parent is locked
** --private Do not sync changes and their descendants
** --tag TAG-NAME Assign given tag TAG-NAME to the check-in
** --trace Debug tracing
** --user-override USER USER to use instead of the current default
**
** 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.
|
| ︙ | ︙ | |||
2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 |
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;
privateFlag = find_option("private",0,0)!=0;
forceDelta = find_option("delta",0,0)!=0;
forceBaseline = find_option("baseline",0,0)!=0;
if( forceDelta ){
if( forceBaseline ){
fossil_fatal("cannot use --delta and --baseline together");
}
if( db_get_boolean("forbid-delta-manifests",0) ){
fossil_fatal("delta manifests are prohibited in this repository");
}
| > > > > | 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 |
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;
privateFlag = find_option("private",0,0)!=0;
forceDelta = find_option("delta",0,0)!=0;
forceBaseline = find_option("baseline",0,0)!=0;
db_must_be_within_tree();
if( db_get_boolean("dont-commit",0) ){
fossil_fatal("committing is prohibited: the 'dont-commit' option is set");
}
if( forceDelta ){
if( forceBaseline ){
fossil_fatal("cannot use --delta and --baseline together");
}
if( db_get_boolean("forbid-delta-manifests",0) ){
fossil_fatal("delta manifests are prohibited in this repository");
}
|
| ︙ | ︙ | |||
2295 2296 2297 2298 2299 2300 2301 |
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);
| < | 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 |
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();
mxSize = db_large_file_size();
if( find_option("ignore-oversize",0,0)!=0 ) mxSize = 0;
|
| ︙ | ︙ | |||
2403 2404 2405 2406 2407 2408 2409 |
if( cReply!='y' && cReply!='Y' ){
fossil_exit(1);
}
}
/* There are two ways this command may be executed. If there are
** no arguments following the word "commit", then all modified files
| | | 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 |
if( cReply!='y' && cReply!='Y' ){
fossil_exit(1);
}
}
/* There are two ways this command may be executed. If there are
** no arguments following the word "commit", then all modified files
** in the checked-out directory are committed. If one or more arguments
** follows "commit", then only those files are committed.
**
** After the following function call has returned, the Global.aCommitFile[]
** array is allocated to contain the "id" field from the vfile table
** for each file to be committed. Or, if aCommitFile is NULL, all files
** should be committed.
*/
|
| ︙ | ︙ | |||
2659 2660 2661 2662 2663 2664 2665 |
blob_reset(&content);
if( nrid!=rid ){
if( rid>0 ){
content_deltify(rid, &nrid, 1, 0);
}
db_multi_exec("UPDATE vfile SET mrid=%d, rid=%d, mhash=NULL WHERE id=%d",
nrid,nrid,id);
| | | 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 |
blob_reset(&content);
if( nrid!=rid ){
if( rid>0 ){
content_deltify(rid, &nrid, 1, 0);
}
db_multi_exec("UPDATE vfile SET mrid=%d, rid=%d, mhash=NULL WHERE id=%d",
nrid,nrid,id);
db_add_unsent(nrid);
}
}
db_finalize(&q);
if( nConflict && !allowConflict ){
fossil_fatal("abort due to unresolved merge conflicts; "
"use --allow-conflict to override");
}else if( abortCommit ){
|
| ︙ | ︙ | |||
2757 2758 2759 2760 2761 2762 2763 |
free(zManifestFile);
}
nvid = content_put(&manifest);
if( nvid==0 ){
fossil_fatal("trouble committing manifest: %s", g.zErrMsg);
}
| | | 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 |
free(zManifestFile);
}
nvid = content_put(&manifest);
if( nvid==0 ){
fossil_fatal("trouble committing manifest: %s", g.zErrMsg);
}
db_add_unsent(nvid);
if( manifest_crosslink(nvid, &manifest,
dryRunFlag ? MC_NONE : MC_PERMIT_HOOKS)==0 ){
fossil_fatal("%s", g.zErrMsg);
}
assert( blob_is_reset(&manifest) );
content_deltify(vid, &nvid, 1, 0);
zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", nvid);
|
| ︙ | ︙ | |||
2824 2825 2826 2827 2828 2829 2830 |
/* Verify that the repository checksum matches the expected checksum
** calculated before the check-in started (and stored as the R record
** of the manifest file).
*/
vfile_aggregate_checksum_repository(nvid, &cksum2);
if( blob_compare(&cksum1, &cksum2) ){
vfile_compare_repository_to_disk(nvid);
| | | | | 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 |
/* Verify that the repository checksum matches the expected checksum
** calculated before the check-in started (and stored as the R record
** of the manifest file).
*/
vfile_aggregate_checksum_repository(nvid, &cksum2);
if( blob_compare(&cksum1, &cksum2) ){
vfile_compare_repository_to_disk(nvid);
fossil_fatal("working check-out does not match what would have ended "
"up in the repository: %b versus %b",
&cksum1, &cksum2);
}
/* Verify that the manifest checksum matches the expected checksum */
vfile_aggregate_checksum_manifest(nvid, &cksum2, &cksum1b);
if( blob_compare(&cksum1, &cksum1b) ){
fossil_fatal("manifest checksum self-test failed: "
"%b versus %b", &cksum1, &cksum1b);
}
if( blob_compare(&cksum1, &cksum2) ){
fossil_fatal(
"working check-out does not match manifest after commit: "
"%b versus %b", &cksum1, &cksum2);
}
/* Verify that the commit did not modify any disk images. */
vfile_aggregate_checksum_disk(nvid, &cksum2);
if( blob_compare(&cksum1, &cksum2) ){
fossil_fatal("working check-out before and after commit does not match");
}
}
/* Clear the undo/redo stack */
undo_reset();
/* Commit */
|
| ︙ | ︙ |
Changes to src/checkout.c.
| ︙ | ︙ | |||
19 20 21 22 23 24 25 | ** from the local repository. */ #include "config.h" #include "checkout.h" #include <assert.h> /* | | | | | 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
** from the local repository.
*/
#include "config.h"
#include "checkout.h"
#include <assert.h>
/*
** Check to see if there is an existing check-out that has been
** modified. Return values:
**
** 0: There is an existing check-out but it is unmodified
** 1: There is a modified check-out - there are unsaved changes
*/
int unsaved_changes(unsigned int cksigFlags){
int vid;
db_must_be_within_tree();
vid = db_lget_int("checkout",0);
vfile_check_signature(vid, cksigFlags|CKSIG_ENOTFILE);
return db_exists("SELECT 1 FROM vfile WHERE chnged"
|
| ︙ | ︙ | |||
106 107 108 109 110 111 112 |
if( vid==0 ){
fossil_fatal("no such check-in: %s", g.argv[2]);
}
if( !is_a_version(vid) ){
fossil_fatal("object [%S] is not a check-in", blob_str(&uuid));
}
if( load_vfile_from_rid(vid) && !forceMissingFlag ){
| | | 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
if( vid==0 ){
fossil_fatal("no such check-in: %s", g.argv[2]);
}
if( !is_a_version(vid) ){
fossil_fatal("object [%S] is not a check-in", blob_str(&uuid));
}
if( load_vfile_from_rid(vid) && !forceMissingFlag ){
fossil_fatal("missing content, unable to check out");
};
return vid;
}
/*
** Set or clear the vfile.isexe flag for a file.
*/
|
| ︙ | ︙ | |||
267 268 269 270 271 272 273 | ** NOTE: Most people use "fossil update" instead of "fossil checkout" for ** day-to-day operations. If you are new to Fossil and trying to learn your ** way around, it is recommended that you become familiar with the ** "fossil update" command first. ** ** This command changes the current check-out to the version specified ** as an argument. The command aborts if there are edited files in the | | | | | | | | | | | 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 |
** NOTE: Most people use "fossil update" instead of "fossil checkout" for
** day-to-day operations. If you are new to Fossil and trying to learn your
** way around, it is recommended that you become familiar with the
** "fossil update" command first.
**
** This command changes the current check-out to the version specified
** as an argument. The command aborts if there are edited files in the
** current check-out unless the --force option is used. The --keep option
** 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:
** --force Ignore edited files in the current check-out
** --keep Only update the manifest file(s)
** --force-missing Force check-out even if content is missing
** --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();
|
| ︙ | ︙ | |||
311 312 313 314 315 316 317 |
/* 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?");
}
if( !forceFlag && unsaved_changes(0) ){
| | | 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 |
/* 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?");
}
if( !forceFlag && unsaved_changes(0) ){
fossil_fatal("there are unsaved changes in the current check-out");
}
if( forceFlag ){
db_multi_exec("DELETE FROM vfile");
prior = 0;
}else{
prior = db_lget_int("checkout",0);
}
|
| ︙ | ︙ | |||
395 396 397 398 399 400 401 | ** Usage: %fossil close ?OPTIONS? ** ** The opposite of "[[open]]". Close the current database connection. ** Require a -f or --force flag if there are unsaved changes in the ** current check-out or if there is non-empty stash. ** ** Options: | | | | | 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 |
** Usage: %fossil close ?OPTIONS?
**
** The opposite of "[[open]]". Close the current database connection.
** Require a -f or --force flag if there are unsaved changes in the
** current check-out or if there is non-empty stash.
**
** Options:
** -f|--force Necessary to close a check-out with uncommitted changes
**
** See also: [[open]]
*/
void close_cmd(void){
int forceFlag = find_option("force","f",0)!=0;
db_must_be_within_tree();
/* We should be done with options.. */
verify_all_options();
if( !forceFlag && unsaved_changes(0) ){
fossil_fatal("there are unsaved changes in the current check-out");
}
if( !forceFlag
&& db_table_exists("localdb","stash")
&& db_exists("SELECT 1 FROM localdb.stash")
){
fossil_fatal("closing the check-out will delete your stash");
}
if( db_is_writeable("repository") ){
db_unset_mprintf(1, "ckout:%q", g.zLocalRoot);
}
unlink_local_database(1);
db_close(1);
unlink_local_database(0);
}
|
Changes to src/clone.c.
| ︙ | ︙ | |||
106 107 108 109 110 111 112 | ** '/' to use an absolute path. ** ** Use %HH escapes for special characters in the userid and ** password. For example "%40" in place of "@", "%2f" in place ** of "/", and "%3a" in place of ":". ** ** Note that in Fossil (in contrast to some other DVCSes) a repository | | | | | | 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 |
** '/' to use an absolute path.
**
** Use %HH escapes for special characters in the userid and
** password. For example "%40" in place of "@", "%2f" in place
** of "/", and "%3a" in place of ":".
**
** Note that in Fossil (in contrast to some other DVCSes) a repository
** is distinct from a check-out. Cloning a repository is not the same thing
** as opening a repository. This command always clones the repository. This
** command might also open the repository, but only if the --no-open option
** is omitted and either the --workdir option is included or the FILENAME
** argument is omitted. Use the separate [[open]] command to open a
** repository that was previously cloned and already exists on the
** local machine.
**
** By default, the current login name is used to create the default
** admin user for the new clone. This can be overridden using
** the -A|--admin-user parameter.
**
** Options:
** -A|--admin-user USERNAME Make USERNAME the administrator
** -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
**
** See also: [[init]], [[open]]
*/
void clone_cmd(void){
char *zPassword;
const char *zDefaultUser; /* Optional name of the default user */
const char *zHttpAuth; /* HTTP Authorization user:pass information */
|
| ︙ | ︙ | |||
159 160 161 162 163 164 165 |
if( find_option("private",0,0)!=0 ) syncFlags |= SYNC_PRIVATE;
if( find_option("once",0,0)!=0) urlFlags &= ~URL_REMEMBER;
if( find_option("save-http-password",0,0)!=0 ){
urlFlags &= ~URL_PROMPT_PW;
urlFlags |= URL_REMEMBER_PW;
}
if( find_option("verbose","v",0)!=0) syncFlags |= SYNC_VERBOSE;
| | > > > > > | 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 |
if( find_option("private",0,0)!=0 ) syncFlags |= SYNC_PRIVATE;
if( find_option("once",0,0)!=0) urlFlags &= ~URL_REMEMBER;
if( find_option("save-http-password",0,0)!=0 ){
urlFlags &= ~URL_PROMPT_PW;
urlFlags |= URL_REMEMBER_PW;
}
if( find_option("verbose","v",0)!=0) syncFlags |= SYNC_VERBOSE;
if( find_option("unversioned","u",0)!=0 ){
syncFlags |= SYNC_UNVERSIONED;
if( syncFlags & SYNC_VERBOSE ){
syncFlags |= SYNC_UV_TRACE;
}
}
zHttpAuth = find_option("httpauth","B",1);
zDefaultUser = find_option("admin-user","A",1);
zWorkDir = find_option("workdir", 0, 1);
clone_ssh_find_options();
url_proxy_options();
g.zHttpCmd = find_option("transport-command",0,1);
|
| ︙ | ︙ | |||
193 194 195 196 197 198 199 |
zWorkDir = mprintf("./%s", zBase);
}
fossil_free(zBase);
}
if( -1 != file_size(zRepo, ExtFILE) ){
fossil_fatal("file already exists: %s", zRepo);
}
| | | 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 |
zWorkDir = mprintf("./%s", zBase);
}
fossil_free(zBase);
}
if( -1 != file_size(zRepo, ExtFILE) ){
fossil_fatal("file already exists: %s", zRepo);
}
/* Fail before clone if open will fail because inside an open check-out */
if( zWorkDir!=0 && zWorkDir[0]!=0 && !noOpen ){
if( db_open_local_v2(0, allowNested) ){
fossil_fatal("there is already an open tree at %s", g.zLocalRoot);
}
}
url_parse(g.argv[2], urlFlags);
if( zDefaultUser==0 && g.url.user!=0 ) zDefaultUser = g.url.user;
|
| ︙ | ︙ | |||
272 273 274 275 276 277 278 279 |
if( db_exists("SELECT 1 FROM delta WHERE srcId IN phantom") ){
fossil_fatal("there are unresolved deltas -"
" the clone is probably incomplete and unusable.");
}
fossil_print("Rebuilding repository meta-data...\n");
rebuild_db(1, 0);
if( !noCompress ){
fossil_print("Extra delta compression... "); fflush(stdout);
| > > | > > > > > | > > | 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 |
if( db_exists("SELECT 1 FROM delta WHERE srcId IN phantom") ){
fossil_fatal("there are unresolved deltas -"
" the clone is probably incomplete and unusable.");
}
fossil_print("Rebuilding repository meta-data...\n");
rebuild_db(1, 0);
if( !noCompress ){
int nDelta = 0;
i64 nByte;
fossil_print("Extra delta compression... "); fflush(stdout);
nByte = extra_deltification(&nDelta);
if( nDelta==1 ){
fossil_print("1 delta saves %,lld bytes\n", nByte);
}else if( nDelta>1 ){
fossil_print("%d deltas save %,lld bytes\n", nDelta, nByte);
}else{
fossil_print("none found\n");
}
}
db_end_transaction(0);
fossil_print("Vacuuming the database... "); fflush(stdout);
if( db_int(0, "PRAGMA page_count")>1000
&& db_int(0, "PRAGMA page_size")<8192 ){
db_multi_exec("PRAGMA page_size=8192;");
}
db_unprotect(PROTECT_ALL);
db_multi_exec("VACUUM");
db_protect_pop();
fossil_print("\nproject-id: %s\n", db_get("project-code", 0));
fossil_print("server-id: %s\n", db_get("server-code", 0));
zPassword = db_text(0, "SELECT pw FROM user WHERE login=%Q", g.zLogin);
fossil_print("admin-user: %s (password is \"%s\")\n", g.zLogin, zPassword);
hash_user_password(g.zLogin);
if( zWorkDir!=0 && zWorkDir[0]!=0 && !noOpen ){
Blob cmd;
fossil_print("opening the new %s repository in directory %s...\n",
zRepo, zWorkDir);
blob_init(&cmd, 0, 0);
blob_append_escaped_arg(&cmd, g.nameOfExe, 1);
blob_append(&cmd, " open ", -1);
|
| ︙ | ︙ | |||
383 384 385 386 387 388 389 390 391 392 393 394 395 396 |
** WEBPAGE: download
**
** Provide a simple page that enables newbies to download the latest tarball or
** ZIP archive, and provides instructions on how to clone.
*/
void download_page(void){
login_check_credentials();
style_header("Download Page");
if( !g.perm.Zip ){
@ <p>Bummer. You do not have permission to download.
if( g.zLogin==0 || g.zLogin[0]==0 ){
@ Maybe it would work better if you
@ %z(href("%R/login"))logged in</a>.
}else{
| > | 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 |
** WEBPAGE: download
**
** Provide a simple page that enables newbies to download the latest tarball or
** ZIP archive, and provides instructions on how to clone.
*/
void download_page(void){
login_check_credentials();
cgi_check_for_malice();
style_header("Download Page");
if( !g.perm.Zip ){
@ <p>Bummer. You do not have permission to download.
if( g.zLogin==0 || g.zLogin[0]==0 ){
@ Maybe it would work better if you
@ %z(href("%R/login"))logged in</a>.
}else{
|
| ︙ | ︙ |
Changes to src/color.c.
| ︙ | ︙ | |||
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
** This file contains code used to select colors based on branch and
** user names.
**
*/
#include "config.h"
#include <string.h>
#include "color.h"
/*
** Hash a string and use the hash to determine a background color.
**
** This value returned is in static space and is overwritten with
** each subsequent call.
*/
char *hash_color(const char *z){
| > > > > > > > > > > > > < < | < | 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 |
** 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;
for(i=0; z[i]; i++ ){
h = (h<<11) ^ (h<<1) ^ (h>>3) ^ z[i];
}
return h;
}
/*
** Hash a string and use the hash to determine a background color.
**
** This value returned is in static space and is overwritten with
** each subsequent call.
*/
char *hash_color(const char *z){
unsigned int h = 0; /* Hash on the branch name */
int r, g, b; /* Values for red, green, and blue */
int h1, h2, h3, h4; /* Elements of the hash value */
int mx, mn; /* Components of HSV */
static char zColor[10]; /* The resulting color */
static int ix[3] = {0,0}; /* Color chooser parameters */
if( ix[0]==0 ){
if( skin_detail_boolean("white-foreground") ){
ix[0] = 0x50;
ix[1] = 0x20;
}else{
ix[0] = 0xf8;
ix[1] = 0x20;
}
}
h = hash_of_name(z);
h1 = h % 6; h /= 6;
h3 = h % 10; h /= 10;
h4 = h % 10; h /= 10;
mx = ix[0] - h3;
mn = mx - h4 - ix[1];
h2 = (h%(mx - mn)) + mn;
switch( h1 ){
|
| ︙ | ︙ | |||
152 153 154 155 156 157 158 |
style_set_current_feature("test");
style_header("Hash Color Test");
for(i=cnt=0; i<10; i++){
sqlite3_snprintf(sizeof(zNm),zNm,"b%d",i);
zBr = P(zNm);
if( zBr && zBr[0] ){
@ <p style='border:1px solid;background-color:%s(hash_color(zBr));'>
| | | | | 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 |
style_set_current_feature("test");
style_header("Hash Color Test");
for(i=cnt=0; i<10; i++){
sqlite3_snprintf(sizeof(zNm),zNm,"b%d",i);
zBr = P(zNm);
if( zBr && zBr[0] ){
@ <p style='border:1px solid;background-color:%s(hash_color(zBr));'>
@ %h(zBr) - hash 0x%x(hash_of_name(zBr)) - color %s(hash_color(zBr)) -
@ Omnes nos quasi oves erravimus unusquisque in viam
@ suam declinavit.</p>
cnt++;
}
}
if( cnt ){
@ <hr>
}
@ <form method="POST">
@ <p>Enter candidate branch names below and see them displayed in their
@ default background colors above.</p>
for(i=0; i<10; i++){
sqlite3_snprintf(sizeof(zNm),zNm,"b%d",i);
zBr = P(zNm);
@ <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();
}
|
Changes to src/comformat.c.
| ︙ | ︙ | |||
211 212 213 214 215 216 217 | int cchUTF8, maxUTF8; /* Helper variables to count UTF-8 sequences. */ if( !zLine ) return; if( lineChars<=0 ) return; #if 0 assert( indent<sizeof(zBuf)-5 ); /* See following comments to explain */ assert( origIndent<sizeof(zBuf)-5 ); /* these limits. */ #endif | | | | | 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 |
int cchUTF8, maxUTF8; /* Helper variables to count UTF-8 sequences. */
if( !zLine ) return;
if( lineChars<=0 ) return;
#if 0
assert( indent<sizeof(zBuf)-5 ); /* See following comments to explain */
assert( origIndent<sizeof(zBuf)-5 ); /* these limits. */
#endif
if( indent>(int)sizeof(zBuf)-6 ){
/* Limit initial indent to fit output buffer. */
indent = sizeof(zBuf)-6;
}
comment_calc_indent(zLine, indent, trimCrLf, trimSpace, &index);
if( indent>0 ){
for(i=0; i<indent; i++){
zBuf[iBuf++] = ' ';
}
}
if( origIndent>(int)sizeof(zBuf)-6 ){
/* Limit line indent to fit output buffer. */
origIndent = sizeof(zBuf)-6;
}
maxChars = lineChars;
for(;;){
int useChars = 1;
char c = zLine[index];
/* Flush the output buffer if there's no space left for at least one more
** (potentially 4-byte) UTF-8 sequence, one level of indentation spaces,
** a new line, and a terminating NULL. */
if( iBuf>(int)sizeof(zBuf)-origIndent-6 ){
zBuf[iBuf]=0;
iBuf=0;
fossil_print("%s", zBuf);
}
if( c==0 ){
break;
}else{
|
| ︙ | ︙ | |||
272 273 274 275 276 277 278 |
if( maxChars<useChars ){
zBuf[iBuf++] = ' ';
break;
}
}else if( wordBreak && fossil_isspace(c) ){
int distUTF8;
int nextIndex = comment_next_space(zLine, index, &distUTF8);
| | | 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 |
if( maxChars<useChars ){
zBuf[iBuf++] = ' ';
break;
}
}else if( wordBreak && fossil_isspace(c) ){
int distUTF8;
int nextIndex = comment_next_space(zLine, index, &distUTF8);
if( nextIndex<=0 || distUTF8>=maxChars ){
break;
}
charCnt++;
}else{
charCnt++;
}
assert( c!='\n' || charCnt==0 );
|
| ︙ | ︙ | |||
346 347 348 349 350 351 352 |
comment_set_maxchars(indent, &maxChars);
}
if( zText==0 ) zText = "(NULL)";
if( maxChars<=0 ){
maxChars = strlen(zText);
}
/* Ensure the buffer can hold the longest-possible UTF-8 sequences. */
| | | 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 |
comment_set_maxchars(indent, &maxChars);
}
if( zText==0 ) zText = "(NULL)";
if( maxChars<=0 ){
maxChars = strlen(zText);
}
/* Ensure the buffer can hold the longest-possible UTF-8 sequences. */
if( maxChars >= ((int)sizeof(zBuffer)/4-1) ){
zBuf = fossil_malloc(maxChars*4+1);
}else{
zBuf = zBuffer;
}
for(;;){
while( fossil_isspace(zText[0]) ){ zText++; }
if( zText[0]==0 ){
|
| ︙ | ︙ | |||
511 512 513 514 515 516 517 518 519 |
** 1. The global --comfmtflags (alias --comment-format) command-line option.
** 2. The local (per-repository) "comment-format" setting.
** 3. The global (all-repositories) "comment-format" setting.
** 4. The default value COMMENT_PRINT_DEFAULT.
*/
int get_comment_format(){
int comFmtFlags;
/* The global command-line option is present, or the value has been cached. */
if( g.comFmtFlags!=COMMENT_PRINT_UNSET ){
| > > > > > > > | < | | | | | | | | | 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 |
** 1. The global --comfmtflags (alias --comment-format) command-line option.
** 2. The local (per-repository) "comment-format" setting.
** 3. The global (all-repositories) "comment-format" setting.
** 4. 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
** network-mounted. Discussed in:
** https://fossil-scm.org/forum/forumpost/9aaefe4e536e01bf */
/* The global command-line option is present, or the value has been cached. */
if( g.comFmtFlags!=COMMENT_PRINT_UNSET ){
return g.comFmtFlags;
}
/* Load the local (per-repository) or global (all-repositories) value, and use
** g.comFmtFlags as a cache. */
comFmtFlags = db_get_int("comment-format", COMMENT_PRINT_UNSET);
if( comFmtFlags!=COMMENT_PRINT_UNSET ){
g.comFmtFlags = comFmtFlags;
return comFmtFlags;
}
/* Fallback to the default value. */
g.comFmtFlags = COMMENT_PRINT_DEFAULT;
return g.comFmtFlags;
}
/*
**
** COMMAND: test-comment-format
**
** Usage: %fossil test-comment-format ?OPTIONS? PREFIX TEXT ?ORIGTEXT?
**
** Test comment formatting and printing. Use for testing only.
**
** Options:
** --file The comment text is really just a file name to
** read it from
** --decode Decode the text using the same method used when
** handling the value of a C-card from a manifest.
** --legacy Use the legacy comment printing algorithm
** --trimcrlf Enable trimming of leading/trailing CR/LF
** --trimspace Enable trimming of leading/trailing spaces
** --wordbreak Attempt to break lines on word boundaries
** --origbreak Attempt to break when the original comment text
** is detected
** --indent Number of spaces to indent (default (-1) is to
** auto-detect). Zero means no indent.
** -W|--width NUM Width of lines (default (-1) is to auto-detect).
** Zero means no limit.
*/
void test_comment_format(void){
const char *zWidth;
|
| ︙ | ︙ |
Changes to src/configure.c.
| ︙ | ︙ | |||
355 356 357 358 359 360 361 | ** In overview, we have: ** ** NAME CONTENT ** ------- ----------------------------------------------------------- ** /config $MTIME $NAME value $VALUE ** /user $MTIME $LOGIN pw $VALUE cap $VALUE info $VALUE photo $VALUE ** /shun $MTIME $UUID scom $VALUE | | | | | | | | | 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 |
** In overview, we have:
**
** NAME CONTENT
** ------- -----------------------------------------------------------
** /config $MTIME $NAME value $VALUE
** /user $MTIME $LOGIN pw $VALUE cap $VALUE info $VALUE photo $VALUE
** /shun $MTIME $UUID scom $VALUE
** /reportfmt $MTIME $TITLE owner $VALUE cols $VALUE sqlcode $VALUE jx $JSON
** /concealed $MTIME $HASH content $VALUE
** /subscriber $SMTIME $SEMAIL suname $V ...
*/
void configure_receive(const char *zName, Blob *pContent, int groupMask){
int checkMask; /* Masks for which we must first check existance of tables */
checkMask = CONFIGSET_SCRIBER;
if( zName[0]=='/' ){
/* The new format */
char *azToken[24];
int nToken = 0;
int ii, jj;
int thisMask;
Blob name, value, sql;
static const struct receiveType {
const char *zName; /* Configuration key for this table */
const char *zPrimKey; /* Primary key column */
int nField; /* Number of data fields */
const char *azField[6]; /* Names of the data fields */
} aType[] = {
{ "/config", "name", 1, { "value", 0,0,0,0,0 } },
{ "@user", "login", 5, { "pw","cap","info","photo","jx",0} },
{ "@shun", "uuid", 1, { "scom", 0,0,0,0,0} },
{ "@reportfmt", "title", 4, { "owner","cols","sqlcode","jx",0,0}},
{ "@concealed", "hash", 1, { "content", 0,0,0,0,0 } },
{ "@subscriber","semail",6,
{ "suname","sdigest","sdonotcall","ssub","sctime","smip"} },
};
/* Locate the receiveType in aType[ii] */
for(ii=0; ii<count(aType); ii++){
if( fossil_strcmp(&aType[ii].zName[1],&zName[1])==0 ) break;
}
if( ii>=count(aType) ) return;
|
| ︙ | ︙ | |||
443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 |
}
blob_append_sql(&sql,") VALUES(%s,%s",
azToken[1] /*safe-for-%s*/, azToken[0]/*safe-for-%s*/);
for(jj=2; jj<nToken; jj+=2){
blob_append_sql(&sql, ",%s", azToken[jj+1] /*safe-for-%s*/);
}
db_protect_only(PROTECT_SENSITIVE);
db_multi_exec("%s)", blob_sql_text(&sql));
if( db_changes()==0 ){
blob_reset(&sql);
blob_append_sql(&sql, "UPDATE \"%w\" SET mtime=%s",
&zName[1], azToken[0]/*safe-for-%s*/);
for(jj=2; jj<nToken; jj+=2){
blob_append_sql(&sql, ", \"%w\"=%s",
azToken[jj], azToken[jj+1]/*safe-for-%s*/);
| > > > > > > > > > | 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 |
}
blob_append_sql(&sql,") VALUES(%s,%s",
azToken[1] /*safe-for-%s*/, azToken[0]/*safe-for-%s*/);
for(jj=2; jj<nToken; jj+=2){
blob_append_sql(&sql, ",%s", azToken[jj+1] /*safe-for-%s*/);
}
db_protect_only(PROTECT_SENSITIVE);
/* Make sure tables have the "jx" column */
if( strcmp(&zName[1],"user")==0 ){
user_update_user_table();
}else if( strcmp(&zName[1],"reportfmt")==0 ){
report_update_reportfmt_table();
}
db_multi_exec("%s)", blob_sql_text(&sql));
if( db_changes()==0 ){
blob_reset(&sql);
blob_append_sql(&sql, "UPDATE \"%w\" SET mtime=%s",
&zName[1], azToken[0]/*safe-for-%s*/);
for(jj=2; jj<nToken; jj+=2){
blob_append_sql(&sql, ", \"%w\"=%s",
azToken[jj], azToken[jj+1]/*safe-for-%s*/);
|
| ︙ | ︙ | |||
530 531 532 533 534 535 536 |
blob_size(&rec), blob_str(&rec));
nCard++;
blob_reset(&rec);
}
db_finalize(&q);
}
if( groupMask & CONFIGSET_USER ){
| > | | | > > > > > < > | | > | > | > | > | < > > | > > > > | | > < > | | > | > | > | < > | 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 |
blob_size(&rec), blob_str(&rec));
nCard++;
blob_reset(&rec);
}
db_finalize(&q);
}
if( groupMask & CONFIGSET_USER ){
if( db_table_has_column("repository","user","jx") ){
db_prepare(&q, "SELECT mtime, quote(login), quote(pw), quote(cap),"
" quote(info), quote(photo), quote(jx) FROM user"
" WHERE mtime>=%lld", iStart);
}else{
db_prepare(&q, "SELECT mtime, quote(login), quote(pw), quote(cap),"
" quote(info), quote(photo), 'NULL' FROM user"
" WHERE mtime>=%lld", iStart);
}
while( db_step(&q)==SQLITE_ROW ){
const char *z;
blob_appendf(&rec,"%s %s", db_column_text(&q,0), db_column_text(&q,1));
z = db_column_text(&q,2);
if( strcmp(z,"NULL")!=0 ) blob_appendf(&rec," pw %s", z);
z = db_column_text(&q,3);
if( strcmp(z,"NULL")!=0 ) blob_appendf(&rec," cap %s", z);
z = db_column_text(&q,4);
if( strcmp(z,"NULL")!=0 ) blob_appendf(&rec," info %s", z);
z = db_column_text(&q,5);
if( strcmp(z,"NULL")!=0 ) blob_appendf(&rec," photo %s", z);
z = db_column_text(&q,6);
if( strcmp(z,"NULL")!=0 ) blob_appendf(&rec," jx %s", z);
blob_appendf(pOut, "config /user %d\n%s\n",
blob_size(&rec), blob_str(&rec));
nCard++;
blob_reset(&rec);
}
db_finalize(&q);
}
if( groupMask & CONFIGSET_TKT ){
if( db_table_has_column("repository","reportfmt","jx") ){
db_prepare(&q, "SELECT mtime, quote(title), quote(owner), quote(cols),"
" quote(sqlcode), quote(jx) FROM reportfmt"
" WHERE mtime>=%lld", iStart);
}else{
db_prepare(&q, "SELECT mtime, quote(title), quote(owner), quote(cols),"
" quote(sqlcode), 'NULL' FROM reportfmt"
" WHERE mtime>=%lld", iStart);
}
while( db_step(&q)==SQLITE_ROW ){
const char *z;
blob_appendf(&rec,"%s %s", db_column_text(&q,0), db_column_text(&q,1));
z = db_column_text(&q,2);
if( strcmp(z,"NULL")!=0 ) blob_appendf(&rec," owner %s", z);
z = db_column_text(&q,3);
if( strcmp(z,"NULL")!=0 ) blob_appendf(&rec," cols %s", z);
z = db_column_text(&q,4);
if( strcmp(z,"NULL")!=0 ) blob_appendf(&rec," sqlcode %s", z);
z = db_column_text(&q,5);
if( strcmp(z,"NULL")!=0 ) blob_appendf(&rec," jx %s", z);
blob_appendf(pOut, "config /reportfmt %d\n%s\n",
blob_size(&rec), blob_str(&rec));
nCard++;
blob_reset(&rec);
}
db_finalize(&q);
}
|
| ︙ | ︙ |
Changes to src/content.c.
| ︙ | ︙ | |||
318 319 320 321 322 323 324 | /* ** COMMAND: artifact* ** ** Usage: %fossil artifact ARTIFACT-ID ?OUTPUT-FILENAME? ?OPTIONS? ** ** Extract an artifact by its artifact hash and write the results on | | | 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 | /* ** COMMAND: artifact* ** ** Usage: %fossil artifact ARTIFACT-ID ?OUTPUT-FILENAME? ?OPTIONS? ** ** Extract an artifact by its artifact hash and write the results on ** standard output, or if the optional second argument is given, in ** the named output file. ** ** Options: ** -R|--repository REPO Extract artifacts from repository REPO ** ** See also: [[finfo]] */ |
| ︙ | ︙ | |||
812 813 814 815 816 817 818 | ** converted to undeltaed text before the aSrc[bestSrc]->rid delta is ** created, in order to prevent a delta loop. ** ** If either rid or aSrc[i] contain less than 50 bytes, or if the ** resulting delta does not achieve a compression of at least 25% ** the rid is left untouched. ** | | > | 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 |
** converted to undeltaed text before the aSrc[bestSrc]->rid delta is
** created, in order to prevent a delta loop.
**
** If either rid or aSrc[i] contain less than 50 bytes, or if the
** resulting delta does not achieve a compression of at least 25%
** the rid is left untouched.
**
** Return the number of bytes by which the storage associated with rid
** is reduced. A return of 0 means no new deltification occurs.
*/
int content_deltify(int rid, int *aSrc, int nSrc, int force){
int s;
Blob data; /* Content of rid */
Blob src; /* Content of aSrc[i] */
Blob delta; /* Delta from aSrc[i] to rid */
Blob bestDelta; /* Best delta seen so far */
|
| ︙ | ︙ | |||
901 902 903 904 905 906 907 908 909 910 911 912 913 |
if( bestSrc>0 ){
Stmt s1, s2; /* Statements used to create the delta */
blob_compress(&bestDelta, &bestDelta);
db_prepare(&s1, "UPDATE blob SET content=:data WHERE rid=%d", rid);
db_prepare(&s2, "REPLACE INTO delta(rid,srcid)VALUES(%d,%d)", rid, bestSrc);
db_bind_blob(&s1, ":data", &bestDelta);
db_begin_transaction();
db_exec(&s1);
db_exec(&s2);
db_end_transaction(0);
db_finalize(&s1);
db_finalize(&s2);
verify_before_commit(rid);
| > | | 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 |
if( bestSrc>0 ){
Stmt s1, s2; /* Statements used to create the delta */
blob_compress(&bestDelta, &bestDelta);
db_prepare(&s1, "UPDATE blob SET content=:data WHERE rid=%d", rid);
db_prepare(&s2, "REPLACE INTO delta(rid,srcid)VALUES(%d,%d)", rid, bestSrc);
db_bind_blob(&s1, ":data", &bestDelta);
db_begin_transaction();
rc = db_int(0, "SELECT octet_length(content) FROM blob WHERE rid=%d", rid);
db_exec(&s1);
db_exec(&s2);
db_end_transaction(0);
db_finalize(&s1);
db_finalize(&s2);
verify_before_commit(rid);
rc -= blob_size(&bestDelta);
}
blob_reset(&data);
blob_reset(&bestDelta);
return rc;
}
/*
|
| ︙ | ︙ | |||
955 956 957 958 959 960 961 | ** COMMAND: test-integrity ** ** Verify that all content can be extracted from the BLOB table correctly. ** If the BLOB table is correct, then the repository can always be ** successfully reconstructed using "fossil rebuild". ** ** Options: | < < < | 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 |
** COMMAND: test-integrity
**
** Verify that all content can be extracted from the BLOB table correctly.
** If the BLOB table is correct, then the repository can always be
** successfully reconstructed using "fossil rebuild".
**
** Options:
** -d|--db-only Run "PRAGMA integrity_check" on the database only.
** No other validation is performed.
** --parse Parse all manifests, wikis, tickets, events, and
** so forth, reporting any errors found.
** -q|--quick Run "PRAGMA quick_check" on the database only.
** No other validation is performed.
*/
void test_integrity(void){
Stmt q;
Blob content;
int n1 = 0;
|
| ︙ | ︙ | |||
1028 1029 1030 1031 1032 1033 1034 |
fossil_print(" %d/%d\r", n1, total);
fflush(stdout);
if( size<0 ){
fossil_print("skip phantom %d %s\n", rid, zUuid);
continue; /* Ignore phantoms */
}
content_get(rid, &content);
| | | | 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 |
fossil_print(" %d/%d\r", n1, total);
fflush(stdout);
if( size<0 ){
fossil_print("skip phantom %d %s\n", rid, zUuid);
continue; /* Ignore phantoms */
}
content_get(rid, &content);
if( (int)blob_size(&content)!=size ){
fossil_print("size mismatch on artifact %d: wanted %d but got %d\n",
rid, size, blob_size(&content));
nErr++;
}
if( !hname_verify_hash(&content, zUuid, nUuid) ){
fossil_print("wrong hash on artifact %d\n",rid);
nErr++;
}
if( bParse && looks_like_control_artifact(&content) ){
Blob err;
int i, n;
char *z;
Manifest *p;
char zFirstLine[400];
blob_zero(&err);
z = blob_buffer(&content);
n = blob_size(&content);
for(i=0; i<n && z[i] && z[i]!='\n' && i<(int)sizeof(zFirstLine)-1; i++){}
memcpy(zFirstLine, z, i);
zFirstLine[i] = 0;
p = manifest_parse(&content, 0, &err);
if( p==0 ){
fossil_print("manifest_parse failed for %s:\n%s\n",
zUuid, blob_str(&err));
if( strncmp(blob_str(&err), "line 1:", 7)==0 ){
|
| ︙ | ︙ | |||
1195 1196 1197 1198 1199 1200 1201 | ** Usage: %fossil test-missing ** ** Look at every artifact in the repository and verify that ** all references are satisfied. Report any referenced artifacts ** that are missing or shunned. ** ** Options: | < | 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 |
** Usage: %fossil test-missing
**
** Look at every artifact in the repository and verify that
** all references are satisfied. Report any referenced artifacts
** that are missing or shunned.
**
** Options:
** --notshunned Do not report shunned artifacts
** --quiet Only show output if there are errors
*/
void test_missing(void){
Stmt q;
Blob content;
int nErr = 0;
|
| ︙ | ︙ |
Changes to src/cookies.c.
| ︙ | ︙ | |||
173 174 175 176 177 178 179 |
const char *zDflt /* Default value for the parameter */
){
cookie_readwrite(zQP, zPName, zDflt, COOKIE_READ|COOKIE_WRITE);
}
/* Update the user preferences cookie, if necessary, and shut down
** this module. The cookie is only emitted if its value has actually
| | > > > > > > > > > > | | 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 |
const char *zDflt /* Default value for the parameter */
){
cookie_readwrite(zQP, zPName, zDflt, COOKIE_READ|COOKIE_WRITE);
}
/* Update the user preferences cookie, if necessary, and shut down
** this module. The cookie is only emitted if its value has actually
** changed since the request started and the "udc" (Update Display
** Cookie) URL argument was provided.
**
** Historical note: from 2021-03-02 [71a2d68a7a113e7c] until
** 2023-01-16, the udc was not observed (it had been prior to that),
** and that led to the unfortunate side effect that a timeline link
** from the /reports page would end up persistently setting a user's
** timeline length preference to the number of items in that
** report. In a /chat discussion it was agreed that updating the
** cookie requires explicit opt-in via the udc argument or ?skin=...,
** which implies udc.
*/
void cookie_render(void){
if( cookies.bChanged && P("udc")!=0 ){
Blob new;
int i;
blob_init(&new, 0, 0);
for(i=0;i<cookies.nParam;i++){
if( i>0 ) blob_append(&new, ",", 1);
blob_appendf(&new, "%s=%T",
cookies.aParam[i].zPName, cookies.aParam[i].zPValue);
|
| ︙ | ︙ |
Changes to src/copybtn.js.
| ︙ | ︙ | |||
42 43 44 45 46 47 48 |
elButton.style.opacity = 1;
if( idTarget ) elButton.setAttribute("data-copytarget",idTarget);
if( cchLength ) elButton.setAttribute("data-copylength",cchLength);
elButton.onclick = clickCopyButton;
return elButton;
}
setTimeout(function(){
| | | | < | | | | | < < | | < | | | | | | | | | | | 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 |
elButton.style.opacity = 1;
if( idTarget ) elButton.setAttribute("data-copytarget",idTarget);
if( cchLength ) elButton.setAttribute("data-copylength",cchLength);
elButton.onclick = clickCopyButton;
return elButton;
}
setTimeout(function(){
var elButtons = document.getElementsByClassName("copy-button");
for ( var i=0; i<elButtons.length; i++ ){
initCopyButton(elButtons[i],0,0);
}
},1);
/* The onclick handler for the "Copy Button". */
function clickCopyButton(e){
e.preventDefault(); /* Mandatory for <a> and <button>. */
e.stopPropagation();
if( this.getAttribute("data-copylocked") ) return;
this.setAttribute("data-copylocked","1");
this.style.transition = "opacity 400ms ease-in-out";
this.style.opacity = 0;
var idTarget = this.getAttribute("data-copytarget");
var elTarget = document.getElementById(idTarget);
if( elTarget ){
var text = elTarget.innerText.replace(/^\s+|\s+$/g,"");
var cchLength = parseInt(this.getAttribute("data-copylength"));
if( !isNaN(cchLength) && cchLength>0 ){
text = text.slice(0,cchLength); /* Assume single-byte chars. */
}
copyTextToClipboard(text);
}
setTimeout(function(){
this.style.transition = "";
this.style.opacity = 1;
this.removeAttribute("data-copylocked");
}.bind(this),400);
}
/* Create a temporary <textarea> element and copy the contents to clipboard. */
function copyTextToClipboard(text){
if( window.clipboardData && window.clipboardData.setData ){
window.clipboardData.setData("Text",text);
}else{
var elTextarea = document.createElement("textarea");
elTextarea.style.position = "fixed";
elTextarea.value = text;
document.body.appendChild(elTextarea);
elTextarea.select();
try{
document.execCommand("copy");
}catch(err){
}finally{
document.body.removeChild(elTextarea);
}
}
}
|
Changes to src/db.c.
| ︙ | ︙ | |||
21 22 23 24 25 26 27 | ** with: ** ** (1) The "configdb" database in ~/.fossil or ~/.config/fossil.db ** or in %LOCALAPPDATA%/_fossil ** ** (2) The "repository" database ** | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 |
** with:
**
** (1) The "configdb" database in ~/.fossil or ~/.config/fossil.db
** or in %LOCALAPPDATA%/_fossil
**
** (2) The "repository" database
**
** (3) A local check-out database named "_FOSSIL_" or ".fslckout"
** and located at the root of the local copy of the source tree.
**
*/
#include "config.h"
#if defined(_WIN32)
# if USE_SEE
# include <windows.h>
# define GETPID (int)GetCurrentProcessId
# endif
#else
# include <pwd.h>
# if USE_SEE
# define GETPID getpid
# endif
#endif
#if USE_SEE && !defined(SQLITE_HAS_CODEC)
# define SQLITE_HAS_CODEC
#endif
#if USE_SEE && defined(__linux__)
# include <sys/uio.h>
#endif
#include <sqlite3.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <time.h>
/* BUGBUG: This (PID_T) does not work inside of INTERFACE block. */
#if USE_SEE
#if defined(_WIN32)
typedef DWORD PID_T;
#else
typedef pid_t PID_T;
#endif
#endif
#include "db.h"
#if INTERFACE
/*
** Type definitions used for handling the saved encryption key for SEE.
*/
#if !defined(_WIN32)
typedef void *LPVOID;
typedef size_t SIZE_T;
#endif
/*
** Operations for db_maybe_handle_saved_encryption_key_for_process, et al.
*/
#define SEE_KEY_READ ((int)0)
#define SEE_KEY_WRITE ((int)1)
#define SEE_KEY_ZERO ((int)2)
/*
** An single SQL statement is represented as an instance of the following
** structure.
*/
struct Stmt {
Blob sql; /* The SQL for this statement */
sqlite3_stmt *pStmt; /* The results of sqlite3_prepare_v2() */
|
| ︙ | ︙ | |||
135 136 137 138 139 140 141 | const char *zStartFile; /* File in which transaction was started */ int iStartLine; /* Line of zStartFile where transaction started */ int (*xAuth)(void*,int,const char*,const char*,const char*,const char*); void *pAuthArg; /* Argument to the authorizer */ const char *zAuthName; /* Name of the authorizer */ int bProtectTriggers; /* True if protection triggers already exist */ int nProtect; /* Slots of aProtect used */ | | | | 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 |
const char *zStartFile; /* File in which transaction was started */
int iStartLine; /* Line of zStartFile where transaction started */
int (*xAuth)(void*,int,const char*,const char*,const char*,const char*);
void *pAuthArg; /* Argument to the authorizer */
const char *zAuthName; /* Name of the authorizer */
int bProtectTriggers; /* True if protection triggers already exist */
int nProtect; /* Slots of aProtect used */
unsigned aProtect[12]; /* Saved values of protectMask */
} db = {
PROTECT_USER|PROTECT_CONFIG|PROTECT_BASELINE, /* protectMask */
0, 0, 0, 0, 0, 0, 0, {{0}}, {0}, {0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0}};
/*
** Arrange for the given file to be deleted on a failure.
*/
void db_delete_on_failure(const char *zFilename){
assert( db.nDeleteOnFail<count(db.azDeleteOnFail) );
if( zFilename==0 ) return;
|
| ︙ | ︙ | |||
367 368 369 370 371 372 373 | ** ------------------------------- ** ** This is *not* a primary means of defending the application from ** attack. Fossil should be secure even if this mechanism is disabled. ** The purpose of database write protection is to provide an additional ** layer of defense in case SQL injection bugs somehow slip into other ** parts of the system. In other words, database write protection is | | | | 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 | ** ------------------------------- ** ** This is *not* a primary means of defending the application from ** attack. Fossil should be secure even if this mechanism is disabled. ** The purpose of database write protection is to provide an additional ** layer of defense in case SQL injection bugs somehow slip into other ** parts of the system. In other words, database write protection is ** not the primary defense but rather defense in depth. ** ** This mechanism mostly focuses on the USER table, to prevent an ** attacker from giving themselves Admin privilegs, and on the ** CONFIG table and especially "sensitive" settings such as ** "diff-command" or "editor" that if compromised by an attacker ** could lead to an RCE. ** ** By default, the USER and CONFIG tables are read-only. Various ** subsystems that legitimately need to change those tables can ** temporarily do so using: ** |
| ︙ | ︙ | |||
397 398 399 400 401 402 403 404 405 406 407 408 409 410 | ** pages) are still writable, however. ** ** The PROTECT_SENSITIVE protection is a subset of PROTECT_CONFIG ** that blocks changes to all of the global_config table, but only ** "sensitive" settings in the config table. PROTECT_SENSITIVE ** relies on triggers and the protected_setting() SQL function to ** prevent changes to sensitive settings. ** ** Additional Notes ** ---------------- ** ** Calls to routines like db_set() and db_unset() temporarily disable ** the PROTECT_CONFIG protection. The assumption is that these calls ** cannot be invoked by an SQL injection and are thus safe. Make sure | > > > > > > > > > > | 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 | ** pages) are still writable, however. ** ** The PROTECT_SENSITIVE protection is a subset of PROTECT_CONFIG ** that blocks changes to all of the global_config table, but only ** "sensitive" settings in the config table. PROTECT_SENSITIVE ** relies on triggers and the protected_setting() SQL function to ** prevent changes to sensitive settings. ** ** PROTECT_READONLY is set for any HTTP request for which the HTTP_REFERER ** is not the same origin. This is an additional defense against cross-site- ** scripting attacks. As with all of these defenses, this is only an extra ** backup layer. Fossil should be proof against XSS attacks even without this. ** ** Any violation of these security restrictions results in a SECURITY message ** in the server log (if enabled). A violation of any of these restrictions ** probably indicates a bug in Fossil and should be reported to the ** developers. ** ** Additional Notes ** ---------------- ** ** Calls to routines like db_set() and db_unset() temporarily disable ** the PROTECT_CONFIG protection. The assumption is that these calls ** cannot be invoked by an SQL injection and are thus safe. Make sure |
| ︙ | ︙ | |||
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 |
&& g.repositoryOpen
){
/* Create the triggers needed to protect sensitive settings from
** being created or modified the first time that PROTECT_SENSITIVE
** is enabled. Deleting a sensitive setting is harmless, so there
** is not trigger to block deletes. After being created once, the
** triggers persist for the life of the database connection. */
db_multi_exec(
"CREATE TEMP TRIGGER protect_1 BEFORE INSERT ON config"
" WHEN protected_setting(new.name) BEGIN"
" SELECT raise(abort,'not authorized');"
"END;\n"
"CREATE TEMP TRIGGER protect_2 BEFORE UPDATE ON config"
" WHEN protected_setting(new.name) BEGIN"
" SELECT raise(abort,'not authorized');"
"END;\n"
);
db.bProtectTriggers = 1;
}
db.protectMask = flags;
}
void db_protect(unsigned flags){
db_protect_only(db.protectMask | flags);
}
void db_unprotect(unsigned flags){
if( db.nProtect>=count(db.aProtect)-2 ){
fossil_panic("too many db_unprotect() calls");
}
db.aProtect[db.nProtect++] = db.protectMask;
| > > > | > > > | 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 |
&& g.repositoryOpen
){
/* Create the triggers needed to protect sensitive settings from
** being created or modified the first time that PROTECT_SENSITIVE
** is enabled. Deleting a sensitive setting is harmless, so there
** is not trigger to block deletes. After being created once, the
** triggers persist for the life of the database connection. */
unsigned savedProtectMask = db.protectMask;
db.protectMask = 0;
db_multi_exec(
"CREATE TEMP TRIGGER protect_1 BEFORE INSERT ON config"
" WHEN protected_setting(new.name) BEGIN"
" SELECT raise(abort,'not authorized');"
"END;\n"
"CREATE TEMP TRIGGER protect_2 BEFORE UPDATE ON config"
" WHEN protected_setting(new.name) BEGIN"
" SELECT raise(abort,'not authorized');"
"END;\n"
);
db.bProtectTriggers = 1;
db.protectMask = savedProtectMask;
}
db.protectMask = flags;
}
void db_protect(unsigned flags){
db_protect_only(db.protectMask | flags);
}
void db_unprotect(unsigned flags){
if( db.nProtect>=count(db.aProtect)-2 ){
fossil_panic("too many db_unprotect() calls");
}
db.aProtect[db.nProtect++] = db.protectMask;
db.protectMask &= ~(flags|PROTECT_READONLY);
}
void db_protect_pop(void){
if( db.nProtect<1 ){
fossil_panic("too many db_protect_pop() calls");
}
db.protectMask = db.aProtect[--db.nProtect];
}
int db_is_protected(unsigned flags){
return (db.protectMask & flags)!=0;
}
/*
** Verify that the desired database write protections are in place.
** Throw a fatal error if not.
*/
void db_assert_protected(unsigned flags){
if( (flags & db.protectMask)!=flags ){
|
| ︙ | ︙ | |||
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 |
}
/*
** Every Fossil database connection automatically registers the following
** overarching authenticator callback, and leaves it registered for the
** duration of the connection. This authenticator will call any
** sub-authenticators that are registered using db_set_authorizer().
*/
int db_top_authorizer(
void *pNotUsed,
int eCode,
const char *z0,
const char *z1,
const char *z2,
const char *z3
){
int rc = SQLITE_OK;
switch( eCode ){
case SQLITE_INSERT:
case SQLITE_UPDATE:
case SQLITE_DELETE: {
if( (db.protectMask & PROTECT_USER)!=0
&& sqlite3_stricmp(z0,"user")==0 ){
rc = SQLITE_DENY;
}else if( (db.protectMask & PROTECT_CONFIG)!=0 &&
(sqlite3_stricmp(z0,"config")==0 ||
sqlite3_stricmp(z0,"global_config")==0) ){
rc = SQLITE_DENY;
}else if( (db.protectMask & PROTECT_SENSITIVE)!=0 &&
sqlite3_stricmp(z0,"global_config")==0 ){
rc = SQLITE_DENY;
}else if( (db.protectMask & PROTECT_READONLY)!=0
| > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > | 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 |
}
/*
** Every Fossil database connection automatically registers the following
** overarching authenticator callback, and leaves it registered for the
** duration of the connection. This authenticator will call any
** sub-authenticators that are registered using db_set_authorizer().
**
** == Testing Notes ==
**
** Run Fossil as using a command like this:
**
** ./fossil sql --test --errorlog -
**
** Then enter SQL commands like one of these:
**
** SELECT db_protect('user');
** SELECT db_protect('config');
** SELECT db_protect('sensitive');
** SELECT db_protect('readonly');
** SELECT db_protect('all');
**
** Then try to do SQL statements that would violate the constraints and
** verify that SECURITY warnings appear in the error log output. See
** also the sqlcmd_db_protect() function in sqlcmd.c.
*/
int db_top_authorizer(
void *pNotUsed,
int eCode,
const char *z0,
const char *z1,
const char *z2,
const char *z3
){
int rc = SQLITE_OK;
switch( eCode ){
case SQLITE_INSERT:
case SQLITE_UPDATE:
case SQLITE_DELETE: {
if( (db.protectMask & PROTECT_USER)!=0
&& sqlite3_stricmp(z0,"user")==0 ){
fossil_errorlog(
"SECURITY: authorizer blocks DML on protected USER table\n");
rc = SQLITE_DENY;
}else if( (db.protectMask & PROTECT_CONFIG)!=0 &&
(sqlite3_stricmp(z0,"config")==0 ||
sqlite3_stricmp(z0,"global_config")==0) ){
fossil_errorlog(
"SECURITY: authorizer blocks DML on protected table \"%s\"\n", z0);
rc = SQLITE_DENY;
}else if( (db.protectMask & PROTECT_SENSITIVE)!=0 &&
sqlite3_stricmp(z0,"global_config")==0 ){
fossil_errorlog(
"SECURITY: authorizer blocks DML on protected GLOBAL_CONFIG table\n");
rc = SQLITE_DENY;
}else if( (db.protectMask & PROTECT_READONLY)!=0
&& (sqlite3_stricmp(z2, "repository")==0
|| sqlite3_stricmp(z2,"configdb")==0
|| sqlite3_stricmp(z2,"localdb")==0) ){
/* The READONLY constraint only applies to persistent database files.
** "temp" and "mem1" and other transient databases are not
** constrained by READONLY. */
fossil_errorlog(
"SECURITY: authorizer blocks DML on table \"%s\" due to the "
"request coming from a different origin\n", z0);
rc = SQLITE_DENY;
}
break;
}
case SQLITE_DROP_TEMP_TRIGGER: {
/* Do not allow the triggers that enforce PROTECT_SENSITIVE
** to be dropped */
fossil_errorlog(
"SECURITY: authorizer blocks attempt to drop a temporary trigger\n");
rc = SQLITE_DENY;
break;
}
}
if( db.xAuth && rc==SQLITE_OK ){
rc = db.xAuth(db.pAuthArg, eCode, z0, z1, z2, z3);
}
|
| ︙ | ︙ | |||
865 866 867 868 869 870 871 | } /* ** COMMAND: test-db-prepare ** Usage: %fossil test-db-prepare ?OPTIONS? SQL-STATEMENT ** ** Options: | < | | | 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 |
}
/*
** COMMAND: test-db-prepare
** Usage: %fossil test-db-prepare ?OPTIONS? SQL-STATEMENT
**
** Options:
** --auth-report Enable the ticket report query authorizer
** --auth-ticket Enable the ticket schema query authorizer
**
** Invoke db_prepare() on the SQL input. Report any errors encountered.
** This command is used to verify error detection logic in the db_prepare()
** utility routine.
*/
void db_test_db_prepare(void){
const int fAuthReport = find_option("auth-report",0,0)!=0;
|
| ︙ | ︙ | |||
1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 |
**
** Note that user.pw uses a different obscuration algorithm, but
** you don't need to use 'fossil sql' for that anyway. Just call
**
** fossil user pass monkey123
**
** to change the local user entry's password in the same way.
*/
void db_obscure(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
const unsigned char *zIn = sqlite3_value_text(argv[0]);
int nIn = sqlite3_value_bytes(argv[0]);
char *zOut, *zTemp;
if( 0==zIn ) return;
if( 0==(zOut = sqlite3_malloc64( nIn * 2 + 3 )) ){
sqlite3_result_error_nomem(context);
return;
}
| > > > > > > > > > > > | | 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 |
**
** Note that user.pw uses a different obscuration algorithm, but
** you don't need to use 'fossil sql' for that anyway. Just call
**
** fossil user pass monkey123
**
** to change the local user entry's password in the same way.
**
** 2022-12-30: If the user-data pointer is not NULL, then operate
** as unobscure() rather than obscure(). The obscure() variant of
** this routine is commonly available. But unobscure is (currently)
** only registered by the "fossil remote config-data --show-passwords"
** command.
*/
void db_obscure(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
const unsigned char *zIn = sqlite3_value_text(argv[0]);
int nIn = sqlite3_value_bytes(argv[0]);
char *zOut, *zTemp;
if( 0==zIn ) return;
if( 0==(zOut = sqlite3_malloc64( nIn * 2 + 3 )) ){
sqlite3_result_error_nomem(context);
return;
}
if( sqlite3_user_data(context)==0 ){
zTemp = obscure((char*)zIn);
}else{
zTemp = unobscure((char*)zIn);
}
strcpy(zOut, zTemp);
fossil_free(zTemp);
sqlite3_result_text(context, zOut, strlen(zOut), sqlite3_free);
}
/*
** Return True if zName is a protected (a.k.a. "sensitive") setting.
*/
|
| ︙ | ︙ | |||
1477 1478 1479 1480 1481 1482 1483 | ** This is a pointer to the saved database encryption key string. */ static char *zSavedKey = 0; /* ** This is the size of the saved database encryption key, in bytes. */ | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 |
** This is a pointer to the saved database encryption key string.
*/
static char *zSavedKey = 0;
/*
** This is the size of the saved database encryption key, in bytes.
*/
static size_t savedKeySize = 0;
/*
** This function returns non-zero if there is a saved database encryption
** key available.
*/
int db_have_saved_encryption_key(){
return db_is_valid_saved_encryption_key(zSavedKey, savedKeySize);
}
/*
** This function returns non-zero if the specified database encryption key
** is valid.
*/
int db_is_valid_saved_encryption_key(const char *p, size_t n){
if( p==0 ) return 0;
if( n==0 ) return 0;
if( p[0]==0 ) return 0;
return 1;
}
/*
** This function returns the saved database encryption key -OR- zero if
** no database encryption key is saved.
*/
char *db_get_saved_encryption_key(){
return zSavedKey;
}
/*
** This function returns the size of the saved database encryption key
** -OR- zero if no database encryption key is saved.
*/
size_t db_get_saved_encryption_key_size(){
return savedKeySize;
}
/*
** This function arranges for the saved database encryption key buffer
** to be allocated and then sets up the environment variable to allow
** a child process to initialize it with the actual database encryption
** key.
*/
void db_setup_for_saved_encryption_key(){
void *p = NULL;
size_t n = 0;
size_t pageSize = 0;
Blob pidKey;
assert( !db_have_saved_encryption_key() );
db_unsave_encryption_key();
fossil_get_page_size(&pageSize);
assert( pageSize>0 );
p = fossil_secure_alloc_page(&n);
assert( p!=NULL );
assert( n==pageSize );
blob_zero(&pidKey);
blob_appendf(&pidKey, "%lu:%p:%u", (unsigned long)GETPID(), p, n);
fossil_setenv("FOSSIL_SEE_PID_KEY", blob_str(&pidKey));
zSavedKey = p;
savedKeySize = n;
}
/*
** This function arranges for the database encryption key to be securely
** saved in non-pagable memory (on platforms where this is possible).
*/
static void db_save_encryption_key(
Blob *pKey
){
void *p = NULL;
size_t n = 0;
size_t pageSize = 0;
size_t blobSize = 0;
assert( !db_have_saved_encryption_key() );
blobSize = blob_size(pKey);
if( blobSize==0 ) return;
fossil_get_page_size(&pageSize);
assert( pageSize>0 );
if( blobSize>pageSize ){
fossil_panic("key blob too large: %u versus %u", blobSize, pageSize);
}
|
| ︙ | ︙ | |||
1537 1538 1539 1540 1541 1542 1543 | savedKeySize = 0; } /* ** This function sets the saved database encryption key to the specified ** string value, allocating or freeing the underlying memory if needed. */ | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | < > > | > | | | | > | < < < < | | | | | > | | | | > | > > > > > > > > > > > > > > > > > > > | | | > > > < > | > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1675 1676 1677 1678 1679 1680 1681 1682 1683 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 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 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 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 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 |
savedKeySize = 0;
}
/*
** This function sets the saved database encryption key to the specified
** string value, allocating or freeing the underlying memory if needed.
*/
static void db_set_saved_encryption_key(
Blob *pKey
){
if( zSavedKey!=NULL ){
size_t blobSize = blob_size(pKey);
if( blobSize==0 ){
db_unsave_encryption_key();
}else{
if( blobSize>savedKeySize ){
fossil_panic("key blob too large: %u versus %u",
blobSize, savedKeySize);
}
fossil_secure_zero(zSavedKey, savedKeySize);
memcpy(zSavedKey, blob_str(pKey), blobSize);
}
}else{
db_save_encryption_key(pKey);
}
}
/*
** WEBPAGE: setseekey
**
** Sets the sets the saved database encryption key to one that gets passed
** via the "key" query string parameter. If the saved database encryption
** key has already been set, does nothing. This web page does not produce
** any output on success or failure. No permissions are required and none
** are checked (partially due to lack of encrypted database access).
**
** Query parameters:
**
** key The string to set as the saved database encryption
** key.
*/
void db_set_see_key_page(void){
Blob key;
const char *zKey;
if( db_have_saved_encryption_key() ){
fossil_trace("SEE: encryption key was already set\n");
return;
}
zKey = P("key");
blob_init(&key, 0, 0);
if( zKey!=0 ){
PID_T processId;
blob_set(&key, zKey);
db_set_saved_encryption_key(&key);
processId = db_maybe_handle_saved_encryption_key_for_process(
SEE_KEY_WRITE
);
fossil_trace("SEE: set encryption key for process %lu, length %u\n",
(unsigned long)processId, blob_size(&key));
}else{
fossil_trace("SEE: no encryption key specified\n");
}
blob_reset(&key);
}
/*
** WEBPAGE: unsetseekey
**
** Sets the saved database encryption key to zeros in the current and parent
** Fossil processes. This web page does not produce any output on success
** or failure. Setup permission is required.
*/
void db_unset_see_key_page(void){
PID_T processId;
login_check_credentials();
if( !g.perm.Setup ){ login_needed(0); return; }
processId = db_maybe_handle_saved_encryption_key_for_process(
SEE_KEY_ZERO
);
fossil_trace("SEE: unset encryption key for process %lu\n",
(unsigned long)processId);
}
/*
** This function reads the saved database encryption key from the
** specified Fossil parent process. This is only necessary (or
** functional) on Windows or Linux.
*/
static void db_read_saved_encryption_key_from_process(
PID_T processId, /* Identifier for Fossil parent process. */
LPVOID pAddress, /* Pointer to saved key buffer in the parent process. */
SIZE_T nSize /* Size of saved key buffer in the parent process. */
){
void *p = NULL;
size_t n = 0;
size_t pageSize = 0;
fossil_get_page_size(&pageSize);
assert( pageSize>0 );
if( nSize>pageSize ){
fossil_panic("key too large: %u versus %u", nSize, pageSize);
}
p = fossil_secure_alloc_page(&n);
assert( p!=NULL );
assert( n==pageSize );
assert( n>=nSize );
{
#if defined(_WIN32)
HANDLE hProcess = OpenProcess(PROCESS_VM_READ, FALSE, processId);
if( hProcess!=NULL ){
SIZE_T nRead = 0;
if( ReadProcessMemory(hProcess, pAddress, p, nSize, &nRead) ){
CloseHandle(hProcess);
if( nRead==nSize ){
db_unsave_encryption_key();
zSavedKey = p;
savedKeySize = n;
}else{
fossil_secure_free_page(p, n);
fossil_panic("bad size read, %u out of %u bytes at %p from pid %lu",
nRead, nSize, pAddress, processId);
}
}else{
CloseHandle(hProcess);
fossil_secure_free_page(p, n);
fossil_panic("failed read, %u bytes at %p from pid %lu: %lu", nSize,
pAddress, processId, GetLastError());
}
}else{
fossil_secure_free_page(p, n);
fossil_panic("failed to open pid %lu: %lu", processId, GetLastError());
}
#elif defined(__linux__)
ssize_t nRead;
struct iovec liov = {0};
struct iovec riov = {0};
liov.iov_base = p;
liov.iov_len = n;
riov.iov_base = pAddress;
riov.iov_len = nSize;
nRead = process_vm_readv(processId, &liov, 1, &riov, 1, 0);
if( nRead==nSize ){
db_unsave_encryption_key();
zSavedKey = p;
savedKeySize = n;
}else{
fossil_secure_free_page(p, n);
fossil_panic("bad size read, %zd out of %zu bytes at %p from pid %lu",
nRead, nSize, pAddress, (unsigned long)processId);
}
#else
fossil_secure_free_page(p, n);
fossil_trace("db_read_saved_encryption_key_from_process unsupported");
#endif
}
}
/*
** This function writes the saved database encryption key into the
** specified Fossil parent process. This is only necessary (or
** functional) on Windows or Linux.
*/
static void db_write_saved_encryption_key_to_process(
PID_T processId, /* Identifier for Fossil parent process. */
LPVOID pAddress, /* Pointer to saved key buffer in the parent process. */
SIZE_T nSize /* Size of saved key buffer in the parent process. */
){
void *p = db_get_saved_encryption_key();
size_t n = db_get_saved_encryption_key_size();
size_t pageSize = 0;
fossil_get_page_size(&pageSize);
assert( pageSize>0 );
if( nSize>pageSize ){
fossil_panic("key too large: %u versus %u", nSize, pageSize);
}
assert( p!=NULL );
assert( n==pageSize );
assert( n>=nSize );
{
#if defined(_WIN32)
HANDLE hProcess = OpenProcess(PROCESS_VM_OPERATION|PROCESS_VM_WRITE,
FALSE, processId);
if( hProcess!=NULL ){
SIZE_T nWrite = 0;
if( WriteProcessMemory(hProcess, pAddress, p, nSize, &nWrite) ){
CloseHandle(hProcess);
if( nWrite!=nSize ){
fossil_panic("bad size write, %u out of %u bytes at %p from pid %lu",
nWrite, nSize, pAddress, processId);
}
}else{
CloseHandle(hProcess);
fossil_panic("failed write, %u bytes at %p from pid %lu: %lu", nSize,
pAddress, processId, GetLastError());
}
}else{
fossil_panic("failed to open pid %lu: %lu", processId, GetLastError());
}
#elif defined(__linux__)
ssize_t nWrite;
struct iovec liov = {0};
struct iovec riov = {0};
liov.iov_base = p;
liov.iov_len = n;
riov.iov_base = pAddress;
riov.iov_len = nSize;
nWrite = process_vm_writev(processId, &liov, 1, &riov, 1, 0);
if( nWrite!=nSize ){
fossil_panic("bad size write, %zd out of %zu bytes at %p from pid %lu",
nWrite, nSize, pAddress, (unsigned long)processId);
}
#else
fossil_trace("db_write_saved_encryption_key_to_process unsupported");
#endif
}
}
/*
** This function zeros the saved database encryption key in the specified
** Fossil parent process. This is only necessary (or functional) on
** Windows or Linux.
*/
static void db_zero_saved_encryption_key_in_process(
PID_T processId, /* Identifier for Fossil parent process. */
LPVOID pAddress, /* Pointer to saved key buffer in the parent process. */
SIZE_T nSize /* Size of saved key buffer in the parent process. */
){
void *p = NULL;
size_t n = 0;
size_t pageSize = 0;
fossil_get_page_size(&pageSize);
assert( pageSize>0 );
if( nSize>pageSize ){
fossil_panic("key too large: %u versus %u", nSize, pageSize);
}
p = fossil_secure_alloc_page(&n);
assert( p!=NULL );
assert( n==pageSize );
assert( n>=nSize );
{
#if defined(_WIN32)
HANDLE hProcess = OpenProcess(PROCESS_VM_OPERATION|PROCESS_VM_WRITE,
FALSE, processId);
if( hProcess!=NULL ){
SIZE_T nWrite = 0;
if( WriteProcessMemory(hProcess, pAddress, p, nSize, &nWrite) ){
CloseHandle(hProcess);
fossil_secure_free_page(p, n);
if( nWrite!=nSize ){
fossil_panic("bad size zero, %u out of %u bytes at %p from pid %lu",
nWrite, nSize, pAddress, processId);
}
}else{
CloseHandle(hProcess);
fossil_secure_free_page(p, n);
fossil_panic("failed zero, %u bytes at %p from pid %lu: %lu", nSize,
pAddress, processId, GetLastError());
}
}else{
fossil_secure_free_page(p, n);
fossil_panic("failed to open pid %lu: %lu", processId, GetLastError());
}
#elif defined(__linux__)
ssize_t nWrite;
struct iovec liov = {0};
struct iovec riov = {0};
liov.iov_base = p;
liov.iov_len = n;
riov.iov_base = pAddress;
riov.iov_len = nSize;
nWrite = process_vm_writev(processId, &liov, 1, &riov, 1, 0);
if( nWrite!=nSize ){
fossil_secure_free_page(p, n);
fossil_panic("bad size zero, %zd out of %zu bytes at %p from pid %lu",
nWrite, nSize, pAddress, (unsigned long)processId);
}
#else
fossil_secure_free_page(p, n);
fossil_trace("db_zero_saved_encryption_key_in_process unsupported");
#endif
}
}
/*
** This function evaluates the specified TH1 script and attempts to parse
** its result as a colon-delimited triplet containing a process identifier,
** address, and size (in bytes) of the database encryption key. This is
** only necessary (or functional) on Windows or Linux.
*/
static PID_T db_handle_saved_encryption_key_for_process_via_th1(
const char *zConfig, /* The TH1 script to evaluate. */
int eType /* Non-zero to write key to parent process -OR-
* zero to read it from the parent process. */
){
PID_T processId = 0;
int rc;
char *zResult;
char *zPwd = file_getcwd(0, 0);
Th_FossilInit(TH_INIT_DEFAULT | TH_INIT_NEED_CONFIG | TH_INIT_NO_REPO);
rc = Th_Eval(g.interp, 0, zConfig, -1);
zResult = (char*)Th_GetResult(g.interp, 0);
if( rc!=TH_OK ){
fossil_fatal("script for pid key failed: %s", zResult);
}
if( zResult ){
LPVOID pAddress = NULL;
SIZE_T nSize = 0;
parse_pid_key_value(zResult, &processId, &pAddress, &nSize);
if( eType==SEE_KEY_READ ){
db_read_saved_encryption_key_from_process(processId, pAddress, nSize);
}else if( eType==SEE_KEY_WRITE ){
db_write_saved_encryption_key_to_process(processId, pAddress, nSize);
}else if( eType==SEE_KEY_ZERO ){
db_zero_saved_encryption_key_in_process(processId, pAddress, nSize);
}else{
fossil_panic("unsupported SEE key operation %d", eType);
}
}
file_chdir(zPwd, 0);
fossil_free(zPwd);
return processId;
}
/*
** This function sets the saved database encryption key to one that gets
** read from the specified Fossil parent process, if applicable. This is
** only necessary (or functional) on Windows or Linux.
*/
PID_T db_maybe_handle_saved_encryption_key_for_process(int eType){
PID_T processId = 0;
g.zPidKey = find_option("usepidkey",0,1);
if( !g.zPidKey ){
g.zPidKey = fossil_getenv("FOSSIL_SEE_PID_KEY");
}
if( g.zPidKey ){
LPVOID pAddress = NULL;
SIZE_T nSize = 0;
parse_pid_key_value(g.zPidKey, &processId, &pAddress, &nSize);
if( eType==SEE_KEY_READ ){
db_read_saved_encryption_key_from_process(processId, pAddress, nSize);
}else if( eType==SEE_KEY_WRITE ){
db_write_saved_encryption_key_to_process(processId, pAddress, nSize);
}else if( eType==SEE_KEY_ZERO ){
db_zero_saved_encryption_key_in_process(processId, pAddress, nSize);
}else{
fossil_panic("unsupported SEE key operation %d", eType);
}
}else{
const char *zSeeDbConfig = find_option("seedbcfg",0,1);
if( !zSeeDbConfig ){
zSeeDbConfig = fossil_getenv("FOSSIL_SEE_DB_CONFIG");
}
if( zSeeDbConfig ){
processId = db_handle_saved_encryption_key_for_process_via_th1(
zSeeDbConfig, eType
);
}
}
return processId;
}
#endif /* USE_SEE */
/*
** If the database file zDbFile has a name that suggests that it is
** encrypted, then prompt for the database encryption key and return it
** in the blob *pKey. Or, if the encryption key has previously been
** requested, just return a copy of the previous result. The blob in
|
| ︙ | ︙ | |||
1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 |
db, "if_selected", 3, SQLITE_UTF8, 0, file_is_selected,0,0
);
if( g.fSqlTrace ) sqlite3_trace_v2(db, SQLITE_TRACE_PROFILE, db_sql_trace, 0);
db_add_aux_functions(db);
re_add_sql_func(db); /* The REGEXP operator */
foci_register(db); /* The "files_of_checkin" virtual table */
sqlite3_set_authorizer(db, db_top_authorizer, db);
return db;
}
/*
** Detaches the zLabel database.
*/
| > | 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 |
db, "if_selected", 3, SQLITE_UTF8, 0, file_is_selected,0,0
);
if( g.fSqlTrace ) sqlite3_trace_v2(db, SQLITE_TRACE_PROFILE, db_sql_trace, 0);
db_add_aux_functions(db);
re_add_sql_func(db); /* The REGEXP operator */
foci_register(db); /* The "files_of_checkin" virtual table */
sqlite3_set_authorizer(db, db_top_authorizer, db);
db_register_fts5(db) /* in search.c */;
return db;
}
/*
** Detaches the zLabel database.
*/
|
| ︙ | ︙ | |||
2050 2051 2052 2053 2054 2055 2056 | i64 lsize; if( file_access(zDbName, F_OK) ) return 0; lsize = file_size(zDbName, ExtFILE); if( lsize%1024!=0 || lsize<4096 ) return 0; db_open_or_attach(zDbName, "localdb"); | | | | | 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 |
i64 lsize;
if( file_access(zDbName, F_OK) ) return 0;
lsize = file_size(zDbName, ExtFILE);
if( lsize%1024!=0 || lsize<4096 ) return 0;
db_open_or_attach(zDbName, "localdb");
/* Check to see if the check-out database has the lastest schema changes.
** The most recent schema change (2019-01-19) is the addition of the
** vmerge.mhash and vfile.mhash fields. If the schema has the vmerge.mhash
** column, assume everything else is up-to-date.
*/
if( db_table_has_column("localdb","vmerge","mhash") ){
return 1; /* This is a check-out database with the latest schema */
}
/* If there is no vfile table, then assume we have picked up something
** that is not even close to being a valid check-out database */
if( !db_table_exists("localdb","vfile") ){
return 0; /* Not a DB */
}
/* If the "isexe" column is missing from the vfile table, then
** add it now. This code added on 2010-03-06. After all users have
** upgraded, this code can be safely deleted.
|
| ︙ | ︙ | |||
2090 2091 2092 2093 2094 2095 2096 |
db_multi_exec("ALTER TABLE undo ADD COLUMN isLink BOOLEAN DEFAULT 0");
}
if( db_local_table_exists_but_lacks_column("undo_vfile", "islink") ){
db_multi_exec("ALTER TABLE undo_vfile ADD COLUMN islink BOOL DEFAULT 0");
}
}
| | | 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 |
db_multi_exec("ALTER TABLE undo ADD COLUMN isLink BOOLEAN DEFAULT 0");
}
if( db_local_table_exists_but_lacks_column("undo_vfile", "islink") ){
db_multi_exec("ALTER TABLE undo_vfile ADD COLUMN islink BOOL DEFAULT 0");
}
}
/* The design of the check-out database changed on 2019-01-19, adding the mhash
** column to vfile and vmerge and changing the UNIQUE index on vmerge into
** a PRIMARY KEY that includes the new mhash column. However, we must have
** the repository database at hand in order to do the migration, so that
** step is deferred. */
return 1;
}
|
| ︙ | ︙ | |||
2112 2113 2114 2115 2116 2117 2118 | ** ** If no valid _FOSSIL_ or .fslckout file is found, we move up one level and ** try again. Once the file is found, the g.zLocalRoot variable is set ** to the root of the repository tree and this routine returns 1. If ** no database is found, then this routine return 0. ** ** In db_open_local_v2(), if the bRootOnly flag is true, then only | | | 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 |
**
** If no valid _FOSSIL_ or .fslckout file is found, we move up one level and
** try again. Once the file is found, the g.zLocalRoot variable is set
** to the root of the repository tree and this routine returns 1. If
** no database is found, then this routine return 0.
**
** In db_open_local_v2(), if the bRootOnly flag is true, then only
** look in the CWD for the check-out database. Do not scan upwards in
** the file hierarchy.
**
** This routine always opens the user database regardless of whether or
** not the repository database is found. If the _FOSSIL_ or .fslckout file
** is found, it is attached to the open database connection too.
*/
int db_open_local_v2(const char *zDbName, int bRootOnly){
|
| ︙ | ︙ | |||
2134 2135 2136 2137 2138 2139 2140 |
while( n>0 ){
for(i=0; i<count(aDbName); i++){
sqlite3_snprintf(sizeof(zPwd)-n, &zPwd[n], "/%s", aDbName[i]);
if( isValidLocalDb(zPwd) ){
if( db_open_config(0, 1)==0 ){
return 0; /* Configuration could not be opened */
}
| | | | 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 |
while( n>0 ){
for(i=0; i<count(aDbName); i++){
sqlite3_snprintf(sizeof(zPwd)-n, &zPwd[n], "/%s", aDbName[i]);
if( isValidLocalDb(zPwd) ){
if( db_open_config(0, 1)==0 ){
return 0; /* Configuration could not be opened */
}
/* Found a valid check-out database file */
g.zLocalDbName = mprintf("%s", zPwd);
zPwd[n] = 0;
while( n>0 && zPwd[n-1]=='/' ){
n--;
zPwd[n] = 0;
}
g.zLocalRoot = mprintf("%s/", zPwd);
g.localOpen = 1;
db_open_repository(zDbName);
return 1;
}
}
if( bRootOnly ) break;
n--;
while( n>1 && zPwd[n]!='/' ){ n--; }
while( n>1 && zPwd[n-1]=='/' ){ n--; }
zPwd[n] = 0;
}
/* A check-out database file could not be found */
return 0;
}
int db_open_local(const char *zDbName){
return db_open_local_v2(zDbName, 0);
}
/*
|
| ︙ | ︙ | |||
2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 |
g.zAuxSchema = db_get("aux-schema","");
g.eHashPolicy = db_get_int("hash-policy",-1);
if( g.eHashPolicy<0 ){
g.eHashPolicy = hname_default_policy();
db_set_int("hash-policy", g.eHashPolicy, 0);
}
/* Make a change to the CHECK constraint on the BLOB table for
** version 2.0 and later.
*/
rebuild_schema_update_2_0(); /* Do the Fossil-2.0 schema updates */
| > > | | | 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 |
g.zAuxSchema = db_get("aux-schema","");
g.eHashPolicy = db_get_int("hash-policy",-1);
if( g.eHashPolicy<0 ){
g.eHashPolicy = hname_default_policy();
db_set_int("hash-policy", g.eHashPolicy, 0);
}
#if 0 /* No longer automatic. Need to run "fossil rebuild" to migrate */
/* Make a change to the CHECK constraint on the BLOB table for
** version 2.0 and later.
*/
rebuild_schema_update_2_0(); /* Do the Fossil-2.0 schema updates */
#endif
/* Additional checks that occur when opening the check-out database */
if( g.localOpen ){
/* If the repository database that was just opened has been
** eplaced by a clone of the same project, with different RID
** values, then renumber the RID values stored in various tables
** of the check-out database, so that the repository and check-out
** databases align.
*/
if( !db_fingerprint_ok() ){
if( find_option("no-rid-adjust",0,0)!=0 ){
/* The --no-rid-adjust command-line option bypasses the RID value
** updates. Intended for use during debugging, especially to be
** able to run "fossil sql" after a database swap. */
|
| ︙ | ︙ | |||
2331 2332 2333 2334 2335 2336 2337 |
fossil_print(
"WARNING: The repository database has been replaced by a clone.\n"
"Bisect history and undo have been lost.\n"
);
}
}
| | | 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 |
fossil_print(
"WARNING: The repository database has been replaced by a clone.\n"
"Bisect history and undo have been lost.\n"
);
}
}
/* Make sure the check-out database schema migration of 2019-01-20
** has occurred.
**
** The 2019-01-19 migration is the addition of the vmerge.mhash and
** vfile.mhash columns and making the vmerge.mhash column part of the
** PRIMARY KEY for vmerge.
*/
if( !db_table_has_column("localdb", "vfile", "mhash") ){
|
| ︙ | ︙ | |||
2386 2387 2388 2389 2390 2391 2392 | #define OPEN_ANY_SCHEMA 0x002 /* Do not error if schema is wrong */ #define OPEN_SUBSTITUTE 0x004 /* Fake in-memory repo if not found */ #endif /* ** Try to find the repository and open it. Use the -R or --repository ** option to locate the repository. If no such option is available, then | | | 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 |
#define OPEN_ANY_SCHEMA 0x002 /* Do not error if schema is wrong */
#define OPEN_SUBSTITUTE 0x004 /* Fake in-memory repo if not found */
#endif
/*
** Try to find the repository and open it. Use the -R or --repository
** option to locate the repository. If no such option is available, then
** use the repository of the open check-out if there is one.
**
** Error out if the repository cannot be opened.
*/
void db_find_and_open_repository(int bFlags, int nArgUsed){
const char *zRep = find_repository_option();
if( zRep && file_isdir(zRep, ExtFILE)==1 ){
goto rep_not_found;
|
| ︙ | ︙ | |||
2469 2470 2471 2472 2473 2474 2475 | /* ** COMMAND: test-move-repository ** ** Usage: %fossil test-move-repository PATHNAME ** ** Change the location of the repository database on a local check-out. | | | | | 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 |
/*
** COMMAND: test-move-repository
**
** Usage: %fossil test-move-repository PATHNAME
**
** Change the location of the repository database on a local check-out.
** Use this command to avoid having to close and reopen a check-out
** when relocating the repository database.
*/
void move_repo_cmd(void){
Blob repo;
char *zRepo;
if( g.argc!=3 ){
usage("PATHNAME");
}
file_canonical_name(g.argv[2], &repo, 0);
zRepo = blob_str(&repo);
if( file_access(zRepo, F_OK) ){
fossil_fatal("no such file: %s", zRepo);
}
if( db_open_local(zRepo)==0 ){
fossil_fatal("not in a local check-out");
return;
}
db_open_or_attach(zRepo, "test_repo");
db_lset("repository", blob_str(&repo));
db_record_repository_filename(blob_str(&repo));
db_close(1);
}
/*
** Open the local database. If unable, exit with an error.
*/
void db_must_be_within_tree(void){
if( find_repository_option() ){
fossil_fatal("the \"%s\" command only works from within an open check-out",
g.argv[1]);
}
if( db_open_local(0)==0 ){
fossil_fatal("current directory is not within an open check-out");
}
db_open_repository(0);
db_verify_schema();
}
/*
** Close the database connection.
|
| ︙ | ︙ | |||
2663 2664 2665 2666 2667 2668 2669 |
db_multi_exec(
"UPDATE user SET cap='s', pw=%Q"
" WHERE login=%Q", fossil_random_password(10), zUser
);
if( !setupUserOnly ){
db_multi_exec(
"INSERT OR IGNORE INTO user(login,pw,cap,info)"
| | | 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 |
db_multi_exec(
"UPDATE user SET cap='s', pw=%Q"
" WHERE login=%Q", fossil_random_password(10), zUser
);
if( !setupUserOnly ){
db_multi_exec(
"INSERT OR IGNORE INTO user(login,pw,cap,info)"
" VALUES('anonymous',hex(randomblob(8)),'hz','Anon');"
"INSERT OR IGNORE INTO user(login,pw,cap,info)"
" VALUES('nobody','','gjorz','Nobody');"
"INSERT OR IGNORE INTO user(login,pw,cap,info)"
" VALUES('developer','','ei','Dev');"
"INSERT OR IGNORE INTO user(login,pw,cap,info)"
" VALUES('reader','','kptw','Reader');"
);
|
| ︙ | ︙ | |||
2836 2837 2838 2839 2840 2841 2842 | ** associated permissions will be copied. ** ** Options: ** --template FILE Copy settings from repository file ** -A|--admin-user USERNAME Select given USERNAME as admin user ** --date-override DATETIME Use DATETIME as time of the initial check-in ** --sha1 Use an initial hash policy of "sha1" | | > | > | > | 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 |
** associated permissions will be copied.
**
** Options:
** --template FILE Copy settings from repository file
** -A|--admin-user USERNAME Select given USERNAME as admin user
** --date-override DATETIME Use DATETIME as time of the initial check-in
** --sha1 Use an initial hash policy of "sha1"
** --project-name STRING The name of the project "project name in
** quotes"
** --project-desc STRING The description of the project "project
** description in quotes"
**
** 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.
**
** See also: [[clone]]
*/
void create_repository_cmd(void){
char *zPassword;
const char *zTemplate; /* Repository from which to copy settings */
const char *zDate; /* Date of the initial check-in */
const char *zDefaultUser; /* Optional name of the default user */
const char *zProjectName; /* Optional project name of the repo */
const char *zProjectDesc; /* Optional project description "description
** of project in quotes" */
int bUseSha1 = 0; /* True to set the hash-policy to sha1 */
zTemplate = find_option("template",0,1);
zDate = find_option("date-override",0,1);
zDefaultUser = find_option("admin-user","A",1);
bUseSha1 = find_option("sha1",0,0)!=0;
|
| ︙ | ︙ | |||
2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 |
if( zProjectName ) fossil_print("project-name: %s\n", zProjectName);
if( zProjectDesc ) fossil_print("project-description: %s\n", zProjectDesc);
fossil_print("project-id: %s\n", db_get("project-code", 0));
fossil_print("server-id: %s\n", db_get("server-code", 0));
zPassword = db_text(0, "SELECT pw FROM user WHERE login=%Q", g.zLogin);
fossil_print("admin-user: %s (initial password is \"%s\")\n",
g.zLogin, zPassword);
}
/*
** SQL functions for debugging.
**
** The print() function writes its arguments on stdout, but only
** if the -sqlprint command-line option is turned on.
| > | 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 |
if( zProjectName ) fossil_print("project-name: %s\n", zProjectName);
if( zProjectDesc ) fossil_print("project-description: %s\n", zProjectDesc);
fossil_print("project-id: %s\n", db_get("project-code", 0));
fossil_print("server-id: %s\n", db_get("server-code", 0));
zPassword = db_text(0, "SELECT pw FROM user WHERE login=%Q", g.zLogin);
fossil_print("admin-user: %s (initial password is \"%s\")\n",
g.zLogin, zPassword);
hash_user_password(g.zLogin);
}
/*
** SQL functions for debugging.
**
** The print() function writes its arguments on stdout, but only
** if the -sqlprint command-line option is turned on.
|
| ︙ | ︙ | |||
3187 3188 3189 3190 3191 3192 3193 |
while( cacheEntry!=0 ){
if( fossil_strcmp(cacheEntry->zName, zName)==0 ){
zVersionedSetting = fossil_strdup(cacheEntry->zValue);
break;
}
cacheEntry = cacheEntry->next;
}
| | | 3590 3591 3592 3593 3594 3595 3596 3597 3598 3599 3600 3601 3602 3603 3604 |
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_zero(&versionedPathname);
blob_zero(&setting);
blob_appendf(&versionedPathname, "%s.fossil-settings/%s",
g.zLocalRoot, zName);
|
| ︙ | ︙ | |||
3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 |
blob_append(&versionedPathname, ".no-warn", -1);
if( file_size(blob_str(&versionedPathname), ExtFILE)>=0 ){
noWarn = 1;
}
}
blob_reset(&versionedPathname);
if( found ){
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 */
cacheEntry = (struct _cacheEntry*)fossil_malloc(sizeof(struct _cacheEntry));
| > | 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 |
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 */
cacheEntry = (struct _cacheEntry*)fossil_malloc(sizeof(struct _cacheEntry));
|
| ︙ | ︙ | |||
3294 3295 3296 3297 3298 3299 3300 |
if( db_step(&q2)==SQLITE_ROW && (zRes = db_column_text(&q2,0))!=0 ){
z = fossil_strdup(zRes);
}
db_reset(&q2);
}
if( pSetting!=0 && pSetting->versionable ){
/* This is a versionable setting, try and get the info from a
| | | 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 |
if( db_step(&q2)==SQLITE_ROW && (zRes = db_column_text(&q2,0))!=0 ){
z = fossil_strdup(zRes);
}
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);
if(zZ != z){
fossil_free(zZ);
}
}
if( z==0 ){
|
| ︙ | ︙ | |||
3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 |
z = fossil_strdup(zDefault);
}else if( zFormat!=0 ){
z = db_text(0, "SELECT strftime(%Q,%Q,'unixepoch');", zFormat, z);
}
return z;
}
void db_set(const char *zName, const char *zValue, int globalFlag){
db_assert_protection_off_or_not_sensitive(zName);
db_unprotect(PROTECT_CONFIG);
db_begin_transaction();
if( globalFlag ){
db_swap_connections();
db_multi_exec("REPLACE INTO global_config(name,value) VALUES(%Q,%Q)",
zName, zValue);
db_swap_connections();
| > > > > > > > > > > | 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 |
z = fossil_strdup(zDefault);
}else if( zFormat!=0 ){
z = db_text(0, "SELECT strftime(%Q,%Q,'unixepoch');", zFormat, z);
}
return z;
}
void db_set(const char *zName, const char *zValue, int globalFlag){
const CmdOrPage *pCmd = 0;
db_assert_protection_off_or_not_sensitive(zName);
if( zValue!=0 && zValue[0]==0
&& dispatch_name_search(zName, CMDFLAG_SETTING, &pCmd)==0
&& (pCmd->eCmdFlags & CMDFLAG_KEEPEMPTY)==0
){
/* Changing a setting to an empty string is the same as unsetting it,
** unless that setting has the keep-empty flag. */
db_unset(zName/*works-like:"x"*/, globalFlag);
return;
}
db_unprotect(PROTECT_CONFIG);
db_begin_transaction();
if( globalFlag ){
db_swap_connections();
db_multi_exec("REPLACE INTO global_config(name,value) VALUES(%Q,%Q)",
zName, zValue);
db_swap_connections();
|
| ︙ | ︙ | |||
3586 3587 3588 3589 3590 3591 3592 | ** The repository filename %s is recorded as an entry with a "name" field ** of the following form: ** ** repo:%s ** ** The value field is set to 1. ** | | | | 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 |
** The repository filename %s is recorded as an entry with a "name" field
** of the following form:
**
** repo:%s
**
** The value field is set to 1.
**
** If running from a local check-out, also record the root of the check-out
** as follows:
**
** ckout:%s
**
** Where %s is the check-out root. The value is the repository file.
*/
void db_record_repository_filename(const char *zName){
char *zRepoSetting;
char *zCkoutSetting;
Blob full;
if( zName==0 ){
if( !g.localOpen ) return;
|
| ︙ | ︙ | |||
3656 3657 3658 3659 3660 3661 3662 | } /* ** COMMAND: open ** ** Usage: %fossil open REPOSITORY ?VERSION? ?OPTIONS? ** | | | 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 | } /* ** COMMAND: open ** ** Usage: %fossil open REPOSITORY ?VERSION? ?OPTIONS? ** ** Open a new connection to the repository name REPOSITORY. A check-out ** for the repository is created with its root at the current working ** directory, or in DIR if the "--workdir DIR" is used. If VERSION is ** specified then that version is checked out. Otherwise the most recent ** check-in on the main branch (usually "trunk") is used. ** ** REPOSITORY can be the filename for a repository that already exists on the ** local machine or it can be a URI for a remote repository. If REPOSITORY |
| ︙ | ︙ | |||
3678 3679 3680 3681 3682 3683 3684 | ** fossil open https://fossil-scm.org/home/new-name ** ** The base URI for cloning is "https://fossil-scm.org/home". The extra ** "new-name" term means that the cloned repository will be called ** "new-name.fossil". ** ** Options: | | | | | | < < | | 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 |
** fossil open https://fossil-scm.org/home/new-name
**
** The base URI for cloning is "https://fossil-scm.org/home". The extra
** "new-name" term means that the cloned repository will be called
** "new-name.fossil".
**
** Options:
** --empty Initialize check-out as being empty, but still connected
** with the local repository. If you commit this check-out,
** it will become a new "initial" commit in the repository.
** -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
** --workdir DIR Use DIR as the working directory instead of ".". The DIR
** directory is created if it does not exist.
**
** See also: [[close]], [[clone]]
*/
void cmd_open(void){
int emptyFlag;
|
| ︙ | ︙ | |||
3881 3882 3883 3884 3885 3886 3887 | info_cmd(); } /* ** Print the current value of a setting identified by the pSetting ** pointer. */ | | > > > > > > > > > > > > > > > > > > > | | > > > < < | < < < < | | < | 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302 4303 4304 4305 4306 4307 4308 4309 4310 4311 4312 4313 4314 4315 4316 4317 4318 4319 4320 4321 4322 4323 4324 4325 4326 4327 4328 4329 4330 4331 4332 4333 4334 4335 4336 4337 4338 4339 4340 4341 4342 4343 4344 4345 4346 4347 4348 4349 4350 4351 4352 |
info_cmd();
}
/*
** Print the current value of a setting identified by the pSetting
** pointer.
*/
void print_setting(const Setting *pSetting, int valueOnly){
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 ){
fossil_print("%s\n", db_get_versioned(pSetting->name, NULL));
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 ){
if( valueOnly ){
fossil_print("%s\n", db_column_text(&q, 1));
}else{
fossil_print("%-20s %-8s %s\n", pSetting->name, db_column_text(&q, 0),
db_column_text(&q, 1));
}
}else if( valueOnly ){
fossil_print("\n");
}else{
fossil_print("%-20s\n", pSetting->name);
}
if( versioned ){
fossil_print(" (overridden by contents of file .fossil-settings/%s)\n",
pSetting->name);
}
db_finalize(&q);
}
#if INTERFACE
/*
** Define all settings, which can be controlled via the set/unset
|
| ︙ | ︙ | |||
4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 |
**
** on Always autosync for command where autosync
** makes sense ("commit", "merge", "open", "update")
**
** off Never autosync.
**
** pullonly Only to pull autosyncs
**
** on,open=off Autosync for most commands, but not for "open"
**
** off,commit=pullonly Do not autosync, except do a pull before each
** "commit", presumably to avoid undesirable
** forks.
**
| > > | 4470 4471 4472 4473 4474 4475 4476 4477 4478 4479 4480 4481 4482 4483 4484 4485 |
**
** on Always autosync for command where autosync
** makes sense ("commit", "merge", "open", "update")
**
** off Never autosync.
**
** pullonly Only to pull autosyncs
**
** all Sync with all remotes
**
** on,open=off Autosync for most commands, but not for "open"
**
** off,commit=pullonly Do not autosync, except do a pull before each
** "commit", presumably to avoid undesirable
** forks.
**
|
| ︙ | ︙ | |||
4089 4090 4091 4092 4093 4094 4095 | ** If backoffice-logfile is not an empty string and is a valid ** filename, then a one-line message is appended to that file ** every time the backoffice runs. This can be used for debugging, ** to ensure that backoffice is running appropriately. */ /* ** SETTING: binary-glob width=40 versionable block-text | | | | > | 4518 4519 4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535 | ** If backoffice-logfile is not an empty string and is a valid ** filename, then a one-line message is appended to that file ** every time the backoffice runs. This can be used for debugging, ** to ensure that backoffice is running appropriately. */ /* ** SETTING: binary-glob width=40 versionable block-text ** The VALUE of this setting is a list of GLOB patterns matching files ** that should be treated as "binary" for committing and merging ** purposes. Example: *.jpg,*.png The parsing rules are complex; ** see https://fossil-scm.org/home/doc/trunk/www/globs.md#syntax */ #if defined(_WIN32)||defined(__CYGWIN__)||defined(__DARWIN__) /* ** SETTING: case-sensitive boolean default=off ** If TRUE, the files whose names differ only in case ** are considered distinct. If FALSE files whose names ** differ only in case are the same file. Defaults to |
| ︙ | ︙ | |||
4113 4114 4115 4116 4117 4118 4119 | ** are considered distinct. If FALSE files whose names ** differ only in case are the same file. Defaults to ** TRUE for unix and FALSE for Cygwin, Mac and Windows. */ #endif /* ** SETTING: clean-glob width=40 versionable block-text | | | < | > | 4543 4544 4545 4546 4547 4548 4549 4550 4551 4552 4553 4554 4555 4556 4557 4558 4559 4560 | ** are considered distinct. If FALSE files whose names ** differ only in case are the same file. Defaults to ** TRUE for unix and FALSE for Cygwin, Mac and Windows. */ #endif /* ** SETTING: clean-glob width=40 versionable block-text ** The VALUE of this setting is a list of GLOB patterns matching files ** that the "clean" command will delete without prompting or allowing ** undo. Example: *.a,*.o,*.so The parsing rules are complex; ** see https://fossil-scm.org/home/doc/trunk/www/globs.md#syntax */ /* ** SETTING: clearsign boolean default=off ** When enabled, fossil will attempt to sign all commits ** with gpg. When disabled, commits will be unsigned. */ /* |
| ︙ | ︙ | |||
4148 4149 4150 4151 4152 4153 4154 | ** printing format (i.e. set to "0", or a combination not including "1"). ** ** Note: The options for timeline comments displayed on the web UI can be ** configured through the /setup_timeline web page. */ /* ** SETTING: crlf-glob width=40 versionable block-text | | | > | | > > > > > | | | | | < | | | > | | | > | > > > > > > > > > > > > > > > > | 4578 4579 4580 4581 4582 4583 4584 4585 4586 4587 4588 4589 4590 4591 4592 4593 4594 4595 4596 4597 4598 4599 4600 4601 4602 4603 4604 4605 4606 4607 4608 4609 4610 4611 4612 4613 4614 4615 4616 4617 4618 4619 4620 4621 4622 4623 4624 4625 4626 4627 4628 4629 4630 4631 4632 4633 4634 4635 4636 4637 4638 4639 4640 4641 4642 4643 4644 4645 4646 4647 4648 4649 4650 4651 4652 4653 4654 4655 4656 4657 4658 4659 4660 4661 4662 4663 4664 4665 4666 4667 4668 4669 4670 4671 4672 4673 4674 4675 4676 4677 4678 4679 4680 4681 4682 4683 4684 4685 4686 4687 4688 4689 4690 4691 4692 4693 | ** printing format (i.e. set to "0", or a combination not including "1"). ** ** Note: The options for timeline comments displayed on the web UI can be ** configured through the /setup_timeline web page. */ /* ** 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 ** The crnl-glob setting is a compatibility alias. */ /* ** SETTING: crnl-glob width=40 versionable block-text ** This is an alias for the crlf-glob setting. */ /* ** SETTING: default-perms width=16 default=u sensitive keep-empty ** Permissions given automatically to new users. For more ** information on permissions see the Users page in Server ** Administration of the HTTP UI. */ /* ** SETTING: diff-binary boolean default=on ** If enabled, permit files that may be binary ** or that match the "binary-glob" setting to be used with ** external diff programs. If disabled, skip these files. */ /* ** SETTING: diff-command width=40 sensitive ** The value is an external command to run when performing a diff. ** If undefined, the internal text diff will be used. */ /* ** SETTING: dont-commit boolean default=off ** If enabled, prevent committing to this repository, as an extra precaution ** against accidentally checking in to a repository intended to be read-only. */ /* ** SETTING: dont-push boolean default=off ** If enabled, prevent this repository from pushing from client to ** server. This can be used as an extra precaution to prevent ** accidental pushes to a public server from a private clone. */ /* ** 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. */ /* ** SETTING: encoding-glob width=40 versionable block-text ** The VALUE of this setting is a list of GLOB patterns matching files that ** the "commit" command will ignore when issuing warnings about text files ** that may use another encoding than ASCII or UTF-8. Set to "*" to disable ** encoding checking. Example: *.md,*.txt The parsing rules are complex; ** see https://fossil-scm.org/home/doc/trunk/www/globs.md#syntax */ #if defined(FOSSIL_ENABLE_EXEC_REL_PATHS) /* ** SETTING: exec-rel-paths boolean default=on ** When executing certain external commands (e.g. diff and ** gdiff), use relative paths. */ #endif #if !defined(FOSSIL_ENABLE_EXEC_REL_PATHS) /* ** SETTING: exec-rel-paths boolean default=off ** When executing certain external commands (e.g. diff and ** gdiff), use relative paths. */ #endif /* ** SETTING: fileedit-glob width=40 block-text ** The VALUE of this setting is a list of GLOB patterns matching files ** which are allowed to be edited using the /fileedit page. An empty list ** suppresses the feature. Example: *.md,*.txt The parsing rules are ** complex; see https://fossil-scm.org/home/doc/trunk/www/globs.md#syntax ** Note that /fileedit cannot edit binary files, so the list should not ** contain any globs for, e.g., images or PDFs. */ /* ** SETTING: forbid-delta-manifests boolean default=off ** If enabled on a client, new delta manifests are prohibited on ** 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: forum-close-policy boolean default=off ** If true, forum moderators may close/re-open forum posts, and reply ** to closed posts. If false, only administrators may do so. Note that ** this only affects the forum web UI, not post-closing tags which ** arrive via the command-line or from synchronization with a remote. */ /* ** SETTING: gdiff-command width=40 default=gdiff sensitive ** The value is an external command to run when performing a graphical ** diff. If undefined, text diff will be used. */ /* ** SETTING: gmerge-command width=40 sensitive |
| ︙ | ︙ | |||
4257 4258 4259 4260 4261 4262 4263 | /* ** SETTING: https-login boolean default=off ** If true, then the Fossil web server will redirect unencrypted ** login screen requests to HTTPS. */ /* ** SETTING: ignore-glob width=40 versionable block-text | | < | < | > | | | > | 4710 4711 4712 4713 4714 4715 4716 4717 4718 4719 4720 4721 4722 4723 4724 4725 4726 4727 4728 4729 4730 4731 4732 4733 4734 | /* ** SETTING: https-login boolean default=off ** If true, then the Fossil web server will redirect unencrypted ** login screen requests to HTTPS. */ /* ** SETTING: ignore-glob width=40 versionable block-text ** The VALUE of this setting is a list of GLOB patterns matching files that ** the "add", "addremove", "clean", and "extras" commands will ignore. ** Example: *.log,notes.txt The parsing rules are complex; see ** https://fossil-scm.org/home/doc/trunk/www/globs.md#syntax */ /* ** SETTING: keep-glob width=40 versionable block-text ** The VALUE of this setting is a list of GLOB patterns matching files that ** the "clean" command must not delete. Example: build/precious.exe ** The parsing rules are complex; see ** https://fossil-scm.org/home/doc/trunk/www/globs.md#syntax */ /* ** SETTING: localauth boolean default=off ** If enabled, require that HTTP connections from the loopback ** address (127.0.0.1) be authenticated by password. If false, ** some HTTP requests might be granted full "Setup" user ** privileges without having to present login credentials. |
| ︙ | ︙ | |||
4328 4329 4330 4331 4332 4333 4334 | /* ** SETTING: main-branch width=40 default=trunk ** The value is the primary branch for the project. */ /* ** SETTING: manifest width=5 versionable ** If enabled, automatically create files "manifest" and "manifest.uuid" | | | 4781 4782 4783 4784 4785 4786 4787 4788 4789 4790 4791 4792 4793 4794 4795 | /* ** SETTING: main-branch width=40 default=trunk ** The value is the primary branch for the project. */ /* ** SETTING: manifest width=5 versionable ** If enabled, automatically create files "manifest" and "manifest.uuid" ** in every check-out. ** ** Optionally use combinations of characters 'r' for "manifest", ** 'u' for "manifest.uuid" and 't' for "manifest.tags". The SQLite ** and Fossil repositories both require manifests. */ /* ** SETTING: max-loadavg width=25 default=0.0 |
| ︙ | ︙ | |||
4364 4365 4366 4367 4368 4369 4370 | ** files have been modified. If disabled, all managed files ** are hashed to detect changes, which can be slow for large ** projects. */ /* ** SETTING: mv-rm-files boolean default=off ** If enabled, the "mv" and "rename" commands will also move | | | < < < < < < < < < | | | > | | 4817 4818 4819 4820 4821 4822 4823 4824 4825 4826 4827 4828 4829 4830 4831 4832 4833 4834 4835 4836 4837 4838 4839 4840 4841 4842 4843 4844 4845 4846 4847 4848 4849 4850 4851 4852 4853 4854 4855 4856 4857 4858 4859 4860 | ** files have been modified. If disabled, all managed files ** are hashed to detect changes, which can be slow for large ** projects. */ /* ** SETTING: mv-rm-files boolean default=off ** If enabled, the "mv" and "rename" commands will also move ** the associated files within the check-out -AND- the "rm" ** and "delete" commands will also remove the associated ** files from within the check-out. */ /* ** SETTING: pgp-command width=40 sensitive ** Command used to clear-sign manifests at check-in. ** Default value is "gpg --clearsign -o" */ /* ** SETTING: proxy width=32 default=system ** URL of the HTTP proxy. If undefined or "system", the "http_proxy" ** environment variable is consulted. If "off", a direct HTTP connection is ** used. */ /* ** SETTING: redirect-to-https default=0 width=-1 ** Specifies whether or not to redirect http:// requests to ** https:// URIs. A value of 0 (the default) means not to ** redirect, 1 means to redirect only the /login page, and 2 ** means to always redirect. */ /* ** SETTING: relative-paths boolean default=on ** When showing changes and extras, report paths relative ** to the current working directory. */ /* ** SETTING: repo-cksum boolean default=on ** Compute checksums over all files in each check-out as a double-check ** of correctness. Disable this on large repositories for a performance ** improvement. */ /* ** SETTING: repolist-skin width=2 default=0 ** If non-zero then use this repository as the skin for a repository list ** such as created by the one of: |
| ︙ | ︙ | |||
4426 4427 4428 4429 4430 4431 4432 4433 4434 4435 4436 4437 4438 4439 |
** 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").
**
** 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-register boolean default=off sensitive
** Allow users to register themselves through the HTTP UI.
** This is useful if you want to see other names than
** "Anonymous" in e.g. ticketing system. On the other hand
** users can not be deleted.
*/
| > > > > > > > | 4871 4872 4873 4874 4875 4876 4877 4878 4879 4880 4881 4882 4883 4884 4885 4886 4887 4888 4889 4890 4891 |
** 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").
**
** 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
** to the /resetpw page be sent to their email address of record,
** thus allowing forgetful users to reset their forgotten passwords
** without administrator involvement.
*/
/*
** SETTING: self-register boolean default=off sensitive
** Allow users to register themselves through the HTTP UI.
** This is useful if you want to see other names than
** "Anonymous" in e.g. ticketing system. On the other hand
** users can not be deleted.
*/
|
| ︙ | ︙ | |||
4519 4520 4521 4522 4523 4524 4525 | /* ** SETTING: th1-uri-regexp width=40 block-text ** Specify which URI's are allowed in HTTP requests from ** TH1 scripts. If empty, no HTTP requests are allowed ** whatsoever. */ /* | | | 4971 4972 4973 4974 4975 4976 4977 4978 4979 4980 4981 4982 4983 4984 4985 | /* ** SETTING: th1-uri-regexp width=40 block-text ** Specify which URI's are allowed in HTTP requests from ** TH1 scripts. If empty, no HTTP requests are allowed ** whatsoever. */ /* ** SETTING: default-csp width=40 block-text keep-empty ** ** The text of the Content Security Policy that is included ** in the Content-Security-Policy: header field of the HTTP ** reply and in the default HTML <head> section that is added when the ** skin header does not specify a <head> section. The text "$nonce" ** is replaced by the random nonce that is created for each web page. ** |
| ︙ | ︙ | |||
4619 4620 4621 4622 4623 4624 4625 | ** 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: | | | < | > > > > > > > > | | | 5071 5072 5073 5074 5075 5076 5077 5078 5079 5080 5081 5082 5083 5084 5085 5086 5087 5088 5089 5090 5091 5092 5093 5094 5095 5096 5097 5098 5099 5100 5101 5102 5103 5104 5105 5106 5107 5108 5109 5110 5111 5112 5113 5114 5115 5116 5117 5118 5119 5120 5121 5122 5123 5124 5125 5126 5127 5128 5129 5130 5131 5132 5133 5134 5135 5136 5137 5138 |
** 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
** --exact Only consider exact name matches
** --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 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;
const Setting *aSetting = setting_info(&nSetting);
find_repository_option();
verify_all_options();
db_open_config(1, 0);
if( !globalFlag ){
db_find_and_open_repository(OPEN_ANY_SCHEMA | OPEN_OK_NOT_FOUND, 0);
}
if( !g.repositoryOpen ){
globalFlag = 1;
}
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");
}
exactFlag = 1;
}
if( g.argc==2 ){
for(i=0; i<nSetting; i++){
print_setting(&aSetting[i], 0);
}
}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);
}
if( globalFlag && fossil_strcmp(pSetting->name, "manifest")==0 ){
fossil_fatal("cannot set 'manifest' globally");
}
if( unsetFlag || g.argc==4 ){
int isManifest = fossil_strcmp(pSetting->name, "manifest")==0;
if( n!=(int)strlen(pSetting[0].name) && pSetting[1].name &&
fossil_strncmp(pSetting[1].name, zName, n)==0 ){
Blob x;
int i;
blob_init(&x,0,0);
for(i=0; pSetting[i].name; i++){
if( fossil_strncmp(pSetting[i].name,zName,n)!=0 ) break;
blob_appendf(&x, " %s", pSetting[i].name);
|
| ︙ | ︙ | |||
4706 4707 4708 4709 4710 4711 4712 |
fossil_print("%s (subsystem %s) ->", pSetting->name, zSubsys);
if( zValue ){
fossil_print(" [%s]", zValue);
fossil_free(zValue);
}
fossil_print("\n");
}else{
| | | 5165 5166 5167 5168 5169 5170 5171 5172 5173 5174 5175 5176 5177 5178 5179 |
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);
}
pSetting++;
}
}
}else{
usage("?PROPERTY? ?VALUE? ?-global?");
}
|
| ︙ | ︙ | |||
4775 4776 4777 4778 4779 4780 4781 | ** optimization. FILENAME can also be the configuration database file ** (~/.fossil or ~/.config/fossil.db) or a local .fslckout or _FOSSIL_ file. ** ** The purpose of this command is for testing the WITHOUT ROWID capabilities ** of SQLite. There is no big advantage to using WITHOUT ROWID in Fossil. ** ** Options: | | | 5234 5235 5236 5237 5238 5239 5240 5241 5242 5243 5244 5245 5246 5247 5248 |
** optimization. FILENAME can also be the configuration database file
** (~/.fossil or ~/.config/fossil.db) or a local .fslckout or _FOSSIL_ file.
**
** The purpose of this command is for testing the WITHOUT ROWID capabilities
** of SQLite. There is no big advantage to using WITHOUT ROWID in Fossil.
**
** Options:
** -n|--dry-run No changes. Just print what would happen.
*/
void test_without_rowid(void){
int i, j;
Stmt q;
Blob allSql;
int dryRun = find_option("dry-run", "n", 0)!=0;
for(i=2; i<g.argc; i++){
|
| ︙ | ︙ | |||
4836 4837 4838 4839 4840 4841 4842 |
/*
** Make sure the adminlog table exists. Create it if it does not
*/
void create_admin_log_table(void){
static int once = 0;
if( once ) return;
| > | | | | | | | | | | > | 5295 5296 5297 5298 5299 5300 5301 5302 5303 5304 5305 5306 5307 5308 5309 5310 5311 5312 5313 5314 5315 5316 5317 5318 5319 5320 |
/*
** Make sure the adminlog table exists. Create it if it does not
*/
void create_admin_log_table(void){
static int once = 0;
if( once ) return;
if( !db_table_exists("repository","admin_log") ){
once = 1;
db_multi_exec(
"CREATE TABLE repository.admin_log(\n"
" id INTEGER PRIMARY KEY,\n"
" time INTEGER, -- Seconds since 1970\n"
" page TEXT, -- path of page\n"
" who TEXT, -- User who made the change\n"
" what TEXT -- What changed\n"
")"
);
}
}
/*
** Write a message into the admin_event table, if admin logging is
** enabled via the admin-log configuration option.
*/
void admin_log(const char *zFormat, ...){
|
| ︙ | ︙ | |||
4876 4877 4878 4879 4880 4881 4882 | } /* ** COMMAND: test-database-names ** ** Print the names of the various database files: ** (1) The main repository database | | | | | | 5337 5338 5339 5340 5341 5342 5343 5344 5345 5346 5347 5348 5349 5350 5351 5352 5353 5354 5355 5356 5357 5358 5359 5360 5361 5362 5363 5364 5365 5366 5367 5368 5369 |
}
/*
** COMMAND: test-database-names
**
** Print the names of the various database files:
** (1) The main repository database
** (2) The local check-out database
** (3) The global configuration database
*/
void test_database_name_cmd(void){
db_find_and_open_repository(OPEN_ANY_SCHEMA, 0);
fossil_print("Repository database: %s\n", g.zRepositoryName);
fossil_print("Local database: %s\n", g.zLocalDbName);
fossil_print("Config database: %s\n", g.zConfigDbName);
}
/*
** Compute a "fingerprint" on the repository. A fingerprint is used
** to verify that that the repository has not been replaced by a clone
** of the same repository. More precisely, a fingerprint are used to
** verify that the mapping between SHA3 hashes and RID values is unchanged.
**
** The check-out database ("localdb") stores RID values. When associating
** a check-out database against a repository database, it is useful to verify
** the fingerprint so that we know tha the RID values in the check-out
** database still correspond to the correct entries in the BLOB table of
** the repository.
**
** The fingerprint is based on the RCVFROM table. When constructing a
** new fingerprint, use the most recent RCVFROM entry. (Set rcvid==0 to
** accomplish this.) When verifying an old fingerprint, use the same
** RCVFROM entry that generated the fingerprint in the first place.
|
| ︙ | ︙ | |||
5001 5002 5003 5004 5005 5006 5007 |
/*
** Verify that the fingerprint recorded in the "fingerprint" entry
** of the VVAR table matches the fingerprint on the currently
** connected repository. Return true if the fingerprint is ok, and
** return false if the fingerprint does not match.
*/
int db_fingerprint_ok(void){
| | | | > > > > > > > | 5462 5463 5464 5465 5466 5467 5468 5469 5470 5471 5472 5473 5474 5475 5476 5477 5478 5479 5480 5481 5482 5483 5484 5485 5486 5487 5488 5489 5490 5491 5492 5493 5494 5495 5496 5497 5498 5499 5500 5501 5502 |
/*
** Verify that the fingerprint recorded in the "fingerprint" entry
** of the VVAR table matches the fingerprint on the currently
** connected repository. Return true if the fingerprint is ok, and
** return false if the fingerprint does not match.
*/
int db_fingerprint_ok(void){
char *zCkout; /* The fingerprint recorded in the check-out database */
char *zRepo; /* The fingerprint of the repository */
int rc; /* Result */
if( !db_lget_int("checkout", 0) ){
/* We have an empty check-out, fingerprint is still NULL. */
return 2;
}
zCkout = db_text(0,"SELECT value FROM localdb.vvar WHERE name='fingerprint'");
if( zCkout==0 ){
/* This is an older check-out that does not record a fingerprint.
** We have to assume everything is ok */
return 2;
}
zRepo = db_fingerprint(atoi(zCkout), 1);
rc = fossil_strcmp(zCkout,zRepo)==0;
fossil_free(zRepo);
/* If the initial test fails, try again using the older fingerprint
** algorithm */
if( !rc ){
zRepo = db_fingerprint(atoi(zCkout), 0);
rc = fossil_strcmp(zCkout,zRepo)==0;
fossil_free(zRepo);
}
fossil_free(zCkout);
return rc;
}
/*
** Adds the given rid to the UNSENT table.
*/
void db_add_unsent(int rid){
db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", rid);
}
|
Changes to src/default.css.
| ︙ | ︙ | |||
129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
content: '';
position: absolute;
top: 3px;
left: 3px;
width: 4px;
height: 4px;
background: #000;
}
.tl-node.sel:after {
content: '';
position: absolute;
top: 2px;
left: 2px;
width: 6px;
| > > > > > > > > | 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 |
content: '';
position: absolute;
top: 3px;
left: 3px;
width: 4px;
height: 4px;
background: #000;
}
.tl-node.closed-leaf svg {
position: absolute;
top: 0px;
left: 0px;
width: 10px;
height: 10px;
color: #000;
}
.tl-node.sel:after {
content: '';
position: absolute;
top: 2px;
left: 2px;
width: 6px;
|
| ︙ | ︙ | |||
315 316 317 318 319 320 321 322 323 324 |
ul.browser {
list-style-type: none;
padding: 10px;
margin: 0px;
white-space: nowrap;
}
ul.browser li.file {
background-image: url("data:image/gif;base64,R0lGODlhEAAQAJEAAP\/\/\/\
yEhIf\/\/\/wAAACH5BAEHAAIALAAAAAAQABAAAAIvlIKpxqcfmgOUvoaqDSCxrEEfF14Gq\
FXImJZsu73wepJzVMNxrtNTj3NATMKhpwAAOw==");
| > > > > > > < < > | | > < < | > > > > > > > | 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 |
ul.browser {
list-style-type: none;
padding: 10px;
margin: 0px;
white-space: nowrap;
}
ul.browser li.file {
padding-top: 2px;
}
ul.browser li.file > a {
padding-left: 20px;
background-repeat: no-repeat;
background-position: 0px center;
background-image: url("data:image/gif;base64,R0lGODlhEAAQAJEAAP\/\/\/\
yEhIf\/\/\/wAAACH5BAEHAAIALAAAAAAQABAAAAIvlIKpxqcfmgOUvoaqDSCxrEEfF14Gq\
FXImJZsu73wepJzVMNxrtNTj3NATMKhpwAAOw==");
}
ul.browser li.dir {
padding-top: 2px;
}
ul.browser li.dir > a {
padding-left: 20px;
background-image: url("data:image/gif;base64,R0lGODlhEAAQAJEAAP/WVCIiI\
v\/\/\/wAAACH5BAEHAAIALAAAAAAQABAAAAInlI9pwa3XYniCgQtkrAFfLXkiFo1jaXpo+\
jUs6b5Z/K4siDu5RPUFADs=");
background-repeat: no-repeat;
background-position: 0px center;
}
div.filetreeline {
display: table;
width: 100%;
white-space: nowrap;
}
.filetree .dir > div.filetreeline > a {
background-image: url("data:image/gif;base64,R0lGODlhEAAQAJEAAP/WVCIiI\
v\/\/\/wAAACH5BAEHAAIALAAAAAAQABAAAAInlI9pwa3XYniCgQtkrAFfLXkiFo1jaXpo\
+jUs6b5Z/K4siDu5RPUFADs=");
}
div.filetreeage {
display: table-cell;
padding-left: 1.5em;
text-align: right;
width: 8em;
}
div.filetreesize {
display: table-cell;
padding-left: 1em;
text-align: right;
width: 7em;
}
div.filetreeline:hover {
background-color: #eee;
}
table.login_out {
text-align: left;
margin-right: 10px;
|
| ︙ | ︙ | |||
587 588 589 590 591 592 593 |
/* Avoid odd-looking color swatches in conjunction with
(table.diff pre > ins/del) padding */
padding: inherit;
}
table.diff td.diffln > pre {
padding: 0 0.35em 0 0.5em;
}
| < < < < | 606 607 608 609 610 611 612 613 614 615 616 617 618 619 |
/* Avoid odd-looking color swatches in conjunction with
(table.diff pre > ins/del) padding */
padding: inherit;
}
table.diff td.diffln > pre {
padding: 0 0.35em 0 0.5em;
}
table.diff td > pre {
box-sizing: border-box;
/* Workaround for "slight wiggle" when using mouse-wheel in some FF
versions, apparently caused by the increased line-height forcing
these elements to be a *tick* larger than they should be but not
large enough to force a scroll bar to show up. */
overflow-y: hidden;
|
| ︙ | ︙ | |||
719 720 721 722 723 724 725 |
font-weight: bold;
}
td.difftxt ins > ins.edit {
background-color: #c0c0ff;
text-decoration: none;
font-weight: bold;
}
| > > > | > > > > > > > > > > > | 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 |
font-weight: bold;
}
td.difftxt ins > ins.edit {
background-color: #c0c0ff;
text-decoration: none;
font-weight: bold;
}
body.tkt div.content li > table.udiff {
margin-left: 1.5em;
margin-top: 0.5em;
}
body.tkt div.content ol.tkt-changes > li:target > p > span {
border-bottom: 3px solid gold;
}
body.tkt div.content ol.tkt-changes > li:target > ol {
border-left: 1px solid gold;
}
span.modpending {
color: #b03800;
font-style: italic;
}
pre.th1result {
white-space: pre-wrap;
word-wrap: break-word;
}
pre.th1error {
white-space: pre-wrap;
word-wrap: break-word;
color: red;
}
pre.textPlain {
white-space: pre-wrap;
word-wrap: break-word;
}
.statistics-report-graph-line {
border: 2px solid #446979;
background-color: #446979;
}
.statistics-report-graph-extra {
border: 2px dashed #446979;
border-left-style: none;
}
.statistics-report-table-events th {
padding: 0 1em 0 1em;
}
.statistics-report-table-events td {
padding: 0.1em 1em 0.1em 1em;
}
|
| ︙ | ︙ | |||
906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 |
border: 1px solid black;
padding-left: 1ex;
padding-right: 1ex;
margin-top: 1ex;
display: flex;
flex-direction: column;
}
.forum div > form {
margin: 0.5em 0;
}
.forum-post-collapser {
/* Common style for the bottom-of-post and right-of-post
expand/collapse widgets. */
font-size: 0.8em;
padding: 0;
border: 1px solid rgba(0, 0, 0, 0.2);
| > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 |
border: 1px solid black;
padding-left: 1ex;
padding-right: 1ex;
margin-top: 1ex;
display: flex;
flex-direction: column;
}
div.forumClosed {
}
div.forumClosed > .forumPostBody {
opacity: 0.7;
}
div.forumClosed > .forumPostHdr::before {
content: "[CLOSED] ";
}
/*div.forumClosed > div.forumPostBody {
filter: blur(5px);
}*/
div.forumpost-closure-warning {
margin-top: 1em;
margin-bottom: 1em;
border-style: solid;
padding: 0.25em 0.5em;
background: #f4f400bb;
/*font-weight: bold;*/
}
div.forumpost-closure-warning input[type=submit] {
padding: 0.25em;
}
div.forumpost-single-controls {
/* UI controls along the bottom of a single post
** in the thread view. */
}
.forum div > form {
margin: 0.5em 0;
display: inline-block;
}
.forum-post-collapser {
/* Common style for the bottom-of-post and right-of-post
expand/collapse widgets. */
font-size: 0.8em;
padding: 0;
border: 1px solid rgba(0, 0, 0, 0.2);
|
| ︙ | ︙ | |||
992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 |
max-height: initial;
}
div.forumPostBody.shrunken {
/* When an expandable post is un-expanded, it is shrunkend down
to this size instead of its original size. */
max-height: 8em;
}
div.forumSel {
background-color: #cef;
}
div.forumObs {
color: #bbb;
}
#capabilitySummary {
text-align: center;
}
#capabilitySummary td {
padding-left: 3ex;
padding-right: 3ex;
| > > > > > > > > > > > > > > > > > > > > > > > > | 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 |
max-height: initial;
}
div.forumPostBody.shrunken {
/* When an expandable post is un-expanded, it is shrunkend down
to this size instead of its original size. */
max-height: 8em;
}
span.forumPostReplyTitle {
/* thread title part of the page header when replying to a post */
font-style: italic;
}
div.forumSel {
background-color: #cef;
}
div.forumObs {
color: #bbb;
}
div.setup_forum-column {
display: flex;
flex-direction: column;
}
body.cpage-setup_forum > .content table {
margin-bottom: 1em;
}
body.cpage-setup_forum > .content table.bordered {
border: 1px solid;
border-radius: 0.25em;
}
body.cpage-setup_forum > .content table td,
body.cpage-setup_forum > .content table th {
text-align: left;
}
body.cpage-setup_forum table.forum-settings-list > tbody > tr > td {
min-width: 2em;
}
#capabilitySummary {
text-align: center;
}
#capabilitySummary td {
padding-left: 3ex;
padding-right: 3ex;
|
| ︙ | ︙ | |||
1570 1571 1572 1573 1574 1575 1576 |
width: 100%/*necessary for SOME SVGs for Chrome!*/;
}
pre.pikchr-src {/*source code view for a pikchr (see fossil.pikchr.js)*/
box-sizing: border-box;
text-align: left;
}
/* The .source-inline class tells the .source class that the
| | > | 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 |
width: 100%/*necessary for SOME SVGs for Chrome!*/;
}
pre.pikchr-src {/*source code view for a pikchr (see fossil.pikchr.js)*/
box-sizing: border-box;
text-align: left;
}
/* The .source-inline class tells the .source class that the
source view, when enabled, should be "inline" (same position
as the graphic), else the sources are shifted to the left as
if they were "plain text". */
div.pikchr-wrapper.center:not(.source),
div.pikchr-wrapper.center.source.source-inline{
text-align: center;
/* Reminder for The Future: this impl also works:
display: grid; place-items: center;
and does not require setting display:inline-block on the relevant
child items, but caniuse.com/css-grid suggests that some
still-seemingly-legitimate browsers don't support grid mode. */
}
div.pikchr-wrapper.center > div.pikchr-svg {
width: 100%/*necessary for Chrome!*/;
}
div.pikchr-wrapper.center:not(.source) > pre.pikchr-src,
div.pikchr-wrapper.center:not(.source) > div.pikchr-svg,
/* ^^^ Centered non-source-view elements */
div.pikchr-wrapper.center.source.source-inline > pre.pikchr-src,
div.pikchr-wrapper.center.source.source-inline > div.pikchr-svg
/* ^^^ Centered inline-source-view elements */{
|
| ︙ | ︙ |
Changes to src/delta.c.
| ︙ | ︙ | |||
202 203 204 205 206 207 208 |
return v;
}
/*
** Return the number digits in the base-64 representation of a positive integer
*/
static int digit_count(int v){
| | > | 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 |
return v;
}
/*
** Return the number digits in the base-64 representation of a positive integer
*/
static int digit_count(int v){
unsigned int i;
int x;
for(i=1, x=64; v>=x; i++, x <<= 6){}
return i;
}
#ifdef __GNUC__
# define GCC_VERSION (__GNUC__*1000000+__GNUC_MINOR__*1000+__GNUC_PATCHLEVEL__)
#else
|
| ︙ | ︙ | |||
377 378 379 380 381 382 383 | /* Compute the hash table used to locate matching sections in the ** source file. */ nHash = lenSrc/NHASH; collide = fossil_malloc( nHash*2*sizeof(int) ); memset(collide, -1, nHash*2*sizeof(int)); landmark = &collide[nHash]; | | | | 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 |
/* Compute the hash table used to locate matching sections in the
** source file.
*/
nHash = lenSrc/NHASH;
collide = fossil_malloc( nHash*2*sizeof(int) );
memset(collide, -1, nHash*2*sizeof(int));
landmark = &collide[nHash];
for(i=0; i<(int)lenSrc-NHASH; i+=NHASH){
int hv = hash_once(&zSrc[i]) % nHash;
collide[i/NHASH] = landmark[hv];
landmark[hv] = i/NHASH;
}
/* Begin scanning the target file and generating copy commands and
** literal sections of the delta.
*/
base = 0; /* We have already generated everything before zOut[base] */
while( base+NHASH<(int)lenOut ){
int iSrc, iBlock;
unsigned int bestCnt, bestOfst=0, bestLitsz=0;
hash_init(&h, &zOut[base]);
i = 0; /* Trying to match a landmark against zOut[base+i] */
bestCnt = 0;
while( 1 ){
int hv;
|
| ︙ | ︙ | |||
447 448 449 450 451 452 453 |
cnt = j+k+1;
litsz = i-k; /* Number of bytes of literal text before the copy */
DEBUG2( printf("MATCH %d bytes at %d: [%s] litsz=%d\n",
cnt, ofst, print16(&zSrc[ofst]), litsz); )
/* sz will hold the number of bytes needed to encode the "insert"
** command and the copy command, not counting the "insert" text */
sz = digit_count(i-k)+digit_count(cnt)+digit_count(ofst)+3;
| | | 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 |
cnt = j+k+1;
litsz = i-k; /* Number of bytes of literal text before the copy */
DEBUG2( printf("MATCH %d bytes at %d: [%s] litsz=%d\n",
cnt, ofst, print16(&zSrc[ofst]), litsz); )
/* sz will hold the number of bytes needed to encode the "insert"
** command and the copy command, not counting the "insert" text */
sz = digit_count(i-k)+digit_count(cnt)+digit_count(ofst)+3;
if( cnt>=sz && cnt>(int)bestCnt ){
/* Remember this match only if it is the best so far and it
** does not increase the file size */
bestCnt = cnt;
bestOfst = iSrc-k;
bestLitsz = litsz;
DEBUG2( printf("... BEST SO FAR\n"); )
}
|
| ︙ | ︙ | |||
479 480 481 482 483 484 485 |
}
base += bestCnt;
putInt(bestCnt, &zDelta);
*(zDelta++) = '@';
putInt(bestOfst, &zDelta);
DEBUG2( printf("copy %d bytes from %d\n", bestCnt, bestOfst); )
*(zDelta++) = ',';
| | | | | 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 |
}
base += bestCnt;
putInt(bestCnt, &zDelta);
*(zDelta++) = '@';
putInt(bestOfst, &zDelta);
DEBUG2( printf("copy %d bytes from %d\n", bestCnt, bestOfst); )
*(zDelta++) = ',';
if( (int)(bestOfst + bestCnt -1) > lastRead ){
lastRead = bestOfst + bestCnt - 1;
DEBUG2( printf("lastRead becomes %d\n", lastRead); )
}
bestCnt = 0;
break;
}
/* If we reach this point, it means no match is found so far */
if( base+i+NHASH>=(int)lenOut ){
/* We have reached the end of the file and have not found any
** matches. Do an "insert" for everything that does not match */
putInt(lenOut-base, &zDelta);
*(zDelta++) = ':';
memcpy(zDelta, &zOut[base], lenOut-base);
zDelta += lenOut-base;
base = lenOut;
break;
}
/* Advance the hash by one character. Keep looking for a match */
hash_next(&h, zOut[base+i+NHASH]);
i++;
}
}
/* Output a final "insert" record to get all the text at the end of
** the file that does not match anything in the source file.
*/
if( base<(int)lenOut ){
putInt(lenOut-base, &zDelta);
*(zDelta++) = ':';
memcpy(zDelta, &zOut[base], lenOut-base);
zDelta += lenOut-base;
}
/* Output the final checksum record. */
putInt(checksum(zOut, lenOut), &zDelta);
|
| ︙ | ︙ | |||
597 598 599 600 601 602 603 |
zDelta++; lenDelta--;
DEBUG1( printf("COPY %d from %d\n", cnt, ofst); )
total += cnt;
if( total>limit ){
/* ERROR: copy exceeds output file size */
return -1;
}
| | | | 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 |
zDelta++; lenDelta--;
DEBUG1( printf("COPY %d from %d\n", cnt, ofst); )
total += cnt;
if( total>limit ){
/* ERROR: copy exceeds output file size */
return -1;
}
if( (int)(ofst+cnt) > lenSrc ){
/* ERROR: copy extends past end of input */
return -1;
}
memcpy(zOut, &zSrc[ofst], cnt);
zOut += cnt;
break;
}
case ':': {
zDelta++; lenDelta--;
total += cnt;
if( total>limit ){
/* ERROR: insert command gives an output larger than predicted */
return -1;
}
DEBUG1( printf("INSERT %d\n", cnt); )
if( (int)cnt>lenDelta ){
/* ERROR: insert count exceeds size of delta */
return -1;
}
memcpy(zOut, zDelta, cnt);
zOut += cnt;
zDelta += cnt;
lenDelta -= cnt;
|
| ︙ | ︙ | |||
686 687 688 689 690 691 692 |
zDelta++; lenDelta--;
nCopy += cnt;
break;
}
case ':': {
zDelta++; lenDelta--;
nInsert += cnt;
| | | 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 |
zDelta++; lenDelta--;
nCopy += cnt;
break;
}
case ':': {
zDelta++; lenDelta--;
nInsert += cnt;
if( (int)cnt>lenDelta ){
/* ERROR: insert count exceeds size of delta */
return -1;
}
zDelta += cnt;
lenDelta -= cnt;
break;
}
|
| ︙ | ︙ |
Changes to src/deltacmd.c.
| ︙ | ︙ | |||
58 59 60 61 62 63 64 |
if( blob_read_from_file(&orig, g.argv[2], ExtFILE)<0 ){
fossil_fatal("cannot read %s", g.argv[2]);
}
if( blob_read_from_file(&target, g.argv[3], ExtFILE)<0 ){
fossil_fatal("cannot read %s", g.argv[3]);
}
blob_delta_create(&orig, &target, &delta);
| | | 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
if( blob_read_from_file(&orig, g.argv[2], ExtFILE)<0 ){
fossil_fatal("cannot read %s", g.argv[2]);
}
if( blob_read_from_file(&target, g.argv[3], ExtFILE)<0 ){
fossil_fatal("cannot read %s", g.argv[3]);
}
blob_delta_create(&orig, &target, &delta);
if( blob_write_to_file(&delta, g.argv[4])<(int)blob_size(&delta) ){
fossil_fatal("cannot write %s", g.argv[4]);
}
blob_reset(&orig);
blob_reset(&target);
blob_reset(&delta);
}
|
| ︙ | ︙ | |||
141 142 143 144 145 146 147 | *pTarget = out; return len; } /* ** COMMAND: test-delta-apply ** | | | > | | 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 |
*pTarget = out;
return len;
}
/*
** COMMAND: test-delta-apply
**
** Usage: %fossil test-delta-apply FILE1 DELTA FILE2
**
** Apply DELTA to FILE1 and output the result in FILE2.
*/
void delta_apply_cmd(void){
Blob orig, target, delta;
if( g.argc!=5 ){
usage("ORIGIN DELTA TARGET");
}
if( blob_read_from_file(&orig, g.argv[2], ExtFILE)<0 ){
fossil_fatal("cannot read %s", g.argv[2]);
}
if( blob_read_from_file(&delta, g.argv[3], ExtFILE)<0 ){
fossil_fatal("cannot read %s", g.argv[3]);
}
blob_init(&target, 0, 0);
blob_delta_apply(&orig, &delta, &target);
if( blob_write_to_file(&target, g.argv[4])<(int)blob_size(&target) ){
fossil_fatal("cannot write %s", g.argv[4]);
}
blob_reset(&orig);
blob_reset(&target);
blob_reset(&delta);
}
|
| ︙ | ︙ |
Changes to src/deltafunc.c.
| ︙ | ︙ | |||
484 485 486 487 488 489 490 | /* xCommit */ 0, /* xRollback */ 0, /* xFindMethod */ 0, /* xRename */ 0, /* xSavepoint */ 0, /* xRelease */ 0, /* xRollbackTo */ 0, | | > | 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 |
/* xCommit */ 0,
/* xRollback */ 0,
/* xFindMethod */ 0,
/* xRename */ 0,
/* xSavepoint */ 0,
/* xRelease */ 0,
/* xRollbackTo */ 0,
/* xShadowName */ 0,
/* xIntegrity */ 0
};
/*
** Invoke this routine to register the various delta functions.
*/
int deltafunc_init(sqlite3 *db){
int rc = SQLITE_OK;
|
| ︙ | ︙ |
Changes to src/descendants.c.
| ︙ | ︙ | |||
574 575 576 577 578 579 580 581 582 583 584 585 586 587 |
if( !showClosed ){
style_submenu_element("Closed", "%s", url_render(&url, "closed", "", 0, 0));
}
if( showClosed || showAll ){
style_submenu_element("Open", "%s", url_render(&url, 0, 0, 0, 0));
}
url_reset(&url);
style_set_current_feature("leaves");
style_header("Leaves");
login_anonymous_available();
timeline_ss_submenu();
#if 0
style_sidebox_begin("Nomenclature:", "33%");
@ <ol>
| > | 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 |
if( !showClosed ){
style_submenu_element("Closed", "%s", url_render(&url, "closed", "", 0, 0));
}
if( showClosed || showAll ){
style_submenu_element("Open", "%s", url_render(&url, 0, 0, 0, 0));
}
url_reset(&url);
cgi_check_for_malice();
style_set_current_feature("leaves");
style_header("Leaves");
login_anonymous_available();
timeline_ss_submenu();
#if 0
style_sidebox_begin("Nomenclature:", "33%");
@ <ol>
|
| ︙ | ︙ | |||
625 626 627 628 629 630 631 | ** many descenders to (off-screen) parents. */ tmFlags = TIMELINE_LEAFONLY | TIMELINE_DISJOINT | TIMELINE_NOSCROLL; if( fNg==0 ) tmFlags |= TIMELINE_GRAPH; if( fBrBg ) tmFlags |= TIMELINE_BRCOLOR; if( fUBg ) tmFlags |= TIMELINE_UCOLOR; www_print_timeline(&q, tmFlags, 0, 0, 0, 0, 0, 0); db_finalize(&q); | | | 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 | ** many descenders to (off-screen) parents. */ tmFlags = TIMELINE_LEAFONLY | TIMELINE_DISJOINT | TIMELINE_NOSCROLL; if( fNg==0 ) tmFlags |= TIMELINE_GRAPH; if( fBrBg ) tmFlags |= TIMELINE_BRCOLOR; if( fUBg ) tmFlags |= TIMELINE_UCOLOR; www_print_timeline(&q, tmFlags, 0, 0, 0, 0, 0, 0); db_finalize(&q); @ <br> style_finish_page(); } #if INTERFACE /* Flag parameters to compute_uses_file() */ #define USESFILE_DELETE 0x01 /* Include the check-ins where file deleted */ |
| ︙ | ︙ |
Changes to src/diff.c.
| ︙ | ︙ | |||
46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
#define DIFF_BROWSER 0x00008000 /* The --browser option */
#define DIFF_JSON 0x00010000 /* JSON output */
#define DIFF_DEBUG 0x00020000 /* Debugging diff output */
#define DIFF_RAW 0x00040000 /* Raw triples - for debugging */
#define DIFF_TCL 0x00080000 /* For the --tk option */
#define DIFF_INCBINARY 0x00100000 /* The --diff-binary option */
#define DIFF_SHOW_VERS 0x00200000 /* Show compared versions */
/*
** These error messages are shared in multiple locations. They are defined
** here for consistency.
*/
#define DIFF_CANNOT_COMPUTE_BINARY \
"cannot compute difference between binary files\n"
| > > > > > > > > | 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
#define DIFF_BROWSER 0x00008000 /* The --browser option */
#define DIFF_JSON 0x00010000 /* JSON output */
#define DIFF_DEBUG 0x00020000 /* Debugging diff output */
#define DIFF_RAW 0x00040000 /* Raw triples - for debugging */
#define DIFF_TCL 0x00080000 /* For the --tk option */
#define DIFF_INCBINARY 0x00100000 /* The --diff-binary option */
#define DIFF_SHOW_VERS 0x00200000 /* Show compared versions */
#define DIFF_DARKMODE 0x00400000 /* Use dark mode for HTML */
/*
** Per file information that may influence output.
*/
#define DIFF_FILE_ADDED 0x40000000 /* Added or rename destination */
#define DIFF_FILE_DELETED 0x80000000 /* Deleted or rename source */
#define DIFF_FILE_MASK 0xc0000000 /* Used for clearing file flags */
/*
** These error messages are shared in multiple locations. They are defined
** here for consistency.
*/
#define DIFF_CANNOT_COMPUTE_BINARY \
"cannot compute difference between binary files\n"
|
| ︙ | ︙ | |||
407 408 409 410 411 412 413 | int r; /* Index into R[] */ int nr; /* Number of COPY/DELETE/INSERT triples to process */ int mxr; /* Maximum value for r */ int na, nb; /* Number of lines shown from A and B */ int i, j; /* Loop counters */ int m; /* Number of lines to output */ int skip; /* Number of lines to skip */ | < | | 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 |
int r; /* Index into R[] */
int nr; /* Number of COPY/DELETE/INSERT triples to process */
int mxr; /* Maximum value for r */
int na, nb; /* Number of lines shown from A and B */
int i, j; /* Loop counters */
int m; /* Number of lines to output */
int skip; /* Number of lines to skip */
int nContext; /* Number of lines of context */
int showLn; /* Show line numbers */
int showDivider = 0; /* True to show the divider between diff blocks */
nContext = diff_context_lines(pCfg);
showLn = (pCfg->diffFlags & DIFF_LINENO)!=0;
A = p->aFrom;
B = p->aTo;
R = p->aEdit;
mxr = p->nEdit;
while( mxr>2 && R[mxr-1]==0 && R[mxr-2]==0 ){ mxr -= 3; }
for(r=0; r<mxr; r += 3*nr){
/* Figure out how many triples to show in a single block */
for(nr=1; 3*nr<mxr && R[r+nr*3]>0 && R[r+nr*3]<(int)nContext*2; nr++){}
/* printf("r=%d nr=%d\n", r, nr); */
/* For the current block comprising nr triples, figure out
** how many lines of A and B are to be displayed
*/
if( R[r]>nContext ){
na = nb = nContext;
|
| ︙ | ︙ | |||
1127 1128 1129 1130 1131 1132 1133 | ** The Json array consists of integer opcodes with each opcode followed ** by zero or more arguments: ** ** Syntax Mnemonic Description ** ----------- -------- -------------------------- ** 0 END This is the end of the diff ** 1 INTEGER SKIP Skip N lines from both files | | | 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 | ** The Json array consists of integer opcodes with each opcode followed ** by zero or more arguments: ** ** Syntax Mnemonic Description ** ----------- -------- -------------------------- ** 0 END This is the end of the diff ** 1 INTEGER SKIP Skip N lines from both files ** 2 STRING COMMON The line shown by STRING is in both files ** 3 STRING INSERT The line STRING is in only the right file ** 4 STRING DELETE The STRING line is in only the left file ** 5 SUBARRAY EDIT One line is different on left and right. ** ** The SUBARRAY is an array of 3*N+1 strings with N>=0. The triples ** represent common-text, left-text, and right-text. The last string ** in SUBARRAY is the common-suffix. Any string can be empty if it does |
| ︙ | ︙ | |||
2068 2069 2070 2071 2072 2073 2074 |
DiffConfig *pCfg, /* Configuration options */
int *pNResult /* OUTPUT: Bytes of result */
){
int i, j, k; /* Loop counters */
int *a; /* One row of the Wagner matrix */
int *pToFree; /* Space that needs to be freed */
unsigned char *aM; /* Wagner result matrix */
| < | 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 |
DiffConfig *pCfg, /* Configuration options */
int *pNResult /* OUTPUT: Bytes of result */
){
int i, j, k; /* Loop counters */
int *a; /* One row of the Wagner matrix */
int *pToFree; /* Space that needs to be freed */
unsigned char *aM; /* Wagner result matrix */
int aBuf[100]; /* Stack space for a[] if nRight not to big */
if( nLeft==0 ){
aM = fossil_malloc( nRight + 2 );
memset(aM, 2, nRight);
*pNResult = nRight;
return aM;
|
| ︙ | ︙ | |||
2093 2094 2095 2096 2097 2098 2099 |
aLeft[0].n, aLeft[0].z, nLeft,
aRight[0].n, aRight[0].z, nRight);
}
/* For large alignments, try to use alternative algorithms that are
** faster than the O(N*N) Wagner edit distance.
*/
| > | > | 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 |
aLeft[0].n, aLeft[0].z, nLeft,
aRight[0].n, aRight[0].z, nRight);
}
/* For large alignments, try to use alternative algorithms that are
** faster than the O(N*N) Wagner edit distance.
*/
if( (i64)nLeft*(i64)nRight>DIFF_ALIGN_MX
&& (pCfg->diffFlags & DIFF_SLOW_SBS)==0
){
if( (pCfg->diffFlags & DIFF_IGNORE_ALLWS)==0 ){
unsigned char *aRes;
aRes = diffBlockAlignmentIgnoreSpace(
aLeft, nLeft,aRight, nRight,pCfg,pNResult);
if( aRes ) return aRes;
}
return diffBlockAlignmentDivideAndConquer(
|
| ︙ | ︙ | |||
2150 2151 2152 2153 2154 2155 2156 |
}
}
/* Compute the lowest-cost path back through the matrix */
i = nRight;
j = nLeft;
k = (nRight+1)*(nLeft+1)-1;
| < < < | 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 |
}
}
/* Compute the lowest-cost path back through the matrix */
i = nRight;
j = nLeft;
k = (nRight+1)*(nLeft+1)-1;
while( i+j>0 ){
unsigned char c = aM[k];
if( c>=3 ){
assert( i>0 && j>0 );
i--;
j--;
aM[k] = 3;
}else if( c==2 ){
assert( i>0 );
i--;
}else{
assert( j>0 );
j--;
|
| ︙ | ︙ | |||
2224 2225 2226 2227 2228 2229 2230 |
B = p->aTo;
R = p->aEdit;
mxr = p->nEdit;
while( mxr>2 && R[mxr-1]==0 && R[mxr-2]==0 ){ mxr -= 3; }
for(r=0; r<mxr; r += 3*nr){
/* Figure out how many triples to show in a single block */
| | | 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 |
B = p->aTo;
R = p->aEdit;
mxr = p->nEdit;
while( mxr>2 && R[mxr-1]==0 && R[mxr-2]==0 ){ mxr -= 3; }
for(r=0; r<mxr; r += 3*nr){
/* Figure out how many triples to show in a single block */
for(nr=1; 3*nr<mxr && R[r+nr*3]>0 && R[r+nr*3]<(int)nContext*2; nr++){}
/* If there is a regex, skip this block (generate no diff output)
** if the regex matches or does not match both insert and delete.
** Only display the block if one side matches but the other side does
** not.
*/
if( pCfg->pRe ){
|
| ︙ | ︙ | |||
2254 2255 2256 2257 2258 2259 2260 |
continue;
}
}
/* Figure out how many lines of A and B are to be displayed
** for this change block.
*/
| | | | | 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 |
continue;
}
}
/* Figure out how many lines of A and B are to be displayed
** for this change block.
*/
if( R[r]>(int)nContext ){
skip = R[r] - nContext;
}else{
skip = 0;
}
/* Show the initial common area */
a += skip;
b += skip;
m = R[r] - skip;
if( r ) skip -= nContext;
if( skip>0 ){
if( skip<(int)nContext ){
/* If the amount to skip is less that the context band, then
** go ahead and show the skip band as it is not worth eliding */
for(j=0; (int)j<skip; j++){
pBuilder->xCommon(pBuilder, &A[a+j-skip]);
}
}else{
pBuilder->xSkip(pBuilder, skip, 0);
}
}
for(j=0; j<m; j++){
|
| ︙ | ︙ | |||
2302 2303 2304 2305 2306 2307 2308 |
mb += R[r+i*3+2] + m;
}
/* Try to find an alignment for the lines within this one block */
alignment = diffBlockAlignment(&A[a], ma, &B[b], mb, pCfg, &nAlign);
for(j=0; ma+mb>0; j++){
| | | 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 |
mb += R[r+i*3+2] + m;
}
/* Try to find an alignment for the lines within this one block */
alignment = diffBlockAlignment(&A[a], ma, &B[b], mb, pCfg, &nAlign);
for(j=0; ma+mb>0; j++){
assert( (int)j<nAlign );
switch( alignment[j] ){
case 1: {
/* Delete one line from the left */
pBuilder->xDelete(pBuilder, &A[a]);
ma--;
a++;
break;
|
| ︙ | ︙ | |||
2344 2345 2346 2347 2348 2349 2350 |
a++;
mb--;
b++;
break;
}
}
}
| | | | 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 |
a++;
mb--;
b++;
break;
}
}
}
assert( nAlign==(int)j );
fossil_free(alignment);
if( i<nr-1 ){
m = R[r+i*3+3];
for(j=0; j<m; j++){
pBuilder->xCommon(pBuilder, &A[a+j]);
}
b += m;
a += m;
}
}
/* Show the final common area */
assert( nr==i );
m = R[r+nr*3];
if( m>nContext ) m = nContext;
for(j=0; j<m && j<nContext; j++){
pBuilder->xCommon(pBuilder, &A[a+j]);
}
}
if( R[r]>(int)nContext ){
pBuilder->xSkip(pBuilder, R[r] - nContext, 1);
}
pBuilder->xEnd(pBuilder);
}
/*
|
| ︙ | ︙ | |||
2889 2890 2891 2892 2893 2894 2895 |
** NULL then the compile-time default is used (which gets propagated
** to JS-side state by certain pages).
*/
int diff_context_lines(DiffConfig *pCfg){
const int dflt = 5;
if(pCfg!=0){
int n = pCfg->nContext;
| | | | 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 |
** NULL then the compile-time default is used (which gets propagated
** to JS-side state by certain pages).
*/
int diff_context_lines(DiffConfig *pCfg){
const int dflt = 5;
if(pCfg!=0){
int n = pCfg->nContext;
if( n==0 && (pCfg->diffFlags & DIFF_CONTEXT_EX)==0 ) n = dflt;
return n<0 ? 0x7ffffff : n;
}else{
return dflt;
}
}
/*
** Extract the width of columns for side-by-side diff. Supply an
|
| ︙ | ︙ | |||
2957 2958 2959 2960 2961 2962 2963 | ** returns a pointer to an array of integers. The integers come in ** triples. The elements of each triple are: ** ** 1. The number of lines to copy ** 2. The number of lines to delete ** 3. The number of lines to insert ** | | | 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 | ** returns a pointer to an array of integers. The integers come in ** triples. The elements of each triple are: ** ** 1. The number of lines to copy ** 2. The number of lines to delete ** 3. The number of lines to insert ** ** The return vector is terminated by a triple of all zeros. The caller ** should free the returned vector using fossil_free(). ** ** This diff utility does not work on binary files. If a binary ** file is encountered, 0 is returned and pOut is written with ** text "cannot compute difference between binary files". */ int *text_diff( |
| ︙ | ︙ | |||
3150 3151 3152 3153 3154 3155 3156 |
}
/* Undocumented and unsupported flags used for development
** debugging and analysis: */
if( find_option("debug",0,0)!=0 ) diffFlags |= DIFF_DEBUG;
if( find_option("raw",0,0)!=0 ) diffFlags |= DIFF_RAW;
}
| | > | 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 |
}
/* Undocumented and unsupported flags used for development
** debugging and analysis: */
if( find_option("debug",0,0)!=0 ) diffFlags |= DIFF_DEBUG;
if( find_option("raw",0,0)!=0 ) diffFlags |= DIFF_RAW;
}
if( (z = find_option("context","c",1))!=0 && (f = atoi(z))!=0 ){
pCfg->nContext = f;
diffFlags |= DIFF_CONTEXT_EX;
}
if( (z = find_option("width","W",1))!=0 && (f = atoi(z))>0 ){
pCfg->wColumn = f;
}
if( find_option("linenum","n",0)!=0 ) diffFlags |= DIFF_LINENO;
if( find_option("noopt",0,0)!=0 ) diffFlags |= DIFF_NOOPT;
if( find_option("numstat",0,0)!=0 ) diffFlags |= DIFF_NUMSTAT;
if( find_option("versions","h",0)!=0 ) diffFlags |= DIFF_SHOW_VERS;
if( find_option("dark",0,0)!=0 ) diffFlags |= DIFF_DARKMODE;
if( find_option("invert",0,0)!=0 ) diffFlags |= DIFF_INVERT;
if( find_option("brief",0,0)!=0 ) diffFlags |= DIFF_BRIEF;
if( find_option("internal","i",0)==0
&& (diffFlags & (DIFF_HTML|DIFF_TCL|DIFF_DEBUG|DIFF_JSON))==0
){
pCfg->zDiffCmd = find_option("command", 0, 1);
if( pCfg->zDiffCmd==0 ) pCfg->zDiffCmd = diff_command_external(isGDiff);
|
| ︙ | ︙ | |||
3196 3197 3198 3199 3200 3201 3202 | ** ** Usage: %fossil xdiff [options] FILE1 FILE2 ** ** Compute an "external diff" between two files. By "external diff" we mean ** a diff between two disk files that are not necessarily under management. ** In other words, this command provides a mechanism to use Fossil's file ** difference engine on arbitrary disk files. See the "diff" command for | | | 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 | ** ** Usage: %fossil xdiff [options] FILE1 FILE2 ** ** Compute an "external diff" between two files. By "external diff" we mean ** a diff between two disk files that are not necessarily under management. ** In other words, this command provides a mechanism to use Fossil's file ** difference engine on arbitrary disk files. See the "diff" command for ** computing differences between files that are under management. ** ** This command prints the differences between the two files FILE1 and FILE2. ** all of the usual diff formatting options (--tk, --by, -c N, etc.) apply. ** See the "diff" command for a full list of command-line options. ** ** This command used to be called "test-diff". The older "test-diff" spelling ** still works, for compatibility. |
| ︙ | ︙ | |||
3546 3547 3548 3549 3550 3551 3552 | ** filename=FILENAME The filename. ** filevers=BOOLEAN Show file versions rather than check-in versions ** limit=LIMIT Limit the amount of analysis. LIMIT can be one of: ** none No limit ** Xs As much as can be computed in X seconds ** N N versions ** log=BOOLEAN Show a log of versions analyzed | | | 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 |
** filename=FILENAME The filename.
** filevers=BOOLEAN Show file versions rather than check-in versions
** limit=LIMIT Limit the amount of analysis. LIMIT can be one of:
** none No limit
** Xs As much as can be computed in X seconds
** N N versions
** log=BOOLEAN Show a log of versions analyzed
** origin=ID The origin check-in. If unspecified, the root
** check-in over the entire repository is used.
** Specify "origin=trunk" or similar for a reverse
** annotation
** w=BOOLEAN Ignore whitespace
*/
void annotation_page(void){
int i;
|
| ︙ | ︙ | |||
3584 3585 3586 3587 3588 3589 3590 3591 3592 3593 3594 3595 3596 3597 |
zRevision = PD("checkin",0);
zOrigin = P("origin");
zLimit = P("limit");
showLog = PB("log");
fileVers = PB("filevers");
ignoreWs = PB("w");
if( ignoreWs ) annFlags |= DIFF_IGNORE_ALLWS;
/* compute the annotation */
annotate_file(&ann, zFilename, zRevision, zLimit, zOrigin, annFlags);
zCI = ann.aVers[0].zMUuid;
/* generate the web page */
style_set_current_feature("annotate");
| > | 3590 3591 3592 3593 3594 3595 3596 3597 3598 3599 3600 3601 3602 3603 3604 |
zRevision = PD("checkin",0);
zOrigin = P("origin");
zLimit = P("limit");
showLog = PB("log");
fileVers = PB("filevers");
ignoreWs = PB("w");
if( ignoreWs ) annFlags |= DIFF_IGNORE_ALLWS;
cgi_check_for_malice();
/* compute the annotation */
annotate_file(&ann, zFilename, zRevision, zLimit, zOrigin, annFlags);
zCI = ann.aVers[0].zMUuid;
/* generate the web page */
style_set_current_feature("annotate");
|
| ︙ | ︙ | |||
3639 3640 3641 3642 3643 3644 3645 |
for(p=ann.aVers, i=0; i<ann.nVers; i++, p++){
@ <li><span style='background-color:%s(p->zBgColor);'>%s(p->zDate)
@ check-in %z(href("%R/info/%!S",p->zMUuid))%S(p->zMUuid)</a>
@ artifact %z(href("%R/artifact/%!S",p->zFUuid))%S(p->zFUuid)</a>
@ </span>
}
@ </ol>
| | | 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 3660 |
for(p=ann.aVers, i=0; i<ann.nVers; i++, p++){
@ <li><span style='background-color:%s(p->zBgColor);'>%s(p->zDate)
@ check-in %z(href("%R/info/%!S",p->zMUuid))%S(p->zMUuid)</a>
@ artifact %z(href("%R/artifact/%!S",p->zFUuid))%S(p->zFUuid)</a>
@ </span>
}
@ </ol>
@ <hr>
@ </div>
if( !ann.bMoreToDo ){
assert( ann.origId==0 ); /* bMoreToDo always set for a point-to-point */
@ <h2>Origin for each line in
@ %z(href("%R/finfo?name=%h&from=%!S", zFilename, zCI))%h(zFilename)</a>
@ from check-in %z(href("%R/info/%!S",zCI))%S(zCI)</a>:</h2>
|
| ︙ | ︙ |
Changes to src/diff.tcl.
1 2 3 4 5 6 7 8 9 10 11 12 |
# The "diff --tk" command outputs prepends a "set fossilcmd {...}" line
# to this file, then runs this file using "tclsh" in order to display the
# graphical diff in a separate window. A typical "set fossilcmd" line
# looks like this:
#
# set fossilcmd {| "./fossil" diff --html -y -i -v}
#
# This header comment is stripped off by the "mkbuiltin.c" program.
#
set prog {
package require Tk
| | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
# The "diff --tk" command outputs prepends a "set fossilcmd {...}" line
# to this file, then runs this file using "tclsh" in order to display the
# graphical diff in a separate window. A typical "set fossilcmd" line
# looks like this:
#
# set fossilcmd {| "./fossil" diff --html -y -i -v}
#
# This header comment is stripped off by the "mkbuiltin.c" program.
#
set prog {
package require Tk
array set CFG_light {
TITLE {Fossil Diff}
LN_COL_BG #dddddd
LN_COL_FG #444444
TXT_COL_BG #ffffff
TXT_COL_FG #000000
MKR_COL_BG #444444
MKR_COL_FG #dddddd
|
| ︙ | ︙ | |||
30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
ERR_FG #ee0000
PADX 5
WIDTH 80
HEIGHT 45
LB_HEIGHT 25
}
if {![namespace exists ttk]} {
interp alias {} ::ttk::scrollbar {} ::scrollbar
interp alias {} ::ttk::menubutton {} ::menubutton
}
proc dehtml {x} {
set x [regsub -all {<[^>]*>} $x {}]
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 |
ERR_FG #ee0000
PADX 5
WIDTH 80
HEIGHT 45
LB_HEIGHT 25
}
array set CFG_dark {
TITLE {Fossil Diff}
LN_COL_BG #dddddd
LN_COL_FG #444444
TXT_COL_BG #3f3f3f
TXT_COL_FG #dcdccc
MKR_COL_BG #444444
MKR_COL_FG #dddddd
CHNG_BG #6a6afc
ADD_BG #57934c
RM_BG #ef6767
HR_FG #444444
HR_PAD_TOP 4
HR_PAD_BTM 8
FN_BG #5e5e5e
FN_FG #ffffff
FN_PAD 5
ERR_FG #ee0000
PADX 5
WIDTH 80
HEIGHT 45
LB_HEIGHT 25
}
array set CFG_arr {
0 CFG_light
1 CFG_dark
}
array set CFG [array get $CFG_arr($darkmode)]
if {![namespace exists ttk]} {
interp alias {} ::ttk::scrollbar {} ::scrollbar
interp alias {} ::ttk::menubutton {} ::menubutton
}
proc dehtml {x} {
set x [regsub -all {<[^>]*>} $x {}]
|
| ︙ | ︙ | |||
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
}
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}
while {[set line [getLine $difftxt $N ii]] != -1} {
switch -- [lindex $line 0] {
FILE {
incr nDiffs
foreach wx [list [string length $n1] [string length $n2]] {
if {$wx>$widths(ln)} {set widths(ln) $wx}
}
.lnA insert end \n fn \n -
| > > > > > > > > > > > > > > | | | 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 |
}
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}
set fromIndex [lsearch -glob $fossilcmd *-from]
set toIndex [lsearch -glob $fossilcmd *-to]
set branchIndex [lsearch -glob $fossilcmd *-branch]
set checkinIndex [lsearch -glob $fossilcmd *-checkin]
set fA {base check-in}
set fB {current check-out}
if {$fromIndex > -1} {set fA [lindex $fossilcmd $fromIndex+1]}
if {$toIndex > -1} {set fB [lindex $fossilcmd $toIndex+1]}
if {$branchIndex > -1} {set fA "branch point"; set fB "leaf of branch '[lindex $fossilcmd $branchIndex+1]'"}
if {$checkinIndex > -1} {set fA "primary parent"; set fB [lindex $fossilcmd $checkinIndex+1]}
while {[set line [getLine $difftxt $N ii]] != -1} {
switch -- [lindex $line 0] {
FILE {
incr nDiffs
foreach wx [list [string length $n1] [string length $n2]] {
if {$wx>$widths(ln)} {set widths(ln) $wx}
}
.lnA insert end \n fn \n -
.txtA insert end "[lindex $line 1] ($fA)\n" fn \n -
.mkr insert end \n fn \n -
.lnB insert end \n fn \n -
.txtB insert end "[lindex $line 2] ($fB)\n" fn \n -
.wfiles.lb insert end [lindex $line 2]
set n1 0
set n2 0
}
SKIP {
set n [lindex $line 1]
incr n1 $n
|
| ︙ | ︙ |
Changes to src/diffcmd.c.
| ︙ | ︙ | |||
159 160 161 162 163 164 165 166 167 168 169 170 171 172 |
void diff_print_filenames(
const char *zLeft, /* Name of the left file */
const char *zRight, /* Name of the right file */
DiffConfig *pCfg, /* Diff configuration */
Blob *pOut /* Write to this blob, or stdout of this is NULL */
){
u64 diffFlags = pCfg->diffFlags;
if( diffFlags & (DIFF_BRIEF|DIFF_RAW) ){
/* no-op */
}else if( diffFlags & DIFF_DEBUG ){
blob_appendf(pOut, "FILE-LEFT %s\nFILE-RIGHT %s\n", zLeft, zRight);
}else if( diffFlags & DIFF_WEBPAGE ){
if( fossil_strcmp(zLeft,zRight)==0 ){
blob_appendf(pOut,"<h1>%h</h1>\n", zLeft);
| > > > | 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 |
void diff_print_filenames(
const char *zLeft, /* Name of the left file */
const char *zRight, /* Name of the right file */
DiffConfig *pCfg, /* Diff configuration */
Blob *pOut /* Write to this blob, or stdout of this is NULL */
){
u64 diffFlags = pCfg->diffFlags;
/* Standardize on /dev/null, regardless of platform. */
if( pCfg->diffFlags & DIFF_FILE_ADDED ) zLeft = "/dev/null";
if( pCfg->diffFlags & DIFF_FILE_DELETED ) zRight = "/dev/null";
if( diffFlags & (DIFF_BRIEF|DIFF_RAW) ){
/* no-op */
}else if( diffFlags & DIFF_DEBUG ){
blob_appendf(pOut, "FILE-LEFT %s\nFILE-RIGHT %s\n", zLeft, zRight);
}else if( diffFlags & DIFF_WEBPAGE ){
if( fossil_strcmp(zLeft,zRight)==0 ){
blob_appendf(pOut,"<h1>%h</h1>\n", zLeft);
|
| ︙ | ︙ | |||
211 212 213 214 215 216 217 |
}else{
blob_appendf(pOut, "--- %s\n+++ %s\n", zLeft, zRight);
}
}
/*
| | | 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 |
}else{
blob_appendf(pOut, "--- %s\n+++ %s\n", zLeft, zRight);
}
}
/*
** Default header texts for diff with --webpage
*/
static const char zWebpageHdr[] =
@ <!DOCTYPE html>
@ <html>
@ <head>
@ <meta charset="UTF-8">
@ <style>
|
| ︙ | ︙ | |||
308 309 310 311 312 313 314 315 316 317 318 319 320 321 |
@ font-weight: bold;
@ }
@ td.difftxt ins > ins.edit {
@ background-color: #c0c0ff;
@ text-decoration: none;
@ font-weight: bold;
@ }
@
@ </style>
@ </head>
@ <body>
;
const char zWebpageEnd[] =
@ </body>
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 |
@ font-weight: bold;
@ }
@ td.difftxt ins > ins.edit {
@ background-color: #c0c0ff;
@ text-decoration: none;
@ font-weight: bold;
@ }
@ @media (prefers-color-scheme: dark) {
@ body {
@ background-color: #353535;
@ color: #ffffff;
@ }
@ td.diffln ins {
@ background-color: #559855;
@ color: #000000;
@ }
@ td.diffln del {
@ background-color: #cc5555;
@ color: #000000;
@ }
@ td.difftxt del {
@ background-color: #f9cfcf;
@ color: #000000;
@ }
@ td.difftxt del > del {
@ background-color: #cc5555;
@ color: #000000;
@ }
@ td.difftxt ins {
@ background-color: #a2dbb2;
@ color: #000000;
@ }
@ td.difftxt ins > ins {
@ background-color: #559855;
@ }
@ }
@
@ </style>
@ </head>
@ <body>
;
static const char zWebpageHdrDark[] =
@ <!DOCTYPE html>
@ <html>
@ <head>
@ <meta charset="UTF-8">
@ <style>
@ body {
@ background-color: #353535;
@ color: #ffffff;
@ }
@ h1 {
@ font-size: 150%;
@ }
@
@ table.diff {
@ width: 100%;
@ border-spacing: 0;
@ border: 1px solid black;
@ line-height: inherit;
@ font-size: inherit;
@ }
@ table.diff td {
@ vertical-align: top;
@ line-height: inherit;
@ font-size: inherit;
@ }
@ table.diff pre {
@ margin: 0 0 0 0;
@ line-height: inherit;
@ font-size: inherit;
@ }
@ td.diffln {
@ width: 1px;
@ text-align: right;
@ padding: 0 1em 0 0;
@ }
@ td.difflne {
@ padding-bottom: 0.4em;
@ }
@ td.diffsep {
@ width: 1px;
@ padding: 0 0.3em 0 1em;
@ line-height: inherit;
@ font-size: inherit;
@ }
@ td.diffsep pre {
@ line-height: inherit;
@ font-size: inherit;
@ }
@ td.difftxt pre {
@ overflow-x: auto;
@ }
@ td.diffln ins {
@ background-color: #559855;
@ color: #000000;
@ text-decoration: none;
@ line-height: inherit;
@ font-size: inherit;
@ }
@ td.diffln del {
@ background-color: #cc5555;
@ color: #000000;
@ text-decoration: none;
@ line-height: inherit;
@ font-size: inherit;
@ }
@ td.difftxt del {
@ background-color: #f9cfcf;
@ color: #000000;
@ text-decoration: none;
@ line-height: inherit;
@ font-size: inherit;
@ }
@ td.difftxt del > del {
@ background-color: #cc5555;
@ color: #000000;
@ text-decoration: none;
@ font-weight: bold;
@ }
@ td.difftxt del > del.edit {
@ background-color: #c0c0ff;
@ text-decoration: none;
@ font-weight: bold;
@ }
@ td.difftxt ins {
@ background-color: #a2dbb2;
@ color: #000000;
@ text-decoration: none;
@ line-height: inherit;
@ font-size: inherit;
@ }
@ td.difftxt ins > ins {
@ background-color: #559855;
@ text-decoration: none;
@ font-weight: bold;
@ }
@ td.difftxt ins > ins.edit {
@ background-color: #c0c0ff;
@ text-decoration: none;
@ font-weight: bold;
@ }
@
@ </style>
@ </head>
@ <body>
;
const char zWebpageEnd[] =
@ </body>
|
| ︙ | ︙ | |||
366 367 368 369 370 371 372 |
*/
void diff_begin(DiffConfig *pCfg){
if( (pCfg->diffFlags & DIFF_BROWSER)!=0 ){
tempDiffFilename = fossil_temp_filename();
tempDiffFilename = sqlite3_mprintf("%z.html", tempDiffFilename);
diffOut = fossil_freopen(tempDiffFilename,"wb",stdout);
if( diffOut==0 ){
| | > | | 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 |
*/
void diff_begin(DiffConfig *pCfg){
if( (pCfg->diffFlags & DIFF_BROWSER)!=0 ){
tempDiffFilename = fossil_temp_filename();
tempDiffFilename = sqlite3_mprintf("%z.html", tempDiffFilename);
diffOut = fossil_freopen(tempDiffFilename,"wb",stdout);
if( diffOut==0 ){
fossil_fatal("unable to create temporary file \"%s\"",
tempDiffFilename);
}
#ifndef _WIN32
signal(SIGINT, diff_www_interrupt);
#else
SetConsoleCtrlHandler(diff_console_ctrl_handler, TRUE);
#endif
}
if( (pCfg->diffFlags & DIFF_WEBPAGE)!=0 ){
fossil_print("%s",(pCfg->diffFlags & DIFF_DARKMODE)!=0 ? zWebpageHdrDark :
zWebpageHdr);
fflush(stdout);
}
}
/* Do any final output required by a diff and complete the diff
** process.
**
|
| ︙ | ︙ | |||
436 437 438 439 440 441 442 |
if( pCfg->zDiffCmd==0 ){
Blob out; /* Diff output text */
Blob file2; /* Content of zFile2 */
const char *zName2; /* Name of zFile2 for display */
/* Read content of zFile2 into memory */
blob_zero(&file2);
| | | 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 |
if( pCfg->zDiffCmd==0 ){
Blob out; /* Diff output text */
Blob file2; /* Content of zFile2 */
const char *zName2; /* Name of zFile2 for display */
/* Read content of zFile2 into memory */
blob_zero(&file2);
if( pCfg->diffFlags & DIFF_FILE_DELETED || file_size(zFile2, ExtFILE)<0 ){
zName2 = NULL_DEVICE;
}else{
blob_read_from_file(&file2, zFile2, ExtFILE);
zName2 = zName;
}
/* Compute and output the differences */
|
| ︙ | ︙ | |||
467 468 469 470 471 472 473 474 475 476 477 478 479 480 |
}
/* Release memory resources */
blob_reset(&file2);
}else{
Blob nameFile1; /* Name of temporary file to old pFile1 content */
Blob cmd; /* Text of command to run */
if( (pCfg->diffFlags & DIFF_INCBINARY)==0 ){
Blob file2;
if( looks_like_binary(pFile1) ){
fossil_print("%s",DIFF_CANNOT_COMPUTE_BINARY);
return;
}
| > | 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 |
}
/* Release memory resources */
blob_reset(&file2);
}else{
Blob nameFile1; /* Name of temporary file to old pFile1 content */
Blob cmd; /* Text of command to run */
int useTempfile = 1;
if( (pCfg->diffFlags & DIFF_INCBINARY)==0 ){
Blob file2;
if( looks_like_binary(pFile1) ){
fossil_print("%s",DIFF_CANNOT_COMPUTE_BINARY);
return;
}
|
| ︙ | ︙ | |||
498 499 500 501 502 503 504 |
}
blob_reset(&file2);
}
/* Construct a temporary file to hold pFile1 based on the name of
** zFile2 */
file_tempname(&nameFile1, zFile2, "orig");
| > > > > > > > > > | | | 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 |
}
blob_reset(&file2);
}
/* Construct a temporary file to hold pFile1 based on the name of
** zFile2 */
file_tempname(&nameFile1, zFile2, "orig");
#if !defined(_WIN32)
/* On Unix, use /dev/null for added or deleted files. */
if( pCfg->diffFlags & DIFF_FILE_ADDED ){
blob_init(&nameFile1, NULL_DEVICE, -1);
useTempfile = 0;
}else if( pCfg->diffFlags & DIFF_FILE_DELETED ){
zFile2 = NULL_DEVICE;
}
#endif
if( useTempfile ) blob_write_to_file(pFile1, blob_str(&nameFile1));
/* Construct the external diff command */
blob_zero(&cmd);
blob_append(&cmd, pCfg->zDiffCmd, -1);
if( pCfg->diffFlags & DIFF_INVERT ){
blob_append_escaped_arg(&cmd, zFile2, 1);
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 */
fossil_system(blob_str(&cmd));
/* Delete the temporary file and clean up memory used */
if( useTempfile ) file_delete(blob_str(&nameFile1));
blob_reset(&nameFile1);
blob_reset(&cmd);
}
}
/*
** Show the difference between two files, both in memory.
|
| ︙ | ︙ | |||
559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 |
/* Release memory resources */
blob_reset(&out);
}else{
Blob cmd;
Blob temp1;
Blob temp2;
if( (pCfg->diffFlags & DIFF_INCBINARY)==0 ){
if( looks_like_binary(pFile1) || looks_like_binary(pFile2) ){
fossil_print("%s",DIFF_CANNOT_COMPUTE_BINARY);
return;
}
if( pCfg->zBinGlob ){
Glob *pBinary = glob_create(pCfg->zBinGlob);
if( glob_match(pBinary, zName) ){
fossil_print("%s",DIFF_CANNOT_COMPUTE_BINARY);
glob_free(pBinary);
return;
}
glob_free(pBinary);
}
}
| > > | > > > > > > > > > > | | | | | 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 |
/* Release memory resources */
blob_reset(&out);
}else{
Blob cmd;
Blob temp1;
Blob temp2;
int useTempfile1 = 1;
int useTempfile2 = 1;
if( (pCfg->diffFlags & DIFF_INCBINARY)==0 ){
if( looks_like_binary(pFile1) || looks_like_binary(pFile2) ){
fossil_print("%s",DIFF_CANNOT_COMPUTE_BINARY);
return;
}
if( pCfg->zBinGlob ){
Glob *pBinary = glob_create(pCfg->zBinGlob);
if( glob_match(pBinary, zName) ){
fossil_print("%s",DIFF_CANNOT_COMPUTE_BINARY);
glob_free(pBinary);
return;
}
glob_free(pBinary);
}
}
/* Construct temporary file names */
file_tempname(&temp1, zName, "before");
file_tempname(&temp2, zName, "after");
#if !defined(_WIN32)
/* On Unix, use /dev/null for added or deleted files. */
if( pCfg->diffFlags & DIFF_FILE_ADDED ){
useTempfile1 = 0;
blob_init(&temp1, NULL_DEVICE, -1);
}else if( pCfg->diffFlags & DIFF_FILE_DELETED ){
useTempfile2 = 0;
blob_init(&temp2, NULL_DEVICE, -1);
}
#endif
if( useTempfile1 ) blob_write_to_file(pFile1, blob_str(&temp1));
if( useTempfile2 ) blob_write_to_file(pFile2, blob_str(&temp2));
/* Construct the external diff command */
blob_zero(&cmd);
blob_append(&cmd, pCfg->zDiffCmd, -1);
blob_append_escaped_arg(&cmd, blob_str(&temp1), 1);
blob_append_escaped_arg(&cmd, blob_str(&temp2), 1);
/* Run the external diff command */
fossil_system(blob_str(&cmd));
/* Delete the temporary file and clean up memory used */
if( useTempfile1 ) file_delete(blob_str(&temp1));
if( useTempfile2 ) file_delete(blob_str(&temp2));
blob_reset(&temp1);
blob_reset(&temp2);
blob_reset(&cmd);
}
}
|
| ︙ | ︙ | |||
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 |
blob_zero(&fname);
file_relative_name(zPathname, &fname, 1);
}else{
blob_set(&fname, g.zLocalRoot);
blob_append(&fname, zPathname, -1);
}
zFullName = blob_str(&fname);
if( isDeleted ){
if( !isNumStat ){ fossil_print("DELETED %s\n", zPathname); }
if( !asNewFile ){ showDiff = 0; zFullName = NULL_DEVICE; }
}else if( file_access(zFullName, F_OK) ){
if( !isNumStat ){ fossil_print("MISSING %s\n", zPathname); }
if( !asNewFile ){ showDiff = 0; }
}else if( isNew ){
if( !isNumStat ){ fossil_print("ADDED %s\n", zPathname); }
srcid = 0;
if( !asNewFile ){ showDiff = 0; }
}else if( isChnged==3 ){
if( !isNumStat ){ fossil_print("ADDED_BY_MERGE %s\n", zPathname); }
srcid = 0;
if( !asNewFile ){ showDiff = 0; }
}else if( isChnged==5 ){
if( !isNumStat ){ fossil_print("ADDED_BY_INTEGRATE %s\n", zPathname); }
srcid = 0;
if( !asNewFile ){ showDiff = 0; }
}
if( showDiff ){
Blob content;
if( !isLink != !file_islink(zFullName) ){
diff_print_index(zPathname, pCfg, 0);
diff_print_filenames(zPathname, zPathname, pCfg, 0);
fossil_print("%s",DIFF_CANNOT_COMPUTE_SYMLINK);
continue;
}
if( srcid>0 ){
content_get(srcid, &content);
}else{
blob_zero(&content);
}
| > > > > > > > | > | 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 |
blob_zero(&fname);
file_relative_name(zPathname, &fname, 1);
}else{
blob_set(&fname, g.zLocalRoot);
blob_append(&fname, zPathname, -1);
}
zFullName = blob_str(&fname);
pCfg->diffFlags &= (~DIFF_FILE_MASK);
if( isDeleted ){
if( !isNumStat ){ fossil_print("DELETED %s\n", zPathname); }
pCfg->diffFlags |= DIFF_FILE_DELETED;
if( !asNewFile ){ showDiff = 0; zFullName = NULL_DEVICE; }
}else if( file_access(zFullName, F_OK) ){
if( !isNumStat ){ fossil_print("MISSING %s\n", zPathname); }
if( !asNewFile ){ showDiff = 0; }
}else if( isNew ){
if( !isNumStat ){ fossil_print("ADDED %s\n", zPathname); }
pCfg->diffFlags |= DIFF_FILE_ADDED;
srcid = 0;
if( !asNewFile ){ showDiff = 0; }
}else if( isChnged==3 ){
if( !isNumStat ){ fossil_print("ADDED_BY_MERGE %s\n", zPathname); }
pCfg->diffFlags |= DIFF_FILE_ADDED;
srcid = 0;
if( !asNewFile ){ showDiff = 0; }
}else if( isChnged==5 ){
if( !isNumStat ){ fossil_print("ADDED_BY_INTEGRATE %s\n", zPathname); }
pCfg->diffFlags |= DIFF_FILE_ADDED;
srcid = 0;
if( !asNewFile ){ showDiff = 0; }
}
if( showDiff ){
Blob content;
if( !isLink != !file_islink(zFullName) ){
diff_print_index(zPathname, pCfg, 0);
diff_print_filenames(zPathname, zPathname, pCfg, 0);
fossil_print("%s",DIFF_CANNOT_COMPUTE_SYMLINK);
continue;
}
if( srcid>0 ){
content_get(srcid, &content);
}else{
blob_zero(&content);
}
if( isChnged==0
|| pCfg->diffFlags & DIFF_FILE_DELETED
|| !file_same_as_blob(&content, zFullName)
){
diff_print_index(zPathname, pCfg, pOut);
diff_file(&content, zFullName, zPathname, pCfg, pOut);
}
blob_reset(&content);
}
blob_reset(&fname);
}
|
| ︙ | ︙ | |||
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 |
if( pFromFile==0 ){
cmp = +1;
}else if( pToFile==0 ){
cmp = -1;
}else{
cmp = fossil_strcmp(pFromFile->zName, pToFile->zName);
}
if( cmp<0 ){
if( file_dir_match(pFileDir, pFromFile->zName) ){
if( (pCfg->diffFlags & (DIFF_NUMSTAT|DIFF_HTML))==0 ){
fossil_print("DELETED %s\n", pFromFile->zName);
}
if( asNewFlag ){
diff_manifest_entry(pFromFile, 0, pCfg);
}
}
pFromFile = manifest_file_next(pFrom,0);
}else if( cmp>0 ){
if( file_dir_match(pFileDir, pToFile->zName) ){
if( (pCfg->diffFlags &
(DIFF_NUMSTAT|DIFF_HTML|DIFF_TCL|DIFF_JSON))==0 ){
fossil_print("ADDED %s\n", pToFile->zName);
}
if( asNewFlag ){
diff_manifest_entry(0, pToFile, pCfg);
}
}
pToFile = manifest_file_next(pTo,0);
}else if( fossil_strcmp(pFromFile->zUuid, pToFile->zUuid)==0 ){
/* No changes */
| > > > | 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 |
if( pFromFile==0 ){
cmp = +1;
}else if( pToFile==0 ){
cmp = -1;
}else{
cmp = fossil_strcmp(pFromFile->zName, pToFile->zName);
}
pCfg->diffFlags &= (~DIFF_FILE_MASK);
if( cmp<0 ){
if( file_dir_match(pFileDir, pFromFile->zName) ){
if( (pCfg->diffFlags & (DIFF_NUMSTAT|DIFF_HTML))==0 ){
fossil_print("DELETED %s\n", pFromFile->zName);
}
pCfg->diffFlags |= DIFF_FILE_DELETED;
if( asNewFlag ){
diff_manifest_entry(pFromFile, 0, pCfg);
}
}
pFromFile = manifest_file_next(pFrom,0);
}else if( cmp>0 ){
if( file_dir_match(pFileDir, pToFile->zName) ){
if( (pCfg->diffFlags &
(DIFF_NUMSTAT|DIFF_HTML|DIFF_TCL|DIFF_JSON))==0 ){
fossil_print("ADDED %s\n", pToFile->zName);
}
pCfg->diffFlags |= DIFF_FILE_ADDED;
if( asNewFlag ){
diff_manifest_entry(0, pToFile, pCfg);
}
}
pToFile = manifest_file_next(pTo,0);
}else if( fossil_strcmp(pFromFile->zUuid, pToFile->zUuid)==0 ){
/* No changes */
|
| ︙ | ︙ | |||
954 955 956 957 958 959 960 961 962 963 964 965 966 967 |
*/
void diff_tk(const char *zSubCmd, int firstArg){
int i;
Blob script;
const char *zTempFile = 0;
char *zCmd;
const char *zTclsh;
blob_zero(&script);
blob_appendf(&script, "set fossilcmd {| \"%/\" %s -tcl -i -v",
g.nameOfExe, zSubCmd);
find_option("tcl",0,0);
find_option("html",0,0);
find_option("side-by-side","y",0);
find_option("internal","i",0);
| > | 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 |
*/
void diff_tk(const char *zSubCmd, int firstArg){
int i;
Blob script;
const char *zTempFile = 0;
char *zCmd;
const char *zTclsh;
int bDarkMode = find_option("dark",0,0)!=0;
blob_zero(&script);
blob_appendf(&script, "set fossilcmd {| \"%/\" %s -tcl -i -v",
g.nameOfExe, zSubCmd);
find_option("tcl",0,0);
find_option("html",0,0);
find_option("side-by-side","y",0);
find_option("internal","i",0);
|
| ︙ | ︙ | |||
980 981 982 983 984 985 986 |
blob_appendf(&script, " {%/}", z);
}else{
int j;
blob_append(&script, " ", 1);
for(j=0; z[j]; j++) blob_appendf(&script, "\\%03o", (unsigned char)z[j]);
}
}
| > | | 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 |
blob_appendf(&script, " {%/}", z);
}else{
int j;
blob_append(&script, " ", 1);
for(j=0; z[j]; j++) blob_appendf(&script, "\\%03o", (unsigned char)z[j]);
}
}
blob_appendf(&script, "}\nset darkmode %d\n", bDarkMode);
blob_appendf(&script, "%s", builtin_file("diff.tcl", 0));
if( zTempFile ){
blob_write_to_file(&script, zTempFile);
fossil_print("To see diff, run: %s \"%s\"\n", zTclsh, zTempFile);
}else{
#if defined(FOSSIL_ENABLE_TCL)
Th_FossilInit(TH_INIT_DEFAULT);
if( evaluateTclWithEvents(g.interp, &g.tcl, blob_str(&script),
|
| ︙ | ︙ | |||
1025 1026 1027 1028 1029 1030 1031 | /* ** COMMAND: diff ** COMMAND: gdiff ** ** Usage: %fossil diff|gdiff ?OPTIONS? ?FILE1? ?FILE2 ...? ** ** Show the difference between the current version of each of the FILEs | | | | | | | | > > > > | | | | 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 | /* ** COMMAND: diff ** 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 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 ** -b Show a linear diff in the default web browser ** -y Show a text side-by-side diff ** --webpage Format output as HTML ** --webpage -y HTML output in the side-by-side format ** ** The "--from VERSION" option is used to specify the source check-in ** for the diff operation. If not specified, the source check-in is the ** base check-in for the current check-out. Similarly, the "--to VERSION" ** option specifies the check-in from which the second version of the file ** or files is taken. If there is no "--to" option then the (possibly edited) ** files in the current check-out are used. The "--checkin VERSION" option ** shows the changes made by check-in VERSION relative to its primary parent. ** The "--branch BRANCHNAME" shows all the changes on the branch BRANCHNAME. ** ** The "-i" command-line option forces the use of Fossil's own internal ** diff logic rather than any external diff program that might be configured ** using the "setting" command. If no external diff program is configured, ** then the "-i" option is a no-op. The "-i" option converts "gdiff" into ** "diff". ** ** The "--diff-binary" option enables or disables the inclusion of binary files ** when using an external diff program. ** ** The "--binary" option causes files matching the glob PATTERN to be treated ** as binary when considering if they should be used with the external diff ** program. This option overrides the "binary-glob" setting. ** ** These command show differences between managed files. Use the "fossil xdiff" ** command to see differences in unmanaged files. ** ** Options: ** --binary PATTERN Treat files that match the glob PATTERN ** as binary ** --branch BRANCH Show diff of all changes on BRANCH ** --brief Show filenames only ** -b|--browser Show the diff output in a web-browser ** --by Shorthand for "--browser -y" ** -ci|--checkin VERSION Show diff of all changes in VERSION ** --command PROG External diff program. Overrides "diff-command" ** -c|--context N Show N lines of context around each change, with ** negative N meaning show all content ** --dark Use dark mode for the Tcl/Tk-based GUI and HTML ** --diff-binary BOOL Include binary files with external commands ** --exec-abs-paths Force absolute path names on external commands ** --exec-rel-paths Force relative path names on external commands ** -r|--from VERSION Select VERSION as source for the diff ** -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 only the number of added and deleted lines ** -y|--side-by-side Side-by-side diff ** --strip-trailing-cr Strip trailing CR ** --tcl Tcl-formated 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 Diff against the "undo" buffer ** --unified Unified diff ** -v|--verbose Output complete text of added or deleted files ** -h|--versions Show compared versions in the diff header ** --webpage Format output as a stand-alone HTML webpage |
| ︙ | ︙ | |||
1133 1134 1135 1136 1137 1138 1139 |
zTo = zBranch;
zFrom = mprintf("root:%s", zBranch);
}
if( zCheckin!=0 && ( zFrom!=0 || zTo!=0 ) ){
fossil_fatal("cannot use --checkin together with --from or --to");
}
g.diffCnt[0] = g.diffCnt[1] = g.diffCnt[2] = 0;
| > | | | | > > > | 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 |
zTo = zBranch;
zFrom = mprintf("root:%s", zBranch);
}
if( zCheckin!=0 && ( zFrom!=0 || zTo!=0 ) ){
fossil_fatal("cannot use --checkin together with --from or --to");
}
g.diffCnt[0] = g.diffCnt[1] = g.diffCnt[2] = 0;
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);
}
diff_options(&DCfg, isGDiff, 0);
determine_exec_relative_option(1);
verify_all_options();
if( g.argc>=3 ){
|
| ︙ | ︙ | |||
1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 |
**
** Show a patch that goes from check-in FROM to check-in TO.
*/
void vpatch_page(void){
const char *zFrom = P("from");
const char *zTo = P("to");
DiffConfig DCfg;
login_check_credentials();
if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
if( zFrom==0 || zTo==0 ) fossil_redirect_home();
fossil_nice_default();
cgi_set_content_type("text/plain");
diff_config_init(&DCfg, DIFF_VERBOSE);
diff_two_versions(zFrom, zTo, &DCfg, 0);
}
| > | 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 |
**
** Show a patch that goes from check-in FROM to check-in TO.
*/
void vpatch_page(void){
const char *zFrom = P("from");
const char *zTo = P("to");
DiffConfig DCfg;
cgi_check_for_malice();
login_check_credentials();
if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
if( zFrom==0 || zTo==0 ) fossil_redirect_home();
fossil_nice_default();
cgi_set_content_type("text/plain");
diff_config_init(&DCfg, DIFF_VERBOSE);
diff_two_versions(zFrom, zTo, &DCfg, 0);
}
|
Changes to src/dispatch.c.
| ︙ | ︙ | |||
51 52 53 54 55 56 57 58 59 60 61 62 63 64 | #define CMDFLAG_BLOCKTEXT 0x0080 /* Multi-line text setting */ #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 */ /**************************************************************************/ /* 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 */ | > | 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | #define CMDFLAG_BLOCKTEXT 0x0080 /* Multi-line text setting */ #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 */ |
| ︙ | ︙ | |||
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 |
}
if( nIndent>aIndent[iLevel] ){
assert( iLevel<ArraySize(aIndent)-2 );
if( isLI ){
iLevel++;
aIndent[iLevel] = nIndent;
azEnd[iLevel] = zEndUL;
blob_append(pHtml, "<ul>\n", 5);
}else if( isDT
|| zHelp[nIndent]=='-'
|| hasGap(zHelp+nIndent,i-nIndent) ){
iLevel++;
aIndent[iLevel] = nIndent;
azEnd[iLevel] = zEndDL;
blob_append(pHtml, "<blockquote><dl>\n", -1);
}else if( azEnd[iLevel]==zEndDL ){
iLevel++;
aIndent[iLevel] = nIndent;
azEnd[iLevel] = zEndDD;
blob_append(pHtml, "<dd>", 4);
}else if( wantP ){
iLevel++;
aIndent[iLevel] = nIndent;
azEnd[iLevel] = zEndPRE;
blob_append(pHtml, "<blockquote><pre>", -1);
wantP = 0;
| > > > > > > > > > | 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 |
}
if( nIndent>aIndent[iLevel] ){
assert( iLevel<ArraySize(aIndent)-2 );
if( isLI ){
iLevel++;
aIndent[iLevel] = nIndent;
azEnd[iLevel] = zEndUL;
if( wantP ){
blob_append(pHtml,"<p>", 3);
wantP = 0;
}
blob_append(pHtml, "<ul>\n", 5);
}else if( isDT
|| zHelp[nIndent]=='-'
|| hasGap(zHelp+nIndent,i-nIndent) ){
iLevel++;
aIndent[iLevel] = nIndent;
azEnd[iLevel] = zEndDL;
wantP = 0;
blob_append(pHtml, "<blockquote><dl>\n", -1);
}else if( azEnd[iLevel]==zEndDL ){
iLevel++;
aIndent[iLevel] = nIndent;
azEnd[iLevel] = zEndDD;
if( wantP ){
blob_append(pHtml,"<p>", 3);
wantP = 0;
}
blob_append(pHtml, "<dd>", 4);
}else if( wantP ){
iLevel++;
aIndent[iLevel] = nIndent;
azEnd[iLevel] = zEndPRE;
blob_append(pHtml, "<blockquote><pre>", -1);
wantP = 0;
|
| ︙ | ︙ | |||
548 549 550 551 552 553 554 |
/*
** Display help for all commands based on provided flags.
*/
static void display_all_help(int mask, int useHtml, int rawOut){
int i;
unsigned char occHelp[FOSSIL_MX_CMDIDX] = {0}; /* Help string occurrences */
| | | 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 |
/*
** Display help for all commands based on provided flags.
*/
static void display_all_help(int mask, int useHtml, int rawOut){
int i;
unsigned char occHelp[FOSSIL_MX_CMDIDX] = {0}; /* Help string occurrences */
int bktHelp[FOSSIL_MX_CMDIDX][MX_HELP_DUP] = {{0}};/* Help strings->commands*/
if( useHtml ) fossil_print("<!--\n");
fossil_print("Help text for:\n");
if( mask & CMDFLAG_1ST_TIER ) fossil_print(" * Commands\n");
if( mask & CMDFLAG_2ND_TIER ) fossil_print(" * Auxiliary commands\n");
if( mask & CMDFLAG_ALIAS ) fossil_print(" * Aliases\n");
if( mask & CMDFLAG_TEST ) fossil_print(" * Test commands\n");
if( mask & CMDFLAG_WEBPAGE ) fossil_print(" * Web pages\n");
|
| ︙ | ︙ | |||
622 623 624 625 626 627 628 | ** Usage: %fossil test-all-help ?OPTIONS? ** ** Show help text for commands and pages. Useful for proof-reading. ** Defaults to just the CLI commands. Specify --www to see only the ** web pages, or --everything to see both commands and pages. ** ** Options: | | | | | | | | | 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 |
** Usage: %fossil test-all-help ?OPTIONS?
**
** Show help text for commands and pages. Useful for proof-reading.
** Defaults to just the CLI commands. Specify --www to see only the
** web pages, or --everything to see both commands and pages.
**
** Options:
** -a|--aliases Show aliases
** -e|--everything Show all commands and pages. Omit aliases to
** avoid duplicates.
** -h|--html Transform output to HTML
** -o|--options Show global options
** -r|--raw No output formatting
** -s|--settings Show settings
** -t|--test Include test- commands
** -w|--www Show WWW pages
*/
void test_all_help_cmd(void){
int mask = CMDFLAG_1ST_TIER | CMDFLAG_2ND_TIER;
int useHtml = find_option("html","h",0)!=0;
int rawOut = find_option("raw","r",0)!=0;
if( find_option("www","w",0) ){
|
| ︙ | ︙ | |||
703 704 705 706 707 708 709 |
** first 100 characters of the pattern are considered.
*/
static int edit_distance(const char *zA, const char *zB){
int nA = (int)strlen(zA);
int nB = (int)strlen(zB);
int i, j, m;
int p0, p1, c0;
| | | 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 |
** first 100 characters of the pattern are considered.
*/
static int edit_distance(const char *zA, const char *zB){
int nA = (int)strlen(zA);
int nB = (int)strlen(zB);
int i, j, m;
int p0, p1, c0;
int a[100] = {0};
static const int incr = 4;
for(j=0; j<nB; j++) a[j] = 1;
for(i=0; i<nA; i++){
p0 = i==0 ? 0 : i*incr-1;
c0 = i*incr;
for(j=0; j<nB; j++){
|
| ︙ | ︙ | |||
811 812 813 814 815 816 817 818 819 820 821 |
** raw Show the raw help text without any formatting.
** (Used for debugging.)
*/
void help_page(void){
const char *zCmd = P("cmd");
if( zCmd==0 ) zCmd = P("name");
if( zCmd && *zCmd ){
int rc;
const CmdOrPage *pCmd = 0;
| > | | 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 |
** raw Show the raw help text without any formatting.
** (Used for debugging.)
*/
void help_page(void){
const char *zCmd = P("cmd");
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_header("Help: %s", zCmd);
style_submenu_element("Command-List", "%R/help");
rc = dispatch_name_search(zCmd, CMDFLAG_ANY|CMDFLAG_PREFIX, &pCmd);
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> */
|
| ︙ | ︙ | |||
857 858 859 860 861 862 863 |
help_to_html(pCmd->zHelp, cgi_output_blob());
@ </div>
}
}
}else{
int i;
unsigned char occHelp[FOSSIL_MX_CMDIDX] = {0}; /* Help str occurrences */
| | | 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 |
help_to_html(pCmd->zHelp, cgi_output_blob());
@ </div>
}
}
}else{
int i;
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");
@ <a name='commands'></a>
@ <h1>Available commands:</h1>
@ <div class="columns" style="column-width: 12ex;">
@ <ul>
/* Fill in help string buckets */
|
| ︙ | ︙ | |||
964 965 966 967 968 969 970 |
** WEBPAGE: test-all-help
**
** Show all help text on a single page. Useful for proof-reading.
*/
void test_all_help_page(void){
int i;
unsigned char occHelp[FOSSIL_MX_CMDIDX] = {0}; /* Help string occurrences */
| | | 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 |
** WEBPAGE: test-all-help
**
** Show all help text on a single page. Useful for proof-reading.
*/
void test_all_help_page(void){
int i;
unsigned char occHelp[FOSSIL_MX_CMDIDX] = {0}; /* Help string occurrences */
int bktHelp[FOSSIL_MX_CMDIDX][MX_HELP_DUP] = {{0}};/* Help strings->commands*/
Blob buf;
blob_init(&buf,0,0);
style_set_current_feature("test");
style_header("All Help Text");
@ <dl>
/* Fill in help string buckets */
for(i=0; i<MX_COMMAND; i++){
|
| ︙ | ︙ | |||
1030 1031 1032 1033 1034 1035 1036 |
zDesc = "web page";
}
}
@ <dt><big><b>%s(aCommand[bktHelp[aCommand[i].iHelp][j]].zName)</b>
@</big> (%s(zDesc))</dt>
}
| | | | 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 |
zDesc = "web page";
}
}
@ <dt><big><b>%s(aCommand[bktHelp[aCommand[i].iHelp][j]].zName)</b>
@</big> (%s(zDesc))</dt>
}
@ <p><dd>
help_to_html(aCommand[i].zHelp, cgi_output_blob());
@ </dd><p>
occHelp[aCommand[i].iHelp] = 0;
}
}
@ </dl>
blob_reset(&buf);
style_finish_page();
}
|
| ︙ | ︙ | |||
1268 1269 1270 1271 1272 1273 1274 |
}
z = pCmd->zHelp;
if( z==0 ){
fossil_fatal("no help available for the %s %s",
pCmd->zName, zCmdOrPage);
}
if( pCmd->eCmdFlags & CMDFLAG_SETTING ){
| > > > > > | | > | 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 |
}
z = pCmd->zHelp;
if( z==0 ){
fossil_fatal("no help available for the %s %s",
pCmd->zName, zCmdOrPage);
}
if( 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( useHtml ){
help_to_html(z, &txt);
}else{
help_to_text(z, &txt);
}
|
| ︙ | ︙ | |||
1524 1525 1526 1527 1528 1529 1530 | /* xCommit */ 0, /* xRollback */ 0, /* xFindMethod */ 0, /* xRename */ 0, /* xSavepoint */ 0, /* xRelease */ 0, /* xRollbackTo */ 0, | | > | 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 |
/* xCommit */ 0,
/* xRollback */ 0,
/* xFindMethod */ 0,
/* xRename */ 0,
/* xSavepoint */ 0,
/* xRelease */ 0,
/* xRollbackTo */ 0,
/* xShadowName */ 0,
/* xIntegrity */ 0
};
/*
** Register the helptext virtual table
*/
int helptext_vtab_register(sqlite3 *db){
int rc = sqlite3_create_module(db, "helptext", &helptextVtabModule, 0);
return rc;
}
/* End of the helptext virtual table
******************************************************************************/
|
Changes to src/doc.c.
| ︙ | ︙ | |||
176 177 178 179 180 181 182 |
{ "md", 2, "text/x-markdown" },
{ "me", 2, "application/x-troff-me" },
{ "mesh", 4, "model/mesh" },
{ "mid", 3, "audio/midi" },
{ "midi", 4, "audio/midi" },
{ "mif", 3, "application/x-mif" },
{ "mime", 4, "www/mime" },
| | | 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 |
{ "md", 2, "text/x-markdown" },
{ "me", 2, "application/x-troff-me" },
{ "mesh", 4, "model/mesh" },
{ "mid", 3, "audio/midi" },
{ "midi", 4, "audio/midi" },
{ "mif", 3, "application/x-mif" },
{ "mime", 4, "www/mime" },
{ "mjs", 3, "text/javascript" /*ES6 module*/ },
{ "mkd", 3, "text/x-markdown" },
{ "mov", 3, "video/quicktime" },
{ "movie", 5, "video/x-sgi-movie" },
{ "mp2", 3, "audio/mpeg" },
{ "mp3", 3, "audio/mpeg" },
{ "mp4", 3, "video/mp4" },
{ "mpe", 3, "video/mpeg" },
|
| ︙ | ︙ | |||
457 458 459 460 461 462 463 |
#endif
z = zName;
for(i=0; zName[i]; i++){
if( zName[i]=='.' ) z = &zName[i+1];
}
len = strlen(z);
| | | 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 |
#endif
z = zName;
for(i=0; zName[i]; i++){
if( zName[i]=='.' ) z = &zName[i+1];
}
len = strlen(z);
if( len<(int)sizeof(zSuffix)-1 ){
sqlite3_snprintf(sizeof(zSuffix), zSuffix, "%s", z);
for(i=0; zSuffix[i]; i++) zSuffix[i] = fossil_tolower(zSuffix[i]);
z = mimetype_from_name_custom(zSuffix);
if(z!=0){
return z;
}
first = 0;
|
| ︙ | ︙ | |||
648 649 650 651 652 653 654 |
/*
** Look for a file named zName in the check-in with RID=vid. Load the content
** of that file into pContent and return the RID for the file. Or return 0
** if the file is not found or could not be loaded.
*/
int doc_load_content(int vid, const char *zName, Blob *pContent){
| | > > > > > > > | 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 |
/*
** Look for a file named zName in the check-in with RID=vid. Load the content
** of that file into pContent and return the RID for the file. Or return 0
** if the file is not found or could not be loaded.
*/
int doc_load_content(int vid, const char *zName, Blob *pContent){
int writable;
int rid; /* The RID of the file being loaded */
if( db_is_protected(PROTECT_READONLY)
|| !db_is_writeable("repository")
){
writable = 0;
}else{
writable = 1;
}
if( writable ){
db_end_transaction(0);
db_begin_write();
}
if( !db_table_exists("repository", "vcache") || !writable ){
db_multi_exec(
"CREATE %s TABLE IF NOT EXISTS vcache(\n"
|
| ︙ | ︙ | |||
1010 1011 1012 1013 1014 1015 1016 |
g.isConst = 1;
}
zDfltTitle = zName;
}
}else if( fossil_strcmp(zCheckin,"ckout")==0
|| fossil_strcmp(zCheckin,g.zCkoutAlias)==0
){
| | | 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 |
g.isConst = 1;
}
zDfltTitle = zName;
}
}else if( fossil_strcmp(zCheckin,"ckout")==0
|| fossil_strcmp(zCheckin,g.zCkoutAlias)==0
){
/* Read from the local check-out */
char *zFullpath;
db_must_be_within_tree();
zFullpath = mprintf("%s/%s", g.zLocalRoot, zName);
if( file_isfile(zFullpath, RepoFILE)
&& blob_read_from_file(&filebody, zFullpath, RepoFILE)>0 ){
rid = 1; /* Fake RID just to get the loop to end */
}
|
| ︙ | ︙ | |||
1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 |
Th_Store("doc_name", zName);
if( vid ){
Th_Store("doc_version", db_text(0, "SELECT '[' || substr(uuid,1,10) || ']'"
" FROM blob WHERE rid=%d", vid));
Th_Store("doc_date", db_text(0, "SELECT datetime(mtime) FROM event"
" WHERE objid=%d AND type='ci'", vid));
}
document_render(&filebody, zMime, zDfltTitle, zName);
if( nMiss>=count(azSuffix) ) cgi_set_status(404, "Not Found");
db_end_transaction(0);
return;
/* Jump here when unable to locate the document */
doc_not_found:
| > | 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 |
Th_Store("doc_name", zName);
if( vid ){
Th_Store("doc_version", db_text(0, "SELECT '[' || substr(uuid,1,10) || ']'"
" FROM blob WHERE rid=%d", vid));
Th_Store("doc_date", db_text(0, "SELECT datetime(mtime) FROM event"
" WHERE objid=%d AND type='ci'", vid));
}
cgi_check_for_malice();
document_render(&filebody, zMime, zDfltTitle, zName);
if( nMiss>=count(azSuffix) ) cgi_set_status(404, "Not Found");
db_end_transaction(0);
return;
/* Jump here when unable to locate the document */
doc_not_found:
|
| ︙ | ︙ | |||
1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 |
**
** s=PATTERN Search for PATTERN
*/
void doc_search_page(void){
const int isSearch = P("s")!=0;
login_check_credentials();
style_header("Document Search%s", isSearch ? " Results" : "");
search_screen(SRCH_DOC, 0);
style_finish_page();
}
| > | 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 |
**
** s=PATTERN Search for PATTERN
*/
void doc_search_page(void){
const int isSearch = P("s")!=0;
login_check_credentials();
style_header("Document Search%s", isSearch ? " Results" : "");
cgi_check_for_malice();
search_screen(SRCH_DOC, 0);
style_finish_page();
}
|
Changes to src/encode.c.
| ︙ | ︙ | |||
130 131 132 133 134 135 136 137 138 139 140 141 142 143 |
j = i+1;
break;
case '\'':
if( j<i ) blob_append(p, zIn+j, i-j);
blob_append(p, "'", 5);
j = i+1;
break;
}
}
if( j<i ) blob_append(p, zIn+j, i-j);
}
/*
| > > > > > | 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 |
j = i+1;
break;
case '\'':
if( j<i ) blob_append(p, zIn+j, i-j);
blob_append(p, "'", 5);
j = i+1;
break;
case '\r':
if( j<i ) blob_append(p, zIn+j, i-j);
blob_append(p, " ", 1);
j = i+1;
break;
}
}
if( j<i ) blob_append(p, zIn+j, i-j);
}
/*
|
| ︙ | ︙ | |||
205 206 207 208 209 210 211 |
** by this routine.
*/
char *urlize(const char *z, int n){
return EncodeHttp(z, n, 0);
}
/*
| | | 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 |
** by this routine.
*/
char *urlize(const char *z, int n){
return EncodeHttp(z, n, 0);
}
/*
** If input string does not contain quotes (neither ' nor ")
** then return the argument itself. Otherwise return a newly allocated
** copy of input with all quotes %-escaped.
*/
const char* escape_quotes(const char *zIn){
char *zRet, *zOut;
size_t i, n = 0;
for(i=0; zIn[i]; i++){
|
| ︙ | ︙ | |||
701 702 703 704 705 706 707 |
** Return true if the input string contains only valid base-16 digits.
** If any invalid characters appear in the string, return false.
*/
int validate16(const char *zIn, int nIn){
int i;
if( nIn<0 ) nIn = (int)strlen(zIn);
if( zIn[nIn]==0 ){
| | | 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 |
** Return true if the input string contains only valid base-16 digits.
** If any invalid characters appear in the string, return false.
*/
int validate16(const char *zIn, int nIn){
int i;
if( nIn<0 ) nIn = (int)strlen(zIn);
if( zIn[nIn]==0 ){
return (int)strspn(zIn,"0123456789abcdefABCDEF")==nIn;
}
for(i=0; i<nIn; i++, zIn++){
if( zDecode[zIn[0]&0xff]>63 ){
return zIn[0]==0;
}
}
return 1;
|
| ︙ | ︙ |
Changes to src/event.c.
| ︙ | ︙ | |||
127 128 129 130 131 132 133 134 135 136 137 138 139 140 |
if( !zVerbose ){
zVerbose = P("detail"); /* deprecated */
}
verboseFlag = (zVerbose!=0) && !is_false(zVerbose);
/* Extract the event content.
*/
pTNote = manifest_get(rid, CFTYPE_EVENT, 0);
if( pTNote==0 ){
fossil_fatal("Object #%d is not a tech-note", rid);
}
zMimetype = wiki_filter_mimetypes(PD("mimetype",pTNote->zMimetype));
blob_init(&fullbody, pTNote->zWiki, -1);
blob_init(&title, 0, 0);
| > | 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 |
if( !zVerbose ){
zVerbose = P("detail"); /* deprecated */
}
verboseFlag = (zVerbose!=0) && !is_false(zVerbose);
/* Extract the event content.
*/
cgi_check_for_malice();
pTNote = manifest_get(rid, CFTYPE_EVENT, 0);
if( pTNote==0 ){
fossil_fatal("Object #%d is not a tech-note", rid);
}
zMimetype = wiki_filter_mimetypes(PD("mimetype",pTNote->zMimetype));
blob_init(&fullbody, pTNote->zWiki, -1);
blob_init(&title, 0, 0);
|
| ︙ | ︙ | |||
210 211 212 213 214 215 216 |
}else{
@ <div>
}
blob_init(&comment, pTNote->zComment, -1);
wiki_convert(&comment, 0, WIKI_INLINE);
blob_reset(&comment);
@ </div>
| | | | 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 |
}else{
@ <div>
}
blob_init(&comment, pTNote->zComment, -1);
wiki_convert(&comment, 0, WIKI_INLINE);
blob_reset(&comment);
@ </div>
@ </blockquote><hr>
}
if( fossil_strcmp(zMimetype, "text/x-fossil-wiki")==0 ){
wiki_convert(&fullbody, 0, 0);
}else if( fossil_strcmp(zMimetype, "text/x-markdown")==0 ){
cgi_append_content(blob_buffer(&tail), blob_size(&tail));
}else{
@ <pre>
@ %h(blob_str(&fullbody))
@ </pre>
}
zFullId = db_text(0, "SELECT SUBSTR(tagname,7)"
" FROM tag"
" WHERE tagname GLOB 'event-%q*'",
zId);
attachment_list(zFullId, "<hr><h2>Attachments:</h2><ul>");
document_emit_js();
style_finish_page();
manifest_destroy(pTNote);
}
/*
** Add or update a new tech note to the repository. rid is id of
|
| ︙ | ︙ | |||
326 327 328 329 330 331 332 |
blob_appendf(&event, "U %F\n", login_name());
}
blob_appendf(&event, "W %d\n%s\n", strlen(zBody), zBody);
md5sum_blob(&event, &cksum);
blob_appendf(&event, "Z %b\n", &cksum);
blob_reset(&cksum);
nrid = content_put(&event);
| | | 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 |
blob_appendf(&event, "U %F\n", login_name());
}
blob_appendf(&event, "W %d\n%s\n", strlen(zBody), zBody);
md5sum_blob(&event, &cksum);
blob_appendf(&event, "Z %b\n", &cksum);
blob_reset(&cksum);
nrid = content_put(&event);
db_add_unsent(nrid);
if( manifest_crosslink(nrid, &event, MC_NONE)==0 ){
db_end_transaction(1);
return 0;
}
assert( blob_is_reset(&event) );
content_deltify(rid, &nrid, 1, 0);
db_end_transaction(0);
|
| ︙ | ︙ | |||
465 466 467 468 469 470 471 |
" AND tagxref.tagid=tag.tagid"
" AND tag.tagname GLOB 'sym-*'",
rid
);
}
}
zETime = db_text(0, "SELECT coalesce(datetime(%Q),datetime('now'))", zETime);
| | < | 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 |
" AND tagxref.tagid=tag.tagid"
" AND tag.tagname GLOB 'sym-*'",
rid
);
}
}
zETime = db_text(0, "SELECT coalesce(datetime(%Q),datetime('now'))", zETime);
if( P("submit")!=0 && (zBody!=0 && zComment!=0) && cgi_csrf_safe(2) ){
if ( !event_commit_common(rid, zId, zBody, zETime,
zMimetype, zComment, zTags,
zClrFlag[0] ? zClr : 0) ){
style_header("Error");
@ Internal error: Fossil tried to make an invalid artifact for
@ the edited technote.
style_finish_page();
|
| ︙ | ︙ | |||
511 512 513 514 515 516 517 |
@ </blockquote>
@ <p><b>Page content preview:</b><p>
@ <blockquote>
blob_init(&event, 0, 0);
blob_append(&event, zBody, -1);
safe_html_context(DOCSRC_WIKI);
wiki_render_by_mimetype(&event, zMimetype);
| | | | | | | | | | | 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 |
@ </blockquote>
@ <p><b>Page content preview:</b><p>
@ <blockquote>
blob_init(&event, 0, 0);
blob_append(&event, zBody, -1);
safe_html_context(DOCSRC_WIKI);
wiki_render_by_mimetype(&event, zMimetype);
@ </blockquote><hr>
blob_reset(&event);
}
for(n=2, z=zBody; z[0]; z++){
if( z[0]=='\n' ) n++;
}
if( n<20 ) n = 20;
if( n>40 ) n = 40;
@ <form method="post" action="%R/technoteedit"><div>
login_insert_csrf_secret();
@ <input type="hidden" name="name" value="%h(zId)">
@ <table border="0" cellspacing="10">
@ <tr><th align="right" valign="top">Timestamp (UTC):</th>
@ <td valign="top">
@ <input type="text" name="t" size="25" value="%h(zETime)">
@ </td></tr>
@ <tr><th align="right" valign="top">Timeline Comment:</th>
@ <td valign="top">
@ <textarea name="c" class="technoteedit" cols="80"
@ rows="3" wrap="virtual">%h(zComment)</textarea>
@ </td></tr>
@ <tr><th align="right" valign="top">Timeline Background Color:</th>
@ <td valign="top">
@ <input type='checkbox' name='newclr'%s(zClrFlag)>
@ Use custom color: \
@ <input type='color' name='clr' value='%s(zClr[0]?zClr:"#c0f0ff")'>
@ </td></tr>
@ <tr><th align="right" valign="top">Tags:</th>
@ <td valign="top">
@ <input type="text" name="g" size="40" value="%h(zTags)">
@ </td></tr>
@ <tr><th align="right" valign="top">\
@ %z(href("%R/markup_help"))Markup Style</a>:</th>
@ <td valign="top">
mimetype_option_menu(zMimetype, "mimetype");
@ </td></tr>
@ <tr><th align="right" valign="top">Page Content:</th>
@ <td valign="top">
@ <textarea name="w" class="technoteedit" cols="80"
@ rows="%d(n)" wrap="virtual">%h(zBody)</textarea>
@ </td></tr>
@ <tr><td colspan="2">
@ <input type="submit" name="cancel" value="Cancel">
@ <input type="submit" name="preview" value="Preview">
if( P("preview") ){
@ <input type="submit" name="submit" value="Submit">
}
@ </td></tr></table>
@ </div></form>
style_finish_page();
}
/*
|
| ︙ | ︙ |
Changes to src/export.c.
| ︙ | ︙ | |||
456 457 458 459 460 461 462 | ** ** Write an export of all check-ins to standard output. The export is ** written in the git-fast-export file format assuming the --git option is ** provided. The git-fast-export format is currently the only VCS ** interchange format supported, though other formats may be added in ** the future. ** | | | 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 | ** ** Write an export of all check-ins to standard output. The export is ** written in the git-fast-export file format assuming the --git option is ** provided. The git-fast-export format is currently the only VCS ** interchange format supported, though other formats may be added in ** the future. ** ** Run this command within a check-out. Or use the -R or --repository ** option to specify a Fossil repository to be exported. ** ** Only check-ins are exported using --git. Git does not support tickets ** or wiki or tech notes or attachments, so none of those are exported. ** ** If the "--import-marks FILE" option is used, it contains a list of ** rids to skip. |
| ︙ | ︙ | |||
1558 1559 1560 1561 1562 1563 1564 |
db_multi_exec(
"CREATE TEMP TABLE tomirror(objid,mtime,uuid);\n"
"INSERT INTO tomirror "
"SELECT objid, mtime, blob.uuid FROM event, blob\n"
" WHERE type='ci'"
" AND mtime>coalesce((SELECT value FROM mconfig WHERE key='start'),0.0)"
" AND blob.rid=event.objid"
| | > | 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 |
db_multi_exec(
"CREATE TEMP TABLE tomirror(objid,mtime,uuid);\n"
"INSERT INTO tomirror "
"SELECT objid, mtime, blob.uuid FROM event, blob\n"
" WHERE type='ci'"
" AND mtime>coalesce((SELECT value FROM mconfig WHERE key='start'),0.0)"
" AND blob.rid=event.objid"
" AND blob.uuid NOT IN (SELECT uuid FROM mirror.mmark WHERE NOT isfile)"
" AND NOT EXISTS (SELECT 1 FROM private WHERE rid=blob.rid);"
);
nTotal = db_int(0, "SELECT count(*) FROM tomirror");
if( nLimit<nTotal ){
nTotal = nLimit;
}else if( nLimit>nTotal ){
nLimit = nTotal;
}
|
| ︙ | ︙ | |||
1822 1823 1824 1825 1826 1827 1828 | ** > fossil git export [MIRROR] [OPTIONS] ** ** Write content from the Fossil repository into the Git repository ** in directory MIRROR. The Git repository is created if it does not ** already exist. If the Git repository does already exist, then ** new content added to fossil since the previous export is appended. ** | | | | | | | 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 |
** > fossil git export [MIRROR] [OPTIONS]
**
** Write content from the Fossil repository into the Git repository
** in directory MIRROR. The Git repository is created if it does not
** already exist. If the Git repository does already exist, then
** new content added to fossil since the previous export is appended.
**
** Repeat this command whenever new check-ins are added to the Fossil
** repository in order to reflect those changes into the mirror. If
** the MIRROR option is omitted, the repository from the previous
** invocation is used.
**
** The MIRROR directory will contain a subdirectory named
** ".mirror_state" that contains information that Fossil needs to
** do incremental exports. Do not attempt to manage or edit the files
** in that directory since doing so can disrupt future incremental
** exports.
**
** Options:
** --autopush URL Automatically do a 'git push' to URL. The
** URL is remembered and used on subsequent exports
** to the same repository. Or if URL is "off" the
** auto-push mechanism is disabled
** --debug FILE Write fast-export text to FILE rather than
** piping it into "git fast-import"
** -f|--force Do the export even if nothing has changed
** --if-mirrored No-op if the mirror does not already exist
** --limit N Add no more than N new check-ins to MIRROR.
** Useful for debugging
** --mainbranch NAME Use NAME as the name of the main branch in Git.
** The "trunk" branch of the Fossil repository is
** mapped into this name. "master" is used if
** this option is omitted.
** -q|--quiet Reduce output. Repeat for even less output.
** -v|--verbose More output
**
** > fossil git import MIRROR
**
** TBD...
**
** > fossil git status
**
** Show the status of the current Git mirror, if there is one.
**
** -q|--quiet No output if there is nothing to report
*/
void gitmirror_command(void){
char *zCmd;
int nCmd;
if( g.argc<3 ){
usage("SUBCOMMAND ...");
}
zCmd = g.argv[2];
nCmd = (int)strlen(zCmd);
if( nCmd>2 && strncmp(zCmd,"export",nCmd)==0 ){
gitmirror_export_command();
}else
if( nCmd>2 && strncmp(zCmd,"import",nCmd)==0 ){
|
| ︙ | ︙ |
Changes to src/extcgi.c.
| ︙ | ︙ | |||
47 48 49 50 51 52 53 54 55 56 57 58 59 60 | "FOSSIL_REPOSITORY", "FOSSIL_URI", "FOSSIL_USER", "GATEWAY_INTERFACE", "HTTPS", "HTTP_ACCEPT", /* "HTTP_ACCEPT_ENCODING", // omitted from sub-cgi */ "HTTP_COOKIE", "HTTP_HOST", "HTTP_IF_MODIFIED_SINCE", "HTTP_IF_NONE_MATCH", "HTTP_REFERER", "HTTP_USER_AGENT", "PATH_INFO", | > | 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | "FOSSIL_REPOSITORY", "FOSSIL_URI", "FOSSIL_USER", "GATEWAY_INTERFACE", "HTTPS", "HTTP_ACCEPT", /* "HTTP_ACCEPT_ENCODING", // omitted from sub-cgi */ "HTTP_ACCEPT_LANGUAGE", "HTTP_COOKIE", "HTTP_HOST", "HTTP_IF_MODIFIED_SINCE", "HTTP_IF_NONE_MATCH", "HTTP_REFERER", "HTTP_USER_AGENT", "PATH_INFO", |
| ︙ | ︙ | |||
113 114 115 116 117 118 119 |
static int isDirWithIndexFile(char **pzPath){
static const char *azIndexNames[] = {
"index.html", "index.wiki", "index.md"
};
int i;
if( file_isdir(*pzPath, ExtFILE)!=1 ) return 0;
if( sqlite3_strglob("*/", *pzPath)!=0 ) return 0;
| | | 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 |
static int isDirWithIndexFile(char **pzPath){
static const char *azIndexNames[] = {
"index.html", "index.wiki", "index.md"
};
int i;
if( file_isdir(*pzPath, ExtFILE)!=1 ) return 0;
if( sqlite3_strglob("*/", *pzPath)!=0 ) return 0;
for(i=0; i<(int)(sizeof(azIndexNames)/sizeof(azIndexNames[0])); i++){
char *zNew = mprintf("%s%s", *pzPath, azIndexNames[i]);
if( file_isfile(zNew, ExtFILE) ){
fossil_free(*pzPath);
*pzPath = zNew;
return 1;
}
fossil_free(zNew);
|
| ︙ | ︙ | |||
270 271 272 273 274 275 276 |
char *z = mprintf("fossil version %s", get_version());
if( strncmp(zSrvSw,z,strlen(z)-4)!=0 ){
zSrvSw = mprintf("%z, %s", z, zSrvSw);
}
}
cgi_replace_parameter("SERVER_SOFTWARE", zSrvSw);
cgi_replace_parameter("GATEWAY_INTERFACE","CGI/1.0");
| | | | 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 |
char *z = mprintf("fossil version %s", get_version());
if( strncmp(zSrvSw,z,strlen(z)-4)!=0 ){
zSrvSw = mprintf("%z, %s", z, zSrvSw);
}
}
cgi_replace_parameter("SERVER_SOFTWARE", zSrvSw);
cgi_replace_parameter("GATEWAY_INTERFACE","CGI/1.0");
for(i=0; i<(int)(sizeof(azCgiEnv)/sizeof(azCgiEnv[0])); i++){
(void)P(azCgiEnv[i]);
}
fossil_clearenv();
for(i=0; i<(int)(sizeof(azCgiEnv)/sizeof(azCgiEnv[0])); i++){
const char *zVal = P(azCgiEnv[i]);
if( zVal ) fossil_setenv(azCgiEnv[i], zVal);
}
fossil_setenv("HTTP_ACCEPT_ENCODING","");
rc = popen2(zScript, &fdFromChild, &toChild, &pidChild, 1);
if( rc ){
zFailReason = "cannot exec CGI child process";
|
| ︙ | ︙ |
Changes to src/file.c.
| ︙ | ︙ | |||
57 58 59 60 61 62 63 64 65 66 67 68 69 70 | ** the target pathname of the symbolic link. ** ** RepoFILE Like SymFILE if allow-symlinks is true, or like ** ExtFILE if allow-symlinks is false. In other words, ** symbolic links are only recognized as something different ** from files or directories if allow-symlinks is true. */ #define ExtFILE 0 /* Always follow symlinks */ #define RepoFILE 1 /* Follow symlinks if and only if allow-symlinks is OFF */ #define SymFILE 2 /* Never follow symlinks */ #include <dirent.h> #if defined(_WIN32) # define DIR _WDIR | > | 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | ** the target pathname of the symbolic link. ** ** RepoFILE Like SymFILE if allow-symlinks is true, or like ** ExtFILE if allow-symlinks is false. In other words, ** symbolic links are only recognized as something different ** from files or directories if allow-symlinks is true. */ #include <stdlib.h> #define ExtFILE 0 /* Always follow symlinks */ #define RepoFILE 1 /* Follow symlinks if and only if allow-symlinks is OFF */ #define SymFILE 2 /* Never follow symlinks */ #include <dirent.h> #if defined(_WIN32) # define DIR _WDIR |
| ︙ | ︙ | |||
201 202 203 204 205 206 207 |
/*
** Return the mode bits for a file. Return -1 if the file does not
** exist. If zFilename is NULL return the size of the most recently
** stat-ed file.
*/
int file_mode(const char *zFilename, int eFType){
| | | 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 |
/*
** Return the mode bits for a file. Return -1 if the file does not
** exist. If zFilename is NULL return the size of the most recently
** stat-ed file.
*/
int file_mode(const char *zFilename, int eFType){
return getStat(zFilename, eFType) ? -1 : (int)(fx.fileStat.st_mode);
}
/*
** Return TRUE if either of the following are true:
**
** (1) zFilename is an ordinary file
**
|
| ︙ | ︙ | |||
240 241 242 243 244 245 246 |
void symlink_create(const char *zTargetFile, const char *zLinkFile){
#if !defined(_WIN32)
if( db_allow_symlinks() ){
int i, nName;
char *zName, zBuf[1000];
nName = strlen(zLinkFile);
| | | 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 |
void symlink_create(const char *zTargetFile, const char *zLinkFile){
#if !defined(_WIN32)
if( db_allow_symlinks() ){
int i, nName;
char *zName, zBuf[1000];
nName = strlen(zLinkFile);
if( nName>=(int)sizeof(zBuf) ){
zName = mprintf("%s", zLinkFile);
}else{
zName = zBuf;
memcpy(zName, zLinkFile, nName+1);
}
nName = file_simplify_name(zName, nName, 0);
for(i=1; i<nName; i++){
|
| ︙ | ︙ | |||
376 377 378 379 380 381 382 | return 0; } /* ** The file named zFile is suppose to be an in-tree file. Check to ** ensure that it will be safe to write to this file by verifying that ** there are no symlinks or other non-directory objects in between the | | | 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 |
return 0;
}
/*
** The file named zFile is suppose to be an in-tree file. Check to
** ensure that it will be safe to write to this file by verifying that
** there are no symlinks or other non-directory objects in between the
** root of the check-out and zFile.
**
** If a problem is found, print a warning message (using fossil_warning())
** and return non-zero. If everything is ok, return zero.
*/
int file_unsafe_in_tree_path(const char *zFile){
int n;
if( !file_is_absolute_path(zFile) ){
|
| ︙ | ︙ | |||
1473 1474 1475 1476 1477 1478 1479 | ** ** Usage: %fossil test-file-environment FILENAME... ** ** Display the effective file handling subsystem "settings" and then ** display file system information about the files specified, if any. ** ** Options: | < | | | | | 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 |
**
** Usage: %fossil test-file-environment FILENAME...
**
** Display the effective file handling subsystem "settings" and then
** display file system information about the files specified, if any.
**
** Options:
** --allow-symlinks BOOLEAN Temporarily turn allow-symlinks on/off
** --open-config Open the configuration database first
** --reset Reset cached stat() info for each file
** --root ROOT Use ROOT as the root of the check-out
** --slash Trailing slashes, if any, are retained
*/
void cmd_test_file_environment(void){
int i;
int slashFlag = find_option("slash",0,0)!=0;
int resetFlag = find_option("reset",0,0)!=0;
const char *zRoot = find_option("root",0,1);
const char *zAllow = find_option("allow-symlinks",0,1);
|
| ︙ | ︙ | |||
1697 1698 1699 1700 1701 1702 1703 |
char *zFull;
int (*xCmp)(const char*,const char*,int);
blob_zero(pOut);
if( !g.localOpen ){
if( absolute && !file_is_absolute_path(zOrigName) ){
if( errFatal ){
| | | | | 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 |
char *zFull;
int (*xCmp)(const char*,const char*,int);
blob_zero(pOut);
if( !g.localOpen ){
if( absolute && !file_is_absolute_path(zOrigName) ){
if( errFatal ){
fossil_fatal("relative to absolute needs open check-out tree: %s",
zOrigName);
}
return 0;
}else{
/*
** The original path may be relative or absolute; however, without
** an open check-out tree, the only things we can do at this point
** is return it verbatim or generate a fatal error. The caller is
** probably expecting a tree-relative path name will be returned;
** however, most places where this function is called already check
** if the local check-out tree is open, either directly or indirectly,
** which would make this situation impossible. Alternatively, they
** could check the returned path using the file_is_absolute_path()
** function.
*/
blob_appendf(pOut, "%s", zOrigName);
return 1;
}
|
| ︙ | ︙ | |||
1747 1748 1749 1750 1751 1752 1753 |
return 1;
}
if( nFull<=nLocalRoot || xCmp(zLocalRoot, zFull, nLocalRoot) ){
blob_reset(&localRoot);
blob_reset(&full);
if( errFatal ){
| | | 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 |
return 1;
}
if( nFull<=nLocalRoot || xCmp(zLocalRoot, zFull, nLocalRoot) ){
blob_reset(&localRoot);
blob_reset(&full);
if( errFatal ){
fossil_fatal("file outside of check-out tree: %s", zOrigName);
}
return 0;
}
if( absolute ){
if( !file_is_absolute_path(zOrigName) ){
blob_append(pOut, zLocalRoot, nLocalRoot);
}
|
| ︙ | ︙ | |||
1772 1773 1774 1775 1776 1777 1778 | /* ** COMMAND: test-tree-name ** ** Test the operation of the tree name generator. ** ** Options: | | | 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 |
/*
** COMMAND: test-tree-name
**
** Test the operation of the tree name generator.
**
** Options:
** --absolute Return an absolute path instead of a relative one
** --case-sensitive B Enable or disable case-sensitive filenames. B is
** a boolean: "yes", "no", "true", "false", etc.
*/
void cmd_test_tree_name(void){
int i;
Blob x;
int absoluteFlag = find_option("absolute",0,0)!=0;
|
| ︙ | ︙ | |||
2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 |
*/
void file_test_valid_for_windows(void){
int i;
for(i=2; i<g.argc; i++){
fossil_print("%s %s\n", file_is_win_reserved(g.argv[i]), g.argv[i]);
}
}
/*
** Remove surplus "/" characters from the beginning of a full pathname.
** Extra leading "/" characters are benign on unix. But on Windows
** machines, they must be removed. Example: Convert "/C:/fossil/xyx.fossil"
** into "C:/fossil/xyz.fossil". Cygwin should behave as Windows here.
*/
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 |
*/
void file_test_valid_for_windows(void){
int i;
for(i=2; i<g.argc; i++){
fossil_print("%s %s\n", file_is_win_reserved(g.argv[i]), g.argv[i]);
}
}
/*
** Returns non-zero if the specified file extension belongs to a Fossil
** repository file.
*/
int file_is_repository_extension(const char *zPath){
if( fossil_strcmp(zPath, ".fossil")==0 ) return 1;
#if USE_SEE
if( fossil_strcmp(zPath, ".efossil")==0 ) return 1;
#endif
return 0;
}
/*
** Returns non-zero if the specified path appears to match a file extension
** that should belong to a Fossil repository file.
*/
int file_contains_repository_extension(const char *zPath){
if( sqlite3_strglob("*.fossil*",zPath)==0 ) return 1;
#if USE_SEE
if( sqlite3_strglob("*.efossil*",zPath)==0 ) return 1;
#endif
return 0;
}
/*
** Returns non-zero if the specified path ends with a file extension that
** should belong to a Fossil repository file.
*/
int file_ends_with_repository_extension(const char *zPath, int bQual){
if( bQual ){
if( sqlite3_strglob("*/*.fossil", zPath)==0 ) return 1;
#if USE_SEE
if( sqlite3_strglob("*/*.efossil", zPath)==0 ) return 1;
#endif
}else{
if( sqlite3_strglob("*.fossil", zPath)==0 ) return 1;
#if USE_SEE
if( sqlite3_strglob("*.efossil", zPath)==0 ) return 1;
#endif
}
return 0;
}
/*
** Remove surplus "/" characters from the beginning of a full pathname.
** Extra leading "/" characters are benign on unix. But on Windows
** machines, they must be removed. Example: Convert "/C:/fossil/xyx.fossil"
** into "C:/fossil/xyz.fossil". Cygwin should behave as Windows here.
*/
|
| ︙ | ︙ | |||
2400 2401 2402 2403 2404 2405 2406 |
}
}
return 1;
}
/*
** Internal helper for touch_cmd(). If the given file name is found in
| | | 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 |
}
}
return 1;
}
/*
** Internal helper for touch_cmd(). If the given file name is found in
** the given check-out version, which MUST be the check-out version
** currently populating the vfile table, the vfile.mrid value for the
** file is returned, else 0 is returned. zName must be resolvable
** as-is from the vfile table - this function neither expands nor
** normalizes it, though it does compare using the repo's
** filename_collation() preference.
*/
static int touch_cmd_vfile_mrid( int vid, char const *zName ){
|
| ︙ | ︙ | |||
2429 2430 2431 2432 2433 2434 2435 | } /* ** COMMAND: touch* ** ** Usage: %fossil touch ?OPTIONS? ?FILENAME...? ** | | | | | | | | | | | | 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 |
}
/*
** COMMAND: touch*
**
** Usage: %fossil touch ?OPTIONS? ?FILENAME...?
**
** For each file in the current check-out matching one of the provided
** list of glob patterns and/or file names, the file's mtime is
** updated to a value specified by one of the flags --checkout,
** --checkin, or --now.
**
** If neither glob patterns nor filenames are provided, it operates on
** all files managed by the currently checked-out version.
**
** This command gets its name from the conventional Unix "touch"
** command.
**
** Options:
** --now Stamp each affected file with the current time.
** This is the default behavior.
** -c|--checkin Stamp each affected file with the time of the
** most recent check-in which modified that file
** -C|--checkout Stamp each affected file with the time of the
** currently checked-out version
** -g GLOBLIST Comma-separated list of glob patterns
** -G GLOBFILE Similar to -g but reads its globs from a
** fossil-conventional glob list file
** -v|--verbose Outputs extra information about its globs
** and each file it touches
** -n|--dry-run Outputs which files would require touching,
** but does not touch them
** -q|--quiet Suppress warnings, e.g. when skipping unmanaged
** or out-of-tree files
**
** Only one of --now, --checkin, and --checkout may be used. The
** default is --now.
**
** Only one of -g or -G may be used. If neither is provided and no
** additional filenames are provided, the effect is as if a glob of
** '*' were provided, i.e. all files belonging to the
** currently checked-out version. Note that all glob patterns provided
** via these flags are always evaluated as if they are relative to the
** top of the source tree, not the current working (sub)directory.
** Filenames provided without these flags, on the other hand, are
** treated as relative to the current directory.
**
** As a special case, files currently undergoing an uncommitted merge
** might not get timestamped with --checkin because it may be
** impossible for fossil to choose between multiple potential
** timestamps. A non-fatal warning is emitted for such cases.
**
*/
void touch_cmd(){
const char * zGlobList; /* -g List of glob patterns */
const char * zGlobFile; /* -G File of glob patterns */
Glob * pGlob = 0; /* List of glob patterns */
int verboseFlag;
int dryRunFlag;
int vid; /* Check-out version */
int changeCount = 0; /* Number of files touched */
int quietFlag = 0; /* -q|--quiet */
int timeFlag; /* -1==--checkin, 1==--checkout, 0==--now */
i64 nowTime = 0; /* Timestamp of --now or --checkout */
Stmt q;
Blob absBuffer = empty_blob; /* Absolute filename buffer */
|
| ︙ | ︙ | |||
2511 2512 2513 2514 2515 2516 2517 |
int const now = find_option("now",0,0) ? 1 : 0;
if(ci + co + now > 1){
fossil_fatal("Options --checkin, --checkout, and --now may "
"not be used together.");
}else if(co){
timeFlag = 1;
if(verboseFlag){
| | | | | | | 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 |
int const now = find_option("now",0,0) ? 1 : 0;
if(ci + co + now > 1){
fossil_fatal("Options --checkin, --checkout, and --now may "
"not be used together.");
}else if(co){
timeFlag = 1;
if(verboseFlag){
fossil_print("Timestamp = current check-out version.\n");
}
}else if(ci){
timeFlag = -1;
if(verboseFlag){
fossil_print("Timestamp = check-in in which each file was "
"most recently modified.\n");
}
}else{
timeFlag = 0;
if(verboseFlag){
fossil_print("Timestamp = current system time.\n");
}
}
}
verify_all_options();
db_must_be_within_tree();
vid = db_lget_int("checkout", 0);
if(vid==0){
fossil_fatal("Cannot determine check-out version.");
}
if(zGlobList){
pGlob = *zGlobList ? glob_create(zGlobList) : 0;
}else if(zGlobFile){
Blob globs = empty_blob;
blob_read_from_file(&globs, zGlobFile, ExtFILE);
pGlob = glob_create( globs.aData );
blob_reset(&globs);
}
if( pGlob && verboseFlag!=0 ){
int i;
for(i=0; i<pGlob->nPattern; ++i){
fossil_print("glob: %s\n", pGlob->azPattern[i]);
}
}
db_begin_transaction();
if(timeFlag==0){/*--now*/
nowTime = time(0);
}else if(timeFlag>0){/*--checkout: get the check-out
manifest's timestamp*/
assert(vid>0);
nowTime = db_int64(-1,
"SELECT CAST(strftime('%%s',"
"(SELECT mtime FROM event WHERE objid=%d)"
") AS INTEGER)", vid);
if(nowTime<0){
fossil_fatal("Could not determine check-out version's time!");
}
}else{ /* --checkin */
assert(0 == nowTime);
}
if((pGlob && pGlob->nPattern>0) || g.argc<3){
/*
** We have either (1) globs or (2) no trailing filenames. If there
|
| ︙ | ︙ |
Changes to src/fileedit.c.
| ︙ | ︙ | |||
20 21 22 23 24 25 26 | #include "config.h" #include "fileedit.h" #include <assert.h> #include <stdarg.h> /* ** State for the "mini-checkin" infrastructure, which enables the | | | | 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 |
#include "config.h"
#include "fileedit.h"
#include <assert.h>
#include <stdarg.h>
/*
** State for the "mini-checkin" infrastructure, which enables the
** ability to commit changes to a single file without a check-out
** db, e.g. for use via an HTTP request.
**
** Use CheckinMiniInfo_init() to cleanly initialize one to a known
** valid/empty default state.
**
** Memory for all non-const pointer members is owned by the
** CheckinMiniInfo instance, unless explicitly noted otherwise, and is
** freed by CheckinMiniInfo_cleanup(). Similarly, each instance owns
** any memory for its own Blob members, but NOT for its pointers to
** blobs.
*/
struct CheckinMiniInfo {
Manifest * pParent; /* parent check-in. Memory is owned by this
object. */
char *zParentUuid; /* Full UUID of pParent */
char *zFilename; /* Name of single file to commit. Must be
relative to the top of the repo. */
Blob fileContent; /* Content of file referred to by zFilename. */
Blob fileHash; /* Hash of this->fileContent, using the repo's
preferred hash method. */
|
| ︙ | ︙ | |||
99 100 101 102 103 104 105 | ** than their parent. i.e. they may not have a timestamp ** which predates their parent. This flag bypasses that ** check. */ CIMINI_ALLOW_OLDER = 1<<4, /* | | | 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 | ** than their parent. i.e. they may not have a timestamp ** which predates their parent. This flag bypasses that ** check. */ CIMINI_ALLOW_OLDER = 1<<4, /* ** Indicates that the content of the newly checked-in file is ** converted, if needed, to use the same EOL style as the previous ** version of that file. Only the in-memory/in-repo copies are ** affected, not the original file (if any). */ CIMINI_CONVERT_EOL_INHERIT = 1<<5, /* ** Indicates that the input's EOLs should be converted to Unix-style. |
| ︙ | ︙ | |||
384 385 386 387 388 389 390 | blob_appendf(pOut, "Z %b\n", &zCard); blob_reset(&zCard); return 1; #undef mf_err } /* | | | | | 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 | blob_appendf(pOut, "Z %b\n", &zCard); blob_reset(&zCard); return 1; #undef mf_err } /* ** A so-called "single-file/mini/web check-in" is a slimmed-down form ** of the check-in command which accepts only a single file and is ** intended to accept edits to a file via the web interface or from ** the CLI from outside of a check-out. ** ** Being fully non-interactive is a requirement for this function, ** thus it cannot perform autosync or similar activities (which ** includes checking for repo locks). ** ** This routine uses the state from the given fully-populated pCI ** argument to add pCI->fileContent to the database, and create and |
| ︙ | ︙ | |||
438 439 440 441 442 443 444 | ** ** On error, returns false (0) and, if pErr is not NULL, writes a ** diagnostic message there. ** ** Returns true on success. If pRid is not NULL, the RID of the ** resulting manifest is written to *pRid. ** | | | 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 |
**
** On error, returns false (0) and, if pErr is not NULL, writes a
** diagnostic message there.
**
** Returns true on success. If pRid is not NULL, the RID of the
** resulting manifest is written to *pRid.
**
** The check-in process is largely influenced by pCI->flags, and that
** must be populated before calling this. See the fossil_cimini_flags
** enum for the docs for each flag.
*/
static int checkin_mini(CheckinMiniInfo * pCI, int *pRid, Blob * pErr){
Blob mf = empty_blob; /* output manifest */
int rid = 0, frid = 0; /* various RIDs */
int isPrivate; /* whether this is private content
|
| ︙ | ︙ | |||
492 493 494 495 496 497 498 |
}
if(!file_is_simple_pathname(pCI->zFilename, 1)){
ci_err((pErr,"Invalid filename for use in a repository: %s",
pCI->zFilename));
}
if(!(CIMINI_ALLOW_OLDER & pCI->flags)
&& !checkin_is_younger(pCI->pParent->rid, pCI->zDate)){
| | | 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 |
}
if(!file_is_simple_pathname(pCI->zFilename, 1)){
ci_err((pErr,"Invalid filename for use in a repository: %s",
pCI->zFilename));
}
if(!(CIMINI_ALLOW_OLDER & pCI->flags)
&& !checkin_is_younger(pCI->pParent->rid, pCI->zDate)){
ci_err((pErr,"Check-in time (%s) may not be older "
"than its parent (%z).",
pCI->zDate,
db_text(0, "SELECT strftime('%%Y-%%m-%%dT%%H:%%M:%%f',%lf)",
pCI->pParent->rDate)
));
}
{
|
| ︙ | ︙ | |||
525 526 527 528 529 530 531 |
if(CIMINI_CONVERT_EOL_WINDOWS & pCI->flags) ++n;
if(n>1){
ci_err((pErr,"More than 1 EOL conversion policy was specified."));
}
}
/* Potential TODOs include:
**
| | | | 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 |
if(CIMINI_CONVERT_EOL_WINDOWS & pCI->flags) ++n;
if(n>1){
ci_err((pErr,"More than 1 EOL conversion policy was specified."));
}
}
/* Potential TODOs include:
**
** - Commit allows an empty check-in only with a flag, but we
** currently disallow an empty check-in entirely. Conform with
** commit?
**
** Non-TODOs:
**
** - Check for a commit lock would require auto-sync, which this
** code cannot do if it's going to be run via a web page.
*/
|
| ︙ | ︙ | |||
615 616 617 618 619 620 621 |
}
}else{
assert(CIMINI_CONVERT_EOL_WINDOWS & pCI->flags);
if(!(LOOK_CRLF & lookNew)){
blob_add_cr(&pCI->fileContent);
}
}
| | | 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 |
}
}else{
assert(CIMINI_CONVERT_EOL_WINDOWS & pCI->flags);
if(!(LOOK_CRLF & lookNew)){
blob_add_cr(&pCI->fileContent);
}
}
if((int)blob_size(&pCI->fileContent)!=oldSize){
rehash = 1;
}
}
if(rehash!=0){
hname_hash(&pCI->fileContent, 0, &pCI->fileHash);
}
}
|
| ︙ | ︙ | |||
696 697 698 699 700 701 702 | ** ** Usage: %fossil test-ci-mini ?OPTIONS? FILENAME ** ** where FILENAME is a repo-relative name as it would appear in the ** vfile table. ** ** Options: | < | | | | | | | | | | | | | | | | | | | 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 |
**
** Usage: %fossil test-ci-mini ?OPTIONS? FILENAME
**
** where FILENAME is a repo-relative name as it would appear in the
** vfile table.
**
** Options:
** -R|--repository REPO The repository file to commit to
** --as FILENAME The repository-side name of the input
** file, relative to the top of the
** repository. Default is the same as the
** input file name.
** -m|--comment COMMENT Required check-in comment
** -M|--comment-file FILE Reads check-in comment from the given file
** -r|--revision VERSION Commit from this version. Default is
** the check-out version (if available) or
** trunk (if used without a check-out).
** --allow-fork Allows the commit to be made against a
** non-leaf parent. Note that no autosync
** is performed beforehand.
** --allow-merge-conflict Allows check-in of a file even if it
** appears to contain a fossil merge conflict
** marker
** --user-override USER USER to use instead of the current
** default
** --date-override DATETIME DATE to use instead of 'now'
** --allow-older Allow a commit to be older than its
** ancestor
** --convert-eol-inherit Convert EOL style of the check-in to match
** the previous version's content
** --convert-eol-unix Convert the EOL style to Unix
** --convert-eol-windows Convert the EOL style to Windows.
** (Only one of the --convert-eol-X options may be used and they only
** modified the saved blob, not the input file.)
** --delta Prefer to generate a delta manifest, if
** able. The forbid-delta-manifests repo
** config option trumps this, as do certain
** heuristics.
** --allow-new-file Allow addition of a new file this way.
** Disabled by default to avoid that case-
** sensitivity errors inadvertently lead to
** adding a new file where an update is
** intended.
** -d|--dump-manifest Dumps the generated manifest to stdout
** immediately after it's generated
** --save-manifest FILE Saves the generated manifest to a file
** after successfully processing it
** --wet-run Disables the default dry-run mode
**
** Example:
**
** %fossil test-ci-mini -R REPO -m ... -r foo --as src/myfile.c myfile.c
**
*/
void test_ci_mini_cmd(void){
CheckinMiniInfo cimi; /* check-in state */
int newRid = 0; /* RID of new version */
const char * zFilename; /* argv[2] */
const char * zComment; /* -m comment */
const char * zCommentFile; /* -M FILE */
const char * zAsFilename; /* --as filename */
const char * zRevision; /* -r|--revision [=trunk|checkout] */
const char * zUser; /* --user-override */
|
| ︙ | ︙ | |||
817 818 819 820 821 822 823 |
}else{
if(zCommentFile && *zCommentFile){
blob_read_from_file(&cimi.comment, zCommentFile, ExtFILE);
}else if(zComment && *zComment){
blob_append(&cimi.comment, zComment, -1);
}
if(!blob_size(&cimi.comment)){
| | | | 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 |
}else{
if(zCommentFile && *zCommentFile){
blob_read_from_file(&cimi.comment, zCommentFile, ExtFILE);
}else if(zComment && *zComment){
blob_append(&cimi.comment, zComment, -1);
}
if(!blob_size(&cimi.comment)){
fossil_fatal("Non-empty check-in comment is required.");
}
}
db_begin_transaction();
zFilename = g.argv[2];
cimi.zFilename = mprintf("%/", zAsFilename ? zAsFilename : zFilename);
cimi.filePerm = file_perm(zFilename, ExtFILE);
cimi.zUser = mprintf("%s", zUser ? zUser : login_name());
if(zDate){
cimi.zDate = mprintf("%s", zDate);
}
if(zRevision==0 || zRevision[0]==0){
if(g.localOpen/*check-out*/){
zRevision = db_lget("checkout-hash", 0)/*leak*/;
}else{
zRevision = "trunk";
}
}
name_to_uuid2(zRevision, "ci", &cimi.zParentUuid);
if(cimi.zParentUuid==0){
|
| ︙ | ︙ | |||
871 872 873 874 875 876 877 |
rid_to_uuid(newRid));
}
db_end_transaction(0/*checkin_mini() will have triggered it to roll
** back in dry-run mode, but we need access to
** the transaction-written db state in this
** routine.*/);
if(!(cimi.flags & CIMINI_DRY_RUN) && newRid!=0 && g.localOpen!=0){
| | | 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 |
rid_to_uuid(newRid));
}
db_end_transaction(0/*checkin_mini() will have triggered it to roll
** back in dry-run mode, but we need access to
** the transaction-written db state in this
** routine.*/);
if(!(cimi.flags & CIMINI_DRY_RUN) && newRid!=0 && g.localOpen!=0){
fossil_warning("The check-out state is now out of sync "
"with regards to this commit. It needs to be "
"'update'd or 'close'd and re-'open'ed.");
}
CheckinMiniInfo_cleanup(&cimi);
}
/*
|
| ︙ | ︙ | |||
967 968 969 970 971 972 973 | ** cannot be resolved or is ambiguous, pVid is not assigned. ** ** - *frid = the RID of zFilename's blob content. May not be NULL ** unless zFilename is also NULL. If BOTH of zFilename and frid are ** NULL then no confirmation is done on the filename argument - only ** zRev is checked. ** | | | | | | 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 |
** cannot be resolved or is ambiguous, pVid is not assigned.
**
** - *frid = the RID of zFilename's blob content. May not be NULL
** unless zFilename is also NULL. If BOTH of zFilename and frid are
** NULL then no confirmation is done on the filename argument - only
** zRev is checked.
**
** Returns 0 if the given file is not in the given check-in or if
** fileedit_ajax_check_filename() fails, else returns true. If it
** returns false, it queues up an error response and the caller must
** return immediately.
*/
static int fileedit_ajax_setup_filerev(const char * zRev,
char ** zRevUuid,
int * pVid,
const char * zFilename,
int * frid){
char * zFileUuid = 0; /* file content UUID */
const int checkFile = zFilename!=0 || frid!=0;
int vid = 0;
if(checkFile && !fileedit_ajax_check_filename(zFilename)){
return 0;
}
vid = symbolic_name_to_rid(zRev, "ci");
if(0==vid){
ajax_route_error(404,"Cannot resolve name as a check-in: %s",
zRev);
return 0;
}else if(vid<0){
ajax_route_error(400,"Check-in name is ambiguous: %s",
zRev);
return 0;
}else if(pVid!=0){
*pVid = vid;
}
if(checkFile){
zFileUuid = fileedit_file_uuid(zFilename, vid, 0);
if(zFileUuid==0){
ajax_route_error(404, "Check-in does not contain file.");
return 0;
}
}
if(zRevUuid!=0){
*zRevUuid = rid_to_uuid(vid);
}
if(checkFile){
|
| ︙ | ︙ | |||
1034 1035 1036 1037 1038 1039 1040 | ** produces a JSON response as documented for ajax_route_error(). ** ** Extra response headers: ** ** x-fileedit-file-perm: empty or "x" or "l", representing PERM_REG, ** PERM_EXE, or PERM_LINK, respectively. ** | | | 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 |
** produces a JSON response as documented for ajax_route_error().
**
** Extra response headers:
**
** x-fileedit-file-perm: empty or "x" or "l", representing PERM_REG,
** PERM_EXE, or PERM_LINK, respectively.
**
** x-fileedit-checkin-branch: branch name for the passed-in check-in.
*/
static void fileedit_ajax_content(void){
const char * zFilename = 0;
const char * zRev = 0;
int vid, frid;
Blob content = empty_blob;
const char * zMime;
|
| ︙ | ︙ | |||
1085 1086 1087 1088 1089 1090 1091 | /* ** AJAX route /fileedit?ajax=diff ** ** Required query parameters: ** ** filename=FILENAME ** content=text | | | 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 | /* ** AJAX route /fileedit?ajax=diff ** ** Required query parameters: ** ** filename=FILENAME ** content=text ** checkin=check-in version ** ** Optional parameters: ** ** sbs=integer (1=side-by-side or 0=unified, default=0) ** ** ws=integer (0=diff whitespace, 1=ignore EOL ws, 2=ignore all ws) ** |
| ︙ | ︙ | |||
1153 1154 1155 1156 1157 1158 1159 |
blob_reset(&orig);
}
fossil_free(zRevUuid);
blob_reset(&content);
}
/*
| | | 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 |
blob_reset(&orig);
}
fossil_free(zRevUuid);
blob_reset(&content);
}
/*
** Sets up and validates most, but not all, of p's check-in-related
** state from the CGI environment. Returns 0 on success or a suggested
** HTTP result code on error, in which case a message will have been
** written to pErr.
**
** It always fails if it cannot completely resolve the 'file' and 'r'
** parameters, including verifying that the refer to a real
** file/version combination and editable by the current user. All
|
| ︙ | ︙ | |||
1175 1176 1177 1178 1179 1180 1181 |
**
** Intended to be used only by /filepage and /filepage_commit.
*/
static int fileedit_setup_cimi_from_p(CheckinMiniInfo * p, Blob * pErr,
int * bIsMissingArg){
char * zFileUuid = 0; /* UUID of file content */
const char * zFlag; /* generic flag */
| | | 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 |
**
** Intended to be used only by /filepage and /filepage_commit.
*/
static int fileedit_setup_cimi_from_p(CheckinMiniInfo * p, Blob * pErr,
int * bIsMissingArg){
char * zFileUuid = 0; /* UUID of file content */
const char * zFlag; /* generic flag */
int rc = 0, vid = 0, frid = 0; /* result code, check-in/file rids */
#define fail(EXPR) blob_appendf EXPR; goto end_fail
zFlag = PD("filename",P("fn"));
if(zFlag==0 || !*zFlag){
rc = 400;
if(bIsMissingArg){
*bIsMissingArg = 1;
|
| ︙ | ︙ | |||
1207 1208 1209 1210 1211 1212 1213 |
*bIsMissingArg = 1;
}
fail((pErr,"Missing required 'checkin' parameter."));
}
vid = symbolic_name_to_rid(zFlag, "ci");
if(0==vid){
rc = 404;
| | | | | 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 |
*bIsMissingArg = 1;
}
fail((pErr,"Missing required 'checkin' parameter."));
}
vid = symbolic_name_to_rid(zFlag, "ci");
if(0==vid){
rc = 404;
fail((pErr,"Could not resolve check-in version."));
}else if(vid<0){
rc = 400;
fail((pErr,"Check-in name is ambiguous."));
}
p->zParentUuid = rid_to_uuid(vid)/*fully expand it*/;
zFileUuid = fileedit_file_uuid(p->zFilename, vid, &p->filePerm);
if(!zFileUuid){
rc = 404;
fail((pErr,"Check-in [%S] does not contain file: "
"[%h]", p->zParentUuid, p->zFilename));
}else if(PERM_LNK==p->filePerm){
rc = 400;
fail((pErr,"Editing symlinks is not permitted."));
}
/* Find the repo-side file entry or fail... */
|
| ︙ | ︙ | |||
1340 1341 1342 1343 1344 1345 1346 |
}
CX("]");
db_finalize(&q);
}
/*
** For the given fully resolved UUID, renders a JSON object containing
| | | 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 |
}
CX("]");
db_finalize(&q);
}
/*
** For the given fully resolved UUID, renders a JSON object containing
** the fileeedit-editable files in that check-in:
**
** {
** checkin: UUID,
** editableFiles: [ filename1, ... filenameN ]
** }
**
** They are sorted by name using filename_collation().
|
| ︙ | ︙ | |||
1390 1391 1392 1393 1394 1395 1396 |
** [
** {checkin: UUID, branch: branchName, timestamp: string}
** ]
**
** The entries are ordered newest first.
**
** 'checkin=CHECKIN_NAME': fetch the current list of is-editable files
| | | 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 |
** [
** {checkin: UUID, branch: branchName, timestamp: string}
** ]
**
** The entries are ordered newest first.
**
** 'checkin=CHECKIN_NAME': fetch the current list of is-editable files
** for the current user and given check-in name:
**
** {
** checkin: UUID,
** editableFiles: [ filename1, ... filenameN ] // sorted by name
** }
**
** On error it produces a JSON response as documented for
|
| ︙ | ︙ | |||
1428 1429 1430 1431 1432 1433 1434 | /* ** AJAX route /fileedit?ajax=commit ** ** Required query parameters: ** ** filename=FILENAME | | | 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 | /* ** AJAX route /fileedit?ajax=commit ** ** Required query parameters: ** ** filename=FILENAME ** checkin=Parent check-in UUID ** content=text ** comment=non-empty text ** ** Optional query parameters: ** ** comment_mimetype=text (NOT currently honored) ** |
| ︙ | ︙ | |||
1452 1453 1454 1455 1456 1457 1458 |
** from the input in order to avoid certain race conditions
** client-side):
**
** {
** checkin: newUUID,
** filename: theFilename,
** mimetype: string,
| | | | | 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 |
** from the input in order to avoid certain race conditions
** client-side):
**
** {
** checkin: newUUID,
** filename: theFilename,
** mimetype: string,
** branch: name of the check-in's branch,
** isExe: bool,
** dryRun: bool,
** manifest: text of manifest,
** }
**
** On error it produces a JSON response as documented for
** ajax_route_error().
*/
static void fileedit_ajax_commit(void){
Blob err = empty_blob; /* Error messages */
Blob manifest = empty_blob; /* raw new manifest */
CheckinMiniInfo cimi; /* check-in state */
int rc; /* generic result code */
int newVid = 0; /* new version's RID */
char * zNewUuid = 0; /* newVid's UUID */
char const * zMimetype;
char * zBranch = 0;
if(!ajax_route_bootstrap(1,1)){
return;
}
db_begin_transaction();
CheckinMiniInfo_init(&cimi);
rc = fileedit_setup_cimi_from_p(&cimi, &err, 0);
if(0!=rc){
ajax_route_error(rc,"%b",&err);
goto end_cleanup;
}
if(blob_size(&cimi.comment)==0){
ajax_route_error(400,"Empty check-in comment is not permitted.");
goto end_cleanup;
}
if(0!=atoi(PD("include_manifest","0"))){
cimi.pMfOut = &manifest;
}
checkin_mini(&cimi, &newVid, &err);
if(blob_size(&err)){
|
| ︙ | ︙ | |||
1538 1539 1540 1541 1542 1543 1544 | ** Note that fileedit-glob, by design, is a local-only setting. ** It does not sync across repository clones, and must be explicitly ** set on any repositories where this page should be activated. ** ** Optional query parameters: ** ** filename=FILENAME Repo-relative path to the file. | | | | | | | 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 |
** Note that fileedit-glob, by design, is a local-only setting.
** It does not sync across repository clones, and must be explicitly
** set on any repositories where this page should be activated.
**
** Optional query parameters:
**
** filename=FILENAME Repo-relative path to the file.
** checkin=VERSION Check-in version, using any unambiguous
** symbolic version name.
**
** If passed a filename but no check-in then it will attempt to
** load that file from the most recent leaf check-in.
**
** Once the page is loaded, files may be selected from any open leaf
** version. The only way to edit files from non-leaf checkins is to
** pass both the filename and check-in as URL parameters to the page.
** Users with the proper permissions will be presented with "Edit"
** links in various file-specific contexts for files which match the
** fileedit-glob, regardless of whether they refer to leaf versions or
** not.
*/
void fileedit_page(void){
const char * zFileMime = 0; /* File mime type guess */
CheckinMiniInfo cimi; /* Check-in state */
int previewRenderMode = AJAX_RENDER_GUESS; /* preview mode */
Blob err = empty_blob; /* Error report */
const char *zAjax = P("name"); /* Name of AJAX route for
sub-dispatching. */
/*
** Internal-use URL parameters:
|
| ︙ | ︙ | |||
1697 1698 1699 1700 1701 1702 1703 |
"data-tab-parent='fileedit-tabs' "
"data-tab-label='File Selection' "
"class='hidden'"
">");
CX("<div id='fileedit-file-selector'></div>");
CX("</div>"/*#fileedit-tab-fileselect*/);
}
| | > | > | 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 |
"data-tab-parent='fileedit-tabs' "
"data-tab-label='File Selection' "
"class='hidden'"
">");
CX("<div id='fileedit-file-selector'></div>");
CX("</div>"/*#fileedit-tab-fileselect*/);
}
/******* Content tab *******/
{
CX("<div id='fileedit-tab-content' "
"data-tab-parent='fileedit-tabs' "
"data-tab-label='File Content' "
"class='hidden'"
">");
CX("<div class='fileedit-options flex-container "
"flex-row child-gap-small'>");
CX("<div class='input-with-label'>"
"<button class='fileedit-content-reload confirmer' "
">Discard & Reload</button>"
"<div class='help-buttonlet'>"
"Reload the file from the server, discarding "
"any local edits. To help avoid accidental loss of "
"edits, it requires confirmation (a second click) within "
"a few seconds or it will not reload."
"</div>"
"</div>");
style_select_list_int("select-font-size",
"editor_font_size", "Editor font size",
NULL/*tooltip*/,
100,
"100%", 100, "125%", 125,
"150%", 150, "175%", 175,
"200%", 200, NULL);
wikiedit_emit_toggle_preview();
CX("</div>");
CX("<div class='flex-container flex-column stretch'>");
CX("<textarea name='content' id='fileedit-content-editor' "
"class='fileedit' rows='25'>");
CX("</textarea>");
CX("</div>"/*textarea wrapper*/);
CX("</div>"/*#tab-file-content*/);
|
| ︙ | ︙ | |||
1993 1994 1995 1996 1997 1998 1999 |
builtin_fossil_js_bundle_or("fetch", "dom", "tabs", "confirmer",
"storage", "popupwidget", "copybutton",
"pikchr", NULL);
/*
** Set up a JS-side mapping of the AJAX_RENDER_xyz values. This is
** used for dynamically toggling certain UI components on and off.
| | | 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 |
builtin_fossil_js_bundle_or("fetch", "dom", "tabs", "confirmer",
"storage", "popupwidget", "copybutton",
"pikchr", NULL);
/*
** Set up a JS-side mapping of the AJAX_RENDER_xyz values. This is
** used for dynamically toggling certain UI components on and off.
** Must come after window.fossil has been initialized and before
** fossil.page.fileedit.js. Potential TODO: move this into the
** window.fossil bootstrapping so that we don't have to "fulfill"
** the JS multiple times.
*/
ajax_emit_js_preview_modes(1);
builtin_fossil_js_bundle_or("diff", NULL);
builtin_request_js("fossil.page.fileedit.js");
|
| ︙ | ︙ | |||
2019 2020 2021 2022 2023 2024 2025 |
CX("fossil.config['fileedit-glob'] = ");
glob_render_json_to_cgi(fileedit_glob());
CX(";\n");
if(blob_size(&err)>0){
CX("fossil.error(%!j);\n", blob_str(&err));
}
/* Populate the page with the current leaves and, if available,
| | | 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 |
CX("fossil.config['fileedit-glob'] = ");
glob_render_json_to_cgi(fileedit_glob());
CX(";\n");
if(blob_size(&err)>0){
CX("fossil.error(%!j);\n", blob_str(&err));
}
/* Populate the page with the current leaves and, if available,
the selected check-in's file list, to save 1 or 2 XHR requests
at startup. That makes this page uncacheable, but compressed
delivery of this page is currently less than 6k. */
CX("fossil.page.initialLeaves = ");
fileedit_render_leaves_list(cimi.zParentUuid ? 0 : &zFirstLeafUuid);
CX(";\n");
if(zFirstLeafUuid){
assert(!cimi.zParentUuid);
|
| ︙ | ︙ |
Changes to src/finfo.c.
| ︙ | ︙ | |||
39 40 41 42 43 44 45 | ** option to see similar information about the same file for the check-in ** specified by VERSION. ** ** In the -s mode prints the status as <status> <revision>. This is ** a quick status and does not check for up-to-date-ness of the file. ** ** In the -p mode, there's an optional flag "-r|--revision REVISION". | | | 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | ** option to see similar information about the same file for the check-in ** specified by VERSION. ** ** In the -s mode prints the status as <status> <revision>. This is ** a quick status and does not check for up-to-date-ness of the file. ** ** In the -p mode, there's an optional flag "-r|--revision REVISION". ** The specified version (or the latest checked-out version) is printed ** to stdout. The -p mode is another form of the "cat" command. ** ** Options: ** -b|--brief Display a brief (one line / revision) summary ** --case-sensitive B Enable or disable case-sensitive filenames. B is a ** boolean: "yes", "no", "true", "false", etc. ** -i|--id Print the artifact ID |
| ︙ | ︙ | |||
76 77 78 79 80 81 82 |
/* We should be done with options.. */
verify_all_options();
if( g.argc!=3 ) usage("-s|--status FILENAME");
vid = db_lget_int("checkout", 0);
if( vid==0 ){
| | | 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
/* We should be done with options.. */
verify_all_options();
if( g.argc!=3 ) usage("-s|--status FILENAME");
vid = db_lget_int("checkout", 0);
if( vid==0 ){
fossil_fatal("no check-out to finfo files in");
}
vfile_check_signature(vid, CKSIG_ENOTFILE);
file_tree_name(g.argv[2], &fname, 0, 1);
db_prepare(&q,
"SELECT pathname, deleted, rid, chnged, coalesce(origname!=pathname,0)"
" FROM vfile WHERE vfile.pathname=%B %s",
&fname, filename_collation());
|
| ︙ | ︙ | |||
270 271 272 273 274 275 276 | ** Usage: %fossil cat FILENAME ... ?OPTIONS? ** ** Print on standard output the content of one or more files as they exist ** in the repository. The version currently checked out is shown by default. ** Other versions may be specified using the -r option. ** ** Options: | > | | > > > > > > > > > | > | 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 |
** Usage: %fossil cat FILENAME ... ?OPTIONS?
**
** Print on standard output the content of one or more files as they exist
** in the repository. The version currently checked out is shown by default.
** Other versions may be specified using the -r option.
**
** Options:
** -o|--out OUTFILE For exactly one given FILENAME, write to OUTFILE
** -R|--repository REPO Extract artifacts from repository REPO
** -r VERSION The specific check-in containing the file
**
** See also: [[finfo]]
*/
void cat_cmd(void){
int i;
Blob content, fname;
const char *zRev;
const char *zFileName;
db_find_and_open_repository(0, 0);
zRev = find_option("r","r",1);
zFileName = find_option("out","o",1);
/* We should be done with options.. */
verify_all_options();
if ( zFileName && g.argc>3 ){
fossil_fatal("output file can only be given when retrieving a single file");
}
for(i=2; i<g.argc; i++){
file_tree_name(g.argv[i], &fname, 0, 1);
blob_zero(&content);
historical_blob(zRev, blob_str(&fname), &content, 1);
if ( g.argc==3 && zFileName ){
blob_write_to_file(&content, zFileName);
}else{
blob_write_to_file(&content, "-");
}
blob_reset(&fname);
blob_reset(&content);
}
}
/* Values for the debug= query parameter to finfo */
#define FINFO_DEBUG_MLINK 0x01
|
| ︙ | ︙ | |||
410 411 412 413 414 415 416 417 418 419 420 421 422 423 |
ridTo = name_to_typed_rid(P("to"),"ci");
path_shortest_stored_in_ancestor_table(ridFrom,ridTo);
}else{
compute_direct_ancestors(ridFrom);
}
}
url_add_parameter(&url, "name", zFilename);
blob_zero(&sql);
if( ridCi ){
/* If we will be tracking changes across renames, some extra temp
** tables (implemented as CTEs) are required */
blob_append_sql(&sql,
/* The clade(fid,fnid) table is the set of all (fid,fnid) pairs
** that should participate in the output. Clade is computed by
| > | 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 |
ridTo = name_to_typed_rid(P("to"),"ci");
path_shortest_stored_in_ancestor_table(ridFrom,ridTo);
}else{
compute_direct_ancestors(ridFrom);
}
}
url_add_parameter(&url, "name", zFilename);
cgi_check_for_malice();
blob_zero(&sql);
if( ridCi ){
/* If we will be tracking changes across renames, some extra temp
** tables (implemented as CTEs) are required */
blob_append_sql(&sql,
/* The clade(fid,fnid) table is the set of all (fid,fnid) pairs
** that should participate in the output. Clade is computed by
|
| ︙ | ︙ | |||
556 557 558 559 560 561 562 |
blob_appendf(&title, " and check-in %z%S</a>", zLink, zUuid);
fossil_free(zUuid);
}
}else if( ridCi ){
blob_appendf(&title, "History of the file that is called ");
hyperlinked_path(zFilename, &title, 0, "tree", "", LINKPATH_FILE);
if( fShowId ) blob_appendf(&title, " (%d)", fnid);
| | | 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 |
blob_appendf(&title, " and check-in %z%S</a>", zLink, zUuid);
fossil_free(zUuid);
}
}else if( ridCi ){
blob_appendf(&title, "History of the file that is called ");
hyperlinked_path(zFilename, &title, 0, "tree", "", LINKPATH_FILE);
if( fShowId ) blob_appendf(&title, " (%d)", fnid);
blob_appendf(&title, " at check-in %z%h</a>",
href("%R/info?name=%t",zCI), zCI);
}else{
blob_appendf(&title, "History for ");
hyperlinked_path(zFilename, &title, 0, "tree", "", LINKPATH_FILE);
if( fShowId ) blob_appendf(&title, " (%d)", fnid);
}
if( uBg ){
|
| ︙ | ︙ | |||
679 680 681 682 683 684 685 686 687 688 689 690 691 692 |
fossil_free(zNewName);
}else{
@ <b>Deleted:</b>
}
}
if( (tmFlags & TIMELINE_VERBOSE)!=0 && zUuid ){
hyperlink_to_version(zUuid);
@ part of check-in \
hyperlink_to_version(zCkin);
}
}
@ %W(zCom)</span>
if( (tmFlags & TIMELINE_COMPACT)!=0 ){
@ <span class='timelineEllipsis' data-id='%d(frid)' \
| > > > > > > > > | 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 |
fossil_free(zNewName);
}else{
@ <b>Deleted:</b>
}
}
if( (tmFlags & TIMELINE_VERBOSE)!=0 && zUuid ){
hyperlink_to_version(zUuid);
if( fShowId ){
int srcId = delta_source_rid(frid);
if( srcId ){
@ (%z(href("%R/deltachain/%d",frid))%d(frid)←%d(srcId)</a>)
}else{
@ (%z(href("%R/deltachain/%d",frid))%d(frid)</a>)
}
}
@ part of check-in \
hyperlink_to_version(zCkin);
}
}
@ %W(zCom)</span>
if( (tmFlags & TIMELINE_COMPACT)!=0 ){
@ <span class='timelineEllipsis' data-id='%d(frid)' \
|
| ︙ | ︙ | |||
706 707 708 709 710 711 712 |
if( tmFlags & (TIMELINE_COMPACT|TIMELINE_VERBOSE) ) cgi_printf("(");
if( zUuid && (tmFlags & TIMELINE_VERBOSE)==0 ){
@ file: %z(href("%R/file?name=%T&ci=%!S",zFName,zCkin))\
@ [%S(zUuid)]</a>
if( fShowId ){
int srcId = delta_source_rid(frid);
if( srcId>0 ){
| > | | | 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 |
if( tmFlags & (TIMELINE_COMPACT|TIMELINE_VERBOSE) ) cgi_printf("(");
if( zUuid && (tmFlags & TIMELINE_VERBOSE)==0 ){
@ file: %z(href("%R/file?name=%T&ci=%!S",zFName,zCkin))\
@ [%S(zUuid)]</a>
if( fShowId ){
int srcId = delta_source_rid(frid);
if( srcId>0 ){
@ id: %z(href("%R/deltachain/%d",frid))\
@ %d(frid)←%d(srcId)</a>
}else{
@ id: %z(href("%R/deltachain/%d",frid))%d(frid)</a>
}
}
}
@ check-in: \
hyperlink_to_version(zCkin);
if( fShowId ){
@ (%d(fmid))
|
| ︙ | ︙ | |||
745 746 747 748 749 750 751 |
@ [edit]</a>
}
@ </span></span>
}
if( fDebug & FINFO_DEBUG_MLINK ){
int ii;
char *zAncLink;
| | | 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 |
@ [edit]</a>
}
@ </span></span>
}
if( fDebug & FINFO_DEBUG_MLINK ){
int ii;
char *zAncLink;
@ <br>fid=%d(frid) \
@ graph-id=%lld(frid>0?(GraphRowId)frid*(mxfnid+1)+fnid:fpid+1000000000) \
@ pid=%d(fpid) mid=%d(fmid) fnid=%d(fnid) \
@ pfnid=%d(pfnid) mxfnid=%d(mxfnid)
if( nParent>0 ){
@ parents=%lld(aParent[0])
for(ii=1; ii<nParent; ii++){
@ %lld(aParent[ii])
|
| ︙ | ︙ | |||
908 909 910 911 912 913 914 |
/* 7 */ " isaux"
" FROM mlink WHERE mid=%d ORDER BY 1",
mid
);
@ <h1>MLINK table for check-in %h(zCI)</h1>
render_checkin_context(mid, 0, 1, 0);
style_table_sorter();
| | | 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 |
/* 7 */ " isaux"
" FROM mlink WHERE mid=%d ORDER BY 1",
mid
);
@ <h1>MLINK table for check-in %h(zCI)</h1>
render_checkin_context(mid, 0, 1, 0);
style_table_sorter();
@ <hr>
@ <div class='brlist'>
@ <table class='sortable' data-column-types='ttxtttt' data-init-sort='1'>
@ <thead><tr>
@ <th>File</th>
@ <th>Parent<br>Check-in</th>
@ <th>Merge?</th>
@ <th>New</th>
|
| ︙ | ︙ |
Changes to src/foci.c.
| ︙ | ︙ | |||
261 262 263 264 265 266 267 |
fociColumn, /* xColumn - read data */
fociRowid, /* xRowid - read data */
0, /* xUpdate */
0, /* xBegin */
0, /* xSync */
0, /* xCommit */
0, /* xRollback */
| | | > > | 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 |
fociColumn, /* xColumn - read data */
fociRowid, /* xRowid - read data */
0, /* xUpdate */
0, /* xBegin */
0, /* xSync */
0, /* xCommit */
0, /* xRollback */
0, /* xFindFunction */
0, /* xRename */
0, /* xSavepoint */
0, /* xRelease */
0, /* xRollbackTo */
0, /* xShadowName */
0 /* xIntegrity */
};
sqlite3_create_module(db, "files_of_checkin", &foci_module, 0);
return SQLITE_OK;
}
|
Changes to src/forum.c.
| ︙ | ︙ | |||
45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
ForumPost *pEditNext; /* This post is edited by pEditNext */
ForumPost *pEditPrev; /* This post is an edit of pEditPrev */
ForumPost *pNext; /* Next in chronological order */
ForumPost *pPrev; /* Previous in chronological order */
ForumPost *pDisplay; /* Next in display order */
int nEdit; /* Number of edits to this post */
int nIndent; /* Number of levels of indentation for this post */
};
/*
** A single instance of the following tracks all entries for a thread.
*/
struct ForumThread {
ForumPost *pFirst; /* First post in chronological order */
| > | 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
ForumPost *pEditNext; /* This post is edited by pEditNext */
ForumPost *pEditPrev; /* This post is an edit of pEditPrev */
ForumPost *pNext; /* Next in chronological order */
ForumPost *pPrev; /* Previous in chronological order */
ForumPost *pDisplay; /* Next in display order */
int nEdit; /* Number of edits to this post */
int nIndent; /* Number of levels of indentation for this post */
int iClosed; /* See forum_rid_is_closed() */
};
/*
** A single instance of the following tracks all entries for a thread.
*/
struct ForumThread {
ForumPost *pFirst; /* First post in chronological order */
|
| ︙ | ︙ | |||
75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
" WHERE A.fpid=$rid AND B.froot=A.froot AND B.fprev=$rid"
);
db_bind_int(&q, "$rid", rid);
res = db_step(&q)==SQLITE_ROW;
db_reset(&q);
return res;
}
/*
** Delete a complete ForumThread and all its entries.
*/
static void forumthread_delete(ForumThread *pThread){
ForumPost *pPost, *pNext;
for(pPost=pThread->pFirst; pPost; pPost = pNext){
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 |
" WHERE A.fpid=$rid AND B.froot=A.froot AND B.fprev=$rid"
);
db_bind_int(&q, "$rid", rid);
res = db_step(&q)==SQLITE_ROW;
db_reset(&q);
return res;
}
/*
** Given a valid forumpost.fpid value, this function returns the first
** fpid in the chain of edits for that forum post, or rid if no prior
** versions are found.
*/
static int forumpost_head_rid(int rid){
Stmt q;
int rcRid = rid;
db_prepare(&q, "SELECT fprev FROM forumpost"
" WHERE fpid=:rid AND fprev IS NOT NULL");
db_bind_int(&q, ":rid", rid);
while( SQLITE_ROW==db_step(&q) ){
rcRid = db_column_int(&q, 0);
db_reset(&q);
db_bind_int(&q, ":rid", rcRid);
}
db_finalize(&q);
return rcRid;
}
/*
** Returns true if p, or any parent of p, has a non-zero iClosed
** value. Returns 0 if !p. For an edited chain of post, the tag is
** checked on the pEditHead entry, to simplify subsequent unlocking of
** the post.
**
** If bCheckIrt is true then p's thread in-response-to parents are
** checked (recursively) for closure, else only p is checked.
*/
static int forumpost_is_closed(ForumPost *p, int bCheckIrt){
while(p){
if( p->pEditHead ) p = p->pEditHead;
if( p->iClosed || !bCheckIrt ) return p->iClosed;
p = p->pIrt;
}
return 0;
}
/*
** Given a forum post RID, this function returns true if that post has
** (or inherits) an active "closed" tag. If bCheckIrt is true then
** the post to which the given post responds is also checked
** (recursively), else they are not. When checking in-response-to
** posts, the first one which is closed ends the search.
**
** Note that this function checks _exactly_ the given rid, whereas
** forum post closure/re-opening is always applied to the head of an
** edit chain so that we get consistent implied locking beheavior for
** later versions and responses to arbitrary versions in the
** chain. Even so, the "closed" tag is applied as a propagating tag
** so will apply to all edits in a given chain.
**
** The return value is one of:
**
** - 0 if no "closed" tag is found.
**
** - The tagxref.rowid of the tagxref entry for the closure if rid is
** the forum post to which the closure applies.
**
** - (-tagxref.rowid) if the given rid inherits a "closed" tag from an
** IRT forum post.
*/
static int forum_rid_is_closed(int rid, int bCheckIrt){
static Stmt qIrt = empty_Stmt_m;
int rc = 0, i = 0;
/* TODO: this can probably be turned into a CTE by someone with
** superior SQL-fu. */
for( ; rid; i++ ){
rc = rid_has_active_tag_name(rid, "closed");
if( rc || !bCheckIrt ) break;
else if( !qIrt.pStmt ) {
db_static_prepare(&qIrt,
"SELECT firt FROM forumpost "
"WHERE fpid=$fpid ORDER BY fmtime DESC"
);
}
db_bind_int(&qIrt, "$fpid", rid);
rid = SQLITE_ROW==db_step(&qIrt) ? db_column_int(&qIrt, 0) : 0;
db_reset(&qIrt);
}
return i ? -rc : rc;
}
/*
** Closes or re-opens the given forum RID via addition of a new
** control artifact into the repository. In order to provide
** consistent behavior for implied closing of responses and later
** versions, it always acts on the first version of the given forum
** post, walking the forumpost.fprev values to find the head of the
** chain.
**
** If doClose is true then a propagating "closed" tag is added, except
** as noted below, with the given optional zReason string as the tag's
** value. If doClose is false then any active "closed" tag on frid is
** cancelled, except as noted below. zReason is ignored if doClose is
** false or if zReason is NULL or starts with a NUL byte.
**
** This function only adds a "closed" tag if forum_rid_is_closed()
** indicates that frid's head is not closed. If a parent post is
** already closed, no tag is added. Similarly, it will only remove a
** "closed" tag from a post which has its own "closed" tag, and will
** not remove an inherited one from a parent post.
**
** If doClose is true and frid is closed (directly or inherited), this
** is a no-op. Likewise, if doClose is false and frid itself is not
** closed (not accounting for an inherited closed tag), this is a
** no-op.
**
** Returns true if it actually creates a new tag, else false. Fails
** fatally on error. If it returns true then any ForumPost::iClosed
** values from previously loaded posts are invalidated if they refer
** to the amended post or a response to it.
**
** Sidebars:
**
** - Unless the caller has a transaction open, via
** db_begin_transaction(), there is a very tiny race condition
** window during which the caller's idea of whether or not the forum
** post is closed may differ from the current repository state.
**
** - This routine assumes that frid really does refer to a forum post.
**
** - This routine assumes that frid is not private or pending
** moderation.
**
** - Closure of a forum post requires a propagating "closed" tag to
** account for how edits of posts are handled. This differs from
** closure of a branch, where a non-propagating tag is used.
*/
static int forumpost_close(int frid, int doClose, const char *zReason){
Blob artifact = BLOB_INITIALIZER; /* Output artifact */
Blob cksum = BLOB_INITIALIZER; /* Z-card */
int iClosed; /* true if frid is closed */
int trid; /* RID of new control artifact */
char *zUuid; /* UUID of head version of post */
db_begin_transaction();
frid = forumpost_head_rid(frid);
iClosed = forum_rid_is_closed(frid, 1);
if( (iClosed && doClose
/* Already closed, noting that in the case of (iClosed<0), it's
** actually a parent which is closed. */)
|| (iClosed<=0 && !doClose
/* This entry is not closed, but a parent post may be. */) ){
db_end_transaction(0);
return 0;
}
if( doClose==0 || (zReason && !zReason[0]) ){
zReason = 0;
}
zUuid = rid_to_uuid(frid);
blob_appendf(&artifact, "D %z\n", date_in_standard_format( "now" ));
blob_appendf(&artifact,
"T %cclosed %s%s%F\n",
doClose ? '*' : '-', zUuid,
zReason ? " " : "", zReason ? zReason : "");
blob_appendf(&artifact, "U %F\n", login_name());
md5sum_blob(&artifact, &cksum);
blob_appendf(&artifact, "Z %b\n", &cksum);
blob_reset(&cksum);
trid = content_put_ex(&artifact, 0, 0, 0, 0);
if( trid==0 ){
fossil_fatal("Error saving tag artifact: %s", g.zErrMsg);
}
if( manifest_crosslink(trid, &artifact,
MC_NONE /*MC_PERMIT_HOOKS?*/)==0 ){
fossil_fatal("%s", g.zErrMsg);
}
assert( blob_is_reset(&artifact) );
db_add_unsent(trid);
admin_log("%s forum post %S", doClose ? "Close" : "Re-open", zUuid);
fossil_free(zUuid);
/* Potential TODO: if (iClosed>0) then we could find the initial tag
** artifact and content_deltify(thatRid,&trid,1,0). Given the tiny
** size of these artifacts, however, that would save little space,
** if any. */
db_end_transaction(0);
return 1;
}
/*
** Returns true if the forum-close-policy setting is true, else false,
** caching the result for subsequent calls.
*/
static int forumpost_close_policy(void){
static int closePolicy = -99;
if( closePolicy==-99 ){
closePolicy = db_get_boolean("forum-close-policy",0)>0;
}
return closePolicy;
}
/*
** Returns 1 if the current user is an admin, -1 if the current user
** is a forum moderator and the forum-close-policy setting is true,
** else returns 0. The value is cached for subsequent calls.
*/
static int forumpost_may_close(void){
static int permClose = -99;
if( permClose!=-99 ){
return permClose;
}else if( g.perm.Admin ){
return permClose = 1;
}else if( g.perm.ModForum ){
return permClose = forumpost_close_policy()>0 ? -1 : 0;
}else{
return permClose = 0;
}
}
/*
** Emits a warning that the current forum post is CLOSED and can only
** be edited or responded to by an administrator. */
static void forumpost_error_closed(void){
@ <div class='error'>This (sub)thread is CLOSED and can only be
@ edited or replied to by an admin user.</div>
}
/*
** Delete a complete ForumThread and all its entries.
*/
static void forumthread_delete(ForumThread *pThread){
ForumPost *pPost, *pNext;
for(pPost=pThread->pFirst; pPost; pPost = pNext){
|
| ︙ | ︙ | |||
213 214 215 216 217 218 219 220 221 222 223 224 225 226 |
pPost->pEditPrev = p;
pPost->pEditHead = p->pEditHead ? p->pEditHead : p;
for(; p; p=p->pEditPrev ){
p->nEdit = pPost->nEdit;
p->pEditTail = pPost;
}
}
}
db_finalize(&q);
if( computeHierarchy ){
/* Compute the hierarchical display order */
pPost = pThread->pFirst;
pPost->nIndent = 1;
| > > > | 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 |
pPost->pEditPrev = p;
pPost->pEditHead = p->pEditHead ? p->pEditHead : p;
for(; p; p=p->pEditPrev ){
p->nEdit = pPost->nEdit;
p->pEditTail = pPost;
}
}
pPost->iClosed = forum_rid_is_closed(pPost->pEditHead
? pPost->pEditHead->fpid
: pPost->fpid, 1);
}
db_finalize(&q);
if( computeHierarchy ){
/* Compute the hierarchical display order */
pPost = pThread->pFirst;
pPost->nIndent = 1;
|
| ︙ | ︙ | |||
298 299 300 301 302 303 304 |
fossil_print("fpid = %d\n", fpid);
fossil_print("froot = %d\n", froot);
pThread = forumthread_create(froot, 1);
fossil_print("Chronological:\n");
fossil_print(
/* 0 1 2 3 4 5 6 7 */
/* 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123 */
| | | > > | > > > > > | | > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 |
fossil_print("fpid = %d\n", fpid);
fossil_print("froot = %d\n", froot);
pThread = forumthread_create(froot, 1);
fossil_print("Chronological:\n");
fossil_print(
/* 0 1 2 3 4 5 6 7 */
/* 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123 */
" sid rev closed fpid pIrt pEditPrev pEditTail hash\n");
for(p=pThread->pFirst; p; p=p->pNext){
fossil_print("%4d %4d %7d %9d %9d %9d %9d %8.8s\n",
p->sid, p->rev,
p->iClosed,
p->fpid, p->pIrt ? p->pIrt->fpid : 0,
p->pEditPrev ? p->pEditPrev->fpid : 0,
p->pEditTail ? p->pEditTail->fpid : 0, p->zUuid);
}
fossil_print("\nDisplay\n");
for(p=pThread->pDisplay; p; p=p->pDisplay){
fossil_print("%*s", (p->nIndent-1)*3, "");
if( p->pEditTail ){
fossil_print("%d->%d", p->fpid, p->pEditTail->fpid);
}else{
fossil_print("%d", p->fpid);
}
if( p->iClosed ){
fossil_print(" [closed%s]", p->iClosed<0 ? " via parent" : "");
}
fossil_print("\n");
}
forumthread_delete(pThread);
}
/*
** WEBPAGE: forumthreadhashlist
**
** Usage: /forumthreadhashlist/HASH-OF-ROOT
**
** This page (accessibly only to admins) shows a list of all artifacts
** associated with a single forum thread. An admin might copy/paste this
** list into the /shun page in order to shun an entire thread.
*/
void forumthreadhashlist(void){
int fpid;
int froot;
const char *zName = P("name");
ForumThread *pThread;
ForumPost *p;
char *fuuid;
login_check_credentials();
if( !g.perm.Admin ){
return;
}
if( zName==0 ){
webpage_error("Missing \"name=\" query parameter");
}
fpid = symbolic_name_to_rid(zName, "f");
if( fpid<=0 ){
if( fpid==0 ){
webpage_notfound_error("Unknown forum id: \"%s\"", zName);
}else{
ambiguous_page();
}
return;
}
froot = db_int(0, "SELECT froot FROM forumpost WHERE fpid=%d", fpid);
if( froot==0 ){
webpage_notfound_error("Not a forum post: \"%s\"", zName);
}
fuuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", froot);
style_set_current_feature("forum");
style_header("Artifacts Of Forum Thread");
@ <h2>
@ Artifacts associated with the forum thread
@ <a href="%R/forumthread/%S(fuuid)">%S(fuuid)</a>:</h2>
@ <pre>
pThread = forumthread_create(froot, 1);
for(p=pThread->pFirst; p; p=p->pNext){
@ %h(p->zUuid)
}
forumthread_delete(pThread);
@ </pre>
style_finish_page();
}
/*
** Render a forum post for display
*/
void forum_render(
const char *zTitle, /* The title. Might be NULL for no title */
|
| ︙ | ︙ | |||
456 457 458 459 460 461 462 463 464 465 466 467 | char *zEditorName; /* Name of user who provided the current edit */ char *zDate; /* The time/date string */ char *zHist; /* History query string */ Manifest *pManifest; /* Manifest comprising the current post */ int bPrivate; /* True for posts awaiting moderation */ int bSameUser; /* True if author is also the reader */ int iIndent; /* Indent level */ const char *zMimetype;/* Formatting MIME type */ /* Get the manifest for the post. Abort if not found (e.g. shunned). */ pManifest = manifest_get(p->fpid, CFTYPE_FORUM, 0); if( !pManifest ) return; | > | > | | | | | 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 |
char *zEditorName; /* Name of user who provided the current edit */
char *zDate; /* The time/date string */
char *zHist; /* History query string */
Manifest *pManifest; /* Manifest comprising the current post */
int bPrivate; /* True for posts awaiting moderation */
int bSameUser; /* True if author is also the reader */
int iIndent; /* Indent level */
int iClosed; /* True if (sub)thread is closed */
const char *zMimetype;/* Formatting MIME type */
/* Get the manifest for the post. Abort if not found (e.g. shunned). */
pManifest = manifest_get(p->fpid, CFTYPE_FORUM, 0);
if( !pManifest ) return;
iClosed = forumpost_is_closed(p, 1);
/* When not in raw mode, create the border around the post. */
if( !bRaw ){
/* Open the <div> enclosing the post. Set the class string to mark the post
** as selected and/or obsolete. */
iIndent = (p->pEditHead ? p->pEditHead->nIndent : p->nIndent)-1;
@ <div id='forum%d(p->fpid)' class='forumTime\
@ %s(bSelect ? " forumSel" : "")\
@ %s(iClosed ? " forumClosed" : "")\
@ %s(p->pEditTail ? " forumObs" : "")' \
if( iIndent && iIndentScale ){
@ style='margin-left:%d(iIndent*iIndentScale)ex;'>
}else{
@ >
}
/* If this is the first post (or an edit thereof), emit the thread title. */
if( pManifest->zThreadTitle ){
@ <h1>%h(pManifest->zThreadTitle)</h1>
}
/* Begin emitting the header line. The forum of the title
** varies depending on whether:
** * The post is unedited
** * The post was last edited by the original author
** * The post was last edited by a different person
*/
if( p->pEditHead ){
zDate = db_text(0, "SELECT datetime(%.17g,toLocal())",
p->pEditHead->rDate);
}else{
zPosterName = forum_post_display_name(p, pManifest);
zEditorName = zPosterName;
}
zDate = db_text(0, "SELECT datetime(%.17g,toLocal())", p->rDate);
if( p->pEditPrev ){
zPosterName = forum_post_display_name(p->pEditHead, 0);
zEditorName = forum_post_display_name(p, pManifest);
zHist = bHist ? "" : zQuery[0]==0 ? "?hist" : "&hist";
@ <h3 class='forumPostHdr'>(%d(p->sid)\
@ .%0*d(fossil_num_digits(p->nEdit))(p->rev))
if( fossil_strcmp(zPosterName, zEditorName)==0 ){
@ By %s(zPosterName) on %h(zDate) edited from \
@ %z(href("%R/forumpost/%S%s%s",p->pEditPrev->zUuid,zQuery,zHist))\
@ %d(p->sid).%0*d(fossil_num_digits(p->nEdit))(p->pEditPrev->rev)</a>
}else{
@ Originally by %s(zPosterName) \
@ with edits by %s(zEditorName) on %h(zDate) from \
@ %z(href("%R/forumpost/%S%s%s",p->pEditPrev->zUuid,zQuery,zHist))\
@ %d(p->sid).%0*d(fossil_num_digits(p->nEdit))(p->pEditPrev->rev)</a>
}
}else{
zPosterName = forum_post_display_name(p, pManifest);
@ <h3 class='forumPostHdr'>(%d(p->sid))
@ By %s(zPosterName) on %h(zDate)
}
fossil_free(zDate);
/* If debugging is enabled, link to the artifact page. */
if( g.perm.Debug ){
|
| ︙ | ︙ | |||
576 577 578 579 580 581 582 |
}
/* When not in raw mode, finish creating the border around the post. */
if( !bRaw ){
/* If the user is able to write to the forum and if this post has not been
** edited, create a form with various interaction buttons. */
if( g.perm.WrForum && !p->pEditTail ){
| > | | > > > > | | | > > | > > | > > > > > > > > > > > > | 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 |
}
/* When not in raw mode, finish creating the border around the post. */
if( !bRaw ){
/* If the user is able to write to the forum and if this post has not been
** edited, create a form with various interaction buttons. */
if( g.perm.WrForum && !p->pEditTail ){
@ <div class="forumpost-single-controls">\
@ <form action="%R/forumedit" method="POST">
@ <input type="hidden" name="fpid" value="%s(p->zUuid)">
if( !bPrivate ){
/* Reply and Edit are only available if the post has been
** approved. Closed threads can only be edited or replied to
** if forumpost_may_close() is true but a user may delete
** their own posts even if they are closed. */
if( forumpost_may_close() || !iClosed ){
@ <input type="submit" name="reply" value="Reply">
if( g.perm.Admin || (bSameUser && !iClosed) ){
@ <input type="submit" name="edit" value="Edit">
}
if( g.perm.Admin || bSameUser ){
@ <input type="submit" name="nullout" value="Delete">
}
}
}else if( g.perm.ModForum ){
/* Allow moderators to approve or reject pending posts. Also allow
** forum supervisors to mark non-special users as trusted and therefore
** able to post unmoderated. */
@ <input type="submit" name="approve" value="Approve">
@ <input type="submit" name="reject" value="Reject">
if( g.perm.AdminForum && !login_is_special(pManifest->zUser) ){
@ <br><label><input type="checkbox" name="trust">
@ Trust user "%h(pManifest->zUser)" so that future posts by \
@ "%h(pManifest->zUser)" do not require moderation.
@ </label>
@ <input type="hidden" name="trustuser" value="%h(pManifest->zUser)">
}
}else if( bSameUser ){
/* Allow users to delete (reject) their own pending posts. */
@ <input type="submit" name="reject" value="Delete">
}
login_insert_csrf_secret();
@ </form>
if( bSelect && forumpost_may_close() && iClosed>=0 ){
int iHead = forumpost_head_rid(p->fpid);
@ <form method="post" \
@ action='%R/forumpost_%s(iClosed > 0 ? "reopen" : "close")'>
login_insert_csrf_secret();
@ <input type="hidden" name="fpid" value="%z(rid_to_uuid(iHead))" />
if( moderation_pending(p->fpid)==0 ){
@ <input type="submit" value='%s(iClosed ? "Re-open" : "Close")' />
}
@ </form>
}
@ </div>
}
@ </div>
}
/* Clean up. */
manifest_destroy(pManifest);
}
|
| ︙ | ︙ | |||
702 703 704 705 706 707 708 |
if( bHist ){
zQuery[i] = i==0 ? '?' : '&'; i++;
zQuery[i++] = 'h';
zQuery[i++] = 'i';
zQuery[i++] = 's';
zQuery[i++] = 't';
}
| | > | 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 |
if( bHist ){
zQuery[i] = i==0 ? '?' : '&'; i++;
zQuery[i++] = 'h';
zQuery[i++] = 'i';
zQuery[i++] = 's';
zQuery[i++] = 't';
}
assert( i<(int)sizeof(zQuery) );
zQuery[i] = 0;
assert( zQuery[0]==0 || zQuery[0]=='?' );
/* Identify which post to display first. If history is shown, start with the
** original, unedited post. Otherwise advance to the post's latest edit. */
if( mode==FD_RAW || mode==FD_SINGLE ){
p = pSelect;
if( bHist && p->pEditHead ) p = p->pEditHead;
}else{
|
| ︙ | ︙ | |||
847 848 849 850 851 852 853 854 855 856 857 858 859 860 |
if( !g.perm.RdForum ){
login_needed(g.anon.RdForum);
return;
}
if( zName==0 ){
webpage_error("Missing \"name=\" query parameter");
}
fpid = symbolic_name_to_rid(zName, "f");
if( fpid<=0 ){
if( fpid==0 ){
webpage_notfound_error("Unknown forum id: \"%s\"", zName);
}else{
ambiguous_page();
}
| > | 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 |
if( !g.perm.RdForum ){
login_needed(g.anon.RdForum);
return;
}
if( zName==0 ){
webpage_error("Missing \"name=\" query parameter");
}
cgi_check_for_malice();
fpid = symbolic_name_to_rid(zName, "f");
if( fpid<=0 ){
if( fpid==0 ){
webpage_notfound_error("Unknown forum id: \"%s\"", zName);
}else{
ambiguous_page();
}
|
| ︙ | ︙ | |||
911 912 913 914 915 916 917 918 919 920 921 922 923 924 |
}
if( mode!=FD_HIER ){
style_submenu_element("Hierarchical", "%R/%s/%s?t=h%s%s", g.zPath, zName,
bUnf ? "&unf" : "", bHist ? "&hist" : "");
}
style_submenu_checkbox("unf", "Unformatted", 0, 0);
style_submenu_checkbox("hist", "History", 0, 0);
/* Display the thread. */
if( fossil_strcmp(g.zPath,"forumthread")==0 ) fpid = 0;
forum_display_thread(froot, fpid, mode, autoMode, bUnf, bHist);
/* Emit Forum Javascript. */
builtin_request_js("forum.js");
| > > > | 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 |
}
if( mode!=FD_HIER ){
style_submenu_element("Hierarchical", "%R/%s/%s?t=h%s%s", g.zPath, zName,
bUnf ? "&unf" : "", bHist ? "&hist" : "");
}
style_submenu_checkbox("unf", "Unformatted", 0, 0);
style_submenu_checkbox("hist", "History", 0, 0);
if( g.perm.Admin ){
style_submenu_element("Artifacts", "%R/forumthreadhashlist/%t", zName);
}
/* Display the thread. */
if( fossil_strcmp(g.zPath,"forumthread")==0 ) fpid = 0;
forum_display_thread(froot, fpid, mode, autoMode, bUnf, bHist);
/* Emit Forum Javascript. */
builtin_request_js("forum.js");
|
| ︙ | ︙ | |||
942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 |
** Return true if the string is white-space only.
*/
static int whitespace_only(const char *z){
if( z==0 ) return 1;
while( z[0] && fossil_isspace(z[0]) ){ z++; }
return z[0]==0;
}
/*
** Add a new Forum Post artifact to the repository.
**
** Return true if a redirect occurs.
*/
static int forum_post(
const char *zTitle, /* Title. NULL for replies */
int iInReplyTo, /* Post replying to. 0 for new threads */
int iEdit, /* Post being edited, or zero for a new post */
const char *zUser, /* Username. NULL means use login name */
const char *zMimetype, /* Mimetype of content. */
| > > > > > > > > > > > > > > > | > > > > > > | 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 |
** Return true if the string is white-space only.
*/
static int whitespace_only(const char *z){
if( z==0 ) return 1;
while( z[0] && fossil_isspace(z[0]) ){ z++; }
return z[0]==0;
}
/* Flags for use with forum_post() */
#define FPOST_NO_ALERT 1 /* do not send any alerts */
/*
** Return a flags value for use with the final argument to
** forum_post(), extracted from the CGI environment.
*/
static int forum_post_flags(void){
int iPostFlags = 0;
if( g.perm.Debug && P("fpsilent")!=0 ){
iPostFlags |= FPOST_NO_ALERT;
}
return iPostFlags;
}
/*
** Add a new Forum Post artifact to the repository.
**
** Return true if a redirect occurs.
*/
static int forum_post(
const char *zTitle, /* Title. NULL for replies */
int iInReplyTo, /* Post replying to. 0 for new threads */
int iEdit, /* Post being edited, or zero for a new post */
const char *zUser, /* Username. NULL means use login name */
const char *zMimetype, /* Mimetype of content. */
const char *zContent, /* Content */
int iFlags /* FPOST_xyz flag values */
){
char *zDate;
char *zI;
char *zG;
int iBasis;
Blob x, cksum, formatCheck, errMsg;
Manifest *pPost;
int nContent = zContent ? (int)strlen(zContent) : 0;
schema_forum();
if( !g.perm.Admin && (iEdit || iInReplyTo)
&& forum_rid_is_closed(iEdit ? iEdit : iInReplyTo, 1) ){
forumpost_error_closed();
return 0;
}
if( iEdit==0 && whitespace_only(zContent) ){
return 0;
}
if( iInReplyTo==0 && iEdit>0 ){
iBasis = iEdit;
iInReplyTo = db_int(0, "SELECT firt FROM forumpost WHERE fpid=%d", iEdit);
}else{
|
| ︙ | ︙ | |||
1036 1037 1038 1039 1040 1041 1042 |
@ <div class='debug'>
@ This is the artifact that would have been generated:
@ <pre>%h(blob_str(&x))</pre>
@ </div>
blob_reset(&x);
return 0;
}else{
| | > | > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 1453 1454 1455 1456 1457 1458 |
@ <div class='debug'>
@ This is the artifact that would have been generated:
@ <pre>%h(blob_str(&x))</pre>
@ </div>
blob_reset(&x);
return 0;
}else{
int nrid;
db_begin_transaction();
nrid = wiki_put(&x, iEdit>0 ? iEdit : 0, forum_need_moderation());
blob_reset(&x);
if( (iFlags & FPOST_NO_ALERT)!=0 ){
alert_unqueue('f', nrid);
}
db_commit_transaction();
cgi_redirectf("%R/forumpost/%S", rid_to_uuid(nrid));
return 1;
}
}
/*
** Paint the form elements for entering a Forum post
*/
static void forum_post_widget(
const char *zTitle,
const char *zMimetype,
const char *zContent
){
if( zTitle ){
@ Title: <input type="input" name="title" value="%h(zTitle)" size="50"
@ maxlength="125"><br>
}
@ %z(href("%R/markup_help"))Markup style</a>:
mimetype_option_menu(zMimetype, "mimetype");
@ <br><textarea aria-label="Content:" name="content" class="wikiedit" \
@ cols="80" rows="25" wrap="virtual">%h(zContent)</textarea><br>
}
/*
** WEBPAGE: forumpost_close hidden
** WEBPAGE: forumpost_reopen hidden
**
** fpid=X Hash of the post to be edited. REQUIRED
** reason=X Optional reason for closure.
**
** Closes or re-opens the given forum post, within the bounds of the
** API for forumpost_close(). After (perhaps) modifying the "closed"
** status of the given thread, it redirects to that post's thread
** view. Requires admin privileges.
*/
void forum_page_close(void){
const char *zFpid = PD("fpid","");
const char *zReason = 0;
int fClose;
int fpid;
login_check_credentials();
if( forumpost_may_close()==0 ){
login_needed(g.anon.Admin);
return;
}
cgi_csrf_verify();
fpid = symbolic_name_to_rid(zFpid, "f");
if( fpid<=0 ){
webpage_error("Missing or invalid fpid query parameter");
}
fClose = sqlite3_strglob("*_close*", g.zPath)==0;
if( fClose ) zReason = PD("reason",0);
forumpost_close(fpid, fClose, zReason);
cgi_redirectf("%R/forumpost/%S",zFpid);
return;
}
/*
** WEBPAGE: forumnew
** WEBPAGE: forumedit
**
** Start a new thread on the forum or reply to an existing thread.
** But first prompt to see if the user would like to log in.
*/
void forum_page_init(void){
int isEdit;
char *zGoto;
login_check_credentials();
if( !g.perm.WrForum ){
login_needed(g.anon.WrForum);
return;
}
if( sqlite3_strglob("*edit*", g.zPath)==0 ){
zGoto = mprintf("forume2?fpid=%S",PD("fpid",""));
|
| ︙ | ︙ | |||
1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 |
static void forum_from_line(void){
if( login_is_nobody() ){
@ From: anonymous<br>
}else{
@ From: %h(login_name())<br>
}
}
/*
** WEBPAGE: forume1
**
** Start a new forum thread.
*/
void forumnew_page(void){
const char *zTitle = PDT("title","");
const char *zMimetype = PD("mimetype",DEFAULT_FORUM_MIMETYPE);
const char *zContent = PDT("content","");
login_check_credentials();
if( !g.perm.WrForum ){
login_needed(g.anon.WrForum);
return;
}
| > > > > > > > > > > > > > > > > > > | | > < < < | < < < < < < < < > | 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 |
static void forum_from_line(void){
if( login_is_nobody() ){
@ From: anonymous<br>
}else{
@ From: %h(login_name())<br>
}
}
static void forum_render_debug_options(void){
if( g.perm.Debug ){
/* Give extra control over the post to users with the special
* Debug capability, which includes Admin and Setup users */
@ <div class="debug">
@ <label><input type="checkbox" name="dryrun" %s(PCK("dryrun"))> \
@ Dry run</label>
@ <br><label><input type="checkbox" name="domod" %s(PCK("domod"))> \
@ Require moderator approval</label>
@ <br><label><input type="checkbox" name="showqp" %s(PCK("showqp"))> \
@ Show query parameters</label>
@ <br><label><input type="checkbox" name="fpsilent" %s(PCK("fpsilent"))> \
@ Do not sent notification emails</label>
@ </div>
}
}
/*
** WEBPAGE: forume1
**
** Start a new forum thread.
*/
void forumnew_page(void){
const char *zTitle = PDT("title","");
const char *zMimetype = PD("mimetype",DEFAULT_FORUM_MIMETYPE);
const char *zContent = PDT("content","");
login_check_credentials();
if( !g.perm.WrForum ){
login_needed(g.anon.WrForum);
return;
}
if( P("submit") && cgi_csrf_safe(2) ){
if( forum_post(zTitle, 0, 0, 0, zMimetype, zContent,
forum_post_flags()) ) return;
}
if( P("preview") && !whitespace_only(zContent) ){
@ <h1>Preview:</h1>
forum_render(zTitle, zMimetype, zContent, "forumEdit", 1);
}
style_set_current_feature("forum");
style_header("New Forum Thread");
@ <form action="%R/forume1" method="POST">
@ <h1>New Thread:</h1>
forum_from_line();
forum_post_widget(zTitle, zMimetype, zContent);
@ <input type="submit" name="preview" value="Preview">
if( P("preview") && !whitespace_only(zContent) ){
@ <input type="submit" name="submit" value="Submit">
}else{
@ <input type="submit" name="submit" value="Submit" disabled>
}
forum_render_debug_options();
login_insert_csrf_secret();
@ </form>
forum_emit_js();
style_finish_page();
}
/*
** WEBPAGE: forume2
|
| ︙ | ︙ | |||
1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 |
const char *zMimetype = 0;
const char *zContent = 0;
const char *zTitle = 0;
char *zDate = 0;
const char *zFpid = PD("fpid","");
int isCsrfSafe;
int isDelete = 0;
login_check_credentials();
if( !g.perm.WrForum ){
login_needed(g.anon.WrForum);
return;
}
fpid = symbolic_name_to_rid(zFpid, "f");
if( fpid<=0 || (pPost = manifest_get(fpid, CFTYPE_FORUM, 0))==0 ){
webpage_error("Missing or invalid fpid query parameter");
}
froot = db_int(0, "SELECT froot FROM forumpost WHERE fpid=%d", fpid);
if( froot==0 || (pRootPost = manifest_get(froot, CFTYPE_FORUM, 0))==0 ){
webpage_error("fpid does not appear to be a forum post: \"%d\"", fpid);
}
if( P("cancel") ){
| > > > > > | > > > | > > > > | < | 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 |
const char *zMimetype = 0;
const char *zContent = 0;
const char *zTitle = 0;
char *zDate = 0;
const char *zFpid = PD("fpid","");
int isCsrfSafe;
int isDelete = 0;
int iClosed = 0;
int bSameUser; /* True if author is also the reader */
int bPreview; /* True in preview mode. */
int bPrivate; /* True if post is private (not yet moderated) */
int bReply; /* True if replying to a post */
login_check_credentials();
if( !g.perm.WrForum ){
login_needed(g.anon.WrForum);
return;
}
fpid = symbolic_name_to_rid(zFpid, "f");
if( fpid<=0 || (pPost = manifest_get(fpid, CFTYPE_FORUM, 0))==0 ){
webpage_error("Missing or invalid fpid query parameter");
}
froot = db_int(0, "SELECT froot FROM forumpost WHERE fpid=%d", fpid);
if( froot==0 || (pRootPost = manifest_get(froot, CFTYPE_FORUM, 0))==0 ){
webpage_error("fpid does not appear to be a forum post: \"%d\"", fpid);
}
if( P("cancel") ){
cgi_redirectf("%R/forumpost/%S",zFpid);
return;
}
bPreview = P("preview")!=0;
bReply = P("reply")!=0;
iClosed = forum_rid_is_closed(fpid, 1);
isCsrfSafe = cgi_csrf_safe(2);
bPrivate = content_is_private(fpid);
bSameUser = login_is_individual()
&& fossil_strcmp(pPost->zUser, g.zLogin)==0;
if( isCsrfSafe && (g.perm.ModForum || (bPrivate && bSameUser)) ){
if( g.perm.ModForum && P("approve") ){
const char *zUserToTrust;
moderation_approve('f', fpid);
if( g.perm.AdminForum
&& PB("trust")
&& (zUserToTrust = P("trustuser"))!=0
){
db_unprotect(PROTECT_USER);
|
| ︙ | ︙ | |||
1264 1265 1266 1267 1268 1269 1270 |
if( P("submit")
&& isCsrfSafe
&& (zContent = PDT("content",""))!=0
&& (!whitespace_only(zContent) || isDelete)
){
int done = 1;
const char *zMimetype = PD("mimetype",DEFAULT_FORUM_MIMETYPE);
| | | > | > > | 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 1688 1689 1690 1691 1692 1693 |
if( P("submit")
&& isCsrfSafe
&& (zContent = PDT("content",""))!=0
&& (!whitespace_only(zContent) || isDelete)
){
int done = 1;
const char *zMimetype = PD("mimetype",DEFAULT_FORUM_MIMETYPE);
if( bReply ){
done = forum_post(0, fpid, 0, 0, zMimetype, zContent,
forum_post_flags());
}else if( P("edit") || isDelete ){
done = forum_post(P("title"), 0, fpid, 0, zMimetype, zContent,
forum_post_flags());
}else{
webpage_error("Missing 'reply' query parameter");
}
if( done ) return;
}
if( isDelete ){
zMimetype = "text/x-fossil-wiki";
zContent = "";
if( pPost->zThreadTitle ) zTitle = "";
style_header("Delete %s", zTitle ? "Post" : "Reply");
@ <h1>Original Post:</h1>
forum_render(pPost->zThreadTitle, pPost->zMimetype, pPost->zWiki,
"forumEdit", 1);
@ <h1>Change Into:</h1>
forum_render(zTitle, zMimetype, zContent,"forumEdit", 1);
@ <form action="%R/forume2" method="POST">
login_insert_csrf_secret();
@ <input type="hidden" name="fpid" value="%h(P("fpid"))">
@ <input type="hidden" name="nullout" value="1">
@ <input type="hidden" name="mimetype" value="%h(zMimetype)">
@ <input type="hidden" name="content" value="%h(zContent)">
if( zTitle ){
@ <input aria-label="Title" type="hidden" name="title" value="%h(zTitle)">
}
|
| ︙ | ︙ | |||
1305 1306 1307 1308 1309 1310 1311 |
if( zTitle==0 && pPost->zThreadTitle!=0 ){
zTitle = fossil_strdup(pPost->zThreadTitle);
}
style_header("Edit %s", zTitle ? "Post" : "Reply");
@ <h2>Original Post:</h2>
forum_render(pPost->zThreadTitle, pPost->zMimetype, pPost->zWiki,
"forumEdit", 1);
| | > > > > | < < < | | > | | < < < < < < < < < < > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > | 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 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 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 |
if( zTitle==0 && pPost->zThreadTitle!=0 ){
zTitle = fossil_strdup(pPost->zThreadTitle);
}
style_header("Edit %s", zTitle ? "Post" : "Reply");
@ <h2>Original Post:</h2>
forum_render(pPost->zThreadTitle, pPost->zMimetype, pPost->zWiki,
"forumEdit", 1);
if( bPreview ){
@ <h2>Preview of Edited Post:</h2>
forum_render(zTitle, zMimetype, zContent,"forumEdit", 1);
}
@ <h2>Revised Message:</h2>
@ <form action="%R/forume2" method="POST">
login_insert_csrf_secret();
@ <input type="hidden" name="fpid" value="%h(P("fpid"))">
@ <input type="hidden" name="edit" value="1">
forum_from_line();
forum_post_widget(zTitle, zMimetype, zContent);
}else{
/* Reply */
char *zDisplayName;
zMimetype = PD("mimetype",DEFAULT_FORUM_MIMETYPE);
zContent = PDT("content","");
style_header("Reply");
@ <h2>Replying to
@ <a href="%R/forumpost/%!S(zFpid)" target="_blank">%S(zFpid)</a>
if( pRootPost->zThreadTitle ){
@ in thread
@ <span class="forumPostReplyTitle">%h(pRootPost->zThreadTitle)</span>
}
@ </h2>
zDate = db_text(0, "SELECT datetime(%.17g,toLocal())", pPost->rDate);
zDisplayName = display_name_from_login(pPost->zUser);
@ <h3 class='forumPostHdr'>By %s(zDisplayName) on %h(zDate)</h3>
fossil_free(zDisplayName);
fossil_free(zDate);
forum_render(0, pPost->zMimetype, pPost->zWiki, "forumEdit", 1);
if( bPreview && !whitespace_only(zContent) ){
@ <h2>Preview:</h2>
forum_render(0, zMimetype,zContent, "forumEdit", 1);
}
@ <h2>Enter Reply:</h2>
@ <form action="%R/forume2" method="POST">
@ <input type="hidden" name="fpid" value="%h(P("fpid"))">
@ <input type="hidden" name="reply" value="1">
forum_from_line();
forum_post_widget(0, zMimetype, zContent);
}
if( !isDelete ){
@ <input type="submit" name="preview" value="Preview">
}
@ <input type="submit" name="cancel" value="Cancel">
if( (bPreview && !whitespace_only(zContent)) || isDelete ){
if( !iClosed || g.perm.Admin ) {
@ <input type="submit" name="submit" value="Submit">
}
}
forum_render_debug_options();
login_insert_csrf_secret();
@ </form>
forum_emit_js();
style_finish_page();
}
/*
** WEBPAGE: setup_forum
**
** Forum configuration and metrics.
*/
void forum_setup(void){
/* boolean config settings specific to the forum. */
const char * zSettingsBool[] = {
"forum-close-policy",
NULL /* sentinel entry */
};
login_check_credentials();
if( !g.perm.Setup ){
login_needed(g.anon.Setup);
return;
}
style_set_current_feature("forum");
style_header("Forum Setup");
@ <h2>Metrics</h2>
{
int nPosts = db_int(0, "SELECT COUNT(*) FROM event WHERE type='f'");
@ <p><a href='%R/forum'>Forum posts</a>:
@ <a href='%R/timeline?y=f'>%d(nPosts)</a></p>
}
@ <h2>Supervisors</h2>
@ <p>Users with capabilities 's', 'a', or '6'.</p>
{
Stmt q = empty_Stmt;
int nRows = 0;
db_prepare(&q, "SELECT uid, login, cap FROM user "
"WHERE cap GLOB '*[as6]*' ORDER BY login");
@ <table class='bordered'>
@ <thead><tr><th>User</th><th>Capabilities</th></tr></thead>
@ <tbody>
while( SQLITE_ROW==db_step(&q) ){
const int iUid = db_column_int(&q, 0);
const char *zUser = db_column_text(&q, 1);
const char *zCap = db_column_text(&q, 2);
++nRows;
@ <tr>
@ <td><a href='%R/setup_uedit?id=%d(iUid)'>%h(zUser)</a></td>
@ <td>(%h(zCap))</td>
@ </tr>
}
db_finalize(&q);
@</tbody></table>
if( 0==nRows ){
@ No supervisors
}else{
@ %d(nRows) supervisor(s)
}
}
@ <h2>Moderators</h2>
@ <p>Users with capability '5'.</p>
{
Stmt q = empty_Stmt;
int nRows = 0;
db_prepare(&q, "SELECT uid, login, cap FROM user "
"WHERE cap GLOB '*5*' ORDER BY login");
@ <table class='bordered'>
@ <thead><tr><th>User</th><th>Capabilities</th></tr></thead>
@ <tbody>
while( SQLITE_ROW==db_step(&q) ){
const int iUid = db_column_int(&q, 0);
const char *zUser = db_column_text(&q, 1);
const char *zCap = db_column_text(&q, 2);
++nRows;
@ <tr>
@ <td><a href='%R/setup_uedit?id=%d(iUid)'>%h(zUser)</a></td>
@ <td>(%h(zCap))</td>
@ </tr>
}
db_finalize(&q);
@ </tbody></table>
if( 0==nRows ){
@ No non-supervisor moderators
}else{
@ %d(nRows) moderator(s)
}
}
@ <h2>Settings</h2>
@ <p>Configuration settings specific to the forum.</p>
if( P("submit") && cgi_csrf_safe(2) ){
int i = 0;
const char *zSetting;
db_begin_transaction();
while( (zSetting = zSettingsBool[i++]) ){
const char *z = P(zSetting);
if( !z || !z[0] ) z = "off";
db_set(zSetting/*works-like:"x"*/, z, 0);
}
db_end_transaction(0);
@ <p><em>Settings saved.</em></p>
}
{
int i = 0;
const char *zSetting;
@ <form action="%R/setup_forum" method="post">
login_insert_csrf_secret();
@ <table class='forum-settings-list'><tbody>
while( (zSetting = zSettingsBool[i++]) ){
@ <tr><td>
onoff_attribute("", zSetting, zSetting/*works-like:"x"*/, 0, 0);
@ </td><td>
@ <a href='%R/help?cmd=%h(zSetting)'>%h(zSetting)</a>
@ </td></tr>
}
@ </tbody></table>
@ <input type='submit' name='submit' value='Apply changes'>
@ </form>
}
style_finish_page();
}
/*
** WEBPAGE: forummain
** WEBPAGE: forum
**
** The main page for the forum feature. Show a list of recent forum
** threads. Also show a search box at the top if search is enabled,
** and a button for creating a new thread, if enabled.
**
** Query parameters:
**
** n=N The number of threads to show on each page
** x=X Skip the first X threads
** s=Y Search for term Y.
*/
void forum_main_page(void){
Stmt q;
int iLimit = 0, iOfst, iCnt;
int srchFlags;
const int isSearch = P("s")!=0;
char const *zLimit = 0;
login_check_credentials();
srchFlags = search_restrict(SRCH_FORUM);
if( !g.perm.RdForum ){
login_needed(g.anon.RdForum);
return;
}
cgi_check_for_malice();
style_set_current_feature("forum");
style_header( "%s", isSearch ? "Forum Search Results" : "Forum" );
style_submenu_element("Timeline", "%R/timeline?ss=v&y=f&vfx");
if( g.perm.WrForum ){
style_submenu_element("New Thread","%R/forumnew");
}else{
/* Can't combine this with previous case using the ternary operator
|
| ︙ | ︙ | |||
1415 1416 1417 1418 1419 1420 1421 |
if( (srchFlags & SRCH_FORUM)!=0 ){
if( search_screen(SRCH_FORUM, 0) ){
style_submenu_element("Recent Threads","%R/forum");
style_finish_page();
return;
}
}
| > > > | > > > > > > > > > > | 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 |
if( (srchFlags & SRCH_FORUM)!=0 ){
if( search_screen(SRCH_FORUM, 0) ){
style_submenu_element("Recent Threads","%R/forum");
style_finish_page();
return;
}
}
cookie_read_parameter("n","forum-n");
zLimit = P("n");
if( zLimit!=0 ){
iLimit = atoi(zLimit);
if( iLimit>=0 && P("udc")!=0 ){
cookie_write_parameter("n","forum-n",0);
}
}
if( iLimit<=0 ){
cgi_replace_query_parameter("n", fossil_strdup("25"))
/*for the sake of Max, below*/;
iLimit = 25;
}
style_submenu_entry("n","Max:",4,0);
iOfst = atoi(PD("x","0"));
iCnt = 0;
if( db_table_exists("repository","forumpost") ){
db_prepare(&q,
"WITH thread(age,duration,cnt,root,last) AS ("
" SELECT"
" julianday('now') - max(fmtime),"
|
| ︙ | ︙ |
Changes to src/fossil.diff.js.
| ︙ | ︙ | |||
167 168 169 170 171 172 173 174 175 |
endRhs: extractLineNo(false, false, tr.previousElementSibling, this.isSplit)
};
}
let btnUp = false, btnDown = false;
/**
this.pos.next refers to the line numbers in the next TR's chunk.
this.pos.prev refers to the line numbers in the previous TR's chunk.
*/
if(this.pos.prev && this.pos.next
| > | | 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 |
endRhs: extractLineNo(false, false, tr.previousElementSibling, this.isSplit)
};
}
let btnUp = false, btnDown = false;
/**
this.pos.next refers to the line numbers in the next TR's chunk.
this.pos.prev refers to the line numbers in the previous TR's chunk.
this.pos corresponds to the line numbers of the gap.
*/
if(this.pos.prev && this.pos.next
&& ((this.pos.endLhs - this.pos.startLhs)
<= Diff.config.chunkLoadLines)){
/* Place a single button to load the whole block, rather
than separate up/down buttons. */
btnDown = false;
btnUp = this.createButton(this.FetchType.FillGap);
}else{
/* Figure out which chunk-load buttons to add... */
|
| ︙ | ︙ | |||
664 665 666 667 668 669 670 671 672 673 674 675 676 677 |
if(force || !f.colsR){
f.colsR = document.querySelectorAll('td.difftxtr pre');
}
f.colsR.forEach(function(e){
e.style.width = w + "px";
e.style.maxWidth = w + "px";
});
if(0){ // seems to be unnecessary
if(!f.allDiffs){
f.allDiffs = document.querySelectorAll('table.diff');
}
w = lastWidth;
f.allDiffs.forEach(function f(e){
if(0 && !f.$){
| > > > > > > > > > > | 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 |
if(force || !f.colsR){
f.colsR = document.querySelectorAll('td.difftxtr pre');
}
f.colsR.forEach(function(e){
e.style.width = w + "px";
e.style.maxWidth = w + "px";
});
if(force || !f.colsU){
f.colsU = document.querySelectorAll('td.difftxtu pre');
}
f.colsU.forEach(function(e){
w = lastWidth - 3; // Outer border
var k = e.parentElement/*TD*/;
while(k = k.previousElementSibling/*TD*/) w -= k.scrollWidth;
e.style.width = w + "px";
e.style.maxWidth = w + "px";
});
if(0){ // seems to be unnecessary
if(!f.allDiffs){
f.allDiffs = document.querySelectorAll('table.diff');
}
w = lastWidth;
f.allDiffs.forEach(function f(e){
if(0 && !f.$){
|
| ︙ | ︙ | |||
689 690 691 692 693 694 695 |
const scrollLeft = function(event){
//console.debug("scrollLeft",this,event);
const table = this.parentElement/*TD*/.parentElement/*TR*/.
parentElement/*TBODY*/.parentElement/*TABLE*/;
table.$txtPres.forEach((e)=>(e===this) ? 1 : (e.scrollLeft = this.scrollLeft));
return false;
};
| | > | | > > > > | > | | | | | | | | | | | | | | > | 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 |
const scrollLeft = function(event){
//console.debug("scrollLeft",this,event);
const table = this.parentElement/*TD*/.parentElement/*TR*/.
parentElement/*TBODY*/.parentElement/*TABLE*/;
table.$txtPres.forEach((e)=>(e===this) ? 1 : (e.scrollLeft = this.scrollLeft));
return false;
};
Diff.initTableDiff = function f(diff, unifiedDiffs){
if(!diff){
let i, diffs;
diffs = document.querySelectorAll('table.splitdiff');
for(i=0; i<diffs.length; ++i){
f.call(this, diffs[i], false);
}
diffs = document.querySelectorAll('table.udiff');
for(i=0; i<diffs.length; ++i){
f.call(this, diffs[i], true);
}
return this;
}
diff.$txtCols = diff.querySelectorAll('td.difftxt');
diff.$txtPres = diff.querySelectorAll('td.difftxt pre');
var width = 0;
diff.$txtPres.forEach(function(e){
if(width < e.scrollWidth) width = e.scrollWidth;
});
//console.debug("diff.$txtPres =",diff.$txtPres);
diff.$txtCols.forEach((e)=>e.style.width = width + 'px');
diff.$txtPres.forEach(function(e){
e.style.maxWidth = width + 'px';
e.style.width = width + 'px';
if(!unifiedDiffs && !e.classList.contains('scroller')){
D.addClass(e, 'scroller');
e.addEventListener('scroll', scrollLeft, false);
}
});
if(!unifiedDiffs){
diff.tabIndex = 0;
if(!diff.classList.contains('scroller')){
D.addClass(diff, 'scroller');
diff.addEventListener('keydown', function(e){
e = e || event;
const len = {37: -SCROLL_LEN, 39: SCROLL_LEN}[e.keyCode];
if( !len ) return;
this.$txtPres[0].scrollLeft += len;
/* ^^^ bug: if there is a 2nd column and it has a scrollbar
but txtPres[0] does not, no scrolling happens here. We need
to find the widest of txtPres and scroll that one. Example:
Checkin a7fbefee38a1c522 file diff.c */
return false;
}, false);
}
}
return this;
}
window.fossil.page.tweakSbsDiffs = function(){
document.querySelectorAll('table.splitdiff').forEach((e)=>Diff.initTableDiff(e));
Diff.checkTableWidth();
};
Diff.initTableDiff().checkTableWidth();
window.addEventListener('resize', F.debounce(()=>Diff.checkTableWidth()));
}, false);
|
Changes to src/fossil.page.chat.js.
1 2 | /** This file contains the client-side implementation of fossil's /chat | | > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
/**
This file contains the client-side implementation of fossil's /chat
application.
*/
window.fossil.onPageLoad(function(){
const F = window.fossil, D = F.dom;
const E1 = function(selector){
const e = document.querySelector(selector);
if(!e) throw new Error("missing required DOM element: "+selector);
return e;
};
/**
Returns true if e is entirely within the bounds of the window's viewport.
*/
const isEntirelyInViewport = function(e) {
const rect = e.getBoundingClientRect();
return (
rect.top >= 0 &&
|
| ︙ | ︙ | |||
380 381 382 383 384 385 386 |
return !v;
},
addListener: function(setting, f){
F.page.addEventListener('chat-setting', function(ev){
if(ev.detail.key===setting) f(ev.detail);
}, false);
},
| | > > > > > | 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 |
return !v;
},
addListener: function(setting, f){
F.page.addEventListener('chat-setting', function(ev){
if(ev.detail.key===setting) f(ev.detail);
}, false);
},
/* Default values of settings. These are used for initializing
the setting event listeners and config view UI. */
defaults:{
/* When on, inbound images are displayed inlined, else as a
link to download the image. */
"images-inline": !!F.config.chat.imagesInline,
/* When on, ctrl-enter sends messages, else enter and
ctrl-enter both send them. */
"edit-ctrl-send": false,
/* When on, the edit field starts as a single line and
expands as the user types, and the relevant buttons are
laid out in a compact form. When off, the edit field and
buttons are larger. */
"edit-compact-mode": true,
/* See notes for this setting in fossil.page.wikiedit.js.
Both /wikiedit and /fileedit share this persistent config
option under the same storage key. */
"edit-shift-enter-preview":
F.storage.getBool('edit-shift-enter-preview', true),
/* When on, sets the font-family on messages and the edit
field to monospace. */
"monospace-messages": false,
/* When on, non-chat UI elements (page header/footer) are
hidden */
"chat-only-mode": false,
/* When set to a URI, it is assumed to be an audio file,
|
| ︙ | ︙ | |||
912 913 914 915 916 917 918 919 920 |
//'-',pad2(d.getDate()), ' ',
d.getHours(),":",
(d.getMinutes()+100).toString().slice(1,3),
' ', dowMap[d.getDay()]
].join('');
};
const canEmbedFile = function f(msg){
if(!f.$rx){
| > > > > | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > < | | 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 |
//'-',pad2(d.getDate()), ' ',
d.getHours(),":",
(d.getMinutes()+100).toString().slice(1,3),
' ', dowMap[d.getDay()]
].join('');
};
/**
Returns true if this page believes it can embed a view of the
file wrapped by the given message object, else returns false.
*/
const canEmbedFile = function f(msg){
if(!f.$rx){
f.$rx = /\.((html?)|(txt)|(md)|(wiki)|(pikchr))$/i;
f.$specificTypes = [
'text/plain',
'text/html',
'text/x-markdown',
/* Firefox sends text/markdown when uploading .md files */
'text/markdown',
'text/x-pikchr',
'text/x-fossil-wiki'
// add more as we discover which ones Firefox won't
// force the user to try to download.
];
}
if(msg.fmime){
if(msg.fmime.startsWith("image/")
|| f.$specificTypes.indexOf(msg.fmime)>=0){
return true;
}
}
return (msg.fname && f.$rx.test(msg.fname));
};
/**
Returns true if the given message object "should"
be embedded in fossil-rendered form instead of
raw content form. This is only intended to be passed
message objects for which canEmbedFile() returns true.
*/
const shouldWikiRenderEmbed = function f(msg){
if(!f.$rx){
f.$rx = /\.((md)|(wiki)|(pikchr))$/i;
f.$specificTypes = [
'text/x-markdown',
'text/markdown' /* Firefox-uploaded md files */,
'text/x-pikchr',
'text/x-fossil-wiki'
// add more as we discover which ones Firefox won't
// force the user to try to download.
];
}
if(msg.fmime){
if(f.$specificTypes.indexOf(msg.fmime)>=0) return true;
}
return msg.fname && f.$rx.test(msg.fname);
};
const adjustIFrameSize = function(msgObj){
const iframe = msgObj.e.iframe;
const body = iframe.contentWindow.document.querySelector('body');
|
| ︙ | ︙ | |||
1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 |
"(" + m.fname + " " + m.fsize + " bytes)"
)
D.attr(a,'target','_blank');
D.append(w, a);
if(canEmbedFile(m)){
/* Add an option to embed HTML attachments in an iframe. The primary
use case is attached diffs. */
D.addClass(contentTarget, 'wide');
const embedTarget = this.e.content;
const self = this;
const btnEmbed = D.attr(D.checkbox("1", false), 'id',
'embed-'+ds.msgid);
| > > | > | 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 |
"(" + m.fname + " " + m.fsize + " bytes)"
)
D.attr(a,'target','_blank');
D.append(w, a);
if(canEmbedFile(m)){
/* Add an option to embed HTML attachments in an iframe. The primary
use case is attached diffs. */
const shouldWikiRender = shouldWikiRenderEmbed(m);
const downloadArgs = shouldWikiRender ? '?render' : '';
D.addClass(contentTarget, 'wide');
const embedTarget = this.e.content;
const self = this;
const btnEmbed = D.attr(D.checkbox("1", false), 'id',
'embed-'+ds.msgid);
const btnLabel = D.label(btnEmbed, shouldWikiRender
? "Embed (fossil-rendered)" : "Embed");
/* Maintenance reminder: do not disable the toggle
button while the content is loading because that will
cause it to get stuck in disabled mode if the browser
decides that loading the content should prompt the
user to download it, rather than embed it in the
iframe. */
btnEmbed.addEventListener('change',function(){
|
| ︙ | ︙ | |||
1039 1040 1041 1042 1043 1044 1045 |
}
const iframe = self.e.iframe = document.createElement('iframe');
D.append(embedTarget, iframe);
iframe.addEventListener('load', function(){
self.e.$iframeLoaded = true;
adjustIFrameSize(self);
});
| | | 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 |
}
const iframe = self.e.iframe = document.createElement('iframe');
D.append(embedTarget, iframe);
iframe.addEventListener('load', function(){
self.e.$iframeLoaded = true;
adjustIFrameSize(self);
});
iframe.setAttribute('src', downloadUri + downloadArgs);
});
D.append(w, btnEmbed, btnLabel);
}
contentTarget.appendChild(w);
}
}
if(m.xmsg){
|
| ︙ | ︙ | |||
1459 1460 1461 1462 1463 1464 1465 |
/* Shift-enter will run preview mode UNLESS preview mode is
active AND the input field is empty, in which case it will
switch back to message view. */
if(Chat.e.currentView===Chat.e.viewPreview && !text){
Chat.setCurrentView(Chat.e.viewMessages);
}else if(!text){
f.$toggleCompact(compactMode);
| | | | | 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 |
/* Shift-enter will run preview mode UNLESS preview mode is
active AND the input field is empty, in which case it will
switch back to message view. */
if(Chat.e.currentView===Chat.e.viewPreview && !text){
Chat.setCurrentView(Chat.e.viewMessages);
}else if(!text){
f.$toggleCompact(compactMode);
}else if(Chat.settings.getBool('edit-shift-enter-preview', true)){
Chat.e.btnPreview.click();
}
return false;
}
if(ev.ctrlKey && !text && !BlobXferState.blob){
/* Ctrl-enter on empty input field(s) toggles Enter/Ctrl-enter mode */
ev.preventDefault();
ev.stopPropagation();
f.$toggleCtrl(ctrlMode);
return false;
}
if(!ctrlMode && ev.ctrlKey && text){
//console.debug("!ctrlMode && ev.ctrlKey && text.");
/* Ctrl-enter in Enter-sends mode SHOULD, with this logic add a
newline, but that is not happening, for unknown reasons
(possibly related to this element being a contenteditable DIV
instead of a textarea). Forcibly appending a newline do the
input area does not work, also for unknown reasons, and would
only be suitable when we're at the end of the input.
Strangely, this approach DOES work for shift-enter, but we
need shift-enter as a hotkey for preview mode.
*/
//return;
// return here "should" cause newline to be added, but that doesn't work
}
if((!ctrlMode && !ev.ctrlKey) || (ev.ctrlKey/* && ctrlMode*/)){
/* Ship it! */
ev.preventDefault();
ev.stopPropagation();
Chat.submitMessage();
return false;
}
};
Chat.e.inputFields.forEach(
(e)=>e.addEventListener('keydown', inputWidgetKeydown, false)
);
Chat.e.btnSubmit.addEventListener('click',(e)=>{
e.preventDefault();
Chat.submitMessage();
return false;
|
| ︙ | ︙ | |||
1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 |
boolValue: 'edit-widget-x',
hint: [
"When enabled, chat input uses a so-called 'contenteditable' ",
"field. Though generally more comfortable and modern than ",
"plain-text input fields, browser-specific quirks and bugs ",
"may lead to frustration. Ideal for mobile devices."
].join('')
}]
},{
label: "Appearance Options...",
children:[{
label: "Left-align my posts",
hint: "Default alignment of your own messages is selected "
+ "based window width/height ratio.",
| > > > > > > > | 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 |
boolValue: 'edit-widget-x',
hint: [
"When enabled, chat input uses a so-called 'contenteditable' ",
"field. Though generally more comfortable and modern than ",
"plain-text input fields, browser-specific quirks and bugs ",
"may lead to frustration. Ideal for mobile devices."
].join('')
},{
label: "Shift-enter to preview",
hint: ["Use shift-enter to preview being-edited messages. ",
"This is normally desirable but some software-mode ",
"keyboards misinteract with this, in which cases it can be ",
"disabled."],
boolValue: 'edit-shift-enter-preview'
}]
},{
label: "Appearance Options...",
children:[{
label: "Left-align my posts",
hint: "Default alignment of your own messages is selected "
+ "based window width/height ratio.",
|
| ︙ | ︙ | |||
1925 1926 1927 1928 1929 1930 1931 |
D.enable(elemsToEnable);
}
});
return false;
};
btnPreview.addEventListener('click', submit, false);
})()/*message preview setup*/;
| | | 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 |
D.enable(elemsToEnable);
}
});
return false;
};
btnPreview.addEventListener('click', submit, false);
})()/*message preview setup*/;
/** Callback for poll() to inject new content into the page. jx ==
the response from /chat-poll. If atEnd is true, the message is
appended to the end of the chat list (for loading older
messages), else the beginning (the default). */
const newcontent = function f(jx,atEnd){
if(!f.processPost){
/** Processes chat message m, placing it either the start (if atEnd
|
| ︙ | ︙ |
Changes to src/fossil.page.fileedit.js.
| ︙ | ︙ | |||
68 69 70 71 72 73 74 |
);
*/
const E = (s)=>document.querySelector(s),
D = F.dom,
P = F.page;
P.config = {
| | > > > > > > | 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
);
*/
const E = (s)=>document.querySelector(s),
D = F.dom,
P = F.page;
P.config = {
defaultMaxStashSize: 7,
/**
See notes for this setting in fossil.page.wikiedit.js. Both
/wikiedit and /fileedit share this persistent config option
under the same storage key.
*/
shiftEnterPreview: F.storage.getBool('edit-shift-enter-preview', true)
};
/**
$stash is an internal-use-only object for managing "stashed"
local edits, to help avoid that users accidentally lose content
by switching tabs or following links or some such. The basic
theory of operation is...
|
| ︙ | ︙ | |||
568 569 570 571 572 573 574 |
opt._finfo = finfo;
if(0===f.compare(currentFinfo, finfo)){
D.attr(opt, 'selected', true);
}
});
}
}/*P.stashWidget*/;
| | | 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 |
opt._finfo = finfo;
if(0===f.compare(currentFinfo, finfo)){
D.attr(opt, 'selected', true);
}
});
}
}/*P.stashWidget*/;
/**
Internal workaround to select the current preview mode
and fire a change event if the value actually changes
or if forceEvent is truthy.
*/
P.selectPreviewMode = function(modeValue, forceEvent){
const s = this.e.selectPreviewMode;
|
| ︙ | ︙ | |||
722 723 724 725 726 727 728 |
}
}
);
////////////////////////////////////////////////////////////
// Trigger preview on Ctrl-Enter. This only works on the built-in
// editor widget, not a client-provided one.
P.e.taEditor.addEventListener('keydown',function(ev){
| | | 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 |
}
}
);
////////////////////////////////////////////////////////////
// Trigger preview on Ctrl-Enter. This only works on the built-in
// editor widget, not a client-provided one.
P.e.taEditor.addEventListener('keydown',function(ev){
if(P.config.shiftEnterPreview && ev.shiftKey && 13===ev.keyCode){
ev.preventDefault();
ev.stopPropagation();
P.e.taEditor.blur(/*force change event, if needed*/);
P.tabs.switchToTab(P.e.tabs.preview);
if(!P.e.cbAutoPreview.checked){/* If NOT in auto-preview mode, trigger an update. */
P.preview();
}
|
| ︙ | ︙ | |||
843 844 845 846 847 848 849 850 851 852 853 854 855 856 |
}
);
P.fileSelectWidget.init();
P.stashWidget.init(
P.e.tabs.content.lastElementChild
);
}/*F.onPageLoad()*/);
/**
Getter (if called with no args) or setter (if passed an arg) for
the current file content.
The setter form sets the content, dispatches a
| > > > > > > > | 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 |
}
);
P.fileSelectWidget.init();
P.stashWidget.init(
P.e.tabs.content.lastElementChild
);
const cbEditPreview = E('#edit-shift-enter-preview');
cbEditPreview.addEventListener('change', function(e){
F.storage.set('edit-shift-enter-preview',
P.config.shiftEnterPreview = e.target.checked);
}, false);
cbEditPreview.checked = P.config.shiftEnterPreview;
}/*F.onPageLoad()*/);
/**
Getter (if called with no args) or setter (if passed an arg) for
the current file content.
The setter form sets the content, dispatches a
|
| ︙ | ︙ | |||
1159 1160 1161 1162 1163 1164 1165 |
const target = this.e.previewTarget;
D.clearElement(target);
if('string'===typeof c) D.parseHtml(target,c);
if(F.pikchr){
F.pikchr.addSrcView(target.querySelectorAll('svg.pikchr'));
}
};
| | | 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 |
const target = this.e.previewTarget;
D.clearElement(target);
if('string'===typeof c) D.parseHtml(target,c);
if(F.pikchr){
F.pikchr.addSrcView(target.querySelectorAll('svg.pikchr'));
}
};
/**
Callback for use with F.connectPagePreviewers()
*/
P._postPreview = function(content,callback){
if(!affirmHasFile()) return this;
if(!content){
callback(content);
|
| ︙ | ︙ |
Changes to src/fossil.page.forumpost.js.
1 2 |
(function(F/*the fossil object*/){
"use strict";
| | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
(function(F/*the fossil object*/){
"use strict";
/* JS code for /forumpost and friends. Requires fossil.dom
and can optionally use fossil.pikchr. */
const P = F.page, D = F.dom;
/**
When the page is loaded, this handler does the following:
- Installs expand/collapse UI elements on "long" posts and collapses
them.
- Any pikchr-generated SVGs get a source-toggle button added to them
which activates when the mouse is over the image or it is tapped.
This is a harmless no-op if the current page has neither forum
post constructs for (1) nor any pikchr images for (2), nor will
NOT running this code cause any breakage for clients with no JS
support: this is all "nice-to-have", not required functionality.
|
| ︙ | ︙ | |||
97 98 99 100 101 102 103 |
rightTapZone.addEventListener('click', widgetEventHandler, false);
refillTapZone();
})/*F.onPageLoad()*/;
if(F.pikchr){
F.pikchr.addSrcView();
}
| | > > > > > > | > > > > > > > > > > > > | 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 |
rightTapZone.addEventListener('click', widgetEventHandler, false);
refillTapZone();
})/*F.onPageLoad()*/;
if(F.pikchr){
F.pikchr.addSrcView();
}
/* Attempt to keep stray double-clicks from double-posting. */
const formSubmitted = function(event){
const form = event.target;
if( form.dataset.submitted ){
event.preventDefault();
return;
}
form.dataset.submitted = '1';
/** If the user is left waiting "a long time," disable the
resubmit protection. If we don't do this and they tap the
browser's cancel button while waiting, they'll be stuck with
an unsubmittable form. */
setTimeout(()=>{delete form.dataset.submitted}, 7000);
return;
};
document.querySelectorAll("form").forEach(function(form){
form.addEventListener('submit',formSubmitted);
});
})/*F.onPageLoad callback*/;
})(window.fossil);
|
Changes to src/fossil.page.pikchrshowasm.js.
| ︙ | ︙ | |||
59 60 61 62 63 64 65 |
previewCopyButton: E('#preview-copy-button'),
previewModeLabel: E('label[for=preview-copy-button]'),
zoneInputButtons: E('.zone-wrapper.input > legend > .button-bar'),
zoneOutputButtons: E('.zone-wrapper.output > legend > .button-bar'),
outText: E('#pikchr-output-text'),
pikOutWrapper: E('#pikchr-output-wrapper'),
pikOut: E('#pikchr-output'),
| | | 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
previewCopyButton: E('#preview-copy-button'),
previewModeLabel: E('label[for=preview-copy-button]'),
zoneInputButtons: E('.zone-wrapper.input > legend > .button-bar'),
zoneOutputButtons: E('.zone-wrapper.output > legend > .button-bar'),
outText: E('#pikchr-output-text'),
pikOutWrapper: E('#pikchr-output-wrapper'),
pikOut: E('#pikchr-output'),
btnRender: E('#btn-render')
},
renderModes: ['svg'/*SVG must be at index 0*/,'markdown', 'wiki', 'text'],
renderModeLabels: {
svg: 'SVG', markdown: 'Markdown', wiki: 'Fossil Wiki', text: 'Text'
},
_msgMap: {},
/** Adds a worker message handler for messages of the given
|
| ︙ | ︙ | |||
675 676 677 678 679 680 681 682 683 684 685 686 | circle rad 0.9 at 0.6 heading -120 from O thick color blue text "HIGH" big bold "QUALITY" big bold at 0.9 heading -120 from O color blue text "EXPENSIVE" at 0.55 below O color cyan text "SLOW" at 0.55 heading -60 from O color magenta text "POOR" "QUALITY" at 0.55 heading 60 from O color gold `} ]; })(window.fossil); | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 |
circle rad 0.9 at 0.6 heading -120 from O thick color blue
text "HIGH" big bold "QUALITY" big bold at 0.9 heading -120 from O color blue
text "EXPENSIVE" at 0.55 below O color cyan
text "SLOW" at 0.55 heading -60 from O color magenta
text "POOR" "QUALITY" at 0.55 heading 60 from O color gold
`},{name:"Precision Arrows",code:`
# Source: https://pikchr.org/home/forumpost/7f2f9a03eb
define quiver {
dot invis at 0.5 < $1.ne , $1.e >
dot invis at 0.5 < $1.nw , $1.w >
dot invis at 0.5 < $1.se , $1.e >
dot invis at 0.5 < $1.sw , $1.w >
dot at $2 right of 4th previous dot
dot at $3 right of 4th previous dot
dot at $4 right of 4th previous dot
dot at $5 right of 4th previous dot
arrow <- from previous dot to 2nd previous dot
arrow -> from 3rd previous dot to 4th previous dot
}
define show_compass_l {
dot color red at $1.e " .e" ljust
dot same at $1.ne " .ne" ljust above
line thick color green from previous to 2nd last dot
}
define show_compass_r {
dot color red at $1.w " .w" ljust
dot same at $1.nw " .nw" ljust above
line thick color green from previous to 2nd last dot
}
PROGRAM: file "Program" rad 45px
show_compass_l(PROGRAM)
QUIVER: box invis ht 0.75
DATABASE: oval "Database" ht 0.75 wid 1.1
show_compass_r(DATABASE)
quiver(QUIVER, 5px, -5px, 5px, 0px)
text "Query" with .c at 0.1in above last arrow
text "Records" with .c at 0.1in below 2nd last arrow
`}
];
})(window.fossil);
|
Changes to src/fossil.page.whistory.js.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
/* This script adds interactivity for wiki-history webpages.
*
* The main code is within the 'on-click' handler of the "diff" links.
* Instead of standard redirection it fills-in two hidden inputs with
* the appropriate values and submits the corresponding form.
* A special care should be taken if some intermediate edits are hidden.
*
* For the sake of compatibility with ascetic browsers the code tries
* to avoid modern API and ECMAScript constructs. This makes it less
* readable and may be reconsidered in the future.
*/
window.addEventListener( 'load', function() {
| | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
/* This script adds interactivity for wiki-history webpages.
*
* The main code is within the 'on-click' handler of the "diff" links.
* Instead of standard redirection it fills-in two hidden inputs with
* the appropriate values and submits the corresponding form.
* A special care should be taken if some intermediate edits are hidden.
*
* For the sake of compatibility with ascetic browsers the code tries
* to avoid modern API and ECMAScript constructs. This makes it less
* readable and may be reconsidered in the future.
*/
window.addEventListener( 'load', function() {
var form = document.getElementById("wh-form");
form.method = "GET";
var csrf = form.querySelector("input[name='csrf']");
if( csrf ) form.removeChild( csrf );
var wh_id = document.getElementById("wh-id" );
var wh_pid = document.getElementById("wh-pid");
var wh_cleaner = document.getElementById("wh-cleaner");
var wh_collapser = document.getElementById("wh-collapser");
var wh_radios = []; // user-visible controls for baseline selection
|
| ︙ | ︙ |
Changes to src/fossil.page.wikiedit.js.
| ︙ | ︙ | |||
73 74 75 76 77 78 79 |
useConfirmerButtons:{
/* If true during fossil.page setup, certain buttons will use a
"confirmer" step, else they will not. The confirmer topic has
been the source of much contention in the forum. */
save: false,
reload: true,
discardStash: true
| > > > > > > > | > > > > > > | 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 |
useConfirmerButtons:{
/* If true during fossil.page setup, certain buttons will use a
"confirmer" step, else they will not. The confirmer topic has
been the source of much contention in the forum. */
save: false,
reload: true,
discardStash: true
},
/**
If true, a keyboard combo of shift-enter (from the editor)
toggles between preview and edit modes. This is normally
desired but at least one software keyboard is known to
misinteract with this, treating an Enter after
automatically-capitalized letters as a shift-enter:
https://fossil-scm.org/forum/forumpost/dbd5b68366147ce8
Maintenance note: /fileedit also uses this same key for the
same purpose.
*/
shiftEnterPreview: F.storage.getBool('edit-shift-enter-preview', true)
};
/**
$stash is an internal-use-only object for managing "stashed"
local edits, to help avoid that users accidentally lose content
by switching tabs or following links or some such. The basic
theory of operation is...
|
| ︙ | ︙ | |||
452 453 454 455 456 457 458 |
opt.dataset.isDeleted = true;
}
self._refreshStashMarks(opt);
});
D.enable(sel);
if(P.winfo) sel.value = P.winfo.name;
},
| | | 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 |
opt.dataset.isDeleted = true;
}
self._refreshStashMarks(opt);
});
D.enable(sel);
if(P.winfo) sel.value = P.winfo.name;
},
/** Loads the page list and populates the selection list. */
loadList: function callee(){
if(!callee.onload){
const self = this;
callee.onload = function(list){
self.cache.pageList = list;
self._rebuildList();
|
| ︙ | ︙ | |||
649 650 651 652 653 654 655 |
}, false);
D.append(
parentElem,
D.append(D.addClass(D.div(), 'fieldset-wrapper'),
fsFilter, fsNewPage, fsLegend)
);
| | | 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 |
}, false);
D.append(
parentElem,
D.append(D.addClass(D.div(), 'fieldset-wrapper'),
fsFilter, fsNewPage, fsLegend)
);
D.append(parentElem, btn);
btn.addEventListener('click', ()=>this.loadList(), false);
this.loadList();
const onSelect = (e)=>P.loadPage(e.target.value);
sel.addEventListener('change', onSelect, false);
sel.addEventListener('dblclick', onSelect, false);
F.page.addEventListener('wiki-stash-updated', ()=>{
|
| ︙ | ︙ | |||
672 673 674 675 676 677 678 679 |
if(page.isEmpty) opt.dataset.isDeleted = true;
else delete opt.dataset.isDeleted;
self._refreshStashMarks(opt);
}else if('sandbox'!==page.type){
F.error("BUG: internal mis-handling of page object: missing OPTION for page "+page.name);
}
});
delete this.init;
| > > > > > > > | | 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 |
if(page.isEmpty) opt.dataset.isDeleted = true;
else delete opt.dataset.isDeleted;
self._refreshStashMarks(opt);
}else if('sandbox'!==page.type){
F.error("BUG: internal mis-handling of page object: missing OPTION for page "+page.name);
}
});
const cbEditPreview = E('#edit-shift-enter-preview');
cbEditPreview.addEventListener('change', function(e){
F.storage.set('edit-shift-enter-preview',
P.config.shiftEnterPreview = e.target.checked);
}, false);
cbEditPreview.checked = P.config.shiftEnterPreview;
delete this.init;
}/*init()*/
};
/**
Widget for listing and selecting $stash entries.
*/
P.stashWidget = {
e:{/*DOM element(s)*/},
|
| ︙ | ︙ | |||
912 913 914 915 916 917 918 |
}
}
);
////////////////////////////////////////////////////////////
// Trigger preview on Ctrl-Enter. This only works on the built-in
// editor widget, not a client-provided one.
P.e.taEditor.addEventListener('keydown',function(ev){
| | | 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 |
}
}
);
////////////////////////////////////////////////////////////
// Trigger preview on Ctrl-Enter. This only works on the built-in
// editor widget, not a client-provided one.
P.e.taEditor.addEventListener('keydown',function(ev){
if(P.config.shiftEnterPreview && ev.shiftKey && 13===ev.keyCode){
ev.preventDefault();
ev.stopPropagation();
P.e.taEditor.blur(/*force change event, if needed*/);
P.tabs.switchToTab(P.e.tabs.preview);
if(!P.e.cbAutoPreview.checked){/* If NOT in auto-preview mode, trigger an update. */
P.preview();
}
|
| ︙ | ︙ | |||
1459 1460 1461 1462 1463 1464 1465 |
const target = this.e.previewTarget;
D.clearElement(target);
if('string'===typeof c) D.parseHtml(target,c);
if(F.pikchr){
F.pikchr.addSrcView(target.querySelectorAll('svg.pikchr'));
}
};
| | | 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 |
const target = this.e.previewTarget;
D.clearElement(target);
if('string'===typeof c) D.parseHtml(target,c);
if(F.pikchr){
F.pikchr.addSrcView(target.querySelectorAll('svg.pikchr'));
}
};
/**
Callback for use with F.connectPagePreviewers()
*/
P._postPreview = function(content,callback){
if(!affirmPageLoaded()) return this;
if(!content){
callback(content);
|
| ︙ | ︙ |
Changes to src/glob.c.
| ︙ | ︙ | |||
87 88 89 90 91 92 93 |
struct Glob {
int nPattern; /* Number of patterns */
char **azPattern; /* Array of pointers to patterns */
};
#endif /* INTERFACE */
/*
| | | | | > | | 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 |
struct Glob {
int nPattern; /* Number of patterns */
char **azPattern; /* Array of pointers to patterns */
};
#endif /* INTERFACE */
/*
** zPatternList is a comma- or whitespace-separated list of glob patterns.
** Parse that list and use it to create a new Glob object.
**
** Elements of the glob list may be optionally enclosed in single- or
** double-quotes. This allows commas and whitespace to be part of a
** glob pattern.
**
** Leading and trailing spaces on glob patterns are ignored unless quoted.
**
** An empty or null pattern list results in a null glob, which will
** match nothing.
*/
Glob *glob_create(const char *zPatternList){
int nList; /* Size of zPatternList in bytes */
int i; /* Loop counters */
|
| ︙ | ︙ | |||
124 125 126 127 128 129 130 |
delimiter = z[0];
z++;
}else{
delimiter = ',';
}
p->azPattern = fossil_realloc(p->azPattern, (p->nPattern+1)*sizeof(char*) );
p->azPattern[p->nPattern++] = z;
| | | < | > | 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
delimiter = z[0];
z++;
}else{
delimiter = ',';
}
p->azPattern = fossil_realloc(p->azPattern, (p->nPattern+1)*sizeof(char*) );
p->azPattern[p->nPattern++] = z;
/* Find the next delimiter (or the end of the string). */
for(i=0; z[i] && z[i]!=delimiter &&
!(delimiter==',' && fossil_isspace(z[i])); i++){
/* keep looking for the end of the glob pattern */
}
if( z[i]==0 ) break;
z[i] = 0;
z += i+1;
}
return p;
}
|
| ︙ | ︙ |
Changes to src/graph.js.
| ︙ | ︙ | |||
132 133 134 135 136 137 138 |
function hideGraphTooltip(){ /* Hide the tooltip */
document.removeEventListener('keydown',onKeyDown,/* useCapture == */true);
stopCloseTimer();
tooltipObj.style.display = "none";
tooltipInfo.ixActive = -1;
tooltipInfo.idNodeActive = 0;
}
| | | 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
function hideGraphTooltip(){ /* Hide the tooltip */
document.removeEventListener('keydown',onKeyDown,/* useCapture == */true);
stopCloseTimer();
tooltipObj.style.display = "none";
tooltipInfo.ixActive = -1;
tooltipInfo.idNodeActive = 0;
}
window.onpagehide = hideGraphTooltip;
function stopDwellTimer(){
if(tooltipInfo.idTimer!=0){
clearTimeout(tooltipInfo.idTimer);
tooltipInfo.idTimer = 0;
}
}
function resumeCloseTimer(){
|
| ︙ | ︙ | |||
387 388 389 390 391 392 393 |
if(e) e.style.backgroundColor = p.bg;
}
if( p.r<0 ) return;
if( p.u>0 ) drawUpArrow(p,tx.rowinfo[p.u-tx.iTopRow],p.fg,p.id);
if( p.sb>0 ) drawDotted(p,tx.rowinfo[p.sb-tx.iTopRow],p.fg,p.id);
var cls = node.cls;
if( p.hasOwnProperty('mi') && p.mi.length ) cls += " merge";
| > | > > > > > > > > > > > > | 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 |
if(e) e.style.backgroundColor = p.bg;
}
if( p.r<0 ) return;
if( p.u>0 ) drawUpArrow(p,tx.rowinfo[p.u-tx.iTopRow],p.fg,p.id);
if( p.sb>0 ) drawDotted(p,tx.rowinfo[p.sb-tx.iTopRow],p.fg,p.id);
var cls = node.cls;
if( p.hasOwnProperty('mi') && p.mi.length ) cls += " merge";
if( p.f&2 ) cls += " closed-leaf";
else if( p.f&1 ) cls += " leaf";
var n = drawBox(cls,p.bg,p.x,p.y);
n.id = "tln"+p.id;
n.onclick = clickOnNode;
n.ondblclick = dblclickOnNode;
n.onmousemove = mouseOverNode;
n.style.zIndex = 10;
if( p.f&2 ){
var pt1 = 0;
var pt2 = 100;
if( tx.circleNodes ){
pt1 = 14;
pt2 = 86;
}
n.innerHTML = "<svg width='100%' height='100%'viewbox='0 0 100 100'>"
+ `<path d='M ${pt1},${pt1} L ${pt2},${pt2} M ${pt1},${pt2} L ${pt2},${pt1}'`
+ " stroke='currentcolor' stroke-width='13'/>"
+ "</svg>";
}
if( !tx.omitDescenders ){
if( p.u==0 ){
if( p.hasOwnProperty('mo') && p.r==p.mo ){
var ix = p.hasOwnProperty('cu') ? p.cu : p.mu;
var top = tx.rowinfo[ix-tx.iTopRow]
drawUpArrow(p,{x: p.x, y: top.y-node.h}, p.fg, p.id);
}else if( p.y>100 ){
|
| ︙ | ︙ |
Changes to src/hook.c.
| ︙ | ︙ | |||
230 231 232 233 234 235 236 | ** ** > 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 | | | 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 | ** ** > 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 valud is M ** --aux-file NAME NAME is substituted for %A in the script ** ** The --base-rcvid and --new-rcvid options are silently ignored if ** the hook type is not "after-receive". The default values for ** --base-rcvid and --new-rcvid cause the last receive to be processed. */ |
| ︙ | ︙ |
Changes to src/http.c.
| ︙ | ︙ | |||
88 89 90 91 92 93 94 |
zPw = 0;
}else{
/* Password failure while doing a sync from the command-line interface */
url_prompt_for_password();
zPw = g.url.passwd;
}
| | > | > > > > > > < > > > > > > > | > > > > > > > > | 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 |
zPw = 0;
}else{
/* Password failure while doing a sync from the command-line interface */
url_prompt_for_password();
zPw = g.url.passwd;
}
/* The login card wants the SHA1 hash of the password (as computed by
** sha1_shared_secret()), not the original password. So convert the
** password to its SHA1 encoding if it isn't already a SHA1 hash.
**
** We assume that a hexadecimal string of exactly 40 characters is a
** SHA1 hash, not an original password. If a user has a password which
** just happens to be a 40-character hex string, then this routine won't
** be able to distinguish it from a hash, the translation will not be
** performed, and the sync won't work.
*/
if( zPw && zPw[0] && (strlen(zPw)!=40 || !validate16(zPw,40)) ){
const char *zProjectCode = 0;
if( g.url.flags & URL_USE_PARENT ){
zProjectCode = db_get("parent-project-code", 0);
}else{
zProjectCode = db_get("project-code", 0);
}
zPw = sha1_shared_secret(zPw, zLogin, zProjectCode);
if( g.url.pwConfig!=0 && (g.url.flags & URL_REMEMBER_PW)!=0 ){
char *x = obscure(zPw);
db_set(g.url.pwConfig/*works-like:"x"*/, x, 0);
fossil_free(x);
}
fossil_free(g.url.passwd);
g.url.passwd = fossil_strdup(zPw);
}
blob_append(&pw, zPw, -1);
sha1sum_blob(&pw, &sig);
blob_appendf(pLogin, "login %F %b %b\n", zLogin, &nonce, &sig);
blob_reset(&pw);
blob_reset(&sig);
blob_reset(&nonce);
|
| ︙ | ︙ | |||
538 539 540 541 542 543 544 | ** ** If a second filename (OUTPUT) is given after PAYLOAD, then the reply ** is written into that second file instead of being written on standard ** output. Use the "--out OUTPUT" option to specify an output file for ** a GET request where there is no PAYLOAD. ** ** Options: | < | 559 560 561 562 563 564 565 566 567 568 569 570 571 572 |
**
** If a second filename (OUTPUT) is given after PAYLOAD, then the reply
** is written into that second file instead of being written on standard
** output. Use the "--out OUTPUT" option to specify an output file for
** a GET request where there is no PAYLOAD.
**
** Options:
** --compress Use ZLIB compression on the payload
** --mimetype TYPE Mimetype of the payload
** --out FILE Store the reply in FILE
** -v Verbose output
** --xfer PAYLOAD in a Fossil xfer protocol message
*/
void test_httpmsg_command(void){
|
| ︙ | ︙ |
Changes to src/http_socket.c.
| ︙ | ︙ | |||
230 231 232 233 234 235 236 |
if( got<=0 ) break;
total += (size_t)got;
N -= (size_t)got;
pContent = (void*)&((char*)pContent)[got];
}
return total;
}
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 230 231 232 233 234 235 236 |
if( got<=0 ) break;
total += (size_t)got;
N -= (size_t)got;
pContent = (void*)&((char*)pContent)[got];
}
return total;
}
|
Changes to src/http_ssl.c.
| ︙ | ︙ | |||
127 128 129 130 131 132 133 | BIO *in; int rc = 1; X509 *x = 0; X509 *cert = 0; in = BIO_new_mem_buf(pData, nData); if( in==0 ) goto end_of_ucfm; | | | 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 | BIO *in; int rc = 1; X509 *x = 0; X509 *cert = 0; in = BIO_new_mem_buf(pData, nData); if( in==0 ) goto end_of_ucfm; /* x = X509_new_ex(ctx->libctx, ctx->propq); */ x = X509_new(); if( x==0 ) goto end_of_ucfm; cert = PEM_read_bio_X509(in, &x, 0, 0); if( cert==0 ) goto end_of_ucfm; rc = SSL_CTX_use_certificate(ctx, x)<=0; end_of_ucfm: X509_free(x); |
| ︙ | ︙ | |||
539 540 541 542 543 544 545 |
/* MMNNFFPPS */
#if OPENSSL_VERSION_NUMBER >= 0x010000000
x = X509_digest(cert, EVP_sha256(), md, &mdLength);
#else
x = X509_digest(cert, EVP_sha1(), md, &mdLength);
#endif
if( x ){
| | | 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 |
/* MMNNFFPPS */
#if OPENSSL_VERSION_NUMBER >= 0x010000000
x = X509_digest(cert, EVP_sha256(), md, &mdLength);
#else
x = X509_digest(cert, EVP_sha1(), md, &mdLength);
#endif
if( x ){
unsigned j;
for(j=0; j<mdLength && j*2+1<sizeof(zHash); ++j){
zHash[j*2] = "0123456789abcdef"[md[j]>>4];
zHash[j*2+1] = "0123456789abcdef"[md[j]&0xf];
}
zHash[j*2] = 0;
}
|
| ︙ | ︙ | |||
913 914 915 916 917 918 919 | ** 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 | | | 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 |
** 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);
|
| ︙ | ︙ | |||
1173 1174 1175 1176 1177 1178 1179 | cgi_set_content(&content); cgi_set_content_type(mimetype_from_name(zPath)); cgi_reply(); return; wellknown_notfound: fossil_free(zPath); | | | 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 | cgi_set_content(&content); cgi_set_content_type(mimetype_from_name(zPath)); cgi_reply(); return; wellknown_notfound: fossil_free(zPath); webpage_notfound_error(0 /*works-like:""*/); return; } /* ** Return the OpenSSL version number being used. Space to hold ** this name is obtained from fossil_malloc() and should be ** freed by the caller. |
| ︙ | ︙ |
Changes to src/http_transport.c.
| ︙ | ︙ | |||
80 81 82 83 84 85 86 |
** Check zFossil to see if it is a reasonable "fossil" command to
** run on the server. Do not allow an attacker to substitute something
** like "/bin/rm".
*/
static int is_safe_fossil_command(const char *zFossil){
static const char *const azSafe[] = { "*/fossil", "*/fossil.exe", "*/echo" };
int i;
| | | 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
** Check zFossil to see if it is a reasonable "fossil" command to
** run on the server. Do not allow an attacker to substitute something
** like "/bin/rm".
*/
static int is_safe_fossil_command(const char *zFossil){
static const char *const azSafe[] = { "*/fossil", "*/fossil.exe", "*/echo" };
int i;
for(i=0; i<(int)(sizeof(azSafe)/sizeof(azSafe[0])); i++){
if( sqlite3_strglob(azSafe[i], zFossil)==0 ) return 1;
if( strcmp(azSafe[i]+2, zFossil)==0 ) return 1;
}
return 0;
}
/*
|
| ︙ | ︙ | |||
115 116 117 118 119 120 121 |
int transport_ssh_open(UrlData *pUrlData){
/* For SSH we need to create and run SSH fossil http
** to talk to the remote machine.
*/
Blob zCmd; /* The SSH command */
char *zHost; /* The host name to contact */
| > | | 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
int transport_ssh_open(UrlData *pUrlData){
/* For SSH we need to create and run SSH fossil http
** to talk to the remote machine.
*/
Blob zCmd; /* The SSH command */
char *zHost; /* The host name to contact */
fossil_free(g.zIpAddr);
g.zIpAddr = mprintf("%s", pUrlData->name);
transport_ssh_command(&zCmd);
if( pUrlData->port!=pUrlData->dfltPort && pUrlData->port ){
blob_appendf(&zCmd, " -p %d", pUrlData->port);
}
blob_appendf(&zCmd, " -T --"); /* End of switches */
if( pUrlData->user && pUrlData->user[0] ){
zHost = mprintf("%s@%s", pUrlData->user, pUrlData->name);
|
| ︙ | ︙ |
Changes to src/import.c.
| ︙ | ︙ | |||
294 295 296 297 298 299 300 |
fflush(stdout);
}
for(i=0; i<gg.nFile; i++){
const char *zUuid = gg.aFile[i].zUuid;
if( zUuid==0 ) continue;
blob_appendf(&record, "F %F %s", gg.aFile[i].zName, zUuid);
if( gg.aFile[i].isExe ){
| | | | > > > > | 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 |
fflush(stdout);
}
for(i=0; i<gg.nFile; i++){
const char *zUuid = gg.aFile[i].zUuid;
if( zUuid==0 ) continue;
blob_appendf(&record, "F %F %s", gg.aFile[i].zName, zUuid);
if( gg.aFile[i].isExe ){
blob_append(&record, " x", 2);
}else if( gg.aFile[i].isLink ){
blob_append(&record, " l", 2);
}else{
blob_append(&record, " w", 2);
}
if( gg.aFile[i].zPrior!=0 ){
blob_appendf(&record, " %F", gg.aFile[i].zPrior);
}
blob_append(&record, "\n", 1);
}
if( gg.zFrom ){
blob_appendf(&record, "P %s", gg.zFrom);
for(i=0; i<gg.nMerge; i++){
blob_appendf(&record, " %s", gg.azMerge[i]);
}
blob_append(&record, "\n", 1);
|
| ︙ | ︙ | |||
540 541 542 543 544 545 546 |
}
zName[i] = 0;
}
static struct{
const char *zMasterName; /* Name of master branch */
| | | 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 |
}
zName[i] = 0;
}
static struct{
const char *zMasterName; /* Name of master branch */
int authorFlag; /* Use author as check-in committer */
int nGitAttr; /* Number of Git --attribute entries */
struct { /* Git --attribute details */
char *zUser;
char *zEmail;
} *gitUserInfo;
} ggit;
|
| ︙ | ︙ | |||
595 596 597 598 599 600 601 |
** tag to the new commit. However, if there are multiple instances
** of pattern B with the same TAGNAME, then only put the tag on the
** last commit that holds that tag.
**
** None of the above is explained in the git-fast-export
** documentation. We had to figure it out via trial and error.
*/
| | | 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 |
** tag to the new commit. However, if there are multiple instances
** of pattern B with the same TAGNAME, then only put the tag on the
** last commit that holds that tag.
**
** None of the above is explained in the git-fast-export
** documentation. We had to figure it out via trial and error.
*/
for(i=5; i<(int)strlen(zRefName) && zRefName[i]!='/'; i++){}
gg.tagCommit = strncmp(&zRefName[5], "tags", 4)==0; /* pattern B */
if( zRefName[i+1]!=0 ) zRefName += i+1;
if( fossil_strcmp(zRefName, "master")==0 ) zRefName = ggit.zMasterName;
gg.zBranch = fossil_strdup(zRefName);
gg.fromLoaded = 0;
}else
if( strncmp(zLine, "tag ", 4)==0 ){
|
| ︙ | ︙ | |||
765 766 767 768 769 770 771 |
i = 0;
mx = gg.nFile;
nFrom = strlen(zFrom);
while( (pFile = import_find_file(zFrom, &i, mx))!=0 ){
if( pFile->isFrom==0 ) continue;
pNew = import_add_file();
pFile = &gg.aFile[i-1];
| | | 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 |
i = 0;
mx = gg.nFile;
nFrom = strlen(zFrom);
while( (pFile = import_find_file(zFrom, &i, mx))!=0 ){
if( pFile->isFrom==0 ) continue;
pNew = import_add_file();
pFile = &gg.aFile[i-1];
if( (int)strlen(pFile->zName)>nFrom ){
pNew->zName = mprintf("%s%s", zTo, pFile->zName+nFrom);
}else{
pNew->zName = fossil_strdup(zTo);
}
pNew->isExe = pFile->isExe;
pNew->isLink = pFile->isLink;
pNew->zUuid = fossil_strdup(pFile->zUuid);
|
| ︙ | ︙ | |||
788 789 790 791 792 793 794 |
zTo = rest_of_line(&z);
i = 0;
nFrom = strlen(zFrom);
while( (pFile = import_find_file(zFrom, &i, gg.nFile))!=0 ){
if( pFile->isFrom==0 ) continue;
pNew = import_add_file();
pFile = &gg.aFile[i-1];
| | | 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 |
zTo = rest_of_line(&z);
i = 0;
nFrom = strlen(zFrom);
while( (pFile = import_find_file(zFrom, &i, gg.nFile))!=0 ){
if( pFile->isFrom==0 ) continue;
pNew = import_add_file();
pFile = &gg.aFile[i-1];
if( (int)strlen(pFile->zName)>nFrom ){
pNew->zName = mprintf("%s%s", zTo, pFile->zName+nFrom);
}else{
pNew->zName = fossil_strdup(zTo);
}
pNew->zPrior = pFile->zName;
pNew->isExe = pFile->isExe;
pNew->isLink = pFile->isLink;
|
| ︙ | ︙ | |||
848 849 850 851 852 853 854 | const char *zTrunk; /* Name of trunk folder in repo root */ int lenTrunk; /* String length of zTrunk */ const char *zBranches; /* Name of branches folder in repo root */ int lenBranches; /* String length of zBranches */ const char *zTags; /* Name of tags folder in repo root */ int lenTags; /* String length of zTags */ Bag newBranches; /* Branches that were created in this revision */ | | | 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 |
const char *zTrunk; /* Name of trunk folder in repo root */
int lenTrunk; /* String length of zTrunk */
const char *zBranches; /* Name of branches folder in repo root */
int lenBranches; /* String length of zBranches */
const char *zTags; /* Name of tags folder in repo root */
int lenTags; /* String length of zTags */
Bag newBranches; /* Branches that were created in this revision */
int revFlag; /* Add svn-rev-nn tags on every check-in */
const char *zRevPre; /* Prepended to revision tag names */
const char *zRevSuf; /* Appended to revision tag names */
const char **azIgnTree; /* NULL-terminated list of dirs to ignore */
} gsvn;
typedef struct {
char *zKey;
char *zVal;
|
| ︙ | ︙ | |||
1011 1012 1013 1014 1015 1016 1017 |
svn_read_props(pIn, rec);
blob_zero(&rec->content);
zLen = svn_find_header(*rec, "Text-content-length");
if( zLen ){
rec->contentFlag = 1;
nLen = atoi(zLen);
blob_read_from_channel(&rec->content, pIn, nLen);
| | | 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 |
svn_read_props(pIn, rec);
blob_zero(&rec->content);
zLen = svn_find_header(*rec, "Text-content-length");
if( zLen ){
rec->contentFlag = 1;
nLen = atoi(zLen);
blob_read_from_channel(&rec->content, pIn, nLen);
if( (int)blob_size(&rec->content)!=nLen ){
fossil_fatal("short read: got %d of %d bytes",
blob_size(&rec->content), nLen
);
}
}else{
rec->contentFlag = 0;
}
|
| ︙ | ︙ | |||
1276 1277 1278 1279 1280 1281 1282 |
char *zBranch = 0;
int branchId = 0;
if( gsvn.azIgnTree ){
const char **pzIgnTree;
unsigned nPath = strlen(zPath);
for( pzIgnTree = gsvn.azIgnTree; *pzIgnTree; ++pzIgnTree ){
const char *zIgn = *pzIgnTree;
| | | 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 |
char *zBranch = 0;
int branchId = 0;
if( gsvn.azIgnTree ){
const char **pzIgnTree;
unsigned nPath = strlen(zPath);
for( pzIgnTree = gsvn.azIgnTree; *pzIgnTree; ++pzIgnTree ){
const char *zIgn = *pzIgnTree;
unsigned nIgn = strlen(zIgn);
if( strncmp(zPath, zIgn, nIgn) == 0
&& ( nPath == nIgn || (nPath > nIgn && zPath[nIgn] == '/')) ){
return 0;
}
}
}
*type = SVN_UNKNOWN;
|
| ︙ | ︙ | |||
1687 1688 1689 1690 1691 1692 1693 | ** --flat The whole dump is a single branch ** --rev-tags Tag each revision, implied by -i ** --no-rev-tags Disables tagging effect of -i ** --rename-rev PAT Rev tag names, default "svn-rev-%" ** --ignore-tree DIR Ignores subtree rooted at DIR ** ** Common Options: | | | | | | | | | | | > > > > | 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 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 |
** --flat The whole dump is a single branch
** --rev-tags Tag each revision, implied by -i
** --no-rev-tags Disables tagging effect of -i
** --rename-rev PAT Rev tag names, default "svn-rev-%"
** --ignore-tree DIR Ignores subtree rooted at DIR
**
** Common Options:
** -i|--incremental Allow importing into an existing repository
** -f|--force Overwrite repository if already exists
** -q|--quiet Omit progress output
** --no-rebuild Skip the "rebuilding metadata" step
** --no-vacuum Skip the final VACUUM of the database file
** --rename-trunk NAME Use NAME as name of imported trunk branch
** --rename-branch PAT Rename all branch names using PAT pattern
** --rename-tag PAT Rename all tag names using PAT pattern
** -A|--admin-user NAME Use NAME for the admin user
**
** The --incremental option allows an existing repository to be extended
** with new content. The --rename-* options may be useful to avoid name
** conflicts when using the --incremental option. The --admin-user
** option is ignored if --incremental is specified.
**
** The argument to --rename-* contains one "%" character to be replaced
** with the original name. For example, "--rename-tag svn-%-tag" renames
** the tag called "release" to "svn-release-tag".
**
** --ignore-tree is useful for importing Subversion repositories which
** move branches to subdirectories of "branches/deleted" instead of
** deleting them. It can be supplied multiple times if necessary.
**
** The --attribute option takes a quoted string argument comprised of a
** Git committer email and the username to be attributed to corresponding
** check-ins in the Fossil repository. This option can be repeated. For
** example, --attribute "drh@sqlite.org drh" --attribute "xyz@abc.net X".
** Attributions are persisted to the repository so that subsequent
** 'fossil git export' operations attribute Fossil commits to corresponding
** 'Git Committer <git@committer.com>' users, and incremental imports with
** 'fossil import --git --incremental' use previous --attribute records.
**
** See also: export
*/
void import_cmd(void){
char *zPassword;
FILE *pIn;
Stmt q;
|
| ︙ | ︙ | |||
1949 1950 1951 1952 1953 1954 1955 |
** The following 'fx_' table is used to hold information needed for
** importing and exporting to attribute Fossil check-ins or Git commits
** to either a desired username or full contact information string.
*/
if(ggit.nGitAttr > 0) {
int idx;
db_unprotect(PROTECT_ALL);
| > | | | > | 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 |
** The following 'fx_' table is used to hold information needed for
** importing and exporting to attribute Fossil check-ins or Git commits
** to either a desired username or full contact information string.
*/
if(ggit.nGitAttr > 0) {
int idx;
db_unprotect(PROTECT_ALL);
if( !db_table_exists("repository", "fx_git") ){
db_multi_exec(
"CREATE TABLE fx_git(user TEXT, email TEXT UNIQUE);"
);
}
for(idx = 0; idx < ggit.nGitAttr; ++idx ){
db_multi_exec(
"INSERT OR IGNORE INTO fx_git(user, email) VALUES(%Q, %Q)",
ggit.gitUserInfo[idx].zUser, ggit.gitUserInfo[idx].zEmail
);
}
db_protect_pop();
|
| ︙ | ︙ | |||
2020 2021 2022 2023 2024 2025 2026 2027 2028 |
}
fossil_print(" ok\n");
if( !incrFlag ){
fossil_print("project-id: %s\n", db_get("project-code", 0));
fossil_print("server-id: %s\n", db_get("server-code", 0));
zPassword = db_text(0, "SELECT pw FROM user WHERE login=%Q", g.zLogin);
fossil_print("admin-user: %s (password is \"%s\")\n", g.zLogin, zPassword);
}
}
| > | 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 |
}
fossil_print(" ok\n");
if( !incrFlag ){
fossil_print("project-id: %s\n", db_get("project-code", 0));
fossil_print("server-id: %s\n", db_get("server-code", 0));
zPassword = db_text(0, "SELECT pw FROM user WHERE login=%Q", g.zLogin);
fossil_print("admin-user: %s (password is \"%s\")\n", g.zLogin, zPassword);
hash_user_password(g.zLogin);
}
}
|
Changes to src/info.c.
| ︙ | ︙ | |||
50 51 52 53 54 55 56 | ** * The record ID ** * mtime and ctime ** * who signed it ** */ void show_common_info( int rid, /* The rid for the check-in to display info for */ | | | 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
** * The record ID
** * mtime and ctime
** * who signed it
**
*/
void show_common_info(
int rid, /* The rid for the check-in to display info for */
const char *zRecDesc, /* Brief record description; e.g. "check-out:" */
int showComment, /* True to show the check-in comment */
int showFamily /* True to show parents and children */
){
Stmt q;
char *zComment = 0;
char *zTags;
char *zDate;
|
| ︙ | ︙ | |||
182 183 184 185 186 187 188 | ** ** If the argument is a repository name, then the --verbose option shows ** all known check-out locations for that repository and all URLs used ** to access the repository. The --verbose is (currently) a no-op if ** the argument is the name of an object within the repository. ** ** Use the "finfo" command to get information about a specific | | < | 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 |
**
** If the argument is a repository name, then the --verbose option shows
** all known check-out locations for that repository and all URLs used
** to access the repository. The --verbose is (currently) a no-op if
** the argument is the name of an object within the repository.
**
** Use the "finfo" command to get information about a specific
** file in a check-out.
**
** Options:
** -R|--repository REPO Extract info from repository REPO
** -v|--verbose Show extra information about repositories
**
** See also: [[annotate]], [[artifact]], [[finfo]], [[timeline]]
*/
void info_cmd(void){
i64 fsize;
|
| ︙ | ︙ | |||
363 364 365 366 367 368 369 | } /* ** Write a line of web-page output that shows changes that have occurred ** to a file between two check-ins. */ static void append_file_change_line( | | | 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 |
}
/*
** Write a line of web-page output that shows changes that have occurred
** to a file between two check-ins.
*/
static void append_file_change_line(
const char *zCkin, /* The check-in on which the change occurs */
const char *zName, /* Name of the file that has changed */
const char *zOld, /* blob.uuid before change. NULL for added files */
const char *zNew, /* blob.uuid after change. NULL for deletes */
const char *zOldName, /* Prior name. NULL if no name change. */
DiffConfig *pCfg, /* Flags for text_diff() or NULL to omit all */
int mperm /* executable or symlink permission for zNew */
){
|
| ︙ | ︙ | |||
396 397 398 399 400 401 402 |
}
if( pCfg ){
append_diff(zOld, zNew, pCfg);
}
}else{
if( zOld && zNew ){
if( fossil_strcmp(zOld, zNew)!=0 ){
| > > > > > > > > > | | | | > | 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 |
}
if( pCfg ){
append_diff(zOld, zNew, pCfg);
}
}else{
if( zOld && zNew ){
if( fossil_strcmp(zOld, zNew)!=0 ){
if( zOldName!=0 && fossil_strcmp(zName,zOldName)!=0 ){
@ Renamed and modified
@ %z(href("%R/finfo?name=%T&m=%!S&ci=%!S",zOldName,zOld,zCkin))\
@ %h(zOldName)</a>
@ %z(href("%R/artifact/%!S",zOld))[%S(zOld)]</a>
@ to %z(href("%R/finfo?name=%T&m=%!S&ci=%!S",zName,zNew,zCkin))\
@ %h(zName)</a>
@ %z(href("%R/artifact/%!S",zNew))[%S(zNew)]</a>.
}else{
@ Modified %z(href("%R/finfo?name=%T&m=%!S&ci=%!S",zName,zNew,zCkin))\
@ %h(zName)</a>
@ from %z(href("%R/artifact/%!S",zOld))[%S(zOld)]</a>
@ to %z(href("%R/artifact/%!S",zNew))[%S(zNew)]</a>.
}
}else if( zOldName!=0 && fossil_strcmp(zName,zOldName)!=0 ){
@ Name change
@ from %z(href("%R/finfo?name=%T&m=%!S&ci=%!S",zOldName,zOld,zCkin))\
@ %h(zOldName)</a>
@ to %z(href("%R/finfo?name=%T&m=%!S&ci=%!S",zName,zNew,zCkin))\
@ %h(zName)</a>.
}else{
|
| ︙ | ︙ | |||
452 453 454 455 456 457 458 |
** parameters and the to boolean arguments.
*/
DiffConfig *construct_diff_flags(int diffType, DiffConfig *pCfg){
u64 diffFlags = 0; /* Zero means do not show any diff */
if( diffType>0 ){
int x;
if( diffType==2 ) diffFlags = DIFF_SIDEBYSIDE;
| | | | 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 |
** parameters and the to boolean arguments.
*/
DiffConfig *construct_diff_flags(int diffType, DiffConfig *pCfg){
u64 diffFlags = 0; /* Zero means do not show any diff */
if( diffType>0 ){
int x;
if( diffType==2 ) diffFlags = DIFF_SIDEBYSIDE;
if( P_NoBot("w") ) diffFlags |= DIFF_IGNORE_ALLWS;
if( PD_NoBot("noopt",0)!=0 ) diffFlags |= DIFF_NOOPT;
diffFlags |= DIFF_STRIP_EOLCR;
diff_config_init(pCfg, diffFlags);
/* "dc" query parameter determines lines of context */
x = atoi(PD("dc","7"));
if( x>0 ) pCfg->nContext = x;
|
| ︙ | ︙ | |||
495 496 497 498 499 500 501 502 503 504 505 506 507 508 |
rid = name_to_rid_www("name");
if( rid==0 ){
style_header("Check-in Information Error");
@ No such object: %h(PD("name",""))
style_finish_page();
return;
}
zHash = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
style_header("Tags and Properties");
zType = whatis_rid_type_label(rid);
if(!zType) zType = "Artifact";
@ <h1>Tags and Properties for %s(zType) \
@ %z(href("%R/ci/%!S",zHash))%S(zHash)</a></h1>
db_prepare(&q,
| > | 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 |
rid = name_to_rid_www("name");
if( rid==0 ){
style_header("Check-in Information Error");
@ No such object: %h(PD("name",""))
style_finish_page();
return;
}
cgi_check_for_malice();
zHash = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
style_header("Tags and Properties");
zType = whatis_rid_type_label(rid);
if(!zType) zType = "Artifact";
@ <h1>Tags and Properties for %s(zType) \
@ %z(href("%R/ci/%!S",zHash))%S(zHash)</a></h1>
db_prepare(&q,
|
| ︙ | ︙ | |||
647 648 649 650 651 652 653 |
" datetime(omtime,toLocal()), mtime"
" FROM blob, event"
" WHERE blob.rid=%d"
" AND event.objid=%d",
rid, rid
);
zBrName = branch_of_rid(rid);
| | > | 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 |
" datetime(omtime,toLocal()), mtime"
" FROM blob, event"
" WHERE blob.rid=%d"
" AND event.objid=%d",
rid, rid
);
zBrName = branch_of_rid(rid);
diffType = preferred_diff_type();
cgi_check_for_malice();
if( db_step(&q1)==SQLITE_ROW ){
const char *zUuid = db_column_text(&q1, 0);
int nUuid = db_column_bytes(&q1, 0);
char *zEUser, *zEComment;
const char *zUser;
const char *zOrigUser;
const char *zComment;
|
| ︙ | ︙ | |||
817 818 819 820 821 822 823 |
&& ((okWiki = wiki_tagid2("checkin",zUuid))!=0 ||
blob_size(&wiki_read_links)>0)
&& db_get_boolean("wiki-about",1)
){
const char *zLinks = blob_str(&wiki_read_links);
@ <tr><th>Edit Wiki:</th><td>\
if( okWiki ){
| | | | 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 |
&& ((okWiki = wiki_tagid2("checkin",zUuid))!=0 ||
blob_size(&wiki_read_links)>0)
&& db_get_boolean("wiki-about",1)
){
const char *zLinks = blob_str(&wiki_read_links);
@ <tr><th>Edit Wiki:</th><td>\
if( okWiki ){
@ %z(href("%R/wikiedit?name=checkin/%s",zUuid))this check-in</a>\
}else if( zLinks[0] ){
zLinks += 3;
}
@ %s(zLinks)</td></tr>
}
/* Only show links to create new wiki pages if the users can write wiki
** and if the wiki pages do not already exist */
if( g.perm.WrWiki
&& g.perm.RdWiki
&& g.perm.Write
&& (blob_size(&wiki_add_links)>0 || !okWiki)
&& db_get_boolean("wiki-about",1)
){
const char *zLinks = blob_str(&wiki_add_links);
@ <tr><th>Add Wiki:</th><td>\
if( !okWiki ){
@ %z(href("%R/wikiedit?name=checkin/%s",zUuid))this check-in</a>\
}else if( zLinks[0] ){
zLinks += 3;
}
@ %s(zLinks)</td></tr>
}
if( g.perm.Hyperlink ){
|
| ︙ | ︙ | |||
868 869 870 871 872 873 874 |
blob_reset(&wiki_add_links);
}else{
style_header("Check-in Information");
login_anonymous_available();
}
db_finalize(&q1);
@ </div>
| | | | | 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 |
blob_reset(&wiki_add_links);
}else{
style_header("Check-in Information");
login_anonymous_available();
}
db_finalize(&q1);
@ </div>
builtin_request_js("accordion.js");
if( !PB("nowiki") ){
wiki_render_associated("checkin", zUuid, 0);
}
render_backlink_graph(zUuid,
"<div class=\"section accordion\">References</div>\n");
@ <div class="section accordion">Context</div><div class="accordion_panel">
render_checkin_context(rid, 0, 0, 0);
@ </div><div class="section accordion">Changes</div>
@ <div class="accordion_panel">
@ <div class="sectionmenu">
pCfg = construct_diff_flags(diffType, &DCfg);
DCfg.pRe = pRe;
zW = (DCfg.diffFlags&DIFF_IGNORE_ALLWS)?"&w":"";
if( diffType!=0 ){
@ %z(chref("button","%R/%s/%T?diff=0",zPageHide,zName))\
@ Hide Diffs</a>
}
if( diffType!=1 ){
@ %z(chref("button","%R/%s/%T?diff=1%s",zPage,zName,zW))\
|
| ︙ | ︙ | |||
934 935 936 937 938 939 940 |
);
while( db_step(&q3)==SQLITE_ROW ){
const char *zName = db_column_text(&q3,0);
int mperm = db_column_int(&q3, 1);
const char *zOld = db_column_text(&q3,2);
const char *zNew = db_column_text(&q3,3);
const char *zOldName = db_column_text(&q3, 4);
| | | 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 |
);
while( db_step(&q3)==SQLITE_ROW ){
const char *zName = db_column_text(&q3,0);
int mperm = db_column_int(&q3, 1);
const char *zOld = db_column_text(&q3,2);
const char *zNew = db_column_text(&q3,3);
const char *zOldName = db_column_text(&q3, 4);
append_file_change_line(zUuid, zName, zOld, zNew, zOldName,
pCfg,mperm);
}
db_finalize(&q3);
@ </div>
append_diff_javascript(diffType);
style_finish_page();
}
|
| ︙ | ︙ | |||
990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 |
/*NOTREACHED*/
}
}
if( strcmp(zModAction,"approve")==0 ){
moderation_approve('w', rid);
}
}
style_header("Update of \"%h\"", pWiki->zWikiTitle);
zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
zDate = db_text(0, "SELECT datetime(%.17g,toLocal())", pWiki->rDate);
style_submenu_element("Raw", "%R/artifact/%s", zUuid);
style_submenu_element("History", "%R/whistory?name=%t", pWiki->zWikiTitle);
style_submenu_element("Page", "%R/wiki?name=%t", pWiki->zWikiTitle);
login_anonymous_available();
| > | 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 |
/*NOTREACHED*/
}
}
if( strcmp(zModAction,"approve")==0 ){
moderation_approve('w', rid);
}
}
cgi_check_for_malice();
style_header("Update of \"%h\"", pWiki->zWikiTitle);
zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
zDate = db_text(0, "SELECT datetime(%.17g,toLocal())", pWiki->rDate);
style_submenu_element("Raw", "%R/artifact/%s", zUuid);
style_submenu_element("History", "%R/whistory?name=%t", pWiki->zWikiTitle);
style_submenu_element("Page", "%R/wiki?name=%t", pWiki->zWikiTitle);
login_anonymous_available();
|
| ︙ | ︙ | |||
1039 1040 1041 1042 1043 1044 1045 |
@ </table>
if( g.perm.ModWiki && modPending ){
@ <div class="section">Moderation</div>
@ <blockquote>
@ <form method="POST" action="%R/winfo/%s(zUuid)">
@ <label><input type="radio" name="modaction" value="delete">
| | | | 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 |
@ </table>
if( g.perm.ModWiki && modPending ){
@ <div class="section">Moderation</div>
@ <blockquote>
@ <form method="POST" action="%R/winfo/%s(zUuid)">
@ <label><input type="radio" name="modaction" value="delete">
@ Delete this change</label><br>
@ <label><input type="radio" name="modaction" value="approve">
@ Approve this change</label><br>
@ <input type="submit" value="Submit">
@ </form>
@ </blockquote>
}
@ <div class="section">Content</div>
|
| ︙ | ︙ | |||
1210 1211 1212 1213 1214 1215 1216 |
}
}
pTo = vdiff_parse_manifest("to", &ridTo);
if( pTo==0 ) return;
pFrom = vdiff_parse_manifest("from", &ridFrom);
if( pFrom==0 ) return;
zGlob = P("glob");
| | | | 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 |
}
}
pTo = vdiff_parse_manifest("to", &ridTo);
if( pTo==0 ) return;
pFrom = vdiff_parse_manifest("from", &ridFrom);
if( pFrom==0 ) return;
zGlob = P("glob");
zFrom = P_NoBot("from");
zTo = P_NoBot("to");
if( bInvert ){
Manifest *pTemp = pTo;
const char *zTemp = zTo;
pTo = pFrom;
pFrom = pTemp;
zTo = zFrom;
zFrom = zTemp;
|
| ︙ | ︙ | |||
1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 |
graphFlags |= TIMELINE_NOCOLOR;
blob_appendf(&qp, "&nc");
}
pCfg = construct_diff_flags(diffType, &DCfg);
if( DCfg.diffFlags & DIFF_IGNORE_ALLWS ){
blob_appendf(&qp, "&w");
}
style_set_current_feature("vdiff");
if( zBranch==0 ){
style_submenu_element("Path", "%R/timeline?me=%T&you=%T", zFrom, zTo);
}
if( diffType!=0 ){
style_submenu_element("Hide Diff", "%R/vdiff?diff=0&%b", &qp);
}
| > | 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 |
graphFlags |= TIMELINE_NOCOLOR;
blob_appendf(&qp, "&nc");
}
pCfg = construct_diff_flags(diffType, &DCfg);
if( DCfg.diffFlags & DIFF_IGNORE_ALLWS ){
blob_appendf(&qp, "&w");
}
cgi_check_for_malice();
style_set_current_feature("vdiff");
if( zBranch==0 ){
style_submenu_element("Path", "%R/timeline?me=%T&you=%T", zFrom, zTo);
}
if( diffType!=0 ){
style_submenu_element("Hide Diff", "%R/vdiff?diff=0&%b", &qp);
}
|
| ︙ | ︙ | |||
1295 1296 1297 1298 1299 1300 1301 |
if( pRe ){
@ <p><b>Only differences that match regular expression "%h(zRe)"
@ are shown.</b></p>
}
if( zGlob ){
@ <p><b>Only files matching the glob "%h(zGlob)" are shown.</b></p>
}
| | | 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 |
if( pRe ){
@ <p><b>Only differences that match regular expression "%h(zRe)"
@ are shown.</b></p>
}
if( zGlob ){
@ <p><b>Only files matching the glob "%h(zGlob)" are shown.</b></p>
}
@<hr><p>
}
blob_reset(&qp);
manifest_file_rewind(pFrom);
pFileFrom = manifest_file_next(pFrom, 0);
manifest_file_rewind(pTo);
pFileTo = manifest_file_next(pTo, 0);
|
| ︙ | ︙ | |||
1685 1686 1687 1688 1689 1690 1691 |
static char zDflt[2]
/*static b/c cookie_link_parameter() does not copy it!*/;
dflt = db_get_int("preferred-diff-type",-99);
if( dflt<=0 ) dflt = user_agent_is_likely_mobile() ? 1 : 2;
zDflt[0] = dflt + '0';
zDflt[1] = 0;
cookie_link_parameter("diff","diff", zDflt);
| | | 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 |
static char zDflt[2]
/*static b/c cookie_link_parameter() does not copy it!*/;
dflt = db_get_int("preferred-diff-type",-99);
if( dflt<=0 ) dflt = user_agent_is_likely_mobile() ? 1 : 2;
zDflt[0] = dflt + '0';
zDflt[1] = 0;
cookie_link_parameter("diff","diff", zDflt);
return atoi(PD_NoBot("diff",zDflt));
}
/*
** WEBPAGE: fdiff
** URL: fdiff?v1=HASH&v2=HASH
**
|
| ︙ | ︙ | |||
1721 1722 1723 1724 1725 1726 1727 |
int v1, v2;
int isPatch = P("patch")!=0;
int diffType; /* 0: none, 1: unified, 2: side-by-side */
char *zV1;
char *zV2;
const char *zRe;
ReCompiled *pRe = 0;
| < > | 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 |
int v1, v2;
int isPatch = P("patch")!=0;
int diffType; /* 0: none, 1: unified, 2: side-by-side */
char *zV1;
char *zV2;
const char *zRe;
ReCompiled *pRe = 0;
u32 objdescFlags = 0;
int verbose = PB("verbose");
DiffConfig DCfg;
login_check_credentials();
if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
diff_config_init(&DCfg, 0);
diffType = preferred_diff_type();
if( P("from") && P("to") ){
v1 = artifact_from_ci_and_filename("from");
v2 = artifact_from_ci_and_filename("to");
}else{
Stmt q;
v1 = name_to_rid_www("v1");
|
| ︙ | ︙ | |||
1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 |
"%R/annotate?origin=%s&checkin=%s&filename=%T",
zOrig, zCkin, zFN);
}
db_finalize(&q);
}
if( v1==0 || v2==0 ) fossil_redirect_home();
zRe = P("regex");
if( zRe ) re_compile(&pRe, zRe, 0);
if( verbose ) objdescFlags |= OBJDESC_DETAIL;
if( isPatch ){
Blob c1, c2, *pOut;
DiffConfig DCfg;
pOut = cgi_output_blob();
cgi_set_content_type("text/plain");
| > | < | 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 |
"%R/annotate?origin=%s&checkin=%s&filename=%T",
zOrig, zCkin, zFN);
}
db_finalize(&q);
}
if( v1==0 || v2==0 ) fossil_redirect_home();
zRe = P("regex");
cgi_check_for_malice();
if( zRe ) re_compile(&pRe, zRe, 0);
if( verbose ) objdescFlags |= OBJDESC_DETAIL;
if( isPatch ){
Blob c1, c2, *pOut;
DiffConfig DCfg;
pOut = cgi_output_blob();
cgi_set_content_type("text/plain");
DCfg.diffFlags = DIFF_VERBOSE;
content_get(v1, &c1);
content_get(v2, &c2);
DCfg.pRe = pRe;
text_diff(&c1, &c2, pOut, &DCfg);
blob_reset(&c1);
blob_reset(&c2);
return;
}
|
| ︙ | ︙ | |||
1820 1821 1822 1823 1824 1825 1826 |
object_description(v2, objdescFlags,0, 0);
}
if( pRe ){
@ <b>Only differences that match regular expression "%h(zRe)"
@ are shown.</b>
DCfg.pRe = pRe;
}
| | | 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 |
object_description(v2, objdescFlags,0, 0);
}
if( pRe ){
@ <b>Only differences that match regular expression "%h(zRe)"
@ are shown.</b>
DCfg.pRe = pRe;
}
@ <hr>
append_diff(zV1, zV2, &DCfg);
append_diff_javascript(diffType);
style_finish_page();
}
/*
** WEBPAGE: raw
|
| ︙ | ︙ | |||
1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 |
** Return the uninterpreted content of an artifact. Used primarily
** to view artifacts that are images.
*/
void rawartifact_page(void){
int rid = 0;
char *zUuid;
if( P("ci") ){
rid = artifact_from_ci_and_filename(0);
}
if( rid==0 ){
rid = name_to_rid_www("name");
}
login_check_credentials();
if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
if( rid==0 ) fossil_redirect_home();
zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
etag_check(ETAG_HASH, zUuid);
if( fossil_strcmp(P("name"), zUuid)==0 && login_is_nobody() ){
g.isConst = 1;
}
free(zUuid);
| > > > | 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 |
** Return the uninterpreted content of an artifact. Used primarily
** to view artifacts that are images.
*/
void rawartifact_page(void){
int rid = 0;
char *zUuid;
(void)P("at")/*for cgi_check_for_malice()*/;
(void)P("m");
if( P("ci") ){
rid = artifact_from_ci_and_filename(0);
}
if( rid==0 ){
rid = name_to_rid_www("name");
}
login_check_credentials();
if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
cgi_check_for_malice();
if( rid==0 ) fossil_redirect_home();
zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
etag_check(ETAG_HASH, zUuid);
if( fossil_strcmp(P("name"), zUuid)==0 && login_is_nobody() ){
g.isConst = 1;
}
free(zUuid);
|
| ︙ | ︙ | |||
1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 |
** is by the full-length SHA1 or SHA3 hash. Abbreviations are not
** accepted.
*/
void secure_rawartifact_page(void){
int rid = 0;
const char *zName = PD("name", "");
login_check_credentials();
if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
rid = db_int(0, "SELECT rid FROM blob WHERE uuid=%Q", zName);
if( rid==0 ){
cgi_set_status(404, "Not Found");
@ Unknown artifact: "%h(zName)"
return;
| > > > | 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 |
** is by the full-length SHA1 or SHA3 hash. Abbreviations are not
** accepted.
*/
void secure_rawartifact_page(void){
int rid = 0;
const char *zName = PD("name", "");
(void)P("at")/*for cgi_check_for_malice()*/;
(void)P("m");
cgi_check_for_malice();
login_check_credentials();
if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
rid = db_int(0, "SELECT rid FROM blob WHERE uuid=%Q", zName);
if( rid==0 ){
cgi_set_status(404, "Not Found");
@ Unknown artifact: "%h(zName)"
return;
|
| ︙ | ︙ | |||
1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 |
if(0){
ajax_route_error(400, "Just testing client-side error handling.");
return;
}
login_check_credentials();
if( !g.perm.Read ){
ajax_route_error(403, "Access requires Read permissions.");
return;
}
#if 1
/* Re-enable this block once this code is integrated somewhere into
the UI. */
| > | 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 |
if(0){
ajax_route_error(400, "Just testing client-side error handling.");
return;
}
login_check_credentials();
cgi_check_for_malice();
if( !g.perm.Read ){
ajax_route_error(403, "Access requires Read permissions.");
return;
}
#if 1
/* Re-enable this block once this code is integrated somewhere into
the UI. */
|
| ︙ | ︙ | |||
2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 |
char *zUuid;
u32 objdescFlags = 0;
rid = name_to_rid_www("name");
login_check_credentials();
if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
if( rid==0 ) fossil_redirect_home();
if( g.perm.Admin ){
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#delshun", zUuid);
}else{
style_submenu_element("Shun", "%R/shun?shun=%s#addshun", zUuid);
}
| > | 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 |
char *zUuid;
u32 objdescFlags = 0;
rid = name_to_rid_www("name");
login_check_credentials();
if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
if( rid==0 ) fossil_redirect_home();
cgi_check_for_malice();
if( g.perm.Admin ){
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#delshun", zUuid);
}else{
style_submenu_element("Shun", "%R/shun?shun=%s#addshun", zUuid);
}
|
| ︙ | ︙ | |||
2128 2129 2130 2131 2132 2133 2134 |
@ :</h2>
}
blob_zero(&downloadName);
if( P("verbose")!=0 ) objdescFlags |= OBJDESC_DETAIL;
object_description(rid, objdescFlags, 0, &downloadName);
style_submenu_element("Download", "%R/raw/%s?at=%T",
zUuid, file_tail(blob_str(&downloadName)));
| | | 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 |
@ :</h2>
}
blob_zero(&downloadName);
if( P("verbose")!=0 ) objdescFlags |= OBJDESC_DETAIL;
object_description(rid, objdescFlags, 0, &downloadName);
style_submenu_element("Download", "%R/raw/%s?at=%T",
zUuid, file_tail(blob_str(&downloadName)));
@ <hr>
content_get(rid, &content);
if( !g.isHuman ){
/* Prevent robots from running hexdump on megabyte-sized source files
** and there by eating up lots of CPU time and bandwidth. There is
** no good reason for a robot to need a hexdump. */
@ <p>A hex dump of this file is not available.
@ Please download the raw binary file and generate a hex dump yourself.</p>
|
| ︙ | ︙ | |||
2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 |
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; }
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");
| > | 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 |
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");
|
| ︙ | ︙ | |||
2494 2495 2496 2497 2498 2499 2500 |
if( db_step(&q)==SQLITE_ROW ){
rid = db_column_int(&q, 0);
zCI = fossil_strdup(db_column_text(&q, 1));
zCIUuid = fossil_strdup(zCI);
url_add_parameter(&url, "ci", zCI);
}
db_finalize(&q);
| | | 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 |
if( db_step(&q)==SQLITE_ROW ){
rid = db_column_int(&q, 0);
zCI = fossil_strdup(db_column_text(&q, 1));
zCIUuid = fossil_strdup(zCI);
url_add_parameter(&url, "ci", zCI);
}
db_finalize(&q);
if( rid==0 ){
style_header("No such file");
@ File '%h(zName)' does not exist in this repository.
}
}else{
style_header("No such artifact");
@ Artifact '%h(zName)' does not exist in this repository.
}
|
| ︙ | ︙ | |||
2654 2655 2656 2657 2658 2659 2660 |
}
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{
| | | 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 |
}
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{
@ <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)"
|
| ︙ | ︙ | |||
2696 2697 2698 2699 2700 2701 2702 |
" WHERE filename.fnid=mlink.fnid"
" AND mlink.fid=%d",
rid);
zExt = zFileName ? file_extension(zFileName) : 0;
if( zLn ){
output_text_with_line_numbers(z, blob_size(&content),
zFileName, zLn, 1);
| | | 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 |
" WHERE filename.fnid=mlink.fnid"
" AND mlink.fid=%d",
rid);
zExt = zFileName ? file_extension(zFileName) : 0;
if( zLn ){
output_text_with_line_numbers(z, blob_size(&content),
zFileName, zLn, 1);
}else if( zExt && zExt[0] ){
@ <pre>
@ <code class="language-%s(zExt)">%h(z)</code>
@ </pre>
}else{
@ <pre>
@ %h(z)
@ </pre>
|
| ︙ | ︙ | |||
2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 |
int modPending;
const char *zModAction;
char *zTktTitle;
login_check_credentials();
if( !g.perm.RdTkt ){ login_needed(g.anon.RdTkt); return; }
rid = name_to_rid_www("name");
if( rid==0 ){ fossil_redirect_home(); }
zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid);
if( g.perm.Admin ){
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);
}
}
pTktChng = manifest_get(rid, CFTYPE_TICKET, 0);
if( pTktChng==0 ) fossil_redirect_home();
| > | | 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 |
int modPending;
const char *zModAction;
char *zTktTitle;
login_check_credentials();
if( !g.perm.RdTkt ){ login_needed(g.anon.RdTkt); return; }
rid = name_to_rid_www("name");
if( rid==0 ){ fossil_redirect_home(); }
cgi_check_for_malice();
zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid);
if( g.perm.Admin ){
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);
}
}
pTktChng = manifest_get(rid, CFTYPE_TICKET, 0);
if( pTktChng==0 ) fossil_redirect_home();
zDate = db_text(0, "SELECT datetime(%.12f,toLocal())", pTktChng->rDate);
sqlite3_snprintf(sizeof(zTktName), zTktName, "%s", pTktChng->zTicketUuid);
if( g.perm.ModTkt && (zModAction = P("modaction"))!=0 ){
if( strcmp(zModAction,"delete")==0 ){
moderation_disapprove(rid);
/*
** Next, check if the ticket still exists; if not, we cannot
** redirect to it.
|
| ︙ | ︙ | |||
2781 2782 2783 2784 2785 2786 2787 |
zTktTitle = db_table_has_column("repository", "ticket", "title" )
? db_text("(No title)",
"SELECT title FROM ticket WHERE tkt_uuid=%Q", zTktName)
: 0;
style_set_current_feature("tinfo");
style_header("Ticket Change Details");
style_submenu_element("Raw", "%R/artifact/%s", zUuid);
| | | | | | | 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 |
zTktTitle = db_table_has_column("repository", "ticket", "title" )
? db_text("(No title)",
"SELECT title FROM ticket WHERE tkt_uuid=%Q", zTktName)
: 0;
style_set_current_feature("tinfo");
style_header("Ticket Change Details");
style_submenu_element("Raw", "%R/artifact/%s", zUuid);
style_submenu_element("History", "%R/tkthistory/%s#%S", zTktName,zUuid);
style_submenu_element("Page", "%R/tktview/%t", zTktName);
style_submenu_element("Timeline", "%R/tkttimeline/%t", zTktName);
if( P("plaintext") ){
style_submenu_element("Formatted", "%R/info/%s", zUuid);
}else{
style_submenu_element("Plaintext", "%R/info/%s?plaintext", zUuid);
}
@ <div class="section">Overview</div>
@ <p><table class="label-value">
@ <tr><th>Artifact ID:</th>
@ <td>%z(href("%R/artifact/%!S",zUuid))%s(zUuid)</a>
if( g.perm.Setup ){
@ (%d(rid))
}
modPending = moderation_pending_www(rid);
@ <tr><th>Ticket:</th>
@ <td>%z(href("%R/tktview/%s",zTktName))%s(zTktName)</a>
if( zTktTitle ){
@<br>%h(zTktTitle)
}
@</td></tr>
@ <tr><th>User & Date:</th><td>
hyperlink_to_user(pTktChng->zUser, zDate, " on ");
hyperlink_to_date(zDate, "</td></tr>");
@ </table>
free(zDate);
free(zTktTitle);
if( g.perm.ModTkt && modPending ){
@ <div class="section">Moderation</div>
@ <blockquote>
@ <form method="POST" action="%R/tinfo/%s(zUuid)">
@ <label><input type="radio" name="modaction" value="delete">
@ Delete this change</label><br>
@ <label><input type="radio" name="modaction" value="approve">
@ Approve this change</label><br>
@ <input type="submit" value="Submit">
@ </form>
@ </blockquote>
}
@ <div class="section">Changes</div>
@ <p>
ticket_output_change_artifact(pTktChng, 0, 1, 0);
manifest_destroy(pTktChng);
style_finish_page();
}
/*
** WEBPAGE: info
|
| ︙ | ︙ | |||
2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 |
Blob uuid;
int rid;
int rc;
int nLen;
zName = P("name");
if( zName==0 ) fossil_redirect_home();
nLen = strlen(zName);
blob_set(&uuid, zName);
if( name_collisions(zName) ){
cgi_set_parameter("src","info");
ambiguous_page();
return;
}
| > | 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 |
Blob uuid;
int rid;
int rc;
int nLen;
zName = P("name");
if( zName==0 ) fossil_redirect_home();
cgi_check_for_malice();
nLen = strlen(zName);
blob_set(&uuid, zName);
if( name_collisions(zName) ){
cgi_set_parameter("src","info");
ambiguous_page();
return;
}
|
| ︙ | ︙ | |||
3187 3188 3189 3190 3191 3192 3193 |
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" : "";
| | < | 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 |
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);
zNow = date_in_standard_format(zChngTime ? zChngTime : "now");
blob_appendf(&ctrl, "D %s\n", zNow);
init_newtags();
if( zNewColorFlag[0]
&& zNewColor[0]
&& (fPropagateColor!=fNewPropagateColor
|
| ︙ | ︙ | |||
3268 3269 3270 3271 3272 3273 3274 |
@ %s(blob_str(&suffix))
@ </td></tr></table>
if( zChngTime ){
@ <p>The timestamp on the tag used to make the changes above
@ will be overridden as: %s(date_in_standard_format(zChngTime))</p>
}
@ </blockquote>
| | < | | | | | | | | | < | 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 |
@ %s(blob_str(&suffix))
@ </td></tr></table>
if( zChngTime ){
@ <p>The timestamp on the tag used to make the changes above
@ will be overridden as: %s(date_in_standard_format(zChngTime))</p>
}
@ </blockquote>
@ <hr>
blob_reset(&suffix);
}
@ <p>Make changes to attributes of check-in
@ [%z(href("%R/ci/%!S",zUuid))%s(zUuid)</a>]:</p>
form_begin(0, "%R/ci_edit");
@ <div><input type="hidden" name="r" value="%s(zUuid)">
@ <table border="0" cellspacing="10">
@ <tr><th align="right" valign="top">User:</th>
@ <td valign="top">
@ <input type="text" name="u" size="20" value="%h(zNewUser)">
@ </td></tr>
@ <tr><th align="right" valign="top">Comment:</th>
@ <td valign="top">
@ <textarea name="c" rows="10" cols="80">%h(zNewComment)</textarea>
@ </td></tr>
@ <tr><th align="right" valign="top">Check-in Time:</th>
@ <td valign="top">
@ <input type="text" name="dt" size="20" value="%h(zNewDate)">
@ </td></tr>
if( zChngTime ){
@ <tr><th align="right" valign="top">Timestamp of this change:</th>
@ <td valign="top">
@ <input type="text" name="chngtime" size="20" value="%h(zChngTime)">
@ </td></tr>
}
@ <tr><th align="right" valign="top">Background Color:</th>
@ <td valign="top">
@ <div><label><input type='checkbox' name='newclr'%s(zNewColorFlag)>
@ Change background color: \
@ <input type='color' name='clr'\
@ value='%s(zNewColor[0]?zNewColor:"#808080")'></label></div>
@ <div><label>
if( fNewPropagateColor ){
@ <input type="checkbox" name="pclr" checked="checked">
}else{
@ <input type="checkbox" name="pclr">
}
@ Propagate color to descendants</label></div>
@ <div class='font-size-80'>Be aware that fixed background
@ colors will not interact well with all available skins.
@ It is recommended that Fossil be allowed to select these
@ colors automatically so that it can take the skin's
@ preferences into account.</div>
@ </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)">
zBranchName = db_text(0, "SELECT value FROM tagxref, tag"
" WHERE tagxref.rid=%d AND tagtype>0 AND tagxref.tagid=tag.tagid"
" AND tagxref.tagid=%d", rid, TAG_BRANCH);
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)"
|
| ︙ | ︙ | |||
3353 3354 3355 3356 3357 3358 3359 |
}else if( tagid==TAG_HIDDEN ){
fHasHidden = 1;
}else if( !isSpecialTag && zTagName &&
fossil_strcmp(&zTagName[4], zBranchName)==0){
continue;
}
sqlite3_snprintf(sizeof(zLabel), zLabel, "c%d", tagid);
| | | | | | | | | | | | | | 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 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 |
}else if( tagid==TAG_HIDDEN ){
fHasHidden = 1;
}else if( !isSpecialTag && zTagName &&
fossil_strcmp(&zTagName[4], zBranchName)==0){
continue;
}
sqlite3_snprintf(sizeof(zLabel), zLabel, "c%d", tagid);
@ <br><label>
if( P(zLabel) ){
@ <input type="checkbox" name="c%d(tagid)" checked="checked">
}else{
@ <input type="checkbox" name="c%d(tagid)">
}
if( isSpecialTag ){
@ Cancel special tag <b>%h(zTagName)</b></label>
}else{
@ Cancel tag <b>%h(&zTagName[4])</b></label>
}
}
db_finalize(&q);
@ </td></tr>
if( !zBranchName ){
zBranchName = db_get("main-branch", 0);
}
if( !zNewBranch || !zNewBranch[0]){
zNewBranch = zBranchName;
}
@ <tr><th align="right" valign="top">Branching:</th>
@ <td valign="top">
@ <label><input id="newbr" type="checkbox" name="newbr" \
@ data-branch='%h(zBranchName)'%s(zNewBrFlag)>
@ Starting from this check-in, rename the branch to:</label>
@ <input id="brname" type="text" style="width:15;" name="brname" \
@ value="%h(zNewBranch)"></td></tr>
if( !fHasHidden ){
@ <tr><th align="right" valign="top">Branch Hiding:</th>
@ <td valign="top">
@ <label><input type="checkbox" id="hidebr" name="hide"%s(zHideFlag)>
@ Hide branch
@ <span style="font-weight:bold" id="hbranch">%h(zBranchName)</span>
@ from the timeline starting from this check-in</label>
@ </td></tr>
}
if( !fHasClosed ){
if( is_a_leaf(rid) ){
@ <tr><th align="right" valign="top">Leaf Closure:</th>
@ <td valign="top">
@ <label><input type="checkbox" name="close"%s(zCloseFlag)>
@ Mark this leaf as "closed" so that it no longer appears on the
@ "leaves" page and is no longer labeled as a "<b>Leaf</b>"</label>
@ </td></tr>
}else if( zBranchName ){
@ <tr><th align="right" valign="top">Branch Closure:</th>
@ <td valign="top">
@ <label><input type="checkbox" name="close"%s(zCloseFlag)>
@ Mark branch
@ <span style="font-weight:bold" id="cbranch">%h(zBranchName)</span>
@ as "closed".</label>
@ </td></tr>
}
}
if( zBranchName ) fossil_free(zBranchName);
@ <tr><td colspan="2">
@ <input type="submit" name="cancel" value="Cancel">
@ <input type="submit" name="preview" value="Preview">
if( P("preview") ){
@ <input type="submit" name="apply" value="Apply Changes">
}
@ </td></tr>
@ </table>
@ </div></form>
builtin_request_js("ci_edit.js");
style_finish_page();
}
|
| ︙ | ︙ | |||
3469 3470 3471 3472 3473 3474 3475 | ** COMMAND: amend ** ** Usage: %fossil amend HASH OPTION ?OPTION ...? ** ** Amend the tags on check-in HASH to change how it displays in the timeline. ** ** Options: | < | | 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 | ** 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 ** -m|--comment COMMENT Make COMMENT the check-in comment ** -M|--message-file FILE Read the amended comment from FILE ** -e|--edit-comment Launch editor to revise comment ** --date DATETIME Make DATETIME the check-in time ** --bgcolor COLOR Apply COLOR to this check-in ** --branchcolor COLOR Apply and propagate COLOR to the branch ** --tag TAG Add new TAG to this check-in ** --cancel TAG Cancel TAG from this check-in ** --branch NAME Rename branch of check-in to NAME ** --hide Hide branch starting from this check-in ** --close Mark this "leaf" as closed ** -n|--dry-run Print control artifact, but make no changes ** --date-override DATETIME Set the change time on the control artifact ** --user-override USER Set the user name on the control artifact ** ** DATETIME may be "now" or "YYYY-MM-DDTHH:MM:SS.SSS". If in |
| ︙ | ︙ | |||
3525 3526 3527 3528 3529 3530 3531 | Blob ctrl; Blob comment; char *zNow; int nTags, nCancels; int i; Stmt q; | < | 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 |
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);
if( zNewBrColor ){
|
| ︙ | ︙ | |||
3686 3687 3688 3689 3690 3691 3692 |
db_column_text(&q,2),
db_column_text(&q,3));
}
db_finalize(&q);
}
#if INTERFACE
| | | 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 3719 |
db_column_text(&q,2),
db_column_text(&q,3));
}
db_finalize(&q);
}
#if INTERFACE
/*
** Description of a check-in relative to an earlier, tagged check-in.
*/
typedef struct CommitDescr {
char *zRelTagname; /* Tag name on the relative check-in */
int nCommitsSince; /* Number of commits since then */
char *zCommitHash; /* Hash of the described check-in */
int isDirty; /* Working directory has uncommitted changes */
|
| ︙ | ︙ | |||
3804 3805 3806 3807 3808 3809 3810 | ** Usage: %fossil describe ?VERSION? ?OPTIONS? ** ** Provide a description of the given VERSION by showing a non-propagating ** tag of the youngest tagged ancestor, followed by the number of commits ** since that, and the short hash of VERSION. Only tags applied to a single ** check-in are considered. ** | | < | 3823 3824 3825 3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 |
** Usage: %fossil describe ?VERSION? ?OPTIONS?
**
** Provide a description of the given VERSION by showing a non-propagating
** tag of the youngest tagged ancestor, followed by the number of commits
** since that, and the short hash of VERSION. Only tags applied to a single
** check-in are considered.
**
** If no VERSION is provided, describe the currently checked-out version.
**
** If VERSION and the found ancestor refer to the same commit, the last two
** components are omitted, unless --long is provided. When no fitting tagged
** ancestor is found, show only the short hash of VERSION.
**
** Options:
** --digits Display so many hex digits of the hash
** (default: the larger of 6 and the 'hash-digit' setting)
** -d|--dirty Show whether there are changes to be committed
** --long Always show all three components
** --match GLOB Consider only non-propagating tags matching GLOB
*/
void describe_cmd(void){
|
| ︙ | ︙ | |||
3846 3847 3848 3849 3850 3851 3852 |
if( g.argc<3 ){
zName = "current";
}else{
zName = g.argv[2];
}
if( bDirtyFlag ){
| | | 3864 3865 3866 3867 3868 3869 3870 3871 3872 3873 3874 3875 3876 3877 3878 |
if( g.argc<3 ){
zName = "current";
}else{
zName = g.argv[2];
}
if( bDirtyFlag ){
if ( g.argc>=3 ) fossil_fatal("cannot use --dirty with specific check-in");
}
switch( describe_commit(zName, zMatchGlob, &descr) ){
case -1:
fossil_fatal("commit %s does not exist", zName);
break;
case -2:
|
| ︙ | ︙ |
Changes to src/interwiki.c.
| ︙ | ︙ | |||
292 293 294 295 296 297 298 |
blob_appendf(out,"</table></blockquote>\n");
}else{
blob_appendf(out,"<i>None</i></blockquote>\n");
}
}
/*
| | | | 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 |
blob_appendf(out,"</table></blockquote>\n");
}else{
blob_appendf(out,"<i>None</i></blockquote>\n");
}
}
/*
** WEBPAGE: intermap
**
** View and modify the interwiki tag map or "intermap".
** This page is visible to administrators only.
*/
void interwiki_page(void){
Stmt q;
int n = 0;
const char *z;
const char *zTag = "";
const char *zBase = "";
const char *zHash = "";
const char *zWiki = "";
char *zErr = 0;
login_check_credentials();
if( !g.perm.Read && !g.perm.RdWiki && ~g.perm.RdTkt ){
login_needed(0);
return;
}
if( g.perm.Setup && P("submit")!=0 && cgi_csrf_safe(2) ){
zTag = PT("tag");
zBase = PT("base");
zHash = PT("hash");
zWiki = PT("wiki");
if( zTag==0 || zTag[0]==0 || !interwiki_valid_name(zTag) ){
zErr = mprintf("Not a valid interwiki tag name: \"%s\"", zTag?zTag : "");
}else if( zBase==0 || zBase[0]==0 ){
|
| ︙ | ︙ |
Changes to src/json.c.
| ︙ | ︙ | |||
152 153 154 155 156 157 158 |
C(STMT_PREP,"Statement preparation failed");
C(STMT_BIND,"Statement parameter binding failed");
C(STMT_EXEC,"Statement execution/stepping failed");
C(DB_LOCKED,"Database is locked");
C(DB_NEEDS_REBUILD,"Fossil repository needs to be rebuilt");
C(DB_NOT_FOUND,"Fossil repository db file could not be found.");
C(DB_NOT_VALID, "Fossil repository db file is not valid.");
| | | 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 |
C(STMT_PREP,"Statement preparation failed");
C(STMT_BIND,"Statement parameter binding failed");
C(STMT_EXEC,"Statement execution/stepping failed");
C(DB_LOCKED,"Database is locked");
C(DB_NEEDS_REBUILD,"Fossil repository needs to be rebuilt");
C(DB_NOT_FOUND,"Fossil repository db file could not be found.");
C(DB_NOT_VALID, "Fossil repository db file is not valid.");
C(DB_NEEDS_CHECKOUT, "Command requires a local check-out.");
#undef C
default:
return "Unknown Error";
}
}
/*
|
| ︙ | ︙ | |||
286 287 288 289 290 291 292 | cson_value * v; char * zStr; va_list vargs; va_start(vargs,fmt); zStr = vmprintf(fmt,vargs); va_end(vargs); v = cson_value_new_string(zStr, strlen(zStr)); | | | 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 |
cson_value * v;
char * zStr;
va_list vargs;
va_start(vargs,fmt);
zStr = vmprintf(fmt,vargs);
va_end(vargs);
v = cson_value_new_string(zStr, strlen(zStr));
fossil_free(zStr);
return v;
}
cson_value * json_new_int( i64 v ){
return cson_value_new_integer((cson_int_t)v);
}
|
| ︙ | ︙ | |||
628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 |
** In CLI mode pResponse is sent to stdout immediately. In HTTP
** mode pResponse replaces any current CGI content but cgi_reply()
** is not called to flush the output.
**
** If g.json.jsonp is not NULL then the content type is set to
** text/javascript and the output is wrapped in a jsonp
** wrapper.
*/
void json_send_response( cson_value const * pResponse ){
assert( NULL != pResponse );
if( g.isHTTP ){
cgi_reset_content();
if( g.json.jsonp ){
cgi_set_content_type("text/javascript");
cgi_printf("%s(",g.json.jsonp);
}
cson_output( pResponse, cson_data_dest_cgi, NULL, &g.json.outOpt );
| > > > > > > > | 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 |
** In CLI mode pResponse is sent to stdout immediately. In HTTP
** mode pResponse replaces any current CGI content but cgi_reply()
** is not called to flush the output.
**
** If g.json.jsonp is not NULL then the content type is set to
** text/javascript and the output is wrapped in a jsonp
** wrapper.
**
** This function works only the first time it is called. It "should
** not" ever be called more than once but certain calling
** constellations might trigger that, in which case the second and
** subsequent calls are no-ops.
*/
void json_send_response( cson_value const * pResponse ){
static int once = 0;
assert( NULL != pResponse );
if( once++ ) return;
if( g.isHTTP ){
cgi_reset_content();
if( g.json.jsonp ){
cgi_set_content_type("text/javascript");
cgi_printf("%s(",g.json.jsonp);
}
cson_output( pResponse, cson_data_dest_cgi, NULL, &g.json.outOpt );
|
| ︙ | ︙ | |||
842 843 844 845 846 847 848 |
*/
va_list vargs;
char * msg;
va_start(vargs,fmt);
msg = vmprintf(fmt,vargs);
va_end(vargs);
cson_object_set(obj,"text", cson_value_new_string(msg,strlen(msg)));
| | | 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 |
*/
va_list vargs;
char * msg;
va_start(vargs,fmt);
msg = vmprintf(fmt,vargs);
va_end(vargs);
cson_object_set(obj,"text", cson_value_new_string(msg,strlen(msg)));
fossil_free(msg);
}
}
/*
** Splits zStr (which must not be NULL) into tokens separated by the
** given separator character. If doDeHttp is true then each element
** will be passed through dehttpize(), otherwise they are used
|
| ︙ | ︙ | |||
1621 1622 1623 1624 1625 1626 1627 |
** Sets g.json.resultCode and g.zErrMsg, but does not report the error
** via json_err(). Returns the code passed to it.
**
** code must be in the inclusive range 1000..9999.
*/
int json_set_err( int code, char const * fmt, ... ){
assert( (code>=1000) && (code<=9999) );
| | | 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 |
** Sets g.json.resultCode and g.zErrMsg, but does not report the error
** via json_err(). Returns the code passed to it.
**
** code must be in the inclusive range 1000..9999.
*/
int json_set_err( int code, char const * fmt, ... ){
assert( (code>=1000) && (code<=9999) );
fossil_free(g.zErrMsg);
g.json.resultCode = code;
if(!fmt || !*fmt){
g.zErrMsg = mprintf("%s", json_err_cstr(code));
}else{
va_list vargs;
char * msg;
va_start(vargs,fmt);
|
| ︙ | ︙ | |||
1769 1770 1771 1772 1773 1774 1775 |
cson_value * json_tags_for_checkin_rid(int rid, int propagatingOnly){
cson_value * v = NULL;
char * tags = info_tags_of_checkin(rid, propagatingOnly);
if(tags){
if(*tags){
v = json_string_split2(tags,',',0);
}
| | | 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 |
cson_value * json_tags_for_checkin_rid(int rid, int propagatingOnly){
cson_value * v = NULL;
char * tags = info_tags_of_checkin(rid, propagatingOnly);
if(tags){
if(*tags){
v = json_string_split2(tags,',',0);
}
fossil_free(tags);
}
return v;
}
/*
** Returns a "new" value representing the boolean value of zVal
** (false if zVal is NULL). Note that cson does not really allocate
|
| ︙ | ︙ | |||
1791 1792 1793 1794 1795 1796 1797 |
: cson_value_false();
}
/*
** Impl of /json/resultCodes
**
*/
| | | 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 |
: cson_value_false();
}
/*
** Impl of /json/resultCodes
**
*/
cson_value * json_page_resultCodes(void){
cson_array * list = cson_new_array();
cson_object * obj = NULL;
cson_string * kRC;
cson_string * kSymbol;
cson_string * kNumber;
cson_string * kDesc;
cson_array_reserve( list, 35 );
|
| ︙ | ︙ | |||
1858 1859 1860 1861 1862 1863 1864 | /* ** /json/version implementation. ** ** Returns the payload object (owned by the caller). */ | | | 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 |
/*
** /json/version implementation.
**
** Returns the payload object (owned by the caller).
*/
cson_value * json_page_version(void){
cson_value * jval = NULL;
cson_object * jobj = NULL;
jval = cson_value_new_object();
jobj = cson_value_get_object(jval);
#define FSET(X,K) cson_object_set( jobj, K, cson_value_new_string(X,strlen(X)))
FSET(MANIFEST_UUID,"manifestUuid");
FSET(MANIFEST_VERSION,"manifestVersion");
|
| ︙ | ︙ | |||
1912 1913 1914 1915 1916 1917 1918 | ** ** Returned object contains details about the "capabilities" of the ** current user (what he may/may not do). ** ** This is primarily intended for debuggering, but may have ** a use in client code. (?) */ | | | 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 |
**
** Returned object contains details about the "capabilities" of the
** current user (what he may/may not do).
**
** This is primarily intended for debuggering, but may have
** a use in client code. (?)
*/
cson_value * json_page_cap(void){
cson_value * payload = cson_value_new_object();
cson_value * sub = cson_value_new_object();
Stmt q;
cson_object * obj = cson_value_get_object(payload);
db_prepare(&q, "SELECT login, cap FROM user WHERE uid=%d", g.userUid);
if( db_step(&q)==SQLITE_ROW ){
/* reminder: we don't use g.zLogin because it's 0 for the guest
|
| ︙ | ︙ | |||
1979 1980 1981 1982 1983 1984 1985 | return payload; } /* ** Implementation of the /json/stat page/command. ** */ | | | 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 |
return payload;
}
/*
** Implementation of the /json/stat page/command.
**
*/
cson_value * json_page_stat(void){
i64 t, fsize;
int n, m;
int full;
enum { BufLen = 1000 };
char zBuf[BufLen];
cson_value * jv = NULL;
cson_object * jo = NULL;
|
| ︙ | ︙ | |||
2004 2005 2006 2007 2008 2009 2010 |
#define SETBUF(O,K) cson_object_set(O, K, cson_value_new_string(zBuf, strlen(zBuf)));
jv = cson_value_new_object();
jo = cson_value_get_object(jv);
zTmp = db_get("project-name",NULL);
cson_object_set(jo, "projectName", json_new_string(zTmp));
| | | | 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 |
#define SETBUF(O,K) cson_object_set(O, K, cson_value_new_string(zBuf, strlen(zBuf)));
jv = cson_value_new_object();
jo = cson_value_get_object(jv);
zTmp = db_get("project-name",NULL);
cson_object_set(jo, "projectName", json_new_string(zTmp));
fossil_free(zTmp);
zTmp = db_get("project-description",NULL);
cson_object_set(jo, "projectDescription", json_new_string(zTmp));
fossil_free(zTmp);
zTmp = NULL;
fsize = file_size(g.zRepositoryName, ExtFILE);
cson_object_set(jo, "repositorySize",
cson_value_new_integer((cson_int_t)fsize));
if(full){
n = db_int(0, "SELECT count(*) FROM blob");
|
| ︙ | ︙ | |||
2159 2160 2161 2162 2163 2164 2165 | } } /* ** Impl of /json/rebuild. Requires admin privileges. */ | | | 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 |
}
}
/*
** Impl of /json/rebuild. Requires admin privileges.
*/
static cson_value * json_page_rebuild(void){
if( !g.perm.Admin ){
json_set_err(FSL_JSON_E_DENIED,"Requires 'a' privileges.");
return NULL;
}else{
/* Reminder: the db_xxx() ops "should" fail via the fossil core
error handlers, which will cause a JSON error and exit(). i.e. we
don't handle the errors here. TODO: confirm that all these db
|
| ︙ | ︙ | |||
2185 2186 2187 2188 2189 2190 2191 |
return NULL;
}
}
/*
** Impl of /json/g. Requires admin/setup rights.
*/
| | | | | | | | | | | | | | | | | 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 |
return NULL;
}
}
/*
** Impl of /json/g. Requires admin/setup rights.
*/
static cson_value * json_page_g(void){
if(!g.perm.Admin || !g.perm.Setup){
json_set_err(FSL_JSON_E_DENIED,
"Requires 'a' or 's' privileges.");
return NULL;
}
return json_g_to_json();
}
/* Impl in json_login.c. */
cson_value * json_page_anon_password(void);
/* Impl in json_artifact.c. */
cson_value * json_page_artifact(void);
/* Impl in json_branch.c. */
cson_value * json_page_branch(void);
/* Impl in json_diff.c. */
cson_value * json_page_diff(void);
/* Impl in json_dir.c. */
cson_value * json_page_dir(void);
/* Impl in json_login.c. */
cson_value * json_page_login(void);
/* Impl in json_login.c. */
cson_value * json_page_logout(void);
/* Impl in json_query.c. */
cson_value * json_page_query(void);
/* Impl in json_report.c. */
cson_value * json_page_report(void);
/* Impl in json_tag.c. */
cson_value * json_page_tag(void);
/* Impl in json_user.c. */
cson_value * json_page_user(void);
/* Impl in json_config.c. */
cson_value * json_page_config(void);
/* Impl in json_finfo.c. */
cson_value * json_page_finfo(void);
/* Impl in json_status.c. */
cson_value * json_page_status(void);
/*
** Mapping of names to JSON pages/commands. Each name is a subpath of
** /json (in CGI mode) or a subcommand of the json command in CLI mode
*/
static const JsonPageDef JsonPageDefs[] = {
/* please keep alphabetically sorted (case-insensitive) for maintenance reasons. */
|
| ︙ | ︙ | |||
2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 |
{"HAI",json_page_version,0},
{"login",json_page_login,0},
{"logout",json_page_logout,0},
{"query",json_page_query,0},
{"rebuild",json_page_rebuild,0},
{"report", json_page_report, 0},
{"resultCodes", json_page_resultCodes,0},
{"stat",json_page_stat,0},
{"status", json_page_status, 0},
{"tag", json_page_tag,0},
/*{"ticket", json_page_nyi,0},*/
{"timeline", json_page_timeline,0},
{"user",json_page_user,0},
{"version",json_page_version,0},
| > | 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 |
{"HAI",json_page_version,0},
{"login",json_page_login,0},
{"logout",json_page_logout,0},
{"query",json_page_query,0},
{"rebuild",json_page_rebuild,0},
{"report", json_page_report, 0},
{"resultCodes", json_page_resultCodes,0},
{"settings",json_page_settings,0},
{"stat",json_page_stat,0},
{"status", json_page_status, 0},
{"tag", json_page_tag,0},
/*{"ticket", json_page_nyi,0},*/
{"timeline", json_page_timeline,0},
{"user",json_page_user,0},
{"version",json_page_version,0},
|
| ︙ | ︙ |
Changes to src/json_artifact.c.
| ︙ | ︙ | |||
244 245 246 247 248 249 250 | ** Internal helper which returns: ** ** If the "format" (CLI: -f) flag is set function returns the same as ** json_wiki_get_content_format_flag(), else it returns true (non-0) ** if either the includeContent (HTTP) or -content|-c boolean flags ** (CLI) are set. */ | | | 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 |
** Internal helper which returns:
**
** If the "format" (CLI: -f) flag is set function returns the same as
** json_wiki_get_content_format_flag(), else it returns true (non-0)
** if either the includeContent (HTTP) or -content|-c boolean flags
** (CLI) are set.
*/
static int json_artifact_get_content_format_flag(void){
enum { MagicValue = -9 };
int contentFormat = json_wiki_get_content_format_flag(MagicValue);
if(MagicValue == contentFormat){
contentFormat = json_find_option_bool("includeContent","content","c",0) /* deprecated */ ? -1 : 0;
}
return contentFormat;
}
|
| ︙ | ︙ | |||
396 397 398 399 400 401 402 | return cson_object_value(pay); } /* ** Impl of /json/artifact. This basically just determines the type of ** an artifact and forwards the real work to another function. */ | | | 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 |
return cson_object_value(pay);
}
/*
** Impl of /json/artifact. This basically just determines the type of
** an artifact and forwards the real work to another function.
*/
cson_value * json_page_artifact(void){
cson_object * pay = NULL;
char const * zName = NULL;
char const * zType = NULL;
char const * zUuid = NULL;
cson_value * entry = NULL;
Blob uuid = empty_blob;
int rc;
|
| ︙ | ︙ |
Changes to src/json_branch.c.
| ︙ | ︙ | |||
20 21 22 23 24 25 26 | #include "json_branch.h" #if INTERFACE #include "json_detail.h" #endif | | | | | | 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 |
#include "json_branch.h"
#if INTERFACE
#include "json_detail.h"
#endif
static cson_value * json_branch_list(void);
static cson_value * json_branch_create(void);
/*
** Mapping of /json/branch/XXX commands/paths to callbacks.
*/
static const JsonPageDef JsonPageDefs_Branch[] = {
{"create", json_branch_create, 0},
{"list", json_branch_list, 0},
{"new", json_branch_create, -1/* for compat with non-JSON branch command.*/},
/* Last entry MUST have a NULL name. */
{NULL,NULL,0}
};
/*
** Implements the /json/branch family of pages/commands. Far from
** complete.
**
*/
cson_value * json_page_branch(void){
return json_page_dispatch_helper(&JsonPageDefs_Branch[0]);
}
/*
** Impl for /json/branch/list
**
**
** CLI mode options:
**
** -r|--range X, where X is one of (open,closed,all)
** (only the first letter is significant, default=open)
** -a (same as --range a)
** -c (same as --range c)
**
** HTTP mode options:
**
** "range" GET/POST.payload parameter. FIXME: currently we also use
** POST, but really want to restrict this to POST.payload.
*/
static cson_value * json_branch_list(void){
cson_value * payV;
cson_object * pay;
cson_value * listV;
cson_array * list;
char const * range = NULL;
int branchListFlags = BRL_OPEN_ONLY;
char * sawConversionError = NULL;
|
| ︙ | ︙ | |||
126 127 128 129 130 131 132 |
: 0;
if(zCurrent){
cson_object_set(pay,"current",json_new_string(zCurrent));
}
}
| | | 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 |
: 0;
if(zCurrent){
cson_object_set(pay,"current",json_new_string(zCurrent));
}
}
branch_prepare_list_query(&q, branchListFlags, 0, 0, 0); /* Allow a user? */
cson_object_set(pay,"branches",listV);
while((SQLITE_ROW==db_step(&q))){
cson_value * v = cson_sqlite3_column_to_value(q.pStmt,0);
if(v){
cson_array_append(list,v);
}else if(!sawConversionError){
sawConversionError = mprintf("Column-to-json failed @ %s:%d",
|
| ︙ | ︙ | |||
291 292 293 294 295 296 297 |
md5sum_blob(&branch, &mcksum);
blob_appendf(&branch, "Z %b\n", &mcksum);
brid = content_put_ex(&branch, 0, 0, 0, zOpt->isPrivate);
if( brid==0 ){
fossil_panic("Problem committing manifest: %s", g.zErrMsg);
}
| | | | 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 |
md5sum_blob(&branch, &mcksum);
blob_appendf(&branch, "Z %b\n", &mcksum);
brid = content_put_ex(&branch, 0, 0, 0, zOpt->isPrivate);
if( brid==0 ){
fossil_panic("Problem committing manifest: %s", g.zErrMsg);
}
db_add_unsent(brid);
if( manifest_crosslink(brid, &branch, MC_PERMIT_HOOKS)==0 ){
fossil_panic("%s", g.zErrMsg);
}
assert( blob_is_reset(&branch) );
content_deltify(rootid, &brid, 1, 0);
if( zNewRid ){
*zNewRid = brid;
}
/* Commit */
db_end_transaction(0);
return 0;
}
/*
** Impl of /json/branch/create.
*/
static cson_value * json_branch_create(void){
cson_value * payV = NULL;
cson_object * pay = NULL;
int rc = 0;
BranchCreateOptions opt;
char * zUuid = NULL;
int rid = 0;
if( !g.perm.Write ){
|
| ︙ | ︙ |
Changes to src/json_config.c.
| ︙ | ︙ | |||
19 20 21 22 23 24 25 | #include "config.h" #include "json_config.h" #if INTERFACE #include "json_detail.h" #endif | | | > > > > > > > > > > > > | > > > > > > > > | 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 |
#include "config.h"
#include "json_config.h"
#if INTERFACE
#include "json_detail.h"
#endif
static cson_value * json_config_get(void);
static cson_value * json_config_save(void);
/*
** Mapping of /json/config/XXX commands/paths to callbacks.
*/
static const JsonPageDef JsonPageDefs_Config[] = {
{"get", json_config_get, 0},
{"save", json_config_save, 0},
/* Last entry MUST have a NULL name. */
{NULL,NULL,0}
};
static cson_value * json_settings_get(void);
static cson_value * json_settings_set(void);
/*
** Mapping of /json/settings/XXX commands/paths to callbacks.
*/
static const JsonPageDef JsonPageDefs_Settings[] = {
{"get", json_settings_get, 0},
{"set", json_settings_set, 0},
/* Last entry MUST have a NULL name. */
{NULL,NULL,0}
};
/*
** Implements the /json/config family of pages/commands.
**
*/
cson_value * json_page_config(void){
return json_page_dispatch_helper(&JsonPageDefs_Config[0]);
}
/*
** Implements the /json/settings family of pages/commands.
**
*/
cson_value * json_page_settings(void){
return json_page_dispatch_helper(&JsonPageDefs_Settings[0]);
}
/*
** JSON-internal mapping of config options to config groups. This is
** mostly a copy of the config options in configure.c, but that data
** is private and cannot be re-used directly here.
*/
|
| ︙ | ︙ | |||
103 104 105 106 107 108 109 | }; /* ** Impl of /json/config/get. Requires setup rights. ** */ | | | 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
};
/*
** Impl of /json/config/get. Requires setup rights.
**
*/
static cson_value * json_config_get(void){
cson_object * pay = NULL;
Stmt q = empty_Stmt;
Blob sql = empty_blob;
char const * zName = NULL;
int confMask = 0;
char optSkinBackups = 0;
unsigned int i;
|
| ︙ | ︙ | |||
179 180 181 182 183 184 185 | } /* ** Impl of /json/config/save. ** ** TODOs: */ | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 |
}
/*
** Impl of /json/config/save.
**
** TODOs:
*/
static cson_value * json_config_save(void){
json_set_err(FSL_JSON_E_NYI, NULL);
return NULL;
}
/*
** Impl of /json/settings/get.
*/
static cson_value * json_settings_get(void){
cson_object * pay = cson_new_object(); /* output payload */
int nSetting, i; /* setting count and loop var */
const Setting *aSetting = setting_info(&nSetting);
const char * zRevision = 0; /* revision to look for
versioned settings in */
char * zUuid = 0; /* Resolved UUID of zRevision */
Stmt q = empty_Stmt; /* Config-search query */
Stmt qFoci = empty_Stmt; /* foci query */
if( !g.perm.Read ){
json_set_err( FSL_JSON_E_DENIED, "Fetching settings requires 'o' access." );
return NULL;
}
zRevision = json_find_option_cstr("version",NULL,NULL);
if( 0!=zRevision ){
int rid = name_to_uuid2(zRevision, "ci", &zUuid);
if(rid<=0){
json_set_err(FSL_JSON_E_RESOURCE_NOT_FOUND,
"Cannot find the given version.");
return NULL;
}
db_multi_exec("CREATE VIRTUAL TABLE IF NOT EXISTS "
"temp.foci USING files_of_checkin;");
db_prepare(&qFoci,
"SELECT uuid FROM temp.foci WHERE "
"checkinID=%d AND filename='.fossil-settings/' || :name",
rid);
}
zRevision = 0;
if( g.localOpen ){
db_prepare(&q,
"SELECT 'checkout', value FROM vvar WHERE name=:name"
" UNION ALL "
"SELECT 'repo', value FROM config WHERE name=:name"
);
}else{
db_prepare(&q,
"SELECT 'repo', value FROM config WHERE name=:name"
);
}
for(i=0; i<nSetting; ++i){
const Setting *pSet = &aSetting[i];
cson_object * jSet;
cson_value * pVal = 0, * pSrc = 0;
jSet = cson_new_object();
cson_object_set(pay, pSet->name, cson_object_value(jSet));
cson_object_set(jSet, "versionable", cson_value_new_bool(pSet->versionable));
cson_object_set(jSet, "sensitive", cson_value_new_bool(pSet->sensitive));
cson_object_set(jSet, "defaultValue", (pSet->def && pSet->def[0])
? json_new_string(pSet->def)
: cson_value_null());
if( 0==pSet->sensitive || 0!=g.perm.Setup ){
if( pSet->versionable ){
/* Check to see if this is overridden by a versionable
** settings file */
if( 0!=zUuid ){
/* Attempt to find a versioned setting stored in the given
** check-in version. */
db_bind_text(&qFoci, ":name", pSet->name);
if( SQLITE_ROW==db_step(&qFoci) ){
int frid = fast_uuid_to_rid(db_column_text(&qFoci, 0));
Blob content;
blob_zero(&content);
if( 0!=content_get(frid, &content) ){
pSrc = json_new_string("versioned");
pVal = json_new_string(blob_str(&content));
}
blob_reset(&content);
}
db_reset(&qFoci);
}
if( 0==pSrc && g.localOpen ){
/* Pull value from a checkout-local .fossil-settings/X file,
** if one exists. */
Blob versionedPathname;
blob_zero(&versionedPathname);
blob_appendf(&versionedPathname, "%s.fossil-settings/%s",
g.zLocalRoot, pSet->name);
if( file_size(blob_str(&versionedPathname), ExtFILE)>=0 ){
Blob content;
blob_zero(&content);
blob_read_from_file(&content, blob_str(&versionedPathname), ExtFILE);
pSrc = json_new_string("versioned");
pVal = json_new_string(blob_str(&content));
blob_reset(&content);
}
blob_reset(&versionedPathname);
}
}
if( 0==pSrc ){
/* Setting is not versionable or we had no versioned value, so
** use the value from localdb.vvar or repository.config (in
** that order). */
db_bind_text(&q, ":name", pSet->name);
if( SQLITE_ROW==db_step(&q) ){
pSrc = json_new_string(db_column_text(&q, 0));
pVal = json_new_string(db_column_text(&q, 1));
}
db_reset(&q);
}
}
cson_object_set(jSet, "valueSource", pSrc ? pSrc : cson_value_null());
cson_object_set(jSet, "value", pVal ? pVal : cson_value_null());
}/*aSetting loop*/
db_finalize(&q);
db_finalize(&qFoci);
fossil_free(zUuid);
return cson_object_value(pay);
}
/*
** Impl of /json/settings/set.
**
** Input payload is an object mapping setting names to values. All
** values are set in the repository.config table. It has no response
** payload.
*/
static cson_value * json_settings_set(void){
Stmt q = empty_Stmt; /* Config-set query */
cson_object_iterator objIter = cson_object_iterator_empty;
cson_kvp * pKvp;
int nErr = 0, nProp = 0;
if( 0==g.perm.Setup ){
json_set_err( FSL_JSON_E_DENIED, "Setting settings requires 's' access." );
return NULL;
}
else if( 0==g.json.reqPayload.o ){
json_set_err(FSL_JSON_E_MISSING_ARGS,
"Missing payload of setting-to-value mappings.");
return NULL;
}
db_unprotect(PROTECT_CONFIG);
db_prepare(&q,
"INSERT OR REPLACE INTO config (name, value, mtime) "
"VALUES(:name, :value, CAST(strftime('%%s') AS INT))"
);
db_begin_transaction();
cson_object_iter_init( g.json.reqPayload.o, &objIter );
while( (pKvp = cson_object_iter_next(&objIter)) ){
char const * zKey = cson_string_cstr( cson_kvp_key(pKvp) );
cson_value * pVal;
const Setting *pSetting = db_find_setting( zKey, 0 );
if( 0==pSetting ){
nErr = json_set_err(FSL_JSON_E_INVALID_ARGS,
"Unknown setting: %s", zKey);
break;
}
pVal = cson_kvp_value(pKvp);
switch( cson_value_type_id(pVal) ){
case CSON_TYPE_NULL:
db_multi_exec("DELETE FROM config WHERE name=%Q", pSetting->name);
continue;
case CSON_TYPE_BOOL:
db_bind_int(&q, ":value", cson_value_get_bool(pVal) ? 1 : 0);
break;
case CSON_TYPE_INTEGER:
db_bind_int64(&q, ":value", cson_value_get_integer(pVal));
break;
case CSON_TYPE_DOUBLE:
db_bind_double(&q, ":value", cson_value_get_double(pVal));
break;
case CSON_TYPE_STRING:
db_bind_text(&q, ":value", cson_value_get_cstr(pVal));
break;
default:
nErr = json_set_err(FSL_JSON_E_USAGE,
"Invalid value type for setting '%s'.",
pSetting->name);
break;
}
if( 0!=nErr ) break;
db_bind_text(&q, ":name", zKey);
db_step(&q);
db_reset(&q);
++nProp;
}
db_finalize(&q);
if( 0==nErr && 0==nProp ){
nErr = json_set_err(FSL_JSON_E_INVALID_ARGS,
"Payload contains no settings to set.");
}
db_end_transaction(nErr);
db_protect_pop();
return NULL;
}
#endif /* FOSSIL_ENABLE_JSON */
|
Changes to src/json_detail.h.
| ︙ | ︙ | |||
147 148 149 150 151 152 153 | ** It is imperative that NO callback functions EVER output ANYTHING to ** stdout, as that will effectively corrupt any JSON output, and ** almost certainly will corrupt any HTTP response headers. Output ** sent to stderr ends up in my apache log, so that might be useful ** for debugging in some cases, but no such code should be left ** enabled for non-debugging builds. */ | | | 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 | ** It is imperative that NO callback functions EVER output ANYTHING to ** stdout, as that will effectively corrupt any JSON output, and ** almost certainly will corrupt any HTTP response headers. Output ** sent to stderr ends up in my apache log, so that might be useful ** for debugging in some cases, but no such code should be left ** enabled for non-debugging builds. */ typedef cson_value * (*fossil_json_f)(void); /* ** Holds name-to-function mappings for JSON page/command dispatching. ** ** Internally we model page dispatching lists as arrays of these ** objects, where the final entry in the array has a NULL name value ** to act as the end-of-list sentinel. |
| ︙ | ︙ | |||
258 259 260 261 262 263 264 | ** b) We are running in JSON CLI mode, but no POST data has been fed ** in. ** ** Whether or not we need to take args from CLI or POST data makes a ** difference in argument/parameter handling in many JSON routines, ** and thus this distinction. */ | | | 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 |
** b) We are running in JSON CLI mode, but no POST data has been fed
** in.
**
** Whether or not we need to take args from CLI or POST data makes a
** difference in argument/parameter handling in many JSON routines,
** and thus this distinction.
*/
int fossil_has_json(void);
enum json_get_changed_files_flags {
json_get_changed_files_ELIDE_PARENT = 1 << 0
};
#endif /* !defined(_RC_COMPILE_) */
#endif/*FOSSIL_JSON_DETAIL_H_INCLUDED*/
#endif /* FOSSIL_ENABLE_JSON */
|
Changes to src/json_diff.c.
| ︙ | ︙ | |||
81 82 83 84 85 86 87 | ** v1=1st version to diff ** v2=2nd version to diff ** ** Can come from GET, POST.payload, CLI -v1/-v2 or as positional ** parameters following the command name (in HTTP and CLI modes). ** */ | | | 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
** v1=1st version to diff
** v2=2nd version to diff
**
** Can come from GET, POST.payload, CLI -v1/-v2 or as positional
** parameters following the command name (in HTTP and CLI modes).
**
*/
cson_value * json_page_diff(void){
cson_object * pay = NULL;
cson_value * v = NULL;
char const * zFrom;
char const * zTo;
int nContext = 0;
char doSBS;
char doHtml;
|
| ︙ | ︙ |
Changes to src/json_dir.c.
| ︙ | ︙ | |||
19 20 21 22 23 24 25 | #include "config.h" #include "json_dir.h" #if INTERFACE #include "json_detail.h" #endif | | | | | 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 |
#include "config.h"
#include "json_dir.h"
#if INTERFACE
#include "json_detail.h"
#endif
static cson_value * json_page_dir_list(void);
/*
** Mapping of /json/wiki/XXX commands/paths to callbacks.
*/
#if 0 /* TODO: Not used? */
static const JsonPageDef JsonPageDefs_Dir[] = {
/* Last entry MUST have a NULL name. */
{NULL,NULL,0}
};
#endif
#if 0 /* TODO: Not used? */
static char const * json_dir_path_extra(void){
static char const * zP = NULL;
if( !zP ){
zP = g.zExtra;
while(zP && *zP && ('/'==*zP)){
++zP;
}
}
return zP;
}
#endif
/*
** Impl of /json/dir. 98% of it was taken directly
** from browse.c::page_dir()
*/
static cson_value * json_page_dir_list(void){
cson_object * zPayload = NULL; /* return value */
cson_array * zEntries = NULL; /* accumulated list of entries. */
cson_object * zEntry = NULL; /* a single dir/file entry. */
cson_array * keyStore = NULL; /* garbage collector for shared strings. */
cson_string * zKeyName = NULL;
cson_string * zKeySize = NULL;
cson_string * zKeyIsDir = NULL;
|
| ︙ | ︙ | |||
279 280 281 282 283 284 285 | return cson_object_value(zPayload); } /* ** Implements the /json/dir family of pages/commands. ** */ | | | 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 |
return cson_object_value(zPayload);
}
/*
** Implements the /json/dir family of pages/commands.
**
*/
cson_value * json_page_dir(void){
#if 1
return json_page_dir_list();
#else
return json_page_dispatch_helper(&JsonPageDefs_Dir[0]);
#endif
}
#endif /* FOSSIL_ENABLE_JSON */
|
Changes to src/json_finfo.c.
| ︙ | ︙ | |||
23 24 25 26 27 28 29 | #include "json_detail.h" #endif /* ** Implements the /json/finfo page/command. ** */ | | | | 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 |
#include "json_detail.h"
#endif
/*
** Implements the /json/finfo page/command.
**
*/
cson_value * json_page_finfo(void){
cson_object * pay = NULL;
cson_array * checkins = NULL;
char const * zFilename = NULL;
Blob sql = empty_blob;
Stmt q = empty_Stmt;
char const * zAfter = NULL;
char const * zBefore = NULL;
int limit = -1;
int currentRow = 0;
char const * zCheckin = NULL;
signed char sort = -1;
if(!g.perm.Read){
json_set_err(FSL_JSON_E_DENIED,"Requires 'o' privileges.");
return NULL;
}
json_warn( FSL_JSON_W_UNKNOWN, "Achtung: the output of the finfo command is up for change.");
/* For the "name" argument we have to jump through some hoops to make sure that we don't
|
| ︙ | ︙ |
Changes to src/json_login.c.
| ︙ | ︙ | |||
24 25 26 27 28 29 30 | #endif /* ** Implementation of the /json/login page. ** */ | | | 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
#endif
/*
** Implementation of the /json/login page.
**
*/
cson_value * json_page_login(void){
char preciseErrors = /* if true, "complete" JSON error codes are used,
else they are "dumbed down" to a generic login
error code.
*/
#if 1
g.json.errorDetailParanoia ? 0 : 1
#else
|
| ︙ | ︙ | |||
179 180 181 182 183 184 185 | } } /* ** Impl of /json/logout. ** */ | | | 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 |
}
}
/*
** Impl of /json/logout.
**
*/
cson_value * json_page_logout(void){
cson_value const *token = g.json.authToken;
/* Remember that json_bootstrap_late() replaces the login cookie
with the JSON auth token if the request contains it. If the
request is missing the auth token then this will fetch fossil's
original cookie. Either way, it's what we want :).
We require the auth token to avoid someone maliciously
|
| ︙ | ︙ | |||
205 206 207 208 209 210 211 | } return json_page_whoami(); } /* ** Implementation of the /json/anonymousPassword page. */ | | | | 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 |
}
return json_page_whoami();
}
/*
** Implementation of the /json/anonymousPassword page.
*/
cson_value * json_page_anon_password(void){
cson_value * v = cson_value_new_object();
cson_object * o = cson_value_get_object(v);
unsigned const int seed = captcha_seed();
char const * zCaptcha = captcha_decode(seed);
cson_object_set(o, "seed",
cson_value_new_integer( (cson_int_t)seed )
);
cson_object_set(o, "password",
cson_value_new_string( zCaptcha, strlen(zCaptcha) )
);
return v;
}
/*
** Implements the /json/whoami page/command.
*/
cson_value * json_page_whoami(void){
cson_value * payload = NULL;
cson_object * obj = NULL;
Stmt q;
if(!g.json.authToken && g.userUid==0){
/* assume we just logged out. */
db_prepare(&q, "SELECT login, cap FROM user WHERE login='nobody'");
}
|
| ︙ | ︙ |
Changes to src/json_query.c.
| ︙ | ︙ | |||
36 37 38 39 40 41 42 | ** ** format=string 'a' means each row is an Array of values, 'o' ** (default) creates each row as an Object. ** ** TODO: in CLI mode (only) use -S FILENAME to read the sql ** from a file. */ | | | 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
**
** format=string 'a' means each row is an Array of values, 'o'
** (default) creates each row as an Object.
**
** TODO: in CLI mode (only) use -S FILENAME to read the sql
** from a file.
*/
cson_value * json_page_query(void){
char const * zSql = NULL;
cson_value * payV;
char const * zFmt;
Stmt q = empty_Stmt;
int check;
if(!g.perm.Admin && !g.perm.Setup){
json_set_err(FSL_JSON_E_DENIED,
|
| ︙ | ︙ |
Changes to src/json_report.c.
| ︙ | ︙ | |||
20 21 22 23 24 25 26 | #include "json_report.h" #if INTERFACE #include "json_detail.h" #endif | | | | | | | | 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 |
#include "json_report.h"
#if INTERFACE
#include "json_detail.h"
#endif
static cson_value * json_report_create(void);
static cson_value * json_report_get(void);
static cson_value * json_report_list(void);
static cson_value * json_report_run(void);
static cson_value * json_report_save(void);
/*
** Mapping of /json/report/XXX commands/paths to callbacks.
*/
static const JsonPageDef JsonPageDefs_Report[] = {
{"create", json_report_create, 0},
{"get", json_report_get, 0},
{"list", json_report_list, 0},
{"run", json_report_run, 0},
{"save", json_report_save, 0},
/* Last entry MUST have a NULL name. */
{NULL,NULL,0}
};
/*
** Implementation of the /json/report page.
**
**
*/
cson_value * json_page_report(void){
if(!g.perm.RdTkt && !g.perm.NewTkt ){
json_set_err(FSL_JSON_E_DENIED,
"Requires 'r' or 'n' permissions.");
return NULL;
}
return json_page_dispatch_helper(JsonPageDefs_Report);
}
|
| ︙ | ︙ | |||
75 76 77 78 79 80 81 |
if(arg && fossil_isdigit(*arg)) {
nReport = atoi(arg);
}
}
return nReport;
}
| | | | 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
if(arg && fossil_isdigit(*arg)) {
nReport = atoi(arg);
}
}
return nReport;
}
static cson_value * json_report_create(void){
json_set_err(FSL_JSON_E_NYI, NULL);
return NULL;
}
static cson_value * json_report_get(void){
int nReport;
Stmt q = empty_Stmt;
cson_value * pay = NULL;
if(!g.perm.TktFmt){
json_set_err(FSL_JSON_E_DENIED,
"Requires 't' privileges.");
|
| ︙ | ︙ | |||
120 121 122 123 124 125 126 | db_finalize(&q); return pay; } /* ** Impl of /json/report/list. */ | | | 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
db_finalize(&q);
return pay;
}
/*
** Impl of /json/report/list.
*/
static cson_value * json_report_list(void){
Blob sql = empty_blob;
cson_value * pay = NULL;
if(!g.perm.RdTkt){
json_set_err(FSL_JSON_E_DENIED,
"Requires 'r' privileges.");
return NULL;
}
|
| ︙ | ︙ | |||
156 157 158 159 160 161 162 | ** report=int (CLI: -report # or -r #) is the report number to run. ** ** limit=int (CLI: -limit # or -n #) -n is for compat. with other commands. ** ** format=a|o Specifies result format: a=each row is an arry, o=each ** row is an object. Default=o. */ | | | 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 |
** report=int (CLI: -report # or -r #) is the report number to run.
**
** limit=int (CLI: -limit # or -n #) -n is for compat. with other commands.
**
** format=a|o Specifies result format: a=each row is an arry, o=each
** row is an object. Default=o.
*/
static cson_value * json_report_run(void){
int nReport;
Stmt q = empty_Stmt;
cson_object * pay = NULL;
cson_array * tktList = NULL;
char const * zFmt;
char * zTitle = NULL;
Blob sql = empty_blob;
|
| ︙ | ︙ | |||
253 254 255 256 257 258 259 | pay = NULL; end: return pay ? cson_object_value(pay) : NULL; } | | | 253 254 255 256 257 258 259 260 261 262 263 |
pay = NULL;
end:
return pay ? cson_object_value(pay) : NULL;
}
static cson_value * json_report_save(void){
return NULL;
}
#endif /* FOSSIL_ENABLE_JSON */
|
Changes to src/json_status.c.
| ︙ | ︙ | |||
58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
cson_object_set(oPay, "localRoot",
json_new_string(g.zLocalRoot));
vid = db_lget_int("checkout", 0);
if(!vid){
json_set_err( FSL_JSON_E_UNKNOWN, "Can this even happen?" );
return 0;
}
/* TODO: dupe show_common_info() state */
tmpO = cson_new_object();
cson_object_set(oPay, "checkout", cson_object_value(tmpO));
zTmp = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", vid);
cson_object_set(tmpO, "uuid", json_new_string(zTmp) );
free(zTmp);
| > | 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
cson_object_set(oPay, "localRoot",
json_new_string(g.zLocalRoot));
vid = db_lget_int("checkout", 0);
if(!vid){
json_set_err( FSL_JSON_E_UNKNOWN, "Can this even happen?" );
return 0;
}
vfile_check_signature(vid, 0);
/* TODO: dupe show_common_info() state */
tmpO = cson_new_object();
cson_object_set(oPay, "checkout", cson_object_value(tmpO));
zTmp = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", vid);
cson_object_set(tmpO, "uuid", json_new_string(zTmp) );
free(zTmp);
|
| ︙ | ︙ | |||
91 92 93 94 95 96 97 | #endif /* Now get the list of non-pristine files... */ aFiles = cson_new_array(); cson_object_set( oPay, "files", cson_array_value( aFiles ) ); db_prepare(&q, | | > > < < | 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 |
#endif
/* Now get the list of non-pristine files... */
aFiles = cson_new_array();
cson_object_set( oPay, "files", cson_array_value( aFiles ) );
db_prepare(&q,
"SELECT pathname, deleted, chnged, rid, "
" coalesce(origname!=pathname,0), origname"
" FROM vfile "
" WHERE is_selected(id)"
" AND (chnged OR deleted OR rid=0 OR pathname!=origname) ORDER BY 1"
);
while( db_step(&q)==SQLITE_ROW ){
cson_array *aStatuses = NULL;
const char *zPathname = db_column_text(&q,0);
int isDeleted = db_column_int(&q, 1);
int isChnged = db_column_int(&q,2);
int isNew = db_column_int(&q,3)==0;
int isRenamed = db_column_int(&q,4);
cson_object * oFile;
char const * zStatus = "???";
char * zFullName = mprintf("%s%s", g.zLocalRoot, zPathname);
if( isDeleted ){
zStatus = "deleted";
}else if( isNew ){
zStatus = "new" /* maintenance reminder: MUST come
BEFORE the isChnged checks. */;
}else if( !file_isfile_or_link(zFullName) ){
if( file_access(zFullName, F_OK)==0 ){
zStatus = "notAFile";
++nErr;
}else{
zStatus = "missing";
++nErr;
|
| ︙ | ︙ | |||
135 136 137 138 139 140 141 |
}else if( 1==isChnged ){
if( file_contains_merge_marker(zFullName) ){
zStatus = "conflict";
}else{
zStatus = "edited";
}
}
| < > > > > > > > > > > > > > | > | 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 |
}else if( 1==isChnged ){
if( file_contains_merge_marker(zFullName) ){
zStatus = "conflict";
}else{
zStatus = "edited";
}
}
oFile = cson_new_object();
cson_array_append( aFiles, cson_object_value(oFile) );
if( isRenamed ){
if( *zStatus!='?' ){
aStatuses = cson_new_array();
cson_object_set( oFile, "status", cson_array_value( aStatuses ) );
cson_array_append(aStatuses,
cson_value_new_string(zStatus, strlen(zStatus)));
cson_array_append(aStatuses, cson_value_new_string("renamed", 7));
}else{
zStatus = "renamed";
}
cson_object_set( oFile, "priorName",
cson_sqlite3_column_to_value(q.pStmt,5));
}
/* optimization potential: move these keys into cson_strings
to take advantage of refcounting. */
cson_object_set( oFile, "name", json_new_string( zPathname ) );
cson_object_set( oFile, "status", aStatuses!=NULL ?
cson_array_value(aStatuses) : json_new_string( zStatus ) );
free(zFullName);
}
cson_object_set( oPay, "errorCount", json_new_int( nErr ) );
db_finalize(&q);
#if 0
|
| ︙ | ︙ |
Changes to src/json_tag.c.
| ︙ | ︙ | |||
20 21 22 23 24 25 26 | #include "json_tag.h" #if INTERFACE #include "json_detail.h" #endif | | | | | | | | 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 |
#include "json_tag.h"
#if INTERFACE
#include "json_detail.h"
#endif
static cson_value * json_tag_add(void);
static cson_value * json_tag_cancel(void);
static cson_value * json_tag_find(void);
static cson_value * json_tag_list(void);
/*
** Mapping of /json/tag/XXX commands/paths to callbacks.
*/
static const JsonPageDef JsonPageDefs_Tag[] = {
{"add", json_tag_add, 0},
{"cancel", json_tag_cancel, 0},
{"find", json_tag_find, 0},
{"list", json_tag_list, 0},
/* Last entry MUST have a NULL name. */
{NULL,NULL,0}
};
/*
** Implements the /json/tag family of pages/commands.
**
*/
cson_value * json_page_tag(void){
return json_page_dispatch_helper(&JsonPageDefs_Tag[0]);
}
/*
** Impl of /json/tag/add.
*/
static cson_value * json_tag_add(void){
cson_value * payV = NULL;
cson_object * pay = NULL;
char const * zName = NULL;
char const * zCheckin = NULL;
char fRaw = 0;
char fPropagate = 0;
char const * zValue = NULL;
|
| ︙ | ︙ | |||
136 137 138 139 140 141 142 | return payV; } /* ** Impl of /json/tag/cancel. */ | | | 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 |
return payV;
}
/*
** Impl of /json/tag/cancel.
*/
static cson_value * json_tag_cancel(void){
char const * zName = NULL;
char const * zCheckin = NULL;
char fRaw = 0;
const char *zPrefix = NULL;
if( !g.perm.Write ){
json_set_err(FSL_JSON_E_DENIED,
|
| ︙ | ︙ | |||
186 187 188 189 190 191 192 | return NULL; } /* ** Impl of /json/tag/find. */ | | | 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 |
return NULL;
}
/*
** Impl of /json/tag/find.
*/
static cson_value * json_tag_find(void){
cson_value * payV = NULL;
cson_object * pay = NULL;
cson_value * listV = NULL;
cson_array * list = NULL;
char const * zName = NULL;
char const * zType = NULL;
char const * zType2 = NULL;
|
| ︙ | ︙ | |||
321 322 323 324 325 326 327 | /* ** Impl for /json/tag/list ** ** TODOs: ** ** Add -type TYPE (ci, w, e, t) */ | | | 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 |
/*
** Impl for /json/tag/list
**
** TODOs:
**
** Add -type TYPE (ci, w, e, t)
*/
static cson_value * json_tag_list(void){
cson_value * payV = NULL;
cson_object * pay = NULL;
cson_value const * tagsVal = NULL;
char const * zCheckin = NULL;
char fRaw = 0;
char fTicket = 0;
Stmt q = empty_Stmt;
|
| ︙ | ︙ |
Changes to src/json_timeline.c.
| ︙ | ︙ | |||
20 21 22 23 24 25 26 | #include "config.h" #include "json_timeline.h" #if INTERFACE #include "json_detail.h" #endif | | | | | 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
#include "config.h"
#include "json_timeline.h"
#if INTERFACE
#include "json_detail.h"
#endif
static cson_value * json_timeline_branch(void);
static cson_value * json_timeline_ci(void);
static cson_value * json_timeline_ticket(void);
/*
** Mapping of /json/timeline/XXX commands/paths to callbacks.
*/
static const JsonPageDef JsonPageDefs_Timeline[] = {
/* the short forms are only enabled in CLI mode, to avoid
that we end up with HTTP clients using 3 different names
for the same requests.
|
| ︙ | ︙ | |||
47 48 49 50 51 52 53 | /* ** Implements the /json/timeline family of pages/commands. Far from ** complete. ** */ | | | 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
/*
** Implements the /json/timeline family of pages/commands. Far from
** complete.
**
*/
cson_value * json_page_timeline(void){
#if 0
/* The original timeline code does not require 'h' access,
but it arguably should. For JSON mode i think one could argue
that History permissions are required.
*/
if(! g.perm.Hyperlink && !g.perm.Read ){
json_set_err(FSL_JSON_E_DENIED, "Timeline requires 'h' or 'o' access.");
|
| ︙ | ︙ | |||
141 142 143 144 145 146 147 | ** ** If payload is not NULL then on success its "tag" or "branch" ** property is set to the tag/branch name found in the request. ** ** Only one of "tag" or "branch" modes will work at a time, and if ** both are specified, which one takes precedence is unspecified. */ | | | | 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 |
**
** If payload is not NULL then on success its "tag" or "branch"
** property is set to the tag/branch name found in the request.
**
** Only one of "tag" or "branch" modes will work at a time, and if
** both are specified, which one takes precedence is unspecified.
*/
static signed char json_timeline_add_tag_branch_clause(Blob *pSql,
cson_object * pPayload){
char const * zTag = NULL;
char const * zBranch = NULL;
char const * zMiOnly = NULL;
char const * zUnhide = NULL;
int tagid = 0;
if(! g.perm.Read ){
return 0;
|
| ︙ | ︙ | |||
218 219 220 221 222 223 224 |
** of the "after" ("a") or "before" ("b") environment parameters.
** This function gives "after" precedence over "before", and only
** applies one of them.
**
** Returns -1 if it adds a "before" clause, 1 if it adds
** an "after" clause, and 0 if adds only an order-by clause.
*/
| | | 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 |
** of the "after" ("a") or "before" ("b") environment parameters.
** This function gives "after" precedence over "before", and only
** applies one of them.
**
** Returns -1 if it adds a "before" clause, 1 if it adds
** an "after" clause, and 0 if adds only an order-by clause.
*/
static signed char json_timeline_add_time_clause(Blob *pSql){
char const * zAfter = NULL;
char const * zBefore = NULL;
int rc = 0;
zAfter = json_find_option_cstr("after",NULL,"a");
zBefore = zAfter ? NULL : json_find_option_cstr("before",NULL,"b");
if(zAfter&&*zAfter){
|
| ︙ | ︙ | |||
362 363 364 365 366 367 368 |
cson_object_set(row, "downloadPath", json_new_string(zDownload));
free(zDownload);
}
db_finalize(&q);
return rowsV;
}
| | | 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 |
cson_object_set(row, "downloadPath", json_new_string(zDownload));
free(zDownload);
}
db_finalize(&q);
return rowsV;
}
static cson_value * json_timeline_branch(void){
cson_value * pay = NULL;
Blob sql = empty_blob;
Stmt q = empty_Stmt;
int limit = 0;
if(!g.perm.Read){
json_set_err(FSL_JSON_E_DENIED,
"Requires 'o' permissions.");
|
| ︙ | ︙ | |||
443 444 445 446 447 448 449 | /* ** Implementation of /json/timeline/ci. ** ** Still a few TODOs (like figuring out how to structure ** inheritance info). */ | | | 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 |
/*
** Implementation of /json/timeline/ci.
**
** Still a few TODOs (like figuring out how to structure
** inheritance info).
*/
static cson_value * json_timeline_ci(void){
cson_value * payV = NULL;
cson_object * pay = NULL;
cson_value * tmp = NULL;
cson_value * listV = NULL;
cson_array * list = NULL;
int check = 0;
char verboseFlag;
|
| ︙ | ︙ | |||
524 525 526 527 528 529 530 | return payV; } /* ** Implementation of /json/timeline/event. ** */ | | | 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 |
return payV;
}
/*
** Implementation of /json/timeline/event.
**
*/
cson_value * json_timeline_event(void){
/* This code is 95% the same as json_timeline_ci(), by the way. */
cson_value * payV = NULL;
cson_object * pay = NULL;
cson_array * list = NULL;
int check = 0;
Stmt q = empty_Stmt;
Blob sql = empty_blob;
|
| ︙ | ︙ | |||
580 581 582 583 584 585 586 | return payV; } /* ** Implementation of /json/timeline/wiki. ** */ | | | 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 |
return payV;
}
/*
** Implementation of /json/timeline/wiki.
**
*/
cson_value * json_timeline_wiki(void){
/* This code is 95% the same as json_timeline_ci(), by the way. */
cson_value * payV = NULL;
cson_object * pay = NULL;
cson_array * list = NULL;
int check = 0;
Stmt q = empty_Stmt;
Blob sql = empty_blob;
|
| ︙ | ︙ | |||
641 642 643 644 645 646 647 | return payV; } /* ** Implementation of /json/timeline/ticket. ** */ | | | 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 |
return payV;
}
/*
** Implementation of /json/timeline/ticket.
**
*/
static cson_value * json_timeline_ticket(void){
/* This code is 95% the same as json_timeline_ci(), by the way. */
cson_value * payV = NULL;
cson_object * pay = NULL;
cson_value * tmp = NULL;
cson_value * listV = NULL;
cson_array * list = NULL;
int check = 0;
|
| ︙ | ︙ |
Changes to src/json_user.c.
| ︙ | ︙ | |||
19 20 21 22 23 24 25 | #include "config.h" #include "json_user.h" #if INTERFACE #include "json_detail.h" #endif | | | | | | | 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 |
#include "config.h"
#include "json_user.h"
#if INTERFACE
#include "json_detail.h"
#endif
static cson_value * json_user_get(void);
static cson_value * json_user_list(void);
static cson_value * json_user_save(void);
/*
** Mapping of /json/user/XXX commands/paths to callbacks.
*/
static const JsonPageDef JsonPageDefs_User[] = {
{"save", json_user_save, 0},
{"get", json_user_get, 0},
{"list", json_user_list, 0},
/* Last entry MUST have a NULL name. */
{NULL,NULL,0}
};
/*
** Implements the /json/user family of pages/commands.
**
*/
cson_value * json_page_user(void){
return json_page_dispatch_helper(&JsonPageDefs_User[0]);
}
/*
** Impl of /json/user/list. Requires admin/setup rights.
*/
static cson_value * json_user_list(void){
cson_value * payV = NULL;
Stmt q;
if(!g.perm.Admin && !g.perm.Setup){
json_set_err(FSL_JSON_E_DENIED,
"Requires 'a' or 's' privileges.");
return NULL;
}
|
| ︙ | ︙ | |||
120 121 122 123 124 125 126 | return u; } /* ** Impl of /json/user/get. Requires admin or setup rights. */ | | | 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
return u;
}
/*
** Impl of /json/user/get. Requires admin or setup rights.
*/
static cson_value * json_user_get(void){
cson_value * payV = NULL;
char const * pUser = NULL;
if(!g.perm.Admin && !g.perm.Setup){
json_set_err(FSL_JSON_E_DENIED,
"Requires 'a' or 's' privileges.");
return NULL;
}
|
| ︙ | ︙ | |||
391 392 393 394 395 396 397 | return g.json.resultCode; } /* ** Impl of /json/user/save. */ | | | 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 |
return g.json.resultCode;
}
/*
** Impl of /json/user/save.
*/
static cson_value * json_user_save(void){
/* try to get user info from GET/CLI args and construct
a JSON form of it... */
cson_object * u = cson_new_object();
char const * str = NULL;
int b = -1;
int i = -1;
int uid = -1;
|
| ︙ | ︙ |
Changes to src/json_wiki.c.
| ︙ | ︙ | |||
19 20 21 22 23 24 25 | #include "config.h" #include "json_wiki.h" #if INTERFACE #include "json_detail.h" #endif | | | | | | | | | 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 |
#include "config.h"
#include "json_wiki.h"
#if INTERFACE
#include "json_detail.h"
#endif
static cson_value * json_wiki_create(void);
static cson_value * json_wiki_get(void);
static cson_value * json_wiki_list(void);
static cson_value * json_wiki_preview(void);
static cson_value * json_wiki_save(void);
static cson_value * json_wiki_diff(void);
/*
** Mapping of /json/wiki/XXX commands/paths to callbacks.
*/
static const JsonPageDef JsonPageDefs_Wiki[] = {
{"create", json_wiki_create, 0},
{"diff", json_wiki_diff, 0},
{"get", json_wiki_get, 0},
{"list", json_wiki_list, 0},
{"preview", json_wiki_preview, 0},
{"save", json_wiki_save, 0},
{"timeline", json_timeline_wiki,0},
/* Last entry MUST have a NULL name. */
{NULL,NULL,0}
};
/*
** Implements the /json/wiki family of pages/commands.
**
*/
cson_value * json_page_wiki(void){
return json_page_dispatch_helper(JsonPageDefs_Wiki);
}
/*
** Returns the UUID for the given wiki blob RID, or NULL if not
** found. The returned string is allocated via db_text() and must be
** free()d by the caller.
|
| ︙ | ︙ | |||
242 243 244 245 246 247 248 | } } /* ** Implementation of /json/wiki/get. ** */ | | | 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 |
}
}
/*
** Implementation of /json/wiki/get.
**
*/
static cson_value * json_wiki_get(void){
char const * zPageName;
char const * zSymName = NULL;
int contentFormat = -1;
if( !g.perm.RdWiki && !g.perm.Read ){
json_set_err(FSL_JSON_E_DENIED,
"Requires 'o' or 'j' access.");
return NULL;
|
| ︙ | ︙ | |||
272 273 274 275 276 277 278 | contentFormat = json_wiki_get_content_format_flag(contentFormat); return json_wiki_get_by_name_or_symname( zPageName, zSymName, contentFormat ); } /* ** Implementation of /json/wiki/preview. */ | | | 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 |
contentFormat = json_wiki_get_content_format_flag(contentFormat);
return json_wiki_get_by_name_or_symname( zPageName, zSymName, contentFormat );
}
/*
** Implementation of /json/wiki/preview.
*/
static cson_value * json_wiki_preview(void){
char const * zContent = NULL;
char const * zMime = NULL;
cson_string * sContent = NULL;
cson_value * pay = NULL;
Blob contentOrig = empty_blob;
Blob contentHtml = empty_blob;
if( !g.perm.WrWiki ){
|
| ︙ | ︙ | |||
447 448 449 450 451 452 453 | return payV; } /* ** Implementation of /json/wiki/create. */ | | | | | 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 |
return payV;
}
/*
** Implementation of /json/wiki/create.
*/
static cson_value * json_wiki_create(void){
return json_wiki_create_or_save(1,0);
}
/*
** Implementation of /json/wiki/save.
*/
static cson_value * json_wiki_save(void){
char const createIfNotExists = json_getenv_bool("createIfNotExists",0);
return json_wiki_create_or_save(0,createIfNotExists);
}
/*
** Implementation of /json/wiki/list.
*/
static cson_value * json_wiki_list(void){
cson_value * listV = NULL;
cson_array * list = NULL;
char const * zGlob = NULL;
Stmt q = empty_Stmt;
Blob sql = empty_blob;
char const verbose = json_find_option_bool("verbose",NULL,"v",0);
char fInvert = json_find_option_bool("invert",NULL,"i",0);;
|
| ︙ | ︙ | |||
529 530 531 532 533 534 535 | cson_value_free(listV); listV = NULL; end: db_finalize(&q); return listV; } | | | 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 |
cson_value_free(listV);
listV = NULL;
end:
db_finalize(&q);
return listV;
}
static cson_value * json_wiki_diff(void){
char const * zV1 = NULL;
char const * zV2 = NULL;
cson_object * pay = NULL;
int argPos = g.json.dispatchDepth;
int r1 = 0, r2 = 0;
Manifest * pW1 = NULL, *pW2 = NULL;
Blob w1 = empty_blob, w2 = empty_blob, d = empty_blob;
|
| ︙ | ︙ |
Changes to src/loadctrl.c.
| ︙ | ︙ | |||
63 64 65 66 67 68 69 |
}
#endif
style_set_current_feature("test");
style_header("Server Overload");
@ <h2>The server load is currently too high.
@ Please try again later.</h2>
| | | 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
}
#endif
style_set_current_feature("test");
style_header("Server Overload");
@ <h2>The server load is currently too high.
@ Please try again later.</h2>
@ <p>Current load average: %f(load_average()).<br>
@ Load average limit: %f(mxLoad)</p>
style_finish_page();
cgi_set_status(503,"Server Overload");
cgi_reply();
exit(0);
}
|
Changes to src/login.c.
| ︙ | ︙ | |||
47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
# include <windows.h> /* for Sleep */
# if defined(__MINGW32__) || defined(_MSC_VER)
# define sleep Sleep /* windows does not have sleep, but Sleep */
# endif
#endif
#include <time.h>
/*
** Return the login-group name. Or return 0 if this repository is
** not a member of a login-group.
*/
const char *login_group_name(void){
static const char *zGroup = 0;
| > > > > > > > > > > > > > > > | 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 |
# include <windows.h> /* for Sleep */
# if defined(__MINGW32__) || defined(_MSC_VER)
# define sleep Sleep /* windows does not have sleep, but Sleep */
# endif
#endif
#include <time.h>
/*
** Compute an appropriate Anti-CSRF token into g.zCsrfToken[].
*/
static void login_create_csrf_secret(const char *zSeed){
unsigned char zResult[20];
unsigned int i;
sha1sum_binary(zSeed, zResult);
for(i=0; i<sizeof(g.zCsrfToken)-1; i++){
g.zCsrfToken[i] = "abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"0123456789-/"[zResult[i]%64];
}
g.zCsrfToken[i] = 0;
}
/*
** Return the login-group name. Or return 0 if this repository is
** not a member of a login-group.
*/
const char *login_group_name(void){
static const char *zGroup = 0;
|
| ︙ | ︙ | |||
142 143 144 145 146 147 148 | if( zUsername==0 ) return 0; else if( zPassword==0 ) return 0; else if( zCS==0 ) return 0; else if( fossil_strcmp(zUsername,"anonymous")!=0 ) return 0; zPw = captcha_decode((unsigned int)atoi(zCS)); if( fossil_stricmp(zPw, zPassword)!=0 ) return 0; uid = db_int(0, "SELECT uid FROM user WHERE login='anonymous'" | | > > | | | | | | | | > > > > | 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 |
if( zUsername==0 ) return 0;
else if( zPassword==0 ) return 0;
else if( zCS==0 ) return 0;
else if( fossil_strcmp(zUsername,"anonymous")!=0 ) return 0;
zPw = captcha_decode((unsigned int)atoi(zCS));
if( fossil_stricmp(zPw, zPassword)!=0 ) return 0;
uid = db_int(0, "SELECT uid FROM user WHERE login='anonymous'"
" AND octet_length(pw)>0 AND octet_length(cap)>0");
return uid;
}
/*
** Make sure the accesslog table exists. Create it if it does not
*/
void create_accesslog_table(void){
if( !db_table_exists("repository","accesslog") ){
db_unprotect(PROTECT_READONLY);
db_multi_exec(
"CREATE TABLE IF NOT EXISTS repository.accesslog("
" uname TEXT,"
" ipaddr TEXT,"
" success BOOLEAN,"
" mtime TIMESTAMP"
");"
);
db_protect_pop();
}
}
/*
** Make a record of a login attempt, if login record keeping is enabled.
*/
static void record_login_attempt(
const char *zUsername, /* Name of user logging in */
const char *zIpAddr, /* IP address from which they logged in */
int bSuccess /* True if the attempt was a success */
){
db_unprotect(PROTECT_READONLY);
if( db_get_boolean("access-log", 0) ){
create_accesslog_table();
db_multi_exec(
"INSERT INTO accesslog(uname,ipaddr,success,mtime)"
"VALUES(%Q,%Q,%d,julianday('now'));",
zUsername, zIpAddr, bSuccess
);
}
if( bSuccess ){
alert_user_contact(zUsername);
}
db_protect_pop();
}
/*
** Searches for the user ID matching the given name and password.
** On success it returns a positive value. On error it returns 0.
** On serious (DB-level) error it will probably exit.
**
|
| ︙ | ︙ | |||
202 203 204 205 206 207 208 |
** form of the user's password.
*/
int login_search_uid(const char **pzUsername, const char *zPasswd){
char *zSha1Pw = sha1_shared_secret(zPasswd, *pzUsername, 0);
int uid = db_int(0,
"SELECT uid FROM user"
" WHERE login=%Q"
| | | 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 |
** form of the user's password.
*/
int login_search_uid(const char **pzUsername, const char *zPasswd){
char *zSha1Pw = sha1_shared_secret(zPasswd, *pzUsername, 0);
int uid = db_int(0,
"SELECT uid FROM user"
" WHERE login=%Q"
" AND octet_length(cap)>0 AND octet_length(pw)>0"
" AND login NOT IN ('anonymous','nobody','developer','reader')"
" AND (pw=%Q OR (length(pw)<>40 AND pw=%Q))"
" AND (info NOT LIKE '%%expires 20%%'"
" OR substr(info,instr(lower(info),'expires')+8,10)>datetime('now'))",
*pzUsername, zSha1Pw, zPasswd
);
|
| ︙ | ︙ | |||
502 503 504 505 506 507 508 509 510 511 512 513 514 515 |
int rc;
if( zReferer==0 ) return 0;
zPattern = mprintf("%s/login*", g.zBaseURL);
rc = sqlite3_strglob(zPattern, zReferer)==0;
fossil_free(zPattern);
return rc;
}
/*
** Return TRUE if self-registration is available. If the zNeeded
** argument is not NULL, then only return true if self-registration is
** available and any of the capabilities named in zNeeded are available
** to self-registered users.
*/
| > > > > > > > > > | 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 |
int rc;
if( zReferer==0 ) return 0;
zPattern = mprintf("%s/login*", g.zBaseURL);
rc = sqlite3_strglob(zPattern, zReferer)==0;
fossil_free(zPattern);
return rc;
}
/*
** Return true if users are allowed to reset their own passwords.
*/
int login_self_password_reset_available(void){
if( !db_get_boolean("self-pw-reset",0) ) return 0;
if( !alert_tables_exist() ) return 0;
return 1;
}
/*
** Return TRUE if self-registration is available. If the zNeeded
** argument is not NULL, then only return true if self-registration is
** available and any of the capabilities named in zNeeded are available
** to self-registered users.
*/
|
| ︙ | ︙ | |||
552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 |
char *zSha1Pw;
const char *zIpAddr; /* IP address of requestor */
const int noAnon = P("noanon")!=0;
int rememberMe; /* If true, use persistent cookie, else
session cookie. Toggled per
checkbox. */
login_check_credentials();
fossil_redirect_to_https_if_needed(1);
sqlite3_create_function(g.db, "constant_time_cmp", 2, SQLITE_UTF8, 0,
constant_time_cmp_function, 0, 0);
zUsername = P("u");
zPasswd = P("p");
anonFlag = g.zLogin==0 && PB("anon");
/* Handle log-out requests */
| > > > > > > | > | 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 |
char *zSha1Pw;
const char *zIpAddr; /* IP address of requestor */
const int noAnon = P("noanon")!=0;
int rememberMe; /* If true, use persistent cookie, else
session cookie. Toggled per
checkbox. */
if( P("pwreset")!=0 && login_self_password_reset_available() ){
/* If the "Reset Password" button in the form was pressed, render
** the Request Password Reset page in place of this one. */
login_reqpwreset_page();
return;
}
login_check_credentials();
fossil_redirect_to_https_if_needed(1);
sqlite3_create_function(g.db, "constant_time_cmp", 2, SQLITE_UTF8, 0,
constant_time_cmp_function, 0, 0);
zUsername = P("u");
zPasswd = P("p");
anonFlag = g.zLogin==0 && PB("anon");
/* Handle log-out requests */
if( P("out") && cgi_csrf_safe(2) ){
login_clear_login_data();
redirect_to_g();
return;
}
/* Redirect for create-new-account requests */
if( P("self") ){
cgi_redirectf("%R/register");
return;
}
/* Deal with password-change requests */
if( g.perm.Password && zPasswd
&& (zNew1 = P("n1"))!=0 && (zNew2 = P("n2"))!=0
&& cgi_csrf_safe(2)
){
/* If there is not a "real" login, we cannot change any password. */
if( g.zLogin ){
/* The user requests a password change */
zSha1Pw = sha1_shared_secret(zPasswd, g.zLogin, 0);
if( db_int(1, "SELECT 0 FROM user"
" WHERE uid=%d"
|
| ︙ | ︙ | |||
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 |
;
}else{
char *zNewPw = sha1_shared_secret(zNew1, g.zLogin, 0);
char *zChngPw;
char *zErr;
int rc;
db_unprotect(PROTECT_USER);
db_multi_exec(
"UPDATE user SET pw=%Q WHERE uid=%d", zNewPw, g.userUid
);
zChngPw = mprintf(
"UPDATE user"
" SET pw=shared_secret(%Q,%Q,"
" (SELECT value FROM config WHERE name='project-code'))"
" WHERE login=%Q",
zNew1, g.zLogin, g.zLogin
);
fossil_free(zNewPw);
rc = login_group_sql(zChngPw, "<p>", "</p>\n", &zErr);
db_protect_pop();
if( rc ){
zErrMsg = mprintf("<span class=\"loginError\">%s</span>", zErr);
fossil_free(zErr);
}else{
redirect_to_g();
return;
}
| > > > > > > > > > > > | 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 |
;
}else{
char *zNewPw = sha1_shared_secret(zNew1, g.zLogin, 0);
char *zChngPw;
char *zErr;
int rc;
/* vvvvvvv--- tag-20230106-1 ----vvvvvv
**
** Replicate changes made below to tag-20230106-2
*/
admin_log("password change for user %s", g.zLogin);
db_unprotect(PROTECT_USER);
db_multi_exec(
"UPDATE user SET pw=%Q WHERE uid=%d", zNewPw, g.userUid
);
zChngPw = mprintf(
"UPDATE user"
" SET pw=shared_secret(%Q,%Q,"
" (SELECT value FROM config WHERE name='project-code'))"
" WHERE login=%Q",
zNew1, g.zLogin, g.zLogin
);
fossil_free(zNewPw);
rc = login_group_sql(zChngPw, "<p>", "</p>\n", &zErr);
db_protect_pop();
/*
** ^^^^^^^^--- tag-20230106-1 ----^^^^^^^^^
**
** Replicate changes above to tag-20230106-2
*/
if( rc ){
zErrMsg = mprintf("<span class=\"loginError\">%s</span>", zErr);
fossil_free(zErr);
}else{
redirect_to_g();
return;
}
|
| ︙ | ︙ | |||
703 704 705 706 707 708 709 |
&& db_get_boolean("https-login",0)
){
form_begin(0, "https:%s/login", g.zBaseURL+5);
}else{
form_begin(0, "%R/login");
}
if( zGoto ){
| | | | 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 |
&& db_get_boolean("https-login",0)
){
form_begin(0, "https:%s/login", g.zBaseURL+5);
}else{
form_begin(0, "%R/login");
}
if( zGoto ){
@ <input type="hidden" name="g" value="%h(zGoto)">
}
if( anonFlag ){
@ <input type="hidden" name="anon" value="1">
}
if( g.zLogin ){
@ <p>Currently logged in as <b>%h(g.zLogin)</b>.
@ <input type="submit" name="out" value="Logout"></p>
@ </form>
}else{
unsigned int uSeed = captcha_seed();
|
| ︙ | ︙ | |||
741 742 743 744 745 746 747 |
@ <td class="form_label" id="userlabel1">User ID:</td>
@ <td><input type="text" id="u" aria-labelledby="userlabel1" name="u" \
@ size="30" value="%s(anonFlag?"anonymous":"")"></td>
@ </tr>
@ <tr>
@ <td class="form_label" id="pswdlabel">Password:</td>
@ <td><input aria-labelledby="pswdlabel" type="password" id="p" \
| | > > > > > > | | | 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 |
@ <td class="form_label" id="userlabel1">User ID:</td>
@ <td><input type="text" id="u" aria-labelledby="userlabel1" name="u" \
@ size="30" value="%s(anonFlag?"anonymous":"")"></td>
@ </tr>
@ <tr>
@ <td class="form_label" id="pswdlabel">Password:</td>
@ <td><input aria-labelledby="pswdlabel" type="password" id="p" \
@ name="p" value="" size="30">\
if( zAnonPw && !noAnon ){
captcha_speakit_button(uSeed, "Speak password for \"anonymous\"");
}
@ </td>
@ </tr>
@ <tr>
@ <td></td>
@ <td><input type="checkbox" name="remember" value="1" \
@ id="remember-me" %s(rememberMe ? "checked=\"checked\"" : "")>
@ <label for="remember-me">Remember me?</label></td>
@ </tr>
@ <tr>
@ <td></td>
@ <td><input type="submit" name="in" value="Login">
@ </tr>
if( !noAnon && login_self_register_available(0) ){
@ <tr>
@ <td></td>
@ <td><input type="submit" name="self" value="Create A New Account">
@ </tr>
}
if( login_self_password_reset_available() ){
@ <tr>
@ <td></td>
@ <td><input type="submit" name="pwreset" value="Reset My Password">
@ </tr>
}
@ </table>
if( zAnonPw && !noAnon ){
const char *zDecoded = captcha_decode(uSeed);
int bAutoCaptcha = db_get_boolean("auto-captcha", 0);
char *zCaptcha = captcha_render(zDecoded);
@ <p><input type="hidden" name="cs" value="%u(uSeed)">
@ Visitors may enter <b>anonymous</b> as the user-ID with
@ the 8-character hexadecimal password shown below:</p>
@ <div class="captcha"><table class="captcha"><tr><td>\
@ <pre class="captcha">
@ %h(zCaptcha)
@ </pre></td></tr></table>
if( bAutoCaptcha ) {
@ <input type="button" value="Fill out captcha" id='autofillButton' \
@ data-af='%s(zDecoded)'>
builtin_request_js("login.js");
}
@ </div>
free(zCaptcha);
}
@ </form>
}
|
| ︙ | ︙ | |||
808 809 810 811 812 813 814 |
form_begin(0, "%R/login");
@ <table>
@ <tr><td class="form_label" id="oldpw">Old Password:</td>
@ <td><input aria-labelledby="oldpw" type="password" name="p" \
@ size="30"/></td></tr>
@ <tr><td class="form_label" id="newpw">New Password:</td>
@ <td><input aria-labelledby="newpw" type="password" name="n1" \
| | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 |
form_begin(0, "%R/login");
@ <table>
@ <tr><td class="form_label" id="oldpw">Old Password:</td>
@ <td><input aria-labelledby="oldpw" type="password" name="p" \
@ size="30"/></td></tr>
@ <tr><td class="form_label" id="newpw">New Password:</td>
@ <td><input aria-labelledby="newpw" type="password" name="n1" \
@ size="30"> Suggestion: %z(zRPW)</td></tr>
@ <tr><td class="form_label" id="reppw">Repeat New Password:</td>
@ <td><input aria-labledby="reppw" type="password" name="n2" \
@ size="30"></td></tr>
@ <tr><td></td>
@ <td><input type="submit" value="Change Password"></td></tr>
@ </table>
@ </form>
}
}
style_finish_page();
}
/*
** Construct an appropriate URL suffix for the /resetpw page. The
** suffix will be of the form:
**
** UID-TIMESTAMP-HASH
**
** Where UID and TIMESTAMP are the parameters to this function, and HASH
** is constructed from information that is unique to the user in question
** and which is not publicly available. In particular, the HASH includes
** the existing user password. Thus, in order to construct a URL that can
** change a password, an attacker must know the current password, in which
** case the attacker does not need to construct the URL in order to take
** over the account.
**
** Return a pointer to the resulting string in memory obtained
** from fossil_malloc().
*/
char *login_resetpw_suffix(int uid, i64 timestamp){
char *zHash;
char *zInnerSql;
char *zResult;
extern int sqlite3_shathree_init(sqlite3*,char**,const sqlite3_api_routines*);
if( timestamp<=0 ){ timestamp = time(0); }
sqlite3_shathree_init(g.db, 0, 0);
if( db_table_exists("repository","subscriber") ){
zInnerSql = mprintf(
"SELECT %lld, login, pw, cookie, user.mtime, user.info, subscriberCode"
" FROM user LEFT JOIN subscriber ON suname=login"
" WHERE uid=%d", timestamp, uid);
}else{
zInnerSql = mprintf(
"SELECT %lld, login, pw, cookie, user.mtime, user.info"
" FROM user WHERE uid=%d", timestamp, uid);
}
zHash = db_text(0, "SELECT lower(hex(sha3_query(%Q)))", zInnerSql);
fossil_free(zInnerSql);
zResult = mprintf("%x-%llx-%s", uid, timestamp, zHash);
if( strlen(zHash)<64 || strlen(zResult)<70 ){
/* This should never happen, but if it does, we don't want it to lead
** to a security breach. */
fossil_panic("insecure password reset hash generated\n");
}
fossil_free(zHash);
return zResult;
}
/*
** Check to see if the "name" query parameter is a valid resetpw suffix
** for a user whose password we are allowed to reset. If it is, then return
** the positive integer UID for that user. If the query parameter is not
** valid, return 0.
*/
static int login_resetpw_suffix_is_valid(const char *zName){
int i, j;
int uid;
i64 timestamp;
i64 now;
char *zHash;
if( zName==0 || strlen(zName)<70 ) goto not_valid_suffix;
for(i=0; fossil_isxdigit(zName[i]); i++){}
if( i<1 || zName[i]!='-' ) goto not_valid_suffix;
for(j=i+1; fossil_isxdigit(zName[j]); j++){}
if( j<=i+1 || zName[j]!='-' ) goto not_valid_suffix;
uid = strtol(zName, 0, 16);
if( uid<=0 ) goto not_valid_suffix;
if( !db_exists("SELECT 1 FROM user WHERE uid=%d", uid) ){
goto not_valid_suffix;
}
timestamp = strtoll(&zName[i+1], 0, 16);
now = time(0);
if( timestamp+3600 <= now ) goto not_valid_suffix;
zHash = login_resetpw_suffix(uid,timestamp);
if( fossil_strcmp(zHash, zName)!=0 ){
fossil_free(zHash);
goto not_valid_suffix;
}
fossil_free(zHash);
return uid;
not_valid_suffix:
return 0;
}
/*
** COMMAND: test-resetpw-url
** Usage: fossil test-resetpw-url UID
**
** Generate and verify a /resetpw URL for user UID.
**
** This command is intended for unit testing the login_resetpw_suffix()
** and login_resetpw_suffix_is_valid() functions.
*/
void test_resetpw_url(void){
char *zSuffix;
int uid;
int xuid;
char *zLogin;
int i;
db_find_and_open_repository(0, 0);
verify_all_options();
if( g.argc<3 ){
usage("UID ...");
}
for(i=2; i<g.argc; i++){
uid = atoi(g.argv[i]);
zSuffix = login_resetpw_suffix(uid, 0);
xuid = login_resetpw_suffix_is_valid(zSuffix);
if( xuid>0 ){
zLogin = db_text(0, "SELECT login FROM user WHERE uid=%d", xuid);
}else{
zLogin = 0;
}
fossil_print("/resetpw/%s %d (%s)\n",
zSuffix, xuid, zLogin ? zLogin : "???");
fossil_free(zSuffix);
fossil_free(zLogin);
}
}
/*
** WEBPAGE: resetpw
**
** The URL format must be like this:
**
** /resetpw/UID-TIMESTAMP-HASH
**
** Where UID is the uid of the user whose password is to be reset,
** TIMESTAMP is the unix timestamp when the request was made, and
** HASH is a hash based on UID, TIMESTAMP, and other information that
** is unavailable to an attacher.
**
** With no other arguments, a form is present which allows the user to
** enter a new password. When the SUBMIT button is pressed, a POST request
** back to the same URL that will change the password.
*/
void login_resetpw(void){
const char *zName;
int uid;
char *zRPW;
const char *zNew1, *zNew2;
style_set_current_feature("resetpw");
style_header("Reset Password");
style_adunit_config(ADUNIT_OFF);
zName = PD("name","");
uid = login_resetpw_suffix_is_valid(zName);
if( uid==0 ){
@ <p><span class="loginError">
@ This password-reset URL is invalid, probably because it has expired.
@ Password-reset URLs have a short lifespan.
@ </span></p>
style_finish_page();
sleep(1); /* Introduce a small delay on an invalid suffix as an
** extra defense against search attacks */
return;
}
fossil_redirect_to_https_if_needed(1);
login_set_uid(uid, 0);
if( g.perm.Setup || g.perm.Admin || !g.perm.Password || g.zLogin==0 ){
@ <p><span class="loginError">
@ Cannot change the password for user <b>%h(g.zLogin)</b>.
@ </span></p>
style_finish_page();
return;
}
if( (zNew1 = P("n1"))!=0 && (zNew2 = P("n2"))!=0 ){
if( fossil_strcmp(zNew1,zNew2)!=0 ){
@ <p><span class="loginError">
@ The two copies of your new passwords do not match.
@ Try again.
@ </span></p>
}else{
char *zNewPw = sha1_shared_secret(zNew1, g.zLogin, 0);
char *zChngPw;
char *zErr;
int rc;
/* vvvvvvv--- tag-20230106-2 ----vvvvvv
**
** Replicate changes made below to tag-20230106-1
*/
admin_log("password change for user %s", g.zLogin);
db_unprotect(PROTECT_USER);
db_multi_exec(
"UPDATE user SET pw=%Q WHERE uid=%d", zNewPw, g.userUid
);
zChngPw = mprintf(
"UPDATE user"
" SET pw=shared_secret(%Q,%Q,"
" (SELECT value FROM config WHERE name='project-code'))"
" WHERE login=%Q",
zNew1, g.zLogin, g.zLogin
);
fossil_free(zNewPw);
rc = login_group_sql(zChngPw, "<p>", "</p>\n", &zErr);
db_protect_pop();
/*
** ^^^^^^^^--- tag-20230106-2 ----^^^^^^^^^
**
** Replicate changes above to tag-20230106-1
*/
if( rc ){
@ <p><span class='loginError'>
@ %s(zErr);
@ </span></p>
fossil_free(zErr);
}else{
@ <p>Password changed successfully. Go to the
@ <a href="%R/login?u=%t(g.zLogin)">Login</a> page and log in
@ using the new password to continue.
@ </p>
style_finish_page();
return;
}
}
}
zRPW = fossil_random_password(12);
@ <p>Change Password for user <b>%h(g.zLogin)</b>:</p>
form_begin(0, "%R/resetpw");
@ <input type='hidden' name='name' value='%h(zName)'>
@ <table>
@ <tr><td class="form_label" id="newpw">New Password:</td>
@ <td><input aria-labelledby="newpw" type="password" name="n1" \
@ size="30"> Suggestion: %z(zRPW)</td></tr>
@ <tr><td class="form_label" id="reppw">Repeat New Password:</td>
@ <td><input aria-labledby="reppw" type="password" name="n2" \
@ size="30"></td></tr>
@ <tr><td></td>
@ <td><input type="submit" value="Change Password"></td></tr>
@ </table>
@ </form>
style_finish_page();
}
/*
** Attempt to find login credentials for user zLogin on a peer repository
** with project code zCode. Transfer those credentials to the local
** repository.
**
** Return true if a transfer was made and false if not.
|
| ︙ | ︙ | |||
859 860 861 862 863 864 865 |
sqlite3_create_function(pOther,"now",0,SQLITE_UTF8,0,db_now_function,0,0);
sqlite3_create_function(pOther, "constant_time_cmp", 2, SQLITE_UTF8, 0,
constant_time_cmp_function, 0, 0);
sqlite3_busy_timeout(pOther, 5000);
zSQL = mprintf(
"SELECT cexpire FROM user"
" WHERE login=%Q"
| | | | 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 |
sqlite3_create_function(pOther,"now",0,SQLITE_UTF8,0,db_now_function,0,0);
sqlite3_create_function(pOther, "constant_time_cmp", 2, SQLITE_UTF8, 0,
constant_time_cmp_function, 0, 0);
sqlite3_busy_timeout(pOther, 5000);
zSQL = mprintf(
"SELECT cexpire FROM user"
" WHERE login=%Q"
" AND octet_length(cap)>0"
" AND octet_length(pw)>0"
" AND cexpire>julianday('now')"
" AND constant_time_cmp(cookie,%Q)=0",
zLogin, zHash
);
pStmt = 0;
rc = sqlite3_prepare_v2(pOther, zSQL, -1, &pStmt, 0);
if( rc==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){
|
| ︙ | ︙ | |||
913 914 915 916 917 918 919 |
){
int uid;
if( login_is_special(zLogin) ) return 0;
uid = db_int(0,
"SELECT uid FROM user"
" WHERE login=%Q"
" AND cexpire>julianday('now')"
| | | | 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 |
){
int uid;
if( login_is_special(zLogin) ) return 0;
uid = db_int(0,
"SELECT uid FROM user"
" WHERE login=%Q"
" AND cexpire>julianday('now')"
" AND octet_length(cap)>0"
" AND octet_length(pw)>0"
" AND constant_time_cmp(cookie,%Q)=0",
zLogin, zCookie
);
return uid;
}
/*
|
| ︙ | ︙ | |||
991 992 993 994 995 996 997 |
**
*/
void login_check_credentials(void){
int uid = 0; /* User id */
const char *zCookie; /* Text of the login cookie */
const char *zIpAddr; /* Raw IP address of the requestor */
const char *zCap = 0; /* Capability string */
| < | 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 |
**
*/
void login_check_credentials(void){
int uid = 0; /* User id */
const char *zCookie; /* Text of the login cookie */
const char *zIpAddr; /* Raw IP address of the requestor */
const char *zCap = 0; /* Capability string */
const char *zLogin = 0; /* Login user for credentials */
/* Only run this check once. */
if( g.userUid!=0 ) return;
sqlite3_create_function(g.db, "constant_time_cmp", 2, SQLITE_UTF8, 0,
constant_time_cmp_function, 0, 0);
|
| ︙ | ︙ | |||
1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 |
zIpAddr = PD("REMOTE_ADDR","nil");
if( ( cgi_is_loopback(zIpAddr)
|| (g.fSshClient & CGI_SSH_CLIENT)!=0 )
&& g.useLocalauth
&& db_get_int("localauth",0)==0
&& P("HTTPS")==0
){
if( g.localOpen ) zLogin = db_lget("default-user",0);
if( zLogin!=0 ){
uid = db_int(0, "SELECT uid FROM user WHERE login=%Q", zLogin);
}else{
uid = db_int(0, "SELECT uid FROM user WHERE cap LIKE '%%s%%'");
}
g.zLogin = db_text("?", "SELECT login FROM user WHERE uid=%d", uid);
zCap = "sxy";
g.noPswd = 1;
g.isHuman = 1;
| > | > > > | 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 |
zIpAddr = PD("REMOTE_ADDR","nil");
if( ( cgi_is_loopback(zIpAddr)
|| (g.fSshClient & CGI_SSH_CLIENT)!=0 )
&& g.useLocalauth
&& db_get_int("localauth",0)==0
&& P("HTTPS")==0
){
char *zSeed;
if( g.localOpen ) zLogin = db_lget("default-user",0);
if( zLogin!=0 ){
uid = db_int(0, "SELECT uid FROM user WHERE login=%Q", zLogin);
}else{
uid = db_int(0, "SELECT uid FROM user WHERE cap LIKE '%%s%%'");
}
g.zLogin = db_text("?", "SELECT login FROM user WHERE uid=%d", uid);
zCap = "sxy";
g.noPswd = 1;
g.isHuman = 1;
zSeed = db_text("??", "SELECT uid||quote(login)||quote(pw)||quote(cookie)"
" FROM user WHERE uid=%d", uid);
login_create_csrf_secret(zSeed);
fossil_free(zSeed);
}
/* Check the login cookie to see if it matches a known valid user.
*/
if( uid==0 && (zCookie = P(login_cookie_name()))!=0 ){
/* Parse the cookie value up into HASH/ARG/USER */
char *zHash = fossil_strdup(zCookie);
|
| ︙ | ︙ | |||
1061 1062 1063 1064 1065 1066 1067 |
Blob b;
blob_zero(&b);
blob_appendf(&b, "%s/%s", zArg, db_get("captcha-secret",""));
sha1sum_blob(&b, &b);
if( fossil_strcmp(zHash, blob_str(&b))==0 ){
uid = db_int(0,
"SELECT uid FROM user WHERE login='anonymous'"
| | | | > | | 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 |
Blob b;
blob_zero(&b);
blob_appendf(&b, "%s/%s", zArg, db_get("captcha-secret",""));
sha1sum_blob(&b, &b);
if( fossil_strcmp(zHash, blob_str(&b))==0 ){
uid = db_int(0,
"SELECT uid FROM user WHERE login='anonymous'"
" AND octet_length(cap)>0"
" AND octet_length(pw)>0"
" AND %.17g+0.25>julianday('now')",
rTime
);
}
blob_reset(&b);
}else{
/* Cookies of the form "HASH/CODE/USER". Search first in the
** local user table, then the user table for project CODE if we
** are part of a login-group.
*/
uid = login_find_user(zUser, zHash);
if( uid==0 && login_transfer_credentials(zUser,zArg,zHash) ){
uid = login_find_user(zUser, zHash);
if( uid ) record_login_attempt(zUser, zIpAddr, 1);
}
}
login_create_csrf_secret(zHash);
}
/* If no user found and the REMOTE_USER environment variable is set,
** then accept the value of REMOTE_USER as the user.
*/
if( uid==0 ){
const char *zRemoteUser = P("REMOTE_USER");
if( zRemoteUser && db_get_boolean("remote_user_ok",0) ){
uid = db_int(0, "SELECT uid FROM user WHERE login=%Q"
" AND octet_length(cap)>0 AND octet_length(pw)>0",
zRemoteUser);
}
}
/* If the request didn't provide a login cookie or the login cookie didn't
** match a known valid user, check the HTTP "Authorization" header and
** see if those credentials are valid for a known user.
*/
|
| ︙ | ︙ | |||
1128 1129 1130 1131 1132 1133 1134 |
if( uid==0 ){
uid = db_int(0, "SELECT uid FROM user WHERE login='nobody'");
if( uid==0 ){
/* If there is no user "nobody", then make one up - with no privileges */
uid = -1;
zCap = "";
}
| > > | > | > > > > > > > > | 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 |
if( uid==0 ){
uid = db_int(0, "SELECT uid FROM user WHERE login='nobody'");
if( uid==0 ){
/* If there is no user "nobody", then make one up - with no privileges */
uid = -1;
zCap = "";
}
login_create_csrf_secret("none");
}
login_set_uid(uid, zCap);
}
/*
** Set the current logged in user to be uid. zCap is precomputed
** (override) capabilities. If zCap==0, then look up the capabilities
** in the USER table.
*/
int login_set_uid(int uid, const char *zCap){
const char *zPublicPages = 0; /* GLOB patterns of public pages */
/* At this point, we know that uid!=0. Find the privileges associated
** with user uid.
*/
assert( uid!=0 );
if( zCap==0 ){
Stmt s;
db_prepare(&s, "SELECT login, cap FROM user WHERE uid=%d", uid);
|
| ︙ | ︙ | |||
1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 |
const char *zUri = PD("REQUEST_URI","");
zUri += (int)strlen(g.zTop);
if( glob_match(pGlob, zUri) ){
login_set_capabilities(db_get("default-perms", "u"), 0);
}
glob_free(pGlob);
}
}
/*
** Memory of settings
*/
static int login_anon_once = 1;
| > | 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 |
const char *zUri = PD("REQUEST_URI","");
zUri += (int)strlen(g.zTop);
if( glob_match(pGlob, zUri) ){
login_set_capabilities(db_get("default-perms", "u"), 0);
}
glob_free(pGlob);
}
return g.zLogin!=0;
}
/*
** Memory of settings
*/
static int login_anon_once = 1;
|
| ︙ | ︙ | |||
1504 1505 1506 1507 1508 1509 1510 |
** the anonymous user has Hyperlink permission, then paint a mesage
** to inform the user that much more information is available by
** logging in as anonymous.
*/
void login_anonymous_available(void){
if( !g.perm.Hyperlink && g.anon.Hyperlink ){
const char *zUrl = PD("PATH_INFO", "");
| | | < < < < < < < < < < < < < < < < > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 |
** the anonymous user has Hyperlink permission, then paint a mesage
** to inform the user that much more information is available by
** logging in as anonymous.
*/
void login_anonymous_available(void){
if( !g.perm.Hyperlink && g.anon.Hyperlink ){
const char *zUrl = PD("PATH_INFO", "");
@ <p>Many <span class="disabled">hyperlinks are disabled.</span><br>
@ Use <a href="%R/login?anon=1&g=%T(zUrl)">anonymous login</a>
@ to enable hyperlinks.</p>
}
}
/*
** While rendering a form, call this routine to add the Anti-CSRF token
** as a hidden element of the form.
*/
void login_insert_csrf_secret(void){
@ <input type="hidden" name="csrf" value="%s(g.zCsrfToken)">
}
/*
** Check to see if the candidate username zUserID is already used.
** Return 1 if it is already in use. Return 0 if the name is
** available for a self-registeration.
*/
static int login_self_choosen_userid_already_exists(const char *zUserID){
int rc = db_exists(
"SELECT 1 FROM user WHERE login=%Q "
"UNION ALL "
"SELECT 1 FROM event WHERE user=%Q OR euser=%Q",
zUserID, zUserID, zUserID
);
return rc;
}
/*
** zEMail is an email address. (Example: "xyz@gmail.com".) This routine
** searches for a user or subscriber that has that email address. If the
** email address is used no-where in the system, return 0. If the email
** address is assigned to a particular user return the UID for that user.
** If the email address is used, but not by a particular user, return -1.
*/
static int email_address_in_use(const char *zEMail){
int uid;
uid = db_int(0,
"SELECT uid FROM user"
" WHERE info LIKE '%%<%q>%%'", zEMail);
if( uid>0 ){
if( db_exists("SELECT 1 FROM user WHERE uid=%d AND ("
" cap GLOB '*[as]*' OR"
" find_emailaddr(info)<>%Q COLLATE nocase)",
uid, zEMail) ){
uid = -1;
}
}
if( uid==0 && alert_tables_exist() ){
uid = db_int(0,
"SELECT user.uid FROM subscriber JOIN user ON login=suname"
" WHERE semail=%Q AND sverified", zEMail);
if( uid ){
if( db_exists("SELECT 1 FROM user WHERE uid=%d AND "
" cap GLOB '*[as]*'",
uid) ){
uid = -1;
}
}
}
return uid;
}
/*
** COMMAND: test-email-used
** Usage: fossil test-email-used EMAIL ...
**
** Given a list of email addresses, show the UID and LOGIN associated
** with each one.
*/
void test_email_used(void){
int i;
db_find_and_open_repository(0, 0);
verify_all_options();
if( g.argc<3 ){
usage("EMAIL ...");
}
for(i=2; i<g.argc; i++){
const char *zEMail = g.argv[i];
int uid = email_address_in_use(zEMail);
if( uid==0 ){
fossil_print("%s: not used\n", zEMail);
}else if( uid<0 ){
fossil_print("%s: used but no password reset is available\n", zEMail);
}else{
char *zLogin = db_text(0, "SELECT login FROM user WHERE uid=%d", uid);
fossil_print("%s: UID %d (%s)\n", zEMail, uid, zLogin);
fossil_free(zLogin);
}
}
}
/*
** Check an email address and confirm that it is valid for self-registration.
** The email address is known already to be well-formed. Return true
** if the email address is on the allowed list.
**
** The default behavior is that any valid email address is accepted.
** But if the "auth-sub-email" setting exists and is not empty, then
|
| ︙ | ︙ | |||
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 |
void register_page(void){
const char *zUserID, *zPasswd, *zConfirm, *zEAddr;
const char *zDName;
unsigned int uSeed;
const char *zDecoded;
int iErrLine = -1;
const char *zErr = 0;
int captchaIsCorrect = 0; /* True on a correct captcha */
char *zCaptcha = ""; /* Value of the captcha text */
char *zPerms; /* Permissions for the default user */
int canDoAlerts = 0; /* True if receiving email alerts is possible */
int doAlerts = 0; /* True if subscription is wanted too */
if( !db_get_boolean("self-register", 0) ){
style_header("Registration not possible");
@ <p>This project does not allow user self-registration. Please contact the
@ project administrator to obtain an account.</p>
style_finish_page();
return;
}
zPerms = db_get("default-perms", "u");
/* Prompt the user for email alerts if this repository is configured for
** email alerts and if the default permissions include "7" */
canDoAlerts = alert_tables_exist() && (db_int(0,
"SELECT fullcap(%Q) GLOB '*7*'", zPerms
) || db_get_boolean("selfreg-verify",0));
doAlerts = canDoAlerts && atoi(PD("alerts","1"))!=0;
zUserID = PDT("u","");
zPasswd = PDT("p","");
zConfirm = PDT("cp","");
zEAddr = PDT("ea","");
zDName = PDT("dn","");
/* Verify user imputs */
| > > > > > > > > > | > > > > > > > > > > < < < < < < < < < < < < < | 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 |
void register_page(void){
const char *zUserID, *zPasswd, *zConfirm, *zEAddr;
const char *zDName;
unsigned int uSeed;
const char *zDecoded;
int iErrLine = -1;
const char *zErr = 0;
int uid = 0; /* User id with the same email */
int captchaIsCorrect = 0; /* True on a correct captcha */
char *zCaptcha = ""; /* Value of the captcha text */
char *zPerms; /* Permissions for the default user */
int canDoAlerts = 0; /* True if receiving email alerts is possible */
int doAlerts = 0; /* True if subscription is wanted too */
if( !db_get_boolean("self-register", 0) ){
style_header("Registration not possible");
@ <p>This project does not allow user self-registration. Please contact the
@ project administrator to obtain an account.</p>
style_finish_page();
return;
}
if( P("pwreset")!=0 && login_self_password_reset_available() ){
/* The "Request Password Reset" button was pressed, so render the
** "Request Password Reset" page instead of this one. */
login_reqpwreset_page();
return;
}
zPerms = db_get("default-perms", "u");
login_check_credentials();
/* Prompt the user for email alerts if this repository is configured for
** email alerts and if the default permissions include "7" */
canDoAlerts = alert_tables_exist() && (db_int(0,
"SELECT fullcap(%Q) GLOB '*7*'", zPerms
) || db_get_boolean("selfreg-verify",0));
doAlerts = canDoAlerts && atoi(PD("alerts","1"))!=0;
zUserID = PDT("u","");
zPasswd = PDT("p","");
zConfirm = PDT("cp","");
zEAddr = PDT("ea","");
zDName = PDT("dn","");
/* Verify user imputs */
if( P("new")==0 || !cgi_csrf_safe(2) ){
/* This is not a valid form submission. Fall through into
** the form display */
}else if( (captchaIsCorrect = captcha_is_correct(1))==0 ){
iErrLine = 6;
zErr = "Incorrect CAPTCHA";
}else if( strlen(zUserID)<6 ){
iErrLine = 1;
zErr = "User ID too short. Must be at least 6 characters.";
}else if( sqlite3_strglob("*[^-a-zA-Z0-9_.]*",zUserID)==0 ){
iErrLine = 1;
zErr = "User ID may not contain spaces or special characters.";
}else if( sqlite3_strlike("anonymous%", zUserID, 0)==0
|| sqlite3_strlike("nobody%", zUserID, 0)==0
|| sqlite3_strlike("reader%", zUserID, 0)==0
|| sqlite3_strlike("developer%", zUserID, 0)==0
){
iErrLine = 1;
zErr = "This User ID is reserved. Choose something different.";
}else if( zDName[0]==0 ){
iErrLine = 2;
zErr = "Required";
}else if( zEAddr[0]==0 ){
iErrLine = 3;
zErr = "Required";
}else if( email_address_is_valid(zEAddr,0)==0 ){
iErrLine = 3;
zErr = "Not a valid email address";
}else if( authorized_subscription_email(zEAddr)==0 ){
iErrLine = 3;
zErr = "Not an authorized email address";
}else if( strlen(zPasswd)<6 ){
iErrLine = 4;
zErr = "Password must be at least 6 characters long";
}else if( fossil_strcmp(zPasswd,zConfirm)!=0 ){
iErrLine = 5;
zErr = "Passwords do not match";
}else if( (uid = email_address_in_use(zEAddr))!=0 ){
iErrLine = 3;
zErr = "This email address is already associated with a user";
}else if( login_self_choosen_userid_already_exists(zUserID) ){
iErrLine = 1;
zErr = "This User ID is already taken. Choose something different.";
}else{
/* If all of the tests above have passed, that means that the submitted
** form contains valid data and we can proceed to create the new login */
Blob sql;
int uid;
char *zPass = sha1_shared_secret(zPasswd, zUserID, 0);
const char *zStartPerms = zPerms;
|
| ︙ | ︙ | |||
1774 1775 1776 1777 1778 1779 1780 |
zCaptcha = captcha_render(zDecoded);
style_header("Register");
/* Print out the registration form. */
g.perm.Hyperlink = 1; /* Artificially enable hyperlinks */
form_begin(0, "%R/register");
if( P("g") ){
| | | | 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 |
zCaptcha = captcha_render(zDecoded);
style_header("Register");
/* Print out the registration form. */
g.perm.Hyperlink = 1; /* Artificially enable hyperlinks */
form_begin(0, "%R/register");
if( P("g") ){
@ <input type="hidden" name="g" value="%h(P("g"))">
}
@ <p><input type="hidden" name="captchaseed" value="%u(uSeed)">
@ <table class="login_out">
@ <tr>
@ <td class="form_label" align="right" id="uid">User ID:</td>
@ <td><input aria-labelledby="uid" type="text" name="u" \
@ value="%h(zUserID)" size="30"></td>
@
if( iErrLine==1 ){
|
| ︙ | ︙ | |||
1801 1802 1803 1804 1805 1806 1807 |
@ </tr>
@ <tr>
@ <td class="form_label" align="right" id="emaddr">Email Address:</td>
@ <td><input aria-labelledby="emaddr" type="text" name="ea" \
@ value="%h(zEAddr)" size="30"></td>
@ </tr>
if( iErrLine==3 ){
| | > > > > > > | 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 |
@ </tr>
@ <tr>
@ <td class="form_label" align="right" id="emaddr">Email Address:</td>
@ <td><input aria-labelledby="emaddr" type="text" name="ea" \
@ value="%h(zEAddr)" size="30"></td>
@ </tr>
if( iErrLine==3 ){
@ <tr><td><td><span class='loginError'>↑ %h(zErr)</span>
if( uid>0 && login_self_password_reset_available() ){
@ <br>
@ <input type="submit" name="pwreset" \
@ value="Request Password Reset For %h(zEAddr)">
}
@ </td></tr>
}
if( canDoAlerts ){
int a = atoi(PD("alerts","1"));
@ <tr>
@ <td class="form_label" align="right" id="emalrt">Email Alerts?</td>
@ <td><select aria-labelledby="emalrt" size='1' name='alerts'>
@ <option value="1" %s(a?"selected":"")>Yes</option>
|
| ︙ | ︙ | |||
1845 1846 1847 1848 1849 1850 1851 |
captcha_speakit_button(uSeed, "Speak the captcha text");
@ </td>
@ </tr>
if( iErrLine==6 ){
@ <tr><td><td><span class='loginError'>↑ %h(zErr)</span></td></tr>
}
@ <tr><td></td>
| | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 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 |
captcha_speakit_button(uSeed, "Speak the captcha text");
@ </td>
@ </tr>
if( iErrLine==6 ){
@ <tr><td><td><span class='loginError'>↑ %h(zErr)</span></td></tr>
}
@ <tr><td></td>
@ <td><input type="submit" name="new" value="Register"></td></tr>
@ </table>
@ <div class="captcha"><table class="captcha"><tr><td><pre class="captcha">
@ %h(zCaptcha)
@ </pre>
@ Enter this 8-letter code in the "Captcha" box above.
@ </td></tr></table></div>
@ </form>
style_finish_page();
free(zCaptcha);
}
/*
** WEBPAGE: reqpwreset
**
** A web page to request a password reset.
**
** A form is presented where the user can enter their email address
** and a captcha. If the email address entered corresponds to a known
** users, an email is sent to that address that contains a link to the
** /resetpw page that allows the users to enter a new password.
**
** This page is only available if the self-pw-reset property is enabled
** and email notifications are configured and operating. Password resets
** are not available to users with Admin or Setup privilege.
*/
void login_reqpwreset_page(void){
const char *zEAddr;
const char *zDecoded;
unsigned int uSeed;
int iErrLine = -1;
const char *zErr = 0;
int uid = 0; /* User id with the email zEAddr */
int captchaIsCorrect = 0; /* True on a correct captcha */
char *zCaptcha = ""; /* Value of the captcha text */
if( !login_self_password_reset_available() ){
style_header("Password reset not possible");
@ <p>This project does not allow users to reset their own passwords.
@ If you need a password reset, you will have to negotiate that directly
@ with the project administrator.
style_finish_page();
return;
}
zEAddr = PDT("ea","");
/* Verify user imputs */
if( !cgi_csrf_safe(1) || P("reqpwreset")==0 ){
/* This is the initial display of the form. No processing or error
** checking is to be done. Fall through into the form display
**
** cgi_csrf_safe(): Nothing interesting happens on this page without
** a valid captcha solution, so we only need to check referrer and that
** the request is a POST.
*/
}else if( (captchaIsCorrect = captcha_is_correct(1))==0 ){
iErrLine = 2;
zErr = "Incorrect CAPTCHA";
}else if( zEAddr[0]==0 ){
iErrLine = 1;
zErr = "Required";
}else if( email_address_is_valid(zEAddr,0)==0 ){
iErrLine = 1;
zErr = "Not a valid email address";
}else if( authorized_subscription_email(zEAddr)==0 ){
iErrLine = 1;
zErr = "Not an authorized email address";
}else if( (uid = email_address_in_use(zEAddr))<=0 ){
iErrLine = 1;
zErr = "This email address is not associated with a user who has "
"password reset privileges.";
}else if( login_set_uid(uid,0)==0 || g.perm.Admin || g.perm.Setup
|| !g.perm.Password ){
iErrLine = 1;
zErr = "This email address is not associated with a user who has "
"password reset privileges.";
}else{
/* If all of the tests above have passed, that means that the submitted
** form contains valid data and we can proceed to issue the password
** reset email. */
Blob hdr, body;
AlertSender *pSender;
char *zUrl = login_resetpw_suffix(uid, 0);
pSender = alert_sender_new(0,0);
blob_init(&hdr,0,0);
blob_init(&body,0,0);
blob_appendf(&hdr, "To: <%s>\n", zEAddr);
blob_appendf(&hdr, "Subject: Password reset for %s\n", g.zBaseURL);
blob_appendf(&body,
"Someone has requested to reset the password for user \"%s\"\n",
g.zLogin);
blob_appendf(&body, "at %s.\n\n", g.zBaseURL);
blob_appendf(&body,
"If you did not request this password reset, ignore\n"
"this email\n\n");
blob_appendf(&body,
"To reset the password, visit the following link:\n\n"
" %s/resetpw/%s\n\n", g.zBaseURL, zUrl);
fossil_free(zUrl);
alert_send(pSender, &hdr, &body, 0);
style_header("Email Verification");
if( pSender->zErr ){
@ <h1>Internal Error</h1>
@ <p>The following internal error was encountered while trying
@ to send the confirmation email:
@ <blockquote><pre>
@ %h(pSender->zErr)
@ </pre></blockquote>
}else{
@ <p>An email containing a hyperlink that can be used to reset
@ your password has been sent to "%h(zEAddr)".</p>
}
alert_sender_free(pSender);
style_finish_page();
return;
}
/* Prepare the captcha. */
if( captchaIsCorrect ){
uSeed = strtoul(P("captchaseed"),0,10);
}else{
uSeed = captcha_seed();
}
zDecoded = captcha_decode(uSeed);
zCaptcha = captcha_render(zDecoded);
style_header("Request Password Reset");
/* Print out the registration form. */
g.perm.Hyperlink = 1; /* Artificially enable hyperlinks */
form_begin(0, "%R/reqpwreset");
@ <p><input type="hidden" name="captchaseed" value="%u(uSeed)">
@ <p><input type="hidden" name="reqpwreset" value="1">
@ <table class="login_out">
@ <tr>
@ <td class="form_label" align="right" id="emaddr">Email Address:</td>
@ <td><input aria-labelledby="emaddr" type="text" name="ea" \
@ value="%h(zEAddr)" size="30"></td>
@ </tr>
if( iErrLine==1 ){
@ <tr><td><td><span class='loginError'>↑ %h(zErr)</span></td></tr>
}
@ <tr>
@ <td class="form_label" align="right" id="cptcha">Captcha:</td>
@ <td><input type="text" name="captcha" aria-labelledby="cptcha" \
@ value="%h(captchaIsCorrect?zDecoded:"")" size="30">
captcha_speakit_button(uSeed, "Speak the captcha text");
@ </td>
@ </tr>
if( iErrLine==2 ){
@ <tr><td><td><span class='loginError'>↑ %h(zErr)</span></td></tr>
}
@ <tr><td></td>
@ <td><input type="submit" name="new" value="Request Password Reset"/>\
@ </td></tr>
@ </table>
@ <div class="captcha"><table class="captcha"><tr><td><pre class="captcha">
@ %h(zCaptcha)
@ </pre>
@ Enter this 8-letter code in the "Captcha" box above.
@ </td></tr></table></div>
@ </form>
style_finish_page();
free(zCaptcha);
}
/*
** Run SQL on the repository database for every repository in our
** login group. The SQL is run in a separate database connection.
**
** Any members of the login group whose repository database file
** cannot be found is silently removed from the group.
|
| ︙ | ︙ | |||
2123 2124 2125 2126 2127 2128 2129 | ** Usage: %fossil login-group ?SUBCOMMAND? ?OPTIONS? ** ** Run various subcommands to manage login-group related settings of the open ** repository or of the repository identified by the -R or --repository option. ** ** > fossil login-group ?-R REPO? ** | | | | | > | | | > | > | | | | 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 | ** Usage: %fossil login-group ?SUBCOMMAND? ?OPTIONS? ** ** Run various subcommands to manage login-group related settings of the open ** repository or of the repository identified by the -R or --repository option. ** ** > fossil login-group ?-R REPO? ** ** Show the login-group to which REPO, or if invoked from within a check-out ** the repository on which the current check-out is based, belongs. ** ** > fossil login-group join ?-R REPO? ?--name NAME? REPO2 ** ** This command will either: (1) add the repository on which the current ** check-out is based, or the repository REPO specified with -R, to the ** login group where REPO2 is a member, in which case the optional --name ** argument is not required; or (2) create a new login group between the ** repository on which the current check-out is based, or the repository ** REPO specified with -R, and REPO2, in which case the new group NAME is ** determined by the mandatory --name option. In both cases, the specified ** repositories will first leave any group in which they are currently a ** member before joining the new login group. ** ** > fossil login-group leave ?-R REPO? ** ** Take the repository REPO, or if invoked from within a check-out the ** repository on which the current check-out is based, out of whatever ** login group it is a member. ** ** About Login Groups: ** ** A login-group is a set of repositories that share user credentials. ** If a user is logged into one member of the group, then that user can ** access any other group member as long as they have an entry in the USER |
| ︙ | ︙ | |||
2161 2162 2163 2164 2165 2166 2167 |
Stmt q;
db_find_and_open_repository(0, 0);
if( g.argc>2 ){
zCmd = g.argv[2];
nCmd = (int)strlen(zCmd);
if( strncmp(zCmd,"join",nCmd)==0 && nCmd>=1 ){
const char *zNewName = find_option("name",0,1);
| | < | > | 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 |
Stmt q;
db_find_and_open_repository(0, 0);
if( g.argc>2 ){
zCmd = g.argv[2];
nCmd = (int)strlen(zCmd);
if( strncmp(zCmd,"join",nCmd)==0 && nCmd>=1 ){
const char *zNewName = find_option("name",0,1);
const char *zOther = 0;
char *zErr = 0;
verify_all_options();
if( g.argc!=4 ){
fossil_fatal("unexpected argument count for \"login-group join\"");
}
zOther = g.argv[3];
login_group_leave(&zErr);
sqlite3_free(zErr);
zErr = 0;
login_group_join(zOther,0,0,0,zNewName,&zErr);
if( zErr ){
fossil_fatal("%s", zErr);
}
|
| ︙ | ︙ |
Changes to src/lookslike.c.
| ︙ | ︙ | |||
341 342 343 344 345 346 347 |
*/
int starts_with_utf8_bom(const Blob *pContent, int *pnByte){
const char *z = blob_buffer(pContent);
int bomSize = 0;
const unsigned char *bom = get_utf8_bom(&bomSize);
if( pnByte ) *pnByte = bomSize;
| | | 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 |
*/
int starts_with_utf8_bom(const Blob *pContent, int *pnByte){
const char *z = blob_buffer(pContent);
int bomSize = 0;
const unsigned char *bom = get_utf8_bom(&bomSize);
if( pnByte ) *pnByte = bomSize;
if( (int)blob_size(pContent)<bomSize ) return 0;
return memcmp(z, bom, bomSize)==0;
}
/*
** This function returns non-zero if the blob starts with a UTF-16
** byte-order-mark (BOM), either in the endianness of the machine
** or in reversed byte order. The UTF-32 BOM is ruled out by checking
|
| ︙ | ︙ | |||
458 459 460 461 462 463 464 |
fossil_print("Has flag LOOK_LONG: %s\n",(lookFlags&LOOK_LONG)?"yes":"no");
fossil_print("Has flag LOOK_INVALID: %s\n",
(lookFlags&LOOK_INVALID)?"yes":"no");
fossil_print("Has flag LOOK_ODD: %s\n",(lookFlags&LOOK_ODD)?"yes":"no");
fossil_print("Has flag LOOK_SHORT: %s\n",(lookFlags&LOOK_SHORT)?"yes":"no");
blob_reset(&blob);
}
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 |
fossil_print("Has flag LOOK_LONG: %s\n",(lookFlags&LOOK_LONG)?"yes":"no");
fossil_print("Has flag LOOK_INVALID: %s\n",
(lookFlags&LOOK_INVALID)?"yes":"no");
fossil_print("Has flag LOOK_ODD: %s\n",(lookFlags&LOOK_ODD)?"yes":"no");
fossil_print("Has flag LOOK_SHORT: %s\n",(lookFlags&LOOK_SHORT)?"yes":"no");
blob_reset(&blob);
}
/*
** Return true if z[i] is the whole word given by zWord in a context that
** might be an attempted SQL injection.
*/
static int isWholeWord(const char *z, unsigned int i, const char *zWord, int n){
if( i==0 ) return 0;
if( sqlite3_strnicmp(z+i, zWord, n)!=0 ) return 0;
if( fossil_isalnum(z[i-1]) ) return 0;
if( fossil_isalnum(z[i+n]) ) return 0;
if( strchr("-)_", z[i-1])!=0 ) return 0;
if( strchr("(_", z[i+n])!=0 ) return 0;
return 1;
}
/*
** Returns true if the given text contains certain keywords or
** punctuation which indicate that it might be an SQL injection attempt
** or some other kind of mischief.
**
** This is not a defense against vulnerabilities in the Fossil code.
** Rather, this is part of an effort to do early detection of malicious
** spiders to avoid them using up too many CPU cycles.
*/
int looks_like_sql_injection(const char *zTxt){
unsigned int i;
if( zTxt==0 ) return 0;
for(i=0; zTxt[i]; i++){
switch( zTxt[i] ){
case ';':
case '\'':
return 1;
case '/': /* 0123456789 123456789 */
if( strncmp(zTxt+i+1, "/wp-content/plugins/", 20)==0 ) return 1;
if( strncmp(zTxt+i+1, "/wp-admin/admin-ajax", 20)==0 ) return 1;
break;
case 'a':
case 'A':
if( isWholeWord(zTxt, i, "and", 3) ) return 1;
break;
case 'n':
case 'N':
if( isWholeWord(zTxt, i, "null", 4) ) return 1;
break;
case 'o':
case 'O':
if( isWholeWord(zTxt, i, "order", 5) && fossil_isspace(zTxt[i+5]) ){
return 1;
}
if( isWholeWord(zTxt, i, "or", 2) ) return 1;
break;
case 's':
case 'S':
if( isWholeWord(zTxt, i, "select", 6) ) return 1;
break;
case 'w':
case 'W':
if( isWholeWord(zTxt, i, "waitfor", 7) ) return 1;
break;
}
}
return 0;
}
/*
** This is a utility routine associated with the test-looks-like-sql-injection
** command.
**
** Read input from zInFile and print only those lines that look like they
** might be SQL injection.
**
** Or if bInvert is true, then show the opposite - those lines that do NOT
** look like SQL injection.
*/
static void show_sql_injection_lines(
const char *zInFile, /* Name of input file */
int bInvert, /* Invert the sense of the output (-v) */
int bDeHttpize /* De-httpize the inputs. (-d) */
){
FILE *in;
char zLine[10000];
if( zInFile==0 || strcmp(zInFile,"-")==0 ){
in = stdin;
}else{
in = fopen(zInFile, "rb");
if( in==0 ){
fossil_fatal("cannot open \"%s\" for reading\n", zInFile);
}
}
while( fgets(zLine, sizeof(zLine), in) ){
dehttpize(zLine);
if( (looks_like_sql_injection(zLine)!=0) ^ bInvert ){
fossil_print("%s", zLine);
}
}
if( in!=stdin ) fclose(in);
}
/*
** COMMAND: test-looks-like-sql-injection
**
** Read lines of input from files named as arguments (or from standard
** input if no arguments are provided) and print those that look like they
** might be part of an SQL injection attack.
**
** Used to test the looks_lide_sql_injection() utility subroutine, possibly
** by piping in actual server log data.
*/
void test_looks_like_sql_injection(void){
int i;
int bInvert = find_option("invert","v",0)!=0;
int bDeHttpize = find_option("dehttpize","d",0)!=0;
verify_all_options();
if( g.argc==2 ){
show_sql_injection_lines(0, bInvert, bDeHttpize);
}
for(i=2; i<g.argc; i++){
show_sql_injection_lines(g.argv[i], bInvert, bDeHttpize);
}
}
|
Changes to src/main.c.
| ︙ | ︙ | |||
22 23 24 25 26 27 28 29 30 31 32 33 34 35 | #include "config.h" #if defined(_WIN32) # include <windows.h> # include <io.h> # define isatty(h) _isatty(h) # define GETPID (int)GetCurrentProcessId #endif #include "main.h" #include <string.h> #include <time.h> #include <fcntl.h> #include <sys/types.h> #include <sys/stat.h> #include <stdlib.h> /* atexit() */ | > > > > > > > > > > | 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | #include "config.h" #if defined(_WIN32) # include <windows.h> # include <io.h> # define isatty(h) _isatty(h) # define GETPID (int)GetCurrentProcessId #endif /* BUGBUG: This (PID_T) does not work inside of INTERFACE block. */ #if USE_SEE #if defined(_WIN32) typedef DWORD PID_T; #else typedef pid_t PID_T; #endif #endif #include "main.h" #include <string.h> #include <time.h> #include <fcntl.h> #include <sys/types.h> #include <sys/stat.h> #include <stdlib.h> /* atexit() */ |
| ︙ | ︙ | |||
134 135 136 137 138 139 140 141 142 143 144 145 146 147 |
void *xPostEval; /* Optional, called after Tcl_Eval*(). */
void *pPostContext; /* Optional, provided to xPostEval(). */
};
#endif
struct Global {
int argc; char **argv; /* Command-line arguments to the program */
char *nameOfExe; /* Full path of executable. */
const char *zErrlog; /* Log errors to this file, if not NULL */
const char *zPhase; /* Phase of operation, for use by the error log
** and for deriving $canonical_page TH1 variable */
int isConst; /* True if the output is unchanging & cacheable */
const char *zVfsName; /* The VFS to use for database connections */
sqlite3 *db; /* The connection to the databases */
| > | 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 |
void *xPostEval; /* Optional, called after Tcl_Eval*(). */
void *pPostContext; /* Optional, provided to xPostEval(). */
};
#endif
struct Global {
int argc; char **argv; /* Command-line arguments to the program */
char **argvOrig; /* Original g.argv prior to removing options */
char *nameOfExe; /* Full path of executable. */
const char *zErrlog; /* Log errors to this file, if not NULL */
const char *zPhase; /* Phase of operation, for use by the error log
** and for deriving $canonical_page TH1 variable */
int isConst; /* True if the output is unchanging & cacheable */
const char *zVfsName; /* The VFS to use for database connections */
sqlite3 *db; /* The connection to the databases */
|
| ︙ | ︙ | |||
213 214 215 216 217 218 219 |
Blob httpHeader; /* Complete text of the HTTP request header */
UrlData url; /* Information about current URL */
const char *zLogin; /* Login name. NULL or "" if not logged in. */
const char *zCkoutAlias; /* doc/ uses this branch as an alias for "ckout" */
const char *zMainMenuFile; /* --mainmenu FILE from server/ui/cgi */
const char *zSSLIdentity; /* Value of --ssl-identity option, filename of
** SSL client identity */
| | | | 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 |
Blob httpHeader; /* Complete text of the HTTP request header */
UrlData url; /* Information about current URL */
const char *zLogin; /* Login name. NULL or "" if not logged in. */
const char *zCkoutAlias; /* doc/ uses this branch as an alias for "ckout" */
const char *zMainMenuFile; /* --mainmenu FILE from server/ui/cgi */
const char *zSSLIdentity; /* Value of --ssl-identity option, filename of
** SSL client identity */
#if USE_SEE
const char *zPidKey; /* Saved value of the --usepidkey option. Only
* applicable when using SEE on Windows or Linux. */
#endif
int useLocalauth; /* No login required if from 127.0.0.1 */
int noPswd; /* Logged in without password (on 127.0.0.1) */
int userUid; /* Integer user id */
int isHuman; /* True if access by a human, not a spider or bot */
int comFmtFlags; /* Zero or more "COMMENT_PRINT_*" bit flags, should be
** accessed through get_comment_format(). */
|
| ︙ | ︙ | |||
243 244 245 246 247 248 249 | #ifdef FOSSIL_ENABLE_TCL /* all Tcl related context necessary for integration */ struct TclContext tcl; #endif /* For defense against Cross-site Request Forgery attacks */ | | | > > > > | 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 |
#ifdef FOSSIL_ENABLE_TCL
/* all Tcl related context necessary for integration */
struct TclContext tcl;
#endif
/* For defense against Cross-site Request Forgery attacks */
char zCsrfToken[16]; /* Value of the anti-CSRF token */
int okCsrf; /* -1: unsafe
** 0: unknown
** 1: same origin
** 2: same origin + is POST
** 3: same origin, POST, valid csrf token */
int parseCnt[10]; /* Counts of artifacts parsed */
FILE *fDebug; /* Write debug information here, if the file exists */
#ifdef FOSSIL_ENABLE_TH1_HOOKS
int fNoThHook; /* Disable all TH1 command/webpage hooks */
#endif
int thTrace; /* True to enable TH1 debugging output */
|
| ︙ | ︙ | |||
425 426 427 428 429 430 431 | const char *zFileName; /* input file name */ FILE *inFile; /* input FILE */ g.argc = argc; g.argv = argv; sqlite3_initialize(); #if defined(_WIN32) && defined(BROKEN_MINGW_CMDLINE) | | | | | > > > > | 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 |
const char *zFileName; /* input file name */
FILE *inFile; /* input FILE */
g.argc = argc;
g.argv = argv;
sqlite3_initialize();
#if defined(_WIN32) && defined(BROKEN_MINGW_CMDLINE)
for(i=0; (int)i<g.argc; i++) g.argv[i] = fossil_mbcs_to_utf8(g.argv[i]);
#else
for(i=0; (int)i<g.argc; i++) g.argv[i] = fossil_path_to_utf8(g.argv[i]);
#endif
g.nameOfExe = file_fullexename(g.argv[0]);
for(i=1; (int)i<g.argc-1; i++){
z = g.argv[i];
if( z[0]!='-' ) continue;
z++;
if( z[0]=='-' ) z++;
/* Maintenance reminder: we do not stop at a "--" flag here,
** instead delegating that to find_option(). Doing it here
** introduces some weird corner cases, as covered in forum thread
** 4382bbc66757c39f. e.g. (fossil -U -- --args ...) is handled
** differently when we stop at "--" here. */
if( fossil_strcmp(z, "args")==0 ) break;
}
if( (int)i>=g.argc-1 ){
g.argvOrig = fossil_malloc( sizeof(char*)*(g.argc+1) );
memcpy(g.argvOrig, g.argv, sizeof(g.argv[0])*(g.argc+1));
return;
}
zFileName = g.argv[i+1];
if( strcmp(zFileName,"-")==0 ){
inFile = stdin;
}else if( !file_isfile(zFileName, ExtFILE) ){
fossil_fatal("Not an ordinary file: \"%s\"", zFileName);
}else{
|
| ︙ | ︙ | |||
465 466 467 468 469 470 471 |
}
inFile = NULL;
blob_to_utf8_no_bom(&file, 1);
z = blob_str(&file);
for(k=0, nLine=1; z[k]; k++) if( z[k]=='\n' ) nLine++;
if( nLine>100000000 ) fossil_fatal("too many command-line arguments");
nArg = g.argc + nLine*2;
| | | 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 |
}
inFile = NULL;
blob_to_utf8_no_bom(&file, 1);
z = blob_str(&file);
for(k=0, nLine=1; z[k]; k++) if( z[k]=='\n' ) nLine++;
if( nLine>100000000 ) fossil_fatal("too many command-line arguments");
nArg = g.argc + nLine*2;
newArgv = fossil_malloc( sizeof(char*)*nArg*2 + 2);
for(j=0; j<i; j++) newArgv[j] = g.argv[j];
blob_rewind(&file);
while( nLine-->0 && (n = blob_line(&file, &line))>0 ){
/* Reminder: ^^^ nLine check avoids that embedded NUL bytes in the
** --args file causes nLine to be less than blob_line() will end
** up reporting, as such a miscount leads to an illegal memory
|
| ︙ | ︙ | |||
504 505 506 507 508 509 510 |
z[k] = 0;
k++;
if( z[k] ) newArgv[j++] = &z[k];
}
}
}
i += 2;
| | > > | 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 |
z[k] = 0;
k++;
if( z[k] ) newArgv[j++] = &z[k];
}
}
}
i += 2;
while( (int)i<g.argc ) newArgv[j++] = g.argv[i++];
newArgv[j] = 0;
g.argc = j;
g.argv = newArgv;
g.argvOrig = &g.argv[j+1];
memcpy(g.argvOrig, g.argv, sizeof(g.argv[0])*(j+1));
}
#ifdef FOSSIL_ENABLE_TCL
/*
** Make a deep copy of the provided argument array and return it.
*/
static char **copy_args(int argc, char **argv){
|
| ︙ | ︙ | |||
693 694 695 696 697 698 699 | 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! */ | | | | | 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 |
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()<3043000
|| strncmp(sqlite3_sourceid(),"2023-06-12",10)<0
){
fossil_panic("Unsuitable SQLite version %s, must be at least 3.43.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);
|
| ︙ | ︙ | |||
791 792 793 794 795 796 797 |
g.zErrlog = find_option("errorlog", 0, 1);
fossil_init_flags_from_options();
if( find_option("utc",0,0) ) g.fTimeFormat = 1;
if( find_option("localtime",0,0) ) g.fTimeFormat = 2;
if( zChdir && file_chdir(zChdir, 0) ){
fossil_fatal("unable to change directories to %s", zChdir);
}
| | < < < < < < < < < < < < < < | < < < | 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 |
g.zErrlog = find_option("errorlog", 0, 1);
fossil_init_flags_from_options();
if( find_option("utc",0,0) ) g.fTimeFormat = 1;
if( find_option("localtime",0,0) ) g.fTimeFormat = 2;
if( zChdir && file_chdir(zChdir, 0) ){
fossil_fatal("unable to change directories to %s", zChdir);
}
#if USE_SEE
db_maybe_handle_saved_encryption_key_for_process(SEE_KEY_READ);
#endif
if( find_option("help",0,0)!=0 ){
/* If --help is found anywhere on the command line, translate the command
* to "fossil help cmdname" where "cmdname" is the first argument that
* does not begin with a "-" character. If all arguments start with "-",
* translate to "fossil help argv[1] argv[2]...". */
int i, nNewArgc;
|
| ︙ | ︙ | |||
1018 1019 1020 1021 1022 1023 1024 |
int i;
int nLong;
const char *zReturn = 0;
assert( hasArg==0 || hasArg==1 );
nLong = strlen(zLong);
for(i=1; i<g.argc; i++){
char *z;
| < > > | 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 |
int i;
int nLong;
const char *zReturn = 0;
assert( hasArg==0 || hasArg==1 );
nLong = strlen(zLong);
for(i=1; i<g.argc; i++){
char *z;
z = g.argv[i];
if( z[0]!='-' ) continue;
z++;
if( z[0]=='-' ){
if( z[1]==0 ){
/* Stop processing at "--" without consuming it.
verify_all_options() will consume this flag. */
break;
}
z++;
}
if( strncmp(z,zLong,nLong)==0 ){
if( hasArg && z[nLong]=='=' ){
zReturn = &z[nLong+1];
remove_from_argv(i, 1);
break;
}else if( z[nLong]==0 ){
if( i+hasArg >= g.argc ) break;
zReturn = g.argv[i+hasArg];
remove_from_argv(i, 1+hasArg);
break;
}
}else if( fossil_strcmp(z,zShort)==0 ){
if( i+hasArg >= g.argc ) break;
zReturn = g.argv[i+hasArg];
remove_from_argv(i, 1+hasArg);
break;
}
}
return zReturn;
}
|
| ︙ | ︙ | |||
1261 1262 1263 1264 1265 1266 1267 | #if defined(HAVE_PLEDGE) blob_append(pOut, "HAVE_PLEDGE\n", -1); #endif #if defined(USE_MMAN_H) blob_append(pOut, "USE_MMAN_H\n", -1); #endif #if defined(USE_SEE) | | > | 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 |
#if defined(HAVE_PLEDGE)
blob_append(pOut, "HAVE_PLEDGE\n", -1);
#endif
#if defined(USE_MMAN_H)
blob_append(pOut, "USE_MMAN_H\n", -1);
#endif
#if defined(USE_SEE)
blob_appendf(pOut, "USE_SEE (%s)\n",
db_have_saved_encryption_key() ? "SET" : "UNSET");
#endif
#if defined(FOSSIL_ALLOW_OUT_OF_ORDER_DATES)
blob_append(pOut, "FOSSIL_ALLOW_OUT_OF_ORDER_DATES\n");
#endif
if( g.db==0 ) sqlite3_open(":memory:", &g.db);
db_prepare(&q,
|
| ︙ | ︙ | |||
1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 |
if( g.zTop==g.zBaseURL ){
fossil_fatal("argument to --baseurl should be 'http://host/path'"
" or 'https://host/path'");
}
if( g.zTop[1]==0 ) g.zTop++;
}else{
char *z;
zHost = PD("HTTP_HOST","");
z = fossil_strdup(zHost);
for(i=0; z[i]; i++){
if( z[i]<='Z' && z[i]>='A' ) z[i] += 'a' - 'A';
}
| > > > > > > > > | > < | 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 |
if( g.zTop==g.zBaseURL ){
fossil_fatal("argument to --baseurl should be 'http://host/path'"
" or 'https://host/path'");
}
if( g.zTop[1]==0 ) g.zTop++;
}else{
char *z;
zMode = PD("HTTPS","off");
zHost = PD("HTTP_HOST","");
z = fossil_strdup(zHost);
for(i=0; z[i]; i++){
if( z[i]<='Z' && z[i]>='A' ) z[i] += 'a' - 'A';
}
if( fossil_strcmp(zMode,"on")==0 ){
/* Remove trailing ":443" from the HOST, if any */
if( i>4 && z[i-1]=='3' && z[i-2]=='4' && z[i-3]=='4' && z[i-4]==':' ){
i -= 4;
}
}else{
/* Remove trailing ":80" from the HOST */
if( i>3 && z[i-1]=='0' && z[i-2]=='8' && z[i-3]==':' ) i -= 3;
}
if( i && z[i-1]=='.' ) i--;
z[i] = 0;
zCur = PD("SCRIPT_NAME","/");
i = strlen(zCur);
while( i>0 && zCur[i-1]=='/' ) i--;
if( fossil_stricmp(zMode,"on")==0 ){
g.zBaseURL = mprintf("https://%s%.*s", z, i, zCur);
g.zTop = &g.zBaseURL[8+strlen(z)];
g.zHttpsURL = g.zBaseURL;
|
| ︙ | ︙ | |||
1454 1455 1456 1457 1458 1459 1460 |
}
/*
** Send an HTTP redirect back to the designated Index Page.
*/
NORETURN void fossil_redirect_home(void){
/* In order for ?skin=... to work when visiting the site from
| | | 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 |
}
/*
** Send an HTTP redirect back to the designated Index Page.
*/
NORETURN void fossil_redirect_home(void){
/* In order for ?skin=... to work when visiting the site from
** a typical external link, we have to process it here, as
** that parameter gets lost during the redirect. We "could"
** pass the whole query string along instead, but that seems
** unnecessary. */
if(cgi_setup_query_string()>1){
cookie_render();
}
cgi_redirectf("%R%s", db_get("index-page", "/index"));
|
| ︙ | ︙ | |||
1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 |
int allowRepoList /* Send repo list for "/" URL */
){
const char *zPathInfo = PD("PATH_INFO", "");
char *zPath = NULL;
int i;
const CmdOrPage *pCmd = 0;
const char *zBase = g.zRepositoryName;
g.zPhase = "process_one_web_page";
#if !defined(_WIN32)
signal(SIGSEGV, sigsegv_handler);
#endif
/* Handle universal query parameters */
| > | 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 |
int allowRepoList /* Send repo list for "/" URL */
){
const char *zPathInfo = PD("PATH_INFO", "");
char *zPath = NULL;
int i;
const CmdOrPage *pCmd = 0;
const char *zBase = g.zRepositoryName;
int isReadonly = 0;
g.zPhase = "process_one_web_page";
#if !defined(_WIN32)
signal(SIGSEGV, sigsegv_handler);
#endif
/* Handle universal query parameters */
|
| ︙ | ︙ | |||
1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 |
json_bootstrap_early();
}
#endif
/* If the repository has not been opened already, then find the
** repository based on the first element of PATH_INFO and open it.
*/
if( !g.repositoryOpen ){
char *zRepo; /* Candidate repository name */
char *zToFree = 0; /* Malloced memory that needs to be freed */
const char *zCleanRepo; /* zRepo with surplus leading "/" removed */
const char *zOldScript = PD("SCRIPT_NAME", ""); /* Original SCRIPT_NAME */
char *zNewScript; /* Revised SCRIPT_NAME after processing */
int j, k; /* Loop variables */
i64 szFile; /* File size of the candidate repository */
| > > | 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 |
json_bootstrap_early();
}
#endif
/* If the repository has not been opened already, then find the
** repository based on the first element of PATH_INFO and open it.
*/
if( !g.repositoryOpen ){
char zBuf[24];
const char *zRepoExt = ".fossil";
char *zRepo; /* Candidate repository name */
char *zToFree = 0; /* Malloced memory that needs to be freed */
const char *zCleanRepo; /* zRepo with surplus leading "/" removed */
const char *zOldScript = PD("SCRIPT_NAME", ""); /* Original SCRIPT_NAME */
char *zNewScript; /* Revised SCRIPT_NAME after processing */
int j, k; /* Loop variables */
i64 szFile; /* File size of the candidate repository */
|
| ︙ | ︙ | |||
1719 1720 1721 1722 1723 1724 1725 |
}
while( 1 ){
size_t nBase = strlen(zBase);
while( zPathInfo[i] && zPathInfo[i]!='/' ){ i++; }
/* The candidate repository name is some prefix of the PATH_INFO
** with ".fossil" appended */
| | | 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 |
}
while( 1 ){
size_t nBase = strlen(zBase);
while( zPathInfo[i] && zPathInfo[i]!='/' ){ i++; }
/* The candidate repository name is some prefix of the PATH_INFO
** with ".fossil" appended */
zRepo = zToFree = mprintf("%s%.*s%s",zBase,i,zPathInfo,zRepoExt);
if( g.fHttpTrace ){
@ <!-- Looking for repository named "%h(zRepo)" -->
fprintf(stderr, "# looking for repository named \"%s\"\n", zRepo);
}
/* For safety -- to prevent an attacker from accessing arbitrary disk
|
| ︙ | ︙ | |||
1750 1751 1752 1753 1754 1755 1756 |
#endif
if( c=='/' ) continue;
if( c=='_' ) continue;
if( c=='-' && zRepo[j-1]!='/' ) continue;
if( c=='.' && fossil_isalnum(zRepo[j-1]) && fossil_isalnum(zRepo[j+1])){
continue;
}
| | | 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 |
#endif
if( c=='/' ) continue;
if( c=='_' ) continue;
if( c=='-' && zRepo[j-1]!='/' ) continue;
if( c=='.' && fossil_isalnum(zRepo[j-1]) && fossil_isalnum(zRepo[j+1])){
continue;
}
if( c=='.' && g.fAllowACME && j==(int)nBase+1
&& strncmp(&zRepo[j-1],"/.well-known/",12)==0
){
/* We allow .well-known as the top-level directory for ACME */
continue;
}
/* If we reach this point, it means that the request URI contains
** an illegal character or character combination. Provoke a
|
| ︙ | ︙ | |||
1777 1778 1779 1780 1781 1782 1783 |
** 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 ){
| < | | 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 |
** 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);
}
}
/* If no file named by zRepo exists, remove the added ".fossil" suffix
** and check to see if there is a file or directory with the same
** name as the raw PATH_INFO text.
*/
if( szFile<0 && i>0 ){
const char *zMimetype;
assert( file_is_repository_extension(&zRepo[j]) );
zRepo[j] = 0; /* Remove the ".fossil" suffix */
/* The PATH_INFO prefix seen so far is a valid directory.
** Continue the loop with the next element of the PATH_INFO */
if( zPathInfo[i]=='/' && file_isdir(zCleanRepo, ExtFILE)==1 ){
fossil_free(zToFree);
i++;
|
| ︙ | ︙ | |||
1815 1816 1817 1818 1819 1820 1821 |
** general-purpose web server. The "--file GLOB" mechanism is
** designed to allow the delivery of a few static images or HTML
** pages.
*/
if( pFileGlob!=0
&& file_isfile(zCleanRepo, ExtFILE)
&& glob_match(pFileGlob, file_cleanup_fullpath(zRepo+nBase))
| | | 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 |
** general-purpose web server. The "--file GLOB" mechanism is
** designed to allow the delivery of a few static images or HTML
** pages.
*/
if( pFileGlob!=0
&& file_isfile(zCleanRepo, ExtFILE)
&& glob_match(pFileGlob, file_cleanup_fullpath(zRepo+nBase))
&& !file_contains_repository_extension(zRepo)
&& (zMimetype = mimetype_from_name(zRepo))!=0
&& strcmp(zMimetype, "application/x-fossil-artifact")!=0
){
Blob content;
blob_read_from_file(&content, file_cleanup_fullpath(zRepo), ExtFILE);
cgi_set_content_type(zMimetype);
cgi_set_content(&content);
|
| ︙ | ︙ | |||
1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 |
/* If we reach this point, it means that the search of the PATH_INFO
** string is finished. Either zRepo contains the name of the
** repository to be used, or else no repository could be found and
** some kind of error response is required.
*/
if( szFile<1024 ){
set_base_url(0);
if( (zPathInfo[0]==0 || strcmp(zPathInfo,"/")==0)
&& allowRepoList
&& repo_list_page() ){
/* Will return a list of repositories */
}else if( zNotFound ){
cgi_redirect(zNotFound);
| > > > > > > > | 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 |
/* If we reach this point, it means that the search of the PATH_INFO
** string is finished. Either zRepo contains the name of the
** repository to be used, or else no repository could be found and
** some kind of error response is required.
*/
if( szFile<1024 ){
#if USE_SEE
if( strcmp(zRepoExt,".fossil")==0 ){
fossil_free(zToFree);
zRepoExt = ".efossil";
continue;
}
#endif
set_base_url(0);
if( (zPathInfo[0]==0 || strcmp(zPathInfo,"/")==0)
&& allowRepoList
&& repo_list_page() ){
/* Will return a list of repositories */
}else if( zNotFound ){
cgi_redirect(zNotFound);
|
| ︙ | ︙ | |||
1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 |
*/
zNewScript = mprintf("%s%.*s", zOldScript, i, zPathInfo);
if( g.zTop ) g.zTop = mprintf("%R%.*s", i, zPathInfo);
if( g.zBaseURL ) g.zBaseURL = mprintf("%s%.*s", g.zBaseURL, i, zPathInfo);
cgi_replace_parameter("PATH_INFO", &zPathInfo[i+1]);
zPathInfo += i;
cgi_replace_parameter("SCRIPT_NAME", zNewScript);
db_open_repository(file_cleanup_fullpath(zRepo));
if( g.fHttpTrace ){
@ <!-- repository: "%h(zRepo)" -->
@ <!-- translated PATH_INFO: "%h(zPathInfo)" -->
@ <!-- translated SCRIPT_NAME: "%h(zNewScript)" -->
fprintf(stderr,
"# repository: [%s]\n"
| > > > > > > > > > > > > > > > > | 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 |
*/
zNewScript = mprintf("%s%.*s", zOldScript, i, zPathInfo);
if( g.zTop ) g.zTop = mprintf("%R%.*s", i, zPathInfo);
if( g.zBaseURL ) g.zBaseURL = mprintf("%s%.*s", g.zBaseURL, i, zPathInfo);
cgi_replace_parameter("PATH_INFO", &zPathInfo[i+1]);
zPathInfo += i;
cgi_replace_parameter("SCRIPT_NAME", zNewScript);
#if USE_SEE
if( zPathInfo ){
if( g.fHttpTrace ){
sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", i);
@ <!-- see_path_info(%s(zBuf)) is %h(zPathInfo) -->
fprintf(stderr, "# see_path_info(%d) = %s\n", i, zPathInfo);
}
if( strcmp(zPathInfo,"/setseekey")==0
&& strcmp(zRepoExt,".efossil")==0
&& !db_have_saved_encryption_key() ){
db_set_see_key_page();
cgi_reply();
fossil_exit(0);
}
}
#endif
db_open_repository(file_cleanup_fullpath(zRepo));
if( g.fHttpTrace ){
@ <!-- repository: "%h(zRepo)" -->
@ <!-- translated PATH_INFO: "%h(zPathInfo)" -->
@ <!-- translated SCRIPT_NAME: "%h(zNewScript)" -->
fprintf(stderr,
"# repository: [%s]\n"
|
| ︙ | ︙ | |||
1964 1965 1966 1967 1968 1969 1970 |
}else{
zPath = mprintf("%s", zPathInfo);
}
/* Make g.zPath point to the first element of the path. Make
** g.zExtra point to everything past that point.
*/
| < | | | | | | | < < | 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 |
}else{
zPath = mprintf("%s", zPathInfo);
}
/* Make g.zPath point to the first element of the path. Make
** g.zExtra point to everything past that point.
*/
g.zPath = &zPath[1];
for(i=1; zPath[i] && zPath[i]!='/'; i++){}
if( zPath[i]=='/' ){
zPath[i] = 0;
g.zExtra = &zPath[i+1];
}else{
g.zExtra = 0;
}
if( g.zExtra ){
/* CGI parameters get this treatment elsewhere, but places like getfile
** will use g.zExtra directly.
** Reminder: the login mechanism uses 'name' differently, and may
** eventually have a problem/collision with this.
**
|
| ︙ | ︙ | |||
2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 |
json_bootstrap_late();
jsonOnce = 1;
}
}
#endif
if( (pCmd->eCmdFlags & CMDFLAG_RAWCONTENT)==0 ){
cgi_decode_post_parameters();
}
if( g.fCgiTrace ){
fossil_trace("######## Calling %s #########\n", pCmd->zName);
| > > > > | | 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 |
json_bootstrap_late();
jsonOnce = 1;
}
}
#endif
if( (pCmd->eCmdFlags & CMDFLAG_RAWCONTENT)==0 ){
cgi_decode_post_parameters();
if( !cgi_same_origin() ){
isReadonly = 1;
db_protect(PROTECT_READONLY);
}
}
if( g.fCgiTrace ){
fossil_trace("######## Calling %s #########\n", pCmd->zName);
cgi_print_all(1, 1, 0);
}
#ifdef FOSSIL_ENABLE_TH1_HOOKS
{
/*
** The TH1 return codes from the hook will be handled as follows:
**
** TH_OK: The xFunc() and the TH1 notification will both be executed.
|
| ︙ | ︙ | |||
2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 |
}
if( !g.fNoThHook && (rc==TH_OK || rc==TH_CONTINUE) ){
Th_WebpageNotify(pCmd->zName+1, pCmd->eCmdFlags);
}
}
}
#endif
}
/* Return the result.
*/
g.zPhase = "web-page reply";
cgi_reply();
}
| > > > | 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 |
}
if( !g.fNoThHook && (rc==TH_OK || rc==TH_CONTINUE) ){
Th_WebpageNotify(pCmd->zName+1, pCmd->eCmdFlags);
}
}
}
#endif
if( isReadonly ){
db_protect_pop();
}
}
/* Return the result.
*/
g.zPhase = "web-page reply";
cgi_reply();
}
|
| ︙ | ︙ | |||
2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 | ** ** repolist When in "directory:" mode, display a page ** showing a list of available repositories if ** the URL is "/". ** ** localauth Grant administrator privileges to connections ** from 127.0.0.1 or ::1. ** ** skin: LABEL Use the built-in skin called LABEL rather than ** the default. If there are no skins called LABEL ** then this line is a no-op. ** ** files: GLOBLIST GLOBLIST is a comma-separated list of GLOB ** patterns that specify files that can be | > > > > | 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 | ** ** repolist When in "directory:" mode, display a page ** showing a list of available repositories if ** the URL is "/". ** ** localauth Grant administrator privileges to connections ** from 127.0.0.1 or ::1. ** ** nossl Signal that no SSL connections are available. ** ** nocompress Do not compress HTTP replies. ** ** skin: LABEL Use the built-in skin called LABEL rather than ** the default. If there are no skins called LABEL ** then this line is a no-op. ** ** files: GLOBLIST GLOBLIST is a comma-separated list of GLOB ** patterns that specify files that can be |
| ︙ | ︙ | |||
2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 |
/* localauth
**
** Grant "administrator" privileges to users connecting with HTTP
** from IP address 127.0.0.1. Do not bother checking credentials.
*/
g.useLocalauth = 1;
continue;
}
if( blob_eq(&key, "repolist") ){
/* repolist
**
** If using "directory:" and the URL is "/" then generate a page
** showing a list of available repositories.
*/
| > > > > > > > > > > > > > > > > | 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 |
/* localauth
**
** Grant "administrator" privileges to users connecting with HTTP
** from IP address 127.0.0.1. Do not bother checking credentials.
*/
g.useLocalauth = 1;
continue;
}
if( blob_eq(&key, "nossl") ){
/* nossl
**
** Signal that no SSL connections are available.
*/
g.sslNotAvailable = 1;
continue;
}
if( blob_eq(&key, "nocompress") ){
/* nocompress
**
** Do not compress HTTP replies.
*/
g.fNoHttpCompress = 1;
continue;
}
if( blob_eq(&key, "repolist") ){
/* repolist
**
** If using "directory:" and the URL is "/" then generate a page
** showing a list of available repositories.
*/
|
| ︙ | ︙ | |||
2502 2503 2504 2505 2506 2507 2508 |
*/
char *zNow = cgi_iso8601_datestamp();
cgi_load_environment();
g.fDebug = fossil_fopen(blob_str(&value), "ab");
blob_reset(&value);
cgi_debug("-------- BEGIN cgi at %s --------\n", zNow);
fossil_free(zNow);
| | | 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 |
*/
char *zNow = cgi_iso8601_datestamp();
cgi_load_environment();
g.fDebug = fossil_fopen(blob_str(&value), "ab");
blob_reset(&value);
cgi_debug("-------- BEGIN cgi at %s --------\n", zNow);
fossil_free(zNow);
cgi_print_all(1,2,0);
continue;
}
}
blob_reset(&config);
if( g.db==0 && g.zRepositoryName==0 && nRedirect==0 ){
cgi_panic("Unable to find or open the project repository");
}
|
| ︙ | ︙ | |||
2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 |
db_initial_setup(0, "now", g.zLogin);
db_end_transaction(0);
fossil_print("project-id: %s\n", db_get("project-code", 0));
fossil_print("server-id: %s\n", db_get("server-code", 0));
zPassword = db_text(0, "SELECT pw FROM user WHERE login=%Q", g.zLogin);
fossil_print("admin-user: %s (initial password is \"%s\")\n",
g.zLogin, zPassword);
cache_initialize();
g.zLogin = 0;
g.userUid = 0;
}else{
db_open_repository(zRepo);
}
}
}
}
| > | | | | | > | > | > | | | 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 |
db_initial_setup(0, "now", g.zLogin);
db_end_transaction(0);
fossil_print("project-id: %s\n", db_get("project-code", 0));
fossil_print("server-id: %s\n", db_get("server-code", 0));
zPassword = db_text(0, "SELECT pw FROM user WHERE login=%Q", g.zLogin);
fossil_print("admin-user: %s (initial password is \"%s\")\n",
g.zLogin, zPassword);
hash_user_password(g.zLogin);
cache_initialize();
g.zLogin = 0;
g.userUid = 0;
}else{
db_open_repository(zRepo);
}
}
}
}
#if USE_SEE
/*
** This function attempts to parse a string value in the following
** format:
**
** "%lu:%p:%u"
**
** There are three parts, which must be delimited by colons. The
** first part is an unsigned long integer in base-10 (decimal) format.
** The second part is a numerical representation of a native pointer,
** in the appropriate implementation defined format. The third part
** is an unsigned integer in base-10 (decimal) format.
**
** If the specified value cannot be parsed, for any reason, a fatal
** error will be raised and the process will be terminated.
*/
void parse_pid_key_value(
const char *zPidKey, /* The value to be parsed. */
PID_T *pProcessId, /* The extracted process identifier. */
LPVOID *ppAddress, /* The extracted pointer value. */
SIZE_T *pnSize /* The extracted size value. */
){
unsigned long processId = 0;
unsigned int nSize = 0;
if( sscanf(zPidKey, "%lu:%p:%u", &processId, ppAddress, &nSize)==3 ){
*pProcessId = (PID_T)processId;
*pnSize = (SIZE_T)nSize;
}else{
fossil_fatal("failed to parse pid key");
}
}
#endif
/*
** WEBPAGE: test-pid
**
** Return the process identifier of the running Fossil server instance.
**
** Query parameters:
**
** usepidkey When present and available, also return the
** address and size, within this server process,
** of the saved database encryption key. This
** is only supported when using SEE on Windows
** or Linux.
*/
void test_pid_page(void){
login_check_credentials();
if( !g.perm.Setup ){ login_needed(0); return; }
#if USE_SEE
if( P("usepidkey")!=0 ){
if( g.zPidKey ){
@ %s(g.zPidKey)
return;
}else{
const char *zSavedKey = db_get_saved_encryption_key();
size_t savedKeySize = db_get_saved_encryption_key_size();
if( zSavedKey!=0 && savedKeySize>0 ){
@ %lu(GETPID()):%p(zSavedKey):%u(savedKeySize)
return;
}
}
}
#endif
@ %d(GETPID())
}
|
| ︙ | ︙ | |||
2678 2679 2680 2681 2682 2683 2684 | ** and every "." must be surrounded on both sides by alphanumerics or else ** a 404 error is returned. Static content files in the directory are ** returned if they match comma-separate GLOB pattern specified by --files ** and do not match "*.fossil*" and have a well-known suffix. ** ** Options: ** --acme Deliver files from the ".well-known" subdirectory | | | 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 | ** and every "." must be surrounded on both sides by alphanumerics or else ** a 404 error is returned. Static content files in the directory are ** returned if they match comma-separate GLOB pattern specified by --files ** and do not match "*.fossil*" and have a well-known suffix. ** ** Options: ** --acme Deliver files from the ".well-known" subdirectory ** --baseurl URL Base URL (useful with reverse proxies) ** --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 N Treat URIs of the form /doc/N/... as if they were ** /doc/ckout/... ** --extroot DIR Document root for the /ext extension mechanism ** --files GLOB Comma-separate glob patterns for static file to serve |
| ︙ | ︙ | |||
2706 2707 2708 2709 2710 2711 2712 | ** more bundled requests which ** concatenate scripts together. ** Depending on the needs of any given page, inline ** and bundled modes might result in a single ** amalgamated script or several, but both approaches ** result in fewer HTTP requests than the separate mode. ** --localauth Connections from localhost are given "setup" | | | | | | | 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 |
** more bundled requests which
** concatenate scripts together.
** Depending on the needs of any given page, inline
** and bundled modes might result in a single
** amalgamated script or several, but both approaches
** result in fewer HTTP requests than the separate mode.
** --localauth Connections from localhost are given "setup"
** privileges without having to log in
** --mainmenu FILE Override the mainmenu config setting with the contents
** of the given file
** --nocompress Do not compress HTTP replies
** --nodelay Omit backoffice processing if it would delay
** process exit
** --nojail Drop root privilege but do not enter the chroot jail
** --nossl Do not do http: to https: redirects, regardless of
** the redirect-to-https setting.
** --notfound URL Use URL as the "HTTP 404, object not found" page
** --out FILE Write the HTTP reply to FILE instead of to
** standard output
** --pkey FILE Read the private key used for TLS from FILE
** --repolist If REPOSITORY is directory, URL "/" lists all repos
** --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]]
*/
void cmd_http(void){
const char *zIpAddr = 0;
const char *zNotFound;
const char *zHost;
|
| ︙ | ︙ | |||
2892 2893 2894 2895 2896 2897 2898 | ** option on interactive sessions to avoid that special processing when ** using this command interactively over SSH. A better solution would be ** to use a different command for "ssh" sync, but we cannot do that without ** breaking legacy. ** ** Options: ** --test Do not do special "sync" processing when operating | | | 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 |
** option on interactive sessions to avoid that special processing when
** using this command interactively over SSH. A better solution would be
** to use a different command for "ssh" sync, but we cannot do that without
** breaking legacy.
**
** Options:
** --test Do not do special "sync" processing when operating
** over an SSH link
** --th-trace Trace TH1 execution (for debugging purposes)
** --usercap CAP User capability string (Default: "sxy")
**
*/
void cmd_test_http(void){
const char *zIpAddr; /* IP address of remote client */
const char *zUserCap;
|
| ︙ | ︙ | |||
2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 |
** is one) and exiting.
*/
#ifndef _WIN32
static int nAlarmSeconds = 0;
static void sigalrm_handler(int x){
sqlite3_uint64 tmUser = 0, tmKernel = 0;
fossil_cpu_times(&tmUser, &tmKernel);
fossil_panic("Timeout after %d seconds during %s"
" - user %,llu µs, sys %,llu µs",
nAlarmSeconds, g.zPhase, tmUser, tmKernel);
}
#endif
/*
| > > > > > > > | 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 |
** is one) and exiting.
*/
#ifndef _WIN32
static int nAlarmSeconds = 0;
static void sigalrm_handler(int x){
sqlite3_uint64 tmUser = 0, tmKernel = 0;
fossil_cpu_times(&tmUser, &tmKernel);
if( fossil_strcmp(g.zPhase, "web-page reply")==0
&& tmUser+tmKernel<1000000
){
/* Do not log time-outs during web-page reply unless more than
** 1 second of CPU time has been consumed */
return;
}
fossil_panic("Timeout after %d seconds during %s"
" - user %,llu µs, sys %,llu µs",
nAlarmSeconds, g.zPhase, tmUser, tmKernel);
}
#endif
/*
|
| ︙ | ︙ | |||
2973 2974 2975 2976 2977 2978 2979 | ** Usage: %fossil server ?OPTIONS? ?REPOSITORY? ** or: %fossil ui ?OPTIONS? ?REPOSITORY? ** ** Open a socket and begin listening and responding to HTTP requests on ** TCP port 8080, or on any other TCP port defined by the -P or ** --port option. The optional REPOSITORY argument is the name of the ** Fossil repository to be served. The REPOSITORY argument may be omitted | | | | | > > > > | 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 | ** Usage: %fossil server ?OPTIONS? ?REPOSITORY? ** or: %fossil ui ?OPTIONS? ?REPOSITORY? ** ** Open a socket and begin listening and responding to HTTP requests on ** TCP port 8080, or on any other TCP port defined by the -P or ** --port option. The optional REPOSITORY argument is the name of the ** Fossil repository to be served. The REPOSITORY argument may be omitted ** if the working directory is within an open check-out, in which case the ** repository associated with that check-out is used. ** ** The "ui" command automatically starts a web browser after initializing ** the web server. The "ui" command also binds to 127.0.0.1 and so will ** only process HTTP traffic from the local machine. ** ** If REPOSITORY is a directory name which is the root of a ** check-out, then use the repository associated with that check-out. ** This only works for the "fossil ui" command, not the "fossil server" ** command. ** ** If REPOSITORY begins with a "HOST:" or "USER@HOST:" prefix, then ** the command is run on the remote host specified and the results are ** tunneled back to the local machine via SSH. This feature only works for ** the "fossil ui" command, not the "fossil server" command. The name of the ** fossil executable on the remote host is specified by the --fossilcmd option, ** or if there is no --fossilcmd, it first tries "$HOME/bin/fossil" and if ** not found there it searches for any executable named "fossil" on the ** default $PATH set by SSH on the remote. ** ** REPOSITORY may also be a directory (aka folder) that contains one or ** more repositories with names ending in ".fossil". In this case, a ** prefix of the URL pathname is used to search the directory for an ** appropriate repository. To thwart mischief, the pathname in the URL must ** contain only alphanumerics, "_", "/", "-", and ".", and no "-" may ** occur after "/", and every "." must be surrounded on both sides by |
| ︙ | ︙ | |||
3018 3019 3020 3021 3022 3023 3024 | ** having to log in. This can be disabled by turning off the "localauth" ** setting. Automatic login for the "server" command is available if the ** --localauth option is present and the "localauth" setting is off and the ** connection is from localhost. The "ui" command also enables --repolist ** by default. ** ** Options: | | | > | | | | | | | | | | | | | 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 |
** having to log in. This can be disabled by turning off the "localauth"
** setting. Automatic login for the "server" command is available if the
** --localauth option is present and the "localauth" setting is off and the
** connection is from localhost. The "ui" command also enables --repolist
** by default.
**
** Options:
** --acme Deliver files from the ".well-known" subdirectory
** --baseurl URL Use URL as the base (useful for reverse proxies)
** --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.
** --localauth Enable automatic login for requests from localhost
** --localhost Listen on 127.0.0.1 only (always true for "ui")
** --https Indicates that the input is coming through a reverse
** proxy that has already translated HTTPS into HTTP.
** --jsmode MODE Determine how JavaScript is delivered with pages.
** Mode can be one of:
** inline All JavaScript is inserted inline at
** the end of the HTML file.
** separate Separate HTTP requests are made for
** each JavaScript file.
** bundled One single separate HTTP fetches all
** JavaScript concatenated together.
** Depending on the needs of any given page, inline
** and bundled modes might result in a single
** amalgamated script or several, but both approaches
** result in fewer HTTP requests than the separate mode.
** --mainmenu FILE Override the mainmenu config setting with the contents
** of the given file
** --max-latency N Do not let any single HTTP request run for more than N
** seconds (only works on unix)
** -B|--nobrowser Do not automatically launch a web-browser for the
** "fossil ui" command
** --nocompress Do not compress HTTP replies
** --nojail Drop root privileges but do not enter the chroot jail
** --nossl Do not force redirects to SSL even if the repository
** setting "redirect-to-https" requests it. This is set
** by default for the "ui" command.
** --notfound URL Redirect to URL if a page is not found.
** -p|--page PAGE Start "ui" on PAGE. ex: --page "timeline?y=ci"
** --pkey FILE Read the private key used for TLS from FILE
** -P|--port TCPPORT Listen to request on port TCPPORT
** --repolist If REPOSITORY is dir, URL "/" lists repos
** --scgi Accept SCGI rather than HTTP
** --skin LABEL Use override skin LABEL
** --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]]
*/
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 */
|
| ︙ | ︙ | |||
3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 |
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 */
#if defined(_WIN32)
const char *zStopperFile; /* Name of file used to terminate server */
zStopperFile = find_option("stopper", 0, 1);
#endif
if( g.zErrlog==0 ){
| > > > > | 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 |
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 */
#if USE_SEE
db_setup_for_saved_encryption_key();
#endif
#if defined(_WIN32)
const char *zStopperFile; /* Name of file used to terminate server */
zStopperFile = find_option("stopper", 0, 1);
#endif
if( g.zErrlog==0 ){
|
| ︙ | ︙ | |||
3176 3177 3178 3179 3180 3181 3182 |
verify_all_options();
if( g.argc!=2 && g.argc!=3 ) usage("?REPOSITORY?");
if( g.httpUseSSL && (flags & HTTP_SERVER_SCGI)!=0 ){
fossil_fatal("SCGI does not (yet) support TLS-encrypted connections");
}
if( isUiCmd && 3==g.argc && file_isdir(g.argv[2], ExtFILE)>0 ){
| | | | 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 |
verify_all_options();
if( g.argc!=2 && g.argc!=3 ) usage("?REPOSITORY?");
if( g.httpUseSSL && (flags & HTTP_SERVER_SCGI)!=0 ){
fossil_fatal("SCGI does not (yet) support TLS-encrypted connections");
}
if( isUiCmd && 3==g.argc && file_isdir(g.argv[2], ExtFILE)>0 ){
/* If REPOSITORY arg is the root of a check-out,
** chdir to that check-out so that the current version
** gets highlighted in the timeline by default. */
const char * zDir = g.argv[2];
if(dir_has_ckout_db(zDir)){
if(0!=file_chdir(zDir, 0)){
fossil_fatal("Cannot chdir to %s", zDir);
}
findServerArg = 99;
|
| ︙ | ︙ | |||
3240 3241 3242 3243 3244 3245 3246 |
}else{
iPort = db_get_int("http-port", 8080);
mxPort = iPort+100;
}
if( isUiCmd && !fNoBrowser ){
char *zBrowserArg;
const char *zProtocol = g.httpUseSSL ? "https" : "http";
| | | 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 |
}else{
iPort = db_get_int("http-port", 8080);
mxPort = iPort+100;
}
if( isUiCmd && !fNoBrowser ){
char *zBrowserArg;
const char *zProtocol = g.httpUseSSL ? "https" : "http";
db_open_config(0,0);
zBrowser = fossil_web_browser();
if( zIpAddr==0 ){
zBrowserArg = mprintf("%s://localhost:%%d/%s", zProtocol, zInitPage);
}else if( strchr(zIpAddr,':') ){
zBrowserArg = mprintf("%s://[%s]:%%d/%s", zProtocol, zIpAddr, zInitPage);
}else{
zBrowserArg = mprintf("%s://%s:%%d/%s", zProtocol, zIpAddr, zInitPage);
|
| ︙ | ︙ | |||
3262 3263 3264 3265 3266 3267 3268 |
** tunnel from the local machine to the remote. */
FILE *sshIn;
Blob ssh;
char zLine[1000];
blob_init(&ssh, 0, 0);
transport_ssh_command(&ssh);
db_close_config();
| < | < | > > > > > > > | 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 |
** tunnel from the local machine to the remote. */
FILE *sshIn;
Blob ssh;
char zLine[1000];
blob_init(&ssh, 0, 0);
transport_ssh_command(&ssh);
db_close_config();
blob_appendf(&ssh,
" -t -L 127.0.0.1:%d:127.0.0.1:%d %!$",
iPort, iPort, zRemote
);
if( zFossilCmd==0 ){
blob_appendf(&ssh, " %$ fossil", "PATH=$HOME/bin:$PATH");
}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( 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");
|
| ︙ | ︙ | |||
3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 |
** allow the container to shut down quickly.
**
** This has to happen ahead of the other signal() calls below.
** They apply after the HTTP hit is handled, but this one needs
** to be registered while we're waiting for that to occur.
**/
signal(SIGTERM, fossil_exit);
}
#endif /* !WIN32 */
/* Start up an HTTP server
*/
fossil_setenv("SERVER_SOFTWARE", "fossil version " RELEASE_VERSION
" " MANIFEST_VERSION " " MANIFEST_DATE);
| > | 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 |
** allow the container to shut down quickly.
**
** This has to happen ahead of the other signal() calls below.
** They apply after the HTTP hit is handled, but this one needs
** to be registered while we're waiting for that to occur.
**/
signal(SIGTERM, fossil_exit);
signal(SIGINT, fossil_exit);
}
#endif /* !WIN32 */
/* Start up an HTTP server
*/
fossil_setenv("SERVER_SOFTWARE", "fossil version " RELEASE_VERSION
" " MANIFEST_VERSION " " MANIFEST_DATE);
|
| ︙ | ︙ |
Changes to src/main.mk.
| ︙ | ︙ | |||
177 178 179 180 181 182 183 | $(SRCDIR)/../skins/black_and_white/footer.txt \ $(SRCDIR)/../skins/black_and_white/header.txt \ $(SRCDIR)/../skins/blitz/css.txt \ $(SRCDIR)/../skins/blitz/details.txt \ $(SRCDIR)/../skins/blitz/footer.txt \ $(SRCDIR)/../skins/blitz/header.txt \ $(SRCDIR)/../skins/blitz/ticket.txt \ | < < < < | 177 178 179 180 181 182 183 184 185 186 187 188 189 190 | $(SRCDIR)/../skins/black_and_white/footer.txt \ $(SRCDIR)/../skins/black_and_white/header.txt \ $(SRCDIR)/../skins/blitz/css.txt \ $(SRCDIR)/../skins/blitz/details.txt \ $(SRCDIR)/../skins/blitz/footer.txt \ $(SRCDIR)/../skins/blitz/header.txt \ $(SRCDIR)/../skins/blitz/ticket.txt \ $(SRCDIR)/../skins/darkmode/css.txt \ $(SRCDIR)/../skins/darkmode/details.txt \ $(SRCDIR)/../skins/darkmode/footer.txt \ $(SRCDIR)/../skins/darkmode/header.txt \ $(SRCDIR)/../skins/default/css.txt \ $(SRCDIR)/../skins/default/details.txt \ $(SRCDIR)/../skins/default/footer.txt \ |
| ︙ | ︙ | |||
647 648 649 650 651 652 653 |
-DSQLITE_ENABLE_EXPLAIN_COMMENTS \
-DSQLITE_ENABLE_FTS4 \
-DSQLITE_ENABLE_DBSTAT_VTAB \
-DSQLITE_ENABLE_FTS5 \
-DSQLITE_ENABLE_STMTVTAB \
-DSQLITE_HAVE_ZLIB \
-DSQLITE_ENABLE_DBPAGE_VTAB \
| | > | 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 |
-DSQLITE_ENABLE_EXPLAIN_COMMENTS \
-DSQLITE_ENABLE_FTS4 \
-DSQLITE_ENABLE_DBSTAT_VTAB \
-DSQLITE_ENABLE_FTS5 \
-DSQLITE_ENABLE_STMTVTAB \
-DSQLITE_HAVE_ZLIB \
-DSQLITE_ENABLE_DBPAGE_VTAB \
-DSQLITE_TRUSTED_SCHEMA=0 \
-DHAVE_USLEEP
# Setup the options used to compile the included SQLite shell.
SHELL_OPTIONS = -DNDEBUG=1 \
-DSQLITE_DQS=0 \
-DSQLITE_THREADSAFE=0 \
-DSQLITE_DEFAULT_MEMSTATUS=0 \
-DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 \
|
| ︙ | ︙ | |||
672 673 674 675 676 677 678 679 680 681 682 683 684 685 |
-DSQLITE_ENABLE_FTS4 \
-DSQLITE_ENABLE_DBSTAT_VTAB \
-DSQLITE_ENABLE_FTS5 \
-DSQLITE_ENABLE_STMTVTAB \
-DSQLITE_HAVE_ZLIB \
-DSQLITE_ENABLE_DBPAGE_VTAB \
-DSQLITE_TRUSTED_SCHEMA=0 \
-Dmain=sqlite3_shell \
-DSQLITE_SHELL_IS_UTF8=1 \
-DSQLITE_OMIT_LOAD_EXTENSION=1 \
-DUSE_SYSTEM_SQLITE=$(USE_SYSTEM_SQLITE) \
-DSQLITE_SHELL_DBNAME_PROC=sqlcmd_get_dbname \
-DSQLITE_SHELL_INIT_PROC=sqlcmd_init_proc
| > | 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 |
-DSQLITE_ENABLE_FTS4 \
-DSQLITE_ENABLE_DBSTAT_VTAB \
-DSQLITE_ENABLE_FTS5 \
-DSQLITE_ENABLE_STMTVTAB \
-DSQLITE_HAVE_ZLIB \
-DSQLITE_ENABLE_DBPAGE_VTAB \
-DSQLITE_TRUSTED_SCHEMA=0 \
-DHAVE_USLEEP \
-Dmain=sqlite3_shell \
-DSQLITE_SHELL_IS_UTF8=1 \
-DSQLITE_OMIT_LOAD_EXTENSION=1 \
-DUSE_SYSTEM_SQLITE=$(USE_SYSTEM_SQLITE) \
-DSQLITE_SHELL_DBNAME_PROC=sqlcmd_get_dbname \
-DSQLITE_SHELL_INIT_PROC=sqlcmd_init_proc
|
| ︙ | ︙ | |||
2114 2115 2116 2117 2118 2119 2120 | $(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 | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 |
$(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
$(EMCC_WRAPPER) -o $@ $(EMCC_OPT) --no-entry \
-sEXPORTED_RUNTIME_METHODS=cwrap,setValue,getValue,stackSave,stackRestore \
-sEXPORTED_FUNCTIONS=_pikchr $(SRCDIR_extsrc)/pikchr.c \
-sENVIRONMENT=web \
-sMODULARIZE \
-sEXPORT_NAME=initPikchrModule \
--minify 0
@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
# tools, as those compile with BCC, which may differ from TCC.
# e.g. BCC might be gcc (which does not support -MJ ...) while TCC is
# clang (which does).
#
# What follows is more verbose than strictly necessary because we're
# limited to POSIX make syntax.
all:
compile-commands-dir.yes = $(OBJDIR)
compile-commands-dir.no =
compile-commands-dir = $(compile-commands-dir.$(MAKE_COMPILATION_DB))
compile-command-args.yes = -MJ $(TOPDIR)/$(compile-commands-dir)/$(@F:.o=.o.json)
compile-command-args.no =
TCCFLAGS += $(compile-command-args.$(MAKE_COMPILATION_DB))
compile_commands.json = $(TOPDIR)/compile_commands.json
# compile_commands.json is a concatenation of the .o.json files
# generated by the compilation process via TCCFLAGS. We have a
# potential race condition in parallel builds, where a .o.json file is
# not yet written to completion before compile_commands.json is
# processed. How to resolve that in a way compatible with POSIX make
# is unclear.
#
# This obscure sed bit ensures that the resulting JSON array does not
# have a trailing comma.
$(compile_commands.json): $(OBJ)
@-rm -f $@
@{ echo '['; cat $(compile-commands-dir)/*.o.json | tr '\n' ' ' | sed -e 's/, $$//'; echo ']'; } > $@
@echo "Generated $@"
compile-commands.no:
compile-commands.yes: $(compile_commands.json)
all: compile-commands.$(MAKE_COMPILATION_DB)
clean: compile-commands-clean
compile-commands-clean:
rm -fr $(compile_commands.json)
#
# End compile_commands.json support
#
#
# The list of all the targets that do not correspond to real files. This stops
# 'make' from getting confused when someone makes an error in a rule.
#
.PHONY: all install test clean
.PHONY: compile-commands-clean compile-commands-dir
|
Changes to src/manifest.c.
| ︙ | ︙ | |||
1288 1289 1290 1291 1292 1293 1294 | ** ** Parse all entries in the BLOB table that are believed to be non-data ** artifacts and report any errors. Run this test command on historical ** repositories after making any changes to the manifest_parse() ** implementation to confirm that the changes did not break anything. ** ** Options: | < | 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 | ** ** Parse all entries in the BLOB table that are believed to be non-data ** artifacts and report any errors. Run this test command on historical ** repositories after making any changes to the manifest_parse() ** implementation to confirm that the changes did not break anything. ** ** Options: ** --limit N Parse no more than N artifacts before stopping ** --wellformed Use all BLOB table entries as input, not just ** those entries that are believed to be valid ** artifacts, and verify that the result the ** manifest_is_well_formed() agrees with the ** result of manifest_parse(). */ |
| ︙ | ︙ | |||
1932 1933 1934 1935 1936 1937 1938 |
isPublic, 1, manifest_file_mperm(&p->aFile[i]));
}
}
return parentid;
}
/*
| | | 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 |
isPublic, 1, manifest_file_mperm(&p->aFile[i]));
}
}
return parentid;
}
/*
** There exists a "parent" tag against check-in rid that has value zValue.
** If value is well-formed (meaning that it is a list of hashes), then use
** zValue to reparent check-in rid.
*/
void manifest_reparent_checkin(int rid, const char *zValue){
int nParent = 0;
char *zCopy = 0;
char **azParent = 0;
|
| ︙ | ︙ | |||
2196 2197 2198 2199 2200 2201 2202 |
pManifest->zTicketUuid, pManifest->zTicketUuid, zTitle
);
blob_appendf(&brief, "New ticket [%!S|%S].", pManifest->zTicketUuid,
pManifest->zTicketUuid);
}
fossil_free(zTitle);
manifest_create_event_triggers();
| > > > > > | > > > > > > > | | | | | > | 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 |
pManifest->zTicketUuid, pManifest->zTicketUuid, zTitle
);
blob_appendf(&brief, "New ticket [%!S|%S].", pManifest->zTicketUuid,
pManifest->zTicketUuid);
}
fossil_free(zTitle);
manifest_create_event_triggers();
if( db_exists("SELECT 1 FROM event WHERE type='t' AND objid=%d", rid) ){
/* The ticket_rebuild_entry() function redoes all of the event entries
** for a ticket whenever a new event appears. Be careful to only UPDATE
** existing events, so that they do not get turned into alerts by
** the alert trigger. */
db_multi_exec(
"UPDATE event SET tagid=%d, mtime=%.17g, user=%Q, comment=%Q, brief=%Q"
" WHERE objid=%d",
tktTagId, pManifest->rDate, pManifest->zUser,
blob_str(&comment), blob_str(&brief), rid
);
}else{
db_multi_exec(
"REPLACE INTO event(type,tagid,mtime,objid,user,comment,brief)"
"VALUES('t',%d,%.17g,%d,%Q,%Q,%Q)",
tktTagId, pManifest->rDate, rid, pManifest->zUser,
blob_str(&comment), blob_str(&brief)
);
}
blob_reset(&comment);
blob_reset(&brief);
}
/*
** Add an extra line of text to the end of a manifest to prevent it being
** recognized as a valid manifest.
|
| ︙ | ︙ |
Changes to src/markdown.c.
| ︙ | ︙ | |||
111 112 113 114 115 116 117 | #define MKD_CELL_ALIGN_LEFT 1 #define MKD_CELL_ALIGN_RIGHT 2 #define MKD_CELL_ALIGN_CENTER 3 /* LEFT | RIGHT */ #define MKD_CELL_ALIGN_MASK 3 #define MKD_CELL_HEAD 4 | < < < < < < < < < < < < < < | 111 112 113 114 115 116 117 118 119 120 121 122 123 124 | #define MKD_CELL_ALIGN_LEFT 1 #define MKD_CELL_ALIGN_RIGHT 2 #define MKD_CELL_ALIGN_CENTER 3 /* LEFT | RIGHT */ #define MKD_CELL_ALIGN_MASK 3 #define MKD_CELL_HEAD 4 #endif /* INTERFACE */ #define BLOB_COUNT(pBlob,el_type) (blob_size(pBlob)/sizeof(el_type)) #define COUNT_FOOTNOTES(pBlob) BLOB_COUNT(pBlob,struct footnote) #define CAST_AS_FOOTNOTES(pBlob) ((struct footnote*)blob_buffer(pBlob)) /*************** |
| ︙ | ︙ | |||
394 395 396 397 398 399 400 |
/* release the given working buffer back to the cache */
static void release_work_buffer(struct render *rndr, struct Blob *buf){
if( !buf ) return;
rndr->iDepth--;
blob_reset(buf);
| | | 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 |
/* release the given working buffer back to the cache */
static void release_work_buffer(struct render *rndr, struct Blob *buf){
if( !buf ) return;
rndr->iDepth--;
blob_reset(buf);
if( rndr->nBlobCache < (int)(sizeof(rndr->aBlobCache)/sizeof(rndr->aBlobCache[0])) ){
rndr->aBlobCache[rndr->nBlobCache++] = buf;
}else{
fossil_free(buf);
}
}
|
| ︙ | ︙ | |||
1568 1569 1570 1571 1572 1573 1574 |
/* Return the number of characters in the delimiter of a fenced code
** block. */
static size_t prefix_fencedcode(char *data, size_t size){
char c = data[0];
int nb;
if( c!='`' && c!='~' ) return 0;
| | | | 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 |
/* Return the number of characters in the delimiter of a fenced code
** block. */
static size_t prefix_fencedcode(char *data, size_t size){
char c = data[0];
int nb;
if( c!='`' && c!='~' ) return 0;
for(nb=1; nb<(int)size-3 && data[nb]==c; nb++){}
if( nb<3 ) return 0;
if( nb>=(int)size-nb ) return 0;
return nb;
}
/* prefix_oli -- returns ordered list item prefix */
static size_t prefix_oli(char *data, size_t size){
size_t i = 0;
if( i<size && data[i]==' ') i++;
|
| ︙ | ︙ | |||
1685 1686 1687 1688 1689 1690 1691 |
size_t i = 0, end = 0;
int level = 0;
char *work_data = data;
size_t work_size = 0;
while( i<size ){
char *zEnd = memchr(data+i, '\n', size-i-1);
| | | > > > > | 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 |
size_t i = 0, end = 0;
int level = 0;
char *work_data = data;
size_t work_size = 0;
while( i<size ){
char *zEnd = memchr(data+i, '\n', size-i-1);
end = zEnd==0 ? size : (size_t)(zEnd - (data-1));
/* The above is the same as:
** for(end=i+1; end<size && data[end-1]!='\n'; end++);
** "end" is left with a value such that data[end] is one byte
** past the first '\n' or one byte past the end of the string */
if( is_empty(data+i, size-i)
|| (level = is_headerline(data+i, size-i))!= 0
){
break;
}
if( (i && data[i]=='#')
|| is_hrule(data+i, size-i)
|| prefix_uli(data+i, size-i)
|| prefix_oli(data+i, size-i)
){
end = i;
break;
}
i = end;
}
work_size = i;
|
| ︙ | ︙ | |||
1758 1759 1760 1761 1762 1763 1764 |
){
size_t beg, end, pre;
struct Blob *work = new_work_buffer(rndr);
beg = 0;
while( beg<size ){
char *zEnd = memchr(data+beg, '\n', size-beg-1);
| | | 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 |
){
size_t beg, end, pre;
struct Blob *work = new_work_buffer(rndr);
beg = 0;
while( beg<size ){
char *zEnd = memchr(data+beg, '\n', size-beg-1);
end = zEnd==0 ? size : (size_t)(zEnd - (data-1));
/* The above is the same as:
** for(end=beg+1; end<size && data[end-1]!='\n'; end++);
** "end" is left with a value such that data[end] is one byte
** past the first \n or past then end of the string. */
pre = prefix_code(data+beg, end-beg);
if( pre ){
beg += pre; /* skipping prefix */
|
| ︙ | ︙ | |||
1968 1969 1970 1971 1972 1973 1974 |
size_t size
){
int level = 0;
size_t i, end, skip, span_beg, span_size;
if( !size || data[0]!='#' ) return 0;
| | | | 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 |
size_t size
){
int level = 0;
size_t i, end, skip, span_beg, span_size;
if( !size || data[0]!='#' ) return 0;
while( level<(int)size && level<6 && data[level]=='#' ){ level++; }
for(i=level; i<size && (data[i]==' ' || data[i]=='\t'); i++);
if ( (int)i == level ) return parse_paragraph(ob, rndr, data, size);
span_beg = i;
for(end=i; end<size && data[end]!='\n'; end++);
skip = end;
if( end<=i ) return parse_paragraph(ob, rndr, data, size);
while( end && data[end-1]=='#' ){ end--; }
while( end && (data[end-1]==' ' || data[end-1]=='\t') ){ end--; }
|
| ︙ | ︙ | |||
2003 2004 2005 2006 2007 2008 2009 |
size_t size
){
size_t i, w;
/* assuming data[0]=='<' && data[1]=='/' already tested */
/* checking tag is a match */
| | | 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 |
size_t size
){
size_t i, w;
/* assuming data[0]=='<' && data[1]=='/' already tested */
/* checking tag is a match */
if( (tag->size+3)>(int)size
|| fossil_strnicmp(data+2, tag->text, tag->size)
|| data[tag->size+2]!='>'
){
return 0;
}
/* checking white lines */
|
| ︙ | ︙ | |||
2633 2634 2635 2636 2637 2638 2639 |
void markdown(
struct Blob *ob, /* output blob for rendered text */
const struct Blob *ib, /* input blob in markdown */
const struct mkd_renderer *rndrer /* renderer descriptor (callbacks) */
){
struct link_ref *lr;
struct footnote *fn;
| > | | 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 |
void markdown(
struct Blob *ob, /* output blob for rendered text */
const struct Blob *ib, /* input blob in markdown */
const struct mkd_renderer *rndrer /* renderer descriptor (callbacks) */
){
struct link_ref *lr;
struct footnote *fn;
int i;
size_t beg, end = 0;
struct render rndr;
size_t size;
Blob text = BLOB_INITIALIZER; /* input after the first pass */
Blob * const allNotes = &rndr.notes.all;
/* filling the render structure */
if( !rndrer ) return;
|
| ︙ | ︙ | |||
2717 2718 2719 2720 2721 2722 2723 |
int nDups = 0;
fn = CAST_AS_FOOTNOTES( allNotes );
qsort(fn, rndr.notes.nLbled, sizeof(struct footnote), cmp_footnote_id);
/* concatenate footnotes with equal labels */
for(i=0; i<rndr.notes.nLbled ;){
struct footnote *x = fn + i;
| > | | | | | 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 |
int nDups = 0;
fn = CAST_AS_FOOTNOTES( allNotes );
qsort(fn, rndr.notes.nLbled, sizeof(struct footnote), cmp_footnote_id);
/* concatenate footnotes with equal labels */
for(i=0; i<rndr.notes.nLbled ;){
struct footnote *x = fn + i;
int j = i+1;
size_t k = blob_size(&x->text) + 64 + blob_size(&x->upc);
while(j<rndr.notes.nLbled && !blob_compare(&x->id, &fn[j].id)){
k += blob_size(&fn[j].text) + 10 + blob_size(&fn[j].upc);
j++;
nDups++;
}
if( i+1<j ){
Blob list = empty_blob;
blob_reserve(&list, k);
/* must match _joined_footnote_indicator in html_footnote_item() */
blob_append_literal(&list, "<ul class='fn-joined'>\n");
for(k=i; (int)k<j; k++){
struct footnote *y = fn + k;
blob_append_literal(&list, "<li>");
if( blob_size(&y->upc) ){
blob_appendb(&list, &y->upc);
blob_reset(&y->upc);
}
blob_appendb(&list, &y->text);
blob_append_literal(&list, "</li>\n");
/* free memory buffer */
blob_reset(&y->text);
if( (int)k!=i ) blob_reset(&y->id);
}
blob_append_literal(&list, "</ul>\n");
x->text = list;
g.ftntsIssues[2]++;
}
i = j;
}
if( nDups ){ /* clean rndr.notes.all from invalidated footnotes */
const int n = rndr.notes.nLbled - nDups;
struct Blob filtered = empty_blob;
blob_reserve(&filtered, n*sizeof(struct footnote));
for(i=0; i<rndr.notes.nLbled; i++){
if( blob_size(&fn[i].id) ){
blob_append(&filtered, (char*)(fn+i), sizeof(struct footnote));
}
}
blob_reset( allNotes );
rndr.notes.all = filtered;
rndr.notes.nLbled = n;
assert( (int)(COUNT_FOOTNOTES(allNotes)) == rndr.notes.nLbled );
}
}
fn = CAST_AS_FOOTNOTES( allNotes );
for(i=0; i<rndr.notes.nLbled; i++){
fn[i].index = i;
}
assert( rndr.notes.nMarks==0 );
|
| ︙ | ︙ | |||
2828 2829 2830 2831 2832 2833 2834 |
/* Assert that the in-memory layout of id, text and upc within
** footnote struct matches the expectations of html_footnote_item()
** If it doesn't then a compiler has done something very weird.
*/
assert( &(rndr.notes.misref.id) == &(rndr.notes.misref.text) - 1 );
assert( &(rndr.notes.misref.upc) == &(rndr.notes.misref.text) + 1 );
| | | | | | 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 |
/* Assert that the in-memory layout of id, text and upc within
** footnote struct matches the expectations of html_footnote_item()
** If it doesn't then a compiler has done something very weird.
*/
assert( &(rndr.notes.misref.id) == &(rndr.notes.misref.text) - 1 );
assert( &(rndr.notes.misref.upc) == &(rndr.notes.misref.text) + 1 );
for(i=0; i<(int)(COUNT_FOOTNOTES(notes)); i++){
const struct footnote* x = CAST_AS_FOOTNOTES(notes) + i;
const int xUsed = x->bRndred ? x->nUsed : 0;
if( !x->iMark ) break;
assert( x->nUsed );
rndr.make.footnote_item(all_items, &x->text, x->iMark,
xUsed, rndr.make.opaque);
if( !xUsed ) g.ftntsIssues[3]++; /* an overnested footnote */
j = i;
}
if( rndr.notes.misref.nUsed ){
rndr.make.footnote_item(all_items, 0, -1,
rndr.notes.misref.nUsed, rndr.make.opaque);
g.ftntsIssues[0] += rndr.notes.misref.nUsed;
}
while( ++j < (int)(COUNT_FOOTNOTES(notes)) ){
const struct footnote* x = CAST_AS_FOOTNOTES(notes) + j;
assert( !x->iMark );
assert( !x->nUsed );
assert( !x->bRndred );
rndr.make.footnote_item(all_items,&x->text,0,0,rndr.make.opaque);
g.ftntsIssues[1]++;
}
rndr.make.footnotes(ob, all_items, rndr.make.opaque);
release_work_buffer(&rndr, all_items);
}
release_work_buffer(&rndr, notes);
}
if( rndr.make.epilog ) rndr.make.epilog(ob, rndr.make.opaque);
/* clean-up */
assert( rndr.iDepth==0 );
blob_reset(&text);
lr = (struct link_ref *)blob_buffer(&rndr.refs);
end = blob_size(&rndr.refs)/sizeof(struct link_ref);
for(i=0; i<(int)end; i++){
blob_reset(&lr[i].id);
blob_reset(&lr[i].link);
blob_reset(&lr[i].title);
}
blob_reset(&rndr.refs);
fn = CAST_AS_FOOTNOTES( allNotes );
end = COUNT_FOOTNOTES( allNotes );
for(i=0; i<(int)end; i++){
if(blob_size(&fn[i].id)) blob_reset(&fn[i].id);
if(blob_size(&fn[i].upc)) blob_reset(&fn[i].upc);
blob_reset(&fn[i].text);
}
blob_reset(&rndr.notes.all);
for(i=0; i<rndr.nBlobCache; i++){
fossil_free(rndr.aBlobCache[i]);
}
}
|
Changes to src/markdown.md.
| ︙ | ︙ | |||
153 154 155 156 157 158 159 | ~~~ pikchr oval "Start" fit; arrow; box "Hello, World!" fit; arrow; oval "Done" fit ~~~ <a id="ftnts"></a> ## Footnotes ## | | | 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 | ~~~ pikchr oval "Start" fit; arrow; box "Hello, World!" fit; arrow; oval "Done" fit ~~~ <a id="ftnts"></a> ## Footnotes ## > Footnotes (or "endnotes") is a Fossil extension of classical Markdown. > Fossil's syntax for footnotes is similar to links and > is distinguished by the use of character **^** > that *immediately* follows an opening bracket. > 1. **\(^** footnote's text **)** > 2. **\[** fragment of text **]\(^** a comment about that fragment **\)** > 3. **\[^** label **\]** |
| ︙ | ︙ |
Changes to src/markdown_html.c.
| ︙ | ︙ | |||
228 229 230 231 232 233 234 |
blob_appendf(ob, "<h%d>", level);
blob_appendb(ob, text);
blob_appendf(ob, "</h%d>", level);
}
static void html_hrule(struct Blob *ob, void *opaque){
INTER_BLOCK(ob);
| | | 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 |
blob_appendf(ob, "<h%d>", level);
blob_appendb(ob, text);
blob_appendf(ob, "</h%d>", level);
}
static void html_hrule(struct Blob *ob, void *opaque){
INTER_BLOCK(ob);
blob_append_literal(ob, "<hr>\n");
}
static void html_list(
struct Blob *ob,
struct Blob *text,
int flags,
|
| ︙ | ︙ | |||
400 401 402 403 404 405 406 |
const struct MarkdownToHtml* ctx = (struct MarkdownToHtml*)opaque;
const bitfield64_t l = to_base26(locus-1,0);
char pos[32];
memset(pos,0,32);
assert( locus > 0 );
/* expect BUGs if the following yields compiler warnings */
if( iMark > 0 ){ /* a regular reference to a footnote */
| | | 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 |
const struct MarkdownToHtml* ctx = (struct MarkdownToHtml*)opaque;
const bitfield64_t l = to_base26(locus-1,0);
char pos[32];
memset(pos,0,32);
assert( locus > 0 );
/* expect BUGs if the following yields compiler warnings */
if( iMark > 0 ){ /* a regular reference to a footnote */
sqlite3_snprintf(sizeof(pos), pos, "%s-%d-%s", ctx->unique.c, iMark, l.c);
if(span && blob_size(span)) {
blob_append_literal(ob,"<span class='");
append_footnote_upc(ob, upc, 0);
blob_append_literal(ob,"notescope' id='noteref");
blob_appendf(ob,"%s'>",pos);
blob_appendb(ob, span);
blob_trim(ob);
|
| ︙ | ︙ | |||
423 424 425 426 427 428 429 |
BLOB_APPEND_URI(ob, ctx);
blob_appendf(ob,"#footnote%s' id='noteref%s'>%d</a></sup>",
pos, pos, iMark);
}
}else{ /* misreference */
assert( iMark == -1 );
| | | 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 |
BLOB_APPEND_URI(ob, ctx);
blob_appendf(ob,"#footnote%s' id='noteref%s'>%d</a></sup>",
pos, pos, iMark);
}
}else{ /* misreference */
assert( iMark == -1 );
sqlite3_snprintf(sizeof(pos), pos, "%s-%s", ctx->unique.c, l.c);
if(span && blob_size(span)) {
blob_appendf(ob, "<span class='notescope' id='misref%s'>", pos);
blob_appendb(ob, span);
blob_trim(ob);
blob_append_literal(ob, "<sup class='noteref misref'><a href='");
BLOB_APPEND_URI(ob, ctx);
blob_appendf(ob, "#misreference%s'>misref</a></sup></span>", pos);
|
| ︙ | ︙ | |||
483 484 485 486 487 488 489 |
#define _joined_footnote_indicator "<ul class='fn-joined'>"
#define _jfi_sz (sizeof(_joined_footnote_indicator)-1)
/* make.footnote_item() invocations should pass args accordingly */
const struct Blob *upc = text+1;
assert( text );
/* allow blob_size(text)==0 for constructs like [...](^ [] ()) */
memset(pos,0,24);
| | | 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 |
#define _joined_footnote_indicator "<ul class='fn-joined'>"
#define _jfi_sz (sizeof(_joined_footnote_indicator)-1)
/* make.footnote_item() invocations should pass args accordingly */
const struct Blob *upc = text+1;
assert( text );
/* allow blob_size(text)==0 for constructs like [...](^ [] ()) */
memset(pos,0,24);
sqlite3_snprintf(sizeof(pos), pos, "%s-%d", unique, iMark);
blob_appendf(ob, "<li id='footnote%s' class='", pos);
if( nUsed ){
if( blob_size(text)>=_jfi_sz &&
!memcmp(blob_buffer(text),_joined_footnote_indicator,_jfi_sz)){
bJoin = 1;
blob_append_literal(ob, "fn-joined ");
}
|
| ︙ | ︙ | |||
756 757 758 759 760 761 762 |
html_quote(ob, blob_buffer(link), blob_size(link));
blob_append_literal(ob, "\" alt=\"");
html_quote(ob, blob_buffer(alt), blob_size(alt));
if( title && blob_size(title)>0 ){
blob_append_literal(ob, "\" title=\"");
html_quote(ob, blob_buffer(title), blob_size(title));
}
| | | | 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 |
html_quote(ob, blob_buffer(link), blob_size(link));
blob_append_literal(ob, "\" alt=\"");
html_quote(ob, blob_buffer(alt), blob_size(alt));
if( title && blob_size(title)>0 ){
blob_append_literal(ob, "\" title=\"");
html_quote(ob, blob_buffer(title), blob_size(title));
}
blob_append_literal(ob, "\">");
return 1;
}
static int html_linebreak(struct Blob *ob, void *opaque){
blob_append_literal(ob, "<br>\n");
return 1;
}
static int html_link(
struct Blob *ob,
struct Blob *link,
struct Blob *title,
|
| ︙ | ︙ |
Changes to src/merge.c.
| ︙ | ︙ | |||
133 134 135 136 137 138 139 | /* ** Add an entry to the FV table for all files renamed between ** version N and the version specified by vid. */ static void add_renames( const char *zFnCol, /* The FV column for the filename in vid */ | | | | 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 |
/*
** Add an entry to the FV table for all files renamed between
** version N and the version specified by vid.
*/
static void add_renames(
const char *zFnCol, /* The FV column for the filename in vid */
int vid, /* The desired version's- RID */
int nid, /* The check-in rid for the name pivot */
int revOK, /* OK to move backwards (child->parent) if true */
const char *zDebug /* Generate trace output if not NULL */
){
int nChng; /* Number of file name changes */
int *aChng; /* An array of file name changes */
int i; /* Loop counter */
find_filename_changes(nid, vid, revOK, &nChng, &aChng, zDebug);
|
| ︙ | ︙ | |||
277 278 279 280 281 282 283 | /* ** COMMAND: merge ** COMMAND: cherry-pick ** ** Usage: %fossil merge ?OPTIONS? ?VERSION? ** ** The argument VERSION is a version that should be merged into the | | | | | | > > > < < < < < < < < | < | < | < | < < < | 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 |
/*
** COMMAND: merge
** COMMAND: cherry-pick
**
** Usage: %fossil merge ?OPTIONS? ?VERSION?
**
** The argument VERSION is a version that should be merged into the
** current check-out. All changes from VERSION back to the nearest
** common ancestor are merged. Except, if either of the --cherrypick
** or --backout options are used only the changes associated with the
** single check-in VERSION are merged. The --backout option causes
** the changes associated with VERSION to be removed from the current
** check-out rather than added. When invoked with the name
** cherry-pick, this command works exactly like merge --cherrypick.
**
** Files which are renamed in the merged-in branch will be renamed in
** the current check-out.
**
** If the VERSION argument is omitted, then Fossil attempts to find
** a recent fork on the current branch to merge.
**
** Options:
** --backout Do a reverse cherrypick merge against VERSION.
** In other words, back out the changes that were
** added by VERSION.
** --baseline BASELINE Use BASELINE as the "pivot" of the merge instead
** of the nearest common ancestor. This allows
** a sequence of changes in a branch to be merged
** without having to merge the entire branch.
** --binary GLOBPATTERN Treat files that match GLOBPATTERN as binary
** and do not try to merge parallel changes. This
** option overrides the "binary-glob" setting.
** --cherrypick Do a cherrypick merge VERSION into the current
** check-out. A cherrypick merge pulls in the changes
** of the single check-in VERSION, rather than all
** changes back to the nearest common ancestor.
** -f|--force Force the merge even if it would be a no-op
** --force-missing Force the merge even if there is missing content
** --integrate Merged branch will be closed when committing
** -K|--keep-merge-files On merge conflict, retain the temporary files
** used for merging, named *-baseline, *-original,
** and *-merge.
** -n|--dry-run If given, display instead of run actions
** -v|--verbose Show additional details of the merge
*/
void merge_cmd(void){
int vid; /* Current version "V" */
int mid; /* Version we are merging from "M" */
int pid = 0; /* The pivot version - most recent common ancestor P */
int nid = 0; /* The name pivot version "N" */
|
| ︙ | ︙ | |||
351 352 353 354 355 356 357 | int nOverwrite = 0; /* Number of unmanaged files overwritten */ char vAncestor = 'p'; /* If P is an ancestor of V then 'p', else 'n' */ Stmt q; /* Notation: ** | | | 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 |
int nOverwrite = 0; /* Number of unmanaged files overwritten */
char vAncestor = 'p'; /* If P is an ancestor of V then 'p', else 'n' */
Stmt q;
/* Notation:
**
** V The current check-out
** M The version being merged in
** P The "pivot" - the most recent common ancestor of V and M.
** N The "name pivot" - for detecting renames
*/
undo_capture_command_line();
verboseFlag = find_option("verbose","v",0)!=0;
|
| ︙ | ︙ | |||
421 422 423 424 425 426 427 |
mid = name_to_typed_rid(g.argv[2], "ci");
if( mid==0 || !is_a_version(mid) ){
fossil_fatal("not a version: %s", g.argv[2]);
}
}else if( g.argc==2 ){
/* No version specified on the command-line so pick the most recent
** leaf that is (1) not the version currently checked out and (2)
| | | | 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 |
mid = name_to_typed_rid(g.argv[2], "ci");
if( mid==0 || !is_a_version(mid) ){
fossil_fatal("not a version: %s", g.argv[2]);
}
}else if( g.argc==2 ){
/* No version specified on the command-line so pick the most recent
** leaf that is (1) not the version currently checked out and (2)
** has not already been merged into the current check-out and (3)
** the leaf is not closed and (4) the leaf is in the same branch
** as the current check-out.
*/
Stmt q;
if( pickFlag || backoutFlag || integrateFlag){
fossil_fatal("cannot use --backout, --cherrypick or --integrate "
"with a fork merge");
}
mid = fossil_find_nearest_fork(vid, db_open_local(0));
|
| ︙ | ︙ | |||
490 491 492 493 494 495 496 |
while( db_step(&q)==SQLITE_ROW ){
pivot_set_secondary(db_column_int(&q,0));
}
db_finalize(&q);
pid = pivot_find(0);
if( pid<=0 ){
fossil_fatal("cannot find a common ancestor between the current "
| | | 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 |
while( db_step(&q)==SQLITE_ROW ){
pivot_set_secondary(db_column_int(&q,0));
}
db_finalize(&q);
pid = pivot_find(0);
if( pid<=0 ){
fossil_fatal("cannot find a common ancestor between the current "
"check-out and %s", g.argv[2]);
}
}
pivot_set_primary(mid);
pivot_set_secondary(vid);
nid = pivot_find(1);
if( nid!=pid ){
pivot_set_primary(nid);
|
| ︙ | ︙ | |||
569 570 571 572 573 574 575 |
fossil_print("vAncestor = '%c'\n", vAncestor);
}
if( showVfileFlag ) debug_show_vfile();
/*
** The vfile.pathname field is used to match files against each other. The
** FV table contains one row for each each unique filename in
| | | 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 |
fossil_print("vAncestor = '%c'\n", vAncestor);
}
if( showVfileFlag ) debug_show_vfile();
/*
** The vfile.pathname field is used to match files against each other. The
** FV table contains one row for each each unique filename in
** in the current check-out, the pivot, and the version being merged.
*/
db_multi_exec(
"DROP TABLE IF EXISTS fv;"
"CREATE TEMP TABLE fv(\n"
" fn TEXT UNIQUE %s,\n" /* The filename */
" idv INTEGER DEFAULT 0,\n" /* VFILE entry for current version */
" idp INTEGER DEFAULT 0,\n" /* VFILE entry for the pivot */
|
| ︙ | ︙ | |||
770 771 772 773 774 775 776 |
debug_fv_dump( debugFlag>=2 );
}
/************************************************************************
** All of the information needed to do the merge is now contained in the
** FV table. Starting here, we begin to actually carry out the merge.
**
| < < < < < < < < < < < < < < < < < | | 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 |
debug_fv_dump( debugFlag>=2 );
}
/************************************************************************
** All of the information needed to do the merge is now contained in the
** FV table. Starting here, we begin to actually carry out the merge.
**
** First, find files that have changed from P->M but not P->V.
** Copy the M content over into V.
*/
db_prepare(&q,
"SELECT idv, ridm, fn, islinkm FROM fv"
" WHERE idp>0 AND idv>0 AND idm>0"
" AND ridm!=ridp AND ridv=ridp AND NOT chnged"
);
|
| ︙ | ︙ | |||
817 818 819 820 821 822 823 824 825 826 |
vfile_to_disk(0, idv, 0, 0);
}
}
db_finalize(&q);
/*
** Do a three-way merge on files that have changes on both P->M and P->V.
*/
db_prepare(&q,
"SELECT ridm, idv, ridp, ridv, %s, fn, isexe, islinkv, islinkm FROM fv"
| > > > > | | 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 |
vfile_to_disk(0, idv, 0, 0);
}
}
db_finalize(&q);
/*
** Do a three-way merge on files that have changes on both P->M and P->V.
**
** Proceed even if the file doesn't exist on P, just like the common ancestor
** of M and V is an empty file. In this case, merge conflict marks will be
** added to the file and user will be forced to take a decision.
*/
db_prepare(&q,
"SELECT ridm, idv, ridp, ridv, %s, fn, isexe, islinkv, islinkm FROM fv"
" WHERE idv>0 AND idm>0"
" AND ridm!=ridp AND (ridv!=ridp OR chnged)",
glob_expr("fv.fn", zBinGlob)
);
while( db_step(&q)==SQLITE_ROW ){
int ridm = db_column_int(&q, 0);
int idv = db_column_int(&q, 1);
int ridp = db_column_int(&q, 2);
|
| ︙ | ︙ |
Changes to src/merge3.c.
| ︙ | ︙ | |||
454 455 456 457 458 459 460 |
if( blob_read_from_file(&v1, g.argv[3], ExtFILE)<0 ){
fossil_fatal("cannot read %s", g.argv[3]);
}
if( blob_read_from_file(&v2, g.argv[4], ExtFILE)<0 ){
fossil_fatal("cannot read %s", g.argv[4]);
}
nConflict = blob_merge(&pivot, &v1, &v2, &merged);
| | | 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 |
if( blob_read_from_file(&v1, g.argv[3], ExtFILE)<0 ){
fossil_fatal("cannot read %s", g.argv[3]);
}
if( blob_read_from_file(&v2, g.argv[4], ExtFILE)<0 ){
fossil_fatal("cannot read %s", g.argv[4]);
}
nConflict = blob_merge(&pivot, &v1, &v2, &merged);
if( blob_write_to_file(&merged, g.argv[5])<(int)blob_size(&merged) ){
fossil_fatal("cannot write %s", g.argv[4]);
}
blob_reset(&pivot);
blob_reset(&v1);
blob_reset(&v2);
blob_reset(&merged);
if( nConflict>0 ) fossil_warning("WARNING: %d merge conflicts", nConflict);
|
| ︙ | ︙ |
Changes to src/name.c.
| ︙ | ︙ | |||
17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
**
** This file contains code used to resolved user-supplied object names.
*/
#include "config.h"
#include "name.h"
#include <assert.h>
/*
** Return TRUE if the string begins with something that looks roughly
** like an ISO date/time string. The SQLite date/time functions will
** have the final say-so about whether or not the date/time string is
** well-formed.
*/
int fossil_isdate(const char *z){
| > > > > > > > > > > > > > | 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 |
**
** This file contains code used to resolved user-supplied object names.
*/
#include "config.h"
#include "name.h"
#include <assert.h>
#if INTERFACE
/*
** An upper boundary on RIDs, provided in order to be able to
** distinguish real RID values from RID_CKOUT and any future
** RID_... values.
*/
#define RID_MAX 0x7ffffff0
/*
** A "magic" RID representing the current checkout in some contexts.
*/
#define RID_CKOUT (RID_MAX+1)
#endif
/*
** Return TRUE if the string begins with something that looks roughly
** like an ISO date/time string. The SQLite date/time functions will
** have the final say-so about whether or not the date/time string is
** well-formed.
*/
int fossil_isdate(const char *z){
|
| ︙ | ︙ | |||
163 164 165 166 167 168 169 |
" par(pid, ex, cnt) as ("
" SELECT pid, EXISTS(SELECT 1 FROM tagxref"
" WHERE tagid=%d AND tagtype>0"
" AND value=%Q AND rid=plink.pid), 1"
" FROM plink WHERE cid=%d AND isprim"
" UNION ALL "
" SELECT plink.pid, EXISTS(SELECT 1 FROM tagxref "
| | | | | 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 |
" par(pid, ex, cnt) as ("
" SELECT pid, EXISTS(SELECT 1 FROM tagxref"
" WHERE tagid=%d AND tagtype>0"
" AND value=%Q AND rid=plink.pid), 1"
" FROM plink WHERE cid=%d AND isprim"
" UNION ALL "
" SELECT plink.pid, EXISTS(SELECT 1 FROM tagxref "
" WHERE tagid=%d AND tagtype>0"
" AND value=%Q AND rid=plink.pid),"
" 1+par.cnt"
" FROM plink, par"
" WHERE cid=par.pid AND isprim AND par.ex "
" LIMIT 100000 "
" )"
" SELECT pid FROM par WHERE ex>=%d ORDER BY cnt DESC LIMIT 1",
TAG_BRANCH, zBr, ans, TAG_BRANCH, zBr, eType%2
);
fossil_free(zBr);
rc = db_step(&q);
if( rc==SQLITE_ROW ){
ans = db_column_int(&q, 0);
}
db_finalize(&q);
if( eType==2 && ans>0 ){
zBr = branch_of_rid(ans);
ans = compute_youngest_ancestor_in_branch(rid, zBr);
fossil_free(zBr);
}
return ans;
}
/*
** Find the RID of the most recent object with symbolic tag zTag
** and having a type that matches zType.
**
** 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 searching
** 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 show below as Q2.
*/
static int most_recent_event_with_tag(const char *zTag, const char *zType){
|
| ︙ | ︙ | |||
228 229 230 231 232 233 234 235 236 237 238 239 240 241 |
" AND event.objid=tagxref.rid"
" AND event.type GLOB '%q'"
" ORDER BY event.mtime DESC LIMIT 1"
") LIMIT 1;",
zType, zTag, zTag, zType
);
}
/*
** Return true if character "c" is a character that might have been
** accidentally appended to the end of a URL.
*/
static int is_trailing_punct(char c){
return c=='.' || c=='_' || c==')' || c=='>' || c=='!' || c=='?' || c==',';
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 |
" AND event.objid=tagxref.rid"
" AND event.type GLOB '%q'"
" ORDER BY event.mtime DESC LIMIT 1"
") LIMIT 1;",
zType, zTag, zTag, zType
);
}
/*
** Find the RID for a check-in that is the most recent check-in with
** tag zTag that occurs on or prior to rDate.
**
** See also the performance note on most_recent_event_with_tag() which
** applies to this routine too.
*/
int last_checkin_with_tag_before_date(const char *zTag, double rLimit){
Stmt s;
int rid = 0;
if( strncmp(zTag, "tag:", 4)==0 ) zTag += 4;
db_prepare(&s,
"SELECT objid FROM ("
/* Q1: Begin by looking for the tag in the 30 most recent events */
"SELECT objid"
" FROM (SELECT * FROM event WHERE mtime<=:datelimit"
" ORDER BY mtime DESC LIMIT 30) AS ex"
" WHERE type='ci'"
" AND EXISTS(SELECT 1 FROM tagxref, tag"
" WHERE tag.tagname='sym-%q'"
" AND tagxref.tagid=tag.tagid"
" AND tagxref.tagtype>0"
" AND tagxref.rid=ex.objid)"
" ORDER BY mtime DESC LIMIT 1"
") UNION ALL SELECT * FROM ("
/* Q2: If the tag is not found in the 30 most recent events, then using
** the tagxref table to index for the tag */
"SELECT event.objid"
" FROM tag, tagxref, event"
" WHERE tag.tagname='sym-%q'"
" AND tagxref.tagid=tag.tagid"
" AND tagxref.tagtype>0"
" AND event.objid=tagxref.rid"
" AND event.type='ci'"
" AND event.mtime<=:datelimit"
" ORDER BY event.mtime DESC LIMIT 1"
") LIMIT 1;",
zTag, zTag
);
db_bind_double(&s, ":datelimit", rLimit);
if( db_step(&s)==SQLITE_ROW ){
rid = db_column_int(&s,0);
}
db_finalize(&s);
return rid;
}
/*
** Find the RID of the first check-in (chronologically) after rStart that
** has tag zTag.
**
** See also the performance note on most_recent_event_with_tag() which
** applies to this routine too.
*/
int first_checkin_with_tag_after_date(const char *zTag, double rStart){
Stmt s;
int rid = 0;
if( strncmp(zTag, "tag:", 4)==0 ) zTag += 4;
db_prepare(&s,
"SELECT objid FROM ("
/* Q1: Begin by looking for the tag in the 30 most recent events */
"SELECT objid"
" FROM (SELECT * FROM event WHERE mtime>=:startdate"
" ORDER BY mtime LIMIT 30) AS ex"
" WHERE type='ci'"
" AND EXISTS(SELECT 1 FROM tagxref, tag"
" WHERE tag.tagname='sym-%q'"
" AND tagxref.tagid=tag.tagid"
" AND tagxref.tagtype>0"
" AND tagxref.rid=ex.objid)"
" ORDER BY mtime LIMIT 1"
") UNION ALL SELECT * FROM ("
/* Q2: If the tag is not found in the 30 most recent events, then using
** the tagxref table to index for the tag */
"SELECT event.objid"
" FROM tag, tagxref, event"
" WHERE tag.tagname='sym-%q'"
" AND tagxref.tagid=tag.tagid"
" AND tagxref.tagtype>0"
" AND event.objid=tagxref.rid"
" AND event.type='ci'"
" AND event.mtime>=:startdate"
" ORDER BY event.mtime LIMIT 1"
") LIMIT 1;",
zTag, zTag
);
db_bind_double(&s, ":startdate", rStart);
if( db_step(&s)==SQLITE_ROW ){
rid = db_column_int(&s,0);
}
db_finalize(&s);
return rid;
}
/*
** Return true if character "c" is a character that might have been
** accidentally appended to the end of a URL.
*/
static int is_trailing_punct(char c){
return c=='.' || c=='_' || c==')' || c=='>' || c=='!' || c=='?' || c==',';
|
| ︙ | ︙ | |||
263 264 265 266 267 268 269 | ** The following modifier prefixes may be applied to the above forms: ** ** * "root:BR" = The origin of the branch named BR. ** * "start:BR" = The first check-in of the branch named BR. ** * "merge-in:BR" = The most recent merge-in for the branch named BR. ** ** In those forms, BR may be any symbolic form but is assumed to be a | | | > > > > > | | > > > > > > > | > > | > > > > | < > > | | > | > > | 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 |
** The following modifier prefixes may be applied to the above forms:
**
** * "root:BR" = The origin of the branch named BR.
** * "start:BR" = The first check-in of the branch named BR.
** * "merge-in:BR" = The most recent merge-in for the branch named BR.
**
** In those forms, BR may be any symbolic form but is assumed to be a
** check-in. Thus root:2021-02-01 would resolve to a check-in, possibly
** in a branch and possibly in the trunk, but never a wiki edit or
** forum post.
**
** Return the RID of the matching artifact. Or return 0 if the name does not
** match any known object. Or return -1 if the name is ambiguous.
**
** The zType parameter specifies the type of artifact: ci, t, w, e, g, f.
** If zType is NULL or "" or "*" then any type of artifact will serve.
** If zType is "br" then find the first check-in of the named branch
** rather than the last.
**
** zType is "ci" in most use cases since we are usually searching for
** a check-in. A value of "ci+" works like "ci" but adds these
** semantics: if zTag is "ckout" and a checkout is open, "ci+" causes
** RID_CKOUT to be returned, in which case g.localOpen will hold the
** RID of the checkout. Conversely, passing in the hash, or another
** symbolic name of the local checkout version, will always result in
** its RID being returned.
**
** Note that the input zTag for types "t" and "e" is the artifact hash of
** the ticket-change or technote-change artifact, not the randomly generated
** hexadecimal identifier assigned to tickets and events. Those identifiers
** live in a separate namespace.
*/
int symbolic_name_to_rid(const char *zTag, const char *zType){
int rid = 0;
int ridCkout = 0;
int nTag;
int i;
int startOfBranch = 0;
const char *zXTag; /* zTag with optional [...] removed */
int nXTag; /* Size of zXTag */
const char *zDate; /* Expanded date-time string */
int isCheckin = 0; /* zType==ci = 1, zType==ci+ = 2 */
if( zType==0 || zType[0]==0 ){
zType = "*";
}else if( zType[0]=='b' ){
zType = "ci";
startOfBranch = 1;
}
if( zTag==0 || zTag[0]==0 ) return 0;
else if( 'c'==zType[0] ){
if( fossil_strcmp(zType,"ci")==0 ){
isCheckin = 1;
}else if( fossil_strcmp(zType,"ci+")==0 ){
isCheckin = 2;
zType = "ci";
}
}
/* special keyword: "tip" */
if( fossil_strcmp(zTag, "tip")==0 && (zType[0]=='*' || isCheckin!=0) ){
rid = db_int(0,
"SELECT objid"
" FROM event"
" WHERE type='ci'"
" ORDER BY event.mtime DESC"
);
if( rid ) return rid;
}
if( g.localOpen ) {
ridCkout = db_lget_int("checkout",0);
}
/* special keywords: "prev", "previous", "current", "ckout", and
** "next" */
if( (zType[0]=='*' || isCheckin!=0) && 0<ridCkout ){
if( fossil_strcmp(zTag, "current")==0 ){
rid = ridCkout;
}else if( fossil_strcmp(zTag, "prev")==0
|| fossil_strcmp(zTag, "previous")==0 ){
rid = db_int(0, "SELECT pid FROM plink WHERE cid=%d AND isprim",
ridCkout);
}else if( fossil_strcmp(zTag, "next")==0 ){
rid = db_int(0, "SELECT cid FROM plink WHERE pid=%d"
" ORDER BY isprim DESC, mtime DESC", ridCkout);
}else if( isCheckin>1 && fossil_strcmp(zTag, "ckout")==0 ){
rid = RID_CKOUT;
}
if( rid ) return rid;
}
/* Date and times */
if( memcmp(zTag, "date:", 5)==0 ){
zDate = fossil_expand_datetime(&zTag[5],0);
|
| ︙ | ︙ | |||
521 522 523 524 525 526 527 |
if( nTag>4
&& is_trailing_punct(zTag[nTag-1])
&& !is_trailing_punct(zTag[nTag-2])
){
char *zNew = fossil_strndup(zTag, nTag-1);
rid = symbolic_name_to_rid(zNew,zType);
fossil_free(zNew);
| | | 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 |
if( nTag>4
&& is_trailing_punct(zTag[nTag-1])
&& !is_trailing_punct(zTag[nTag-2])
){
char *zNew = fossil_strndup(zTag, nTag-1);
rid = symbolic_name_to_rid(zNew,zType);
fossil_free(zNew);
}else
if( nTag>5
&& is_trailing_punct(zTag[nTag-1])
&& is_trailing_punct(zTag[nTag-2])
&& !is_trailing_punct(zTag[nTag-3])
){
char *zNew = fossil_strndup(zTag, nTag-2);
rid = symbolic_name_to_rid(zNew,zType);
|
| ︙ | ︙ | |||
586 587 588 589 590 591 592 |
** negative value is returned. On success the rid is returned and
** pUuid (if it is not NULL) is set to a newly-allocated string,
** the full hash, which must eventually be free()d by the caller.
*/
int name_to_uuid2(const char *zName, const char *zType, char **pUuid){
int rid = symbolic_name_to_rid(zName, zType);
if((rid>0) && pUuid){
| > | > | 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 |
** negative value is returned. On success the rid is returned and
** pUuid (if it is not NULL) is set to a newly-allocated string,
** the full hash, which must eventually be free()d by the caller.
*/
int name_to_uuid2(const char *zName, const char *zType, char **pUuid){
int rid = symbolic_name_to_rid(zName, zType);
if((rid>0) && pUuid){
*pUuid = (rid<RID_MAX)
? db_text(NULL, "SELECT uuid FROM blob WHERE rid=%d", rid)
: NULL;
}
return rid;
}
/*
** name_collisions searches through events, blobs, and tickets for
|
| ︙ | ︙ | |||
621 622 623 624 625 626 627 | } return c; } /* ** COMMAND: test-name-to-id ** | | > > > > > | | 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 |
}
return c;
}
/*
** COMMAND: test-name-to-id
**
** Usage: %fossil test-name-to-id [--count N] [--type ARTIFACT_TYPE] NAME
**
** Convert a NAME to a full artifact ID. Repeat the conversion N
** times (for timing purposes) if the --count option is given.
*/
void test_name_to_id(void){
int i;
int n = 0;
Blob name;
const char *zType;
db_must_be_within_tree();
if( (zType = find_option("type","t",1))==0 ){
zType = "*";
}
for(i=2; i<g.argc; i++){
if( strcmp(g.argv[i],"--count")==0 && i+1<g.argc ){
i++;
n = atoi(g.argv[i]);
continue;
}
do{
blob_init(&name, g.argv[i], -1);
fossil_print("%s -> ", g.argv[i]);
if( name_to_uuid(&name, 1, zType) ){
fossil_print("ERROR: %s\n", g.zErrMsg);
fossil_error_reset();
}else{
fossil_print("%s\n", blob_buffer(&name));
}
blob_reset(&name);
}while( n-- > 0 );
|
| ︙ | ︙ | |||
846 847 848 849 850 851 852 | return zType; } /* ** Flag values for whatis_rid(). */ #if INTERFACE | | | > > | 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 |
return zType;
}
/*
** Flag values for whatis_rid().
*/
#if INTERFACE
#define WHATIS_VERBOSE 0x01 /* Extra output */
#define WHATIS_BRIEF 0x02 /* Omit unnecessary output */
#define WHATIS_REPO 0x04 /* Show repository name */
#define WHATIS_OMIT_UNK 0x08 /* Do not show "unknown" lines */
#endif
/*
** Generate a description of artifact "rid"
*/
void whatis_rid(int rid, int flags){
Stmt q;
|
| ︙ | ︙ | |||
1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 |
zDesc = db_text(0,
"SELECT printf('%%-12s%%s %%s',type||':',summary,substr(ref,1,16))"
" FROM description WHERE rid=%d", rid);
fossil_print("%s\n", zDesc);
fossil_free(zDesc);
}
}
/*
** COMMAND: whatis*
**
** Usage: %fossil whatis NAME
**
** Resolve the symbol NAME into its canonical artifact hash
** artifact name and provide a description of what role that artifact
** plays.
**
** Options:
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > | < | | > > > > > > | < | | > | > | | < > | | | < | > > > > > < < < | > < | | 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 |
zDesc = db_text(0,
"SELECT printf('%%-12s%%s %%s',type||':',summary,substr(ref,1,16))"
" FROM description WHERE rid=%d", rid);
fossil_print("%s\n", zDesc);
fossil_free(zDesc);
}
}
/*
** Generate a description of artifact from it symbolic name.
*/
void whatis_artifact(
const char *zName, /* Symbolic name or full hash */
const char *zFileName,/* Optional: original filename (in file mode) */
const char *zType, /* Artifact type filter */
int mFlags /* WHATIS_* flags */
){
int rid = symbolic_name_to_rid(zName, zType);
if( rid<0 ){
Stmt q;
int cnt = 0;
if( mFlags & WHATIS_REPO ){
fossil_print("\nrepository: %s\n", g.zRepositoryName);
}
if( zFileName ){
fossil_print("%-12s%s\n", "name:", zFileName);
}
fossil_print("%-12s%s (ambiguous)\n", "hash:", zName);
db_prepare(&q,
"SELECT rid FROM blob WHERE uuid>=lower(%Q) AND uuid<(lower(%Q)||'z')",
zName, zName
);
while( db_step(&q)==SQLITE_ROW ){
if( cnt++ ) fossil_print("%12s---- meaning #%d ----\n", " ", cnt);
whatis_rid(db_column_int(&q, 0), mFlags);
}
db_finalize(&q);
}else if( rid==0 ){
if( (mFlags & WHATIS_OMIT_UNK)==0 ){
/* 0123456789 12 */
if( zFileName ){
fossil_print("%-12s%s\n", "name:", zFileName);
}
fossil_print("unknown: %s\n", zName);
}
}else{
if( mFlags & WHATIS_REPO ){
fossil_print("\nrepository: %s\n", g.zRepositoryName);
}
if( zFileName ){
zName = zFileName;
}
fossil_print("%-12s%s\n", "name:", zName);
whatis_rid(rid, mFlags);
}
}
/*
** COMMAND: whatis*
**
** Usage: %fossil whatis NAME
**
** Resolve the symbol NAME into its canonical artifact hash
** artifact name and provide a description of what role that artifact
** plays.
**
** Options:
** -f|--file Find artifacts with the same hash as file NAME.
** If NAME is "-", read content from standard input.
** -q|--quiet Show nothing if NAME is not found
** --type TYPE Only find artifacts of TYPE (one of: 'ci', 't',
** 'w', 'g', or 'e')
** -v|--verbose Provide extra information (such as the RID)
*/
void whatis_cmd(void){
int mFlags = 0;
int fileFlag;
int i;
const char *zType = 0;
db_find_and_open_repository(0,0);
if( find_option("verbose","v",0)!=0 ){
mFlags |= WHATIS_VERBOSE;
}
if( find_option("quiet","q",0)!=0 ){
mFlags |= WHATIS_OMIT_UNK | WHATIS_REPO;
}
fileFlag = find_option("file","f",0)!=0;
zType = find_option("type",0,1);
/* We should be done with options.. */
verify_all_options();
if( g.argc<3 ) usage("NAME ...");
for(i=2; i<g.argc; i++){
const char *zName = g.argv[i];
if( i>2 ) fossil_print("%.79c\n",'-');
if( fileFlag ){
Blob in;
Blob hash = empty_blob;
const char *zHash;
/* Always follow symlinks (when applicable) */
blob_read_from_file(&in, zName, ExtFILE);
/* First check the auxiliary hash to see if there is already an artifact
** that uses the auxiliary hash name */
hname_hash(&in, 1, &hash);
zHash = (const char*)blob_str(&hash);
if( fast_uuid_to_rid(zHash)==0 ){
/* No existing artifact with the auxiliary hash name. Therefore, use
** the primary hash name. */
blob_reset(&hash);
hname_hash(&in, 0, &hash);
zHash = (const char*)blob_str(&hash);
}
whatis_artifact(zHash, zName, zType, mFlags);
blob_reset(&hash);
}else{
whatis_artifact(zName, 0, zType, mFlags);
}
}
}
/*
** COMMAND: test-whatis-all
**
|
| ︙ | ︙ | |||
1148 1149 1150 1151 1152 1153 1154 | */ static const char zDescTab[] = @ CREATE TEMP TABLE IF NOT EXISTS description( @ rid INTEGER PRIMARY KEY, -- RID of the object @ uuid TEXT, -- hash of the object @ ctime DATETIME, -- Time of creation @ isPrivate BOOLEAN DEFAULT 0, -- True for unpublished artifacts | | | 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 | */ static const char zDescTab[] = @ CREATE TEMP TABLE IF NOT EXISTS description( @ rid INTEGER PRIMARY KEY, -- RID of the object @ uuid TEXT, -- hash of the object @ ctime DATETIME, -- Time of creation @ isPrivate BOOLEAN DEFAULT 0, -- True for unpublished artifacts @ type TEXT, -- file, check-in, wiki, ticket, etc. @ rcvid INT, -- When the artifact was received @ summary TEXT, -- Summary comment for the object @ ref TEXT -- hash of an object to link against @ ); @ CREATE INDEX IF NOT EXISTS desctype @ ON description(summary) WHERE summary='unknown'; ; |
| ︙ | ︙ | |||
1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 |
int hashClr = PB("hclr");
char *zRange;
char *zSha1Bg;
char *zSha3Bg;
login_check_credentials();
if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
style_header("List Of Artifacts");
style_submenu_element("250 Largest", "bigbloblist");
if( g.perm.Admin ){
style_submenu_element("Artifact Log", "rcvfromlist");
}
if( !phantomOnly ){
style_submenu_element("Phantoms", "bloblist?phan");
| > | 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 |
int hashClr = PB("hclr");
char *zRange;
char *zSha1Bg;
char *zSha3Bg;
login_check_credentials();
if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
cgi_check_for_malice();
style_header("List Of Artifacts");
style_submenu_element("250 Largest", "bigbloblist");
if( g.perm.Admin ){
style_submenu_element("Artifact Log", "rcvfromlist");
}
if( !phantomOnly ){
style_submenu_element("Phantoms", "bloblist?phan");
|
| ︙ | ︙ | |||
1659 1660 1661 1662 1663 1664 1665 | /* ** WEBPAGE: bigbloblist ** ** Return a page showing the largest artifacts in the repository in order ** of decreasing size. ** | | | 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 |
/*
** WEBPAGE: bigbloblist
**
** Return a page showing the largest artifacts in the repository in order
** of decreasing size.
**
** n=N Show the top N artifacts (default: 250)
*/
void bigbloblist_page(void){
Stmt q;
int n = atoi(PD("n","250"));
login_check_credentials();
if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
|
| ︙ | ︙ | |||
1694 1695 1696 1697 1698 1699 1700 |
" FROM description, blob LEFT JOIN delta ON delta.rid=blob.rid"
" WHERE description.rid=blob.rid"
" ORDER BY length(content) DESC"
);
@ <table cellpadding="2" cellspacing="0" border="1" \
@ class='sortable' data-column-types='NnnttT' data-init-sort='0'>
@ <thead><tr><th align="right">Size<th align="right">RID
| | | 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 |
" FROM description, blob LEFT JOIN delta ON delta.rid=blob.rid"
" WHERE description.rid=blob.rid"
" ORDER BY length(content) DESC"
);
@ <table cellpadding="2" cellspacing="0" border="1" \
@ class='sortable' data-column-types='NnnttT' data-init-sort='0'>
@ <thead><tr><th align="right">Size<th align="right">RID
@ <th align="right">From<th>Hash<th>Description<th>Date</tr></thead>
@ <tbody>
while( db_step(&q)==SQLITE_ROW ){
int rid = db_column_int(&q,0);
const char *zUuid = db_column_text(&q, 1);
const char *zDesc = db_column_text(&q, 2);
int sz = db_column_int(&q,3);
const char *zSrcId = db_column_text(&q,4);
|
| ︙ | ︙ | |||
1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 |
@ </tr>
}
@ </tbody></table>
db_finalize(&q);
style_table_sorter();
style_finish_page();
}
/*
** COMMAND: test-unsent
**
** Usage: %fossil test-unsent
**
** Show all artifacts in the unsent table
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 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 |
@ </tr>
}
@ </tbody></table>
db_finalize(&q);
style_table_sorter();
style_finish_page();
}
/*
** WEBPAGE: deltachain
**
** Usage: /deltachain/RID
**
** The RID query parameter is required. Generate a page with a table
** showing storage characteristics of RID and other artifacts that are
** derived from RID via delta.
*/
void deltachain_page(void){
Stmt q;
int id = atoi(PD("name","0"));
int top;
i64 nStored = 0;
i64 nExpanded = 0;
login_check_credentials();
if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
top = db_int(id,
"WITH RECURSIVE chain(aa,bb) AS (\n"
" SELECT rid, srcid FROM delta WHERE rid=%d\n"
" UNION ALL\n"
" SELECT bb, delta.srcid"
" FROM chain LEFT JOIN delta ON delta.rid=bb"
" WHERE bb IS NOT NULL\n"
")\n"
"SELECT aa FROM chain WHERE bb IS NULL",
id
);
style_header("Delta Chain Containing Artifact %d", id);
db_multi_exec(
"CREATE TEMP TABLE toshow(rid INT, gen INT);\n"
"WITH RECURSIVE tx(id,px) AS (\n"
" VALUES(%d,0)\n"
" UNION ALL\n"
" SELECT delta.rid, px+1 FROM tx, delta where delta.srcid=tx.id\n"
" ORDER BY 2\n"
") "
"INSERT INTO toshow(rid,gen) SELECT id,px FROM tx;",
top
);
db_multi_exec("CREATE INDEX toshow_rid ON toshow(rid);");
describe_artifacts("IN (SELECT rid FROM toshow)");
db_prepare(&q,
"SELECT description.rid, description.uuid, description.summary,"
" length(blob.content), coalesce(delta.srcid,''),"
" datetime(description.ctime), toshow.gen, blob.size"
" FROM description, toshow, blob LEFT JOIN delta ON delta.rid=blob.rid"
" WHERE description.rid=blob.rid"
" AND toshow.rid=description.rid"
" ORDER BY toshow.gen, description.ctime"
);
@ <table cellpadding="2" cellspacing="0" border="1" \
@ class='sortable' data-column-types='nNnnttT' data-init-sort='0'>
@ <thead><tr><th align="right">Level</th>
@ <th align="right">Size<th align="right">RID
@ <th align="right">From<th>Hash<th>Description<th>Date</tr></thead>
@ <tbody>
while( db_step(&q)==SQLITE_ROW ){
int rid = db_column_int(&q,0);
const char *zUuid = db_column_text(&q, 1);
const char *zDesc = db_column_text(&q, 2);
int sz = db_column_int(&q,3);
const char *zSrcId = db_column_text(&q,4);
const char *zDate = db_column_text(&q,5);
int gen = db_column_int(&q,6);
nExpanded += db_column_int(&q,7);
nStored += sz;
@ <tr><td align="right">%d(gen)</td>
@ <td align="right">%d(sz)</td>
if( rid==id ){
@ <td align="right"><b>%d(rid)</b></td>
}else{
@ <td align="right">%d(rid)</td>
}
@ <td align="right">%s(zSrcId)</td>
@ <td> %z(href("%R/info/%!S",zUuid))%S(zUuid)</a> </td>
@ <td align="left">%h(zDesc)</td>
@ <td align="left">%z(href("%R/timeline?c=%T",zDate))%s(zDate)</a></td>
@ </tr>
}
@ </tbody></table>
db_finalize(&q);
style_table_sorter();
@ <p>
@ <table border="0" cellspacing="0" cellpadding="0">
@ <tr><td>Bytes of content</td><td> </td>
@ <td align="right">%,lld(nExpanded)</td></tr>
@ <tr><td>Bytes stored in repository</td><td></td>
@ <td align="right">%,lld(nStored)</td>
@ </table>
@ </p>
style_finish_page();
}
/*
** COMMAND: test-unsent
**
** Usage: %fossil test-unsent
**
** Show all artifacts in the unsent table
|
| ︙ | ︙ |
Changes to src/patch.c.
| ︙ | ︙ | |||
11 12 13 14 15 16 17 | ** ** Author contact information: ** drh@hwaci.com ** http://www.hwaci.com/drh/ ** ******************************************************************************* ** | | | | | 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 |
**
** Author contact information:
** drh@hwaci.com
** http://www.hwaci.com/drh/
**
*******************************************************************************
**
** This file contains code used to implement the "patch" command
*/
#include "config.h"
#include "patch.h"
#include <assert.h>
/*
** Try to compute the name of the computer on which this process
** is running.
*/
char *fossil_hostname(void){
FILE *in;
char zBuf[200];
in = popen("hostname","r");
if( in ){
int n = fread(zBuf, 1, sizeof(zBuf)-1, in);
while( n>0 && fossil_isspace(zBuf[n-1]) ){ n--; }
if( n<0 ) n = 0;
zBuf[n] = 0;
pclose(in);
return fossil_strdup(zBuf);
}
return 0;
}
/*
** Flags passed from the main patch_cmd() routine into subfunctions used
** to implement the various subcommands.
*/
#define PATCH_DRYRUN 0x0001
#define PATCH_VERBOSE 0x0002
#define PATCH_FORCE 0x0004
/*
** Implementation of the "readfile(X)" SQL function. The entire content
** of the check-out file named X is read and returned as a BLOB.
*/
static void readfileFunc(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
const char *zName;
|
| ︙ | ︙ | |||
373 374 375 376 377 378 379 |
void patch_apply(unsigned mFlags){
Stmt q;
Blob cmd;
blob_init(&cmd, 0, 0);
if( unsaved_changes(0) ){
if( (mFlags & PATCH_FORCE)==0 ){
| | | 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 |
void patch_apply(unsigned mFlags){
Stmt q;
Blob cmd;
blob_init(&cmd, 0, 0);
if( unsaved_changes(0) ){
if( (mFlags & PATCH_FORCE)==0 ){
fossil_fatal("there are unsaved changes in the current check-out");
}else{
blob_appendf(&cmd, "%$ revert", g.nameOfExe);
if( mFlags & PATCH_DRYRUN ){
fossil_print("%s\n", blob_str(&cmd));
}else{
int rc = fossil_system(blob_str(&cmd));
if( rc ){
|
| ︙ | ︙ | |||
494 495 496 497 498 499 500 |
db_finalize(&q);
if( blob_size(&cmd)>0 ){
if( mFlags & PATCH_DRYRUN ){
fossil_print("%s", blob_str(&cmd));
}else{
int rc = fossil_unsafe_system(blob_str(&cmd));
if( rc ){
| | | | 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 |
db_finalize(&q);
if( blob_size(&cmd)>0 ){
if( mFlags & PATCH_DRYRUN ){
fossil_print("%s", blob_str(&cmd));
}else{
int rc = fossil_unsafe_system(blob_str(&cmd));
if( rc ){
fossil_print("%-10s unable to rename files:\n%s", "WARNING!",
blob_str(&cmd));
}
}
blob_reset(&cmd);
}
/* Edits and new files */
db_prepare(&q,
|
| ︙ | ︙ | |||
691 692 693 694 695 696 697 |
}else{
Blob remote;
*(char*)(zDir-1) = 0;
transport_ssh_command(&cmd);
blob_appendf(&cmd, " -T");
blob_append_escaped_arg(&cmd, zRemote, 0);
blob_init(&remote, 0, 0);
| | > > > < | | < | 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 |
}else{
Blob remote;
*(char*)(zDir-1) = 0;
transport_ssh_command(&cmd);
blob_appendf(&cmd, " -T");
blob_append_escaped_arg(&cmd, zRemote, 0);
blob_init(&remote, 0, 0);
if( zFossilCmd==0 ){
blob_append_escaped_arg(&cmd, "PATH=$HOME/bin:$PATH", 0);
zFossilCmd = "fossil";
}
blob_appendf(&remote, "%$ patch %s%s --dir64 %z -",
zFossilCmd, zRemoteCmd, zForce, encode64(zDir, -1));
blob_append_escaped_arg(&cmd, blob_str(&remote), 0);
blob_reset(&remote);
}
fossil_print("%s\n", blob_str(&cmd));
fflush(stdout);
f = popen(blob_str(&cmd), zRW);
if( f==0 ){
fossil_fatal("cannot run command: %s", blob_str(&cmd));
}
blob_reset(&cmd);
blob_reset(&flgs);
return f;
|
| ︙ | ︙ | |||
796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 |
fossil_fatal("base artifact %S for file \"%s\" not found",
zUuid, zName);
}
}
zName = db_column_text(&q, 1);
rid = db_column_int(&q, 0);
if( db_column_type(&q,3)==SQLITE_NULL ){
if( !bWebpage ) fossil_print("DELETE %s\n", zName);
diff_print_index(zName, pCfg, 0);
content_get(rid, &a);
diff_file_mem(&a, &empty, zName, pCfg);
}else if( rid==0 ){
db_ephemeral_blob(&q, 3, &a);
blob_uncompress(&a, &a);
if( !bWebpage ) fossil_print("ADDED %s\n", zName);
diff_print_index(zName, pCfg, 0);
diff_file_mem(&empty, &a, zName, pCfg);
blob_reset(&a);
}else if( db_column_bytes(&q, 3)>0 ){
Blob delta;
db_ephemeral_blob(&q, 3, &delta);
blob_uncompress(&delta, &delta);
| > > > | 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 |
fossil_fatal("base artifact %S for file \"%s\" not found",
zUuid, zName);
}
}
zName = db_column_text(&q, 1);
rid = db_column_int(&q, 0);
pCfg->diffFlags &= (~DIFF_FILE_MASK);
if( db_column_type(&q,3)==SQLITE_NULL ){
if( !bWebpage ) fossil_print("DELETE %s\n", zName);
pCfg->diffFlags |= DIFF_FILE_DELETED;
diff_print_index(zName, pCfg, 0);
content_get(rid, &a);
diff_file_mem(&a, &empty, zName, pCfg);
}else if( rid==0 ){
db_ephemeral_blob(&q, 3, &a);
blob_uncompress(&a, &a);
if( !bWebpage ) fossil_print("ADDED %s\n", zName);
pCfg->diffFlags |= DIFF_FILE_ADDED;
diff_print_index(zName, pCfg, 0);
diff_file_mem(&empty, &a, zName, pCfg);
blob_reset(&a);
}else if( db_column_bytes(&q, 3)>0 ){
Blob delta;
db_ephemeral_blob(&q, 3, &delta);
blob_uncompress(&delta, &delta);
|
| ︙ | ︙ | |||
836 837 838 839 840 841 842 | ** 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. ** | | | | > | | | | > | | | > | > > | > > > > > > > | | | | | | | 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 |
** 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 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.
**
** Options:
** -f|--force Overwrite an existing patch with the same name
**
** > fossil patch apply [DIRECTORY] PATCHFILE
**
** Apply the changes in PATCHFILE to the check-out at DIRECTORY, or
** in the current directory if DIRECTORY is omitted.
**
** Options:
** -f|--force Apply the patch even though there are unsaved
** changes in the current check-out. Unsaved changes
** are reverted and permanently lost.
** -n|--dry-run Do nothing, but print what would have happened
** -v|--verbose Extra output explaining what happens
**
** > fossil patch diff [DIRECTORY] PATCHFILE
** > fossil patch gdiff [DIRECTORY] PATCHFILE
**
** Show a human-readable diff for the patch in PATCHFILE and associated
** with the repository checked out in DIRECTORY. The current
** directory is used if DIRECTORY is omitted. All the usual
** diff flags described at "fossil help diff" apply. With gdiff,
** gdiff-command is used instead of internal diff logic. In addition:
**
** -f|--force Continue trying to perform the diff even if
** baseline information is missing from the current
** repository
**
** > fossil patch push REMOTE-CHECKOUT
**
** Create a patch for the current check-out, transfer that patch to
** a remote machine (using ssh) and apply the patch there. The
** REMOTE-CHECKOUT is in one of the following formats:
**
** * DIRECTORY
** * HOST:DIRECTORY
** * USER@HOST:DIRECTORY
**
** The name of the fossil executable on the remote host is specified
** by the --fossilcmd option, or if there is no --fossilcmd, it first
** tries "$HOME/bin/fossil" and if not found there it searches for any
** executable named "fossil" on the default $PATH set by SSH on the
** remote.
**
** Command-line options:
**
** -f|--force Apply the patch even though there are unsaved
** changes in the current check-out. Unsaved
** changes will be reverted and then the patch is
** applied.
** --fossilcmd EXE Name of the "fossil" executable on the remote
** -n|--dry-run Do nothing, but print what would have happened
** -v|--verbose Extra output explaining what happens
**
**
** > fossil patch pull REMOTE-CHECKOUT
**
** Like "fossil patch push" except that the transfer is from remote
** to local. All the same command-line options apply.
**
** > fossil patch view PATCHFILE
**
** View a summary of the changes in the binary patch in PATCHFILE.
** Use "fossil patch diff" for detailed patch content.
**
** -v|--verbose Show extra detail about the patch
**
*/
void patch_cmd(void){
const char *zCmd;
size_t n;
if( g.argc<3 ){
patch_usage:
usage("apply|create|diff|gdiff|pull|push|view");
}
zCmd = g.argv[2];
n = strlen(zCmd);
if( strncmp(zCmd, "apply", n)==0 ){
char *zIn;
unsigned flags = 0;
if( find_option("dry-run","n",0) ) flags |= PATCH_DRYRUN;
|
| ︙ | ︙ | |||
930 931 932 933 934 935 936 |
if( find_option("force","f",0) ) flags |= PATCH_FORCE;
zOut = patch_find_patch_filename("create");
verify_all_options();
db_must_be_within_tree();
patch_create(flags, zOut, stdout);
fossil_free(zOut);
}else
| | < > | 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 |
if( find_option("force","f",0) ) flags |= PATCH_FORCE;
zOut = patch_find_patch_filename("create");
verify_all_options();
db_must_be_within_tree();
patch_create(flags, zOut, stdout);
fossil_free(zOut);
}else
if( (strncmp(zCmd, "diff", n)==0) || (strncmp(zCmd, "gdiff", n)==0) ){
char *zIn;
unsigned flags = 0;
DiffConfig DCfg;
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();
zIn = patch_find_patch_filename("apply");
patch_attach(zIn, stdin);
patch_diff(flags, &DCfg);
fossil_free(zIn);
}else
if( strncmp(zCmd, "pull", n)==0 ){
|
| ︙ | ︙ |
Changes to src/piechart.c.
| ︙ | ︙ | |||
310 311 312 313 314 315 316 |
fossil_free(zLabel);
}
db_finalize(&ins);
if( n>1 ){
@ <svg width=%d(width) height=%d(height) style="border:1px solid #d3d3d3;">
piechart_render(width,height, PIE_OTHER|PIE_PERCENT);
@ </svg>
| | | | | | 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 |
fossil_free(zLabel);
}
db_finalize(&ins);
if( n>1 ){
@ <svg width=%d(width) height=%d(height) style="border:1px solid #d3d3d3;">
piechart_render(width,height, PIE_OTHER|PIE_PERCENT);
@ </svg>
@ <hr>
}
@ <form method="POST" action='%R/test-piechart'>
@ <p>Comma-separated list of slice widths:<br>
@ <input type='text' name='data' size='80' value='%h(zData)'/><br>
@ Width: <input type='text' size='8' name='width' value='%d(width)'/>
@ Height: <input type='text' size='8' name='height' value='%d(height)'/><br>
@ <input type='submit' value='Draw The Pie Chart'/>
@ </form>
@ <p>Interesting test cases:
@ <ul>
@ <li> <a href='test-piechart?data=44,2,2,2,2,2,3,2,2,2,2,2,44'>Case 1</a>
@ <li> <a href='test-piechart?data=2,2,2,2,2,44,44,2,2,2,2,2'>Case 2</a>
@ <li> <a href='test-piechart?data=20,2,2,2,2,2,2,2,2,2,2,80'>Case 3</a>
|
| ︙ | ︙ |
Changes to src/pikchrshow.c.
| ︙ | ︙ | |||
424 425 426 427 428 429 430 |
/* Wasm load/init progress widget... */
CX("<div class='emscripten'>"); {
CX("<figure id='module-spinner'>");
CX("<div class='spinner'></div>");
CX("<div class='center'><strong>Initializing app...</strong></div>");
CX("<div class='center'>");
CX("On a slow internet connection this may take a moment. If this ");
| | | 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 |
/* Wasm load/init progress widget... */
CX("<div class='emscripten'>"); {
CX("<figure id='module-spinner'>");
CX("<div class='spinner'></div>");
CX("<div class='center'><strong>Initializing app...</strong></div>");
CX("<div class='center'>");
CX("On a slow internet connection this may take a moment. If this ");
CX("message displays for \"a long time\", initialization may have ");
CX("failed and the JavaScript console may contain clues as to why. ");
CX("</div>");
CX("<div><a href='?legacy'>Switch to legacy mode</a></div>");
CX("</figure>");
CX("<div class='emscripten' id='module-status'>Downloading...</div>");
CX("<progress value='0' max='100' id='module-progress' hidden='1'>"
"</progress>");
|
| ︙ | ︙ | |||
523 524 525 526 527 528 529 | ** ** Accepts a pikchr script as input and outputs the rendered script as ** an SVG graphic. The INFILE and OUTFILE options default to stdin ** resp. stdout, and the names "-" can be used as aliases for those ** streams. ** ** Options: | < | | | | | | | | | | | 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 | ** ** Accepts a pikchr script as input and outputs the rendered script as ** an SVG graphic. The INFILE and OUTFILE options default to stdin ** resp. stdout, and the names "-" can be used as aliases for those ** streams. ** ** Options: ** -div On success, add a DIV wrapper around the ** resulting SVG output which limits its max-width to ** its computed maximum ideal size ** ** -div-indent Like -div but indent the div ** ** -div-center Like -div but center the div ** ** -div-left Like -div but float the div left ** ** -div-right Like -div but float the div right ** ** -div-toggle Set the 'toggle' CSS class on the div (used by the ** JavaScript-side post-processor) ** ** -div-source Set the 'source' CSS class on the div, which tells ** CSS to hide the SVG and reveal the source by default. ** ** -src Store the input pikchr's source code in the output as ** a separate element adjacent to the SVG one. Implied ** by -div-source. ** ** ** -th Process the input using TH1 before passing it to pikchr ** ** -th-novar Disable $var and $<var> TH1 processing. Use this if the ** pikchr script uses '$' for its own purposes and that ** causes issues. This only affects parsing of '$' outside ** of TH1 script blocks. Code in such blocks is unaffected. ** ** -th-nosvg When using -th, output the post-TH1'd script ** instead of the pikchr-rendered output ** ** -th-trace Trace TH1 execution (for debugging purposes) ** ** ** The -div-indent/center/left/right flags may not be combined. ** ** TH1-related Notes and Caveats: ** ** If the -th flag is used, this command must open a fossil database ** for certain functionality to work (via a check-out or the -R REPO ** flag). If opening a db fails, execution will continue but any TH1 ** commands which require a db will trigger a fatal error. ** ** In Fossil skins, TH1 variables in the form $varName are expanded ** as-is and those in the form $<varName> are htmlized in the ** resulting output. This processor disables the htmlizing step, so $x ** and $<x> are equivalent unless the TH1-processed pikchr script |
| ︙ | ︙ |
Changes to src/pivot.c.
| ︙ | ︙ | |||
28 29 30 31 32 33 34 | ** Set the primary file. The primary version is one of the two ** files that have a common ancestor. The other file is the secondary. ** There can be multiple secondaries but only a single primary. ** The primary must be set first. ** ** In the merge algorithm, the file being merged in is the primary. ** The current check-out or other files that have been merged into | | | 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
** Set the primary file. The primary version is one of the two
** files that have a common ancestor. The other file is the secondary.
** There can be multiple secondaries but only a single primary.
** The primary must be set first.
**
** In the merge algorithm, the file being merged in is the primary.
** The current check-out or other files that have been merged into
** the current check-out are the secondaries.
**
** The act of setting the primary resets the pivot-finding algorithm.
*/
void pivot_set_primary(int rid){
/* Set up table used to do the search */
db_multi_exec(
"CREATE TEMP TABLE IF NOT EXISTS aqueue("
|
| ︙ | ︙ | |||
150 151 152 153 154 155 156 | db_finalize(&q2); db_finalize(&i1); db_finalize(&u1); return rid; } /* | | | > | | | > > > > | | < > | 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 |
db_finalize(&q2);
db_finalize(&i1);
db_finalize(&u1);
return rid;
}
/*
** COMMAND: merge-base
**
** Usage: %fossil merge-base ?options? PRIMARY SECONDARY ...
**
** Find a common ancestor given two or more check-in versions to
** hypothetically merge.
**
** Options:
** --ignore-merges Ignore merges for discovering name pivots
*/
void merge_base_cmd(void){
int i, rid;
int ignoreMerges = find_option("ignore-merges",0,0)!=0;
int showDetails = find_option("details",0,0)!=0
/* intentionally undocumented */;
if( g.argc<4 ){
usage("?options? PRIMARY SECONDARY ...");
}
db_must_be_within_tree();
pivot_set_primary(name_to_rid(g.argv[2]));
for(i=3; i<g.argc; i++){
pivot_set_secondary(name_to_rid(g.argv[i]));
}
rid = pivot_find(ignoreMerges);
if( rid==0 ){
puts("No common ancestor found.");
}else{
printf("pivot=%s\n",
db_text("?","SELECT uuid FROM blob WHERE rid=%d",rid));
}
if( showDetails ){
Stmt q;
db_prepare(&q,
"SELECT substr(uuid,1,12), aqueue.rid, datetime(aqueue.mtime),"
" aqueue.pending, aqueue.src\n"
" FROM aqueue JOIN blob ON aqueue.rid=blob.rid\n"
" ORDER BY aqueue.mtime DESC"
|
| ︙ | ︙ |
Changes to src/popen.c.
| ︙ | ︙ | |||
181 182 183 184 185 186 187 |
close(pout[1]);
*pChildPid = 0;
return 1;
}
signal(SIGPIPE,SIG_IGN);
if( *pChildPid==0 ){
int fd;
| < | | | 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 |
close(pout[1]);
*pChildPid = 0;
return 1;
}
signal(SIGPIPE,SIG_IGN);
if( *pChildPid==0 ){
int fd;
/* This is the child process */
close(0);
fd = dup(pout[0]);
if( fd!=0 ) fossil_panic("popen() failed to open file descriptor 0");
close(pout[0]);
close(pout[1]);
close(1);
fd = dup(pin[1]);
if( fd!=1 ) fossil_panic("popen() failed to open file descriptor 1");
close(pin[0]);
close(pin[1]);
if( bDirect ){
execl(zCmd, zCmd, (char*)0);
}else{
execl("/bin/sh", "/bin/sh", "-c", zCmd, (char*)0);
}
|
| ︙ | ︙ |
Changes to src/printf.c.
| ︙ | ︙ | |||
862 863 864 865 866 867 868 |
** the output.
*/
if( !flag_leftjustify ){
register int nspace;
nspace = width-length;
if( nspace>0 ){
count += nspace;
| | | | 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 |
** the output.
*/
if( !flag_leftjustify ){
register int nspace;
nspace = width-length;
if( nspace>0 ){
count += nspace;
while( nspace>=(int)etSPACESIZE ){
blob_append(pBlob,spaces,etSPACESIZE);
nspace -= etSPACESIZE;
}
if( nspace>0 ) blob_append(pBlob,spaces,nspace);
}
}
if( length>0 ){
blob_append(pBlob,bufpt,length);
count += length;
}
if( flag_leftjustify ){
register int nspace;
nspace = width-length;
if( nspace>0 ){
count += nspace;
while( nspace>=(int)etSPACESIZE ){
blob_append(pBlob,spaces,etSPACESIZE);
nspace -= etSPACESIZE;
}
if( nspace>0 ) blob_append(pBlob,spaces,nspace);
}
}
if( zExtra ){
|
| ︙ | ︙ | |||
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 |
blob_reset(&b);
va_end(ap);
}
/*
** Write a message to the error log, if the error log filename is
** defined.
*/
void fossil_errorlog(const char *zFormat, ...){
struct tm *pNow;
time_t now;
FILE *out;
const char *z;
int i;
va_list ap;
static const char *const azEnv[] = { "HTTP_HOST", "HTTP_REFERER",
"HTTP_USER_AGENT",
"PATH_INFO", "QUERY_STRING", "REMOTE_ADDR", "REQUEST_METHOD",
"REQUEST_URI", "SCRIPT_NAME" };
if( g.zErrlog==0 ) return;
if( g.zErrlog[0]=='-' && g.zErrlog[1]==0 ){
out = stderr;
}else{
out = fossil_fopen(g.zErrlog, "a");
if( out==0 ) return;
}
now = time(0);
pNow = gmtime(&now);
fprintf(out, "------------- %04d-%02d-%02d %02d:%02d:%02d UTC ------------\n",
pNow->tm_year+1900, pNow->tm_mon+1, pNow->tm_mday,
pNow->tm_hour, pNow->tm_min, pNow->tm_sec);
va_start(ap, zFormat);
vfprintf(out, zFormat, ap);
fprintf(out, "\n");
va_end(ap);
| > > > > > > > > > > > | | | | | | | > | 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 |
blob_reset(&b);
va_end(ap);
}
/*
** Write a message to the error log, if the error log filename is
** defined.
**
** If the message format begins with 'X', then omit that X from the
** beginning of the message and add much more CGI context.
*/
void fossil_errorlog(const char *zFormat, ...){
struct tm *pNow;
time_t now;
FILE *out;
const char *z;
int i;
int bDetail = 0;
va_list ap;
static const char *const azEnv[] = { "HTTP_HOST", "HTTP_REFERER",
"HTTP_USER_AGENT",
"PATH_INFO", "QUERY_STRING", "REMOTE_ADDR", "REQUEST_METHOD",
"REQUEST_URI", "SCRIPT_NAME" };
if( g.zErrlog==0 ) return;
if( g.zErrlog[0]=='-' && g.zErrlog[1]==0 ){
out = stderr;
}else{
out = fossil_fopen(g.zErrlog, "a");
if( out==0 ) return;
}
now = time(0);
pNow = gmtime(&now);
fprintf(out, "------------- %04d-%02d-%02d %02d:%02d:%02d UTC ------------\n",
pNow->tm_year+1900, pNow->tm_mon+1, pNow->tm_mday,
pNow->tm_hour, pNow->tm_min, pNow->tm_sec);
va_start(ap, zFormat);
if( zFormat[0]=='X' ){
bDetail = 1;
zFormat++;
}
vfprintf(out, zFormat, ap);
fprintf(out, "\n");
va_end(ap);
if( bDetail ){
cgi_print_all(1,3,out);
}else{
for(i=0; i<count(azEnv); i++){
char *p;
if( (p = fossil_getenv(azEnv[i]))!=0 && p[0]!=0 ){
fprintf(out, "%s=%s\n", azEnv[i], p);
fossil_path_free(p);
}else if( (z = P(azEnv[i]))!=0 && z[0]!=0 ){
fprintf(out, "%s=%s\n", azEnv[i], z);
}
}
}
fclose(out);
}
/*
** The following variable becomes true while processing a fatal error
|
| ︙ | ︙ |
Changes to src/publish.c.
| ︙ | ︙ | |||
29 30 31 32 33 34 35 | ** ** Show a list of unpublished or "private" artifacts. Unpublished artifacts ** will never push and hence will not be shared with collaborators. ** ** By default, this command only shows unpublished check-ins. To show ** all unpublished artifacts, use the --all command-line option. ** | | | 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
**
** Show a list of unpublished or "private" artifacts. Unpublished artifacts
** will never push and hence will not be shared with collaborators.
**
** By default, this command only shows unpublished check-ins. To show
** all unpublished artifacts, use the --all command-line option.
**
** Options:
** --all Show all artifacts, not just check-ins
*/
void unpublished_cmd(void){
int bAll = find_option("all",0,0)!=0;
db_find_and_open_repository(0,0);
verify_all_options();
|
| ︙ | ︙ |
Changes to src/purge.c.
| ︙ | ︙ | |||
558 559 560 561 562 563 564 |
db_multi_exec("CREATE TEMP TABLE ok(rid INTEGER PRIMARY KEY)");
for(i=3; i<g.argc; i++){
int r = name_to_typed_rid(g.argv[i], "br");
compute_descendants(r, 1000000000);
}
vid = db_lget_int("checkout",0);
if( db_exists("SELECT 1 FROM ok WHERE rid=%d",vid) ){
| | | 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 |
db_multi_exec("CREATE TEMP TABLE ok(rid INTEGER PRIMARY KEY)");
for(i=3; i<g.argc; i++){
int r = name_to_typed_rid(g.argv[i], "br");
compute_descendants(r, 1000000000);
}
vid = db_lget_int("checkout",0);
if( db_exists("SELECT 1 FROM ok WHERE rid=%d",vid) ){
fossil_fatal("cannot purge the current check-out");
}
find_checkin_associates("ok", 1);
purge_artifact_list("ok", "", purgeFlags);
db_end_transaction(0);
}else if( strncmp(zSubcmd, "files", n)==0 ){
verify_all_options();
db_begin_transaction();
|
| ︙ | ︙ |
Changes to src/rebuild.c.
| ︙ | ︙ | |||
254 255 256 257 258 259 260 |
Blob copy;
Blob *pUse;
int nChild, i, cid;
while( rid>0 ){
/* Fix up the "blob.size" field if needed. */
| | | 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 |
Blob copy;
Blob *pUse;
int nChild, i, cid;
while( rid>0 ){
/* Fix up the "blob.size" field if needed. */
if( size!=(int)blob_size(pBase) ){
db_multi_exec(
"UPDATE blob SET size=%d WHERE rid=%d", blob_size(pBase), rid
);
}
/* Find all children of artifact rid */
db_static_prepare(&q1, "SELECT rid FROM delta WHERE srcid=:rid");
|
| ︙ | ︙ | |||
486 487 488 489 490 491 492 | /* ** Number of neighbors to search */ #define N_NEIGHBOR 5 /* ** Attempt to convert more full-text blobs into delta-blobs for | | > | > > > | > > > > | 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 |
/*
** Number of neighbors to search
*/
#define N_NEIGHBOR 5
/*
** Attempt to convert more full-text blobs into delta-blobs for
** storage efficiency. Return the number of bytes of storage space
** saved.
*/
i64 extra_deltification(int *pnDelta){
Stmt q;
int aPrev[N_NEIGHBOR];
int nPrev;
int rid;
int prevfnid, fnid;
int nDelta = 0;
i64 nByte = 0;
int nSaved;
db_begin_transaction();
/* Look for manifests that have not been deltaed and try to make them
** children of one of the 5 chronologically subsequent check-ins
*/
db_prepare(&q,
"SELECT rid FROM event, blob"
" WHERE blob.rid=event.objid"
" AND event.type='ci'"
" AND NOT EXISTS(SELECT 1 FROM delta WHERE rid=blob.rid)"
" ORDER BY event.mtime DESC"
);
nPrev = 0;
while( db_step(&q)==SQLITE_ROW ){
rid = db_column_int(&q, 0);
if( nPrev>0 ){
nSaved = content_deltify(rid, aPrev, nPrev, 0);
if( nSaved>0 ){
nDelta++;
nByte += nSaved;
}
}
if( nPrev<N_NEIGHBOR ){
aPrev[nPrev++] = rid;
}else{
int i;
for(i=0; i<N_NEIGHBOR-1; i++) aPrev[i] = aPrev[i+1];
aPrev[N_NEIGHBOR-1] = rid;
|
| ︙ | ︙ | |||
541 542 543 544 545 546 547 |
prevfnid = 0;
while( db_step(&q)==SQLITE_ROW ){
rid = db_column_int(&q, 0);
fnid = db_column_int(&q, 1);
if( fnid!=prevfnid ) nPrev = 0;
prevfnid = fnid;
if( nPrev>0 ){
| | > > > > > > | 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 |
prevfnid = 0;
while( db_step(&q)==SQLITE_ROW ){
rid = db_column_int(&q, 0);
fnid = db_column_int(&q, 1);
if( fnid!=prevfnid ) nPrev = 0;
prevfnid = fnid;
if( nPrev>0 ){
nSaved = content_deltify(rid, aPrev, nPrev, 0);
if( nSaved>0 ){
nDelta++;
nByte += nSaved;
}
}
if( nPrev<N_NEIGHBOR ){
aPrev[nPrev++] = rid;
}else{
int i;
for(i=0; i<N_NEIGHBOR-1; i++) aPrev[i] = aPrev[i+1];
aPrev[N_NEIGHBOR-1] = rid;
}
}
db_finalize(&q);
db_end_transaction(0);
if( pnDelta!=0 ) *pnDelta = nDelta;
return nByte;
}
/* Reconstruct the private table. The private table contains the rid
** of every manifest that is tagged with "private" and every file that
** is not used by a manifest that is not private.
*/
|
| ︙ | ︙ | |||
575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 |
" EXCEPT SELECT fid FROM mlink WHERE mid NOT IN private_ckin;"
"INSERT OR IGNORE INTO private SELECT rid FROM private_ckin;"
"DROP TABLE private_ckin;", TAG_PRIVATE
);
fix_private_blob_dependencies(0);
}
/*
** COMMAND: rebuild
**
** Usage: %fossil rebuild ?REPOSITORY? ?OPTIONS?
**
** Reconstruct the named repository database from the core
** records. Run this command after updating the fossil
** executable in a way that changes the database schema.
**
** Options:
** --analyze Run ANALYZE on the database after rebuilding
** --cluster Compute clusters for unclustered artifacts
** --compress Strive to make the database as small as possible
** --compress-only Skip the rebuilding step. Do --compress only
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > < | 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 |
" EXCEPT SELECT fid FROM mlink WHERE mid NOT IN private_ckin;"
"INSERT OR IGNORE INTO private SELECT rid FROM private_ckin;"
"DROP TABLE private_ckin;", TAG_PRIVATE
);
fix_private_blob_dependencies(0);
}
/*
** COMMAND: repack
**
** Usage: %fossil repack ?REPOSITORY?
**
** Perform extra delta-compression to try to minimize the size of the
** repository. This command is simply a short-hand for:
**
** fossil rebuild --compress-only
**
** The name for this command is stolen from the "git repack" command that
** does approximately the same thing in Git.
*/
void repack_command(void){
i64 nByte = 0;
int nDelta = 0;
int runVacuum = 0;
verify_all_options();
if( g.argc==3 ){
db_open_repository(g.argv[2]);
}else if( g.argc==2 ){
db_find_and_open_repository(OPEN_ANY_SCHEMA, 0);
if( g.argc!=2 ){
usage("?REPOSITORY-FILENAME?");
}
db_close(1);
db_open_repository(g.zRepositoryName);
}else{
usage("?REPOSITORY-FILENAME?");
}
db_unprotect(PROTECT_ALL);
nByte = extra_deltification(&nDelta);
if( nDelta>0 ){
if( nDelta==1 ){
fossil_print("1 new delta saves %,lld bytes\n", nByte);
}else{
fossil_print("%d new deltas save %,lld bytes\n", nDelta, nByte);
}
runVacuum = 1;
}else{
fossil_print("no new compression opportunities found\n");
runVacuum = db_int(0, "PRAGMA repository.freelist_count")>0;
}
if( runVacuum ){
fossil_print("Vacuuming the database... "); fflush(stdout);
db_multi_exec("VACUUM");
fossil_print("done\n");
}
}
/*
** COMMAND: rebuild
**
** Usage: %fossil rebuild ?REPOSITORY? ?OPTIONS?
**
** Reconstruct the named repository database from the core
** records. Run this command after updating the fossil
** executable in a way that changes the database schema.
**
** Options:
** --analyze Run ANALYZE on the database after rebuilding
** --cluster Compute clusters for unclustered artifacts
** --compress Strive to make the database as small as possible
** --compress-only Skip the rebuilding step. Do --compress only
** --force Force the rebuild to complete even if errors are seen
** --ifneeded Only do the rebuild if it would change the schema version
** --index Always add in the full-text search index
** --noverify Skip the verification of changes to the BLOB table
** --noindex Always omit the full-text search index
** --pagesize N Set the database pagesize to N. (512..65536 and power of 2)
** --quiet Only show output if there are errors
|
| ︙ | ︙ | |||
625 626 627 628 629 630 631 |
int optIfNeeded;
int compressOnlyFlag;
omitVerify = find_option("noverify",0,0)!=0;
forceFlag = find_option("force","f",0)!=0;
doClustering = find_option("cluster", 0, 0)!=0;
runVacuum = find_option("vacuum",0,0)!=0;
| | | | 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 |
int optIfNeeded;
int compressOnlyFlag;
omitVerify = find_option("noverify",0,0)!=0;
forceFlag = find_option("force","f",0)!=0;
doClustering = find_option("cluster", 0, 0)!=0;
runVacuum = find_option("vacuum",0,0)!=0;
runDeanalyze = find_option("deanalyze",0,0)!=0; /* Deprecated */
runAnalyze = find_option("analyze",0,0)!=0;
runCompress = find_option("compress",0,0)!=0;
zPagesize = find_option("pagesize",0,1);
showStats = find_option("stats",0,0)!=0;
optIndex = find_option("index",0,0)!=0;
optNoIndex = find_option("noindex",0,0)!=0;
optIfNeeded = find_option("ifneeded",0,0)!=0;
compressOnlyFlag = find_option("compress-only",0,0)!=0;
if( compressOnlyFlag ) runCompress = 1;
if( zPagesize ){
newPagesize = atoi(zPagesize);
if( newPagesize<512 || newPagesize>65536
|| (newPagesize&(newPagesize-1))!=0
){
fossil_fatal("page size must be a power of two between 512 and 65536");
}
|
| ︙ | ︙ | |||
686 687 688 689 690 691 692 693 |
fossil_print(
"%d errors. Rolling back changes. Use --force to force a commit.\n",
errCnt
);
db_end_transaction(1);
}else{
if( runCompress ){
fossil_print("Extra delta compression... "); fflush(stdout);
| > > | > > > > > > | > > > > | | 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 |
fossil_print(
"%d errors. Rolling back changes. Use --force to force a commit.\n",
errCnt
);
db_end_transaction(1);
}else{
if( runCompress ){
i64 nByte = 0;
int nDelta = 0;
fossil_print("Extra delta compression... "); fflush(stdout);
nByte = extra_deltification(&nDelta);
if( nDelta>0 ){
if( nDelta==1 ){
fossil_print("1 new delta saves %,lld bytes", nByte);
}else{
fossil_print("%d new deltas save %,lld bytes", nDelta, nByte);
}
runVacuum = 1;
}else{
fossil_print("none found");
}
fflush(stdout);
}
if( omitVerify ) verify_cancel();
db_end_transaction(0);
if( runCompress ) fossil_print("\n");
db_close(0);
db_open_repository(g.zRepositoryName);
if( newPagesize ){
db_multi_exec("PRAGMA page_size=%d", newPagesize);
runVacuum = 1;
}
if( runDeanalyze ){
|
| ︙ | ︙ | |||
1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 |
verify_cancel();
db_end_transaction(0);
fossil_print("project-id: %s\n", db_get("project-code", 0));
fossil_print("server-id: %s\n", db_get("server-code", 0));
zPassword = db_text(0, "SELECT pw FROM user WHERE login=%Q", g.zLogin);
fossil_print("admin-user: %s (initial password is \"%s\")\n", g.zLogin, zPassword);
}
/*
** 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.
**
** Options:
| > | | | | | | 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 |
verify_cancel();
db_end_transaction(0);
fossil_print("project-id: %s\n", db_get("project-code", 0));
fossil_print("server-id: %s\n", db_get("server-code", 0));
zPassword = db_text(0, "SELECT pw FROM user WHERE login=%Q", g.zLogin);
fossil_print("admin-user: %s (initial password is \"%s\")\n", g.zLogin, 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.
**
** Options:
** -R|--repository REPO Deconstruct given REPOSITORY
** -K|--keep-rid1 Save the filename of the artifact with RID=1 to
** the file .rid1 in the DESTINATION directory
** -L|--prefixlength N Set the length of the names of the DESTINATION
** subdirectories to N
** --private Include private artifacts
** -P|--keep-private Save the list of private artifacts to the file
** .private in the DESTINATION directory (implies
** the --private option)
*/
void deconstruct_cmd(void){
const char *zPrefixOpt;
Stmt s;
int privateFlag;
int fKeepPrivate;
|
| ︙ | ︙ |
Changes to src/regexp.c.
| ︙ | ︙ | |||
807 808 809 810 811 812 813 | ** ** Usage: %fossil test-grep REGEXP [FILE...] ** ** Run a regular expression match over the named disk files, or against ** standard input if no disk files are named on the command-line. ** ** Options: | < | 807 808 809 810 811 812 813 814 815 816 817 818 819 820 |
**
** Usage: %fossil test-grep REGEXP [FILE...]
**
** Run a regular expression match over the named disk files, or against
** standard input if no disk files are named on the command-line.
**
** Options:
** -i|--ignore-case Ignore case
*/
void re_test_grep(void){
ReCompiled *pRe;
const char *zErr;
int ignoreCase = find_option("ignore-case","i",0)!=0;
if( g.argc<3 ){
|
| ︙ | ︙ | |||
851 852 853 854 855 856 857 | ** be specified, in which case all named files are searched in reverse ** chronological order. ** ** For details of the supported regular expression dialect, see ** https://fossil-scm.org/fossil/doc/trunk/www/grep.md ** ** Options: | < | 850 851 852 853 854 855 856 857 858 859 860 861 862 863 | ** be specified, in which case all named files are searched in reverse ** chronological order. ** ** For details of the supported regular expression dialect, see ** https://fossil-scm.org/fossil/doc/trunk/www/grep.md ** ** Options: ** -c|--count Suppress normal output; instead print a count ** of the number of matching files ** -i|--ignore-case Ignore case ** -l|--files-with-matches List only hash for each match ** --once Stop searching after the first match ** -s|--no-messages Suppress error messages about nonexistent ** or unreadable files |
| ︙ | ︙ |
Changes to src/repolist.c.
| ︙ | ︙ | |||
141 142 143 144 145 146 147 |
** directory.
*/
blob_init(&base, g.zRepositoryName, -1);
sqlite3_open(":memory:", &g.db);
db_multi_exec("CREATE TABLE sfile(pathname TEXT);");
db_multi_exec("CREATE TABLE vfile(pathname);");
vfile_scan(&base, blob_size(&base), 0, 0, 0, ExtFILE);
| | > > > > | 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 |
** directory.
*/
blob_init(&base, g.zRepositoryName, -1);
sqlite3_open(":memory:", &g.db);
db_multi_exec("CREATE TABLE sfile(pathname TEXT);");
db_multi_exec("CREATE TABLE vfile(pathname);");
vfile_scan(&base, blob_size(&base), 0, 0, 0, ExtFILE);
db_multi_exec("DELETE FROM sfile WHERE pathname NOT GLOB '*[^/].fossil'"
#if USE_SEE
" AND pathname NOT GLOB '*[^/].efossil'"
#endif
);
allRepo = 0;
}
n = db_int(0, "SELECT count(*) FROM sfile");
if( n==0 ){
sqlite3_close(g.db);
g.db = 0;
g.repositoryOpen = 0;
|
| ︙ | ︙ | |||
168 169 170 171 172 173 174 175 176 177 178 179 |
"</thead><tbody>\n");
db_prepare(&q, "SELECT pathname"
" FROM sfile ORDER BY pathname COLLATE nocase;");
rNow = db_double(0, "SELECT julianday('now')");
while( db_step(&q)==SQLITE_ROW ){
const char *zName = db_column_text(&q, 0);
int nName = (int)strlen(zName);
char *zUrl;
char *zAge;
char *zFull;
RepoInfo x;
sqlite3_int64 iAge;
| > > > > > | | | > > > > | | | > > > | > > > > | 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 |
"</thead><tbody>\n");
db_prepare(&q, "SELECT pathname"
" FROM sfile ORDER BY pathname COLLATE nocase;");
rNow = db_double(0, "SELECT julianday('now')");
while( db_step(&q)==SQLITE_ROW ){
const char *zName = db_column_text(&q, 0);
int nName = (int)strlen(zName);
int nSuffix = 7; /* ".fossil" */
char *zUrl;
char *zAge;
char *zFull;
RepoInfo x;
sqlite3_int64 iAge;
#if USE_SEE
int bEncrypted = sqlite3_strglob("*.efossil", zName)==0;
if( bEncrypted ) nSuffix = 8; /* ".efossil" */
#endif
if( nName<nSuffix ) continue;
zUrl = sqlite3_mprintf("%.*s", nName-nSuffix, zName);
if( zName[0]=='/'
#ifdef _WIN32
|| sqlite3_strglob("[a-zA-Z]:/*", zName)==0
#endif
){
zFull = mprintf("%s", zName);
}else if ( allRepo ){
zFull = mprintf("/%s", zName);
}else{
zFull = mprintf("%s/%s", g.zRepositoryName, zName);
}
x.zRepoName = zFull;
remote_repo_info(&x);
if( x.isRepolistSkin ){
if( zSkinRepo==0 ){
zSkinRepo = mprintf("%s", x.zRepoName);
zSkinUrl = mprintf("%s", zUrl);
}
}
fossil_free(zFull);
if( !x.isValid
#if USE_SEE
&& !bEncrypted
#endif
){
continue;
}
if( x.isRepolistSkin==2 && !allRepo ){
/* Repositories with repolist-skin==2 are omitted from directory
** scan lists, but included in "fossil all ui" lists */
continue;
}
if( rNow <= x.rMTime ){
x.rMTime = rNow;
}else if( x.rMTime<0.0 ){
x.rMTime = rNow;
}
iAge = (sqlite3_int64)((rNow - x.rMTime)*86400);
zAge = human_readable_age(rNow - x.rMTime);
if( x.rMTime==0.0 ){
/* This repository has no entry in the "event" table.
** Its age will still be maximum, so data-sortkey will work. */
zAge = mprintf("unknown");
}
blob_append_sql(&html, "<tr><td valign='top'>");
if( !file_ends_with_repository_extension(zName,0) ){
/* The "fossil server DIRECTORY" and "fossil ui DIRECTORY" commands
** do not work for repositories whose names do not end in ".fossil".
** So do not hyperlink those cases. */
blob_append_sql(&html,"%h",zName);
} else if( sqlite3_strglob("*/.*", zName)==0 ){
/* Do not show hyperlinks for hidden repos */
blob_append_sql(&html, "%h (hidden)", zName);
} else if( allRepo && sqlite3_strglob("[a-zA-Z]:/?*", zName)!=0 ){
blob_append_sql(&html,
"<a href='%R/%T/home' target='_blank'>/%h</a>\n",
zUrl, zName);
}else if( file_ends_with_repository_extension(zName,1) ){
/* As described in
** https://fossil-scm.org/forum/info/f50f647c97c72fc1: if
** foo.fossil and foo/bar.fossil both exist and we create a
** link to foo/bar/... then the URI dispatcher will instead
** see that as a link to foo.fossil. In such cases, do not
** emit a link to foo/bar.fossil. */
char * zDirPart = file_dirname(zName);
if( db_exists("SELECT 1 FROM sfile "
"WHERE pathname=(%Q || '.fossil') COLLATE nocase"
#if USE_SEE
" OR pathname=(%Q || '.efossil') COLLATE nocase"
#endif
, zDirPart
#if USE_SEE
, zDirPart
#endif
) ){
blob_append_sql(&html,
"<s>%h</s> (directory/repo name collision)\n",
zName);
}else{
blob_append_sql(&html,
"<a href='%R/%T/home' target='_blank'>%h</a>\n",
zUrl, zName);
|
| ︙ | ︙ | |||
261 262 263 264 265 266 267 |
blob_append_sql(&html, "<td></td><td>%h</td>\n", x.zProjName);
fossil_free(x.zProjName);
}else{
blob_append_sql(&html, "<td></td><td></td>\n");
}
blob_append_sql(&html,
"<td></td><td data-sortkey='%08x'>%h</td>\n",
| | | 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 |
blob_append_sql(&html, "<td></td><td>%h</td>\n", x.zProjName);
fossil_free(x.zProjName);
}else{
blob_append_sql(&html, "<td></td><td></td>\n");
}
blob_append_sql(&html,
"<td></td><td data-sortkey='%08x'>%h</td>\n",
(int)iAge, zAge);
fossil_free(zAge);
if( x.zLoginGroup ){
blob_append_sql(&html, "<td></td><td>%h</td></tr>\n", x.zLoginGroup);
fossil_free(x.zLoginGroup);
}else{
blob_append_sql(&html, "<td></td><td></td></tr>\n");
}
|
| ︙ | ︙ | |||
298 299 300 301 302 303 304 |
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>
| | | 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 |
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">
@ <title>Repository List</title>
@ </head>
@ <body>
@ <h1 align="center">Fossil Repositories</h1>
@ %s(blob_str(&html))
@ <script>%s(builtin_text("sorttable.js"))</script>
|
| ︙ | ︙ |
Changes to src/report.c.
| ︙ | ︙ | |||
43 44 45 46 47 48 49 |
** Main menu for Tickets.
*/
void view_list(void){
const char *zScript;
Blob ril; /* Report Item List */
Stmt q;
int rn = 0;
| < | | < | | | | | | 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 |
** Main menu for Tickets.
*/
void view_list(void){
const char *zScript;
Blob ril; /* Report Item List */
Stmt q;
int rn = 0;
char *defaultReport = db_get("ticket-default-report", 0);
login_check_credentials();
if( !g.perm.RdTkt && !g.perm.NewTkt ){
login_needed(g.anon.RdTkt || g.anon.NewTkt);
return;
}
style_header("Ticket Main Menu");
ticket_standard_submenu(T_ALL_BUT(T_REPLIST));
if( g.thTrace ) Th_Trace("BEGIN_REPORTLIST<br>\n", -1);
zScript = ticket_reportlist_code();
if( g.thTrace ) Th_Trace("BEGIN_REPORTLIST_SCRIPT<br>\n", -1);
blob_zero(&ril);
ticket_init();
db_prepare(&q, "SELECT rn, title, owner FROM reportfmt ORDER BY title");
while( db_step(&q)==SQLITE_ROW ){
const char *zTitle = db_column_text(&q, 1);
const char *zOwner = db_column_text(&q, 2);
if( zTitle[0] =='_' && !g.perm.TktFmt ){
continue;
}
rn = db_column_int(&q, 0);
blob_appendf(&ril, "<li>");
if( zTitle[0] == '_' ){
blob_appendf(&ril, "%s", zTitle);
} else {
blob_appendf(&ril, "%z%h</a>", href("%R/rptview/%d", rn), zTitle);
}
blob_appendf(&ril, " ");
if( g.perm.Write && zOwner && zOwner[0] ){
blob_appendf(&ril, "(by <i>%h</i>) ", zOwner);
}
if( g.perm.TktFmt ){
blob_appendf(&ril, "[%zcopy</a>] ",
href("%R/rptedit/%d?copy=1", rn));
}
if( g.perm.Admin
|| (g.perm.WrTkt && zOwner && fossil_strcmp(g.zLogin,zOwner)==0)
){
blob_appendf(&ril, "[%zedit</a>]",
href("%R/rptedit/%d", rn));
}
if( g.perm.TktFmt ){
blob_appendf(&ril, "[%zsql</a>]",
href("%R/rptsql/%d", rn));
}
if( fossil_strcmp(zTitle, defaultReport)==0 ){
blob_appendf(&ril, " ← default");
}
blob_appendf(&ril, "</li>\n");
}
db_finalize(&q);
Th_Store("report_items", blob_str(&ril));
Th_Render(zScript);
blob_reset(&ril);
if( g.thTrace ) Th_Trace("END_REPORTLIST<br>\n", -1);
style_finish_page();
}
/*
** Remove whitespace from both ends of a string.
*/
|
| ︙ | ︙ | |||
251 252 253 254 255 256 257 258 259 260 261 262 263 264 |
*(char**)pError = mprintf("only SELECT statements are allowed");
rc = SQLITE_DENY;
break;
}
}
return rc;
}
/*
** Activate the ticket report query authorizer. Must be followed by an
** eventual call to report_unrestrict_sql().
*/
void report_restrict_sql(char **pzErr){
db_set_authorizer(report_query_authorizer,(void*)pzErr,"Ticket-Report");
| > > > > > > > > > > > > > > | 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 |
*(char**)pError = mprintf("only SELECT statements are allowed");
rc = SQLITE_DENY;
break;
}
}
return rc;
}
/*
** Make sure the reportfmt table is up-to-date. It should contain
** the "jx" column (as of version 2.21). If it does not, add it.
**
** The "jx" column is intended to hold a JSON object containing optional
** key-value pairs.
*/
void report_update_reportfmt_table(void){
if( db_table_has_column("repository","reportfmt","jx")==0 ){
db_multi_exec("ALTER TABLE repository.reportfmt"
" ADD COLUMN jx TEXT DEFAULT '{}';");
}
}
/*
** Activate the ticket report query authorizer. Must be followed by an
** eventual call to report_unrestrict_sql().
*/
void report_restrict_sql(char **pzErr){
db_set_authorizer(report_query_authorizer,(void*)pzErr,"Ticket-Report");
|
| ︙ | ︙ | |||
319 320 321 322 323 324 325 326 327 328 |
}
if( pStmt ){
sqlite3_finalize(pStmt);
}
report_unrestrict_sql();
return zErr;
}
/*
** WEBPAGE: rptsql
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | | 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 |
}
if( pStmt ){
sqlite3_finalize(pStmt);
}
report_unrestrict_sql();
return zErr;
}
/*
** Get a report number from query parameters. This can be done in various
** ways:
**
** (1) (legacy) rn=NNN where NNN is the reportfmt.rn integer primary key.
**
** (2) name=NNN where NNN is the rn.
**
** (3) name=TAG where TAG matches reportfmt.jx->>tag
**
** Regardless of how the report is specified, return the primary key, rn.
** Return 0 if not found.
*/
static int report_number(void){
int rn;
const char *zName;
char *zEnd;
/* Case (1) */
rn = atoi(PD("rn","0"));
if( rn>0 ) return rn;
zName = P("name");
if( zName==0 || zName[0]==0 ) return 0;
if( fossil_isdigit(zName[0])
&& (rn = strtol(zName, &zEnd, 10))>0
&& zEnd[0]==0
){
/* Case 2 */
return rn;
}
rn = db_int(0, "SELECT rn FROM reportfmt WHERE jx->>'tag'==%Q", zName);
return rn;
}
/*
** WEBPAGE: rptsql
** URL: /rptsql/N
**
** Display the SQL query used to generate a ticket report. The N value
** is either the report number of a report tag.
*/
void view_see_sql(void){
int rn;
const char *zTitle;
const char *zSQL;
const char *zOwner;
const char *zClrKey;
Stmt q;
login_check_credentials();
if( !g.perm.TktFmt ){
login_needed(g.anon.TktFmt);
return;
}
rn = report_number();
db_prepare(&q, "SELECT title, sqlcode, owner, cols "
"FROM reportfmt WHERE rn=%d",rn);
style_set_current_feature("report");
style_header("SQL For Report Format Number %d", rn);
if( db_step(&q)!=SQLITE_ROW ){
@ <p>Unknown report number: %d(rn)</p>
style_finish_page();
|
| ︙ | ︙ | |||
380 381 382 383 384 385 386 | /* ** WEBPAGE: rptnew ** WEBPAGE: rptedit ** ** Create (/rptnew) or edit (/rptedit) a ticket report format. ** Query parameters: ** | > | > > > > | | | | | > > > | > > > > | < | | 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 |
/*
** WEBPAGE: rptnew
** WEBPAGE: rptedit
**
** Create (/rptnew) or edit (/rptedit) a ticket report format.
** Query parameters:
**
** name=N Ticket report number or tag.
** rn=N Ticket report number (legacy).
** ^^^-- one of the two previous is required.
** t=TITLE Title of the report format
** w=USER Owner of the report format
** s=SQL SQL text used to implement the report
** k=KEY Color key
** d=DESC Optional descriptive text
** m=MIMETYPE Mimetype for DESC
** x=TAG Symbolic name for the report
*/
void view_edit(void){
int rn;
const char *zTitle; /* Title of the report */
const char *z;
const char *zOwner; /* Owner of the report */
const char *zClrKey; /* Color key - used to add colors to lines */
char *zSQL; /* The SQL text that gnerates the report */
char *zErr = 0; /* An error message */
const char *zDesc; /* Extra descriptive text about the report */
const char *zMimetype; /* Mimetype for zDesc */
const char *zTag; /* Symbolic name for this report */
int dflt = P("dflt") ? 1 : 0;
login_check_credentials();
if( !g.perm.TktFmt ){
login_needed(g.anon.TktFmt);
return;
}
style_set_current_feature("report");
/*view_add_functions(0);*/
rn = report_number();
zTitle = P("t");
zOwner = PD("w",g.zLogin);
z = P("s");
zSQL = z ? trim_string(z) : 0;
zClrKey = trim_string(PD("k",""));
zDesc = trim_string(PD("d",""));
zMimetype = P("m");
zTag = P("x");
report_update_reportfmt_table();
if( rn>0 && P("del2") && cgi_csrf_safe(2) ){
db_multi_exec("DELETE FROM reportfmt WHERE rn=%d", rn);
cgi_redirect("reportlist");
return;
}else if( rn>0 && P("del1") && cgi_csrf_safe(2) ){
zTitle = db_text(0, "SELECT title FROM reportfmt "
"WHERE rn=%d", rn);
if( zTitle==0 ) cgi_redirect("reportlist");
style_header("Are You Sure?");
@ <form action="rptedit" method="post">
@ <p>You are about to delete all traces of the report
|
| ︙ | ︙ | |||
452 453 454 455 456 457 458 |
}
if( zErr==0
&& db_exists("SELECT 1 FROM reportfmt WHERE title=%Q and rn<>%d",
zTitle, rn)
){
zErr = mprintf("There is already another report named \"%h\"", zTitle);
}
| | | > > > | | > > | > | | > | | > > > > | > > > > > > > > > > > | | | | | | | > > > | > > > | > > > > > > > > | | | | 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 |
}
if( zErr==0
&& db_exists("SELECT 1 FROM reportfmt WHERE title=%Q and rn<>%d",
zTitle, rn)
){
zErr = mprintf("There is already another report named \"%h\"", zTitle);
}
if( zErr==0 && cgi_csrf_safe(2) ){
if( zTag && zTag[0]==0 ) zTag = 0;
if( zDesc && zDesc[0]==0 ){ zDesc = 0; zMimetype = 0; }
if( zMimetype && zMimetype[0]==0 ){ zDesc = 0; zMimetype = 0; }
if( rn>0 ){
db_multi_exec(
"UPDATE reportfmt SET title=%Q, sqlcode=%Q,"
" owner=%Q, cols=%Q, mtime=now(), "
" jx=json_patch(jx,json_object('desc',%Q,'descmt',%Q,'tag',%Q))"
" WHERE rn=%d",
zTitle, zSQL, zOwner, zClrKey, zDesc, zMimetype, zTag, rn);
}else{
db_multi_exec(
"INSERT INTO reportfmt(title,sqlcode,owner,cols,mtime,jx) "
"VALUES(%Q,%Q,%Q,%Q,now(),"
"json_object('desc',%Q,'descmt',%Q,'tag',%Q))",
zTitle, zSQL, zOwner, zClrKey, zDesc, zMimetype, zTag);
rn = db_last_insert_rowid();
}
if( dflt ){
db_set("ticket-default-report", zTitle, 0);
}else{
char *defaultReport = db_get("ticket-default-report", 0);
if( fossil_strcmp(zTitle, defaultReport)==0 ){
db_set("ticket-default-report", "", 0);
}
}
cgi_redirect(mprintf("rptview/%d", rn));
return;
}
}else if( rn==0 ){
zTitle = "";
zSQL = ticket_report_template();
zClrKey = ticket_key_template();
}else{
Stmt q;
int hasJx = 0;
zDesc = 0;
zMimetype = 0;
zTag = 0;
db_prepare(&q, "SELECT title, sqlcode, owner, cols, json_valid(jx) "
"FROM reportfmt WHERE rn=%d",rn);
if( db_step(&q)==SQLITE_ROW ){
char *defaultReport = db_get("ticket-default-report", 0);
zTitle = db_column_malloc(&q, 0);
zSQL = db_column_malloc(&q, 1);
zOwner = db_column_malloc(&q, 2);
zClrKey = db_column_malloc(&q, 3);
dflt = fossil_strcmp(zTitle, defaultReport)==0;
hasJx = db_column_int(&q, 4);
}
db_finalize(&q);
if( hasJx ){
db_prepare(&q, "SELECT jx->>'desc', jx->>'descmt', jx->>'tag'"
" FROM reportfmt WHERE rn=%d", rn);
if( db_step(&q)==SQLITE_ROW ){
zDesc = db_column_malloc(&q, 0);
zMimetype = db_column_malloc(&q, 1);
zTag = db_column_malloc(&q, 2);
}
db_finalize(&q);
}
if( P("copy") ){
rn = 0;
zTitle = mprintf("Copy Of %s", zTitle);
zOwner = g.zLogin;
}
}
if( zOwner==0 ) zOwner = g.zLogin;
style_submenu_element("Cancel", "%R/reportlist");
if( rn>0 ){
style_submenu_element("Delete", "%R/rptedit/%d?del1=1", rn);
}
style_header("%s", rn>0 ? "Edit Report Format":"Create New Report Format");
if( zErr ){
@ <blockquote class="reportError">%h(zErr)</blockquote>
}
@ <form action="rptedit" method="post"><div>
@ <input type="hidden" name="rn" value="%d(rn)">
@ <p>Report Title:<br>
@ <input type="text" name="t" value="%h(zTitle)" size="60"></p>
@ <p>Enter a complete SQL query statement against the "TICKET" table:<br>
@ <textarea name="s" rows="20" cols="80">%h(zSQL)</textarea>
@ </p>
login_insert_csrf_secret();
if( g.perm.Admin ){
@ <p>Report owner:
@ <input type="text" name="w" size="20" value="%h(zOwner)">
@ </p>
@ <p>Tag:
@ <input type="text" name="x" size="20" value="%h(zTag?zTag:"")">
@ </p>
} else {
@ <input type="hidden" name="w" value="%h(zOwner)">
if( zTag && zTag[0] ){
@ <input type="hidden" name="x" value="%h(zTag)">
}
}
@ <p>Enter an optional color key in the following box. (If blank, no
@ color key is displayed.) Each line contains the text for a single
@ entry in the key. The first token of each line is the background
@ color for that line.<br>
@ <textarea name="k" rows="8" cols="50">%h(zClrKey)</textarea>
@ </p>
@ <p>Optional human-readable description for this report<br>
@ %z(href("%R/markup_help"))Markup style</a>:
mimetype_option_menu(zMimetype, "m");
@ <br><textarea aria-label="Description:" name="d" class="wikiedit" \
@ cols="80" rows="15" wrap="virtual">%h(zDesc)</textarea>
@ </p>
@ <p><label><input type="checkbox" name="dflt" %s(dflt?"checked":"")> \
@ Make this the default report</label></p>
if( !g.perm.Admin && fossil_strcmp(zOwner,g.zLogin)!=0 ){
@ <p>This report format is owned by %h(zOwner). You are not allowed
@ to change it.</p>
@ </form>
report_format_hints();
style_finish_page();
return;
}
@ <input type="submit" value="Apply Changes">
if( rn>0 ){
@ <input type="submit" value="Delete This Report" name="del1">
}
@ </div></form>
report_format_hints();
style_finish_page();
}
/*
** Output a bunch of text that provides information about report
** formats
*/
static void report_format_hints(void){
char *zSchema;
zSchema = db_text(0,"SELECT sql FROM sqlite_schema WHERE name='ticket'");
if( zSchema==0 ){
zSchema = db_text(0,"SELECT sql FROM repository.sqlite_schema"
" WHERE name='ticket'");
}
@ <hr><h3>TICKET Schema</h3>
@ <blockquote><pre>
@ <code class="language-sql">%h(zSchema)</code>
@ </pre></blockquote>
@ <h3>Notes</h3>
@ <ul>
@ <li><p>The SQL must consist of a single SELECT statement</p></li>
@
|
| ︙ | ︙ | |||
751 752 753 754 755 756 757 |
pState->wikiFlags = WIKI_NOBADLINKS;
pState->zWikiStart = "";
pState->zWikiEnd = "";
if( P("plaintext") ){
pState->wikiFlags |= WIKI_LINKSONLY;
pState->zWikiStart = "<pre class='verbatim'>";
pState->zWikiEnd = "</pre>";
| | | | 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 |
pState->wikiFlags = WIKI_NOBADLINKS;
pState->zWikiStart = "";
pState->zWikiEnd = "";
if( P("plaintext") ){
pState->wikiFlags |= WIKI_LINKSONLY;
pState->zWikiStart = "<pre class='verbatim'>";
pState->zWikiEnd = "</pre>";
style_submenu_element("Formatted", "%R/rptview/%d", pState->rn);
}else{
style_submenu_element("Plaintext", "%R/rptview/%d?plaintext",
pState->rn);
}
}else{
pState->nCol++;
}
}
}
|
| ︙ | ︙ | |||
831 832 833 834 835 836 837 |
blob_init(&content, zData, -1);
wiki_convert(&content, 0, pState->wikiFlags);
blob_reset(&content);
@ %s(pState->zWikiEnd)
}
}else if( azName[i][0]=='#' ){
zTid = zData;
| | | 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 |
blob_init(&content, zData, -1);
wiki_convert(&content, 0, pState->wikiFlags);
blob_reset(&content);
@ %s(pState->zWikiEnd)
}
}else if( azName[i][0]=='#' ){
zTid = zData;
@ <td valign="top">%z(href("%R/tktview/%h",zData))%h(zData)</a></td>
}else if( zData[0]==0 ){
@ <td valign="top"> </td>
}else{
@ <td valign="top">
@ %h(zData)
@ </td>
}
|
| ︙ | ︙ | |||
1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 |
){
int count = 0;
int rn, rc;
char *zSql;
char *zTitle;
char *zOwner;
char *zClrKey;
int tabs;
Stmt q;
char *zErr1 = 0;
char *zErr2 = 0;
| > > | > > | < > | > > > | 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 |
){
int count = 0;
int rn, rc;
char *zSql;
char *zTitle;
char *zOwner;
char *zClrKey;
char *zDesc;
char *zMimetype;
int tabs;
Stmt q;
char *zErr1 = 0;
char *zErr2 = 0;
login_check_credentials();
if( !g.perm.RdTkt ){ login_needed(g.anon.RdTkt); return; }
report_update_reportfmt_table();
rn = report_number();
tabs = P("tablist")!=0;
db_prepare(&q,
"SELECT title, sqlcode, owner, cols, rn, jx->>'desc', jx->>'descmt'"
" FROM reportfmt WHERE rn=%d", rn);
rc = db_step(&q);
if( rc!=SQLITE_ROW ){
const char *titleSearch =
defaultTitleSearch==0 || trim_string(defaultTitleSearch)[0]==0 ?
P("title") : defaultTitleSearch;
db_finalize(&q);
db_prepare(&q,
"SELECT title, sqlcode, owner, cols, rn, jx->>'desc', jx->>'descmt'"
" FROM reportfmt WHERE title GLOB %Q",
titleSearch);
rc = db_step(&q);
}
if( rc!=SQLITE_ROW ){
db_finalize(&q);
if( redirectMissing ) {
cgi_redirect("reportlist");
}
return;
}
zTitle = db_column_malloc(&q, 0);
zSql = db_column_malloc(&q, 1);
zOwner = db_column_malloc(&q, 2);
zClrKey = db_column_malloc(&q, 3);
rn = db_column_int(&q,4);
zDesc = db_column_malloc(&q, 5);
zMimetype = db_column_malloc(&q, 6);
db_finalize(&q);
if( P("order_by") ){
/*
** If the user wants to do a column sort, wrap the query into a sub
** query and then sort the results. This is a whole lot easier than
** trying to insert an ORDER BY into the query itself, especially
|
| ︙ | ︙ | |||
1084 1085 1086 1087 1088 1089 1090 |
const char *zQS = PD("QUERY_STRING","");
db_multi_exec("PRAGMA empty_result_callbacks=ON");
style_set_current_feature("report");
if( pageWrap ) {
/* style_finish_page() should provide escaping via %h formatting */
if( zQS[0] ){
| > > > > | > > > > | > | | > > > > > > > | 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 |
const char *zQS = PD("QUERY_STRING","");
db_multi_exec("PRAGMA empty_result_callbacks=ON");
style_set_current_feature("report");
if( pageWrap ) {
/* style_finish_page() should provide escaping via %h formatting */
if( zQS[0] ){
if( g.zExtra && g.zExtra[0] ){
style_submenu_element("Raw","%R/%s/%s?tablist=1&%s",
g.zPath, g.zExtra, zQS);
}else{
style_submenu_element("Raw","%R/%s?tablist=1&%s",g.zPath,zQS);
}
style_submenu_element("Reports","%R/reportlist?%s",zQS);
} else {
if( g.zExtra && g.zExtra[0] ){
style_submenu_element("Raw","%R/%s/%s?tablist=1",g.zPath,g.zExtra);
}else{
style_submenu_element("Raw","%R/%s?tablist=1",g.zPath);
}
style_submenu_element("Reports","%R/reportlist");
}
if( g.perm.Admin
|| (g.perm.TktFmt && g.zLogin && fossil_strcmp(g.zLogin,zOwner)==0) ){
style_submenu_element("Edit", "%R/rptedit/%d", rn);
}
if( g.perm.TktFmt ){
style_submenu_element("SQL", "%R/rptsql/%d",rn);
}
if( g.perm.NewTkt ){
style_submenu_element("New Ticket", "%R/tktnew");
}
style_header("%s", zTitle);
}
if( zDesc && zDesc[0] && zMimetype ){
Blob src;
blob_init(&src, zDesc, -1);
wiki_render_by_mimetype(&src, zMimetype);
blob_reset(&src);
@ <br>
}
output_color_key(zClrKey, 1,
"border=\"0\" cellpadding=\"3\" cellspacing=\"0\" class=\"report\"");
@ <table border="1" cellpadding="2" cellspacing="0" class="report sortable"
@ data-column-types='' data-init-sort='0'>
sState.rn = rn;
sState.nCount = 0;
|
| ︙ | ︙ |
Changes to src/rss.c.
| ︙ | ︙ | |||
228 229 230 231 232 233 234 | /* ** COMMAND: rss* ** ** Usage: %fossil rss ?OPTIONS? ** ** The CLI variant of the /timeline.rss page, this produces an RSS | | > | | | | | 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 | /* ** COMMAND: rss* ** ** Usage: %fossil rss ?OPTIONS? ** ** The CLI variant of the /timeline.rss page, this produces an RSS ** feed of the timeline to stdout. ** ** Options: ** -type|y FLAG May be: all (default), ci (show check-ins only), ** t (show tickets only), w (show wiki only) ** ** -limit|n LIMIT The maximum number of items to show ** ** -tkt HASH Filter for only those events for the specified ticket ** ** -tag TAG Filter for a tag ** ** -wiki NAME Filter on a specific wiki page ** ** Only one of -tkt, -tag, or -wiki may be used. ** ** -name FILENAME Filter for a specific file. This may be combined ** with one of the other filters (useful for looking ** at a specific branch). ** |
| ︙ | ︙ |
Changes to src/schema.c.
| ︙ | ︙ | |||
124 125 126 127 128 129 130 | @ pw TEXT, -- password @ cap TEXT, -- Capabilities of this user @ cookie TEXT, -- WWW login cookie @ ipaddr TEXT, -- IP address for which cookie is valid @ cexpire DATETIME, -- Time when cookie expires @ info TEXT, -- contact information @ mtime DATE, -- last change. seconds since 1970 | | > | 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 |
@ pw TEXT, -- password
@ cap TEXT, -- Capabilities of this user
@ cookie TEXT, -- WWW login cookie
@ ipaddr TEXT, -- IP address for which cookie is valid
@ cexpire DATETIME, -- Time when cookie expires
@ info TEXT, -- contact information
@ mtime DATE, -- last change. seconds since 1970
@ photo BLOB, -- JPEG image of this user
@ jx TEXT DEFAULT '{}' -- Extra fields in JSON
@ );
@
@ -- The config table holds miscellanous information about the repository.
@ -- in the form of name-value pairs.
@ --
@ CREATE TABLE config(
@ name TEXT PRIMARY KEY NOT NULL, -- Primary name of the entry
|
| ︙ | ︙ | |||
174 175 176 177 178 179 180 | @ -- @ CREATE TABLE reportfmt( @ rn INTEGER PRIMARY KEY, -- Report number @ owner TEXT, -- Owner of this report format (not used) @ title TEXT UNIQUE, -- Title of this report @ mtime DATE, -- Last modified. seconds since 1970 @ cols TEXT, -- A color-key specification | | > | 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 |
@ --
@ CREATE TABLE reportfmt(
@ rn INTEGER PRIMARY KEY, -- Report number
@ owner TEXT, -- Owner of this report format (not used)
@ title TEXT UNIQUE, -- Title of this report
@ mtime DATE, -- Last modified. seconds since 1970
@ cols TEXT, -- A color-key specification
@ sqlcode TEXT, -- An SQL SELECT statement for this report
@ jx TEXT DEFAULT '{}' -- Additional fields encoded as JSON
@ );
@
@ -- Some ticket content (such as the originators email address or contact
@ -- information) needs to be obscured to protect privacy. This is achieved
@ -- by storing an SHA1 hash of the content. For display, the hash is
@ -- mapped back into the original text using this table.
@ --
|
| ︙ | ︙ | |||
387 388 389 390 391 392 393 | @ @ -- Assignments of tags to artifacts. Note that we allow tags to @ -- have values assigned to them. So we are not really dealing with @ -- tags here. These are really properties. But we are going to @ -- keep calling them tags because in many cases the value is ignored. @ -- @ CREATE TABLE tagxref( | | > | > | > | 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 | @ @ -- Assignments of tags to artifacts. Note that we allow tags to @ -- have values assigned to them. So we are not really dealing with @ -- tags here. These are really properties. But we are going to @ -- keep calling them tags because in many cases the value is ignored. @ -- @ CREATE TABLE tagxref( @ tagid INTEGER REFERENCES tag, -- The tag being added, removed, @ -- or propagated @ tagtype INTEGER, -- 0:-,cancel 1:+,single 2:*,propagate @ srcid INTEGER REFERENCES blob, -- Artifact tag originates from, or @ -- 0 for propagated tags @ origid INTEGER REFERENCES blob, -- Artifact holding propagated tag @ -- (any artifact type with a P-card) @ value TEXT, -- Value of the tag. Might be NULL. @ mtime TIMESTAMP, -- Time of addition or removal. Julian day @ rid INTEGER REFERENCE blob, -- Artifact tag is applied to @ UNIQUE(rid, tagid) @ ); @ CREATE INDEX tagxref_i1 ON tagxref(tagid, mtime); @ |
| ︙ | ︙ | |||
518 519 520 521 522 523 524 | # define TAG_PARENT 10 /* Change to parentage on a check-in */ # define TAG_NOTE 11 /* Extra text appended to a check-in comment */ #endif /* ** The schema for the local FOSSIL database file found at the root ** of every check-out. This database contains the complete state of | | | | | | | 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 | # define TAG_PARENT 10 /* Change to parentage on a check-in */ # define TAG_NOTE 11 /* Extra text appended to a check-in comment */ #endif /* ** The schema for the local FOSSIL database file found at the root ** of every check-out. This database contains the complete state of ** the check-out. See also the addendum in zLocalSchemaVmerge[]. */ const char zLocalSchema[] = @ -- The VVAR table holds miscellanous information about the local database @ -- in the form of name-value pairs. This is similar to the VAR table @ -- table in the repository except that this table holds information that @ -- is specific to the local check-out. @ -- @ -- Important Variables: @ -- @ -- repository Full pathname of the repository database @ -- user-id Userid to use @ -- @ CREATE TABLE vvar( @ name TEXT PRIMARY KEY NOT NULL, -- Primary name of the entry @ value CLOB, -- Content of the named parameter @ CHECK( typeof(name)='text' AND length(name)>=1 ) @ ); @ @ -- Each entry in the vfile table represents a single file in the @ -- current check-out. @ -- @ -- The file.rid field is 0 for files or folders that have been @ -- added but not yet committed. @ -- @ -- Vfile.chnged meaning: @ -- 0 File is unmodified @ -- 1 Manually edited and/or modified as part of a merge command @ -- 2 Replaced by a merge command @ -- 3 Added by a merge command @ -- 4,5 Same as 2,3 except merge using --integrate @ -- @ CREATE TABLE vfile( @ id INTEGER PRIMARY KEY, -- ID of the checked-out file @ vid INTEGER REFERENCES blob, -- The check-in this file is part of. @ chnged INT DEFAULT 0, -- 0:unchng 1:edit 2:m-chng 3:m-add 4:i-chng 5:i-add @ deleted BOOLEAN DEFAULT 0, -- True if deleted @ isexe BOOLEAN, -- True if file should be executable @ islink BOOLEAN, -- True if file should be symlink @ rid INTEGER, -- Originally from this repository record @ mrid INTEGER, -- Based on this record due to a merge @ mtime INTEGER, -- Mtime of file on disk. sec since 1970 |
| ︙ | ︙ | |||
601 602 603 604 605 606 607 | @ -- vmerge table. This must be done with a trigger, since legacy Fossil @ -- uses INSERT OR IGNORE to update vmerge, and the OR IGNORE will cause @ -- a NOT NULL constraint to be silently ignored. @ @ CREATE TRIGGER vmerge_ck1 AFTER INSERT ON vmerge @ WHEN new.mhash IS NULL BEGIN @ SELECT raise(FAIL, | | | 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 | @ -- vmerge table. This must be done with a trigger, since legacy Fossil @ -- uses INSERT OR IGNORE to update vmerge, and the OR IGNORE will cause @ -- a NOT NULL constraint to be silently ignored. @ @ CREATE TRIGGER vmerge_ck1 AFTER INSERT ON vmerge @ WHEN new.mhash IS NULL BEGIN @ SELECT raise(FAIL, @ 'trying to update a newer check-out with an older version of Fossil'); @ END; @ ; /* ** The following table holds information about forum posts. It ** is created on-demand whenever the manifest parser encounters |
| ︙ | ︙ |
Changes to src/search.c.
| ︙ | ︙ | |||
332 333 334 335 336 337 338 | ** ** Usage: %fossil test-match SEARCHSTRING FILE1 FILE2 ... ** ** Run the full-scan search algorithm using SEARCHSTRING against ** the text of the files listed. Output matches and snippets. ** ** Options: | < | 332 333 334 335 336 337 338 339 340 341 342 343 344 345 |
**
** Usage: %fossil test-match SEARCHSTRING FILE1 FILE2 ...
**
** Run the full-scan search algorithm using SEARCHSTRING against
** the text of the files listed. Output matches and snippets.
**
** Options:
** --begin TEXT Text to insert before each match
** --end TEXT Text to insert after each match
** --gap TEXT Text to indicate elided content
** --html Input is HTML
** --static Use the static Search object
*/
void test_match_cmd(void){
|
| ︙ | ︙ | |||
581 582 583 584 585 586 587 | ** Outputs, by default, some top-N fraction of the results. The -all ** option can be used to output all matches, regardless of their search ** score. The -limit option can be used to limit the number of entries ** returned. The -width option can be used to set the output width used ** when printing matches. ** ** Options: | < | > > | > > | < < > > | < > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | | | | | | | | | | | | | | | | | | | | | | | | > | 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 |
** Outputs, by default, some top-N fraction of the results. The -all
** option can be used to output all matches, regardless of their search
** score. The -limit option can be used to limit the number of entries
** returned. The -width option can be used to set the output width used
** when printing matches.
**
** Options:
** -a|--all Output all matches, not just best matches
** --debug Show additional debug content on --fts search
** --fts Use the full-text search mechanism (testing only)
** -n|--limit N Limit output to N matches
** --scope SCOPE Scope of search. Valid for --fts only. One or
** more of: all, c, d, e, f, t, w. Defaults to all.
** -W|--width WIDTH Set display width to WIDTH columns, 0 for
** unlimited. Defaults the terminal's width.
*/
void search_cmd(void){
Blob pattern;
int i;
Blob sql = empty_blob;
Stmt q;
int iBest;
char fAll = NULL != find_option("all", "a", 0);
const char *zLimit = find_option("limit","n",1);
const char *zWidth = find_option("width","W",1);
const char *zScope = find_option("scope",0,1);
int bDebug = find_option("debug",0,0)!=0;
int nLimit = zLimit ? atoi(zLimit) : -1000;
int width;
int bFts = find_option("fts",0,0)!=0;
if( zWidth ){
width = atoi(zWidth);
if( (width!=0) && (width<=20) ){
fossil_fatal("-W|--width value must be >20 or 0");
}
}else{
width = -1;
}
db_find_and_open_repository(0, 0);
if( g.argc<3 ) 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);
int srchFlags;
unsigned int j;
if( zScope==0 ){
srchFlags = SRCH_ALL;
}else{
srchFlags = 0;
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 't': srchFlags |= SRCH_TKT; break;
case 'w': srchFlags |= SRCH_WIKI; break;
}
}
}
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 */
}
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 = 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);
blob_appendf(&snip, "%s", zSnippet);
for(j=0; j<snip.nUsed; j++){
if( snip.aData[j]=='\n' ){
if( j>0 && snip.aData[j-1]=='\r' ) snip.aData[j-1] = ' ';
snip.aData[j] = ' ';
}
}
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 |
COMMENT_PRINT_TRIM_SPACE);
blob_reset(&com);
blob_reset(&snip);
if( nLimit>=1 ){
nLimit--;
if( nLimit==0 ) break;
}
}
db_finalize(&q);
blob_reset(&pattern);
}else{
/* Legacy timeline search (the default) */
(void)search_init(blob_str(&pattern),"*","*","...",SRCHFLG_STATIC);
blob_reset(&pattern);
search_sql_setup(g.db);
db_multi_exec(
"CREATE TEMP TABLE srch(rid,uuid,date,comment,x);"
"CREATE INDEX srch_idx1 ON srch(x);"
"INSERT INTO srch(rid,uuid,date,comment,x)"
" SELECT blob.rid, uuid, datetime(event.mtime,toLocal()),"
" coalesce(ecomment,comment),"
" search_score()"
" FROM event, blob"
" WHERE blob.rid=event.objid"
" AND search_match(coalesce(ecomment,comment));"
);
iBest = db_int(0, "SELECT max(x) FROM srch");
blob_append(&sql,
"SELECT rid, uuid, date, comment, 0, 0 FROM srch "
"WHERE 1 ", -1);
if(!fAll){
blob_append_sql(&sql,"AND x>%d ", iBest/3);
}
blob_append(&sql, "ORDER BY x DESC, date DESC ", -1);
db_prepare(&q, "%s", blob_sql_text(&sql));
blob_reset(&sql);
print_timeline(&q, nLimit, width, 0, 0);
db_finalize(&q);
}
}
#if INTERFACE
/* 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 */
|
| ︙ | ︙ | |||
706 707 708 709 710 711 712 | ** snip: A snippet for the match ** ** And the srchFlags parameter has been validated. This routine ** fills the X table with search results using a full-scan search. ** ** The companion indexed search routine is search_indexed(). */ | | | 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 |
** snip: A snippet for the match
**
** And the srchFlags parameter has been validated. This routine
** fills the X table with search results using a full-scan search.
**
** The companion indexed search routine is search_indexed().
*/
LOCAL void search_fullscan(
const char *zPattern, /* The query pattern */
unsigned int srchFlags /* What to search over */
){
search_init(zPattern, "<mark>", "</mark>", " ... ",
SRCHFLG_STATIC|SRCHFLG_HTML);
if( (srchFlags & SRCH_DOC)!=0 ){
char *zDocGlob = db_get("doc-glob","");
|
| ︙ | ︙ | |||
914 915 916 917 918 919 920 | ** snip: A snippet for the match ** ** And the srchFlags parameter has been validated. This routine ** fills the X table with search results using FTS indexed search. ** ** The companion full-scan search routine is search_fullscan(). */ | | > | > > > > > > > > | | | | 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 |
** snip: A snippet for the match
**
** And the srchFlags parameter has been validated. This routine
** fills the X table with search results using FTS indexed search.
**
** The companion full-scan search routine is search_fullscan().
*/
LOCAL void search_indexed(
const char *zPattern, /* The query pattern */
unsigned int srchFlags /* What to search over */
){
Blob sql;
char *zPat = mprintf("%s",zPattern);
int i;
static const char *zSnippetCall;
if( srchFlags==0 ) return;
sqlite3_create_function(g.db, "rank", 1, SQLITE_UTF8|SQLITE_INNOCUOUS, 0,
search_rank_sqlfunc, 0, 0);
for(i=0; zPat[i]; i++){
if( (zPat[i]&0x80)==0 && !fossil_isalnum(zPat[i]) ) zPat[i] = ' ';
}
blob_init(&sql, 0, 0);
if( search_index_type(0)==4 ){
/* If this repo is still using the legacy FTS4 search index, then
** the snippet() function is slightly different */
zSnippetCall = "snippet(ftsidx,'<mark>','</mark>',' ... ',-1,35)";
}else{
/* This is the common case - Using newer FTS5 search index */
zSnippetCall = "snippet(ftsidx,-1,'<mark>','</mark>',' ... ',35)";
}
blob_appendf(&sql,
"INSERT INTO x(label,url,score,id,date,snip) "
" SELECT ftsdocs.label,"
" ftsdocs.url,"
" rank(matchinfo(ftsidx,'pcsx')),"
" ftsdocs.type || ftsdocs.rid,"
" datetime(ftsdocs.mtime),"
" %s"
" FROM ftsidx CROSS JOIN ftsdocs"
" WHERE ftsidx MATCH %Q"
" AND ftsdocs.rowid=ftsidx.rowid",
zSnippetCall /*safe-for-%s*/, zPat
);
fossil_free(zPat);
if( srchFlags!=SRCH_ALL ){
const char *zSep = " AND (";
static const struct { unsigned m; char c; } aMask[] = {
{ SRCH_CKIN, 'c' },
{ SRCH_DOC, 'd' },
|
| ︙ | ︙ | |||
1069 1070 1071 1072 1073 1074 1075 |
@ <ol>
}
nRow++;
@ <li><p><a href='%R%s(zUrl)'>%h(zLabel)</a>
if( fDebug ){
@ (%e(db_column_double(&q,3)), %s(db_column_text(&q,4))
}
| | | 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 |
@ <ol>
}
nRow++;
@ <li><p><a href='%R%s(zUrl)'>%h(zLabel)</a>
if( fDebug ){
@ (%e(db_column_double(&q,3)), %s(db_column_text(&q,4))
}
@ <br><span class='snippet'>%z(cleanSnippet(zSnippet)) \
if( zDate && zDate[0] && strstr(zLabel,zDate)==0 ){
@ <small>(%h(zDate))</small>
}
@ </span></li>
if( nLimit && nRow>=nLimit ) break;
}
db_finalize(&q);
|
| ︙ | ︙ | |||
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 |
** f -> forum
** all -> everything
*/
void search_page(void){
const int isSearch = P("s")!=0;
login_check_credentials();
style_header("Search%s", isSearch ? " Results" : "");
search_screen(SRCH_ALL, 1);
style_finish_page();
}
/*
** This is a helper function for search_stext(). Writing into pOut
** the search text obtained from pIn according to zMimetype.
**
** The title of the document is the first line of text. All subsequent
** lines are the body. If the document has no title, the first line
** is blank.
*/
static void get_stext_by_mimetype(
Blob *pIn,
const char *zMimetype,
Blob *pOut
){
Blob html, title;
blob_init(&html, 0, 0);
| > > > > > > > | > > > > > > | | | | | | | | | > | > | < | < | < < < | < > | < | 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 1358 1359 1360 1361 1362 1363 1364 1365 1366 |
** f -> forum
** 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);
style_finish_page();
}
/*
** This is a helper function for search_stext(). Writing into pOut
** the search text obtained from pIn according to zMimetype.
**
** If a title is not specified in zTitle (e.g. for wiki pages that do not
** include the title in the body), it is determined from the page content.
**
** The title of the document is the first line of text. All subsequent
** lines are the body. If the document has no title, the first line
** is blank.
*/
static void get_stext_by_mimetype(
Blob *pIn,
const char *zMimetype,
const char *zTitle,
Blob *pOut
){
Blob html, title;
Blob *pHtml = &html;
blob_init(&html, 0, 0);
if( zTitle==0 ){
blob_init(&title, 0, 0);
}else{
blob_init(&title, zTitle, -1);
}
if( zMimetype==0 ) zMimetype = "text/plain";
if( fossil_strcmp(zMimetype,"text/x-fossil-wiki")==0 ){
if( blob_size(&title) ){
wiki_convert(pIn, &html, 0);
}else{
Blob tail;
blob_init(&tail, 0, 0);
if( wiki_find_title(pIn, &title, &tail) ){
blob_appendf(pOut, "%s\n", blob_str(&title));
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);
}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);
}else{
blob_append(pOut, blob_buffer(pIn), blob_size(pIn));
}
blob_reset(&html);
blob_reset(&title);
}
/*
|
| ︙ | ︙ | |||
1295 1296 1297 1298 1299 1300 1301 |
if( fossil_strcmp(zMime,"text/plain")==0 ) zMime = 0;
}else if( zMime==0 || eType!=SQLITE_TEXT ){
blob_appendf(pAccum, "%s: %s |\n", zColName, db_column_text(pQuery,i));
}else{
Blob txt;
blob_init(&txt, db_column_text(pQuery,i), -1);
blob_appendf(pAccum, "%s: ", zColName);
| | | 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 |
if( fossil_strcmp(zMime,"text/plain")==0 ) zMime = 0;
}else if( zMime==0 || eType!=SQLITE_TEXT ){
blob_appendf(pAccum, "%s: %s |\n", zColName, db_column_text(pQuery,i));
}else{
Blob txt;
blob_init(&txt, db_column_text(pQuery,i), -1);
blob_appendf(pAccum, "%s: ", zColName);
get_stext_by_mimetype(&txt, zMime, NULL, pAccum);
blob_append(pAccum, " |", 2);
blob_reset(&txt);
}
}
}
|
| ︙ | ︙ | |||
1334 1335 1336 1337 1338 1339 1340 |
){
blob_init(pOut, 0, 0);
switch( cType ){
case 'd': { /* Documents */
Blob doc;
content_get(rid, &doc);
blob_to_utf8_no_bom(&doc, 0);
| | | 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 |
){
blob_init(pOut, 0, 0);
switch( cType ){
case 'd': { /* Documents */
Blob doc;
content_get(rid, &doc);
blob_to_utf8_no_bom(&doc, 0);
get_stext_by_mimetype(&doc, mimetype_from_name(zName), NULL, pOut);
blob_reset(&doc);
break;
}
case 'f': /* Forum messages */
case 'e': /* Tech Notes */
case 'w': { /* Wiki */
Manifest *pWiki = manifest_get(rid,
|
| ︙ | ︙ | |||
1356 1357 1358 1359 1360 1361 1362 |
blob_appendf(&wiki, "<h1>%h</h1>\n", pWiki->zThreadTitle);
}
blob_appendf(&wiki, "From %s:\n\n%s", pWiki->zUser, pWiki->zWiki);
}else{
blob_init(&wiki, pWiki->zWiki, -1);
}
get_stext_by_mimetype(&wiki, wiki_filter_mimetypes(pWiki->zMimetype),
| | | 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 |
blob_appendf(&wiki, "<h1>%h</h1>\n", pWiki->zThreadTitle);
}
blob_appendf(&wiki, "From %s:\n\n%s", pWiki->zUser, pWiki->zWiki);
}else{
blob_init(&wiki, pWiki->zWiki, -1);
}
get_stext_by_mimetype(&wiki, wiki_filter_mimetypes(pWiki->zMimetype),
cType=='w' ? pWiki->zWikiTitle : NULL, pOut);
blob_reset(&wiki);
manifest_destroy(pWiki);
break;
}
case 'c': { /* Check-in Comments */
static Stmt q;
static int isPlainText = -1;
|
| ︙ | ︙ | |||
1386 1387 1388 1389 1390 1391 1392 |
blob_append(pOut, "\n", 1);
if( isPlainText ){
db_column_blob(&q, 0, pOut);
}else{
Blob x;
blob_init(&x,0,0);
db_column_blob(&q, 0, &x);
| | | 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 |
blob_append(pOut, "\n", 1);
if( isPlainText ){
db_column_blob(&q, 0, pOut);
}else{
Blob x;
blob_init(&x,0,0);
db_column_blob(&q, 0, &x);
get_stext_by_mimetype(&x, "text/x-fossil-wiki", NULL, pOut);
blob_reset(&x);
}
}
db_reset(&q);
break;
}
case 't': { /* Tickets */
|
| ︙ | ︙ | |||
1497 1498 1499 1500 1501 1502 1503 |
*/
void test_convert_stext(void){
Blob in, out;
db_find_and_open_repository(0,0);
if( g.argc!=4 ) usage("FILENAME MIMETYPE");
blob_read_from_file(&in, g.argv[2], ExtFILE);
blob_init(&out, 0, 0);
| | > | > > | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > | 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 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 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 |
*/
void test_convert_stext(void){
Blob in, out;
db_find_and_open_repository(0,0);
if( g.argc!=4 ) usage("FILENAME MIMETYPE");
blob_read_from_file(&in, g.argv[2], ExtFILE);
blob_init(&out, 0, 0);
get_stext_by_mimetype(&in, g.argv[3], NULL, &out);
fossil_print("%s\n",blob_str(&out));
blob_reset(&in);
blob_reset(&out);
}
/*
** The schema for the full-text index. The %s part must be an empty
** string or a comma followed by additional flags for the FTS virtual
** table.
*/
static const char zFtsSchema[] =
@ -- One entry for each possible search result
@ CREATE TABLE IF NOT EXISTS repository.ftsdocs(
@ rowid INTEGER PRIMARY KEY, -- Maps to the ftsidx.rowid
@ type CHAR(1), -- Type of document
@ rid INTEGER, -- BLOB.RID or TAG.TAGID for the document
@ name TEXT, -- Additional document description
@ idxed BOOLEAN, -- True if currently in the index
@ label TEXT, -- Label to print on search results
@ url TEXT, -- URL to access this document
@ mtime DATE, -- Date when document created
@ bx TEXT, -- Temporary "body" content cache
@ UNIQUE(type,rid)
@ );
@ CREATE INDEX repository.ftsdocIdxed ON ftsdocs(type,rid,name) WHERE idxed==0;
@ CREATE INDEX repository.ftsdocName ON ftsdocs(name) WHERE type='w';
@ CREATE VIEW IF NOT EXISTS repository.ftscontent AS
@ SELECT rowid, type, rid, name, idxed, label, url, mtime,
@ title(type,rid,name) AS 'title', body(type,rid,name) AS 'body'
@ FROM ftsdocs;
@ CREATE VIRTUAL TABLE IF NOT EXISTS repository.ftsidx
@ USING fts5(content="ftscontent", title, body%s);
;
static const char zFtsDrop[] =
@ DROP TABLE IF EXISTS repository.ftsidx;
@ DROP VIEW IF EXISTS repository.ftscontent;
@ DROP TABLE IF EXISTS repository.ftsdocs;
;
#if INTERFACE
/*
** Values for the search-tokenizer config option.
*/
#define FTS5TOK_NONE 0 /* disabled */
#define FTS5TOK_PORTER 1 /* porter stemmer */
#define FTS5TOK_UNICODE61 2 /* unicode61 tokenizer */
#define FTS5TOK_TRIGRAM 3 /* trigram tokenizer */
#endif
/*
** Cached FTS5TOK_xyz value for search_tokenizer_type() and
** friends.
*/
static int iFtsTokenizer = -1;
/*
** Returns one of the FTS5TOK_xyz values, depending on the value of
** the search-tokenizer config entry, defaulting to FTS5TOK_NONE. The
** result of the first call is cached for subsequent calls unless
** bRecheck is true.
*/
int search_tokenizer_type(int bRecheck){
char *z;
if( iFtsTokenizer>=0 && bRecheck==0 ){
return iFtsTokenizer;
}
z = db_get("search-tokenizer",0);
if( 0==z ){
iFtsTokenizer = FTS5TOK_NONE;
}else if(0==fossil_strcmp(z,"porter")){
iFtsTokenizer = FTS5TOK_PORTER;
}else if(0==fossil_strcmp(z,"unicode61")){
iFtsTokenizer = FTS5TOK_UNICODE61;
}else if(0==fossil_strcmp(z,"trigram")){
iFtsTokenizer = FTS5TOK_TRIGRAM;
}else{
iFtsTokenizer = is_truth(z) ? FTS5TOK_PORTER : FTS5TOK_NONE;
}
fossil_free(z);
return iFtsTokenizer;
}
/*
** Returns a string value suitable for use as the search-tokenizer
** setting's value, depending on the value of z. If z is 0 then the
** current search-tokenizer value is used as the basis for formulating
** the result (which may differ from the current value but will have
** the same meaning). Any unknown/unsupported value is interpreted as
** "off".
*/
const char *search_tokenizer_for_string(const char *z){
char * zTmp = 0;
const char *zRc = 0;
if( 0==z ){
z = zTmp = db_get("search-tokenizer",0);
}
if( 0==z ){
zRc = "off";
}else if( 0==fossil_strcmp(z,"porter") ){
zRc = "porter";
}else if( 0==fossil_strcmp(z,"unicode61") ){
zRc = "unicode61";
}else if( 0==fossil_strcmp(z,"trigram") ){
zRc = "trigram";
}else{
zRc = is_truth(z) ? "porter" : "off";
}
fossil_free(zTmp);
return zRc;
}
/*
** Sets the search-tokenizer config setting to the value of
** search_tokenizer_for_string(zName).
*/
void search_set_tokenizer(const char *zName){
db_set("search-tokenizer", search_tokenizer_for_string( zName ), 0);
iFtsTokenizer = -1;
}
/*
** Create or drop the tables associated with a full-text index.
*/
static int searchIdxExists = -1;
void search_create_index(void){
const int useTokenizer = search_tokenizer_type(0);
const char *zExtra;
switch(useTokenizer){
case FTS5TOK_PORTER: zExtra = ",tokenize=porter"; break;
case FTS5TOK_UNICODE61: zExtra = ",tokenize=unicode61"; break;
case FTS5TOK_TRIGRAM: zExtra = ",tokenize=trigram"; break;
default: zExtra = ""; break;
}
search_sql_setup(g.db);
db_multi_exec(zFtsSchema/*works-like:"%s"*/, zExtra/*safe-for-%s*/);
searchIdxExists = 1;
}
void search_drop_index(void){
db_multi_exec(zFtsDrop/*works-like:""*/);
searchIdxExists = 0;
}
/*
** Return true if the full-text search index exists. See also the
** search_index_type() function.
*/
int search_index_exists(void){
if( searchIdxExists<0 ){
searchIdxExists = db_table_exists("repository","ftsdocs");
}
return searchIdxExists;
}
/*
** Determine which full-text search index is currently being used to
** add searching. Return values:
**
** 0 No search index is available
** 4 FTS3/4
** 5 FTS5
**
** Results are cached. Make the argument 1 to reset the cache. See
** also the search_index_exists() routine.
*/
int search_index_type(int bReset){
static int idxType = -1;
if( idxType<0 || bReset ){
idxType = db_int(0,
"SELECT CASE WHEN sql GLOB '*fts4*' THEN 4 ELSE 5 END"
" FROM repository.sqlite_schema WHERE name='ftsidx'"
);
}
return idxType;
}
/*
** Fill the FTSDOCS table with unindexed entries for everything
** in the repository. This uses INSERT OR IGNORE so entries already
** in FTSDOCS are unchanged.
*/
void search_fill_index(void){
|
| ︙ | ︙ | |||
1606 1607 1608 1609 1610 1611 1612 |
void search_doc_touch(char cType, int rid, const char *zName){
if( search_index_exists() && !content_is_private(rid) ){
char zType[2];
zType[0] = cType;
zType[1] = 0;
search_sql_setup(g.db);
db_multi_exec(
| | | | 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 |
void search_doc_touch(char cType, int rid, const char *zName){
if( search_index_exists() && !content_is_private(rid) ){
char zType[2];
zType[0] = cType;
zType[1] = 0;
search_sql_setup(g.db);
db_multi_exec(
"DELETE FROM ftsidx WHERE rowid IN"
" (SELECT rowid FROM ftsdocs WHERE type=%Q AND rid=%d AND idxed)",
zType, rid
);
db_multi_exec(
"REPLACE INTO ftsdocs(type,rid,name,idxed)"
" VALUES(%Q,%d,%Q,0)",
zType, rid, zName
);
if( cType=='w' || cType=='e' ){
db_multi_exec(
"DELETE FROM ftsidx WHERE rowid IN"
" (SELECT rowid FROM ftsdocs WHERE type='%c' AND name=%Q AND idxed)",
cType, zName
);
db_multi_exec(
"DELETE FROM ftsdocs WHERE type='%c' AND name=%Q AND rid!=%d",
cType, zName, rid
);
|
| ︙ | ︙ | |||
1657 1658 1659 1660 1661 1662 1663 |
"INSERT OR IGNORE INTO current_docs(rid, name)"
" SELECT blob.rid, foci.filename FROM foci, blob"
" WHERE foci.checkinID=%d AND blob.uuid=foci.uuid"
" AND %z",
ckid, glob_expr("foci.filename", db_get("doc-glob",""))
);
db_multi_exec(
| | | | | 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 |
"INSERT OR IGNORE INTO current_docs(rid, name)"
" SELECT blob.rid, foci.filename FROM foci, blob"
" WHERE foci.checkinID=%d AND blob.uuid=foci.uuid"
" AND %z",
ckid, glob_expr("foci.filename", db_get("doc-glob",""))
);
db_multi_exec(
"DELETE FROM ftsidx WHERE rowid IN"
" (SELECT rowid FROM ftsdocs WHERE type='d'"
" AND rid NOT IN (SELECT rid FROM current_docs))"
);
db_multi_exec(
"DELETE FROM ftsdocs WHERE type='d'"
" AND rid NOT IN (SELECT rid FROM current_docs)"
);
db_multi_exec(
"INSERT OR IGNORE INTO ftsdocs(type,rid,name,idxed,label,bx,url,mtime)"
" SELECT 'd', rid, name, 0,"
" title('d',rid,name),"
" body('d',rid,name),"
" printf('/doc/%T/%%s',urlencode(name)),"
" %.17g"
" FROM current_docs",
zDocBr, rTime
);
db_multi_exec(
"INSERT INTO ftsidx(rowid,title,body)"
" SELECT rowid, label, bx FROM ftsdocs WHERE type='d' AND NOT idxed"
);
db_multi_exec(
"UPDATE ftsdocs SET"
" idxed=1,"
" bx=NULL,"
" label='Document: '||label"
" WHERE type='d' AND NOT idxed"
);
}
/*
** Deal with all of the unindexed 'c' terms in FTSDOCS
*/
static void search_update_checkin_index(void){
db_multi_exec(
"INSERT INTO ftsidx(rowid,title,body)"
" SELECT rowid, '', body('c',rid,NULL) FROM ftsdocs"
" WHERE type='c' AND NOT idxed;"
);
db_multi_exec(
"UPDATE ftsdocs SET idxed=1, name=NULL,"
" (label,url,mtime) = "
" (SELECT printf('Check-in [%%.16s] on %%s',blob.uuid,"
|
| ︙ | ︙ | |||
1716 1717 1718 1719 1720 1721 1722 |
}
/*
** Deal with all of the unindexed 't' terms in FTSDOCS
*/
static void search_update_ticket_index(void){
db_multi_exec(
| | | 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 |
}
/*
** Deal with all of the unindexed 't' terms in FTSDOCS
*/
static void search_update_ticket_index(void){
db_multi_exec(
"INSERT INTO ftsidx(rowid,title,body)"
" SELECT rowid, title('t',rid,NULL), body('t',rid,NULL) FROM ftsdocs"
" WHERE type='t' AND NOT idxed;"
);
if( db_changes()==0 ) return;
db_multi_exec(
"UPDATE ftsdocs SET idxed=1, name=NULL,"
" (label,url,mtime) ="
|
| ︙ | ︙ | |||
1739 1740 1741 1742 1743 1744 1745 |
}
/*
** Deal with all of the unindexed 'w' terms in FTSDOCS
*/
static void search_update_wiki_index(void){
db_multi_exec(
| | | 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 |
}
/*
** Deal with all of the unindexed 'w' terms in FTSDOCS
*/
static void search_update_wiki_index(void){
db_multi_exec(
"INSERT INTO ftsidx(rowid,title,body)"
" SELECT rowid, title('w',rid,NULL),body('w',rid,NULL) FROM ftsdocs"
" WHERE type='w' AND NOT idxed;"
);
if( db_changes()==0 ) return;
db_multi_exec(
"UPDATE ftsdocs SET idxed=1,"
" (name,label,url,mtime) = "
|
| ︙ | ︙ | |||
1761 1762 1763 1764 1765 1766 1767 |
}
/*
** Deal with all of the unindexed 'f' terms in FTSDOCS
*/
static void search_update_forum_index(void){
db_multi_exec(
| | | 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 |
}
/*
** Deal with all of the unindexed 'f' terms in FTSDOCS
*/
static void search_update_forum_index(void){
db_multi_exec(
"INSERT INTO ftsidx(rowid,title,body)"
" SELECT rowid, title('f',rid,NULL),body('f',rid,NULL) FROM ftsdocs"
" WHERE type='f' AND NOT idxed;"
);
if( db_changes()==0 ) return;
db_multi_exec(
"UPDATE ftsdocs SET idxed=1, name=NULL,"
" (label,url,mtime) = "
|
| ︙ | ︙ | |||
1784 1785 1786 1787 1788 1789 1790 |
}
/*
** Deal with all of the unindexed 'e' terms in FTSDOCS
*/
static void search_update_technote_index(void){
db_multi_exec(
| | | 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 |
}
/*
** Deal with all of the unindexed 'e' terms in FTSDOCS
*/
static void search_update_technote_index(void){
db_multi_exec(
"INSERT INTO ftsidx(rowid,title,body)"
" SELECT rowid, title('e',rid,NULL),body('e',rid,NULL) FROM ftsdocs"
" WHERE type='e' AND NOT idxed;"
);
if( db_changes()==0 ) return;
db_multi_exec(
"UPDATE ftsdocs SET idxed=1,"
" (name,label,url,mtime) = "
|
| ︙ | ︙ | |||
1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 |
** is to say, all the entries with FTSDOCS.IDXED=0. Add them to the
** index.
*/
void search_update_index(unsigned int srchFlags){
if( !search_index_exists() ) return;
if( !db_exists("SELECT 1 FROM ftsdocs WHERE NOT idxed") ) return;
search_sql_setup(g.db);
if( srchFlags & (SRCH_CKIN|SRCH_DOC) ){
search_update_doc_index();
search_update_checkin_index();
}
if( srchFlags & SRCH_TKT ){
search_update_ticket_index();
}
if( srchFlags & SRCH_WIKI ){
search_update_wiki_index();
}
if( srchFlags & SRCH_TECHNOTE ){
search_update_technote_index();
}
if( srchFlags & SRCH_FORUM ){
search_update_forum_index();
}
}
/*
** Construct, prepopulate, and then update the full-text index.
*/
void search_rebuild_index(void){
fossil_print("rebuilding the search index...");
| > > | 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 |
** is to say, all the entries with FTSDOCS.IDXED=0. Add them to the
** index.
*/
void search_update_index(unsigned int srchFlags){
if( !search_index_exists() ) return;
if( !db_exists("SELECT 1 FROM ftsdocs WHERE NOT idxed") ) return;
search_sql_setup(g.db);
db_unprotect(PROTECT_READONLY);
if( srchFlags & (SRCH_CKIN|SRCH_DOC) ){
search_update_doc_index();
search_update_checkin_index();
}
if( srchFlags & SRCH_TKT ){
search_update_ticket_index();
}
if( srchFlags & SRCH_WIKI ){
search_update_wiki_index();
}
if( srchFlags & SRCH_TECHNOTE ){
search_update_technote_index();
}
if( srchFlags & SRCH_FORUM ){
search_update_forum_index();
}
db_protect_pop();
}
/*
** Construct, prepopulate, and then update the full-text index.
*/
void search_rebuild_index(void){
fossil_print("rebuilding the search index...");
|
| ︙ | ︙ | |||
1855 1856 1857 1858 1859 1860 1861 | ** 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 ** | | | > | | > > | | | | 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 |
** 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 cdtwef Enable various kinds of search. c=Check-ins,
** d=Documents, t=Tickets, w=Wiki, e=Tech Notes,
** f=Forum.
**
** disable cdtwef Disable various kinds of search
**
** 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" },
|
| ︙ | ︙ | |||
1904 1905 1906 1907 1908 1909 1910 |
for(i=0; i<count(aCmd); i++){
if( fossil_strncmp(aCmd[i].z, zSubCmd, n)==0 ) break;
}
if( i>=count(aCmd) ){
Blob all;
blob_init(&all,0,0);
for(i=0; i<count(aCmd); i++) blob_appendf(&all, " %s", aCmd[i].z);
| | | 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 |
for(i=0; i<count(aCmd); i++){
if( fossil_strncmp(aCmd[i].z, zSubCmd, n)==0 ) break;
}
if( i>=count(aCmd) ){
Blob all;
blob_init(&all,0,0);
for(i=0; i<count(aCmd); i++) blob_appendf(&all, " %s", aCmd[i].z);
fossil_fatal("unknown \"%s\" - should be one of:%s",
zSubCmd, blob_str(&all));
return;
}
iCmd = aCmd[i].iCmd;
}
g.perm.Read = 1;
g.perm.RdTkt = 1;
|
| ︙ | ︙ | |||
1932 1933 1934 1935 1936 1937 1938 |
if( g.argc<4 ) usage(mprintf("%s STRING",zSubCmd));
zCtrl = g.argv[3];
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);
}
}
| < | > | > > | > > > > > | | | | > > > > > > | > > > | 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 |
if( g.argc<4 ) usage(mprintf("%s STRING",zSubCmd));
zCtrl = g.argv[3];
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",
search_tokenizer_for_string(g.argv[3]), 0);
iNewTokenizer = search_tokenizer_type(1);
if( iOldTokenizer!=iNewTokenizer ){
/* Drop or rebuild index if tokenizer changes. */
iAction = 1 + ((iOldTokenizer && iNewTokenizer)
? 1 : (iNewTokenizer ? 1 : 0));
}
}
/* destroy or rebuild the index, if requested */
if( iAction>=1 ){
search_drop_index();
}
if( iAction>=2 ){
search_rebuild_index();
}
/* Always show the status before ending */
for(i=0; i<count(aSetng); i++){
fossil_print("%-17s %s\n", aSetng[i].zName,
db_get_boolean(aSetng[i].zSetting,0) ? "on" : "off");
}
fossil_print("%-17s %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("%-17s FTS%d\n", "full-text index:", search_index_type(1));
fossil_print("%-17s %d\n", "documents:",
db_int(0, "SELECT count(*) FROM ftsdocs"));
approxSizeName(sizeof(zSize), zSize, nFts);
fossil_print("%-17s %s (%.1f%% of repository)\n", "space used",
zSize, 100.0*((double)nFts/(double)nTotal));
}else{
fossil_print("%-17s disabled\n", "full-text index:");
}
db_end_transaction(0);
}
/*
|
| ︙ | ︙ | |||
2000 2001 2002 2003 2004 2005 2006 |
);
if( db_step(&q)==SQLITE_ROW ){
const char *zUrl = db_column_text(&q,4);
const char *zDocId = db_column_text(&q,0);
char *zName;
char *z;
@ <table border=0>
| | | | | 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 |
);
if( db_step(&q)==SQLITE_ROW ){
const char *zUrl = db_column_text(&q,4);
const char *zDocId = db_column_text(&q,0);
char *zName;
char *z;
@ <table border=0>
@ <tr><td align='right'>rowid:<td> <td>%d(id)
@ <tr><td align='right'>id:<td><td>%s(zDocId)
@ <tr><td align='right'>name:<td><td>%h(db_column_text(&q,1))
@ <tr><td align='right'>idxed:<td><td>%d(db_column_int(&q,2))
@ <tr><td align='right'>label:<td><td>%h(db_column_text(&q,3))
@ <tr><td align='right'>url:<td><td>
@ <a href='%R%s(zUrl)'>%h(zUrl)</a>
@ <tr><td align='right'>mtime:<td><td>%s(db_column_text(&q,5))
z = db_text(0, "SELECT title FROM ftsidx WHERE rowid=%d",id);
if( z && z[0] ){
@ <tr><td align="right">title:<td><td>%h(z)
fossil_free(z);
}
z = db_text(0, "SELECT body FROM ftsidx WHERE rowid=%d",id);
if( z && z[0] ){
@ <tr><td align="right" valign="top">body:<td><td>%h(z)
fossil_free(z);
}
@ </table>
zName = mprintf("Indexed '%c' docs",zDocId[0]);
style_submenu_element(zName,"%R/test-ftsdocs?y=%c&ixed=1",zDocId[0]);
|
| ︙ | ︙ | |||
2101 2102 2103 2104 2105 2106 2107 | @ </tbody><tfooter> @ <tr><th>Total<th align="right">%d(cnt1)<th align="right">%d(cnt2) @ <th align="right">%d(cnt3) @ </tfooter> @ </table> style_finish_page(); } | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 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 |
@ </tbody><tfooter>
@ <tr><th>Total<th align="right">%d(cnt1)<th align="right">%d(cnt2)
@ <th align="right">%d(cnt3)
@ </tfooter>
@ </table>
style_finish_page();
}
/*
** The Fts5MatchinfoCtx bits were all taken verbatim from:
**
** https://sqlite.org/src/finfo?name=ext/fts5/fts5_test_mi.c
*/
typedef struct Fts5MatchinfoCtx Fts5MatchinfoCtx;
#if INTERFACE
#ifndef SQLITE_AMALGAMATION
typedef unsigned int u32;
#endif
#endif
struct Fts5MatchinfoCtx {
int nCol; /* Number of cols in FTS5 table */
int nPhrase; /* Number of phrases in FTS5 query */
char *zArg; /* nul-term'd copy of 2nd arg */
int nRet; /* Number of elements in aRet[] */
u32 *aRet; /* Array of 32-bit unsigned ints to return */
};
/*
** Return a pointer to the fts5_api pointer for database connection db.
** If an error occurs, return NULL and leave an error in the database
** handle (accessible using sqlite3_errcode()/errmsg()).
*/
static int fts5_api_from_db(sqlite3 *db, fts5_api **ppApi){
sqlite3_stmt *pStmt = 0;
int rc;
*ppApi = 0;
rc = sqlite3_prepare(db, "SELECT fts5(?1)", -1, &pStmt, 0);
if( rc==SQLITE_OK ){
sqlite3_bind_pointer(pStmt, 1, (void*)ppApi, "fts5_api_ptr", 0);
(void)sqlite3_step(pStmt);
rc = sqlite3_finalize(pStmt);
}
return rc;
}
/*
** Argument f should be a flag accepted by matchinfo() (a valid character
** in the string passed as the second argument). If it is not, -1 is
** returned. Otherwise, if f is a valid matchinfo flag, the value returned
** is the number of 32-bit integers added to the output array if the
** table has nCol columns and the query nPhrase phrases.
*/
static int fts5MatchinfoFlagsize(int nCol, int nPhrase, char f){
int ret = -1;
switch( f ){
case 'p': ret = 1; break;
case 'c': ret = 1; break;
case 'x': ret = 3 * nCol * nPhrase; break;
case 'y': ret = nCol * nPhrase; break;
case 'b': ret = ((nCol + 31) / 32) * nPhrase; break;
case 'n': ret = 1; break;
case 'a': ret = nCol; break;
case 'l': ret = nCol; break;
case 's': ret = nCol; break;
}
return ret;
}
static int fts5MatchinfoIter(
const Fts5ExtensionApi *pApi, /* API offered by current FTS version */
Fts5Context *pFts, /* First arg to pass to pApi functions */
Fts5MatchinfoCtx *p,
int(*x)(const Fts5ExtensionApi*,Fts5Context*,Fts5MatchinfoCtx*,char,u32*)
){
int i;
int n = 0;
int rc = SQLITE_OK;
char f;
for(i=0; (f = p->zArg[i]); i++){
rc = x(pApi, pFts, p, f, &p->aRet[n]);
if( rc!=SQLITE_OK ) break;
n += fts5MatchinfoFlagsize(p->nCol, p->nPhrase, f);
}
return rc;
}
static int fts5MatchinfoXCb(
const Fts5ExtensionApi *pApi,
Fts5Context *pFts,
void *pUserData
){
Fts5PhraseIter iter;
int iCol, iOff;
u32 *aOut = (u32*)pUserData;
int iPrev = -1;
for(pApi->xPhraseFirst(pFts, 0, &iter, &iCol, &iOff);
iCol>=0;
pApi->xPhraseNext(pFts, &iter, &iCol, &iOff)
){
aOut[iCol*3+1]++;
if( iCol!=iPrev ) aOut[iCol*3 + 2]++;
iPrev = iCol;
}
return SQLITE_OK;
}
static int fts5MatchinfoGlobalCb(
const Fts5ExtensionApi *pApi,
Fts5Context *pFts,
Fts5MatchinfoCtx *p,
char f,
u32 *aOut
){
int rc = SQLITE_OK;
switch( f ){
case 'p':
aOut[0] = p->nPhrase;
break;
case 'c':
aOut[0] = p->nCol;
break;
case 'x': {
int i;
for(i=0; i<p->nPhrase && rc==SQLITE_OK; i++){
void *pPtr = (void*)&aOut[i * p->nCol * 3];
rc = pApi->xQueryPhrase(pFts, i, pPtr, fts5MatchinfoXCb);
}
break;
}
case 'n': {
sqlite3_int64 nRow;
rc = pApi->xRowCount(pFts, &nRow);
aOut[0] = (u32)nRow;
break;
}
case 'a': {
sqlite3_int64 nRow = 0;
rc = pApi->xRowCount(pFts, &nRow);
if( nRow==0 ){
memset(aOut, 0, sizeof(u32) * p->nCol);
}else{
int i;
for(i=0; rc==SQLITE_OK && i<p->nCol; i++){
sqlite3_int64 nToken;
rc = pApi->xColumnTotalSize(pFts, i, &nToken);
if( rc==SQLITE_OK){
aOut[i] = (u32)((2*nToken + nRow) / (2*nRow));
}
}
}
break;
}
}
return rc;
}
static int fts5MatchinfoLocalCb(
const Fts5ExtensionApi *pApi,
Fts5Context *pFts,
Fts5MatchinfoCtx *p,
char f,
u32 *aOut
){
int i;
int rc = SQLITE_OK;
switch( f ){
case 'b': {
int iPhrase;
int nInt = ((p->nCol + 31) / 32) * p->nPhrase;
for(i=0; i<nInt; i++) aOut[i] = 0;
for(iPhrase=0; iPhrase<p->nPhrase; iPhrase++){
Fts5PhraseIter iter;
int iCol;
for(pApi->xPhraseFirstColumn(pFts, iPhrase, &iter, &iCol);
iCol>=0;
pApi->xPhraseNextColumn(pFts, &iter, &iCol)
){
aOut[iPhrase * ((p->nCol+31)/32) + iCol/32] |= ((u32)1 << iCol%32);
}
}
break;
}
case 'x':
case 'y': {
int nMul = (f=='x' ? 3 : 1);
int iPhrase;
for(i=0; i<(p->nCol*p->nPhrase); i++) aOut[i*nMul] = 0;
for(iPhrase=0; iPhrase<p->nPhrase; iPhrase++){
Fts5PhraseIter iter;
int iOff, iCol;
for(pApi->xPhraseFirst(pFts, iPhrase, &iter, &iCol, &iOff);
iOff>=0;
pApi->xPhraseNext(pFts, &iter, &iCol, &iOff)
){
aOut[nMul * (iCol + iPhrase * p->nCol)]++;
}
}
break;
}
case 'l': {
for(i=0; rc==SQLITE_OK && i<p->nCol; i++){
int nToken;
rc = pApi->xColumnSize(pFts, i, &nToken);
aOut[i] = (u32)nToken;
}
break;
}
case 's': {
int nInst;
memset(aOut, 0, sizeof(u32) * p->nCol);
rc = pApi->xInstCount(pFts, &nInst);
for(i=0; rc==SQLITE_OK && i<nInst; i++){
int iPhrase, iOff, iCol = 0;
int iNextPhrase;
int iNextOff;
u32 nSeq = 1;
int j;
rc = pApi->xInst(pFts, i, &iPhrase, &iCol, &iOff);
iNextPhrase = iPhrase+1;
iNextOff = iOff+pApi->xPhraseSize(pFts, 0);
for(j=i+1; rc==SQLITE_OK && j<nInst; j++){
int ip, ic, io;
rc = pApi->xInst(pFts, j, &ip, &ic, &io);
if( ic!=iCol || io>iNextOff ) break;
if( ip==iNextPhrase && io==iNextOff ){
nSeq++;
iNextPhrase = ip+1;
iNextOff = io + pApi->xPhraseSize(pFts, ip);
}
}
if( nSeq>aOut[iCol] ) aOut[iCol] = nSeq;
}
break;
}
}
return rc;
}
static Fts5MatchinfoCtx *fts5MatchinfoNew(
const Fts5ExtensionApi *pApi, /* API offered by current FTS version */
Fts5Context *pFts, /* First arg to pass to pApi functions */
sqlite3_context *pCtx, /* Context for returning error message */
const char *zArg /* Matchinfo flag string */
){
Fts5MatchinfoCtx *p;
int nCol;
int nPhrase;
int i;
int nInt;
sqlite3_int64 nByte;
int rc;
nCol = pApi->xColumnCount(pFts);
nPhrase = pApi->xPhraseCount(pFts);
nInt = 0;
for(i=0; zArg[i]; i++){
int n = fts5MatchinfoFlagsize(nCol, nPhrase, zArg[i]);
if( n<0 ){
char *zErr = sqlite3_mprintf("unrecognized matchinfo flag: %c", zArg[i]);
sqlite3_result_error(pCtx, zErr, -1);
sqlite3_free(zErr);
return 0;
}
nInt += n;
}
nByte = sizeof(Fts5MatchinfoCtx) /* The struct itself */
+ sizeof(u32) * nInt /* The p->aRet[] array */
+ (i+1); /* The p->zArg string */
p = (Fts5MatchinfoCtx*)sqlite3_malloc64(nByte);
if( p==0 ){
sqlite3_result_error_nomem(pCtx);
return 0;
}
memset(p, 0, nByte);
p->nCol = nCol;
p->nPhrase = nPhrase;
p->aRet = (u32*)&p[1];
p->nRet = nInt;
p->zArg = (char*)&p->aRet[nInt];
memcpy(p->zArg, zArg, i);
rc = fts5MatchinfoIter(pApi, pFts, p, fts5MatchinfoGlobalCb);
if( rc!=SQLITE_OK ){
sqlite3_result_error_code(pCtx, rc);
sqlite3_free(p);
p = 0;
}
return p;
}
static void fts5MatchinfoFunc(
const Fts5ExtensionApi *pApi, /* API offered by current FTS version */
Fts5Context *pFts, /* First arg to pass to pApi functions */
sqlite3_context *pCtx, /* Context for returning result/error */
int nVal, /* Number of values in apVal[] array */
sqlite3_value **apVal /* Array of trailing arguments */
){
const char *zArg;
Fts5MatchinfoCtx *p;
int rc = SQLITE_OK;
if( nVal>0 ){
zArg = (const char*)sqlite3_value_text(apVal[0]);
}else{
zArg = "pcx";
}
p = (Fts5MatchinfoCtx*)pApi->xGetAuxdata(pFts, 0);
if( p==0 || sqlite3_stricmp(zArg, p->zArg) ){
p = fts5MatchinfoNew(pApi, pFts, pCtx, zArg);
if( p==0 ){
rc = SQLITE_NOMEM;
}else{
rc = pApi->xSetAuxdata(pFts, p, sqlite3_free);
}
}
if( rc==SQLITE_OK ){
rc = fts5MatchinfoIter(pApi, pFts, p, fts5MatchinfoLocalCb);
}
if( rc!=SQLITE_OK ){
sqlite3_result_error_code(pCtx, rc);
}else{
/* No errors has occured, so return a copy of the array of integers. */
int nByte = p->nRet * sizeof(u32);
sqlite3_result_blob(pCtx, (void*)p->aRet, nByte, SQLITE_TRANSIENT);
}
}
int db_register_fts5(sqlite3 *db){
int rc; /* Return code */
fts5_api *pApi; /* FTS5 API functions */
/* Extract the FTS5 API pointer from the database handle. The
** fts5_api_from_db() function above is copied verbatim from the
** FTS5 documentation. Refer there for details. */
rc = fts5_api_from_db(db, &pApi);
if( rc!=SQLITE_OK ) return rc;
/* If fts5_api_from_db() returns NULL, then either FTS5 is not registered
** with this database handle, or an error (OOM perhaps?) has occurred.
**
** Also check that the fts5_api object is version 2 or newer.
*/
if( pApi==0 || pApi->iVersion<2 ){
return SQLITE_ERROR;
}
/* Register the implementation of matchinfo() */
rc = pApi->xCreateFunction(pApi, "matchinfo", 0, fts5MatchinfoFunc, 0);
return rc;
}
|
Changes to src/security_audit.c.
| ︙ | ︙ | |||
98 99 100 101 102 103 104 105 | const char *zAnonCap; /* Capabilities of user "anonymous" and "nobody" */ const char *zDevCap; /* Capabilities of user group "developer" */ const char *zReadCap; /* Capabilities of user group "reader" */ const char *zPubPages; /* GLOB pattern for public pages */ const char *zSelfCap; /* Capabilities of self-registered users */ int hasSelfReg = 0; /* True if able to self-register */ const char *zPublicUrl; /* Canonical access URL */ char *z; | > | | 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 |
const char *zAnonCap; /* Capabilities of user "anonymous" and "nobody" */
const char *zDevCap; /* Capabilities of user group "developer" */
const char *zReadCap; /* Capabilities of user group "reader" */
const char *zPubPages; /* GLOB pattern for public pages */
const char *zSelfCap; /* Capabilities of self-registered users */
int hasSelfReg = 0; /* True if able to self-register */
const char *zPublicUrl; /* Canonical access URL */
Blob cmd;
char *z;
int n, i;
CapabilityString *pCap;
char **azCSP; /* Parsed content security policy */
login_check_credentials();
if( !g.perm.Admin ){
login_needed(0);
return;
|
| ︙ | ︙ | |||
273 274 275 276 277 278 279 280 281 282 283 284 285 286 |
@
@ <p>Disable TH1 docs by recompiling Fossil without the
@ -DFOSSIL_ENABLE_TH1_DOCS flag, and/or clear the th1-docs setting
@ and ensure that the TH1_ENABLE_DOCS environment variable does not
@ exist in the environment.</p>
}
#endif
/* Anonymous users should not be able to harvest email addresses
** from tickets.
*/
if( hasAnyCap(zAnonCap, "e") ){
@ <li><p><b>WARNING:</b>
@ Anonymous users can view email addresses and other personally
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 |
@
@ <p>Disable TH1 docs by recompiling Fossil without the
@ -DFOSSIL_ENABLE_TH1_DOCS flag, and/or clear the th1-docs setting
@ and ensure that the TH1_ENABLE_DOCS environment variable does not
@ exist in the environment.</p>
}
#endif
#if FOSSIL_ENABLE_TCL
@ <li><p>
if( db_get_boolean("tcl",0) ){
#ifdef FOSSIL_ENABLE_TH1_DOCS
if( Th_AreDocsEnabled() ){
@ <b>DANGER:</b>
}else{
@ <b>WARNING:</b>
}
#else
@ <b>WARNING:</b>
#endif
@ This server is compiled with -DFOSSIL_ENABLE_TCL and Tcl integration
@ is enabled for this repository. Anyone who can execute malicious
@ TH1 script on that server can also execute arbitrary Tcl script
@ under the identity of the operating system process of that server.
@ This is a serious security concern.</p>
@
@ <p>Disable Tcl integration by recompiling Fossil without the
@ -DFOSSIL_ENABLE_TCL flag, and/or clear the 'tcl' setting.</p>
}else{
@ This server is compiled with -DFOSSIL_ENABLE_TCL. Tcl integration
@ is disabled for this particular repository, so you are safe for
@ now. However, to prevent potential problems caused by accidentally
@ enabling Tcl integration in the future, it is recommended that you
@ recompile Fossil without the -DFOSSIL_ENABLE_TCL flag.</p>
}
#endif
/* Anonymous users should not be able to harvest email addresses
** from tickets.
*/
if( hasAnyCap(zAnonCap, "e") ){
@ <li><p><b>WARNING:</b>
@ Anonymous users can view email addresses and other personally
|
| ︙ | ︙ | |||
661 662 663 664 665 666 667 668 669 670 671 672 673 674 |
@ INSERT INTO private SELECT rid FROM blob WHERE content IS NULL;
@ </pre></blockquote>
@ </p>
table_of_public_phantoms();
@ </li>
}
@ </ol>
style_finish_page();
}
/*
** WEBPAGE: takeitprivate
**
| > > > > > > > > > > > | 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 |
@ INSERT INTO private SELECT rid FROM blob WHERE content IS NULL;
@ </pre></blockquote>
@ </p>
table_of_public_phantoms();
@ </li>
}
blob_init(&cmd, 0, 0);
for(i=0; g.argvOrig[i]!=0; i++){
blob_append_escaped_arg(&cmd, g.argvOrig[i], 0);
}
@ <li><p>
@ The command that generated this page:
@ <blockquote>
@ <tt>%h(blob_str(&cmd))</tt>
@ </blockquote></li>
blob_zero(&cmd);
@ </ol>
style_finish_page();
}
/*
** WEBPAGE: takeitprivate
**
|
| ︙ | ︙ | |||
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 |
if( !g.perm.Admin ){
login_needed(0);
return;
}
style_header("Server Error Log");
style_submenu_element("Test", "%R/test-warning");
style_submenu_element("Refresh", "%R/errorlog");
if( g.zErrlog==0 || fossil_strcmp(g.zErrlog,"-")==0 ){
@ <p>To create a server error log:
@ <ol>
@ <li><p>
@ If the server is running as CGI, then create a line in the CGI file
@ like this:
@ <blockquote><pre>
@ errorlog: <i>FILENAME</i>
@ </pre></blockquote>
@ <li><p>
@ If the server is running using one of
@ the "fossil http" or "fossil server" commands then add
@ a command-line option "--errorlog <i>FILENAME</i>" to that
@ command.
@ </ol>
style_finish_page();
return;
}
| > > > > | > | 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 |
if( !g.perm.Admin ){
login_needed(0);
return;
}
style_header("Server Error Log");
style_submenu_element("Test", "%R/test-warning");
style_submenu_element("Refresh", "%R/errorlog");
style_submenu_element("Admin-Log", "admin_log");
style_submenu_element("User-Log", "access_log");
style_submenu_element("Artifact-Log", "rcvfromlist");
if( g.zErrlog==0 || fossil_strcmp(g.zErrlog,"-")==0 ){
@ <p>To create a server error log:
@ <ol>
@ <li><p>
@ If the server is running as CGI, then create a line in the CGI file
@ like this:
@ <blockquote><pre>
@ errorlog: <i>FILENAME</i>
@ </pre></blockquote>
@ <li><p>
@ If the server is running using one of
@ the "fossil http" or "fossil server" commands then add
@ a command-line option "--errorlog <i>FILENAME</i>" to that
@ command.
@ </ol>
style_finish_page();
return;
}
if( P("truncate1") && cgi_csrf_safe(2) ){
fclose(fopen(g.zErrlog,"w"));
}
if( P("download") ){
Blob log;
blob_read_from_file(&log, g.zErrlog, ExtFILE);
cgi_set_content_type("text/plain");
cgi_set_content(&log);
return;
}
szFile = file_size(g.zErrlog, ExtFILE);
if( P("truncate") ){
@ <form action="%R/errorlog" method="POST">
login_insert_csrf_secret();
@ <p>Confirm that you want to truncate the %,lld(szFile)-byte error log:
@ <input type="submit" name="truncate1" value="Confirm">
@ <input type="submit" name="cancel" value="Cancel">
@ </form>
style_finish_page();
return;
}
|
| ︙ | ︙ |
Changes to src/setup.c.
| ︙ | ︙ | |||
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 |
setup_menu_entry("Login-Group", "setup_login_group",
"Manage single sign-on between this repository and others"
" on the same server");
setup_menu_entry("Tickets", "tktsetup",
"Configure the trouble-ticketing system for this repository");
setup_menu_entry("Wiki", "setup_wiki",
"Configure the wiki for this repository");
setup_menu_entry("Chat", "setup_chat",
"Configure the chatroom");
}
setup_menu_entry("Search","srchsetup",
"Configure the built-in search engine");
setup_menu_entry("URL Aliases", "waliassetup",
"Configure URL aliases");
if( setup_user ){
setup_menu_entry("Notification", "setup_notification",
| > > > > | 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 |
setup_menu_entry("Login-Group", "setup_login_group",
"Manage single sign-on between this repository and others"
" on the same server");
setup_menu_entry("Tickets", "tktsetup",
"Configure the trouble-ticketing system for this repository");
setup_menu_entry("Wiki", "setup_wiki",
"Configure the wiki for this repository");
setup_menu_entry("Interwiki Map", "intermap",
"Mapping keywords for interwiki links");
setup_menu_entry("Chat", "setup_chat",
"Configure the chatroom");
setup_menu_entry("Forum", "setup_forum",
"Forum config and metrics");
}
setup_menu_entry("Search","srchsetup",
"Configure the built-in search engine");
setup_menu_entry("URL Aliases", "waliassetup",
"Configure URL aliases");
if( setup_user ){
setup_menu_entry("Notification", "setup_notification",
|
| ︙ | ︙ | |||
196 197 198 199 200 201 202 |
const char *zQ = P(zQParm);
int iVal = db_get_boolean(zVar, dfltVal);
if( zQ==0 && !disabled && P("submit") ){
zQ = "off";
}
if( zQ ){
int iQ = fossil_strcmp(zQ,"on")==0 || atoi(zQ);
| | < | | < | | < | 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 |
const char *zQ = P(zQParm);
int iVal = db_get_boolean(zVar, dfltVal);
if( zQ==0 && !disabled && P("submit") ){
zQ = "off";
}
if( zQ ){
int iQ = fossil_strcmp(zQ,"on")==0 || atoi(zQ);
if( iQ!=iVal && cgi_csrf_safe(2) ){
db_protect_only(PROTECT_NONE);
db_set(zVar/*works-like:"x"*/, iQ ? "1" : "0", 0);
db_protect_pop();
setup_incr_cfgcnt();
admin_log("Set option [%q] to [%q].",
zVar, iQ ? "on" : "off");
iVal = iQ;
}
}
@ <label><input type="checkbox" name="%s(zQParm)" \
@ aria-label="%h(zLabel[0]?zLabel:zQParm)" \
if( iVal ){
@ checked="checked" \
}
if( disabled ){
@ disabled="disabled" \
}
@ > <b>%s(zLabel)</b></label>
}
/*
** Generate an entry box for an attribute.
*/
void entry_attribute(
const char *zLabel, /* The text label on the entry box */
int width, /* Width of the entry box */
const char *zVar, /* The corresponding row in the CONFIG table */
const char *zQParm, /* The query parameter */
const char *zDflt, /* Default value if CONFIG table entry does not exist */
int disabled /* 1 if disabled */
){
const char *zVal = db_get(zVar, zDflt);
const char *zQ = P(zQParm);
if( zQ && fossil_strcmp(zQ,zVal)!=0 && cgi_csrf_safe(2) ){
const int nZQ = (int)strlen(zQ);
setup_incr_cfgcnt();
db_protect_only(PROTECT_NONE);
db_set(zVar/*works-like:"x"*/, zQ, 0);
db_protect_pop();
admin_log("Set entry_attribute %Q to: %.*s%s",
zVar, 20, zQ, (nZQ>20 ? "..." : ""));
zVal = zQ;
}
@ <input aria-label="%h(zLabel[0]?zLabel:zQParm)" type="text" \
@ id="%s(zQParm)" name="%s(zQParm)" value="%h(zVal)" size="%d(width)" \
if( disabled ){
@ disabled="disabled" \
}
@ > <b>%s(zLabel)</b>
}
/*
** Generate a text box for an attribute.
*/
const char *textarea_attribute(
const char *zLabel, /* The text label on the textarea */
int rows, /* Rows in the textarea */
int cols, /* Columns in the textarea */
const char *zVar, /* The corresponding row in the CONFIG table */
const char *zQP, /* The query parameter */
const char *zDflt, /* Default value if CONFIG table entry does not exist */
int disabled /* 1 if the textarea should not be editable */
){
const char *z = db_get(zVar, zDflt);
const char *zQ = P(zQP);
if( zQ && !disabled && fossil_strcmp(zQ,z)!=0 && cgi_csrf_safe(2) ){
const int nZQ = (int)strlen(zQ);
db_protect_only(PROTECT_NONE);
db_set(zVar/*works-like:"x"*/, zQ, 0);
db_protect_pop();
setup_incr_cfgcnt();
admin_log("Set textarea_attribute %Q to: %.*s%s",
zVar, 20, zQ, (nZQ>20 ? "..." : ""));
z = zQ;
|
| ︙ | ︙ | |||
303 304 305 306 307 308 309 |
const char *zDflt, /* Default value if CONFIG table entry does not exist */
int nChoice, /* Number of choices */
const char *const *azChoice /* Choices in pairs (VAR value, Display) */
){
const char *z = db_get(zVar, zDflt);
const char *zQ = P(zQP);
int i;
| | < | 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 |
const char *zDflt, /* Default value if CONFIG table entry does not exist */
int nChoice, /* Number of choices */
const char *const *azChoice /* Choices in pairs (VAR value, Display) */
){
const char *z = db_get(zVar, zDflt);
const char *zQ = P(zQP);
int i;
if( zQ && fossil_strcmp(zQ,z)!=0 && cgi_csrf_safe(2) ){
const int nZQ = (int)strlen(zQ);
db_unprotect(PROTECT_ALL);
db_set(zVar/*works-like:"x"*/, zQ, 0);
setup_incr_cfgcnt();
db_protect_pop();
admin_log("Set multiple_choice_attribute %Q to: %.*s%s",
zVar, 20, zQ, (nZQ>20 ? "..." : ""));
z = zQ;
|
| ︙ | ︙ | |||
367 368 369 370 371 372 373 |
@ this means that hyperlink visited/unvisited colors will not operate
@ on those platforms when "UserAgent and Javascript" is selected.</p>
@
@ <p>Additional parameters that control the behavior of Javascript:</p>
@ <blockquote>
entry_attribute("Delay in milliseconds before enabling hyperlinks", 5,
"auto-hyperlink-delay", "ah-delay", "50", 0);
| | | 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 |
@ this means that hyperlink visited/unvisited colors will not operate
@ on those platforms when "UserAgent and Javascript" is selected.</p>
@
@ <p>Additional parameters that control the behavior of Javascript:</p>
@ <blockquote>
entry_attribute("Delay in milliseconds before enabling hyperlinks", 5,
"auto-hyperlink-delay", "ah-delay", "50", 0);
@ <br>
onoff_attribute("Also require a mouse event before enabling hyperlinks",
"auto-hyperlink-mouseover", "ahmo", 0, 0);
@ </blockquote>
@ <p>For maximum robot defense, "Delay" should be at least 50 milliseconds
@ and "require a mouse event" should be turned on. These values only come
@ into play when the main auto-hyperlink settings is 2 ("UserAgent and
@ Javascript").</p>
|
| ︙ | ︙ | |||
408 409 410 411 412 413 414 | @ website can present a crippling CPU and bandwidth load. @ @ <p>The settings on this page are intended to help site administrators @ defend the site against robots. @ @ <form action="%R/setup_robot" method="post"><div> login_insert_csrf_secret(); | | | > | > > > > > > > > > > > > | | 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 |
@ website can present a crippling CPU and bandwidth load.
@
@ <p>The settings on this page are intended to help site administrators
@ defend the site against robots.
@
@ <form action="%R/setup_robot" method="post"><div>
login_insert_csrf_secret();
@ <input type="submit" name="submit" value="Apply Changes"></p>
@ <hr>
addAutoHyperlinkSettings();
@ <hr>
entry_attribute("Server Load Average Limit", 11, "max-loadavg", "mxldavg",
"0.0", 0);
@ <p>Some expensive operations (such as computing tarballs, zip archives,
@ or annotation/blame pages) are prohibited if the load average on the host
@ computer is too large. Set the threshold for disallowing expensive
@ computations here. Set this to 0.0 to disable the load average limit.
@ This limit is only enforced on Unix servers. On Linux systems,
@ access to the /proc virtual filesystem is required, which means this limit
@ might not work inside a chroot() jail.
@ (Property: "max-loadavg")</p>
@ <hr>
@ <p><input type="submit" name="submit" value="Apply Changes"></p>
@ </div></form>
db_end_transaction(0);
style_finish_page();
}
/*
** WEBPAGE: setup_access
|
| ︙ | ︙ | |||
440 441 442 443 444 445 446 |
}
style_set_current_feature("setup");
style_header("Access Control Settings");
db_begin_transaction();
@ <form action="%R/setup_access" method="post"><div>
login_insert_csrf_secret();
| | | | | 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 |
}
style_set_current_feature("setup");
style_header("Access Control Settings");
db_begin_transaction();
@ <form action="%R/setup_access" method="post"><div>
login_insert_csrf_secret();
@ <input type="submit" name="submit" value="Apply Changes"></p>
@ <hr>
multiple_choice_attribute("Redirect to HTTPS",
"redirect-to-https", "redirhttps", "0",
count(azRedirectOpts)/2, azRedirectOpts);
@ <p>Force the use of HTTPS by redirecting to HTTPS when an
@ unencrypted request is received. This feature can be enabled
@ for the Login page only, or for all pages.
@ <p>Further details: When enabled, this option causes the $secureurl TH1
@ variable is set to an "https:" variant of $baseurl. Otherwise,
@ $secureurl is just an alias for $baseurl.
@ (Property: "redirect-to-https". "0" for off, "1" for Login page only,
@ "2" otherwise.)
@ <hr>
onoff_attribute("Require password for local access",
"localauth", "localauth", 0, 0);
@ <p>When enabled, the password sign-in is always required for
@ web access. When disabled, unrestricted web access from 127.0.0.1
@ is allowed for the <a href="%R/help/ui">fossil ui</a> command or
@ from the <a href="%R/help/server">fossil server</a>,
@ <a href="%R/help/http">fossil http</a> commands when the
|
| ︙ | ︙ | |||
479 480 481 482 483 484 485 | @ <a href="%R/help/server">fossil http</a> commands @ without the "--localauth" option. @ <li> The server is started from CGI without the "localauth" keyword @ in the CGI script. @ </ol> @ (Property: "localauth") @ | | | | | | | | | | | | | | > > > > > > > > > | | | | | | | 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 |
@ <a href="%R/help/server">fossil http</a> commands
@ without the "--localauth" option.
@ <li> The server is started from CGI without the "localauth" keyword
@ in the CGI script.
@ </ol>
@ (Property: "localauth")
@
@ <hr>
onoff_attribute("Enable /test_env",
"test_env_enable", "test_env_enable", 0, 0);
@ <p>When enabled, the %h(g.zBaseURL)/test_env URL is available to all
@ users. When disabled (the default) only users Admin and Setup can visit
@ the /test_env page.
@ (Property: "test_env_enable")
@ </p>
@
@ <hr>
onoff_attribute("Enable /artifact_stats",
"artifact_stats_enable", "artifact_stats_enable", 0, 0);
@ <p>When enabled, the %h(g.zBaseURL)/artifact_stats URL is available to all
@ users. When disabled (the default) only users with check-in privilege may
@ access the /artifact_stats page.
@ (Property: "artifact_stats_enable")
@ </p>
@
@ <hr>
onoff_attribute("Allow REMOTE_USER authentication",
"remote_user_ok", "remote_user_ok", 0, 0);
@ <p>When enabled, if the REMOTE_USER environment variable is set to the
@ login name of a valid user and no other login credentials are available,
@ then the REMOTE_USER is accepted as an authenticated user.
@ (Property: "remote_user_ok")
@ </p>
@
@ <hr>
onoff_attribute("Allow HTTP_AUTHENTICATION authentication",
"http_authentication_ok", "http_authentication_ok", 0, 0);
@ <p>When enabled, allow the use of the HTTP_AUTHENTICATION environment
@ variable or the "Authentication:" HTTP header to find the username and
@ password. This is another way of supporting Basic Authentication.
@ (Property: "http_authentication_ok")
@ </p>
@
@ <hr>
entry_attribute("Login expiration time", 6, "cookie-expire", "cex",
"8766", 0);
@ <p>The number of hours for which a login is valid. This must be a
@ positive number. The default is 8766 hours which is approximately equal
@ to a year.
@ (Property: "cookie-expire")</p>
@ <hr>
entry_attribute("Download packet limit", 10, "max-download", "mxdwn",
"5000000", 0);
@ <p>Fossil tries to limit out-bound sync, clone, and pull packets
@ to this many bytes, uncompressed. If the client requires more data
@ than this, then the client will issue multiple HTTP requests.
@ Values below 1 million are not recommended. 5 million is a
@ reasonable number. (Property: "max-download")</p>
@ <hr>
entry_attribute("Download time limit", 11, "max-download-time", "mxdwnt",
"30", 0);
@ <p>Fossil tries to spend less than this many seconds gathering
@ the out-bound data of sync, clone, and pull packets.
@ If the client request takes longer, a partial reply is given similar
@ to the download packet limit. 30s is a reasonable default.
@ (Property: "max-download-time")</p>
@ <a id="slal"></a>
@ <hr>
entry_attribute("Server Load Average Limit", 11, "max-loadavg", "mxldavg",
"0.0", 0);
@ <p>Some expensive operations (such as computing tarballs, zip archives,
@ or annotation/blame pages) are prohibited if the load average on the host
@ computer is too large. Set the threshold for disallowing expensive
@ computations here. Set this to 0.0 to disable the load average limit.
@ This limit is only enforced on Unix servers. On Linux systems,
@ access to the /proc virtual filesystem is required, which means this limit
@ might not work inside a chroot() jail.
@ (Property: "max-loadavg")</p>
/* Add the auto-hyperlink settings controls. These same controls
** are also accessible from the /setup_robot page.
*/
@ <hr>
addAutoHyperlinkSettings();
@ <hr>
onoff_attribute("Require a CAPTCHA if not logged in",
"require-captcha", "reqcapt", 1, 0);
@ <p>Require a CAPTCHA for edit operations (appending, creating, or
@ editing wiki or tickets or adding attachments to wiki or tickets)
@ for users who are not logged in. (Property: "require-captcha")</p>
@ <hr>
entry_attribute("Public pages", 30, "public-pages",
"pubpage", "", 0);
@ <p>A comma-separated list of glob patterns for pages that are accessible
@ without needing a login and using the privileges given by the
@ "Default privileges" setting below.
@
@ <p>Example use case: Set this field to "/doc/trunk/www/*" and set
@ the "Default privileges" to include the "o" privilege
@ to give anonymous users read-only permission to the
@ latest version of the embedded documentation in the www/ folder without
@ allowing them to see the rest of the source code.
@ (Property: "public-pages")
@ </p>
@ <hr>
onoff_attribute("Allow users to register themselves",
"self-register", "selfreg", 0, 0);
@ <p>Allow users to register themselves on the /register webpage.
@ A self-registration creates a new entry in the USER table and
@ perhaps also in the SUBSCRIBER table if email notification is
@ enabled.
@ (Property: "self-register")</p>
@ <hr>
onoff_attribute("Allow users to reset their own passwords",
"self-pw-reset", "selfpw", 0, 0);
@ <p>Allow users to request that an email contains a hyperlink to a
@ password reset page be sent to their email address of record. This
@ enables forgetful users to recover their forgotten passwords without
@ administrator intervention.
@ (Property: "self-pw-reset")</p>
@ <hr>
onoff_attribute("Email verification required for self-registration",
"selfreg-verify", "sfverify", 0, 0);
@ <p>If enabled, self-registration creates a new entry in the USER table
@ with only capabilities "7". The default user capabilities are not
@ added until the email address associated with the self-registration
@ has been verified. This setting only makes sense if
@ email notifications are enabled.
@ (Property: "selfreg-verify")</p>
@ <hr>
onoff_attribute("Allow anonymous subscriptions",
"anon-subscribe", "anonsub", 1, 0);
@ <p>If disabled, email notification subscriptions are only allowed
@ for users with a login. If Nobody or Anonymous visit the /subscribe
@ page, they are redirected to /register or /login.
@ (Property: "anon-subscribe")</p>
@ <hr>
entry_attribute("Authorized subscription email addresses", 35,
"auth-sub-email", "asemail", "", 0);
@ <p>This is a comma-separated list of GLOB patterns that specify
@ email addresses that are authorized to subscriptions. If blank
@ (the usual case), then any email address can be used to self-register.
@ This setting is used to limit subscriptions to members of a particular
@ organization or group based on their email address.
@ (Property: "auth-sub-email")</p>
@ <hr>
entry_attribute("Default privileges", 10, "default-perms",
"defaultperms", "u", 0);
@ <p>Permissions given to users that... <ul><li>register themselves using
@ the self-registration procedure (if enabled), or <li>access "public"
@ pages identified by the public-pages glob pattern above, or <li>
@ are users newly created by the administrator.</ul>
@ <p>Recommended value: "u" for Reader.
@ <a href="%R/setup_ucap_list">Capability Key</a>.
@ (Property: "default-perms")
@ </p>
@ <hr>
onoff_attribute("Show javascript button to fill in CAPTCHA",
"auto-captcha", "autocaptcha", 0, 0);
@ <p>When enabled, a button appears on the login screen for user
@ "anonymous" that will automatically fill in the CAPTCHA password.
@ This is less secure than forcing the user to do it manually, but is
@ probably secure enough and it is certainly more convenient for
@ anonymous users. (Property: "auto-captcha")</p>
@ <hr>
@ <p><input type="submit" name="submit" value="Apply Changes"></p>
@ </div></form>
db_end_transaction(0);
style_finish_page();
}
/*
** WEBPAGE: setup_login_group
|
| ︙ | ︙ | |||
749 750 751 752 753 754 755 |
@ </table>
@
@ <p><form action="%R/setup_login_group" method="post"><div>
login_insert_csrf_secret();
@ To leave this login group press
@ <input type="submit" value="Leave Login Group" name="leave">
@ </form></p>
| | | 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 |
@ </table>
@
@ <p><form action="%R/setup_login_group" method="post"><div>
login_insert_csrf_secret();
@ To leave this login group press
@ <input type="submit" value="Leave Login Group" name="leave">
@ </form></p>
@ <hr><h2>Implementation Details</h2>
@ <p>The following are fields from the CONFIG table related to login-groups,
@ provided here for instructional and debugging purposes:</p>
@ <table border='1' class='sortable' data-column-types='ttt' \
@ data-init-sort='1'>
@ <thead><tr>
@ <th>Config.Name<th>Config.Value<th>Config.mtime</tr>
@ </thead><tbody>
|
| ︙ | ︙ | |||
801 802 803 804 805 806 807 |
}
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();
| | | | | | | | | | | | | | | | 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 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 |
}
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("Allow block-markup in timeline",
"timeline-block-markup", "tbm", 0, 0);
@ <p>In timeline displays, check-in comments can be displayed with or
@ without block markup such as paragraphs, tables, etc.
@ (Property: "timeline-block-markup")</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>
@ <hr>
onoff_attribute("Truncate comment at first blank line (Git-style)",
"timeline-truncate-at-blank", "ttb", 0, 0);
@ <p>In timeline displays, check-in comments are displayed only through
@ the first blank line. This is the traditional way to display comments
@ in Git repositories (Property: "timeline-truncate-at-blank")</p>
@ <hr>
onoff_attribute("Break comments at newline characters",
"timeline-hard-newlines", "thnl", 0, 0);
@ <p>In timeline displays, newline characters in check-in comments force
@ a line break on the display.
@ (Property: "timeline-hard-newlines")</p>
@ <hr>
onoff_attribute("Use Universal Coordinated Time (UTC)",
"timeline-utc", "utc", 1, 0);
@ <p>Show times as UTC (also sometimes called Greenwich Mean Time (GMT) or
@ Zulu) instead of in local time. On this server, local time is currently
tmDiff = db_double(0.0, "SELECT julianday('now')");
tmDiff = db_double(0.0,
"SELECT (julianday(%.17g,'localtime')-julianday(%.17g))*24.0",
tmDiff, tmDiff);
sqlite3_snprintf(sizeof(zTmDiff), zTmDiff, "%.1f", tmDiff);
if( strcmp(zTmDiff, "0.0")==0 ){
@ the same as UTC and so this setting will make no difference in
@ the display.</p>
}else if( tmDiff<0.0 ){
sqlite3_snprintf(sizeof(zTmDiff), zTmDiff, "%.1f", -tmDiff);
@ %s(zTmDiff) hours behind UTC.</p>
}else{
@ %s(zTmDiff) hours ahead of UTC.</p>
}
@ <p>(Property: "timeline-utc")
@ <hr>
multiple_choice_attribute("Style", "timeline-default-style",
"tdss", "0", N_TIMELINE_VIEW_STYLE, timeline_view_styles);
@ <p>The default timeline viewing style, for when the user has not
@ specified an alternative. (Property: "timeline-default-style")</p>
@ <hr>
entry_attribute("Default Number Of Rows", 6, "timeline-default-length",
"tldl", "50", 0);
@ <p>The maximum number of rows to show on a timeline in the absence
@ of a user display preference cookie setting or an explicit n= query
@ parameter. (Property: "timeline-default-length")</p>
@ <hr>
multiple_choice_attribute("Per-Item Time Format", "timeline-date-format",
"tdf", "0", count(azTimeFormats)/2, azTimeFormats);
@ <p>If the "HH:MM" or "HH:MM:SS" format is selected, then the date is shown
@ in a separate box (using CSS class "timelineDate") whenever the date
@ changes. With the "YYYY-MM-DD HH:MM" and "YYMMDD ..." formats,
@ the complete date and time is shown on every timeline entry using the
@ CSS class "timelineTime". (Property: "timeline-date-format")</p>
@ <hr>
entry_attribute("Max timeline comment length", 6,
"timeline-max-comment", "tmc", "0", 0);
@ <p>The maximum length of a comment to be displayed in a timeline.
@ "0" there is no length limit.
@ (Property: "timeline-max-comment")</p>
@ <hr>
entry_attribute("Tooltip dwell time (milliseconds)", 6,
"timeline-dwelltime", "tdt", "100", 0);
@ <br>
entry_attribute("Tooltip close time (milliseconds)", 6,
"timeline-closetime", "tct", "250", 0);
@ <p>The <strong>dwell time</strong> defines how long the mouse pointer
@ should be stationary above an object of the graph before a tooltip
@ appears.<br>
@ The <strong>close time</strong> defines how long the mouse pointer
@ can be away from an object before a tooltip is closed.</p>
@ <p>Set <strong>dwell time</strong> to "0" to disable tooltips.<br>
@ Set <strong>close time</strong> to "0" to keep tooltips visible until
@ the mouse is clicked elsewhere.<p>
@ <p>(Properties: "timeline-dwelltime", "timeline-closetime")</p>
@ <hr>
onoff_attribute("Timestamp hyperlinks to /info",
"timeline-tslink-info", "ttlti", 0, 0);
@ <p>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.
@ <p>The /timeline link is the default since it is often useful to
@ see an entry in context, and because that link is not otherwise
@ accessible on the timeline. The /info link is also accessible by
@ double-clicking the timeline node or by clicking on the hash that
@ follows "check-in:" in the supplemental information section on the
@ right of the entry.
@ <p>(Properties: "timeline-tslink-info")
@ <hr>
@ <p><input type="submit" name="submit" value="Apply Changes"></p>
@ </div></form>
db_end_transaction(0);
style_finish_page();
}
/*
** WEBPAGE: setup_settings
|
| ︙ | ︙ | |||
951 952 953 954 955 956 957 |
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
| | | | | | 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 |
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 &&
(db_get_versioned(pSet->name, NULL)!=0);
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)!=0);
@ <tr><td>
|
| ︙ | ︙ | |||
999 1000 1001 1002 1003 1004 1005 |
@</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)!=0;
@ <a href='%R/help?cmd=%s(pSet->name)'>%s(pSet->name)</a>
if( pSet->versionable ){
| | | | | | 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 |
@</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)!=0;
@ <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,
pSet->var!=0 ? pSet->var : pSet->name /*works-like:"x"*/,
(char*)pSet->def, hasVersionableValue);
@<br>
}
}
@ </td></tr></table>
@ </div></form>
db_end_transaction(0);
style_finish_page();
}
/*
** SETTING: mainmenu width=70 block-text keep-empty
**
** The mainmenu setting specifies the entries on the main menu
** for many skins. The mainmenu should be a TCL list. Each set
** of four consecutive values defines a single main menu item:
**
** * The first term is text that appears on the menu.
**
|
| ︙ | ︙ | |||
1084 1085 1086 1087 1088 1089 1090 |
}
style_set_current_feature("setup");
style_header("WWW Configuration");
db_begin_transaction();
@ <form action="%R/setup_config" method="post"><div>
login_insert_csrf_secret();
| | | | | | | | 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 |
}
style_set_current_feature("setup");
style_header("WWW Configuration");
db_begin_transaction();
@ <form action="%R/setup_config" method="post"><div>
login_insert_csrf_secret();
@ <input type="submit" name="submit" value="Apply Changes"></p>
@ <hr>
entry_attribute("Project Name", 60, "project-name", "pn", "", 0);
@ <p>A brief project name so visitors know what this site is about.
@ The project name will also be used as the RSS feed title.
@ (Property: "project-name")
@ </p>
@ <hr>
textarea_attribute("Project Description", 3, 80,
"project-description", "pd", "", 0);
@ <p>Describe your project. This will be used in page headers for search
@ engines as well as a short RSS description.
@ (Property: "project-description")</p>
@ <hr>
entry_attribute("Canonical Server URL", 40, "email-url",
"eurl", "", 0);
@ <p>This is the URL used to access this repository as a server.
@ Other repositories use this URL to clone or sync against this repository.
@ This is also the basename for hyperlinks included in email alert text.
@ Omit the trailing "/".
@ If this repo will not be set up as a persistent server and will not
@ be sending email alerts, then leave this entry blank.
@ Suggested value: "%h(g.zBaseURL)"
@ (Property: "email-url")</p>
@ <hr>
entry_attribute("Tarball and ZIP-archive Prefix", 20, "short-project-name",
"spn", "", 0);
@ <p>This is used as a prefix on the names of generated tarballs and
@ ZIP archive. For best results, keep this prefix brief and avoid special
@ characters such as "/" and "\".
@ If no tarball prefix is specified, then the full Project Name above is used.
@ (Property: "short-project-name")
@ </p>
@ <hr>
entry_attribute("Download Tag", 20, "download-tag", "dlt", "trunk", 0);
@ <p>The <a href='%R/download'>/download</a> page is designed to provide
@ a convenient place for newbies
@ to download a ZIP archive or a tarball of the project. By default,
@ the latest trunk check-in is downloaded. Change this tag to something
@ else (ex: release) to alter the behavior of the /download page.
@ (Property: "download-tag")
@ </p>
@ <hr>
entry_attribute("Index Page", 60, "index-page", "idxpg", "/home", 0);
@ <p>Enter the pathname of the page to display when the "Home" menu
@ option is selected and when no pathname is
@ specified in the URL. For example, if you visit the url:</p>
@
@ <blockquote><p>%h(g.zBaseURL)</p></blockquote>
@
|
| ︙ | ︙ | |||
1207 1208 1209 1210 1211 1212 1213 |
@ </ol>
@
@ <p>The default value is blank, meaning no added entries.
@ (Property: sitemap-extra)
@ <p>
textarea_attribute("Custom Sitemap Entries", 8, 80,
"sitemap-extra", "smextra", "", 0);
| | | | 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 |
@ </ol>
@
@ <p>The default value is blank, meaning no added entries.
@ (Property: sitemap-extra)
@ <p>
textarea_attribute("Custom Sitemap Entries", 8, 80,
"sitemap-extra", "smextra", "", 0);
@ <hr>
@ <p><input type="submit" name="submit" value="Apply Changes"></p>
@ </div></form>
db_end_transaction(0);
style_finish_page();
}
/*
** WEBPAGE: setup_wiki
|
| ︙ | ︙ | |||
1231 1232 1233 1234 1235 1236 1237 |
}
style_set_current_feature("setup");
style_header("Wiki Configuration");
db_begin_transaction();
@ <form action="%R/setup_wiki" method="post"><div>
login_insert_csrf_secret();
| | | | | | | | | | | 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 |
}
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, or Checkins",
"wiki-about", "wiki-about", 1, 0);
@ <p>
@ Associate wiki pages with branches, tags, or checkins, based on
@ the wiki page name. Wiki pages that begin with "branch/", "checkin/"
@ or "tag/" and which continue with the name of an existing branch, check-in
@ or tag 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>
@ </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.
@ This setting is a string where each character indicates a "type" of
@ document in which to allow unsafe HTML:
@ <ul>
@ <li> <b>b</b> → checked-in files, embedded documentation
@ <li> <b>f</b> → forum posts
@ <li> <b>t</b> → tickets
@ <li> <b>w</b> → wiki pages
@ </ul>
@ Include letters for each type of document for which unsafe HTML should
@ be allowed. For example, to allow unsafe HTML only for checked-in files,
@ make this setting be just "<b>b</b>". To allow unsafe HTML anywhere except
@ in forum posts, make this setting be "<b>btw</b>". The default is an
@ empty string which means that Fossil never allows Markdown documents
@ to generate unsafe HTML.
@ (Property: "safe-html")</p>
@ <hr>
@ The current interwiki tag map is as follows:
interwiki_append_map_table(cgi_output_blob());
@ <p>Visit <a href="./intermap">%R/intermap</a> for details or to
@ modify the interwiki tag map.
@ <hr>
onoff_attribute("Use HTML as wiki markup language",
"wiki-use-html", "wiki-use-html", 0, 0);
@ <p>Use HTML as the wiki markup language. Wiki links will still be parsed
@ but all other wiki formatting will be ignored.</p>
@ <p><strong>CAUTION:</strong> when
@ enabling, <i>all</i> HTML tags and attributes are accepted in the wiki.
@ No sanitization is done. This means that it is very possible for malicious
@ users to inject dangerous HTML, CSS and JavaScript code into your wiki.</p>
@ <p>This should <strong>only</strong> be enabled when wiki editing is limited
@ to trusted users. It should <strong>not</strong> be used on a publicly
@ editable wiki.</p>
@ (Property: "wiki-use-html")
@ <hr>
@ <p><input type="submit" name="submit" value="Apply Changes"></p>
@ </div></form>
db_end_transaction(0);
style_finish_page();
}
/*
** WEBPAGE: setup_chat
|
| ︙ | ︙ | |||
1315 1316 1317 1318 1319 1320 1321 |
}
style_set_current_feature("setup");
style_header("Chat Configuration");
db_begin_transaction();
@ <form action="%R/setup_chat" method="post"><div>
login_insert_csrf_secret();
| | | | | | | | | | 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 |
}
style_set_current_feature("setup");
style_header("Chat Configuration");
db_begin_transaction();
@ <form action="%R/setup_chat" method="post"><div>
login_insert_csrf_secret();
@ <input type="submit" name="submit" value="Apply Changes"></p>
@ <hr>
entry_attribute("Initial Chat History Size", 10,
"chat-initial-history", "chatih", "50", 0);
@ <p>When /chat first starts up, it preloads up to this many historical
@ messages.
@ (Property: "chat-initial-history")</p>
@ <hr>
entry_attribute("Minimum Number Of Historical Messages To Retain", 10,
"chat-keep-count", "chatkc", "50", 0);
@ <p>The chat subsystem purges older messages. But it will always retain
@ the N most recent messages where N is the value of this setting.
@ (Property: "chat-keep-count")</p>
@ <hr>
entry_attribute("Maximum Message Age In Days", 10,
"chat-keep-days", "chatkd", "7", 0);
@ <p>Chat message are removed after N days, where N is the value of
@ this setting. N may be fractional. So, for example, to only keep
@ an historical record of chat messages for 12 hours, set this value
@ to 0.5.
@ (Property: "chat-keep-days")</p>
@ <hr>
entry_attribute("Chat Polling Timeout", 10,
"chat-poll-timeout", "chatpt", "420", 0);
@ <p>New chat content is downloaded using the "long poll" technique.
@ HTTP requests are made to /chat-poll which blocks waiting on new
@ content to arrive. But the /chat-poll cannot block forever. It
@ eventual must give up and return an empty message set. This setting
@ determines how long /chat-poll will wait before giving up. The
@ default setting of approximately 7 minutes works well on many systems.
@ Shorter delays might be required on installations that use proxies
@ or web-servers with short timeouts. For best efficiency, this value
@ should be larger rather than smaller.
@ (Property: "chat-poll-timeout")</p>
@ <hr>
entry_attribute("Chat Timeline Robot Username", 15,
"chat-timeline-user", "chatrobot", "", 0);
@ <p>If this setting is not an empty string, then any changes that appear
@ on the timeline are announced in the chatroom under the username
@ supplied. The username does not need to actually exist in the USER table.
@ Suggested username: "chat-robot".
@ (Property: "chat-timeline-user")</p>
@ <hr>
multiple_choice_attribute("Alert sound",
"chat-alert-sound", "snd", azAlerts[0],
count(azAlerts)/2, azAlerts);
@ <p>The sound used in the client-side chat to indicate that a new
@ chat message has arrived.
@ (Property: "chat-alert-sound")</p>
@ <hr/>
@ <p><input type="submit" name="submit" value="Apply Changes"></p>
@ </div></form>
db_end_transaction(0);
@ <script nonce="%h(style_nonce())">
@ (function(){
@ var w = document.getElementById('idsnd');
@ w.onchange = function(){
@ var audio = new Audio('%s(g.zBaseURL)/builtin/' + w.value);
|
| ︙ | ︙ | |||
1399 1400 1401 1402 1403 1404 1405 |
}
style_set_current_feature("setup");
style_header("Moderator For Wiki And Tickets");
db_begin_transaction();
@ <form action="%R/setup_modreq" method="post"><div>
login_insert_csrf_secret();
| | | | | | | | | | | | | | | | | 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 |
}
style_set_current_feature("setup");
style_header("Moderator For Wiki And Tickets");
db_begin_transaction();
@ <form action="%R/setup_modreq" method="post"><div>
login_insert_csrf_secret();
@ <hr>
onoff_attribute("Moderate ticket changes",
"modreq-tkt", "modreq-tkt", 0, 0);
@ <p>When enabled, any change to tickets is subject to the approval
@ by a ticket moderator - a user with the "q" or Mod-Tkt privilege.
@ Ticket changes enter the system and are shown locally, but are not
@ synced until they are approved. The moderator has the option to
@ delete the change rather than approve it. Ticket changes made by
@ a user who has the Mod-Tkt privilege are never subject to
@ moderation. (Property: "modreq-tkt")
@
@ <hr>
onoff_attribute("Moderate wiki changes",
"modreq-wiki", "modreq-wiki", 0, 0);
@ <p>When enabled, any change to wiki is subject to the approval
@ by a wiki moderator - a user with the "l" or Mod-Wiki privilege.
@ Wiki changes enter the system and are shown locally, but are not
@ synced until they are approved. The moderator has the option to
@ delete the change rather than approve it. Wiki changes made by
@ a user who has the Mod-Wiki privilege are never subject to
@ moderation. (Property: "modreq-wiki")
@ </p>
@ <hr>
@ <p><input type="submit" name="submit" value="Apply Changes"></p>
@ </div></form>
db_end_transaction(0);
style_finish_page();
}
/*
** WEBPAGE: setup_adunit
**
** Administrative page for configuring and controlling ad units
** and how they are displayed.
*/
void setup_adunit(void){
login_check_credentials();
if( !g.perm.Admin ){
login_needed(0);
return;
}
db_begin_transaction();
if( P("clear")!=0 && cgi_csrf_safe(2) ){
db_unprotect(PROTECT_CONFIG);
db_multi_exec("DELETE FROM config WHERE name GLOB 'adunit*'");
db_protect_pop();
cgi_replace_parameter("adunit","");
cgi_replace_parameter("adright","");
setup_incr_cfgcnt();
}
style_set_current_feature("setup");
style_header("Edit Ad Unit");
@ <form action="%R/setup_adunit" method="post"><div>
login_insert_csrf_secret();
@ <b>Banner Ad-Unit:</b><br>
textarea_attribute("", 6, 80, "adunit", "adunit", "", 0);
@ <br>
@ <b>Right-Column Ad-Unit:</b><br>
textarea_attribute("", 6, 80, "adunit-right", "adright", "", 0);
@ <br>
onoff_attribute("Omit ads to administrator",
"adunit-omit-if-admin", "oia", 0, 0);
@ <br>
onoff_attribute("Omit ads to logged-in users",
"adunit-omit-if-user", "oiu", 0, 0);
@ <br>
onoff_attribute("Temporarily disable all ads",
"adunit-disable", "oall", 0, 0);
@ <br>
@ <input type="submit" name="submit" value="Apply Changes">
@ <input type="submit" name="clear" value="Delete Ad-Unit">
@ </div></form>
@ <hr>
@ <b>Ad-Unit Notes:</b><ul>
@ <li>Leave both Ad-Units blank to disable all advertising.
@ <li>The "Banner Ad-Unit" is used for wide pages.
@ <li>The "Right-Column Ad-Unit" is used on pages with tall, narrow content.
@ <li>If the "Right-Column Ad-Unit" is blank, the "Banner Ad-Unit" is
@ used on all pages.
@ <li>Properties: "adunit", "adunit-right", "adunit-omit-if-admin", and
|
| ︙ | ︙ | |||
1545 1546 1547 1548 1549 1550 1551 |
}
login_check_credentials();
if( !g.perm.Admin ){
login_needed(0);
return;
}
db_begin_transaction();
| | | 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 |
}
login_check_credentials();
if( !g.perm.Admin ){
login_needed(0);
return;
}
db_begin_transaction();
if( !cgi_csrf_safe(2) ){
/* Allow no state changes if not safe from CSRF */
}else if( P("setlogo")!=0 && zLogoMime && zLogoMime[0] && szLogoImg>0 ){
Blob img;
Stmt ins;
blob_init(&img, aLogoImg, szLogoImg);
db_unprotect(PROTECT_CONFIG);
db_prepare(&ins,
|
| ︙ | ︙ | |||
1638 1639 1640 1641 1642 1643 1644 |
db_end_transaction(0);
cgi_redirect("setup_logo");
}
style_set_current_feature("setup");
style_header("Edit Project Logo And Background");
@ <p>The current project logo has a MIME-Type of <b>%h(zLogoMime)</b>
@ and looks like this:</p>
| | | | | | | | | | | | | | | | | | 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 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 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 |
db_end_transaction(0);
cgi_redirect("setup_logo");
}
style_set_current_feature("setup");
style_header("Edit Project Logo And Background");
@ <p>The current project logo has a MIME-Type of <b>%h(zLogoMime)</b>
@ and looks like this:</p>
@ <blockquote><p>
@ <img src="%R/logo/%z(zLogoMtime)" alt="logo" border="1">
@ </p></blockquote>
@
@ <form action="%R/setup_logo" method="post"
@ enctype="multipart/form-data"><div>
@ <p>The logo is accessible to all users at this URL:
@ <a href="%s(g.zBaseURL)/logo">%s(g.zBaseURL)/logo</a>.
@ The logo may or may not appear on each
@ page depending on the <a href="setup_skinedit?w=0">CSS</a> and
@ <a href="setup_skinedit?w=2">header setup</a>.
@ To change the logo image, use the following form:</p>
login_insert_csrf_secret();
@ Logo Image file:
@ <input type="file" name="logoim" size="60" accept="image/*">
@ <p align="center">
@ <input type="submit" name="setlogo" value="Change Logo">
@ <input type="submit" name="clrlogo" value="Revert To Default"></p>
@ <p>(Properties: "logo-image" and "logo-mimetype")
@ </div></form>
@ <hr>
@
@ <p>The current background image has a MIME-Type of <b>%h(zBgMime)</b>
@ and looks like this:</p>
@ <blockquote><p><img src="%R/background/%z(zBgMtime)" \
@ alt="background" border=1>
@ </p></blockquote>
@
@ <form action="%R/setup_logo" method="post"
@ enctype="multipart/form-data"><div>
@ <p>The background image is accessible to all users at this URL:
@ <a href="%s(g.zBaseURL)/background">%s(g.zBaseURL)/background</a>.
@ The background image may or may not appear on each
@ page depending on the <a href="setup_skinedit?w=0">CSS</a> and
@ <a href="setup_skinedit?w=2">header setup</a>.
@ To change the background image, use the following form:</p>
login_insert_csrf_secret();
@ Background image file:
@ <input type="file" name="bgim" size="60" accept="image/*">
@ <p align="center">
@ <input type="submit" name="setbg" value="Change Background">
@ <input type="submit" name="clrbg" value="Revert To Default"></p>
@ </div></form>
@ <p>(Properties: "background-image" and "background-mimetype")
@ <hr>
@
@ <p>The current icon image has a MIME-Type of <b>%h(zIconMime)</b>
@ and looks like this:</p>
@ <blockquote><p><img src="%R/favicon.ico/%z(zIconMtime)" \
@ alt="icon" border=1>
@ </p></blockquote>
@
@ <form action="%R/setup_logo" method="post"
@ enctype="multipart/form-data"><div>
@ <p>The icon image is accessible to all users at this URL:
@ <a href="%s(g.zBaseURL)/favicon.ico">%s(g.zBaseURL)/favicon.ico</a>.
@ The icon image may or may not appear on each
@ page depending on the web browser in use and the MIME-Types that it
@ supports for icon images.
@ To change the icon image, use the following form:</p>
login_insert_csrf_secret();
@ Icon image file:
@ <input type="file" name="iconim" size="60" accept="image/*">
@ <p align="center">
@ <input type="submit" name="seticon" value="Change Icon">
@ <input type="submit" name="clricon" value="Revert To Default"></p>
@ </div></form>
@ <p>(Properties: "icon-image" and "icon-mimetype")
@ <hr>
@
@ <p><span class="note">Note:</span> Your browser has probably cached these
@ images, so you may need to press the Reload button before changes will
@ take effect. </p>
style_finish_page();
db_end_transaction(0);
}
|
| ︙ | ︙ | |||
1754 1755 1756 1757 1758 1759 1760 |
int go = P("go")!=0;
login_check_credentials();
if( !g.perm.Setup ){
login_needed(0);
return;
}
add_content_sql_commands(g.db);
| | | 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 |
int go = P("go")!=0;
login_check_credentials();
if( !g.perm.Setup ){
login_needed(0);
return;
}
add_content_sql_commands(g.db);
zQ = cgi_csrf_safe(2) ? P("q") : 0;
style_set_current_feature("setup");
style_header("Raw SQL Commands");
@ <p><b>Caution:</b> There are no restrictions on the SQL that can be
@ run by this page. You can do serious and irrepairable damage to the
@ repository. Proceed with extreme caution.</p>
@
#if 0
|
| ︙ | ︙ | |||
1791 1792 1793 1794 1795 1796 1797 |
"FROM config\n"
"-- ORDER BY mtime DESC; -- optional";
go = 1;
}
@
@ <form method="post" action="%R/admin_sql">
login_insert_csrf_secret();
| | | | | < | 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 |
"FROM config\n"
"-- ORDER BY mtime DESC; -- optional";
go = 1;
}
@
@ <form method="post" action="%R/admin_sql">
login_insert_csrf_secret();
@ SQL:<br>
@ <textarea name="q" rows="8" cols="80">%h(zQ)</textarea><br>
@ <input type="submit" name="go" value="Run SQL">
@ <input type="submit" name="schema" value="Show Schema">
@ <input type="submit" name="tablelist" value="List Tables">
@ <input type="submit" name="configtab" value="CONFIG Table Query">
@ </form>
if( P("schema") ){
zQ = sqlite3_mprintf(
"SELECT sql FROM repository.sqlite_schema"
" WHERE sql IS NOT NULL ORDER BY name");
go = 1;
}else if( P("tablelist") ){
zQ = sqlite3_mprintf("SELECT*FROM pragma_table_list ORDER BY schema, name");
go = 1;
}
if( go && cgi_csrf_safe(2) ){
sqlite3_stmt *pStmt;
int rc;
const char *zTail;
int nCol;
int nRow = 0;
int i;
@ <hr>
sqlite3_set_authorizer(g.db, raw_sql_query_authorizer, 0);
search_sql_setup(g.db);
rc = sqlite3_prepare_v2(g.db, zQ, -1, &pStmt, &zTail);
if( rc!=SQLITE_OK ){
@ <div class="generalError">%h(sqlite3_errmsg(g.db))</div>
sqlite3_finalize(pStmt);
}else if( pStmt==0 ){
|
| ︙ | ︙ | |||
1898 1899 1900 1901 1902 1903 1904 |
}
style_set_current_feature("setup");
style_header("Raw TH1 Commands");
@ <p><b>Caution:</b> There are no restrictions on the TH1 that can be
@ run by this page. If Tcl integration was enabled at compile-time and
@ the "tcl" setting is enabled, Tcl commands may be run as well.</p>
@
| | < | | | | < | 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 |
}
style_set_current_feature("setup");
style_header("Raw TH1 Commands");
@ <p><b>Caution:</b> There are no restrictions on the TH1 that can be
@ run by this page. If Tcl integration was enabled at compile-time and
@ the "tcl" setting is enabled, Tcl commands may be run as well.</p>
@
form_begin(0, "%R/admin_th1");
@ TH1:<br>
@ <textarea name="q" rows="5" cols="80">%h(zQ)</textarea><br>
@ <input type="submit" name="go" value="Run TH1">
@ </form>
if( go && cgi_csrf_safe(2) ){
const char *zR;
int rc;
int n;
@ <hr>
rc = Th_Eval(g.interp, 0, zQ, -1);
zR = Th_GetResult(g.interp, &n);
if( rc==TH_OK ){
@ <pre class="th1result">%h(zR)</pre>
}else{
@ <pre class="th1error">%h(zR)</pre>
}
|
| ︙ | ︙ | |||
1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 |
login_check_credentials();
if( !g.perm.Admin ){
login_needed(0);
return;
}
style_set_current_feature("setup");
style_header("Admin Log");
create_admin_log_table();
limit = atoi(PD("n","200"));
ofst = atoi(PD("x","0"));
fLogEnabled = db_get_boolean("admin-log", 0);
@ <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>
}
db_prepare(&stLog,
"SELECT datetime(time,'unixepoch'), who, page, what "
"FROM admin_log "
| > > > | | 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 |
login_check_credentials();
if( !g.perm.Admin ){
login_needed(0);
return;
}
style_set_current_feature("setup");
style_header("Admin Log");
style_submenu_element("User-Log", "access_log");
style_submenu_element("Artifact-Log", "rcvfromlist");
style_submenu_element("Error-Log", "errorlog");
create_admin_log_table();
limit = atoi(PD("n","200"));
ofst = atoi(PD("x","0"));
fLogEnabled = db_get_boolean("admin-log", 0);
@ <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>
}
db_prepare(&stLog,
"SELECT datetime(time,'unixepoch'), who, page, what "
"FROM admin_log "
"ORDER BY time DESC, rowid DESC");
style_table_sorter();
@ <table class="sortable adminLogTable" width="100%%" \
@ data-column-types='Tttx' data-init-sort='1'>
@ <thead>
@ <th>Time</th>
@ <th>User</th>
@ <th>Page</th>
|
| ︙ | ︙ | |||
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 |
@ </tbody></table>
if( counter>ofst+limit ){
@ <p><a href="admin_log?n=%d(limit)&x=%d(limit+ofst)">[Older]</a></p>
}
style_finish_page();
}
/*
** WEBPAGE: srchsetup
**
** Configure the search engine. Requires Admin privilege.
*/
void page_srchsetup(){
login_check_credentials();
if( !g.perm.Admin ){
login_needed(0);
return;
}
style_set_current_feature("setup");
style_header("Search Configuration");
@ <form action="%R/srchsetup" method="post"><div>
login_insert_csrf_secret();
@ <div style="text-align:center;font-weight:bold;">
@ Server-specific settings that affect the
@ <a href="%R/search">/search</a> webpage.
@ </div>
| > > > > > > > > > > > > > > > > | | | | | | | | | | | > > > > > > > > > | | < > > > | | | | 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 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 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 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 |
@ </tbody></table>
if( counter>ofst+limit ){
@ <p><a href="admin_log?n=%d(limit)&x=%d(limit+ofst)">[Older]</a></p>
}
style_finish_page();
}
/*
** Renders a selection list of values for the search-tokenizer
** setting, using the form field name "ftstok".
*/
static void select_fts_tokenizer(void){
const char *const aTokenizer[] = {
"off", "None",
"porter", "Porter Stemmer",
"unicode61", "Unicode without stemming",
"trigram", "Trigram",
};
multiple_choice_attribute("FTS Tokenizer", "search-tokenizer",
"ftstok", "off", 4, aTokenizer);
}
/*
** WEBPAGE: srchsetup
**
** Configure the search engine. Requires Admin privilege.
*/
void page_srchsetup(){
login_check_credentials();
if( !g.perm.Admin ){
login_needed(0);
return;
}
style_set_current_feature("setup");
style_header("Search Configuration");
@ <form action="%R/srchsetup" method="post"><div>
login_insert_csrf_secret();
@ <div style="text-align:center;font-weight:bold;">
@ Server-specific settings that affect the
@ <a href="%R/search">/search</a> webpage.
@ </div>
@ <hr>
textarea_attribute("Document Glob List", 3, 35, "doc-glob", "dg", "", 0);
@ <p>The "Document Glob List" is a comma- or newline-separated list
@ of GLOB expressions that identify all documents within the source
@ tree that are to be searched when "Document Search" is enabled.
@ Some examples:
@ <table border=0 cellpadding=2 align=center>
@ <tr><td>*.wiki,*.html,*.md,*.txt<td style="width: 4x;">
@ <td>Search all wiki, HTML, Markdown, and Text files</tr>
@ <tr><td>doc/*.md,*/README.txt,README.txt<td>
@ <td>Search all Markdown files in the doc/ subfolder and all README.txt
@ files.</tr>
@ <tr><td>*<td><td>Search all checked-in files</tr>
@ <tr><td><i>(blank)</i><td>
@ <td>Search nothing. (Disables document search).</tr>
@ </table>
@ <hr>
entry_attribute("Document Branch", 20, "doc-branch", "db", "trunk", 0);
@ <p>When searching documents, use the versions of the files found at the
@ type of the "Document Branch" branch. Recommended value: "trunk".
@ Document search is disabled if blank.
@ <hr>
onoff_attribute("Search Check-in Comments", "search-ci", "sc", 0, 0);
@ <br>
onoff_attribute("Search Documents", "search-doc", "sd", 0, 0);
@ <br>
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");
search_set_tokenizer(zTokenizer);
search_drop_index();
search_create_index();
search_fill_index();
search_update_index(search_restrict(SRCH_ALL));
}
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[30];
approxSizeName(sizeof(zSize),zSize,nFts);
@ <p>Currently using an SQLite FTS%d(search_index_type(0)) search index.
@ The index helps search run faster, especially on large repositories,
@ but takes up space. The index is currently using about %s(zSize)
@ or %.1f(100.0*(double)nFts/(double)nTotal)%% of the repository.</p>
select_fts_tokenizer();
@ <p><input type="submit" name="fts0" value="Delete The Full-Text Index">
@ <input type="submit" name="fts1" value="Rebuild The Full-Text Index">
style_submenu_element("FTS Index Debugging","%R/test-ftsdocs");
}else{
@ <p>The SQLite search index is disabled. All searching will be
@ a full-text scan. This usually works fine, but can be slow for
@ larger repositories.</p>
select_fts_tokenizer();
@ <p><input type="submit" name="fts1" value="Create A Full-Text Index">
}
@ </div></form>
style_finish_page();
}
/*
** A URL Alias originally called zOldName is now zNewName/zValue.
** Write SQL to make this change into pSql.
**
** If zNewName or zValue is an empty string, then delete the entry.
**
** If zOldName is an empty string, create a new entry.
*/
static void setup_update_url_alias(
Blob *pSql,
const char *zOldName,
const char *zNewName,
const char *zValue
){
if( !cgi_csrf_safe(2) ) return;
if( zNewName[0]==0 || zValue[0]==0 ){
if( zOldName[0] ){
blob_append_sql(pSql,
"DELETE FROM config WHERE name='walias:%q';\n",
zOldName);
}
return;
|
| ︙ | ︙ | |||
2128 2129 2130 2131 2132 2133 2134 |
login_check_credentials();
if( !g.perm.Admin ){
login_needed(0);
return;
}
style_set_current_feature("setup");
style_header("URL Alias Configuration");
| | < | 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 |
login_check_credentials();
if( !g.perm.Admin ){
login_needed(0);
return;
}
style_set_current_feature("setup");
style_header("URL Alias Configuration");
if( P("submit")!=0 && cgi_csrf_safe(2) ){
Blob token;
Blob sql;
const char *zNewName;
const char *zValue;
char zCnt[10];
blob_init(&namelist, PD("namelist",""), -1);
blob_init(&sql, 0, 0);
while( blob_token(&namelist, &token) ){
const char *zOldName = blob_str(&token);
sqlite3_snprintf(sizeof(zCnt), zCnt, "n%d", cnt);
zNewName = PD(zCnt, "");
sqlite3_snprintf(sizeof(zCnt), zCnt, "v%d", cnt);
|
| ︙ | ︙ |
Changes to src/setupuser.c.
| ︙ | ︙ | |||
340 341 342 343 344 345 346 |
if( P("can") ){
/* User pressed the cancel button */
cgi_redirect(cgi_referer("setup_ulist"));
return;
}
/* Check for requests to delete the user */
| | | 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 |
if( P("can") ){
/* User pressed the cancel button */
cgi_redirect(cgi_referer("setup_ulist"));
return;
}
/* Check for requests to delete the user */
if( P("delete") && cgi_csrf_safe(2) ){
int n;
if( P("verifydelete") ){
/* Verified delete user request */
db_unprotect(PROTECT_USER);
if( alert_tables_exist() ){
/* Also delete any subscriptions associated with this user */
db_multi_exec("DELETE FROM subscriber WHERE suname="
|
| ︙ | ︙ | |||
384 385 386 387 388 389 390 |
if( !cgi_all("login","info","pw","apply") ){
/* need all of the above properties to make a change. Since one or
** more are missing, no-op */
}else if( higherUser ){
/* An Admin (a) user cannot edit a Superuser (s) */
}else if( zDeleteVerify!=0 ){
/* Need to verify a delete request */
| | | 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 |
if( !cgi_all("login","info","pw","apply") ){
/* need all of the above properties to make a change. Since one or
** more are missing, no-op */
}else if( higherUser ){
/* An Admin (a) user cannot edit a Superuser (s) */
}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;
char zCap[70], zNm[4];
zNm[0] = 'a';
zNm[2] = 0;
|
| ︙ | ︙ | |||
438 439 440 441 442 443 444 |
@ a different user.</span>
@
@ <p><a href="setup_uedit?id=%d(uid)&referer=%T(zRef)">
@ [Bummer]</a></p>
style_finish_page();
return;
}
| | | 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 |
@ a different user.</span>
@
@ <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);
db_multi_exec(
"REPLACE INTO user(uid,login,info,pw,cap,mtime) "
"VALUES(nullif(%d,0),%Q,%Q,%Q,%Q,now())",
uid, zLogin, P("info"), zPw, zCap
);
if( zOldLogin && fossil_strcmp(zLogin, zOldLogin)!=0 ){
|
| ︙ | ︙ | |||
609 610 611 612 613 614 615 |
@ <td class="usetupEditLabel" id="suuid">User ID:</td>
if( uid ){
@ <td>%d(uid) <input aria-labelledby="suuid" type="hidden" \
@ name="id" value="%d(uid)"/>\
@ </td>
}else{
@ <td>(new user)<input aria-labelledby="suuid" type="hidden" name="id" \
| | | | 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 |
@ <td class="usetupEditLabel" id="suuid">User ID:</td>
if( uid ){
@ <td>%d(uid) <input aria-labelledby="suuid" type="hidden" \
@ name="id" value="%d(uid)"/>\
@ </td>
}else{
@ <td>(new user)<input aria-labelledby="suuid" type="hidden" name="id" \
@ value="0"></td>
}
@ </tr>
@ <tr>
@ <td class="usetupEditLabel" id="sulgn">Login:</td>
if( login_is_special(zLogin) ){
@ <td><b>%h(zLogin)</b></td>
}else{
@ <td><input aria-labelledby="sulgn" type="text" name="login" \
@ value="%h(zLogin)">
if( alert_tables_exist() ){
int sid;
sid = db_int(0, "SELECT subscriberId FROM subscriber"
" WHERE suname=%Q", zLogin);
if( sid>0 ){
@ <a href="%R/alerts?sid=%d(sid)">\
@ (subscription info for %h(zLogin))</a>\
|
| ︙ | ︙ | |||
642 643 644 645 646 647 648 |
@ <tr>
@ <td class="usetupEditLabel">Capabilities:</td>
@ <td width="100%%">
#define B(x) inherit[x]
@ <div class="columns" style="column-width:13em;">
@ <ul style="list-style-type: none;">
if( g.perm.Setup ){
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > | | | 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 |
@ <tr>
@ <td class="usetupEditLabel">Capabilities:</td>
@ <td width="100%%">
#define B(x) inherit[x]
@ <div class="columns" style="column-width:13em;">
@ <ul style="list-style-type: none;">
if( g.perm.Setup ){
@ <li><label><input type="checkbox" name="as"%s(oa['s'])>
@ Setup%s(B('s'))</label>
}
@ <li><label><input type="checkbox" name="aa"%s(oa['a'])>
@ Admin%s(B('a'))</label>
@ <li><label><input type="checkbox" name="au"%s(oa['u'])>
@ Reader%s(B('u'))</label>
@ <li><label><input type="checkbox" name="av"%s(oa['v'])>
@ Developer%s(B('v'))</label>
#if 0 /* Not Used */
@ <li><label><input type="checkbox" name="ad"%s(oa['d'])>
@ Delete%s(B('d'))</label>
#endif
@ <li><label><input type="checkbox" name="ae"%s(oa['e'])>
@ View-PII%s(B('e'))</label>
@ <li><label><input type="checkbox" name="ap"%s(oa['p'])>
@ Password%s(B('p'))</label>
@ <li><label><input type="checkbox" name="ai"%s(oa['i'])>
@ Check-In%s(B('i'))</label>
@ <li><label><input type="checkbox" name="ao"%s(oa['o'])>
@ Check-Out%s(B('o'))</label>
@ <li><label><input type="checkbox" name="ah"%s(oa['h'])>
@ Hyperlinks%s(B('h'))</label>
@ <li><label><input type="checkbox" name="ab"%s(oa['b'])>
@ Attachments%s(B('b'))</label>
@ <li><label><input type="checkbox" name="ag"%s(oa['g'])>
@ Clone%s(B('g'))</label>
@ <li><label><input type="checkbox" name="aj"%s(oa['j'])>
@ Read Wiki%s(B('j'))</label>
@ <li><label><input type="checkbox" name="af"%s(oa['f'])>
@ New Wiki%s(B('f'))</label>
@ <li><label><input type="checkbox" name="am"%s(oa['m'])>
@ Append Wiki%s(B('m'))</label>
@ <li><label><input type="checkbox" name="ak"%s(oa['k'])>
@ Write Wiki%s(B('k'))</label>
@ <li><label><input type="checkbox" name="al"%s(oa['l'])>
@ Moderate Wiki%s(B('l'))</label>
@ <li><label><input type="checkbox" name="ar"%s(oa['r'])>
@ Read Ticket%s(B('r'))</label>
@ <li><label><input type="checkbox" name="an"%s(oa['n'])>
@ New Tickets%s(B('n'))</label>
@ <li><label><input type="checkbox" name="ac"%s(oa['c'])>
@ Append To Ticket%s(B('c'))</label>
@ <li><label><input type="checkbox" name="aw"%s(oa['w'])>
@ Write Tickets%s(B('w'))</label>
@ <li><label><input type="checkbox" name="aq"%s(oa['q'])>
@ Moderate Tickets%s(B('q'))</label>
@ <li><label><input type="checkbox" name="at"%s(oa['t'])>
@ Ticket Report%s(B('t'))</label>
@ <li><label><input type="checkbox" name="ax"%s(oa['x'])>
@ Private%s(B('x'))</label>
@ <li><label><input type="checkbox" name="ay"%s(oa['y'])>
@ Write Unversioned%s(B('y'))</label>
@ <li><label><input type="checkbox" name="az"%s(oa['z'])>
@ Download Zip%s(B('z'))</label>
@ <li><label><input type="checkbox" name="a2"%s(oa['2'])>
@ Read Forum%s(B('2'))</label>
@ <li><label><input type="checkbox" name="a3"%s(oa['3'])>
@ Write Forum%s(B('3'))</label>
@ <li><label><input type="checkbox" name="a4"%s(oa['4'])>
@ WriteTrusted Forum%s(B('4'))</label>
@ <li><label><input type="checkbox" name="a5"%s(oa['5'])>
@ Moderate Forum%s(B('5'))</label>
@ <li><label><input type="checkbox" name="a6"%s(oa['6'])>
@ Supervise Forum%s(B('6'))</label>
@ <li><label><input type="checkbox" name="a7"%s(oa['7'])>
@ Email Alerts%s(B('7'))</label>
@ <li><label><input type="checkbox" name="aA"%s(oa['A'])>
@ Send Announcements%s(B('A'))</label>
@ <li><label><input type="checkbox" name="aC"%s(oa['C'])>
@ Chatroom%s(B('C'))</label>
@ <li><label><input type="checkbox" name="aD"%s(oa['D'])>
@ Enable Debug%s(B('D'))</label>
@ </ul></div>
@ </td>
@ </tr>
@ <tr>
@ <td class="usetupEditLabel">Selected Cap:</td>
@ <td>
@ <span id="usetupEditCapability">(missing JS?)</span>
@ <a href="%R/setup_ucap_list">(key)</a>
@ </td>
@ </tr>
if( !login_is_special(zLogin) ){
@ <tr>
@ <td align="right" id="supw">Password:</td>
if( zPw[0] ){
/* Obscure the password for all users */
@ <td><input aria-labelledby="supw" type="password" autocomplete="off" \
@ name="pw" value="**********">
@ (Leave unchanged to retain password)</td>
}else{
/* Show an empty password as an empty input field */
char *zRPW = fossil_random_password(12);
@ <td><input aria-labelledby="supw" type="password" name="pw" \
@ autocomplete="off" value=""> Password suggestion: %z(zRPW)</td>
}
@ </tr>
}
zGroup = login_group_name();
if( zGroup ){
@ <tr>
@ <td valign="top" align="right">Scope:</td>
@ <td valign="top">
@ <input type="radio" name="all" checked value="0">
@ Apply changes to this repository only.<br>
@ <input type="radio" name="all" value="1">
@ Apply changes to all repositories in the "<b>%h(zGroup)</b>"
@ login group.</td></tr>
}
if( !higherUser ){
if( zDeleteVerify ){
@ <tr>
|
| ︙ | ︙ |
Changes to src/sha1.c.
| ︙ | ︙ | |||
390 391 392 393 394 395 396 397 398 399 400 401 402 403 |
blob_zero(pCksum);
}
blob_resize(pCksum, 40);
SHA1Final(zResult, &ctx);
DigestToBase16(zResult, blob_buffer(pCksum));
return 0;
}
/*
** Compute the SHA1 checksum of a zero-terminated string. The
** result is held in memory obtained from mprintf().
*/
char *sha1sum(const char *zIn){
SHA1Context ctx;
| > > > > > > > > > > > > > | 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 |
blob_zero(pCksum);
}
blob_resize(pCksum, 40);
SHA1Final(zResult, &ctx);
DigestToBase16(zResult, blob_buffer(pCksum));
return 0;
}
/*
** Compute a binary SHA1 checksum of a zero-terminated string. The
** result is stored in zOut, which is a buffer that must be at least
** 20 bytes in size.
*/
void sha1sum_binary(const char *zIn, unsigned char *zOut){
SHA1Context ctx;
SHA1Init(&ctx);
SHA1Update(&ctx, (unsigned const char*)zIn, strlen(zIn));
SHA1Final(zOut, &ctx);
}
/*
** Compute the SHA1 checksum of a zero-terminated string. The
** result is held in memory obtained from mprintf().
*/
char *sha1sum(const char *zIn){
SHA1Context ctx;
|
| ︙ | ︙ | |||
499 500 501 502 503 504 505 | /* ** COMMAND: sha1sum* ** ** Usage: %fossil sha1sum FILE... ** ** Compute an SHA1 checksum of all files named on the command-line. ** If a file is named "-" then take its content from standard input. | < > | 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 | /* ** COMMAND: sha1sum* ** ** Usage: %fossil sha1sum FILE... ** ** Compute an SHA1 checksum of all files named on the command-line. ** If a file is named "-" then take its content from standard input. ** ** Options: ** -h|--dereference If FILE is a symbolic link, compute the hash ** on the object that the link points to. Normally, ** the hash is over the name of the object that ** the link points to. ** ** See also: [[md5sum]], [[sha3sum]] */ |
| ︙ | ︙ |
Changes to src/sha3.c.
| ︙ | ︙ | |||
414 415 416 417 418 419 420 |
static void SHA3Update(
SHA3Context *p,
const unsigned char *aData,
unsigned int nData
){
unsigned int i = 0;
#if SHA3_BYTEORDER==1234
| | | 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 |
static void SHA3Update(
SHA3Context *p,
const unsigned char *aData,
unsigned int nData
){
unsigned int i = 0;
#if SHA3_BYTEORDER==1234
if( (p->nLoaded % 8)==0 && (((intptr_t)aData)&7)==0 ){
for(; i+7<nData; i+=8){
p->u.s[p->nLoaded/8] ^= *(u64*)&aData[i];
p->nLoaded += 8;
if( p->nLoaded>=p->nRate ){
KeccakF1600Step(p);
p->nLoaded = 0;
}
|
| ︙ | ︙ | |||
626 627 628 629 630 631 632 | ** Compute an SHA3 checksum of all files named on the command-line. ** If a file is named "-" then take its content from standard input. ** ** To be clear: The official NIST FIPS-202 implementation of SHA3 ** with the added 01 padding is used, not the original Keccak submission. ** ** Options: | < | 626 627 628 629 630 631 632 633 634 635 636 637 638 639 | ** Compute an SHA3 checksum of all files named on the command-line. ** If a file is named "-" then take its content from standard input. ** ** To be clear: The official NIST FIPS-202 implementation of SHA3 ** with the added 01 padding is used, not the original Keccak submission. ** ** Options: ** --224 Compute a SHA3-224 hash ** --256 Compute a SHA3-256 hash (the default) ** --384 Compute a SHA3-384 hash ** --512 Compute a SHA3-512 hash ** --size N An N-bit hash. N must be a multiple of 32 between ** 128 and 512. ** -h|--dereference If FILE is a symbolic link, compute the hash on |
| ︙ | ︙ |
Changes to src/shun.c.
| ︙ | ︙ | |||
45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
void shun_page(void){
Stmt q;
int cnt = 0;
const char *zUuid = P("uuid");
const char *zShun = P("shun");
const char *zAccept = P("accept");
const char *zRcvid = P("rcvid");
int nRcvid = 0;
int numRows = 3;
char *zCanonical = 0;
login_check_credentials();
if( !g.perm.Admin ){
login_needed(0);
| > | 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
void shun_page(void){
Stmt q;
int cnt = 0;
const char *zUuid = P("uuid");
const char *zShun = P("shun");
const char *zAccept = P("accept");
const char *zRcvid = P("rcvid");
int reviewList = P("review")!=0;
int nRcvid = 0;
int numRows = 3;
char *zCanonical = 0;
login_check_credentials();
if( !g.perm.Admin ){
login_needed(0);
|
| ︙ | ︙ | |||
83 84 85 86 87 88 89 |
}
i++;
}
zCanonical[j+1] = zCanonical[j] = 0;
p = zCanonical;
while( *p ){
int nUuid = strlen(p);
| | | < | | | | | < | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 |
}
i++;
}
zCanonical[j+1] = zCanonical[j] = 0;
p = zCanonical;
while( *p ){
int nUuid = strlen(p);
if( !(reviewList || hname_validate(p, nUuid)) ){
@ <p class="generalError">Error: Bad artifact IDs.</p>
fossil_free(zCanonical);
zCanonical = 0;
break;
}else{
canonical16(p, nUuid);
p += nUuid+1;
}
}
zUuid = zCanonical;
}
style_header("Shunned Artifacts");
if( zUuid && P("sub") && cgi_csrf_safe(2) ){
const char *p = zUuid;
int allExist = 1;
while( *p ){
db_multi_exec("DELETE FROM shun WHERE uuid=%Q", p);
if( !db_exists("SELECT 1 FROM blob WHERE uuid=%Q", p) ){
allExist = 0;
}
admin_log("Unshunned %Q", p);
p += strlen(p)+1;
}
if( allExist ){
@ <p class="noMoreShun">Artifact(s)<br>
for( p = zUuid ; *p ; p += strlen(p)+1 ){
@ <a href="%R/artifact/%s(p)">%s(p)</a><br>
}
@ are no longer being shunned.</p>
}else{
@ <p class="noMoreShun">Artifact(s)<br>
for( p = zUuid ; *p ; p += strlen(p)+1 ){
@ %s(p)<br>
}
@ will no longer be shunned. But they may not exist in the repository.
@ It may be necessary to rebuild the repository using the
@ <b>fossil rebuild</b> command-line before the artifact content
@ can pulled in from other repositories.</p>
}
}
if( zUuid && P("add") && cgi_csrf_safe(2) ){
const char *p = zUuid;
int rid, tagid;
while( *p ){
db_multi_exec(
"INSERT OR IGNORE INTO shun(uuid,mtime)"
" VALUES(%Q, now())", p);
db_multi_exec("DELETE FROM attachment WHERE src=%Q", p);
rid = db_int(0, "SELECT rid FROM blob WHERE uuid=%Q", p);
if( rid ){
db_multi_exec("DELETE FROM event WHERE objid=%d", rid);
}
tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname='tkt-%q'", p);
if( tagid ){
db_multi_exec("DELETE FROM ticket WHERE tkt_uuid=%Q", p);
db_multi_exec("DELETE FROM tag WHERE tagid=%d", tagid);
db_multi_exec("DELETE FROM tagxref WHERE tagid=%d", tagid);
}
admin_log("Shunned %Q", p);
p += strlen(p)+1;
}
@ <p class="shunned">Artifact(s)<br>
for( p = zUuid ; *p ; p += strlen(p)+1 ){
@ <a href="%R/artifact/%s(p)">%s(p)</a><br>
}
@ have been shunned. They will no longer be pushed.
@ They will be removed from the repository the next time the repository
@ is rebuilt using the <b>fossil rebuild</b> command-line</p>
}
if( zUuid && reviewList ){
const char *p;
int nTotal = 0;
int nOk = 0;
@ <table class="shun-review"><tbody><tr><td>
for( p = zUuid ; *p ; p += strlen(p)+1 ){
int rid = symbolic_name_to_rid(p, 0);
nTotal++;
if( rid < 0 ){
@ Ambiguous<br>
}else if( rid == 0 ){
if( !hname_validate(p, strlen(p)) ){
@ Bad artifact<br>
}else if(db_int(0, "SELECT 1 FROM shun WHERE uuid=%Q", p)){
@ Already shunned<br>
}else{
@ Unknown<br>
}
}else{
char *zCmpUuid = db_text(0,
"SELECT uuid"
" FROM blob, rcvfrom"
" WHERE rid=%d"
" AND rcvfrom.rcvid=blob.rcvid",
rid);
if( fossil_strcmp(p, zCmpUuid)==0 ){
nOk++;
@ OK</br>
}else{
@ Abbreviated<br>
}
}
}
@ </td><td>
for( p = zUuid ; *p ; p += strlen(p)+1 ){
int rid = symbolic_name_to_rid(p, 0);
if( rid > 0 ){
@ <a href="%R/artifact/%s(p)">%s(p)</a><br>
}else{
@ %s(p)<br>
}
}
@ </td></tr></tbody></table>
@ <p class="shunned">
if( nOk < nTotal){
@ <b>Warning:</b> Not all artifacts
}else if( nTotal==1 ){
@ The artifact is present and
}else{
@ All %i(nOk) artifacts are present and
}
@ can be shunned with its hash above.</p>
}
if( zRcvid ){
nRcvid = atoi(zRcvid);
numRows = db_int(0, "SELECT min(count(), 10) FROM blob WHERE rcvid=%d",
nRcvid);
}
@ <p>A shunned artifact will not be pushed nor accepted in a pull and the
@ artifact content will be purged from the repository the next time the
|
| ︙ | ︙ | |||
196 197 198 199 200 201 202 |
}else if( nRcvid ){
db_prepare(&q, "SELECT uuid FROM blob WHERE rcvid=%d", nRcvid);
while( db_step(&q)==SQLITE_ROW ){
@ %s(db_column_text(&q, 0))
}
db_finalize(&q);
}
| > > > > | > | > | 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 |
}else if( nRcvid ){
db_prepare(&q, "SELECT uuid FROM blob WHERE rcvid=%d", nRcvid);
while( db_step(&q)==SQLITE_ROW ){
@ %s(db_column_text(&q, 0))
}
db_finalize(&q);
}
}else if( zUuid && reviewList ){
const char *p;
for( p = zUuid ; *p ; p += strlen(p)+1 ){
@ %s(p)
}
}
@ </textarea>
@ <input type="submit" name="add" value="Shun">
@ <input type="submit" name="review" value="Review">
@ </div></form>
@ </blockquote>
@
@ <a name="delshun"></a>
@ <p>Enter the UUIDs of previously shunned artifacts to cause them to be
@ accepted again in the repository. The artifacts content is not
@ restored because the content is unknown. The only change is that
|
| ︙ | ︙ | |||
225 226 227 228 229 230 231 |
while( db_step(&q)==SQLITE_ROW ){
@ %s(db_column_text(&q, 0))
}
db_finalize(&q);
}
}
@ </textarea>
| | | | | | | 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 |
while( db_step(&q)==SQLITE_ROW ){
@ %s(db_column_text(&q, 0))
}
db_finalize(&q);
}
}
@ </textarea>
@ <input type="submit" name="sub" value="Accept">
@ </div></form>
@ </blockquote>
@
@ <p>Press the Rebuild button below to rebuild the repository. The
@ content of newly shunned artifacts is not purged until the repository
@ is rebuilt. On larger repositories, the rebuild may take minute or
@ two, so be patient after pressing the button.</p>
@
@ <blockquote>
@ <form method="post" action="%R/%s(g.zPath)"><div>
login_insert_csrf_secret();
@ <input type="submit" name="rebuild" value="Rebuild">
@ </div></form>
@ </blockquote>
@
@ <hr><p>Shunned Artifacts:</p>
@ <blockquote><p>
db_prepare(&q,
"SELECT uuid, EXISTS(SELECT 1 FROM blob WHERE blob.uuid=shun.uuid)"
" FROM shun ORDER BY uuid");
while( db_step(&q)==SQLITE_ROW ){
const char *zUuid = db_column_text(&q, 0);
int stillExists = db_column_int(&q, 1);
cnt++;
if( stillExists ){
@ <b><a href="%R/artifact/%s(zUuid)">%s(zUuid)</a></b><br>
}else{
@ <b>%s(zUuid)</b><br>
}
}
if( cnt==0 ){
@ <i>no artifacts are shunned on this server</i>
}
db_finalize(&q);
@ </p></blockquote>
|
| ︙ | ︙ | |||
314 315 316 317 318 319 320 321 322 323 324 325 326 327 |
login_check_credentials();
if( !g.perm.Admin ){
login_needed(0);
return;
}
style_header("Artifact Receipts");
if( showAll ){
ofst = 0;
}else{
style_submenu_element("All", "rcvfromlist?all=1");
}
if( ofst>0 ){
style_submenu_element("Newer", "rcvfromlist?ofst=%d",
| > > > | 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 |
login_check_credentials();
if( !g.perm.Admin ){
login_needed(0);
return;
}
style_header("Artifact Receipts");
style_submenu_element("Admin-Log", "admin_log");
style_submenu_element("User-Log", "access_log");
style_submenu_element("Error-Log", "errorlog");
if( showAll ){
ofst = 0;
}else{
style_submenu_element("All", "rcvfromlist?all=1");
}
if( ofst>0 ){
style_submenu_element("Newer", "rcvfromlist?ofst=%d",
|
| ︙ | ︙ | |||
476 477 478 479 480 481 482 |
if( zDesc==0 ) zDesc = "";
if( cnt==0 ){
@ <tr><th valign="top" align="right">Artifacts:</th>
@ <td valign="top">
}
cnt++;
@ <a href="%R/info/%s(zUuid)">%s(zUuid)</a>
| | | 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 |
if( zDesc==0 ) zDesc = "";
if( cnt==0 ){
@ <tr><th valign="top" align="right">Artifacts:</th>
@ <td valign="top">
}
cnt++;
@ <a href="%R/info/%s(zUuid)">%s(zUuid)</a>
@ %h(zDesc) (size: %d(size))<br>
}
if( cnt>0 ){
@ <p>
if( db_exists(
"SELECT 1 FROM blob WHERE rcvid=%d AND"
" NOT EXISTS (SELECT 1 FROM shun WHERE shun.uuid=blob.uuid)", rcvid)
){
|
| ︙ | ︙ | |||
526 527 528 529 530 531 532 |
int isDeleted = zHash==0;
if( cnt==0 ){
@ <tr><th valign="top" align="right">Unversioned Files:</th>
@ <td valign="top">
}
cnt++;
if( isDeleted ){
| | | | 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 |
int isDeleted = zHash==0;
if( cnt==0 ){
@ <tr><th valign="top" align="right">Unversioned Files:</th>
@ <td valign="top">
}
cnt++;
if( isDeleted ){
@ %h(zName) (deleted)<br>
}else{
@ <a href="%R/uv/%h(zName)">%h(zName)</a> (size: %d(size))<br>
}
}
if( cnt>0 ){
@ <p><form action='%R/rcvfrom'>
@ <input type="hidden" name="rcvid" value='%d(rcvid)'>
@ <input type="hidden" name="uvdelete" value="1">
if( PB("uvdelete") ){
|
| ︙ | ︙ |
Changes to src/sitemap.c.
| ︙ | ︙ | |||
325 326 327 328 329 330 331 |
@ <li>%z(href("%R/test_env"))CGI Environment Test</a></li>
}
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>
| | < | 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 |
@ <li>%z(href("%R/test_env"))CGI Environment Test</a></li>
}
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>
|
| ︙ | ︙ |
Changes to src/skins.c.
| ︙ | ︙ | |||
41 42 43 44 45 46 47 |
const char *zLabel; /* The directory under skins/ holding this skin */
char *zSQL; /* Filled in at run-time with SQL to insert this skin */
} aBuiltinSkin[] = {
{ "Default", "default", 0 },
{ "Ardoise", "ardoise", 0 },
{ "Black & White", "black_and_white", 0 },
{ "Blitz", "blitz", 0 },
| < | 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
const char *zLabel; /* The directory under skins/ holding this skin */
char *zSQL; /* Filled in at run-time with SQL to insert this skin */
} aBuiltinSkin[] = {
{ "Default", "default", 0 },
{ "Ardoise", "ardoise", 0 },
{ "Black & White", "black_and_white", 0 },
{ "Blitz", "blitz", 0 },
{ "Dark Mode", "darkmode", 0 },
{ "Eagle", "eagle", 0 },
{ "Khaki", "khaki", 0 },
{ "Original", "original", 0 },
{ "Plain Gray", "plain_gray", 0 },
{ "Xekri", "xekri", 0 },
};
|
| ︙ | ︙ | |||
530 531 532 533 534 535 536 |
zCurrent = getSkin(0);
for(i=0; i<count(aBuiltinSkin); i++){
aBuiltinSkin[i].zSQL = getSkin(aBuiltinSkin[i].zLabel);
}
style_set_current_feature("skins");
| | | | | | 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 |
zCurrent = getSkin(0);
for(i=0; i<count(aBuiltinSkin); i++){
aBuiltinSkin[i].zSQL = getSkin(aBuiltinSkin[i].zLabel);
}
style_set_current_feature("skins");
if( cgi_csrf_safe(2) ){
/* Process requests to delete a user-defined skin */
if( P("del1") && (zName = skinVarName(P("sn"), 1))!=0 ){
style_header("Confirm Custom Skin Delete");
@ <form action="%R/setup_skin_admin" method="post"><div>
@ <p>Deletion of a custom skin is a permanent action that cannot
@ be undone. Please confirm that this is what you want to do:</p>
@ <input type="hidden" name="sn" value="%h(P("sn"))">
@ <input type="submit" name="del2" value="Confirm - Delete The Skin">
@ <input type="submit" name="cancel" value="Cancel - Do Not Delete">
login_insert_csrf_secret();
@ </div></form>
style_finish_page();
db_end_transaction(1);
return;
}
if( P("del2")!=0 && (zName = skinVarName(P("sn"), 1))!=0 ){
|
| ︙ | ︙ | |||
625 626 627 628 629 630 631 |
z = aBuiltinSkin[i].zDesc;
@ <tr><td>%d(i+1).<td>%h(z)<td> <td>
if( fossil_strcmp(aBuiltinSkin[i].zSQL, zCurrent)==0 ){
@ (Currently In Use)
seenCurrent = 1;
}else{
@ <form action="%R/setup_skin_admin" method="post">
| | | > | 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 |
z = aBuiltinSkin[i].zDesc;
@ <tr><td>%d(i+1).<td>%h(z)<td> <td>
if( fossil_strcmp(aBuiltinSkin[i].zSQL, zCurrent)==0 ){
@ (Currently In Use)
seenCurrent = 1;
}else{
@ <form action="%R/setup_skin_admin" method="post">
@ <input type="hidden" name="sn" value="%h(z)">
@ <input type="submit" name="load" value="Install">
login_insert_csrf_secret();
if( pAltSkin==&aBuiltinSkin[i] ){
@ (Current override)
}
@ </form>
}
@ </tr>
}
|
| ︙ | ︙ | |||
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 |
if( once ){
once = 0;
@ <tr><td colspan=4><h2>Skins saved as "skin:*' entries \
@ in the CONFIG table:</h2></td></tr>
}
@ <tr><td>%d(i).<td>%h(zN)<td> <td>
@ <form action="%R/setup_skin_admin" method="post">
if( fossil_strcmp(zV, zCurrent)==0 ){
@ (Currently In Use)
seenCurrent = 1;
}else{
@ <input type="submit" name="load" value="Install">
@ <input type="submit" name="del1" value="Delete">
}
@ <input type="submit" name="rename" value="Rename">
@ <input type="hidden" name="sn" value="%h(zN)">
@ </form></tr>
}
db_finalize(&q);
if( !seenCurrent ){
i++;
@ <tr><td colspan=4><h2>Current skin in css/header/footer/details entries \
@ in the CONFIG table:</h2></td></tr>
@ <tr><td>%d(i).<td><i>Current</i><td> <td>
@ <form action="%R/setup_skin_admin" method="post">
@ <input type="submit" name="save" value="Backup">
@ </form>
}
db_prepare(&q,
"SELECT DISTINCT substr(name, 1, 6) FROM config"
" WHERE name GLOB 'draft[1-9]-*'"
" ORDER BY name"
);
once = 1;
while( db_step(&q)==SQLITE_ROW ){
const char *zN = db_column_text(&q, 0);
i++;
if( once ){
once = 0;
@ <tr><td colspan=4><h2>Draft skins stored as "draft[1-9]-*' entries \
@ in the CONFIG table:</h2></td></tr>
}
@ <tr><td>%d(i).<td>%h(zN)<td> <td>
@ <form action="%R/setup_skin_admin" method="post">
@ <input type="submit" name="draftdel" value="Delete">
@ <input type="hidden" name="name" value="%h(zN)">
@ </form></tr>
}
db_finalize(&q);
@ </table>
| > > > | 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 |
if( once ){
once = 0;
@ <tr><td colspan=4><h2>Skins saved as "skin:*' entries \
@ in the CONFIG table:</h2></td></tr>
}
@ <tr><td>%d(i).<td>%h(zN)<td> <td>
@ <form action="%R/setup_skin_admin" method="post">
login_insert_csrf_secret();
if( fossil_strcmp(zV, zCurrent)==0 ){
@ (Currently In Use)
seenCurrent = 1;
}else{
@ <input type="submit" name="load" value="Install">
@ <input type="submit" name="del1" value="Delete">
}
@ <input type="submit" name="rename" value="Rename">
@ <input type="hidden" name="sn" value="%h(zN)">
@ </form></tr>
}
db_finalize(&q);
if( !seenCurrent ){
i++;
@ <tr><td colspan=4><h2>Current skin in css/header/footer/details entries \
@ in the CONFIG table:</h2></td></tr>
@ <tr><td>%d(i).<td><i>Current</i><td> <td>
@ <form action="%R/setup_skin_admin" method="post">
@ <input type="submit" name="save" value="Backup">
login_insert_csrf_secret();
@ </form>
}
db_prepare(&q,
"SELECT DISTINCT substr(name, 1, 6) FROM config"
" WHERE name GLOB 'draft[1-9]-*'"
" ORDER BY name"
);
once = 1;
while( db_step(&q)==SQLITE_ROW ){
const char *zN = db_column_text(&q, 0);
i++;
if( once ){
once = 0;
@ <tr><td colspan=4><h2>Draft skins stored as "draft[1-9]-*' entries \
@ in the CONFIG table:</h2></td></tr>
}
@ <tr><td>%d(i).<td>%h(zN)<td> <td>
@ <form action="%R/setup_skin_admin" method="post">
login_insert_csrf_secret();
@ <input type="submit" name="draftdel" value="Delete">
@ <input type="hidden" name="name" value="%h(zN)">
@ </form></tr>
}
db_finalize(&q);
@ </table>
|
| ︙ | ︙ | |||
835 836 837 838 839 840 841 |
zFile = aSkinAttr[ii].zFile;
zDraft = mprintf("draft%d", iSkin);
zTitle = mprintf("%s for Draft%d", aSkinAttr[ii].zTitle, iSkin);
zBasis = PD("basis","current");
zDflt = skin_file_content(zBasis, zFile);
zOrig = db_get_mprintf(zDflt, "draft%d-%s",iSkin,zFile);
zContent = PD(zFile,zOrig);
| | | > > | | | | | | | 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 |
zFile = aSkinAttr[ii].zFile;
zDraft = mprintf("draft%d", iSkin);
zTitle = mprintf("%s for Draft%d", aSkinAttr[ii].zTitle, iSkin);
zBasis = PD("basis","current");
zDflt = skin_file_content(zBasis, zFile);
zOrig = db_get_mprintf(zDflt, "draft%d-%s",iSkin,zFile);
zContent = PD(zFile,zOrig);
if( P("revert")!=0 && cgi_csrf_safe(2) ){
zContent = zDflt;
isRevert = 1;
}
db_begin_transaction();
style_set_current_feature("skins");
style_header("%s", zTitle);
for(j=0; j<count(aSkinAttr); j++){
style_submenu_element(aSkinAttr[j].zSubmenu,
"%R/setup_skinedit?w=%d&basis=%h&sk=%d",j,zBasis,iSkin);
}
@ <form action="%R/setup_skinedit" method="post"><div>
login_insert_csrf_secret();
@ <input type='hidden' name='w' value='%d(ii)'>
@ <input type='hidden' name='sk' value='%d(iSkin)'>
@ <h2>Edit %s(zTitle):</h2>
if( P("submit") && cgi_csrf_safe(2)
&& (zOrig==0 || strcmp(zOrig,zContent)!=0)
){
db_set_mprintf(zContent, 0, "draft%d-%s",iSkin,zFile);
}
@ <textarea name="%s(zFile)" rows="10" cols="80">\
@ %h(zContent)</textarea>
@ <br>
@ <input type="submit" name="submit" value="Apply Changes">
if( isRevert ){
@ ← Press to complete reversion to "%s(zBasis)"
}else if( fossil_strcmp(zContent,zDflt)!=0 ){
@ <input type="submit" name="revert" value='Revert To "%s(zBasis)"'>
}
@ <hr>
@ Baseline: \
skin_emit_skin_selector("basis", zBasis, zDraft);
@ <input type="submit" name="diff" value="Unified Diff">
@ <input type="submit" name="sbsdiff" value="Side-by-Side Diff">
if( P("diff")!=0 || P("sbsdiff")!=0 ){
Blob from, to, out;
DiffConfig DCfg;
construct_diff_flags(1, &DCfg);
DCfg.diffFlags |= DIFF_STRIP_EOLCR;
if( P("sbsdiff")!=0 ) DCfg.diffFlags |= DIFF_SIDEBYSIDE;
blob_init(&to, zContent, -1);
|
| ︙ | ︙ | |||
1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 |
@ <option value='%d(i)' selected>draft%d(i)</option>
}else{
@ <option value='%d(i)'>draft%d(i)</option>
}
}
@ </select>
@ </p>
@
@ <a name='step2'></a>
@ <h1>Step 2: Authenticate</h1>
@
if( isSetup ){
@ <p>As an administrator, you can make any edits you like to this or
@ any other skin. You can also authorize other users to edit this
| > | 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 |
@ <option value='%d(i)' selected>draft%d(i)</option>
}else{
@ <option value='%d(i)'>draft%d(i)</option>
}
}
@ </select>
@ </p>
@ </form>
@
@ <a name='step2'></a>
@ <h1>Step 2: Authenticate</h1>
@
if( isSetup ){
@ <p>As an administrator, you can make any edits you like to this or
@ any other skin. You can also authorize other users to edit this
|
| ︙ | ︙ |
Changes to src/smtp.c.
| ︙ | ︙ | |||
421 422 423 424 425 426 427 | ** Usage: %fossil test-smtp-probe DOMAIN [ME] ** ** Interact with the SMTP server for DOMAIN by setting up a connection ** and then immediately shutting it back down. Log all interaction ** on the console. Use ME as the domain name of the sender. ** ** Options: | < | 421 422 423 424 425 426 427 428 429 430 431 432 433 434 |
** Usage: %fossil test-smtp-probe DOMAIN [ME]
**
** Interact with the SMTP server for DOMAIN by setting up a connection
** and then immediately shutting it back down. Log all interaction
** on the console. Use ME as the domain name of the sender.
**
** Options:
** --direct Use DOMAIN directly without going through MX
** --port N Talk on TCP port N
*/
void test_smtp_probe(void){
SmtpSession *p;
const char *zDomain;
const char *zSelf;
|
| ︙ | ︙ | |||
576 577 578 579 580 581 582 | }while( bMore ); if( iCode!=250 ) return 1; return 0; } /* ** The input is a base email address of the form "local@domain". | | > | < | 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 |
}while( bMore );
if( iCode!=250 ) return 1;
return 0;
}
/*
** The input is a base email address of the form "local@domain".
** Return a pointer to just the "domain" part, or 0 if the string
** contains no "@".
*/
const char *domain_of_addr(const char *z){
while( z[0] && z[0]!='@' ) z++;
if( z[0]==0 ) return 0;
return z+1;
}
/*
** COMMAND: test-smtp-send
**
** Usage: %fossil test-smtp-send EMAIL FROM TO ...
**
** Use SMTP to send the email message contained in the file named EMAIL
** to the list of users TO. FROM is the sender of the email.
**
** Options:
** --direct Go directly to the TO domain. Bypass MX lookup
** --relayhost R Use R as relay host directly for delivery.
** --port N Use TCP port N instead of 25
** --trace Show the SMTP conversation on the console
*/
void test_smtp_send(void){
SmtpSession *p;
|
| ︙ | ︙ | |||
623 624 625 626 627 628 629 |
zRelay = find_option("relayhost",0,1);
verify_all_options();
if( g.argc<5 ) usage("EMAIL FROM TO ...");
blob_read_from_file(&body, g.argv[2], ExtFILE);
zFrom = g.argv[3];
nTo = g.argc-4;
azTo = (const char**)g.argv+4;
| | | | 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 |
zRelay = find_option("relayhost",0,1);
verify_all_options();
if( g.argc<5 ) usage("EMAIL FROM TO ...");
blob_read_from_file(&body, g.argv[2], ExtFILE);
zFrom = g.argv[3];
nTo = g.argc-4;
azTo = (const char**)g.argv+4;
zFromDomain = domain_of_addr(zFrom);
if( zRelay!=0 && zRelay[0]!= 0) {
smtpFlags |= SMTP_DIRECT;
zToDomain = zRelay;
}else{
zToDomain = domain_of_addr(azTo[0]);
}
p = smtp_session_new(zFromDomain, zToDomain, smtpFlags, smtpPort);
if( p->zErr ){
fossil_fatal("%s", p->zErr);
}
fossil_print("Connection to \"%s\"\n", p->zHostname);
smtp_client_startup(p);
|
| ︙ | ︙ |
Changes to src/sqlcmd.c.
| ︙ | ︙ | |||
244 245 246 247 248 249 250 251 252 253 254 255 256 257 |
db_protect_only(PROTECT_NONE);
sqlite3_set_authorizer(db, db_top_authorizer, db);
if( local_bSqlCmdTest ){
sqlite3_create_function(db, "db_protect", 1, SQLITE_UTF8, 0,
sqlcmd_db_protect, 0, 0);
sqlite3_create_function(db, "db_protect_pop", 0, SQLITE_UTF8, 0,
sqlcmd_db_protect_pop, 0, 0);
}
return SQLITE_OK;
}
/*
** atexit() handler that cleans up global state modified by this module.
*/
| > > | 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 |
db_protect_only(PROTECT_NONE);
sqlite3_set_authorizer(db, db_top_authorizer, db);
if( local_bSqlCmdTest ){
sqlite3_create_function(db, "db_protect", 1, SQLITE_UTF8, 0,
sqlcmd_db_protect, 0, 0);
sqlite3_create_function(db, "db_protect_pop", 0, SQLITE_UTF8, 0,
sqlcmd_db_protect_pop, 0, 0);
sqlite3_create_function(db, "shared_secret", 2, SQLITE_UTF8, 0,
sha1_shared_secret_sql_function, 0, 0);
}
return SQLITE_OK;
}
/*
** atexit() handler that cleans up global state modified by this module.
*/
|
| ︙ | ︙ | |||
283 284 285 286 287 288 289 |
** is pointed to by the value placed in pzKey must be obtained from malloc.
*/
void fossil_key(const char **pzKey, int *pnKey){
char *zSavedKey = db_get_saved_encryption_key();
char *zKey;
size_t savedKeySize = db_get_saved_encryption_key_size();
| | | 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 |
** is pointed to by the value placed in pzKey must be obtained from malloc.
*/
void fossil_key(const char **pzKey, int *pnKey){
char *zSavedKey = db_get_saved_encryption_key();
char *zKey;
size_t savedKeySize = db_get_saved_encryption_key_size();
if( !db_is_valid_saved_encryption_key(zSavedKey, savedKeySize) ) return;
zKey = (char*)malloc( savedKeySize );
if( zKey ){
memcpy(zKey, zSavedKey, savedKeySize);
*pzKey = zKey;
if( fossil_getenv("FOSSIL_USE_SEE_TEXTKEY")==0 ){
*pnKey = (int)strlen(zKey);
}else{
|
| ︙ | ︙ | |||
328 329 330 331 332 333 334 | ** ** WARNING: Careless use of this command can corrupt a Fossil repository ** in ways that are unrecoverable. Be sure you know what you are doing before ** running any SQL commands that modify the repository database. Use the ** --readonly option to prevent accidental damage to the repository. ** ** Options: | < | < < < | 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 | ** ** WARNING: Careless use of this command can corrupt a Fossil repository ** in ways that are unrecoverable. Be sure you know what you are doing before ** running any SQL commands that modify the repository database. Use the ** --readonly option to prevent accidental damage to the repository. ** ** Options: ** --no-repository Skip opening the repository database ** --readonly Open the repository read-only. No changes ** are allowed. This is a recommended safety ** precaution to prevent repository damage. ** -R REPOSITORY Use REPOSITORY as the repository database ** --test Enable some testing and analysis features ** that are normally disabled. ** ** All of the standard sqlite3 command-line shell options should also ** work. ** ** The following SQL extensions are provided with this Fossil-enhanced |
| ︙ | ︙ |
Changes to src/stash.c.
| ︙ | ︙ | |||
254 255 256 257 258 259 260 |
**
** If files are named on the command-line, then only stash the named
** files.
*/
static int stash_create(void){
const char *zComment; /* Comment to add to the stash */
int stashid; /* ID of the new stash */
| | | 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 |
**
** If files are named on the command-line, then only stash the named
** files.
*/
static int stash_create(void){
const char *zComment; /* Comment to add to the stash */
int stashid; /* ID of the new stash */
int vid; /* Current check-out */
zComment = find_option("comment", "m", 1);
verify_all_options();
if( zComment==0 ){
Blob prompt; /* Prompt for stash comment */
Blob comment; /* User comment reply */
#if defined(_WIN32) || defined(__CYGWIN__)
|
| ︙ | ︙ | |||
299 300 301 302 303 304 305 |
}else{
stash_add_file_or_dir(stashid, vid, g.zLocalRoot);
}
return stashid;
}
/*
| | | 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 |
}else{
stash_add_file_or_dir(stashid, vid, g.zLocalRoot);
}
return stashid;
}
/*
** Apply a stash to the current check-out.
*/
static void stash_apply(int stashid, int nConflict){
int vid;
Stmt q;
db_prepare(&q,
"SELECT blob.rid, isRemoved, isExec, isLink, origname, newname, delta"
" FROM stashfile, blob WHERE stashid=%d AND blob.uuid=stashfile.hash"
|
| ︙ | ︙ | |||
425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 |
int rid = db_column_int(&q, 0);
int isRemoved = db_column_int(&q, 1);
int isLink = db_column_int(&q, 3);
const char *zOrig = db_column_text(&q, 4);
const char *zNew = db_column_text(&q, 5);
char *zOPath = mprintf("%s%s", g.zLocalRoot, zOrig);
Blob a, b;
if( rid==0 ){
db_ephemeral_blob(&q, 6, &a);
if( !bWebpage ) fossil_print("ADDED %s\n", zNew);
diff_print_index(zNew, pCfg, 0);
diff_file_mem(&empty, &a, zNew, pCfg);
}else if( isRemoved ){
if( !bWebpage) fossil_print("DELETE %s\n", zOrig);
diff_print_index(zNew, pCfg, 0);
if( fBaseline ){
content_get(rid, &a);
diff_file_mem(&a, &empty, zOrig, pCfg);
}
}else{
Blob delta;
| > > > | 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 |
int rid = db_column_int(&q, 0);
int isRemoved = db_column_int(&q, 1);
int isLink = db_column_int(&q, 3);
const char *zOrig = db_column_text(&q, 4);
const char *zNew = db_column_text(&q, 5);
char *zOPath = mprintf("%s%s", g.zLocalRoot, zOrig);
Blob a, b;
pCfg->diffFlags &= (~DIFF_FILE_MASK);
if( rid==0 ){
db_ephemeral_blob(&q, 6, &a);
if( !bWebpage ) fossil_print("ADDED %s\n", zNew);
pCfg->diffFlags |= DIFF_FILE_ADDED;
diff_print_index(zNew, pCfg, 0);
diff_file_mem(&empty, &a, zNew, pCfg);
}else if( isRemoved ){
if( !bWebpage) fossil_print("DELETE %s\n", zOrig);
pCfg->diffFlags |= DIFF_FILE_DELETED;
diff_print_index(zNew, pCfg, 0);
if( fBaseline ){
content_get(rid, &a);
diff_file_mem(&a, &empty, zOrig, pCfg);
}
}else{
Blob delta;
|
| ︙ | ︙ | |||
511 512 513 514 515 516 517 | ** > fossil stash snapshot ?-m|--comment COMMENT? ?FILES...? ** ** Save the current changes in the working tree as a new stash. ** Then revert the changes back to the last check-in. If FILES ** are listed, then only stash and revert the named files. The ** "save" verb can be omitted if and only if there are no other ** arguments. The "snapshot" verb works the same as "save" but | | | | | 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 | ** > fossil stash snapshot ?-m|--comment COMMENT? ?FILES...? ** ** Save the current changes in the working tree as a new stash. ** Then revert the changes back to the last check-in. If FILES ** are listed, then only stash and revert the named files. The ** "save" verb can be omitted if and only if there are no other ** arguments. The "snapshot" verb works the same as "save" but ** omits the revert, keeping the check-out unchanged. ** ** > fossil stash list|ls ?-v|--verbose? ?-W|--width NUM? ** ** List all changes sets currently stashed. Show information about ** individual files in each changeset if -v or --verbose is used. ** ** > fossil stash show|cat ?STASHID? ?DIFF-OPTIONS? ** > fossil stash gshow|gcat ?STASHID? ?DIFF-OPTIONS? ** ** Show the contents of a stash as a diff against its baseline. ** With gshow and gcat, gdiff-command is used instead of internal ** diff logic. ** ** > fossil stash pop ** > fossil stash apply ?STASHID? ** ** Apply STASHID or the most recently created stash to the current ** working check-out. The "pop" command deletes that changeset from ** the stash after applying it but the "apply" command retains the ** changeset. ** ** > fossil stash goto ?STASHID? ** ** Update to the baseline check-out for STASHID then apply the ** changes of STASHID. Keep STASHID so that it can be reused ** This command is undoable. ** ** > fossil stash drop|rm ?STASHID? ?-a|--all? ** ** Forget everything about STASHID. Forget the whole stash if the ** -a|--all flag is used. Individual drops are undoable but -a|--all |
| ︙ | ︙ | |||
567 568 569 570 571 572 573 |
stash_tables_exist_and_current();
if( g.argc<=2 ){
zCmd = "save";
}else{
zCmd = g.argv[2];
}
nCmd = strlen(zCmd);
| | | 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 |
stash_tables_exist_and_current();
if( g.argc<=2 ){
zCmd = "save";
}else{
zCmd = g.argv[2];
}
nCmd = strlen(zCmd);
if( strncmp(zCmd, "save", nCmd)==0 ){
if( unsaved_changes(0)==0 ){
fossil_fatal("nothing to stash");
}
stashid = stash_create();
undo_disable();
if( g.argc>=2 ){
int nFile = db_int(0, "SELECT count(*) FROM stashfile WHERE stashid=%d",
|
| ︙ | ︙ | |||
598 599 600 601 602 603 604 |
** we have a copy of the changes before deleting them. */
db_commit_transaction();
g.argv[1] = "revert";
revert_cmd();
fossil_print("stash %d saved\n", stashid);
return;
}else
| | | | 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 |
** we have a copy of the changes before deleting them. */
db_commit_transaction();
g.argv[1] = "revert";
revert_cmd();
fossil_print("stash %d saved\n", stashid);
return;
}else
if( strncmp(zCmd, "snapshot", nCmd)==0 ){
stash_create();
}else
if( strncmp(zCmd, "list", nCmd)==0 || strncmp(zCmd, "ls", nCmd)==0 ){
Stmt q, q2;
int n = 0, width;
int verboseFlag = find_option("verbose","v",0)!=0;
const char *zWidth = find_option("width","W",1);
if( zWidth ){
width = atoi(zWidth);
|
| ︙ | ︙ | |||
665 666 667 668 669 670 671 |
db_reset(&q2);
}
}
db_finalize(&q);
if( verboseFlag ) db_finalize(&q2);
if( n==0 ) fossil_print("empty stash\n");
}else
| | | 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 |
db_reset(&q2);
}
}
db_finalize(&q);
if( verboseFlag ) db_finalize(&q2);
if( n==0 ) fossil_print("empty stash\n");
}else
if( strncmp(zCmd, "drop", nCmd)==0 || strncmp(zCmd, "rm", nCmd)==0 ){
int allFlag = find_option("all", "a", 0)!=0;
if( allFlag ){
Blob ans;
char cReply;
prompt_user("This action is not undoable. Continue (y/N)? ", &ans);
cReply = blob_str(&ans)[0];
if( cReply=='y' || cReply=='Y' ){
|
| ︙ | ︙ | |||
691 692 693 694 695 696 697 |
}else{
undo_begin();
undo_save_stash(0);
stash_drop(stashid);
undo_finish();
}
}else
| | | 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 |
}else{
undo_begin();
undo_save_stash(0);
stash_drop(stashid);
undo_finish();
}
}else
if( strncmp(zCmd, "pop", nCmd)==0 || strncmp(zCmd, "apply", nCmd)==0 ){
char *zCom = 0, *zDate = 0, *zHash = 0;
int popped = *zCmd=='p';
if( popped ){
if( g.argc>3 ) usage("pop");
stashid = stash_get_id(0);
}else{
if( g.argc>4 ) usage("apply STASHID");
|
| ︙ | ︙ | |||
720 721 722 723 724 725 726 |
}
fossil_free(zCom);
fossil_free(zDate);
fossil_free(zHash);
undo_finish();
if( popped ) stash_drop(stashid);
}else
| | | | | | | | | | 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 |
}
fossil_free(zCom);
fossil_free(zDate);
fossil_free(zHash);
undo_finish();
if( popped ) stash_drop(stashid);
}else
if( strncmp(zCmd, "goto", nCmd)==0 ){
int nConflict;
int vid;
if( g.argc>4 ) usage("apply STASHID");
stashid = stash_get_id(g.argc==4 ? g.argv[3] : 0);
undo_begin();
vid = db_int(0, "SELECT blob.rid FROM stash,blob"
" WHERE stashid=%d AND blob.uuid=stash.hash", stashid);
nConflict = update_to(vid);
stash_apply(stashid, nConflict);
db_multi_exec("UPDATE vfile SET mtime=0 WHERE pathname IN "
"(SELECT origname FROM stashfile WHERE stashid=%d)",
stashid);
undo_finish();
}else
if( strncmp(zCmd, "diff", nCmd)==0
|| strncmp(zCmd, "gdiff", nCmd)==0
|| strncmp(zCmd, "show", nCmd)==0
|| strncmp(zCmd, "gshow", nCmd)==0
|| strncmp(zCmd, "cat", nCmd)==0
|| strncmp(zCmd, "gcat", nCmd)==0
){
int fBaseline = 0;
DiffConfig DCfg;
if( strstr(zCmd,"show")!=0 || strstr(zCmd,"cat")!=0 ){
fBaseline = 1;
}
if( find_option("tk",0,0)!=0 ){
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);
}else
if( strncmp(zCmd, "help", nCmd)==0 ){
g.argv[1] = "help";
g.argv[2] = "stash";
g.argc = 3;
help_cmd();
}else
{
usage("SUBCOMMAND ARGS...");
}
db_end_transaction(0);
}
|
Changes to src/stat.c.
| ︙ | ︙ | |||
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
if( fossil_strcmp(zDest,"db")==0
&& (zDb = db_get("email-send-db",0))!=0
){
sqlite3 *db;
sqlite3_stmt *pStmt;
int rc;
@ Queued to database "%h(zDb)"
rc = sqlite3_open(zDb, &db);
if( rc==SQLITE_OK ){
rc = sqlite3_prepare_v2(db, "SELECT count(*) FROM email",-1,&pStmt,0);
if( rc==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){
@ (%,d(sqlite3_column_int(pStmt,0)) messages,
@ %,d(file_size(zDb,ExtFILE)) bytes)
}
sqlite3_finalize(pStmt);
}
sqlite3_close(db);
}else
if( fossil_strcmp(zDest,"dir")==0
&& (zDir = db_get("email-send-dir",0))!=0
){
@ Written to files in "%h(zDir)"
@ (%,d(file_directory_size(zDir,0,1)) messages)
| > > > > > | 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 |
if( fossil_strcmp(zDest,"db")==0
&& (zDb = db_get("email-send-db",0))!=0
){
sqlite3 *db;
sqlite3_stmt *pStmt;
int rc;
@ Queued to database "%h(zDb)"
g.dbIgnoreErrors++;
rc = sqlite3_open(zDb, &db);
if( rc==SQLITE_OK ){
rc = sqlite3_prepare_v2(db, "SELECT count(*) FROM email",-1,&pStmt,0);
if( rc==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){
@ (%,d(sqlite3_column_int(pStmt,0)) messages,
@ %,d(file_size(zDb,ExtFILE)) bytes)
}
sqlite3_finalize(pStmt);
}
g.dbIgnoreErrors--;
if( rc ){
@ ← cannot access database!
}
sqlite3_close(db);
}else
if( fossil_strcmp(zDest,"dir")==0
&& (zDir = db_get("email-send-dir",0))!=0
){
@ Written to files in "%h(zDir)"
@ (%,d(file_directory_size(zDir,0,1)) messages)
|
| ︙ | ︙ | |||
112 113 114 115 116 117 118 |
@ <tr><th><a href="%R/subscribers">Subscribers:</a></th><td>
}else{
@ <tr><th>Subscribers:</th><td>
}
nSub = db_int(0, "SELECT count(*) FROM subscriber");
iCutoff = db_get_int("email-renew-cutoff",0);
nASub = db_int(0, "SELECT count(*) FROM subscriber WHERE sverified"
| | | 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 |
@ <tr><th><a href="%R/subscribers">Subscribers:</a></th><td>
}else{
@ <tr><th>Subscribers:</th><td>
}
nSub = db_int(0, "SELECT count(*) FROM subscriber");
iCutoff = db_get_int("email-renew-cutoff",0);
nASub = db_int(0, "SELECT count(*) FROM subscriber WHERE sverified"
" AND NOT sdonotcall AND octet_length(ssub)>1"
" AND lastContact>=%d;", iCutoff);
@ %,d(nASub) active, %,d(nSub) total
@ </td></tr>
rDigest = db_double(-1.0, "SELECT (julianday('now') - value)*24.0"
" FROM config WHERE name='email-last-digest'");
if( rDigest>0.0 ){
@ <tr><th>Last Digest:</th><td>Approximately \
|
| ︙ | ︙ | |||
139 140 141 142 143 144 145 146 147 148 149 150 151 152 |
*/
void stat_page(void){
i64 t, fsize;
int n, m;
int szMax, szAvg;
int brief;
const char *p;
login_check_credentials();
if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
brief = P("brief")!=0;
style_header("Repository Statistics");
style_adunit_config(ADUNIT_RIGHT_OK);
if( g.perm.Admin ){
| > > | 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 |
*/
void stat_page(void){
i64 t, fsize;
int n, m;
int szMax, szAvg;
int brief;
const char *p;
char *z;
int Y, M, D;
login_check_credentials();
if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
brief = P("brief")!=0;
style_header("Repository Statistics");
style_adunit_config(ADUNIT_RIGHT_OK);
if( g.perm.Admin ){
|
| ︙ | ︙ | |||
200 201 202 203 204 205 206 |
@ %d(a):%d(b)
@ </td></tr>
}
if( db_table_exists("repository","unversioned") ){
Stmt q;
char zStored[100];
db_prepare(&q,
| | | 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 |
@ %d(a):%d(b)
@ </td></tr>
}
if( db_table_exists("repository","unversioned") ){
Stmt q;
char zStored[100];
db_prepare(&q,
"SELECT count(*), sum(sz), sum(octet_length(content))"
" FROM unversioned"
" WHERE length(hash)>1"
);
if( db_step(&q)==SQLITE_ROW && (n = db_column_int(&q,0))>0 ){
sqlite3_int64 iStored, pct;
iStored = db_column_int64(&q,2);
pct = (iStored*100 + fsize/2)/fsize;
|
| ︙ | ︙ | |||
234 235 236 237 238 239 240 |
@ %,d(n)
@ </td></tr>
if( g.perm.Chat && db_table_exists("repository","chat") ){
sqlite3_int64 sz = 0;
char zSz[100];
n = db_int(0, "SELECT max(msgid) FROM chat");
m = db_int(0, "SELECT count(*) FROM chat WHERE mdel IS NOT TRUE");
| | | | | > | | > > > > > | 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 |
@ %,d(n)
@ </td></tr>
if( g.perm.Chat && db_table_exists("repository","chat") ){
sqlite3_int64 sz = 0;
char zSz[100];
n = db_int(0, "SELECT max(msgid) FROM chat");
m = db_int(0, "SELECT count(*) FROM chat WHERE mdel IS NOT TRUE");
sz = db_int64(0, "SELECT sum(coalesce(octet_length(xmsg),0)+"
"coalesce(octet_length(file),0)) FROM chat");
approxSizeName(sizeof(zSz), zSz, sz);
@ <tr><th>Number Of Chat Messages:</th>
@ <td>%,d(n) (%,d(m) still alive, %s(zSz) in size)</td></tr>
}
n = db_int(0, "SELECT count(*) FROM tag /*scan*/"
" WHERE +tagname GLOB 'tkt-*'");
if( n>0 ){
@ <tr><th>Number Of Tickets:</th><td>%,d(n)</td></tr>
}
if( db_table_exists("repository","forumpost") ){
n = db_int(0, "SELECT count(*) FROM forumpost/*scan*/");
if( n>0 ){
int nThread = db_int(0, "SELECT count(*) FROM forumpost"
" WHERE froot=fpid");
@ <tr><th>Number Of Forum Posts:</th>
@ <td>%,d(n) on %d(nThread) threads</td></tr>
}
}
}
@ <tr><th>Project Age:</th><td>
z = db_text(0, "SELECT timediff('now',(SELECT min(mtime) FROM event));");
sscanf(z, "+%d-%d-%d", &Y, &M, &D);
if( Y>0 ){
@ %d(Y) years, \
}
if( M>0 ){
@ %d(M) months, \
}
@ %d(D) days
@ </td></tr>
p = db_get("project-code", 0);
if( p ){
@ <tr><th>Project ID:</th>
@ <td>%h(p) %h(db_get("project-name",""))</td></tr>
}
p = db_get("parent-project-code", 0);
|
| ︙ | ︙ | |||
331 332 333 334 335 336 337 | ** ** Usage: %fossil dbstat OPTIONS ** ** Shows statistics and global information about the repository and/or ** verify the integrity of a repository. ** ** Options: | < | | | | 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 |
**
** Usage: %fossil dbstat OPTIONS
**
** Shows statistics and global information about the repository and/or
** verify the integrity of a repository.
**
** Options:
** -b|--brief Only show essential elements
** --db-check Run "PRAGMA quick_check" on the repository database
** --db-verify Run a full verification of the repository integrity.
** This involves decoding and reparsing all artifacts
** and can take significant time.
** --omit-version-info Omit the SQLite and Fossil version information
*/
void dbstat_cmd(void){
i64 t, fsize;
int n, m;
int szMax, szAvg;
int brief;
int omitVers; /* Omit Fossil and SQLite version information */
|
| ︙ | ︙ | |||
700 701 702 703 704 705 706 707 708 709 710 711 712 713 |
*/
void repo_schema_page(void){
Stmt q;
Blob sql;
const char *zArg = P("n");
login_check_credentials();
if( !g.perm.Admin ){ login_needed(0); return; }
style_set_current_feature("stat");
style_header("Repository Schema");
style_adunit_config(ADUNIT_RIGHT_OK);
style_submenu_element("Stat", "stat");
style_submenu_element("URLs", "urllist");
if( sqlite3_compileoption_used("ENABLE_DBSTAT_VTAB") ){
| > > > > > > > > > > > > > > > > | 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 |
*/
void repo_schema_page(void){
Stmt q;
Blob sql;
const char *zArg = P("n");
login_check_credentials();
if( !g.perm.Admin ){ login_needed(0); return; }
if( zArg!=0
&& db_table_exists("repository",zArg)
&& cgi_csrf_safe(1)
){
if( P("analyze")!=0 ){
db_multi_exec("ANALYZE \"%w\"", zArg);
}else if( P("analyze200")!=0 ){
db_multi_exec("PRAGMA analysis_limit=200; ANALYZE \"%w\"", zArg);
}else if( P("deanalyze")!=0 ){
db_unprotect(PROTECT_ALL);
db_multi_exec("DELETE FROM repository.sqlite_stat1"
" WHERE tbl LIKE %Q", zArg);
db_protect_pop();
}
}
style_set_current_feature("stat");
style_header("Repository Schema");
style_adunit_config(ADUNIT_RIGHT_OK);
style_submenu_element("Stat", "stat");
style_submenu_element("URLs", "urllist");
if( sqlite3_compileoption_used("ENABLE_DBSTAT_VTAB") ){
|
| ︙ | ︙ | |||
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 |
}
@ </pre>
db_finalize(&q);
}else{
style_submenu_element("Stat1","repo_stat1");
}
}
style_finish_page();
}
/*
** WEBPAGE: repo_stat1
**
** Show the sqlite_stat1 table for the repository schema
*/
void repo_stat1_page(void){
login_check_credentials();
if( !g.perm.Admin ){ login_needed(0); return; }
style_set_current_feature("stat");
style_header("Repository STAT1 Table");
style_adunit_config(ADUNIT_RIGHT_OK);
style_submenu_element("Stat", "stat");
style_submenu_element("Schema", "repo_schema");
if( db_table_exists("repository","sqlite_stat1") ){
Stmt q;
db_prepare(&q,
"SELECT tbl, idx, stat FROM repository.sqlite_stat1"
" ORDER BY tbl, idx");
| > > > > > > > > > > > > > > > > > > > > > > > | > > > > > | | > > > > | > > > > > > > > > > > > | 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 |
}
@ </pre>
db_finalize(&q);
}else{
style_submenu_element("Stat1","repo_stat1");
}
}
@ <hr><form method="POST">
@ <input type="submit" name="analyze" value="Run ANALYZE"><br />
@ <input type="submit" name="analyze200"\
@ value="Run ANALYZE with limit=200"><br />
@ <input type="submit" name="deanalyze" value="De-ANALYZE">
@ </form>
style_finish_page();
}
/*
** WEBPAGE: repo_stat1
**
** Show the sqlite_stat1 table for the repository schema
*/
void repo_stat1_page(void){
int bTabular;
login_check_credentials();
if( !g.perm.Admin ){ login_needed(0); return; }
bTabular = PB("tabular");
if( P("analyze")!=0 && cgi_csrf_safe(1) ){
db_multi_exec("ANALYZE");
}else if( P("analyze200")!=0 && cgi_csrf_safe(1) ){
db_multi_exec("PRAGMA analysis_limit=200; ANALYZE;");
}else if( P("deanalyze")!=0 && cgi_csrf_safe(1) ){
db_unprotect(PROTECT_ALL);
db_multi_exec("DELETE FROM repository.sqlite_stat1;");
db_protect_pop();
}
style_set_current_feature("stat");
style_header("Repository STAT1 Table");
style_adunit_config(ADUNIT_RIGHT_OK);
style_submenu_element("Stat", "stat");
style_submenu_element("Schema", "repo_schema");
style_submenu_checkbox("tabular", "Tabular", 0, 0);
if( db_table_exists("repository","sqlite_stat1") ){
Stmt q;
db_prepare(&q,
"SELECT tbl, idx, stat FROM repository.sqlite_stat1"
" ORDER BY tbl, idx");
if( bTabular ){
@ <table border="1" cellpadding="0" cellspacing="0">
@ <tr><th>Table<th>Index<th>Stat
}else{
@ <pre>
}
while( db_step(&q)==SQLITE_ROW ){
const char *zTab = db_column_text(&q,0);
const char *zIdx = db_column_text(&q,1);
const char *zStat = db_column_text(&q,2);
char *zUrl = href("%R/repo_schema?n=%t",zTab);
if( bTabular ){
@ <tr><td>%z(zUrl)%h(zTab)</a><td>%h(zIdx)<td>%h(zStat)
}else{
@ INSERT INTO sqlite_stat1 \
@ VALUES('%z(zUrl)%h(zTab)</a>','%h(zIdx)','%h(zStat)');
}
}
if( bTabular ){
@ </table>
}else{
@ </pre>
}
db_finalize(&q);
}
@ <p><form method="POST">
if( bTabular ){
@ <input type="hidden" name="tabular" value="1">
}
@ <input type="submit" name="analyze" value="Run ANALYZE"><br />
@ <input type="submit" name="analyze200"\
@ value="Run ANALYZE with limit=200"><br>
@ <input type="submit" name="deanalyze"\
@ value="De-ANALYZE">
@ </form>
style_finish_page();
}
/*
** WEBPAGE: repo-tabsize
**
** Show relative sizes of tables in the repository database.
*/
void repo_tabsize_page(void){
int nPageFree;
sqlite3_int64 fsize;
char zBuf[100];
login_check_credentials();
if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
cgi_check_for_malice();
style_set_current_feature("stat");
style_header("Repository Table Sizes");
style_adunit_config(ADUNIT_RIGHT_OK);
style_submenu_element("Stat", "stat");
if( g.perm.Admin ){
style_submenu_element("Schema", "repo_schema");
}
|
| ︙ | ︙ | |||
871 872 873 874 875 876 877 |
@ isDelta BOOLEAN, -- true if stored as a delta
@ szExp, -- expanded, uncompressed size
@ szCmpr -- size as stored on disk
@ );
@ INSERT INTO artstat(id,atype,isDelta,szExp,szCmpr)
@ SELECT blob.rid, NULL,
@ delta.rid IS NOT NULL,
| | | 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 |
@ isDelta BOOLEAN, -- true if stored as a delta
@ szExp, -- expanded, uncompressed size
@ szCmpr -- size as stored on disk
@ );
@ INSERT INTO artstat(id,atype,isDelta,szExp,szCmpr)
@ SELECT blob.rid, NULL,
@ delta.rid IS NOT NULL,
@ size, octet_length(content)
@ FROM blob LEFT JOIN delta ON blob.rid=delta.rid
@ WHERE content IS NOT NULL;
;
static const char zSql2[] =
@ UPDATE artstat SET atype='file'
@ WHERE +id IN (SELECT fid FROM mlink);
@ UPDATE artstat SET atype='manifest'
|
| ︙ | ︙ | |||
969 970 971 972 973 974 975 976 977 978 979 980 981 982 |
** user without check-in privileges, to prevent excessive usage by
** robots and random passers-by on the internet
*/
if( !g.perm.Write && !db_get_boolean("artifact_stats_enable",0) ){
login_needed(g.anon.Write);
return;
}
fossil_nice_default();
style_set_current_feature("stat");
style_header("Artifact Statistics");
style_submenu_element("Repository Stats", "stat");
style_submenu_element("Artifact List", "bloblist");
gather_artifact_stats(1);
| > | 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 |
** user without check-in privileges, to prevent excessive usage by
** robots and random passers-by on the internet
*/
if( !g.perm.Write && !db_get_boolean("artifact_stats_enable",0) ){
login_needed(g.anon.Write);
return;
}
cgi_check_for_malice();
fossil_nice_default();
style_set_current_feature("stat");
style_header("Artifact Statistics");
style_submenu_element("Repository Stats", "stat");
style_submenu_element("Artifact List", "bloblist");
gather_artifact_stats(1);
|
| ︙ | ︙ |
Changes to src/statrep.c.
| ︙ | ︙ | |||
79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
rc = *zRealType;
break;
case 'g':
case 'G':
zRealType = "g";
rc = *zRealType;
break;
case 't':
case 'T':
zRealType = "t";
rc = *zRealType;
break;
case 'w':
case 'W':
| > > > > > > > > > > | 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 |
rc = *zRealType;
break;
case 'g':
case 'G':
zRealType = "g";
rc = *zRealType;
break;
case 'm':
case 'M':
zRealType = "m";
rc = *zRealType;
break;
case 'n':
case 'N':
zRealType = "n";
rc = *zRealType;
break;
case 't':
case 'T':
zRealType = "t";
rc = *zRealType;
break;
case 'w':
case 'W':
|
| ︙ | ︙ | |||
101 102 103 104 105 106 107 |
if( P("from")!=0 && P("to")!=0 ){
zTimeSpan = mprintf(
" (event.mtime BETWEEN julianday(%Q) AND julianday(%Q))",
P("from"), P("to"));
}else{
zTimeSpan = " 1";
}
| | > > > > > | > | | > > > > > > > < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | > | | > | < > | > | | > > > > > > > > > | > > > > > | | 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 |
if( P("from")!=0 && P("to")!=0 ){
zTimeSpan = mprintf(
" (event.mtime BETWEEN julianday(%Q) AND julianday(%Q))",
P("from"), P("to"));
}else{
zTimeSpan = " 1";
}
if( zRealType==0 ){
statsReportTimelineYFlag = "a";
db_multi_exec("CREATE TEMP VIEW v_reports AS "
"SELECT * FROM event WHERE %s", zTimeSpan/*safe-for-%s*/);
}else if( rc!='n' && rc!='m' ){
statsReportTimelineYFlag = zRealType;
db_multi_exec("CREATE TEMP VIEW v_reports AS "
"SELECT * FROM event WHERE (type GLOB %Q) AND %s",
zRealType, zTimeSpan/*safe-for-%s*/);
}else{
const char *zNot = rc=='n' ? "NOT" : "";
statsReportTimelineYFlag = "ci";
db_multi_exec(
"CREATE TEMP VIEW v_reports AS "
"SELECT * FROM event WHERE type='ci' AND %s"
" AND objid %s IN (SELECT cid FROM plink WHERE NOT isprim)",
zTimeSpan/*safe-for-%s*/, zNot/*safe-for-%s*/
);
}
return statsReportType = rc;
}
/*
** Returns a string suitable (for a given value of suitable) for
** use in a label with the header of the /reports pages, dependent
** on the 'type' flag. See stats_report_init_view().
** The returned bytes are static.
*/
static const char *stats_report_label_for_type(){
assert( statsReportType && "Must call stats_report_init_view() first." );
switch( statsReportType ){
case 'c':
return "check-ins";
case 'm':
return "merge check-ins";
case 'n':
return "non-merge check-ins";
case 'e':
return "technotes";
case 'f':
return "forum posts";
case 'w':
return "wiki changes";
case 't':
return "ticket changes";
case 'g':
return "tag changes";
default:
return "all types";
}
}
/*
** Implements the "byyear" and "bymonth" reports for /reports.
** If includeMonth is true then it generates the "bymonth" report,
** else the "byyear" report. If zUserName is not NULL then the report is
** restricted to events created by the named user account.
*/
static void stats_report_by_month_year(
char includeMonth, /* 0 for stats-by-year. 1 for stats-by-month */
const char *zUserName /* Only report events by this user */
){
Stmt query = empty_Stmt;
int nRowNumber = 0; /* current TR number */
int nEventTotal = 0; /* Total event count */
int rowClass = 0; /* counter for alternating
row colors */
const char *zTimeLabel = includeMonth ? "Year/Month" : "Year";
char zPrevYear[5] = {0}; /* For keeping track of when
we change years while looping */
int nEventsPerYear = 0; /* Total event count for the
current year */
char showYearTotal = 0; /* Flag telling us when to show
the per-year event totals */
int nMaxEvents = 1; /* for calculating length of graph
bars. */
int iterations = 0; /* number of weeks/months we iterate
over */
char *zCurrentTF; /* The timeframe in which 'now' lives */
double rNowFraction; /* Fraction of 'now' timeframe that has
passed */
int nTFChar; /* Prefix of date() for timeframe */
nTFChar = includeMonth ? 7 : 4;
stats_report_init_view();
db_prepare(&query,
"SELECT substr(date(mtime),1,%d) AS timeframe,"
" count(*) AS eventCount"
" FROM v_reports"
" WHERE ifnull(coalesce(euser,user,'')=%Q,1)"
" GROUP BY timeframe"
" ORDER BY timeframe DESC",
nTFChar, zUserName);
@ <h1>Timeline Events (%s(stats_report_label_for_type()))
@ by year%s(includeMonth ? "/month" : "")
if( zUserName ){
@ for user %h(zUserName)
}
@ </h1>
@ <table border='0' cellpadding='2' cellspacing='0' \
zCurrentTF = db_text(0, "SELECT substr(date(),1,%d)", nTFChar);
if( !includeMonth ){
@ class='statistics-report-table-events sortable' \
@ data-column-types='tnx' data-init-sort='0'>
style_table_sorter();
rNowFraction = db_double(0.5,
"SELECT (unixepoch() - unixepoch('now','start of year'))*1.0/"
" (unixepoch('now','start of year','+1 year') - "
" unixepoch('now','start of year'));");
}else{
@ class='statistics-report-table-events'>
rNowFraction = db_double(0.5,
"SELECT (unixepoch() - unixepoch('now','start of month'))*1.0/"
" (unixepoch('now','start of month','+1 month') - "
" unixepoch('now','start of month'));");
}
@ <thead>
@ <th>%s(zTimeLabel)</th>
@ <th>Events</th>
@ <th width='90%%'><!-- relative commits graph --></th>
@ </thead><tbody>
/*
Run the query twice. The first time we calculate the maximum
number of events for a given row. Maybe someone with better SQL
Fu can re-implement this with a single query.
*/
while( SQLITE_ROW == db_step(&query) ){
int nCount = db_column_int(&query, 1);
if( strcmp(db_column_text(&query,0),zCurrentTF)==0
&& rNowFraction>0.05
){
nCount = (int)(((double)nCount)/rNowFraction);
}
if(nCount>nMaxEvents){
nMaxEvents = nCount;
}
++iterations;
}
db_reset(&query);
while( SQLITE_ROW == db_step(&query) ){
const char *zTimeframe = db_column_text(&query, 0);
const int nCount = db_column_int(&query, 1);
int nSize = (nCount>0 && nMaxEvents>0)
? (int)(100 * nCount / nMaxEvents)
: 1;
showYearTotal = 0;
if(!nSize) nSize = 1;
if(includeMonth){
/* For Month/year view, add a separator for each distinct year. */
if(!*zPrevYear ||
|
| ︙ | ︙ | |||
296 297 298 299 300 301 302 |
zTimeframe, (char)statsReportType);
if( zUserName ){
cgi_printf("&u=%t", zUserName);
}
cgi_printf("'>%s</a>", zTimeframe);
}
@ </td><td>%d(nCount)</td>
| | > > > > > > > > > > > > > > > | | > | < < < < < < < < < < < | | | 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 |
zTimeframe, (char)statsReportType);
if( zUserName ){
cgi_printf("&u=%t", zUserName);
}
cgi_printf("'>%s</a>", zTimeframe);
}
@ </td><td>%d(nCount)</td>
@ <td style='white-space: nowrap;'>
if( strcmp(zTimeframe, zCurrentTF)==0
&& 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>\
@ <span class='statistics-report-graph-extra' \
@ style='display:inline-block;min-width:%d(nXSize)%%;'> </span>\
}else{
@ <div class='statistics-report-graph-line' \
@ style='width:%d(nSize)%%;'> </div> \
}
@ </td>
@ </tr>
/*
Potential improvement: calculate the min/max event counts and
use percent-based graph bars.
*/
}
db_finalize(&query);
if(includeMonth && !showYearTotal && *zPrevYear){
/* Add final year total separator. */
rowClass = ++nRowNumber % 2;
@ <tr class='row%d(rowClass)'>
@ <td></td>
@ <td colspan='2'>Yearly total: %d(nEventsPerYear)</td>
@</tr>
}
@ </tbody></table>
if(nEventTotal){
const char *zAvgLabel = includeMonth ? "month" : "year";
int nAvg = iterations ? (nEventTotal/iterations) : 0;
@ <br><div>Total events: %d(nEventTotal)
@ <br>Average per active %s(zAvgLabel): %d(nAvg)
@ </div>
}
}
/*
** Implements the "byuser" view for /reports.
*/
|
| ︙ | ︙ | |||
357 358 359 360 361 362 363 |
"CREATE TEMP VIEW piechart(amt,label) AS"
" SELECT count(*), ifnull(euser,user) FROM v_reports"
" GROUP BY ifnull(euser,user) ORDER BY count(*) DESC;"
);
if( db_int(0, "SELECT count(*) FROM piechart")>=2 ){
@ <center><svg width=700 height=400>
piechart_render(700, 400, PIE_OTHER|PIE_PERCENT);
| | | 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 |
"CREATE TEMP VIEW piechart(amt,label) AS"
" SELECT count(*), ifnull(euser,user) FROM v_reports"
" GROUP BY ifnull(euser,user) ORDER BY count(*) DESC;"
);
if( db_int(0, "SELECT count(*) FROM piechart")>=2 ){
@ <center><svg width=700 height=400>
piechart_render(700, 400, PIE_OTHER|PIE_PERCENT);
@ </svg></centre><hr>
}
style_table_sorter();
@ <table class='statistics-report-table-events sortable' border='0' \
@ cellpadding='2' cellspacing='0' data-column-types='tkx' data-init-sort='2'>
@ <thead><tr>
@ <th>User</th>
@ <th>Events</th>
|
| ︙ | ︙ | |||
475 476 477 478 479 480 481 |
static void stats_report_day_of_week(const char *zUserName){
Stmt query = empty_Stmt;
int nRowNumber = 0; /* current TR number */
int rowClass = 0; /* counter for alternating
row colors */
int nMaxEvents = 1; /* max number of events for
all rows. */
| < < < < | 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 |
static void stats_report_day_of_week(const char *zUserName){
Stmt query = empty_Stmt;
int nRowNumber = 0; /* current TR number */
int rowClass = 0; /* counter for alternating
row colors */
int nMaxEvents = 1; /* max number of events for
all rows. */
static const char *const daysOfWeek[] = {
"Sunday", "Monday", "Tuesday", "Wednesday",
"Thursday", "Friday", "Saturday"
};
stats_report_init_view();
db_prepare(&query,
"SELECT cast(strftime('%%w', mtime) AS INTEGER) dow,"
" COUNT(*) AS eventCount"
" FROM v_reports"
" WHERE ifnull(coalesce(euser,user,'')=%Q,1)"
" GROUP BY dow ORDER BY dow", zUserName);
@ <h1>Timeline Events (%h(stats_report_label_for_type())) by Day of the Week
|
| ︙ | ︙ | |||
517 518 519 520 521 522 523 |
" WHERE ifnull(coalesce(euser,user,'')=%Q,1)"
" GROUP BY 2 ORDER BY cast(strftime('%%w', mtime) AS INT);"
, zUserName
);
if( db_int(0, "SELECT count(*) FROM piechart")>=2 ){
@ <center><svg width=700 height=400>
piechart_render(700, 400, PIE_OTHER|PIE_PERCENT);
| | | 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 |
" WHERE ifnull(coalesce(euser,user,'')=%Q,1)"
" GROUP BY 2 ORDER BY cast(strftime('%%w', mtime) AS INT);"
, zUserName
);
if( db_int(0, "SELECT count(*) FROM piechart")>=2 ){
@ <center><svg width=700 height=400>
piechart_render(700, 400, PIE_OTHER|PIE_PERCENT);
@ </svg></centre><hr>
}
style_table_sorter();
@ <table class='statistics-report-table-events sortable' border='0' \
@ cellpadding='2' cellspacing='0' data-column-types='ntnx' data-init-sort='1'>
@ <thead><tr>
@ <th>DoW</th>
@ <th>Day</th>
|
| ︙ | ︙ | |||
558 559 560 561 562 563 564 565 566 567 |
@ </td>
@</tr>
}
@ </tbody></table>
db_finalize(&query);
}
/*
** Helper for stats_report_by_month_year(), which generates a list of
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | > > > | > > > > > > > | | | | | > > > > > > | | | > > > > > > > > > > > > > > > | | < | > | | | 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 |
@ </td>
@</tr>
}
@ </tbody></table>
db_finalize(&query);
}
/*
** Implements the "byhour" view for /reports. If zUserName is not NULL
** then the report is restricted to events created by the named user
** account.
*/
static void stats_report_hour_of_day(const char *zUserName){
Stmt query = empty_Stmt;
int nRowNumber = 0; /* current TR number */
int rowClass = 0; /* counter for alternating
row colors */
int nMaxEvents = 1; /* max number of events for
all rows. */
stats_report_init_view();
db_prepare(&query,
"SELECT cast(strftime('%%H', mtime) AS INTEGER) hod,"
" COUNT(*) AS eventCount"
" FROM v_reports"
" WHERE ifnull(coalesce(euser,user,'')=%Q,1)"
" GROUP BY hod ORDER BY hod", zUserName);
@ <h1>Timeline Events (%h(stats_report_label_for_type())) by Hour of Day
if( zUserName ){
@ for user %h(zUserName)
}
@ </h1>
db_multi_exec(
"CREATE TEMP VIEW piechart(amt,label) AS"
" SELECT count(*), strftime('%%H', mtime) hod"
" FROM v_reports"
" WHERE ifnull(coalesce(euser,user,'')=%Q,1)"
" GROUP BY 2 ORDER BY hod;",
zUserName
);
if( db_int(0, "SELECT count(*) FROM piechart")>=2 ){
@ <center><svg width=700 height=400>
piechart_render(700, 400, PIE_OTHER|PIE_PERCENT);
@ </svg></centre><hr>
}
style_table_sorter();
@ <table class='statistics-report-table-events sortable' border='0' \
@ cellpadding='2' cellspacing='0' data-column-types='nnx' data-init-sort='1'>
@ <thead><tr>
@ <th>Hour</th>
@ <th>Events</th>
@ <th width='90%%'><!-- relative commits graph --></th>
@ </tr></thead><tbody>
while( SQLITE_ROW == db_step(&query) ){
const int nCount = db_column_int(&query, 1);
if(nCount>nMaxEvents){
nMaxEvents = nCount;
}
}
db_reset(&query);
while( SQLITE_ROW == db_step(&query) ){
const int hourNum =db_column_int(&query, 0);
const int nCount = db_column_int(&query, 1);
int nSize = nCount
? (int)(100 * nCount / nMaxEvents)
: 0;
if(!nCount) continue /* arguable! Possible? */;
else if(!nSize) nSize = 1;
rowClass = ++nRowNumber % 2;
@<tr class='row%d(rowClass)'>
@ <td>%d(hourNum)</td>
@ <td>%d(nCount)</td>
@ <td>
@ <div class='statistics-report-graph-line'
@ style='width:%d(nSize)%%;'> </div>
@ </td>
@</tr>
}
@ </tbody></table>
db_finalize(&query);
}
/*
** Helper for stats_report_by_month_year(), which generates a list of
** week numbers. The "y" query parameter is the year in format YYYY.
** If zUserName is not NULL then the report is restricted to events
** created by the named user account.
*/
static void stats_report_year_weeks(const char *zUserName){
const char *zYear = P("y"); /* Year for which report shown */
Stmt q;
int nMaxEvents = 1; /* max number of events for
all rows. */
int iterations = 0; /* # of active time periods. */
int rowCount = 0;
int total = 0;
char *zCurrentWeek; /* Current week number */
double rNowFraction = 0.0; /* Fraction of current week that has
** passed */
stats_report_init_view();
style_submenu_sql("y", "Year:",
"WITH RECURSIVE a(b) AS ("
" SELECT substr(date('now'),1,4) UNION ALL"
" SELECT b-1 FROM a"
" WHERE b>0+(SELECT substr(date(min(mtime)),1,4) FROM event)"
") SELECT b, b FROM a ORDER BY b DESC");
if( zYear==0 || strlen(zYear)!=4 ){
zYear = db_text("1970","SELECT substr(date('now'),1,4);");
}
cgi_printf("<br>\n");
db_prepare(&q,
"SELECT DISTINCT strftime('%%W',mtime) AS wk, "
" count(*) AS n "
" FROM v_reports "
" WHERE %Q=substr(date(mtime),1,4) "
" AND mtime < current_timestamp "
" AND ifnull(coalesce(euser,user,'')=%Q,1)"
" GROUP BY wk ORDER BY wk DESC", zYear, zUserName);
@ <h1>Timeline events (%h(stats_report_label_for_type()))
@ for the calendar weeks of %h(zYear)
if( zUserName ){
@ for user %h(zUserName)
}
@ </h1>
zCurrentWeek = db_text(0,
"SELECT strftime('%%W','now') WHERE date() LIKE '%q%%'",
zYear);
if( zCurrentWeek ){
rNowFraction = db_double(0.5,
"SELECT (unixepoch()-unixepoch('now','weekday 0','-7 days'))/604800.0;");
}
style_table_sorter();
cgi_printf("<table class='statistics-report-table-events sortable' "
"border='0' cellpadding='2' width='100%%' "
"cellspacing='0' data-column-types='tnx' data-init-sort='0'>\n");
cgi_printf("<thead><tr>"
"<th>Week</th>"
"<th>Events</th>"
"<th width='90%%'><!-- relative commits graph --></th>"
"</tr></thead>\n"
"<tbody>\n");
while( SQLITE_ROW == db_step(&q) ){
int nCount = db_column_int(&q, 1);
if( zCurrentWeek!=0
&& strcmp(db_column_text(&q,0),zCurrentWeek)==0
&& rNowFraction>0.05
){
nCount = (int)(((double)nCount)/rNowFraction);
}
if(nCount>nMaxEvents){
nMaxEvents = nCount;
}
++iterations;
}
db_reset(&q);
while( SQLITE_ROW == db_step(&q) ){
const char *zWeek = db_column_text(&q,0);
const int nCount = db_column_int(&q,1);
int nSize = (nCount>0 && nMaxEvents>0)
? (int)(100 * nCount / nMaxEvents)
: 0;
if(!nSize) nSize = 1;
total += nCount;
cgi_printf("<tr class='row%d'>", ++rowCount % 2 );
cgi_printf("<td><a href='%R/timeline?yw=%t-%s&n=%d&y=%s",
zYear, zWeek, nCount,
statsReportTimelineYFlag);
if( zUserName ){
cgi_printf("&u=%t",zUserName);
}
cgi_printf("'>%s</a></td>",zWeek);
cgi_printf("<td>%d</td>",nCount);
cgi_printf("<td style='white-space: nowrap;'>");
if( nCount ){
if( zCurrentWeek!=0
&& strcmp(zWeek, zCurrentWeek)==0
&& rNowFraction>0.05
&& nMaxEvents>0
){
/* If the covered 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 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' \
@ 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");
}
db_finalize(&q);
cgi_printf("</tbody></table>");
if(total){
int nAvg = iterations ? (total/iterations) : 0;
cgi_printf("<br><div>Total events: %d<br>"
"Average per active week: %d</div>",
total, nAvg);
}
}
/*
|
| ︙ | ︙ | |||
707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 | #define RPT_BYFILE 1 #define RPT_BYMONTH 2 #define RPT_BYUSER 3 #define RPT_BYWEEK 4 #define RPT_BYWEEKDAY 5 #define RPT_BYYEAR 6 #define RPT_LASTCHNG 7 /* Last change made for each user */ #define RPT_NONE 0 /* None of the above */ /* ** WEBPAGE: reports ** ** Shows activity reports for the repository. ** ** Query Parameters: ** | > | > > > > > > > > > | > > > > > > | 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 | #define RPT_BYFILE 1 #define RPT_BYMONTH 2 #define RPT_BYUSER 3 #define RPT_BYWEEK 4 #define RPT_BYWEEKDAY 5 #define RPT_BYYEAR 6 #define RPT_LASTCHNG 7 /* Last change made for each user */ #define RPT_BYHOUR 8 /* hour-of-day */ #define RPT_NONE 0 /* None of the above */ /* ** WEBPAGE: reports ** ** Shows activity reports for the repository. ** ** Query Parameters: ** ** view=REPORT_NAME Valid REPORT_NAME values: ** * byyear ** * bymonth ** * byweek ** * byweekday ** * byhour ** * byuser ** * byfile ** * lastchng ** user=NAME Restricts statistics to the given user ** type=TYPE Restricts the report to a specific event type: ** * all (everything), ** * ci (check-in) ** * m (merge check-in), ** * n (non-merge check-in) ** * f (forum post) ** * w (wiki page change) ** * t (ticket change) ** * g (tag added or removed) ** Defaulting to all event types. ** ** The view-specific query parameters include: ** ** view=byweek: ** ** y=YYYY The year to report (default is the server's |
| ︙ | ︙ | |||
747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 |
{ "File Changes","byfile", RPT_BYFILE },
{ "Last Change", "lastchng", RPT_LASTCHNG },
{ "By Month", "bymonth", RPT_BYMONTH },
{ "By User", "byuser", RPT_BYUSER },
{ "By Week", "byweek", RPT_BYWEEK },
{ "By Weekday", "byweekday", RPT_BYWEEKDAY },
{ "By Year", "byyear", RPT_BYYEAR },
};
static const char *const azType[] = {
"a", "All Changes",
"ci", "Check-ins",
"f", "Forum Posts",
"g", "Tags",
"e", "Tech Notes",
"t", "Tickets",
"w", "Wiki"
};
login_check_credentials();
| > > > | 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 |
{ "File Changes","byfile", RPT_BYFILE },
{ "Last Change", "lastchng", RPT_LASTCHNG },
{ "By Month", "bymonth", RPT_BYMONTH },
{ "By User", "byuser", RPT_BYUSER },
{ "By Week", "byweek", RPT_BYWEEK },
{ "By Weekday", "byweekday", RPT_BYWEEKDAY },
{ "By Year", "byyear", RPT_BYYEAR },
{ "By Hour", "byhour", RPT_BYHOUR },
};
static const char *const azType[] = {
"a", "All Changes",
"ci", "Check-ins",
"f", "Forum Posts",
"m", "Merge check-ins",
"n", "Non-merge check-ins",
"g", "Tags",
"e", "Tech Notes",
"t", "Tickets",
"w", "Wiki"
};
login_check_credentials();
|
| ︙ | ︙ | |||
773 774 775 776 777 778 779 780 781 782 783 784 785 786 |
}
for(i=0; i<count(aViewType); i++){
if( fossil_strcmp(zView, aViewType[i].zVal)==0 ){
eType = aViewType[i].eType;
break;
}
}
if( eType!=RPT_NONE ){
int nView = 0; /* Slots used in azView[] */
for(i=0; i<count(aViewType); i++){
azView[nView++] = aViewType[i].zVal;
azView[nView++] = aViewType[i].zName;
}
if( eType!=RPT_BYFILE ){
| > | 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 |
}
for(i=0; i<count(aViewType); i++){
if( fossil_strcmp(zView, aViewType[i].zVal)==0 ){
eType = aViewType[i].eType;
break;
}
}
cgi_check_for_malice();
if( eType!=RPT_NONE ){
int nView = 0; /* Slots used in azView[] */
for(i=0; i<count(aViewType); i++){
azView[nView++] = aViewType[i].zVal;
azView[nView++] = aViewType[i].zName;
}
if( eType!=RPT_BYFILE ){
|
| ︙ | ︙ | |||
797 798 799 800 801 802 803 |
);
}
}
style_submenu_element("Stats", "%R/stat");
style_header("Activity Reports");
switch( eType ){
case RPT_BYYEAR:
| | | > > > | 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 |
);
}
}
style_submenu_element("Stats", "%R/stat");
style_header("Activity Reports");
switch( eType ){
case RPT_BYYEAR:
stats_report_by_month_year(0, zUserName);
break;
case RPT_BYMONTH:
stats_report_by_month_year(1, zUserName);
break;
case RPT_BYWEEK:
stats_report_year_weeks(zUserName);
break;
default:
case RPT_BYUSER:
stats_report_by_user();
break;
case RPT_BYWEEKDAY:
stats_report_day_of_week(zUserName);
break;
case RPT_BYFILE:
stats_report_by_file(zUserName);
break;
case RPT_BYHOUR:
stats_report_hour_of_day(zUserName);
break;
case RPT_LASTCHNG:
stats_report_last_change();
break;
}
style_finish_page();
}
|
Changes to src/style.c.
| ︙ | ︙ | |||
257 258 259 260 261 262 263 264 265 266 267 268 269 270 |
if( g.perm.Hyperlink ){
@ <form method="POST" action="%z(zLink)" %s(zOtherArgs)>
}else{
needHrefJs = 1;
@ <form method="POST" data-action='%s(zLink)' action='%R/login' \
@ %s(zOtherArgs)>
}
}
/*
** Add a new element to the submenu
*/
void style_submenu_element(
const char *zLabel,
| > | 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 |
if( g.perm.Hyperlink ){
@ <form method="POST" action="%z(zLink)" %s(zOtherArgs)>
}else{
needHrefJs = 1;
@ <form method="POST" data-action='%s(zLink)' action='%R/login' \
@ %s(zOtherArgs)>
}
login_insert_csrf_secret();
}
/*
** Add a new element to the submenu
*/
void style_submenu_element(
const char *zLabel,
|
| ︙ | ︙ | |||
605 606 607 608 609 610 611 |
"img-src * data:";
const char *zFormat;
Blob csp;
char *zNonce;
char *zCsp;
int i;
if( disableCSP ) return fossil_strdup("");
| | | | 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 |
"img-src * data:";
const char *zFormat;
Blob csp;
char *zNonce;
char *zCsp;
int i;
if( disableCSP ) return fossil_strdup("");
zFormat = db_get("default-csp",0);
if( zFormat==0 ){
zFormat = zBackupCSP;
}
blob_init(&csp, 0, 0);
while( zFormat[0] && (zNonce = strstr(zFormat,"$nonce"))!=0 ){
blob_append(&csp, zFormat, (int)(zNonce - zFormat));
blob_append(&csp, style_nonce(), -1);
zFormat = zNonce + 6;
|
| ︙ | ︙ | |||
646 647 648 649 650 651 652 | ** header template lacks a <body> tag, then all of the following is ** prepended. */ static const char zDfltHeader[] = @ <html> @ <head> @ <meta charset="UTF-8"> | | | | | | 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 | ** header template lacks a <body> tag, then all of the following is ** prepended. */ static const char zDfltHeader[] = @ <html> @ <head> @ <meta charset="UTF-8"> @ <base href="$baseurl/$current_page"> @ <meta http-equiv="Content-Security-Policy" content="$default_csp"> @ <meta name="viewport" content="width=device-width, initial-scale=1.0"> @ <title>$<project_name>: $<title></title> @ <link rel="alternate" type="application/rss+xml" title="RSS Feed" \ @ href="$home/timeline.rss"> @ <link rel="stylesheet" href="$stylesheet_url" type="text/css"> @ </head> @ <body class="$current_feature rpage-$requested_page cpage-$canonical_page"> ; /* ** Returns the default page header. */ |
| ︙ | ︙ | |||
728 729 730 731 732 733 734 | /* ** Returns the current mainmenu value from either the --mainmenu flag ** (handled by the server/ui/cgi commands), the "mainmenu" config ** setting, or style_default_mainmenu(), in that order, returning the ** first of those which is defined. */ | | | 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 |
/*
** Returns the current mainmenu value from either the --mainmenu flag
** (handled by the server/ui/cgi commands), the "mainmenu" config
** setting, or style_default_mainmenu(), in that order, returning the
** first of those which is defined.
*/
const char *style_get_mainmenu(){
static const char *zMenu = 0;
if(!zMenu){
if(g.zMainMenuFile){
Blob b = empty_blob;
blob_read_from_file(&b, g.zMainMenuFile, ExtFILE);
zMenu = blob_str(&b);
}else{
|
| ︙ | ︙ | |||
792 793 794 795 796 797 798 |
if( !login_is_nobody() ){
Th_Store("login", g.zLogin);
}
Th_MaybeStore("current_feature", feature_from_page_path(local_zCurrentPage) );
if( g.ftntsIssues[0] || g.ftntsIssues[1] ||
g.ftntsIssues[2] || g.ftntsIssues[3] ){
char buf[80];
| | | 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 |
if( !login_is_nobody() ){
Th_Store("login", g.zLogin);
}
Th_MaybeStore("current_feature", feature_from_page_path(local_zCurrentPage) );
if( g.ftntsIssues[0] || g.ftntsIssues[1] ||
g.ftntsIssues[2] || g.ftntsIssues[3] ){
char buf[80];
sqlite3_snprintf(sizeof(buf),buf,"%i %i %i %i",g.ftntsIssues[0],g.ftntsIssues[1],
g.ftntsIssues[2],g.ftntsIssues[3]);
Th_Store("footnotes_issues_counters", buf);
}
}
/*
** Draw the header.
|
| ︙ | ︙ | |||
815 816 817 818 819 820 821 | zTitle = vmprintf(zTitleFormat, ap); va_end(ap); cgi_destination(CGI_HEADER); @ <!DOCTYPE html> | | | | | | 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 |
zTitle = vmprintf(zTitleFormat, ap);
va_end(ap);
cgi_destination(CGI_HEADER);
@ <!DOCTYPE html>
if( g.thTrace ) Th_Trace("BEGIN_HEADER<br>\n", -1);
/* Generate the header up through the main menu */
style_init_th1_vars(zTitle);
if( sqlite3_strlike("%<body%", zHeader, 0)!=0 ){
Th_Render(zDfltHeader);
}
if( g.thTrace ) Th_Trace("BEGIN_HEADER_SCRIPT<br>\n", -1);
Th_Render(zHeader);
if( g.thTrace ) Th_Trace("END_HEADER<br>\n", -1);
Th_Unstore("title"); /* Avoid collisions with ticket field names */
cgi_destination(CGI_BODY);
g.cgiOutput = 1;
headerHasBeenGenerated = 1;
sideboxUsed = 0;
if( g.perm.Debug && P("showqp") ){
@ <div class="debug">
cgi_print_all(0, 0, 0);
@ </div>
}
}
#if INTERFACE
/* Allowed parameters for style_adunit() */
#define ADUNIT_OFF 0x0001 /* Do not allow ads on this page */
|
| ︙ | ︙ | |||
993 994 995 996 997 998 999 |
if( nSubmenu>0 ){
qsort(aSubmenu, nSubmenu, sizeof(aSubmenu[0]), submenuCompare);
for(i=0; i<nSubmenu; i++){
struct Submenu *p = &aSubmenu[i];
style_derive_classname(p->zLabel, zClass, sizeof zClass);
/* switching away from the %h formatting below might be dangerous
** because some places use %s to compose zLabel and zLink;
| > | | 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 |
if( nSubmenu>0 ){
qsort(aSubmenu, nSubmenu, sizeof(aSubmenu[0]), submenuCompare);
for(i=0; i<nSubmenu; i++){
struct Submenu *p = &aSubmenu[i];
style_derive_classname(p->zLabel, zClass, sizeof zClass);
/* switching away from the %h formatting below might be dangerous
** because some places use %s to compose zLabel and zLink;
** e.g. /rptview page and the submenuCmd() function.
** "sml" stands for submenu link.
*/
if( p->zLink==0 ){
@ <span class="label sml-%s(zClass)">%h(p->zLabel)</span>
}else{
@ <a class="label sml-%s(zClass)" href="%h(p->zLink)">%h(p->zLabel)</a>
}
}
|
| ︙ | ︙ | |||
1118 1119 1120 1121 1122 1123 1124 |
@ </div>
/* Put the footer at the bottom of the page. */
zFooter = skin_get("footer");
if( sqlite3_strlike("%</body>%", zFooter, 0)==0 ){
style_load_all_js_files();
}
| | | | | < < | 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 |
@ </div>
/* Put the footer at the bottom of the page. */
zFooter = skin_get("footer");
if( sqlite3_strlike("%</body>%", zFooter, 0)==0 ){
style_load_all_js_files();
}
if( g.thTrace ) Th_Trace("BEGIN_FOOTER<br>\n", -1);
Th_Render(zFooter);
if( g.thTrace ) Th_Trace("END_FOOTER<br>\n", -1);
/* Render trace log if TH1 tracing is enabled. */
if( g.thTrace ){
cgi_append_content("<span class=\"thTrace\"><hr>\n", -1);
cgi_append_content(blob_str(&g.thLog), blob_size(&g.thLog));
cgi_append_content("</span>\n", -1);
}
/* Add document end mark if it was not in the footer */
if( sqlite3_strlike("%</body>%", zFooter, 0)!=0 ){
style_load_all_js_files();
@ </body>
@ </html>
}
/* Update the user display prefs cookie if it was modified */
cookie_render();
}
/*
** Begin a side-box on the right-hand side of a page. The title and
** the width of the box are given as arguments. The width is usually
** a percentage of total screen width.
|
| ︙ | ︙ | |||
1428 1429 1430 1431 1432 1433 1434 |
showAll = PB("showall");
style_submenu_checkbox("showall", "Cookies", 0, 0);
style_submenu_element("Stats", "%R/stat");
}
if( isAuth ){
#if !defined(_WIN32)
| | | | | | | | | | > > > > > | | | | | | | | > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > | | | | 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 |
showAll = PB("showall");
style_submenu_checkbox("showall", "Cookies", 0, 0);
style_submenu_element("Stats", "%R/stat");
}
if( isAuth ){
#if !defined(_WIN32)
@ uid=%d(getuid()), gid=%d(getgid())<br>
#endif
@ g.zBaseURL = %h(g.zBaseURL)<br>
@ g.zHttpsURL = %h(g.zHttpsURL)<br>
@ g.zTop = %h(g.zTop)<br>
@ g.zPath = %h(g.zPath)<br>
@ g.userUid = %d(g.userUid)<br>
@ g.zLogin = %h(g.zLogin)<br>
@ g.isHuman = %d(g.isHuman)<br>
@ g.jsHref = %d(g.jsHref)<br>
if( g.zLocalRoot ){
@ g.zLocalRoot = %h(g.zLocalRoot)<br>
}else{
@ g.zLocalRoot = <i>none</i><br>
}
if( g.nRequest ){
@ g.nRequest = %d(g.nRequest)<br>
}
if( g.nPendingRequest>1 ){
@ g.nPendingRequest = %d(g.nPendingRequest)<br>
}
@ capabilities = %s(find_capabilities(zCap))<br>
if( zCap[0] ){
@ anonymous-adds = %s(find_anon_capabilities(zCap))<br>
}
@ g.zRepositoryName = %h(g.zRepositoryName)<br>
@ load_average() = %f(load_average())<br>
#ifndef _WIN32
@ RSS = %.2f(fossil_rss()/1000000.0) MB</br>
#endif
(void)cgi_csrf_safe(2);
switch( g.okCsrf ){
case 1: {
@ CSRF safety = Same origin<br>
break;
}
case 2: {
@ CSRF safety = Same origin, POST<br>
break;
}
case 3: {
@ CSRF safety = Same origin, POST, CSRF token<br>
break;
}
default: {
@ CSRF safety = unsafe<br>
break;
}
}
@ fossil_exe_id() = %h(fossil_exe_id())<br>
if( g.perm.Admin ){
int k;
for(k=0; g.argvOrig[k]; k++){
Blob t;
blob_init(&t, 0, 0);
blob_append_escaped_arg(&t, g.argvOrig[k], 0);
@ argv[%d(k)] = %h(blob_str(&t))<br>
blob_zero(&t);
}
}
@ <hr>
P("HTTP_USER_AGENT");
P("SERVER_SOFTWARE");
cgi_print_all(showAll, 0, 0);
if( showAll && blob_size(&g.httpHeader)>0 ){
@ <hr>
@ <pre>
@ %h(blob_str(&g.httpHeader))
@ </pre>
}
}
if( zErr && zErr[0] ){
style_finish_page();
|
| ︙ | ︙ |
Changes to src/style.chat.css.
| ︙ | ︙ | |||
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
border: 1px solid rgba(0,0,0,0.2);
box-shadow: 0.2em 0.2em 0.2em rgba(0, 0, 0, 0.29);
padding: 0.25em 0.5em;
margin-top: 0;
min-width: 9em /*avoid unsightly "underlap" with the neighboring
.message-widget-tab element*/;
white-space: normal;
}
body.chat .message-widget-content.wide {
/* Special case for when embedding content which we really want to
expand, namely iframes. */
width: 98%;
}
body.chat .message-widget-content label[for] {
margin-left: 0.25em;
| > > | 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
border: 1px solid rgba(0,0,0,0.2);
box-shadow: 0.2em 0.2em 0.2em rgba(0, 0, 0, 0.29);
padding: 0.25em 0.5em;
margin-top: 0;
min-width: 9em /*avoid unsightly "underlap" with the neighboring
.message-widget-tab element*/;
white-space: normal;
word-break: break-word /* so that full hashes wrap on narrow screens */;
}
body.chat .message-widget-content.wide {
/* Special case for when embedding content which we really want to
expand, namely iframes. */
width: 98%;
}
body.chat .message-widget-content label[for] {
margin-left: 0.25em;
|
| ︙ | ︙ | |||
175 176 177 178 179 180 181 182 183 184 185 186 187 188 |
body.chat #load-msg-toolbar > div > button {
flex: 1 1 auto;
}
/* "Chat-only mode" hides the site header/footer, showing only
the chat app. */
body.chat.chat-only-mode{
padding: 0;
}
body.chat #chat-button-settings {}
/** Popup widget for the /chat settings. */
body.chat .chat-settings-popup {
font-size: 0.8em;
text-align: left;
display: flex;
| > | 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 |
body.chat #load-msg-toolbar > div > button {
flex: 1 1 auto;
}
/* "Chat-only mode" hides the site header/footer, showing only
the chat app. */
body.chat.chat-only-mode{
padding: 0;
margin: 0 auto;
}
body.chat #chat-button-settings {}
/** Popup widget for the /chat settings. */
body.chat .chat-settings-popup {
font-size: 0.8em;
text-align: left;
display: flex;
|
| ︙ | ︙ |
Changes to src/style.fileedit.css.
| ︙ | ︙ | |||
74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
overflow: auto;
}
body.fileedit #fileedit-tab-preview-wrapper > pre {
margin: 0;
}
body.fileedit #fileedit-tab-fileselect > h1 {
margin: 0;
}
body.fileedit .fileedit-options.commit-message > div {
display: flex;
flex-direction: column;
align-items: stretch;
font-family: monospace;
}
| > > > | 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
overflow: auto;
}
body.fileedit #fileedit-tab-preview-wrapper > pre {
margin: 0;
}
body.fileedit #fileedit-tab-fileselect > h1 {
margin: 0;
}
body.fileedit .fileedit-options > div > * {
margin: 0.25em;
}
body.fileedit .fileedit-options.commit-message > div {
display: flex;
flex-direction: column;
align-items: stretch;
font-family: monospace;
}
|
| ︙ | ︙ | |||
103 104 105 106 107 108 109 |
margin: 0.5em;
}
body.fileedit .tab-container > .tabs > .tab-panel > .fileedit-options > input {
vertical-align: middle;
margin: 0.5em;
}
body.fileedit .tab-container > .tabs > .tab-panel > .fileedit-options > .input-with-label {
| < | | 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
margin: 0.5em;
}
body.fileedit .tab-container > .tabs > .tab-panel > .fileedit-options > input {
vertical-align: middle;
margin: 0.5em;
}
body.fileedit .tab-container > .tabs > .tab-panel > .fileedit-options > .input-with-label {
margin: 0 0.5em 0.25em 0.5em;
}
body.fileedit .fileedit-options > div > * {
margin: 0.25em;
}
body.fileedit .fileedit-options.flex-container.flex-row {
align-items: first baseline;
}
|
| ︙ | ︙ |
Changes to src/style.pikchrshow.css.
1 | /* CSS for the WASM /pikchrshow app. */ | | | 1 2 3 4 5 6 7 8 9 |
/* CSS for the WASM /pikchrshow app. */
/* emcscript-related styling, used during the module load/initialization processes... */
.emscripten { padding-right: 0; margin-left: auto; margin-right: auto; display: block; }
div.emscripten { text-align: center; }
div.emscripten_border { border: 1px solid black; }
#module-spinner { overflow: visible; }
#module-spinner > * {
margin-top: 1em;
}
|
| ︙ | ︙ |
Changes to src/style.wikiedit.css.
| ︙ | ︙ | |||
41 42 43 44 45 46 47 |
margin: 0.5em;
}
body.wikiedit .tab-container > .tabs > .tab-panel > .wikiedit-options > input {
vertical-align: middle;
margin: 0.5em;
}
body.wikiedit .tab-container > .tabs > .tab-panel > .wikiedit-options > .input-with-label {
| < | 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
margin: 0.5em;
}
body.wikiedit .tab-container > .tabs > .tab-panel > .wikiedit-options > input {
vertical-align: middle;
margin: 0.5em;
}
body.wikiedit .tab-container > .tabs > .tab-panel > .wikiedit-options > .input-with-label {
margin: 0 0.5em 0.25em 0.5em;
}
body.wikiedit label {
display: inline; /* some skins set label display to block! */
}
body.wikiedit .wikiedit-options > div > * {
margin: 0.25em;
|
| ︙ | ︙ |
Changes to src/sync.c.
| ︙ | ︙ | |||
103 104 105 106 107 108 109 | /* ** If the repository is configured for autosyncing, then do an ** autosync. Bits of the "flags" parameter determine details of behavior: ** ** SYNC_PULL Pull content from the server to the local repo ** SYNC_PUSH Push content from local up to the server | | | 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 | /* ** If the repository is configured for autosyncing, then do an ** autosync. Bits of the "flags" parameter determine details of behavior: ** ** SYNC_PULL Pull content from the server to the local repo ** SYNC_PUSH Push content from local up to the server ** SYNC_CKIN_LOCK Take a check-in lock on the current check-out. ** SYNC_VERBOSE Extra output ** ** Return the number of errors. ** ** The autosync setting can be a boolean or "pullonly". No autosync ** is attempted if the autosync setting is off, and only auto-pull is ** attempted if autosync is set to "pullonly". The check-in lock is |
| ︙ | ︙ | |||
232 233 234 235 236 237 238 239 240 241 242 243 244 245 |
}
}
if( find_option("private",0,0)!=0 ){
*pSyncFlags |= SYNC_PRIVATE;
}
if( find_option("verbose","v",0)!=0 ){
*pSyncFlags |= SYNC_VERBOSE;
}
if( find_option("no-http-compression",0,0)!=0 ){
*pSyncFlags |= SYNC_NOHTTPCOMPRESS;
}
if( find_option("all",0,0)!=0 ){
*pSyncFlags |= SYNC_ALLURL;
}
| > > > | 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 |
}
}
if( find_option("private",0,0)!=0 ){
*pSyncFlags |= SYNC_PRIVATE;
}
if( find_option("verbose","v",0)!=0 ){
*pSyncFlags |= SYNC_VERBOSE;
if( find_option("verbose","v",0)!=0 ){
*pSyncFlags |= SYNC_XVERBOSE;
}
}
if( find_option("no-http-compression",0,0)!=0 ){
*pSyncFlags |= SYNC_NOHTTPCOMPRESS;
}
if( find_option("all",0,0)!=0 ){
*pSyncFlags |= SYNC_ALLURL;
}
|
| ︙ | ︙ | |||
317 318 319 320 321 322 323 | ** "configuration pull" command to pull website configuration details. ** ** If URL is not specified, then the URL from the most recent clone, push, ** pull, remote, or sync command is used. See "fossil help clone" for ** details on the URL formats. ** ** Options: | < | > | 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 |
** "configuration pull" command to pull website configuration details.
**
** If URL is not specified, then the URL from the most recent clone, push,
** pull, remote, or sync command is used. See "fossil help clone" for
** details on the URL formats.
**
** Options:
** --all Pull from all remotes, not just the default
** -B|--httpauth USER:PASS Credentials for the simple HTTP auth protocol,
** if required by the remote website
** --from-parent-project Pull content from the parent project
** --ipv4 Use only IPv4, not IPv6
** --no-http-compression Do not compress HTTP traffic
** --once Do not remember URL for subsequent syncs
** --private Pull private branches too
** --project-code CODE Use CODE as the project code
** --proxy PROXY Use the specified HTTP proxy
** -R|--repository REPO Local repository to pull into
** --ssl-identity FILE Local SSL credentials, if requested by remote
** --ssh-command SSH Use SSH as the "ssh" command
** --transport-command CMD Use external command CMD to move messages
** between client and server
** -v|--verbose Additional (debugging) output - use twice to
** also trace network traffic.
** --verily Exchange extra information with the remote
** to ensure no content is overlooked
**
** See also: [[clone]], [[config]], [[push]], [[remote]], [[sync]]
*/
void pull_cmd(void){
unsigned configFlags = 0;
|
| ︙ | ︙ | |||
372 373 374 375 376 377 378 | ** push" command to push website configuration details. ** ** If URL is not specified, then the URL from the most recent clone, push, ** pull, remote, or sync command is used. See "fossil help clone" for ** details on the URL formats. ** ** Options: | < | > | 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 |
** push" command to push website configuration details.
**
** If URL is not specified, then the URL from the most recent clone, push,
** pull, remote, or sync command is used. See "fossil help clone" for
** details on the URL formats.
**
** Options:
** --all Push to all remotes, not just the default
** -B|--httpauth USER:PASS Credentials for the simple HTTP auth protocol,
** if required by the remote website
** --ipv4 Use only IPv4, not IPv6
** --no-http-compression Do not compress HTTP traffic
** --once Do not remember URL for subsequent syncs
** --proxy PROXY Use the specified HTTP proxy
** --private Push private branches too
** -R|--repository REPO Local repository to push from
** --ssl-identity FILE Local SSL credentials, if requested by remote
** --ssh-command SSH Use SSH as the "ssh" command
** --transport-command CMD Use external command CMD to communicate with
** the server
** -v|--verbose Additional (debugging) output - use twice for
** network debugging
** --verily Exchange extra information with the remote
** to ensure no content is overlooked
**
** See also: [[clone]], [[config]], [[pull]], [[remote]], [[sync]]
*/
void push_cmd(void){
unsigned configFlags = 0;
|
| ︙ | ︙ | |||
421 422 423 424 425 426 427 | ** edits to wiki pages, tickets, forum posts, and technical notes. ** ** If URL is not specified, then the URL from the most recent clone, push, ** pull, remote, or sync command is used. See "fossil help clone" for ** details on the URL formats. ** ** Options: | < | > | 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 |
** edits to wiki pages, tickets, forum posts, and technical notes.
**
** If URL is not specified, then the URL from the most recent clone, push,
** pull, remote, or sync command is used. See "fossil help clone" for
** details on the URL formats.
**
** Options:
** --all Sync with all remotes, not just the default
** -B|--httpauth USER:PASS Credentials for the simple HTTP auth protocol,
** if required by the remote website
** --ipv4 Use only IPv4, not IPv6
** --no-http-compression Do not compress HTTP traffic
** --once Do not remember URL for subsequent syncs
** --proxy PROXY Use the specified HTTP proxy
** --private Sync private branches too
** -R|--repository REPO Local repository to sync with
** --ssl-identity FILE Local SSL credentials, if requested by remote
** --ssh-command SSH Use SSH as the "ssh" command
** --transport-command CMD Use external command CMD to move message
** between the client and the server
** -u|--unversioned Also sync unversioned content
** -v|--verbose Additional (debugging) output - use twice to
** get network debug info
** --verily Exchange extra information with the remote
** to ensure no content is overlooked
**
** See also: [[clone]], [[pull]], [[push]], [[remote]]
*/
void sync_cmd(void){
unsigned configFlags = 0;
|
| ︙ | ︙ | |||
510 511 512 513 514 515 516 | ** ** > fossil remote delete NAME ** ** Delete a named URL previously created by the "add" subcommand. ** ** > fossil remote hyperlink ?FILENAME? ?LINENUM? ?LINENUM? ** | | | | 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 | ** ** > fossil remote delete NAME ** ** Delete a named URL previously created by the "add" subcommand. ** ** > fossil remote hyperlink ?FILENAME? ?LINENUM? ?LINENUM? ** ** Print a URL that will access the current check-out on the remote ** repository. Or if the FILENAME argument is included, print the ** URL to access that particular file within the current check-out. ** If one or two linenumber arguments are provided after the filename, ** then the URL is for the line or range of lines specified. ** ** > fossil remote list|ls ** ** Show all remote repository URLs. ** |
| ︙ | ︙ | |||
544 545 546 547 548 549 550 | ** Forget any saved passwords for remote repositories, but continue ** to remember the URLs themselves. You will be prompted for the ** password the next time it is needed. ** ** > fossil remote ui ?FILENAME? ?LINENUM? ?LINENUM? ** ** Bring up a web browser pointing at the remote repository, and | | > > | 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 |
** Forget any saved passwords for remote repositories, but continue
** to remember the URLs themselves. You will be prompted for the
** password the next time it is needed.
**
** > fossil remote ui ?FILENAME? ?LINENUM? ?LINENUM?
**
** Bring up a web browser pointing at the remote repository, and
** specifically to the page that describes the current check-out
** on that remote repository. Or if FILENAME and/or LINENUM arguments
** are provided, to the specific file and range of lines. This
** command is similar to "fossil remote hyperlink" except that instead
** of printing the URL, it passes the URL off to the web browser.
**
** > fossil remote REF
**
** Make REF the new default URL, replacing the prior default.
** REF may be a URL or a NAME from a prior "add".
*/
void remote_url_cmd(void){
char *zUrl, *zArg;
int nArg;
int showPw;
db_find_and_open_repository(0, 0);
showPw = find_option("show-passwords",0,0)!=0;
/* We should be done with options.. */
verify_all_options();
/* 2021-10-25: A note about data structures.
**
** The remote URLs are stored in the CONFIG table. The URL is stored
|
| ︙ | ︙ | |||
758 759 760 761 762 763 764 |
db_multi_exec("DELETE FROM config WHERE name glob 'sync-pw:*'");
db_multi_exec("DELETE FROM config WHERE name = 'last-sync-pw'");
db_protect_pop();
db_commit_transaction();
return;
}
if( strncmp(zArg, "config-data", nArg)==0 ){
| | > > | > > | | > > | | | > > | > | 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 |
db_multi_exec("DELETE FROM config WHERE name glob 'sync-pw:*'");
db_multi_exec("DELETE FROM config WHERE name = 'last-sync-pw'");
db_protect_pop();
db_commit_transaction();
return;
}
if( strncmp(zArg, "config-data", nArg)==0 ){
/* Undocumented command: "fossil remote config-data [-show-passwords]"
**
** Show the CONFIG table entries that relate to remembering remote URLs
*/
Stmt q;
int n;
sqlite3_create_function(g.db, "unobscure", 1, SQLITE_UTF8, &g.db,
db_obscure, 0, 0);
n = db_int(13,
"SELECT max(length(name))"
" FROM config"
" WHERE name GLOB 'sync-*:*'"
" OR name GLOB 'last-sync-*'"
" OR name GLOB 'parent-project-*'"
);
db_prepare(&q,
"SELECT name,"
" CASE WHEN name NOT LIKE '%%sync-pw%%' AND name<>'parent-project-pw'"
" THEN value"
" WHEN %d THEN unobscure(value)"
" ELSE printf('%%.*c',length(value)/2-1,'*') END"
" FROM config"
" WHERE name GLOB 'sync-*:*'"
" OR name GLOB 'last-sync-*'"
" OR name GLOB 'parent-project-*'"
" ORDER BY name LIKE '%%sync-pw%%' OR name='parent-project-pw', name",
showPw
);
while( db_step(&q)==SQLITE_ROW ){
fossil_print("%-*s %s\n",
n, db_column_text(&q,0),
db_column_text(&q,1)
);
}
|
| ︙ | ︙ | |||
814 815 816 817 818 819 820 | ** ** Make a backup of the repository into the named file or into the named ** directory. This backup is guaranteed to be consistent even if there are ** concurrent changes taking place on the repository. In other words, it ** is safe to run "fossil backup" on a repository that is in active use. ** ** Only the main repository database is backed up by this command. The | | < | 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 |
**
** Make a backup of the repository into the named file or into the named
** directory. This backup is guaranteed to be consistent even if there are
** concurrent changes taking place on the repository. In other words, it
** is safe to run "fossil backup" on a repository that is in active use.
**
** Only the main repository database is backed up by this command. The
** open check-out file (if any) is not saved. Nor is the global configuration
** database.
**
** Options:
** --overwrite OK to overwrite an existing file
** -R NAME Filename of the repository to backup
*/
void backup_cmd(void){
char *zDest;
int bOverwrite = 0;
db_find_and_open_repository(OPEN_ANY_SCHEMA, 0);
|
| ︙ | ︙ |
Changes to src/tag.c.
| ︙ | ︙ | |||
393 394 395 396 397 398 399 | ** Usage: %fossil tag SUBCOMMAND ... ** ** Run various subcommands to control tags and properties. ** ** > fossil tag add ?OPTIONS? TAGNAME ARTIFACT-ID ?VALUE? ** ** Add a new tag or property to an artifact referenced by | | | | | | | | | | | | | 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 | ** Usage: %fossil tag SUBCOMMAND ... ** ** Run various subcommands to control tags and properties. ** ** > fossil tag add ?OPTIONS? TAGNAME ARTIFACT-ID ?VALUE? ** ** Add a new tag or property to an artifact referenced by ** ARTIFACT-ID. For check-ins, the tag will be usable instead ** of a CHECK-IN in commands such as update and merge. If the ** --propagate flag is present and ARTIFACT-ID refers to a ** wiki page, forum post, technote, or check-in, the tag ** propagates to all descendants of that artifact. ** ** Options: ** --raw Raw tag name. Ignored for ** non-CHECK-IN artifacts. ** --propagate Propagating tag ** --date-override DATETIME Set date and time added ** --user-override USER Name USER when adding the tag ** -n|--dry-run Display the tag text, but do not ** actually insert it into the database ** ** The --date-override and --user-override options support ** importing history from other SCM systems. DATETIME has ** the form 'YYYY-MMM-DD HH:MM:SS'. ** ** Note that fossil uses some tag prefixes internally and this ** command will reject tags with these prefixes to avoid ** causing problems or confusion: "wiki-", "tkt-", "event-". ** ** > fossil tag cancel ?--raw? TAGNAME ARTIFACT-ID ** ** Remove the tag TAGNAME from the artifact referenced by ** ARTIFACT-ID, and also remove the propagation of the tag to ** any descendants. Use the the -n|--dry-run option to see ** what would have happened. Certain tag name prefixes are ** forbidden, as documented for the 'add' subcommand. ** ** Options: ** --raw Raw tag name. Ignored for ** non-CHECK-IN artifacts. ** --date-override DATETIME Set date and time deleted ** --user-override USER Name USER when deleting the tag ** -n|--dry-run Display the control artifact, but do ** not insert it into the database ** ** > fossil tag find ?OPTIONS? TAGNAME ** ** List all objects that use TAGNAME. ** ** Options: ** --raw Interprets tag as a raw name instead of a ** branch name and matches any type of artifact. ** Changes the output to include only the ** hashes of matching objects. ** -t|--type TYPE One of: ci (check-in), w (wiki), ** e (event/technote), f (forum post), ** t (ticket). Default is all types. Ignored ** if --raw is used. ** -n|--limit N Limit to N results ** ** > fossil tag list|ls ?OPTIONS? ?ARTIFACT-ID? ** ** List all tags or, if ARTIFACT-ID is supplied, all tags and ** their values for that artifact. The tagtype option accepts ** one of: propagated, singleton, cancel. For historical ** scripting compatibility, the internal tag types "wiki-", ** "tkt-", and "event-" (technote) are elided by default ** unless the --raw or --prefix options are used. ** ** Options: ** --raw List raw names of tags ** --tagtype TYPE List only tags of type TYPE, which must ** be one of: cancel, singleton, propagated ** -v|--inverse Inverse the meaning of --tagtype TYPE ** --prefix List only tags with the given prefix ** Fossil-internal prefixes include "sym-" ** (branch name), "wiki-", "event-" ** (technote), and "tkt-" (ticket). The ** prefix is stripped from the resulting ** list unless --raw is provided. Ignored if ** ARTIFACT-ID is provided. ** |
| ︙ | ︙ | |||
803 804 805 806 807 808 809 810 811 812 813 814 815 816 |
void taglist_page(void){
Stmt q;
login_check_credentials();
if( !g.perm.Read ){
login_needed(g.anon.Read);
}
login_anonymous_available();
style_header("Tags");
style_adunit_config(ADUNIT_RIGHT_OK);
style_submenu_element("Timeline", "tagtimeline");
@ <h2>Non-propagating tags:</h2>
db_prepare(&q,
"SELECT substr(tagname,5)"
| > | 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 |
void taglist_page(void){
Stmt q;
login_check_credentials();
if( !g.perm.Read ){
login_needed(g.anon.Read);
}
cgi_check_for_malice();
login_anonymous_available();
style_header("Tags");
style_adunit_config(ADUNIT_RIGHT_OK);
style_submenu_element("Timeline", "tagtimeline");
@ <h2>Non-propagating tags:</h2>
db_prepare(&q,
"SELECT substr(tagname,5)"
|
| ︙ | ︙ | |||
884 885 886 887 888 889 890 |
** many descenders to (off-screen) parents. */
tmFlags = TIMELINE_XMERGE | TIMELINE_FILLGAPS | TIMELINE_NOSCROLL;
if( PB("ng")==0 ) tmFlags |= TIMELINE_GRAPH;
if( PB("brbg")!=0 ) tmFlags |= TIMELINE_BRCOLOR;
if( PB("ubg")!=0 ) tmFlags |= TIMELINE_UCOLOR;
www_print_timeline(&q, tmFlags, 0, 0, 0, 0, 0, 0);
db_finalize(&q);
| | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 |
** many descenders to (off-screen) parents. */
tmFlags = TIMELINE_XMERGE | TIMELINE_FILLGAPS | TIMELINE_NOSCROLL;
if( PB("ng")==0 ) tmFlags |= TIMELINE_GRAPH;
if( PB("brbg")!=0 ) tmFlags |= TIMELINE_BRCOLOR;
if( PB("ubg")!=0 ) tmFlags |= TIMELINE_UCOLOR;
www_print_timeline(&q, tmFlags, 0, 0, 0, 0, 0, 0);
db_finalize(&q);
@ <br>
style_finish_page();
}
/*
** Returns true if the given blob.rid value has the given tag ID
** applied to it, else false.
*/
int rid_has_tag(int rid, int tagId){
return db_exists(
"SELECT tag.tagid FROM tagxref, tag"
" WHERE tagxref.rid=%d AND tagtype>0 "
" AND tag.tagid=%d"
" AND tagxref.tagid=tag.tagid",
rid, tagId
);
}
/*
** Returns tagxref.rowid if the given blob.rid has a tagxref.rid entry
** of an active (non-cancelled) tag matching the given rid and tag
** name string, else returns 0. Note that this function does not
** distinguish between a non-existent tag and a cancelled tag.
**
** Design note: the return value is the tagxref.rowid because that
** gives us an easy way to fetch the value of the tag later on, if
** needed.
*/
int rid_has_active_tag_name(int rid, const char *zTagName){
static Stmt q = empty_Stmt_m;
int rc;
assert( 0 != zTagName );
if( !q.pStmt ){
db_static_prepare(&q,
"SELECT x.rowid FROM tagxref x, tag t"
" WHERE x.rid=$rid AND x.tagtype>0 "
" AND x.tagid=t.tagid"
" AND t.tagname=$tagname"
);
}
db_bind_int(&q, "$rid", rid);
db_bind_text(&q, "$tagname", zTagName);
rc = (SQLITE_ROW==db_step(&q)) ? db_column_int(&q, 0) : 0;
db_reset(&q);
return rc;
}
|
Changes to src/tar.c.
| ︙ | ︙ | |||
244 245 246 247 248 249 250 |
/* adding the length extended the length field? */
if(blen > next10){
blen++;
}
/* build the string */
blob_appendf(&tball.pax, "%d %s=%*.*s\n", blen, zField, nValue, nValue, zValue);
/* this _must_ be right */
| | | 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 |
/* adding the length extended the length field? */
if(blen > next10){
blen++;
}
/* build the string */
blob_appendf(&tball.pax, "%d %s=%*.*s\n", blen, zField, nValue, nValue, zValue);
/* this _must_ be right */
if((int)blob_size(&tball.pax) != blen){
fossil_panic("internal error: PAX tar header has bad length");
}
}
/*
** set the header type, calculate the checksum and output
|
| ︙ | ︙ | |||
463 464 465 466 467 468 469 | ** added to as part of the tarball. It may be 0 or an empty string, in ** which case it is ignored. The intention is to create a tarball which ** politely expands into a subdir instead of filling your current dir ** with source files. For example, pass an artifact hash or "ProjectName". ** */ void tarball_of_checkin( | | | 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 |
** added to as part of the tarball. It may be 0 or an empty string, in
** which case it is ignored. The intention is to create a tarball which
** politely expands into a subdir instead of filling your current dir
** with source files. For example, pass an artifact hash or "ProjectName".
**
*/
void tarball_of_checkin(
int rid, /* The RID of the check-in from which to form a tarball*/
Blob *pTar, /* Write the tarball into this blob */
const char *zDir, /* Directory prefix for all file added to tarball */
Glob *pInclude, /* Only add files matching this pattern */
Glob *pExclude, /* Exclude files matching this pattern */
int listFlag /* Show filenames on stdout */
){
Blob mfile, hash, file;
|
| ︙ | ︙ | |||
605 606 607 608 609 610 611 | ** in "..." or '...' so that it may contain commas. If a file matches both ** --include and --exclude then it is excluded. ** ** If OUTPUTFILE is an empty string or "/dev/null" then no tarball is ** actually generated. This feature can be used in combination with ** the --list option to get a list of the filenames that would be in the ** tarball had it actually been generated. Note that --list shows only | | | 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 | ** in "..." or '...' so that it may contain commas. If a file matches both ** --include and --exclude then it is excluded. ** ** If OUTPUTFILE is an empty string or "/dev/null" then no tarball is ** actually generated. This feature can be used in combination with ** the --list option to get a list of the filenames that would be in the ** tarball had it actually been generated. Note that --list shows only ** filenames. "tar tzf" shows both filenames and subdirectory names. ** ** Options: ** -X|--exclude GLOBLIST Comma-separated list of GLOBs of files to exclude ** --include GLOBLIST Comma-separated list of GLOBs of files to include ** -l|--list Show archive content on stdout ** --name DIRECTORYNAME The name of the top-level directory in the archive ** -R REPOSITORY Specify a Fossil repository |
| ︙ | ︙ | |||
674 675 676 677 678 679 680 |
blob_reset(&tarball);
}
}
/*
** Check to see if the input string is of the form:
**
| | | 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 |
blob_reset(&tarball);
}
}
/*
** Check to see if the input string is of the form:
**
** check-in-name/filename.ext
**
** In other words, check to see if the input contains a single '/'
** character that separates a valid check-in name from a filename.
**
** If the condition is true, return the check-in name and set the
** input string to be the filename.
**
|
| ︙ | ︙ | |||
702 703 704 705 706 707 708 | zName[n] = 0; *pzName = fossil_strdup(&zName[n+1]); return zName; } /* ** WEBPAGE: tarball | | | | | | | | | | > > > | | | | < | | > | | | 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 | zName[n] = 0; *pzName = fossil_strdup(&zName[n+1]); return zName; } /* ** WEBPAGE: tarball ** URL: /tarball/[VERSION/]NAME.tar.gz ** ** Generate a compressed tarball for the check-in specified by VERSION. ** The tarball is called NAME.tar.gz and has a top-level directory called ** NAME. ** ** The optional VERSION element defaults to "trunk" per the r= rules below. ** All of the following URLs are equivalent: ** ** /tarball/release/xyz.tar.gz ** /tarball?r=release&name=xyz.tar.gz ** /tarball/xyz.tar.gz?r=release ** /tarball?name=release/xyz.tar.gz ** ** Query parameters: ** ** name=[CKIN/]NAME The optional CKIN component of the name= parameter ** identifies the check-in from which the tarball is ** constructed. If CKIN is omitted and there is no ** r= query parameter, then use "trunk". NAME is the ** name of the download file. The top-level directory ** in the generated tarball is called by NAME with the ** file extension removed. ** ** r=TAG TAG identifies the check-in that is turned into a ** compressed tarball. The default value is "trunk". ** If r= is omitted and if the name= query parameter ** contains one "/" character then the of part the ** name= value before the / becomes the TAG and the ** part of the name= value after the / is the download ** filename. If no check-in is specified by either ** name= or r=, then "trunk" is used. ** ** in=PATTERN Only include files that match the comma-separate ** list of GLOB patterns in PATTERN, as with ex= ** ** ex=PATTERN Omit any file that match PATTERN. PATTERN is a ** comma-separated list of GLOB patterns, where each ** pattern can optionally be quoted using ".." or '..'. |
| ︙ | ︙ | |||
803 804 805 806 807 808 809 |
if( zInclude ) blob_appendf(&cacheKey, ",in=%Q", zInclude);
if( zExclude ) blob_appendf(&cacheKey, ",ex=%Q", zExclude);
zKey = blob_str(&cacheKey);
etag_check(ETAG_HASH, zKey);
if( P("debug")!=0 ){
style_header("Tarball Generator Debug Screen");
| | | | | | > | 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 |
if( zInclude ) blob_appendf(&cacheKey, ",in=%Q", zInclude);
if( zExclude ) blob_appendf(&cacheKey, ",ex=%Q", zExclude);
zKey = blob_str(&cacheKey);
etag_check(ETAG_HASH, zKey);
if( P("debug")!=0 ){
style_header("Tarball Generator Debug Screen");
@ zName = "%h(zName)"<br>
@ rid = %d(rid)<br>
if( zInclude ){
@ zInclude = "%h(zInclude)"<br>
}
if( zExclude ){
@ zExclude = "%h(zExclude)"<br>
}
@ zKey = "%h(zKey)"
style_finish_page();
return;
}
if( referred_from_login() ){
style_header("Tarball Download");
@ <form action='%R/tarball/%h(zName).tar.gz'>
cgi_query_parameters_to_hidden();
@ <p>Tarball named <b>%h(zName).tar.gz</b> holding the content
@ of check-in <b>%h(zRid)</b>:
@ <input type="submit" value="Download">
@ </form>
style_finish_page();
return;
}
cgi_check_for_malice();
blob_zero(&tarball);
if( cache_read(&tarball, zKey)==0 ){
tarball_of_checkin(rid, &tarball, zName, pInclude, pExclude, 0);
cache_write(&tarball, zKey);
}
glob_free(pInclude);
glob_free(pExclude);
|
| ︙ | ︙ |
Changes to src/terminal.c.
| ︙ | ︙ | |||
20 21 22 23 24 25 26 27 28 29 30 31 32 33 | #include "config.h" #include "terminal.h" #include <assert.h> #ifdef _WIN32 # include <windows.h> #else #include <sys/ioctl.h> #include <stdio.h> #include <unistd.h> #endif | > > > | 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | #include "config.h" #include "terminal.h" #include <assert.h> #ifdef _WIN32 # include <windows.h> #else #ifdef __EXTENSIONS__ #include <termio.h> #endif #include <sys/ioctl.h> #include <stdio.h> #include <unistd.h> #endif |
| ︙ | ︙ |
Changes to src/th.c.
| ︙ | ︙ | |||
243 244 245 246 247 248 249 |
Buffer *pBuffer,
const char *zAdd,
int nAdd
){
if( pBuffer->nBuf+nAdd > pBuffer->nBufAlloc ){
thBufferWriteResize(interp, pBuffer, zAdd, nAdd);
}else{
| > | > < | 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 |
Buffer *pBuffer,
const char *zAdd,
int nAdd
){
if( pBuffer->nBuf+nAdd > pBuffer->nBufAlloc ){
thBufferWriteResize(interp, pBuffer, zAdd, nAdd);
}else{
if( pBuffer->zBuf ){
memcpy(pBuffer->zBuf + pBuffer->nBuf, zAdd, nAdd);
}
pBuffer->nBuf += nAdd;
}
}
#define thBufferWrite(a,b,c,d) thBufferWriteFast(a,b,(const char *)c,d)
/*
** Add a single character to a buffer
*/
|
| ︙ | ︙ | |||
851 852 853 854 855 856 857 |
zWord = Th_GetResult(interp, &nWord);
thBufferWrite(interp, &strbuf, zWord, nWord);
thBufferAddChar(interp, &strbuf, 0);
thBufferWrite(interp, &lenbuf, &nWord, sizeof(int));
nCount++;
}
}
| | | 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 |
zWord = Th_GetResult(interp, &nWord);
thBufferWrite(interp, &strbuf, zWord, nWord);
thBufferAddChar(interp, &strbuf, 0);
thBufferWrite(interp, &lenbuf, &nWord, sizeof(int));
nCount++;
}
}
assert((int)(lenbuf.nBuf/sizeof(int))==nCount);
assert((pazElem && panElem) || (!pazElem && !panElem));
if( pazElem && rc==TH_OK ){
int i;
char *zElem;
int *anElem;
char **azElem = Th_Malloc(interp,
|
| ︙ | ︙ | |||
1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 |
if( !pValue->zData ){
Th_ErrorMessage(interp, "no such variable:", zVar, nVar);
return TH_ERROR;
}
return Th_SetResult(interp, pValue->zData, pValue->nData);
}
/*
** Return true if variable (zVar, nVar) exists.
*/
int Th_ExistsVar(Th_Interp *interp, const char *zVar, int nVar){
Th_Variable *pValue = thFindValue(interp, zVar, nVar, 0, 1, 1, 0);
return pValue && (pValue->zData || pValue->pHash);
| > > > > > > > > > > > > > > > > > > > > > | 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 |
if( !pValue->zData ){
Th_ErrorMessage(interp, "no such variable:", zVar, nVar);
return TH_ERROR;
}
return Th_SetResult(interp, pValue->zData, pValue->nData);
}
/*
** If interp has a variable with the given name, its value is returned
** and its length is returned via *nOut if nOut is not NULL. If
** interp has no such var then NULL is returned without setting any
** error state and *nOut, if not NULL, is set to -1. The returned value
** is owned by the interpreter and may be invalidated the next time
** the interpreter is modified.
*/
const char * Th_MaybeGetVar(Th_Interp *interp, const char *zVarName,
int *nOut){
Th_Variable *pValue;
pValue = thFindValue(interp, zVarName, -1, 0, 0, 1, 0);
if( !pValue || !pValue->zData ){
if( nOut!=0 ) *nOut = -1;
return NULL;
}
if( nOut!=0 ) *nOut = pValue->nData;
return pValue->zData;
}
/*
** Return true if variable (zVar, nVar) exists.
*/
int Th_ExistsVar(Th_Interp *interp, const char *zVar, int nVar){
Th_Variable *pValue = thFindValue(interp, zVar, nVar, 0, 1, 1, 0);
return pValue && (pValue->zData || pValue->pHash);
|
| ︙ | ︙ | |||
1748 1749 1750 1751 1752 1753 1754 |
int *pnList, /* IN/OUT: Current length of *pzList */
const char *zElem, /* Data to append */
int nElem /* Length of nElem */
){
Buffer output;
int i;
| | | | | > > > > > > > > > | 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 1806 1807 1808 1809 1810 1811 1812 1813 |
int *pnList, /* IN/OUT: Current length of *pzList */
const char *zElem, /* Data to append */
int nElem /* Length of nElem */
){
Buffer output;
int i;
int hasSpecialChar = 0; /* Whitespace or {}[]'" */
int hasEscapeChar = 0; /* '}' without matching '{' to the left or a '\\' */
int nBrace = 0;
output.zBuf = *pzList;
output.nBuf = *pnList;
output.nBufAlloc = output.nBuf;
if( nElem<0 ){
nElem = th_strlen(zElem);
}
if( output.nBuf>0 ){
thBufferAddChar(interp, &output, ' ');
}
for(i=0; i<nElem; i++){
char c = zElem[i];
if( th_isspecial(c) ) hasSpecialChar = 1;
if( c=='\\' ){ hasEscapeChar = 1; break; }
if( c=='{' ) nBrace++;
if( c=='}' ){
if( nBrace==0 ){
/* A closing brace that does not have a matching open brace to
** its left needs to be excaped. See ticket 4d73b4a2258a78e2 */
hasEscapeChar = 1;
break;
}else{
nBrace--;
}
}
}
if( nElem==0 || (!hasEscapeChar && hasSpecialChar && nBrace==0) ){
thBufferAddChar(interp, &output, '{');
thBufferWrite(interp, &output, zElem, nElem);
thBufferAddChar(interp, &output, '}');
}else{
|
| ︙ | ︙ | |||
2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 |
/*
** Set the result of the interpreter to the th1 representation of
** the integer iVal and return TH_OK.
*/
int Th_SetResultInt(Th_Interp *interp, int iVal){
int isNegative = 0;
char zBuf[32];
char *z = &zBuf[32];
if( iVal<0 ){
isNegative = 1;
| > | | | | | 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 |
/*
** Set the result of the interpreter to the th1 representation of
** the integer iVal and return TH_OK.
*/
int Th_SetResultInt(Th_Interp *interp, int iVal){
int isNegative = 0;
unsigned int uVal = iVal;
char zBuf[32];
char *z = &zBuf[32];
if( iVal<0 ){
isNegative = 1;
uVal = iVal * -1;
}
*(--z) = '\0';
*(--z) = (char)(48+(uVal%10));
while( (uVal = (uVal/10))>0 ){
*(--z) = (char)(48+(uVal%10));
assert(z>zBuf);
}
if( isNegative ){
*(--z) = '-';
}
return Th_SetResult(interp, z, -1);
|
| ︙ | ︙ |
Changes to src/th.h.
| ︙ | ︙ | |||
54 55 56 57 58 59 60 61 62 63 64 65 66 67 | int Th_ExistsVar(Th_Interp *, const char *, int); int Th_ExistsArrayVar(Th_Interp *, const char *, int); int Th_GetVar(Th_Interp *, const char *, int); int Th_SetVar(Th_Interp *, const char *, int, const char *, int); int Th_LinkVar(Th_Interp *, const char *, int, int, const char *, int); int Th_UnsetVar(Th_Interp *, const char *, int); typedef int (*Th_CommandProc)(Th_Interp *, void *, int, const char **, int *); /* ** Register new commands. */ int Th_CreateCommand( Th_Interp *interp, | > > > > > > > > > > > > > | 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 |
int Th_ExistsVar(Th_Interp *, const char *, int);
int Th_ExistsArrayVar(Th_Interp *, const char *, int);
int Th_GetVar(Th_Interp *, const char *, int);
int Th_SetVar(Th_Interp *, const char *, int, const char *, int);
int Th_LinkVar(Th_Interp *, const char *, int, int, const char *, int);
int Th_UnsetVar(Th_Interp *, const char *, int);
/*
** If interp has a variable with the given name, its value is returned
** and its length is returned via *nOut if nOut is not NULL. If
** interp has no such var then NULL is returned without setting any
** error state and *nOut, if not NULL, is set to 0. The returned value
** is owned by the interpreter and may be invalidated the next time
** the interpreter is modified.
**
** zVarName must be NUL-terminated.
*/
const char * Th_MaybeGetVar(Th_Interp *interp, const char *zVarName,
int *nOut);
typedef int (*Th_CommandProc)(Th_Interp *, void *, int, const char **, int *);
/*
** Register new commands.
*/
int Th_CreateCommand(
Th_Interp *interp,
|
| ︙ | ︙ |
Changes to src/th_lang.c.
| ︙ | ︙ | |||
1368 1369 1370 1371 1372 1373 1374 |
static int breakpoint_command(
Th_Interp *interp,
void *ctx,
int argc,
const char **argv,
int *argl
){
| | | | 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 |
static int breakpoint_command(
Th_Interp *interp,
void *ctx,
int argc,
const char **argv,
int *argl
){
static unsigned int cnt = 0;
if( (cnt++)==0xffffffff ) printf("too many TH3 breakpoints\n");
return TH_OK;
}
/*
** Register the built-in th1 language commands with interpreter interp.
** Usually this is called soon after interpreter creation.
*/
|
| ︙ | ︙ |
Changes to src/th_main.c.
| ︙ | ︙ | |||
154 155 156 157 158 159 160 | } /* ** - adopted from ls_cmd_rev in checkin.c ** - adopted commands/error handling for usage within th1 ** - interface adopted to allow result creation as TH1 List ** | | | 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 | } /* ** - adopted from ls_cmd_rev in checkin.c ** - adopted commands/error handling for usage within th1 ** - interface adopted to allow result creation as TH1 List ** ** Takes a check-in identifier in zRev and an optiona glob pattern in zGLOB ** as parameter returns a TH list in pzList,pnList with filenames matching ** glob pattern with the checking */ static void dir_cmd_rev( Th_Interp *interp, char **pzList, int *pnList, |
| ︙ | ︙ | |||
288 289 290 291 292 293 294 |
){
int rc;
if( argc<2 || argc>3 ){
return Th_WrongNumArgs(interp, "enable_output [LABEL] BOOLEAN");
}
rc = Th_ToInt(interp, argv[argc-1], argl[argc-1], &enableOutput);
if( g.thTrace ){
| | | 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 |
){
int rc;
if( argc<2 || argc>3 ){
return Th_WrongNumArgs(interp, "enable_output [LABEL] BOOLEAN");
}
rc = Th_ToInt(interp, argv[argc-1], argl[argc-1], &enableOutput);
if( g.thTrace ){
Th_Trace("enable_output {%.*s} -> %d<br>\n", argl[1],argv[1],enableOutput);
}
return rc;
}
/*
** TH1 command: enable_htmlify ?BOOLEAN?
**
|
| ︙ | ︙ | |||
318 319 320 321 322 323 324 |
return Th_WrongNumArgs(interp,
"enable_htmlify [TRACE_LABEL] ?BOOLEAN?");
}
buul = (TH_INIT_NO_ENCODE & g.th1Flags) ? 0 : 1;
Th_SetResultInt(g.interp, buul);
if(argc>1){
if( g.thTrace ){
| | | 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 |
return Th_WrongNumArgs(interp,
"enable_htmlify [TRACE_LABEL] ?BOOLEAN?");
}
buul = (TH_INIT_NO_ENCODE & g.th1Flags) ? 0 : 1;
Th_SetResultInt(g.interp, buul);
if(argc>1){
if( g.thTrace ){
Th_Trace("enable_htmlify {%.*s} -> %d<br>\n",
argl[1],argv[1],buul);
}
rc = Th_ToInt(interp, argv[argc-1], argl[argc-1], &buul);
if(!rc){
if(buul){
g.th1Flags &= ~TH_INIT_NO_ENCODE;
}else{
|
| ︙ | ︙ | |||
410 411 412 413 414 415 416 |
/*
** error-reporting counterpart of sendText().
*/
static void sendError(Blob * pOut, const char *z, int n, int forceCgi){
int savedEnable = enableOutput;
enableOutput = 1;
if( forceCgi || g.cgiOutput ){
| | | 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 |
/*
** error-reporting counterpart of sendText().
*/
static void sendError(Blob * pOut, const char *z, int n, int forceCgi){
int savedEnable = enableOutput;
enableOutput = 1;
if( forceCgi || g.cgiOutput ){
sendText(pOut, "<hr><p class=\"thmainError\">", -1, 0);
}
sendText(pOut,"ERROR: ", -1, 0);
sendText(pOut,(char*)z, n, 1);
sendText(pOut,forceCgi || g.cgiOutput ? "</p>" : "\n", -1, 0);
enableOutput = savedEnable;
}
|
| ︙ | ︙ | |||
603 604 605 606 607 608 609 |
int argc,
const char **argv,
int *argl
){
if( argc!=1 ){
return Th_WrongNumArgs(interp, "verifyCsrf");
}
| | > > | 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 |
int argc,
const char **argv,
int *argl
){
if( argc!=1 ){
return Th_WrongNumArgs(interp, "verifyCsrf");
}
if( !cgi_csrf_safe(2) ){
fossil_fatal("possible CSRF attack");
}
return TH_OK;
}
/*
** TH1 command: verifyLogin
**
** Returns non-zero if the specified user name and password represent a
|
| ︙ | ︙ | |||
789 790 791 792 793 794 795 |
for(i=1; rc==1 && i<argc; i++){
if( g.thTrace ){
Th_ListAppend(interp, &zCapList, &nCapList, argv[i], argl[i]);
}
rc = login_has_capability((char*)argv[i],argl[i],*(int*)p);
}
if( g.thTrace ){
| | | 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 |
for(i=1; rc==1 && i<argc; i++){
if( g.thTrace ){
Th_ListAppend(interp, &zCapList, &nCapList, argv[i], argl[i]);
}
rc = login_has_capability((char*)argv[i],argl[i],*(int*)p);
}
if( g.thTrace ){
Th_Trace("[%s %#h] => %d<br>\n", argv[0], nCapList, zCapList, rc);
Th_Free(interp, zCapList);
}
Th_SetResultInt(interp, rc);
return TH_OK;
}
/*
|
| ︙ | ︙ | |||
906 907 908 909 910 911 912 |
case 't': match |= searchCap & SRCH_TKT; break;
case 'w': match |= searchCap & SRCH_WIKI; break;
}
}
if( !match ) rc = 0;
}
if( g.thTrace ){
| | | 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 |
case 't': match |= searchCap & SRCH_TKT; break;
case 'w': match |= searchCap & SRCH_WIKI; break;
}
}
if( !match ) rc = 0;
}
if( g.thTrace ){
Th_Trace("[searchable %#h] => %d<br>\n", argl[1], argv[1], rc);
}
Th_SetResultInt(interp, rc);
return TH_OK;
}
/*
** TH1 command: hasfeature STRING
|
| ︙ | ︙ | |||
1025 1026 1027 1028 1029 1030 1031 |
rc = 1;
}
#endif
else if( 0 == fossil_strnicmp( zArg, "markdown\0", 9 ) ){
rc = 1;
}
if( g.thTrace ){
| | | 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 |
rc = 1;
}
#endif
else if( 0 == fossil_strnicmp( zArg, "markdown\0", 9 ) ){
rc = 1;
}
if( g.thTrace ){
Th_Trace("[hasfeature %#h] => %d<br>\n", argl[1], zArg, rc);
}
Th_SetResultInt(interp, rc);
return TH_OK;
}
/*
|
| ︙ | ︙ | |||
1056 1057 1058 1059 1060 1061 1062 |
}
#if defined(FOSSIL_ENABLE_TCL)
if( g.tcl.interp ){
rc = 1;
}
#endif
if( g.thTrace ){
| | | 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 |
}
#if defined(FOSSIL_ENABLE_TCL)
if( g.tcl.interp ){
rc = 1;
}
#endif
if( g.thTrace ){
Th_Trace("[tclReady] => %d<br>\n", rc);
}
Th_SetResultInt(interp, rc);
return TH_OK;
}
/*
|
| ︙ | ︙ | |||
1085 1086 1087 1088 1089 1090 1091 |
if( argc!=2 ){
return Th_WrongNumArgs(interp, "anycap STRING");
}
for(i=0; rc==0 && i<argl[1]; i++){
rc = login_has_capability((char*)&argv[1][i],1,0);
}
if( g.thTrace ){
| | | 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 |
if( argc!=2 ){
return Th_WrongNumArgs(interp, "anycap STRING");
}
for(i=0; rc==0 && i<argl[1]; i++){
rc = login_has_capability((char*)&argv[1][i],1,0);
}
if( g.thTrace ){
Th_Trace("[anycap %#h] => %d<br>\n", argl[1], argv[1], rc);
}
Th_SetResultInt(interp, rc);
return TH_OK;
}
/*
** TH1 command: combobox NAME TEXT-LIST NUMLINES
|
| ︙ | ︙ | |||
1265 1266 1267 1268 1269 1270 1271 | Th_SetResult(interp, g.zRepositoryName, -1); return TH_OK; } /* ** TH1 command: checkout ?BOOLEAN? ** | | | | 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 |
Th_SetResult(interp, g.zRepositoryName, -1);
return TH_OK;
}
/*
** TH1 command: checkout ?BOOLEAN?
**
** Return the fully qualified directory name of the current check-out or an
** empty string if it is not available. Optionally, it will attempt to find
** the current check-out, opening the configuration ("user") database and the
** repository as necessary, if the boolean argument is non-zero.
*/
static int checkoutCmd(
Th_Interp *interp,
void *p,
int argc,
const char **argv,
|
| ︙ | ︙ | |||
1320 1321 1322 1323 1324 1325 1326 | /* ** TH1 command: globalState NAME ?DEFAULT? ** ** Returns a string containing the value of the specified global state ** variable -OR- the specified default value. Currently, the supported ** items are: ** | | | 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 | /* ** TH1 command: globalState NAME ?DEFAULT? ** ** Returns a string containing the value of the specified global state ** variable -OR- the specified default value. Currently, the supported ** items are: ** ** "checkout" = The active local check-out directory, if any. ** "configuration" = The active configuration database file name, ** if any. ** "executable" = The fully qualified executable file name. ** "flags" = The TH1 initialization flags. ** "log" = The error log file name, if any. ** "repository" = The active local repository file name, if ** any. |
| ︙ | ︙ | |||
1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 |
Th_SetResult(interp, 0, 0);
return TH_OK;
}else{
Th_SetResult(interp, "repository unavailable", -1);
return TH_ERROR;
}
}
/*
** TH1 command: builtin_request_js NAME
**
** Request that the built-in javascript file called NAME be added to the
** end of the generated page.
**
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 |
Th_SetResult(interp, 0, 0);
return TH_OK;
}else{
Th_SetResult(interp, "repository unavailable", -1);
return TH_ERROR;
}
}
/*
** TH1 command: submenu link LABEL URL
**
** Add a hyperlink to the submenu.
*/
static int submenuCmd(
Th_Interp *interp,
void *p,
int argc,
const char **argv,
int *argl
){
if( argc!=4 || memcmp(argv[1],"link",5)!=0 ){
return Th_WrongNumArgs(interp, "submenu link LABEL URL");
}
if( argl[2]==0 ){
Th_SetResult(interp, "link's LABEL is empty", -1);
return TH_ERROR;
}
if( argl[3]==0 ){
Th_SetResult(interp, "link's URL is empty", -1);
return TH_ERROR;
}
/*
** Label and URL are unescaped because it is expected that
** style_finish_page() provides propper escaping via %h format.
*/
style_submenu_element( fossil_strdup(argv[2]), "%s", argv[3] );
Th_SetResult(interp, 0, 0);
return TH_OK;
}
/*
** TH1 command: builtin_request_js NAME
**
** Request that the built-in javascript file called NAME be added to the
** end of the generated page.
**
|
| ︙ | ︙ | |||
1815 1816 1817 1818 1819 1820 1821 |
return Th_WrongNumArgs(interp, "repository ?BOOLEAN?");
}
if( argc==2 ){
if( Th_ToInt(interp, argv[1], argl[1], &n) ){
return TH_ERROR;
}
if( n<1 ) n = 1;
| | | 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 |
return Th_WrongNumArgs(interp, "repository ?BOOLEAN?");
}
if( argc==2 ){
if( Th_ToInt(interp, argv[1], argl[1], &n) ){
return TH_ERROR;
}
if( n<1 ) n = 1;
if( n>(int)sizeof(aRand) ) n = sizeof(aRand);
}else{
n = 10;
}
sqlite3_randomness(n, aRand);
encode16(aRand, zOut, n);
Th_SetResult(interp, (const char *)zOut, -1);
return TH_OK;
|
| ︙ | ︙ | |||
1919 1920 1921 1922 1923 1924 1925 |
const char *zCol = sqlite3_column_name(pStmt, i);
int szCol = th_strlen(zCol);
const char *zVal = (const char*)sqlite3_column_text(pStmt, i);
int szVal = sqlite3_column_bytes(pStmt, i);
Th_SetVar(interp, zCol, szCol, zVal, szVal);
}
if( g.thTrace ){
| | | | 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 |
const char *zCol = sqlite3_column_name(pStmt, i);
int szCol = th_strlen(zCol);
const char *zVal = (const char*)sqlite3_column_text(pStmt, i);
int szVal = sqlite3_column_bytes(pStmt, i);
Th_SetVar(interp, zCol, szCol, zVal, szVal);
}
if( g.thTrace ){
Th_Trace("query_eval {<pre>%#h</pre>}<br>\n", argl[2], argv[2]);
}
res = Th_Eval(interp, 0, argv[2], argl[2]);
if( g.thTrace ){
int nTrRes;
char *zTrRes = (char*)Th_GetResult(g.interp, &nTrRes);
Th_Trace("[query_eval] => %h {%#h}<br>\n",
Th_ReturnCodeName(res, 0), nTrRes, zTrRes);
}
if( res==TH_BREAK || res==TH_CONTINUE ) res = TH_OK;
}
rc = sqlite3_finalize(pStmt);
if( rc!=SQLITE_OK ){
if( noComplain ) return TH_OK;
|
| ︙ | ︙ | |||
1979 1980 1981 1982 1983 1984 1985 |
Th_ErrorMessage(interp, "no value for setting \"", argv[nArg], -1);
rc = TH_ERROR;
}else{
Th_SetResult(interp, 0, 0);
rc = TH_OK;
}
if( g.thTrace ){
| | | 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 |
Th_ErrorMessage(interp, "no value for setting \"", argv[nArg], -1);
rc = TH_ERROR;
}else{
Th_SetResult(interp, 0, 0);
rc = TH_OK;
}
if( g.thTrace ){
Th_Trace("[setting %s%#h] => %d<br>\n", strict ? "strict " : "",
argl[nArg], argv[nArg], rc);
}
return rc;
}
/*
** TH1 command: glob_match ?-one? ?--? patternList string
|
| ︙ | ︙ | |||
2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 |
{"repository", repositoryCmd, 0},
{"searchable", searchableCmd, 0},
{"setParameter", setParameterCmd, 0},
{"setting", settingCmd, 0},
{"styleFooter", styleFooterCmd, 0},
{"styleHeader", styleHeaderCmd, 0},
{"styleScript", styleScriptCmd, 0},
{"tclReady", tclReadyCmd, 0},
{"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 ){
| > | | | 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 |
{"repository", repositoryCmd, 0},
{"searchable", searchableCmd, 0},
{"setParameter", setParameterCmd, 0},
{"setting", settingCmd, 0},
{"styleFooter", styleFooterCmd, 0},
{"styleHeader", styleHeaderCmd, 0},
{"styleScript", styleScriptCmd, 0},
{"submenu", submenuCmd, 0},
{"tclReady", tclReadyCmd, 0},
{"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 ){
/*
** This function uses several settings which may be defined in the
** repository and/or the global configuration. Since the caller
** passed a non-zero value for the needConfig parameter, make sure
** the necessary database connections are open prior to continuing.
*/
Th_OpenConfig(!noRepo);
}
if( forceReset || forceTcl || g.interp==0 ){
int created = 0;
int i;
if( g.interp==0 ){
Th_Vtab *pVtab = 0;
#if defined(TH_MEMDEBUG)
if( fossil_getenv("TH1_DELETE_INTERP")!=0 ){
pVtab = &vtab;
if( g.thTrace ){
Th_Trace("th1-init MEMDEBUG ENABLED<br>\n");
}
}
#endif
g.interp = Th_CreateInterp(pVtab);
created = 1;
}
if( forceReset || created ){
|
| ︙ | ︙ | |||
2400 2401 2402 2403 2404 2405 2406 |
if( rc==TH_ERROR ){
int nResult = 0;
char *zResult = (char*)Th_GetResult(g.interp, &nResult);
sendError(0,zResult, nResult, 0);
}
}
if( g.thTrace ){
| | | | | 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 |
if( rc==TH_ERROR ){
int nResult = 0;
char *zResult = (char*)Th_GetResult(g.interp, &nResult);
sendError(0,zResult, nResult, 0);
}
}
if( g.thTrace ){
Th_Trace("th1-setup {%h} => %h<br>\n", g.th1Setup,
Th_ReturnCodeName(rc, 0));
}
}
g.th1Flags &= ~TH_INIT_MASK;
g.th1Flags |= (flags & TH_INIT_MASK);
}
/*
** Store a string value in a variable in the interpreter if the variable
** does not already exist.
*/
void Th_MaybeStore(const char *zName, const char *zValue){
Th_FossilInit(TH_INIT_DEFAULT);
if( zValue && !Th_ExistsVar(g.interp, zName, -1) ){
if( g.thTrace ){
Th_Trace("maybe_set %h {%h}<br>\n", zName, zValue);
}
Th_SetVar(g.interp, zName, -1, zValue, strlen(zValue));
}
}
/*
** Store a string value in a variable in the interpreter.
*/
void Th_Store(const char *zName, const char *zValue){
Th_FossilInit(TH_INIT_DEFAULT);
if( zValue ){
if( g.thTrace ){
Th_Trace("set %h {%h}<br>\n", zName, zValue);
}
Th_SetVar(g.interp, zName, -1, zValue, strlen(zValue));
}
}
/*
** Appends an element to a TH1 list value. This function is called by the
|
| ︙ | ︙ | |||
2472 2473 2474 2475 2476 2477 2478 |
char *zValue = 0;
int nValue = 0;
int i;
for(i=0; i<nList; i++){
Th_ListAppend(g.interp, &zValue, &nValue, pzList[i], -1);
}
if( g.thTrace ){
| | | | 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 |
char *zValue = 0;
int nValue = 0;
int i;
for(i=0; i<nList; i++){
Th_ListAppend(g.interp, &zValue, &nValue, pzList[i], -1);
}
if( g.thTrace ){
Th_Trace("set %h {%h}<br>\n", zName, zValue);
}
Th_SetVar(g.interp, zName, -1, zValue, nValue);
Th_Free(g.interp, zValue);
}
}
/*
** Store an integer value in a variable in the interpreter.
*/
void Th_StoreInt(const char *zName, int iValue){
Blob value;
char *zValue;
Th_FossilInit(TH_INIT_DEFAULT);
blob_zero(&value);
blob_appendf(&value, "%d", iValue);
zValue = blob_str(&value);
if( g.thTrace ){
Th_Trace("set %h {%h}<br>\n", zName, zValue);
}
Th_SetVar(g.interp, zName, -1, zValue, strlen(zValue));
blob_reset(&value);
}
/*
** Unset a variable.
|
| ︙ | ︙ | |||
2638 2639 2640 2641 2642 2643 2644 |
** If the script returned TH_ERROR (e.g. the "command_hook" TH1 command does
** not exist because commands are not being hooked), return TH_OK because we
** do not want to skip executing essential commands unless the called command
** (i.e. "command_hook") explicitly forbids this by successfully returning
** TH_BREAK or TH_CONTINUE.
*/
if( g.thTrace ){
| | | 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 |
** If the script returned TH_ERROR (e.g. the "command_hook" TH1 command does
** not exist because commands are not being hooked), return TH_OK because we
** do not want to skip executing essential commands unless the called command
** (i.e. "command_hook") explicitly forbids this by successfully returning
** TH_BREAK or TH_CONTINUE.
*/
if( g.thTrace ){
Th_Trace("[command_hook {%h}] => %h<br>\n", zName,
Th_ReturnCodeName(rc, 0));
}
/*
** Does our call to Th_FossilInit() result in opening a database? If so,
** clean it up now. This is very important because some commands do not
** expect the repository and/or the configuration ("user") database to be
** open prior to their own code doing so.
|
| ︙ | ︙ | |||
2670 2671 2672 2673 2674 2675 2676 |
if( !Th_AreHooksEnabled() ) return rc;
Th_FossilInit(TH_INIT_HOOK);
Th_Store("cmd_name", zName);
Th_StoreList("cmd_args", g.argv, g.argc);
Th_StoreInt("cmd_flags", cmdFlags);
rc = Th_Eval(g.interp, 0, "command_notify", -1);
if( g.thTrace ){
| | | 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 |
if( !Th_AreHooksEnabled() ) return rc;
Th_FossilInit(TH_INIT_HOOK);
Th_Store("cmd_name", zName);
Th_StoreList("cmd_args", g.argv, g.argc);
Th_StoreInt("cmd_flags", cmdFlags);
rc = Th_Eval(g.interp, 0, "command_notify", -1);
if( g.thTrace ){
Th_Trace("[command_notify {%h}] => %h<br>\n", zName,
Th_ReturnCodeName(rc, 0));
}
/*
** Does our call to Th_FossilInit() result in opening a database? If so,
** clean it up now. This is very important because some commands do not
** expect the repository and/or the configuration ("user") database to be
** open prior to their own code doing so.
|
| ︙ | ︙ | |||
2725 2726 2727 2728 2729 2730 2731 |
** If the script returned TH_ERROR (e.g. the "webpage_hook" TH1 command does
** not exist because commands are not being hooked), return TH_OK because we
** do not want to skip processing essential web pages unless the called
** command (i.e. "webpage_hook") explicitly forbids this by successfully
** returning TH_BREAK or TH_CONTINUE.
*/
if( g.thTrace ){
| | | 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 |
** If the script returned TH_ERROR (e.g. the "webpage_hook" TH1 command does
** not exist because commands are not being hooked), return TH_OK because we
** do not want to skip processing essential web pages unless the called
** command (i.e. "webpage_hook") explicitly forbids this by successfully
** returning TH_BREAK or TH_CONTINUE.
*/
if( g.thTrace ){
Th_Trace("[webpage_hook {%h}] => %h<br>\n", zName,
Th_ReturnCodeName(rc, 0));
}
/*
** Does our call to Th_FossilInit() result in opening a database? If so,
** clean it up now. This is very important because some commands do not
** expect the repository and/or the configuration ("user") database to be
** open prior to their own code doing so.
|
| ︙ | ︙ | |||
2757 2758 2759 2760 2761 2762 2763 |
if( !Th_AreHooksEnabled() ) return rc;
Th_FossilInit(TH_INIT_HOOK);
Th_Store("web_name", zName);
Th_StoreList("web_args", g.argv, g.argc);
Th_StoreInt("web_flags", cmdFlags);
rc = Th_Eval(g.interp, 0, "webpage_notify", -1);
if( g.thTrace ){
| | | 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 |
if( !Th_AreHooksEnabled() ) return rc;
Th_FossilInit(TH_INIT_HOOK);
Th_Store("web_name", zName);
Th_StoreList("web_args", g.argv, g.argc);
Th_StoreInt("web_flags", cmdFlags);
rc = Th_Eval(g.interp, 0, "webpage_notify", -1);
if( g.thTrace ){
Th_Trace("[webpage_notify {%h}] => %h<br>\n", zName,
Th_ReturnCodeName(rc, 0));
}
/*
** Does our call to Th_FossilInit() result in opening a database? If so,
** clean it up now. This is very important because some commands do not
** expect the repository and/or the configuration ("user") database to be
** open prior to their own code doing so.
|
| ︙ | ︙ | |||
2840 2841 2842 2843 2844 2845 2846 |
zResult = (char*)Th_GetResult(g.interp, &n);
sendText(pOut,(char*)zResult, n, encode);
}else if( z[i]=='<' && isBeginScriptTag(&z[i]) ){
sendText(pOut,z, i, 0);
z += i+5;
for(i=0; z[i] && (z[i]!='<' || !isEndScriptTag(&z[i])); i++){}
if( g.thTrace ){
| | | | 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 |
zResult = (char*)Th_GetResult(g.interp, &n);
sendText(pOut,(char*)zResult, n, encode);
}else if( z[i]=='<' && isBeginScriptTag(&z[i]) ){
sendText(pOut,z, i, 0);
z += i+5;
for(i=0; z[i] && (z[i]!='<' || !isEndScriptTag(&z[i])); i++){}
if( g.thTrace ){
Th_Trace("render_eval {<pre>%#h</pre>}<br>\n", i, z);
}
rc = Th_Eval(g.interp, 0, (const char*)z, i);
if( g.thTrace ){
int nTrRes;
char *zTrRes = (char*)Th_GetResult(g.interp, &nTrRes);
Th_Trace("[render_eval] => %h {%#h}<br>\n",
Th_ReturnCodeName(rc, 0), nTrRes, zTrRes);
}
if( rc!=TH_OK ) break;
z += i;
if( z[0] ){ z += 6; }
i = 0;
}else{
|
| ︙ | ︙ | |||
2904 2905 2906 2907 2908 2909 2910 | ** Usage: %fossil test-th-render FILE ** ** Read the content of the file named "FILE" as if it were a header or ** footer or ticket rendering script, evaluate it, and show the results ** on standard output. ** ** Options: | < | 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 | ** Usage: %fossil test-th-render FILE ** ** Read the content of the file named "FILE" as if it were a header or ** footer or ticket rendering script, evaluate it, and show the results ** on standard output. ** ** Options: ** --cgi Include a CGI response header in the output ** --http Include an HTTP response header in the output ** --open-config Open the configuration database ** --set-anon-caps Set anonymous login capabilities ** --set-user-caps Set user login capabilities ** --th-trace Trace TH1 execution (for debugging purposes) */ |
| ︙ | ︙ | |||
2954 2955 2956 2957 2958 2959 2960 | ** Usage: %fossil test-th-eval SCRIPT ** ** Evaluate SCRIPT as if it were a header or footer or ticket rendering ** script and show the results on standard output. SCRIPT may be either ** a filename or a string of th1 script code. ** ** Options: | < | 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 | ** Usage: %fossil test-th-eval SCRIPT ** ** Evaluate SCRIPT as if it were a header or footer or ticket rendering ** script and show the results on standard output. SCRIPT may be either ** a filename or a string of th1 script code. ** ** Options: ** --cgi Include a CGI response header in the output ** --http Include an HTTP response header in the output ** --open-config Open the configuration database ** --set-anon-caps Set anonymous login capabilities ** --set-user-caps Set user login capabilities ** --th-trace Trace TH1 execution (for debugging purposes) */ |
| ︙ | ︙ | |||
3015 3016 3017 3018 3019 3020 3021 | ** Usage: %fossil test-th-source FILE ** ** Evaluate the contents of the file named "FILE" as if it were a header ** or footer or ticket rendering script and show the results on standard ** output. ** ** Options: | < | 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 | ** Usage: %fossil test-th-source FILE ** ** Evaluate the contents of the file named "FILE" as if it were a header ** or footer or ticket rendering script and show the results on standard ** output. ** ** Options: ** --cgi Include a CGI response header in the output ** --http Include an HTTP response header in the output ** --open-config Open the configuration database ** --set-anon-caps Set anonymous login capabilities ** --set-user-caps Set user login capabilities ** --th-trace Trace TH1 execution (for debugging purposes) ** --no-print-result Do not output the final result. Use if it |
| ︙ | ︙ | |||
3098 3099 3100 3101 3102 3103 3104 | ** and "web_flags" to appropriate values. ** ** webnotify Executes the TH1 procedure [webpage_notify], after ** setting the TH1 variables "web_name", "web_args", ** and "web_flags" to appropriate values. ** ** Options: | < | 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 |
** and "web_flags" to appropriate values.
**
** webnotify Executes the TH1 procedure [webpage_notify], after
** setting the TH1 variables "web_name", "web_args",
** and "web_flags" to appropriate values.
**
** Options:
** --cgi Include a CGI response header in the output
** --http Include an HTTP response header in the output
** --th-trace Trace TH1 execution (for debugging purposes)
*/
void test_th_hook(void){
int rc = TH_OK;
int nResult = 0;
|
| ︙ | ︙ |
Changes to src/timeline.c.
| ︙ | ︙ | |||
33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
*/
#define TIMELINE_MODE_NONE 0
#define TIMELINE_MODE_BEFORE 1
#define TIMELINE_MODE_AFTER 2
#define TIMELINE_MODE_CHILDREN 3
#define TIMELINE_MODE_PARENTS 4
/*
** Add an appropriate tag to the output if "rid" is unpublished (private)
*/
#define UNPUB_TAG "<em>(unpublished)</em>"
void tag_private_status(int rid){
if( content_is_private(rid) ){
cgi_printf(" %s", UNPUB_TAG);
| > > > > > > > | 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
*/
#define TIMELINE_MODE_NONE 0
#define TIMELINE_MODE_BEFORE 1
#define TIMELINE_MODE_AFTER 2
#define TIMELINE_MODE_CHILDREN 3
#define TIMELINE_MODE_PARENTS 4
#define TIMELINE_FMT_ONELINE \
"%h %c"
#define TIMELINE_FMT_MEDIUM \
"Commit: %h%nDate: %d%nAuthor: %a%nComment: %c"
#define TIMELINE_FMT_FULL \
"Commit: %H%nDate: %d%nAuthor: %a%nComment: %c%n"\
"Branch: %b%nTags: %t%nPhase: %p"
/*
** Add an appropriate tag to the output if "rid" is unpublished (private)
*/
#define UNPUB_TAG "<em>(unpublished)</em>"
void tag_private_status(int rid){
if( content_is_private(rid) ){
cgi_printf(" %s", UNPUB_TAG);
|
| ︙ | ︙ | |||
142 143 144 145 146 147 148 149 150 151 152 153 154 155 |
"SELECT 1 FROM tagxref WHERE rid=$rid AND tagid=%d AND tagtype>0",
TAG_CLOSED);
db_bind_int(&q, "$rid", rid);
res = db_step(&q)==SQLITE_ROW;
db_reset(&q);
return res;
}
/*
** Output a timeline in the web format given a query. The query
** should return these columns:
**
** 0. rid
** 1. artifact hash
| > > > > > > > > > > > > > > > > > > | 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 |
"SELECT 1 FROM tagxref WHERE rid=$rid AND tagid=%d AND tagtype>0",
TAG_CLOSED);
db_bind_int(&q, "$rid", rid);
res = db_step(&q)==SQLITE_ROW;
db_reset(&q);
return res;
}
/*
** Return the text of the unformatted
** forum post given by the RID in the argument.
*/
static void forum_post_content_function(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
int rid = sqlite3_value_int(argv[0]);
Manifest *pPost = manifest_get(rid, CFTYPE_FORUM, 0);
if( pPost ){
sqlite3_result_text(context, pPost->zWiki, -1, SQLITE_TRANSIENT);
manifest_destroy(pPost);
}
}
/*
** Output a timeline in the web format given a query. The query
** should return these columns:
**
** 0. rid
** 1. artifact hash
|
| ︙ | ︙ | |||
180 181 182 183 184 185 186 | 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 */ static Stmt qbranch; int pendingEndTr = 0; /* True if a </td></tr> is needed */ | | | 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 |
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 */
static Stmt qbranch;
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 */
|
| ︙ | ︙ | |||
276 277 278 279 280 281 282 |
}
if( pendingEndTr ){
@ </td></tr>
pendingEndTr = 0;
}
if( fossil_strcmp(zType,"div")==0 ){
if( !prevWasDivider ){
| | | 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 |
}
if( pendingEndTr ){
@ </td></tr>
pendingEndTr = 0;
}
if( fossil_strcmp(zType,"div")==0 ){
if( !prevWasDivider ){
@ <tr><td colspan="3"><hr class="timelineMarker"></td></tr>
}
prevWasDivider = 1;
continue;
}
prevWasDivider = 0;
/* Date format codes:
** (0) HH:MM
|
| ︙ | ︙ | |||
430 431 432 433 434 435 436 |
while( db_step(&qcherrypick)==SQLITE_ROW && nParent<count(aParent) ){
aParent[nParent++] = db_column_int(&qcherrypick, 0);
nCherrypick++;
}
db_reset(&qcherrypick);
}
gidx = graph_add_row(pGraph, rid, nParent, nCherrypick, aParent,
| | > | 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 |
while( db_step(&qcherrypick)==SQLITE_ROW && nParent<count(aParent) ){
aParent[nParent++] = db_column_int(&qcherrypick, 0);
nCherrypick++;
}
db_reset(&qcherrypick);
}
gidx = graph_add_row(pGraph, rid, nParent, nCherrypick, aParent,
zBr, zBgClr, zUuid,
isLeaf ? isLeaf + 2 * has_closed_tag(rid) : 0);
db_reset(&qbranch);
@ <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);
|
| ︙ | ︙ | |||
492 493 494 495 496 497 498 |
hyperlink_to_event_tagid(tagid<0?-tagid:tagid);
}else if( (tmFlags & TIMELINE_ARTID)!=0 ){
hyperlink_to_version(zUuid);
}
if( tmFlags & TIMELINE_SHOWRID ){
int srcId = delta_source_rid(rid);
if( srcId ){
| | | | 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 |
hyperlink_to_event_tagid(tagid<0?-tagid:tagid);
}else if( (tmFlags & TIMELINE_ARTID)!=0 ){
hyperlink_to_version(zUuid);
}
if( tmFlags & TIMELINE_SHOWRID ){
int srcId = delta_source_rid(rid);
if( srcId ){
@ (%z(href("%R/deltachain/%d",rid))%d(rid)←%d(srcId)</a>)
}else{
@ (%z(href("%R/deltachain/%d",rid))%d(rid)</a>)
}
}
}
if( zType[0]!='c' ){
/* Comments for anything other than a check-in are generated by
** "fossil rebuild" and expect to be rendered as text/x-fossil-wiki */
if( zType[0]=='w' ){
|
| ︙ | ︙ | |||
545 546 547 548 549 550 551 |
if( z[ii]=='\n' ){
for(jj=ii+1; jj<n && z[jj]!='\n' && fossil_isspace(z[jj]); jj++){}
if( z[jj]=='\n' ) break;
}
}
z[ii] = 0;
cgi_printf("%W",z);
| | | 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 |
if( z[ii]=='\n' ){
for(jj=ii+1; jj<n && z[jj]!='\n' && fossil_isspace(z[jj]); jj++){}
if( z[jj]=='\n' ) break;
}
}
z[ii] = 0;
cgi_printf("%W",z);
}else if( mxWikiLen>0 && (int)blob_size(&comment)>mxWikiLen ){
Blob truncated;
blob_zero(&truncated);
blob_append(&truncated, blob_buffer(&comment), mxWikiLen);
blob_append(&truncated, "...", 3);
@ %W(blob_str(&truncated))
blob_reset(&truncated);
drawDetailEllipsis = 0;
|
| ︙ | ︙ | |||
648 649 650 651 652 653 654 |
cgi_printf(" tags: %h", zTagList);
}
}
if( tmFlags & TIMELINE_SHOWRID ){
int srcId = delta_source_rid(rid);
if( srcId ){
| | > | > | 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 |
cgi_printf(" tags: %h", zTagList);
}
}
if( tmFlags & TIMELINE_SHOWRID ){
int srcId = delta_source_rid(rid);
if( srcId ){
cgi_printf(" id: %z%d←%d</a>",
href("%R/deltachain/%d",rid), rid, srcId);
}else{
cgi_printf(" id: %z%d</a>",
href("%R/deltachain/%d",rid), rid);
}
}
tag_private_status(rid);
if( xExtra ){
xExtra(rid);
}
/* End timelineDetail */
|
| ︙ | ︙ | |||
701 702 703 704 705 706 707 |
int fid = db_column_int(&fchngQuery, 1);
int isDel = fid==0;
const char *zOldName = db_column_text(&fchngQuery, 5);
const char *zOld = db_column_text(&fchngQuery, 4);
const char *zNew = db_column_text(&fchngQuery, 3);
const char *zUnpub = "";
char *zA;
| | > | | > | | 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 |
int fid = db_column_int(&fchngQuery, 1);
int isDel = fid==0;
const char *zOldName = db_column_text(&fchngQuery, 5);
const char *zOld = db_column_text(&fchngQuery, 4);
const char *zNew = db_column_text(&fchngQuery, 3);
const char *zUnpub = "";
char *zA;
char *zId;
if( !inUl ){
@ <ul class="filelist">
inUl = 1;
}
if( tmFlags & TIMELINE_SHOWRID ){
int srcId = delta_source_rid(fid);
if( srcId ){
zId = mprintf(" (%z%d←%d</a>) ",
href("%R/deltachain/%d", fid), fid, srcId);
}else{
zId = mprintf(" (%z%d</a>) ",
href("%R/deltachain/%d", fid), fid);
}
}else{
zId = fossil_strdup("");
}
if( (tmFlags & TIMELINE_FRENAMES)!=0 ){
if( !isNew && !isDel && zOldName!=0 ){
@ <li> %h(zOldName) → %h(zFilename)%s(zId)
}
continue;
}
|
| ︙ | ︙ | |||
748 749 750 751 752 753 754 755 756 757 758 759 760 761 |
@ <li>%h(zOldName) → %s(zA)%h(zFilename)%s(zId)</a> %s(zUnpub)
}else{
@ <li>%s(zA)%h(zFilename)</a>%s(zId) %s(zUnpub)
}
@ %z(href("%R/fdiff?v1=%!S&v2=%!S",zOld,zNew))[diff]</a></li>
}
fossil_free(zA);
}
db_reset(&fchngQuery);
if( inUl ){
@ </ul>
}
}
| > | 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 |
@ <li>%h(zOldName) → %s(zA)%h(zFilename)%s(zId)</a> %s(zUnpub)
}else{
@ <li>%s(zA)%h(zFilename)</a>%s(zId) %s(zUnpub)
}
@ %z(href("%R/fdiff?v1=%!S&v2=%!S",zOld,zNew))[diff]</a></li>
}
fossil_free(zA);
fossil_free(zId);
}
db_reset(&fchngQuery);
if( inUl ){
@ </ul>
}
}
|
| ︙ | ︙ | |||
916 917 918 919 920 921 922 |
** the node with an id equal to this value. 0 if it is straight to
** the top of the page or just up a little ways, -1 if there is
** no thick-line riser (if the node is a leaf).
** sb: Draw a dotted child-line out of the top of this node up to the
** node with the id equal to the value. This is like "u" except
** that the line is dotted instead of solid and has no arrow.
** Mnemonic: "Same Branch".
| | | 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 |
** the node with an id equal to this value. 0 if it is straight to
** the top of the page or just up a little ways, -1 if there is
** no thick-line riser (if the node is a leaf).
** sb: Draw a dotted child-line out of the top of this node up to the
** node with the id equal to the value. This is like "u" except
** that the line is dotted instead of solid and has no arrow.
** Mnemonic: "Same Branch".
** f: 0x01: a leaf node, 0x02: a closed leaf node.
** au: An array of integers that define thick-line risers for branches.
** The integers are in pairs. For each pair, the first integer is
** is the rail on which the riser should run and the second integer
** is the id of the node upto which the riser should run. If there
** are no risers, this array does not exist.
** mi: "merge-in". An array of integer rail positions from which
** merge arrows should be drawn into this node. If the value is
|
| ︙ | ︙ | |||
956 957 958 959 960 961 962 963 964 965 966 967 968 969 |
if( pRow->isStepParent ){
cgi_printf("\"sb\":%d,", pRow->aiRiser[pRow->iRail]);
}else{
cgi_printf("\"u\":%d,", pRow->aiRiser[pRow->iRail]);
}
k = 0;
if( pRow->isLeaf ) k |= 1;
cgi_printf("\"f\":%d,",k);
for(i=k=0; i<GR_MAX_RAIL; i++){
if( i==pRow->iRail ) continue;
if( pRow->aiRiser[i]>0 ){
if( k==0 ){
cgi_printf("\"au\":");
cSep = '[';
| > | 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 |
if( pRow->isStepParent ){
cgi_printf("\"sb\":%d,", pRow->aiRiser[pRow->iRail]);
}else{
cgi_printf("\"u\":%d,", pRow->aiRiser[pRow->iRail]);
}
k = 0;
if( pRow->isLeaf ) k |= 1;
if( pRow->isLeaf & 2) k |= 2;
cgi_printf("\"f\":%d,",k);
for(i=k=0; i<GR_MAX_RAIL; i++){
if( i==pRow->iRail ) continue;
if( pRow->aiRiser[i]>0 ){
if( k==0 ){
cgi_printf("\"au\":");
cSep = '[';
|
| ︙ | ︙ | |||
1390 1391 1392 1393 1394 1395 1396 |
zIntro = "regular expression ";
}else/* if( matchStyle==MS_BRLIST )*/{
zStart = "tagname IN ('sym-";
zDelimiter = "','sym-";
zEnd = "')";
zPrefix = "";
zSuffix = "";
| | | 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 |
zIntro = "regular expression ";
}else/* if( matchStyle==MS_BRLIST )*/{
zStart = "tagname IN ('sym-";
zDelimiter = "','sym-";
zEnd = "')";
zPrefix = "";
zSuffix = "";
zIntro = "";
}
/* Convert the list of matches into an SQL expression and text description. */
blob_zero(&expr);
blob_zero(&desc);
blob_zero(&err);
while( 1 ){
|
| ︙ | ︙ | |||
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 | ** c=TIMEORTAG Show events that happen "circa" TIMEORTAG ** cf=FILEHASH Show events around the time of the first use of ** the file with FILEHASH ** m=TIMEORTAG Highlight the event at TIMEORTAG, or the closest available ** event if TIMEORTAG is not part of the timeline. If ** the t= or r= is used, the m event is added to the timeline ** if it isn't there already. ** sel1=TIMEORTAG Highlight the check-in at TIMEORTAG if it is part of ** the timeline. Similar to m= except TIMEORTAG must ** match a check-in that is already in the timeline. ** sel2=TIMEORTAG Like sel1= but use the secondary highlight. ** n=COUNT Maximum number of events. "all" for no limit ** n1=COUNT Same as "n" but doesn't set the display-preference cookie ** Use "n1=COUNT" for a one-time display change ** p=CHECKIN Parents and ancestors of CHECKIN ** bt=PRIOR ... going back to PRIOR ** d=CHECKIN Children and descendants of CHECKIN ** dp=CHECKIN Same as 'd=CHECKIN&p=CHECKIN' ** df=CHECKIN Same as 'd=CHECKIN&n1=all&nd'. Mnemonic: "Derived From" ** bt=CHECKIN In conjunction with p=CX, this means show all ** ancestors of CX going back to the time of CHECKIN. ** All qualifying check-ins are shown unless there ** is also an n= or n1= query parameter. ** t=TAG Show only check-ins with the given TAG ** r=TAG Show check-ins related to TAG, equivalent to t=TAG&rel ** rel Show related check-ins as well as those matching t=TAG ** mionly Limit rel to show ancestors but not descendants ** nowiki Do not show wiki associated with branch or tag ** ms=MATCHSTYLE Set tag match style to EXACT, GLOB, LIKE, REGEXP ** u=USER Only show items associated with USER ** y=TYPE 'ci', 'w', 't', 'n', 'e', 'f', or 'all'. ** ss=VIEWSTYLE c: "Compact", v: "Verbose", m: "Modern", j: "Columnar", | > > > > > | 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 | ** c=TIMEORTAG Show events that happen "circa" TIMEORTAG ** cf=FILEHASH Show events around the time of the first use of ** the file with FILEHASH ** m=TIMEORTAG Highlight the event at TIMEORTAG, or the closest available ** event if TIMEORTAG is not part of the timeline. If ** the t= or r= is used, the m event is added to the timeline ** if it isn't there already. ** x=HASHLIST Show all check-ins in the comma-separated HASHLIST ** in addition to check-ins specified by t= or r= ** sel1=TIMEORTAG Highlight the check-in at TIMEORTAG if it is part of ** the timeline. Similar to m= except TIMEORTAG must ** match a check-in that is already in the timeline. ** sel2=TIMEORTAG Like sel1= but use the secondary highlight. ** n=COUNT Maximum number of events. "all" for no limit ** n1=COUNT Same as "n" but doesn't set the display-preference cookie ** Use "n1=COUNT" for a one-time display change ** p=CHECKIN Parents and ancestors of CHECKIN ** bt=PRIOR ... going back to PRIOR ** d=CHECKIN Children and descendants of CHECKIN ** ft=DESCENDANT ... going forward to DESCENDANT ** dp=CHECKIN Same as 'd=CHECKIN&p=CHECKIN' ** df=CHECKIN Same as 'd=CHECKIN&n1=all&nd'. Mnemonic: "Derived From" ** bt=CHECKIN In conjunction with p=CX, this means show all ** ancestors of CX going back to the time of CHECKIN. ** All qualifying check-ins are shown unless there ** is also an n= or n1= query parameter. ** t=TAG Show only check-ins with the given TAG ** r=TAG Show check-ins related to TAG, equivalent to t=TAG&rel ** tl=TAGLIST Shorthand for t=TAGLIST&ms=brlist ** rl=TAGLIST Shorthand for r=TAGLIST&ms=brlist ** rel Show related check-ins as well as those matching t=TAG ** mionly Limit rel to show ancestors but not descendants ** nowiki Do not show wiki associated with branch or tag ** ms=MATCHSTYLE Set tag match style to EXACT, GLOB, LIKE, REGEXP ** u=USER Only show items associated with USER ** y=TYPE 'ci', 'w', 't', 'n', 'e', 'f', or 'all'. ** ss=VIEWSTYLE c: "Compact", v: "Verbose", m: "Modern", j: "Columnar", |
| ︙ | ︙ | |||
1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 | ** to see all changes for the current week. ** year=YYYY Show only events on the given year. The use "year=0" ** to see all changes for the current year. ** days=N Show events over the previous N days ** datefmt=N Override the date format: 0=HH:MM, 1=HH:MM:SS, ** 2=YYYY-MM-DD HH:MM:SS, 3=YYMMDD HH:MM, and 4 means "off". ** bisect Show the check-ins that are in the current bisect ** showid Show RIDs ** showsql Show the SQL text ** ** p= and d= can appear individually or together. If either p= or d= ** appear, then u=, y=, a=, and b= are ignored. ** ** If both a= and b= appear then both upper and lower bounds are honored. | > | 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 | ** to see all changes for the current week. ** year=YYYY Show only events on the given year. The use "year=0" ** to see all changes for the current year. ** days=N Show events over the previous N days ** datefmt=N Override the date format: 0=HH:MM, 1=HH:MM:SS, ** 2=YYYY-MM-DD HH:MM:SS, 3=YYMMDD HH:MM, and 4 means "off". ** bisect Show the check-ins that are in the current bisect ** oldestfirst Show events oldest first. ** showid Show RIDs ** showsql Show the SQL text ** ** p= and d= can appear individually or together. If either p= or d= ** appear, then u=, y=, a=, and b= are ignored. ** ** If both a= and b= appear then both upper and lower bounds are honored. |
| ︙ | ︙ | |||
1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 |
char *zPlural; /* Ending for plural forms */
int showCherrypicks = 1; /* True to show cherrypick merges */
int haveParameterN; /* True if n= query parameter present */
url_initialize(&url, "timeline");
cgi_query_parameters_to_url(&url);
/* Set number of rows to display */
z = P("n");
if( z!=0 ){
haveParameterN = 1;
cookie_write_parameter("n","n",0);
}else{
| > > > | 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 |
char *zPlural; /* Ending for plural forms */
int showCherrypicks = 1; /* True to show cherrypick merges */
int haveParameterN; /* True if n= query parameter present */
url_initialize(&url, "timeline");
cgi_query_parameters_to_url(&url);
(void)P_NoBot("ss")
/* "ss" is processed via the udc but at least one spider likes to
** try to SQL inject via this argument, so let's catch that. */;
/* Set number of rows to display */
z = P("n");
if( z!=0 ){
haveParameterN = 1;
cookie_write_parameter("n","n",0);
}else{
|
| ︙ | ︙ | |||
1800 1801 1802 1803 1804 1805 1806 |
}
cookie_read_parameter("y","y");
zType = P("y");
if( zType==0 ){
zType = g.perm.Read ? "ci" : "all";
cgi_set_parameter("y", zType);
}
| | > > > > > > > > > > > > > > > > > > > | | 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 |
}
cookie_read_parameter("y","y");
zType = P("y");
if( zType==0 ){
zType = g.perm.Read ? "ci" : "all";
cgi_set_parameter("y", zType);
}
if( zType[0]=='a' ||
( g.perm.Read && zType[0]=='c' ) ||
( g.perm.RdTkt && (zType[0]=='t' || zType[0]=='n') ) ||
( g.perm.RdWiki && (zType[0]=='w' || zType[0]=='e') ) ||
( g.perm.RdForum && zType[0]=='f' )
){
cookie_write_parameter("y","y",zType);
}
/* Convert the cf=FILEHASH query parameter into a c=CHECKINHASH value */
if( P("cf")!=0 ){
zCirca = db_text(0,
"SELECT (SELECT uuid FROM blob WHERE rid=mlink.mid)"
" FROM mlink, event"
" WHERE mlink.fid=(SELECT rid FROM blob WHERE uuid LIKE '%q%%')"
" AND event.objid=mlink.mid"
" ORDER BY event.mtime LIMIT 1",
P("cf")
);
}
/* Check for tl=TAGLIST and rl=TAGLIST which are abbreviations for
** t=TAGLIST&ms=brlist and r=TAGLIST&ms=brlist repectively. */
if( zBrName==0 && zTagName==0 ){
const char *z;
if( (z = P("tl"))!=0 ){
zTagName = z;
zMatchStyle = "brlist";
}
if( (z = P("rl"))!=0 ){
zBrName = z;
zMatchStyle = "brlist";
}
}
/* Convert r=TAG to t=TAG&rel in order to populate the UI style widgets. */
if( zBrName && !related ){
cgi_delete_query_parameter("r");
cgi_set_query_parameter("t", zBrName); (void)P("t");
cgi_set_query_parameter("rel", "1");
zTagName = zBrName;
related = 1;
zType = "ci";
}
/* Ignore empty tag query strings. */
|
| ︙ | ︙ | |||
2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 |
addFileGlobDescription(zChng, &desc);
}else if( (p_rid || d_rid) && g.perm.Read && zTagSql==0 ){
/* If p= or d= is present, ignore all other parameters other than n= */
char *zUuid;
const char *zCiName;
int np = 0, nd;
const char *zBackTo = 0;
int ridBackTo = 0;
tmFlags |= TIMELINE_XMERGE | TIMELINE_FILLGAPS;
if( p_rid && d_rid ){
if( p_rid!=d_rid ) p_rid = d_rid;
if( !haveParameterN ) nEntry = 10;
}
db_multi_exec(
"CREATE TEMP TABLE IF NOT EXISTS ok(rid INTEGER PRIMARY KEY)"
);
zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d",
p_rid ? p_rid : d_rid);
zCiName = pd_rid ? P("pd") : p_rid ? P("p") : P("d");
if( zCiName==0 ) zCiName = zUuid;
blob_append_sql(&sql, " AND event.objid IN ok");
nd = 0;
if( d_rid ){
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > | > | > | 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 |
addFileGlobDescription(zChng, &desc);
}else if( (p_rid || d_rid) && g.perm.Read && zTagSql==0 ){
/* If p= or d= is present, ignore all other parameters other than n= */
char *zUuid;
const char *zCiName;
int np = 0, nd;
const char *zBackTo = 0;
const char *zFwdTo = 0;
int ridBackTo = 0;
int ridFwdTo = 0;
tmFlags |= TIMELINE_XMERGE | TIMELINE_FILLGAPS;
if( p_rid && d_rid ){
if( p_rid!=d_rid ) p_rid = d_rid;
if( !haveParameterN ) nEntry = 10;
}
db_multi_exec(
"CREATE TEMP TABLE IF NOT EXISTS ok(rid INTEGER PRIMARY KEY)"
);
zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d",
p_rid ? p_rid : d_rid);
zCiName = pd_rid ? P("pd") : p_rid ? P("p") : P("d");
if( zCiName==0 ) zCiName = zUuid;
blob_append_sql(&sql, " AND event.objid IN ok");
nd = 0;
if( d_rid ){
Stmt s;
double rStopTime = 9e99;
zFwdTo = P("ft");
if( zFwdTo ){
double rStartDate = db_double(0.0,
"SELECT mtime FROM event WHERE objid=%d", d_rid);
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 = db_double(9e99,
"SELECT mtime FROM event WHERE objid=%d", ridFwdTo);
}
}
db_prepare(&s,
"WITH RECURSIVE"
" dx(rid,mtime) AS ("
" SELECT %d, 0"
" UNION"
" SELECT plink.cid, plink.mtime FROM dx, plink"
" WHERE plink.pid=dx.rid"
" AND (:stop>=8e99 OR plink.mtime<=:stop)"
" ORDER BY 2"
" )"
"INSERT OR IGNORE INTO ok SELECT rid FROM dx LIMIT %d",
d_rid, nEntry<=0 ? -1 : nEntry+1
);
db_bind_double(&s, ":stop", rStopTime);
db_step(&s);
db_finalize(&s);
/* compute_descendants(d_rid, nEntry==0 ? 0 : nEntry+1); */
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 ){
double rDateLimit = db_double(0.0,
"SELECT mtime FROM event WHERE objid=%d", p_rid);
ridBackTo = last_checkin_with_tag_before_date(zBackTo, rDateLimit);
if( ridBackTo==0 ){
ridBackTo = name_to_typed_rid(zBackTo,"ci");
}
if( ridBackTo && !haveParameterN ) nEntry = 0;
}
compute_ancestors(p_rid, nEntry==0 ? 0 : nEntry+1, 0, ridBackTo);
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));
}
|
| ︙ | ︙ | |||
2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 |
blob_appendf(&desc,
"Check-in %z%h</a> only (%z%h</a> is not an ancestor)",
href("%R/info?name=%h",zCiName), zCiName,
href("%R/info?name=%h",zBackTo), zBackTo);
}else{
blob_appendf(&desc, " back to %z%h</a>",
href("%R/info?name=%h",zBackTo), zBackTo);
}
}
if( d_rid ){
if( p_rid ){
/* If both p= and d= are set, we don't have the uuid of d yet. */
zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", d_rid);
}
| > > > > > > > > > > > > > > > | 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 |
blob_appendf(&desc,
"Check-in %z%h</a> only (%z%h</a> is not an ancestor)",
href("%R/info?name=%h",zCiName), zCiName,
href("%R/info?name=%h",zBackTo), zBackTo);
}else{
blob_appendf(&desc, " back to %z%h</a>",
href("%R/info?name=%h",zBackTo), zBackTo);
if( ridFwdTo && zFwdTo ){
blob_appendf(&desc, " and up to %z%h</a>",
href("%R/info?name=%h",zFwdTo), zFwdTo);
}
}
}else if( ridFwdTo ){
if( nd==0 ){
blob_reset(&desc);
blob_appendf(&desc,
"Check-in %z%h</a> only (%z%h</a> is not an descendant)",
href("%R/info?name=%h",zCiName), zCiName,
href("%R/info?name=%h",zFwdTo), zFwdTo);
}else{
blob_appendf(&desc, " up to %z%h</a>",
href("%R/info?name=%h",zFwdTo), zFwdTo);
}
}
if( d_rid ){
if( p_rid ){
/* If both p= and d= are set, we don't have the uuid of d yet. */
zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", d_rid);
}
|
| ︙ | ︙ | |||
2214 2215 2216 2217 2218 2219 2220 |
blob_append_sql(&cond, " AND event.objid IN rnfile ");
}
if( forkOnly ){
blob_append_sql(&cond, " AND event.objid IN rnfork ");
}
if( cpOnly && showCherrypicks ){
db_multi_exec(
| | | 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 |
blob_append_sql(&cond, " AND event.objid IN rnfile ");
}
if( forkOnly ){
blob_append_sql(&cond, " AND event.objid IN rnfork ");
}
if( cpOnly && showCherrypicks ){
db_multi_exec(
"CREATE TEMP TABLE IF NOT EXISTS cpnodes(rid INTEGER PRIMARY KEY);"
"INSERT OR IGNORE INTO cpnodes SELECT childid FROM cherrypick;"
"INSERT OR IGNORE INTO cpnodes SELECT parentid FROM cherrypick;"
);
blob_append_sql(&cond, " AND event.objid IN cpnodes ");
}
if( bisectLocal || zBisect!=0 ){
blob_append_sql(&cond, " AND event.objid IN (SELECT rid FROM bilog) ");
|
| ︙ | ︙ | |||
2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 |
);
if( zMark ){
/* If the t=release option is used with m=UUID, then also
** include the UUID check-in in the display list */
int ridMark = name_to_rid(zMark);
db_multi_exec(
"INSERT OR IGNORE INTO selected_nodes(rid) VALUES(%d)", ridMark);
}
if( !related ){
blob_append_sql(&cond, " AND blob.rid IN selected_nodes");
}else{
db_multi_exec(
"CREATE TEMP TABLE related_nodes(rid INTEGER PRIMARY KEY);"
"INSERT INTO related_nodes SELECT rid FROM selected_nodes;"
| > > > > > > > > > > > > > > > > > | 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 |
);
if( zMark ){
/* If the t=release option is used with m=UUID, then also
** include the UUID check-in in the display list */
int ridMark = name_to_rid(zMark);
db_multi_exec(
"INSERT OR IGNORE INTO selected_nodes(rid) VALUES(%d)", ridMark);
}
if( P("x")!=0 ){
char *zX = fossil_strdup(P("x"));
int ii;
int ridX;
while( zX[0] ){
char c;
if( zX[0]==',' || zX[0]==' ' ){ zX++; continue; }
for(ii=1; zX[ii] && zX[ii]!=',' && zX[ii]!=' '; ii++){}
c = zX[ii];
zX[ii] = 0;
ridX = name_to_rid(zX);
db_multi_exec(
"INSERT OR IGNORE INTO selected_nodes(rid) VALUES(%d)", ridX);
zX[ii] = c;
zX += ii;
}
}
if( !related ){
blob_append_sql(&cond, " AND blob.rid IN selected_nodes");
}else{
db_multi_exec(
"CREATE TEMP TABLE related_nodes(rid INTEGER PRIMARY KEY);"
"INSERT INTO related_nodes SELECT rid FROM selected_nodes;"
|
| ︙ | ︙ | |||
2491 2492 2493 2494 2495 2496 2497 |
if( zType[0]=='c' ){
zEType = "check-in";
}else if( zType[0]=='w' ){
zEType = "wiki";
}else if( zType[0]=='t' ){
zEType = "ticket change";
}else if( zType[0]=='n' ){
| | < > > > | > > > > > > > | | > | 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 |
if( zType[0]=='c' ){
zEType = "check-in";
}else if( zType[0]=='w' ){
zEType = "wiki";
}else if( zType[0]=='t' ){
zEType = "ticket change";
}else if( zType[0]=='n' ){
zEType = "new ticket";
}else if( zType[0]=='e' ){
zEType = "technical note";
}else if( zType[0]=='g' ){
zEType = "tag";
}else if( zType[0]=='f' ){
zEType = "forum post";
}
}
if( zUser ){
int n = db_int(0,"SELECT count(*) FROM event"
" WHERE user=%Q OR euser=%Q", zUser, zUser);
if( n<=nEntry ){
nEntry = -1;
}
blob_append_sql(&cond, " AND (event.user=%Q OR event.euser=%Q)",
zUser, zUser);
zThisUser = zUser;
}
if( zSearch ){
if( tmFlags & TIMELINE_FORUMTXT ){
sqlite3_create_function(g.db, "forum_post_content", 1, SQLITE_UTF8,
0, forum_post_content_function, 0, 0);
blob_append_sql(&cond,
" AND (event.comment LIKE '%%%q%%'"
" OR event.brief LIKE '%%%q%%'"
" OR (event.type=='f' AND"
" forum_post_content(event.objid) LIKE '%%%q%%'))",
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);
rAfter = symbolic_name_to_mtime(zAfter, &zAfter);
rCirca = symbolic_name_to_mtime(zCirca, &zCirca);
blob_append_sql(&sql, "%s", blob_sql_text(&cond));
if( rAfter>0.0 ){
if( rBefore>0.0 ){
|
| ︙ | ︙ | |||
2611 2612 2613 2614 2615 2616 2617 |
tmFlags |= TIMELINE_CHPICK|TIMELINE_DISJOINT;
}
if( zUser ){
blob_appendf(&desc, " by user %h", zUser);
tmFlags |= TIMELINE_XMERGE | TIMELINE_FILLGAPS;
}
if( zTagSql ){
| | | | | | | 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 |
tmFlags |= TIMELINE_CHPICK|TIMELINE_DISJOINT;
}
if( zUser ){
blob_appendf(&desc, " by user %h", zUser);
tmFlags |= TIMELINE_XMERGE | TIMELINE_FILLGAPS;
}
if( zTagSql ){
if( matchStyle==MS_EXACT || matchStyle==MS_BRLIST ){
if( related ){
blob_appendf(&desc, " related to %h", zMatchDesc);
}else{
blob_appendf(&desc, " tagged with %h", zMatchDesc);
}
}else{
if( related ){
blob_appendf(&desc, " related to tags matching %h", zMatchDesc);
}else{
blob_appendf(&desc, " with tags matching %h", zMatchDesc);
}
}
if( zMark ){
blob_appendf(&desc," plus check-in \"%h\"", zMark);
}
tmFlags |= TIMELINE_XMERGE | TIMELINE_FILLGAPS;
}
addFileGlobDescription(zChng, &desc);
if( rAfter>0.0 ){
if( rBefore>0.0 ){
blob_appendf(&desc, " occurring between %h and %h.<br>",
zAfter, zBefore);
}else{
blob_appendf(&desc, " occurring on or after %h.<br>", zAfter);
}
}else if( rBefore>0.0 ){
blob_appendf(&desc, " occurring on or before %h.<br>", zBefore);
}else if( rCirca>0.0 ){
blob_appendf(&desc, " occurring around %h.<br>", zCirca);
}
if( zSearch ){
blob_appendf(&desc, " matching \"%h\"", zSearch);
}
if( g.perm.Hyperlink ){
static const char *const azMatchStyles[] = {
"exact", "Exact", "glob", "Glob", "like", "Like", "regexp", "Regexp",
|
| ︙ | ︙ | |||
2717 2718 2719 2720 2721 2722 2723 |
}
if( PB("showid") ) tmFlags |= TIMELINE_SHOWRID;
if( useDividers && zMark && zMark[0] ){
double r = symbolic_name_to_mtime(zMark, 0);
if( r>0.0 && !selectedRid ) selectedRid = timeline_add_divider(r);
}
blob_zero(&sql);
| > > > | > | 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 |
}
if( PB("showid") ) tmFlags |= TIMELINE_SHOWRID;
if( useDividers && zMark && zMark[0] ){
double r = symbolic_name_to_mtime(zMark, 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*/");
}
if( fossil_islower(desc.aData[0]) ){
desc.aData[0] = fossil_toupper(desc.aData[0]);
}
if( zBrName ){
if( !PB("nowiki")
&& wiki_render_associated("branch", zBrName, WIKIASSOC_ALL)
){
|
| ︙ | ︙ | |||
2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 |
@ <p class="generalError">%h(zError)</p>
}
if( zNewerButton ){
@ %z(chref("button tl-button-next","%s",zNewerButton))%h(zNewerButtonLabel)\
@ ↑</a>
}
www_print_timeline(&q, tmFlags, zThisUser, zThisTag, zBrName,
selectedRid, secondaryRid, 0);
db_finalize(&q);
if( zOlderButton ){
@ %z(chref("button tl-button-prev","%s",zOlderButton))%h(zOlderButtonLabel)\
@ ↓</a>
}
| > | 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 |
@ <p class="generalError">%h(zError)</p>
}
if( zNewerButton ){
@ %z(chref("button tl-button-next","%s",zNewerButton))%h(zNewerButtonLabel)\
@ ↑</a>
}
cgi_check_for_malice();
www_print_timeline(&q, tmFlags, zThisUser, zThisTag, zBrName,
selectedRid, secondaryRid, 0);
db_finalize(&q);
if( zOlderButton ){
@ %z(chref("button tl-button-prev","%s",zOlderButton))%h(zOlderButtonLabel)\
@ ↓</a>
}
|
| ︙ | ︙ | |||
2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 |
int nLine = 0;
int nEntry = 0;
char zPrevDate[20];
const char *zCurrentUuid = 0;
int fchngQueryInit = 0; /* True if fchngQuery is initialized */
Stmt fchngQuery; /* Query for file changes on check-ins */
int rc;
zPrevDate[0] = 0;
if( g.localOpen ){
int rid = db_lget_int("checkout", 0);
zCurrentUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
}
| > > > > > | 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 |
int nLine = 0;
int nEntry = 0;
char zPrevDate[20];
const char *zCurrentUuid = 0;
int fchngQueryInit = 0; /* True if fchngQuery is initialized */
Stmt fchngQuery; /* Query for file changes on check-ins */
int rc;
/* True: separate entries with a newline after file listing */
int bVerboseNL = (zFormat && (fossil_strcmp(zFormat, TIMELINE_FMT_ONELINE)!=0));
/* True: separate entries with a newline even with no file listing */
int bNoVerboseNL = (zFormat && (fossil_strcmp(zFormat, TIMELINE_FMT_MEDIUM)==0 ||
fossil_strcmp(zFormat, TIMELINE_FMT_FULL)==0));
zPrevDate[0] = 0;
if( g.localOpen ){
int rid = db_lget_int("checkout", 0);
zCurrentUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
}
|
| ︙ | ︙ | |||
3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 |
fossil_print(" DELETED %s\n",zFilename);
}else{
fossil_print(" EDITED %s\n", zFilename);
}
nLine++; /* record another line */
}
db_reset(&fchngQuery);
}
nEntry++; /* record another complete entry */
}
if( rc==SQLITE_DONE ){
/* Did the underlying query actually have all entries? */
if( nAbsLimit==0 ){
fossil_print("+++ end of timeline (%d) +++\n", nEntry);
}else{
| > > > > | 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 |
fossil_print(" DELETED %s\n",zFilename);
}else{
fossil_print(" EDITED %s\n", zFilename);
}
nLine++; /* record another line */
}
db_reset(&fchngQuery);
if( bVerboseNL ) fossil_print("\n");
}else{
if( bNoVerboseNL ) fossil_print("\n");
}
nEntry++; /* record another complete entry */
}
if( rc==SQLITE_DONE ){
/* Did the underlying query actually have all entries? */
if( nAbsLimit==0 ){
fossil_print("+++ end of timeline (%d) +++\n", nEntry);
}else{
|
| ︙ | ︙ | |||
3154 3155 3156 3157 3158 3159 3160 | ** *FORK*, *UNPUBLISHED*, *LEAF*, *BRANCH* ** --oneline Show only short hash and comment for each entry ** --medium Medium-verbose entry formatting ** --full Extra verbose entry formatting ** -n|--limit N If N is positive, output the first N entries. If ** N is negative, output the first -N lines. If N is ** zero, no limit. Default is -20 meaning 20 lines. | | | | 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 | ** *FORK*, *UNPUBLISHED*, *LEAF*, *BRANCH* ** --oneline Show only short hash and comment for each entry ** --medium Medium-verbose entry formatting ** --full Extra verbose entry formatting ** -n|--limit N If N is positive, output the first N entries. If ** N is negative, output the first -N lines. If N is ** zero, no limit. Default is -20 meaning 20 lines. ** --offset P Skip P changes ** -p|--path PATH Output items affecting PATH only. ** PATH can be a file or a sub directory. ** -R REPO_FILE Specifies the repository db to use. Default is ** the current check-out's repository. ** --sql Show the SQL used to generate the timeline ** -t|--type TYPE Output items from the given types only, such as: ** ci = file commits only ** e = technical notes only ** f = forum posts only ** t = tickets only ** w = wiki commits only |
| ︙ | ︙ | |||
3208 3209 3210 3211 3212 3213 3214 |
zWidth = find_option("width","W",1);
zType = find_option("type","t",1);
zFilePattern = find_option("path","p",1);
zFormat = find_option("format","F",1);
zBr = find_option("branch","b",1);
if( find_option("current-branch","c",0)!=0 ){
if( !g.localOpen ){
| | | | > | | > | | < > | 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 |
zWidth = find_option("width","W",1);
zType = find_option("type","t",1);
zFilePattern = find_option("path","p",1);
zFormat = find_option("format","F",1);
zBr = find_option("branch","b",1);
if( find_option("current-branch","c",0)!=0 ){
if( !g.localOpen ){
fossil_fatal("not within an open check-out");
}else{
int vid = db_lget_int("checkout", 0);
zBr = db_text(0, "SELECT value FROM tagxref WHERE rid=%d AND tagid=%d",
vid, TAG_BRANCH);
}
}
if( find_option("oneline",0,0)!= 0 || fossil_strcmp(zFormat,"oneline")==0 ){
zFormat = TIMELINE_FMT_ONELINE;
}
if( find_option("medium",0,0)!= 0 || fossil_strcmp(zFormat,"medium")==0 ){
zFormat = TIMELINE_FMT_MEDIUM;
}
if( find_option("full",0,0)!= 0 || fossil_strcmp(zFormat,"full")==0 ){
zFormat = TIMELINE_FMT_FULL;
}
showSql = find_option("sql",0,0)!=0;
if( !zLimit ){
zLimit = find_option("count",0,1);
}
if( zLimit ){
n = atoi(zLimit);
|
| ︙ | ︙ | |||
3284 3285 3286 3287 3288 3289 3290 |
if( fossil_strcmp(zOrigin, "now")==0 ){
if( mode==TIMELINE_MODE_CHILDREN || mode==TIMELINE_MODE_PARENTS ){
fossil_fatal("cannot compute descendants or ancestors of a date");
}
zDate = mprintf("(SELECT datetime('now'))");
}else if( strncmp(zOrigin, "current", k)==0 ){
if( !g.localOpen ){
| | | 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 |
if( fossil_strcmp(zOrigin, "now")==0 ){
if( mode==TIMELINE_MODE_CHILDREN || mode==TIMELINE_MODE_PARENTS ){
fossil_fatal("cannot compute descendants or ancestors of a date");
}
zDate = mprintf("(SELECT datetime('now'))");
}else if( strncmp(zOrigin, "current", k)==0 ){
if( !g.localOpen ){
fossil_fatal("must be within a local check-out to use 'current'");
}
objid = db_lget_int("checkout",0);
zDate = mprintf("(SELECT mtime FROM plink WHERE cid=%d)", objid);
}else if( fossil_is_julianday(zOrigin) ){
const char *zShift = "";
if( mode==TIMELINE_MODE_CHILDREN || mode==TIMELINE_MODE_PARENTS ){
fossil_fatal("cannot compute descendants or ancestors of a date");
|
| ︙ | ︙ | |||
3371 3372 3373 3374 3375 3376 3377 |
" WHERE tagtype>0 AND tagname='sym-%q'\n"
" UNION\n" /* Tags */
" SELECT srcid FROM tagxref WHERE origid IN (\n"
" SELECT rid FROM tagxref NATURAL JOIN tag\n"
" WHERE tagname='sym-%q')\n"
" UNION\n" /* Branch wikis */
" SELECT objid FROM event WHERE comment LIKE '_branch/%q'\n"
| | | 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 |
" WHERE tagtype>0 AND tagname='sym-%q'\n"
" UNION\n" /* Tags */
" SELECT srcid FROM tagxref WHERE origid IN (\n"
" SELECT rid FROM tagxref NATURAL JOIN tag\n"
" WHERE tagname='sym-%q')\n"
" UNION\n" /* Branch wikis */
" SELECT objid FROM event WHERE comment LIKE '_branch/%q'\n"
" UNION\n" /* Check-in wikis */
" SELECT e.objid FROM event e\n"
" INNER JOIN blob b ON b.uuid=substr(e.comment, 10)\n"
" AND e.comment LIKE '_checkin/%%'\n"
" LEFT JOIN tagxref tx ON tx.rid=b.rid AND tx.tagid=%d\n"
" WHERE tx.value='%q'\n"
")\n" /* No merge closures */
" AND (tagxref.value IS NULL OR tagxref.value='%q')",
|
| ︙ | ︙ | |||
3439 3440 3441 3442 3443 3444 3445 |
z = db_text(0, "SELECT date(%Q,'+1 day')", zToday);
style_submenu_element("Tomorrow", "%R/thisdayinhistory?today=%t", z);
zStartOfProject = db_text(0,
"SELECT datetime(min(mtime),toLocal(),'startofday') FROM event;"
);
timeline_temp_table();
db_prepare(&q, "SELECT * FROM timeline ORDER BY sortby DESC /*scan*/");
| | | 3598 3599 3600 3601 3602 3603 3604 3605 3606 3607 3608 3609 3610 3611 3612 |
z = db_text(0, "SELECT date(%Q,'+1 day')", zToday);
style_submenu_element("Tomorrow", "%R/thisdayinhistory?today=%t", z);
zStartOfProject = db_text(0,
"SELECT datetime(min(mtime),toLocal(),'startofday') FROM event;"
);
timeline_temp_table();
db_prepare(&q, "SELECT * FROM timeline ORDER BY sortby DESC /*scan*/");
for(i=0; i<(int)(sizeof(aYearsAgo)/sizeof(aYearsAgo[0])); i++){
int iAgo = aYearsAgo[i];
char *zThis = db_text(0, "SELECT date(%Q,'-%d years')", zToday, iAgo);
Blob sql;
char *zId;
if( strcmp(zThis, zStartOfProject)<0 ) break;
blob_init(&sql, 0, 0);
blob_append(&sql, "INSERT OR IGNORE INTO timeline ", -1);
|
| ︙ | ︙ |
Changes to src/tkt.c.
| ︙ | ︙ | |||
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 |
** use. The internal-use fields begin with "tkt_".
*/
static int nField = 0;
static struct tktFieldInfo {
char *zName; /* Name of the database field */
char *zValue; /* Value to store */
char *zAppend; /* Value to append */
unsigned mUsed; /* 01: TICKET 02: TICKETCHNG */
} *aField;
#define USEDBY_TICKET 01
#define USEDBY_TICKETCHNG 02
#define USEDBY_BOTH 03
static u8 haveTicket = 0; /* True if the TICKET table exists */
static u8 haveTicketCTime = 0; /* True if TICKET.TKT_CTIME exists */
static u8 haveTicketChng = 0; /* True if the TICKETCHNG table exists */
static u8 haveTicketChngRid = 0; /* True if TICKETCHNG.TKT_RID exists */
static u8 haveTicketChngUser = 0;/* True if TICKETCHNG.TKT_USER exists */
static u8 useTicketGenMt = 0; /* use generated TICKET.MIMETYPE */
static u8 useTicketChngGenMt = 0;/* use generated TICKETCHNG.MIMETYPE */
/*
** Compare two entries in aField[] for sorting purposes
*/
static int nameCmpr(const void *a, const void *b){
return fossil_strcmp(((const struct tktFieldInfo*)a)->zName,
| > > > > > | 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 |
** use. The internal-use fields begin with "tkt_".
*/
static int nField = 0;
static struct tktFieldInfo {
char *zName; /* Name of the database field */
char *zValue; /* Value to store */
char *zAppend; /* Value to append */
char *zBsln; /* "baseline for $zName" if that field exists*/
unsigned mUsed; /* 01: TICKET 02: TICKETCHNG */
} *aField;
#define USEDBY_TICKET 01
#define USEDBY_TICKETCHNG 02
#define USEDBY_BOTH 03
#define JCARD_ASSIGN ('=')
#define JCARD_APPEND ('+')
#define JCARD_PRIVATE ('p')
static u8 haveTicket = 0; /* True if the TICKET table exists */
static u8 haveTicketCTime = 0; /* True if TICKET.TKT_CTIME exists */
static u8 haveTicketChng = 0; /* True if the TICKETCHNG table exists */
static u8 haveTicketChngRid = 0; /* True if TICKETCHNG.TKT_RID exists */
static u8 haveTicketChngUser = 0;/* True if TICKETCHNG.TKT_USER exists */
static u8 useTicketGenMt = 0; /* use generated TICKET.MIMETYPE */
static u8 useTicketChngGenMt = 0;/* use generated TICKETCHNG.MIMETYPE */
static int nTicketBslns = 0; /* number of valid "baseline for ..." */
/*
** Compare two entries in aField[] for sorting purposes
*/
static int nameCmpr(const void *a, const void *b){
return fossil_strcmp(((const struct tktFieldInfo*)a)->zName,
|
| ︙ | ︙ | |||
71 72 73 74 75 76 77 |
** in sorted order in aField[].
**
** The haveTicket and haveTicketChng variables are set to 1 if the TICKET and
** TICKETCHANGE tables exist, respectively.
*/
static void getAllTicketFields(void){
Stmt q;
| | > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 |
** in sorted order in aField[].
**
** The haveTicket and haveTicketChng variables are set to 1 if the TICKET and
** TICKETCHANGE tables exist, respectively.
*/
static void getAllTicketFields(void){
Stmt q;
int i, noRegularMimetype, nBaselines;
static int once = 0;
if( once ) return;
once = 1;
nBaselines = 0;
db_prepare(&q, "PRAGMA table_info(ticket)");
while( db_step(&q)==SQLITE_ROW ){
const char *zFieldName = db_column_text(&q, 1);
haveTicket = 1;
if( memcmp(zFieldName,"tkt_",4)==0 ){
if( strcmp(zFieldName, "tkt_ctime")==0 ) haveTicketCTime = 1;
continue;
}
if( memcmp(zFieldName,"baseline for ",13)==0 ){
if( strcmp(db_column_text(&q,2),"INTEGER")==0 ){
nBaselines++;
}
continue;
}
if( strchr(zFieldName,' ')!=0 ) continue;
if( nField%10==0 ){
aField = fossil_realloc(aField, sizeof(aField[0])*(nField+10) );
}
aField[nField].zBsln = 0;
aField[nField].zName = mprintf("%s", zFieldName);
aField[nField].mUsed = USEDBY_TICKET;
nField++;
}
db_finalize(&q);
if( nBaselines ){
db_prepare(&q, "SELECT 1 FROM pragma_table_info('ticket') "
"WHERE type = 'INTEGER' AND name = :n");
for(i=0; i<nField && nBaselines!=0; i++){
char *zBsln = mprintf("baseline for %s",aField[i].zName);
db_bind_text(&q, ":n", zBsln);
if( db_step(&q)==SQLITE_ROW ){
aField[i].zBsln = zBsln;
nTicketBslns++;
nBaselines--;
}else{
free(zBsln);
}
db_reset(&q);
}
db_finalize(&q);
}
db_prepare(&q, "PRAGMA table_info(ticketchng)");
while( db_step(&q)==SQLITE_ROW ){
const char *zFieldName = db_column_text(&q, 1);
haveTicketChng = 1;
if( memcmp(zFieldName,"tkt_",4)==0 ){
if( strcmp(zFieldName+4,"rid")==0 ){
haveTicketChngRid = 1; /* tkt_rid */
}else if( strcmp(zFieldName+4,"user")==0 ){
haveTicketChngUser = 1; /* tkt_user */
}
continue;
}
if( strchr(zFieldName,' ')!=0 ) continue;
if( (i = fieldId(zFieldName))>=0 ){
aField[i].mUsed |= USEDBY_TICKETCHNG;
continue;
}
if( nField%10==0 ){
aField = fossil_realloc(aField, sizeof(aField[0])*(nField+10) );
}
aField[nField].zBsln = 0;
aField[nField].zName = mprintf("%s", zFieldName);
aField[nField].mUsed = USEDBY_TICKETCHNG;
nField++;
}
db_finalize(&q);
qsort(aField, nField, sizeof(aField[0]), nameCmpr);
noRegularMimetype = 1;
|
| ︙ | ︙ | |||
199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 |
const char *z;
for(i=0; (z = cgi_parameter_name(i))!=0; i++){
Th_Store(z, P(z));
}
}
/*
** Update an entry of the TICKET and TICKETCHNG tables according to the
** information in the ticket artifact given in p. Attempt to create
** the appropriate TICKET table entry if tktid is zero. If tktid is nonzero
** then it will be the ROWID of an existing TICKET entry.
**
** Parameter rid is the recordID for the ticket artifact in the BLOB table.
**
** Return the new rowid of the TICKET table entry.
*/
| > > > > > > > > > > > > > > > > > | > | < > > > > | 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 |
const char *z;
for(i=0; (z = cgi_parameter_name(i))!=0; i++){
Th_Store(z, P(z));
}
}
/*
** Information about a single J-card
*/
struct jCardInfo {
char *zValue;
int mimetype;
int rid;
double mtime;
};
/*
** Update an entry of the TICKET and TICKETCHNG tables according to the
** information in the ticket artifact given in p. Attempt to create
** the appropriate TICKET table entry if tktid is zero. If tktid is nonzero
** then it will be the ROWID of an existing TICKET entry.
**
** Parameter rid is the recordID for the ticket artifact in the BLOB table.
** Upon assignment of a field this rid is stored into a corresponding
** zBsln integer column (provided that it is defined within TICKET table).
**
** If a field is USEDBY_TICKETCHNG table then back-references within it
** are extracted and inserted into the BACKLINK table; otherwise
** a corresponding blob in the `fields` array is updated so that the
** caller could extract backlinks from the most recent field's values.
**
** Return the new rowid of the TICKET table entry.
*/
static int ticket_insert(const Manifest *p, const int rid, int tktid,
Blob *fields){
Blob sql1; /* update or replace TICKET ... */
Blob sql2; /* list of TICKETCHNG's fields that are in the manifest */
Blob sql3; /* list of values which correspond to the previous list */
Stmt q;
int i, j;
char *aUsed;
int mimetype_tkt = MT_NONE, mimetype_tktchng = MT_NONE;
if( tktid==0 ){
db_multi_exec("INSERT INTO ticket(tkt_uuid, tkt_mtime) "
"VALUES(%Q, 0)", p->zTicketUuid);
tktid = db_last_insert_rowid();
}
blob_zero(&sql1);
blob_zero(&sql2);
blob_zero(&sql3);
blob_append_sql(&sql1, "UPDATE OR REPLACE ticket SET tkt_mtime=:mtime");
if( haveTicketCTime ){
blob_append_sql(&sql1, ", tkt_ctime=coalesce(tkt_ctime,:mtime)");
}
aUsed = fossil_malloc_zero( nField );
for(i=0; i<p->nField; i++){
const char * const zName = p->aField[i].zName;
const char * const zBaseName = zName[0]=='+' ? zName+1 : zName;
j = fieldId(zBaseName);
if( j<0 ) continue;
aUsed[j] = 1;
if( aField[j].mUsed & USEDBY_TICKET ){
if( zName[0]=='+' ){
blob_append_sql(&sql1,", \"%w\"=coalesce(\"%w\",'') || %Q",
zBaseName, zBaseName, p->aField[i].zValue);
/* when appending keep "baseline for ..." unchanged */
}else{
blob_append_sql(&sql1,", \"%w\"=%Q", zBaseName, p->aField[i].zValue);
if( aField[j].zBsln ){
blob_append_sql(&sql1,", \"%w\"=%d", aField[j].zBsln, rid);
}
}
}
if( aField[j].mUsed & USEDBY_TICKETCHNG ){
blob_append_sql(&sql2, ",\"%w\"", zBaseName);
blob_append_sql(&sql3, ",%Q", p->aField[i].zValue);
}
if( strcmp(zBaseName,"mimetype")==0 ){
|
| ︙ | ︙ | |||
325 326 327 328 329 330 331 |
}
db_finalize(&q);
}
blob_reset(&sql2);
blob_reset(&sql3);
fossil_free(aUsed);
if( rid>0 ){ /* extract backlinks */
| < | > > > > > > > | | > > > > | > | < > > > | 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 |
}
db_finalize(&q);
}
blob_reset(&sql2);
blob_reset(&sql3);
fossil_free(aUsed);
if( rid>0 ){ /* extract backlinks */
for(i=0; i<p->nField; i++){
const char *zName = p->aField[i].zName;
const char *zBaseName = zName[0]=='+' ? zName+1 : zName;
j = fieldId(zBaseName);
if( j<0 ) continue;
if( aField[j].mUsed & USEDBY_TICKETCHNG ){
backlink_extract(p->aField[i].zValue, mimetype_tktchng,
rid, BKLNK_TICKET, p->rDate,
/* existing backlinks must have been
* already deleted by the caller */ 0 );
}else{
/* update field's data with the most recent values */
Blob *cards = fields + j;
struct jCardInfo card = {
fossil_strdup(p->aField[i].zValue),
mimetype_tkt, rid, p->rDate
};
if( blob_size(cards) && zName[0]!='+' ){
struct jCardInfo *x = (struct jCardInfo *)blob_buffer(cards);
struct jCardInfo *end = x + blob_count(cards,struct jCardInfo);
for(; x!=end; x++){
fossil_free( x->zValue );
}
blob_truncate(cards,0);
}
blob_append(cards, (const char*)(&card), sizeof(card));
}
}
}
return tktid;
}
/*
** Returns non-zero if moderation is required for ticket changes and ticket
|
| ︙ | ︙ | |||
375 376 377 378 379 380 381 |
** Rebuild an entire entry in the TICKET table
*/
void ticket_rebuild_entry(const char *zTktUuid){
char *zTag = mprintf("tkt-%s", zTktUuid);
int tagid = tag_findid(zTag, 1);
Stmt q;
Manifest *pTicket;
| | > | > > > | > > > > > > > > > > > > > > > > > | 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 |
** Rebuild an entire entry in the TICKET table
*/
void ticket_rebuild_entry(const char *zTktUuid){
char *zTag = mprintf("tkt-%s", zTktUuid);
int tagid = tag_findid(zTag, 1);
Stmt q;
Manifest *pTicket;
int tktid, i;
int createFlag = 1;
Blob *fields; /* array of blobs; each blob holds array of jCardInfo */
fossil_free(zTag);
getAllTicketFields();
if( haveTicket==0 ) return;
tktid = db_int(0, "SELECT tkt_id FROM ticket WHERE tkt_uuid=%Q", zTktUuid);
if( tktid!=0 ) search_doc_touch('t', tktid, 0);
if( haveTicketChng ){
db_multi_exec("DELETE FROM ticketchng WHERE tkt_id=%d;", tktid);
}
db_multi_exec("DELETE FROM ticket WHERE tkt_id=%d", tktid);
tktid = 0;
fields = blobarray_new( nField );
db_multi_exec("DELETE FROM backlink WHERE srctype=%d AND srcid IN "
"(SELECT rid FROM tagxref WHERE tagid=%d)",BKLNK_TICKET, tagid);
db_prepare(&q, "SELECT rid FROM tagxref WHERE tagid=%d ORDER BY mtime",tagid);
while( db_step(&q)==SQLITE_ROW ){
int rid = db_column_int(&q, 0);
pTicket = manifest_get(rid, CFTYPE_TICKET, 0);
if( pTicket ){
tktid = ticket_insert(pTicket, rid, tktid, fields);
manifest_ticket_event(rid, pTicket, createFlag, tagid);
manifest_destroy(pTicket);
}
createFlag = 0;
}
db_finalize(&q);
search_doc_touch('t', tktid, 0);
/* Extract backlinks from the most recent values of TICKET fields */
for(i=0; i<nField; i++){
Blob *cards = fields + i;
if( blob_size(cards) ){
struct jCardInfo *x = (struct jCardInfo *)blob_buffer(cards);
struct jCardInfo *end = x + blob_count(cards,struct jCardInfo);
for(; x!=end; x++){
assert( x->zValue );
backlink_extract(x->zValue,x->mimetype,
x->rid,BKLNK_TICKET,x->mtime,0);
fossil_free( x->zValue );
}
}
blob_truncate(cards,0);
}
blobarray_delete(fields,nField);
}
/*
** Create the TH1 interpreter and load the "common" code.
*/
void ticket_init(void){
|
| ︙ | ︙ | |||
506 507 508 509 510 511 512 513 514 515 516 517 518 519 |
&& sqlite3_strnicmp(z0,"sqlite_",7)!=0
&& sqlite3_strnicmp(z0,"fx_",3)!=0
){
goto ticket_schema_error;
}
break;
}
case SQLITE_FUNCTION:
case SQLITE_REINDEX:
case SQLITE_TRANSACTION:
case SQLITE_READ: {
break;
}
default: {
| > | 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 |
&& sqlite3_strnicmp(z0,"sqlite_",7)!=0
&& sqlite3_strnicmp(z0,"fx_",3)!=0
){
goto ticket_schema_error;
}
break;
}
case SQLITE_SELECT:
case SQLITE_FUNCTION:
case SQLITE_REINDEX:
case SQLITE_TRANSACTION:
case SQLITE_READ: {
break;
}
default: {
|
| ︙ | ︙ | |||
625 626 627 628 629 630 631 |
@ mUsed = %d(aField[i].mUsed);
}
@ </ul></div>
}
/*
** WEBPAGE: tktview
| | | > | > | 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 |
@ mUsed = %d(aField[i].mUsed);
}
@ </ul></div>
}
/*
** WEBPAGE: tktview
** URL: tktview/HASH
**
** View a ticket identified by the name= query parameter.
** Other query parameters:
**
** tl Show a timeline of the ticket above the status
*/
void tktview_page(void){
const char *zScript;
char *zFullName;
const char *zUuid = PD("name","");
int showTimeline = P("tl")!=0;
login_check_credentials();
if( !g.perm.RdTkt ){ login_needed(g.anon.RdTkt); return; }
if( g.anon.WrTkt || g.anon.ApndTkt ){
style_submenu_element("Edit", "%R/tktedit/%T", PD("name",""));
}
if( g.perm.Hyperlink ){
style_submenu_element("History", "%R/tkthistory/%T", zUuid);
if( g.perm.Read ){
style_submenu_element("Check-ins", "%R/tkttimeline/%T?y=ci", zUuid);
}
}
if( g.anon.NewTkt ){
style_submenu_element("New Ticket", "%R/tktnew");
}
if( g.anon.ApndTkt && g.anon.Attach ){
style_submenu_element("Attach", "%R/attachadd?tkt=%T&from=%R/tktview/%t",
zUuid, zUuid);
|
| ︙ | ︙ | |||
674 675 676 677 678 679 680 |
}else{
showTimeline = 0;
}
}
if( !showTimeline && g.perm.Hyperlink ){
style_submenu_element("Timeline", "%R/info/%T", zUuid);
}
| | | | | | 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 |
}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);
zFullName = db_text(0,
"SELECT tkt_uuid FROM ticket"
" WHERE tkt_uuid GLOB '%q*'", zUuid);
if( zFullName ){
attachment_list(zFullName, "<hr><h2>Attachments:</h2><ul>");
}
style_finish_page();
}
/*
** TH1 command: append_field FIELD STRING
|
| ︙ | ︙ | |||
717 718 719 720 721 722 723 |
){
int idx;
if( argc!=3 ){
return Th_WrongNumArgs(interp, "append_field FIELD STRING");
}
if( g.thTrace ){
| | > > > > > > > > > > > > > > > > > > | | 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 |
){
int idx;
if( argc!=3 ){
return Th_WrongNumArgs(interp, "append_field FIELD STRING");
}
if( g.thTrace ){
Th_Trace("append_field %#h {%#h}<br>\n",
argl[1], argv[1], argl[2], argv[2]);
}
for(idx=0; idx<nField; idx++){
if( memcmp(aField[idx].zName, argv[1], argl[1])==0
&& aField[idx].zName[argl[1]]==0 ){
break;
}
}
if( idx>=nField ){
Th_ErrorMessage(g.interp, "no such TICKET column: ", argv[1], argl[1]);
return TH_ERROR;
}
aField[idx].zAppend = mprintf("%.*s", argl[2], argv[2]);
return TH_OK;
}
/*
** Write a ticket into the repository.
** Upon reassignment of fields try to delta-compress an artifact against
** all artifacts that are referenced in the corresponding zBsln fields.
*/
static int ticket_put(
Blob *pTicket, /* The text of the ticket change record */
const char *zTktId, /* The ticket to which this change is applied */
const char *aUsed, /* Indicators for fields' modifications */
int needMod /* True if moderation is needed */
){
int result;
int rid;
manifest_crosslink_begin();
rid = content_put_ex(pTicket, 0, 0, 0, needMod);
if( rid==0 ){
fossil_fatal("trouble committing ticket: %s", g.zErrMsg);
}
if( nTicketBslns ){
int i, s, buf[8], nSrc=0, *aSrc=&(buf[0]);
if( nTicketBslns > count(buf) ){
aSrc = (int*)fossil_malloc(sizeof(int)*nTicketBslns);
}
for(i=0; i<nField; i++){
if( aField[i].zBsln && aUsed[i]==JCARD_ASSIGN ){
s = db_int(0,"SELECT \"%w\" FROM ticket WHERE tkt_uuid = '%q'",
aField[i].zBsln, zTktId );
if( s > 0 ) aSrc[nSrc++] = s;
}
}
if( nSrc ) content_deltify(rid, aSrc, nSrc, 0);
if( aSrc!=&(buf[0]) ) fossil_free( aSrc );
}
if( needMod ){
moderation_table_create();
db_multi_exec(
"INSERT INTO modreq(objid, tktid) VALUES(%d,%Q)",
rid, zTktId
);
}else{
db_add_unsent(rid);
db_multi_exec("INSERT OR IGNORE INTO unclustered VALUES(%d);", rid);
}
result = (manifest_crosslink(rid, pTicket, MC_NONE)==0);
assert( blob_is_reset(pTicket) );
if( !result ){
result = manifest_crosslink_end(MC_PERMIT_HOOKS);
}else{
|
| ︙ | ︙ | |||
785 786 787 788 789 790 791 |
static int submitTicketCmd(
Th_Interp *interp,
void *pUuid,
int argc,
const char **argv,
int *argl
){
| | | | > > > > > | > > | | < | | > > > | > | < > > > > > > > > > > > > > > > | | | 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 |
static int submitTicketCmd(
Th_Interp *interp,
void *pUuid,
int argc,
const char **argv,
int *argl
){
char *zDate, *aUsed;
const char *zUuid;
int i;
int nJ = 0, rc = TH_OK;
Blob tktchng, cksum;
int needMod;
if( !cgi_csrf_safe(2) ){
@ <p class="generalError">Error: Invalid CSRF token.</p>
return TH_OK;
}
if( !captcha_is_correct(0) ){
@ <p class="generalError">Error: Incorrect security code.</p>
return TH_OK;
}
zUuid = (const char *)pUuid;
blob_zero(&tktchng);
zDate = date_in_standard_format("now");
blob_appendf(&tktchng, "D %s\n", zDate);
free(zDate);
aUsed = fossil_malloc_zero( nField );
for(i=0; i<nField; i++){
if( aField[i].zAppend ){
blob_appendf(&tktchng, "J +%s %z\n", aField[i].zName,
fossilize(aField[i].zAppend, -1));
++nJ;
aUsed[i] = JCARD_APPEND;
}
}
for(i=0; i<nField; i++){
const char *zValue;
int nValue;
if( aField[i].zAppend ) continue;
zValue = Th_Fetch(aField[i].zName, &nValue);
if( zValue ){
while( nValue>0 && fossil_isspace(zValue[nValue-1]) ){ nValue--; }
if( ((aField[i].mUsed & USEDBY_TICKETCHNG)!=0 && nValue>0)
|| memcmp(zValue, aField[i].zValue, nValue)!=0
||(int)strlen(aField[i].zValue)!=nValue
){
if( memcmp(aField[i].zName, "private_", 8)==0 ){
zValue = db_conceal(zValue, nValue);
blob_appendf(&tktchng, "J %s %s\n", aField[i].zName, zValue);
aUsed[i] = JCARD_PRIVATE;
}else{
blob_appendf(&tktchng, "J %s %#F\n", aField[i].zName, nValue, zValue);
aUsed[i] = JCARD_ASSIGN;
}
nJ++;
}
}
}
if( *(char**)pUuid ){
zUuid = db_text(0,
"SELECT tkt_uuid FROM ticket WHERE tkt_uuid GLOB '%q*'", P("name")
);
}else{
zUuid = db_text(0, "SELECT lower(hex(randomblob(20)))");
}
*(const char**)pUuid = zUuid;
blob_appendf(&tktchng, "K %s\n", zUuid);
blob_appendf(&tktchng, "U %F\n", login_name());
md5sum_blob(&tktchng, &cksum);
blob_appendf(&tktchng, "Z %b\n", &cksum);
if( nJ==0 ){
blob_reset(&tktchng);
goto finish;
}
needMod = ticket_need_moderation(0);
if( g.zPath[0]=='d' ){
const char *zNeedMod = needMod ? "required" : "skipped";
/* If called from /debug_tktnew or /debug_tktedit... */
@ <div style="color:blue">
@ <p>Ticket artifact that would have been submitted:</p>
@ <blockquote><pre>%h(blob_str(&tktchng))</pre></blockquote>
@ <blockquote><pre>Moderation would be %h(zNeedMod).</pre></blockquote>
@ </div>
@ <hr>
}else{
if( g.thTrace ){
Th_Trace("submit_ticket {\n<blockquote><pre>\n%h\n</pre></blockquote>\n"
"}<br>\n",
blob_str(&tktchng));
}
ticket_put(&tktchng, zUuid, aUsed, needMod);
rc = ticket_change(zUuid);
}
finish:
fossil_free( aUsed );
return rc;
}
/*
** WEBPAGE: tktnew
** WEBPAGE: debug_tktnew
**
** Enter a new ticket. The tktnew_template script in the ticket
** configuration is used. The /tktnew page is the official ticket
** entry page. The /debug_tktnew page is used for debugging the
** tktnew_template in the ticket configuration. /debug_tktnew works
** just like /tktnew except that it does not really save the new ticket
** when you press submit - it just prints the ticket artifact at the
** top of the screen.
*/
void tktnew_page(void){
const char *zScript;
char *zNewUuid = 0;
int uid;
login_check_credentials();
if( !g.perm.NewTkt ){ login_needed(g.anon.NewTkt); return; }
if( P("cancel") ){
cgi_redirect("home");
}
style_set_current_feature("tkt");
style_header("New Ticket");
ticket_standard_submenu(T_ALL_BUT(T_NEW));
if( g.thTrace ) Th_Trace("BEGIN_TKTNEW<br>\n", -1);
ticket_init();
initializeVariablesFromCGI();
getAllTicketFields();
initializeVariablesFromDb();
if( g.zPath[0]=='d' ) showAllFields();
form_begin(0, "%R/%s", g.zPath);
if( P("date_override") && g.perm.Setup ){
@ <input type="hidden" name="date_override" value="%h(P("date_override"))">
}
zScript = ticket_newpage_code();
if( g.zLogin && g.zLogin[0] ){
int nEmail = 0;
(void)Th_MaybeGetVar(g.interp, "private_contact", &nEmail);
uid = nEmail>0
? 0 : db_int(0, "SELECT uid FROM user WHERE login=%Q", g.zLogin);
if( uid ){
char * zEmail =
db_text(0, "SELECT find_emailaddr(info) FROM user WHERE uid=%d",
uid);
if( zEmail ){
Th_Store("private_contact", zEmail);
fossil_free(zEmail);
}
}
}
Th_Store("login", login_name());
Th_Store("date", db_text(0, "SELECT datetime('now')"));
Th_CreateCommand(g.interp, "submit_ticket", submitTicketCmd,
(void*)&zNewUuid, 0);
if( g.thTrace ) Th_Trace("BEGIN_TKTNEW_SCRIPT<br>\n", -1);
if( Th_Render(zScript)==TH_RETURN && !g.thTrace && zNewUuid ){
cgi_redirect(mprintf("%R/tktview/%s", zNewUuid));
return;
}
captcha_generate(0);
@ </form>
if( g.thTrace ) Th_Trace("END_TKTVIEW<br>\n", -1);
style_finish_page();
}
/*
** WEBPAGE: tktedit
** WEBPAGE: debug_tktedit
**
|
| ︙ | ︙ | |||
944 945 946 947 948 949 950 |
login_check_credentials();
if( !g.perm.ApndTkt && !g.perm.WrTkt ){
login_needed(g.anon.ApndTkt || g.anon.WrTkt);
return;
}
zName = P("name");
if( P("cancel") ){
| | | 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 |
login_check_credentials();
if( !g.perm.ApndTkt && !g.perm.WrTkt ){
login_needed(g.anon.ApndTkt || g.anon.WrTkt);
return;
}
zName = P("name");
if( P("cancel") ){
cgi_redirectf("tktview/%T", zName);
}
style_set_current_feature("tkt");
style_header("Edit Ticket");
if( zName==0 || (nName = strlen(zName))<4 || nName>HNAME_LEN_SHA1
|| !validate16(zName,nName) ){
@ <span class="tktError">Not a valid ticket id: "%h(zName)"</span>
style_finish_page();
|
| ︙ | ︙ | |||
967 968 969 970 971 972 973 |
}
if( nRec>1 ){
@ <span class="tktError">%d(nRec) tickets begin with:
@ "%h(zName)"</span>
style_finish_page();
return;
}
| | | < | | | 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 |
}
if( nRec>1 ){
@ <span class="tktError">%d(nRec) tickets begin with:
@ "%h(zName)"</span>
style_finish_page();
return;
}
if( g.thTrace ) Th_Trace("BEGIN_TKTEDIT<br>\n", -1);
ticket_init();
getAllTicketFields();
initializeVariablesFromCGI();
initializeVariablesFromDb();
if( g.zPath[0]=='d' ) showAllFields();
form_begin(0, "%R/%s", g.zPath);
@ <input type="hidden" name="name" value="%s(zName)">
zScript = ticket_editpage_code();
Th_Store("login", login_name());
Th_Store("date", db_text(0, "SELECT datetime('now')"));
Th_CreateCommand(g.interp, "append_field", appendRemarkCmd, 0, 0);
Th_CreateCommand(g.interp, "submit_ticket", submitTicketCmd, (void*)&zName,0);
if( g.thTrace ) Th_Trace("BEGIN_TKTEDIT_SCRIPT<br>\n", -1);
if( Th_Render(zScript)==TH_RETURN && !g.thTrace && zName ){
cgi_redirect(mprintf("%R/tktview/%s", zName));
return;
}
captcha_generate(0);
@ </form>
if( g.thTrace ) Th_Trace("BEGIN_TKTEDIT<br>\n", -1);
style_finish_page();
}
/*
** Check the ticket table schema in zSchema to see if it appears to
** be well-formed. If everything is OK, return NULL. If something is
** amiss, then return a pointer to a string (obtained from malloc) that
|
| ︙ | ︙ | |||
1101 1102 1103 1104 1105 1106 1107 |
if( !g.perm.Hyperlink || !g.perm.RdTkt ){
login_needed(g.anon.Hyperlink && g.anon.RdTkt);
return;
}
zUuid = PD("name","");
zType = PD("y","a");
if( zType[0]!='c' ){
| > | > | | 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 |
if( !g.perm.Hyperlink || !g.perm.RdTkt ){
login_needed(g.anon.Hyperlink && g.anon.RdTkt);
return;
}
zUuid = PD("name","");
zType = PD("y","a");
if( zType[0]!='c' ){
if( g.perm.Read ){
style_submenu_element("Check-ins", "%R/tkttimeline/%T?y=ci", zUuid);
}
}else{
style_submenu_element("Timeline", "%R/tkttimeline/%T", zUuid);
}
style_submenu_element("History", "%R/tkthistory/%s", zUuid);
style_submenu_element("Status", "%R/info/%s", zUuid);
if( zType[0]=='c' ){
zTitle = mprintf("Check-ins Associated With Ticket %h", zUuid);
}else{
zTitle = mprintf("Timeline Of Ticket %h", zUuid);
|
| ︙ | ︙ | |||
1129 1130 1131 1132 1133 1134 1135 | } tkt_draw_timeline(tagid, zType); style_finish_page(); } /* ** WEBPAGE: tkthistory | | > > > > > | > | > > > > | 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 |
}
tkt_draw_timeline(tagid, zType);
style_finish_page();
}
/*
** WEBPAGE: tkthistory
** URL: /tkthistory/TICKETUUID
**
** Show the complete change history for a single ticket. Or (to put it
** another way) show a list of artifacts associated with a single ticket.
**
** By default, the artifacts are decoded and formatted. Text fields
** are formatted as text/plain, since in the general case Fossil does
** not have knowledge of the encoding. If the "raw" query parameter
** is present, then the undecoded and unformatted text of each artifact
** is displayed.
**
** Reassignments of a field of the TICKET table that has a corresponding
** "baseline for ..." companion are rendered as unified diffs.
*/
void tkthistory_page(void){
Stmt q;
char *zTitle;
const char *zUuid;
int tagid;
int nChng = 0;
Blob *aLastVal = 0; /* holds the last rendered value for each field */
login_check_credentials();
if( !g.perm.Hyperlink || !g.perm.RdTkt ){
login_needed(g.anon.Hyperlink && g.anon.RdTkt);
return;
}
zUuid = PD("name","");
zTitle = mprintf("History Of Ticket %h", zUuid);
style_submenu_element("Status", "%R/info/%s", zUuid);
if( g.perm.Read ){
style_submenu_element("Check-ins", "%R/tkttimeline/%s?y=ci", zUuid);
}
style_submenu_element("Timeline", "%R/tkttimeline/%s", zUuid);
if( P("raw")!=0 ){
style_submenu_element("Decoded", "%R/tkthistory/%s", zUuid);
}else if( g.perm.Admin ){
style_submenu_element("Raw", "%R/tkthistory/%s?raw", zUuid);
}
style_set_current_feature("tkt");
style_header("%z", zTitle);
tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname GLOB 'tkt-%q*'",zUuid);
if( tagid==0 ){
@ No such ticket: %h(zUuid)
style_finish_page();
return;
}
if( P("raw")!=0 ){
@ <h2>Raw Artifacts Associated With Ticket %h(zUuid)</h2>
}else{
@ <h2>Artifacts Associated With Ticket %h(zUuid)</h2>
getAllTicketFields();
if( nTicketBslns ){
aLastVal = blobarray_new(nField);
}
}
db_prepare(&q,
"SELECT datetime(mtime,toLocal()), objid, uuid, NULL, NULL, NULL"
" FROM event, blob"
" WHERE objid IN (SELECT rid FROM tagxref WHERE tagid=%d)"
" AND blob.rid=event.objid"
" UNION "
|
| ︙ | ︙ | |||
1196 1197 1198 1199 1200 1201 1202 |
for(nChng=0; db_step(&q)==SQLITE_ROW; nChng++){
Manifest *pTicket;
const char *zDate = db_column_text(&q, 0);
int rid = db_column_int(&q, 1);
const char *zChngUuid = db_column_text(&q, 2);
const char *zFile = db_column_text(&q, 4);
if( nChng==0 ){
| | < | > > | < | | | | | > > > > > | > < < < | < | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | | | | | | > > > > > | > > > > > > > > > | 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 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 |
for(nChng=0; db_step(&q)==SQLITE_ROW; nChng++){
Manifest *pTicket;
const char *zDate = db_column_text(&q, 0);
int rid = db_column_int(&q, 1);
const char *zChngUuid = db_column_text(&q, 2);
const char *zFile = db_column_text(&q, 4);
if( nChng==0 ){
@ <ol class="tkt-changes">
}
if( zFile!=0 ){
const char *zSrc = db_column_text(&q, 3);
const char *zUser = db_column_text(&q, 5);
@
@ <li id="%S(zChngUuid)"><p><span>
if( zSrc==0 || zSrc[0]==0 ){
@ Delete attachment "%h(zFile)"
}else{
@ Add attachment
@ "%z(href("%R/artifact/%!S",zSrc))%s(zFile)</a>"
}
@ [%z(href("%R/artifact/%!S",zChngUuid))%S(zChngUuid)</a>]</span>
@ (rid %d(rid)) by
hyperlink_to_user(zUser,zDate," on");
hyperlink_to_date(zDate, ".</p>");
}else{
pTicket = manifest_get(rid, CFTYPE_TICKET, 0);
if( pTicket ){
@
@ <li id="%S(zChngUuid)"><p><span>Ticket change
@ [%z(href("%R/artifact/%!S",zChngUuid))%S(zChngUuid)</a>]</span>
@ (rid %d(rid)) by
hyperlink_to_user(pTicket->zUser,zDate," on");
hyperlink_to_date(zDate, ":");
@ </p>
if( P("raw")!=0 ){
Blob c;
content_get(rid, &c);
@ <blockquote><pre>
@ %h(blob_str(&c))
@ </pre></blockquote>
blob_reset(&c);
}else{
ticket_output_change_artifact(pTicket, "a", nChng, aLastVal);
}
}
manifest_destroy(pTicket);
}
@ </li>
}
db_finalize(&q);
if( nChng ){
@ </ol>
}
style_finish_page();
if( aLastVal ) blobarray_delete(aLastVal, nField);
}
/*
** Return TRUE if the given BLOB contains a newline character.
*/
static int contains_newline(Blob *p){
const char *z = blob_str(p);
while( *z ){
if( *z=='\n' ) return 1;
z++;
}
return 0;
}
/*
** The pTkt object is a ticket change artifact. Output a detailed
** description of this object.
**
** If `aLastVal` is not NULL then render selected fields as unified diffs
** and update corresponding elements of that array with values from `pTkt`.
*/
void ticket_output_change_artifact(
Manifest *pTkt, /* Parsed artifact for the ticket change */
const char *zListType, /* Which type of list */
int n, /* Which ticket change is this */
Blob *aLastVal /* Array of the latest values for the diffs */
){
int i;
if( zListType==0 ) zListType = "1";
getAllTicketFields();
@ <ol type="%s(zListType)">
for(i=0; i<pTkt->nField; i++){
const char *z = pTkt->aField[i].zName;
const char *zX = z[0]=='+' ? z+1 : z;
const int id = fieldId(zX);
const char *zValue = pTkt->aField[i].zValue;
const size_t nValue = strlen(zValue);
const int bLong = nValue>50 || memchr(zValue,'\n',nValue)!=NULL;
/* zValue is long enough to justify a <blockquote> */
const int bCanDiff = aLastVal && id>=0 && aField[id].zBsln;
/* preliminary flag for rendering via unified diff */
int bAppend = 0; /* zValue is being appended to a TICKET's field */
int bRegular = 0; /* prev value of a TICKET's field is being superseded*/
@ <li>\
if( id<0 ){
@ Untracked field %h(zX):
}else if( aField[id].mUsed==USEDBY_TICKETCHNG ){
@ %h(zX):
}else if( n==0 ){
@ %h(zX) initialized to:
}else if( z[0]=='+' && (aField[id].mUsed&USEDBY_TICKET)!=0 ){
@ Appended to %h(zX):
bAppend = 1;
}else{
if( !bCanDiff ){
@ %h(zX) changed to: \
}
bRegular = 1;
}
if( bCanDiff ){
Blob *prev = aLastVal+id;
Blob val = BLOB_INITIALIZER;
if( nValue ){
blob_init(&val, zValue, nValue+1);
val.nUsed--; /* makes blob_str() faster */
}
if( bRegular && nValue && blob_buffer(prev) && blob_size(prev) ){
Blob d = BLOB_INITIALIZER;
DiffConfig DCfg;
construct_diff_flags(1, &DCfg);
DCfg.diffFlags |= DIFF_HTML | DIFF_LINENO;
text_diff(prev, &val, &d, &DCfg);
@ %h(zX) changed as:
@ %s(blob_str(&d))
@ </li>
blob_reset(&d);
}else{
if( bRegular ){
@ %h(zX) changed to:
}
if( bLong ){
@ <blockquote><pre class='verbatim'>
@ %h(zValue)
@ </pre></blockquote></li>
}else{
@ "%h(zValue)"</li>
}
}
if( blob_buffer(prev) && blob_size(prev) && !bAppend ){
blob_truncate(prev,0);
}
if( nValue ) blob_appendb(prev, &val);
blob_reset(&val);
}else{
if( bLong ){
@ <blockquote><pre class='verbatim'>
@ %h(zValue)
@ </pre></blockquote></li>
}else{
@ "%h(zValue)"</li>
}
}
}
@ </ol>
}
/*
** COMMAND: ticket*
**
|
| ︙ | ︙ | |||
1381 1382 1383 1384 1385 1386 1387 |
*/
void ticket_cmd(void){
int n;
const char *zUser;
const char *zDate;
const char *zTktUuid;
| | | 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 |
*/
void ticket_cmd(void){
int n;
const char *zUser;
const char *zDate;
const char *zTktUuid;
/* do some ints, we want to be inside a check-out */
db_find_and_open_repository(0, 0);
user_select();
zUser = find_option("user-override",0,1);
if( zUser==0 ) zUser = login_name();
zDate = find_option("date-override",0,1);
if( zDate==0 ) zDate = "now";
|
| ︙ | ︙ | |||
1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 |
rptshow( zRep, zSep, zFilterUuid, tktEncoding );
}
}else{
/* add a new ticket or update an existing ticket */
enum { set,add,history,err } eCmd = err;
int i = 0;
Blob tktchng, cksum;
/* get command type (set/add) and get uuid, if needed for set */
if( strncmp(g.argv[2],"set",n)==0 || strncmp(g.argv[2],"change",n)==0 ||
strncmp(g.argv[2],"history",n)==0 ){
if( strncmp(g.argv[2],"history",n)==0 ){
eCmd = history;
}else{
| > | 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 |
rptshow( zRep, zSep, zFilterUuid, tktEncoding );
}
}else{
/* add a new ticket or update an existing ticket */
enum { set,add,history,err } eCmd = err;
int i = 0;
Blob tktchng, cksum;
char *aUsed;
/* get command type (set/add) and get uuid, if needed for set */
if( strncmp(g.argv[2],"set",n)==0 || strncmp(g.argv[2],"change",n)==0 ||
strncmp(g.argv[2],"history",n)==0 ){
if( strncmp(g.argv[2],"history",n)==0 ){
eCmd = history;
}else{
|
| ︙ | ︙ | |||
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 |
if( append ){
aField[j].zAppend = zFValue;
}else{
aField[j].zValue = zFValue;
}
}
}
/* now add the needed artifacts to the repository */
blob_zero(&tktchng);
/* add the time to the ticket manifest */
blob_appendf(&tktchng, "D %s\n", zDate);
/* append defined elements */
for(i=0; i<nField; i++){
char *zValue = 0;
char *zPfx;
if( aField[i].zAppend && aField[i].zAppend[0] ){
zPfx = " +";
zValue = aField[i].zAppend;
}else if( aField[i].zValue && aField[i].zValue[0] ){
zPfx = " ";
zValue = aField[i].zValue;
}else{
continue;
}
if( memcmp(aField[i].zName, "private_", 8)==0 ){
zValue = db_conceal(zValue, strlen(zValue));
blob_appendf(&tktchng, "J%s%s %s\n", zPfx, aField[i].zName, zValue);
}else{
blob_appendf(&tktchng, "J%s%s %#F\n", zPfx,
aField[i].zName, strlen(zValue), zValue);
}
}
blob_appendf(&tktchng, "K %s\n", zTktUuid);
blob_appendf(&tktchng, "U %F\n", zUser);
md5sum_blob(&tktchng, &cksum);
blob_appendf(&tktchng, "Z %b\n", &cksum);
| > > > > | > > | 1792 1793 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 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 |
if( append ){
aField[j].zAppend = zFValue;
}else{
aField[j].zValue = zFValue;
}
}
}
aUsed = fossil_malloc_zero( nField );
/* now add the needed artifacts to the repository */
blob_zero(&tktchng);
/* add the time to the ticket manifest */
blob_appendf(&tktchng, "D %s\n", zDate);
/* append defined elements */
for(i=0; i<nField; i++){
char *zValue = 0;
char *zPfx;
if( aField[i].zAppend && aField[i].zAppend[0] ){
zPfx = " +";
zValue = aField[i].zAppend;
aUsed[i] = JCARD_APPEND;
}else if( aField[i].zValue && aField[i].zValue[0] ){
zPfx = " ";
zValue = aField[i].zValue;
aUsed[i] = JCARD_ASSIGN;
}else{
continue;
}
if( memcmp(aField[i].zName, "private_", 8)==0 ){
zValue = db_conceal(zValue, strlen(zValue));
blob_appendf(&tktchng, "J%s%s %s\n", zPfx, aField[i].zName, zValue);
aUsed[i] = JCARD_PRIVATE;
}else{
blob_appendf(&tktchng, "J%s%s %#F\n", zPfx,
aField[i].zName, strlen(zValue), zValue);
}
}
blob_appendf(&tktchng, "K %s\n", zTktUuid);
blob_appendf(&tktchng, "U %F\n", zUser);
md5sum_blob(&tktchng, &cksum);
blob_appendf(&tktchng, "Z %b\n", &cksum);
if( ticket_put(&tktchng, zTktUuid, aUsed,
ticket_need_moderation(1) )==0 ){
fossil_fatal("%s", g.zErrMsg);
}else{
fossil_print("ticket %s succeeded for %s\n",
(eCmd==set?"set":"add"),zTktUuid);
}
fossil_free( aUsed );
}
}
}
#if INTERFACE
/* Standard submenu items for wiki pages */
|
| ︙ | ︙ |
Changes to src/tktsetup.c.
| ︙ | ︙ | |||
133 134 135 136 137 138 139 |
isSubmit = P("submit")!=0;
z = P("x");
if( z==0 ){
z = db_get(zDbField, zDfltValue);
}
style_set_current_feature("tktsetup");
style_header("Edit %s", zTitle);
| | < | < | | | | | 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 |
isSubmit = P("submit")!=0;
z = P("x");
if( z==0 ){
z = db_get(zDbField, zDfltValue);
}
style_set_current_feature("tktsetup");
style_header("Edit %s", zTitle);
if( P("clear")!=0 && cgi_csrf_safe(2) ){
db_unset(zDbField/*works-like:"x"*/, 0);
if( xRebuild ) xRebuild();
cgi_redirect("tktsetup");
}else if( isSubmit && cgi_csrf_safe(2) ){
char *zErr = 0;
if( xText && (zErr = xText(z))!=0 ){
@ <p class="tktsetupError">ERROR: %h(zErr)</p>
}else{
db_set(zDbField/*works-like:"x"*/, z, 0);
if( xRebuild ) xRebuild();
cgi_redirect("tktsetup");
}
}
@ <form action="%R/%s(g.zPath)" method="post"><div>
login_insert_csrf_secret();
@ <p>%s(zDesc)</p>
@ <textarea name="x" rows="%d(height)" cols="80">%h(z)</textarea>
@ <blockquote><p>
@ <input type="submit" name="submit" value="Apply Changes">
@ <input type="submit" name="clear" value="Revert To Default">
@ <input type="submit" name="setup" value="Cancel">
@ </p></blockquote>
@ </div></form>
@ <hr>
@ <h2>Default %s(zTitle)</h2>
@ <blockquote><pre>
@ %h(zDfltValue)
@ </pre></blockquote>
style_finish_page();
}
|
| ︙ | ︙ | |||
322 323 324 325 326 327 328 | @ set preview 1 @ } @ </th1> @ <h1 style="text-align: center;">Enter A New Ticket</h1> @ <table cellpadding="5"> @ <tr> @ <td colspan="3"> | | | | | < | | | | | | | | 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 |
@ set preview 1
@ }
@ </th1>
@ <h1 style="text-align: center;">Enter A New Ticket</h1>
@ <table cellpadding="5">
@ <tr>
@ <td colspan="3">
@ Enter a one-line summary of the ticket:<br>
@ <input type="text" name="title" size="60" value="$<title>">
@ </td>
@ </tr>
@
@ <tr>
@ <td align="right">Type:</td>
@ <td align="left"><th1>combobox type $type_choices 1</th1></td>
@ <td align="left">What type of ticket is this?</td>
@ </tr>
@
@ <tr>
@ <td align="right">Version:</td>
@ <td align="left">
@ <input type="text" name="foundin" size="20" value="$<foundin>">
@ </td>
@ <td align="left">In what version or build number do you observe
@ the problem?</td>
@ </tr>
@
@ <tr>
@ <td align="right">Severity:</td>
@ <td align="left"><th1>combobox severity $severity_choices 1</th1></td>
@ <td align="left">How debilitating is the problem? How badly does the problem
@ affect the operation of the product?</td>
@ </tr>
@
@ <tr>
@ <td align="right">EMail:</td>
@ <td align="left">
@ <input name="private_contact" value="$<private_contact>" size="30">
@ </td>
@ <td align="left"><u>Not publicly visible</u>
@ Used by developers to contact you with questions.</td>
@ </tr>
@
@ <tr>
@ <td colspan="3">
@ Enter a detailed description of the problem.
@ For code defects, be sure to provide details on exactly how
@ the problem can be reproduced. Provide as much detail as
@ possible. Format:
@ <th1>combobox mutype {HTML {[links only]} Markdown {Plain Text} Wiki} 1</th1>
@ <br>
@ <th1>set nline [linecount $comment 50 10]</th1>
@ <textarea name="icomment" cols="80" rows="$nline"
@ wrap="virtual" class="wikiedit">$<icomment></textarea><br>
@ </tr>
@
@ <th1>enable_output [info exists preview]</th1>
@ <tr><td colspan="3">
@ Description Preview:<br><hr>
@ <th1>
@ if {$mutype eq "Wiki"} {
@ wiki $icomment
@ } elseif {$mutype eq "Plain Text"} {
@ set r [randhex]
@ wiki "<verbatim-$r>[string trimright $icomment]\n</verbatim-$r>"
@ } elseif {$mutype eq "Markdown"} {
@ html [lindex [markdown "$icomment\n"] 1]
@ } elseif {$mutype eq {[links only]}} {
@ set r [randhex]
@ wiki "<verbatim-$r links>[string trimright $icomment]\n</verbatim-$r>"
@ } else {
@ wiki "<nowiki>$icomment\n</nowiki>"
@ }
@ </th1>
@ <hr></td></tr>
@ <th1>enable_output 1</th1>
@
@ <tr>
@ <td><td align="left">
@ <input type="submit" name="preview" value="Preview">
@ </td>
@ <td align="left">See how the description will appear after formatting.</td>
@ </tr>
@
@ <th1>enable_output [info exists preview]</th1>
@ <tr>
@ <td><td align="left">
@ <input type="submit" name="submit" value="Submit">
@ </td>
@ <td align="left">After filling in the information above, press this
@ button to create the new ticket</td>
@ </tr>
@ <th1>enable_output 1</th1>
@
@ <tr>
@ <td><td align="left">
@ <input type="submit" name="cancel" value="Cancel">
@ </td>
@ <td>Abandon and forget this ticket</td>
@ </tr>
@ </table>
;
/*
|
| ︙ | ︙ | |||
530 531 532 533 534 535 536 |
@ set alwaysPlaintext [info exists plaintext]
@ query {SELECT datetime(tkt_mtime) AS xdate, login AS xlogin,
@ mimetype as xmimetype, icomment AS xcomment,
@ username AS xusername
@ FROM ticketchng
@ WHERE tkt_id=$tkt_id AND length(icomment)>0} {
@ if {$seenRow} {
| | | 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 |
@ set alwaysPlaintext [info exists plaintext]
@ query {SELECT datetime(tkt_mtime) AS xdate, login AS xlogin,
@ 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'>User Comments:</td></tr>\n"
@ html "<tr><td colspan='5' class='tktDspValue'>\n"
@ set seenRow 1
@ }
@ html "<span class='tktDspCommenter'>"
@ html "[htmlize $xlogin]"
|
| ︙ | ︙ | |||
614 615 616 617 618 619 620 | @ } @ submit_ticket @ set preview 1 @ } @ </th1> @ <table cellpadding="5"> @ <tr><td class="tktDspLabel">Title:</td><td> | | | 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 | @ } @ submit_ticket @ set preview 1 @ } @ </th1> @ <table cellpadding="5"> @ <tr><td class="tktDspLabel">Title:</td><td> @ <input type="text" name="title" value="$<title>" size="60"> @ </td></tr> @ @ <tr><td class="tktDspLabel">Status:</td><td> @ <th1>combobox status $status_choices 1</th1> @ </td></tr> @ @ <tr><td class="tktDspLabel">Type:</td><td> |
| ︙ | ︙ | |||
644 645 646 647 648 649 650 | @ <tr><td class="tktDspLabel">Subsystem:</td><td> @ <th1>combobox subsystem $subsystem_choices 1</th1> @ </td></tr> @ @ <th1>enable_output [hascap e]</th1> @ <tr><td class="tktDspLabel">Contact:</td><td> @ <input type="text" name="private_contact" size="40" | | | | | | | | | | 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 |
@ <tr><td class="tktDspLabel">Subsystem:</td><td>
@ <th1>combobox subsystem $subsystem_choices 1</th1>
@ </td></tr>
@
@ <th1>enable_output [hascap e]</th1>
@ <tr><td class="tktDspLabel">Contact:</td><td>
@ <input type="text" name="private_contact" size="40"
@ value="$<private_contact>">
@ </td></tr>
@ <th1>enable_output 1</th1>
@
@ <tr><td class="tktDspLabel">Version Found In:</td><td>
@ <input type="text" name="foundin" size="50" value="$<foundin>">
@ </td></tr>
@
@ <tr><td colspan="2">
@ Append Remark with format
@ <th1>combobox mutype {HTML {[links only]} Markdown {Plain Text} Wiki} 1</th1>
@ from
@ <input type="text" name="username" value="$<username>" size="30">:<br>
@ <textarea name="icomment" cols="80" rows="15"
@ wrap="virtual" class="wikiedit">$<icomment></textarea>
@ </td></tr>
@
@ <th1>enable_output [info exists preview]</th1>
@ <tr><td colspan="2">
@ Description Preview:<br><hr>
@ <th1>
@ if {$mutype eq "Wiki"} {
@ wiki $icomment
@ } elseif {$mutype eq "Plain Text"} {
@ set r [randhex]
@ wiki "<verbatim-$r>\n[string trimright $icomment]\n</verbatim-$r>"
@ } elseif {$mutype eq "Markdown"} {
@ html [lindex [markdown "$icomment\n"] 1]
@ } elseif {$mutype eq {[links only]}} {
@ set r [randhex]
@ wiki "<verbatim-$r links>\n[string trimright $icomment]</verbatim-$r>"
@ } else {
@ wiki "<nowiki>\n[string trimright $icomment]\n</nowiki>"
@ }
@ </th1>
@ <hr>
@ </td></tr>
@ <th1>enable_output 1</th1>
@
@ <tr>
@ <td align="right">
@ <input type="submit" name="preview" value="Preview">
@ </td>
@ <td align="left">See how the description will appear after formatting.</td>
@ </tr>
@
@ <th1>enable_output [info exists preview]</th1>
@ <tr>
@ <td align="right">
@ <input type="submit" name="submit" value="Submit">
@ </td>
@ <td align="left">Apply the changes shown above</td>
@ </tr>
@ <th1>enable_output 1</th1>
@
@ <tr>
@ <td align="right">
@ <input type="submit" name="cancel" value="Cancel">
@ </td>
@ <td>Abandon this edit</td>
@ </tr>
@
@ </table>
;
|
| ︙ | ︙ | |||
910 911 912 913 914 915 916 |
}
style_set_current_feature("tktsetup");
style_header("Ticket Display On Timelines");
db_begin_transaction();
@ <form action="%R/tktsetup_timeline" method="post"><div>
login_insert_csrf_secret();
| | | | | | | | 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 |
}
style_set_current_feature("tktsetup");
style_header("Ticket Display On Timelines");
db_begin_transaction();
@ <form action="%R/tktsetup_timeline" method="post"><div>
login_insert_csrf_secret();
@ <hr>
entry_attribute("Ticket Title", 40, "ticket-title-expr", "t",
"title", 0);
@ <p>An SQL expression in a query against the TICKET table that will
@ return the title of the ticket for display purposes.
@ (Property: ticket-title-expr)</p>
@ <hr>
entry_attribute("Ticket Status", 40, "ticket-status-column", "s",
"status", 0);
@ <p>The name of the column in the TICKET table that contains the ticket
@ status in human-readable form. Case sensitive.
@ (Property: ticket-status-column)</p>
@ <hr>
entry_attribute("Ticket Closed", 40, "ticket-closed-expr", "c",
"status='Closed'", 0);
@ <p>An SQL expression that evaluates to true in a TICKET table query if
@ the ticket is closed.
@ (Property: ticket-closed-expr)</p>
@ <hr>
@ <p>
@ <input type="submit" name="submit" value="Apply Changes">
@ <input type="submit" name="setup" value="Cancel">
@ </p>
@ </div></form>
db_end_transaction(0);
style_finish_page();
}
|
Changes to src/undo.c.
| ︙ | ︙ | |||
453 454 455 456 457 458 459 | ** If the most recent command is not one of those listed as undoable, ** then the undo command might try to restore the state to be what it was ** prior to the last undoable command, or it might be a no-op. If in ** doubt about what the undo command will do, first run it with the -n ** option. ** ** A single level of undo/redo is supported. The undo/redo stack | | | | 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 |
** If the most recent command is not one of those listed as undoable,
** then the undo command might try to restore the state to be what it was
** prior to the last undoable command, or it might be a no-op. If in
** doubt about what the undo command will do, first run it with the -n
** option.
**
** A single level of undo/redo is supported. The undo/redo stack
** is cleared by the commit and check-out commands. Other commands may
** or may not clear the undo stack.
**
** Future versions of Fossil might add new commands to the set of commands
** that are undoable.
**
** Options:
** -n|--dry-run Do not make changes, but show what would be done
**
** See also: [[commit]], [[status]]
*/
void undo_cmd(void){
int isRedo = g.argv[1][0]=='r';
int undo_available;
int dryRunFlag = find_option("dry-run", "n", 0)!=0;
|
| ︙ | ︙ |
Changes to src/unversioned.c.
| ︙ | ︙ | |||
248 249 250 251 252 253 254 | ** cat FILE ... Concatenate the content of FILEs to stdout. ** ** edit FILE Bring up FILE in a text editor for modification. ** ** export FILE OUTPUT Write the content of FILE into OUTPUT on disk ** ** list | ls Show all unversioned files held in the local | | > | > > < | | 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 |
** cat FILE ... Concatenate the content of FILEs to stdout.
**
** edit FILE Bring up FILE in a text editor for modification.
**
** export FILE OUTPUT Write the content of FILE into OUTPUT on disk
**
** list | ls Show all unversioned files held in the local
** repository.
**
** Options:
** --glob PATTERN Show only files that match
** --like PATTERN Show only files that match
** -l Show additional details for
** files that match. Implied
** when 'list' is used.
**
** 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 FILE as the repository
*/
void unversioned_cmd(void){
const char *zCmd;
int nCmd;
const char *zMtime = find_option("mtime", 0, 1);
sqlite3_int64 mtime;
db_find_and_open_repository(0, 0);
unversioned_schema();
zCmd = g.argc>=3 ? g.argv[2] : "x";
nCmd = (int)strlen(zCmd);
if( zMtime==0 ){
mtime = time(0);
}else{
mtime = db_int(0, "SELECT strftime('%%s',%Q)", zMtime);
if( mtime<=0 ) fossil_fatal("bad timestamp: %Q", zMtime);
}
if( strncmp(zCmd, "add", nCmd)==0 ){
const char *zError = 0;
const char *zIn;
const char *zAs;
Blob file;
int i;
zAs = find_option("as",0,1);
|
| ︙ | ︙ | |||
336 337 338 339 340 341 342 |
}
blob_init(&file,0,0);
blob_read_from_file(&file, g.argv[i], ExtFILE);
unversioned_write(zIn, &file, mtime);
blob_reset(&file);
}
db_end_transaction(0);
| | | | 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 |
}
blob_init(&file,0,0);
blob_read_from_file(&file, g.argv[i], ExtFILE);
unversioned_write(zIn, &file, mtime);
blob_reset(&file);
}
db_end_transaction(0);
}else if( strncmp(zCmd, "cat", nCmd)==0 ){
int i;
verify_all_options();
db_begin_transaction();
for(i=3; i<g.argc; i++){
Blob content;
if( unversioned_content(g.argv[i], &content)!=0 ){
blob_write_to_file(&content, "-");
}
blob_reset(&content);
}
db_end_transaction(0);
}else if( strncmp(zCmd, "edit", nCmd)==0 ){
const char *zEditor; /* Name of the text-editor command */
const char *zTFile; /* Temporary file */
const char *zUVFile; /* Name of the unversioned file */
char *zCmd; /* Command to run the text editor */
Blob content; /* Content of the unversioned file */
verify_all_options();
|
| ︙ | ︙ | |||
391 392 393 394 395 396 397 |
blob_to_lf_only(&content);
#endif
file_delete(zTFile);
if( zMtime==0 ) mtime = time(0);
unversioned_write(zUVFile, &content, mtime);
db_end_transaction(0);
blob_reset(&content);
| | | | | 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 |
blob_to_lf_only(&content);
#endif
file_delete(zTFile);
if( zMtime==0 ) mtime = time(0);
unversioned_write(zUVFile, &content, mtime);
db_end_transaction(0);
blob_reset(&content);
}else if( strncmp(zCmd, "export", nCmd)==0 ){
Blob content;
verify_all_options();
if( g.argc!=5 ) usage("export UVFILE OUTPUT");
if( unversioned_content(g.argv[3], &content)==0 ){
fossil_fatal("no such uv-file: %Q", g.argv[3]);
}
blob_write_to_file(&content, g.argv[4]);
blob_reset(&content);
}else if( strncmp(zCmd, "hash", nCmd)==0 ){ /* undocumented */
/* Show the hash value used during uv sync */
int debugFlag = find_option("debug",0,0)!=0;
fossil_print("%s\n", unversioned_content_hash(debugFlag));
}else if( strncmp(zCmd, "list", nCmd)==0 || strncmp(zCmd, "ls", nCmd)==0 ){
Stmt q;
int allFlag = find_option("all","a",0)!=0;
int longFlag = find_option("l",0,0)!=0 || (nCmd>1 && zCmd[1]=='i');
char *zPattern = sqlite3_mprintf("true");
const char *zGlob;
zGlob = find_option("glob",0,1);
if( zGlob ){
|
| ︙ | ︙ | |||
460 461 462 463 464 465 466 |
db_column_text(&q,4),
zNoContent
);
}
}
db_finalize(&q);
sqlite3_free(zPattern);
| | | | | | 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 |
db_column_text(&q,4),
zNoContent
);
}
}
db_finalize(&q);
sqlite3_free(zPattern);
}else if( strncmp(zCmd, "revert", nCmd)==0 ){
unsigned syncFlags =
unversioned_sync_flags(SYNC_UNVERSIONED|SYNC_UV_REVERT);
g.argv[1] = "sync";
g.argv[2] = "--uv-noop";
sync_unversioned(syncFlags);
}else if( strncmp(zCmd, "remove", nCmd)==0 || strncmp(zCmd, "rm", nCmd)==0
|| strncmp(zCmd, "delete", nCmd)==0 ){
int i;
const char *zGlob;
db_begin_transaction();
while( (zGlob = find_option("glob",0,1))!=0 ){
db_multi_exec(
"UPDATE unversioned"
" SET hash=NULL, content=NULL, mtime=%lld, sz=0 WHERE name GLOB %Q",
|
| ︙ | ︙ | |||
495 496 497 498 499 500 501 |
"UPDATE unversioned"
" SET hash=NULL, content=NULL, mtime=%lld, sz=0 WHERE name=%Q",
mtime, g.argv[i]
);
}
db_unset("uv-hash", 0);
db_end_transaction(0);
| | | | 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 |
"UPDATE unversioned"
" SET hash=NULL, content=NULL, mtime=%lld, sz=0 WHERE name=%Q",
mtime, g.argv[i]
);
}
db_unset("uv-hash", 0);
db_end_transaction(0);
}else if( strncmp(zCmd,"sync",nCmd)==0 ){
unsigned syncFlags = unversioned_sync_flags(SYNC_UNVERSIONED);
g.argv[1] = "sync";
g.argv[2] = "--uv-noop";
sync_unversioned(syncFlags);
}else if( strncmp(zCmd, "touch", nCmd)==0 ){
int i;
verify_all_options();
db_begin_transaction();
for(i=3; i<g.argc; i++){
db_multi_exec(
"UPDATE unversioned SET mtime=%lld WHERE name=%Q",
mtime, g.argv[i]
|
| ︙ | ︙ | |||
538 539 540 541 542 543 544 545 546 547 548 549 550 551 |
int n = 0;
const char *zOrderBy = "name";
int showDel = 0;
char zSzName[100];
login_check_credentials();
if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
etag_check(ETAG_DATA,0);
style_header("Unversioned Files");
if( !db_table_exists("repository","unversioned") ){
@ No unversioned files on this server
style_finish_page();
return;
}
| > | 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 |
int n = 0;
const char *zOrderBy = "name";
int showDel = 0;
char zSzName[100];
login_check_credentials();
if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
cgi_check_for_malice();
etag_check(ETAG_DATA,0);
style_header("Unversioned Files");
if( !db_table_exists("repository","unversioned") ){
@ No unversioned files on this server
style_finish_page();
return;
}
|
| ︙ | ︙ | |||
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 |
);
iNow = db_int64(0, "SELECT strftime('%%s','now');");
while( db_step(&q)==SQLITE_ROW ){
const char *zName = db_column_text(&q, 0);
sqlite3_int64 mtime = db_column_int(&q, 1);
const char *zHash = db_column_text(&q, 2);
int isDeleted = zHash==0;
int fullSize = db_column_int(&q, 3);
char *zAge = human_readable_age((iNow - mtime)/86400.0);
const char *zLogin = db_column_text(&q, 4);
int rcvid = db_column_int(&q,5);
if( zLogin==0 ) zLogin = "";
if( (n++)==0 ){
style_table_sorter();
@ <div class="uvlist">
@ <table cellpadding="2" cellspacing="0" border="1" class='sortable' \
@ data-column-types='tkKttn' data-init-sort='1'>
@ <thead><tr>
@ <th> Name
@ <th> Age
@ <th> Size
@ <th> User
@ <th> Hash
if( g.perm.Admin ){
@ <th> rcvid
}
@ </tr></thead>
@ <tbody>
}
@ <tr>
| > > > > | 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 |
);
iNow = db_int64(0, "SELECT strftime('%%s','now');");
while( db_step(&q)==SQLITE_ROW ){
const char *zName = db_column_text(&q, 0);
sqlite3_int64 mtime = db_column_int(&q, 1);
const char *zHash = db_column_text(&q, 2);
int isDeleted = zHash==0;
const char *zAlgo;
int fullSize = db_column_int(&q, 3);
char *zAge = human_readable_age((iNow - mtime)/86400.0);
const char *zLogin = db_column_text(&q, 4);
int rcvid = db_column_int(&q,5);
if( isDeleted ) zAlgo = "deleted";
else zAlgo = hname_alg(strlen(zHash));
if( zLogin==0 ) zLogin = "";
if( (n++)==0 ){
style_table_sorter();
@ <div class="uvlist">
@ <table cellpadding="2" cellspacing="0" border="1" class='sortable' \
@ data-column-types='tkKttn' data-init-sort='1'>
@ <thead><tr>
@ <th> Name
@ <th> Age
@ <th> Size
@ <th> User
@ <th> Hash
@ <th> Algo
if( g.perm.Admin ){
@ <th> rcvid
}
@ </tr></thead>
@ <tbody>
}
@ <tr>
|
| ︙ | ︙ | |||
603 604 605 606 607 608 609 |
iTotalSz += fullSize;
cnt++;
@ <td> <a href='%R/uv/%T(zName)'>%h(zName)</a> </td>
}
@ <td data-sortkey='%016llx(-mtime)'> %s(zAge) </td>
@ <td data-sortkey='%08x(fullSize)'> %s(zSzName) </td>
@ <td> %h(zLogin) </td>
| | > > | 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 |
iTotalSz += fullSize;
cnt++;
@ <td> <a href='%R/uv/%T(zName)'>%h(zName)</a> </td>
}
@ <td data-sortkey='%016llx(-mtime)'> %s(zAge) </td>
@ <td data-sortkey='%08x(fullSize)'> %s(zSzName) </td>
@ <td> %h(zLogin) </td>
@ <td><code> %h(zHash) </code></td>
@ <td> %s(zAlgo) </td>
if( g.perm.Admin ){
if( rcvid ){
@ <td> <a href="%R/rcvfrom?rcvid=%d(rcvid)">%d(rcvid)</a>
}else{
@ <td>
}
}
@ </tr>
fossil_free(zAge);
}
db_finalize(&q);
if( n ){
approxSizeName(sizeof(zSzName), zSzName, iTotalSz);
@ </tbody>
@ <tfoot><tr><td><b>Total for %d(cnt) files</b><td><td>%s(zSzName)
@ <td><td>
if( g.perm.Admin ){
@ <td>
}
@ <td>
@ </tfoot>
@ </table></div>
}else{
@ No unversioned files on this server.
}
style_finish_page();
}
|
| ︙ | ︙ | |||
650 651 652 653 654 655 656 657 658 659 660 661 662 663 |
void uvlist_json_page(void){
Stmt q;
char *zSep = "[";
Blob json;
login_check_credentials();
if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
cgi_set_content_type("application/json");
etag_check(ETAG_DATA,0);
if( !db_table_exists("repository","unversioned") ){
blob_init(&json, "[]", -1);
cgi_set_content(&json);
return;
}
| > | 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 |
void uvlist_json_page(void){
Stmt q;
char *zSep = "[";
Blob json;
login_check_credentials();
if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
cgi_check_for_malice();
cgi_set_content_type("application/json");
etag_check(ETAG_DATA,0);
if( !db_table_exists("repository","unversioned") ){
blob_init(&json, "[]", -1);
cgi_set_content(&json);
return;
}
|
| ︙ | ︙ |
Changes to src/update.c.
| ︙ | ︙ | |||
12 13 14 15 16 17 18 | ** Author contact information: ** drh@hwaci.com ** http://www.hwaci.com/drh/ ** ******************************************************************************* ** ** This file contains code used to merge the changes in the current | | | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | ** Author contact information: ** drh@hwaci.com ** http://www.hwaci.com/drh/ ** ******************************************************************************* ** ** This file contains code used to merge the changes in the current ** check-out into a different version and switch to that version. */ #include "config.h" #include "update.h" #include <assert.h> /* ** Return true if artifact rid is a version |
| ︙ | ︙ | |||
60 61 62 63 64 65 66 | } /* ** COMMAND: update ** ** Usage: %fossil update ?OPTIONS? ?VERSION? ?FILES...? ** | | | | | | | | | 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 | } /* ** COMMAND: update ** ** Usage: %fossil update ?OPTIONS? ?VERSION? ?FILES...? ** ** Change the version of the current check-out to VERSION. Any ** uncommitted changes are retained and applied to the new check-out. ** ** The VERSION argument can be a specific version or tag or branch ** name. If the VERSION argument is omitted, then the leaf of the ** subtree that begins at the current version is used, if there is ** only a single leaf. VERSION can also be "current" to select the ** leaf of the current version or "latest" to select the most recent ** check-in. ** ** If one or more FILES are listed after the VERSION then only the ** named files are candidates to be updated, and any updates to them ** will be treated as edits to the current version. Using a directory ** name for one of the FILES arguments is the same as using every ** subdirectory and file beneath that directory. ** ** If FILES is omitted, all files in the current check-out are subject ** to being updated and the version of the current check-out is changed ** to VERSION. Any uncommitted changes are retained and applied to the ** new check-out. ** ** The -n or --dry-run option causes this command to do a "dry run". ** It prints out what would have happened but does not actually make ** any changes to the current check-out or the repository. ** ** The -v or --verbose option prints status information about ** unchanged files in addition to those file that actually do change. ** ** Options: ** --case-sensitive BOOL Override case-sensitive setting ** --debug Print debug information on stdout ** -n|--dry-run If given, display instead of run actions ** --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). ** ** See also: [[revert]] */ |
| ︙ | ︙ | |||
250 251 252 253 254 255 256 |
if( load_vfile_from_rid(tid) && !forceMissingFlag ){
fossil_fatal("missing content, unable to update");
};
/*
** The record.fn field is used to match files against each other. The
** FV table contains one row for each each unique filename in
| | | 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 |
if( load_vfile_from_rid(tid) && !forceMissingFlag ){
fossil_fatal("missing content, unable to update");
};
/*
** The record.fn field is used to match files against each other. The
** FV table contains one row for each each unique filename in
** in the current check-out, the pivot, and the version being merged.
*/
db_multi_exec(
"DROP TABLE IF EXISTS fv;"
"CREATE TEMP TABLE fv("
" fn TEXT %s PRIMARY KEY," /* The filename relative to root */
" idv INTEGER," /* VFILE entry for current version */
" idt INTEGER," /* VFILE entry for target version */
|
| ︙ | ︙ | |||
387 388 389 390 391 392 393 |
blob_reset(&treename);
}
db_multi_exec("%s", blob_sql_text(&sql));
blob_reset(&sql);
}
/*
| | | 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 |
blob_reset(&treename);
}
db_multi_exec("%s", blob_sql_text(&sql));
blob_reset(&sql);
}
/*
** Alter the content of the check-out so that it conforms with the
** target
*/
db_prepare(&q,
"SELECT fn, idv, ridv, idt, ridt, chnged, fnt,"
" isexe, islinkv, islinkt, deleted FROM fv ORDER BY 1"
);
db_prepare(&mtimeXfer,
|
| ︙ | ︙ | |||
425 426 427 428 429 430 431 |
zFullNewPath = mprintf("%s%s", g.zLocalRoot, zNewName);
nameChng = fossil_strcmp(zName, zNewName);
nUpdate++;
if( deleted ){
db_multi_exec("UPDATE vfile SET deleted=1 WHERE id=%d", idt);
}
if( idv>0 && ridv==0 && idt>0 && ridt>0 ){
| | | | 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 |
zFullNewPath = mprintf("%s%s", g.zLocalRoot, zNewName);
nameChng = fossil_strcmp(zName, zNewName);
nUpdate++;
if( deleted ){
db_multi_exec("UPDATE vfile SET deleted=1 WHERE id=%d", idt);
}
if( idv>0 && ridv==0 && idt>0 && ridt>0 ){
/* Conflict. This file has been added to the current check-out
** but also exists in the target check-out. Use the current version.
*/
fossil_print("CONFLICT %s\n", zName);
nConflict++;
}else if( idt>0 && idv==0 ){
/* File added in the target. */
if( file_isfile_or_link(zFullPath) ){
/* Name of backup file with Original content */
|
| ︙ | ︙ | |||
464 465 466 467 468 469 470 |
/* The file missing from the local check-out. Restore it to the
** version that appears in the target. */
fossil_print("UPDATE %s\n", zName);
if( !dryRunFlag && !internalUpdate ) undo_save(zName);
if( !dryRunFlag ) vfile_to_disk(0, idt, 0, 0);
}else if( idt==0 && idv>0 ){
if( ridv==0 ){
| | | 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 |
/* The file missing from the local check-out. Restore it to the
** version that appears in the target. */
fossil_print("UPDATE %s\n", zName);
if( !dryRunFlag && !internalUpdate ) undo_save(zName);
if( !dryRunFlag ) vfile_to_disk(0, idt, 0, 0);
}else if( idt==0 && idv>0 ){
if( ridv==0 ){
/* Added in current check-out. Continue to hold the file as
** as an addition */
db_multi_exec("UPDATE vfile SET vid=%d WHERE id=%d", tid, idv);
}else if( chnged ){
/* Edited locally but deleted from the target. Do not track the
** file but keep the edited version around. */
fossil_print("CONFLICT %s - edited locally but deleted by update\n",
zName);
|
| ︙ | ︙ | |||
627 628 629 630 631 632 633 |
db_multi_exec(
"SELECT rmdir(%Q||name) FROM dir_to_delete"
" WHERE (%Q||name)<>%Q ORDER BY name DESC",
g.zLocalRoot, g.zLocalRoot, zPwd
);
fossil_free(zPwd);
if( g.argc<=3 ){
| | | | < < | < < < < | | 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 |
db_multi_exec(
"SELECT rmdir(%Q||name) FROM dir_to_delete"
" WHERE (%Q||name)<>%Q ORDER BY name DESC",
g.zLocalRoot, g.zLocalRoot, zPwd
);
fossil_free(zPwd);
if( g.argc<=3 ){
/* All files updated. Shift the current check-out to the target. */
db_multi_exec("DELETE FROM vfile WHERE vid!=%d", tid);
checkout_set_all_exe(tid);
manifest_to_disk(tid);
db_set_checkout(tid);
}else{
/* A subset of files have been checked out. Keep the current
** check-out unchanged. */
db_multi_exec("DELETE FROM vfile WHERE vid!=%d", vid);
}
if( !internalUpdate ) undo_finish();
if( setmtimeFlag ) vfile_check_signature(tid, CKSIG_SETMTIME);
db_end_transaction(0);
}
}
/*
** Create empty directories specified by the empty-dirs setting.
*/
void ensure_empty_dirs_created(int clearDirTable){
char *zEmptyDirs = db_get("empty-dirs", 0);
if( zEmptyDirs!=0 ){
int i;
Glob *pGlob = glob_create(zEmptyDirs);
for(i=0; pGlob!=0 && i<pGlob->nPattern; i++){
const char *zDir = pGlob->azPattern[i];
char *zPath = mprintf("%s/%s", g.zLocalRoot, zDir);
switch( file_isdir(zPath, RepoFILE) ){
case 0: { /* doesn't exist */
fossil_free(zPath);
zPath = mprintf("%s/%s/x", g.zLocalRoot, zDir);
if( file_mkfolder(zPath, RepoFILE, 0, 1)!=0 ) {
fossil_warning("couldn't create directory %s as "
|
| ︙ | ︙ | |||
686 687 688 689 690 691 692 |
}
case 2: { /* exists, but isn't a directory */
fossil_warning("file %s found, but a directory is required "
"by empty-dirs setting", zDir);
}
}
fossil_free(zPath);
| < < | | | | | | | 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 |
}
case 2: { /* exists, but isn't a directory */
fossil_warning("file %s found, but a directory is required "
"by empty-dirs setting", zDir);
}
}
fossil_free(zPath);
}
glob_free(pGlob);
}
}
/*
** Get the manifest record for a given revision, or the current check-out if
** zRevision is NULL.
*/
Manifest *historical_manifest(
const char *zRevision /* The check-in to query, or NULL for current */
){
int vid;
Manifest *pManifest;
/* Determine the check-in manifest artifact ID. Panic on failure. */
if( zRevision ){
vid = name_to_typed_rid(zRevision, "ci");
}else if( !g.localOpen ){
vid = name_to_typed_rid(db_get("main-branch", 0), "ci");
}else{
vid = db_lget_int("checkout", 0);
if( !is_a_version(vid) ){
if( vid==0 ) return 0;
zRevision = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", vid);
if( zRevision ){
fossil_fatal("check-out artifact is not a check-in: %s", zRevision);
}else{
fossil_fatal("invalid check-out artifact ID: %d", vid);
}
}
}
/* Parse the manifest, given its artifact ID. Panic on failure. */
if( !(pManifest = manifest_get(vid, CFTYPE_MANIFEST, 0)) ){
if( zRevision ){
fossil_fatal("could not parse manifest for check-in: %s", zRevision);
}else{
fossil_fatal("could not parse manifest for current check-out");
}
}
/* Return the manifest pointer. The caller must use manifest_destroy() to
* clean up when finished using the manifest. */
return pManifest;
}
/*
** Get the contents of a file within the check-in "zRevision". If
** zRevision==NULL then get the file content for the current check-out.
*/
int historical_blob(
const char *zRevision, /* The check-in containing the file */
const char *zFile, /* Full treename of the file */
Blob *pBlob, /* Put the content here */
int fatal /* If nonzero, panic if file/artifact not found */
){
|
| ︙ | ︙ | |||
811 812 813 814 815 816 817 |
** Options:
** -r|--revision VERSION Revert given FILE(s) back to given
** VERSION
**
** See also: [[redo]], [[undo]], [[checkout]], [[update]]
*/
void revert_cmd(void){
| | | | | | 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 |
** Options:
** -r|--revision VERSION Revert given FILE(s) back to given
** VERSION
**
** See also: [[redo]], [[undo]], [[checkout]], [[update]]
*/
void revert_cmd(void){
Manifest *pCoManifest; /* Manifest of current check-out */
Manifest *pRvManifest; /* Manifest of selected revert version */
ManifestFile *pCoFile; /* File within current check-out manifest */
ManifestFile *pRvFile; /* File within revert version manifest */
const char *zFile; /* Filename relative to check-out root */
const char *zRevision; /* Selected revert version, NULL if current */
Blob record = BLOB_INITIALIZER; /* Contents of each reverted file */
int i;
Stmt q;
int revertAll = 0;
int revisionOptNotSupported = 0;
undo_capture_command_line();
zRevision = find_option("revision", "r", 1);
verify_all_options();
if( g.argc<2 ){
usage("?OPTIONS? [FILE] ...");
}
if( zRevision && g.argc<3 ){
fossil_fatal("directories or the entire tree can only be reverted"
" back to current version");
}
db_must_be_within_tree();
/* Get manifests of revert version and (if different) current check-out. */
pRvManifest = historical_manifest(zRevision);
pCoManifest = zRevision ? historical_manifest(0) : 0;
db_begin_transaction();
undo_begin();
db_multi_exec("CREATE TEMP TABLE torevert(name UNIQUE);");
|
| ︙ | ︙ | |||
956 957 958 959 960 961 962 |
}else if( file_unsafe_in_tree_path(zFull) ){
/* Ignore this file */
}else{
sqlite3_int64 mtime;
int rvChnged = 0;
int rvPerm = manifest_file_mperm(pRvFile);
| | | 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 |
}else if( file_unsafe_in_tree_path(zFull) ){
/* Ignore this file */
}else{
sqlite3_int64 mtime;
int rvChnged = 0;
int rvPerm = manifest_file_mperm(pRvFile);
/* Determine if reverted-to file is different than checked-out file. */
if( pCoManifest && (pCoFile = manifest_file_find(pCoManifest, zFile)) ){
rvChnged = manifest_file_mperm(pRvFile)!=rvPerm
|| fossil_strcmp(pRvFile->zUuid, pCoFile->zUuid)!=0;
}
/* Get contents of reverted-to file. */
content_get(fast_uuid_to_rid(pRvFile->zUuid), &record);
|
| ︙ | ︙ |
Changes to src/url.c.
| ︙ | ︙ | |||
59 60 61 62 63 64 65 66 67 | int dfltPort; /* The default port for the given protocol */ char *path; /* Pathname for http: */ char *user; /* User id for http: */ char *passwd; /* Password for http: */ char *canonical; /* Canonical representation of the URL */ char *proxyAuth; /* Proxy-Authorizer: string */ char *fossil; /* The fossil query parameter on ssh: */ unsigned flags; /* Boolean flags controlling URL processing */ int useProxy; /* Used to remember that a proxy is in use */ | > > | < | 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 | int dfltPort; /* The default port for the given protocol */ char *path; /* Pathname for http: */ char *user; /* User id for http: */ char *passwd; /* Password for http: */ char *canonical; /* Canonical representation of the URL */ char *proxyAuth; /* Proxy-Authorizer: string */ char *fossil; /* The fossil query parameter on ssh: */ char *pwConfig; /* CONFIG table entry that gave us the password */ unsigned flags; /* Boolean flags controlling URL processing */ int useProxy; /* Used to remember that a proxy is in use */ int proxyOrigPort; /* Tunneled port number for https through proxy */ char *proxyUrlPath; /* Remember path when proxy is use */ char *proxyUrlCanonical; /* Remember canonical path when proxy is use */ }; #endif /* INTERFACE */ /* ** Parse the URL in the zUrl argument. Store results in the pUrlData object. ** Populate members of pUrlData as follows: |
| ︙ | ︙ | |||
85 86 87 88 89 90 91 | ** dfltPort Default TCP port number (80 or 443). ** path Path name for HTTP or HTTPS. ** user Userid. ** passwd Password. ** hostname HOST:PORT or just HOST if port is the default. ** canonical The URL in canonical form, omitting the password ** | | | | > > < > > | 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 |
** dfltPort Default TCP port number (80 or 443).
** path Path name for HTTP or HTTPS.
** user Userid.
** passwd Password.
** hostname HOST:PORT or just HOST if port is the default.
** canonical The URL in canonical form, omitting the password
**
** If URL_USECONFIG is set and zUrl is NULL or "default", then parse the
** URL stored in last-sync-url and last-sync-pw of the CONFIG table. Or if
** URL_USE_PARENT is also set, then use parent-project-url and
** parent-project-pw from the CONFIG table instead of last-sync-url
** and last-sync-pw.
**
** If URL_USE_CONFIG is set and zUrl is a symbolic name, then look up
** the URL in sync-url:%Q and sync-pw:%Q elements of the CONFIG table where
** %Q is the symbolic name.
**
** This routine differs from url_parse() in that this routine stores the
** results in pUrlData and does not change the values of global variables.
** The url_parse() routine puts its result in g.url.
*/
void url_parse_local(
const char *zUrl,
unsigned int urlFlags,
UrlData *pUrlData
){
int i, j, c;
char *zFile = 0;
pUrlData->pwConfig = 0;
if( urlFlags & URL_USE_CONFIG ){
if( zUrl==0 || strcmp(zUrl,"default")==0 ){
const char *zPwConfig = "last-sync-pw";
if( urlFlags & URL_USE_PARENT ){
zUrl = db_get("parent-project-url", 0);
if( zUrl==0 ){
zUrl = db_get("last-sync-url",0);
}else{
zPwConfig = "parent-project-pw";
}
}else{
zUrl = db_get("last-sync-url", 0);
}
if( zUrl==0 ) return;
if( pUrlData->passwd==0 ){
pUrlData->passwd = unobscure(db_get(zPwConfig, 0));
pUrlData->pwConfig = fossil_strdup(zPwConfig);
}
pUrlData->isAlias = 1;
}else{
char *zKey = sqlite3_mprintf("sync-url:%q", zUrl);
char *zAlt = db_get(zKey, 0);
if( zAlt ){
pUrlData->pwConfig = mprintf("sync-pw:%q", zUrl);
pUrlData->passwd = unobscure(
db_text(0, "SELECT value FROM config WHERE name='sync-pw:%q'",zUrl)
);
zUrl = zAlt;
urlFlags |= URL_REMEMBER_PW;
pUrlData->isAlias = 1;
}else{
pUrlData->isAlias = 0;
}
sqlite3_free(zKey);
}
}else{
if( zUrl==0 ) return;
}
if( strncmp(zUrl, "http://", 7)==0
|| strncmp(zUrl, "https://", 8)==0
|
| ︙ | ︙ | |||
402 403 404 405 406 407 408 409 410 411 412 413 414 415 | } fossil_free(p->canonical); fossil_free(p->name); fossil_free(p->path); fossil_free(p->user); fossil_free(p->passwd); fossil_free(p->fossil); memset(p, 0, sizeof(*p)); } /* ** Parse the given URL, which describes a sync server. Populate variables ** in the global "g.url" structure as shown below. If zUrl is NULL, then ** parse the URL given in the last-sync-url setting, taking the password | > | 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 | } fossil_free(p->canonical); fossil_free(p->name); fossil_free(p->path); fossil_free(p->user); fossil_free(p->passwd); fossil_free(p->fossil); fossil_free(p->pwConfig); memset(p, 0, sizeof(*p)); } /* ** Parse the given URL, which describes a sync server. Populate variables ** in the global "g.url" structure as shown below. If zUrl is NULL, then ** parse the URL given in the last-sync-url setting, taking the password |
| ︙ | ︙ | |||
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 |
** g.url.port TCP port number for HTTP or HTTPS.
** g.url.dfltPort Default TCP port number (80 or 443).
** g.url.path Path name for HTTP or HTTPS.
** g.url.user Userid.
** g.url.passwd Password.
** g.url.hostname HOST:PORT or just HOST if port is the default.
** g.url.canonical The URL in canonical form, omitting the password
**
** HTTP url format as follows (HTTPS is the same with a different scheme):
**
** http://userid:password@host:port/path
**
** SSH url format is:
**
** ssh://userid@host:port/path?fossil=path/to/fossil.exe
**
*/
void url_parse(const char *zUrl, unsigned int urlFlags){
url_parse_local(zUrl, urlFlags, &g.url);
}
/*
** COMMAND: test-urlparser
**
** Usage: %fossil test-urlparser URL ?options?
**
** --remember Store results in last-sync-url
| > > > > > > > > > > > > > | > > | < < < | > > > > > | > > > > | 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 |
** g.url.port TCP port number for HTTP or HTTPS.
** g.url.dfltPort Default TCP port number (80 or 443).
** g.url.path Path name for HTTP or HTTPS.
** g.url.user Userid.
** g.url.passwd Password.
** g.url.hostname HOST:PORT or just HOST if port is the default.
** g.url.canonical The URL in canonical form, omitting the password
** g.url.pwConfig Name of CONFIG table entry containing the password
**
** HTTP url format as follows (HTTPS is the same with a different scheme):
**
** http://userid:password@host:port/path
**
** SSH url format is:
**
** ssh://userid@host:port/path?fossil=path/to/fossil.exe
**
** If URL_USE_CONFIG is set then the URL and password might be pulled from
** the CONFIG table rather than from the zUrl parameter. If zUrl is NULL
** or "default" then the URL is given by the "last-sync-url" setting and
** the password comes form the "last-sync-pw" setting. If zUrl is a symbolic
** name, then the URL comes from "sync-url:NAME" and the password from
** "sync-pw:NAME" where NAME is the input zUrl string. Whenever the
** password is taken from the CONFIG table, the g.url.pwConfig field is
** set to the CONFIG.NAME value from which that password is taken. Otherwise,
** g.url.pwConfig is NULL.
*/
void url_parse(const char *zUrl, unsigned int urlFlags){
url_parse_local(zUrl, urlFlags, &g.url);
}
/*
** COMMAND: test-urlparser
**
** Usage: %fossil test-urlparser URL ?options?
**
** --prompt-pw Prompt for password if missing
** --remember Store results in last-sync-url
** --show-pw Show the CONFIG-derived password in the output
** --use-config Pull URL and password from the CONFIG table
** --use-parent Use the parent project URL
*/
void cmd_test_urlparser(void){
int i;
unsigned fg = 0;
int showPw = 0;
db_must_be_within_tree();
url_proxy_options();
if( find_option("remember",0,0) ) fg |= URL_REMEMBER;
if( find_option("prompt-pw",0,0) ) fg |= URL_PROMPT_PW;
if( find_option("use-parent",0,0) ) fg |= URL_USE_PARENT|URL_USE_CONFIG;
if( find_option("use-config",0,0) ) fg |= URL_USE_CONFIG;
if( find_option("show-pw",0,0) ) showPw = 1;
if( (fg & URL_USE_CONFIG)==0 ) showPw = 1;
if( g.argc!=3 && g.argc!=4 ){
usage("URL");
}
url_parse(g.argv[2], fg);
for(i=0; i<2; i++){
fossil_print("g.url.isFile = %d\n", g.url.isFile);
fossil_print("g.url.isHttps = %d\n", g.url.isHttps);
fossil_print("g.url.isSsh = %d\n", g.url.isSsh);
fossil_print("g.url.protocol = %s\n", g.url.protocol);
fossil_print("g.url.name = %s\n", g.url.name);
fossil_print("g.url.port = %d\n", g.url.port);
fossil_print("g.url.dfltPort = %d\n", g.url.dfltPort);
fossil_print("g.url.hostname = %s\n", g.url.hostname);
fossil_print("g.url.path = %s\n", g.url.path);
fossil_print("g.url.user = %s\n", g.url.user);
if( showPw || g.url.pwConfig==0 ){
fossil_print("g.url.passwd = %s\n", g.url.passwd);
}else{
fossil_print("g.url.passwd = ************\n");
}
fossil_print("g.url.pwConfig = %s\n", g.url.pwConfig);
fossil_print("g.url.canonical = %s\n", g.url.canonical);
fossil_print("g.url.fossil = %s\n", g.url.fossil);
fossil_print("g.url.flags = 0x%02x\n", g.url.flags);
fossil_print("url_full(g.url) = %z\n", url_full(&g.url));
if( g.url.isFile || g.url.isSsh ) break;
if( i==0 ){
fossil_print("********\n");
|
| ︙ | ︙ | |||
532 533 534 535 536 537 538 |
** If zMsg is not NULL and a proxy is used, then print zMsg followed
** by the canonical name of the proxy (with userid and password suppressed).
*/
void url_enable_proxy(const char *zMsg){
const char *zProxy;
zProxy = zProxyOpt;
if( zProxy==0 ){
| | | 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 |
** If zMsg is not NULL and a proxy is used, then print zMsg followed
** by the canonical name of the proxy (with userid and password suppressed).
*/
void url_enable_proxy(const char *zMsg){
const char *zProxy;
zProxy = zProxyOpt;
if( zProxy==0 ){
zProxy = db_get("proxy", "system");
if( fossil_strcmp(zProxy, "system")==0 ){
zProxy = fossil_getenv("http_proxy");
}
}
if( zProxy && zProxy[0] && !is_false(zProxy)
&& !g.url.isSsh && !g.url.isFile ){
char *zOriginalUrl = g.url.canonical;
|
| ︙ | ︙ |
Changes to src/user.c.
| ︙ | ︙ | |||
155 156 157 158 159 160 161 | unsigned char zB[30]; int nA = 25; int nB = 0; int i; memcpy(zOrig, "abcdefghijklmnopqrstuvwyz", nA+1); memcpy(zA, zOrig, nA+1); assert( nA==(int)strlen((char*)zA) ); | | | 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 |
unsigned char zB[30];
int nA = 25;
int nB = 0;
int i;
memcpy(zOrig, "abcdefghijklmnopqrstuvwyz", nA+1);
memcpy(zA, zOrig, nA+1);
assert( nA==(int)strlen((char*)zA) );
for(i=0; i<(int)sizeof(aSubst); i++) aSubst[i] = i;
printFive(zA);
while( nA>0 ){
int x = randint(nA);
zB[nB++] = zA[x];
zA[x] = zA[--nA];
}
assert( nB==25 );
|
| ︙ | ︙ | |||
557 558 559 560 561 562 563 |
** Print details about sources of fossil usernames.
*/
void test_usernames_cmd(void){
db_find_and_open_repository(0, 0);
fossil_print("Initial g.zLogin: %s\n", g.zLogin);
fossil_print("Initial g.userUid: %d\n", g.userUid);
| | | > > > > > > > > > > > > > > | 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 |
** Print details about sources of fossil usernames.
*/
void test_usernames_cmd(void){
db_find_and_open_repository(0, 0);
fossil_print("Initial g.zLogin: %s\n", g.zLogin);
fossil_print("Initial g.userUid: %d\n", g.userUid);
fossil_print("check-out default-user: %s\n", g.localOpen ?
db_lget("default-user","") : "<<no open check-out>>");
fossil_print("default-user: %s\n", db_get("default-user",""));
fossil_print("FOSSIL_USER: %s\n", fossil_getenv("FOSSIL_USER"));
fossil_print("USER: %s\n", fossil_getenv("USER"));
fossil_print("LOGNAME: %s\n", fossil_getenv("LOGNAME"));
fossil_print("USERNAME: %s\n", fossil_getenv("USERNAME"));
url_parse(0, URL_USE_CONFIG);
fossil_print("URL user: %s\n", g.url.user);
user_select();
fossil_print("Final g.zLogin: %s\n", g.zLogin);
fossil_print("Final g.userUid: %d\n", g.userUid);
}
/*
** Make sure the USER table is up-to-date. It should contain
** the "JX" column (as of version 2.21). If it does not, add it.
**
** The "JX" column is intended to hold a JSON object containing optional
** key-value pairs.
*/
void user_update_user_table(void){
if( db_table_has_column("repository","user","jx")==0 ){
db_multi_exec("ALTER TABLE repository.user"
" ADD COLUMN jx TEXT DEFAULT '{}';");
}
}
/*
** COMMAND: test-hash-passwords
**
** Usage: %fossil test-hash-passwords REPOSITORY
**
** Convert all local password storage to use a SHA1 hash of the password
|
| ︙ | ︙ | |||
592 593 594 595 596 597 598 599 600 601 602 603 604 605 |
sha1_shared_secret_sql_function, 0, 0);
db_unprotect(PROTECT_ALL);
db_multi_exec(
"UPDATE user SET pw=shared_secret(pw,login), mtime=now()"
" WHERE length(pw)>0 AND length(pw)!=40"
);
}
/*
** COMMAND: test-prompt-user
**
** Usage: %fossil test-prompt-user PROMPT
**
** Prompts the user for input and then prints it verbatim (i.e. without
| > > > > > > > > > > > > > > | 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 |
sha1_shared_secret_sql_function, 0, 0);
db_unprotect(PROTECT_ALL);
db_multi_exec(
"UPDATE user SET pw=shared_secret(pw,login), mtime=now()"
" WHERE length(pw)>0 AND length(pw)!=40"
);
}
/*
** Ensure that the password for a user is hashed.
*/
void hash_user_password(const char *zUser){
sqlite3_create_function(g.db, "shared_secret", 2, SQLITE_UTF8, 0,
sha1_shared_secret_sql_function, 0, 0);
db_unprotect(PROTECT_USER);
db_multi_exec(
"UPDATE user SET pw=shared_secret(pw,login), mtime=now()"
" WHERE login=%Q AND length(pw)>0 AND length(pw)!=40", zUser
);
db_protect_pop();
}
/*
** COMMAND: test-prompt-user
**
** Usage: %fossil test-prompt-user PROMPT
**
** Prompts the user for input and then prints it verbatim (i.e. without
|
| ︙ | ︙ | |||
685 686 687 688 689 690 691 692 693 694 695 696 697 698 |
db_multi_exec("DELETE FROM accesslog WHERE rowid in"
"(SELECT rowid FROM accesslog ORDER BY rowid DESC"
" LIMIT -1 OFFSET 200)");
cgi_redirectf("%R/access_log?y=%d&n=%d", y, n);
return;
}
style_header("Access Log");
blob_zero(&sql);
blob_append_sql(&sql,
"SELECT uname, ipaddr, datetime(mtime,toLocal()), success"
" FROM accesslog"
);
if( zUser ){
blob_append_sql(&sql, " WHERE uname=%Q", zUser);
| > > > > | 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 |
db_multi_exec("DELETE FROM accesslog WHERE rowid in"
"(SELECT rowid FROM accesslog ORDER BY rowid DESC"
" LIMIT -1 OFFSET 200)");
cgi_redirectf("%R/access_log?y=%d&n=%d", y, n);
return;
}
style_header("Access Log");
style_submenu_element("Admin-Log", "admin_log");
style_submenu_element("Artifact-Log", "rcvfromlist");
style_submenu_element("Error-Log", "errorlog");
blob_zero(&sql);
blob_append_sql(&sql,
"SELECT uname, ipaddr, datetime(mtime,toLocal()), success"
" FROM accesslog"
);
if( zUser ){
blob_append_sql(&sql, " WHERE uname=%Q", zUser);
|
| ︙ | ︙ | |||
735 736 737 738 739 740 741 |
@ <td>%s(zDate)</td><td>%h(zName)</td><td>%h(zIP)</td></tr>
}
if( skip>0 || cnt>n ){
style_submenu_element("All", "%R/access_log?n=10000000");
}
@ </tbody></table>
db_finalize(&q);
| | | 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 |
@ <td>%s(zDate)</td><td>%h(zName)</td><td>%h(zIP)</td></tr>
}
if( skip>0 || cnt>n ){
style_submenu_element("All", "%R/access_log?n=10000000");
}
@ </tbody></table>
db_finalize(&q);
@ <hr>
@ <form method="post" action="%R/access_log">
@ <label><input type="checkbox" name="delold">
@ Delete all but the most recent 200 entries</input></label>
@ <input type="submit" name="deloldbtn" value="Delete"></input>
@ </form>
@ <form method="post" action="%R/access_log">
@ <label><input type="checkbox" name="delanon">
|
| ︙ | ︙ |
Changes to src/util.c.
| ︙ | ︙ | |||
678 679 680 681 682 683 684 |
&& ( zTempDirA = fossil_path_to_utf8(zTempDirW) )){
zDir = zTempDirA;
}else{
zDir = fossil_getenv("LOCALAPPDATA");
if( zDir==0 ) zDir = ".";
}
#else
| | | | 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 |
&& ( zTempDirA = fossil_path_to_utf8(zTempDirW) )){
zDir = zTempDirA;
}else{
zDir = fossil_getenv("LOCALAPPDATA");
if( zDir==0 ) zDir = ".";
}
#else
for(i=0; i<(int)(sizeof(azTmp)/sizeof(azTmp[0])); i++){
struct stat buf;
zDir = azTmp[i];
if( stat(zDir,&buf)==0 && S_ISDIR(buf.st_mode) && access(zDir,03)==0 ){
break;
}
}
if( i>=(int)(sizeof(azTmp)/sizeof(azTmp[0])) ) zDir = ".";
cDirSep = '/';
#endif
nDir = strlen(zDir);
zSep[1] = 0;
zSep[0] = (nDir && zDir[nDir-1]==cDirSep) ? 0 : cDirSep;
zTFile = sqlite3_mprintf("%s%sfossil%016llx%016llx", zDir,zSep,r[0],r[1]);
#ifdef _WIN32
|
| ︙ | ︙ |
Changes to src/vfile.c.
| ︙ | ︙ | |||
157 158 159 160 161 162 163 | ** the file has changed without having the check the size, mtime, ** or on-disk content. ** ** If the size of the file has changed, then we always know that the file ** changed without having to look at the mtime or on-disk content. ** ** The mtime of the file is only a factor if the mtime-changes setting | < | > | | | 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 |
** the file has changed without having the check the size, mtime,
** or on-disk content.
**
** If the size of the file has changed, then we always know that the file
** changed without having to look at the mtime or on-disk content.
**
** The mtime of the file is only a factor if the mtime-changes setting
** is true (or undefined - it defaults to true) and the CKSIG_HASH
** flag is false. If the mtime-changes setting is false or if
** CKSIG_HASH is true, then we do not trust the mtime and will examine
** the on-disk content to determine if a file really is the same.
**
** If the mtime is used, it is used only to determine if files are the same.
** If the mtime of a file has changed, we still examine the on-disk content
** to see whether or not the edit was a null-edit.
*/
void vfile_check_signature(int vid, unsigned int cksigFlags){
int nErr = 0;
|
| ︙ | ︙ | |||
253 254 255 256 257 258 259 260 261 262 263 264 265 266 |
}
}
}
#ifndef _WIN32
if( origPerm!=PERM_LNK && currentPerm==PERM_LNK ){
/* Changing to a symlink takes priority over all other change types. */
chnged = 7;
}else if( chnged==0 || chnged==6 || chnged==7 || chnged==8 || chnged==9 ){
/* Confirm metadata change types. */
if( origPerm==currentPerm ){
chnged = 0;
}else if( currentPerm==PERM_EXE ){
chnged = 6;
}else if( origPerm==PERM_EXE ){
| > > > | 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 |
}
}
}
#ifndef _WIN32
if( origPerm!=PERM_LNK && currentPerm==PERM_LNK ){
/* Changing to a symlink takes priority over all other change types. */
chnged = 7;
}else if( origPerm==PERM_LNK && currentPerm!=PERM_LNK ){
/* Ditto, other direction */
chnged = 9;
}else if( chnged==0 || chnged==6 || chnged==7 || chnged==8 || chnged==9 ){
/* Confirm metadata change types. */
if( origPerm==currentPerm ){
chnged = 0;
}else if( currentPerm==PERM_EXE ){
chnged = 6;
}else if( origPerm==PERM_EXE ){
|
| ︙ | ︙ | |||
361 362 363 364 365 366 367 |
db_multi_exec("UPDATE vfile SET mtime=%lld WHERE id=%d",
file_mtime(zName, RepoFILE), id);
}
db_finalize(&q);
}
/*
| | | | 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 |
db_multi_exec("UPDATE vfile SET mtime=%lld WHERE id=%d",
file_mtime(zName, RepoFILE), id);
}
db_finalize(&q);
}
/*
** Check to see if the directory named in zPath is the top of a check-out.
** In other words, check to see if directory pPath contains a file named
** "_FOSSIL_" or ".fslckout". Return true or false.
*/
int vfile_top_of_checkout(const char *zPath){
char *zFile;
int fileFound = 0;
zFile = mprintf("%s/_FOSSIL_", zPath);
fileFound = file_size(zFile, ExtFILE)>=1024;
fossil_free(zFile);
if( !fileFound ){
zFile = mprintf("%s/.fslckout", zPath);
fileFound = file_size(zFile, ExtFILE)>=1024;
fossil_free(zFile);
}
/* Check for ".fos" for legacy support. But the use of ".fos" as the
** per-check-out database name is deprecated. At some point, all support
** for ".fos" will end and this code should be removed. This comment
** added on 2012-02-04.
*/
if( !fileFound ){
zFile = mprintf("%s/.fos", zPath);
fileFound = file_size(zFile, ExtFILE)>=1024;
fossil_free(zFile);
|
| ︙ | ︙ | |||
1064 1065 1066 1067 1068 1069 1070 |
" UNION SELECT %d"
")"
"SELECT group_concat(x,' ') FROM allrid"
" WHERE x<>0 AND x NOT IN (SELECT oldrid FROM idMap);",
oldVid
);
if( zUnresolved[0] ){
| | > > > > > > > | 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 |
" UNION SELECT %d"
")"
"SELECT group_concat(x,' ') FROM allrid"
" WHERE x<>0 AND x NOT IN (SELECT oldrid FROM idMap);",
oldVid
);
if( zUnresolved[0] ){
fossil_fatal("Unresolved RID values: %s\n"
"\n"
"Local check-out database is out of sync with repository file:\n"
"\n"
" %s\n"
"\n"
"Has the repository file been replaced?\n",
zUnresolved, db_repository_filename());
}
/* Make the changes to the VFILE and VMERGE tables */
if( !dryRun ){
db_multi_exec(
"UPDATE vfile"
" SET rid=(SELECT newrid FROM idMap WHERE oldrid=vfile.rid)"
|
| ︙ | ︙ |
Changes to src/wiki.c.
| ︙ | ︙ | |||
113 114 115 116 117 118 119 120 121 122 123 124 125 126 |
** The /home, /index, and /not_found pages all redirect to the homepage
** configured by the administrator.
*/
void home_page(void){
char *zPageName = db_get("project-name",0);
char *zIndexPage = db_get("index-page",0);
login_check_credentials();
if( zIndexPage ){
const char *zPathInfo = P("PATH_INFO");
while( zIndexPage[0]=='/' ) zIndexPage++;
while( zPathInfo[0]=='/' ) zPathInfo++;
if( fossil_strcmp(zIndexPage, zPathInfo)==0 ) zIndexPage = 0;
}
if( zIndexPage ){
| > | 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 |
** The /home, /index, and /not_found pages all redirect to the homepage
** configured by the administrator.
*/
void home_page(void){
char *zPageName = db_get("project-name",0);
char *zIndexPage = db_get("index-page",0);
login_check_credentials();
cgi_check_for_malice();
if( zIndexPage ){
const char *zPathInfo = P("PATH_INFO");
while( zIndexPage[0]=='/' ) zIndexPage++;
while( zPathInfo[0]=='/' ) zPathInfo++;
if( fossil_strcmp(zIndexPage, zPathInfo)==0 ) zIndexPage = 0;
}
if( zIndexPage ){
|
| ︙ | ︙ | |||
465 466 467 468 469 470 471 |
break;
}
case WIKITYPE_CHECKIN: {
zPageName += 8;
if( zExtra[0]==0 && !P("p") ){
cgi_redirectf("%R/info/%s",zPageName);
}else{
| | | | | 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 |
break;
}
case WIKITYPE_CHECKIN: {
zPageName += 8;
if( zExtra[0]==0 && !P("p") ){
cgi_redirectf("%R/info/%s",zPageName);
}else{
style_header("Notes About Check-in %S", zPageName);
style_submenu_element("Check-in Timeline","%R/timeline?f=%s", zPageName);
style_submenu_element("Check-in Info","%R/info/%s", zPageName);
}
break;
}
case WIKITYPE_BRANCH: {
zPageName += 7;
if( zExtra[0]==0 && !P("p") ){
cgi_redirectf("%R/timeline?r=%t", zPageName);
|
| ︙ | ︙ | |||
548 549 550 551 552 553 554 555 556 557 558 559 560 561 |
int isPopup = P("popup")!=0;
char *zBody = mprintf("%s","<i>Empty Page</i>");
int noSubmenu = P("nsm")!=0 || g.isHome;
login_check_credentials();
if( !g.perm.RdWiki ){ login_needed(g.anon.RdWiki); return; }
zPageName = P("name");
if( zPageName==0 ){
if( search_restrict(SRCH_WIKI)!=0 ){
wiki_srchpage();
}else{
wiki_helppage();
}
return;
| > | 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 |
int isPopup = P("popup")!=0;
char *zBody = mprintf("%s","<i>Empty Page</i>");
int noSubmenu = P("nsm")!=0 || g.isHome;
login_check_credentials();
if( !g.perm.RdWiki ){ login_needed(g.anon.RdWiki); return; }
zPageName = P("name");
cgi_check_for_malice();
if( zPageName==0 ){
if( search_restrict(SRCH_WIKI)!=0 ){
wiki_srchpage();
}else{
wiki_helppage();
}
return;
|
| ︙ | ︙ | |||
610 611 612 613 614 615 616 |
blob_init(&wiki, zBody, -1);
safe_html_context(DOCSRC_WIKI);
wiki_render_by_mimetype(&wiki, zMimetype);
blob_reset(&wiki);
}
manifest_destroy(pWiki);
if( !isPopup ){
| | | 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 |
blob_init(&wiki, zBody, -1);
safe_html_context(DOCSRC_WIKI);
wiki_render_by_mimetype(&wiki, zMimetype);
blob_reset(&wiki);
}
manifest_destroy(pWiki);
if( !isPopup ){
char * zLabel = mprintf("<hr><h2><a href='%R/attachlist?name=%T'>"
"Attachments</a>:</h2><ul>",
zPageName);
attachment_list(zPageName, zLabel);
fossil_free(zLabel);
document_emit_js(/*for optional pikchr support*/);
style_finish_page();
}
|
| ︙ | ︙ | |||
633 634 635 636 637 638 639 |
nrid = content_put_ex(pWiki, 0, 0, 0, 0);
if( parent ) content_deltify(parent, &nrid, 1, 0);
}else{
nrid = content_put_ex(pWiki, 0, 0, 0, 1);
moderation_table_create();
db_multi_exec("INSERT INTO modreq(objid) VALUES(%d)", nrid);
}
| | | > > > | | | 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 |
nrid = content_put_ex(pWiki, 0, 0, 0, 0);
if( parent ) content_deltify(parent, &nrid, 1, 0);
}else{
nrid = content_put_ex(pWiki, 0, 0, 0, 1);
moderation_table_create();
db_multi_exec("INSERT INTO modreq(objid) VALUES(%d)", nrid);
}
db_add_unsent(nrid);
db_multi_exec("INSERT OR IGNORE INTO unclustered VALUES(%d);", nrid);
manifest_crosslink(nrid, pWiki, MC_NONE);
if( login_is_individual() ){
alert_user_contact(login_name());
}
return nrid;
}
/*
** Output a selection box from which the user can select the
** wiki mimetype. Arguments:
**
** zMimetype - The current value of the query parameter
** zParam - The name of the query parameter
*/
void mimetype_option_menu(const char *zMimetype, const char *zParam){
unsigned i;
@ <select name="%s(zParam)" size="1">
for(i=0; i<count(azStyles); i+=3){
if( fossil_strcmp(zMimetype,azStyles[i])==0 ){
@ <option value="%s(azStyles[i])" selected>%s(azStyles[i+1])</option>
}else{
@ <option value="%s(azStyles[i])">%s(azStyles[i+1])</option>
}
}
|
| ︙ | ︙ | |||
1128 1129 1130 1131 1132 1133 1134 |
** Outputs the wiki page list in JSON form. If verbose is false then
** it emits an array of strings (page names). If verbose is true it outputs
** an array of objects in this form:
**
** { name: string, version: string or null of sandbox box,
** parent: uuid or null for first version or sandbox,
** mimetype: string,
| | | 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 |
** Outputs the wiki page list in JSON form. If verbose is false then
** it emits an array of strings (page names). If verbose is true it outputs
** an array of objects in this form:
**
** { name: string, version: string or null of sandbox box,
** parent: uuid or null for first version or sandbox,
** mimetype: string,
** type: string (normal, branch, tag, check-in, or sandbox)
** }
**
** If includeContent is true, the object contains a "content" member
** with the raw page content. includeContent is ignored if verbose is
** false.
**
*/
|
| ︙ | ︙ | |||
1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 |
"CSRF violation (make sure sending of HTTP "
"Referer headers is enabled for XHR "
"connections).");
return;
}
pRoute->xCallback();
}
/*
** WEBPAGE: wikiedit
** URL: /wikedit?name=PAGENAME
**
** The main front-end for the Ajax-based wiki editor app. Passing
** in the name of an unknown page will trigger the creation
| > > > > > > > > > > > > > > > > | 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 |
"CSRF violation (make sure sending of HTTP "
"Referer headers is enabled for XHR "
"connections).");
return;
}
pRoute->xCallback();
}
/*
** Emits a preview-toggle option widget for /wikiedit and /fileedit.
*/
void wikiedit_emit_toggle_preview(void){
CX("<div class='input-with-label'>"
"<input type='checkbox' id='edit-shift-enter-preview' "
"></input><label for='edit-shift-enter-preview'>"
"Shift-enter previews</label>"
"<div class='help-buttonlet'>"
"When enabled, shift-enter switches between preview and edit modes. "
"Some software-based keyboards misinteract with this, so it can be "
"disabled when needed."
"</div>"
"</div>");
}
/*
** WEBPAGE: wikiedit
** URL: /wikedit?name=PAGENAME
**
** The main front-end for the Ajax-based wiki editor app. Passing
** in the name of an unknown page will trigger the creation
|
| ︙ | ︙ | |||
1304 1305 1306 1307 1308 1309 1310 |
"Status messages will go here.</div>\n"
/* will be moved into the tab container via JS */);
CX("<div id='wikiedit-edit-status''>"
"<span class='name'></span>"
"<span class='links'></span>"
"</div>");
| | | 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 |
"Status messages will go here.</div>\n"
/* will be moved into the tab container via JS */);
CX("<div id='wikiedit-edit-status''>"
"<span class='name'></span>"
"<span class='links'></span>"
"</div>");
/* Main tab container... */
CX("<div id='wikiedit-tabs' class='tab-container'>Loading...</div>");
/* The .hidden class on the following tab elements is to help lessen
the FOUC effect of the tabs before JS re-assembles them. */
/******* Page list *******/
{
|
| ︙ | ︙ | |||
1332 1333 1334 1335 1336 1337 1338 |
"data-tab-label='Editor' "
"class='hidden'"
">");
CX("<div class='"
"wikiedit-options flex-container flex-row child-gap-small'>");
CX("<div class='input-with-label'>"
"<label>Mime type</label>");
| | | 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 |
"data-tab-label='Editor' "
"class='hidden'"
">");
CX("<div class='"
"wikiedit-options flex-container flex-row child-gap-small'>");
CX("<div class='input-with-label'>"
"<label>Mime type</label>");
mimetype_option_menu("text/x-markdown", "mimetype");
CX("</div>");
style_select_list_int("select-font-size",
"editor_font_size", "Editor font size",
NULL/*tooltip*/,
100,
"100%", 100, "125%", 125,
"150%", 150, "175%", 175,
|
| ︙ | ︙ | |||
1364 1365 1366 1367 1368 1369 1370 |
"<div class='help-buttonlet'>"
"Reload the file from the server, discarding "
"any local edits. To help avoid accidental loss of "
"edits, it requires confirmation (a second click) within "
"a few seconds or it will not reload."
"</div>"
"</div>");
| | | 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 |
"<div class='help-buttonlet'>"
"Reload the file from the server, discarding "
"any local edits. To help avoid accidental loss of "
"edits, it requires confirmation (a second click) within "
"a few seconds or it will not reload."
"</div>"
"</div>");
wikiedit_emit_toggle_preview();
CX("</div>");
CX("<div class='flex-container flex-column stretch'>");
CX("<textarea name='content' id='wikiedit-content-editor' "
"class='wikiedit' rows='25'>");
CX("</textarea>");
CX("</div>"/*textarea wrapper*/);
CX("</div>"/*#tab-file-content*/);
|
| ︙ | ︙ | |||
1531 1532 1533 1534 1535 1536 1537 |
style_set_current_feature("wiki");
style_header("Create A New Wiki Page");
wiki_standard_submenu(W_ALL_BUT(W_NEW));
@ <p>Rules for wiki page names:</p>
well_formed_wiki_name_rules();
form_begin(0, "%R/wikinew");
@ <p>Name of new wiki page:
| | | | | 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 |
style_set_current_feature("wiki");
style_header("Create A New Wiki Page");
wiki_standard_submenu(W_ALL_BUT(W_NEW));
@ <p>Rules for wiki page names:</p>
well_formed_wiki_name_rules();
form_begin(0, "%R/wikinew");
@ <p>Name of new wiki page:
@ <input style="width: 35;" type="text" name="name" value="%h(zName)"><br>
@ %z(href("%R/markup_help"))Markup style</a>:
mimetype_option_menu("text/x-markdown", "mimetype");
@ <br><input type="submit" value="Create">
@ </p></form>
if( zName[0] ){
@ <p><span class="wikiError">
@ "%h(zName)" is not a valid wiki page name!</span></p>
}
style_finish_page();
}
|
| ︙ | ︙ | |||
1558 1559 1560 1561 1562 1563 1564 |
char *zId;
zDate = db_text(0, "SELECT datetime('now')");
zRemark = PD("r","");
zUser = PD("u",g.zLogin);
if( fossil_strcmp(zMimetype, "text/x-fossil-wiki")==0 ){
zId = db_text(0, "SELECT lower(hex(randomblob(8)))");
| | | | 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 |
char *zId;
zDate = db_text(0, "SELECT datetime('now')");
zRemark = PD("r","");
zUser = PD("u",g.zLogin);
if( fossil_strcmp(zMimetype, "text/x-fossil-wiki")==0 ){
zId = db_text(0, "SELECT lower(hex(randomblob(8)))");
blob_appendf(p, "\n\n<hr><div id=\"%s\"><i>On %s UTC %h",
zId, zDate, login_name());
if( zUser[0] && fossil_strcmp(zUser,login_name()) ){
blob_appendf(p, " (claiming to be %h)", zUser);
}
blob_appendf(p, " added:</i><br>\n%s</div id=\"%s\">", zRemark, zId);
}else if( fossil_strcmp(zMimetype, "text/x-markdown")==0 ){
blob_appendf(p, "\n\n------\n*On %s UTC %h", zDate, login_name());
if( zUser[0] && fossil_strcmp(zUser,login_name()) ){
blob_appendf(p, " (claiming to be %h)", zUser);
}
blob_appendf(p, " added:*\n\n%s\n", zRemark);
}else{
|
| ︙ | ︙ | |||
1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 |
return;
}
zMimetype = wiki_filter_mimetypes(pWiki->zMimetype)
/* see https://fossil-scm.org/forum/forumpost/0acfdaac80 */;
}
if( !isSandbox && P("submit")!=0 && P("r")!=0 && P("u")!=0
&& (goodCaptcha = captcha_is_correct(0))
){
char *zDate;
Blob cksum;
Blob body;
Blob wiki;
blob_zero(&body);
| > < | 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 |
return;
}
zMimetype = wiki_filter_mimetypes(pWiki->zMimetype)
/* see https://fossil-scm.org/forum/forumpost/0acfdaac80 */;
}
if( !isSandbox && P("submit")!=0 && P("r")!=0 && P("u")!=0
&& (goodCaptcha = captcha_is_correct(0))
&& cgi_csrf_safe(2)
){
char *zDate;
Blob cksum;
Blob body;
Blob wiki;
blob_zero(&body);
blob_append(&body, pWiki->zWiki, -1);
blob_zero(&wiki);
db_begin_transaction();
zDate = date_in_standard_format("now");
blob_appendf(&wiki, "D %s\n", zDate);
blob_appendf(&wiki, "L %F\n", zPageName);
if( fossil_strcmp(zMimetype, "text/x-fossil-wiki")!=0 ){
|
| ︙ | ︙ | |||
1680 1681 1682 1683 1684 1685 1686 |
@ <p class="generalError">Error: the Sandbox page may not
@ be appended to.</p>
}
if( !isSandbox && P("preview")!=0 ){
Blob preview;
blob_zero(&preview);
appendRemark(&preview, zMimetype);
| | | < | | | | | | | | | 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 |
@ <p class="generalError">Error: the Sandbox page may not
@ be appended to.</p>
}
if( !isSandbox && P("preview")!=0 ){
Blob preview;
blob_zero(&preview);
appendRemark(&preview, zMimetype);
@ Preview:<hr>
safe_html_context(DOCSRC_WIKI);
wiki_render_by_mimetype(&preview, zMimetype);
@ <hr>
blob_reset(&preview);
}
zUser = PD("u", g.zLogin);
form_begin(0, "%R/wikiappend");
@ <input type="hidden" name="name" value="%h(zPageName)">
@ <input type="hidden" name="mimetype" value="%h(zMimetype)">
@ Your Name:
@ <input type="text" name="u" size="20" value="%h(zUser)"><br>
zFormat = mimetype_common_name(zMimetype);
@ Comment to append (formatted as %s(zFormat)):<br>
@ <textarea name="r" class="wikiedit" cols="80"
@ rows="10" wrap="virtual">%h(PD("r",""))</textarea>
@ <br>
@ <input type="submit" name="preview" value="Preview Your Comment">
@ <input type="submit" name="submit" value="Append Your Changes">
@ <input type="submit" name="cancel" value="Cancel">
captcha_generate(0);
@ </form>
manifest_destroy(pWiki);
style_finish_page();
}
/*
|
| ︙ | ︙ | |||
1745 1746 1747 1748 1749 1750 1751 |
" AND tag.tagname='wiki-%q'"
" AND tagxref.tagid=tag.tagid AND tagxref.srcid=event.objid"
" ORDER BY event.mtime DESC",
zPageName
);
@ <h2>History of <a href="%R/wiki?name=%T(zPageName)">%h(zPageName)</a></h2>
form_begin( "id='wh-form'", "%R/wdiff" );
| | | | 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 |
" AND tag.tagname='wiki-%q'"
" AND tagxref.tagid=tag.tagid AND tagxref.srcid=event.objid"
" ORDER BY event.mtime DESC",
zPageName
);
@ <h2>History of <a href="%R/wiki?name=%T(zPageName)">%h(zPageName)</a></h2>
form_begin( "id='wh-form'", "%R/wdiff" );
@ <input id="wh-pid" name="pid" type="radio" hidden>
@ <input id="wh-id" name="id" type="hidden">
@ </form>
@ <style> .wh-clickable { cursor: pointer; } </style>
@ <div class="brlist">
@ <table>
@ <thead><tr>
@ <th>Age</th>
@ <th>Hash</th>
|
| ︙ | ︙ | |||
1785 1786 1787 1788 1789 1790 1791 |
@ <tr class="wh-major" title="%s(zWhen)">
}
/* @ <td data-sortkey="%016llx(iMtime)">%s(zAge)</td> */
@ <td>%s(zAge)</td>
fossil_free(zAge);
@ <td>%z(href("%R/info/%s",zUuid))%S(zUuid)</a></td>
@ <td><input disabled type="radio" name="baseline" value="%S(zUuid)"/></td>
| | | 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 |
@ <tr class="wh-major" title="%s(zWhen)">
}
/* @ <td data-sortkey="%016llx(iMtime)">%s(zAge)</td> */
@ <td>%s(zAge)</td>
fossil_free(zAge);
@ <td>%z(href("%R/info/%s",zUuid))%S(zUuid)</a></td>
@ <td><input disabled type="radio" name="baseline" value="%S(zUuid)"/></td>
@ <td>%h(zUser)<span class="wh-iterations" hidden></td>
if( showRid ){
@ <td>%z(href("%R/artifact/%S",zUuid))%d(wrid)</a></td>
}
@ <td>%z(chref("wh-difflink","%R/wdiff?id=%S",zUuid))diff</a></td>
@ </tr>
}
@ </tbody></table></div>
|
| ︙ | ︙ | |||
1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 |
pW1 = manifest_get(rid1, CFTYPE_WIKI, 0);
if( pW1==0 ) fossil_redirect_home();
blob_init(&w1, pW1->zWiki, -1);
zPid = P("pid");
if( ( zPid==0 || zPid[0] == 0 ) && pW1->nParent ){
zPid = pW1->azParent[0];
}
if( zPid && zPid[0] != 0 ){
char *zDate;
rid2 = name_to_typed_rid(zPid, "w");
pW2 = manifest_get(rid2, CFTYPE_WIKI, 0);
blob_init(&w2, pW2->zWiki, -1);
@ <h2>Changes to \
@ "%z(href("%R/whistory?name=%s",pW1->zWikiTitle))%h(pW1->zWikiTitle)</a>" \
| > | 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 |
pW1 = manifest_get(rid1, CFTYPE_WIKI, 0);
if( pW1==0 ) fossil_redirect_home();
blob_init(&w1, pW1->zWiki, -1);
zPid = P("pid");
if( ( zPid==0 || zPid[0] == 0 ) && pW1->nParent ){
zPid = pW1->azParent[0];
}
cgi_check_for_malice();
if( zPid && zPid[0] != 0 ){
char *zDate;
rid2 = name_to_typed_rid(zPid, "w");
pW2 = manifest_get(rid2, CFTYPE_WIKI, 0);
blob_init(&w2, pW2->zWiki, -1);
@ <h2>Changes to \
@ "%z(href("%R/whistory?name=%s",pW1->zWikiTitle))%h(pW1->zWikiTitle)</a>" \
|
| ︙ | ︙ | |||
1865 1866 1867 1868 1869 1870 1871 |
}
style_set_current_feature("wiki");
style_header("Changes To %s", pW1->zWikiTitle);
blob_zero(&d);
construct_diff_flags(1, &DCfg);
DCfg.diffFlags |= DIFF_HTML | DIFF_LINENO;
text_diff(&w2, &w1, &d, &DCfg);
| < < | 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 |
}
style_set_current_feature("wiki");
style_header("Changes To %s", pW1->zWikiTitle);
blob_zero(&d);
construct_diff_flags(1, &DCfg);
DCfg.diffFlags |= DIFF_HTML | DIFF_LINENO;
text_diff(&w2, &w1, &d, &DCfg);
@ %s(blob_str(&d))
manifest_destroy(pW1);
manifest_destroy(pW2);
style_finish_page();
}
/*
** A query that returns information about all wiki pages.
|
| ︙ | ︙ | |||
1915 1916 1917 1918 1919 1920 1921 |
** List all available wiki pages with date created and last modified.
*/
void wcontent_page(void){
Stmt q;
double rNow;
int showAll = P("all")!=0;
int showRid = P("showid")!=0;
| | > > > > > > > | > | 1934 1935 1936 1937 1938 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 |
** List all available wiki pages with date created and last modified.
*/
void wcontent_page(void){
Stmt q;
double rNow;
int showAll = P("all")!=0;
int showRid = P("showid")!=0;
int showCkBr;
login_check_credentials();
if( !g.perm.RdWiki ){ login_needed(g.anon.RdWiki); return; }
style_set_current_feature("wiki");
style_header("Available Wiki Pages");
if( showAll ){
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/*' ) "
" 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:""*/);
@ <div class="brlist">
@ <table class='sortable' data-column-types='tKN' data-init-sort='1'>
@ <thead><tr>
@ <th>Name</th>
@ <th>Last Change</th>
|
| ︙ | ︙ | |||
1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 |
int wrid = db_column_int(&q, 2);
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( sqlite3_strglob("checkin/*", zWName)==0 ){
zWDisplayName = mprintf("%.25s...", zWName);
}else{
zWDisplayName = mprintf("%s", zWName);
}
| > > > > > < < < < < | 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 |
int wrid = db_column_int(&q, 2);
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 &&
(sqlite3_strglob("checkin/*", zWName)==0 ||
sqlite3_strglob("branch/*", zWName)==0) ){
continue;
}
if( sqlite3_strglob("checkin/*", zWName)==0 ){
zWDisplayName = mprintf("%.25s...", zWName);
}else{
zWDisplayName = mprintf("%s", 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)">\
@ %z(href("%R/wiki?name=%T&p",zWName))%h(zWDisplayName)</a></td>
|
| ︙ | ︙ | |||
1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 |
*/
void wfind_page(void){
Stmt q;
const char *zTitle;
login_check_credentials();
if( !g.perm.RdWiki ){ login_needed(g.anon.RdWiki); return; }
zTitle = PD("title","*");
style_set_current_feature("wiki");
style_header("Wiki Pages Found");
@ <ul>
db_prepare(&q,
"SELECT substr(tagname, 6, 1000) FROM tag WHERE tagname like 'wiki-%%%q%%'"
" ORDER BY lower(tagname) /*sort*/" ,
zTitle);
| > | 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 |
*/
void wfind_page(void){
Stmt q;
const char *zTitle;
login_check_credentials();
if( !g.perm.RdWiki ){ login_needed(g.anon.RdWiki); return; }
zTitle = PD("title","*");
cgi_check_for_malice();
style_set_current_feature("wiki");
style_header("Wiki Pages Found");
@ <ul>
db_prepare(&q,
"SELECT substr(tagname, 6, 1000) FROM tag WHERE tagname like 'wiki-%%%q%%'"
" ORDER BY lower(tagname) /*sort*/" ,
zTitle);
|
| ︙ | ︙ | |||
2494 2495 2496 2497 2498 2499 2500 |
const char *zPrefix, /* "branch", "tag", or "checkin" */
const char *zName, /* Name of the object */
unsigned int mFlags /* Zero or more WIKIASSOC_* flags */
){
if( (mFlags & WIKIASSOC_FULL_TITLE)==0 ){
@ <div class="section accordion">About</div>
}else if( zPrefix[0]=='c' ){ /* checkin/... */
| | | 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 |
const char *zPrefix, /* "branch", "tag", or "checkin" */
const char *zName, /* Name of the object */
unsigned int mFlags /* Zero or more WIKIASSOC_* flags */
){
if( (mFlags & WIKIASSOC_FULL_TITLE)==0 ){
@ <div class="section accordion">About</div>
}else if( zPrefix[0]=='c' ){ /* checkin/... */
@ <div class="section accordion">About check-in %.20h(zName)</div>
}else{
@ <div class="section accordion">About %s(zPrefix) %h(zName)</div>
}
}
/*
** Add an "Wiki" button in a submenu that links to the read-wiki page.
|
| ︙ | ︙ |
Changes to src/wikiformat.c.
| ︙ | ︙ | |||
193 194 195 196 197 198 199 200 201 202 203 204 205 206 | MARKUP_CENTER, MARKUP_CITE, MARKUP_CODE, MARKUP_COL, MARKUP_COLGROUP, MARKUP_DD, MARKUP_DEL, MARKUP_DFN, MARKUP_DIV, MARKUP_DL, MARKUP_DT, MARKUP_EM, MARKUP_FONT, MARKUP_HTML5_FOOTER, | > | 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 | MARKUP_CENTER, MARKUP_CITE, MARKUP_CODE, MARKUP_COL, MARKUP_COLGROUP, MARKUP_DD, MARKUP_DEL, MARKUP_DETAILS, MARKUP_DFN, MARKUP_DIV, MARKUP_DL, MARKUP_DT, MARKUP_EM, MARKUP_FONT, MARKUP_HTML5_FOOTER, |
| ︙ | ︙ | |||
227 228 229 230 231 232 233 234 235 236 237 238 239 240 | MARKUP_SAMP, MARKUP_HTML5_SECTION, MARKUP_SMALL, MARKUP_SPAN, MARKUP_STRIKE, MARKUP_STRONG, MARKUP_SUB, MARKUP_SUP, MARKUP_TABLE, MARKUP_TBODY, MARKUP_TD, MARKUP_TFOOT, MARKUP_TH, MARKUP_THEAD, | > | 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 | MARKUP_SAMP, MARKUP_HTML5_SECTION, MARKUP_SMALL, MARKUP_SPAN, MARKUP_STRIKE, MARKUP_STRONG, MARKUP_SUB, MARKUP_SUMMARY, MARKUP_SUP, MARKUP_TABLE, MARKUP_TBODY, MARKUP_TD, MARKUP_TFOOT, MARKUP_TH, MARKUP_THEAD, |
| ︙ | ︙ | |||
284 285 286 287 288 289 290 |
{ "a", MARKUP_A, MUTYPE_HYPERLINK,
AMSK_HREF|AMSK_NAME|AMSK_CLASS|AMSK_TARGET|AMSK_STYLE|
AMSK_TITLE},
{ "abbr", MARKUP_ABBR, MUTYPE_FONT,
AMSK_ID|AMSK_CLASS|AMSK_STYLE|AMSK_TITLE },
{ "address", MARKUP_ADDRESS, MUTYPE_BLOCK, AMSK_STYLE },
{ "article", MARKUP_HTML5_ARTICLE, MUTYPE_BLOCK,
| | | < > > | < < | < | | > > | 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 |
{ "a", MARKUP_A, MUTYPE_HYPERLINK,
AMSK_HREF|AMSK_NAME|AMSK_CLASS|AMSK_TARGET|AMSK_STYLE|
AMSK_TITLE},
{ "abbr", MARKUP_ABBR, MUTYPE_FONT,
AMSK_ID|AMSK_CLASS|AMSK_STYLE|AMSK_TITLE },
{ "address", MARKUP_ADDRESS, MUTYPE_BLOCK, AMSK_STYLE },
{ "article", MARKUP_HTML5_ARTICLE, MUTYPE_BLOCK,
AMSK_ID|AMSK_CLASS|AMSK_STYLE },
{ "aside", MARKUP_HTML5_ASIDE, MUTYPE_BLOCK,
AMSK_ID|AMSK_CLASS|AMSK_STYLE },
{ "b", MARKUP_B, MUTYPE_FONT, AMSK_STYLE },
{ "big", MARKUP_BIG, MUTYPE_FONT, AMSK_STYLE },
{ "blockquote", MARKUP_BLOCKQUOTE, MUTYPE_BLOCK, AMSK_STYLE },
{ "br", MARKUP_BR, MUTYPE_SINGLE, AMSK_CLEAR },
{ "center", MARKUP_CENTER, MUTYPE_BLOCK, AMSK_STYLE },
{ "cite", MARKUP_CITE, MUTYPE_FONT, AMSK_STYLE },
{ "code", MARKUP_CODE, MUTYPE_FONT, AMSK_STYLE },
{ "col", MARKUP_COL, MUTYPE_SINGLE,
AMSK_ALIGN|AMSK_CLASS|AMSK_COLSPAN|AMSK_WIDTH|AMSK_STYLE },
{ "colgroup", MARKUP_COLGROUP, MUTYPE_BLOCK,
AMSK_ALIGN|AMSK_CLASS|AMSK_COLSPAN|AMSK_WIDTH|AMSK_STYLE},
{ "dd", MARKUP_DD, MUTYPE_LI, AMSK_STYLE },
{ "del", MARKUP_DEL, MUTYPE_FONT, AMSK_STYLE },
{ "details", MARKUP_DETAILS, MUTYPE_BLOCK,
AMSK_ID|AMSK_CLASS|AMSK_STYLE },
{ "dfn", MARKUP_DFN, MUTYPE_FONT, AMSK_STYLE },
{ "div", MARKUP_DIV, MUTYPE_BLOCK,
AMSK_ID|AMSK_CLASS|AMSK_STYLE },
{ "dl", MARKUP_DL, MUTYPE_LIST,
AMSK_COMPACT|AMSK_STYLE },
{ "dt", MARKUP_DT, MUTYPE_LI, AMSK_STYLE },
{ "em", MARKUP_EM, MUTYPE_FONT, AMSK_STYLE },
{ "font", MARKUP_FONT, MUTYPE_FONT,
AMSK_COLOR|AMSK_FACE|AMSK_SIZE|AMSK_STYLE },
{ "footer", MARKUP_HTML5_FOOTER, MUTYPE_BLOCK,
AMSK_ID|AMSK_CLASS|AMSK_STYLE },
{ "h1", MARKUP_H1, MUTYPE_BLOCK,
AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE },
{ "h2", MARKUP_H2, MUTYPE_BLOCK,
AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE },
{ "h3", MARKUP_H3, MUTYPE_BLOCK,
AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE },
{ "h4", MARKUP_H4, MUTYPE_BLOCK,
AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE },
{ "h5", MARKUP_H5, MUTYPE_BLOCK,
AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE },
{ "h6", MARKUP_H6, MUTYPE_BLOCK,
AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE },
{ "header", MARKUP_HTML5_HEADER, MUTYPE_BLOCK,
AMSK_ID|AMSK_CLASS|AMSK_STYLE },
{ "hr", MARKUP_HR, MUTYPE_SINGLE,
AMSK_ALIGN|AMSK_COLOR|AMSK_SIZE|AMSK_WIDTH|
AMSK_STYLE|AMSK_CLASS },
{ "i", MARKUP_I, MUTYPE_FONT, AMSK_STYLE },
{ "img", MARKUP_IMG, MUTYPE_SINGLE,
AMSK_ALIGN|AMSK_ALT|AMSK_BORDER|AMSK_HEIGHT|
AMSK_HSPACE|AMSK_SRC|AMSK_VSPACE|AMSK_WIDTH|AMSK_STYLE },
{ "ins", MARKUP_INS, MUTYPE_FONT, AMSK_STYLE },
{ "kbd", MARKUP_KBD, MUTYPE_FONT, AMSK_STYLE },
{ "li", MARKUP_LI, MUTYPE_LI,
AMSK_TYPE|AMSK_VALUE|AMSK_STYLE },
{ "nav", MARKUP_HTML5_NAV, MUTYPE_BLOCK,
AMSK_ID|AMSK_CLASS|AMSK_STYLE },
{ "nobr", MARKUP_NOBR, MUTYPE_FONT, 0 },
{ "nowiki", MARKUP_NOWIKI, MUTYPE_SPECIAL, 0 },
{ "ol", MARKUP_OL, MUTYPE_LIST,
AMSK_START|AMSK_TYPE|AMSK_COMPACT|AMSK_STYLE },
{ "p", MARKUP_P, MUTYPE_BLOCK,
AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE },
{ "pre", MARKUP_PRE, MUTYPE_BLOCK, AMSK_STYLE },
{ "s", MARKUP_S, MUTYPE_FONT, AMSK_STYLE },
{ "samp", MARKUP_SAMP, MUTYPE_FONT, AMSK_STYLE },
{ "section", MARKUP_HTML5_SECTION, MUTYPE_BLOCK,
AMSK_ID|AMSK_CLASS|AMSK_STYLE },
{ "small", MARKUP_SMALL, MUTYPE_FONT, AMSK_STYLE },
{ "span", MARKUP_SPAN, MUTYPE_BLOCK,
AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE },
{ "strike", MARKUP_STRIKE, MUTYPE_FONT, AMSK_STYLE },
{ "strong", MARKUP_STRONG, MUTYPE_FONT, AMSK_STYLE },
{ "sub", MARKUP_SUB, MUTYPE_FONT, AMSK_STYLE },
{ "summary", MARKUP_SUMMARY, MUTYPE_BLOCK,
AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE },
{ "sup", MARKUP_SUP, MUTYPE_FONT, AMSK_STYLE },
{ "table", MARKUP_TABLE, MUTYPE_TABLE,
AMSK_ALIGN|AMSK_BGCOLOR|AMSK_BORDER|AMSK_CELLPADDING|
AMSK_CELLSPACING|AMSK_HSPACE|AMSK_VSPACE|AMSK_CLASS|
AMSK_STYLE },
{ "tbody", MARKUP_TBODY, MUTYPE_BLOCK,
AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE },
|
| ︙ | ︙ | |||
788 789 790 791 792 793 794 |
i = 2;
}else{
p->endTag = 0;
i = 1;
}
j = 0;
while( fossil_isalnum(z[i]) ){
| | | 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 |
i = 2;
}else{
p->endTag = 0;
i = 1;
}
j = 0;
while( fossil_isalnum(z[i]) ){
if( j<(int)sizeof(zTag)-1 ) zTag[j++] = fossil_tolower(z[i]);
i++;
}
zTag[j] = 0;
p->iCode = findTag(zTag);
p->iType = aMarkup[p->iCode].iType;
p->nAttr = 0;
c = 0;
|
| ︙ | ︙ | |||
811 812 813 814 815 816 817 |
if( c=='>' ) return 0;
}
while( fossil_isspace(z[i]) ){ i++; }
while( c!='>' && p->nAttr<8 && fossil_isalpha(z[i]) ){
int attrOk; /* True to preserve attribute. False to ignore it */
j = 0;
while( fossil_isalnum(z[i]) ){
| | | 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 |
if( c=='>' ) return 0;
}
while( fossil_isspace(z[i]) ){ i++; }
while( c!='>' && p->nAttr<8 && fossil_isalpha(z[i]) ){
int attrOk; /* True to preserve attribute. False to ignore it */
j = 0;
while( fossil_isalnum(z[i]) ){
if( j<(int)sizeof(zTag)-1 ) zTag[j++] = fossil_tolower(z[i]);
i++;
}
zTag[j] = 0;
p->aAttr[p->nAttr].iACode = iACode = findAttr(zTag);
attrOk = iACode!=0 && (seen & aAttribute[iACode].iMask)==0;
while( fossil_isspace(z[i]) ){ z++; }
if( z[i]!='=' ){
|
| ︙ | ︙ | |||
1103 1104 1105 1106 1107 1108 1109 |
int n;
char zU2[HNAME_MAX+1];
db_static_prepare(&q,
"SELECT 1 FROM blob WHERE uuid>=:u AND uuid<:u2"
);
db_bind_text(&q, ":u", zUuid);
n = (int)strlen(zUuid);
| | | 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 |
int n;
char zU2[HNAME_MAX+1];
db_static_prepare(&q,
"SELECT 1 FROM blob WHERE uuid>=:u AND uuid<:u2"
);
db_bind_text(&q, ":u", zUuid);
n = (int)strlen(zUuid);
if( n>=(int)sizeof(zU2) ) n = sizeof(zU2)-1;
memcpy(zU2, zUuid, n);
zU2[n-1]++;
zU2[n] = 0;
db_bind_text(&q, ":u2", zU2);
rc = db_step(&q);
db_reset(&q);
return rc==SQLITE_ROW;
|
| ︙ | ︙ | |||
1356 1357 1358 1359 1360 1361 1362 |
/* Also ignore the link if various flags are set */
zTerm = "";
}else{
blob_appendf(pOut, "<span class=\"brokenlink\">[%h]", zTarget);
zTerm = "</span>";
}
if( zExtra ) fossil_free(zExtra);
| | | 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 |
/* Also ignore the link if various flags are set */
zTerm = "";
}else{
blob_appendf(pOut, "<span class=\"brokenlink\">[%h]", zTarget);
zTerm = "</span>";
}
if( zExtra ) fossil_free(zExtra);
assert( (int)strlen(zTerm)<nClose );
sqlite3_snprintf(nClose, zClose, "%s", zTerm);
}
/*
** Check to see if the given parsed markup is the correct
** </verbatim> tag.
*/
|
| ︙ | ︙ | |||
1925 1926 1927 1928 1929 1930 1931 |
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"
" %8d misreference%s\n"
" %8d unreferenced\n"
| | | 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 |
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"
" %8d misreference%s\n"
" %8d unreferenced\n"
" %8d split\n"
" %8d overnested",
g.ftntsIssues[0], g.ftntsIssues[0]==1?"":"s",
g.ftntsIssues[1], g.ftntsIssues[2], g.ftntsIssues[3]);
}
}
/*
|
| ︙ | ︙ |
Changes to src/winhttp.c.
| ︙ | ︙ | |||
407 408 409 410 411 412 413 |
}else{
break;
}
wanted -= got;
}
/*
| | | | 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 |
}else{
break;
}
wanted -= got;
}
/*
** The repository name is only needed if there was no open check-out. This
** is designed to allow the open check-out for the interactive user to work
** with the local Fossil server started via the "ui" command.
*/
zIp = SocketAddr_toString(&p->addr);
if( (p->flags & HTTP_SERVER_HAD_CHECKOUT)==0 ){
assert( g.zRepositoryName && g.zRepositoryName[0] );
sqlite3_snprintf(sizeof(zCmd), zCmd, "%s--in %s\n--out %s\n--ipaddr %s\n%s",
get_utf8_bom(0), zRequestFName, zReplyFName, zIp, g.zRepositoryName
|
| ︙ | ︙ | |||
568 569 570 571 572 573 574 575 576 577 578 579 580 581 | HANDLE hStoppedEvent; WSADATA wd; DualSocket ds; int idCnt = 0; int iPort = mnPort; Blob options; wchar_t zTmpPath[MAX_PATH]; const char *zSkin; #if USE_SEE const char *zSavedKey = 0; size_t savedKeySize = 0; #endif blob_zero(&options); | > > | 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 | HANDLE hStoppedEvent; WSADATA wd; DualSocket ds; int idCnt = 0; int iPort = mnPort; Blob options; wchar_t zTmpPath[MAX_PATH]; char *zTempSubDirPath; const char *zTempSubDir = "fossil"; const char *zSkin; #if USE_SEE const char *zSavedKey = 0; size_t savedKeySize = 0; #endif blob_zero(&options); |
| ︙ | ︙ | |||
621 622 623 624 625 626 627 |
if( builtin_get_js_delivery_mode()!=0 /* JS_INLINE==0 may change? */ ){
blob_appendf(&options, " --jsmode ");
blob_append_escaped_arg(&options, builtin_get_js_delivery_mode_name(), 0);
}
#if USE_SEE
zSavedKey = db_get_saved_encryption_key();
savedKeySize = db_get_saved_encryption_key_size();
| | | 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 |
if( builtin_get_js_delivery_mode()!=0 /* JS_INLINE==0 may change? */ ){
blob_appendf(&options, " --jsmode ");
blob_append_escaped_arg(&options, builtin_get_js_delivery_mode_name(), 0);
}
#if USE_SEE
zSavedKey = db_get_saved_encryption_key();
savedKeySize = db_get_saved_encryption_key_size();
if( db_is_valid_saved_encryption_key(zSavedKey, savedKeySize) ){
blob_appendf(&options, " --usepidkey %lu:%p:%u", GetCurrentProcessId(),
zSavedKey, savedKeySize);
}
#endif
if( WSAStartup(MAKEWORD(2,0), &wd) ){
fossil_panic("unable to initialize winsock");
}
|
| ︙ | ︙ | |||
659 660 661 662 663 664 665 666 667 668 669 670 671 672 |
fossil_fatal("unable to open listening socket on any"
" port in the range %d..%d", mnPort, mxPort);
}
}
if( !GetTempPathW(MAX_PATH, zTmpPath) ){
fossil_panic("unable to get path to the temporary directory.");
}
if( g.fHttpTrace ){
zTempPrefix = mprintf("httptrace");
}else{
zTempPrefix = mprintf("%sfossil_server_P%d",
fossil_unicode_to_utf8(zTmpPath), iPort);
}
fossil_print("Temporary files: %s*\n", zTempPrefix);
| > > > > > > | 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 |
fossil_fatal("unable to open listening socket on any"
" port in the range %d..%d", mnPort, mxPort);
}
}
if( !GetTempPathW(MAX_PATH, zTmpPath) ){
fossil_panic("unable to get path to the temporary directory.");
}
/* Use a subdirectory for temp files (can then be excluded from virus scan) */
zTempSubDirPath = mprintf("%s%s\\",fossil_path_to_utf8(zTmpPath),zTempSubDir);
if ( !file_mkdir(zTempSubDirPath, ExtFILE, 0) ||
file_isdir(zTempSubDirPath, ExtFILE)==1 ){
wcscpy(zTmpPath, fossil_utf8_to_path(zTempSubDirPath, 1));
}
if( g.fHttpTrace ){
zTempPrefix = mprintf("httptrace");
}else{
zTempPrefix = mprintf("%sfossil_server_P%d",
fossil_unicode_to_utf8(zTmpPath), iPort);
}
fossil_print("Temporary files: %s*\n", zTempPrefix);
|
| ︙ | ︙ | |||
1026 1027 1028 1029 1030 1031 1032 | ** Specifies the TCP port (default port is 8080) on which the ** server should listen. ** ** -R|--repository REPO ** ** Specifies the name of the repository to be served. ** The repository option may be omitted if the working directory | | | 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 | ** Specifies the TCP port (default port is 8080) on which the ** server should listen. ** ** -R|--repository REPO ** ** Specifies the name of the repository to be served. ** The repository option may be omitted if the working directory ** is within an open check-out. ** The REPOSITORY can be a directory (aka folder) that contains ** one or more repositories with names ending in ".fossil". ** In that case, the first element of the URL is used to select ** among the various repositories. ** ** --notfound URL ** |
| ︙ | ︙ |
Changes to src/xfer.c.
| ︙ | ︙ | |||
352 353 354 355 356 357 358 |
goto end_accept_unversioned_file;
}
}else{
nullContent = 1;
}
/* The isWriter flag must be true in order to land the new file */
| > > | > | 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 |
goto end_accept_unversioned_file;
}
}else{
nullContent = 1;
}
/* The isWriter flag must be true in order to land the new file */
if( !isWriter ){
blob_appendf(&pXfer->err, "Write permissions for unversioned files missing");
goto end_accept_unversioned_file;
}
/* Make sure we have a valid g.rcvid marker */
content_rcvid_init(0);
/* Check to see if current content really should be overwritten. Ideally,
** a uvfile card should never have been sent unless the overwrite should
** occur. But do not trust the sender. Double-check.
|
| ︙ | ︙ | |||
448 449 450 451 452 453 454 |
if( srcId>0
&& (pXfer->syncPrivate || !content_is_private(srcId))
&& content_get(srcId, &src)
){
char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", srcId);
blob_delta_create(&src, pContent, &delta);
size = blob_size(&delta);
| | | 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 |
if( srcId>0
&& (pXfer->syncPrivate || !content_is_private(srcId))
&& content_get(srcId, &src)
){
char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", srcId);
blob_delta_create(&src, pContent, &delta);
size = blob_size(&delta);
if( size>=(int)blob_size(pContent)-50 ){
size = 0;
}else if( uuid_is_shunned(zUuid) ){
size = 0;
}else{
if( isPrivate ) blob_append(pXfer->pOut, "private\n", -1);
blob_appendf(pXfer->pOut, "file %b %s %d\n", pUuid, zUuid, size);
blob_append(pXfer->pOut, blob_buffer(&delta), size);
|
| ︙ | ︙ | |||
575 576 577 578 579 580 581 |
pUuid = &uuid;
}
if( uuid_is_shunned(blob_str(pUuid)) ){
blob_reset(&uuid);
return;
}
if( (pXfer->maxTime != -1 && time(NULL) >= pXfer->maxTime) ||
| | | 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 |
pUuid = &uuid;
}
if( uuid_is_shunned(blob_str(pUuid)) ){
blob_reset(&uuid);
return;
}
if( (pXfer->maxTime != -1 && time(NULL) >= pXfer->maxTime) ||
pXfer->mxSend<=(int)blob_size(pXfer->pOut) ){
const char *zFormat = isPriv ? "igot %b 1\n" : "igot %b\n";
blob_appendf(pXfer->pOut, zFormat /*works-like:"%b"*/, pUuid);
pXfer->nIGotSent++;
blob_reset(&uuid);
return;
}
if( nativeDelta ){
|
| ︙ | ︙ | |||
699 700 701 702 703 704 705 |
static void send_unversioned_file(
Xfer *pXfer, /* Transfer context */
const char *zName, /* Name of unversioned file to be sent */
int noContent /* True to omit the content */
){
Stmt q1;
| | | | 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 |
static void send_unversioned_file(
Xfer *pXfer, /* Transfer context */
const char *zName, /* Name of unversioned file to be sent */
int noContent /* True to omit the content */
){
Stmt q1;
if( (int)blob_size(pXfer->pOut)>=pXfer->mxSend ) noContent = 1;
if( noContent ){
db_prepare(&q1,
"SELECT mtime, hash, encoding, sz FROM unversioned WHERE name=%Q",
zName
);
}else{
db_prepare(&q1,
"SELECT mtime, hash, encoding, sz, content FROM unversioned"
" WHERE name=%Q",
zName
);
}
if( db_step(&q1)==SQLITE_ROW ){
sqlite3_int64 mtime = db_column_int64(&q1, 0);
const char *zHash = db_column_text(&q1, 1);
if( pXfer->remoteVersion<20000 && db_column_bytes(&q1,1)>HNAME_LEN_SHA1 ){
xfer_cannot_send_sha3_error(pXfer);
db_reset(&q1);
return;
}
if( (int)blob_size(pXfer->pOut)>=pXfer->mxSend ){
/* If we have already reached the send size limit, send a (short)
** uvigot card rather than a uvfile card. This only happens on the
** server side. The uvigot card will provoke the client to resend
** another uvgimme on the next cycle. */
blob_appendf(pXfer->pOut, "uvigot %s %lld %s %d\n",
zName, mtime, zHash, db_column_int(&q1,3));
}else{
|
| ︙ | ︙ | |||
796 797 798 799 800 801 802 | ** Check the signature on an application/x-fossil payload received by ** the HTTP server. The signature is a line of the following form: ** ** login LOGIN NONCE SIGNATURE ** ** The NONCE is the SHA1 hash of the remainder of the input. ** SIGNATURE is the SHA1 checksum of the NONCE concatenated | | > > | | 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 |
** Check the signature on an application/x-fossil payload received by
** the HTTP server. The signature is a line of the following form:
**
** login LOGIN NONCE SIGNATURE
**
** The NONCE is the SHA1 hash of the remainder of the input.
** SIGNATURE is the SHA1 checksum of the NONCE concatenated
** with the sha1_shared_secret() encoding of the users password.
**
** SIGNATURE = sha1_sum( NONCE + sha1_shared_secret(PASSWORD) );
**
** The parameters to this routine are ephemeral blobs holding the
** LOGIN, NONCE and SIGNATURE.
**
** This routine attempts to locate the user and verify the signature.
** If everything checks out, the USER.CAP column for the USER table
** is consulted to set privileges in the global g variable.
**
** If anything fails to check out, no changes are made to privileges.
**
** Signature generation on the client side is handled by the
** http_exchange() routine.
**
** Return non-zero for a login failure and zero for success.
*/
static int check_login(Blob *pLogin, Blob *pNonce, Blob *pSig){
Stmt q;
int rc = -1;
char *zLogin = blob_terminate(pLogin);
defossilize(zLogin);
if( fossil_strcmp(zLogin, "nobody")==0
|| fossil_strcmp(zLogin,"anonymous")==0
|
| ︙ | ︙ | |||
1025 1026 1027 1028 1029 1030 1031 |
" AND NOT EXISTS(SELECT 1 FROM private WHERE rid=blob.rid)%s",
zExtra /*safe-for-%s*/
);
}
while( db_step(&q)==SQLITE_ROW ){
blob_appendf(pXfer->pOut, "igot %s\n", db_column_text(&q, 0));
cnt++;
| | | 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 |
" AND NOT EXISTS(SELECT 1 FROM private WHERE rid=blob.rid)%s",
zExtra /*safe-for-%s*/
);
}
while( db_step(&q)==SQLITE_ROW ){
blob_appendf(pXfer->pOut, "igot %s\n", db_column_text(&q, 0));
cnt++;
if( pXfer->resync && pXfer->mxSend<(int)blob_size(pXfer->pOut) ){
pXfer->resync = db_column_int(&q, 1)-1;
}
}
db_finalize(&q);
if( cnt==0 ) pXfer->resync = 0;
return cnt;
}
|
| ︙ | ︙ | |||
1059 1060 1061 1062 1063 1064 1065 |
** pXfer is a "pragma uv-hash HASH" card.
**
** If HASH is different from the unversioned content hash on this server,
** then send a bunch of uvigot cards, one for each entry unversioned file
** on this server.
*/
static void send_unversioned_catalog(Xfer *pXfer){
| < < | 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 |
** pXfer is a "pragma uv-hash HASH" card.
**
** If HASH is different from the unversioned content hash on this server,
** then send a bunch of uvigot cards, one for each entry unversioned file
** on this server.
*/
static void send_unversioned_catalog(Xfer *pXfer){
Stmt uvq;
unversioned_schema();
db_prepare(&uvq,
"SELECT name, mtime, hash, sz FROM unversioned"
);
while( db_step(&uvq)==SQLITE_ROW ){
const char *zName = db_column_text(&uvq,0);
sqlite3_int64 mtime = db_column_int64(&uvq,1);
const char *zHash = db_column_text(&uvq,2);
int sz = db_column_int(&uvq,3);
if( zHash==0 ){ sz = 0; zHash = "-"; }
blob_appendf(pXfer->pOut, "uvigot %s %lld %s %d\n",
zName, mtime, zHash, sz);
}
db_finalize(&uvq);
}
|
| ︙ | ︙ | |||
1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 |
if( fossil_strcmp(PD("REQUEST_METHOD","POST"),"POST") ){
fossil_redirect_home();
}
g.zLogin = "anonymous";
login_set_anon_nobody_capabilities();
login_check_credentials();
memset(&xfer, 0, sizeof(xfer));
blobarray_zero(xfer.aToken, count(xfer.aToken));
cgi_set_content_type(g.zContentType);
cgi_reset_content();
if( db_schema_is_outofdate() ){
@ error database\sschema\sis\sout-of-date\son\sthe\sserver.
return;
| > | 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 |
if( fossil_strcmp(PD("REQUEST_METHOD","POST"),"POST") ){
fossil_redirect_home();
}
g.zLogin = "anonymous";
login_set_anon_nobody_capabilities();
login_check_credentials();
cgi_check_for_malice();
memset(&xfer, 0, sizeof(xfer));
blobarray_zero(xfer.aToken, count(xfer.aToken));
cgi_set_content_type(g.zContentType);
cgi_reset_content();
if( db_schema_is_outofdate() ){
@ error database\sschema\sis\sout-of-date\son\sthe\sserver.
return;
|
| ︙ | ︙ | |||
1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 |
** Server accepts an unversioned file from the client.
*/
if( blob_eq(&xfer.aToken[0], "uvfile") ){
xfer_accept_unversioned_file(&xfer, g.perm.WrUnver);
if( blob_size(&xfer.err) ){
cgi_reset_content();
@ error %T(blob_str(&xfer.err))
nErr++;
break;
}
}else
/* gimme HASH
**
| > | 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 |
** Server accepts an unversioned file from the client.
*/
if( blob_eq(&xfer.aToken[0], "uvfile") ){
xfer_accept_unversioned_file(&xfer, g.perm.WrUnver);
if( blob_size(&xfer.err) ){
cgi_reset_content();
@ error %T(blob_str(&xfer.err))
fossil_print("%%%%%%%% xfer.err: '%s'\n", blob_str(&xfer.err));
nErr++;
break;
}
}else
/* gimme HASH
**
|
| ︙ | ︙ | |||
1455 1456 1457 1458 1459 1460 1461 |
){
int seqno, max;
if( iVers>=3 ){
cgi_set_content_type("application/x-fossil-uncompressed");
}
blob_is_int(&xfer.aToken[2], &seqno);
max = db_int(0, "SELECT max(rid) FROM blob");
| | | 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 |
){
int seqno, max;
if( iVers>=3 ){
cgi_set_content_type("application/x-fossil-uncompressed");
}
blob_is_int(&xfer.aToken[2], &seqno);
max = db_int(0, "SELECT max(rid) FROM blob");
while( xfer.mxSend>(int)blob_size(xfer.pOut) && seqno<=max){
if( time(NULL) >= xfer.maxTime ) break;
if( iVers>=3 ){
send_compressed_file(&xfer, seqno);
}else{
send_file(&xfer, seqno, 0, 1);
}
seqno++;
|
| ︙ | ︙ | |||
1577 1578 1579 1580 1581 1582 1583 |
xfer.nextIsPrivate = 1;
}
}else
/* pragma NAME VALUE...
**
| | | 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 |
xfer.nextIsPrivate = 1;
}
}else
/* pragma NAME VALUE...
**
** The client issues pragmas to try to influence the behavior of the
** server. These are requests only. Unknown pragmas are silently
** ignored.
*/
if( blob_eq(&xfer.aToken[0], "pragma") && xfer.nToken>=2 ){
/* pragma send-private
**
|
| ︙ | ︙ | |||
1836 1837 1838 1839 1840 1841 1842 |
db_finalize(&q);
}
/* Send the server timestamp last, in case prior processing happened
** to use up a significant fraction of our time window.
*/
zNow = db_text(0, "SELECT strftime('%%Y-%%m-%%dT%%H:%%M:%%S', 'now')");
| | | 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 |
db_finalize(&q);
}
/* Send the server timestamp last, in case prior processing happened
** to use up a significant fraction of our time window.
*/
zNow = db_text(0, "SELECT strftime('%%Y-%%m-%%dT%%H:%%M:%%S', 'now')");
@ # timestamp %s(zNow) errors %d(nErr)
free(zNow);
db_commit_transaction();
configure_rebuild();
}
/*
|
| ︙ | ︙ | |||
1870 1871 1872 1873 1874 1875 1876 | ** The complete HTTP requests are stored in files named "http-request-N.txt". ** Find one of those requests, remove the HTTP header, and make other edits ** as necessary to generate an appropriate XFERFILE test case. Then run: ** ** fossil test-xfer xferfile.txt ** ** Options: | < | 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 |
** The complete HTTP requests are stored in files named "http-request-N.txt".
** Find one of those requests, remove the HTTP header, and make other edits
** as necessary to generate an appropriate XFERFILE test case. Then run:
**
** fossil test-xfer xferfile.txt
**
** Options:
** --host HOSTNAME Supply a server hostname used to populate
** g.zBaseURL and similar.
*/
void cmd_test_xfer(void){
const char *zHost;
db_find_and_open_repository(0,0);
zHost = find_option("host",0,1);
|
| ︙ | ︙ | |||
1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 |
#define SYNC_UV_TRACE 0x00400 /* Describe UV activities */
#define SYNC_UV_DRYRUN 0x00800 /* Do not actually exchange files */
#define SYNC_IFABLE 0x01000 /* Inability to sync is not fatal */
#define SYNC_CKIN_LOCK 0x02000 /* Lock the current check-in */
#define SYNC_NOHTTPCOMPRESS 0x04000 /* Do not compression HTTP messages */
#define SYNC_ALLURL 0x08000 /* The --all flag - sync to all URLs */
#define SYNC_SHARE_LINKS 0x10000 /* Request alternate repo links */
#endif
/*
** Floating-point absolute value
*/
static double fossil_fabs(double x){
return x>0.0 ? x : -x;
| > | 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 |
#define SYNC_UV_TRACE 0x00400 /* Describe UV activities */
#define SYNC_UV_DRYRUN 0x00800 /* Do not actually exchange files */
#define SYNC_IFABLE 0x01000 /* Inability to sync is not fatal */
#define SYNC_CKIN_LOCK 0x02000 /* Lock the current check-in */
#define SYNC_NOHTTPCOMPRESS 0x04000 /* Do not compression HTTP messages */
#define SYNC_ALLURL 0x08000 /* The --all flag - sync to all URLs */
#define SYNC_SHARE_LINKS 0x10000 /* Request alternate repo links */
#define SYNC_XVERBOSE 0x20000 /* Extra verbose. Network traffic */
#endif
/*
** Floating-point absolute value
*/
static double fossil_fabs(double x){
return x>0.0 ? x : -x;
|
| ︙ | ︙ | |||
2066 2067 2068 2069 2070 2071 2072 |
if( (syncFlags & (SYNC_UNVERSIONED|SYNC_CLONE))!=0 ){
unversioned_schema();
db_multi_exec(
"CREATE TEMP TABLE IF NOT EXISTS uv_tosend("
" name TEXT PRIMARY KEY," /* Name of file to send client->server */
" mtimeOnly BOOLEAN" /* True to only send mtime, not content */
") WITHOUT ROWID;"
| | | 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 |
if( (syncFlags & (SYNC_UNVERSIONED|SYNC_CLONE))!=0 ){
unversioned_schema();
db_multi_exec(
"CREATE TEMP TABLE IF NOT EXISTS uv_tosend("
" name TEXT PRIMARY KEY," /* Name of file to send client->server */
" mtimeOnly BOOLEAN" /* True to only send mtime, not content */
") WITHOUT ROWID;"
"REPLACE INTO uv_tosend(name,mtimeOnly)"
" SELECT name, 0 FROM unversioned WHERE hash IS NOT NULL;"
);
}
/*
** The request from the client always begin with a clone, pull,
** or push message.
|
| ︙ | ︙ | |||
2227 2228 2229 2230 2231 2232 2233 |
send_unversioned_file(&xfer, zName, db_column_int(&uvq,1));
nCardSent++;
nArtifactSent++;
db_multi_exec("DELETE FROM uv_tosend WHERE name=%Q", zName);
if( syncFlags & SYNC_VERBOSE ){
fossil_print("\rUnversioned-file sent: %s\n", zName);
}
| | | 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 |
send_unversioned_file(&xfer, zName, db_column_int(&uvq,1));
nCardSent++;
nArtifactSent++;
db_multi_exec("DELETE FROM uv_tosend WHERE name=%Q", zName);
if( syncFlags & SYNC_VERBOSE ){
fossil_print("\rUnversioned-file sent: %s\n", zName);
}
if( (int)blob_size(xfer.pOut)>xfer.mxSend ) break;
}
db_finalize(&uvq);
if( rc==SQLITE_DONE ) uvDoPush = 0;
}
}
/* Lock the current check-out */
|
| ︙ | ︙ | |||
2254 2255 2256 2257 2258 2259 2260 |
** messages unique so that that the login-card nonce will always
** be unique.
*/
zRandomness = db_text(0, "SELECT hex(randomblob(20))");
blob_appendf(&send, "# %s\n", zRandomness);
free(zRandomness);
| | > > > > > | 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 |
** messages unique so that that the login-card nonce will always
** be unique.
*/
zRandomness = db_text(0, "SELECT hex(randomblob(20))");
blob_appendf(&send, "# %s\n", zRandomness);
free(zRandomness);
if( (syncFlags & SYNC_VERBOSE)!=0
&& (syncFlags & SYNC_XVERBOSE)==0
){
fossil_print("waiting for server...");
}
fflush(stdout);
/* Exchange messages with the server */
if( (syncFlags & SYNC_CLONE)!=0 && nCycle==0 ){
/* Do not send a login card on the first round-trip of a clone */
mHttpFlags = 0;
}else{
mHttpFlags = HTTP_USE_LOGIN;
}
if( syncFlags & SYNC_NOHTTPCOMPRESS ){
mHttpFlags |= HTTP_NOCOMPRESS;
}
if( syncFlags & SYNC_XVERBOSE ){
mHttpFlags |= HTTP_VERBOSE;
}
/* Do the round-trip to the server */
if( http_exchange(&send, &recv, mHttpFlags, MAX_REDIRECTS, 0) ){
nErr++;
go = 2;
break;
|
| ︙ | ︙ | |||
2633 2634 2635 2636 2637 2638 2639 |
** The server can send pragmas to try to convey meta-information to
** the client. These are informational only. Unknown pragmas are
** silently ignored.
*/
if( blob_eq(&xfer.aToken[0], "pragma") && xfer.nToken>=2 ){
/* pragma server-version VERSION ?DATE? ?TIME?
**
| | | | 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 |
** The server can send pragmas to try to convey meta-information to
** the client. These are informational only. Unknown pragmas are
** silently ignored.
*/
if( blob_eq(&xfer.aToken[0], "pragma") && xfer.nToken>=2 ){
/* pragma server-version VERSION ?DATE? ?TIME?
**
** The server announces to the server what version of Fossil it
** is running. The DATE and TIME are a pure numeric ISO8601 time
** for the specific check-in of the client.
*/
if( xfer.nToken>=3 && blob_eq(&xfer.aToken[1], "server-version") ){
xfer.remoteVersion = atoi(blob_str(&xfer.aToken[2]));
if( xfer.nToken>=5 ){
xfer.remoteDate = atoi(blob_str(&xfer.aToken[3]));
xfer.remoteTime = atoi(blob_str(&xfer.aToken[4]));
}
}
/* pragma uv-pull-only
** pragma uv-push-ok
**
** If the server is unwilling to accept new unversioned content (because
** this client lacks the necessary permissions) then it sends a
** "uv-pull-only" pragma so that the client will know not to waste
** bandwidth trying to upload unversioned content. If the server
** does accept new unversioned content, it sends "uv-push-ok".
*/
else if( syncFlags & SYNC_UNVERSIONED ){
if( blob_eq(&xfer.aToken[1], "uv-pull-only") ){
|
| ︙ | ︙ | |||
2805 2806 2807 2808 2809 2810 2811 |
/* Set go to 1 if we need to continue the sync/push/pull/clone for
** another round. Set go to 0 if it is time to quit. */
nFileRecv = xfer.nFileRcvd + xfer.nDeltaRcvd + xfer.nDanglingFile;
if( (nFileRecv>0 || newPhantom) && db_exists("SELECT 1 FROM phantom") ){
go = 1;
mxPhantomReq = nFileRecv*2;
if( mxPhantomReq<200 ) mxPhantomReq = 200;
| < < > > > > > > < < < < | 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 |
/* Set go to 1 if we need to continue the sync/push/pull/clone for
** another round. Set go to 0 if it is time to quit. */
nFileRecv = xfer.nFileRcvd + xfer.nDeltaRcvd + xfer.nDanglingFile;
if( (nFileRecv>0 || newPhantom) && db_exists("SELECT 1 FROM phantom") ){
go = 1;
mxPhantomReq = nFileRecv*2;
if( mxPhantomReq<200 ) mxPhantomReq = 200;
}else if( xfer.nFileSent+xfer.nDeltaSent>0 || uvDoPush ){
/* Go another round if files are queued to send */
go = 1;
}else if( xfer.nPrivIGot>0 && nCycle==1 ){
go = 1;
}else if( nUvGimmeSent>0 && (nUvFileRcvd>0 || nCycle<3) ){
/* Continue looping as long as new uvfile cards are being received
** and uvgimme cards are being sent. */
go = 1;
}else if( (syncFlags & SYNC_CLONE)!=0 ){
if( nCycle==1 ){
go = 1; /* go at least two rounds on a clone */
}else if( nFileRecv>0 ){
go = 1;
}else if( cloneSeqno>0 && nArtifactRcvd>nPriorArtifact ){
/* Continue the clone until we see the clone_seqno 0" card or
** until we stop receiving artifacts */
go = 1;
}
}
nCardRcvd = 0;
xfer.nFileRcvd = 0;
xfer.nDeltaRcvd = 0;
xfer.nDanglingFile = 0;
db_multi_exec("DROP TABLE onremote; DROP TABLE unk;");
|
| ︙ | ︙ | |||
2852 2853 2854 2855 2856 2857 2858 |
fossil_warning("*** time skew *** server is slow by %s",
db_timespan_name(-rSkew));
g.clockSkewSeen = 1;
}
fossil_force_newline();
if( g.zHttpCmd==0 ){
| > | | > > > > > > > > | > | 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 |
fossil_warning("*** time skew *** server is slow by %s",
db_timespan_name(-rSkew));
g.clockSkewSeen = 1;
}
fossil_force_newline();
if( g.zHttpCmd==0 ){
if( syncFlags & SYNC_VERBOSE ){
fossil_print(
"%s done, wire bytes sent: %lld received: %lld remote: %s%s\n",
zOpType, nSent, nRcvd,
(g.url.name && g.url.name[0]!='\0') ? g.url.name : "",
(g.zIpAddr && g.zIpAddr[0]!='\0'
&& fossil_strcmp(g.zIpAddr, g.url.name))
? mprintf(" (%s)", g.zIpAddr) : "");
}else{
fossil_print(
"%s done, wire bytes sent: %lld received: %lld remote: %s\n",
zOpType, nSent, nRcvd, g.zIpAddr);
}
}
if( syncFlags & SYNC_VERBOSE ){
fossil_print(
"Uncompressed payload sent: %lld received: %lld\n", nUncSent, nUncRcvd);
}
transport_close(&g.url);
transport_global_shutdown(&g.url);
|
| ︙ | ︙ |
Changes to src/xfersetup.c.
| ︙ | ︙ | |||
59 60 61 62 63 64 65 |
}else{
syncFlags = SYNC_PUSH | SYNC_PULL;
zButton = "Synchronize";
zWarning = mprintf("WARNING: Pushing to \"%s\" is enabled.",
g.url.canonical);
}
@ <p>Press the <strong>%h(zButton)</strong> button below to
| | | | 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 |
}else{
syncFlags = SYNC_PUSH | SYNC_PULL;
zButton = "Synchronize";
zWarning = mprintf("WARNING: Pushing to \"%s\" is enabled.",
g.url.canonical);
}
@ <p>Press the <strong>%h(zButton)</strong> button below to
@ synchronize with the <em>%h(g.url.canonical)</em> repository now.<br>
@ This may be useful when testing the various transfer scripts.</p>
@ <p>You can use the <code>http -async</code> command in your scripts, but
@ make sure the <code>th1-uri-regexp</code> setting is set first.</p>
if( zWarning ){
@
@ <big><b>%h(zWarning)</b></big>
free(zWarning);
}
@
@ <form method="post" action="%R/%s(g.zPath)"><div>
login_insert_csrf_secret();
@ <input type="submit" name="sync" value="%h(zButton)">
@ </div></form>
@
if( P("sync") ){
user_select();
url_enable_proxy(0);
@ <pre class="xfersetup">
client_sync(syncFlags, 0, 0, 0);
|
| ︙ | ︙ | |||
116 117 118 119 120 121 122 |
isSubmit = P("submit")!=0;
z = P("x");
if( z==0 ){
z = db_get(zDbField, zDfltValue);
}
style_set_current_feature("xfersetup");
style_header("Edit %s", zTitle);
| | < | < | | | | | 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 |
isSubmit = P("submit")!=0;
z = P("x");
if( z==0 ){
z = db_get(zDbField, zDfltValue);
}
style_set_current_feature("xfersetup");
style_header("Edit %s", zTitle);
if( P("clear")!=0 && cgi_csrf_safe(2) ){
db_unset(zDbField/*works-like:"x"*/, 0);
if( xRebuild ) xRebuild();
z = zDfltValue;
}else if( isSubmit && cgi_csrf_safe(2) ){
char *zErr = 0;
if( xText && (zErr = xText(z))!=0 ){
@ <p class="xfersetupError">ERROR: %h(zErr)</p>
}else{
db_set(zDbField/*works-like:"x"*/, z, 0);
if( xRebuild ) xRebuild();
cgi_redirect("xfersetup");
}
}
@ <form action="%R/%s(g.zPath)" method="post"><div>
login_insert_csrf_secret();
@ <p>%s(zDesc)</p>
@ <textarea name="x" rows="%d(height)" cols="80">%h(z)</textarea>
@ <p>
@ <input type="submit" name="submit" value="Apply Changes">
@ <input type="submit" name="clear" value="Revert To Default">
@ <input type="submit" name="setup" value="Cancel">
@ </p>
@ </div></form>
if ( zDfltValue ){
@ <hr>
@ <h2>Default %s(zTitle)</h2>
@ <blockquote><pre>
@ %h(zDfltValue)
@ </pre></blockquote>
}
style_finish_page();
}
|
| ︙ | ︙ |
Changes to src/zip.c.
| ︙ | ︙ | |||
64 65 66 67 68 69 70 |
sqlite3_vfs vfs; /* VFS object */
};
/*
** Ensure that blob pBlob is at least nMin bytes in size.
*/
static void zip_blob_minsize(Blob *pBlob, int nMin){
| | | 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
sqlite3_vfs vfs; /* VFS object */
};
/*
** Ensure that blob pBlob is at least nMin bytes in size.
*/
static void zip_blob_minsize(Blob *pBlob, int nMin){
if( (int)blob_size(pBlob)<nMin ){
blob_resize(pBlob, nMin);
}
}
/*************************************************************************
** Implementation of "archive" VFS. A VFS designed to store the contents
** of a new database in a Blob. Used to construct sqlar archives in
|
| ︙ | ︙ | |||
439 440 441 442 443 444 445 |
if( mPerm==PERM_LNK ){
sqlite3_bind_int(p->pInsert, 2, 0120755);
sqlite3_bind_int(p->pInsert, 4, -1);
sqlite3_bind_text(p->pInsert, 5,
blob_buffer(pFile), blob_size(pFile), SQLITE_STATIC
);
}else{
| | | | 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 |
if( mPerm==PERM_LNK ){
sqlite3_bind_int(p->pInsert, 2, 0120755);
sqlite3_bind_int(p->pInsert, 4, -1);
sqlite3_bind_text(p->pInsert, 5,
blob_buffer(pFile), blob_size(pFile), SQLITE_STATIC
);
}else{
unsigned int nIn = blob_size(pFile);
unsigned long int nOut = nIn;
sqlite3_bind_int(p->pInsert, 2, mPerm==PERM_EXE ? 0100755 : 0100644);
sqlite3_bind_int(p->pInsert, 4, nIn);
zip_blob_minsize(&p->tmp, nIn);
compress( (unsigned char*)
blob_buffer(&p->tmp), &nOut, (unsigned char*)blob_buffer(pFile), nIn
);
if( nOut>=(unsigned long)nIn ){
sqlite3_bind_blob(p->pInsert, 5,
blob_buffer(pFile), blob_size(pFile), SQLITE_STATIC
);
}else{
sqlite3_bind_blob(p->pInsert, 5,
blob_buffer(&p->tmp), nOut, SQLITE_STATIC
);
|
| ︙ | ︙ | |||
612 613 614 615 616 617 618 | ** in which case it is ignored. The intention is to create a zip which ** politely expands into a subdir instead of filling your current dir ** with source files. For example, pass a commit hash or "ProjectName". ** */ static void zip_of_checkin( int eType, /* Type of archive (ZIP or SQLAR) */ | | | 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 |
** in which case it is ignored. The intention is to create a zip which
** politely expands into a subdir instead of filling your current dir
** with source files. For example, pass a commit hash or "ProjectName".
**
*/
static void zip_of_checkin(
int eType, /* Type of archive (ZIP or SQLAR) */
int rid, /* The RID of the check-in to build the archive from */
Blob *pZip, /* Write the archive content into this blob */
const char *zDir, /* Top-level directory of the archive */
Glob *pInclude, /* Only include files that match this pattern */
Glob *pExclude, /* Exclude files that match this pattern */
int listFlag /* Print each file on stdout */
){
Blob mfile, hash, file;
|
| ︙ | ︙ | |||
862 863 864 865 866 867 868 | archive_cmd(ARCHIVE_SQLAR); } /* ** WEBPAGE: sqlar ** WEBPAGE: zip ** | > > > > > | | > < < > | | | | | | | | > > > | | > | | | | > | | 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 | archive_cmd(ARCHIVE_SQLAR); } /* ** WEBPAGE: sqlar ** WEBPAGE: zip ** ** URLs: ** ** /zip/[VERSION/]NAME.zip ** /sqlar/[VERSION/]NAME.sqlar ** ** Generate a ZIP Archive or an SQL Archive for the check-in specified by ** VERSION. The archive is called NAME.zip or NAME.sqlar and has a top-level ** directory called NAME. ** ** The optional VERSION element defaults to "trunk" per the r= rules below. ** All of the following URLs are equivalent: ** ** /zip/release/xyz.zip ** /zip?r=release&name=xyz.zip ** /zip/xyz.zip?r=release ** /zip?name=release/xyz.zip ** ** Query parameters: ** ** name=[CKIN/]NAME The optional CKIN component of the name= parameter ** identifies the check-in from which the archive is ** constructed. If CKIN is omitted and there is no ** r= query parameter, then use "trunk". NAME is the ** name of the download file. The top-level directory ** in the generated archive is called by NAME with the ** file extension removed. ** ** r=TAG TAG identifies the check-in that is turned into an ** SQL or ZIP archive. The default value is "trunk". ** If r= is omitted and if the name= query parameter ** contains one "/" character then the of part the ** name= value before the / becomes the TAG and the ** part of the name= value after the / is the download ** filename. If no check-in is specified by either ** name= or r=, then "trunk" is used. ** ** in=PATTERN Only include files that match the comma-separate ** list of GLOB patterns in PATTERN, as with ex= ** ** ex=PATTERN Omit any file that match PATTERN. PATTERN is a ** comma-separated list of GLOB patterns, where each ** pattern can optionally be quoted using ".." or '..'. |
| ︙ | ︙ | |||
979 980 981 982 983 984 985 |
if( zExclude ) blob_appendf(&cacheKey, ",ex=%Q", zExclude);
zKey = blob_str(&cacheKey);
etag_check(ETAG_HASH, zKey);
style_set_current_feature("zip");
if( P("debug")!=0 ){
style_header("%s Archive Generator Debug Screen", zType);
| | | | | | > | 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 |
if( zExclude ) blob_appendf(&cacheKey, ",ex=%Q", zExclude);
zKey = blob_str(&cacheKey);
etag_check(ETAG_HASH, zKey);
style_set_current_feature("zip");
if( P("debug")!=0 ){
style_header("%s Archive Generator Debug Screen", zType);
@ zName = "%h(zName)"<br>
@ rid = %d(rid)<br>
if( zInclude ){
@ zInclude = "%h(zInclude)"<br>
}
if( zExclude ){
@ zExclude = "%h(zExclude)"<br>
}
@ zKey = "%h(zKey)"
style_finish_page();
return;
}
if( referred_from_login() ){
style_header("%s Archive Download", zType);
@ <form action='%R/%s(g.zPath)/%h(zName).%s(g.zPath)'>
cgi_query_parameters_to_hidden();
@ <p>%s(zType) Archive named <b>%h(zName).%s(g.zPath)</b>
@ holding the content of check-in <b>%h(zRid)</b>:
@ <input type="submit" value="Download">
@ </form>
style_finish_page();
return;
}
cgi_check_for_malice();
blob_zero(&zip);
if( cache_read(&zip, zKey)==0 ){
zip_of_checkin(eType, rid, &zip, zName, pInclude, pExclude, 0);
cache_write(&zip, zKey);
}
glob_free(pInclude);
glob_free(pExclude);
|
| ︙ | ︙ |
Changes to test/amend.test.
| ︙ | ︙ | |||
304 305 306 307 308 309 310 |
set t5exp "*"
foreach tag $tagt {
lappend tags -tag $tag
lappend cancels -cancel $tag
}
foreach res $result {
append t1exp ", $res"
| < > > > | 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 |
set t5exp "*"
foreach tag $tagt {
lappend tags -tag $tag
lappend cancels -cancel $tag
}
foreach res $result {
append t1exp ", $res"
append t3exp "Add*tag*\"$res\".*"
append t5exp "Cancel*tag*\"$res\".*"
}
foreach res [lsort -nocase $result] {
append t2exp "sym-$res*"
}
eval fossil amend $HASH $tags
test amend-tag-$tc.1 {[string match "*hash:*$HASH*tags:*$t1exp*" $RESULT]}
fossil tag ls --raw $HASH
test amend-tag-$tc.2 {[string match $t2exp $RESULT]}
fossil timeline -n 1
test amend-tag-$tc.3 {[string match $t3exp $RESULT]}
|
| ︙ | ︙ |
Changes to test/commit-warning.test.
| ︙ | ︙ | |||
170 171 172 173 174 175 176 |
# of source files that MUST NEVER BE TEXT.
#
test_block_in_checkout pre-commit-warnings-fossil-1 {
fossil test-commit-warning --no-settings
} {
test pre-commit-warnings-fossil-1 {[normalize_result] eq \
[subst -nocommands -novariables [string trim {
| < < < < < < < < < < < < | 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 |
# of source files that MUST NEVER BE TEXT.
#
test_block_in_checkout pre-commit-warnings-fossil-1 {
fossil test-commit-warning --no-settings
} {
test pre-commit-warnings-fossil-1 {[normalize_result] eq \
[subst -nocommands -novariables [string trim {
1\tcompat/zlib/contrib/blast/test.pk\tbinary data
1\tcompat/zlib/contrib/dotzlib/DotZLib.build\tCR/LF line endings
1\tcompat/zlib/contrib/dotzlib/DotZLib.chm\tbinary data
1\tcompat/zlib/contrib/dotzlib/DotZLib.sln\tCR/LF line endings
1\tcompat/zlib/contrib/dotzlib/DotZLib/AssemblyInfo.cs\tCR/LF line endings
1\tcompat/zlib/contrib/dotzlib/DotZLib/ChecksumImpl.cs\tinvalid UTF-8
1\tcompat/zlib/contrib/dotzlib/DotZLib/CircularBuffer.cs\tinvalid UTF-8
1\tcompat/zlib/contrib/dotzlib/DotZLib/CodecBase.cs\tinvalid UTF-8
1\tcompat/zlib/contrib/dotzlib/DotZLib/Deflater.cs\tinvalid UTF-8
1\tcompat/zlib/contrib/dotzlib/DotZLib/DotZLib.cs\tinvalid UTF-8
1\tcompat/zlib/contrib/dotzlib/DotZLib/DotZLib.csproj\tCR/LF line endings
1\tcompat/zlib/contrib/dotzlib/DotZLib/GZipStream.cs\tinvalid UTF-8
1\tcompat/zlib/contrib/dotzlib/DotZLib/Inflater.cs\tinvalid UTF-8
1\tcompat/zlib/contrib/dotzlib/DotZLib/UnitTests.cs\tCR/LF line endings
1\tcompat/zlib/contrib/dotzlib/LICENSE_1_0.txt\tCR/LF line endings
1\tcompat/zlib/contrib/dotzlib/readme.txt\tCR/LF line endings
1\tcompat/zlib/contrib/gcc_gvmat64/gvmat64.S\tCR/LF line endings
1\tcompat/zlib/contrib/puff/zeros.raw\tbinary data
1\tcompat/zlib/contrib/testzlib/testzlib.c\tCR/LF line endings
1\tcompat/zlib/contrib/testzlib/testzlib.txt\tCR/LF line endings
1\tcompat/zlib/contrib/vstudio/readme.txt\tCR/LF line endings
1\tcompat/zlib/contrib/vstudio/vc10/miniunz.vcxproj\tCR/LF line endings
1\tcompat/zlib/contrib/vstudio/vc10/miniunz.vcxproj.filters\tCR/LF line endings
1\tcompat/zlib/contrib/vstudio/vc10/minizip.vcxproj\tCR/LF line endings
|
| ︙ | ︙ | |||
241 242 243 244 245 246 247 248 249 250 251 252 253 254 | 1\tcompat/zlib/contrib/vstudio/vc9/zlibstat.vcproj\tCR/LF line endings 1\tcompat/zlib/contrib/vstudio/vc9/zlibvc.def\tCR/LF line endings 1\tcompat/zlib/contrib/vstudio/vc9/zlibvc.sln\tCR/LF line endings 1\tcompat/zlib/contrib/vstudio/vc9/zlibvc.vcproj\tCR/LF line endings 1\tcompat/zlib/win32/zlib.def\tCR/LF line endings 1\tcompat/zlib/zlib.3.pdf\tbinary data 1\tcompat/zlib/zlib.map\tCR/LF line endings 1\tskins/blitz/arrow_project.png\tbinary data 1\tskins/blitz/dir.png\tbinary data 1\tskins/blitz/file.png\tbinary data 1\tskins/blitz/fossil_100.png\tbinary data 1\tskins/blitz/fossil_80_reversed_darkcyan.png\tbinary data 1\tskins/blitz/fossil_80_reversed_darkcyan_text.png\tbinary data 1\tskins/blitz/rss_20.png\tbinary data | > < | 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 | 1\tcompat/zlib/contrib/vstudio/vc9/zlibstat.vcproj\tCR/LF line endings 1\tcompat/zlib/contrib/vstudio/vc9/zlibvc.def\tCR/LF line endings 1\tcompat/zlib/contrib/vstudio/vc9/zlibvc.sln\tCR/LF line endings 1\tcompat/zlib/contrib/vstudio/vc9/zlibvc.vcproj\tCR/LF line endings 1\tcompat/zlib/win32/zlib.def\tCR/LF line endings 1\tcompat/zlib/zlib.3.pdf\tbinary data 1\tcompat/zlib/zlib.map\tCR/LF line endings 1\textsrc/pikchr.wasm\tbinary data 1\tskins/blitz/arrow_project.png\tbinary data 1\tskins/blitz/dir.png\tbinary data 1\tskins/blitz/file.png\tbinary data 1\tskins/blitz/fossil_100.png\tbinary data 1\tskins/blitz/fossil_80_reversed_darkcyan.png\tbinary data 1\tskins/blitz/fossil_80_reversed_darkcyan_text.png\tbinary data 1\tskins/blitz/rss_20.png\tbinary data 1\tsrc/alerts/bflat2.wav\tbinary data 1\tsrc/alerts/bflat3.wav\tbinary data 1\tsrc/alerts/bloop.wav\tbinary data 1\tsrc/alerts/plunk.wav\tbinary data 1\tsrc/sounds/0.wav\tbinary data 1\tsrc/sounds/1.wav\tbinary data 1\tsrc/sounds/2.wav\tbinary data |
| ︙ | ︙ |
Changes to test/delta1.test.
| ︙ | ︙ | |||
23 24 25 26 27 28 29 | # Use test script files as the basis for this test. # # For each test, copy the file intact to "./t1". Make # some random changes in "./t2". Then call test-delta on the # two files to make sure that deltas between these two files # work properly. # | | | 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
# Use test script files as the basis for this test.
#
# For each test, copy the file intact to "./t1". Make
# some random changes in "./t2". Then call test-delta on the
# two files to make sure that deltas between these two files
# work properly.
#
set filelist [lsort [glob $testdir/*]]
foreach f $filelist {
if {[file isdir $f]} continue
set base [file root [file tail $f]]
set f1 [read_file $f]
write_file t1 $f1
for {set i 0} {$i<100} {incr i} {
write_file t2 [random_changes $f1 1 1 0 0.1]
|
| ︙ | ︙ |
Changes to test/diff.test.
| ︙ | ︙ | |||
106 107 108 109 110 111 112 113 114 115 116 |
fossil diff file5.dat
test diff-file5-1 {[normalize_result] eq {Index: file5.dat
==================================================================
--- file5.dat
+++ file5.dat
cannot compute difference between binary files}}
###############################################################################
test_cleanup
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 |
fossil diff file5.dat
test diff-file5-1 {[normalize_result] eq {Index: file5.dat
==================================================================
--- file5.dat
+++ file5.dat
cannot compute difference between binary files}}
###############################################################################
write_file file6a.dat "{\n \"abc\": {\n \"def\": false,\n \"ghi\": false\n }\n}\n"
write_file file6b.dat "{\n \"abc\": {\n \"def\": false,\n \"ghi\": false\n },\n \"jkl\": {\n \"mno\": {\n \"pqr\": false\n }\n }\n}\n"
fossil xdiff -y -W 16 file6a.dat file6b.dat
test diff-file-6-1 {[normalize_result] eq {========== file6a.dat ===== versus ===== file6b.dat =====
1 { 1 {
2 "abc": { 2 "abc": {
3 "def": false, 3 "def": false,
4 "ghi": false 4 "ghi": false
> 5 },
> 6 "jkl": {
> 7 "mno": {
> 8 "pqr": false
> 9 }
5 } 10 }
6 } 11 }}}
###############################################################################
fossil rm file1.dat
fossil diff -v file1.dat
test diff-deleted-file-1 {[normalize_result] eq {DELETED file1.dat
Index: file1.dat
==================================================================
--- file1.dat
+++ /dev/null
@@ -1,1 +0,0 @@
-test file 1 (one line no term).}}
###############################################################################
write_file file6.dat "test file 6 (one line no term)."
fossil add file6.dat
fossil diff -v file6.dat
test diff-added-file-1 {[normalize_result] eq {ADDED file6.dat
Index: file6.dat
==================================================================
--- /dev/null
+++ file6.dat
@@ -0,0 +1,1 @@
+test file 6 (one line no term).}}
###############################################################################
test_cleanup
|
Changes to test/fake-editor.tcl.
| ︙ | ︙ | |||
47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
close $channel
return ""
}
###############################################################################
set fileName [lindex $argv 0]
if {[file exists $fileName]} {
set data [readFile $fileName]
} else {
set data ""
}
| > > > > > | 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
close $channel
return ""
}
###############################################################################
set fileName [lindex $argv 0]
if {[regexp {^CYGWIN} $::tcl_platform(os)]} {
# Under Cygwin, we get a Windows path but must access using the unix path.
set fileName [exec cygpath --unix $fileName]
}
if {[file exists $fileName]} {
set data [readFile $fileName]
} else {
set data ""
}
|
| ︙ | ︙ |
Changes to test/json.test.
| ︙ | ︙ | |||
175 176 177 178 179 180 181 182 183 184 185 186 187 188 |
proc test_json_payload {testname okfields badfields} {
test_dict_keys $testname [dict get $::JR payload] $okfields $badfields
}
#### VERSION AKA HAI
# The JSON API generally assumes we have a respository, so let it have one.
test_setup
# Stop backoffice from running during this test as it can cause hangs.
fossil settings backoffice-disable 1
# Check for basic envelope fields in the result with an error
fossil_json -expectError
| > > > > > > > > | 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 |
proc test_json_payload {testname okfields badfields} {
test_dict_keys $testname [dict get $::JR payload] $okfields $badfields
}
#### VERSION AKA HAI
# The JSON API generally assumes we have a respository, so let it have one.
# Set FOSSIL_USER to ensure consistent results in "json user list"
set _fossil_user ""
if [info exists env(FOSSIL_USER)] {
set _fossil_user $env(FOSSIL_USER)
}
set ::env(FOSSIL_USER) "JSON-TEST-USER"
test_setup
# Stop backoffice from running during this test as it can cause hangs.
fossil settings backoffice-disable 1
# Check for basic envelope fields in the result with an error
fossil_json -expectError
|
| ︙ | ︙ | |||
274 275 276 277 278 279 280 |
test_json_payload json-login-a {authToken name capabilities loginCookieName} {}
set AuthAnon [dict get $JR payload]
proc test_hascaps {testname need caps} {
foreach n [split $need {}] {
test $testname-$n {[string first $n $caps] >= 0}
}
}
| | | 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 |
test_json_payload json-login-a {authToken name capabilities loginCookieName} {}
set AuthAnon [dict get $JR payload]
proc test_hascaps {testname need caps} {
foreach n [split $need {}] {
test $testname-$n {[string first $n $caps] >= 0}
}
}
test_hascaps json-login-c "hz" [dict get $AuthAnon capabilities]
fossil user new U1 User-1 Uone
fossil user capabilities U1 s
write_file u1 {
{
"command":"login",
"payload":{
|
| ︙ | ︙ | |||
885 886 887 888 889 890 891 |
# Fossil repository db file could not be found.
fossil close
fossil_json HAI -expectError
test json-RC-4102-CLI-exit {$CODE != 0}
test_json_envelope json-RC-4102-CLI-exit {fossil timestamp command procTimeUs \
procTimeMs resultCode resultText} {payload}
test json-RC-4102 {[dict get $JR resultCode] eq "FOSSIL-4102"}
| < > > > > > > | 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 |
# Fossil repository db file could not be found.
fossil close
fossil_json HAI -expectError
test json-RC-4102-CLI-exit {$CODE != 0}
test_json_envelope json-RC-4102-CLI-exit {fossil timestamp command procTimeUs \
procTimeMs resultCode resultText} {payload}
test json-RC-4102 {[dict get $JR resultCode] eq "FOSSIL-4102"}
# FOSSIL-4103 FSL_JSON_E_DB_NOT_VALID
# Fossil repository db file is not valid.
write_file nope.fossil {
This is not a fossil repo. It ought to be a SQLite db with a well-known schema,
but it is actually just a block of text.
}
fossil_json HAI -R nope.fossil -expectError
test json-RC-4103-CLI-exit {$CODE != 0}
if { $JR ne "" } {
test_json_envelope json-RC-4103-CLI {fossil timestamp command procTimeUs \
procTimeMs resultCode resultText} {payload}
test json-RC-4103 {[dict get $JR resultCode] eq "FOSSIL-4103"}
} else {
test json-RC-4103 0 knownBug
}
###############################################################################
test_cleanup
if { $_fossil_user eq "" } {
unset ::env(FOSSIL_USER)
} else {
set ::env(FOSSIL_USER) $_fossil_user
}
|
Changes to test/markdown-test3.md.
| ︙ | ︙ | |||
188 189 190 191 192 193 194 | ) ) ## Footnotes [branch]: /timeline?r=markdown-footnotes&nowiki | | | 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 |
)
)
## Footnotes
[branch]: /timeline?r=markdown-footnotes&nowiki
[^ 1]: Footnotes is a Fossil extension of
Markdown. Your other tools may have limited support for these.
[^here]: [History of test/markdown-test3.md](/finfo/test/markdown-test3.md)
[src]: /file/test/markdown-test3.md?ci=markdown-footnotes&txt&ln
[^if glitch occurs]:
|
| ︙ | ︙ | |||
250 251 252 253 254 255 256 |
no special processing occured.
[^ <script>alert("You have been pwned!");</script> ]: Labels are escaped
[^ <textarea>"Last words here...' ]:
<textarea>Content is also escaped</textarea>
| < | 250 251 252 253 254 255 256 |
no special processing occured.
[^ <script>alert("You have been pwned!");</script> ]: Labels are escaped
[^ <textarea>"Last words here...' ]:
<textarea>Content is also escaped</textarea>
|
Changes to test/merge1.test.
| ︙ | ︙ | |||
71 72 73 74 75 76 77 |
111 - This is line one OF the demo program - 1111
222 - The second line program line in code - 2222
333 - This is a test of the merging algohm - 3333
444 - If all goes well, we will be pleased - 4444
555 - we think it well and other stuff too - 5555
}
write_file_indented t23 {
| | | | | | | | | | | | 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 |
111 - This is line one OF the demo program - 1111
222 - The second line program line in code - 2222
333 - This is a test of the merging algohm - 3333
444 - If all goes well, we will be pleased - 4444
555 - we think it well and other stuff too - 5555
}
write_file_indented t23 {
<<<<<<< BEGIN MERGE CONFLICT: local copy shown first <<<<<<<<<<<< (line 1)
111 - This is line ONE of the demo program - 1111
||||||| COMMON ANCESTOR content follows ||||||||||||||||||||||||| (line 1)
111 - This is line one of the demo program - 1111
======= MERGED IN content follows =============================== (line 1)
111 - This is line one OF the demo program - 1111
>>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
222 - The second line program line in code - 2222
333 - This is a test of the merging algohm - 3333
444 - If all goes well, we will be pleased - 4444
555 - we think it well and other stuff too - 5555
}
write_file_indented t32 {
<<<<<<< BEGIN MERGE CONFLICT: local copy shown first <<<<<<<<<<<< (line 1)
111 - This is line one OF the demo program - 1111
||||||| COMMON ANCESTOR content follows ||||||||||||||||||||||||| (line 1)
111 - This is line one of the demo program - 1111
======= MERGED IN content follows =============================== (line 1)
111 - This is line ONE of the demo program - 1111
>>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
222 - The second line program line in code - 2222
333 - This is a test of the merging algohm - 3333
444 - If all goes well, we will be pleased - 4444
555 - we think it well and other stuff too - 5555
}
fossil 3-way-merge t1 t3 t2 a32 -expectError
test merge1-2.1 {[same_file t32 a32]}
fossil 3-way-merge t1 t2 t3 a23 -expectError
test merge1-2.2 {[same_file t23 a23]}
write_file_indented t1 {
111 - This is line one of the demo program - 1111
222 - The second line program line in code - 2222
333 - This is a test of the merging algohm - 3333
444 - If all goes well, we will be pleased - 4444
|
| ︙ | ︙ | |||
156 157 158 159 160 161 162 |
write_file_indented t3 {
222 - The second line program line in code - 2222
333 - This is a test of the merging algohm - 3333
444 - If all goes well, we will be pleased - 4444
555 - we think it well and other stuff too - 5555
}
write_file_indented t32 {
| | | | | | | | | | | | 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 |
write_file_indented t3 {
222 - The second line program line in code - 2222
333 - This is a test of the merging algohm - 3333
444 - If all goes well, we will be pleased - 4444
555 - we think it well and other stuff too - 5555
}
write_file_indented t32 {
<<<<<<< BEGIN MERGE CONFLICT: local copy shown first <<<<<<<<<<<< (line 1)
||||||| COMMON ANCESTOR content follows ||||||||||||||||||||||||| (line 1)
111 - This is line one of the demo program - 1111
======= MERGED IN content follows =============================== (line 1)
000 - Zero lines added to the beginning of - 0000
111 - This is line one of the demo program - 1111
>>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
222 - The second line program line in code - 2222
333 - This is a test of the merging algohm - 3333
444 - If all goes well, we will be pleased - 4444
555 - we think it well and other stuff too - 5555
}
write_file_indented t23 {
<<<<<<< BEGIN MERGE CONFLICT: local copy shown first <<<<<<<<<<<< (line 1)
000 - Zero lines added to the beginning of - 0000
111 - This is line one of the demo program - 1111
||||||| COMMON ANCESTOR content follows ||||||||||||||||||||||||| (line 1)
111 - This is line one of the demo program - 1111
======= MERGED IN content follows =============================== (line 1)
>>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
222 - The second line program line in code - 2222
333 - This is a test of the merging algohm - 3333
444 - If all goes well, we will be pleased - 4444
555 - we think it well and other stuff too - 5555
}
fossil 3-way-merge t1 t3 t2 a32 -expectError
test merge1-4.1 {[same_file t32 a32]}
fossil 3-way-merge t1 t2 t3 a23 -expectError
test merge1-4.2 {[same_file t23 a23]}
write_file_indented t1 {
111 - This is line one of the demo program - 1111
222 - The second line program line in code - 2222
333 - This is a test of the merging algohm - 3333
444 - If all goes well, we will be pleased - 4444
|
| ︙ | ︙ | |||
295 296 297 298 299 300 301 |
KLMN
OPQR
STUV
XYZ.
}
write_file_indented t23 {
abcd
| | | | | | | 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 |
KLMN
OPQR
STUV
XYZ.
}
write_file_indented t23 {
abcd
<<<<<<< BEGIN MERGE CONFLICT: local copy shown first <<<<<<<<<<<< (line 2)
efgh 2
ijkl 2
mnop 2
qrst
uvwx
yzAB 2
CDEF 2
GHIJ 2
||||||| COMMON ANCESTOR content follows ||||||||||||||||||||||||| (line 2)
efgh
ijkl
mnop
qrst
uvwx
yzAB
CDEF
GHIJ
======= MERGED IN content follows =============================== (line 2)
efgh
ijkl
mnop 3
qrst 3
uvwx 3
yzAB 3
CDEF
GHIJ
>>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
KLMN
OPQR
STUV
XYZ.
}
fossil 3-way-merge t1 t2 t3 a23 -expectError
test merge1-7.1 {[same_file t23 a23]}
write_file_indented t2 {
abcd
efgh 2
ijkl 2
mnop
|
| ︙ | ︙ | |||
363 364 365 366 367 368 369 |
KLMN
OPQR
STUV
XYZ.
}
write_file_indented t23 {
abcd
| | | | | | | 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 |
KLMN
OPQR
STUV
XYZ.
}
write_file_indented t23 {
abcd
<<<<<<< BEGIN MERGE CONFLICT: local copy shown first <<<<<<<<<<<< (line 2)
efgh 2
ijkl 2
mnop
qrst
uvwx
yzAB 2
CDEF 2
GHIJ 2
||||||| COMMON ANCESTOR content follows ||||||||||||||||||||||||| (line 2)
efgh
ijkl
mnop
qrst
uvwx
yzAB
CDEF
GHIJ
======= MERGED IN content follows =============================== (line 2)
efgh
ijkl
mnop 3
qrst 3
uvwx 3
yzAB 3
CDEF
GHIJ
>>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
KLMN
OPQR
STUV
XYZ.
}
fossil 3-way-merge t1 t2 t3 a23 -expectError
test merge1-7.2 {[same_file t23 a23]}
###############################################################################
test_cleanup
|
Changes to test/merge2.test.
| ︙ | ︙ | |||
16 17 18 19 20 21 22 | ############################################################################ # # Tests of the delta mechanism. # test_setup "" | | | 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
############################################################################
#
# Tests of the delta mechanism.
#
test_setup ""
set filelist [lsort [glob $testdir/*]]
foreach f $filelist {
if {[file isdir $f]} continue
set base [file root [file tail $f]]
if {[string match "utf16*" $base]} continue
set f1 [read_file $f]
write_file t1 $f1
for {set i 0} {$i<100} {incr i} {
|
| ︙ | ︙ |
Changes to test/merge3.test.
| ︙ | ︙ | |||
16 17 18 19 20 21 22 | ############################################################################ # # Tests of the 3-way merge # test_setup "" | | | > | | > | > > | > > | > | 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 |
############################################################################
#
# Tests of the 3-way merge
#
test_setup ""
proc merge-test {testid basis v1 v2 result {fossil_args ""}} {
write_file t1 [join [string trim $basis] \n]\n
write_file t2 [join [string trim $v1] \n]\n
write_file t3 [join [string trim $v2] \n]\n
fossil 3-way-merge t1 t2 t3 t4 {*}$fossil_args
set x [read_file t4]
regsub -all \
{<<<<<<< BEGIN MERGE CONFLICT: local copy shown first <+ \(line \d+\)} \
$x {MINE:} x
regsub -all \
{\|\|\|\|\|\|\| COMMON ANCESTOR content follows \|+ \(line \d+\)} \
$x {COM:} x
regsub -all \
{======= MERGED IN content follows =+ \(line \d+\)} \
$x {YOURS:} x
regsub -all \
{>>>>>>> END MERGE CONFLICT >+} \
$x {END} x
set x [split [string trim $x] \n]
set result [string trim $result]
if {$x!=$result} {
protOut " Expected \[$result\]"
protOut " Got \[$x\]"
test merge3-$testid 0
} else {
|
| ︙ | ︙ | |||
65 66 67 68 69 70 71 |
1 2 3 4 5 6 7 8 9
} {
1 2 3b 4b 5b 6 7 8 9
} {
1 2 3 4 5c 6 7 8 9
} {
1 2 MINE: 3b 4b 5b COM: 3 4 5 YOURS: 3 4 5c END 6 7 8 9
| | | | | | | | 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 |
1 2 3 4 5 6 7 8 9
} {
1 2 3b 4b 5b 6 7 8 9
} {
1 2 3 4 5c 6 7 8 9
} {
1 2 MINE: 3b 4b 5b COM: 3 4 5 YOURS: 3 4 5c END 6 7 8 9
} -expectError
merge-test 4 {
1 2 3 4 5 6 7 8 9
} {
1 2 3b 4b 5b 6b 7 8 9
} {
1 2 3 4 5c 6 7 8 9
} {
1 2 MINE: 3b 4b 5b 6b COM: 3 4 5 6 YOURS: 3 4 5c 6 END 7 8 9
} -expectError
merge-test 5 {
1 2 3 4 5 6 7 8 9
} {
1 2 3b 4b 5b 6b 7 8 9
} {
1 2 3 4 5c 6c 7c 8 9
} {
1 2 MINE: 3b 4b 5b 6b 7 COM: 3 4 5 6 7 YOURS: 3 4 5c 6c 7c END 8 9
} -expectError
merge-test 6 {
1 2 3 4 5 6 7 8 9
} {
1 2 3b 4b 5b 6b 7 8b 9
} {
1 2 3 4 5c 6c 7c 8 9
} {
1 2 MINE: 3b 4b 5b 6b 7 COM: 3 4 5 6 7 YOURS: 3 4 5c 6c 7c END 8b 9
} -expectError
merge-test 7 {
1 2 3 4 5 6 7 8 9
} {
1 2 3b 4b 5b 6b 7 8b 9
} {
1 2 3 4 5c 6c 7c 8c 9
} {
1 2 MINE: 3b 4b 5b 6b 7 8b COM: 3 4 5 6 7 8 YOURS: 3 4 5c 6c 7c 8c END 9
} -expectError
merge-test 8 {
1 2 3 4 5 6 7 8 9
} {
1 2 3b 4b 5b 6b 7 8b 9b
} {
1 2 3 4 5c 6c 7c 8c 9
} {
1 2 MINE: 3b 4b 5b 6b 7 8b 9b COM: 3 4 5 6 7 8 9 YOURS: 3 4 5c 6c 7c 8c 9 END
} -expectError
merge-test 9 {
1 2 3 4 5 6 7 8 9
} {
1 2 3b 4b 5 6 7 8b 9b
} {
1 2 3 4 5c 6c 7c 8 9
} {
|
| ︙ | ︙ | |||
138 139 140 141 142 143 144 |
1 2 3 4 5 6 7 8 9
} {
1 2 3b 4b 5 6 7 8b 9b
} {
1 2 3b 4c 5 6c 7c 8 9
} {
1 2 MINE: 3b 4b COM: 3 4 YOURS: 3b 4c END 5 6c 7c 8b 9b
| | | 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 |
1 2 3 4 5 6 7 8 9
} {
1 2 3b 4b 5 6 7 8b 9b
} {
1 2 3b 4c 5 6c 7c 8 9
} {
1 2 MINE: 3b 4b COM: 3 4 YOURS: 3b 4c END 5 6c 7c 8b 9b
} -expectError
merge-test 12 {
1 2 3 4 5 6 7 8 9
} {
1 2 3b4b 5 6 7 8b 9b
} {
1 2 3b4b 5 6c 7c 8 9
} {
|
| ︙ | ︙ | |||
193 194 195 196 197 198 199 |
1 2 3 4 5 6 7 8 9
} {
1 6 7 8 9
} {
1 2 3 4 9
} {
1 MINE: 6 7 8 COM: 2 3 4 5 6 7 8 YOURS: 2 3 4 END 9
| | | | 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 |
1 2 3 4 5 6 7 8 9
} {
1 6 7 8 9
} {
1 2 3 4 9
} {
1 MINE: 6 7 8 COM: 2 3 4 5 6 7 8 YOURS: 2 3 4 END 9
} -expectError
merge-test 25 {
1 2 3 4 5 6 7 8 9
} {
1 7 8 9
} {
1 2 3 9
} {
1 MINE: 7 8 COM: 2 3 4 5 6 7 8 YOURS: 2 3 END 9
} -expectError
merge-test 30 {
1 2 3 4 5 6 7 8 9
} {
1 2 3 4 5 6 7 9
} {
1 3 4 5 6 7 8 9
|
| ︙ | ︙ | |||
248 249 250 251 252 253 254 |
1 2 3 4 5 6 7 8 9
} {
1 2 3 4 9
} {
1 6 7 8 9
} {
1 MINE: 2 3 4 COM: 2 3 4 5 6 7 8 YOURS: 6 7 8 END 9
| | | | 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 |
1 2 3 4 5 6 7 8 9
} {
1 2 3 4 9
} {
1 6 7 8 9
} {
1 MINE: 2 3 4 COM: 2 3 4 5 6 7 8 YOURS: 6 7 8 END 9
} -expectError
merge-test 35 {
1 2 3 4 5 6 7 8 9
} {
1 2 3 9
} {
1 7 8 9
} {
1 MINE: 2 3 COM: 2 3 4 5 6 7 8 YOURS: 7 8 END 9
} -expectError
merge-test 40 {
2 3 4 5 6 7 8
} {
3 4 5 6 7 8
} {
2 3 4 5 6 7
|
| ︙ | ︙ | |||
303 304 305 306 307 308 309 |
2 3 4 5 6 7 8
} {
6 7 8
} {
2 3 4
} {
MINE: 6 7 8 COM: 2 3 4 5 6 7 8 YOURS: 2 3 4 END
| | | | 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 |
2 3 4 5 6 7 8
} {
6 7 8
} {
2 3 4
} {
MINE: 6 7 8 COM: 2 3 4 5 6 7 8 YOURS: 2 3 4 END
} -expectError
merge-test 45 {
2 3 4 5 6 7 8
} {
7 8
} {
2 3
} {
MINE: 7 8 COM: 2 3 4 5 6 7 8 YOURS: 2 3 END
} -expectError
merge-test 50 {
2 3 4 5 6 7 8
} {
2 3 4 5 6 7
} {
3 4 5 6 7 8
|
| ︙ | ︙ | |||
357 358 359 360 361 362 363 |
2 3 4 5 6 7 8
} {
2 3 4
} {
6 7 8
} {
MINE: 2 3 4 COM: 2 3 4 5 6 7 8 YOURS: 6 7 8 END
| | | | 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 |
2 3 4 5 6 7 8
} {
2 3 4
} {
6 7 8
} {
MINE: 2 3 4 COM: 2 3 4 5 6 7 8 YOURS: 6 7 8 END
} -expectError
merge-test 55 {
2 3 4 5 6 7 8
} {
2 3
} {
7 8
} {
MINE: 2 3 COM: 2 3 4 5 6 7 8 YOURS: 7 8 END
} -expectError
merge-test 60 {
1 2 3 4 5 6 7 8 9
} {
1 2b 3 4 5 6 7 8 9
} {
1 2 3 4 5 6 7 9
|
| ︙ | ︙ | |||
412 413 414 415 416 417 418 |
1 2 3 4 5 6 7 8 9
} {
1 2b 3b 4b 5b 6 7 8 9
} {
1 2 3 4 9
} {
1 MINE: 2b 3b 4b 5b 6 7 8 COM: 2 3 4 5 6 7 8 YOURS: 2 3 4 END 9
| | | | 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 |
1 2 3 4 5 6 7 8 9
} {
1 2b 3b 4b 5b 6 7 8 9
} {
1 2 3 4 9
} {
1 MINE: 2b 3b 4b 5b 6 7 8 COM: 2 3 4 5 6 7 8 YOURS: 2 3 4 END 9
} -expectError
merge-test 65 {
1 2 3 4 5 6 7 8 9
} {
1 2b 3b 4b 5b 6b 7 8 9
} {
1 2 3 9
} {
1 MINE: 2b 3b 4b 5b 6b 7 8 COM: 2 3 4 5 6 7 8 YOURS: 2 3 END 9
} -expectError
merge-test 70 {
1 2 3 4 5 6 7 8 9
} {
1 2 3 4 5 6 7 9
} {
1 2b 3 4 5 6 7 8 9
|
| ︙ | ︙ | |||
467 468 469 470 471 472 473 |
1 2 3 4 5 6 7 8 9
} {
1 2 3 4 9
} {
1 2b 3b 4b 5b 6 7 8 9
} {
1 MINE: 2 3 4 COM: 2 3 4 5 6 7 8 YOURS: 2b 3b 4b 5b 6 7 8 END 9
| | | | 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 |
1 2 3 4 5 6 7 8 9
} {
1 2 3 4 9
} {
1 2b 3b 4b 5b 6 7 8 9
} {
1 MINE: 2 3 4 COM: 2 3 4 5 6 7 8 YOURS: 2b 3b 4b 5b 6 7 8 END 9
} -expectError
merge-test 75 {
1 2 3 4 5 6 7 8 9
} {
1 2 3 9
} {
1 2b 3b 4b 5b 6b 7 8 9
} {
1 MINE: 2 3 COM: 2 3 4 5 6 7 8 YOURS: 2b 3b 4b 5b 6b 7 8 END 9
} -expectError
merge-test 80 {
2 3 4 5 6 7 8
} {
2b 3 4 5 6 7 8
} {
2 3 4 5 6 7
|
| ︙ | ︙ | |||
522 523 524 525 526 527 528 |
2 3 4 5 6 7 8
} {
2b 3b 4b 5b 6 7 8
} {
2 3 4
} {
MINE: 2b 3b 4b 5b 6 7 8 COM: 2 3 4 5 6 7 8 YOURS: 2 3 4 END
| | | | 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 |
2 3 4 5 6 7 8
} {
2b 3b 4b 5b 6 7 8
} {
2 3 4
} {
MINE: 2b 3b 4b 5b 6 7 8 COM: 2 3 4 5 6 7 8 YOURS: 2 3 4 END
} -expectError
merge-test 85 {
2 3 4 5 6 7 8
} {
2b 3b 4b 5b 6b 7 8
} {
2 3
} {
MINE: 2b 3b 4b 5b 6b 7 8 COM: 2 3 4 5 6 7 8 YOURS: 2 3 END
} -expectError
merge-test 90 {
2 3 4 5 6 7 8
} {
2 3 4 5 6 7
} {
2b 3 4 5 6 7 8
|
| ︙ | ︙ | |||
577 578 579 580 581 582 583 |
2 3 4 5 6 7 8
} {
2 3 4
} {
2b 3b 4b 5b 6 7 8
} {
MINE: 2 3 4 COM: 2 3 4 5 6 7 8 YOURS: 2b 3b 4b 5b 6 7 8 END
| | | | 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 |
2 3 4 5 6 7 8
} {
2 3 4
} {
2b 3b 4b 5b 6 7 8
} {
MINE: 2 3 4 COM: 2 3 4 5 6 7 8 YOURS: 2b 3b 4b 5b 6 7 8 END
} -expectError
merge-test 95 {
2 3 4 5 6 7 8
} {
2 3
} {
2b 3b 4b 5b 6b 7 8
} {
MINE: 2 3 COM: 2 3 4 5 6 7 8 YOURS: 2b 3b 4b 5b 6b 7 8 END
} -expectError
merge-test 100 {
1 2 3 4 5 6 7 8 9
} {
1 2b 3 4 5 7 8 9 a b c d e
} {
1 2b 3 4 5 7 8 9 a b c d e
|
| ︙ | ︙ | |||
623 624 625 626 627 628 629 |
1 2 3 4 5 6 7 8 9
} {
1 2 3 4 5 7 8 9b
} {
1 2 3 4 5 7 8 9b a b c d e
} {
1 2 3 4 5 7 8 MINE: 9b COM: 9 YOURS: 9b a b c d e END
| | | | 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 |
1 2 3 4 5 6 7 8 9
} {
1 2 3 4 5 7 8 9b
} {
1 2 3 4 5 7 8 9b a b c d e
} {
1 2 3 4 5 7 8 MINE: 9b COM: 9 YOURS: 9b a b c d e END
} -expectError
merge-test 104 {
1 2 3 4 5 6 7 8 9
} {
1 2 3 4 5 7 8 9b a b c d e
} {
1 2 3 4 5 7 8 9b
} {
1 2 3 4 5 7 8 MINE: 9b a b c d e COM: 9 YOURS: 9b END
} -expectError
###############################################################################
test_cleanup
|
Changes to test/merge4.test.
| ︙ | ︙ | |||
16 17 18 19 20 21 22 | ############################################################################ # # Tests of the 3-way merge # test_setup "" | | | | | | | | | 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 |
############################################################################
#
# Tests of the 3-way merge
#
test_setup ""
proc merge-test {testid basis v1 v2 result1 result2 {fossil_args ""}} {
write_file t1 [join [string trim $basis] \n]\n
write_file t2 [join [string trim $v1] \n]\n
write_file t3 [join [string trim $v2] \n]\n
fossil 3-way-merge t1 t2 t3 t4 {*}$fossil_args
fossil 3-way-merge t1 t3 t2 t5 {*}$fossil_args
set x [read_file t4]
regsub -all {<<<<<<< BEGIN MERGE CONFLICT.*<< \(line \d+\)} $x {>} x
regsub -all {\|\|\|\|\|\|\|.*======= \(line \d+\)} $x {=} x
regsub -all {>>>>>>> END MERGE CONFLICT.*>>>>} $x {<} x
set x [split [string trim $x] \n]
set y [read_file t5]
regsub -all {<<<<<<< BEGIN MERGE CONFLICT.*<< \(line \d+\)} $y {>} y
regsub -all {\|\|\|\|\|\|\|.*======= \(line \d+\)} $y {=} y
regsub -all {>>>>>>> END MERGE CONFLICT.*>>>>} $y {<} y
set y [split [string trim $y] \n]
set result1 [string trim $result1]
if {$x!=$result1} {
protOut " Expected \[$result1\]"
protOut " Got \[$x\]"
test merge4-$testid 0
|
| ︙ | ︙ | |||
59 60 61 62 63 64 65 |
1 2b 3b 4b 5 6b 7b 8b 9
} {
1 2 3 4c 5c 6c 7 8 9
} {
1 > 2b 3b 4b 5 6b 7b 8b = 2 3 4c 5c 6c 7 8 < 9
} {
1 > 2 3 4c 5c 6c 7 8 = 2b 3b 4b 5 6b 7b 8b < 9
| | | 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
1 2b 3b 4b 5 6b 7b 8b 9
} {
1 2 3 4c 5c 6c 7 8 9
} {
1 > 2b 3b 4b 5 6b 7b 8b = 2 3 4c 5c 6c 7 8 < 9
} {
1 > 2 3 4c 5c 6c 7 8 = 2b 3b 4b 5 6b 7b 8b < 9
} -expectError
merge-test 1001 {
1 2 3 4 5 6 7 8 9
} {
1 2b 3b 4 5 6 7b 8b 9
} {
1 2 3 4c 5c 6c 7 8 9
} {
|
| ︙ | ︙ | |||
81 82 83 84 85 86 87 |
2b 3b 4b 5 6b 7b 8b
} {
2 3 4c 5c 6c 7 8
} {
> 2b 3b 4b 5 6b 7b 8b = 2 3 4c 5c 6c 7 8 <
} {
> 2 3 4c 5c 6c 7 8 = 2b 3b 4b 5 6b 7b 8b <
| | | 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
2b 3b 4b 5 6b 7b 8b
} {
2 3 4c 5c 6c 7 8
} {
> 2b 3b 4b 5 6b 7b 8b = 2 3 4c 5c 6c 7 8 <
} {
> 2 3 4c 5c 6c 7 8 = 2b 3b 4b 5 6b 7b 8b <
} -expectError
merge-test 1003 {
2 3 4 5 6 7 8
} {
2b 3b 4 5 6 7b 8b
} {
2 3 4c 5c 6c 7 8
} {
|
| ︙ | ︙ |
Changes to test/merge5.test.
| ︙ | ︙ | |||
14 15 16 17 18 19 20 | # http://www.hwaci.com/drh/ # ############################################################################ # # Tests of the "merge" command # | > | > | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
# http://www.hwaci.com/drh/
#
############################################################################
#
# Tests of the "merge" command
#
if {! $::QUIET} {
puts "Skipping Merge5 tests"
}
protOut {
fossil sqlite3 --no-repository reacts badly to SQL dumped from
repositories created from fossil older than version 2.0.
}
test merge5-sqlite3-issue false knownBug
test_cleanup_then_return
|
| ︙ | ︙ |
Changes to test/merge_renames.test.
| ︙ | ︙ | |||
260 261 262 263 264 265 266 | fossil update trunk write_file f1 "f1.2" fossil add f1 fossil commit -b b2 -m "add f1" fossil update trunk fossil merge b1 | | > | | > | | 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 |
fossil update trunk
write_file f1 "f1.2"
fossil add f1
fossil commit -b b2 -m "add f1"
fossil update trunk
fossil merge b1
fossil merge b2 -expectError
test_status_list merge_renames-8-1 $RESULT {
MERGE f1
WARNING: 1 merge conflicts
}
fossil revert
fossil merge --integrate b1
fossil merge b2 -expectError
test_status_list merge_renames-8-2 $RESULT {
MERGE f1
WARNING: 1 merge conflicts
}
#############################################
# Test 9 #
# Merging a delete/rename/add combination #
#############################################
|
| ︙ | ︙ | |||
306 307 308 309 310 311 312 | ADDED f1 } test_status_list merge_renames-9-1 $RESULT $expectedMerge fossil changes test_status_list merge_renames-9-2 $RESULT " MERGED_WITH [commit_id b] ADDED_BY_MERGE f1 | | | | | 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 |
ADDED f1
}
test_status_list merge_renames-9-1 $RESULT $expectedMerge
fossil changes
test_status_list merge_renames-9-2 $RESULT "
MERGED_WITH [commit_id b]
ADDED_BY_MERGE f1
RENAMED f1 -> f2
DELETED f2 -> f2 (overwritten by rename)
"
test_file_contents merge_renames-9-3 f1 "f1.1"
test_file_contents merge_renames-9-4 f2 "f1"
# Undo and ensure a dry run merge results in no changes
fossil undo
test_status_list merge_renames-9-5 $RESULT {
UNDO f1
UNDO f2
}
fossil merge -n b -expectError
test_status_list merge_renames-9-6 $RESULT "
$expectedMerge
REMINDER: this was a dry run - no files were actually changed.
"
test merge_renames-9-7 {[fossil changes] eq ""}
###################################################################
|
| ︙ | ︙ | |||
366 367 368 369 370 371 372 |
test_status_list merge_renames-10-4 $RESULT {
RENAME f1 -> f2
RENAME f2 -> f1
}
test_file_contents merge_renames-10-5 f1 "f1"
test_file_contents merge_renames-10-6 f2 "f2"
test_status_list merge_renames-10-7 [fossil changes] "
| | | | 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 |
test_status_list merge_renames-10-4 $RESULT {
RENAME f1 -> f2
RENAME f2 -> f1
}
test_file_contents merge_renames-10-5 f1 "f1"
test_file_contents merge_renames-10-6 f2 "f2"
test_status_list merge_renames-10-7 [fossil changes] "
RENAMED f1 -> f2
RENAMED f2 -> f1
BACKOUT [commit_id trunk]
"
fossil commit -m "swap back" ;# V
fossil merge b
test_status_list merge_renames-10-8 $RESULT {
UPDATE f1
|
| ︙ | ︙ | |||
493 494 495 496 497 498 499 | ADD f2 } fossil merge trunk fossil commit -m "merge trunk" --tag c4 fossil mv --hard f2 f2n test_status_list merge_renames-13-3 $RESULT " RENAME f2 f2n | | | 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 |
ADD f2
}
fossil merge trunk
fossil commit -m "merge trunk" --tag c4
fossil mv --hard f2 f2n
test_status_list merge_renames-13-3 $RESULT "
RENAME f2 f2n
MOVED_FILE [file normalize $repoDir]/f2
"
fossil commit -m "renamed f2->f2n" --tag c5
fossil update trunk
fossil merge b
test_status_list merge_renames-13-4 $RESULT {ADDED f2n}
fossil commit -m "merge f2n" --tag m1 --tag c6
|
| ︙ | ︙ |
Changes to test/merge_warn.test.
| ︙ | ︙ | |||
38 39 40 41 42 43 44 | write_file f4 "f4" fossil add f4 fossil commit -m "add f4" fossil update trunk write_file f1 "f1.1" write_file f3 "f3.1" | | > | | | | < | 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
write_file f4 "f4"
fossil add f4
fossil commit -m "add f4"
fossil update trunk
write_file f1 "f1.1"
write_file f3 "f3.1"
fossil merge --integrate mrg -expectError
test_status_list merge_warn-1 $RESULT {
WARNING: 1 unmanaged files were overwritten
WARNING: 2 merge conflicts
DELETE f1
MERGE f2
ADDED f3 (overwrites an unmanaged file), original copy backed up locally
WARNING: local edits lost for f1
}
test merge_warn-2 {
[string first "ignoring --integrate: mrg is not a leaf" $RESULT]>=0
}
###############################################################################
|
| ︙ | ︙ |
Changes to test/revert.test.
| ︙ | ︙ | |||
96 97 98 99 100 101 102 |
# Test with a single filename argument
#
revert-test 1-2 f0 {
UNMANAGE f0
} -changes {
DELETED f1
EDITED f2
| | | | | 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 |
# Test with a single filename argument
#
revert-test 1-2 f0 {
UNMANAGE f0
} -changes {
DELETED f1
EDITED f2
RENAMED f3 -> f3n
} -addremove {
ADDED f0
} -exists {f0 f2 f3n} -notexists f3
revert-test 1-3 f1 {
REVERT f1
} -changes {
ADDED f0
EDITED f2
RENAMED f3 -> f3n
} -exists {f0 f1 f2 f3n} -notexists f3
revert-test 1-4 f2 {
REVERT f2
} -changes {
ADDED f0
DELETED f1
RENAMED f3 -> f3n
} -exists {f0 f2 f3n} -notexists {f1 f3}
# Both files involved in a rename are reverted regardless of which filename
# is used as an argument to 'fossil revert'
#
revert-test 1-5 f3 {
REVERT f3
|
| ︙ | ︙ |
Added test/rewrite-test-output.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 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 |
#!/usr/bin/env tclsh
# Script to anonymise test results for comparison.
# - Replaces hashes, pids and similar with fixed strings
# - Rewrites temporary paths to standardise them in output
# Pick up options
set EXTRA 0
set i [lsearch $argv -extra]
while { $i >= 0 } {
incr EXTRA
set argv [lreplace $argv $i $i]
set i [lsearch $argv -extra]
}
# With no arguments or "-", use stdin.
set fname "-"
if { [llength $argv] > 0 } {
set fname [lindex $argv 0]
}
# Any -options, or an empty first argument, is an error.
if { [llength $argv] > 1 || [regexp {^-.+} $fname] } {
puts stderr "Error: argument error"
puts stderr "usage: \[-extra\] [file tail $argv0] ?FILE"
puts stderr " Rewrite test output to ease comparison of outputs."
puts stderr " With -extra, more output is rewritten as is summaries"
puts stderr " to make diff(1) mor euseful across runs and platforms."
exit 1
} elseif { $fname ne "-" && ! [file exists $fname] } {
puts stderr "File does not exist: '$fname'"
exit 1
}
proc common_rewrites { line testname } {
# Normalise the fossil commands with path as just fossil
regsub {^(?:[A-Z]:)?/.*?/fossil(?:\.exe)? } $line {fossil } line
if {[string match "Usage: *" $line]} {
regsub {^(Usage: )/.*?/fossil(?:\.exe)? } $line {\1fossil } line
regsub {^(Usage: )[A-Z]:\\.*?\\fossil(?:\.exe)? } $line {\1fossil } line
}
# Accept 40 and 64 byte hashes as such
regsub -all {[[:<:]][0-9a-f]{40}[[:>:]]} $line HASH line
regsub -all {[[:<:]][0-9a-f]{64}[[:>:]]} $line HASH line
# Date and time
regsub -all {[[:<:]]\d{4}-\d\d-\d\d \d\d:\d\d:\d\d[[:>:]]} $line {YYYY-mm-dd HH:MM:SS} line
if { [lsearch -exact {"amend" "wiki"} $testname] >= 0 } {
# With embedded T and milliseconds
regsub { \d{4}-\d\d-\d\dT\d\d:\d\d:\d\d\.\d{3}$} $line { YYYY-mm-ddTHH:MM:SS.NNN} line
}
if { [lsearch -exact {"amend" "th1-hooks" "wiki"} $testname] >= 0 } {
regsub {[[:<:]]\d{4}-\d\d-\d\d[[:>:]]} $line {YYYY-mm-dd} line
}
# Timelines have HH:MM:SS [HASH], but don't mess with the zero'ed version.
regsub {^(?!00:00:00 \[0000000000\])\d\d:\d\d:\d\d \[[0-9a-f]{10}\] } $line {HH:MM:SS [HASH] } line
# Temporary directories
regsub -all {(?:[A-Z]:)?/.*?/repo_\d+/\d+_\d+} $line {/TMP/repo_PID/SEC_SEQ} line
# Home directories only seem present with .fossil or _fossil. Simplify to .fossil.
regsub -all {(?:[A-Z]:)?/.*?/home_\d+/[._]fossil[[:>:]]} $line {/TMP/home_PID/.fossil} line
# Users in output
regsub { (\(user: )[^\)]*\)$} $line { \1USER)} line
return $line
}
#
# tests/tests_unix/tests_windows contain tuples of
#
# 1. A regular expression to match current line
# 2. A substitution for the current line
#
# Some common patterns applicable to multiples tests are appended below.
#
# The common_rewrites procedure is run first, so use e.g. HASH as needed.
#
dict set tests "amend" {
{^(fossil artifact) [0-9a-f]{10}}
{\1 HASH}
{^U [^ ]+$}
{U USER}
{^Z [0-9a-f]{32}$}
{Z CHECKSUM}
{^(ed -s \./ci-comment-).*?(\.txt)$}
{\1UNIQ\2}
{^(fossil amend HASH -date \{?)\d\d/\d\d/\d{4}}
{\1dd/mm/YYYY}
{^(fossil amend HASH -date \{.* )\d{4}(\})$}
{\1YYYY\2}
{^(fossil amend HASH -date \{.* )\d\d:}
{\1HH:}
{^(fossil amend HASH -date \{)[A-Z][a-z]{2} [A-Z][a-z]{2} [ 0-9]\d }
{\1Day Mon dd }
{(\] Edit \[)[0-9a-f]{16}.[0-9a-f]{10}(\]: )}
{\1HASH1|HASH2\2}
{(\] Edit \[.*?&dp=)[0-9a-f]{16}}
{\1dp=HASH}
}
dict set tests "cmdline" {
{^(fossil test-echo --args) .*/}
{\1 /TMP/}
{^(g\.nameOfExe =) \[[^\]]+[/\\]fossil(?:\.exe)?\]$}
{\1 [/PATH/FOSSILCMD]}
{^(argv\[0\] =) \[[^\]]+[/\\]fossil(?:\.exe)?\]$}
{\1 [/PATH/FOSSILCMD]}
}
dict set tests "contains-selector" {
{^(fossil test-contains-selector) .*?/(compare-selector.css )}
{\1 /TMP/\2}
}
dict set tests "json" {
{^(Content-Length) \d+$}
{\1 LENGTH}
{^(Cookie: fossil-)[0-9a-f]{16}(\=HASH%2F)\d+\.\d+(%2Fanonymous)$}
{\1CODE\2NOW\3}
{^(GET /json/cap\?authToken\=HASH)/\d+\.\d+/(anonymous )}
{\1/NOW/\2}
{^(Cookie: fossil-)[0-9a-f]{16}\=[0-9A-F]{50}%2F[0-9a-f]{16}%2F(.*)$}
{\1CODE=SHA1%2FCODE%2F\2}
{("authToken":").+?(")}
{\1AUTHTOKEN\2}
{("averageArtifactSize":)\d+()}
{\1SIZE\2}
{("compiler":").+?(")}
{\1COMPILER\2}
{("loginCookieName":").+?(")}
{\1COOKIE\2}
{("manifestVersion":"\[)[0-9a-f]{10}(\]")}
{\1HASH\2}
{("manifestYear":")\d{4}(")}
{\1YYYY\2}
{("name":").+?(")}
{\1NAME\2}
{("password":")[0-9a-f]+(")}
{\1PASSWORD\2}
{("projectCode":")[0-9a-f]{40}(")}
{\1HASH\2}
{("procTimeMs":)\d+}
{\1MSEC}
{("procTimeUs":)\d+}
{\1USEC}
{("releaseVersion":")\d+\.\d+(")}
{\1VERSION\2}
{("releaseVersionNumber":")\d+(")}
{\1VERSION_NUMBER\2}
{("timestamp":)\d+}
{\1SEC}
{("seed":)\d+()}
{\1SEED\2}
{("uid":)\d+()}
{\1UID\2}
{("uncompressedArtifactSize":)\d+()}
{\1SIZE\2}
{("user":").+?(")}
{\1USER\2}
{("version":"YYYY-mm-dd HH:MM:SS )\[[0-9a-f]{10}\] \(\d+\.\d+\.\d+\)"}
{\1[HASH] (major.minor.patch)}
{^(Date:) [A-Z][a-z]{2}, \d\d? [A-Z][a-z]{2} \d{4} \d\d:\d\d:\d\d [-+]\d{4}$}
{\1 Day, dd Mon YYYY HH:MM:SS TZ}
}
dict set tests "merge_renames" {
{^(size: {7})\d+( bytes)$}
{\1N\2}
{^(type: {7}Check-in by ).+?( on YYYY-mm-dd HH:MM:SS)$}
{\1USER\2}
}
dict set tests "set-manifest" {
{^(project-code: )[0-9a-f]{40}$}
{\1HASH} line
}
dict set tests "stash" {
{^(---|\+\+\+) NUL$}
{\1 /dev/null}
{(^ 1: \[)[0-9a-f]{14}(\] on YYYY-mm-dd HH:MM:SS)$}
{\1HASH\2}
{(^ 1: \[)[0-9a-f]{14}(\] from YYYY-mm-dd HH:MM:SS)$}
{\1HASH\2}
}
dict set tests "th1" {
{^(fossil test-th-source) (?:[A-Z]:)?.*?/(th1-)\d+([.]th1)$}
{\1 /TMP/\2PID\3}
{^(?:[A-Z]:)?[/\\].*?[/\\]fossil(?:\.exe)?$}
{/PATH/FOSSILCMD}
{[[:<:]](Content-Security-Policy[[:>:]].*'nonce-)[0-9a-f]{48}(';)}
{\1NONCE\2}
{^(<link rel="stylesheet" href="/style.css\?id=)[0-9a-f]+(" type="text/css">)$}
{\1ID\2}
{^\d+\.\d{3}(s by)$}
{N.MMM\1}
{^(Fossil) \d+\.\d+ \[[0-9a-f]{10}\] (YYYY-mm-dd HH:MM:SS)$}
{\1 N.M [HASH] \2}
{^(<script nonce=")[0-9a-f]{48}(">/\* style\.c:)\d+}
{\1NONCE\2LINENO}
}
dict set tests "th1-docs" {
{^(check-ins: ).*}
{\1COUNT}
{^(local-root: ).*}
{\1/PATH/}
{^(repository: ).*}
{\1/PATH/REPO}
{^(comment: ).*}
{\1/COMMENT/}
{^(tags: ).*}
{\1/TAGS/}
{(--ipaddr 127\.0\.0\.1) .*? (--localauth)}
{\1 REPO \2}
}
dict set tests "th1-hooks" {
{^(?:/[^:]*/fossil|[A-Z]:\\[^:]*\\fossil\.exe): (unknown command:|use \"help\")}
{fossil: \1}
{^(project-code: )[0-9a-f]{40}$}
{\1HASH}
}
dict set tests "th1-tcl" {
{^(fossil test-th-render --open-config) \{?.*?[/\\]test[/\\]([^/\\]*?)\}?$}
{\1 /CHECKOUT/test/\2}
{^(fossil)(?:\.exe)?( 3 \{test-th-render --open-config )(?:\{[A-Z]:)?[/\\].*?[/\\]test[/\\](th1-tcl9.txt\})\}?$}
{\1\2/CHECKOUT/test/\3}
{^\d{10}$}
{SEC}
}
dict set tests "unversioned" {
{^(fossil user new uvtester.*) \d+$}
{\1 PASSWORD}
{^(fossil .*http://uvtester:)\d+(@localhost:)\d+}
{\1PASSWORD\2PORT}
{^(Pull from http://uvtester@localhost:)\d+}
{\1PORT}
{^(ERROR \(1\): Usage:) .*?[/\\]fossil(?:\.exe)? (unversioned)}
{\1 /PATH/fossil \2}
{^(Started Fossil server, pid \")\d+(\", port \")\d+}
{\1PID\2PORT}
{^(Now in client directory \")(?:[A-Z]:)?/.*?/uvtest_\d+_\d+\"}
{\1/TMP/uvtest_SEC_SEQ}
{^(Stopped Fossil server, pid \")\d+(\", using argument \")(?:\d+|[^\"]*\.stopper)(\")}
{\1PID\2PID_OR_SCRIPT\3}
{^(This is unversioned file #4\.) \d+ \d+}
{\1 PID SEC}
{^(This is unversioned file #4\. PID SEC) \d+ \d+}
{\1 PID SEC}
{^[0-9a-f]{12}( YYYY-mm-dd HH:MM:SS *)(\d+)( *)\2( unversioned4.txt)$}
{HASH \1SZ\3SZ\4}
{^[0-9a-f]{40}$}
{\1HASH}
{^((?:Clone|Pull)? done, wire bytes sent: )\d+( received: )\d+( remote: )(?:127\.0.0\.1|::1)$}
{\1SENT\2RECV\3LOCALIP}
{^(project-id: )[0-9a-f]{40}$}
{\1HASH}
{^(server-id: )[0-9a-f]{40}$}
{\1HASH}
{^(admin-user: uvtester \(password is ").*("\))$}
{\1PASSWORD\2}
{^(repository: ).*?/uvtest_\d+_\d+/(uvrepo.fossil)$}
{\1/TMP/uvtest_SEC_SEQ/\2}
{^(local-root: ).*?/uvtest_\d+_\d+/$}
{\1/TMP/uvtest_SEC_SEQ/}
{^(project-code: )[0-9a-f]{40}$}
{\1HASH}
}
dict set tests "utf" {
{^(fossil test-looks-like-utf) (?:[A-Z]:)?/.*?/([^/\\]*?)\}?$}
{\1 /TMP/test/\2}
{^(File ")(?:[A-Z]:)?/.*?/(utf-check-\d+-\d+-\d+-\d+.jnk" has \d+ bytes\.)$}
{\1/TMP/\2}
}
dict set tests "wiki" {
{^(fossil (?:attachment|wiki) .*--technote )[0-9a-f]{21}$}
{\1HASH}
{^(fossil (?:attachment|wiki) .* (?:a13|f15|fa) --technote )[0-9a-f]+$}
{\1ID}
{^[0-9a-f]{40}( YYYY-mm-dd HH:MM:SS)}
{HASH\1}
{(\] Add attachment \[/artifact/)[0-9a-f]{16}(|)}
{\1HASH\2}
{ (to tech note \[/technote/)[0-9a-f]{16}\|[0-9a-f]{10}(\] \(user:)}
{\1HASH1|HASH2\2}
{^(ambiguous tech note id: )[0-9a-f]+$}
{\1ID}
{^(Attached fa to tech note )[0-9a-f]{21}(?:[0-9a-f]{19})?\.$}
{\1HASH.}
{^(Date:) [A-Z][a-z]{2}, \d\d? [A-Z][a-z]{2} \d{4} \d\d:\d\d:\d\d [-+]\d{4}$}
{\1 Day, dd Mon YYYY HH:MM:SS TZ}
{(Content-Security-Policy.*'nonce-)[0-9a-f]{48}(';)}
{\1NONCE\2}
{^(<link rel="stylesheet" href="/style.css\?id=)[0-9a-f]+(" type="text/css">)$}
{\1ID\2}
{^(added by )[^ ]*( on)$}
{\1USER\2}
{^(<script nonce=['\"])[0-9a-f]{48}(['\"]>/\* [a-z]+\.c:)\d+}
{\1NONCE\2LINENO}
{^(<script nonce=['\"])[0-9a-f]{48}(['\"]>)$}
{\1NONCE\2}
{^(projectCode: ")[0-9a-f]{40}(",)$}
{\1HASH\2}
{^\d+\.\d+(s by)$}
{N.SUB\1}
{^(window\.fossil.version = ")\d+\.\d+ \[[0-9a-f]{10}\] (YYYY-mm-dd HH:MM:SS(?: UTC";)?)$}
{\1N.M [HASH] \2}
{^(Fossil) \d+\.\d+ \[[0-9a-f]{10}\]( YYYY-mm-dd HH:MM:SS)$}
{\1 N.M [HASH]\2}
{^(type: Wiki-edit by ).+?( on YYYY-mm-dd HH:MM:SS)$$}
{\1USER\2}
{^(size: )\d+( bytes)$}
{\1N\2}
{^U [^ ]+$}
{U USER}
{^Z [0-9a-f]{32}$}
{Z CHECKSUM}
}
#
# Some pattersn are used in multiple groups
#
set testnames {"th1" "th1-docs" "th1-hooks"}
set pat {^((?:ERROR \(1\): )?/[*]{5} Subprocess) \d+ (exit)}
set sub {\1 PID \2}
foreach testname $testnames {
dict lappend tests $testname $pat $sub
}
set testnames {"th1-docs" "th1-hooks"}
set pat {(?:[A-Z]:)?/.*?/(test-http-(?:in|out))-\d+-\d+-\d+(\.txt)}
set sub {/TMP/\1-PID-SEQ-SEC\2}
foreach testname $testnames {
dict lappend tests $testname $pat $sub
}
set testnames {"json" "th1" "wiki"}
set pat {^(Content-Length:) \d+$}
set sub {\1 LENGTH}
foreach testname $testnames {
dict lappend tests $testname $pat $sub
}
set testnames {"th1" "wiki"}
set pat {^\d+\.\d+(s by)$}
set sub {N.SUB\1}
foreach testname $testnames {
dict lappend tests $testname $pat $sub
}
#
# Main
#
if { $fname eq "-" } {
set fd stdin
} else {
set fd [open $fname r]
}
# Platforms we detect
set UNKOWN_PLATFORM 0
set UNIX 1
set WINDOWS 2
set CYGWIN 3
# One specific wiki test creates repetitive output of varying length
set wiki_f13_cmd1 "fossil wiki create {timestamp of 2399999} f13 --technote 2399999"
set wiki_f13_cmd2 "fossil wiki list --technote --show-technote-ids"
set wiki_f13_cmd3 "fossil wiki export a13 --technote ID"
set collecting_f3 0
set collecting_f3_verbose 0
# Collected lines for summaries in --extra mode
set amend_ed_lines [list]
set amend_ed_failed 0
set symlinks_lines [list]
set symlinks_failed 0
set test_simplify_name_lines [list]
set test_simplify_name_failed 0
# State information s we progress
set check_json_empty_line 0
set lineno 0
set platform $UNKOWN_PLATFORM
set prev_line ""
set testname ""
while { [gets $fd line] >= 0 } {
incr lineno
if { $lineno == 1 } {
if { [string index $line 0] in {"\UFFEF" "\UFEFF"} } {
set line [string range $line 1 end]
}
}
# Remove RESULT status while matching (inserted again in output).
# If collecting lines of output, include $result_prefix as needed.
regexp {^(RESULT \([01]\): )?(.*)} $line match result_prefix line
if { [regsub {^\*{5} ([^ ]+) \*{6}$} $line {\1} new_testname] } {
# Pick up test name for special handling below
set testname "$new_testname"
} elseif { [regexp {^\*{5} End of } $line] } {
# Test done. Handle --extra before resetting.
if { $EXTRA } {
if { $testname eq "symlinks" } {
if { $symlinks_failed } {
foreach l $symlinks_lines {
puts "$l"
}
} else {
puts "All symlinks tests OK (not run on Windows)"
}
}
regsub {(: )\d+( errors so far)} $line {\1N\2} line
}
set testname ""
} elseif { $testname ne "" } {
if { $platform == $UNKOWN_PLATFORM } {
if { [regexp {^[A-Z]:/.*?/fossil\.exe } $line] } {
set platform $WINDOWS
} elseif { [regexp {^/.*?/fossil\.exe } $line] } {
# No drive, but still .exe - must be CYGWIN
set platform $CYGWIN
} elseif { [regexp {^/.*?/fossil } $line] } {
set platform $UNIX
}
}
# Do common and per testname rewrites
set line [common_rewrites $line $testname]
if { [dict exists $tests $testname] } {
foreach {pat sub} [dict get $tests $testname] {
regsub $pat $line $sub line
}
}
# On Windows, HTTP headers may get printed with an extra newline
if { $testname eq "json" } {
if { $check_json_empty_line == 1 } {
if { "$result_prefix$line" eq "" } {
set check_json_empty_line 2
continue
}
set check_json_empty_line 0
} elseif { [regexp {^(?:$|GET |POST |[A-Z][A-Za-z]*(?:-[A-Z][A-Za-z]*)*: )} $line] } {
set check_json_empty_line 1
} else {
if { $check_json_empty_line == 2 } {
# The empty line we skipped was meant to be followed by a new
# HTTP header or empty line, but it was not.
puts ""
}
set check_json_empty_line 0
}
}
# Summarise repetitive output of varying length for f13 in wiki test
if { $testname eq "wiki" } {
if { $collecting_f3 == 2 } {
if { $collecting_f3_verbose == 1 && [regexp {^HASH } $line] } {
incr collecting_f3_verbose
} elseif { $line eq $wiki_f13_cmd3 } {
incr collecting_f3
puts "\[...\]"
} else {
continue
}
} elseif { $collecting_f3 == 1 } {
if { $line eq $wiki_f13_cmd2 } {
incr collecting_f3
} elseif { $collecting_f3_verbose == 0 } {
incr collecting_f3_verbose
}
} elseif { $line eq $wiki_f13_cmd1 } {
incr collecting_f3
}
}
if { $EXTRA } {
if { $line eq "ERROR (0): " && $platform == $WINDOWS } {
if { [string match "fossil http --in *" $prev_line] } {
continue
}
}
if { $testname eq "amend" } {
# The amend-comment-5.N tests are not run on Windows
if { $line eq "fossil amend {} -close" } {
if { $amend_ed_failed } {
foreach l $amend_ed_lines {
puts "$l"
}
} else {
puts "All amend tests based on ed -s OK (not run on Windows)"
}
set amend_ed_lines [list]
} elseif { [llength $amend_ed_lines] } {
if { [regexp {^test amend-comment-5\.\d+ (.*)} $line match status] } {
lappend amend_ed_lines "$result_prefix$line"
if { $status ne "OK" } {
incr amend_ed_failed
}
continue
} elseif { [string range $line 0 4] eq "test " } {
# Handle change in tests by simply emitting what we got
foreach l $amend_ed_lines {
puts "$l"
}
set amend_ed_lines [list]
} else {
lappend amend_ed_lines "$result_prefix$line"
continue
}
} elseif { $line eq "fossil settings editor {ed -s}" } {
lappend amend_ed_lines "$result_prefix$line"
continue
}
} elseif { $testname eq "cmdline" } {
if { [regexp {^(fossil test-echo) (.*)} $line match test args] } {
if { ($platform == $UNIX && $args in {"*" "*.*"})
|| ($platform == $WINDOWS && $args eq "--args /TMP/fossil-cmd-line-101.txt")
|| ($platform == $CYGWIN && $args in {"*" "*.*"}) } {
set line "$test ARG_FOR_PLATFORM"
}
}
} elseif { $testname eq "commit-warning" } {
if { [regexp {^(micro-smile|pale facepalm) .*} $line match desc] } {
set line "$desc PLATFORM_SPECIFIC_BYTES"
}
} elseif { $testname eq "file1" } {
# test-simplify-name with question marks is specific to Windows
# They all immediately preceed "fossil test-relative-name --chdir . ."
if { $line eq "fossil test-relative-name --chdir . ." } {
if { $test_simplify_name_failed } {
foreach l $test_simplify_name_lines {
puts "$l"
}
} else {
puts "ALL Windows specific test-relative-name tests OK (if on Windows)"
}
set test_simplify_name_lines [list]
} elseif { [regexp {^fossil test-simplify-name .*([/\\])\?\1} $line] } {
lappend test_simplify_name_lines $line
continue
} elseif { [llength $test_simplify_name_lines] } {
if { [regexp {^test simplify-name-\d+ (.*)} $line match status] } {
if { $status ne "OK" } {
incr test_simplify_name_failed
}
}
lappend test_simplify_name_lines "$result_prefix$line"
continue
}
} elseif { $testname eq "settings-repo" } {
if { [regexp {^fossil test-th-eval (?:--open-config )?\{setting case-sensitive\}$} $prev_line] } {
if { ($platform == $UNIX && $line eq "on")
|| ($platform == $WINDOWS && $line eq "off")
|| ($platform == $CYGWIN && $line eq "off")
} {
set line "EXPECTED_FOR_PLATFORM"
}
}
} elseif { $testname eq "symlinks" } {
# Collect all lines and post-process at the end
lappend symlinks_lines "$result_prefix$line"
if { [regexp {^test symlinks-[^ ]* (.*)} $line match status] } {
if { $status ne "OK" } {
#TODO: incr symlinks_failed
}
}
continue
} elseif { $testname in {"th1" "th1-docs" "th1-hooks"} } {
# Special case that spans a couple of tests
# "Subprocess PID exit(0)" is sent on stderr on Unix. On Windows, there is no output
if { [regexp {^(ERROR \(1\): )?/\*{5} Subprocess PID exit\(0\) \*{5}/$} $line match prefix] } {
if { $prefix eq "" } {
continue
} elseif { $prefix eq "ERROR (1): " } {
set line "RESULT (0): "
}
} elseif { $testname eq "th1" } {
if { [regexp {^fossil test-th-eval --vfs ([^ ]+) \{globalState vfs\}$} $line match vfs] } {
if { ($platform == $UNIX && $vfs == "unix-dotfile")
|| ($platform == $WINDOWS && $vfs == "win32-longpath")
|| ($platform == $CYGWIN && $vfs == "win32-longpath") } {
regsub $vfs $line {EXEPECTED_VFS} line
}
} elseif { $prev_line eq "fossil test-th-eval --vfs EXEPECTED_VFS {globalState vfs}" } {
# Replace $vfs from previous line
regsub "^$vfs\$" $line {EXEPECTED_VFS} line
} elseif { $prev_line eq "fossil test-th-eval {set tcl_platform(platform)}" } {
if { $platform == $UNIX } {
regsub {^unix$} $line {EXPECTED_PLATFORM} line
} elseif { $platform == $WINDOWS } {
regsub {^windows$} $line {EXPECTED_PLATFORM} line
} elseif { $platform == $CYGWIN } {
regsub {^unix$} $line {EXPECTED_PLATFORM} line
}
} elseif { [string match "fossil test-th-eval --th-trace *" $prev_line] } {
if { ($result_prefix eq "RESULT (1): " && $line eq "")
|| ($result_prefix eq "" && $line eq "ERROR (0): ") } {
set result_prefix ""
set line "RESULT (0): / ERROR (1): "
}
}
} elseif { $testname eq "th1-docs" } {
# In th1-docs, the fossil check-out is exposed in various states.
regsub {(^project-code:) CE59BB9F186226D80E49D1FA2DB29F935CCA0333} $line {\1 HASH} line
if { [regexp {^merged-from: HASH YYYY-mm-dd HH:MM:SS UTC$} $line] } {
continue
}
}
}
}
} elseif { $EXTRA } {
# Fix up summaries to be generic and easy to diff(1)
if { [regsub {(^\*{5} (Final|Ignored) results: )\d+} $line {\1N} line] } {
regsub {\d+} $line {N} line
} elseif { [regexp {^(\*{5} (?:Considered failure|Ignored failure|Skipped test))s: (.*)} $line match desc vals] } {
if { $vals ne ""} {
foreach val [split $vals " "] {
puts "$desc: $val"
}
continue
}
}
}
# Not exactly correct if we continue'd, but OK for the purpose
set prev_line "$result_prefix$line"
puts "$prev_line"
}
|
Changes to test/set-manifest.test.
| ︙ | ︙ | |||
44 45 46 47 48 49 50 |
test_setup
#### Verify classic behavior of the manifest setting
# Setting is off by default, and there are no extra files.
fossil settings manifest
test "set-manifest-1" {[regexp {^manifest *$} $RESULT]}
| | | | 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 |
test_setup
#### Verify classic behavior of the manifest setting
# Setting is off by default, and there are no extra files.
fossil settings manifest
test "set-manifest-1" {[regexp {^manifest *$} $RESULT]}
set filelist [lsort [glob -nocomplain manifest*]]
test "set-manifest-1-n" {[llength $filelist] == 0}
# Classic behavior: TRUE value creates manifest and manifest.uuid
set truths [list true on 1]
foreach v $truths {
fossil settings manifest $v
test "set-manifest-2-$v" {$RESULT eq ""}
fossil settings manifest
test "set-manifest-2-$v-a" {[regexp "^manifest\\s+\\(local\\)\\s+$v\\s*$" $RESULT]}
set filelist [lsort [glob manifest*]]
test "set-manifest-2-$v-n" {[llength $filelist] == 2}
foreach f $filelist {
test "set-manifest-2-$v-f-$f" {[file isfile $f]}
}
}
# ... and manifest.uuid is the checkout's hash
|
| ︙ | ︙ | |||
86 87 88 89 90 91 92 |
# Classic behavior: FALSE value removes manifest and manifest.uuid
set falses [list false off 0]
foreach v $falses {
fossil settings manifest $v
test "set-manifest-3-$v" {$RESULT eq ""}
fossil settings manifest
test "set-manifest-3-$v-a" {[regexp "^manifest\\s+\\(local\\)\\s+$v\\s*$" $RESULT]}
| | | | | 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 |
# Classic behavior: FALSE value removes manifest and manifest.uuid
set falses [list false off 0]
foreach v $falses {
fossil settings manifest $v
test "set-manifest-3-$v" {$RESULT eq ""}
fossil settings manifest
test "set-manifest-3-$v-a" {[regexp "^manifest\\s+\\(local\\)\\s+$v\\s*$" $RESULT]}
set filelist [lsort [glob -nocomplain manifest*]]
test "set-manifest-3-$v-n" {[llength $filelist] == 0}
}
# Classic behavior: unset removes manifest and manifest.uuid
fossil unset manifest
test "set-manifest-4" {$RESULT eq ""}
fossil settings manifest
test "set-manifest-4-a" {[regexp {^manifest *$} $RESULT]}
set filelist [lsort [glob -nocomplain manifest*]]
test "set-manifest-4-n" {[llength $filelist] == 0}
##### Tags Manifest feature extends the manifest setting
# Manifest Tags: use letters r, u, and t to select each of manifest,
# manifest.uuid, and manifest.tags files.
set truths [list r u t ru ut rt rut]
foreach v $truths {
fossil settings manifest $v
test "set-manifest-5-$v" {$RESULT eq ""}
fossil settings manifest
test "set-manifest-5-$v-a" {[regexp "^manifest\\s+\\(local\\)\\s+$v\\s*$" $RESULT]}
set filelist [lsort [glob manifest*]]
test "set-manifest-5-$v-n" {[llength $filelist] == [string length $v]}
foreach f $filelist {
test "set-manifest-5-$v-f-$f" {[file isfile $f]}
}
}
# Quick check for tags applied in trunk
|
| ︙ | ︙ |
Changes to test/settings-repo.test.
| ︙ | ︙ | |||
38 39 40 41 42 43 44 |
set all_settings [get_all_settings]
foreach name $all_settings {
#
# HACK: Make 100% sure that there are no non-default setting values
# present anywhere.
#
| > > > | > | | | | | | | | | 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 |
set all_settings [get_all_settings]
foreach name $all_settings {
#
# HACK: Make 100% sure that there are no non-default setting values
# present anywhere.
#
if {$name eq "manifest"} {
fossil unset $name --exact --global -expectError
} else {
fossil unset $name --exact --global
}
fossil unset $name --exact
#
# NOTE: Query for the hard-coded default value of this setting and
# save it.
#
fossil test-th-eval "setting $name"
set defaults($name) [normalize_result]
}
###############################################################################
fossil settings bad-setting some_value -expectError
test settings-set-bad-local {
[normalize_result] eq "no such setting: bad-setting"
}
fossil settings bad-setting some_value --global -expectError
test settings-set-bad-global {
[normalize_result] eq "no such setting: bad-setting"
}
###############################################################################
fossil unset bad-setting -expectError
test settings-unset-bad-local {
[normalize_result] eq "no such setting: bad-setting"
}
fossil unset bad-setting --global -expectError
test settings-unset-bad-global {
[normalize_result] eq "no such setting: bad-setting"
}
###############################################################################
fossil settings ssl some_value -expectError
test settings-set-ambiguous-local {
[normalize_result] eq
"ambiguous setting \"ssl\" - might be: ssl-ca-location ssl-identity"
}
fossil settings ssl some_value --global -expectError
test settings-set-ambiguous-global {
[normalize_result] eq
"ambiguous setting \"ssl\" - might be: ssl-ca-location ssl-identity"
}
###############################################################################
fossil unset ssl -expectError
test settings-unset-ambiguous-local {
[normalize_result] eq
"ambiguous setting \"ssl\" - might be: ssl-ca-location ssl-identity"
}
fossil unset ssl --global -expectError
test settings-unset-ambiguous-global {
[normalize_result] eq
"ambiguous setting \"ssl\" - might be: ssl-ca-location ssl-identity"
}
###############################################################################
|
| ︙ | ︙ | |||
240 241 242 243 244 245 246 |
[regexp -- [string map [list %name% $name] $pattern(5)] $data]
}
fossil test-th-eval --open-config "setting $name"
set data [normalize_result]
test settings-set-check2-versionable-$name {
| | | 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 |
[regexp -- [string map [list %name% $name] $pattern(5)] $data]
}
fossil test-th-eval --open-config "setting $name"
set data [normalize_result]
test settings-set-check2-versionable-$name {
$data eq ""
}
file delete $fileName
fossil settings $name --exact
set data [normalize_result]
|
| ︙ | ︙ |
Changes to test/settings.test.
| ︙ | ︙ | |||
90 91 92 93 94 95 96 |
set data [normalize_result]
test settings-query-local-$name {
[regexp -- [string map [list %name% $name] $pattern(1)] $data] ||
[regexp -- [string map [list %name% $name] $pattern(2)] $data]
}
| > > > | > | | | 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 |
set data [normalize_result]
test settings-query-local-$name {
[regexp -- [string map [list %name% $name] $pattern(1)] $data] ||
[regexp -- [string map [list %name% $name] $pattern(2)] $data]
}
if {$name eq "manifest"} {
fossil settings $name --exact --global -expectError
} else {
fossil settings $name --exact --global
}
set data [normalize_result]
if {$name eq "manifest"} {
test settings-query-global-$name {
$data eq "cannot set 'manifest' globally"
}
} else {
test settings-query-global-$name {
[regexp -- [string map [list %name% $name] $pattern(1)] $data] ||
[regexp -- [string map [list %name% $name] $pattern(2)] $data]
}
}
}
###############################################################################
fossil settings bad-setting -expectError
test settings-query-bad-local {
[normalize_result] eq "no such setting: bad-setting"
}
fossil settings bad-setting --global -expectError
test settings-query-bad-global {
[normalize_result] eq "no such setting: bad-setting"
}
###############################################################################
test_cleanup
|
Changes to test/stash.test.
| ︙ | ︙ | |||
139 140 141 142 143 144 145 |
test stash-1-list-1 {[regexp {^1: \[[0-9a-z]+\] on } [first_data_line]]}
test stash-1-list-2 {[regexp {^\s+stash 1\s*$} [second_data_line]]}
set diff_stash_1 {DELETE f1
Index: f1
==================================================================
--- f1
| | | | 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 |
test stash-1-list-1 {[regexp {^1: \[[0-9a-z]+\] on } [first_data_line]]}
test stash-1-list-2 {[regexp {^\s+stash 1\s*$} [second_data_line]]}
set diff_stash_1 {DELETE f1
Index: f1
==================================================================
--- f1
+++ /dev/null
@@ -1,1 +0,0 @@
-f1
CHANGED f2
--- f2
+++ f2
@@ -1,1 +1,1 @@
-f2
+f2.1
CHANGED f3n
--- f3n
+++ f3n
ADDED f0
Index: f0
==================================================================
--- /dev/null
+++ f0
@@ -0,0 +1,1 @@
+f0}
########
# fossil stash show|cat ?STASHID? ?DIFF-OPTIONS?
# fossil stash [g]diff ?STASHID? ?DIFF-OPTIONS?
|
| ︙ | ︙ | |||
183 184 185 186 187 188 189 |
UPDATE f2
UPDATE f3n
ADDED f0
} -changes {
ADDED f0
MISSING f1
EDITED f2
| | | | 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 |
UPDATE f2
UPDATE f3n
ADDED f0
} -changes {
ADDED f0
MISSING f1
EDITED f2
RENAMED f3 -> f3n
} -addremove {
DELETED f1
} -exists {f0 f2 f3n} -notexists {f1 f3}
# Confirm there is no longer a stash saved
fossil stash list
test stash-2-list {[first_data_line] eq "empty stash"}
# Test stashed mv without touching the file system
# Issue reported by email to fossil-users
# from Warren Young, dated Tue, 9 Feb 2016 01:22:54 -0700
# with checkin [b8c7af5bd9] plus a local patch on CentOS 5
# 64 bit intel, 8-byte pointer, 4-byte integer
# Stashed renamed file said:
# fossil: ./src/delta.c:231: checksum: Assertion '...' failed.
# Should be triggered by this stash-WY-1 test.
fossil checkout --force c1
fossil clean
fossil mv --soft f1 f1new
stash-test WY-1 {-expectError save -m "Reported 2016-02-09"} {
REVERT f1
DELETE f1new
} -changes {
} -addremove {
} -exists {f1 f2 f3} -notexists {f1new} -knownbugs {-code -result}
# TODO: add tests that verify the saved stash is sensible. Possibly
# by applying it and checking results. But until the SQLITE_CONSTRAINT
|
| ︙ | ︙ | |||
263 264 265 266 267 268 269 |
ADDED f3
} -exists {f1 f2 f3} -notexists {}
#fossil status
fossil stash show
test stash-3-1-show {[normalize_result] eq {ADDED f3
Index: f3
==================================================================
| | | 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 |
ADDED f3
} -exists {f1 f2 f3} -notexists {}
#fossil status
fossil stash show
test stash-3-1-show {[normalize_result] eq {ADDED f3
Index: f3
==================================================================
--- /dev/null
+++ f3
@@ -0,0 +1,1 @@
+f3}}
stash-test 3-1-pop {pop} {
ADDED f3
} -changes {
ADDED f3
|
| ︙ | ︙ | |||
290 291 292 293 294 295 296 |
fossil commit -m "baseline"
fossil mv --hard f2 f2n
test_result_state stash-3-2-mv "mv --hard f2 f2n" [concat {
RENAME f2 f2n
MOVED_FILE} [file normalize f2] {
}] -changes {
| | | | 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 |
fossil commit -m "baseline"
fossil mv --hard f2 f2n
test_result_state stash-3-2-mv "mv --hard f2 f2n" [concat {
RENAME f2 f2n
MOVED_FILE} [file normalize f2] {
}] -changes {
RENAMED f2 -> f2n
} -addremove {
} -exists {f1 f2n} -notexists {f2}
stash-test 3-2 {save -m f2n} {
REVERT f2
DELETE f2n
} -exists {f1 f2} -notexists {f2n} -knownbugs {-result}
fossil stash show
test stash-3-2-show-1 {![regexp {\sf1} $RESULT]} knownBug
test stash-3-2-show-2 {[regexp {\sf2n} $RESULT]}
stash-test 3-2-pop {pop} {
UPDATE f1
UPDATE f2n
} -changes {
RENAMED f2 -> f2n
} -addremove {
} -exists {f1 f2n} -notexists {f2}
########
# fossil stash snapshot ?-m|--comment COMMENT? ?FILES...?
|
| ︙ | ︙ | |||
366 367 368 369 370 371 372 |
file rename -force f3 f3n
fossil mv f3 f3n
stash-test 4-3 {snapshot -m "snap 3"} {
} -changes {
ADDED f0
DELETED f1
EDITED f2
| | | 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 |
file rename -force f3 f3n
fossil mv f3 f3n
stash-test 4-3 {snapshot -m "snap 3"} {
} -changes {
ADDED f0
DELETED f1
EDITED f2
RENAMED f3 -> f3n
} -addremove {
} -exists {f0 f2 f3n} -notexists {f1 f3}
fossil stash diff
test stash-4-3-diff-CODE {!$::CODE} knownBug
fossil stash show
test stash-4-3-show-1 {[regexp {DELETE f1} $RESULT]}
test stash-4-3-show-2 {[regexp {CHANGED f2} $RESULT]}
|
| ︙ | ︙ |
Changes to test/symlinks.test.
| ︙ | ︙ | |||
21 22 23 24 25 26 27 |
set path [file dirname [info script]]
if {$is_windows} {
puts "Symlinks are not supported on Windows."
test_cleanup_then_return
}
| < < < < < < < > > > | 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
set path [file dirname [info script]]
if {$is_windows} {
puts "Symlinks are not supported on Windows."
test_cleanup_then_return
}
require_no_open_checkout
###############################################################################
test_setup; set rootDir [file normalize [pwd]]
# Using tempHomePath, allow-symlinks will always be off at this point.
fossil set allow-symlinks on
fossil test-th-eval --open-config {repository}
set repository [normalize_result]
if {[string length $repository] == 0} {
puts "Detection of the open repository file failed."
test_cleanup_then_return
|
| ︙ | ︙ | |||
60 61 62 63 64 65 66 |
test symlinks-dir-1 {[file exists [file join $rootDir subdirA f1.txt]] eq 1}
test symlinks-dir-2 {[file exists [file join $rootDir symdirA f1.txt]] eq 1}
test symlinks-dir-3 {[file exists [file join $rootDir subdirA f2.txt]] eq 1}
test symlinks-dir-4 {[file exists [file join $rootDir symdirA f2.txt]] eq 1}
fossil add [file join $rootDir symdirA f1.txt]
| > > > | > > > | | | | | | 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 |
test symlinks-dir-1 {[file exists [file join $rootDir subdirA f1.txt]] eq 1}
test symlinks-dir-2 {[file exists [file join $rootDir symdirA f1.txt]] eq 1}
test symlinks-dir-3 {[file exists [file join $rootDir subdirA f2.txt]] eq 1}
test symlinks-dir-4 {[file exists [file join $rootDir symdirA f2.txt]] eq 1}
fossil add [file join $rootDir symdirA f1.txt]
test symlinks-skip-dir-traversal {[normalize_result] eq \
"SKIP symdirA/f1.txt"}
fossil commit -m "c1" -expectError
test symlinks-empty-commit {[normalize_result] eq \
"nothing has changed; use --allow-empty to override"}
###############################################################################
fossil ls
test symlinks-dir-5 {[normalize_result] eq ""}
###############################################################################
fossil extras
test symlinks-dir-6 {[normalize_result] eq \
"subdirA/f1.txt\nsubdirA/f2.txt\nsymdirA"}
###############################################################################
fossil close
file delete [file join $rootDir subdirA f1.txt]
test symlinks-dir-7 {[file exists [file join $rootDir subdirA f1.txt]] eq 0}
test symlinks-dir-8 {[file exists [file join $rootDir symdirA f1.txt]] eq 0}
test symlinks-dir-9 {[file exists [file join $rootDir subdirA f2.txt]] eq 1}
test symlinks-dir-10 {[file exists [file join $rootDir symdirA f2.txt]] eq 1}
###############################################################################
fossil open --force $repository
set code [catch {file readlink [file join $rootDir symdirA]} result]
test symlinks-dir-11 {$code == 0}
test symlinks-dir-12 {$result eq [file join $rootDir subdirA]}
test symlinks-dir-13 {[file exists [file join $rootDir subdirA f1.txt]] eq 0}
test symlinks-dir-14 {[file exists [file join $rootDir symdirA f1.txt]] eq 0}
test symlinks-dir-15 {[file exists [file join $rootDir subdirA f2.txt]] eq 1}
test symlinks-dir-16 {[file exists [file join $rootDir symdirA f2.txt]] eq 1}
###############################################################################
#
# TODO: Add tests for symbolic links as files here, including tests with the
# "allow-symlinks" setting on and off.
#
###############################################################################
test_cleanup
|
Changes to test/tester.tcl.
| ︙ | ︙ | |||
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
# This is the main test script. To run a regression test, do this:
#
# tclsh ../test/tester.tcl ../bld/fossil
#
# Where ../test/tester.tcl is the name of this file and ../bld/fossil
# is the name of the executable to be tested.
#
# We use some things introduced in 8.6 such as lmap. auto.def should
# have found us a suitable Tcl installation.
package require Tcl 8.6
set testfiledir [file normalize [file dirname [info script]]]
set testrundir [pwd]
set testdir [file normalize [file dirname $argv0]]
set fossilexe [file normalize [lindex $argv 0]]
set is_windows [expr {$::tcl_platform(platform) eq "windows"}]
if {$::is_windows} {
if {[string length [file extension $fossilexe]] == 0} {
append fossilexe .exe
}
set outside_fossil_repo [expr ![file exists "$::testfiledir\\..\\_FOSSIL_"]]
} else {
| > > > > > > | 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 |
# This is the main test script. To run a regression test, do this:
#
# tclsh ../test/tester.tcl ../bld/fossil
#
# Where ../test/tester.tcl is the name of this file and ../bld/fossil
# is the name of the executable to be tested.
#
# To run a subset of tests (i.e. only one or more of the test/*.test
# scripts), append the script base names as arguments:
#
# tclsh ../test/tester.tcl ../bld/fossil <script-basename>...
#
# We use some things introduced in 8.6 such as lmap. auto.def should
# have found us a suitable Tcl installation.
package require Tcl 8.6
set testfiledir [file normalize [file dirname [info script]]]
set testrundir [pwd]
set testdir [file normalize [file dirname $argv0]]
set fossilexe [file normalize [lindex $argv 0]]
set is_windows [expr {$::tcl_platform(platform) eq "windows"}]
set is_cygwin [regexp {^CYGWIN} $::tcl_platform(os)]
if {$::is_windows} {
if {[string length [file extension $fossilexe]] == 0} {
append fossilexe .exe
}
set outside_fossil_repo [expr ![file exists "$::testfiledir\\..\\_FOSSIL_"]]
} else {
|
| ︙ | ︙ | |||
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 |
#
set result [list \
access-log \
admin-log \
allow-symlinks \
auto-captcha \
auto-hyperlink \
auto-shun \
autosync \
autosync-tries \
backoffice-disable \
backoffice-logfile \
backoffice-nodelay \
binary-glob \
case-sensitive \
chat-alert-sound \
chat-initial-history \
chat-inline-images \
chat-keep-count \
chat-keep-days \
chat-poll-timeout \
clean-glob \
clearsign \
comment-format \
crlf-glob \
crnl-glob \
default-csp \
default-perms \
diff-binary \
diff-command \
dont-push \
dotfiles \
editor \
email-admin \
email-renew-interval \
email-self \
email-send-command \
email-send-db \
email-send-dir \
email-send-method \
email-send-relayhost \
email-subname \
email-url \
empty-dirs \
encoding-glob \
exec-rel-paths \
fileedit-glob \
forbid-delta-manifests \
gdiff-command \
gmerge-command \
hash-digits \
hooks \
http-port \
https-login \
ignore-glob \
keep-glob \
localauth \
lock-timeout \
main-branch \
mainmenu \
manifest \
max-cache-entry \
max-loadavg \
max-upload \
mimetypes \
mtime-changes \
pgp-command \
preferred-diff-type \
proxy \
redirect-to-https \
relative-paths \
repo-cksum \
repolist-skin \
safe-html \
self-register \
sitemap-extra \
ssh-command \
ssl-ca-location \
ssl-identity \
tclsh \
th1-setup \
| > > > > > > > > > | 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 |
#
set result [list \
access-log \
admin-log \
allow-symlinks \
auto-captcha \
auto-hyperlink \
auto-hyperlink-delay \
auto-hyperlink-mouseover \
auto-shun \
autosync \
autosync-tries \
backoffice-disable \
backoffice-logfile \
backoffice-nodelay \
binary-glob \
case-sensitive \
chat-alert-sound \
chat-initial-history \
chat-inline-images \
chat-keep-count \
chat-keep-days \
chat-poll-timeout \
chat-timeline-user \
clean-glob \
clearsign \
comment-format \
crlf-glob \
crnl-glob \
default-csp \
default-perms \
diff-binary \
diff-command \
dont-commit \
dont-push \
dotfiles \
editor \
email-admin \
email-listid \
email-renew-interval \
email-self \
email-send-command \
email-send-db \
email-send-dir \
email-send-method \
email-send-relayhost \
email-subname \
email-url \
empty-dirs \
encoding-glob \
exec-rel-paths \
fileedit-glob \
forbid-delta-manifests \
forum-close-policy \
gdiff-command \
gmerge-command \
hash-digits \
hooks \
http-port \
https-login \
ignore-glob \
keep-glob \
large-file-size \
localauth \
lock-timeout \
main-branch \
mainmenu \
manifest \
max-cache-entry \
max-loadavg \
max-upload \
mimetypes \
mtime-changes \
mv-rm-files \
pgp-command \
preferred-diff-type \
proxy \
redirect-to-https \
relative-paths \
repo-cksum \
repolist-skin \
safe-html \
self-pw-reset \
self-register \
sitemap-extra \
ssh-command \
ssl-ca-location \
ssl-identity \
tclsh \
th1-setup \
|
| ︙ | ︙ | |||
431 432 433 434 435 436 437 438 439 440 441 442 443 444 |
proc require_no_open_checkout {} {
if {[info exists ::env(FOSSIL_TEST_DANGEROUS_IGNORE_OPEN_CHECKOUT)] && \
$::env(FOSSIL_TEST_DANGEROUS_IGNORE_OPEN_CHECKOUT) eq "YES_DO_IT"} {
return
}
catch {exec $::fossilexe info} res
if {[regexp {local-root:} $res]} {
set projectName <unknown>
set localRoot <unknown>
regexp -line -- {^project-name: (.*)$} $res dummy projectName
set projectName [string trim $projectName]
regexp -line -- {^local-root: (.*)$} $res dummy localRoot
set localRoot [string trim $localRoot]
error "Detected an open checkout of project \"$projectName\",\
| > > | 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 |
proc require_no_open_checkout {} {
if {[info exists ::env(FOSSIL_TEST_DANGEROUS_IGNORE_OPEN_CHECKOUT)] && \
$::env(FOSSIL_TEST_DANGEROUS_IGNORE_OPEN_CHECKOUT) eq "YES_DO_IT"} {
return
}
catch {exec $::fossilexe info} res
if {[regexp {local-root:} $res]} {
global skipped_tests testfile
lappend skipped_tests $testfile
set projectName <unknown>
set localRoot <unknown>
regexp -line -- {^project-name: (.*)$} $res dummy projectName
set projectName [string trim $projectName]
regexp -line -- {^local-root: (.*)$} $res dummy localRoot
set localRoot [string trim $localRoot]
error "Detected an open checkout of project \"$projectName\",\
|
| ︙ | ︙ | |||
468 469 470 471 472 473 474 475 476 477 478 479 |
}
after [expr {$try * 100}]
}
error "Could not delete \"$path\", error: $error"
}
proc test_cleanup_then_return {} {
uplevel 1 [list test_cleanup]
return -code return
}
proc test_cleanup {} {
| > > | > > > > | 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 |
}
after [expr {$try * 100}]
}
error "Could not delete \"$path\", error: $error"
}
proc test_cleanup_then_return {} {
global skipped_tests testfile
lappend skipped_tests $testfile
uplevel 1 [list test_cleanup]
return -code return
}
proc test_cleanup {} {
if {$::KEEP} {
# To avoid errors with require_no_open_checkout, cd out of here.
if {[info exists ::tempSavedPwd]} {cd $::tempSavedPwd; unset ::tempSavedPwd}
return
}
if {![info exists ::tempRepoPath]} {return}
if {![file exists $::tempRepoPath]} {return}
if {![file isdirectory $::tempRepoPath]} {return}
set tempPathEnd [expr {[string length $::tempPath] - 1}]
if {[string length $::tempPath] == 0 || \
[string range $::tempRepoPath 0 $tempPathEnd] ne $::tempPath} {
error "Temporary repository path has wrong parent during cleanup."
|
| ︙ | ︙ | |||
502 503 504 505 506 507 508 |
# Finally, attempt to gracefully delete the temporary home directory,
# unless forbidden by external forces.
if {![info exists ::tempKeepHome]} {delete_temporary_home}
}
proc delete_temporary_home {} {
if {$::KEEP} {return}; # All cleanup disabled?
| | | 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 |
# Finally, attempt to gracefully delete the temporary home directory,
# unless forbidden by external forces.
if {![info exists ::tempKeepHome]} {delete_temporary_home}
}
proc delete_temporary_home {} {
if {$::KEEP} {return}; # All cleanup disabled?
if {$::is_windows || $::is_cygwin} {
robust_delete [file join $::tempHomePath _fossil]
} else {
robust_delete [file join $::tempHomePath .fossil]
}
robust_delete $::tempHomePath
}
|
| ︙ | ︙ | |||
829 830 831 832 833 834 835 836 837 838 839 840 841 842 |
lappend bad_test $name
if {$::HALT} {exit 1}
}
}
}
set bad_test {}
set ignored_test {}
# Return a random string N characters long.
#
set vocabulary 01234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
append vocabulary " ()*^!.eeeeeeeeaaaaattiioo "
set nvocabulary [string length $vocabulary]
proc rand_str {N} {
| > | 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 |
lappend bad_test $name
if {$::HALT} {exit 1}
}
}
}
set bad_test {}
set ignored_test {}
set skipped_tests {}
# Return a random string N characters long.
#
set vocabulary 01234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
append vocabulary " ()*^!.eeeeeeeeaaaaattiioo "
set nvocabulary [string length $vocabulary]
proc rand_str {N} {
|
| ︙ | ︙ | |||
993 994 995 996 997 998 999 | set inFileName [file join $::tempPath [appendArgs test-http-in- $suffix]] set outFileName [file join $::tempPath [appendArgs test-http-out- $suffix]] set data [subst [read_file $dataFileName]] write_file $inFileName $data fossil http --in $inFileName --out $outFileName --ipaddr 127.0.0.1 \ | | | 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 |
set inFileName [file join $::tempPath [appendArgs test-http-in- $suffix]]
set outFileName [file join $::tempPath [appendArgs test-http-out- $suffix]]
set data [subst [read_file $dataFileName]]
write_file $inFileName $data
fossil http --in $inFileName --out $outFileName --ipaddr 127.0.0.1 \
$repository --localauth --th-trace -expectError
set result [expr {[file exists $outFileName] ? [read_file $outFileName] : ""}]
if {1} {
catch {file delete $inFileName}
catch {file delete $outFileName}
}
|
| ︙ | ︙ | |||
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 |
} error] != 0} {
error "Could not write file \"$tempFile\" in directory \"$tempPath\",\
please set TEMP variable in environment, error: $error"
}
set tempHomePath [file join $tempPath home_[pid]]
if {[catch {
file mkdir $tempHomePath
} error] != 0} {
error "Could not make directory \"$tempHomePath\",\
please set TEMP variable in environment, error: $error"
}
protInit $fossilexe
set ::tempKeepHome 1
foreach testfile $argv {
protOut "***** $testfile ******"
if { [catch {source $testdir/$testfile.test} testerror testopts] } {
test test-framework-$testfile 0
protOut "!!!!! $testfile: $testerror"
protOutDict $testopts"
} else {
test test-framework-$testfile 1
}
protOut "***** End of $testfile: [llength $bad_test] errors so far ******"
}
unset ::tempKeepHome; delete_temporary_home
set nErr [llength $bad_test]
if {$nErr>0 || !$::QUIET} {
protOut "***** Final results: $nErr errors out of $test_count tests" 1
}
if {$nErr>0} {
protOut "***** Considered failures: $bad_test" 1
}
set nErr [llength $ignored_test]
if {$nErr>0 || !$::QUIET} {
protOut "***** Ignored results: $nErr ignored errors out of $test_count tests" 1
}
if {$nErr>0} {
protOut "***** Ignored failures: $ignored_test" 1
}
| > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 1162 |
} error] != 0} {
error "Could not write file \"$tempFile\" in directory \"$tempPath\",\
please set TEMP variable in environment, error: $error"
}
set tempHomePath [file join $tempPath home_[pid]]
# Close stdin to avoid errors on wrapped text for narrow terminals.
# Closing stdin means that terminal detection returns 0 width, in turn
# causing the relvant strings to be printed on a single line.
# However, closing stdin makes file descriptor 0 avaailable on some systems
# and/or TCL implementations, which triggers fossil to complain about opening
# databases using fd 0. Avoid this by opening the script, consuming fd 0.
close stdin
set possibly_fd0 [open [info script] r]
if {[catch {
file mkdir $tempHomePath
} error] != 0} {
error "Could not make directory \"$tempHomePath\",\
please set TEMP variable in environment, error: $error"
}
protInit $fossilexe
set ::tempKeepHome 1
# Start in tempHomePath to help avoid errors with require_no_open_checkout
set startPwd [pwd]
cd $tempHomePath
foreach testfile $argv {
protOut "***** $testfile ******"
if { [catch {source $testdir/$testfile.test} testerror testopts] } {
test test-framework-$testfile 0
protOut "!!!!! $testfile: $testerror"
protOutDict $testopts"
} else {
test test-framework-$testfile 1
}
protOut "***** End of $testfile: [llength $bad_test] errors so far ******"
}
cd $startPwd
unset ::tempKeepHome; delete_temporary_home
# Clean up the file descriptor
close $possibly_fd0
set nErr [llength $bad_test]
if {$nErr>0 || !$::QUIET} {
protOut "***** Final results: $nErr errors out of $test_count tests" 1
}
if {$nErr>0} {
protOut "***** Considered failures: $bad_test" 1
}
set nErr [llength $ignored_test]
if {$nErr>0 || !$::QUIET} {
protOut "***** Ignored results: $nErr ignored errors out of $test_count tests" 1
}
if {$nErr>0} {
protOut "***** Ignored failures: $ignored_test" 1
}
set nSkipped [llength $skipped_tests]
if {$nSkipped>0} {
protOut "***** Skipped tests: $skipped_tests" 1
}
if {$bad_test>0} {
exit 1
}
|
Changes to test/th1-docs.test.
| ︙ | ︙ | |||
28 29 30 31 32 33 34 |
fossil test-th-eval "hasfeature tcl"
if {[normalize_result] ne "1"} {
puts "Fossil was not compiled with Tcl support."
test_cleanup_then_return
}
| < < < < < < < < | < | < > > > > > > > > > < | | | < | | 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 |
fossil test-th-eval "hasfeature tcl"
if {[normalize_result] ne "1"} {
puts "Fossil was not compiled with Tcl support."
test_cleanup_then_return
}
###############################################################################
test_setup
###############################################################################
set env(TH1_ENABLE_DOCS) 1; # TH1 docs must be enabled for this test.
set env(TH1_ENABLE_TCL) 1; # Tcl integration must be enabled for this test.
###############################################################################
set data [fossil info]
regexp -line -- {^repository: (.*)$} $data dummy repository
if {[string length $repository] == 0 || ![file exists $repository]} {
error "unable to locate repository"
}
set dataFileName [file join $::testdir th1-docs-input.txt]
set origFileStat [file join $::testdir fileStat.th1]
if {![file exists $origFileStat]} {
error "unable to locate [$origFileStat]"
}
file copy $origFileStat fileStat.th1
fossil add fileStat.th1
fossil commit -m "Add fileStat.th1"
###############################################################################
set RESULT [test_fossil_http \
$repository $dataFileName /doc/trunk/fileStat.th1]
test th1-docs-1a {[regexp {<title>Unnamed Fossil Project: fileStat.th1</title>} $RESULT]}
test th1-docs-1b {[regexp {>\[[0-9a-f]{40,64}\]<} $RESULT]}
test th1-docs-1c {[regexp { contains \d+ files\.} $RESULT]}
###############################################################################
test_cleanup
|
Changes to test/th1-hooks.test.
| ︙ | ︙ | |||
144 145 146 147 148 149 150 |
test th1-cmd-hooks-1b {[normalize_result] eq \
{<h1><b>command_hook timeline</b></h1>
+++ some stuff here +++
<h1><b>command_hook timeline command_notify timeline</b></h1>}}
###############################################################################
| | | 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 |
test th1-cmd-hooks-1b {[normalize_result] eq \
{<h1><b>command_hook timeline</b></h1>
+++ some stuff here +++
<h1><b>command_hook timeline command_notify timeline</b></h1>}}
###############################################################################
fossil timeline custom3 -expectError; # NOTE: Bad "WHEN" argument.
test th1-cmd-hooks-1c {[normalize_result] eq \
{<h1><b>command_hook timeline</b></h1>
unknown check-in or invalid date: custom3}}
###############################################################################
|
| ︙ | ︙ | |||
194 195 196 197 198 199 200 |
fossil test3
test th1-custom-cmd-3a {[string trim $RESULT] eq \
{<h1><b>command_hook test3</b></h1>}}
###############################################################################
| | | 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 |
fossil test3
test th1-custom-cmd-3a {[string trim $RESULT] eq \
{<h1><b>command_hook test3</b></h1>}}
###############################################################################
fossil test4 -expectError
test th1-custom-cmd-4a {[first_data_line] eq \
{<h1><b>command_hook test4</b></h1>}}
test th1-custom-cmd-4b {[regexp -- \
{: unknown command: test4$} [second_data_line]]}
|
| ︙ | ︙ |
Changes to test/th1-tcl.test.
| ︙ | ︙ | |||
75 76 77 78 79 80 81 |
}
###############################################################################
fossil test-th-render --open-config \
[file nativename [file join $path th1-tcl3.txt]]
| | | | | | | | | | > > > > > > > | | 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 |
}
###############################################################################
fossil test-th-render --open-config \
[file nativename [file join $path th1-tcl3.txt]]
test th1-tcl-3 {$RESULT eq {<hr><p class="thmainError">ERROR:\
invalid command name "bad_command"</p>}}
###############################################################################
fossil test-th-render --open-config \
[file nativename [file join $path th1-tcl4.txt]]
test th1-tcl-4 {$RESULT eq {<hr><p class="thmainError">ERROR:\
divide by zero</p>}}
###############################################################################
fossil test-th-render --open-config \
[file nativename [file join $path th1-tcl5.txt]]
test th1-tcl-5 {$RESULT eq {<hr><p class="thmainError">ERROR:\
Tcl command not found: bad_command</p>} || $RESULT eq {<hr><p\
class="thmainError">ERROR: invalid command name "bad_command"</p>}}
###############################################################################
fossil test-th-render --open-config \
[file nativename [file join $path th1-tcl6.txt]]
test th1-tcl-6 {$RESULT eq {<hr><p class="thmainError">ERROR:\
no such command: bad_command</p>}}
###############################################################################
fossil test-th-render --open-config \
[file nativename [file join $path th1-tcl7.txt]]
test th1-tcl-7 {$RESULT eq {<hr><p class="thmainError">ERROR:\
syntax error in expression: "2**0"</p>}}
###############################################################################
fossil test-th-render --open-config \
[file nativename [file join $path th1-tcl8.txt]]
test th1-tcl-8 {$RESULT eq {<hr><p class="thmainError">ERROR:\
cannot invoke Tcl command: tailcall</p>} || $RESULT eq {<hr><p\
class="thmainError">ERROR: tailcall can only be called from a proc or\
lambda</p>} || $RESULT eq {<hr><p class="thmainError">ERROR: This test\
requires Tcl 8.6 or higher.</p>}}
###############################################################################
fossil test-th-render --open-config \
[file nativename [file join $path th1-tcl9.txt]]
# Under cygwin, the printed name with Usage: strips the extension
if { $::is_cygwin && [file extension $fossilexe] eq ".exe" } {
set fossilexeref [string range $fossilexe 0 end-4]
} else {
set fossilexeref $fossilexe
}
test th1-tcl-9 {[string trim $RESULT] eq [list [file tail $fossilexeref] 3 \
[list test-th-render --open-config [file nativename [file join $path \
th1-tcl9.txt]]]]}
###############################################################################
fossil test-th-eval "tclMakeSafe a"
test th1-tcl-10 {[normalize_result] eq \
|
| ︙ | ︙ |
Changes to test/th1.test.
| ︙ | ︙ | |||
728 729 730 731 732 733 734 |
###############################################################################
fossil test-th-eval "trace {}"
test th1-trace-1 {$RESULT eq {}}
###############################################################################
| | | | | | | | | | > > | 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 |
###############################################################################
fossil test-th-eval "trace {}"
test th1-trace-1 {$RESULT eq {}}
###############################################################################
fossil test-th-eval --th-trace "trace {}" -expectError
set normalized_result [normalize_result]
regsub -- {\n/\*\*\*\*\* Subprocess \d+ exit\(\d+\) \*\*\*\*\*/} \
$normalized_result {} normalized_result
if {$th1Hooks} {
test th1-trace-2 {$normalized_result eq \
{------------------ BEGIN TRACE LOG ------------------
th1-init 0x0 => 0x0<br>
------------------- END TRACE LOG -------------------}}
} else {
test th1-trace-2 {$normalized_result eq \
{------------------ BEGIN TRACE LOG ------------------
th1-init 0x0 => 0x0<br>
th1-setup {} => TH_OK<br>
------------------- END TRACE LOG -------------------}}
}
###############################################################################
fossil test-th-eval "trace {this is a trace message.}"
test th1-trace-3 {$RESULT eq {}}
###############################################################################
fossil test-th-eval --th-trace "trace {this is a trace message.}" -expectError
set normalized_result [normalize_result]
regsub -- {\n/\*\*\*\*\* Subprocess \d+ exit\(\d+\) \*\*\*\*\*/} \
$normalized_result {} normalized_result
if {$th1Hooks} {
test th1-trace-4 {$normalized_result eq \
{------------------ BEGIN TRACE LOG ------------------
th1-init 0x0 => 0x0<br>
this is a trace message.
------------------- END TRACE LOG -------------------}}
} else {
test th1-trace-4 {$normalized_result eq \
{------------------ BEGIN TRACE LOG ------------------
th1-init 0x0 => 0x0<br>
th1-setup {} => TH_OK<br>
this is a trace message.
------------------- END TRACE LOG -------------------}}
}
###############################################################################
fossil test-th-eval "defHeader {Page Title Here}"
test th1-defHeader-1 {$RESULT eq \
{TH_ERROR: wrong # args: should be "defHeader"}}
###############################################################################
fossil test-th-eval "defHeader"
test th1-defHeader-2 {[string match *<body> [normalize_result]] || \
[string match "*<body class=\"\$current_feature\
rpage-\$requested_page\
cpage-\$canonical_page\">" [normalize_result]]}
###############################################################################
fossil test-th-eval "styleHeader {Page Title Here}"
test th1-header-1 {$RESULT eq {TH_ERROR: repository unavailable}}
###############################################################################
|
| ︙ | ︙ | |||
1019 1020 1021 1022 1023 1024 1025 |
###############################################################################
fossil test-th-eval "globalState vfs"
test th1-globalState-14 {[string length $RESULT] == 0}
###############################################################################
| | | 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 |
###############################################################################
fossil test-th-eval "globalState vfs"
test th1-globalState-14 {[string length $RESULT] == 0}
###############################################################################
if {$is_windows || $is_cygwin} {
set altVfs win32-longpath
} else {
set altVfs unix-dotfile
}
###############################################################################
|
| ︙ | ︙ | |||
1060 1061 1062 1063 1064 1065 1066 |
set sorted_result [lsort $RESULT]
protOut "Sorted: $sorted_result"
set base_commands {anoncap anycap array artifact break breakpoint \
builtin_request_js capexpr captureTh1 catch cgiHeaderLine checkout \
combobox continue copybtn date decorate defHeader dir enable_htmlify \
enable_output encode64 error expr for foreach getParameter glob_match \
globalState hascap hasfeature html htmlize http httpize if info \
| | | | | | 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 |
set sorted_result [lsort $RESULT]
protOut "Sorted: $sorted_result"
set base_commands {anoncap anycap array artifact break breakpoint \
builtin_request_js capexpr captureTh1 catch cgiHeaderLine checkout \
combobox continue copybtn date decorate defHeader dir enable_htmlify \
enable_output encode64 error expr for foreach getParameter glob_match \
globalState hascap hasfeature html htmlize http httpize if info \
insertCsrf lappend lindex linecount list llength lsearch markdown nonce \
proc puts query randhex redirect regexp reinitialize rename render \
repository return searchable set setParameter setting stime string \
styleFooter styleHeader styleScript submenu tclReady trace unset \
unversioned uplevel upvar utime verifyCsrf verifyLogin wiki}
set tcl_commands {tclEval tclExpr tclInvoke tclIsSafe tclMakeSafe}
if {$th1Tcl} {
test th1-info-commands-1 {$sorted_result eq [lsort "$base_commands $tcl_commands"]}
} else {
test th1-info-commands-1 {$sorted_result eq [lsort "$base_commands"]}
}
|
| ︙ | ︙ |
Changes to test/unversioned.test.
| ︙ | ︙ | |||
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 |
puts "The \"sha1\" package is not available."
test_cleanup_then_return
}
require_no_open_checkout
test_setup; set rootDir [file normalize [pwd]]
fossil test-th-eval --open-config {repository}
set repository [normalize_result]
if {[string length $repository] == 0} {
puts "Detection of the open repository file failed."
test_cleanup_then_return
}
write_file unversioned1.txt "This is unversioned file #1."
write_file unversioned2.txt " This is unversioned file #2. "
write_file "unversioned space.txt" "\nThis is unversioned file #3.\n"
write_file unversioned4.txt "This is unversioned file #4."
write_file unversioned5.txt "This is unversioned file #5."
set env(VISUAL) [appendArgs \
[info nameofexecutable] " " [file join $path fake-editor.tcl]]
###############################################################################
| > > > > > > > > > > | | | 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 |
puts "The \"sha1\" package is not available."
test_cleanup_then_return
}
require_no_open_checkout
test_setup; set rootDir [file normalize [pwd]]
# Avoid delays from the backoffice.
fossil set backoffice-disable 1
fossil test-th-eval --open-config {repository}
set repository [normalize_result]
if {[string length $repository] == 0} {
puts "Detection of the open repository file failed."
test_cleanup_then_return
}
write_file unversioned1.txt "This is unversioned file #1."
write_file unversioned2.txt " This is unversioned file #2. "
write_file "unversioned space.txt" "\nThis is unversioned file #3.\n"
write_file unversioned4.txt "This is unversioned file #4."
write_file unversioned5.txt "This is unversioned file #5."
set env(VISUAL) [appendArgs \
[info nameofexecutable] " " [file join $path fake-editor.tcl]]
###############################################################################
# Under cygwin, the printed name with Usage: strips the extension
if { $::is_cygwin && [file extension $fossilexe] eq ".exe" } {
set fossilexeref [string range $fossilexe 0 end-4]
} else {
set fossilexeref $fossilexe
}
fossil unversioned -expectError
test unversioned-1 {[normalize_result] eq \
[string map [list %fossil% [file nativename $fossilexeref]] {Usage: %fossil%\
unversioned add|cat|edit|export|list|revert|remove|sync|touch}]}
###############################################################################
fossil unversioned list
test unversioned-2 {[normalize_result] eq {}}
|
| ︙ | ︙ | |||
310 311 312 313 314 315 316 |
fossil user new uvtester "Unversioned Test User" $password
fossil user capabilities uvtester oy
###############################################################################
foreach {pid port outTmpFile} [test_start_server $repository stopArg] {}
| > | > > | > | | | 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 |
fossil user new uvtester "Unversioned Test User" $password
fossil user capabilities uvtester oy
###############################################################################
foreach {pid port outTmpFile} [test_start_server $repository stopArg] {}
if {! $::QUIET} {
puts [appendArgs "Started Fossil server, pid \"" $pid \" ", port \"" $port \".]
}
set remote [appendArgs http://uvtester: $password @localhost: $port /]
###############################################################################
set clientDir [file join $tempPath [appendArgs \
uvtest_ [string trim [clock seconds] -] _ [getSeqNo]]]
set savedPwd [pwd]
file mkdir $clientDir; cd $clientDir
if {! $::QUIET} {
puts [appendArgs "Now in client directory \"" [pwd] \".]
}
write_file unversioned-client1.txt "This is unversioned client file #1."
###############################################################################
fossil clone --save-http-password $remote uvrepo.fossil
fossil open -f uvrepo.fossil
###############################################################################
fossil unversioned list
test unversioned-45 {[normalize_result] eq {}}
###############################################################################
fossil_maybe_answer y unversioned sync $remote
test unversioned-46 {[regexp \
{Round-trips: 1 Artifacts sent: 0 received: 0
Round-trips: 1 Artifacts sent: 0 received: 0
Round-trips: 2 Artifacts sent: 0 received: 0
Round-trips: 2 Artifacts sent: 0 received: 2
\n? done, wire bytes sent: \d+ received: \d+ remote: (?:127\.0\.0\.1|::1)} \
[normalize_result]]}
###############################################################################
fossil unversioned ls
test unversioned-47 {[normalize_result] eq {unversioned2.txt
unversioned5.txt}}
|
| ︙ | ︙ | |||
387 388 389 390 391 392 393 |
fossil_maybe_answer y unversioned revert $remote
test unversioned-52 {[regexp \
{Round-trips: 1 Artifacts sent: 0 received: 0
Round-trips: 1 Artifacts sent: 0 received: 0
Round-trips: 2 Artifacts sent: 0 received: 0
Round-trips: 2 Artifacts sent: 0 received: 2
| | | 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 |
fossil_maybe_answer y unversioned revert $remote
test unversioned-52 {[regexp \
{Round-trips: 1 Artifacts sent: 0 received: 0
Round-trips: 1 Artifacts sent: 0 received: 0
Round-trips: 2 Artifacts sent: 0 received: 0
Round-trips: 2 Artifacts sent: 0 received: 2
\n? done, wire bytes sent: \d+ received: \d+ remote: (?:127\.0\.0\.1|::1)} \
[normalize_result]]}
###############################################################################
fossil unversioned list
test unversioned-53 {[regexp \
{^[0-9a-f]{12} 2016-10-01 00:00:00 30 30\
|
| ︙ | ︙ | |||
412 413 414 415 416 417 418 |
fossil_maybe_answer y unversioned sync $remote
test unversioned-55 {[regexp \
{Round-trips: 1 Artifacts sent: 0 received: 0
Round-trips: 1 Artifacts sent: 0 received: 0
Round-trips: 2 Artifacts sent: 1 received: 0
Round-trips: 2 Artifacts sent: 1 received: 0
| | > | > > | > | 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 |
fossil_maybe_answer y unversioned sync $remote
test unversioned-55 {[regexp \
{Round-trips: 1 Artifacts sent: 0 received: 0
Round-trips: 1 Artifacts sent: 0 received: 0
Round-trips: 2 Artifacts sent: 1 received: 0
Round-trips: 2 Artifacts sent: 1 received: 0
\n? done, wire bytes sent: \d+ received: \d+ remote: (?:127\.0\.0\.1|::1)} \
[normalize_result]]}
###############################################################################
fossil close
test unversioned-56 {[normalize_result] eq {}}
###############################################################################
cd $savedPwd; unset savedPwd
file delete -force $clientDir
if {! $::QUIET} {
puts [appendArgs "Now in server directory \"" [pwd] \".]
}
###############################################################################
set stopped [test_stop_server $stopArg $pid $outTmpFile]
if {! $::QUIET} {
puts [appendArgs \
[expr {$stopped ? "Stopped" : "Could not stop"}] \
" Fossil server, pid \"" $pid "\", using argument \"" \
$stopArg \".]
}
###############################################################################
fossil unversioned list
test unversioned-57 {[regexp \
{^[0-9a-f]{12} \d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2} 35 35\
unversioned-client1\.txt
|
| ︙ | ︙ |
Added test/update.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 |
#
# Copyright (c) 2024 Preben Guldnerg <preben@guldberg.org>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the Simplified BSD License (also
# known as the "2-Clause License" or "FreeBSD License".)
#
# This program is distributed in the hope that it will be useful,
# but without any warranty; without even the implied warranty of
# merchantability or fitness for a particular purpose.
#
# Author contact information:
# drh@hwaci.com
# http://www.hwaci.com/drh/
#
############################################################################
#
# Tests for the "update" command.
#
# Track number of tests we have set up in test_update_setup. This helps ensure
# that generated files are ordered in `fossil update --verbose` mode.
set UPDATE_TEST 0
proc test_update_setup {desc} {
global UPDATE_TEST
incr UPDATE_TEST
fossil revert
fossil update
return [format "test-%02u-%s.txt" $UPDATE_TEST $desc]
}
# The output is in file name order, so massage $RESULT to remove initial UNCHANGED
# files. Only do this if we have the expected branch information.
proc test_update {testname message changes {fossil_args ""}} {
fossil update --verbose {*}$fossil_args
if { [regsub {\n-{79}\nupdated-from: [0-9a-z]{40} .*} $::RESULT {} test_result ] } {
regsub {^(?:UNCHANGED [-a-z0-9.]+\n)*} $test_result {} test_result
} else {
set test_result $::RESULT
}
test "update-message-$testname" {$message == $test_result}
fossil changes
test "update-changes-$testname" {$changes == $::RESULT}
}
# Use a sequence number for file content that is not important for the test.
set UPDATE_SEQ_NO 0
proc write_seq_to_file {fname} {
global UPDATE_SEQ_NO
incr UPDATE_SEQ_NO
write_file $fname "$UPDATE_SEQ_NO\n"
}
# Make sure we are not in an open repository and initialize new repository
test_setup
###############################################################################
fossil update --verbose
test update-already-up-to-date {
[regexp {^-{79}\ncheckout: .*\nchanges: +None. Already up-to-date$} $RESULT]
}
# Remaining tests are carried out in the order update_cmd() performs checks.
#
# Common approach for tests below:
# 1. Set the testname
# 2. Set the file name, done by calling update_setup
# 3. Set message and changes, the expected message message and subsequent changes
# 3. Optionally set up and commit a common base for the next steps
# 4. Commit a change to the repository (new tip)
# 5. Update to the previous version
# 6. Make changes
# 7. Call test_update to attempt and update to tip
set testname "conflict-standard"
set fname [test_update_setup $testname]
set message "CONFLICT $fname"
set changes "EDITED $fname"
write_seq_to_file $fname
fossil add $fname
fossil commit -m "Add $fname"
fossil up previous
write_seq_to_file $fname
fossil add $fname
test_update $testname $message $changes -expectError
set testname "add-overwrites"
set fname [test_update_setup $testname]
set message "ADD $fname - overwrites an unmanaged file, original copy backed up locally"
set changes ""
write_seq_to_file $fname
fossil add $fname
fossil commit -m "Add $fname"
fossil up previous
write_seq_to_file $fname
test_update $testname $message $changes -expectError
set testname "add-standard"
set fname [test_update_setup $testname]
set message "ADD $fname"
set changes ""
write_seq_to_file $fname
fossil add $fname
fossil commit -m "Add $fname"
fossil up previous
test_update $testname $message $changes
set testname "update-change"
set fname [test_update_setup $testname]
set message "UPDATE $fname - change to unmanaged file"
set changes "DELETED $fname"
write_seq_to_file $fname
fossil add $fname
fossil commit -m "Add $fname"
write_seq_to_file $fname
fossil commit -m "Update $fname"
fossil up previous
fossil rm --hard $fname
test_update $testname $message $changes
set testname "update-standard"
set fname [test_update_setup $testname]
set message "UPDATE $fname"
set changes ""
write_seq_to_file $fname
fossil add $fname
fossil commit -m "Add $fname"
write_seq_to_file $fname
fossil commit -m "Update $testname"
fossil up previous
test_update $testname $message $changes
set testname "update-missing"
set fname [test_update_setup $testname]
set message "UPDATE $fname"
set changes ""
write_seq_to_file $fname
fossil add $fname
fossil commit -m "Add $fname"
write_seq_to_file $fname
fossil commit -m "Update $fname"
fossil up previous
file delete $fname
test_update $testname $message $changes
set testname "conflict-deleted"
set fname [test_update_setup $testname]
set message "CONFLICT $fname - edited locally but deleted by update"
set changes ""
write_seq_to_file $fname
fossil add $fname
fossil commit -m "Add $fname"
fossil rm --hard $fname
fossil commit -m "Remove $fname"
fossil up previous
file delete $fname
test_update $testname $message $changes -expectError
set testname "remove"
set fname [test_update_setup $testname]
set message "REMOVE $fname"
set changes ""
write_seq_to_file $fname
fossil add $fname
fossil commit -m "Add $fname"
fossil rm --hard $fname
fossil commit -m "Remove $fname"
fossil up previous
test_update $testname $message $changes
set testname "merge-renamed"
set fname [test_update_setup $testname]
set message "MERGE $fname -> $fname.renamed"
set changes "EDITED $fname.renamed"
write_file $fname "center\n"
fossil add $fname
fossil commit -m "Add $fname"
write_file $fname "top\ncenter\n"
fossil mv --hard $fname "$fname.renamed"
fossil commit -m "Update and rename $fname"
fossil up previous
write_file $fname "center\nbelow\n"
test_update $testname $message $changes
set testname "merge-standard"
set fname [test_update_setup $testname]
set message "MERGE $fname"
set changes "EDITED $fname"
write_file $fname "center\n"
fossil add $fname
fossil commit -m "Add $fname"
write_file $fname "top\ncenter\n"
fossil commit -m "Update $fname"
fossil up previous
write_file $fname "center\nbelow\n"
test_update $testname $message $changes
# TODO: test for "Cannot merge symlink" would be platform dependent
set testname "merge-conflict"
set fname [test_update_setup $testname]
set message "MERGE $fname\n***** 1 merge conflicts in $fname"
set changes "CONFLICT $fname"
write_seq_to_file $fname
fossil add $fname
fossil commit -m "Add $fname"
write_seq_to_file $fname
fossil commit -m "Update $fname"
fossil up previous
write_seq_to_file $fname
test_update $testname $message $changes -expectError
# TODO: test for "Cannot merge binary file"?
set testname "edited"
set fname [test_update_setup $testname]
set message "EDITED $fname\nADD $fname.other"
set changes "EDITED $fname"
write_seq_to_file $fname
fossil add $fname
fossil commit -m "Add $fname"
write_seq_to_file "$fname.other"
fossil add $fname.other
fossil commit -m "Add $fname.other"
fossil up previous
write_seq_to_file $fname
test_update $testname $message $changes
set testname "unchanged"
set fname [test_update_setup $testname]
set message "ADD $fname\nUNCHANGED $fname.unchanged"
set changes ""
write_seq_to_file "$fname.unchanged"
fossil add "$fname.unchanged"
fossil commit -m "Add $fname.unchanged"
write_seq_to_file "$fname"
fossil add "$fname"
fossil commit -m "Add $fname"
fossil up previous
test_update $testname $message $changes
###############################################################################
test_cleanup
|
Changes to tools/codecheck1.c.
| ︙ | ︙ | |||
28 29 30 31 32 33 34 | ** ** Checks include: ** ** * Verify that vararg formatting routines like blob_printf() or ** db_multi_exec() have the correct number of arguments for their ** format string. ** | | | | 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | ** ** Checks include: ** ** * Verify that vararg formatting routines like blob_printf() or ** db_multi_exec() have the correct number of arguments for their ** format string. ** ** * For routines designed to generate SQL or HTML or a URL or JSON, ** detect and warn about possible injection attacks. */ #include <stdio.h> #include <stdlib.h> #include <ctype.h> #include <string.h> #include <assert.h> |
| ︙ | ︙ | |||
344 345 346 347 348 349 350 | /* ** Processing flags */ #define FMT_SQL 0x00001 /* Generator for SQL text */ #define FMT_HTML 0x00002 /* Generator for HTML text */ #define FMT_URL 0x00004 /* Generator for URLs */ | > | | | > > | 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 |
/*
** Processing flags
*/
#define FMT_SQL 0x00001 /* Generator for SQL text */
#define FMT_HTML 0x00002 /* Generator for HTML text */
#define FMT_URL 0x00004 /* Generator for URLs */
#define FMT_JSON 0x00008 /* Generator for JSON */
#define FMT_SAFE 0x00010 /* Generator for human-readable text */
#define FMT_LIT 0x00020 /* Just verify that a string literal */
#define FMT_PX 0x00040 /* Must have a literal prefix in format string */
/*
** A list of internal Fossil interfaces that take a printf-style format
** string.
*/
struct FmtFunc {
const char *zFName; /* Name of the function */
int iFmtArg; /* Index of format argument. Leftmost is 1. */
unsigned fmtFlags; /* Processing flags */
} aFmtFunc[] = {
{ "admin_log", 1, FMT_SAFE },
{ "ajax_route_error", 2, FMT_SAFE },
{ "audit_append", 3, FMT_SAFE },
{ "backofficeTrace", 1, FMT_SAFE },
{ "backoffice_log", 1, FMT_SAFE },
{ "blob_append_sql", 2, FMT_SQL },
{ "blob_appendf", 2, FMT_SAFE },
{ "cgi_debug", 1, FMT_SAFE },
{ "cgi_panic", 1, FMT_SAFE },
{ "cgi_printf", 1, FMT_HTML },
{ "cgi_printf_header", 1, FMT_HTML },
{ "cgi_redirectf", 1, FMT_URL },
|
| ︙ | ︙ | |||
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 |
{ "fossil_errorlog", 1, FMT_SAFE },
{ "fossil_fatal", 1, FMT_SAFE },
{ "fossil_fatal_recursive", 1, FMT_SAFE },
{ "fossil_panic", 1, FMT_SAFE },
{ "fossil_print", 1, FMT_SAFE },
{ "fossil_trace", 1, FMT_SAFE },
{ "fossil_warning", 1, FMT_SAFE },
{ "href", 1, FMT_URL },
{ "json_new_string_f", 1, FMT_SAFE },
{ "json_set_err", 2, FMT_SAFE },
{ "json_warn", 2, FMT_SAFE },
{ "mprintf", 1, FMT_SAFE },
{ "multiple_choice_attribute", 3, FMT_LIT },
{ "onoff_attribute", 3, FMT_LIT },
{ "pop3_print", 2, FMT_SAFE },
{ "smtp_send_line", 2, FMT_SAFE },
{ "smtp_server_send", 2, FMT_SAFE },
{ "socket_set_errmsg", 1, FMT_SAFE },
{ "ssl_set_errmsg", 1, FMT_SAFE },
{ "style_header", 1, FMT_HTML },
{ "style_set_current_page", 1, FMT_URL },
{ "style_submenu_element", 2, FMT_URL },
{ "style_submenu_sql", 3, FMT_SQL },
{ "textarea_attribute", 5, FMT_LIT },
{ "tktsetup_generic", 1, FMT_LIT },
{ "webpage_error", 1, FMT_SAFE },
{ "xfersetup_generic", 1, FMT_LIT },
{ "xhref", 2, FMT_URL },
};
/*
** Comparison function for two FmtFunc entries
*/
| > > > | 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 |
{ "fossil_errorlog", 1, FMT_SAFE },
{ "fossil_fatal", 1, FMT_SAFE },
{ "fossil_fatal_recursive", 1, FMT_SAFE },
{ "fossil_panic", 1, FMT_SAFE },
{ "fossil_print", 1, FMT_SAFE },
{ "fossil_trace", 1, FMT_SAFE },
{ "fossil_warning", 1, FMT_SAFE },
{ "gitmirror_message", 2, FMT_SAFE },
{ "href", 1, FMT_URL },
{ "json_new_string_f", 1, FMT_SAFE },
{ "json_set_err", 2, FMT_SAFE },
{ "json_warn", 2, FMT_SAFE },
{ "mprintf", 1, FMT_SAFE },
{ "multiple_choice_attribute", 3, FMT_LIT },
{ "onoff_attribute", 3, FMT_LIT },
{ "pop3_print", 2, FMT_SAFE },
{ "smtp_send_line", 2, FMT_SAFE },
{ "smtp_server_send", 2, FMT_SAFE },
{ "socket_set_errmsg", 1, FMT_SAFE },
{ "ssl_set_errmsg", 1, FMT_SAFE },
{ "style_copy_button", 5, FMT_SAFE },
{ "style_header", 1, FMT_HTML },
{ "style_set_current_page", 1, FMT_URL },
{ "style_submenu_element", 2, FMT_URL },
{ "style_submenu_sql", 3, FMT_SQL },
{ "textarea_attribute", 5, FMT_LIT },
{ "tktsetup_generic", 1, FMT_LIT },
{ "webpage_error", 1, FMT_SAFE },
{ "webpage_notfound_error", 1, FMT_SAFE },
{ "xfersetup_generic", 1, FMT_LIT },
{ "xhref", 2, FMT_URL },
};
/*
** Comparison function for two FmtFunc entries
*/
|
| ︙ | ︙ |
Changes to tools/fslsrv.
1 | #!/bin/bash | < > | > | 1 2 3 4 5 6 7 8 9 10 11 12 13 |
#!/bin/bash
FOSSIL=fossil
PGARGS="-P 1"
OLDPID=`pgrep -P 1 fossil`
SITE=https://example.com
PORT=12345
if [ "$1" = "-f" ] ; then PGARGS= ; shift ; fi
if [ -n "$OLDPID" ]
then
echo "Killing running Fossil server first..."
pkill $PGARGS fossil
|
| ︙ | ︙ | |||
35 36 37 38 39 40 41 |
then
# We're running from a build tree, so use that version instead
FOSSIL=./fossil
fi
function start_one() {
bn=$1
| < | < | > > > > > | | | > | | > | 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
then
# We're running from a build tree, so use that version instead
FOSSIL=./fossil
fi
function start_one() {
bn=$1
ln="$2"
$FOSSIL server $extra \
--scgi \
--localhost \
--port $PORT \
--jsmode bundled \
--baseurl ${SITE}/$bn \
--errorlog ~/log/fossil/$bn-errors.log \
~/museum/$bn.fossil > ~/log/fossil/$bn-stdout.log &
echo Started $ln Fossil server, port $PORT, PID $!.
PORT=$(($PORT + 1))
}
start_one first "First Project"
start_one second "Second Project"
start_one third "Third Project"
|
Changes to tools/makeheaders.c.
| ︙ | ︙ | |||
592 593 594 595 596 597 598 |
int nName /* Length of the name */
){
Decl *pDecl;
pDecl = SafeMalloc( sizeof(Decl) + nName + 1);
memset(pDecl,0,sizeof(Decl));
pDecl->zName = (char*)&pDecl[1];
| > | | 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 |
int nName /* Length of the name */
){
Decl *pDecl;
pDecl = SafeMalloc( sizeof(Decl) + nName + 1);
memset(pDecl,0,sizeof(Decl));
pDecl->zName = (char*)&pDecl[1];
memcpy(pDecl->zName, zName, nName);
pDecl->zName[nName] = 0;
pDecl->zFile = zFilename;
pDecl->pInclude = includeList;
pDecl->zIf = GetIfString();
InstallDecl(pDecl);
return pDecl;
}
|
| ︙ | ︙ | |||
625 626 627 628 629 630 631 |
if( strncmp(zId,pId->zName,nId)==0 && pId->zName[nId]==0 ){
/* printf("Already in table: %.*s\n",nId,zId); */
return 0;
}
}
pId = SafeMalloc( sizeof(Ident) + nId + 1 );
pId->zName = (char*)&pId[1];
| | > | 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 |
if( strncmp(zId,pId->zName,nId)==0 && pId->zName[nId]==0 ){
/* printf("Already in table: %.*s\n",nId,zId); */
return 0;
}
}
pId = SafeMalloc( sizeof(Ident) + nId + 1 );
pId->zName = (char*)&pId[1];
memcpy(pId->zName, zId, nId);
pId->zName[nId] = 0;
pId->pNext = pTable->pList;
pTable->pList = pId;
pId->pCollide = pTable->apTable[h];
pTable->apTable[h] = pId;
/* printf("Add to table: %.*s\n",nId,zId); */
return 1;
}
|
| ︙ | ︙ | |||
2074 2075 2076 2077 2078 2079 2080 |
}
nByte += nText + 1;
}
pIf = SafeMalloc( nByte );
if( zText ){
pIf->zCondition = (char*)&pIf[1];
if( zPrefix ){
| > > | > > > | | 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 |
}
nByte += nText + 1;
}
pIf = SafeMalloc( nByte );
if( zText ){
pIf->zCondition = (char*)&pIf[1];
if( zPrefix ){
int nPrefix = (int)strlen(zPrefix);
memcpy(pIf->zCondition, zPrefix, nPrefix);
pIf->zCondition[nPrefix] = '(';
memcpy(&pIf->zCondition[nPrefix+1], zText, nText);
memcpy(&pIf->zCondition[nPrefix+nText+1], ")", 2);
}else{
memcpy(pIf->zCondition, zText, nText);
pIf->zCondition[nText] = 0;
}
}else{
pIf->zCondition = 0;
}
pIf->nLine = nLine;
pIf->flags = flags;
pIf->pNext = ifStack;
|
| ︙ | ︙ | |||
2152 2153 2154 2155 2156 2157 2158 |
if( *zArg==0 || *zArg=='\n' ){ return 0; }
for(nArg=0; ISALNUM(zArg[nArg]); nArg++){}
if( nArg==0 ){ return 0; }
pDecl = CreateDecl(zArg,nArg);
pDecl->pComment = pToken->pComment;
DeclSetProperty(pDecl,TY_Macro);
pDecl->zDecl = SafeMalloc( pToken->nText + 2 );
| | > | 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 |
if( *zArg==0 || *zArg=='\n' ){ return 0; }
for(nArg=0; ISALNUM(zArg[nArg]); nArg++){}
if( nArg==0 ){ return 0; }
pDecl = CreateDecl(zArg,nArg);
pDecl->pComment = pToken->pComment;
DeclSetProperty(pDecl,TY_Macro);
pDecl->zDecl = SafeMalloc( pToken->nText + 2 );
memcpy(pDecl->zDecl, pToken->zText, pToken->nText);
memcpy(&pDecl->zDecl[pToken->nText], "\n", 2);
if( flags & PS_Export ){
DeclSetProperty(pDecl,DP_Export);
}else if( flags & PS_Local ){
DeclSetProperty(pDecl,DP_Local);
}
}else if( nCmd==7 && strncmp(zCmd,"include",7)==0 ){
/*
|
| ︙ | ︙ | |||
2181 2182 2183 2184 2185 2186 2187 |
return 1;
}
zIf = GetIfString();
if( zIf ){
pInclude = SafeMalloc( sizeof(Include) + nArg*2 + strlen(zIf) + 10 );
pInclude->zFile = (char*)&pInclude[1];
pInclude->zLabel = &pInclude->zFile[nArg+1];
| | > | > > | > | 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 |
return 1;
}
zIf = GetIfString();
if( zIf ){
pInclude = SafeMalloc( sizeof(Include) + nArg*2 + strlen(zIf) + 10 );
pInclude->zFile = (char*)&pInclude[1];
pInclude->zLabel = &pInclude->zFile[nArg+1];
memcpy(pInclude->zFile, zArg, nArg);
pInclude->zFile[nArg] = 0;
memcpy(pInclude->zLabel, zArg, nArg);
pInclude->zLabel[nArg] = ':';
memcpy(&pInclude->zLabel[nArg+1], zIf, strlen(zIf)+1);
pInclude->zIf = &pInclude->zLabel[nArg+1];
SafeFree(zIf);
}else{
pInclude = SafeMalloc( sizeof(Include) + nArg + 1 );
pInclude->zFile = (char*)&pInclude[1];
memcpy(pInclude->zFile, zArg, nArg);
pInclude->zFile[nArg] = 0;
pInclude->zIf = 0;
pInclude->zLabel = pInclude->zFile;
}
pInclude->pNext = includeList;
includeList = pInclude;
}else if( nCmd==2 && strncmp(zCmd,"if",2)==0 ){
/*
|
| ︙ | ︙ |
Changes to tools/makemake.tcl.
| ︙ | ︙ | |||
244 245 246 247 248 249 250 251 252 253 254 255 256 257 | -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_DBSTAT_VTAB -DSQLITE_ENABLE_FTS5 -DSQLITE_ENABLE_STMTVTAB -DSQLITE_HAVE_ZLIB -DSQLITE_ENABLE_DBPAGE_VTAB -DSQLITE_TRUSTED_SCHEMA=0 } #lappend SQLITE_OPTIONS -DSQLITE_ENABLE_FTS3=1 #lappend SQLITE_OPTIONS -DSQLITE_ENABLE_STAT4 #lappend SQLITE_OPTIONS -DSQLITE_WIN32_NO_ANSI #lappend SQLITE_OPTIONS -DSQLITE_WINNT_MAX_PATH_CHARS=4096 # Options used to compile the Pikchr library. | > | 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 | -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_DBSTAT_VTAB -DSQLITE_ENABLE_FTS5 -DSQLITE_ENABLE_STMTVTAB -DSQLITE_HAVE_ZLIB -DSQLITE_ENABLE_DBPAGE_VTAB -DSQLITE_TRUSTED_SCHEMA=0 -DHAVE_USLEEP } #lappend SQLITE_OPTIONS -DSQLITE_ENABLE_FTS3=1 #lappend SQLITE_OPTIONS -DSQLITE_ENABLE_STAT4 #lappend SQLITE_OPTIONS -DSQLITE_WIN32_NO_ANSI #lappend SQLITE_OPTIONS -DSQLITE_WINNT_MAX_PATH_CHARS=4096 # Options used to compile the Pikchr library. |
| ︙ | ︙ | |||
553 554 555 556 557 558 559 | writeln "\$(OBJDIR)/th_lang.o:\t\$(SRCDIR)/th_lang.c" writeln "\t\$(XTCC) -c \$(SRCDIR)/th_lang.c -o \$@\n" writeln "\$(OBJDIR)/th_tcl.o:\t\$(SRCDIR)/th_tcl.c" writeln "\t\$(XTCC) -c \$(SRCDIR)/th_tcl.c -o \$@\n" | | | | | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | 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 |
writeln "\$(OBJDIR)/th_lang.o:\t\$(SRCDIR)/th_lang.c"
writeln "\t\$(XTCC) -c \$(SRCDIR)/th_lang.c -o \$@\n"
writeln "\$(OBJDIR)/th_tcl.o:\t\$(SRCDIR)/th_tcl.c"
writeln "\t\$(XTCC) -c \$(SRCDIR)/th_tcl.c -o \$@\n"
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
$(EMCC_WRAPPER) -o $@ $(EMCC_OPT) --no-entry <<<NEXT_LINE>>>
-sEXPORTED_RUNTIME_METHODS=cwrap,setValue,getValue,stackSave,stackRestore <<<NEXT_LINE>>>
-sEXPORTED_FUNCTIONS=_pikchr $(SRCDIR_extsrc)/pikchr.c <<<NEXT_LINE>>>
-sENVIRONMENT=web <<<NEXT_LINE>>>
-sMODULARIZE <<<NEXT_LINE>>>
-sEXPORT_NAME=initPikchrModule <<<NEXT_LINE>>>
--minify 0
@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
# tools, as those compile with BCC, which may differ from TCC.
# e.g. BCC might be gcc (which does not support -MJ ...) while TCC is
# clang (which does).
#
# What follows is more verbose than strictly necessary because we're
# limited to POSIX make syntax.
all:
compile-commands-dir.yes = $(OBJDIR)
compile-commands-dir.no =
compile-commands-dir = $(compile-commands-dir.$(MAKE_COMPILATION_DB))
compile-command-args.yes = -MJ $(TOPDIR)/$(compile-commands-dir)/$(@F:.o=.o.json)
compile-command-args.no =
TCCFLAGS += $(compile-command-args.$(MAKE_COMPILATION_DB))
compile_commands.json = $(TOPDIR)/compile_commands.json
# compile_commands.json is a concatenation of the .o.json files
# generated by the compilation process via TCCFLAGS. We have a
# potential race condition in parallel builds, where a .o.json file is
# not yet written to completion before compile_commands.json is
# processed. How to resolve that in a way compatible with POSIX make
# is unclear.
#
# This obscure sed bit ensures that the resulting JSON array does not
# have a trailing comma.
$(compile_commands.json): $(OBJ)
@-rm -f $@
@{ echo '['; cat $(compile-commands-dir)/*.o.json | tr '\n' ' ' | sed -e 's/, $$//'; echo ']'; } > $@
@echo "Generated $@"
compile-commands.no:
compile-commands.yes: $(compile_commands.json)
all: compile-commands.$(MAKE_COMPILATION_DB)
clean: compile-commands-clean
compile-commands-clean:
rm -fr $(compile_commands.json)
#
# End compile_commands.json support
#
#
# The list of all the targets that do not correspond to real files. This stops
# 'make' from getting confused when someone makes an error in a rule.
#
.PHONY: all install test clean
.PHONY: compile-commands-clean compile-commands-dir
}]
close $output_file
#
# End of the main.mk output
##############################################################################
##############################################################################
##############################################################################
|
| ︙ | ︙ | |||
733 734 735 736 737 738 739 | #### Determine if the optimized assembly routines provided with zlib should be # used, taking into account whether zlib is actually enabled and the target # processor architecture. # ifndef X64 SSLCONFIG = mingw | | | | 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 | #### Determine if the optimized assembly routines provided with zlib should be # used, taking into account whether zlib is actually enabled and the target # processor architecture. # ifndef X64 SSLCONFIG = mingw ZLIBCONFIG = ZLIBTARGETS = else SSLCONFIG = mingw64 ZLIBCONFIG = ZLIBTARGETS = endif #### Disable creation of the OpenSSL shared libraries. Also, disable support |
| ︙ | ︙ | |||
1161 1162 1163 1164 1165 1166 1167 |
$(OBJDIR)/th.o <<<NEXT_LINE>>>
$(OBJDIR)/th_lang.o <<<NEXT_LINE>>>
$(OBJDIR)/th_tcl.o <<<NEXT_LINE>>>
$(OBJDIR)/cson_amalgamation.o
}]
writeln {
| < < < < < < | 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 |
$(OBJDIR)/th.o <<<NEXT_LINE>>>
$(OBJDIR)/th_lang.o <<<NEXT_LINE>>>
$(OBJDIR)/th_tcl.o <<<NEXT_LINE>>>
$(OBJDIR)/cson_amalgamation.o
}]
writeln {
zlib: $(ZLIBTARGETS)
$(MAKE) -C $(ZLIBDIR) PREFIX=$(PREFIX) CC=$(PREFIX)$(TCCEXE) $(ZLIBCONFIG) -f win32/Makefile.gcc libz.a
clean-zlib:
$(MAKE) -C $(ZLIBDIR) PREFIX=$(PREFIX) CC=$(PREFIX)$(TCCEXE) -f win32/Makefile.gcc clean
BLDTARGETS = zlib
|
| ︙ | ︙ | |||
2052 2053 2054 2055 2056 2057 2058 2059 2060 |
writeln {"$(OX)\builtin_data.reslist": $(EXTRA_FILES) "$(B)\win\Makefile.msc"}
set redir {>}
foreach s [lsort $extra_files] {
writeln "\techo \"\$(SRCDIR)\\${s}\" $redir \$@"
set redir {>>}
}
writeln ""
foreach s [lsort $src] {
| > > > > > > | | 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 |
writeln {"$(OX)\builtin_data.reslist": $(EXTRA_FILES) "$(B)\win\Makefile.msc"}
set redir {>}
foreach s [lsort $extra_files] {
writeln "\techo \"\$(SRCDIR)\\${s}\" $redir \$@"
set redir {>>}
}
foreach s [lsort $src] {
set extra_h($s) {}
}
set extra_h(builtin) " \"\$(OX)\\builtin_data.h\""
set extra_h(dispatch) " \"\$(OX)\\page_index.h\""
writeln ""
foreach s [lsort $src] {
writeln "\"\$(OX)\\$s\$O\" : \"\$(OX)\\${s}_.c\" \"\$(OX)\\${s}.h\"$extra_h($s)"
writeln "\t\$(TCC) /Fo\$@ /Fd\$(@D)\\ -c \"\$(OX)\\${s}_.c\"\n"
writeln "\"\$(OX)\\${s}_.c\" : \"\$(SRCDIR)\\$s.c\""
writeln "\t\"\$(OBJDIR)\\translate\$E\" \$** > \$@\n"
}
writeln "\"\$(OX)\\fossil.res\" : \"\$(B)\\win\\fossil.rc\""
writeln "\t\$(RCC) /fo \$@ \$**\n"
|
| ︙ | ︙ |
Changes to tools/mkindex.c.
| ︙ | ︙ | |||
57 58 59 60 61 62 63 64 65 66 67 68 69 70 | ** SETTING: auto-shun boolean default=on ** ** New arguments may be added in future releases that set additional ** bits in the eCmdFlags field. ** ** Additional lines of comment after the COMMAND: or WEBPAGE: or SETTING: ** become the built-in help text for that command or webpage or setting. ** ** Multiple COMMAND: entries can be attached to the same command, thus ** creating multiple aliases for that command. Similarly, multiple ** WEBPAGE: entries can be attached to the same webpage function, to give ** that page aliases. ** ** For SETTING: entries, the default value for the setting can be specified | > | 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
** SETTING: auto-shun boolean default=on
**
** New arguments may be added in future releases that set additional
** bits in the eCmdFlags field.
**
** Additional lines of comment after the COMMAND: or WEBPAGE: or SETTING:
** become the built-in help text for that command or webpage or setting.
** Backslashes must be escaped ("\\" in comment yields "\" in the help text.)
**
** Multiple COMMAND: entries can be attached to the same command, thus
** creating multiple aliases for that command. Similarly, multiple
** WEBPAGE: entries can be attached to the same webpage function, to give
** that page aliases.
**
** For SETTING: entries, the default value for the setting can be specified
|
| ︙ | ︙ | |||
96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
#define CMDFLAG_BLOCKTEXT 0x0080 /* Multi-line text setting */
#define CMDFLAG_BOOLEAN 0x0100 /* A boolean setting */
#define CMDFLAG_RAWCONTENT 0x0200 /* Do not interpret webpage content */
#define CMDFLAG_SENSITIVE 0x0400 /* Security-sensitive setting */
#define CMDFLAG_HIDDEN 0x0800 /* Elide from most listings */
#define CMDFLAG_LDAVG_EXEMPT 0x1000 /* Exempt from load_control() */
#define CMDFLAG_ALIAS 0x2000 /* Command aliases */
/**************************************************************************/
/*
** Each entry looks like this:
*/
typedef struct Entry {
int eType; /* CMDFLAG_* values */
| > | 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 |
#define CMDFLAG_BLOCKTEXT 0x0080 /* Multi-line text setting */
#define CMDFLAG_BOOLEAN 0x0100 /* A boolean setting */
#define CMDFLAG_RAWCONTENT 0x0200 /* Do not interpret webpage content */
#define CMDFLAG_SENSITIVE 0x0400 /* Security-sensitive setting */
#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 */
/**************************************************************************/
/*
** Each entry looks like this:
*/
typedef struct Entry {
int eType; /* CMDFLAG_* values */
|
| ︙ | ︙ | |||
260 261 262 263 264 265 266 267 268 269 270 271 272 273 |
}else if( j==7 && strncmp(&zLine[i], "boolean", j)==0 ){
aEntry[nUsed].eType &= ~(CMDFLAG_BLOCKTEXT);
aEntry[nUsed].iWidth = 0;
aEntry[nUsed].eType |= CMDFLAG_BOOLEAN;
}else if( j==10 && strncmp(&zLine[i], "block-text", j)==0 ){
aEntry[nUsed].eType &= ~(CMDFLAG_BOOLEAN);
aEntry[nUsed].eType |= CMDFLAG_BLOCKTEXT;
}else if( j==11 && strncmp(&zLine[i], "versionable", j)==0 ){
aEntry[nUsed].eType |= CMDFLAG_VERSIONABLE;
}else if( j==9 && strncmp(&zLine[i], "sensitive", j)==0 ){
aEntry[nUsed].eType |= CMDFLAG_SENSITIVE;
}else if( j>6 && strncmp(&zLine[i], "width=", 6)==0 ){
aEntry[nUsed].iWidth = atoi(&zLine[i+6]);
}else if( j>8 && strncmp(&zLine[i], "default=", 8)==0 ){
| > > | 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 |
}else if( j==7 && strncmp(&zLine[i], "boolean", j)==0 ){
aEntry[nUsed].eType &= ~(CMDFLAG_BLOCKTEXT);
aEntry[nUsed].iWidth = 0;
aEntry[nUsed].eType |= CMDFLAG_BOOLEAN;
}else if( j==10 && strncmp(&zLine[i], "block-text", j)==0 ){
aEntry[nUsed].eType &= ~(CMDFLAG_BOOLEAN);
aEntry[nUsed].eType |= CMDFLAG_BLOCKTEXT;
}else if( j==10 && strncmp(&zLine[i], "keep-empty", j)==0 ){
aEntry[nUsed].eType |= CMDFLAG_KEEPEMPTY;
}else if( j==11 && strncmp(&zLine[i], "versionable", j)==0 ){
aEntry[nUsed].eType |= CMDFLAG_VERSIONABLE;
}else if( j==9 && strncmp(&zLine[i], "sensitive", j)==0 ){
aEntry[nUsed].eType |= CMDFLAG_SENSITIVE;
}else if( j>6 && strncmp(&zLine[i], "width=", 6)==0 ){
aEntry[nUsed].iWidth = atoi(&zLine[i+6]);
}else if( j>8 && strncmp(&zLine[i], "default=", 8)==0 ){
|
| ︙ | ︙ | |||
512 513 514 515 516 517 518 |
(aEntry[i].eType & CMDFLAG_SENSITIVE)!=0,
zDef, (int)(10-strlen(zDef)), ""
);
if( aEntry[i].zIf ){
printf("#endif\n");
}
}
| | | 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 |
(aEntry[i].eType & CMDFLAG_SENSITIVE)!=0,
zDef, (int)(10-strlen(zDef)), ""
);
if( aEntry[i].zIf ){
printf("#endif\n");
}
}
printf("{0,0,0,0,0,0,0}};\n");
}
/*
** Process a single file of input
*/
void process_file(void){
|
| ︙ | ︙ |
Changes to tools/mkversion.c.
| ︙ | ︙ | |||
111 112 113 114 115 116 117 |
*z = 0;
printf("#define MANIFEST_UUID \"%s\"\n",b);
printf("#define MANIFEST_VERSION \"[%10.10s]\"\n",b);
n = strlen(b);
if( n + 50 < sizeof(b) ){
#ifdef FOSSIL_BUILD_EPOCH
#define str(s) #s
| > | | | | 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 |
*z = 0;
printf("#define MANIFEST_UUID \"%s\"\n",b);
printf("#define MANIFEST_VERSION \"[%10.10s]\"\n",b);
n = strlen(b);
if( n + 50 < sizeof(b) ){
#ifdef FOSSIL_BUILD_EPOCH
#define str(s) #s
snprintf(b+n, sizeof(b)-n,
"%d", (int)strtoll(str(FOSSIL_BUILD_EPOCH), 0, 10));
#else
const char *zEpoch = getenv("SOURCE_DATE_EPOCH");
if( zEpoch && isdigit(zEpoch[0]) ){
snprintf(b+n, sizeof(b)-n, "%d", (int)strtoll(zEpoch, 0, 10));
}else{
snprintf(b+n, sizeof(b)-n, "%d", (int)time(0));
}
#endif
hash(b,33,vx);
printf("#define FOSSIL_BUILD_HASH \"%s\"\n", vx);
}
m = open_for_reading(argv[2]);
while(b == fgets(b, sizeof(b)-1,m)){
|
| ︙ | ︙ |
Changes to win/Makefile.dmc.
| ︙ | ︙ | |||
24 25 26 27 28 29 30 | SSL = CFLAGS = -o BCC = $(DMDIR)\bin\dmc $(CFLAGS) TCC = $(DMDIR)\bin\dmc $(CFLAGS) $(DMCDEF) $(SSL) $(INCL) LIBS = $(DMDIR)\extra\lib\ zlib wsock32 advapi32 dnsapi | | | | 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | SSL = CFLAGS = -o BCC = $(DMDIR)\bin\dmc $(CFLAGS) TCC = $(DMDIR)\bin\dmc $(CFLAGS) $(DMCDEF) $(SSL) $(INCL) LIBS = $(DMDIR)\extra\lib\ zlib wsock32 advapi32 dnsapi SQLITE_OPTIONS = -DNDEBUG=1 -DSQLITE_DQS=0 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_MEMSTATUS=0 -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 -DSQLITE_LIKE_DOESNT_MATCH_BLOBS -DSQLITE_OMIT_DECLTYPE -DSQLITE_OMIT_DEPRECATED -DSQLITE_OMIT_PROGRESS_CALLBACK -DSQLITE_OMIT_SHARED_CACHE -DSQLITE_OMIT_LOAD_EXTENSION -DSQLITE_MAX_EXPR_DEPTH=0 -DSQLITE_ENABLE_LOCKING_STYLE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_DBSTAT_VTAB -DSQLITE_ENABLE_FTS5 -DSQLITE_ENABLE_STMTVTAB -DSQLITE_HAVE_ZLIB -DSQLITE_ENABLE_DBPAGE_VTAB -DSQLITE_TRUSTED_SCHEMA=0 -DHAVE_USLEEP SHELL_OPTIONS = -DNDEBUG=1 -DSQLITE_DQS=0 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_MEMSTATUS=0 -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 -DSQLITE_LIKE_DOESNT_MATCH_BLOBS -DSQLITE_OMIT_DECLTYPE -DSQLITE_OMIT_DEPRECATED -DSQLITE_OMIT_PROGRESS_CALLBACK -DSQLITE_OMIT_SHARED_CACHE -DSQLITE_OMIT_LOAD_EXTENSION -DSQLITE_MAX_EXPR_DEPTH=0 -DSQLITE_ENABLE_LOCKING_STYLE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_DBSTAT_VTAB -DSQLITE_ENABLE_FTS5 -DSQLITE_ENABLE_STMTVTAB -DSQLITE_HAVE_ZLIB -DSQLITE_ENABLE_DBPAGE_VTAB -DSQLITE_TRUSTED_SCHEMA=0 -DHAVE_USLEEP -Dmain=sqlite3_shell -DSQLITE_SHELL_IS_UTF8=1 -DSQLITE_OMIT_LOAD_EXTENSION=1 -DUSE_SYSTEM_SQLITE=$(USE_SYSTEM_SQLITE) -DSQLITE_SHELL_DBNAME_PROC=sqlcmd_get_dbname -DSQLITE_SHELL_INIT_PROC=sqlcmd_init_proc -Daccess=file_access -Dsystem=fossil_system -Dgetenv=fossil_getenv -Dfopen=fossil_fopen PIKCHR_OPTIONS = -DPIKCHR_TOKEN_LIMIT=10000 SRC = add_.c ajax_.c alerts_.c allrepo_.c attach_.c backlink_.c backoffice_.c bag_.c bisect_.c blob_.c branch_.c browse_.c builtin_.c bundle_.c cache_.c capabilities_.c captcha_.c cgi_.c chat_.c checkin_.c checkout_.c clearsign_.c clone_.c color_.c comformat_.c configure_.c content_.c cookies_.c db_.c delta_.c deltacmd_.c deltafunc_.c descendants_.c diff_.c diffcmd_.c dispatch_.c doc_.c encode_.c etag_.c event_.c export_.c extcgi_.c file_.c fileedit_.c finfo_.c foci_.c forum_.c fshell_.c fusefs_.c fuzz_.c glob_.c graph_.c gzip_.c hname_.c hook_.c http_.c http_socket_.c http_ssl_.c http_transport_.c import_.c info_.c interwiki_.c json_.c json_artifact_.c json_branch_.c json_config_.c json_diff_.c json_dir_.c json_finfo_.c json_login_.c json_query_.c json_report_.c json_status_.c json_tag_.c json_timeline_.c json_user_.c json_wiki_.c leaf_.c loadctrl_.c login_.c lookslike_.c main_.c manifest_.c markdown_.c markdown_html_.c md5_.c merge_.c merge3_.c moderate_.c name_.c patch_.c path_.c piechart_.c pikchrshow_.c pivot_.c popen_.c pqueue_.c printf_.c publish_.c purge_.c rebuild_.c regexp_.c repolist_.c report_.c rss_.c schema_.c search_.c security_audit_.c setup_.c setupuser_.c sha1_.c sha1hard_.c sha3_.c shun_.c sitemap_.c skins_.c smtp_.c sqlcmd_.c stash_.c stat_.c statrep_.c style_.c sync_.c tag_.c tar_.c terminal_.c th_main_.c timeline_.c tkt_.c tktsetup_.c undo_.c unicode_.c unversioned_.c update_.c url_.c user_.c utf8_.c util_.c verify_.c vfile_.c wiki_.c wikiformat_.c winfile_.c winhttp_.c xfer_.c xfersetup_.c zip_.c OBJ = $(OBJDIR)\add$O $(OBJDIR)\ajax$O $(OBJDIR)\alerts$O $(OBJDIR)\allrepo$O $(OBJDIR)\attach$O $(OBJDIR)\backlink$O $(OBJDIR)\backoffice$O $(OBJDIR)\bag$O $(OBJDIR)\bisect$O $(OBJDIR)\blob$O $(OBJDIR)\branch$O $(OBJDIR)\browse$O $(OBJDIR)\builtin$O $(OBJDIR)\bundle$O $(OBJDIR)\cache$O $(OBJDIR)\capabilities$O $(OBJDIR)\captcha$O $(OBJDIR)\cgi$O $(OBJDIR)\chat$O $(OBJDIR)\checkin$O $(OBJDIR)\checkout$O $(OBJDIR)\clearsign$O $(OBJDIR)\clone$O $(OBJDIR)\color$O $(OBJDIR)\comformat$O $(OBJDIR)\configure$O $(OBJDIR)\content$O $(OBJDIR)\cookies$O $(OBJDIR)\db$O $(OBJDIR)\delta$O $(OBJDIR)\deltacmd$O $(OBJDIR)\deltafunc$O $(OBJDIR)\descendants$O $(OBJDIR)\diff$O $(OBJDIR)\diffcmd$O $(OBJDIR)\dispatch$O $(OBJDIR)\doc$O $(OBJDIR)\encode$O $(OBJDIR)\etag$O $(OBJDIR)\event$O $(OBJDIR)\export$O $(OBJDIR)\extcgi$O $(OBJDIR)\file$O $(OBJDIR)\fileedit$O $(OBJDIR)\finfo$O $(OBJDIR)\foci$O $(OBJDIR)\forum$O $(OBJDIR)\fshell$O $(OBJDIR)\fusefs$O $(OBJDIR)\fuzz$O $(OBJDIR)\glob$O $(OBJDIR)\graph$O $(OBJDIR)\gzip$O $(OBJDIR)\hname$O $(OBJDIR)\hook$O $(OBJDIR)\http$O $(OBJDIR)\http_socket$O $(OBJDIR)\http_ssl$O $(OBJDIR)\http_transport$O $(OBJDIR)\import$O $(OBJDIR)\info$O $(OBJDIR)\interwiki$O $(OBJDIR)\json$O $(OBJDIR)\json_artifact$O $(OBJDIR)\json_branch$O $(OBJDIR)\json_config$O $(OBJDIR)\json_diff$O $(OBJDIR)\json_dir$O $(OBJDIR)\json_finfo$O $(OBJDIR)\json_login$O $(OBJDIR)\json_query$O $(OBJDIR)\json_report$O $(OBJDIR)\json_status$O $(OBJDIR)\json_tag$O $(OBJDIR)\json_timeline$O $(OBJDIR)\json_user$O $(OBJDIR)\json_wiki$O $(OBJDIR)\leaf$O $(OBJDIR)\loadctrl$O $(OBJDIR)\login$O $(OBJDIR)\lookslike$O $(OBJDIR)\main$O $(OBJDIR)\manifest$O $(OBJDIR)\markdown$O $(OBJDIR)\markdown_html$O $(OBJDIR)\md5$O $(OBJDIR)\merge$O $(OBJDIR)\merge3$O $(OBJDIR)\moderate$O $(OBJDIR)\name$O $(OBJDIR)\patch$O $(OBJDIR)\path$O $(OBJDIR)\piechart$O $(OBJDIR)\pikchrshow$O $(OBJDIR)\pivot$O $(OBJDIR)\popen$O $(OBJDIR)\pqueue$O $(OBJDIR)\printf$O $(OBJDIR)\publish$O $(OBJDIR)\purge$O $(OBJDIR)\rebuild$O $(OBJDIR)\regexp$O $(OBJDIR)\repolist$O $(OBJDIR)\report$O $(OBJDIR)\rss$O $(OBJDIR)\schema$O $(OBJDIR)\search$O $(OBJDIR)\security_audit$O $(OBJDIR)\setup$O $(OBJDIR)\setupuser$O $(OBJDIR)\sha1$O $(OBJDIR)\sha1hard$O $(OBJDIR)\sha3$O $(OBJDIR)\shun$O $(OBJDIR)\sitemap$O $(OBJDIR)\skins$O $(OBJDIR)\smtp$O $(OBJDIR)\sqlcmd$O $(OBJDIR)\stash$O $(OBJDIR)\stat$O $(OBJDIR)\statrep$O $(OBJDIR)\style$O $(OBJDIR)\sync$O $(OBJDIR)\tag$O $(OBJDIR)\tar$O $(OBJDIR)\terminal$O $(OBJDIR)\th_main$O $(OBJDIR)\timeline$O $(OBJDIR)\tkt$O $(OBJDIR)\tktsetup$O $(OBJDIR)\undo$O $(OBJDIR)\unicode$O $(OBJDIR)\unversioned$O $(OBJDIR)\update$O $(OBJDIR)\url$O $(OBJDIR)\user$O $(OBJDIR)\utf8$O $(OBJDIR)\util$O $(OBJDIR)\verify$O $(OBJDIR)\vfile$O $(OBJDIR)\wiki$O $(OBJDIR)\wikiformat$O $(OBJDIR)\winfile$O $(OBJDIR)\winhttp$O $(OBJDIR)\xfer$O $(OBJDIR)\xfersetup$O $(OBJDIR)\zip$O $(OBJDIR)\shell$O $(OBJDIR)\sqlite3$O $(OBJDIR)\th$O $(OBJDIR)\th_lang$O |
| ︙ | ︙ |
Changes to win/Makefile.mingw.
| ︙ | ︙ | |||
136 137 138 139 140 141 142 | #### Determine if the optimized assembly routines provided with zlib should be # used, taking into account whether zlib is actually enabled and the target # processor architecture. # ifndef X64 SSLCONFIG = mingw | | | | 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 | #### Determine if the optimized assembly routines provided with zlib should be # used, taking into account whether zlib is actually enabled and the target # processor architecture. # ifndef X64 SSLCONFIG = mingw ZLIBCONFIG = ZLIBTARGETS = else SSLCONFIG = mingw64 ZLIBCONFIG = ZLIBTARGETS = endif #### Disable creation of the OpenSSL shared libraries. Also, disable support |
| ︙ | ︙ | |||
563 564 565 566 567 568 569 | $(SRCDIR)/../skins/black_and_white/footer.txt \ $(SRCDIR)/../skins/black_and_white/header.txt \ $(SRCDIR)/../skins/blitz/css.txt \ $(SRCDIR)/../skins/blitz/details.txt \ $(SRCDIR)/../skins/blitz/footer.txt \ $(SRCDIR)/../skins/blitz/header.txt \ $(SRCDIR)/../skins/blitz/ticket.txt \ | < < < < | 563 564 565 566 567 568 569 570 571 572 573 574 575 576 | $(SRCDIR)/../skins/black_and_white/footer.txt \ $(SRCDIR)/../skins/black_and_white/header.txt \ $(SRCDIR)/../skins/blitz/css.txt \ $(SRCDIR)/../skins/blitz/details.txt \ $(SRCDIR)/../skins/blitz/footer.txt \ $(SRCDIR)/../skins/blitz/header.txt \ $(SRCDIR)/../skins/blitz/ticket.txt \ $(SRCDIR)/../skins/darkmode/css.txt \ $(SRCDIR)/../skins/darkmode/details.txt \ $(SRCDIR)/../skins/darkmode/footer.txt \ $(SRCDIR)/../skins/darkmode/header.txt \ $(SRCDIR)/../skins/default/css.txt \ $(SRCDIR)/../skins/default/details.txt \ $(SRCDIR)/../skins/default/footer.txt \ |
| ︙ | ︙ | |||
1102 1103 1104 1105 1106 1107 1108 | $(OBJDIR)/shell.o \ $(OBJDIR)/th.o \ $(OBJDIR)/th_lang.o \ $(OBJDIR)/th_tcl.o \ $(OBJDIR)/cson_amalgamation.o | < < < < < < | 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 | $(OBJDIR)/shell.o \ $(OBJDIR)/th.o \ $(OBJDIR)/th_lang.o \ $(OBJDIR)/th_tcl.o \ $(OBJDIR)/cson_amalgamation.o zlib: $(ZLIBTARGETS) $(MAKE) -C $(ZLIBDIR) PREFIX=$(PREFIX) CC=$(PREFIX)$(TCCEXE) $(ZLIBCONFIG) -f win32/Makefile.gcc libz.a clean-zlib: $(MAKE) -C $(ZLIBDIR) PREFIX=$(PREFIX) CC=$(PREFIX)$(TCCEXE) -f win32/Makefile.gcc clean BLDTARGETS = zlib |
| ︙ | ︙ | |||
2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 |
-DSQLITE_ENABLE_FTS4 \
-DSQLITE_ENABLE_DBSTAT_VTAB \
-DSQLITE_ENABLE_FTS5 \
-DSQLITE_ENABLE_STMTVTAB \
-DSQLITE_HAVE_ZLIB \
-DSQLITE_ENABLE_DBPAGE_VTAB \
-DSQLITE_TRUSTED_SCHEMA=0 \
-DSQLITE_WIN32_NO_ANSI \
$(MINGW_OPTIONS) \
-DSQLITE_USE_MALLOC_H \
-DSQLITE_USE_MSIZE
SHELL_OPTIONS = -DNDEBUG=1 \
-DSQLITE_DQS=0 \
| > | 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 |
-DSQLITE_ENABLE_FTS4 \
-DSQLITE_ENABLE_DBSTAT_VTAB \
-DSQLITE_ENABLE_FTS5 \
-DSQLITE_ENABLE_STMTVTAB \
-DSQLITE_HAVE_ZLIB \
-DSQLITE_ENABLE_DBPAGE_VTAB \
-DSQLITE_TRUSTED_SCHEMA=0 \
-DHAVE_USLEEP \
-DSQLITE_WIN32_NO_ANSI \
$(MINGW_OPTIONS) \
-DSQLITE_USE_MALLOC_H \
-DSQLITE_USE_MSIZE
SHELL_OPTIONS = -DNDEBUG=1 \
-DSQLITE_DQS=0 \
|
| ︙ | ︙ | |||
2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 |
-DSQLITE_ENABLE_FTS4 \
-DSQLITE_ENABLE_DBSTAT_VTAB \
-DSQLITE_ENABLE_FTS5 \
-DSQLITE_ENABLE_STMTVTAB \
-DSQLITE_HAVE_ZLIB \
-DSQLITE_ENABLE_DBPAGE_VTAB \
-DSQLITE_TRUSTED_SCHEMA=0 \
-Dmain=sqlite3_shell \
-DSQLITE_SHELL_IS_UTF8=1 \
-DSQLITE_OMIT_LOAD_EXTENSION=1 \
-DUSE_SYSTEM_SQLITE=$(USE_SYSTEM_SQLITE) \
-DSQLITE_SHELL_DBNAME_PROC=sqlcmd_get_dbname \
-DSQLITE_SHELL_INIT_PROC=sqlcmd_init_proc \
-Daccess=file_access \
| > | 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 |
-DSQLITE_ENABLE_FTS4 \
-DSQLITE_ENABLE_DBSTAT_VTAB \
-DSQLITE_ENABLE_FTS5 \
-DSQLITE_ENABLE_STMTVTAB \
-DSQLITE_HAVE_ZLIB \
-DSQLITE_ENABLE_DBPAGE_VTAB \
-DSQLITE_TRUSTED_SCHEMA=0 \
-DHAVE_USLEEP \
-Dmain=sqlite3_shell \
-DSQLITE_SHELL_IS_UTF8=1 \
-DSQLITE_OMIT_LOAD_EXTENSION=1 \
-DUSE_SYSTEM_SQLITE=$(USE_SYSTEM_SQLITE) \
-DSQLITE_SHELL_DBNAME_PROC=sqlcmd_get_dbname \
-DSQLITE_SHELL_INIT_PROC=sqlcmd_init_proc \
-Daccess=file_access \
|
| ︙ | ︙ |
Changes to win/Makefile.mingw.mistachkin.
| ︙ | ︙ | |||
136 137 138 139 140 141 142 | #### Determine if the optimized assembly routines provided with zlib should be # used, taking into account whether zlib is actually enabled and the target # processor architecture. # ifndef X64 SSLCONFIG = mingw | | | | 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 | #### Determine if the optimized assembly routines provided with zlib should be # used, taking into account whether zlib is actually enabled and the target # processor architecture. # ifndef X64 SSLCONFIG = mingw ZLIBCONFIG = ZLIBTARGETS = else SSLCONFIG = mingw64 ZLIBCONFIG = ZLIBTARGETS = endif #### Disable creation of the OpenSSL shared libraries. Also, disable support |
| ︙ | ︙ | |||
563 564 565 566 567 568 569 | $(SRCDIR)/../skins/black_and_white/footer.txt \ $(SRCDIR)/../skins/black_and_white/header.txt \ $(SRCDIR)/../skins/blitz/css.txt \ $(SRCDIR)/../skins/blitz/details.txt \ $(SRCDIR)/../skins/blitz/footer.txt \ $(SRCDIR)/../skins/blitz/header.txt \ $(SRCDIR)/../skins/blitz/ticket.txt \ | < < < < | 563 564 565 566 567 568 569 570 571 572 573 574 575 576 | $(SRCDIR)/../skins/black_and_white/footer.txt \ $(SRCDIR)/../skins/black_and_white/header.txt \ $(SRCDIR)/../skins/blitz/css.txt \ $(SRCDIR)/../skins/blitz/details.txt \ $(SRCDIR)/../skins/blitz/footer.txt \ $(SRCDIR)/../skins/blitz/header.txt \ $(SRCDIR)/../skins/blitz/ticket.txt \ $(SRCDIR)/../skins/darkmode/css.txt \ $(SRCDIR)/../skins/darkmode/details.txt \ $(SRCDIR)/../skins/darkmode/footer.txt \ $(SRCDIR)/../skins/darkmode/header.txt \ $(SRCDIR)/../skins/default/css.txt \ $(SRCDIR)/../skins/default/details.txt \ $(SRCDIR)/../skins/default/footer.txt \ |
| ︙ | ︙ | |||
1102 1103 1104 1105 1106 1107 1108 | $(OBJDIR)/shell.o \ $(OBJDIR)/th.o \ $(OBJDIR)/th_lang.o \ $(OBJDIR)/th_tcl.o \ $(OBJDIR)/cson_amalgamation.o | < < < < < < | 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 | $(OBJDIR)/shell.o \ $(OBJDIR)/th.o \ $(OBJDIR)/th_lang.o \ $(OBJDIR)/th_tcl.o \ $(OBJDIR)/cson_amalgamation.o zlib: $(ZLIBTARGETS) $(MAKE) -C $(ZLIBDIR) PREFIX=$(PREFIX) CC=$(PREFIX)$(TCCEXE) $(ZLIBCONFIG) -f win32/Makefile.gcc libz.a clean-zlib: $(MAKE) -C $(ZLIBDIR) PREFIX=$(PREFIX) CC=$(PREFIX)$(TCCEXE) -f win32/Makefile.gcc clean BLDTARGETS = zlib |
| ︙ | ︙ | |||
2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 |
-DSQLITE_ENABLE_FTS4 \
-DSQLITE_ENABLE_DBSTAT_VTAB \
-DSQLITE_ENABLE_FTS5 \
-DSQLITE_ENABLE_STMTVTAB \
-DSQLITE_HAVE_ZLIB \
-DSQLITE_ENABLE_DBPAGE_VTAB \
-DSQLITE_TRUSTED_SCHEMA=0 \
-DSQLITE_WIN32_NO_ANSI \
$(MINGW_OPTIONS) \
-DSQLITE_USE_MALLOC_H \
-DSQLITE_USE_MSIZE
SHELL_OPTIONS = -DNDEBUG=1 \
-DSQLITE_DQS=0 \
| > | 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 |
-DSQLITE_ENABLE_FTS4 \
-DSQLITE_ENABLE_DBSTAT_VTAB \
-DSQLITE_ENABLE_FTS5 \
-DSQLITE_ENABLE_STMTVTAB \
-DSQLITE_HAVE_ZLIB \
-DSQLITE_ENABLE_DBPAGE_VTAB \
-DSQLITE_TRUSTED_SCHEMA=0 \
-DHAVE_USLEEP \
-DSQLITE_WIN32_NO_ANSI \
$(MINGW_OPTIONS) \
-DSQLITE_USE_MALLOC_H \
-DSQLITE_USE_MSIZE
SHELL_OPTIONS = -DNDEBUG=1 \
-DSQLITE_DQS=0 \
|
| ︙ | ︙ | |||
2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 |
-DSQLITE_ENABLE_FTS4 \
-DSQLITE_ENABLE_DBSTAT_VTAB \
-DSQLITE_ENABLE_FTS5 \
-DSQLITE_ENABLE_STMTVTAB \
-DSQLITE_HAVE_ZLIB \
-DSQLITE_ENABLE_DBPAGE_VTAB \
-DSQLITE_TRUSTED_SCHEMA=0 \
-Dmain=sqlite3_shell \
-DSQLITE_SHELL_IS_UTF8=1 \
-DSQLITE_OMIT_LOAD_EXTENSION=1 \
-DUSE_SYSTEM_SQLITE=$(USE_SYSTEM_SQLITE) \
-DSQLITE_SHELL_DBNAME_PROC=sqlcmd_get_dbname \
-DSQLITE_SHELL_INIT_PROC=sqlcmd_init_proc \
-Daccess=file_access \
| > | 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 |
-DSQLITE_ENABLE_FTS4 \
-DSQLITE_ENABLE_DBSTAT_VTAB \
-DSQLITE_ENABLE_FTS5 \
-DSQLITE_ENABLE_STMTVTAB \
-DSQLITE_HAVE_ZLIB \
-DSQLITE_ENABLE_DBPAGE_VTAB \
-DSQLITE_TRUSTED_SCHEMA=0 \
-DHAVE_USLEEP \
-Dmain=sqlite3_shell \
-DSQLITE_SHELL_IS_UTF8=1 \
-DSQLITE_OMIT_LOAD_EXTENSION=1 \
-DUSE_SYSTEM_SQLITE=$(USE_SYSTEM_SQLITE) \
-DSQLITE_SHELL_DBNAME_PROC=sqlcmd_get_dbname \
-DSQLITE_SHELL_INIT_PROC=sqlcmd_init_proc \
-Daccess=file_access \
|
| ︙ | ︙ |
Changes to win/Makefile.msc.
| ︙ | ︙ | |||
317 318 319 320 321 322 323 324 325 326 327 328 329 330 |
/DSQLITE_ENABLE_FTS4 \
/DSQLITE_ENABLE_DBSTAT_VTAB \
/DSQLITE_ENABLE_FTS5 \
/DSQLITE_ENABLE_STMTVTAB \
/DSQLITE_HAVE_ZLIB \
/DSQLITE_ENABLE_DBPAGE_VTAB \
/DSQLITE_TRUSTED_SCHEMA=0 \
/DSQLITE_WIN32_NO_ANSI
SHELL_OPTIONS = /DNDEBUG=1 \
/DSQLITE_DQS=0 \
/DSQLITE_THREADSAFE=0 \
/DSQLITE_DEFAULT_MEMSTATUS=0 \
/DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 \
| > | 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 |
/DSQLITE_ENABLE_FTS4 \
/DSQLITE_ENABLE_DBSTAT_VTAB \
/DSQLITE_ENABLE_FTS5 \
/DSQLITE_ENABLE_STMTVTAB \
/DSQLITE_HAVE_ZLIB \
/DSQLITE_ENABLE_DBPAGE_VTAB \
/DSQLITE_TRUSTED_SCHEMA=0 \
/DHAVE_USLEEP \
/DSQLITE_WIN32_NO_ANSI
SHELL_OPTIONS = /DNDEBUG=1 \
/DSQLITE_DQS=0 \
/DSQLITE_THREADSAFE=0 \
/DSQLITE_DEFAULT_MEMSTATUS=0 \
/DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 \
|
| ︙ | ︙ | |||
341 342 343 344 345 346 347 348 349 350 351 352 353 354 |
/DSQLITE_ENABLE_FTS4 \
/DSQLITE_ENABLE_DBSTAT_VTAB \
/DSQLITE_ENABLE_FTS5 \
/DSQLITE_ENABLE_STMTVTAB \
/DSQLITE_HAVE_ZLIB \
/DSQLITE_ENABLE_DBPAGE_VTAB \
/DSQLITE_TRUSTED_SCHEMA=0 \
/Dmain=sqlite3_shell \
/DSQLITE_SHELL_IS_UTF8=1 \
/DSQLITE_OMIT_LOAD_EXTENSION=1 \
/DUSE_SYSTEM_SQLITE=$(USE_SYSTEM_SQLITE) \
/DSQLITE_SHELL_DBNAME_PROC=sqlcmd_get_dbname \
/DSQLITE_SHELL_INIT_PROC=sqlcmd_init_proc \
/Daccess=file_access \
| > | 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 |
/DSQLITE_ENABLE_FTS4 \
/DSQLITE_ENABLE_DBSTAT_VTAB \
/DSQLITE_ENABLE_FTS5 \
/DSQLITE_ENABLE_STMTVTAB \
/DSQLITE_HAVE_ZLIB \
/DSQLITE_ENABLE_DBPAGE_VTAB \
/DSQLITE_TRUSTED_SCHEMA=0 \
/DHAVE_USLEEP \
/Dmain=sqlite3_shell \
/DSQLITE_SHELL_IS_UTF8=1 \
/DSQLITE_OMIT_LOAD_EXTENSION=1 \
/DUSE_SYSTEM_SQLITE=$(USE_SYSTEM_SQLITE) \
/DSQLITE_SHELL_DBNAME_PROC=sqlcmd_get_dbname \
/DSQLITE_SHELL_INIT_PROC=sqlcmd_init_proc \
/Daccess=file_access \
|
| ︙ | ︙ | |||
519 520 521 522 523 524 525 |
"$(SRCDIR)\..\skins\black_and_white\footer.txt" \
"$(SRCDIR)\..\skins\black_and_white\header.txt" \
"$(SRCDIR)\..\skins\blitz\css.txt" \
"$(SRCDIR)\..\skins\blitz\details.txt" \
"$(SRCDIR)\..\skins\blitz\footer.txt" \
"$(SRCDIR)\..\skins\blitz\header.txt" \
"$(SRCDIR)\..\skins\blitz\ticket.txt" \
| < < < < | 521 522 523 524 525 526 527 528 529 530 531 532 533 534 |
"$(SRCDIR)\..\skins\black_and_white\footer.txt" \
"$(SRCDIR)\..\skins\black_and_white\header.txt" \
"$(SRCDIR)\..\skins\blitz\css.txt" \
"$(SRCDIR)\..\skins\blitz\details.txt" \
"$(SRCDIR)\..\skins\blitz\footer.txt" \
"$(SRCDIR)\..\skins\blitz\header.txt" \
"$(SRCDIR)\..\skins\blitz\ticket.txt" \
"$(SRCDIR)\..\skins\darkmode\css.txt" \
"$(SRCDIR)\..\skins\darkmode\details.txt" \
"$(SRCDIR)\..\skins\darkmode\footer.txt" \
"$(SRCDIR)\..\skins\darkmode\header.txt" \
"$(SRCDIR)\..\skins\default\css.txt" \
"$(SRCDIR)\..\skins\default\details.txt" \
"$(SRCDIR)\..\skins\default\footer.txt" \
|
| ︙ | ︙ | |||
1148 1149 1150 1151 1152 1153 1154 | echo "$(SRCDIR)\../skins/black_and_white/footer.txt" >> $@ echo "$(SRCDIR)\../skins/black_and_white/header.txt" >> $@ echo "$(SRCDIR)\../skins/blitz/css.txt" >> $@ echo "$(SRCDIR)\../skins/blitz/details.txt" >> $@ echo "$(SRCDIR)\../skins/blitz/footer.txt" >> $@ echo "$(SRCDIR)\../skins/blitz/header.txt" >> $@ echo "$(SRCDIR)\../skins/blitz/ticket.txt" >> $@ | < < < < | 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 | echo "$(SRCDIR)\../skins/black_and_white/footer.txt" >> $@ echo "$(SRCDIR)\../skins/black_and_white/header.txt" >> $@ echo "$(SRCDIR)\../skins/blitz/css.txt" >> $@ echo "$(SRCDIR)\../skins/blitz/details.txt" >> $@ echo "$(SRCDIR)\../skins/blitz/footer.txt" >> $@ echo "$(SRCDIR)\../skins/blitz/header.txt" >> $@ echo "$(SRCDIR)\../skins/blitz/ticket.txt" >> $@ echo "$(SRCDIR)\../skins/darkmode/css.txt" >> $@ echo "$(SRCDIR)\../skins/darkmode/details.txt" >> $@ echo "$(SRCDIR)\../skins/darkmode/footer.txt" >> $@ echo "$(SRCDIR)\../skins/darkmode/header.txt" >> $@ echo "$(SRCDIR)\../skins/default/css.txt" >> $@ echo "$(SRCDIR)\../skins/default/details.txt" >> $@ echo "$(SRCDIR)\../skins/default/footer.txt" >> $@ |
| ︙ | ︙ | |||
1317 1318 1319 1320 1321 1322 1323 | "$(OX)\browse$O" : "$(OX)\browse_.c" "$(OX)\browse.h" $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\browse_.c" "$(OX)\browse_.c" : "$(SRCDIR)\browse.c" "$(OBJDIR)\translate$E" $** > $@ | | | 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 | "$(OX)\browse$O" : "$(OX)\browse_.c" "$(OX)\browse.h" $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\browse_.c" "$(OX)\browse_.c" : "$(SRCDIR)\browse.c" "$(OBJDIR)\translate$E" $** > $@ "$(OX)\builtin$O" : "$(OX)\builtin_.c" "$(OX)\builtin.h" "$(OX)\builtin_data.h" $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\builtin_.c" "$(OX)\builtin_.c" : "$(SRCDIR)\builtin.c" "$(OBJDIR)\translate$E" $** > $@ "$(OX)\bundle$O" : "$(OX)\bundle_.c" "$(OX)\bundle.h" $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\bundle_.c" |
| ︙ | ︙ | |||
1455 1456 1457 1458 1459 1460 1461 | "$(OX)\diffcmd$O" : "$(OX)\diffcmd_.c" "$(OX)\diffcmd.h" $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\diffcmd_.c" "$(OX)\diffcmd_.c" : "$(SRCDIR)\diffcmd.c" "$(OBJDIR)\translate$E" $** > $@ | | | 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 | "$(OX)\diffcmd$O" : "$(OX)\diffcmd_.c" "$(OX)\diffcmd.h" $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\diffcmd_.c" "$(OX)\diffcmd_.c" : "$(SRCDIR)\diffcmd.c" "$(OBJDIR)\translate$E" $** > $@ "$(OX)\dispatch$O" : "$(OX)\dispatch_.c" "$(OX)\dispatch.h" "$(OX)\page_index.h" $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\dispatch_.c" "$(OX)\dispatch_.c" : "$(SRCDIR)\dispatch.c" "$(OBJDIR)\translate$E" $** > $@ "$(OX)\doc$O" : "$(OX)\doc_.c" "$(OX)\doc.h" $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\doc_.c" |
| ︙ | ︙ |
Changes to www/aboutcgi.wiki.
1 2 | <title>How CGI Works In Fossil</title> <h2>Introduction</h2><blockquote> | | > | | | | | | | | | | | | 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 |
<title>How CGI Works In Fossil</title>
<h2>Introduction</h2><blockquote>
CGI or "Common Gateway Interface" is a venerable yet reliable technique for
generating dynamic web content. This article gives a quick background on how
CGI works and describes how Fossil can act as a CGI service.
This is a "how it works" guide. This document provides background
information on the CGI protocol so that you can better understand what
is going on behind the scenes. If you just want to set up Fossil
as a CGI server, see the [./server/ | Fossil Server Setup] page. Or
if you want to development CGI-based extensions to Fossil, see
the [./serverext.wiki|CGI Server Extensions] page.
</blockquote>
<h2>A Quick Review Of CGI</h2><blockquote>
An HTTP request is a block of text that is sent by a client application
(usually a web browser) and arrives at the web server over a network
connection. The HTTP request contains a URL that describes the information
being requested. The URL in the HTTP request is typically the same URL
that appears in the URL bar at the top of the web browser that is making
the request. The URL might contain a "?" character followed
query parameters. The HTTP will usually also contain other information
such as the name of the application that made the request, whether or
not the requesting application can accept a compressed reply, POST
parameters from forms, and so forth.
The job of the web server is to interpret the HTTP request and formulate
an appropriate reply.
The web server is free to interpret the HTTP request in any way it wants.
But most web servers follow a similar pattern, described below.
(Note: details may vary from one web server to another.)
Suppose the filename component of the URL in the HTTP request looks like this:
<blockquote><b>/one/two/timeline/four</b></blockquote>
Most web servers will search their content area for files that match
some prefix of the URL. The search starts with <b>/one</b>, then goes to
<b>/one/two</b>, then <b>/one/two/timeline</b>, and finally
<b>/one/two/timeline/four</b> is checked. The search stops at the first
match.
Suppose the first match is <b>/one/two</b>. If <b>/one/two</b> is an
ordinary file in the content area, then that file is returned as static
content. The "<b>/timeline/four</b>" suffix is silently ignored.
If <b>/one/two</b> is a CGI script (or program), then the web server
executes the <b>/one/two</b> script. The output generated by
the script is collected and repackaged as the HTTP reply.
Before executing the CGI script, the web server will set up various
environment variables with information useful to the CGI script:
<table border=1 cellpadding=5>
<tr><th>Environment<br>Variable<th>Meaning
<tr><td>GATEWAY_INTERFACE<td>Always set to "CGI/1.0"
<tr><td>REQUEST_URI
<td>The input URL from the HTTP request.
<tr><td>SCRIPT_NAME
<td>The prefix of the input URL that matches the CGI script name.
In this example: "/one/two".
<tr><td>PATH_INFO
<td>The suffix of the URL beyond the name of the CGI script.
In this example: "timeline/four".
<tr><td>QUERY_STRING
<td>The query string that follows the "?" in the URL, if there is one.
</table>
There are other CGI environment variables beyond those listed above.
Many Fossil servers implement the
[https://fossil-scm.org/home/test_env/two/three?abc=xyz|test_env]
webpage that shows some of the CGI environment
variables that Fossil pays attention to.
In addition to setting various CGI environment variables, if the HTTP
request contains POST content, then the web server relays the POST content
to standard input of the CGI script.
In summary, the task of the
CGI script is to read the various CGI environment variables and
the POST content on standard input (if any), figure out an appropriate
reply, then write that reply on standard output.
The web server will read the output from the CGI script, reformat it
into an appropriate HTTP reply, and relay the result back to the
requesting application.
The CGI script exits as soon as it generates a single reply.
The web server will (usually) persist and handle multiple HTTP requests,
but a CGI script handles just one HTTP request and then exits.
The above is a rough outline of how CGI works.
There are many details omitted from this brief discussion.
See other on-line CGI tutorials for further information.
</blockquote>
<h2>How Fossil Acts As A CGI Program</h2>
<blockquote>
An appropriate CGI script for running Fossil will look something
|
| ︙ | ︙ | |||
101 102 103 104 105 106 107 | for this script. On unix, when you execute a script that starts with a shebang, the operating system runs the program identified by the shebang with a single argument that is the full pathname of the script itself. In our example, the interpreter is Fossil, and the argument might be something like "/var/www/cgi-bin/one/two" (depending on how your particular web server is configured). | | | | | | 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 | for this script. On unix, when you execute a script that starts with a shebang, the operating system runs the program identified by the shebang with a single argument that is the full pathname of the script itself. In our example, the interpreter is Fossil, and the argument might be something like "/var/www/cgi-bin/one/two" (depending on how your particular web server is configured). The Fossil program that is run as the script interpreter is the same Fossil that runs when you type ordinary Fossil commands like "fossil sync" or "fossil commit". But in this case, as soon as it launches, the Fossil program recognizes that the GATEWAY_INTERFACE environment variable is set to "CGI/1.0" and it therefore knows that it is being used as CGI rather than as an ordinary command-line tool, and behaves accordingly. When Fossil recognizes that it is being run as CGI, it opens and reads the file identified by its sole argument (the file named by <code>argv[1]</code>). In our example, the second line of that file tells Fossil the location of the repository it will be serving. Fossil then starts looking at the CGI environment variables to figure out what web page is being requested, generates that one web page, then exits. Usually, the webpage being requested is the first term of the PATH_INFO environment variable. (Exceptions to this rule are noted in the sequel.) For our example, the first term of PATH_INFO is "timeline", which means that Fossil will generate the [/help?cmd=/timeline|/timeline] webpage. With Fossil, terms of PATH_INFO beyond the webpage name are converted into the "name" query parameter. Hence, the following two URLs mean exactly the same thing to Fossil: <ol type='A'> <li> [https://fossil-scm.org/home/info/c14ecc43] <li> [https://fossil-scm.org/home/info?name=c14ecc43] </ol> |
| ︙ | ︙ | |||
147 148 149 150 151 152 153 | <blockquote> The previous example showed how to serve a single Fossil repository using a single CGI script. On a website that wants to serve multiple repositories, one could simply create multiple CGI scripts, one script for each repository. But it is also possible to serve multiple Fossil repositories from a single CGI script. | | | 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 | <blockquote> The previous example showed how to serve a single Fossil repository using a single CGI script. On a website that wants to serve multiple repositories, one could simply create multiple CGI scripts, one script for each repository. But it is also possible to serve multiple Fossil repositories from a single CGI script. If the CGI script for Fossil contains a "directory:" line instead of a "repository:" line, then the argument to "directory:" is the name of a directory that contains multiple repository files, each ending with ".fossil". For example: <blockquote><pre> #!/usr/bin/fossil directory: /home/www/repos |
| ︙ | ︙ | |||
198 199 200 201 202 203 204 |
\_________/\____________/\____________________/ \______/
| | | |
HTTP_HOST SCRIPT_NAME PATH_INFO QUERY_STRING
</pre>
</blockquote>
<h2>Additional CGI Script Options</h2>
<blockquote>
| | | | | | | | | 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 |
\_________/\____________/\____________________/ \______/
| | | |
HTTP_HOST SCRIPT_NAME PATH_INFO QUERY_STRING
</pre>
</blockquote>
<h2>Additional CGI Script Options</h2>
<blockquote>
The CGI script can have additional options used to fine-tune
Fossil's behavior. See the [./cgi.wiki|CGI script documentation]
for details.
</blockquote>
<h2>Additional Observations</h2>
<blockquote><ol type="I">
<li><p>
Fossil does not distinguish between the various HTTP methods (GET, PUT,
DELETE, etc). Fossil figures out what it needs to do purely from the
webpage term of the URI.</p></li>
<li><p>
Fossil does not distinguish between query parameters that are part of the
URI, application/x-www-form-urlencoded or multipart/form-data encoded
parameter that are part of the POST content, and cookies. Each information
source is seen as a space of key/value pairs which are loaded into an
internal property hash table. The code that runs to generate the reply
can then reference various properties values.
Fossil does not care where the value of each property comes from (POST
content, cookies, or query parameters) only that the property exists
and has a value.</p></li>
<li><p>
The "[/help?cmd=ui|fossil ui]" and "[/help?cmd=server|fossil server]" commands
are implemented using a simple built-in web server that accepts incoming HTTP
requests, translates each request into a CGI invocation, then creates a
separate child Fossil process to handle each request. In other words, CGI
is used internally to implement "fossil ui/server".
<br><br>
SCGI is processed using the same built-in web server, just modified
to parse SCGI requests instead of HTTP requests. Each SCGI request is
converted into CGI, then Fossil creates a separate child Fossil
process to handle each CGI request.</p></li>
<li><p>
Fossil is itself often launched using CGI. But Fossil can also then
turn around and launch [./serverext.wiki|sub-CGI scripts to implement
extensions].</p></li>
</ol>
</blockquote>
|
Changes to www/aboutdownload.wiki.
| ︙ | ︙ | |||
90 91 92 93 94 95 96 | <h2>3.0 Security</h2> Only users with the [/setup_ulist_notes|"y" permission] are allowed to push unversioned content up to the servers. Having the ability to push check-ins (the [/setup_ulist_notes|"i" permission]) is not sufficient. | | | < | | | > | 90 91 92 93 94 95 96 97 98 99 100 101 102 | <h2>3.0 Security</h2> Only users with the [/setup_ulist_notes|"y" permission] are allowed to push unversioned content up to the servers. Having the ability to push check-ins (the [/setup_ulist_notes|"i" permission]) is not sufficient. On the Fossil project there are (as of 2023-07-31) 71 people who have check-in privileges. But only the project lead can push unversioned content and thus change the build products on the download page. Minimizing the number of people who can change the build products helps to ensure that rogue binaries do not slip onto the download page unnoticed. |
Changes to www/adding_code.wiki.
| ︙ | ︙ | |||
116 117 118 119 120 121 122 | (either to an existing source file, or to a new source file created as described above) according to the following template: <blockquote><verbatim> /* ** COMMAND: xyzzy ** | | | 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
(either to an existing source file, or to a new source file created as
described above) according to the following template:
<blockquote><verbatim>
/*
** COMMAND: xyzzy
**
** Help text goes here. Backslashes must be escaped.
*/
void xyzzy_cmd(void){
/* Implement the command here */
fossil_print("Hello, World!\n");
}
</verbatim></blockquote>
|
| ︙ | ︙ |
Changes to www/alerts.md.
| ︙ | ︙ | |||
364 365 366 367 368 369 370 | occur such that a dot or period in an alert message is at the beginning of a line, you'll get a truncated email message without this option. Statistically, this will happen about once every 70 or so messages, so it is important to give this option if your MTA treats leading dots on a line this way. <a id="msmtp"></a> | | | < | > > | 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 | occur such that a dot or period in an alert message is at the beginning of a line, you'll get a truncated email message without this option. Statistically, this will happen about once every 70 or so messages, so it is important to give this option if your MTA treats leading dots on a line this way. <a id="msmtp"></a> The [`msmtp`][msmtp] SMTP client is compatible with this protocol if you give it the `-t` option. It’s a useful option on a server hosting a Fossil repository which doesn't otherwise require a separate SMTP server for other purposes, such as because you’ve got a separate provider for your email and merely need a way to let Fossil feed messages into it. It is probably also possible to configure [`procmail`][pmdoc] to work with this protocol. If you know how to do it, a patch to this document or a how-to on [the Fossil forum][ff] would be appreciated. [ff]: https://fossil-scm.org/forum/ [msmtp]: https://marlam.de/msmtp/ |
| ︙ | ︙ |
Changes to www/backup.md.
| ︙ | ︙ | |||
199 200 201 202 203 204 205 | leak your information. This addition to the prior scripts will encrypt the resulting backup in such a way that the cloud copy is a useless blob of noise to anyone without the key: ---- ```shell | | | > > > > > > > > > > > > > > > > > > > > > < | | | | | | | | 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 |
leak your information. This addition to the prior scripts will encrypt
the resulting backup in such a way that the cloud copy is a useless blob
of noise to anyone without the key:
----
```shell
iter=152830
pass="h8TixP6Mt6edJ3d6COaexiiFlvAM54auF2AjT7ZYYn"
gd="$HOME/Google Drive/Fossil Backups/$bf.xz.enc"
fossil sql -R ~/museum/backups/"$bf" .dump | xz -9 |
openssl enc -e -aes-256-cbc -pbkdf2 -iter $iter -pass pass:"$pass" -out "$gd"
```
----
If you’re adding this to the first script above, remove the
“`-R repo-name`” bit so you get a dump of the repository backing the
current working directory.
Change the `pass` value to some other long random string, and change the
`iter` value to something in the hundreds of thousands range. A good source for
the first is [here][grcp], and for the second, [here][rint].
You may find posts online written by people recommending millions of
iterations for PBKDF2, but they’re generally talking about this in the
context of memorizable passwords, where adding even one more character
to the password is a significant burden. Given our script’s purely
random maximum-length passphrase, there isn’t much more that increasing
the key derivation iteration count can do for us.
Conversely, if you were to reduce the passphrase to 41 characters, that
would drop the key strength by roughly 2⁶, being the entropy value per
character for using most of printable ASCII in our passphrase. To make
that lost strength up on the PBKDF2 end, you’d have to multiply your
iterations by 2⁶ = 64 times. It’s easier to use a max-length passphrase
in this situation than get crazy with key derivation iteration counts.
(This, by the way, is why the example passphrase above is 42 characters:
with 6 bits of entropy per character, that gives you a key size of 252,
as close as we can get to our chosen encryption algorithm’s 256-bit key
size without going over. If it pleases you to give it 43 random
characters for a passphrase in order to pick up those last four bits of
security, you’re welcome to do so.)
Compressing the data before encrypting it removes redundancies that can
make decryption easier, and it results in a smaller backup than you get
with the previous script alone, at the expense of a lot of CPU time
during the backup. You may wish to switch to a less space-efficient
compression algorithm that takes less CPU power, such as [`lz4`][lz4].
Changing up the compression algorithm also provides some
security-thru-obscurity, which is useless on its own, but it *is* a
useful adjunct to strong encryption.
This requires OpenSSL 1.1 or higher. If you’re on 1.0 or older, you
won’t have the `-pbkdf2` and `-iter` options, and you may have to choose
a different cipher algorithm; both changes are likely to weaken the
encryption significantly, so you should install a newer version rather
than work around the lack of these features.
Beware that macOS ships a fork of OpenSSL called [LibreSSL][lssl] that
lacked this capability until Ventura (13.0). If you’re on Monterey (12)
or older, we recommend use of the [Homebrew][hb] OpenSSL package rather
than give up on the security afforded by use of configurable-iteration
PBKDF2. To avoid a conflict with the platform’s `openssl` binary,
Homebrew’s installation is [unlinked][hbul] by default, so you have to
give an explicit path to it, one of:
/usr/local/opt/openssl/bin/openssl ... # Intel x86 Macs
/opt/homebrew/opt/openssl/bin/openssl ... # ARM Macs (“Apple silicon”)
[lssl]: https://www.libressl.org/
|
| ︙ | ︙ | |||
285 286 287 288 289 290 291 | [bu]: /help?cmd=backup [grcp]: https://www.grc.com/passwords.htm [hb]: https://brew.sh [hbul]: https://docs.brew.sh/FAQ#what-does-keg-only-mean [lz4]: https://lz4.github.io/lz4/ [pbr]: ./private.wiki | | | 305 306 307 308 309 310 311 312 313 314 315 316 | [bu]: /help?cmd=backup [grcp]: https://www.grc.com/passwords.htm [hb]: https://brew.sh [hbul]: https://docs.brew.sh/FAQ#what-does-keg-only-mean [lz4]: https://lz4.github.io/lz4/ [pbr]: ./private.wiki [rint]: https://www.random.org/integers/?num=1&min=100000&max=1000000&col=5&base=10&format=html&rnd=new [Setup]: ./caps/admin-v-setup.md#apsu [shun]: ./shunning.wiki [tkt]: ./tickets.wiki [uv]: ./unvers.wiki |
Changes to www/blockchain.md.
| ︙ | ︙ | |||
58 59 60 61 62 63 64 |
claims to be a $100 bill.
* **Type 2** is creation of new fraudulent currency that will pass
in commerce. To extend our analogy, it is the creation of new
US $10 bills. There are two sub-types to this fraud. In terms of
our analogy, they are:
| | | 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
claims to be a $100 bill.
* **Type 2** is creation of new fraudulent currency that will pass
in commerce. To extend our analogy, it is the creation of new
US $10 bills. There are two sub-types to this fraud. In terms of
our analogy, they are:
* **Type 2a**: copying an existing legitimate $10 bill<br><br>
* **Type 2b**: printing a new $10 bill that is unlike an existing
legitimate one, yet which will still pass in commerce
* **Type 3** is double-spending existing legitimate cryptocurrency.
There is no analogy in paper money due to its physical form; it is a
problem unique to digital currency due to its infinitely-copyable
|
| ︙ | ︙ |
Changes to www/branching.wiki.
1 2 3 4 5 6 7 | <title>Branching, Forking, Merging, and Tagging</title> <h2>Background</h2> In a simple and perfect world, the development of a project would proceed linearly, as shown in Figure 1. <verbatim type="pikchr center toggle"> | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | <title>Branching, Forking, Merging, and Tagging</title> <h2>Background</h2> In a simple and perfect world, the development of a project would proceed linearly, as shown in Figure 1. <verbatim type="pikchr center toggle"> ALL: [circle rad 0.1in thickness 1.5px "1" arrow right 40% circle same "2" arrow same circle same "3" arrow same circle same "4"] box invis "Figure 1" big fit with .n at .3cm below ALL.s |
| ︙ | ︙ | |||
41 42 43 44 45 46 47 | "leaf.") Alas, reality often interferes with the simple linear development of a project. Suppose two programmers make independent modifications to check-in 2. After both changes are committed, the check-in graph looks like Figure 2: <verbatim type="pikchr center toggle"> | | | 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | "leaf.") Alas, reality often interferes with the simple linear development of a project. Suppose two programmers make independent modifications to check-in 2. After both changes are committed, the check-in graph looks like Figure 2: <verbatim type="pikchr center toggle"> ALL: [circle rad 0.1in thickness 1.5px "1" arrow right 40% circle same "2" circle same "3" at 2nd circle+(.4,.3) arrow from 2nd circle to 3rd circle chop circle same "4" at 2nd circle+(.4,-.3) arrow from 2nd circle to 4th circle chop] box invis "Figure 2" big fit with .n at .3cm below ALL.s |
| ︙ | ︙ | |||
117 118 119 120 121 122 123 | merge]</b> command to merge Bob's changes into her local copy of check-in 3. Without arguments, that command merges all leaves on the current branch. Alice can then verify that the merge is sensible and if so, commit the results as check-in 5. This results in a DAG as shown in Figure 3. <verbatim type="pikchr center toggle"> | | | 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 | merge]</b> command to merge Bob's changes into her local copy of check-in 3. Without arguments, that command merges all leaves on the current branch. Alice can then verify that the merge is sensible and if so, commit the results as check-in 5. This results in a DAG as shown in Figure 3. <verbatim type="pikchr center toggle"> ALL: [circle rad 0.1in thickness 1.5px "1" arrow right 40% circle same "2" circle same "3" at 2nd circle+(.4,.3) arrow from 2nd circle to 3rd circle chop circle same "4" at 2nd circle+(.4,-.3) arrow from 2nd circle to 4th circle chop circle same "5" at 3rd circle+(.4,-.3) |
| ︙ | ︙ | |||
180 181 182 183 184 185 186 | When multiple leaves are desirable, we call this <i>branching</i> instead of <i>forking</i>: Figure 4 shows an example of a project where there are two branches, one for development work and another for testing. <verbatim type="pikchr center toggle"> | | | 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 | When multiple leaves are desirable, we call this <i>branching</i> instead of <i>forking</i>: Figure 4 shows an example of a project where there are two branches, one for development work and another for testing. <verbatim type="pikchr center toggle"> ALL: [circle rad 0.1in thickness 1.5px fill white "1" arrow 40% C2: circle same "2" arrow same circle same "3" arrow same C5: circle same "5" arrow same |
| ︙ | ︙ | |||
391 392 393 394 395 396 397 | Tags and properties are used in Fossil to help express the intent, and thus to distinguish between forks and branches. Figure 5 shows the same scenario as Figure 4 but with tags and properties added: <verbatim type="pikchr center toggle"> ALL: [arrowht = 0.07 | | | 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 | Tags and properties are used in Fossil to help express the intent, and thus to distinguish between forks and branches. Figure 5 shows the same scenario as Figure 4 but with tags and properties added: <verbatim type="pikchr center toggle"> ALL: [arrowht = 0.07 C1: circle rad 0.1in thickness 1.5px fill white "1" arrow 40% C2: circle same "2" arrow same circle same "3" arrow same C5: circle same "5" arrow same |
| ︙ | ︙ | |||
422 423 424 425 426 427 428 | box fill lightgray "branch=trunk" "sym-trunk" fit with .ne at C1-(0.05,0.3); line color gray from last box.ne to C1 chop box same "branch=test" "sym-test" "bgcolor=blue" "cancel=sym-trunk" fit \ with .n at C4-(0,0.3) line color gray from last box.n to C4 chop box same "sym-release-1.0" "closed" fit with .n at C9-(0,0.3) line color gray from last box.n to C9 chop] | | | 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 | box fill lightgray "branch=trunk" "sym-trunk" fit with .ne at C1-(0.05,0.3); line color gray from last box.ne to C1 chop box same "branch=test" "sym-test" "bgcolor=blue" "cancel=sym-trunk" fit \ with .n at C4-(0,0.3) line color gray from last box.n to C4 chop box same "sym-release-1.0" "closed" fit with .n at C9-(0,0.3) line color gray from last box.n to C9 chop] box invis "Figure 5" big fit with .n at 0.2cm below ALL.s </verbatim> A <i>tag</i> is a name that is attached to a check-in. A <i>property</i> is a name/value pair. Internally, Fossil implements tags as properties with a NULL value. So, tags and properties really are much the same thing, and henceforth we will use the word "tag" to mean either a tag or a property. |
| ︙ | ︙ |
Changes to www/build.wiki.
1 2 3 4 | <title>Compiling and Installing Fossil</title> <h2>0.0 Using A Pre-compiled Binary</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 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 | <title>Compiling and Installing Fossil</title> <h2>0.0 Using A Pre-compiled Binary</h2> [/uv/download.html|Pre-compiled binaries] are available for recent releases. Just download the appropriate executable for your platform and put it on your $PATH. To uninstall, simply delete the executable. To upgrade from an older release, just overwrite the older binary with the newer one. For details about how those binaries are built, see [/wiki?name=Release+Build+How-To | the Release Build How-To wiki page]. <h2>0.1 Executive Summary</h2> Building and installing is very simple. Three steps: <ol> <li> Download and unpack a source tarball or ZIP. <li> <b>./configure; make</b> <li> Move the resulting "fossil" or "fossil.exe" executable to someplace on your $PATH. </ol> <hr> <h2>1.0 Obtaining The Source Code</h2> Fossil is self-hosting, so you can obtain a ZIP archive or tarball containing a snapshot of the <em>latest</em> version directly from Fossil's own fossil repository. Additionally, source archives of <em>released</em> versions of fossil are available from the [/uv/download.html|downloads page]. To obtain a development version of fossil, follow these steps: <ol> <li>Point your web browser to [https://fossil-scm.org/]</li> <li>Click on the [/timeline|Timeline] link at the top of the page.</li> <li>Select a version of of Fossil you want to download. The latest version on the trunk branch is usually a good choice. Click on its link.</li> <li>Finally, click on one of the "Zip Archive" or "Tarball" links, according to your preference. These link will build a ZIP archive or a gzip-compressed tarball of the complete source code and download it to your computer.</li> </ol> <h2>Aside: Is it really safe to use an unreleased development version of the Fossil source code?</h2> Yes! Any check-in on the [/timeline?t=trunk | trunk branch] of the Fossil [https://fossil-scm.org/ | Fossil self-hosting repository] will work fine. (Dodgy code is always on a branch.) In the unlikely event that you pick a version with a serious bug, it still won't clobber your files. Fossil uses several [./selfcheck.wiki | self-checks] prior to committing any repository change that prevent loss-of-work due to bugs. The Fossil [./selfhost.wiki | self-hosting repositories], especially the one at [https://fossil-scm.org/home], usually run a version of trunk that is less than a week or two old. Look at the bottom left-hand corner of this screen (to the right of "This page was generated in...") to see exactly which version of Fossil is rendering this page. It is always safe to use whatever version of the Fossil code you find running on the main Fossil website. <h2>2.0 Compiling</h2> <ol> <li value="5"> Unpack the ZIP or tarball you downloaded then <b>cd</b> into the directory created.</li> <li><i>(Optional, Debian-compatible Linux only)</i> Make sure you have all the necessary tools and libraries at hand by running: <b>sudo apt install tcl-dev tk libssl-dev zlib1g-dev</b>. <li><i>(Optional, Unix only)</i> Run <b>./configure</b> to construct a makefile. <ol type="a"> <li> The build system for Fossil on Unix-like systems assumes that the OpenSSL development and runtime files are available on your system, because unprotected repositories are trivial to attack otherwise. Indeed, some public Fossil repositories — including Fossil's own — today run in an HTTPS-only mode, so that you can't even do an anonymous clone from them without using the TLS features added to Fossil by OpenSSL. To weaken that stance could allow a [https://en.wikipedia.org/wiki/Man-in-the-middle_attack|man in the middle attack], such as one that substitutes malicious code into your Fossil repository clone. You can force the Fossil build system to avoid searching for, building against, and linking to the OpenSSL library by passing <b>--with-openssl=none</b> to the <tt>configure</tt> script. If you do not have the OpenSSL development libraries on your system, we recommend that you install them, typically via your OS's package manager. The Fossil build system goes to a lot of effort to seek these out wherever they may be found, so that is typically all you need to do. For more advanced use cases, see the [./ssl.wiki#openssl-bin|OpenSSL discussion in the "TLS and Fossil" document]. </li> <li> To build a statically linked binary, you can <i>try</i> adding the <b>--static</b> option, but [https://stackoverflow.com/questions/3430400/linux-static-linking-is-dead | it may well not work]. If your platform of choice is affected by this, the simplest workaround we're aware of is to build a Fossil container, then [./containers.md#static | extract the static executable from it]. </li> <li> To enable the native [./th1.md#tclEval | Tcl integration feature] feature, add the <b>--with-tcl=1</b> and <b>--with-tcl-private-stubs=1</b> options. </li> <li> Other configuration options can be seen by running <b>./configure --help</b> </li> </ol> <li>Run "<b>make</b>" to build the "fossil" or "fossil.exe" executable. The details depend on your platform and compiler.</li> <ol type="a"> <li><i>Unix</i> → the configure-generated Makefile should work on all Unix and Unix-like systems. Simply type "<b>make</b>".</li> <li><i>Unix without running "configure"</i> → if you prefer to avoid running configure, you can also use: <b>make -f Makefile.classic</b>. You may want to make minor edits to Makefile.classic to configure the build for your system.</li> <li><i>MinGW / MinGW-w64</i> → The best-supported path is to build via the MinGW specific Makefile under a POSIX build of GNU make: "<b>make -f win/Makefile.mingw</b>".</li> There is limited support for building under MinGW's native Windows port of GNU Make instead by defining the <tt>USE_WINDOWS=1</tt> variable, but it's better to build under MSYS, Cygwin, or WSL on Windows since this mode doesn't take care of cases such as the "openssl" target, which depends on <tt>sed</tt>. We've gone as far down this path as is practical short of breaking cross-compilation under Linux, macOS, and so |
| ︙ | ︙ | |||
165 166 167 168 169 170 171 | <b>make -f win/Makefile.mingw FOSSIL_ENABLE_TCL=1 FOSSIL_ENABLE_TCL_STUBS=1 FOSSIL_ENABLE_TCL_PRIVATE_STUBS=1</b> Alternatively, running <b>./configure</b> under MSYS should give a suitable top-level Makefile. However, options passed to configure that are not applicable on Windows may cause the configuration or compilation to fail (e.g. fusefs, internal-sqlite, etc). | | | 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 |
<b>make -f win/Makefile.mingw FOSSIL_ENABLE_TCL=1 FOSSIL_ENABLE_TCL_STUBS=1 FOSSIL_ENABLE_TCL_PRIVATE_STUBS=1</b>
Alternatively, running <b>./configure</b> under MSYS should give a
suitable top-level Makefile. However, options passed to configure that are
not applicable on Windows may cause the configuration or compilation to fail
(e.g. fusefs, internal-sqlite, etc).
<li><i>MSVC</i> → Use the MSVC makefile.</li>
Run all of the following from a "x64 Native Tools Command Prompt".
First
change to the "win/" subdirectory ("<b>cd win</b>") then run
"<b>nmake /f Makefile.msc</b>".<br><br>Alternatively, the batch
file "<b>win\buildmsvc.bat</b>" may be used and it will attempt to
|
| ︙ | ︙ | |||
197 198 199 200 201 202 203 | <blockquote><pre> nmake /f Makefile.msc FOSSIL_ENABLE_TCL=1 </pre></blockquote> <blockquote><pre> buildmsvc.bat FOSSIL_ENABLE_TCL=1 </pre></blockquote> | | | | | > | | > | > | > | | > | | 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 | <blockquote><pre> nmake /f Makefile.msc FOSSIL_ENABLE_TCL=1 </pre></blockquote> <blockquote><pre> buildmsvc.bat FOSSIL_ENABLE_TCL=1 </pre></blockquote> <li><i>Cygwin</i> → The same as other Unix-like systems. It is recommended to configure using: "<b>configure --disable-internal-sqlite</b>", making sure you have the "libsqlite3-devel" , "zlib-devel" and "openssl-devel" packages installed first.</li> </ol> </ol> <h2>3.0 Installing</h2> <ol> <li value="9"> The finished binary is named "fossil" (or "fossil.exe" on Windows). Put this binary in a directory that is somewhere on your PATH environment variable. It does not matter where. </li> <li> <b>(Optional:)</b> To uninstall, just delete the binary. </li> </ol> <h2>4.0 Additional Considerations</h2> <ul> <li> If the makefiles that come with Fossil do not work for you, or for some other reason you want to know how to build Fossil manually, then refer to the [./makefile.wiki | Fossil Build Process] document which describes in detail what the makefiles do behind the scenes. </li> <li> The fossil executable is self-contained and stand-alone and usually requires no special libraries or other software to be installed. However, the "--tk" option to the [/help/diff|diff command] requires that Tcl/Tk be installed on the local machine. You can get Tcl/Tk from [http://www.activestate.com/activetcl|ActiveState]. </li> <li> To build on older Macs (circa 2002, MacOS 10.2) edit the Makefile generated by configure to add the following lines: <blockquote><pre> TCC += -DSQLITE_WITHOUT_ZONEMALLOC TCC += -D_BSD_SOURCE TCC += -DWITHOUT_ICONV TCC += -Dsocketlen_t=int TCC += -DSQLITE_MAX_MMAP_SIZE=0 </pre></blockquote> </li> </ul> <h2 id="docker" name="oci">5.0 Building a Docker Container</h2> The information on building Fossil inside an [https://opencontainers.org/ | OCI container] is now in [./containers.md | a separate document]. This includes the instructions on using the OCI container as an expedient intermediary for building a statically-linked Fossil binary on modern Linux platforms, which otherwise make this difficult. <h2>6.0 Building on/for Android</h2> <h3>6.1 Cross-compiling from Linux</h3> The following instructions for building Fossil for Android via Linux, without requiring a rooted OS, are adapted from [forum:/forumpost/e0e9de4a7e | a forum post]. On the development machine, from the fossil source tree: <pre><code>export CC=$NDK_PATH/toolchains/llvm/prebuilt/linux-x86_64/bin/armv7a-linux-androideabi21-clang ./configure --with-openssl=none make </code></pre> |
| ︙ | ︙ |
Changes to www/caps/admin-v-setup.md.
| ︙ | ︙ | |||
450 451 452 453 454 455 456 | [fcp]: https://fossil-scm.org/home/help?cmd=configuration [fdp]: ../fossil-v-git.wiki#devorg [forum]: https://fossil-scm.org/forum/ [fui]: /help?cmd=ui [lg]: ./login-groups.md [rs]: https://fossil-scm.org/home/doc/trunk/www/settings.wiki | | | 450 451 452 453 454 455 456 457 458 459 460 461 | [fcp]: https://fossil-scm.org/home/help?cmd=configuration [fdp]: ../fossil-v-git.wiki#devorg [forum]: https://fossil-scm.org/forum/ [fui]: /help?cmd=ui [lg]: ./login-groups.md [rs]: https://fossil-scm.org/home/doc/trunk/www/settings.wiki [sia]: https://fossil-scm.org/home/artifact?ln=1259-1260&name=0fda31b6683c206a [snoy]: https://fossil-scm.org/forum/forumpost/00e1c4ecff [th1]: ../th1.md [tt]: https://en.wikipedia.org/wiki/Tiger_team#Security [webo]: ./#webonly |
Changes to www/caps/impl.md.
| ︙ | ︙ | |||
100 101 102 103 104 105 106 | [asd]: https://fossil-scm.org/forum/forumpost/ce4a3b5f3e [bc]: ../blockchain.md [dsp]: https://fossil-scm.org/fossil/doc/trunk/www/sync.wiki [for]: ./forum.wiki [ifvc]: https://en.wikipedia.org/wiki/Inter_frame [mn]: https://en.wikipedia.org/wiki/Mnemonic [ref]: ./ref.html | | | | 100 101 102 103 104 105 106 107 108 109 110 111 | [asd]: https://fossil-scm.org/forum/forumpost/ce4a3b5f3e [bc]: ../blockchain.md [dsp]: https://fossil-scm.org/fossil/doc/trunk/www/sync.wiki [for]: ./forum.wiki [ifvc]: https://en.wikipedia.org/wiki/Inter_frame [mn]: https://en.wikipedia.org/wiki/Mnemonic [ref]: ./ref.html [sexp]: /artifact?ln=1223-1298&name=889d6724 [sff]: /artifact?ln=80-117&name=52d2860f [sc]: https://en.cppreference.com/w/c/string/byte/strchr [shun]: ../shunning.wiki [ucap]: ./index.md#ucap |
Changes to www/caps/index.md.
|
| | | > > > > | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | # Administering User Capabilities (a.k.a. Permissions) Fossil includes a powerful [role-based access control system][rbac] which affects which users have which capabilities(^Some parts of the Fossil code call these “permissions” instead, but since there is [a clear and present risk of confusion](#webonly) with operating system level file permissions in this context, we avoid using that term for Fossil’s RBAC capability flags in these pages.) within a given [served][svr] Fossil repository. We call this the “caps” system for short. Fossil stores a user’s caps as an unordered string of ASCII characters, one capability per, [currently](./impl.md#choices) limited to [alphanumerics][an]. Caps are case-sensitive: “**A**” and “**a**” are different user capabilities. This is a complex topic, so some sub-topics have their own documents: |
| ︙ | ︙ |
Changes to www/changes.wiki.
1 2 | <title>Change Log</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 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 |
<title>Change Log</title>
<h2 id='v2_24'>Changes for version 2.24 (pending)</h2>
* Add the x= query paramater to the [/help?cmd=/timeline|/timeline page].
* Moved the /museum/repo.fossil file referenced from the Dockerfile from
the ENTRYPOINT to the CMD part to allow use of --repolist mode.
* The /uvlist page now shows the hash algorithm used so that
outsiders don't have to guess it from the hash length when
double-checking hashes of downloaded files on their end.
* The hash itself is now shown in a fixed-width font on the /uvlist
page, suiting this tabular display.
<h2 id='v2_23'>Changes for version 2.23 (2023-11-01)</h2>
* Add ability to "close" forum threads, such that unprivileged users
may no longer respond to them. Only administrators can close
threads or respond to them by default, and the
[/help?cmd=forum-close-policy|forum-close-policy setting] can be
used to add that capability to moderators.
* Add the [/help?cmd=all|fossil all whatis] command.
* The [/help?cmd=status|fossil status] command and relevant UI pages now
correctly report files which were both renamed <b>and</b> edited as such.
* Show default value of settings that have a default in
[/help?cmd=help|fossil help SETTING] output.
* On timeline graphs, show closed check-ins using an X in the middle of the
node circle or box.
* New options for email notification: Get email only for the first
post in each new thread, and/or posts that are in reply to my posts.
* Fix a regression bug introduced in version 2.22 that caused FTS5 searches
to fail for terms containing non-ASCII characters.
* Improved defense-in-depth against malicious attack:
<ul>
<li> When an attempted SQL injection attack is detected, return
HTTP result code 418, which can signal the web server to sanction
the attacking IP address.
<li> Better defense against cross-site request forgery (CSRF)
attacks.
<li> Improvements to static analysis of source code (the codecheck1.c
file in the source tree).
</ul>
* Enhance the [/help?cmd=/dir|treeview file listings]
([/dir?type=tree&ci=trunk|example]) by displaying file sizes
and adding the option to sort by file size.
* The [/help?cmd=fts-config|fossil fts-config] command now shows how much
repository space is used by the full-text index.
* Changing a setting to an empty string is now the same as deleting the
setting, in most cases. There are a few exceptions, indicated by the
keep-empty flag on the setting definition.
* The [/help?cmd=branch|fossil branch list] command can now filter branches
that have/have not been merged into the current branch.
* Improvements to interactions with remote repositories over SSH:
<ul>
<li> Print the text of the SSH command that is run to do remote interaction,
for full disclosure to the operator.
<li> Add a PATH= argument to the [/help?cmd=ui|fossil ui remote:/] and
[/help?cmd=patch|fossil patch push/pull remote:...] commands so that
they work when the "remote" machine is a Mac and the "fossil"
executable is in the $HOME/bin directory.
</ul>
* Update built-in libraries SQLite, ZLib, Pikchr to their latest versions.
* Documentation enhancements and typo fixes.
<h2 id='v2_22'>Changes for version 2.22 (2023-05-31)</h2>
* Enhancements to the [/help?cmd=/timeline|/timeline webpage]: <ol type="a">
<li> Add the ft=TAG query parameter which in combination with d=Y
shows all descendants of Y up to TAG
<li> Enhance the s=PATTERN (search) query parameter so that forum post
text is also searched when the "vfx" query parameter is used
<li> Fix the u= (user) query parameter so that it works with a= and b=
<li> Add the oldestfirst query parameter to show the events in reverse order.
Useful in combination with y=f and vfs and perhaps also u= to show all
forum events in chronological order
<li> For the p=X and bt=Y query parameter combination, if Y is a tag that
identifies multiple check-ins, search backwards in time for Y beginning
at X
</ol>
* Administrators can select to skip sending notifications about new forum
posts.
* If the value N is negative in "--context N" or "-c N" to the various diff
commands, then treat it as infinite and show the complete file content.
* The stock OCI container no longer includes BusyBox, thus no longer
needs to start as root to chroot that power away. That in turn
frees us from needing to build and install the container as root,
since it no longer has to create a private <tt>/dev</tt> tree
inside the jail for Fossil's use.
* Add support for the trigram tokenizer for FTS5 search to enable
searching in Chinese.
* Comment lines (starting with a '#') are now supported inside
[./settings.wiki#versionable|versioned settings].
* Default permissions for anonymous users in new repositories are
changed to "hz".
* The [/help?cmd=status|fossil status] command now detects when a
file used to be a symlink and has been replaced by a regular file.
(It previously checked for the inverse case only.)
* The [/help?cmd=empty-dirs|empty-dirs setting] now reuses the same
parser as the *-glob settings instead of its prior idiosyncratic
parser, allowing quoted whitespace in patterns.
* Enhancements to the [/help?cmd=/reports|/reports webpage]:
<ol type="a">
<li> The by-week, by-month, and by-year options now show an estimated
size of the current week, month, or year as a dashed box.
<li> New sub-categories "Merge Check-ins" and "Non-Merge Check-ins".
</ol>
<h2 id='v2_21'>Changes for version 2.21 (2023-02-25)</h2>
* Users can request a password reset. This feature is disabled by default.
Use the new [/help?cmd=self-pw-reset|self-pw-reset property] to enable it.
New web pages [/help?cmd=/resetpw|/resetpw] and
[/help?cmd=/reqpwreset|/reqpwreset] added.
* Add the [/help?cmd=repack|fossil repack] command (together with
[/help?cmd=all|fossil all repack]) as a convenient way to optimize the
size of one or all of the repositories on a system.
* Add the ability to put text descriptions on ticket report formats.
* Upgrade the test-find-pivot command to the [/help/merge-base|merge-base command].
* The [/help?cmd=/chat|/chat page] can now embed fossil-rendered
views of wiki/markdown/pikchr file attachments with the caveat that such
embedding happens in an iframe and thus does not inherit styles and such
from the containing browser window.
* The [/help?cmd=all|fossil all remote] subcommand added to "fossil all".
* Passwords for remembered remote repositories are now stored as irreversible
hashes rather than obscured clear-text, for improved security.
* Add the "nossl" and "nocompress" options to CGI.
* Update search infrastructure from FTS4 to FTS5.
* Add the [/help?cmd=/deltachain|/deltachain] page for debugging purposes.
* Writes to the database are disabled by default if the HTTP request
does not come from the same origin. This enhancement is a defense in depth
measure only; it does not address any known vulnerabilities.
* Improvements to automatic detection and mitigation of attacks from
malicious robots.
<h2 id='v2_20'>Changes for version 2.20 (2022-11-16)</h2>
* Added the [/help?cmd=chat-timeline-user|chat-timeline-user setting]. If
it is not an empty string, then any changes that would appear on the timeline
are announced in [./chat.md|the chat room].
* The /unsubscribe page now requests confirmation. [./alerts.md|Email notifications]
now contain only an "Unsubscribe" link, and not a link to subscription management.
* Added the "[/help?cmd=branch|fossil branch lsh]" subcommand to list the
most recently modified branches.
* More elements of the /info page are now inside of an accordion.
* Replace the <tt>--dryrun</tt> flag with <tt>--dry-run</tt> in all
commands which still used the former name, for consistency.
* Rebuilt [/file/Dockerfile | the stock Dockerfile] to create a "from scratch"
Busybox based container image via an Alpine Linux intermediary
* Added [/doc/trunk/www/containers.md | a new document] describing how to
customize, use, and run that container.
* Added "by hour of day" report to [/reports?view=byhour|the /reports page].
* Improved correctness, usability, and efficiency for the case
[/timeline?r=deltify-tkt-blobs|when values in a TICKET's column
tend to be long and volatile].
* Fixed a bug [/info/ea5afad31f478396 | introduced in 2.17] that
prevented <tt>clone --unversioned</tt> from completing the
retrieval of UV files from the remote repo. While fixing that, enabled
UV tracing output with <tt>clone --unversioned --verbose</tt>, making it
consonant with <tt>uv sync --verbose</tt>.
<h2 id='v2_19'>Changes for version 2.19 (2022-07-21)</h2>
* On file listing pages, sort filenames using the "uintnocase" collating
sequence, so that filenames that contains embedded integers sort in
numeric order even if they contain a different number of digits.
(Example: "fossil_80_..." comes before "fossil_100.png" in the
[/dir?ci=92fd091703a28c07&name=skins/blitz|/skins/blitz] directory listing.)
* Enhancements to the graph layout algorithm design to improve readability
and promote better situational awareness.
* Performance enhancement for the
[./checkin_names.wiki#root|"root:BRANCHNAME" style of tag],
accomplished using a Common Table Expression in the underlying SQL.
* Sort tag listings (command line and webpage) by taking numbers into
consideration so as to cater for tags that follow semantic versioning.
* On the wiki listings, omit by default wiki pages that are associated with
check-ins and branches.
* Add the new "[/help?cmd=describe|fossil describe]" command.
* Markdown subsystem extended with [../src/markdown.md#ftnts|footnotes support].
See corresponding [../test/markdown-test3.md|test cases],
[/wiki?name=branch/markdown-footnotes#il|known limitations] and
[forum:/forumthread/ee1f1597e46ec07a|discussion].
* Add the new special name "start:BRANCH" to refer to the first check-in of
the branch.
|
| ︙ | ︙ | |||
55 56 57 58 59 60 61 |
* The new [/help?cmd=cherry-pick|cherry-pick command] is an alias for
[/help?cmd=merge|merge --cherrypick].
* Add new setting "[/help?cmd=large-file-size|large-file-size]". If the size
of any file in a commit exceeds this size, a warning is issued.
* Query parameter "year=YYYY" is now accepted by [/help?cmd=/timeline|/timeline].
* The [/help?cmd=tar|tar] and [/help?cmd=zip|zip commands] no longer
sterilize the manifest file.
| | | | 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 |
* The new [/help?cmd=cherry-pick|cherry-pick command] is an alias for
[/help?cmd=merge|merge --cherrypick].
* Add new setting "[/help?cmd=large-file-size|large-file-size]". If the size
of any file in a commit exceeds this size, a warning is issued.
* Query parameter "year=YYYY" is now accepted by [/help?cmd=/timeline|/timeline].
* The [/help?cmd=tar|tar] and [/help?cmd=zip|zip commands] no longer
sterilize the manifest file.
* Further improvement to diff alignment in cases that involve both
edits and indentation changes.
* [/doc/trunk/www/chat.md|Chat] improvements:<ul>
<li> [/help?cmd=/chat|The /chat page] input options have been reworked
again for better cross-browser portability.
<li> When sending a [/help?cmd=/chat|/chat] message fails, it is no longer
immediately lost and sending may optionally be retried.
<li> [/help?cmd=/chat|/chat] can now optionally embed attachments of certain
types directly into message bodies via an iframe.
<li> Add the "--as FILENAME" option to the "[/help?cmd=chat|fossil chat send]"
command.
<li> Added the "[/help?cmd=chat|fossil chat pull]" command, available to
administrators only, for backing up the chat conversation.
</ul>
* Promote the test-detach command into the [/help?cmd=detach|detach command].
* For "[/help?cmd=pull|fossil pull]" with the --from-parent-project option,
if no URL is specified then use the last URL from the most recent prior
"fossil pull --from-parent-project".
* Add options --project-name and --project-desc to the
"[/help?cmd=init|fossil init]" command.
* The [/help?cmd=/ext|/ext page] generates the SERVER_SOFTWARE environment
variable for clients.
* Fix the REQUEST_URI [/doc/trunk/www/aboutcgi.wiki#cgivar|CGI variable] such
that it includes the query string. This is how most other systems understand
REQUEST_URI.
* Added the --transport-command option to [/help?cmd=sync|fossil sync]
|
| ︙ | ︙ | |||
95 96 97 98 99 100 101 |
<li> Better partial-line matching for side-by-side diffs
<li> Buttons on web-based diffs to show more context
<li> Performance improvements
</ul>
* The --branchcolor option on [/help?cmd=commit|fossil commit] and
[/help?cmd=amend|fossil amend] can now take the value "auto" to
force Fossil to use its built-in automatic color choosing algorithm.
| | | | 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 |
<li> Better partial-line matching for side-by-side diffs
<li> Buttons on web-based diffs to show more context
<li> Performance improvements
</ul>
* The --branchcolor option on [/help?cmd=commit|fossil commit] and
[/help?cmd=amend|fossil amend] can now take the value "auto" to
force Fossil to use its built-in automatic color choosing algorithm.
* Fossil now [./concepts.wiki#workflow|autosyncs] prior to running
[/help?cmd=open|fossil open].
* Add the [/help?cmd=ticket-default-report|ticket-default-report setting],
which if set to the title of a ticket report causes that ticket report
to be displayed below the search box in the /ticket page.
* The "nc" query parameter to the [/help?cmd=/timeline|/timeline] page
causes all graph coloring to be omitted.
* Improvements and bug fixes to the new "[/help?cmd=ui|fossil ui REMOTE]"
feature so that it works better on a wider variety of platforms.
* In [/help?cmd=/wikiedit|/wikiedit], show the list of attachments for
the current page and list URLs suitable for pasting them into the page.
* Add the --no-http-compression option to [/help?cmd=sync|fossil sync]
and similar.
* Print total payload bytes on a [/help?cmd=sync|fossil sync] when using
the --verbose option.
* Add the <tt>close</tt>, <tt>reopen</tt>, <tt>hide</tt>, and
</tt>unhide</tt> subcommands to [/help?cmd=branch|the branch command].
|
| ︙ | ︙ | |||
199 200 201 202 203 204 205 |
* <b>Patch 2.15.1:</b> Fix a data exfiltration bug in the server. <b>Upgrading to
the patch is recommended.</b>
* The [./defcsp.md|default CSP] has been relaxed slightly to allow
images to be loaded from any URL. All other resources are still
locked down by default.
* The built-in skins all use the "[/help?cmd=mainmenu|mainmenu]"
setting to determine the content of the main menu.
| | | | | | | | | | | | | 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 |
* <b>Patch 2.15.1:</b> Fix a data exfiltration bug in the server. <b>Upgrading to
the patch is recommended.</b>
* The [./defcsp.md|default CSP] has been relaxed slightly to allow
images to be loaded from any URL. All other resources are still
locked down by default.
* The built-in skins all use the "[/help?cmd=mainmenu|mainmenu]"
setting to determine the content of the main menu.
The ability to edit the
"mainmenu" setting is added on the /Admin/Configuration page.
* The hamburger menu is now available on most of the built-in skins.
* Any built-in skin named "X" can be used instead of the standard
repository skin by adding the URL parameter <tt>skin=X</tt> to the
request. The selection is persisted using the display
preferences cookie unless the "once" query parameter is also
included. The [/skins] page may be used to select a skin.
* The [/cookies] page now gives the user an opportunity to delete
individual cookies. And the /cookies page is linked from the
/sitemap, so that it appears in hamburger menus.
* The [/sitemap] extensions are now specified by a single new
"[/help?cmd=sitemap-extra|sitemap-extra setting]",
rather than a cluster of various
"sitemap-*" settings. The older settings are no longer used.
<b>This change might require minor server configuration
adjustments on servers that use /sitemap extensions.</b>
The /Admin/Configuration page provides the ability to edit
the new "sitemap-extra" setting.
* Added the "--ckout-alias NAME" option to
[/help?cmd=ui|fossil ui], [/help?cmd=server|fossil server], and
[/help?cmd=http|fossil http]. This option causes Fossil to
understand URIs of the form "/doc/NAME/..." as if they were
"[/help?cmd=/doc|/doc/ckout/...]", to facilitate testing of
[./embeddeddoc.wiki|embedded documentation] changes prior to
check-in.
* For diff web pages, if the diff type (unified versus side-by-side)
is not specified by a query parameter, and if the
"[/help?cmd=preferred-diff-type|preferred-diff-type]"
setting is omitted or less than 1, then select the diff type based
on a guess of whether or not the request is coming from a mobile
device. Mobile gets unified and desktop gets side-by-side.
* The various pages which show diffs now have toggles to show/hide
individual diffs.
* Add the "[/help?cmd=preferred-diff-type|preferred-diff-type]"
setting to allow an admin to force a default diff type.
* The "pikchr-background" setting is now available in
"detail.txt" skin files, for better control of Pikchr
colors in inverted color schemes.
* Add the <tt>--list</tt> option to the
[/help?cmd=tarball|tarball],
[/help?cmd=zip|zip], and [/help?cmd=sqlar|sqlar]
commands.
* The javascript used to implement the hamburger menu on the
default built-in skin has been made generic so that it is usable
by a variety of skins, and promoted to an ordinary built-in
javascript file.
* New TH1 commands:
"[/doc/trunk/www/th1.md#bireqjs|builtin_request_js]",
"[/doc/trunk/www/th1.md#capexpr|capexpr]",
"foreach", "lappend", and "string match"
* The [/help/leaves|leaves command] now shows the branch point
of each leaf.
* The [/help?cmd=add|fossil add] command refuses to add files whose
names are reserved by Windows (ex: "aux") unless the --allow-reserved
option is included. This helps prevent Unix users from accidentally
creating check-ins that are unreadable by Windows users.
* Add the "re=" query parameter to the [/help?cmd=/dir|/dir] webpage,
for symmetry with the [/help?cmd=/tree|/tree] page.
* Update the built-in SQLite to version 3.35.0.
* The ./configure script now has the --print-minimum-sqlite-version option
that prints the minimum SQLite version required by the current version
of Fossil. This might be used by integrators who insist on building
Fossil to link against the system SQLite library rather than the
built-in copy of SQLite, to verify that their system SQLite library
is recent enough.
* Webpage that shows [/help?cmd=/whistory|history of a wiki page]
gained client-side UI to help with comparison between two arbitrary
versions of a wiki (by the means of anchoring a "baseline" version)
and the ability to squeeze several sequential edits made by the same
user into a single "recycled" row (the latest edit in that sequence).
<h2 id='v2_14'>Changes for Version 2.14 (2021-01-20) and Patch 2.14.1 on (2021-04-07)
and 2.14.2 on (2021-06-15)</h2>
* <b>Patch 2.14.2:</b> Fix the client-side TLS so that it verifies that the
server hostname matches its certificate. <b>Upgrading to
the patch is recommended.</b>
* <b>Patch 2.14.1:</b> Fix a data exfiltration bug in the server.
<b>Upgrading to the patch is recommended.</b>
* <b>Schema Update Notice #1:</b>
This release drops a trigger from the database schema (replacing
it with a TEMP trigger that is created as needed). This
change happens automatically the first time you
add content to a repository using Fossil 2.14 or later. No
action is needed on your part. However, if you upgrade to
version 2.14 and then later downgrade or otherwise use an earlier
version of Fossil, the email notification mechanism may fail
to send out notifications for some events, due to the missing
trigger. If you want to
permanently downgrade an installation, then you should run
"[/help?cmd=rebuild|fossil rebuild]" after the downgrade
to get email notifications working again. If you are not using
|
| ︙ | ︙ | |||
308 309 310 311 312 313 314 |
* The "[/help?cmd=clone|fossil clone]" command is enhanced so that
if the repository filename is omitted, an appropriate name is derived
from the remote URL and the newly cloned repo is opened. This makes
the clone command work more like Git, thus making it easier for
people transitioning from Git.
* Added the --mainbranch option to the [/help?cmd=git|fossil git export]
command.
| | | 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 |
* The "[/help?cmd=clone|fossil clone]" command is enhanced so that
if the repository filename is omitted, an appropriate name is derived
from the remote URL and the newly cloned repo is opened. This makes
the clone command work more like Git, thus making it easier for
people transitioning from Git.
* Added the --mainbranch option to the [/help?cmd=git|fossil git export]
command.
* Added the --format option to the
"[/help?cmd=timeline|fossil timeline]" command.
* Enhance the --numstat option on the
"[/help?cmd=diff|fossil diff]" command so that it shows a total
number of lines added and deleted and total number of files
modified.
* Add the "contact" sub-command to [/help?cmd=user|fossil user].
* Added commands "[/help?cmd=all|fossil all git export]" and
|
| ︙ | ︙ | |||
425 426 427 428 429 430 431 |
a setup user.
* Translate built-in help text into HTML for display on web pages.
[/help?cmd=help|Example].
* On the [/help?cmd=/timeline|/timeline] webpage, the combination
of query parameters "p=CHECKIN" and "bt=ANCESTOR" draws all
ancestors of CHECKIN going back to ANCESTOR. For example,
[/timeline?p=202006271506&bt=version-2.11] shows all ancestors
| | | | 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 |
a setup user.
* Translate built-in help text into HTML for display on web pages.
[/help?cmd=help|Example].
* On the [/help?cmd=/timeline|/timeline] webpage, the combination
of query parameters "p=CHECKIN" and "bt=ANCESTOR" draws all
ancestors of CHECKIN going back to ANCESTOR. For example,
[/timeline?p=202006271506&bt=version-2.11] shows all ancestors
of the checkin that occurred on 2020-06-27 15:06 going back to
the 2.11 release.
* Update the built-in SQLite so that the
"[/help?cmd=sql|fossil sql]" command supports new output
modes ".mode box" and ".mode json".
* Add the "<tt>obscure()</tt>" SQL function to the
"[/help?cmd=sql|fossil sql]" command.
* Added virtual tables "<tt>helptext</tt>" and "<tt>builtin</tt>" to
the "[/help?cmd=sql|fossil sql]" command, providing access to the
dispatch table including all help text, and the builtin data files,
respectively.
* [./delta_format.wiki|Delta compression] is now applied to forum edits.
* The [/help?cmd=/wikiedit|wiki editor] has been modernized and is
|
| ︙ | ︙ | |||
467 468 469 470 471 472 473 |
<ul><li> "[/help?cmd=rebuild|fossil rebuild]" is needed to
take full advantage of this fix. Fossil will continue
to work without the rebuild, but the new backlinks will be missing.</ul>
* The algorithm for finding the
[./tech_overview.wiki#configloc|location of the configuration database]
is enhanced to be XDG-compliant.
* Add a hide/show feature to
| | | 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 |
<ul><li> "[/help?cmd=rebuild|fossil rebuild]" is needed to
take full advantage of this fix. Fossil will continue
to work without the rebuild, but the new backlinks will be missing.</ul>
* The algorithm for finding the
[./tech_overview.wiki#configloc|location of the configuration database]
is enhanced to be XDG-compliant.
* Add a hide/show feature to
[./wikitheory.wiki#assocwiki|associated wiki] display on
check-in and branch information pages.
* Enhance the "[/help?cmd=info|fossil info]" command so that it
works with no arguments even if not within an open check-out.
* Many improvements to the forum and especially email notification
of forum posts, in response to community feedback after switching
SQLite support from a mailing list over to the forum.
* Minimum length of a self-registered user ID increased from 3 to 6
|
| ︙ | ︙ | |||
1314 1315 1316 1317 1318 1319 1320 |
* Enhance the SSH transport mechanism so that it runs a single instance of
the "fossil" executable on the remote side, obviating the need for a shell
on the remote side. Some users may need to add the "?fossil=/path/to/fossil"
query parameter to "ssh:" URIs if their fossil binary is not in a standard
place.
* Add the "[/help?cmd=blame | fossil blame]" command that works just like
"fossil annotate" but uses a different output format that includes the
| | | 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 |
* Enhance the SSH transport mechanism so that it runs a single instance of
the "fossil" executable on the remote side, obviating the need for a shell
on the remote side. Some users may need to add the "?fossil=/path/to/fossil"
query parameter to "ssh:" URIs if their fossil binary is not in a standard
place.
* Add the "[/help?cmd=blame | fossil blame]" command that works just like
"fossil annotate" but uses a different output format that includes the
user who made each change and omits line numbers.
* Add the "Tarball and ZIP-archive Prefix" configuration parameter under
Admin/Configuration.
* Fix CGI processing so that it works on web servers that do not
supply REQUEST_URI.
* Add options --dirsonly, --emptydirs, and --allckouts to the
"[/help?cmd=clean | fossil clean]" command.
* Ten-fold performance improvement in large "fossil blame" or
|
| ︙ | ︙ | |||
1520 1521 1522 1523 1524 1525 1526 |
* Improved detection of forks in a commit race.
* Added the --analyze option to "fossil rebuild".
<h2>Changes For Version 1.24 (2012-10-22)</h2>
* Added support for WYSIWYG editing of wiki pages. WYSIWYG is turned off
by default and can be turned on by setting a configuration option.
* Allow style= attribute to occur in HTML markup on wiki pages.
| | | 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 |
* Improved detection of forks in a commit race.
* Added the --analyze option to "fossil rebuild".
<h2>Changes For Version 1.24 (2012-10-22)</h2>
* Added support for WYSIWYG editing of wiki pages. WYSIWYG is turned off
by default and can be turned on by setting a configuration option.
* Allow style= attribute to occur in HTML markup on wiki pages.
* Added the --tk option to the "fossil diff" and "fossil stash diff"
commands, causing color-coded diff output to be displayed in a Tcl/Tk
GUI window. This option only works if Tcl/Tk is installed on the
host.
* On Windows, make the "gdiff" command default to use WinDiff.exe.
* Update the "fossil stash" command so that it always prompts for a
comment if the -m option is omitted.
* Enhance the timeline webpages so that a=, b=, c=, d=, p=, and dp=
|
| ︙ | ︙ |
Changes to www/checkin_names.wiki.
| ︙ | ︙ | |||
31 32 33 34 35 36 37 | <blockquote> <tt>fossil info</tt> <i>checkin-name</i> </blockquote> You are perhaps reading this page from the following URL: <blockquote> | | | 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | <blockquote> <tt>fossil info</tt> <i>checkin-name</i> </blockquote> You are perhaps reading this page from the following URL: <blockquote> https://fossil-scm.org/home/doc/<b>trunk</b>/www/checkin_names.wiki </blockquote> The URL above is an example of an [./embeddeddoc.wiki | embedded documentation] page in Fossil. The bold term of the pathname is a check-in name that determines which version of the documentation to display. Fossil provides a variety of ways to specify a check-in. This |
| ︙ | ︙ | |||
179 180 181 182 183 184 185 | cut, but you could force Fossil to interpret that string as a date rather than as a tag by passing “date:2020-04-01”. For an example of how timestamps are useful, consider the homepage for the Fossil website itself: <blockquote> | | | | 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 | cut, but you could force Fossil to interpret that string as a date rather than as a tag by passing “date:2020-04-01”. For an example of how timestamps are useful, consider the homepage for the Fossil website itself: <blockquote> https://fossil-scm.org/home/doc/<b>trunk</b>/www/index.wiki </blockquote> The bold component of that URL is a check-in name. To see the stored content of the Fossil website repository as of January 1, 2009, one has merely to change the URL to the following: <blockquote> https://fossil-scm.org/home/doc/<b>2009-01-01</b>/www/index.wiki </blockquote> (Note that this won't roll you back to the <i>skin</i> and other cosmetic configurations as of that date. It also won't change screens like the timeline, which has an independent date selector.) <h2 id="tag-ts">Tag And Timestamp</h2> |
| ︙ | ︙ | |||
236 237 238 239 240 241 242 | The resulting diff will then show only the changes in the branch itself, omitting any changes that have already been merged in from the parent branch. <a id="start"></a> The prefix "<tt>start:</tt>" gives the first check-in of the named branch. | | | | 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 | The resulting diff will then show only the changes in the branch itself, omitting any changes that have already been merged in from the parent branch. <a id="start"></a> The prefix "<tt>start:</tt>" gives the first check-in of the named branch. The prefixes "<tt>root:</tt>", "<tt>start:</tt>", and "<tt>merge-in:</tt>" can be chained: one can say for example <blockquote><tt> fossil info merge-in:xyzzy:2022-03-01 </tt></blockquote> to get informations about the most recent merge-in point on the branch "xyzzy" that happened on or before March 1, 2022. |
| ︙ | ︙ |
Changes to www/concepts.wiki.
| ︙ | ︙ | |||
157 158 159 160 161 162 163 | of the file and the name of the file as it appears on disk, and thus serves as a mapping from artifact ID to disk name. The artifact ID of the manifest is the identifier for the entire check-in. When you look at a "timeline" of changes in Fossil, the ID associated with each check-in or commit is really just the artifact ID of the manifest for that check-in. | | | | | | | 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 |
of the file and the name of the file as it appears on disk,
and thus serves as a mapping from artifact ID to disk name. The artifact ID
of the manifest is the identifier for the entire check-in. When
you look at a "timeline" of changes in Fossil, the ID associated
with each check-in or commit is really just the artifact ID of the
manifest for that check-in.
The manifest file is not normally a real file on disk. Instead,
the manifest is computed in memory by Fossil whenever it needs it.
However, the "fossil setting manifest on" command will cause the
manifest file to be materialized to disk, if desired. Both Fossil
itself, and SQLite cause the manifest file to be materialized to disk
so that the makefiles for these project can read the manifest and
embed version information in generated binaries.
Fossil automatically generates a manifest whenever you "commit"
a new check-in. So this is not something that you, the developer,
need to worry with. The format of a manifest is intentionally
designed to be simple to parse, so that if
you want to read and interpret a manifest, either by hand or
with a script, that is easy to do. But you will probably never
need to do so.
In addition to identifying all files in the check-in, a
manifest also contains a check-in comment, the date and time
when the check-in was established, who created the check-in,
and links to other check-ins from which the current check-in
is derived. There is also a couple of checksums used to verify
the integrity of the check-in. And the whole manifest might
be PGP clearsigned.
<h3 id="keyconc">2.3 Key concepts</h3>
<ul>
<li>A <b>check-in</b> is a set of files arranged
in a hierarchy.</li>
<li>A <b>repository</b> keeps a record of historical check-ins.</li>
|
| ︙ | ︙ | |||
433 434 435 436 437 438 439 | </ol> <h2>5.0 Setting Up A Fossil Server</h2> With other configuration management software, setting up a server is a lot of work and normally takes time, patience, and a lot of system knowledge. Fossil is designed to avoid this frustration. Setting up | | < | | | | | | | | | | | | | | | < | 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 |
</ol>
<h2>5.0 Setting Up A Fossil Server</h2>
With other configuration management software, setting up a server is
a lot of work and normally takes time, patience, and a lot of system
knowledge. Fossil is designed to avoid this frustration. Setting up
a server with Fossil is ridiculously easy. You have four options:
# <b>Stand-alone server.</b>
Simply run the [/help?cmd=server|fossil server] or
[/help?cmd=ui|fossil ui] command from the command-line.
<br><br>
# <b>CGI.</b>
Install a 2-line CGI script on a CGI-enabled web-server like Apache.
<br><br>
# <b>SCGI.</b>
Start an SCGI server using the
[/help?cmd=server| fossil server --scgi] command for handling
SCGI requests from web-servers like Nginx.
<br><br>
# <b>Inetd or Stunnel.</b>
Configure programs like inetd, xinetd, or stunnel to hand off HTTP requests
directly to the [/help?cmd=http|fossil http] command.
See the [./server/ | How To Configure A Fossil Server] document
for details.
<h2>6.0 Review Of Key Concepts</h2>
<ul>
|
| ︙ | ︙ |
Changes to www/containers.md.
| ︙ | ︙ | |||
8 9 10 11 12 13 14 | [Docker]: https://www.docker.com/ [OCI]: https://opencontainers.org/ ## 1. Quick Start | | | | < | > | | > > | | | | 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 | [Docker]: https://www.docker.com/ [OCI]: https://opencontainers.org/ ## 1. Quick Start Fossil ships a `Dockerfile` at the top of its source tree, [here][DF], which you can build like so: ``` $ docker build -t fossil . ``` If the image built successfully, you can create a container from it and test that it runs: ``` $ docker run --name fossil -p 9999:8080/tcp fossil ``` This shows us remapping the internal TCP listening port as 9999 on the host. This feature of OCI runtimes means there’s little point to using the “`fossil server --port`” feature inside the container. We can let Fossil default to 8080 internally, then remap it to wherever we want it on the host instead. Our stock `Dockerfile` configures Fossil with the default feature set, so you may wish to modify the `Dockerfile` to add configuration options, add APK packages to support those options, and so forth. The Fossil `Makefile` provides two convenience targets, “`make container-image`” and “`make container-run`”. The first creates a versioned container image, and the second does that and then launches a fresh container based on that image. You can pass extra arguments to the first command via the Makefile’s `DBFLAGS` variable and to the second with the `DCFLAGS` variable. (DB is short for “`docker build`”, and DC is short for “`docker create`”, a sub-step of the “run” target.) To get the custom port setting as in second command above, say: ``` $ make container-run DCFLAGS='-p 9999:8080/tcp' ``` Contrast the raw “`docker`” commands above, which create an _unversioned_ image called `fossil:latest` and from that a container simply called `fossil`. The unversioned names are more convenient for interactive use, while the versioned ones are good for CI/CD type applications since they avoid a conflict with past versions; it lets you keep old containers around for quick roll-backs while replacing them with fresh ones. [DF]: /file/Dockerfile ## 2. <a id="storage"></a>Repository Storage Options If you want the container to serve an existing repository, there are at least two right ways to do it. The wrong way is to use the `Dockerfile COPY` command, because by baking the repo into the image at build time, it will become one of the image’s base layers. The end result is that each time you build a container from that image, the repo will be reset to its build-time state. Worse, restarting the container will do the same thing, since the base image layers are immutable. This is almost certainly not what you want. The correct ways put the repo into the _container_ created from the _image_, not in the image itself. ### <a id="repo-inside"></a> 2.1 Storing the Repo Inside the Container The simplest method is to stop the container if it was running, then say: ``` $ docker cp /path/to/my-project.fossil fossil:/museum/repo.fossil $ docker start fossil $ docker exec fossil chown -R 499 /museum ``` That copies the local Fossil repo into the container where the server expects to find it, so that the “start” command causes it to serve from that copied-in file instead. Since it lives atop the immutable base layers, it persists as part of the container proper, surviving restarts. |
| ︙ | ︙ | |||
110 111 112 113 114 115 116 | privileges after it enters the chroot. (See [below](#args) for how to change this default.) You don’t have to restart the server after fixing this with `chmod`: simply reload the browser, and Fossil will try again. ### 2.2 <a id="bind-mount"></a>Storing the Repo Outside the Container | | | | | | | < < < < < | | | < < < < < < < < < < < < < < < < < < < < < < | | | | < | < | | < < < < < < < < < < < < < | < < < < | < < < < < < | < < < < < < < < | | 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 |
privileges after it enters the chroot. (See [below](#args) for how to
change this default.) You don’t have to restart the server after fixing
this with `chmod`: simply reload the browser, and Fossil will try again.
### 2.2 <a id="bind-mount"></a>Storing the Repo Outside the Container
The simple storage method above has a problem: containers are
designed to be killed off at the slightest cause, rebuilt, and
redeployed. If you do that with the repo inside the container, it gets
destroyed, too. The solution is to replace the “run” command above with
the following:
```
$ docker run \
--publish 9999:8080 \
--name fossil-bind-mount \
--volume ~/museum:/museum \
fossil
```
Because this bind mount maps a host-side directory (`~/museum`) into the
container, you don’t need to `docker cp` the repo into the container at
all. It still expects to find the repository as `repo.fossil` under that
directory, but now both the host and the container can see that repo DB.
Instead of a bind mount, you could instead set up a separate
[volume](https://docs.docker.com/storage/volumes/), at which point you
_would_ need to `docker cp` the repo file into the container.
Either way, files in these mounted directories have a lifetime
independent of the container(s) they’re mounted into. When you need to
rebuild the container or its underlying image — such as to upgrade to a
newer version of Fossil — the external directory remains behind and gets
remapped into the new container when you recreate it with `--volume/-v`.
#### 2.2.1 <a id="wal-mode"></a>WAL Mode Interactions
You might be aware that OCI containers allow mapping a single file into
the repository rather than a whole directory. Since Fossil repositories
are specially-formatted SQLite databases, you might be wondering why we
don’t say things like:
```
--volume ~/museum/my-project.fossil:/museum/repo.fossil
```
That lets us have a convenient file name for the project outside the
container while letting the configuration inside the container refer to
the generic “`/museum/repo.fossil`” name. Why should we have to name
the repo generically on the outside merely to placate the container?
The reason is, you might be serving that repo with [WAL mode][wal]
enabled. If you map the repo DB alone into the container, the Fossil
instance inside the container will write the `-journal` and `-wal` files
alongside the mapped-in repository inside the container. That’s fine as
far as it goes, but if you then try using the same repo DB from outside
the container while there’s an active WAL, the Fossil instance outside
won’t know about it. It will think it needs to write *its own*
`-journal` and `-wal` files *outside* the container, creating a high
risk of [database corruption][dbcorr].
If we map a whole directory, both sides see the same set of WAL files.
[Testing](https://tangentsoft.com/sqlite/dir/walbanger?ci=trunk)
gives us a reasonable level of confidence that using WAL across a
container boundary is safe when used in this manner.
[dbcorr]: https://www.sqlite.org/howtocorrupt.html#_deleting_a_hot_journal
[wal]: https://www.sqlite.org/wal.html
## 3. <a id="security"></a>Security
### 3.1 <a id="chroot"></a>Why Not Chroot?
Prior to 2023.03.26, the stock Fossil container relied on [the chroot
jail feature](./chroot.md) to wall away the shell and other tools
provided by [BusyBox]. It included that as a bare-bones operating system
inside the container on the off chance that someone might need it for
debugging, but the thing is, Fossil is self-contained, needing none of
that power in the main-line use cases.
Our weak “you might need it” justification collapsed when we realized
you could restore this basic shell environment with a one-line change to
the `Dockerfile`, as shown [below](#run).
[BusyBox]: https://www.busybox.net/BusyBox.html
### 3.2 <a id="caps"></a>Dropping Unnecessary Capabilities
The example commands above create the container with [a default set of
Linux kernel capabilities][defcap]. Although Docker strips away almost
all of the traditional root capabilities by default, and Fossil doesn’t
|
| ︙ | ︙ | |||
276 277 278 279 280 281 282 |
* **`CHOWN`**: The Fossil server never even calls `chown(2)`, and our
image build process sets up all file ownership properly, to the
extent that this is possible under the limitations of our
automation.
Curiously, stripping this capability doesn’t affect your ability to
| | | 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 |
* **`CHOWN`**: The Fossil server never even calls `chown(2)`, and our
image build process sets up all file ownership properly, to the
extent that this is possible under the limitations of our
automation.
Curiously, stripping this capability doesn’t affect your ability to
run commands like “`chown -R fossil:fossil /museum`” when
you’re using bind mounts or external volumes — as we recommend
[above](#bind-mount) — because it’s the host OS’s kernel
capabilities that affect the underlying `chown(2)` call in that
case, not those of the container.
If for some reason you did have to change file ownership of
in-container files, it’s best to do that by changing the
|
| ︙ | ︙ | |||
304 305 306 307 308 309 310 |
[backoffice], and then only for processes it created on earlier
runs; it doesn’t need the ability to kill processes created by other
users. You might wish for this ability as an administrator shelled
into the container, but you can pass the “`docker exec --user`”
option to run commands within your container as the legitimate owner
of the process, removing the need for this capability.
| > > > | | < < < | | | > > | > | < | 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 |
[backoffice], and then only for processes it created on earlier
runs; it doesn’t need the ability to kill processes created by other
users. You might wish for this ability as an administrator shelled
into the container, but you can pass the “`docker exec --user`”
option to run commands within your container as the legitimate owner
of the process, removing the need for this capability.
* **`MKNOD`**: As of 2023.03.26, the stock container uses the
runtime’s default `/dev` node tree. Prior to this, we had to create
`/dev/null` and `/dev/urandom` inside [the chroot jail](#chroot),
but even then, these device nodes were created at build time and
were never changed at run time, so we didn’t need this run-time
capability even then.
* **`NET_BIND_SERVICE`**: With containerized deployment, Fossil never
needs the ability to bind the server to low-numbered TCP ports, not
even if you’re running the server in production with TLS enabled and
want the service bound to port 443. It’s perfectly fine to let the
Fossil instance inside the container bind to its default port (8080)
because you can rebind it on the host with the
“`docker create --publish 443:8080`” option. It’s the container’s
_host_ that needs this ability, not the container itself.
(Even the container runtime might not need that capability if you’re
[terminating TLS with a front-end proxy](./ssl.wiki#server). You’re
more likely to say something like “`-p localhost:12345:8080`” and then
configure the reverse proxy to translate external HTTPS calls into
HTTP directed at this internal port 12345.)
* **`NET_RAW`**: Fossil itself doesn’t use raw sockets, and while
you could [swap out the run layer](#run) for something more
functional that *does* make use of raw sockets, there’s little call
for it. The best reason I can come up with is to be able to run
utilities like `ping` and `traceroute`, but since we aren’t doing
anything clever with the networking configuration, there’s no
particularly compelling reason to run these from inside the
container. If you need to ping something, do it on the host.
If we did not take this hard-line stance, an attacker that broke
into the container and gained root privileges might use raw sockets
to do a wide array of bad things to any network the container is
bound to.
|
| ︙ | ︙ | |||
370 371 372 373 374 375 376 | [capchg]: https://stackoverflow.com/a/45752205/142454 ## 4. <a id="static"></a>Extracting a Static Binary Our 2-stage build process uses Alpine Linux only as a build host. Once | | | | | | | | | | | | | | < < < | < < < < < < < < < < < < | > | | | | > | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | | | 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 |
[capchg]: https://stackoverflow.com/a/45752205/142454
## 4. <a id="static"></a>Extracting a Static Binary
Our 2-stage build process uses Alpine Linux only as a build host. Once
we’ve got everything reduced to a single static Fossil binary,
we throw all the rest of it away.
A secondary benefit falls out of this process for free: it’s arguably
the easiest way to build a purely static Fossil binary for Linux. Most
modern Linux distros make this [surprisingly difficult][lsl], but Alpine’s
back-to-basics nature makes static builds work the way they used to,
back in the day. If that’s all you’re after, you can do so as easily as
this:
```
$ docker build -t fossil .
$ docker create --name fossil-static-tmp fossil
$ docker cp fossil-static-tmp:/bin/fossil .
$ docker container rm fossil-static-tmp
```
The result is six or seven megs, depending on the CPU architecture you
build for. It’s built stripped.
[lsl]: https://stackoverflow.com/questions/3430400/linux-static-linking-is-dead
## 5. <a id="custom" name="args"></a>Customization Points
### <a id="pkg-vers"></a> 5.1 Fossil Version
The default version of Fossil fetched in the build is the version in the
checkout directory at the time you run it. You could override it to get
a release build like so:
```
$ docker build -t fossil --build-arg FSLVER=version-2.20 .
```
Or equivalently, using Fossil’s `Makefile` convenience target:
```
$ make container-image DBFLAGS='--build-arg FSLVER=version-2.20'
```
While you could instead use the generic
“`release`” tag here, it’s better to use a specific version number
since container builders cache downloaded files, hoping to
reuse them across builds. If you ask for “`release`” before a new
version is tagged and then immediately after, you might expect to get
two different tarballs, but because the underlying source tarball URL
remains the same when you do that, you’ll end up reusing the
old tarball from cache. This will occur
even if you pass the “`docker build --no-cache`” option.
This is why we default to pulling the Fossil tarball by checkin ID
rather than let it default to the generic “`trunk`” tag: so the URL will
change each time you update your Fossil source tree, forcing the builder to
pull a fresh tarball.
### 5.2 <a id="uids"></a>User & Group IDs
The “`fossil`” user and group IDs inside the container default to 499.
Why? Regular user IDs start at 500 or 1000 on most Unix type systems,
leaving those below it for system users like this Fossil daemon owner.
Since it’s typical for these to start at 0 and go upward, we started at
500 and went *down* one instead to reduce the chance of a conflict to as
close to zero as we can manage.
To change it to something else, say:
```
$ make container-image DBFLAGS='--build-arg UID=501'
```
This is particularly useful if you’re putting your repository on a
separate volume since the IDs “leak” out into the host environment via
file permissions. You may therefore wish them to mean something on both
sides of the container barrier rather than have “499” appear on the host
in “`ls -l`” output.
### 5.3 <a id="cengine"></a>Container Engine
Although the Fossil container build system defaults to Docker, we allow
for use of any OCI container system that implements the same interfaces.
We go into more details about this [below](#light), but
for now, it suffices to point out that you can switch to Podman while
using our `Makefile` convenience targets unchanged by saying:
```
$ make CENGINE=podman container-run
```
### 5.4 <a id="config"></a>Fossil Configuration Options
You can use this same mechanism to enable non-default Fossil
configuration options in your build. For instance, to turn on
the JSON API and the TH1 docs extension:
```
$ make container-image \
DBFLAGS='--build-arg FSLCFG="--json --with-th1-docs"'
```
If you also wanted [the Tcl evaluation extension](./th1.md#tclEval),
that brings us to [the next point](#run).
### 5.5 <a id="run"></a>Elaborating the Run Layer
If you want a basic shell environment for temporary debugging of the
running container, that’s easily added. Simply change this line in the
`Dockerfile`…
FROM scratch AS run
…to this:
FROM busybox AS run
Rebuild and redeploy to give your Fossil container a [BusyBox]-based
shell environment that you can get into via:
$ docker exec -it -u fossil $(make container-version) sh
That command assumes you built it via “`make container`” and are
therefore using its versioning scheme.
You will likely want to remove the `PATH` override in the “RUN” stage
when doing this since it’s written for the case where everything is in
`/bin`, and that will no longer be the case with a more full-featured
“`run`” layer. As long as the parent layer’s `PATH` value contains
`/bin`, delegating to it is more likely the correct thing.
Another useful case to consider is that you’ve installed a [server
extension](./serverext.wiki) and you need an interpreter for that
script. The first option above won’t work except in the unlikely case that
it’s written for one of the bare-bones script interpreters that BusyBox
ships.(^[BusyBox]’s `/bin/sh` is based on the old 4.4BSD Lite Almquist
shell, implementing little more than what POSIX specified in 1989, plus
equally stripped-down versions of `awk` and `sed`.)
Let’s say the extension is written in Python. Because this is one of the
most popular programming languages in the world, we have many options
for achieving this. For instance, there is a whole class of
“[distroless]” images that will do this efficiently by changing
“`STAGE 2`” in the `Dockefile` to this:
```
## ---------------------------------------------------------------------
## STAGE 2: Pare that back to the bare essentials, plus Python.
## ---------------------------------------------------------------------
FROM cgr.dev/chainguard/python:latest
USER root
ARG UID=499
ENV PATH "/sbin:/usr/sbin:/bin:/usr/bin"
COPY --from=builder /tmp/fossil /bin/
COPY --from=builder /bin/busybox.static /bin/busybox
RUN [ "/bin/busybox", "--install", "/bin" ]
RUN set -x \
&& echo "fossil:x:${UID}:${UID}:User:/museum:/false" >> /etc/passwd \
&& echo "fossil:x:${UID}:fossil" >> /etc/group \
&& install -d -m 700 -o fossil -g fossil log museum
```
You will also have to add `busybox-static` to the APK package list in
STAGE 1 for the `RUN` script at the end of that stage to work, since the
[Chainguard Python image][cgimgs] lacks a shell, on purpose. The need to
install root-level binaries is why we change `USER` temporarily here.
Build it and test that it works like so:
```
$ make container-run &&
docker exec -i $(make container-version) python --version
3.11.2
```
The compensation for the hassle of using Chainguard over something more
general purpose like changing the `run` layer to Alpine and then adding
a “`apk add python`” command to the `Dockerfile`
is huge: we no longer leave a package manager sitting around inside the
container, waiting for some malefactor to figure out how to abuse it.
Beware that there’s a limit to this über-jail’s ability to save you when
you go and provide a more capable runtime layer like this. The container
layer should stop an attacker from accessing any files out on the host
that you haven’t explicitly mounted into the container’s namespace, but
it can’t stop them from making outbound network connections or modifying
the repo DB inside the container.
[cgimgs]: https://github.com/chainguard-images/images/tree/main/images
[distroless]: https://www.chainguard.dev/unchained/minimal-container-images-towards-a-more-secure-future
[MTA]: https://en.wikipedia.org/wiki/Message_transfer_agent
### 5.6 <a id="alerts"></a>Email Alerts
The nature of our single static binary container precludes two of the
options for [sending email alerts](./alerts.md) from Fossil:
* pipe to a command
* SMTP relay host
There is no `/usr/sbin/sendmail` inside the container, and the container
cannot connect out to a TCP service on the host by default.
While it is possible to get around the first lack by [elaborating the
run layer](#run), to inject a full-blown Sendmail setup into the
container would go against the whole idea of containerization.
Forwarding an SMTP relay port into the container isn’t nearly as bad,
but it’s still bending the intent behind containers out of shape.
A far better option in this case is the “store emails in database”
method since the containerized Fossil binary knows perfectly well how to
write SQLite DB files without relying on any external code. Using the
paths in the configuration recommended above, the database path should
be set to something like `/museum/mail.db`. This, along with the use of
[bind mounts](#bind-mount) means you can have a process running outside
the container that passes the emails along to the host-side MTA.
The included [`email-sender.tcl`](/file/tools/email-sender.tcl) script
works reasonably well for this, though in my own usage, I had to make
two changes to it:
1. The shebang line at the top has to be `#!/usr/bin/tclsh` on my server.
2. I parameterized the `DBFILE` variable at the top thus:
set DBFILE [lindex $argv 0]
I then wanted a way to start this Tcl script on startup and keep it
running, which made me reach for systemd. My server is set to allow user
services to run at boot(^”Desktop” class Linuxes tend to disable that by
default under the theory that you don’t want those services to run until
you’ve logged into the GUI as that user. If you find yourself running
into this, [enable linger
mode](https://www.freedesktop.org/software/systemd/man/loginctl.html).)
so I was able to create a unit file called
`~/.local/share/systemd/user/alert-sender@.service` with these contents:
```
[Unit]
Description=Fossil email alert sender for %I
[Service]
WorkingDirectory=/home/fossil/museum
ExecStart=/home/fossil/bin/alert-sender %I/mail.db
Restart=always
RestartSec=3
[Install]
WantedBy=default.target
```
I was then able to enable email alert forwarding for select repositories
after configuring them per [the docs](./alerts.md) by saying:
```
$ systemctl --user daemon-reload
$ systemctl --user enable alert-sender@myproject
$ systemctl --user start alert-sender@myproject
```
Because this is a parameterized script and we’ve set our repository
paths predictably, you can do this for as many repositories as you need
to by passing their names after the “`@`” sign in the commands above.
## 6. <a id="light"></a>Lightweight Alternatives to Docker
Those afflicted with sticker shock at seeing the size of a [Docker
Desktop][DD] installation — 1.65 GB here — might’ve immediately
“noped” out of the whole concept of containers. The first thing to
realize is that when it comes to actually serving simple containers like
the ones shown above is that [Docker Engine][DE] suffices, at about a
quarter of the size.
Yet on a small server — say, a $4/month ten gig Digital Ocean droplet —
that’s still a big chunk of your storage budget. It takes ~60:1 overhead
merely to run a Fossil server container? Once again, I wouldn’t
blame you if you noped right on out of here, but if you will be patient,
you will find that there are ways to run Fossil inside a container even
on entry-level cloud VPSes. These are well-suited to running Fossil; you
don’t have to resort to [raw Fossil service][srv] to succeed,
leaving the benefits of containerization to those with bigger budgets.
For the sake of simple examples in this section, we’ll assume you’re
integrating Fossil into a larger web site, such as with our [Debian +
nginx + TLS][DNT] plan. This is why all of the examples below create
the container with this option:
```
--publish 127.0.0.1:9999:8080
```
The assumption is that there’s a reverse proxy running somewhere that
redirects public web hits to localhost port 9999, which in turn goes to
port 8080 inside the container. This use of port
publishing effectively replaces the use of the
“`fossil server --localhost`” option.
For the nginx case, you need to add `--scgi` to these commands, and you
might also need to specify `--baseurl`.
Containers are a fine addition to such a scheme as they isolate the
|
| ︙ | ︙ | |||
514 515 516 517 518 519 520 521 522 523 524 525 | document, but you can find ready advice for that elsewhere. Seeing how we do this with Fossil should help you bridge the gap in extending this idea to the rest of your site.) [DD]: https://www.docker.com/products/docker-desktop/ [DE]: https://docs.docker.com/engine/ [DNT]: ./server/debian/nginx.md ### 6.1 <a id="nerdctl" name="containerd"></a>Stripping Docker Engine Down The core of Docker Engine is its [`containerd`][ctrd] daemon and the | > | > | | | | > | < < < < < < < < < < | < < < < | < | < < | < < < | < < | < < < < < | | | < < < < | < < < < < < < | < | < | < < < | | > | < | > > | < | < < > | | > < > | > | > > > > > > < < < < < < | | > > > < < < < < | > > > < > > > | < | < < < < < | < < < > | < < > > | > | > > > > > > > > | < > | < | < | > > | | | | > > > > > | | | < < < < > > > < < < < < < > > > > | | | | | > > > | > > > > < < > | < | | | | > | > > | > > > | > | | | | < | > | | | < > | < < < < < < | < < < < > > > > > > > > | > > > > > > < > > < < < < < | | < < < < | | < > | | | > > > > | < < < < > < | | | | < < < | > > > > | < > > > > > < > > > > > > | < < < < < < < < < | | | > > | | | | | < > > < | < > | | | | | < | | > | < < < < < > > > < < < | > > > > > < < < > > > > | > > > > | < < < | > | < | | | | | | | | | | > > > | < < < | | < | | | | | | < < | < < < < > > > > > > > < > > > > > > | | | > | | > > > > < > > | < > < > > < < < > > > > > > > < > > > | < < < < < < < < | | > | > | < < | < < > | 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 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 |
document, but you can find ready advice for that elsewhere. Seeing how
we do this with Fossil should help you bridge the gap in extending
this idea to the rest of your site.)
[DD]: https://www.docker.com/products/docker-desktop/
[DE]: https://docs.docker.com/engine/
[DNT]: ./server/debian/nginx.md
[srv]: ./server/
### 6.1 <a id="nerdctl" name="containerd"></a>Stripping Docker Engine Down
The core of Docker Engine is its [`containerd`][ctrd] daemon and the
[`runc`][runc] container runtime. Add to this the out-of-core CLI program
[`nerdctl`][nerdctl] and you have enough of the engine to run Fossil
containers. The big things you’re missing are:
* **BuildKit**: The container build engine, which doesn’t matter if
you’re building elsewhere and shipping the images to the target.
A good example is using a container registry as an
intermediary between the build and deployment hosts.
* **SwarmKit**: A powerful yet simple orchestrator for Docker that you
probably aren’t using with Fossil anyway.
In exchange, you get a runtime that’s about half the size of Docker
Engine. The commands are essentially the same as above, but you say
“`nerdctl`” instead of “`docker`”. You might alias one to the other,
because you’re still going to be using Docker to build and ship your
container images.
[ctrd]: https://containerd.io/
[nerdctl]: https://github.com/containerd/nerdctl
[runc]: https://github.com/opencontainers/runc
### 6.2 <a id="podman"></a>Podman
A lighter-weight [rootless][rl] [drop-in replacement][whatis] that
doesn’t give up the image builder is [Podman]. Initially created by
Red Hat and thus popular on that family of OSes, it will run on
any flavor of Linux. It can even be made to run [on macOS via Homebrew][pmmac]
or [on Windows via WSL2][pmwin].
On Ubuntu 22.04, the installation size is about 38 MiB, roughly a
tenth the size of Docker Engine.
For our purposes here, the only thing that changes relative to the
examples at the top of this document are the initial command:
```
$ podman build -t fossil .
$ podman run --name fossil -p 9999:8080/tcp fossil
```
Your Linux package repo may have a `podman-docker` package which
provides a “`docker`” script that calls “`podman`” for you, eliminating
even the command name difference. With that installed, the `make`
commands above will work with Podman as-is.
The only difference that matters here is that Podman doesn’t have the
same [default Linux kernel capability set](#caps) as Docker, which
affects the `--cap-drop` flags recommended above to:
```
$ podman create \
--name fossil \
--cap-drop CHOWN \
--cap-drop FSETID \
--cap-drop KILL \
--cap-drop NET_BIND_SERVICE \
--cap-drop SETFCAP \
--cap-drop SETPCAP \
--publish 127.0.0.1:9999:8080 \
localhost/fossil
$ podman start fossil
```
[pmmac]: https://podman.io/getting-started/installation.html#macos
[pmwin]: https://github.com/containers/podman/blob/main/docs/tutorials/podman-for-windows.md
[Podman]: https://podman.io/
[rl]: https://github.com/containers/podman/blob/main/docs/tutorials/rootless_tutorial.md
[whatis]: https://podman.io/whatis.html
### 6.3 <a id="nspawn"></a>`systemd-container`
If even the Podman stack is too big for you, the next-best option I’m
aware of is the `systemd-container` infrastructure on modern Linuxes,
available since version 239 or so. Its runtime tooling requires only
about 1.4 MiB of disk space:
```
$ sudo apt install systemd-container btrfs-tools
```
That command assumes the primary test environment for
this guide, Ubuntu 22.04 LTS with `systemd` 249. For best
results, `/var/lib/machines` should be a btrfs volume, because
[`$REASONS`][mcfad]. For CentOS Stream 9 and other Red Hattish
systems, you will have to make several adjustments, which we’ve
collected [below](#nspawn-centos) to keep these examples clear.
We’ll assume your Fossil repository stores something called
“`myproject`” within `~/museum/myproject/repo.fossil`, named according
to the reasons given [above](#repo-inside). We’ll make consistent use of
this naming scheme in the examples below so that you will be able to
replace the “`myproject`” element of the various file and path names.
If you use [the stock `Dockerfile`][DF] to generate your
base image, `nspawn` won’t recognize it as containing an OS unless you
change the “`FROM scratch AS os`” line at the top of the second stage
to something like this:
```
FROM gcr.io/distroless/static-debian11 AS os
```
Using that as a base image provides all the files `nspawn` checks for to
determine whether the container is sufficiently close to a Linux VM for
the following step to proceed:
```
$ make container
$ docker container export $(make container-version) |
machinectl import-tar - myproject
```
Next, create `/etc/systemd/nspawn/myproject.nspawn`:
----
```
[Exec]
WorkingDirectory=/
Parameters=bin/fossil server \
--baseurl https://example.com/myproject \
--create \
--jsmode bundled \
--localhost \
--port 9000 \
--scgi \
--user admin \
museum/repo.fossil
DropCapability= \
CAP_AUDIT_WRITE \
CAP_CHOWN \
CAP_FSETID \
CAP_KILL \
CAP_MKNOD \
CAP_NET_BIND_SERVICE \
CAP_NET_RAW \
CAP_SETFCAP \
CAP_SETPCAP
ProcessTwo=yes
LinkJournal=no
Timezone=no
[Files]
Bind=/home/fossil/museum/myproject:/museum
[Network]
VirtualEthernet=no
```
----
If you recognize most of that from the `Dockerfile` discussion above,
congratulations, you’ve been paying attention. The rest should also
be clear from context.
Some of this is expected to vary:
* The references to `example.com` and `myproject` are stand-ins for
your actual web site and repository name.
* The command given in the `Parameters` directive assumes you’re
setting up [SCGI proxying via nginx][DNT], but with adjustment,
it’ll work with the other repository service methods we’ve
[documented][srv].
* The path in the host-side part of the `Bind` value must point at the
directory containing the `repo.fossil` file referenced in said
command so that `/museum/repo.fossil` refers to your repo out
on the host for the reasons given [above](#bind-mount).
That being done, we also need a generic `systemd` unit file called
`/etc/systemd/system/fossil@.service`, containing:
----
```
[Unit]
Description=Fossil %i Repo Service
Wants=modprobe@tun.service modprobe@loop.service
After=network.target systemd-resolved.service modprobe@tun.service modprobe@loop.service
[Service]
ExecStart=systemd-nspawn --settings=override --read-only --machine=%i bin/fossil
[Install]
WantedBy=multi-user.target
```
----
You shouldn’t have to change any of this because we’ve given the
`--setting=override` flag, meaning any setting in the nspawn file
overrides the setting passed to `systemd-nspawn`. This arrangement
not only keeps the unit file simple, it allows multiple services to
share the base configuration, varying on a per-repo level through
adjustments to their individual `*.nspawn` files.
You may then start the service in the normal way:
```
$ sudo systemctl enable fossil@myproject
$ sudo systemctl start fossil@myproject
```
You should then find it running on localhost port 9000 per the nspawn
configuration file above, suitable for proxying Fossil out to the
public using nginx via SCGI. If you aren’t using a front-end proxy
and want Fossil exposed to the world via HTTPS, you might say this instead in
the `*.nspawn` file:
```
Parameters=bin/fossil server \
--cert /path/to/cert.pem \
--create \
--jsmode bundled \
--port 443 \
--user admin \
museum/repo.fossil
```
You would also need to un-drop the `CAP_NET_BIND_SERVICE` capability
to allow Fossil to bind to this low-numbered port.
We use the `systemd` template file feature to allow multiple Fossil
servers running on a single machine, each on a different TCP port,
as when proxying them out as subdirectories of a larger site.
To add another project, you must first clone the base “machine” layer:
```
$ sudo machinectl clone myproject otherthing
```
That will not only create a clone of `/var/lib/machines/myproject`
as `../otherthing`, it will create a matching `otherthing.nspawn` file for you
as a copy of the first one. Adjust its contents to suit, then enable
and start it as above.
[mcfad]: https://www.freedesktop.org/software/systemd/man/machinectl.html#Files%20and%20Directories
### 6.3.1 <a id="nspawn-rhel"></a>Getting It Working on a RHEL Clone
The biggest difference between doing this on OSes like CentOS versus
Ubuntu is that RHEL (thus also its clones) doesn’t ship btrfs in
its kernel, thus ships with no package repositories containing `mkfs.btrfs`, which
[`machinectl`][mctl] depends on for achieving its various purposes.
Fortunately, there are workarounds.
First, the `apt install` command above becomes:
```
$ sudo dnf install systemd-container
```
Second, you have to hack around the lack of `machinectl import-tar`:
```
$ rootfs=/var/lib/machines/fossil
$ sudo mkdir -p $rootfs
$ docker container export fossil | sudo tar -xf -C $rootfs -
```
The parent directory path in the `rootfs` variable is important,
because although we aren’t able to use `machinectl` on such systems, the
`systemd-nspawn` developers assume you’re using them together; when you give
`--machine`, it assumes the `machinectl` directory scheme. You could
instead use `--directory`, allowing you to store the rootfs wherever
you like, but why make things difficult? It’s a perfectly sensible
default, consistent with the [LHS] rules.
The final element — the machine name — can be anything
you like so long as it matches the nspawn file’s base name.
Finally, since you can’t use `machinectl clone`, you have to make
a wasteful copy of `/var/lib/machines/myproject` when standing up
multiple Fossil repo services on a single machine. (This is one
of the reasons `machinectl` depends on `btrfs`: cheap copy-on-write
subvolumes.) Because we give the `--read-only` flag, you can simply
`cp -r` one machine to a new name rather than go through the
export-and-import dance you used to create the first one.
[LHS]: https://refspecs.linuxfoundation.org/FHS_3.0/fhs/index.html
[mctl]: https://www.freedesktop.org/software/systemd/man/machinectl.html
### 6.3.2 <a id="nspawn-weaknesses"></a>What Am I Missing Out On?
For all the runtime size savings in this method, you may be wondering
what you’re missing out on relative to Podman, which takes up
roughly 27× more disk space. Short answer: lots. Long answer:
1. **Build system.** You’ll have to build and test your containers
some other way. This method is only suitable for running them
once they’re built.
2. **Orchestration.** All of the higher-level things like
“compose” files, Docker Swarm mode, and Kubernetes are
unavailable to you at this level. You can run multiple
instances of Fossil, but on a single machine only and with a
static configuration.
3. **Image layer sharing.** When you update an image using one of the
above methods, Docker and Podman are smart enough to copy only
changed layers. Furthermore, when you base multiple containers
on a single image, they don’t make copies of the base layers;
they can share them, because base layers are immutable, thus
cannot cross-contaminate.
Because we use `systemd-nspawn --read-only`, we get *some*
of this benefit, particularly when using `machinectl` with
`/var/lib/machines` as a btrfs volume. Even so, the disk space
and network I/O optimizations go deeper in the Docker and Podman
worlds.
4. **Tooling.** Hand-creating and modifying those `systemd`
files sucks compared to “`podman container create ...`” This
is but one of many affordances you will find in the runtimes
aimed at daily-use devops warriors.
5. **Network virtualization.** In the scheme above, we turn off the
`systemd` private networking support because in its default mode, it
wants to hide containerized services entirely. While there are
[ways][ndcmp] to expose Fossil’s single network service port under
that scheme, it adds a lot of administration complexity. In the
big-boy container runtimes, `docker create --publish` fixes all this
up in a single option, whereas `systemd-nspawn --port` does
approximately *none* of that despite the command’s superficial
similarity.
From a purely functional point of view, this isn’t a huge problem if
you consider the inbound service direction only, being external
connections to the Fossil service we’re providing. Since we do want
this Fossil service to be exposed — else why are we running it? — we
get all the control we need via `fossil server --localhost` and
similar options.
The complexity of the `systemd` networking infrastructure’s
interactions with containers make more sense when you consider the
outbound path. Consider what happens if you enable Fossil’s
optional TH1 docs feature plus its Tcl evaluation feature. That
would enable anyone with the rights to commit to your repository the
ability to make arbitrary network connections on the Fossil host.
Then, let us say you have a client-server DBMS server on that same
host, bound to localhost for private use by other services on the
machine. Now that DBMS is open to access by a rogue Fossil committer
because the host’s loopback interface is mapped directly into the
container’s network namespace.
Proper network virtualization would protect you in this instance.
This author expects that the set of considerations is broader than
presented here, but that it suffices to make our case as it is: if you
can afford the space of Podman or Docker, we strongly recommend using
either of them over the much lower-level `systemd-container`
infrastructure. You’re getting a considerable amount of value for the
higher runtime cost; it isn’t pointless overhead.
(Incidentally, these are essentially the same reasons why we no longer
talk about the `crun` tool underpinning Podman in this document. It’s
even more limited than `nspawn`, making it even more difficult to administer while
providing no runtime size advantage. The `runc` tool underpinning
Docker is even worse on this score, being scarcely easier to use than
`crun` while having a much larger footprint.)
[ndcmp]: https://wiki.archlinux.org/title/systemd-networkd#Usage_with_containers
### 6.3.3 <a id="nspawn-assumptions"></a>Violated Assumptions
The `systemd-container` infrastructure has a bunch of hard-coded
assumptions baked into it. We papered over these problems above,
but if you’re using these tools for other purposes on the machine
you’re serving Fossil from, you may need to know which assumptions
our container violates and the resulting consequences.
Some of it we discussed above already, but there’s one big class of
problems we haven’t covered yet. It stems from the fact that our stock
container starts a single static executable inside a bare-bones container
rather than “boot” an OS image. That causes a bunch of commands to fail:
* **`machinectl poweroff`** will fail because the container
isn’t running dbus.
* **`machinectl start`** will try to find an `/sbin/init`
program in the rootfs, which we haven’t got. We could
rename `/bin/fossil` to `/sbin/init` and then hack
the chroot scheme to match, but ick. (This, incidentally,
is why we set `ProcessTwo=yes` above even though Fossil is
perfectly capable of running as PID 1, a fact we depend on
in the other methods above.)
* **`machinectl shell`** will fail because there is no login
daemon running, which we purposefully avoided adding by
creating a “`FROM scratch`” container. (If you need a
shell, say: `sudo systemd-nspawn --machine=myproject /bin/sh`)
* **`machinectl status`** won’t give you the container logs
because we disabled the shared journal, which was in turn
necessary because we don’t run `systemd` *inside* the
container, just outside.
If these are problems for you, you may wish to build a
fatter container using `debootstrap` or similar. ([External
tutorial][medtut].)
[medtut]: https://medium.com/@huljar/setting-up-containers-with-systemd-nspawn-b719cff0fb8d
<div style="height:50em" id="this-space-intentionally-left-blank"></div>
|
Changes to www/custom_ticket.wiki.
1 2 3 | <title>Customizing The Ticket System</title> <nowiki> <h2>Introduction</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 |
<title>Customizing The Ticket System</title>
<nowiki>
<h2>Introduction</h2>
This guide will explain how to add the "assigned_to" and "submitted_by" fields
to the ticket system in Fossil, as well as making the system more useful. You
must have "admin" access to the repository to implement these instructions.
<h2>First modify the TICKET table</h2>
<blockquote>
Click on the "Admin" menu, then "Tickets", then "Table". After the other fields
and before the final ")", insert:
<pre>
,
assigned_to TEXT,
opened_by TEXT
</pre>
And "Apply Changes". You have just added two more fields to the ticket
database! NOTE: I won't tell you to "Apply Changes" after each step from here
on out. Now, how do you use these fields?
</blockquote>
<h2>Next add assignees</h2>
<blockquote>
Back to the "Tickets" admin page, and click "Common". Add something like this:
<pre>
set assigned_choices {
unassigned
tom
dick
harriet
}
</pre>
Obviously, choose names corresponding to the logins on your system. The
'unassigned' entry is important, as it prevents you from having a NULL in that
field (which causes problems later when editing).
</blockquote>
<h2>Now modify the 'new ticket' page</h2>
<blockquote>
Back to the "Tickets" admin page, and click "New Ticket Page". This is a little
more tricky. Edit the top part:
<pre>
if {[info exists submit]} {
set status Open
set opened_by $login
set assigned_to "unassigned"
|
| ︙ | ︙ | |||
64 65 66 67 68 69 70 | questions.</td> </tr> <th1>enable_output 1</th1> </pre> This bit of code will get rid of the "email" field entry for logged-in users. Since we know the user's information, we don't have to ask for it. NOTE: it might be good to automatically scoop up the user's email and put it here. | | < < | | > < | | > | | < | | > < | 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 |
questions.</td>
</tr>
<th1>enable_output 1</th1>
</pre>
This bit of code will get rid of the "email" field entry for logged-in users.
Since we know the user's information, we don't have to ask for it. NOTE: it
might be good to automatically scoop up the user's email and put it here.
You might also want to enable people to actually assign the ticket to a specific
person during creation. For this to work, you need to add the code
for "assigned_to" as shown below under the heading "Modify the 'edit ticket' page".
This will give you an additional combobox where you can choose a person during
ticket creation.
</blockquote>
<h2>Modify the 'view ticket' page</h2>
<blockquote>
Look for the text "Contact:" (about halfway through). Then insert these lines
after the closing tr tag and before the "enable_output" line:
<pre>
<tr>
<td align="right">Assigned to:</td><td bgcolor="#d0d0d0">
$<assigned_to>
</td>
<td align="right">Opened by:</td><td bgcolor="#d0d0d0">
$<opened_by>
</td>
</pre>
This will add a row which displays these two fields, in the event the user has
<a href="./caps/ref.html#w">ticket "edit" capability</a>.
</blockquote>
<h2>Modify the 'edit ticket' page</h2>
<blockquote>
Before the "Severity:" line, add this:
<pre>
<tr><td align="right">Assigned to:</td><td>
<th1>combobox assigned_to $assigned_choices 1</th1>
</td></tr>
</pre>
That will give you a drop-down list of assignees. The first argument to the TH1
command 'combobox' is the database field which the combobox is associated to.
The next argument is the list of choices you want to show in the combobox (and
that you specified in the second step above. The last argument should be 1 for a
true combobox (see the <a href="th1.md#combobox">TH1 documentation</a> for
details).
Now, similar to the previous
section, look for "Contact:" and add this:
<pre>
<tr><td align="right">Reported by:</td><td>
<input type="text" name="opened_by" size="40"
value="$<opened_by>">
</td></tr>
</pre>
</blockquote>
<h2>What next?</h2>
<blockquote>
Now you can add custom reports which select based on the person to whom the
ticket is assigned. For example, an "Assigned to me" report could be:
<pre>
SELECT
CASE WHEN status IN ('Open','Verified') THEN '#f2dcdc'
WHEN status='Review' THEN '#e8e8e8'
WHEN status='Fixed' THEN '#cfe8bd'
WHEN status='Tested' THEN '#bde5d6'
WHEN status='Deferred' THEN '#cacae5'
ELSE '#c8c8c8' END AS 'bgcolor',
substr(tkt_uuid,1,10) AS '#',
datetime(tkt_mtime) AS 'mtime',
type,
status,
subsystem,
title
FROM ticket
WHERE assigned_to=user()
</pre>
</blockquote>
</nowiki>
|
Changes to www/customskin.md.
| ︙ | ︙ | |||
76 77 78 79 80 81 82 |
Fossil *usually* (but not always - [see below](#override))
generates the initial HTML Header section of a page. The
generated HTML Header will look something like this:
<html>
<head>
| | | | | 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
Fossil *usually* (but not always - [see below](#override))
generates the initial HTML Header section of a page. The
generated HTML Header will look something like this:
<html>
<head>
<base href="...">
<meta http-equiv="Content-Security-Policy" content="....">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>....</title>
<link rel="stylesheet" href="..." type="text/css">
</head>
<body class="FEATURE">
…where `FEATURE` is either the top-level URL element (e.g. `doc`) or a
feature class that groups multiple URLs under a single name such as
`forum` to contain `/forummain`, `/forumpost`, `/forume2`, etc. This
allows per-feature CSS such as
|
| ︙ | ︙ | |||
178 179 180 181 182 183 184 | approach is to use one of the existing built-in skins as a baseline and make incremental modifications, testing after each step, to obtain the desired result. The skin is controlled by five files: <blockquote><dl> | | | | | | | | | | | | | 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 | approach is to use one of the existing built-in skins as a baseline and make incremental modifications, testing after each step, to obtain the desired result. The skin is controlled by five files: <blockquote><dl> <dt><b>css.txt</b></dt> <dd>The css.txt file is the text of the CSS for Fossil. Fossil might add additional CSS elements after the css.txt file, if it sees that the css.txt omits some CSS components that Fossil needs. But for the most part, the content of the css.txt is the CSS for the page.</dd> <dt><b>details.txt</b><dt> <dd>The details.txt file is short list of settings that control the look and feel, mostly of the timeline. The default details.txt file looks like this: <blockquote><pre> pikchr-background: "" pikchr-fontscale: "" pikchr-foreground: "" pikchr-scale: "" timeline-arrowheads: 1 timeline-circle-nodes: 1 timeline-color-graph-lines: 1 white-foreground: 0 </pre></blockquote> The three "timeline-" settings in details.txt control the appearance of certain aspects of the timeline graph. The number on the right is a boolean - "1" to activate the feature and "0" to disable it. The "white-foreground:" setting should be set to "1" if the page color has light-color text on a darker background, and "0" if the page has dark text on a light-colored background. If the "pikchr-foreground" setting (added in Fossil 2.14) is defined and is not an empty string then it specifies a foreground color to use for [pikchr diagrams](./pikchr.md). The default pikchr foreground color is black, or white if the "white-foreground" boolean is set. The "pikchr-background" settings does the same for the pikchr diagram background color. If the "pikchr-fontscale" and "pikchr-scale" values are not empty strings, then they should be floating point values (close to 1.0) that specify relative scaling of the fonts in pikchr diagrams and other elements of the diagrams, respectively. </dd> <dt><b>footer.txt</b> and <b>header.txt</b></dt> <dd>The footer.txt and header.txt files contain the Content Footer and Content Header respectively. Of these, the Content Header is the most important, as it contains the markup used to generate the banner and menu bar for each page. Both the footer.txt and header.txt file are [processed using TH1](#headfoot) prior to being output as part of the overall web page.</dd> <dt><b>js.txt</b></dt> <dd>The js.txt file is optional. It is intended to be javascript. The complete text of this javascript might be inserted into the Content Footer, after being processed using TH1, using code like the following in the "footer.txt" file: <blockquote><pre> <script nonce="$nonce"> <th1>styleScript</th1> </script> </pre></blockquote> The js.txt file was originally used to insert javascript that controls the hamburger menu in the default skin. More recently, the javascript for the hamburger menu was moved into a separate built-in file. Skins that use the hamburger menu typically cause the javascript to be loaded by including the following TH1 code in the "header.txt" file: <blockquote><pre> |
| ︙ | ︙ |
Changes to www/defcsp.md.
| ︙ | ︙ | |||
255 256 257 258 259 260 261 |
Although those files are all outside the Fossil repo at `/code`,
keep in mind that it is the browser’s notion of “self” that matters
here, not Fossil’s. All resources come from the same Internet
domain, so the browser cannot distinguish Fossil-provided content
from static content served directly by the proxy server.
| | | | 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 |
Although those files are all outside the Fossil repo at `/code`,
keep in mind that it is the browser’s notion of “self” that matters
here, not Fossil’s. All resources come from the same Internet
domain, so the browser cannot distinguish Fossil-provided content
from static content served directly by the proxy server.
This method opens up many other potential benefits, such as
[TLS encryption][tls], high-performance tuning via custom HTTP
headers, integration with other web technologies like PHP, etc.
You might wonder why we rank in-repo content as most preferred above. It
is because the first two options are the only ones that cause such
resources to be included in an initial clone or in subsequent repo
syncs. The methods further down the list have a number of undesirable
properties:
|
| ︙ | ︙ | |||
298 299 300 301 302 303 304 305 306 307 308 309 310 311 | [du]: /help?cmd=/doc [fp]: ./forum.wiki [ru]: /help?cmd=/raw [spof]: https://en.wikipedia.org/wiki/Single_point_of_failure [tkt]: ./tickets.wiki [tn]: ./event.wiki [uu]: /help?cmd=/uv [uv]: ./unvers.wiki [wiki]: ./wikitheory.wiki ## <a id="override"></a>Overriding the Default CSP | > | 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 | [du]: /help?cmd=/doc [fp]: ./forum.wiki [ru]: /help?cmd=/raw [spof]: https://en.wikipedia.org/wiki/Single_point_of_failure [tkt]: ./tickets.wiki [tn]: ./event.wiki [tls]: ./server/debian/nginx.md [uu]: /help?cmd=/uv [uv]: ./unvers.wiki [wiki]: ./wikitheory.wiki ## <a id="override"></a>Overriding the Default CSP |
| ︙ | ︙ |
Changes to www/delta_encoder_algorithm.wiki.
| ︙ | ︙ | |||
81 82 83 84 85 86 87 | computed. </li> <li>A hash table is filled, mapping from the hashes of the chunks to the list of chunk locations having this hash. </li> </ol> | | | 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 | computed. </li> <li>A hash table is filled, mapping from the hashes of the chunks to the list of chunk locations having this hash. </li> </ol> <h3 id="processing">2.2 Processing the target</h3> <p>This, the main phase of the encoder, processes the target in a loop from beginning to end. The state of the encoder is captured by two locations, the "base" and the "slide". "base" points to the first byte of the target for which no delta output has been generated yet, and "slide" is the location of the window used to look in the "origin" for commonalities. This window is NHASH bytes long.</p> |
| ︙ | ︙ |
Changes to www/delta_format.wiki.
1 2 3 | <title>Fossil Delta Format</title> <h1>1.0 Overview</h1> | | < | | | | | | | | 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 |
<title>Fossil Delta Format</title>
<h1>1.0 Overview</h1>
Fossil achieves efficient storage and low-bandwidth synchronization
through the use of delta-compression. Instead of storing
or transmitting the complete content of an artifact, Fossil stores or
transmits only the changes relative to a related artifact.
This document describes the delta-encoding format used by Fossil.
The intended audience is developers working on either
<a href="index.wiki">Fossil</a> itself, or on tools compatible with
Fossil. Understanding of this document is <em>not</em> required for
ordinary users of Fossil. This document is an implementation detail.
This document only describes the delta file format. A
[./delta_encoder_algorithm.wiki|separate document] describes one possible
algorithm for generating deltas in this format.
<h2>1.1 Sample Software And Analysis Tools</h2>
The core routines used to generate and apply deltas in this format
are contained in the [../src/delta.c|delta.c] source file. Interface
logic, including "test-*" commands to directly manipulate deltas are
contained in the [../src/deltacmd.c|deltacmd.c] source file. SQL functions
to create, apply, and analyze deltas are implemented by code in the
[../src/deltafunc.c|deltafunc.c] source file.
The following command-line tools are available to create and apply
deltas and to test the delta logic:
* [/help?cmd=test-delta|fossil test-delta] → Run self-tests of
the delta logic
* [/help?cmd=test-delta-create|fossil test-delta-create X Y] → compute
a delta that converts file X into file Y. Output that delta.
* [/help?cmd=test-delta-apply|fossil test-delta-apply X D] → apply
delta D to input file X and output the result.
* [/help?cmd=test-delta-analyze|fossil test-delta-analyze X Y] → compute
and delta that converts file X into file Y but instead of writing the
delta to output, write performance information about the delta.
When running the [/help?cmd=sqlite3|fossil sql] command to get an
interactive SQL session connected to the repository, the following
additional SQL functions are provided:
* <b>delta_create(</b><i>X</i><b>,</b><i>Y</i><b>)</b> →
Compute a data that carries blob X into blob Y and return that delta
as a blob.
|
| ︙ | ︙ | |||
66 67 68 69 70 71 72 |
<verbatim type="pikchr">
leftmargin = 0.1
box height 50% "Header"
box same "Segments"
box same "Trailer"
</verbatim>
| | | | | | | | | | | | | | | | 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 |
<verbatim type="pikchr">
leftmargin = 0.1
box height 50% "Header"
box same "Segments"
box same "Trailer"
</verbatim>
A delta consists of three parts, a "header", a "trailer", and a
"segment-list" between them.
Both header and trailer provide information about the target
helping the decoder, and the segment-list describes how the target can
be constructed from the original.
<h2 id="header">2.1 Header</h2>
<verbatim type="pikchr">
leftmargin = 0.1
box height 50% "Size"
box same "\"\\n\""
</verbatim>
The header consists of a single number followed by a newline
character (ASCII 0x0a). The number is the length of the target in
bytes.
This means that, given a delta, the decoder can compute the size of
the target (and allocate any necessary memory based on that) by simply
reading the first line of the delta and decoding the number found
there. In other words, before it has to decode everything else.
<h2 id="trailer">2.2 Trailer</h2>
<verbatim type="pikchr">
leftmargin = 0.1
box height 50% "Checksum"
box same "\";\""
</verbatim>
The trailer consists of a single number followed by a semicolon (ASCII
0x3b). This number is a checksum of the target and can be used by a
decoder to verify that the delta applied correctly, reconstructing the
target from the original.
The checksum is computed by treating the target as a series of
32-bit integer numbers (MSB first), and summing these up, modulo
2^32-1. A target whose length is not a multiple of 4 is padded with
0-bytes (ASCII 0x00) at the end.
By putting this information at the end of the delta a decoder has
it available immediately after the target has been reconstructed
fully.
<h2 id="slist">2.3 Segment-List</h2>
<verbatim type="pikchr">
leftmargin = 0.1
PART1: [
B1: box height 50% width 15% ""
B2: box same ""
|
| ︙ | ︙ | |||
136 137 138 139 140 141 142 |
box "Length" height 50%
right
box "\":\"" same
box "Bytes" same
] with .nw at previous.sw
</verbatim>
| | | | | | | | | | | | | < < < < | < | 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 |
box "Length" height 50%
right
box "\":\"" same
box "Bytes" same
] with .nw at previous.sw
</verbatim>
The segment-list of a delta describes how to create the target from
the original by a combination of inserting literal byte-sequences and
copying ranges of bytes from the original. This is where the
compression takes place, by encoding the large common parts of
original and target in small copy instructions.
The target is constructed from beginning to end, with the data
generated by each instruction appended after the data of all previous
instructions, with no gaps.
<h3 id="insertlit">2.3.1 Insert Literal</h3>
A literal is specified by two elements, the size of the literal in
bytes, and the bytes of the literal itself.
<verbatim type="pikchr">
leftmargin = 0.1
box "Length" height 50%
box "\":\"" same
box "Bytes" same
</verbatim>
The length is written first, followed by a colon character (ASCII
0x3a), followed by the bytes of the literal.
<h3 id="copyrange">2.3.2 Copy Range</h3>
A range to copy is specified by two numbers, the offset of the
first byte in the original to copy, and the size of the range, in
bytes. The size zero is special, its usage indicates that the range
extends to the end of the original.
<verbatim type="pikchr">
leftmargin = 0.1
box "Length" height 50%
box "\"@\"" same
box "Offset" same
box "\",\"" same
</verbatim>
The length is written first, followed by an "at" character (ASCII
0x40), then the offset, followed by a comma (ASCII 0x2c).
<h1 id="intcoding">3.0 Encoding of integers</h1>
The format currently handles only 32 bit integer numbers. They are
written base-64 encoded, MSB first, and without leading
"0"-characters, except if they are significant (i.e. 0 => "0").
The base-64 encoding uses one character for each 6 bits of
the integer to be encoded. The encoding characters are:
<blockquote><pre>
0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz~
</pre></blockquote>
The least significant 6 bits of the integer are encoded by
the first character, followed by
the next 6 bits, and so on until all non-zero bits of the integer
are encoded. The minimum number of encoding characters is used.
Note that for integers less than 10, the base-64 coding is a
ASCII decimal rendering of the number itself.
<h1 id="examples">4.0 Examples</h1>
<h2 id="examplesint">4.1 Integer encoding</h2>
<table border=1>
<tr>
|
| ︙ | ︙ | |||
230 231 232 233 234 235 236 | <td>-1101438770</td> <td>2zMM3E</td> </tr> </table> <h2 id="examplesdelta">4.2 Delta encoding</h2> | | | | | 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 | <td>-1101438770</td> <td>2zMM3E</td> </tr> </table> <h2 id="examplesdelta">4.2 Delta encoding</h2> An example of a delta using the specified encoding is: <table border=1><tr><td><pre> 1Xb 4E@0,2:thFN@4C,6:scenda1B@Jd,6:scenda5x@Kt,6:pieces79@Qt,F: Example: eskil~E@Y0,2zMM3E;</pre> </td></tr></table> This can be taken apart into the following parts: <table border=1> <tr><th>What </th> <th>Encoding </th><th>Meaning </th><th>Details</th></tr> <tr><td>Header</td> <td>1Xb </td><td>Size </td><td> 6246 </td></tr> <tr><td>S-List</td> <td>4E@0, </td><td>Copy </td><td> 270 @ 0 </td></tr> <tr><td> </td> <td>2:th </td><td>Literal </td><td> 2 'th' </td></tr> <tr><td> </td> <td>FN@4C, </td><td>Copy </td><td> 983 @ 268 </td></tr> <tr><td> </td> <td>6:scenda </td><td>Literal </td><td> 6 'scenda' </td></tr> <tr><td> </td> <td>1B@Jd, </td><td>Copy </td><td> 75 @ 1256 </td></tr> <tr><td> </td> <td>6:scenda </td><td>Literal </td><td> 6 'scenda' </td></tr> <tr><td> </td> <td>5x@Kt, </td><td>Copy </td><td> 380 @ 1336 </td></tr> <tr><td> </td> <td>6:pieces </td><td>Literal </td><td> 6 'pieces' </td></tr> <tr><td> </td> <td>79@Qt, </td><td>Copy </td><td> 457 @ 1720 </td></tr> <tr><td> </td> <td>F: Example: eskil</td><td>Literal </td><td> 15 ' Example: eskil'</td></tr> <tr><td> </td> <td>~E@Y0, </td><td>Copy </td><td> 4046 @ 2176 </td></tr> <tr><td>Trailer</td><td>2zMM3E </td><td>Checksum</td><td> -1101438770 </td></tr> </table> The unified diff behind the above delta is <table border=1><tr><td><pre> bluepeak:(761) ~/Projects/Tcl/Fossil/Devel/devel > diff -u ../DELTA/old ../DELTA/new --- ../DELTA/old 2007-08-23 21:14:40.000000000 -0700 +++ ../DELTA/new 2007-08-23 21:14:33.000000000 -0700 @@ -5,7 +5,7 @@ |
| ︙ | ︙ |
Changes to www/embeddeddoc.wiki.
| ︙ | ︙ | |||
199 200 201 202 203 204 205 | This file that you are currently reading is an example of embedded documentation. The name of this file in the fossil source tree is "<b>www/embeddeddoc.wiki</b>". You are perhaps looking at this file using the URL: | | | | | 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 | This file that you are currently reading is an example of embedded documentation. The name of this file in the fossil source tree is "<b>www/embeddeddoc.wiki</b>". You are perhaps looking at this file using the URL: [https://fossil-scm.org/home/doc/trunk/www/embeddeddoc.wiki]. The first part of this path, the "[https://fossil-scm.org/home]", is the base URL. You might have originally typed: [https://fossil-scm.org/]. The web server at the fossil-scm.org site automatically redirects such links by appending "home". The "home" file on fossil-scm.org is really a [./server/any/cgi.md|CGI script] which runs the fossil web service in CGI mode. The "home" CGI script looks like this: <blockquote><pre> #!/usr/bin/fossil |
| ︙ | ︙ | |||
241 242 243 244 245 246 247 | When the symbolic name is a date and time, fossil shows the version of the document that was most recently checked in as of the date and time specified. So, for example, to see what the fossil website looked like at the beginning of 2010, enter: <blockquote> | | | | 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 | When the symbolic name is a date and time, fossil shows the version of the document that was most recently checked in as of the date and time specified. So, for example, to see what the fossil website looked like at the beginning of 2010, enter: <blockquote> <a href="/doc/2010-01-01/www/index.wiki"> https://fossil-scm.org/home/doc/<b>2010-01-01</b>/www/index.wiki </a> </blockquote> The file that encodes this document is stored in the fossil source tree under the name "<b>www/embeddeddoc.wiki</b>" and so that name forms the last part of the URL for this document. |
| ︙ | ︙ |
Changes to www/encryptedrepos.wiki.
1 2 3 4 5 6 7 8 9 | <title>How To Use Encrypted Repositories</title> <h2>Introduction</h2><blockquote> Fossil can be compiled so that it works with encrypted repositories using the [https://www.sqlite.org/see/doc/trunk/www/readme.wiki|SQLite Encryption Extension]. This technical note explains the process. </blockquote> <h2>Building An Encryption-Enabled Fossil</h2><blockquote> The SQLite Encryption Extension (SEE) is proprietary software and requires [https://sqlite.org/purchase/see|purchasing a license]. | | | > | | | | 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 | <title>How To Use Encrypted Repositories</title> <h2>Introduction</h2><blockquote> Fossil can be compiled so that it works with encrypted repositories using the [https://www.sqlite.org/see/doc/trunk/www/readme.wiki|SQLite Encryption Extension]. This technical note explains the process. </blockquote> <h2>Building An Encryption-Enabled Fossil</h2><blockquote> The SQLite Encryption Extension (SEE) is proprietary software and requires [https://sqlite.org/purchase/see|purchasing a license]. Assuming you have an SEE license, the first step of compiling Fossil to use SEE is to create an SEE-enabled version of the SQLite database source code. This alternative SQLite database source file should be called "sqlite3-see.c" and should be placed in the extsrc/ subfolder of the Fossil sources, right beside the public-domain "sqlite3.c" source file. Also make a copy of the SEE-enabled "shell.c" file, renamed as "shell-see.c", and place it in the extsrc/ subfolder beside the original "shell.c". Add the --with-see command-line option to the configuration script to enable the use of SEE on unix-like systems. <blockquote><pre> ./configure --with-see; make </pre></blockquote> To build for Windows using MSVC, add the "USE_SEE=1" argument to the "nmake" command line. <blockquote><pre> nmake -f makefile.msc USE_SEE=1 </pre></blockquote> </blockquote> <h2>Using Encrypted Repositories</h2><blockquote> Any Fossil repositories whose filename ends with ".efossil" is taken to be an encrypted repository. Fossil will prompt for the encryption password and attempt to open the repository database using that password. Every invocation of fossil on an encrypted repository requires retyping the encryption password. To avoid excess password typing, consider using the "fossil shell" command which prompts for the password just once, then reuses it for each subsequent Fossil command entered at the prompt. On Windows, the "fossil server", "fossil ui", and "fossil shell" commands do not (currently) work on an encrypted repository. </blockquote> <h2>Additional Security</h2><blockquote> Use the FOSSIL_SECURITY_LEVEL environment for additional protection. <blockquote><pre> export FOSSIL_SECURITY_LEVEL=1 |
| ︙ | ︙ |
Changes to www/faq.tcl.
| ︙ | ︙ | |||
126 127 128 129 130 131 132 |
}
faq {
How do I make a clone of the fossil self-hosting repository?
} {
Any of the following commands should work:
<blockquote><pre>
| | | | | 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
}
faq {
How do I make a clone of the fossil self-hosting repository?
} {
Any of the following commands should work:
<blockquote><pre>
fossil [/help/clone|clone] https://fossil-scm.org/ fossil.fossil
fossil [/help/clone|clone] https://www2.fossil-scm.org/ fossil.fossil
fossil [/help/clone|clone] https://www3.fossil-scm.org/site.cgi fossil.fossil
</pre></blockquote>
Once you have the repository cloned, you can open a local check-out
as follows:
<blockquote><pre>
mkdir src; cd src; fossil [/help/open|open] ../fossil.fossil
</pre></blockquote>
Thereafter you should be able to keep your local check-out up to date
|
| ︙ | ︙ | |||
155 156 157 158 159 160 161 | ############################################################################# # Code to actually generate the FAQ # puts "<title>Fossil FAQ</title>" puts "<h1 align=\"center\">Frequently Asked Questions</h1>\n" | | | 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 |
#############################################################################
# Code to actually generate the FAQ
#
puts "<title>Fossil FAQ</title>"
puts "<h1 align=\"center\">Frequently Asked Questions</h1>\n"
puts "Note: See also <a href=\"qandc.wiki\">Questions and Criticisms</a>.\n"
puts {<ol>}
for {set i 1} {$i<$cnt} {incr i} {
puts "<li><a href=\"#q$i\">[lindex $faq($i) 0]</a></li>"
}
puts {</ol>}
puts {<hr>}
|
| ︙ | ︙ |
Changes to www/faq.wiki.
1 2 3 | <title>Fossil FAQ</title> <h1 align="center">Frequently Asked Questions</h1> | | | 1 2 3 4 5 6 7 8 9 10 11 | <title>Fossil FAQ</title> <h1 align="center">Frequently Asked Questions</h1> Note: See also <a href="qandc.wiki">Questions and Criticisms</a>. <ol> <li><a href="#q1">What GUIs are available for fossil?</a></li> <li><a href="#q2">What is the difference between a "branch" and a "fork"?</a></li> <li><a href="#q3">How do I create a new branch?</a></li> <li><a href="#q4">How do I tag a check-in?</a></li> <li><a href="#q5">How do I create a private branch that won't get pushed back to the |
| ︙ | ︙ | |||
119 120 121 122 123 124 125 | <blockquote>See the article on [./shunning.wiki | "shunning"] for details.</blockquote></li> <p id="q7"><b>(7) How do I make a clone of the fossil self-hosting repository?</b></p> <blockquote>Any of the following commands should work: <blockquote><pre> | | | | | 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 | <blockquote>See the article on [./shunning.wiki | "shunning"] for details.</blockquote></li> <p id="q7"><b>(7) How do I make a clone of the fossil self-hosting repository?</b></p> <blockquote>Any of the following commands should work: <blockquote><pre> fossil [/help/clone|clone] https://fossil-scm.org/ fossil.fossil fossil [/help/clone|clone] https://www2.fossil-scm.org/ fossil.fossil fossil [/help/clone|clone] https://www3.fossil-scm.org/site.cgi fossil.fossil </pre></blockquote> Once you have the repository cloned, you can open a local check-out as follows: <blockquote><pre> mkdir src; cd src; fossil [/help/open|open] ../fossil.fossil </pre></blockquote> Thereafter you should be able to keep your local check-out up to date |
| ︙ | ︙ |
Changes to www/fiveminutes.wiki.
1 2 3 4 5 6 7 8 | <title>Up and running in 5 minutes as a single user</title> <p align="center"><b><i> The following document was contributed by Gilles Ganault on 2013-01-08. </i></b> </p><hr> <h1>Up and running in 5 minutes as a single user</h1> | > | | > | > | | > | > | > | | > | > | | | > | > | > | > | | > | > | | | > | | | > | | > | > | > > > | | > | > > | > | | | 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 | <title>Up and running in 5 minutes as a single user</title> <p align="center"><b><i> The following document was contributed by Gilles Ganault on 2013-01-08. </i></b> </p><hr> <h1>Up and running in 5 minutes as a single user</h1> This short document explains the main basic Fossil commands for a single user, i.e. with no additional users, with no need to synchronize with some remote repository, and no need for branching/forking. <h2>Create a new repository</h2> <tt>fossil new c:\test.repo</tt> This will create the new SQLite binary file that holds the repository, i.e. files, tickets, wiki, etc. It can be located anywhere, although it's considered best practice to keep it outside the work directory where you will work on files after they've been checked out of the repository. <h2>Open the repository</h2> <tt>cd c:\temp\test.fossil <br> fossil open c:\test.repo</tt> This will check out the last revision of all the files in the repository, if any, into the current work directory. In addition, it will create a binary file _FOSSIL_ to keep track of changes (on non-Windows systems it is called <tt>.fslckout</tt>). <h2>Add new files</h2> <tt>fossil add .</tt> To tell Fossil to add new files to the repository. The files aren't actually added until you run "<tt>fossil commit</tt>. When using ".", it tells Fossil to add all the files in the current directory recursively, i.e. including all the files in all the subdirectories. Note: To tell Fossil to ignore some extensions: <tt>fossil settings ignore-glob "*.o,*.obj,*.exe" --global</tt> <h2>Remove files that haven't been committed yet</h2> <tt>fossil delete myfile.c</tt> This will simply remove the item from the list of files that were previously added through "<tt>fossil add</tt>". <h2>Check current status</h2> <tt>fossil changes</tt> This shows the list of changes that have been done and will be committed the next time you run "<tt>fossil commit</tt>". It's a useful command to run before running "<tt>fossil commit</tt>" just to check that things are OK before proceeding. <h2>Commit changes</h2> To actually apply the pending changes to the repository, e.g. new files marked for addition, checked-out files that have been edited and must be checked-in, etc. <tt>fossil commit -m "Added stuff"</tt> If no file names are provided on the command-line then all changes will be checked in, otherwise just the listed file(s) will be checked in. <h2>Compare two revisions of a file</h2> If you wish to compare the last revision of a file and its checked out version in your work directory: <tt>fossil gdiff myfile.c</tt> If you wish to compare two different revisions of a file in the repository: <tt>fossil finfo myfile</tt> Note the first hash, which is the hash of the commit when the file was committed. <tt>fossil gdiff --from HASH#1 --to HASH#2 myfile.c</tt> <h2>Cancel changes and go back to previous revision</h2> <tt>fossil revert myfile.c</tt> Fossil does not prompt when reverting a file. It simply reminds the user about the "undo" command, just in case the revert was a mistake. |
Changes to www/forum.wiki.
| ︙ | ︙ | |||
10 11 12 13 14 15 16 |
* <b>Easy to Administer:</b> If you have already set up a
[./server/|Fossil server] with [./alerts.md|email alerts]
then turning on the forum feature
is just a matter of flipping some permission bits. There is
no new software to install and configure, and the same logins
and passwords work.
| | | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
* <b>Easy to Administer:</b> If you have already set up a
[./server/|Fossil server] with [./alerts.md|email alerts]
then turning on the forum feature
is just a matter of flipping some permission bits. There is
no new software to install and configure, and the same logins
and passwords work.
* <b>Consistent Display:</b> Forum posts can be in [/md_rules|Markdown],
[/wiki_rules|Fossil Wiki], or plain text. Whichever format is used, the result is
displayed consistently across all platforms and operating systems and
between mobile devices and desktops.
* <b>Editable:</b> Forum posts can be amended after they are sent,
to fix typos or provide updates. The original posts are preserved
as part of the historical record, but only the amended posts are
|
| ︙ | ︙ | |||
347 348 349 350 351 352 353 |
repository's administrators and moderators:
<ol>
<li>Add the <b>[./caps/ref.html#5 | ModForum]</b> capability to any of
your users who should have this ability. You don't need to do this
for any user with <b>[./caps/ref.html#s | Setup]</b> or
<b>[./caps/ref.html#a | Admin]</b> capability; it's
| | < > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 |
repository's administrators and moderators:
<ol>
<li>Add the <b>[./caps/ref.html#5 | ModForum]</b> capability to any of
your users who should have this ability. You don't need to do this
for any user with <b>[./caps/ref.html#s | Setup]</b> or
<b>[./caps/ref.html#a | Admin]</b> capability; it's
[/artifact/b16221ffb736caa2?ln=1246-1257 | already included].</li>
<li>When someone updates the forum, an entry will appear in the
timeline if the type filter is set to "Forum" or "Any Type". If that
user has only the <b>WrForum</b> capability, any
other user with the <b>ModForum</b> capability
will see a conditional link appear at the top of the main forum
page: "Moderation Requests". Clicking this takes the moderator to
the <tt>/modreq</tt> page. A moderator may wish to keep the main
forum page open in a browser tab, reloading it occasionally to see
when the "Moderation Requests" link reappears.</li>
<li>A moderator viewing an update pending moderation sees two
buttons at the bottom, "Approve" and "Reject" in place of the
"Delete" button that the post's creator sees. Beware that both
actions are durable and have no undo. Be careful!</li>
</ol>
<h2 id="close-post">Closing Forum Posts</h2>
As of version 2.23, the forum interface supports the notion of
"closing" posts. By default, only users with the [./caps/index.md|'s'
and 'a' capabilities] may close or re-open posts, or reply to closed
posts. If the [/help?cmd=forum-close-policy|forum-close-policy
configuration option] is enabled then users with
[./caps/index.md|forum-moderator permissions] may also perform those
actions.
Closing a post has the following implications:
* Only authorized users may edit or respond to such posts, recursively
through all responses of that post.
* Only authorized users may re-open a closed post.
A forum thread may be closed at any given point in the conversation,
not just the starting point of the thread, and affects that specific
post and all existing responses to it.
Note that closing a post is effectively an "advisory lock" and may be
bypassed. Any user, admin or otherwise, who can push changes to a
repository may bypass closure of a post by setting the appropriate
artifact tags on a local copy and pushing those changes to a remote
copy of the forum.
The option to close a post, permissions permitting, appears as a
"Close" button on the currently-selected post. If the selected post is
alread closed, a "Re-open" button will be shown instead. In order to
re-open a post, <em>the closed post itself</em> must be
selected. Selecting a response to that post, which is implicitly
closed by the closure of its parent, will <em>not</em> offer a re-open
option.
Though forum users are permitted to delete their own posts, they are
not permitted, without appropriate permissions, to close their own
posts. This is intentional, as closing one's own post can be used to
antagonize other forum users. For example, by posting something
trollish or highly contraversial in nature and closing the post to
further responses.
|
Changes to www/foss-cklist.wiki.
1 2 3 | <title>Checklist For Successful Open-Source Projects</title> <nowiki> | | | < | | | | | | | | | | | | | | | | | | | | | | | | | | 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 |
<title>Checklist For Successful Open-Source Projects</title>
<nowiki>
This checklist is loosely derived from Tom "Spot" Callaway's Fail Score
blog post <a href="http://spot.livejournal.com/308370.html">
http://spot.livejournal.com/308370.html</a> (see also
<a href="http://www.theopensourceway.org/book/The_Open_Source_Way-How_to_tell_if_a_FLOSS_project_is_doomed_to_FAIL.html">[1]</a>).
Tom's original post assigned point scores to the various elements and
by adding together the individual points, the reader is supposed to be able
to judge the likelihood that the project will fail.
The point scores, and the items on the list, clearly reflect Tom's
biases and are not necessarily those of the larger open-source community.
Nevertheless, the policy of the Fossil shall be to strive for a perfect
score.
This checklist is an inversion of Tom's original post in that it strives to
say what the project should do in order to succeed rather than what it
should not do to avoid failure. The point values are omitted.
See also:
<ul>
<li><a href="http://offog.org/articles/packaging/">
http://offog.org/articles/packaging/</a>
<li>
<a href="http://www.gnu.org/prep/standards/standards.html#Managing-Releases">
http://www.gnu.org/prep/standards/standards.html#Managing-Releases</a>
</ul>
<hr>
<ol>
<li>The source code size is less than 100 MB, uncompressed.
<li>The project uses a Version Control System (VCS).
<ol type="a">
<li>The VCS has a working web interface.
<li>There is documentation on how to use the VCS.
<li>The VCS is general-purpose, not something hacked together for this
one project.
</ol>
<li>The project comes with documentation on how to build from source
and that documentation is lucid, correct, and up-to-date.
<li>The project is configurable using an autoconf-generated configure
script, or the equivalent, and does not require:
<ol type="a">
<li>Manually editing flat files
<li>Editing code header files
</ol>
<li>The project should be buildable using commonly available and
standard tools like "make".
<li>The project does not depend on 3rd-party proprietary build tools.
<li>The project is able to dynamically link against standard libraries
such as zlib and libjpeg.
<ol type="a">
<li>The project does not ship with the sources to standard libraries.
<i>(On the Fossil project, we will allow the SQLite library sources
to be included in the source tree as long as a system-installed
SQLite library can be used in its stead.)</i>
<li>The project does not use slightly modified versions of standard
libraries. Any required bug fixes in standard libraries are pushed
back upstream.
</ol>
<li>"make install" works and can be configured to target any
directory of the installer's choosing.
<ol type="a">
<li>The project contains no unconfigurable hard-coded pathnames like
"/opt" or "/usr/local".
<li>After installation, the source tree can be moved or deleted and
the application will continue working.
</ol>
<li>The source code uses only \n for line endings, not \r\n.
<li>The code does not depend on any special compiler features or bugs.
<li>The project has a mailing list and announces releases on
the mailing list.
<li>The project has a bug tracker.
<li>The project has a website.
<li>Release version numbers are in the traditional X.Y or X.Y.Z format.
<li>Releases can be downloaded as tarball using
gzip or bzip2 compression.
<li>Releases unpack into a versioned top-level directory.
(ex: "projectname-1.2.3/").
<li>A statement of license appears at the top of every source code file
and the complete text of the license is included in the source code
tarball.
<li>There are no incompatible licenses in the code.
<li>The project has not been blithely proclaimed "public domain" without
having gone through the tedious and exacting legal steps to actually put it
in the public domain.
<li>There is an accurate change log in the code and on the website.
<li>There is documentation in the code and on the website.
</ol>
|
Changes to www/fossil-v-git.wiki.
| ︙ | ︙ | |||
178 179 180 181 182 183 184 | precompiled binaries], unpack the executable from the archive and put it somewhere in your <tt>PATH</tt>. To uninstall it, delete the executable. This policy is particularly useful when running Fossil inside a restrictive container, anything from [./chroot.md | classic chroot jails] to modern [https://en.wikipedia.org/wiki/OS-level_virtualization | OS-level virtualization mechanisms] such as | | > | < | < < < < | < < | | | | 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 | precompiled binaries], unpack the executable from the archive and put it somewhere in your <tt>PATH</tt>. To uninstall it, delete the executable. This policy is particularly useful when running Fossil inside a restrictive container, anything from [./chroot.md | classic chroot jails] to modern [https://en.wikipedia.org/wiki/OS-level_virtualization | OS-level virtualization mechanisms] such as [https://en.wikipedia.org/wiki/Docker_(software) | Docker]. Our [./containers.md | stock container image] is under 8 MB when uncompressed and running. It contains nothing but a single statically-linked binary. If you build a dynamically linked binary instead, Fossil's on-disk size drops to around 6 MB, and it's dependent only on widespread platform libraries with stable ABIs such as glibc, zlib, and openssl. Full static linking is easier on Windows, so our precompiled Windows binaries are just a ZIP archive containing only "<tt>fossil.exe</tt>". There is no "<tt>setup.exe</tt>" to run. Fossil is easy to build from sources. Just run "<tt>./configure && make</tt>" on POSIX systems and "<tt>nmake /f Makefile.msc</tt>" on Windows. Contrast a basic installation of Git, which takes up about 15 MiB on Debian 10 across 230 files, not counting the contents of <tt>/usr/share/doc</tt> or <tt>/usr/share/locale</tt>. If you need to deploy to any platform where you cannot count on facilities like the POSIX shell, Perl interpreter, and Tcl/Tk platform needed to fully use Git as part of the base platform, the full footprint of a Git installation extends to more like 45 MiB and thousands of files. This complicates several common scenarios: Git for Windows, chrooted Git servers, Docker images... Some say that Git more closely adheres to the Unix philosophy, |
| ︙ | ︙ | |||
281 282 283 284 285 286 287 | It is common in Fossil to ask to see [/timeline?df=release&y=ci|all check-ins since the last release]. Git lets you see "what came before". Fossil makes it just as easy to also see "what came after". Leaf check-ins in Git that lack a "ref" become "detached," making them difficult to locate and subject to garbage collection. This | | | 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 | It is common in Fossil to ask to see [/timeline?df=release&y=ci|all check-ins since the last release]. Git lets you see "what came before". Fossil makes it just as easy to also see "what came after". Leaf check-ins in Git that lack a "ref" become "detached," making them difficult to locate and subject to garbage collection. This [http://gitfaq.org/1/01/what-is-a-detached-head/|detached head state] problem has caused grief for [https://www.google.com/search?q=git+detached+head+state | many Git users]. With Fossil, detached heads are simply impossible because we can always find our way back into the Merkle tree using one or more of the relations in the SQL database. |
| ︙ | ︙ | |||
357 358 359 360 361 362 363 | embedded into Fossil itself. Fossil's build system and test suite are largely based on Tcl.⁵ All of this is quite portable. About half of Git's code is POSIX C, and about a third is POSIX shell code. This is largely why the so-called "Git for Windows" distributions (both [https://git-scm.com/download/win|first-party] and [https://gitforwindows.org/|third-party]) are actually an | | > | | 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 | embedded into Fossil itself. Fossil's build system and test suite are largely based on Tcl.⁵ All of this is quite portable. About half of Git's code is POSIX C, and about a third is POSIX shell code. This is largely why the so-called "Git for Windows" distributions (both [https://git-scm.com/download/win|first-party] and [https://gitforwindows.org/|third-party]) are actually an [https://www.msys2.org/wiki/Home/|MSYS POSIX portability environment] bundled with all of the Git stuff, because it would be too painful to port Git natively to Windows. Git is a foreign citizen on Windows, speaking to it only through a translator.⁶ While Fossil does lean toward POSIX norms when given a choice — LF-only line endings are treated as first-class citizens over CR+LF, for example — the Windows build of Fossil is truly native. The third-party extensions to Git tend to follow this same pattern. [https://docs.gitlab.com/ee/install/install_methods.html#microsoft-windows | GitLab isn't portable to Windows at all], for example. For that matter, GitLab isn't even officially supported on macOS, the BSDs, or uncommon Linuxes! We have many users who regularly build and run Fossil on all of these systems. <h3 id="vs-linux">2.5 Linux vs. SQLite</h3> |
| ︙ | ︙ | |||
427 428 429 430 431 432 433 | All of this is exactly what one wants when doing bazaar-style development. Fossil's normal mode of operation differs on every one of these points, with the specific designed-in goal of promoting SQLite's cathedral development model: | < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | < | | 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 |
All of this is exactly what one wants when doing bazaar-style
development.
Fossil's normal mode of operation differs on every one of these points,
with the specific designed-in goal of promoting SQLite's cathedral
development model:
* <b>Personal engagement:</b> SQLite's developers know each
other by name and work together daily on the project.
* <b>Trust over hierarchy:</b> SQLite's developers check
changes into their local repository, and these are immediately and
automatically synchronized up to the central repository; there is no
"[https://git-scm.com/book/en/v2/Distributed-Git-Distributed-Workflows#_dictator_and_lieutenants_workflow|dictator
and lieutenants]" hierarchy as with Linux kernel contributions. D.
Richard Hipp rarely overrides decisions made by those he has trusted
with commit access on his repositories. Fossil allows you to give
[./caps/admin-v-setup.md|some users] more power over what
they can do with the repository, but Fossil [./caps/index.md#ucap |
only loosely supports] the enforcement of a development organization's
social and power hierarchies. Fossil is a great fit for
[https://en.wikipedia.org/wiki/Flat_organization|flat
organizations].
* <b>No easy drive-by contributions:</b> Git
[https://www.git-scm.com/docs/git-request-pull|pull requests] offer
a low-friction path to accepting
[https://www.jonobacon.com/2012/07/25/building-strong-community-structural-integrity/|drive-by
contributions]. Fossil's closest equivalents are its unique
[/help?cmd=bundle|bundle] and [/help?cmd=patch|patch] features, which require higher engagement
than firing off a PR.⁷ This difference comes directly from the
initial designed purpose for each tool: the SQLite project doesn't
accept outside contributions from previously-unknown developers, but
the Linux kernel does.
* <b>No rebasing:</b> When your local repo clone syncs changes
up to its parent, those changes are sent exactly as they were
committed locally. [#history|There is no rebasing mechanism in
Fossil, on purpose.]
* <b>Sync over push:</b> Explicit pushes are uncommon in
Fossil-based projects: the default is to rely on
[/help?cmd=autosync|autosync mode] instead, in which each commit
syncs immediately to its parent repository. This is a mode so you
can turn it off temporarily when needed, such as when working
offline. Fossil is still a truly distributed version control system;
it's just that its starting default is to assume you're rarely out
of communication with the parent repo.
<br><br>
This is not merely a reflection of modern always-connected computing
environments. It is a conscious decision in direct support of
SQLite's cathedral development model: we don't want developers going
dark, then showing up weeks later with a massive bolus of changes
for us to integrate all at once.
[https://en.wikipedia.org/wiki/Jim_McCarthy_(author)|Jim McCarthy]
put it well in his book on software project management,
<i>[https://www.amazon.com/dp/0735623198/|Dynamics of Software
Development]</i>: "[https://www.youtube.com/watch?v=oY6BCHqEbyc|Beware
of a guy in a room]."
* <b>Branch names sync:</b> Unlike in Git, branch names in
Fossil are not purely local labels. They sync along with everything
else, so everyone sees the same set of branch names. Fossil's design
choice here is a direct reflection of the Linux vs. SQLite project
outlook: SQLite's developers collaborate closely on a single
coherent project, whereas Linux's developers go off on tangents and
occasionally send selected change sets to each other.
* <b>Private branches are rare:</b>
[/doc/trunk/www/private.wiki|Private branches exist in Fossil], but
they're normally used to handle rare exception cases, whereas in
many Git projects, they're part of the straight-line development
process.
* <b>Identical clones:</b> Fossil's autosync system tries to
keep each local clone identical to the repository it cloned
from.
Where Git encourages siloed development, Fossil fights against it.
Fossil places a lot of emphasis on synchronizing everyone's work and on
reporting on the state of the project and the work of its developers, so
that everyone — especially the project leader — can maintain a better
mental picture of what is happening, leading to better situational
awareness.
By contrast, "…[https://docs.github.com/en/get-started/quickstart/contributing-to-projects|forking is
at the core of social coding at GitHub]". As of January 2022,
[https://github.com/search?q=is:public|Github hosts 47 million distinct
software projects], most of which were created by forking a
previously-existing project. Since this is
[https://evansdata.com/reports/viewRelease.php?reportID=9 | roughly
twice the number of developers in the world], it beggars belief that
most of these forks are still under active development. The vast bulk
|
| ︙ | ︙ |
Changes to www/gitusers.md.
1 2 3 4 5 6 7 8 | # Git to Fossil Translation Guide ## Introduction Fossil shares many similarities with Git. In many cases, the sub-commands are identical: [`fossil bisect`][fbis] does essentially the same thing as [`git bisect`][gbis], for example. | > > > > | < | > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | # Git to Fossil Translation Guide ## Introduction Fossil shares many similarities with Git. In many cases, the sub-commands are identical: [`fossil bisect`][fbis] does essentially the same thing as [`git bisect`][gbis], for example. Yet, Fossil is not merely Git with a bunch of commands misspelled. If that were the case, we could give you a two-column translation table which would tell you [how to say things like “`git reset --hard HEAD`”](#reset) in this funny ol’ Fossil dialect of Git and be done. The purpose of this document is to cover all the cases where there is no simple 1:1 mapping, usually because of intentional design differences in Fossil that prevent it from working exactly like Git. We choose to explain these differences since to understand the conversion, you need to know why each difference exists. We focus on practical command examples here, leaving discussions of the philosophical underpinnings that drive these command differences to [another document][fvg]. The [case studies](#cs1) do get a bit philosophical, but it is with the aim of illustrating how these Fossil design differences cause Fossil to behave materially differently from Git in everyday operation. |
| ︙ | ︙ | |||
275 276 277 278 279 280 281 | [open]: /help?cmd=open [set]: /help?cmd=setting [server]: /help?cmd=server [stash]: /help?cmd=stash [undo]: /help?cmd=undo | | | 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 | [open]: /help?cmd=open [set]: /help?cmd=setting [server]: /help?cmd=server [stash]: /help?cmd=stash [undo]: /help?cmd=undo ## <a id="log"></a> Fossil’s Timeline Is the “Log” Git users often need to use the `git log` command to dig linearly through commit histories due to its [weak data model][wdm], giving [O(n) performance][ocomp]. Fossil parses a huge amount of information out of commits that allow it to produce its [timeline CLI][tlc] and [its `/timeline` web view][tlw] |
| ︙ | ︙ | |||
436 437 438 439 440 441 442 | The Git convention of a [length-limited summary line][lsl] at the start of commit comments is not enforced or obeyed by default in Fossil. However, there is a setting under Admin → Timeline → “Truncate comment at first blank line (Git-style)” to change this for `/timeline` displays. Alternately, you could enable the “Allow block-markup in timeline” setting under Admin → Timeline, then apply [local skin | | | 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 | The Git convention of a [length-limited summary line][lsl] at the start of commit comments is not enforced or obeyed by default in Fossil. However, there is a setting under Admin → Timeline → “Truncate comment at first blank line (Git-style)” to change this for `/timeline` displays. Alternately, you could enable the “Allow block-markup in timeline” setting under Admin → Timeline, then apply [local skin customizations][cskin] to put that first comment in bold or whatever suits. Because this isn’t a typical Fossil convention, you’re likely to find other odd differences between it and Git-based infrastructure. For instance, Vim doesn’t ship with syntax support for Fossil commit messages if you set `EDITOR=vim` in your shell environment, so you won’t get over-limit highlighting for first-line text beyond the 50th |
| ︙ | ︙ | |||
569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 |
(The version string “current” is one of the [special check-in names][scin] in Fossil. See
that document for the many other names you can give to “`amend`”, or
indeed to any other Fossil command documented to accept a `VERSION` or
`NAME` string.)
[scin]: ./checkin_names.wiki
<a id="autosync"></a>
## Autosync
Fossil’s [autosync][wflow] feature, normally enabled, has no
equivalent in Git. If you want Fossil to behave like Git, you can turn
it off:
fossil set autosync 0
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > | > > > > > > | | > > | > > > > > > > > > | | | > | > | > | > > > > > > > > > | > > | > > > > > | > > | > > > > > > > > > > | > > > | > > | > > > > > > > > > > > > | > > > > > | > > > > > > > > > | > > > > > > > | < < | > | > | 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 |
(The version string “current” is one of the [special check-in names][scin] in Fossil. See
that document for the many other names you can give to “`amend`”, or
indeed to any other Fossil command documented to accept a `VERSION` or
`NAME` string.)
[scin]: ./checkin_names.wiki
<a id="syncall"></a>
## Sync Is All-or-Nothing
Fossil does not support the concept of syncing, pushing, or pulling
individual branches. When you sync/push/pull in Fossil, it
processes all artifacts in its hash tree:
branches, tags, wiki articles, tickets, forum posts, technotes…
This is [not quite “everything,” full stop][bu], but it’s close.
[Fossil is an AP-mode system][capt], which in this case means it works
*very hard* to ensure that all repos are as close to identical as it can
make them under this eventually-consistent design philosophy.
Branch *names* sync automatically in Fossil, not just the
content of those branches. That means this common Git command:
git push origin master
…is simply this in Fossil:
fossil push
Fossil doesn’t need to be told what to push or where to push it: it just
keeps using the same remote server URL you gave it last
until you [tell it to do something different][rem]. It pushes all
branches, not just one named local branch.
[capt]: ./cap-theorem.md
[rem]: /help?cmd=remote
<a id="autosync"></a>
## Autosync
Fossil’s [autosync][wflow] feature, normally enabled, has no
equivalent in Git. If you want Fossil to behave like Git, you can turn
it off:
fossil set autosync 0
Let’s say that you have a typical server-and-workstations model with two
working clones on different machines, that you have disabled autosync,
and that this common sequence then occurs:
1. Alice commits to her local clone and *separately* pushes the change
up to Condor — their central server — in typical Git fashion.
2. Bob does the same.
3. Alice brings Bob’s changes down from Condor with “`fossil pull`,” sees
what he did to their shared working branch, and becomes most wrathful.
(Tsk, tsk.)
We’ll get to what you do about this situation [below](#reset), but for
now let us focus on the fact that disabling autosync makes it easier for
[forks] to occur in the development history. If all three machines had
been online and syncing at the time the sequence above began, Bob would
have been warned in step 2 that committing to the central repo would
create a fork and would be invited to fix it before committing.
Likewise, it would allow Fossil to warn Alice about the new
tip-of-branch commit the next time she triggers an implicit autosync at
step 3, giving her a chance to bring Bob’s changes down in a
non-conflicting manner, allowing work to proceed with minimal fuss.
Fossil, being a distributed version control system, cannot guarantee
that sequence of events. Because it allows Alice’s work to proceed
asynchronously, it gives her the chance to create *another* inadvertent
fork before she can trigger an autosync. This is not a serious problem;
Fossil resolves it the same way as with Bob, by inviting her to fix this
second fork in the same manner as it did with Bob. It gets both parties
back onto a single track as expeditiously as possible by moving the
synchronization point out of the expensive human-time workflow and into
the software system, where it’s cheapest to resolve.
Autosync provides Fossil with most of the advantages of a centralized
version control system while retaining the advantages of distributed
version control:
1. Your work stays synced up with your coworkers’ efforts as long as your
machine can connect to the remote repository. At need, you can go
off-network and continue work atop the last version you synced with
the remote.
2. You get implicit off-machine backup of your commits. Unlike
centralized version control, though, you can still work while
disconnected; your changes will sync up with the remote once you get
back online.
3. Because there is [little distinction][bu] between the clones in the Fossil
model — unlike in Git, where clones often quickly diverge from each
other, quite possibly on purpose — the backup advantage applies in inverse
as well: if the remote server falls over dead, one of those with a
clone of that repository can stand it back up, and everyone can get
back to work simply by re-pointing their local repo at the new
remote. If the failed remote comes back later, it can sync with the
new central version, then perhaps take over as the primary source of
truth once again.
[bu]: ./backup.md
[forks]: ./branching.wiki
[setup]: ./caps/admin-v-setup.md#apsu
[wflow]: ./concepts.wiki#workflow
<a id="reset"></a>
## Resetting the Repository
Extending from [the prior item](#syncall), you may correctly infer that
“[delete the project and download a fresh copy][x1597]” has no part in
the Fossil Way. Ideally, you should never find yourself forced into
desperate measures like this:(^Parsing the output of `fossil status` is
usually a mistake since it relies on a potentially unstable interface.
We make no guarantee that there will always be a line beginning with
“`repo`” and that it will be separated from the repository’s file name
by a colon. The simplified example above is also liable to become
confused by whitespace in file names.)
```
$ repo=$(fossil status | grep ^repo | cut -f2 -d:)
$ url=$(fossil remote)
$ fossil close # Stop here and think if it warns you!
$ mv $repo ${repo}.old
$ fossil clone $url $repo
$ fossil open --force $repo
```
What, then, should you as a Git transplant do instead when you find
yourself reaching for “`git reset`”?
Since the correct answer to that depends on why you think it’s a good
solution to your immediate problem, we’ll take our motivating scenario
from the problem setup above, where we discussed Fossil’s [autosync]
feature. Let us further say Alice’s pique results from a belief that
Bob’s commit is objectively wrong-headed and should be expunged
henceforth. Since Fossil goes out of its way to ensure that [commits are
durable][wdm], it should be no further surprise that there is no easier
method to reset Bob’s clone in favor of Alice’s than the above sequence
in Fossil’s command set. Except in extreme situations, we believe that
sort of thing is unnecessary.
Instead, Bob can say something like this:
```
fossil amend --branch MISTAKE --hide --close -m "mea culpa" tip
fossil up trunk
fossil push
```
Unlike in Git, the “`amend`” command doesn’t modify prior committed
artifacts. Bob’s first command doesn’t delete anything, merely tells
Fossil to hide his mistake from timeline views by inserting a few new
records into the local repository to change how the client interprets
the data it finds there henceforth.(^One to change the tag marking this
commit’s branch name to “`MISTAKE`,” one to mark that branch as hidden,
and one to close it to further commits.)
Bob’s second command switches his working directory back to the prior
commit on that branch. We’re presuming it was “`trunk`” for the sake of
the example, but it works for any parent branch name. The command works
because the name “`trunk`” now means something different to Fossil by
virtue of the first command.
Bob’s third command pushes the changes up to the central machine to
inform everyone else of his amendment.(^Amendments don’t autosync in
Fossil because they don’t change any previous commits, allowing the
other clones to continue working safely with their existing commit
hashes.)
In this scheme, Alice then needs to say “`fossil update trunk`” in order
to return her check-out’s parent commit to the previous version lest her
next attempted commit land atop this mistake branch. The fact that Bob
marked the branch as closed will prevent that from going thru, cluing
Alice into what she needs to do to remedy the situation, but that merely
shows why it’s a better workflow if Alice makes the amendment herself:
```
fossil amend --branch MISTAKE --hide --close \
-m "shunt Bob’s erroneous commit off" tip
fossil up trunk
fossil push
```
Then she can fire off an email listing Bob’s assorted failings and go
about her work. This asynchronous workflow solves the problem without
requiring explicit coordination with Bob. When he gets his email, he can
then say “`fossil up trunk`” himself, which by default will trigger an
autosync, pulling down Alice’s amendments and getting him back onto her
development track.
Remember that [branch names need not be unique](#btnames) in Fossil. You
are free to reuse this “`MISTAKE`” branch name as often as you need to.
[autosync]: #autosync
[x1597]: https://xkcd.com/1597/
<a id="trunk"></a>
## The Main Branch Is Called "`trunk`"
In Fossil, the default name for the main branch
is "`trunk`". The "`trunk`" branch in Fossil corresponds to the
|
| ︙ | ︙ | |||
949 950 951 952 953 954 955 |
git checkout $(git rev-list -n 1 --first-parent --before="2020-03-17" master)
We believe you get such answers to Git help requests in part
because of its lack of an always-up-to-date [index into its log](#log) and in
part because of its “small tools loosely joined” design philosophy. This
sort of command is therefore composed piece by piece:
| | | 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 |
git checkout $(git rev-list -n 1 --first-parent --before="2020-03-17" master)
We believe you get such answers to Git help requests in part
because of its lack of an always-up-to-date [index into its log](#log) and in
part because of its “small tools loosely joined” design philosophy. This
sort of command is therefore composed piece by piece:
<p style="text-align:center">◆ ◆ ◆</p>
“Oh, I know, I’ll search the rev-list, which outputs commit IDs by
parsing the log backwards from `HEAD`! Easy!”
git rev-list --before=2020-03-17
“Blast! Forgot the commit ID!”
|
| ︙ | ︙ | |||
983 984 985 986 987 988 989 |
“Better. Let’s check it out:”
git checkout $(git rev-list -n 1 --first-parent --before=2020-03-17 master)
“Success, I guess?”
| | | 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 |
“Better. Let’s check it out:”
git checkout $(git rev-list -n 1 --first-parent --before=2020-03-17 master)
“Success, I guess?”
<p style="text-align:center">◆ ◆ ◆</p>
This vignette is meant to explain some of Git’s popularity: it rewards
the sort of people who enjoy puzzles, many of whom are software
developers and thus need a tool like Git. Too bad if you’re just a
normal user.
And too bad if you’re a Windows user who doesn’t want to use [Git
|
| ︙ | ︙ | |||
1183 1184 1185 1186 1187 1188 1189 |
Where Fossil really wins is in the next step, making the initial commit
from home:
fossil ci
It’s one short command for Fossil instead of three for Git — or two if
you abbreviate it as “`git commit -a && git push`” — because of Fossil’s
| | | 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 |
Where Fossil really wins is in the next step, making the initial commit
from home:
fossil ci
It’s one short command for Fossil instead of three for Git — or two if
you abbreviate it as “`git commit -a && git push`” — because of Fossil’s
[autosync] feature and deliberate omission of a
[staging feature](#staging).
The “Friday afternoon sync-up” case is simpler, too:
fossil remote work
fossil sync
|
| ︙ | ︙ |
Changes to www/globs.md.
1 2 | # File Name Glob Patterns | < | | | | | | | | > > | | | > | > > > | > | > > > | > | | | 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 |
# File Name Glob Patterns
A [glob pattern][glob] is a text expression that matches one or more
file names using wildcards familiar to most users of a command line.
For example, `*` is a glob that matches any name at all, and
`Readme.txt` is a glob that matches exactly one file. For purposes of
Fossil's globs, a complete path name is just a string,
and the globs do not apply any special meaning to the directory part
of the name. Thus, the glob `*` matches any name, including any
directory prefix, and `*/*` matches a name with _one or more_
directory components.
A glob should not be confused with a [regular expression][regexp] (RE)
even though they use some of the same special characters for similar
purposes. [They are not fully compatible][greinc] pattern
matching languages. Fossil uses globs when matching file names with the
settings described in this document, not REs.
[glob]: https://en.wikipedia.org/wiki/Glob_(programming)
[greinc]: https://unix.stackexchange.com/a/57958/138
[regexp]: https://en.wikipedia.org/wiki/Regular_expression
[Fossil’s `*-glob` settings](#settings) hold one or more patterns to cause Fossil to
give matching named files special treatment. Glob patterns are also
accepted in options to certain commands and as query parameters to
certain Fossil UI web pages. For consistency, settings such as
`empty-dirs` are parsed as a glob even though they aren’t then *applied*
as a glob since it allows [the same syntax rules](#syntax) to apply.
Where Fossil also accepts globs in commands, this handling may interact
with your OS’s command shell or its C runtime system, because they may
have their own glob pattern handling. We will detail such interactions
below.
## <a id="syntax"></a>Syntax
Where Fossil accepts glob patterns, it will usually accept a *list* of
individual patterns separated from the others by whitespace or commas.
The parser allows whitespace and commas in a pattern by quoting _the
entire pattern_ with either single or double quotation marks. Internal
quotation marks are treated literally. Moreover, a pattern that begins
with a quote mark ends when the first instance of the same mark occurs,
_not_ at a whitespace or comma. Thus, this:
"foo bar"qux
…constitutes _two_ patterns rather than one with an embedded space, in
contravention of normal shell quoting rules.
A list matches a file when any pattern in that list matches.
A pattern must consume and
match the *entire* file name to succeed. Partial matches are failed matches.
Most characters in a glob pattern consume a single character of the file
name and must match it exactly. For instance, “a” in a glob simply
matches the letter “a” in the file name unless it is inside a special
character sequence.
Other characters have special meaning, and they may include otherwise
normal characters to give them special meaning:
:Pattern |:Effect
---------------------------------------------------------------------
`*` | Matches any sequence of zero or more characters
`?` | Matches exactly one character
`[...]` | Matches one character from the enclosed list of characters
`[^...]` | Matches one character *not* in the enclosed list
Note that unlike [POSIX globs][pg], these special characters and
sequences are allowed to match `/` directory separators as well as the
initial `.` in the name of a hidden file or directory. This is because
Fossil file names are stored as complete path names. The distinction
between file name and directory name is “underneath” Fossil in this sense.
[pg]: https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_13
The bracket expressions above require some additional explanation:
* A range of characters may be specified with `-`, so `[a-f]` matches
exactly the same characters as `[abcdef]`. Ranges reflect Unicode
|
| ︙ | ︙ | |||
161 162 163 164 165 166 167 168 169 170 | :Pattern |:Effect -------------------------------------------------------------------------------- `README` | Matches only a file named `README` in the root of the tree. It does not match a file named `src/README` because it does not include any characters that consume (and match) the `src/` part. `*/README` | Matches `src/README`. Unlike Unix file globs, it also matches `src/library/README`. However it does not match the file `README` in the root of the tree. `*README` | Matches `src/README` as well as the file `README` in the root of the tree as well as `foo/bar/README` or any other file named `README` in the tree. However, it also matches `A-DIFFERENT-README` and `src/DO-NOT-README`, or any other file whose name ends with `README`. `src/README` | Matches `src\README` on Windows because all directory separators are rewritten as `/` in the canonical name before the glob is matched. This makes it much easier to write globs that work on both Unix and Windows. `*.[ch]` | Matches every C source or header file in the tree at the root or at any depth. Again, this is (deliberately) different from Unix file globs and Windows wild cards. ## Where Globs are Used | > | | 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 | :Pattern |:Effect -------------------------------------------------------------------------------- `README` | Matches only a file named `README` in the root of the tree. It does not match a file named `src/README` because it does not include any characters that consume (and match) the `src/` part. `*/README` | Matches `src/README`. Unlike Unix file globs, it also matches `src/library/README`. However it does not match the file `README` in the root of the tree. `*README` | Matches `src/README` as well as the file `README` in the root of the tree as well as `foo/bar/README` or any other file named `README` in the tree. However, it also matches `A-DIFFERENT-README` and `src/DO-NOT-README`, or any other file whose name ends with `README`. `src/README` | Matches `src\README` on Windows because all directory separators are rewritten as `/` in the canonical name before the glob is matched. This makes it much easier to write globs that work on both Unix and Windows. `*.[ch]` | Matches every C source or header file in the tree at the root or at any depth. Again, this is (deliberately) different from Unix file globs and Windows wild cards. ## Where Globs are Used ### <a id="settings"></a>Settings that are Globs These settings are all lists of glob patterns: :Setting |:Description -------------------------------------------------------------------------------- `binary-glob` | Files that should be treated as binary files for committing and merging purposes `clean-glob` | Files that the [`clean`][] command will delete without prompting or allowing undo |
| ︙ | ︙ | |||
195 196 197 198 199 200 201 202 | The `ignore-glob` is an example of one setting that frequently grows to be an elaborate list of files that should be ignored by most commands. This is especially true when one (or more) IDEs are used in a project because each IDE has its own ideas of how and where to cache information that speeds up its browsing and building tasks but which need not be preserved in your project's history. | > > > > | | 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 | The `ignore-glob` is an example of one setting that frequently grows to be an elaborate list of files that should be ignored by most commands. This is especially true when one (or more) IDEs are used in a project because each IDE has its own ideas of how and where to cache information that speeds up its browsing and building tasks but which need not be preserved in your project's history. Although the `empty-dirs` setting is not a list of glob patterns as such, it is *parsed* that way for consistency among the settings, allowing [the list parsing rules above](#syntax) to apply. ### <a id="commands"></a>Commands that Refer to Globs Many of the commands that respect the settings containing globs have options to override some or all of the settings. These options are usually named to correspond to the setting they override, such as `--ignore` to override the `ignore-glob` setting. These commands are: * [`add`][] |
| ︙ | ︙ | |||
225 226 227 228 229 230 231 | than archiving the entire checkin. The commands [`http`][], [`cgi`][], [`server`][], and [`ui`][] that implement or support with web servers provide a mechanism to name some files to serve with static content where a list of glob patterns specifies what content may be served. | | | | | | | | | | | | | | | | | | | | | 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 | than archiving the entire checkin. The commands [`http`][], [`cgi`][], [`server`][], and [`ui`][] that implement or support with web servers provide a mechanism to name some files to serve with static content where a list of glob patterns specifies what content may be served. [`add`]: /help?cmd=add [`addremove`]: /help?cmd=addremove [`changes`]: /help?cmd=changes [`clean`]: /help?cmd=clean [`commit`]: /help?cmd=commit [`extras`]: /help?cmd=extras [`merge`]: /help?cmd=merge [`settings`]: /help?cmd=settings [`status`]: /help?cmd=status [`touch`]: /help?cmd=touch [`unset`]: /help?cmd=unset [`tarball`]: /help?cmd=tarball [`zip`]: /help?cmd=zip [`http`]: /help?cmd=http [`cgi`]: /help?cmd=cgi [`server`]: /help?cmd=server [`ui`]: /help?cmd=ui ### Web Pages that Refer to Globs The [`/timeline`][] page supports the query parameter `chng=GLOBLIST` that names a list of glob patterns defining which files to focus the timeline on. It also has the query parameters `t=TAG` and `r=TAG` that names a tag to focus on, which can be configured with `ms=STYLE` to use a glob pattern to match tag names instead of the default exact match or a couple of other comparison styles. The pages [`/tarball`][] and [`/zip`][] generate compressed archives of a specific checkin. They may be further restricted by query parameters that specify glob patterns that name files to include or exclude rather than taking the entire checkin. [`/timeline`]: /help?cmd=/timeline [`/tarball`]: /help?cmd=/tarball [`/zip`]: /help?cmd=/zip ## Platform Quirks Fossil glob patterns are based on the glob pattern feature of POSIX shells. Fossil glob patterns also have a quoting mechanism, discussed [above](#syntax). Because other parts of your operating system may interpret glob patterns and quotes separately from Fossil, it is often difficult to give glob patterns correctly to Fossil on the command line. Quotes and special characters in glob patterns are likely to be interpreted when given as part of a `fossil` command, causing unexpected behavior. These problems do not affect [versioned settings files](settings.wiki) or Admin → Settings in Fossil UI. Consequently, it is better to |
| ︙ | ︙ | |||
355 356 357 358 359 360 361 |
$ fossil add --ignore "\"REALLY SECRET STUFF.txt\"" READ*
It bears repeating that the two glob patterns here are not interpreted
the same way when running this command from a *subdirectory* of the top
checkout directory as when running it at the top of the checkout tree.
If these files were in a subdirectory of the checkout tree called `doc`
| | | | | 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 |
$ fossil add --ignore "\"REALLY SECRET STUFF.txt\"" READ*
It bears repeating that the two glob patterns here are not interpreted
the same way when running this command from a *subdirectory* of the top
checkout directory as when running it at the top of the checkout tree.
If these files were in a subdirectory of the checkout tree called `doc`
and that was your current working directory, the command would instead
have to be:
$ fossil add --ignore "'doc/REALLY SECRET STUFF.txt'" READ*
The Fossil glob pattern still needs the `doc/` prefix because
Fossil always interprets glob patterns from the base of the checkout
directory, not from the current working directory as POSIX shells do.
When in doubt, use `fossil status` after running commands like the
above to make sure the right set of files were scheduled for insertion
into the repository before checking the changes in. You never want to
accidentally check something like a password, an API key, or the
|
| ︙ | ︙ | |||
530 531 532 533 534 535 536 | With that in mind, translating a `.gitignore` file into `.fossil-settings/ignore-glob` may be possible in many cases. Here are some of features of `.gitignore` and comments on how they relate to Fossil: * "A blank line matches no files...": same in Fossil. | | > > | 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 |
With that in mind, translating a `.gitignore` file into
`.fossil-settings/ignore-glob` may be possible in many cases. Here are
some of features of `.gitignore` and comments on how they relate to
Fossil:
* "A blank line matches no files...": same in Fossil.
* "A line starting with # serves as a comment...": same in Fossil, including
the possibility of escaping an initial `#` with a backslash to allow globs
beginning with a hash.
* "Trailing spaces are ignored unless they are quoted..." is similar
in Fossil. All whitespace before and after a glob is trimmed in
Fossil unless quoted with single or double quotes. Git uses
backslash quoting instead, which Fossil does not.
* "An optional prefix "!" which negates the pattern...": not in
Fossil.
* Git's globs are relative to the location of the `.gitignore` file:
|
| ︙ | ︙ |
Changes to www/glossary.md.
1 2 3 4 5 6 7 8 9 | # Glossary There are several terms-of-art in Fossil that have specific meanings which are either not immediately obvious to an outsider or which have technical associations that can lead someone to either use the terms incorrectly or to get the wrong idea from someone using those terms correctly. We hope to teach users how to properly “speak Fossil” with this glossary. | | | > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | # Glossary There are several terms-of-art in Fossil that have specific meanings which are either not immediately obvious to an outsider or which have technical associations that can lead someone to either use the terms incorrectly or to get the wrong idea from someone using those terms correctly. We hope to teach users how to properly “speak Fossil” with this glossary. The bullet-point lists following each definition are meant to be clarifying and illustrative. They are not part of the definitions themselves. ## <a id="project"></a>Project A collection of one or more computer files that serve some conceptually unified purpose, which purpose changes and evolves over time, with the history of that project being a valuable record. |
| ︙ | ︙ | |||
42 43 44 45 46 47 48 |
* We speak of projects being more than one file because even though
Fossil can be made to track the history of a single file, it is far
more often the case that when you get to something of a scale
sufficient to be called a “project,” there is more than one
version-tracked file involved, if not at the start, then certainly
by the end of the project.
| | < < < | | < < < | > > < < | | > > | < | < < < < | > > > | | | > > > | 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 |
* We speak of projects being more than one file because even though
Fossil can be made to track the history of a single file, it is far
more often the case that when you get to something of a scale
sufficient to be called a “project,” there is more than one
version-tracked file involved, if not at the start, then certainly
by the end of the project.
To take the example of a fiction book above, instead of putting each
chapter in a separate file, you could use a single AsciiDoc file for
the entire book project rather than make use of its [include
facility][AIF] to assemble it from chapter files, since that does at
least solve the [key problems][IFRS] inherent in version-tracking
something like Word’s DOCX format with Fossil instead.
While Fossil will happily track the single file containing the prose
of your book project for you, you’re still likely to want separate
files for the cover artwork, a style sheet for use in converting the
source document to HTML, scripts to convert that intermediate output
to PDF and ePub in a reliably repeatable fashion, a `README` file
containing instructions to the printing house, and so forth.
* Fossil requires that all the files for a project be collected into a
single directory hierarchy, owned by a single user with full rights
to modify those files. Fossil is not a good choice for managing a
project that has files scattered hither and yon all over the file
system, nor of collections of files with complicated ownership and
access rights.
A project made of an operating system
installation’s configuration file set is not a good use of Fossil,
because you’ll have all of your OS’s *other* files intermixed.
Worse, Fossil doesn’t track OS permissions, so even if you were to
try to use Fossil as a system deployment tool by archiving versions
of the OS configuration files and then unpacking them on a new
system, the extracted project files would have read/write access by
the user who did the extraction, which probably isn’t want you were
wanting.
Even with these problems aside, do you really want a `.fslckout`
SQLite database at the root of your filesystem? Are you prepared for
the consequences of saying `fossil clean --verily` on such a system?
You can constrain that with [the `ignore-glob` setting][IGS], but
are you prepared to write and maintain all the rules needed to keep
Fossil from blowing away the untracked portions of the file system?
We believe Fossil is a poor choice for a whole-system configuration
backup utility.
As a counterexample, a project tracking your [Vim] configuration
history is a much better use of Fossil, because it’s all held within
`~/.vim`, and your user has full rights to that subdirectory.
[AIF]: https://docs.asciidoctor.org/asciidoc/latest/directives/include/
[IGS]: /help?cmd=ignore-glob
[IFRS]: ./image-format-vs-repo-size.md
[tarball]: /help?cmd=tarball
[tw]: /help?cmd=/tarball
[Vim]: https://www.vim.org/
[zip]: /help?cmd=zip
[zw]: /help?cmd=/zip
|
| ︙ | ︙ | |||
197 198 199 200 201 202 203 | move right 0.1 line dotted right until even with previous line.end move right 0.05 box invis "clones of Fossil itself, SQLite, etc." ljust ``` [asdis]: /help?cmd=autosync | | | | | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > | | | | | > > > > > > | < < < < | | | > > > > > > > > > > > > > > > > > > | | | 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 |
move right 0.1
line dotted right until even with previous line.end
move right 0.05
box invis "clones of Fossil itself, SQLite, etc." ljust
```
[asdis]: /help?cmd=autosync
[backup]: ./backup.md
[CAP]: ./cap-theorem.md
[cloned]: /help?cmd=clone
[pull]: /help?cmd=pull
[push]: /help?cmd=push
[svrcmd]: /help?cmd=server
[sync]: /help?cmd=sync
[repository]: #repo
[repositories]: #repo
## Version / Revision / Hash / UUID <a id="version" name="hash"></a>
These terms all mean the same thing: a long hexadecimal
[SHA hash value](./hashes.md) that uniquely identifies a particular
[check-in](#ci).
We’ve listed the alternatives in decreasing preference order:
* **Version** and **revision** are near-synonyms in common usage.
Fossil’s code and documentation use both interchangeably because
Fossil was created to manage the development of the SQLite project,
which formerly used [CVS], the Concurrent Versions System. CVS in
turn started out as a front-end to [RCS], the Revision Control
System, but even though CVS uses “version” in its name, it numbers
check-ins using a system derived from RCS’s scheme, which it calls
“Revisions” in user-facing output. Fossil inherits this confusion
honestly.
* **Hash** refers to the [SHA1 or SHA3-256 hash](./hashes.md) of the
content of the checked-in data, uniquely identifying that version of
the managed files. It is a strictly correct synonym, used more often
in low-level contexts than the term “version.”
* **UUID** is a deprecated term still found in many parts of the
Fossil internals and (decreasingly) its documentation. The problem
with using this as a synonym for a Fossil-managed version of the
managed files is that there are [standards][UUID] defining the
format of a “UUID,” none of which Fossil follows, not even the
[version 4][ruuid] (random) format, the type of UUID closest in
meaning and usage to a Fossil hash.(^A pre-Fossil 2.0 style SHA1
hash is 160 bits, not the 128 bits many people expect for a proper
UUID, and even if you truncate it to 128 bits to create a “good
enough” version prefix, the 6 bits reserved in the UUID format for
the variant code cannot make a correct declaration except by a
random 1:64 chance. The SHA3-256 option allowed in Fossil 2.0 and
higher doesn’t help with this confusion, making a Fossil version
hash twice as large as a proper UUID. Alas, the term will never be
fully obliterated from use since there are columns in the Fossil
repository format that use the obsolete term; we cannot change this
without breaking backwards compatibility.)
You will find all of these synonyms used in the Fossil documentation.
Some day we may settle on a single term, but it doesn’t seem likely.
[CVS]: https://en.wikipedia.org/wiki/Concurrent_Versions_System
[hash]: #version
[RCS]: https://en.wikipedia.org/wiki/Revision_Control_System
[ruuid]: https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_4_(random)
[snfs]: https://en.wikipedia.org/wiki/Snapshot_(computer_storage)#File_systems
[UUID]: https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_4_(random)
[version]: #version
## Check-in <a id="check-in" name="ci"></a>
A [version] of the project’s files that have been committed to the
[repository]; as such, it is sometimes called a “commit” instead. A
check-in is a snapshot of the project at an instant in time, as seen from
a single [check-out’s](#co) perspective. It is sometimes styled
“`CHECKIN`”, especially in command documentation where any
[valid check-in name][ciname] can be used.
* There is a harmless conflation of terms here: any of the various
synonyms for [version] may be used where “check-in” is more accurate,
and vice versa, because there is a 1:1 relation between them. A
check-in *has* a version, but a version suffices to uniquely look up
a particular commit.[^snapshot]
* Combining both sets of synonyms results in a list of terms that is
confusing to new Fossil users, but it’s easy
enough to internalize the concepts. [Committing][commit] creates a
*commit.* It may also be said to create a checked-in *version* of a
particular *revision* of the project’s files, thus creating an
immutable *snapshot* of the project’s state at the time of the
commit. Fossil users find each of these different words for the
same concept useful for expressive purposes among ourselves, but to
Fossil proper, they all mean the same thing.
* Check-ins are immutable.
* Check-ins exist only inside the repository. Contrast a
[check-out](#co).
* Check-ins may have [one or more names][ciname], but only the
[hash] is globally unique, across all time; we call it the check-in’s
canonical name. The other names are either imprecise, contextual, or
change their meaning over time and across [repositories].
[^snapshot]: You may sometimes see the term “snapshot” used as a synonym
for a check-in or the version number identifying said check-in. We
must warn against this usage because there is a potential confusion
here: [the `stash` command][stash] uses the term “snapshot,” as does
[the `undo` system][undo] to make a distinction with check-ins.
Nevertheless, there is a conceptual overlap here between Fossil and
systems that do use the term “snapshot,” the primary distinction being
that Fossil will capture only changes to files you’ve [added][add] to
the [repository], not to everything in [the check-out directory](#co)
at the time of the snapshot. (Thus [the `extras` command][extras].)
Contrast a snapshot taken by a virtual machine system or a
[snapshotting file system][snfs], which captures changes to everything
on the managed storage volume.
[add]: /help?cmd=add
[ciname]: ./checkin_names.wiki
[extras]: /help?cmd=extras
[stash]: /help?cmd=stash
[undo]: /help?cmd=undo
## Check-out <a id="check-out" name="co"></a>
A set of files extracted from a [repository] that represent a
particular [check-in](#ci) of the [project](#project).
* Unlike a check-in, a check-out is mutable. It may start out as a
version of a particular check-in extracted from the repository, but
the user is then free to make modifications to the checked-out
files. Once those changes are formally [committed][commit], they
become a new immutable check-in, derived from its parent check-in.
* You can switch from one check-in to another within a check-out
directory by passing those names to [the `fossil update`
command][update].
* Check-outs relate to repositories in a one-to-many fashion: it is
common to have a single repo clone on a machine but to have it
[open] in [multiple working directories][mwd]. Check-out directories
are associated with the repos they were created from by settings
stored in the check-out directory. This is in the `.fslckout` file on
POSIX type systems, but for historical compatibility reasons, it’s
called `_FOSSIL_` by native Windows builds of Fossil.
(Contrast the Cygwin and WSL Fossil binaries, which use POSIX file
naming rules.)
* In the same way that one cannot extract files from a zip archive
|
| ︙ | ︙ | |||
370 371 372 373 374 375 376 377 | [edoc]: ./embeddeddoc.wiki [fef]: ./fileedit-page.md [fshr]: ./selfhost.wiki [wiki]: ./wikitheory.wiki <div style="height:50em" id="this-space-intentionally-left-blank"></div> | > > > > > > > > > > > > > > > | 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 | [edoc]: ./embeddeddoc.wiki [fef]: ./fileedit-page.md [fshr]: ./selfhost.wiki [wiki]: ./wikitheory.wiki ## <a id="cap"></a>Capability Fossil includes a powerful [role-based access control system][rbac] which affects which users have permission to do certain things within a given [repository]. You can read more about this complex topic [here](./caps/). Some people — and indeed certain parts of Fossil’s own code — use the term “permissions” instead, but since [operating system file permissions also play into this](./caps/#webonly), we prefer the term “capabilities” (or “caps” for short) when talking about Fossil’s RBAC system to avoid a confusion here. [rbac]: https://en.wikipedia.org/wiki/Role-based_access_control <div style="height:50em" id="this-space-intentionally-left-blank"></div> |
Changes to www/hints.wiki.
| ︙ | ︙ | |||
29 30 31 32 33 34 35 |
6. You can manually add a "c=CHECKIN" query parameter to the timeline
URL to get a snapshot of what was going on about the time of some
check-in. The "CHECKIN" can be
[./checkin_names.wiki | any valid check-in or version name], including
tags, branch names, and dates. For example, to see what was going
on in the Fossil repository on 2008-01-01, visit
| | | | | 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 |
6. You can manually add a "c=CHECKIN" query parameter to the timeline
URL to get a snapshot of what was going on about the time of some
check-in. The "CHECKIN" can be
[./checkin_names.wiki | any valid check-in or version name], including
tags, branch names, and dates. For example, to see what was going
on in the Fossil repository on 2008-01-01, visit
[/timeline?c=2008-01-01].
7. Further to the previous two hints, there are lots of query parameters
that you can add to timeline pages. The available query parameters
are tersely documented [/help?cmd=/timeline | here].
8. You can run "[/help?cmd=test-diff | fossil test-diff --tk $file1 $file2]"
to get a pop-up window with side-by-side diffs of two files, even if
neither of the two files is part of any Fossil repository. Note that
this command is "test-diff", not "diff".
9. On web pages showing the content of a file (for example
[/artifact/c7dd1de9f]) you can manually
add a query parameter of the form "ln=FROM,TO" to the URL that
will cause the range of lines indicated to be highlighted. This
is useful in pointing out a few lines of code using a hyperlink
in an email or text message. Example:
[/artifact/c7dd1de9f?ln=28,30].
Adding the "ln" query parameter without any argument simply turns
on line numbers. This feature only works right with files with
a mimetype of text/plain, of course.
10. When editing documentation to be checked in as managed files, you can
preview what the documentation will look like by using the special
"ckout" branch name in the "doc" URL while running "fossil ui".
|
| ︙ | ︙ |
Changes to www/image-format-vs-repo-size.md.
1 2 3 4 5 | # Image Format vs Fossil Repo Size ## The Problem Fossil has a [delta compression][dc] feature which removes redundant | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
# Image Format vs Fossil Repo Size
## The Problem
Fossil has a [delta compression][dc] feature which removes redundant
information from a file relative to its parent on check-in.[^delta-prgs]
That delta is then [zlib][zl]-compressed before being stored
in the Fossil repository database file.
Storing pre-compressed data files in a Fossil repository defeats both of
these space-saving measures:
1. Binary data compression algorithms turn the file data into
pseudorandom noise.[^prn]
Typical data compression algorithms are not [hash functions][hf],
where the goal is that a change to each bit in the input has a
statistically even chance of changing every bit in the output, but
because they do approach that pathological condition, pre-compressed
data tends to defeat Fossil’s delta compression algorithm, there
being so little correlation between two different outputs from the
|
| ︙ | ︙ | |||
32 33 34 35 36 37 38 | itself? It really doesn’t, as far as point 2 above goes, but point 1 causes the Fossil repository to balloon out of proportion to the size of the input data change on each checkin. This article will illustrate that problem, quantify it, and give a solution to it. [dc]: ./delta_format.wiki [hf]: https://en.wikipedia.org/wiki/Hash_function | < | | 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
itself? It really doesn’t, as far as point 2 above goes, but point 1
causes the Fossil repository to balloon out of proportion to the size of
the input data change on each checkin. This article will illustrate that
problem, quantify it, and give a solution to it.
[dc]: ./delta_format.wiki
[hf]: https://en.wikipedia.org/wiki/Hash_function
[zl]: http://www.zlib.net/
## <a id="formats"></a>Affected File Formats
In this article’s core experiment, we use 2D image file formats, but
this article’s advice also applies to many other file types. For just a
few examples out of what must be thousands:
* **Microsoft Office**: The [OOXML document format][oox] used from
Office 2003 onward (`.docx`, `.xlsx`, `.pptx`, etc.) are Zip files
|
| ︙ | ︙ | |||
71 72 73 74 75 76 77 | [jcl]: https://en.wikipedia.org/wiki/Java_(programming_language) [odf]: https://en.wikipedia.org/wiki/OpenDocument [oox]: https://en.wikipedia.org/wiki/Office_Open_XML [wi]: https://en.wikipedia.org/wiki/Windows_Installer | | | | | | | 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 |
[jcl]: https://en.wikipedia.org/wiki/Java_(programming_language)
[odf]: https://en.wikipedia.org/wiki/OpenDocument
[oox]: https://en.wikipedia.org/wiki/Office_Open_XML
[wi]: https://en.wikipedia.org/wiki/Windows_Installer
## <a id="demo"></a>Demonstration
The companion `image-format-vs-repo-size.ipynb` file ([download][nbd],
[preview][nbp]) is a [JupyterLab][jl] notebook implementing the following
experiment:
1. Create a new minimum-size Fossil repository. Save this initial size.
2. Use [ImageMagick][im] via [Wand][wp] to generate a JPEG file of a
particular size — currently 256 px² — filled with Gaussian noise to
make data compression more difficult than with a solid-color image.
3. Check that image into the new Fossil repo, and remember that size.
4. Change a random pixel in the image to a random RGB value, save that
image, check it in, and remember the new Fossil repo size.
5. Iterate on step 4 some number of times — currently 10 — and remember
the Fossil repo size at each step.
6. Repeat the above steps for BMP, PNG, and TIFF.[^tiff-cmp]
7. Create a bar chart showing how the Fossil repository size changes
with each checkin.
We chose to use JupyterLab for this because it makes it easy for you to
modify the notebook to try different things. Want to see how the
results change with a different image size? Easy, change the `size`
value in the second cell of the notebook. Want to try more image
formats? You can put anything ImageMagick can recognize into the
`formats` list. Want to find the break-even point for images like those
in your own repository? Easily done with a small amount of code.
[im]: https://www.imagemagick.org/
[jl]: https://jupyter.org/
[nbd]: ./image-format-vs-repo-size.ipynb
[nbp]: https://nbviewer.jupyter.org/urls/fossil-scm.org/fossil/doc/trunk/www/image-format-vs-repo-size.ipynb
[wp]: http://wand-py.org/
## <a id="results"></a>Results
Running the notebook gives a bar chart something like[^variance] this:

There are a few key things we want to draw your attention to in that
chart:
* BMP and uncompressed TIFF are nearly identical in size for all
checkins, and the repository growth rate is negligible past the
first commit.[^size-jump] We owe this economy to Fossil’s delta compression
feature: it is encoding each of those single-pixel changes in a very
small amount of repository space.
* The JPEG and PNG bars increase by large amounts on most checkins
even though each checkin *also* encodes only a *single-pixel change*.
* The size of the first checkin in the BMP and TIFF cases is roughly
|
| ︙ | ︙ | |||
149 150 151 152 153 154 155 |
tradeoff is to choose JPEG for repositories where each image will
change fewer than that number of times.
[mce]: https://en.wikipedia.org/wiki/Monte_Carlo_method
| | | | 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 |
tradeoff is to choose JPEG for repositories where each image will
change fewer than that number of times.
[mce]: https://en.wikipedia.org/wiki/Monte_Carlo_method
## <a id="makefile"></a>Automated Recompression
Since programs that produce and consume binary-compressed data files
often make it either difficult or impossible to work with the
uncompressed form, we want an automated method for producing the
uncompressed form to make Fossil happy while still having the compressed
form to keep our content creation applications happy. This `Makefile`
should[^makefile] do that for BMP, PNG, SVG, and XLSX files:
.SUFFIXES: .bmp .png .svg .svgz
.svgz.svg:
gzip -dc < $< > $@
.svg.svgz:
|
| ︙ | ︙ | |||
192 193 194 195 196 197 198 |
doc-big.pdf: doc-small.pdf
qpdf --stream-data=uncompress $@ $<
This `Makefile` allows you to treat the compressed version as the
process input, but to actually check in only the changes against the
uncompressed version by typing “`make`” before “`fossil ci`”. This is
not actually an extra step in practice, since if you’ve got a
| | | 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 |
doc-big.pdf: doc-small.pdf
qpdf --stream-data=uncompress $@ $<
This `Makefile` allows you to treat the compressed version as the
process input, but to actually check in only the changes against the
uncompressed version by typing “`make`” before “`fossil ci`”. This is
not actually an extra step in practice, since if you’ve got a
`Makefile`-based project, you should be building — and testing — it
before checking each change in anyway!
Because this technique is based on dependency rules, only the necessary
files are generated on each `make` command.
You only have to run “`make reconstitute`” *once* after opening a fresh
Fossil checkout to produce those compressed sources. After that, you
|
| ︙ | ︙ | |||
237 238 239 240 241 242 243 |
output. Since the file name extension is the same either way, we
treat the compressed PDF as the source to the process, yielding an
automatically-uncompressed PDF for the benefit of Fossil. Unlike
with the Excel case, there is no simple “file base name to directory
name” mapping, so we just created the `-big` to `-small` name scheme
here.
| < | < < | < > | > | > | > | < < > | | 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 |
output. Since the file name extension is the same either way, we
treat the compressed PDF as the source to the process, yielding an
automatically-uncompressed PDF for the benefit of Fossil. Unlike
with the Excel case, there is no simple “file base name to directory
name” mapping, so we just created the `-big` to `-small` name scheme
here.
[^delta-prgs]:
This problem is not Fossil-specific. Several other programs also do
delta compression, so they’ll also be affected by this problem:
[rsync][rs], [Unison][us], [Git][git], etc. You should take this
article’s advice when using all such programs, not just Fossil.
When using file copying and synchronization programs *without* delta
compression, on the other hand, it’s best to use the most
highly-compressed file format you can tolerate, since they copy the
whole file any time any bit of it changes.
[^prn]:
In fact, a good way to gauge the effectiveness of a given
compression scheme is to run its output through the same sort of
tests we use to gauge how “random” a given [PRNG][prng] is. Another
way to look at it is that if there is a discernible pattern in the
output of a compression scheme, that constitutes *information* (in
[the technical sense of that word][ith]) that could be further
compressed.
[^tiff-cmp]:
We're using *uncompressed* TIFF here, not [LZW][lzw]- or
Zip-compressed TIFF, either of which would give similar results to
PNG, which is always zlib-compressed.
[^variance]:
The raw data changes somewhat from one run to the next due to the
use of random noise in the image to make the zlib/PNG compression
more difficult, and the random pixel changes. Those test design
choices make this a [Monte Carlo experiment][mce]. We’ve found that
the overall character of the results doesn’t change from one run to
the next.
[^size-jump]:
It’s not clear to me why there is a one-time jump in size for BMP
and TIFF past the first commit. I suspect it is due to the SQLite
indices being initialized for the first time.
Page size inflation might have something to do with it as well,
though we tried to control that by rebuilding the initial DB with a
minimal page size. If you re-run the program often enough, you will
sometimes see the BMP or TIFF bar jump higher than the other, again
likely due to one of the repos crossing a page boundary.
Another curious artifact in the data is that the BMP is slightly
larger than for the TIFF. This goes against expectation because a
low-tech format like BMP should have a small edge in this test
because TIFF metadata includes the option for multiple timestamps,
UUIDs, etc., which bloat the checkin size by creating many small
deltas.
[^makefile]:
The `Makefile` above is not battle-tested. Please report bugs and
needed extensions [on the forum][for].
[for]: https://fossil-scm.org/forum/forumpost/15e677f2c8
[git]: https://git-scm.com/
[ith]: https://en.wikipedia.org/wiki/Information_theory
[lzw]: https://en.wikipedia.org/wiki/Lempel%E2%80%93Ziv%E2%80%93Welch
[prng]: https://en.wikipedia.org/wiki/Pseudorandom_number_generator
[rs]: https://rsync.samba.org/
[us]: http://www.cis.upenn.edu/~bcpierce/unison/
|
Changes to www/index.wiki.
| ︙ | ︙ | |||
12 13 14 15 16 17 18 | <li> [./changes.wiki | Change Log] <li> [../COPYRIGHT-BSD2.txt | License] <li> [./userlinks.wiki | User Links] <li> [./hacker-howto.wiki | Hacker How-To] <li> [./fossil-v-git.wiki | Fossil vs. Git] <li> [./permutedindex.html | Doc Index] </ul> | | | | | 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 |
<li> [./changes.wiki | Change Log]
<li> [../COPYRIGHT-BSD2.txt | License]
<li> [./userlinks.wiki | User Links]
<li> [./hacker-howto.wiki | Hacker How-To]
<li> [./fossil-v-git.wiki | Fossil vs. Git]
<li> [./permutedindex.html | Doc Index]
</ul>
<p style="text-align:center"><img src="fossil3.gif" alt="Fossil logo"></p>
</div>
Fossil is a simple, high-reliability, distributed software configuration
management system with these advanced features:
1. <b>Project Management</b> -
In addition to doing [./concepts.wiki | distributed version control]
like Git and Mercurial,
Fossil also supports [./bugtheory.wiki | bug tracking],
[./wikitheory.wiki | wiki], [./forum.wiki | forum],
[./alerts.md|email alerts], [./chat.md | chat], and
[./event.wiki | technotes].
2. <b>Built-in Web Interface</b> -
Fossil has a built-in, [/skins | themeable], [./serverext.wiki | extensible],
and intuitive [./webui.wiki | web interface]
with a rich variety of information pages
([./webpage-ex.md|examples]) promoting situational awareness.
<br><br>
This entire website is just a running instance of Fossil.
The pages you see here are all [./wikitheory.wiki | wiki] or
[./embeddeddoc.wiki | embedded documentation] or (in the case of
the [/uv/download.html|download] page)
[./unvers.wiki | unversioned files].
When you clone Fossil from one of its
[./selfhost.wiki | self-hosting repositories],
|
| ︙ | ︙ | |||
81 82 83 84 85 86 87 |
atomic even if interrupted by a power loss or system crash.
Automatic [./selfcheck.wiki | self-checks] verify that all aspects of
the repository are consistent prior to each commit.
8. <b>Free and Open-Source</b> - [../COPYRIGHT-BSD2.txt|2-clause BSD license].
<hr>
| | | | | | 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 |
atomic even if interrupted by a power loss or system crash.
Automatic [./selfcheck.wiki | self-checks] verify that all aspects of
the repository are consistent prior to each commit.
8. <b>Free and Open-Source</b> - [../COPYRIGHT-BSD2.txt|2-clause BSD license].
<hr>
<h3>Latest Release: 2.23 ([/timeline?c=version-2.23|2023-11-01])</h3>
* [/uv/download.html|Download]
* [./changes.wiki#v2_23|Change Summary]
* [/timeline?p=version-2.23&bt=version-2.22&y=ci|Check-ins in version 2.23]
* [/timeline?df=version-2.23&y=ci|Check-ins derived from the 2.23 release]
* [/timeline?t=release|Timeline of all past releases]
<hr>
<h3>Quick Start</h3>
1. [/uv/download.html|Download] or install using a package manager or
[./build.wiki|compile from sources].
|
| ︙ | ︙ |
Changes to www/inout.wiki.
1 2 3 4 5 6 7 8 9 10 | <title>Import And Export</title> Fossil has the ability to import and export repositories from and to [http://git-scm.com/ | Git]. And since most other version control systems will also import/export from Git, that means that you can import/export a Fossil repository to most version control systems using Git as an intermediary. <h2>Git → Fossil</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 | <title>Import And Export</title> Fossil has the ability to import and export repositories from and to [http://git-scm.com/ | Git]. And since most other version control systems will also import/export from Git, that means that you can import/export a Fossil repository to most version control systems using Git as an intermediary. <h2>Git → Fossil</h2> To import a Git repository into Fossil, say something like: <blockquote><pre> cd git-repo git fast-export --all | fossil import --git new-repo.fossil </pre></blockquote> The 3rd argument to the "fossil import" command is the name of a new Fossil repository that is created to hold the Git content. The --git option is not actually required. The git-fast-export file format is currently the only VCS interchange format that Fossil understands. But future versions of Fossil might be enhanced to understand other VCS interchange formats, and so for compatibility, use of the --git option is recommended. <a id="fx_git"></a> Note that in new imports, Fossil defaults to using the email component of the Git <em>committer</em> (or <em>author</em> if <code>--use-author</code> is passed) to attribute check-ins in the imported repository. Alternatively, the [/help?cmd=import | <code>--attribute</code>] option can be passed to have all commits by a given committer attributed to a desired username. This will create and populate the new <code>fx_git</code> table in the repository database to maintain a record of correspondent usernames and email addresses that can be used in subsequent exports or incremental imports. <h3>Converting Repositories on Windows</h3> The above commands work best on proper POSIX systems like Linux, macOS, and the BSDs, where everything <tt>git</tt> sends is consumed by <tt>fossil</tt> as soon as it can manage, with both programs working concurrently. For some reason, the current version of PowerShell included with Windows chokes on the conversion when the in-flight repository size exceeds available memory. We do not know why it buffers the entire stream emitted by "<tt>git fast-export</tt>" before sending it along to Fossil, but we've seen the problem recur on multiple machines. While one workaround is to fall back to <tt>cmd.exe</tt> — which doesn't seem to be affected by this problem — we instead recommend using Mirosoft's own [https://learn.microsoft.com/en-us/windows/wsl/ | Windows Subsystem for Linux] or either of the two popular "Git for Windows" distributions based on MSYS2. They handle pipes the POSIX way, avoiding any dependency on the amount of data involved. <h2>Fossil → Git</h2> To convert a Fossil repository into a Git repository, run commands like this: <blockquote><pre> git init new-repo |
| ︙ | ︙ |
Changes to www/interwiki.md.
1 2 3 4 5 6 7 | # Interwiki Links Interwiki links are a short-hand notation for links that target external wikis or websites. For example, the following two hyperlinks mean the same thing (assuming an appropriate [intermap](#intermap) configuration): | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | # Interwiki Links Interwiki links are a short-hand notation for links that target external wikis or websites. For example, the following two hyperlinks mean the same thing (assuming an appropriate [intermap](#intermap) configuration): * [](wikipedia:MediaWiki#Interwiki_links) * [](https://en.wikipedia.org/wiki/MediaWiki#Interwiki_links) Another example: The Fossil Forum is hosted in a separate repository from the Fossil source code. This page is part of the source code repository. Interwiki links can be used to more easily refer to the forum repository: * [](forum:d5508c3bf44c6393df09c) |
| ︙ | ︙ |
Changes to www/json-api/api-checkout.md.
| ︙ | ︙ | |||
37 38 39 40 41 42 43 44 45 |
Notes:
- The `checkout.tags` property follows the framework-wide convention
that the first tag in the list is the primary branch and any others
are secondary.
- `errorCount` is +1 for each missing file. Conflicts are not treated as
errors because the CLI 'status' command does not treat them as such.
- TODO: Info for the parent version is currently missing.
- TODO: "merged with" info for the checkout is currently missing.
| > > > > > > > > > | 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
Notes:
- The `checkout.tags` property follows the framework-wide convention
that the first tag in the list is the primary branch and any others
are secondary.
- `errorCount` is +1 for each missing file. Conflicts are not treated as
errors because the CLI 'status' command does not treat them as such.
- The `"status"` entry for each of the `"files"` entries will be either a
single string containing a single description of the status change, or
an array of strings if more than one change was made, e.g. `"edited"`
and `"renamed"`. The status strings include:\
`deleted`, `new`, `notAFile`, `missing`, `updatedByMerge`,
`updatedByIntegrate`, `addedBymerge`, `addedByIntegrate`,
`conflict`, `edited`, `renamed`
- File objects with a `"renamed"` status will contain a `"priorName"`
property in addition to the `"name"` property reported in all cases.
- TODO: Info for the parent version is currently missing.
- TODO: "merged with" info for the checkout is currently missing.
|
Added www/json-api/api-settings.md.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 |
# JSON API: /settings
([⬑JSON API Index](index.md))
Jump to:
* [Fetch Settings](#get)
* [Set Settings](#set)
---
<a id="get"></a>
# Fetch Settings
**Status:** Implemented 20230120
**Required permissions:** "o"
**Request:** `/json/settings/get[?version=X]`
**Response payload example:**
```json
{
"access-log":{
"versionable":false,
"sensitive":false,
"defaultValue":"off",
"valueSource":null,
"value":null
},
...
"binary-glob":{
"versionable":true,
"sensitive":false,
"defaultValue":null,
"valueSource":"versioned",
"value":"*.gif\n*.ico\n*.jpg\n*.odp\n*.dia\n*.pdf\n*.png\n*.wav..."
},
...
"web-browser":{
"versionable":false,
"sensitive":true,
"defaultValue":null,
"valueSource":"repo",
"value":"firefox"
}
}
```
Each key in the payload is the name of a fossil-recognized setting,
modeled as an object. The keys of that are:
- `defaultValue`: the setting's default value, or `null` if no default
is defined.
- `value`: The current value of that setting.
- `valueSource`: one of (`"repo"`, `"checkout"`, `"versioned"`, or
`null`), specifying the data source where the setting was found. The
settings sources are checked in this order and the first one found
is the result:
- If `version=X` is provided, check-in `X` is searched for a
versionable-settings file. If found, its value is used and
`valueSource` will be `"versioned"`. If `X` is not a checkin, an
error response is produced with code `FOSSIL-3006`.
- If a versionable setting is found in the current checkout, its
value is used and `valueSource` will be `"versioned"`
- If the setting is found in checkout database's `vvar` table, its
value is used and `valueSource` will be `"checkout"`.
- If the setting is found in repository's `config` table, its
value is used and `valueSource` will be `"repo"`.
- If no value is found, `null` is used for both the `value` and
`valueSource` results. Note that _global settings are never
checked_ because they can leak information which have nothing
specifically to do with the given repository.
- `sensitive`: a value which fossil has flagged as sensitive can only
be fetched by a Setup user. For other users, they will always have
a `value` and `valueSource` of `null`.
- `versionable`: `true` if the setting is tagged as versionable, else
`false`.
Note that settings are internally stored as strings, even if they're
semantically treated as numbers. The way settings are stored and
handled does not give us enough information to recognize their exact
data type here so they are passed on as-is.
<a id="set"></a>
# Set Settings
**Status:** Implemented 20230120
**Required permissions:** "s"
**Request:** `/json/settings/set`
This call requires that the input payload be an object containing a
mapping of fossil-known configuration keys (case-sensitive) to
values. For example:
```json
{
"editor": "emacs",
"admin-log": true,
"auto-captcha": false
}
```
It iterates through each property, which must have a data type of
`null`, boolean, number, or string. A value of `null` _unsets_
(deletes) the setting. Boolean values are stored as integer 0
or 1. All other types are stored as-is. It only updates the
`repository.config` database and never updates a checkout or global
config database, nor is it capable of updating versioned settings
(^Updating versioned settings requires creating a full check-in.).
It has no result payload but this may be changed in the future it
practice shows that it should return something specific.
Error responses include:
- `FOSSIL-2002`: called without "setup" permissions.
- `FOSSIL-3002`: called without a payload object.
- `FOSSIL-3001`: passed an unknown config option.
- `FOSSIL-3000`: a value has an unsupported data type.
If an error is triggered, any settings made by this call up until that
point are discarded.
|
Changes to www/json-api/index.md.
| ︙ | ︙ | |||
26 27 28 29 30 31 32 33 34 35 36 37 38 39 | * [Checkout Status](api-checkout.md) * [Config](api-config.md) * [Diffs](api-diff.md) * [Directory Listing](api-dir.md) * [File Info](api-finfo.md) * [The Obligatory Misc. Category](api-misc.md) * [Repository Stats](api-stat.md) * [SQL Query](api-query.md) * [Tags](api-tag.md) * [Tickets](api-ticket.md) * [Timeline](api-timeline.md) * [User Management](api-user.md) * [Version](api-version.md) * [Wiki](api-wiki.md) | > | 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | * [Checkout Status](api-checkout.md) * [Config](api-config.md) * [Diffs](api-diff.md) * [Directory Listing](api-dir.md) * [File Info](api-finfo.md) * [The Obligatory Misc. Category](api-misc.md) * [Repository Stats](api-stat.md) * [Settings](api-settings.md) * [SQL Query](api-query.md) * [Tags](api-tag.md) * [Tickets](api-ticket.md) * [Timeline](api-timeline.md) * [User Management](api-user.md) * [Version](api-version.md) * [Wiki](api-wiki.md) |
Changes to www/mirrortogithub.md.
1 2 3 4 5 6 | # How To Mirror A Fossil Repository On GitHub Beginning with Fossil version 2.9, you can mirror a Fossil-based project on GitHub (with [limitations](./mirrorlimitations.md)) by following these steps: | < | | < | < | | > | | > | | | | | | | | | | | | | | | | | | | | | | | | | | | | < | < < | | | | | < | < < | 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 |
# How To Mirror A Fossil Repository On GitHub
Beginning with Fossil version 2.9, you can mirror a Fossil-based
project on GitHub (with [limitations](./mirrorlimitations.md))
by following these steps:
1. Create an account on GitHub if you do not have one already. Log
into that account.
2. Create a new project. GitHub will ask you if you want to prepopulate
your project with various things like a README file. Answer "no" to
everything. You want a completely blank project. GitHub will then
supply you with a URL for your project that will look something
like this:
https://github.com/username/project.git
3. Back on your workstation, move to a checkout for your Fossil
project and type:
<blockquote>
<pre>
$ fossil git export /path/to/git/repo --autopush \
https://<font color="orange">username</font>:<font color="red">password</font>@github.com/username/project.git
</pre>
</blockquote>
In place of the <code>/path/to...</code> argument above, put in
some directory name that is <i>outside</i> of your Fossil checkout. If
you keep multiple Fossil checkouts in a directory of their own,
consider using <code>../git-mirror</code> to place the Git export
mirror alongside them, for example. Fossil will create this
directory if necessary. This directory will become a Git
repository that holds a translation of your Fossil repository.
The <code>--autopush</code> option tells Fossil that you want to
push the Git translation up to GitHub every time it is updated.
The URL parameter is the same as the one GitHub gave you, but with
your GitHub <font color="orange">username</font> and <font
color="red">password</font> added.
If your GitHub account uses two-factor authentication (2FA), you
will have to <a href="https://github.com/settings/tokens">generate
a personal access token</a> and use that in place of your actual
password in the URL. This token should have “repo” scope enabled,
only.
You can also run the command above outside of any open checkout of
your project by supplying the “<code>-R repository</code>”
option.
4. Get some coffee. Depending on the size of your project, the
initial "<code>fossil git export</code>" command in the previous
step might run for several minutes.
5. And you are done! Assuming everything worked, your project is now
mirrored on GitHub.
6. Whenever you update your project, simply run this command to update
the mirror:
$ fossil git export
Unlike with the first time you ran that command, you don’t need
the remaining arguments, because Fossil remembers those things.
Subsequent mirror updates should usually happen in a fraction of
a second.
7. To see the status of your mirror, run:
$ fossil git status
## Notes:
* Unless you specify --force, the mirroring only happens if the Fossil
repo has changed, with Fossil reporting "no changes", because Fossil
does not care about the success or failure of the mirror run. If a mirror
run failed (for example, due to an incorrect password, or a transient
|
| ︙ | ︙ |
Changes to www/mkindex.tcl.
| ︙ | ︙ | |||
21 22 23 24 25 26 27 |
backup.md {Backing Up a Remote Fossil Repository}
blame.wiki {The Annotate/Blame Algorithm Of Fossil}
blockchain.md {Is Fossil A Blockchain?}
branching.wiki {Branching, Forking, Merging, and Tagging}
bugtheory.wiki {Bug Tracking In Fossil}
build.wiki {Compiling and Installing Fossil}
cap-theorem.md {Fossil and the CAP Theorem}
| | > | 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 |
backup.md {Backing Up a Remote Fossil Repository}
blame.wiki {The Annotate/Blame Algorithm Of Fossil}
blockchain.md {Is Fossil A Blockchain?}
branching.wiki {Branching, Forking, Merging, and Tagging}
bugtheory.wiki {Bug Tracking In Fossil}
build.wiki {Compiling and Installing Fossil}
cap-theorem.md {Fossil and the CAP Theorem}
caps/ {Administering User Capabilities (a.k.a. Permissions)}
caps/admin-v-setup.md {Differences Between Setup and Admin Users}
caps/ref.html {User Capability Reference}
cgi.wiki {CGI Script Configuration Options}
changes.wiki {Fossil Changelog}
chat.md {Fossil Chat}
checkin_names.wiki {Check-in And Version Names}
checkin.wiki {Check-in Checklist}
childprojects.wiki {Child Projects}
chroot.md {Server Chroot Jail}
ckout-workflows.md {Check-Out Workflows}
co-vs-up.md {Checkout vs Update}
copyright-release.html {Contributor License Agreement}
concepts.wiki {Fossil Core Concepts}
contact.md {Developer Contact Information}
containers.md {OCI Containers}
contribute.wiki {Contributing Code or Documentation To The Fossil Project}
css-tricks.md {Fossil CSS Tips and Tricks}
customgraph.md {Theming: Customizing the Timeline Graph}
customskin.md {Theming: Customizing The Appearance of Web Pages}
customskin.md {Custom Skins}
custom_ticket.wiki {Customizing The Ticket System}
defcsp.md {The Default Content Security Policy}
|
| ︙ | ︙ | |||
150 151 152 153 154 155 156 |
}
set permindex [lsort -dict -index 0 $permindex]
set out [open permutedindex.html w]
fconfigure $out -encoding utf-8 -translation lf
puts $out \
"<div class='fossil-doc' data-title='Index Of Fossil Documentation'>"
puts $out {
| < | < | | 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 |
}
set permindex [lsort -dict -index 0 $permindex]
set out [open permutedindex.html w]
fconfigure $out -encoding utf-8 -translation lf
puts $out \
"<div class='fossil-doc' data-title='Index Of Fossil Documentation'>"
puts $out {
<form action='$ROOT/docsrch' method='GET' style="text-align:center">
<input type="text" name="s" size="40" autofocus>
<input type="submit" value="Search Docs">
</form>
<h2>Primary Documents:</h2>
<ul>
<li> <a href='quickstart.wiki'>Quick-start Guide</a>
<li> <a href='$ROOT/help'>Built-in help for commands and webpages</a>
<li> <a href='history.md'>Purpose and History of Fossil</a>
<li> <a href='build.wiki'>Compiling and installing Fossil</a>
<li> <a href='../COPYRIGHT-BSD2.txt'>License</a>
<li> <a href='userlinks.wiki'>Miscellaneous Docs for Fossil Users</a>
<li> <a href='hacker-howto.wiki'>Fossil Developer's Guide</a>
<ul><li><a href='$ROOT/wiki?name=Release Build How-To'>Release Build How-To</a>, a.k.a.
how deliverables are built</li></ul>
</li>
<li> <a href='$ROOT/wiki?name=To+Do+List'>To Do List (Wiki)</a>
<li> <a href='https://fossil-scm.org/fossil-book/'>Fossil book</a>
</ul>
<h2 id="pindex">Other Documents:</h2>
<ul>}
foreach entry $permindex {
foreach {title file bold} $entry break
# if {$bold} {set title <b>$title</b>}
if {[string match /* $file]} {set file ../../..$file}
puts $out "<li><a href=\"$file\">$title</a></li>"
}
puts $out "</ul></div>"
|
Changes to www/newrepo.wiki.
1 2 | <title>How To Create A New Fossil Repository</title> | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <title>How To Create A New Fossil Repository</title> The [/doc/tip/www/quickstart.wiki|quickstart guide] explains how to get up and running with fossil. But once you're running, what can you do with it? This document will walk you through the process of creating a fossil repository, populating it with files, and then sharing it over the web. The first thing we need to do is create a fossil repository file: <verbatim> stephan@ludo:~/fossil$ fossil new demo.fossil project-id: 9d8ccff5671796ee04e60af6932aa7788f0a990a server-id: 145fe7d71e3b513ac37ac283979d73e12ca04bfe |
| ︙ | ︙ |
Changes to www/permutedindex.html.
1 2 | <div class='fossil-doc' data-title='Index Of Fossil Documentation'> | < | < | | | 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 | <div class='fossil-doc' data-title='Index Of Fossil Documentation'> <form action='$ROOT/docsrch' method='GET' style="text-align:center"> <input type="text" name="s" size="40" autofocus> <input type="submit" value="Search Docs"> </form> <h2>Primary Documents:</h2> <ul> <li> <a href='quickstart.wiki'>Quick-start Guide</a> <li> <a href='$ROOT/help'>Built-in help for commands and webpages</a> <li> <a href='history.md'>Purpose and History of Fossil</a> <li> <a href='build.wiki'>Compiling and installing Fossil</a> <li> <a href='../COPYRIGHT-BSD2.txt'>License</a> <li> <a href='userlinks.wiki'>Miscellaneous Docs for Fossil Users</a> <li> <a href='hacker-howto.wiki'>Fossil Developer's Guide</a> <ul><li><a href='$ROOT/wiki?name=Release Build How-To'>Release Build How-To</a>, a.k.a. how deliverables are built</li></ul> </li> <li> <a href='$ROOT/wiki?name=To+Do+List'>To Do List (Wiki)</a> <li> <a href='https://fossil-scm.org/fossil-book/'>Fossil book</a> </ul> <h2 id="pindex">Other Documents:</h2> <ul> <li><a href="tech_overview.wiki">A Technical Overview Of The Design And Implementation Of Fossil</a></li> <li><a href="serverext.wiki">Adding Extensions To A Fossil Server Using CGI Scripts</a></li> <li><a href="adding_code.wiki">Adding New Features To Fossil</a></li> <li><a href="caps/">Administering User Capabilities (a.k.a. Permissions)</a></li> <li><a href="backup.md">Backing Up a Remote Fossil Repository</a></li> <li><a href="whyusefossil.wiki">Benefits Of Version Control</a></li> <li><a href="branching.wiki">Branching, Forking, Merging, and Tagging</a></li> <li><a href="bugtheory.wiki">Bug Tracking In Fossil</a></li> <li><a href="cgi.wiki">CGI Script Configuration Options</a></li> <li><a href="serverext.wiki">CGI Server Extensions</a></li> <li><a href="checkin_names.wiki">Check-in And Version Names</a></li> |
| ︙ | ︙ | |||
93 94 95 96 97 98 99 100 101 102 103 104 105 106 | <li><a href="fossil-is-not-relational.md">Introduction to the (Non-relational) Fossil Data Model</a></li> <li><a href="blockchain.md">Is Fossil A Blockchain?</a></li> <li><a href="json-api/index.md">JSON API</a></li> <li><a href="mirrorlimitations.md">Limitations On Git Mirrors</a></li> <li><a href="../../../help">Lists of Commands and Webpages</a></li> <li><a href="loadmgmt.md">Managing Server Load</a></li> <li><a href="../../../md_rules">Markdown Formatting Rules</a></li> <li><a href="password.wiki">Password Management And Authentication</a></li> <li><a href="stats.wiki">Performance Statistics</a></li> <li><a href="../test/release-checklist.wiki">Pre-Release Testing Checklist</a></li> <li><a href="pop.wiki">Principles Of Operation</a></li> <li><a href="qandc.wiki">Questions And Criticisms</a></li> <li><a href="quotes.wiki">Quotes: What People Are Saying About Fossil, Git, and DVCSes in General</a></li> <li><a href="rebaseharm.md">Rebase Considered Harmful</a></li> | > | 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 | <li><a href="fossil-is-not-relational.md">Introduction to the (Non-relational) Fossil Data Model</a></li> <li><a href="blockchain.md">Is Fossil A Blockchain?</a></li> <li><a href="json-api/index.md">JSON API</a></li> <li><a href="mirrorlimitations.md">Limitations On Git Mirrors</a></li> <li><a href="../../../help">Lists of Commands and Webpages</a></li> <li><a href="loadmgmt.md">Managing Server Load</a></li> <li><a href="../../../md_rules">Markdown Formatting Rules</a></li> <li><a href="containers.md">OCI Containers</a></li> <li><a href="password.wiki">Password Management And Authentication</a></li> <li><a href="stats.wiki">Performance Statistics</a></li> <li><a href="../test/release-checklist.wiki">Pre-Release Testing Checklist</a></li> <li><a href="pop.wiki">Principles Of Operation</a></li> <li><a href="qandc.wiki">Questions And Criticisms</a></li> <li><a href="quotes.wiki">Quotes: What People Are Saying About Fossil, Git, and DVCSes in General</a></li> <li><a href="rebaseharm.md">Rebase Considered Harmful</a></li> |
| ︙ | ︙ |
Changes to www/pop.wiki.
1 2 3 | <title>Principles Of Operation</title> <h1 align="center">Principles Of Operation</h1> | < < < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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 |
<title>Principles Of Operation</title>
<h1 align="center">Principles Of Operation</h1>
This page attempts to define the foundational principals upon
which Fossil is built.
* A project consists of source files, wiki pages, and
trouble tickets, and control files (collectively "artifacts").
All historical copies of all artifacts
are saved. The project maintains an audit
trail.
* A project resides in one or more repositories. Each
repository is administered and operates independently
of the others.
* Each repository has both global and local state. The
global state is common to all repositories (or at least
has the potential to be shared in common when the
repositories are fully synchronized). The local state
for each repository is private to that repository.
The global state represents the content of the project.
The local state identifies the authorized users and
access policies for a particular repository.
* The global state of a repository is an unordered
collection of artifacts. Each artifact is named by a
cryptographic hash (SHA1 or SHA3-256) encoded in
lowercase hexadecimal.
In many contexts, the name can be
abbreviated to a unique prefix. A five- or six-character
prefix usually suffices to uniquely identify a file.
* Because artifacts are named by a cryptographic hash, all artifacts
are immutable. Any change to the content of an artifact also
changes the hash that forms the artifacts name, thus
creating a new artifact. Both the old original version of the
artifact and the new change are preserved under different names.
* It is theoretically possible for two artifacts with different
content to share the same hash. But finding two such
artifacts is so incredibly difficult and unlikely that we
consider it to be an impossibility.
* The signature of an artifact is the cryptographic hash of the
artifact itself, exactly as it would appear in a disk file. No prefix
or meta-information about the artifact is added before computing
the hash. So you can
always find the signature of a file by using the
"sha1sum" or "sha3sum" or similar command-line utilities.
* The artifacts that comprise the global state of a repository
are the complete global state of that repository. The SQLite
database that holds the repository contains additional information
about linkages between artifacts, but all of that added information
can be discarded and reconstructed by rescanning the content
artifacts.
* Two repositories for the same project can synchronize
their global states simply by sharing artifacts. The local
state of repositories is not normally synchronized or
shared.
* Every check-in has a special file at the top-level
named "manifest" which is an index of all other files in
that check-in. The manifest is automatically created and
maintained by the system.
* The <a href="fileformat.wiki">file formats</a>
used by Fossil are all very simple so that with access
to the original content files, one can easily reconstruct
the content of a check-in without the need for any
special tools or software.
|
Changes to www/private.wiki.
| ︙ | ︙ | |||
48 49 50 51 52 53 54 55 56 57 58 59 60 61 | check-in manifest of the resulting merge child would include a <code>+close</code> tag referring to the leaf check-in on the private branch, and generate a missing artifact reference on repository clones without that private branch. It's still possible to close the leaf of the private branch (after committing the merge child) with the <code>fossil amend --close</code> command. <h2>Syncing Private Branches</h2> A private branch normally stays on the one repository where it was originally created. But sometimes you want to share private branches with another repository. For example, you might be building a cross-platform application and have separate repositories on your Windows laptop, your Linux desktop, and your iMac. You can transfer private branches | > > > > > > > > > > > > > | 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 | check-in manifest of the resulting merge child would include a <code>+close</code> tag referring to the leaf check-in on the private branch, and generate a missing artifact reference on repository clones without that private branch. It's still possible to close the leaf of the private branch (after committing the merge child) with the <code>fossil amend --close</code> command. <blockquote><small> Side note: For the same reason, i.e. so as not to generate a missing artifact reference on peer repositories without the private branch, the merge parent is not recorded when merging the private branch into a public branch. As a consequence, the web UI timeline does not draw a merge line from the private merge parent to the public merge child. Moreover, repeat private-to-public merge operations (without the [/help?cmd=merge | --force option]) with files added on the private branch may only work once, but later abort with "WARNING: no common ancestor for FILE", as the parent-child relationship is not recorded (see the [/doc/trunk/www/branching.wiki | Branching, Forking, Merging, and Tagging] document for more information). </small></blockquote> <h2>Syncing Private Branches</h2> A private branch normally stays on the one repository where it was originally created. But sometimes you want to share private branches with another repository. For example, you might be building a cross-platform application and have separate repositories on your Windows laptop, your Linux desktop, and your iMac. You can transfer private branches |
| ︙ | ︙ |
Changes to www/qandc.wiki.
1 2 3 4 | <title>Questions And Criticisms</title> <nowiki> <h1 align="center">Questions And Criticisms</h1> | | | | | | | | 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 |
<title>Questions And Criticisms</title>
<nowiki>
<h1 align="center">Questions And Criticisms</h1>
This page is a collection of real questions and criticisms that were
raised against Fossil early in its history (circa 2008).
This page is old and has not been kept up-to-date. See the
</nowiki>[/finfo?name=www/qandc.wiki|change history of this page]<nowiki>.
<b>Fossil sounds like a lot of reinvention of the wheel.
Why create your own DVCS when you could have reused mercurial?</b>
<blockquote>
I wrote fossil because none of the
other available DVCSes met my needs. If the other DVCSes do
meet your needs, then you might not need fossil. But they
don't meet mine, and so fossil is necessary for me.
Features provided by fossil that one does not get with other
DVCSes include:
<ol>
<li> Integrated <a href="wikitheory.wiki">wiki</a>. </li>
<li> Integrated <a href="bugtheory.wiki">bug tracking</a> </li>
<li> Immutable artifacts </li>
<li> Self-contained, stand-alone executable that can be run in
a <a href="http://en.wikipedia.org/wiki/Chroot">chroot jail</a> </li>
|
| ︙ | ︙ | |||
47 48 49 50 51 52 53 |
Fossil is an all-in-one turnkey solution. </li>
</ol>
</blockquote>
<b>Love the concept here. Anyone using this for real work yet?</b>
<blockquote>
| | | | | | | | | | | | 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 |
Fossil is an all-in-one turnkey solution. </li>
</ol>
</blockquote>
<b>Love the concept here. Anyone using this for real work yet?</b>
<blockquote>
Fossil is <a href="https://fossil-scm.org/">self-hosting</a>.
In fact, this page was probably delivered
to your web-browser via a working fossil instance. The same virtual
machine that hosts https://fossil-scm.org/
(a <a href="http://www.linode.com/">Linode 720</a>)
also hosts 24 other fossil repositories for various small projects.
The documentation files for
<a href="http://www.sqlite.org/">SQLite</a> are hosted in a
fossil repository <a href="http://www.sqlite.org/docsrc/">here</a>,
for example.
Other projects are also adopting fossil. But fossil does not yet have
the massive user base of git or mercurial.
</blockquote>
<b>Fossil looks like the bug tracker that would be in your
Linksys Router's administration screen.</b>
<blockquote>
I take a pragmatic approach to software: form follows function.
To me, it is more important to have a reliable, fast, efficient,
enduring, and simple DVCS than one that looks pretty.
On the other hand, if you have patches that improve the appearance
of Fossil without seriously compromising its reliability, performance,
and/or maintainability, I will be happy to accept them. Fossil is
self-hosting. Send email to request a password that will let
you push to the main fossil repository.
</blockquote>
<b>It would be useful to have a separate application that
keeps the bug-tracking database in a versioned file. That file can
then be pushed and pulled along with the rest repository.</b>
<blockquote>
Fossil already <u>does</u> push and pull bugs along with the files
in your repository.
But fossil does <u>not</u> track bugs as files in the source tree.
That approach to bug tracking was rejected for three reasons:
<ol>
<li> Check-ins in fossil are immutable. So if
tickets were part of the check-in, then there would be no way to add
new tickets to a check-in as new bugs are discovered.
<li> Any project of reasonable size and complexity will generate thousands
and thousands of tickets, and we do not want all those ticket files
cluttering the source tree.
<li> We want tickets to be managed from the web interface and to have a
permission system that is distinct from check-in permissions.
In other words, we do not want to restrict the creation and editing
of tickets to developers with check-in privileges and an installed
copy of the fossil executable. Casual passers-by on the internet should
be permitted to create tickets.
</ol>
These points are reiterated in the opening paragraphs of
the <a href="bugtheory.wiki">Bug-Tracking In Fossil</a> document.
</blockquote>
<b>Fossil is already the name of a plan9 versioned
append-only filesystem.</b>
<blockquote>
I did not know that. Perhaps they selected the name for the same reason that
|
| ︙ | ︙ | |||
134 135 136 137 138 139 140 | <b>I am dubious of the benefits of including wikis and bug trackers directly in the VCS - either they are under-featured compared to full software like Trac, or the VCS is massively bloated compared to Subversion or Bazaar.</b> <blockquote> | | | | | | 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 | <b>I am dubious of the benefits of including wikis and bug trackers directly in the VCS - either they are under-featured compared to full software like Trac, or the VCS is massively bloated compared to Subversion or Bazaar.</b> <blockquote> I have no doubt that Trac has many features that fossil lacks. But that is not the point. Fossil has several key features that Trac lacks and that I need: most notably the fact that fossil supports disconnected operation. As for bloat: Fossil is a single self-contained executable. You do not need any other packages (diff, patch, merge, cvs, svn, rcs, git, python, perl, tcl, apache, sqlite, and so forth) in order to run fossil. Fossil runs just fine in a chroot jail all by itself. And the self-contained fossil executable is much less than 1MB in size. (Update 2015-01-12: Fossil has grown in the years since the previous sentence was written but is still much less than 2MB according to "size" when compiled using -Os on x64 Linux.) Fossil is the very opposite of bloat. </blockquote> </nowiki> |
Changes to www/quickstart.wiki.
1 2 3 | <title>Fossil Quick Start Guide</title> <h1 align="center">Fossil Quick Start</h1> | | | | | > | | | | | | | | | | | 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 |
<title>Fossil Quick Start Guide</title>
<h1 align="center">Fossil Quick Start</h1>
This is a guide to help you get started using the Fossil [https://en.wikipedia.org/wiki/Distributed_version_control|Distributed Version Control System] quickly
and painlessly.
<h2 id="install">Installing</h2>
Fossil is a single self-contained C program. You need to
either download a
[https://fossil-scm.org/home/uv/download.html|precompiled
binary]
or <a href="build.wiki">compile it yourself</a> from sources.
Install Fossil by putting the fossil binary
someplace on your $PATH.
You can test that Fossil is present and working like this:
<blockquote>
<b>
fossil version<br>
<tt>This is fossil version 2.13 [309af345ab] 2020-09-28 04:02:55 UTC</tt><br>
</b>
</blockquote>
<h2 id="workflow" name="fslclone">General Work Flow</h2>
Fossil works with repository files (a database in a single file with the project's
complete history) and with checked-out local trees (the working directory
you use to do your work).
(See [./glossary.md | the glossary] for more background.)
The workflow looks like this:
<ul>
<li>Create or clone a repository file. ([/help/init|fossil init] or
[/help/clone | fossil clone])
<li>Check out a local tree. ([/help/open | fossil open])
<li>Perform operations on the repository (including repository
configuration).
</ul>
Fossil can be entirely driven from the command line. Many features
can also be conveniently accessed from the built-in web user interface.
The following sections give a brief overview of these
operations.
<h2 id="new">Starting A New Project</h2>
To start a new project with fossil create a new empty repository
this way: ([/help/init | more info])
<blockquote>
<b>fossil init </b><i> repository-filename</i>
</blockquote>
You can name the database anything you like, and you can place it anywhere in the filesystem.
The <tt>.fossil</tt> extension is traditional but only required if you are going to use the
<tt>[/help/server | fossil server DIRECTORY]</tt> feature.”
<h2 id="clone">Cloning An Existing Repository</h2>
Most fossil operations interact with a repository that is on the
local disk drive, not on a remote system. Hence, before accessing
a remote repository it is necessary to make a local copy of that
repository. Making a local copy of a remote repository is called
"cloning".
Clone a remote repository as follows: ([/help/clone | more info])
<blockquote>
<b>fossil clone</b> <i>URL repository-filename</i>
</blockquote>
The <i>URL</i> specifies the fossil repository
you want to clone. The <i>repository-filename</i> is the new local
filename into which the cloned repository will be written. For
example, to clone the source code of Fossil itself:
<blockquote>
<b>fossil clone https://fossil-scm.org/ myclone.fossil</b>
</blockquote>
|
| ︙ | ︙ | |||
92 93 94 95 96 97 98 |
Vacuuming the database... <br>
project-id: 94259BB9F186226D80E49D1FA2DB29F935CCA0333<br>
server-id: 016595e9043054038a9ea9bc526d7f33f7ac0e42<br>
admin-user: exampleuser (password is "yoWgDR42iv")><br>
</tt></b>
</blockquote>
| | | | | | | | | | | | | | | | | | | | | | | | > > | | | | > | > > | | | | | 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 |
Vacuuming the database... <br>
project-id: 94259BB9F186226D80E49D1FA2DB29F935CCA0333<br>
server-id: 016595e9043054038a9ea9bc526d7f33f7ac0e42<br>
admin-user: exampleuser (password is "yoWgDR42iv")><br>
</tt></b>
</blockquote>
If the remote repository requires a login, include a
userid in the URL like this:
<blockquote>
<b>fossil clone https://</b><i>remoteuserid</i><b>@www.example.org/ myclone.fossil</b>
</blockquote>
You will be prompted separately for the password.
Use [https://en.wikipedia.org/wiki/Percent-encoding#Percent-encoding_reserved_characters|"%HH"] escapes for special characters in the userid.
For example "/" would be replaced by "%2F" meaning that a userid of "Projects/Budget" would become "Projects%2FBudget")
If you are behind a restrictive firewall, you might need
to <a href="#proxy">specify an HTTP proxy</a>.
A Fossil repository is a single disk file. Instead of cloning,
you can just make a copy of the repository file (for example, using
"scp"). Note, however, that the repository file contains auxiliary
information above and beyond the versioned files, including some
sensitive information such as password hashes and email addresses. If you
want to share Fossil repositories directly by copying, consider running the
[/help/scrub|fossil scrub] command to remove sensitive information
before transmitting the file.
<h2 id="import">Importing From Another Version Control System</h2>
Rather than start a new project, or clone an existing Fossil project,
you might prefer to
<a href="./inout.wiki">import an existing Git project</a>
into Fossil using the [/help/import | fossil import] command.
You can even decide to export your project back into git using the
[/help/git | fossil git] command, which is how the Fossil project maintains
[https://github.com/drhsqlite/fossil-mirror | its public GitHub mirror]. There
is no limit to the number of times a tree can be imported and exported between
Fossil and git.
The [https://git-scm.com/docs/git-fast-export|Git fast-export format] has become
a popular way to move files between version management systems, including from
[https://www.mercurial-scm.org/|Mercurial].
Fossil can also import [https://subversion.apache.org/|Subversion projects] directly.
<h2 id="checkout">Checking Out A Local Tree</h2>
To work on a project in fossil, you need to check out a local
copy of the source tree. Create the directory you want to be
the root of your tree and cd into that directory. Then
do this: ([/help/open | more info])
<blockquote>
<b>fossil open </b><i> repository-filename</i>
</blockquote>
for example:
<blockquote>
<b><tt>
fossil open ../myclone.fossil<br>
BUILD.txt<br>
COPYRIGHT-BSD2.txt<br>
README.md<br>
︙<br>
</tt></b>
</blockquote>
(or "fossil open ..\myclone.fossil" on Windows).
This leaves you with the newest version of the tree
checked out.
From anywhere underneath the root of your local tree, you
can type commands like the following to find out the status of
your local tree:
<blockquote>
<b>[/help/info | fossil info]</b><br>
<b>[/help/status | fossil status]</b><br>
<b>[/help/changes | fossil changes]</b><br>
<b>[/help/diff | fossil diff]</b><br>
<b>[/help/timeline | fossil timeline]</b><br>
<b>[/help/ls | fossil ls]</b><br>
<b>[/help/branch | fossil branch]</b><br>
</blockquote>
If you created a new repository using "fossil init" some commands will not
produce much output.
Note that Fossil allows you to make multiple check-outs in
separate directories from the same repository. This enables you,
for example, to do builds from multiple branches or versions at
the same time without having to generate extra clones.
To switch a checkout between different versions and branches,
use:<
<blockquote>
<b>[/help/update | fossil update]</b><br>
<b>[/help/checkout | fossil checkout]</b><br>
</blockquote>
[/help/update | update] honors the "autosync" option and
does a "soft" switch, merging any local changes into the target
version, whereas [/help/checkout | checkout] does not
automatically sync and does a "hard" switch, overwriting local
changes if told to do so.
<h2 id="changes">Making and Committing Changes</h2>
To add new files to your project or remove existing ones, use these
commands:
<blockquote>
<b>[/help/add | fossil add]</b> <i>file...</i><br>
<b>[/help/rm | fossil rm]</b> <i>file...</i><br>
<b>[/help/addremove | fossil addremove]</b> <i>file...</i><br>
</blockquote>
The command:
<blockquote>
<b>
[/help/changes | fossil changes]</b>
</blockquote>
lists files that have changed since the last commit to the repository. For
example, if you edit the file "README.md":
<blockquote>
<b>
fossil changes<br>
EDITED README.md
</b>
</blockquote>
To see exactly what change was made you can use the command
<b>[/help/diff | fossil diff]</b>:
<blockquote>
<b>
fossil diff <br><tt>
Index: README.md<br>
============================================================<br>
--- README.md<br>
+++ README.md<br>
@@ -1,5 +1,6 @@<br>
+Made some changes to the project<br>
# Original text<br>
</tt></b>
</blockquote>
"fossil diff" shows the difference between your tree on disk now and as
the tree was when you last committed changes. If you haven't committed
yet, then it shows the difference relative to the tip-of-trunk commit in
the repository, being what you get when you "fossil open" a repository
without specifying a version, populating the working directory.
To see the most recent changes made to the repository by other users, use "fossil timeline" to
find out the most recent commit, and then "fossil diff" between that commit and the
current tree:
<blockquote>
<b>
fossil timeline <br><tt>
=== 2021-03-28 === <br>
03:18:54 [ad75dfa4a0] *CURRENT* Added details to frobnicate command (user: user-one tags: trunk) <br>
=== 2021-03-27 === <br>
23:58:05 [ab975c6632] Update README.md. (user: user-two tags: trunk) <br>
|
| ︙ | ︙ | |||
267 268 269 270 271 272 273 |
# Original text<br>
</tt></b>
</blockquote>
"current" is an alias for the checkout version, so the command
"fossil diff --from ad75dfa4a0 --to ab975c6632" gives identical results.
| | | | | | > | | | | | | | | | | | | | | | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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 |
# Original text<br>
</tt></b>
</blockquote>
"current" is an alias for the checkout version, so the command
"fossil diff --from ad75dfa4a0 --to ab975c6632" gives identical results.
To commit your changes to a local-only repository:
<blockquote>
<b>
fossil commit </b><i>(... Fossil will start your editor, if defined)</i><b><br><tt>
# Enter a commit message for this check-in. Lines beginning with # are ignored.<br>
#<br>
# user: exampleuser<br>
# tags: trunk<br>
#<br>
# EDITED README.md<br>
Edited file to add description of code changes<br>
New_Version: 7b9a416ced4a69a60589dde1aedd1a30fde8eec3528d265dbeed5135530440ab<br>
</tt></b>
</blockquote>
You will be prompted for check-in comments using whatever editor
is specified by your VISUAL or EDITOR environment variable. If none is
specified Fossil uses line-editing in the terminal.
To commit your changes to a repository that was cloned from a remote
repository, you give the same command, but the results are different.
Fossil defaults to [./concepts.wiki#workflow|autosync] mode, a
single-stage commit that sends all changes committed to the local
repository immediately on to the remote parent repository. This only
works if you have write permission to the remote respository.
<h2 id="naming">Naming of Files, Checkins, and Branches</h2>
Fossil deals with information artifacts. This Quickstart document only deals
with files and collections of files, but be aware there are also tickets, wiki pages and more.
Every artifact in Fossil has a universally-unique hash id, and may also have a
human-readable name.
The following are all equivalent ways of identifying a Fossil file,
checkin or branch artifact:
<ul>
<li> the full unique SHA-256 hash, such as be836de35a821523beac2e53168e135d5ebd725d7af421e5f736a28e8034673a
<li> an abbreviated hash prefix, such as the first ten characters: be836de35a . This won't be universally unique, but it is usually unique within any one repository. As an example, the [https://fossil-scm.org/home/hash-collisions|Fossil project hash collisions] showed at the time of writing that there are no artifacts with identical first 8 characters
<li> a branch name, such as "special-features" or "juliet-testing". Each branch also has a unique SHA-256 hash
</ul>
A special convenience branch is "trunk", which is Fossil's default branch name for
the first checkin, and the default for any time a branch name is needed but not
specified.
This will get you started on identifying checkins. The
<a href="./checkin_names.wiki">Checkin Names document</a> is a complete reference, including
how timestamps can also be used.
<h2 id="config">Configuring Your Local Repository</h2>
When you create a new repository, either by cloning an existing
project or create a new project of your own, you usually want to do some
local configuration. This is easily accomplished using the web-server
that is built into fossil. Start the fossil web server like this:
([/help/ui | more info])
<blockquote>
<b>fossil ui </b><i> repository-filename</i>
</blockquote>
You can omit the <i>repository-filename</i> from the command above
if you are inside a checked-out local tree.
This starts a web server then automatically launches your
web browser and makes it point to this web server. If your system
has an unusual configuration, fossil might not be able to figure out
how to start your web browser. In that case, first tell fossil
where to find your web browser using a command like this:
<blockquote>
<b>fossil setting web-browser </b><i> path-to-web-browser</i>
</blockquote>
By default, fossil does not require a login for HTTP connections
coming in from the IP loopback address 127.0.0.1. You can, and perhaps
should, change this after you create a few users.
When you are finished configuring, just press Control-C or use
the <b>kill</b> command to shut down the mini-server.
<h2 id="sharing">Sharing Changes</h2>
When [./concepts.wiki#workflow|autosync] is turned off,
the changes you [/help/commit | commit] are only
on your local repository.
To share those changes with other repositories, do:
<blockquote>
<b>[/help/push | fossil push]</b> <i>URL</i>
</blockquote>
Where <i>URL</i> is the http: URL of the server repository you
want to share your changes with. If you omit the <i>URL</i> argument,
fossil will use whatever server you most recently synced with.
The [/help/push | push] command only sends your changes to others. To
Receive changes from others, use [/help/pull | pull]. Or go both ways at
once using [/help/sync | sync]:
<blockquote>
<b>[/help/pull | fossil pull]</b> <i>URL</i><br>
<b>[/help/sync | fossil sync]</b> <i>URL</i>
</blockquote>
When you pull in changes from others, they go into your repository,
not into your checked-out local tree. To get the changes into your
local tree, use [/help/update | update]:
<blockquote>
<b>[/help/update | fossil update]</b> <i>VERSION</i>
</blockquote>
The <i>VERSION</i> can be the name of a branch or tag or any
abbreviation to the 40-character
artifact identifier for a particular check-in, or it can be a
date/time stamp. ([./checkin_names.wiki | more info])
If you omit
the <i>VERSION</i>, then fossil moves you to the
latest version of the branch your are currently on.
The default behavior is for [./concepts.wiki#workflow|autosync] to
be turned on. That means that a [/help/pull|pull] automatically occurs
when you run [/help/update|update] and a [/help/push|push] happens
automatically after you [/help/commit|commit]. So in normal practice,
the push, pull, and sync commands are rarely used. But it is important
to know about them, all the same.
<blockquote>
<b>[/help/checkout | fossil checkout]</b> <i>VERSION</i>
</blockquote>
Is similar to update except that it does not honor the autosync
setting, nor does it merge in local changes - it prefers to overwrite
them and fails if local changes exist unless the <tt>--force</tt>
flag is used.
<h2 id="branch" name="merge">Branching And Merging</h2>
Use the --branch option to the [/help/commit | commit] command
to start a new branch. Note that in Fossil, branches are normally
created when you commit, not before you start editing. You can
use the [/help/branch | branch new] command to create a new branch
before you start editing, if you want, but most people just wait
until they are ready to commit.
To merge two branches back together, first
[/help/update | update] to the branch you want to merge into.
Then do a [/help/merge|merge] of the other branch that you want to incorporate
the changes from. For example, to merge "featureX" changes into "trunk"
do this:
<blockquote>
<b>fossil [/help/update|update] trunk</b><br>
<b>fossil [/help/merge|merge] featureX</b><br>
<i># make sure the merge didn't break anything...</i><br>
<b>fossil [/help/commit|commit]
</blockquote>
The argument to the [/help/merge|merge] command can be any of the
version identifier forms that work for [/help/update|update].
([./checkin_names.wiki|more info].)
The merge command has options to cherry-pick individual
changes, or to back out individual changes, if you don't want to
do a full merge.
The merge command puts all changes in your working check-out.
No changes are made to the repository.
You must run [/help/commit|commit] separately
to add the merge changes into your repository to make them persistent
and so that your coworkers can see them.
But before you do that, you will normally want to run a few tests
to verify that the merge didn't cause logic breaks in your code.
The same branch can be merged multiple times without trouble. Fossil
automatically keeps up with things and avoids conflicts when doing
multiple merges. So even if you have merged the featureX branch
into trunk previously, you can do so again and Fossil will automatically
know to pull in only those changes that have occurred since the previous
merge.
If a merge or update doesn't work out (perhaps something breaks or
there are many merge conflicts) then you back up using:
<blockquote>
<b>[/help/undo | fossil undo]</b>
</blockquote>
This will back out the changes that the merge or update made to the
working checkout. There is also a [/help/redo|redo] command if you undo by
mistake. Undo and redo only work for changes that have
not yet been checked in using commit and there is only a single
level of undo/redo.
<h2 id="server">Setting Up A Server</h2>
Fossil can act as a stand-alone web server using one of these
commands:
<blockquote>
<b>[/help/server | fossil server]</b> <i>repository-filename</i><br>
<b>[/help/ui | fossil ui]</b> <i>repository-filename</i>
</blockquote>
The <i>repository-filename</i> can be omitted when these commands
are run from within an open check-out, which is a particularly useful
shortcut with the <b>fossil ui</b> command.
The <b>ui</b> command is intended for accessing the web user interface
from a local desktop. (We sometimes call this mode "Fossil UI.")
The <b>ui</b> command differs from the
<b>server</b> command by binding to the loopback IP
address only (thus making the web UI visible only on the
local machine) and by automatically starting your default web browser,
pointing it at the running UI
server. The localhost restriction exists because it also gives anyone
who can access the resulting web UI full control over the
repository. (This is the [./caps/admin-v-setup.md#apsu | all-powerful
Setup capabliity].)
For cross-machine collaboration, use the <b>server</b> command instead,
which binds on all IP addresses, does not try to start a web browser,
and enforces [./caps/ | Fossil's role-based access control system].
Servers are also easily configured as:
<ul>
<li>[./server/any/inetd.md|inetd]
<li>[./server/debian/service.md|systemd]
<li>[./server/any/cgi.md|CGI]
<li>[./server/any/scgi.md|SCGI]
</ul>
…along with [./server/#matrix | several other options].
The [./selfhost.wiki | self-hosting fossil repositories] use
CGI.
You might <i>need</i> to set up a server, whether you know it yet or
not. See the [./server/whyuseaserver.wiki | Benefits of a Fossil Server]
article for details.
<h2 id="proxy">HTTP Proxies</h2>
If you are behind a restrictive firewall that requires you to use
an HTTP proxy to reach the internet, then you can configure the proxy
in three different ways. You can tell fossil about your proxy using
a command-line option on commands that use the network,
<b>sync</b>, <b>clone</b>, <b>push</b>, and <b>pull</b>.
<blockquote>
<b>fossil clone </b><i>URL</i> <b>--proxy</b> <i>Proxy-URL</i>
</blockquote>
It is annoying to have to type in the proxy URL every time you
sync your project, though, so you can make the proxy configuration
persistent using the [/help/setting | setting] command:
<blockquote>
<b>fossil setting proxy </b><i>Proxy-URL</i>
</blockquote>
Or, you can set the "<b>http_proxy</b>" environment variable:
<blockquote>
<b>export http_proxy=</b><i>Proxy-URL</i>
</blockquote>
To stop using the proxy, do:
<blockquote>
<b>fossil setting proxy off</b>
</blockquote>
Or unset the environment variable. The fossil setting for the
HTTP proxy takes precedence over the environment variable and the
command-line option overrides both. If you have a persistent
proxy setting that you want to override for a one-time sync, that
is easily done on the command-line. For example, to sync with
a co-worker's repository on your LAN, you might type:
<blockquote>
<b>fossil sync http://192.168.1.36:8080/ --proxy off</b>
</blockquote>
<h2 id="links">Other Resources</h2>
|
| ︙ | ︙ |
Changes to www/quotes.wiki.
| ︙ | ︙ | |||
17 18 19 20 21 22 23 | <li><nowiki>It's simplest to think of the state of your [git] repository as a point in a high-dimensional "code-space", in which branches are represented as n-dimensional membranes, mapping the spatial loci of successive commits onto the projected manifold of each cloned repository.</nowiki> <blockquote> | | | | | 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | <li><nowiki>It's simplest to think of the state of your [git] repository as a point in a high-dimensional "code-space", in which branches are represented as n-dimensional membranes, mapping the spatial loci of successive commits onto the projected manifold of each cloned repository.</nowiki> <blockquote> <i>by Jonathan Hartley at [https://www.tartley.com/posts/a-guide-to-git-using-spatial-analogies]; <br>Quoted here: [https://lwn.net/Articles/420152/].</i> </blockquote> <li>Git is not a Prius. Git is a Model T. Its plumbing and wiring sticks out all over the place. You have to be a mechanic to operate it successfully or you'll be stuck on the side of the road when it breaks down. And it <b>will</b> break down. |
| ︙ | ︙ | |||
143 144 145 146 147 148 149 | <blockquote> <i>viablepanic at [https://www.reddit.com/r/programming/comments/bxcto/why_not_fossil_scm/c0p30b4?utm_source=share&utm_medium=web2x&context=3]</i> </blockquote> <li>In the fossil community - and hence in fossil itself - development history is pretty much sacrosanct. The very name "fossil" was to chosen to reflect the unchanging nature of things in that history. | | | | 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 | <blockquote> <i>viablepanic at [https://www.reddit.com/r/programming/comments/bxcto/why_not_fossil_scm/c0p30b4?utm_source=share&utm_medium=web2x&context=3]</i> </blockquote> <li>In the fossil community - and hence in fossil itself - development history is pretty much sacrosanct. The very name "fossil" was to chosen to reflect the unchanging nature of things in that history. <br><br> In git (or rather, the git community), the development history is part of the published aspect of the project, so it provides tools for rearranging that history so you can present what you "should" have done rather than what you actually did. <blockquote> <i>Mike Meyer on the Fossil mailing list, 2011-10-04</i> </blockquote> |
| ︙ | ︙ |
Changes to www/rebaseharm.md.
| ︙ | ︙ | |||
196 197 198 199 200 201 202 | branch and from the mainline, whereas in the rebase case diff(C6,C5\') shows only the feature branch changes. But that argument is comparing apples to oranges, since the two diffs do not have the same baseline. The correct way to see only the feature branch changes in the merge case is not diff(C2,C7) but rather diff(C6,C7). | | > | | 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 |
branch and from the mainline, whereas in the rebase case
diff(C6,C5\') shows only the feature branch changes.
But that argument is comparing apples to oranges, since the two diffs
do not have the same baseline. The correct way to see only the feature
branch changes in the merge case is not diff(C2,C7) but rather diff(C6,C7).
<table border="1" cellpadding="5" cellspacing="0"
style="margin-left:auto; margin-right:auto">
<tr><th>Rebase<th>Merge<th>What You See
<tr><td>diff(C2,C5\')<td>diff(C2,C7)<td>Commingled branch and mainline changes
<tr><td>diff(C6,C5\')<td>diff(C6,C7)<td>Branch changes only
</table>
Remember: C7 and C5\' are bit-for-bit identical, so the output of the
diff is not determined by whether you select C7 or C5\' as the target
of the diff, but rather by your choice of the diff source, C2 or C6.
So, to help with the problem of viewing changes associated with a feature
branch, perhaps what is needed is not rebase but rather better tools to
|
| ︙ | ︙ |
Changes to www/relatedwork.md.
1 2 3 4 | # Related Work ## Support Projects | | | | | | > | | > | > > > | > > > > | 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 | # Related Work ## Support Projects * [SQLite]: C-language library that implements a small, fast, self-contained, high-reliability, full-featured, SQL database engine * [pikchr]: PIC-like markup language for diagrams in technical documentation * [althttpd]: simple, secure, and low resource usage webserver that has run the https://sqlite.org/ website since 2004 * [Lemon Parser Generator][lemon]: re-entrant and thread-safe LALR(1) parser with a less error-prone grammar syntax than YACC or BISON * [Makeheaders]: automatically generate header files for C/C++ projects ## Fossil Inspired Projects * [libfossil]: 3rd party Fossil SCM Library API * [fnc]: interactive text-based user interface for Fossil * [ChiselApp]: Free Fossil SCM hosting! * [Inskinerator]: The Fossil Skin Generator * [Fuel]: cross-platform GUI front-end for the excellent Fossil SCM * [fsl]: Tcl/Expect wrapper script extending Fossil functionality ## Editor Plugins * [Emacs-Fossil][emacsfsl]: GNU Emacs VC backend for the Fossil version control system * [VS Code][vscode]: Integrated Fossil source control in Visual Studio Code * [Qt Creator Plugin][qtfsl]: Fossil SCM plugin for the Qt Creator IDE * [Jetbrains IDE Plugin][jetbrains]: Fossil SCM plugin for [CLion], [IntelliJ], [GoLand], and more * [NetBeans Plugin][netbeans]: NetBeans plugin module to use Fossil SCM ## Version Control/Software Configuration Management * [Git]: Free and open source distributed version control system * [Subversion]: Apache's open source version control system * [Mercurial]: free, distributed source control management tool * [Game of Trees][got]: version control which prioritizes ease of use and simplicity over flexibility * [Darcs]: free and open source, cross-platform version control system * [Pijul]: patch-based distributed version control system * [Sapling]: A Scalable, User-Friendly Source Control System ## Podcasts * [Corecursive #066][corec66]: The Untold Story of SQLite * [The Changelog #454][changelog454]: Richard Hipp returns * [The Changelog #201][changelog201]: Why SQLite succeeded as a database * [bsdtalk194][bsdtalk]: Interview with D. Richard Hipp * [Two Weeks of Databases][db2w]: Richard Hipp interviewed by Federico Razzoli * [Software Engineering Daily][swed]: SQLite with D. Richard Hipp * [Floss Weekly 26][floss26]: Interview with D. Richard Hipp, creator of SQLite ## Miscellany * [Tcl]: a simple-to-learn yet very powerful programming language [althttpd]: https://sqlite.org/althttpd/doc/trunk/althttpd.md [bsdtalk]: https://bsdtalk.blogspot.com/2010/07/bsdtalk194-fossil-scm-with-d-richard.html [changelog201]: https://changelog.com/podcast/201 [changelog454]: https://changelog.com/podcast/454 [ChiselApp]: https://chiselapp.com/ [CLion]: https://www.jetbrains.com/clion/ [corec66]: https://corecursive.com/066-sqlite-with-richard-hipp/ [Darcs]: http://darcs.net/ [db2w]: https://youtu.be/2eaQzahCeh4 [emacsfsl]: https://chiselapp.com/user/venks/repository/emacs-fossil/doc/tip/README.md [floss26]: https://twit.tv/shows/floss-weekly/episodes/26 [fnc]: https://fnc.bsdbox.org [fsl]: http://fossil.0branch.com/fsl [Fuel]: https://fuel-scm.org/fossil/index [Git]: https://git-scm.com [GoLand]: https://www.jetbrains.com/go/ [got]: https://gameoftrees.org [Inskinerator]: https://tangentsoft.com/inskinerator [IntelliJ]: https://www.jetbrains.com/idea/ [jetbrains]: https://plugins.jetbrains.com/plugin/7479-fossil-integration [lemon]: https://www.hwaci.com/sw/lemon/ [libfossil]: https://fossil.wanderinghorse.net/r/libfossil/wiki/home [Makeheaders]: https://fossil-scm.org/home/doc/trunk/tools/makeheaders.html [Mercurial]: https://www.mercurial-scm.org/ [netbeans]: https://chiselapp.com/user/backendzeit/repository/netbeans-fossil-plugin/index [Pijul]: https://pijul.org [pikchr]: https://pikchr.org [qtfsl]: https://code.qt.io/cgit/qt-creator/plugin-fossil-scm.git/ [Sapling]: https://sapling-scm.com [SQLite]: https://sqlite.org/index.html [Subversion]: https://subversion.apache.org/ [swed]: https://softwareengineeringdaily.com/2015/11/13/sqlite-with-d-richard-hipp/ [Tcl]: https://core.tcl-lang.org/tcl/wiki?name=Index [VSCode]: https://marketplace.visualstudio.com/items?itemName=koog1000.fossil |
Changes to www/reviews.wiki.
1 2 3 | <title>Reviews</title> <b>External links:</b> | | | 1 2 3 4 5 6 7 8 9 10 11 |
<title>Reviews</title>
<b>External links:</b>
* [https://www.nixtu.info/2010/03/fossil-dvcs-on-go-first-impressions.html |
Fossil DVCS on the Go - First Impressions]
<b>See Also:</b>
* [./quotes.wiki | Short Quotes on Fossil, Git, And DVCSes]
<b>Daniel writes on 2009-01-06:</b>
|
| ︙ | ︙ | |||
54 55 56 57 58 59 60 | run standalone servers or add Apache modules.) So I tried it out. The thing which bugged me most about it was having to type "commit" or "com" instead of "ci" for checking in (as is custom in all other systems I've used), despite the fact that fossil uses "ci" as a filter in things like the timeline view. Looking back now, I have used fossil for about about 95% of my work in the past | | | | 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | run standalone servers or add Apache modules.) So I tried it out. The thing which bugged me most about it was having to type "commit" or "com" instead of "ci" for checking in (as is custom in all other systems I've used), despite the fact that fossil uses "ci" as a filter in things like the timeline view. Looking back now, I have used fossil for about about 95% of my work in the past year (<a href="http://blog.s11n.net/?p=71"><i>dead link</i></a>), in over 15 source trees, and I now get tripped up when I have to use svn or cvs. So, having got over typing "fossil com -m ...", here's why I love it so much... Point #1: CGI Again, this sounds archaic, but fossil has allowed me to share source trees which I cannot justifiably host in other projects I work on |
| ︙ | ︙ |
Changes to www/server/any/althttpd.md.
1 2 3 4 5 6 7 8 9 10 | # Serving via althttpd [Althttpd][althttpd] is a light-weight web server that has been used to implement the SQLite and Fossil websites for well over a decade. Althttpd strives for simplicity, security, ease of configuration, and low resource usage. To set up a Fossil server as CGI on a host running the althttpd web server, follow these steps. <ol> | | | | | | 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 |
# Serving via althttpd
[Althttpd][althttpd]
is a light-weight web server that has been used to implement the SQLite and
Fossil websites for well over a decade. Althttpd strives for simplicity,
security, ease of configuration, and low resource usage.
To set up a Fossil server as CGI on a host running the althttpd web
server, follow these steps.
<ol>
<li>Get the althttpd webserver running on the host. This is easily
done by following the [althttpd documentation][althttpd].
<li>Create a CGI script for your Fossil repository. The script will
be typically be two lines of code that look something like this:
~~~
#!/usr/bin/fossil
repository: /home/yourlogin/fossils/project.fossil
~~~
Modify the filenames to conform to your system, of course. The
CGI script accepts [other options][cgi] besides the
repository:" line. You can add in other options as you desire,
but the single "repository:" line is normally all that is needed
to get started.
<li>Make the CGI script executable.
<li>Verify that the fossil repository file and the directory that contains
the repository are both writable by whatever user the web server is
running and.
</ol>
And you are done. Visit the URL that corresponds to the CGI script
you created to start using your Fossil server.
|
| ︙ | ︙ |
Changes to www/server/any/scgi.md.
| ︙ | ︙ | |||
57 58 59 60 61 62 63 | * [Linux (systemd)](../debian/service.md) * [Windows service](../windows/service.md) * [macOS (launchd)](../macos/service.md) * [xinetd](../any/xinetd.md) * [inetd](../any/inetd.md) We go into more detail on nginx service setup with Fossil in our | | | < | 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | * [Linux (systemd)](../debian/service.md) * [Windows service](../windows/service.md) * [macOS (launchd)](../macos/service.md) * [xinetd](../any/xinetd.md) * [inetd](../any/inetd.md) We go into more detail on nginx service setup with Fossil in our [Debian/Ubuntu specific guide](../debian/nginx.md), which also gets you TLS service. Similarly, our [OpenBSD specific guide](../openbsd/fastcgi.md) details how to setup a Fossil server using httpd and FastCGI on OpenBSD. *[Return to the top-level Fossil server article.](../)* [404]: https://en.wikipedia.org/wiki/HTTP_404 |
Changes to www/server/debian/nginx.md.
1 2 3 4 5 6 7 | # Serving via nginx on Debian and Ubuntu This document is an extension of [the platform-independent SCGI instructions][scgii], which may suffice for your purposes if your needs are simple. Here, we add more detailed information on nginx itself, plus details | | > | > | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | # Serving via nginx on Debian and Ubuntu This document is an extension of [the platform-independent SCGI instructions][scgii], which may suffice for your purposes if your needs are simple. Here, we add more detailed information on nginx itself, plus details about running it on Debian type OSes. This document was originally written for and tested on Debian 10 (Buster) and Ubuntu 20.04, which were common Tier 1 OS offerings for [virtual private servers][vps] at the time. The same configuration appears to run on Ubuntu 22.04 LTS without change. This material may not work for older OSes. It is known in particular to not work as given for Debian 9 and older! We also cover [adding TLS](#tls) to the basic configuration, because several details depend on the host OS and web stack details. Besides, TLS is widely considered part of the baseline configuration these days. [scgii]: ../any/scgi.md [vps]: https://en.wikipedia.org/wiki/Virtual_private_server |
| ︙ | ︙ | |||
107 108 109 110 111 112 113 | source to get a more up-to-date version than is shipped with the host OS. ## <a id="scgi"></a>Running Fossil in SCGI Mode For the following nginx configuration to work, it needs to contact a | | | > > | < | > > > > > | | | > | | | | | | | | | | | < | | > | | | | | | > > > > > > | > > > > > > | | > > > > > > > > > > > > > > > > > > | | | | 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 |
source to get a more up-to-date version than is shipped with the host
OS.
## <a id="scgi"></a>Running Fossil in SCGI Mode
For the following nginx configuration to work, it needs to contact a
background Fossil instance speaking the SCGI protocol. There are
[many ways](../) to set that up, such as [with `systemd`](./service.md)
on mainstream Linux distros. Another way is to [containerize][ctz] your
repository servers, then use the [`fslsrv` wrapper for Podman][fspm] to
generate `systemd` units for use by the front-end proxy.
However you do it, you need to match up the TCP port numbers between it
and those in the nginx configuration below.
[ctz]: ../../containers.md
[fspm]: https://tangentsoft.com/fossil/dir/bin
## <a id="config"></a>Configuration
On Debian and Ubuntu systems the primary user-level configuration file
for nginx is `/etc/nginx/sites-enabled/default`. I recommend that this
file contain only a list of include statements, one for each site that
server hosts:
include local/example.com
include local/foo.net
Those files then each define one domain’s configuration. Here,
`/etc/nginx/local/example.com` contains the configuration for
`*.example.com` and its alias `*.example.net`; and `local/foo.net`
contains the configuration for `*.foo.net`.
The configuration for our `example.com` web site, stored in
`/etc/nginx/sites-enabled/local/example.com` is:
----
server {
server_name .example.com .example.net "";
include local/generic;
include local/code;
access_log /var/log/nginx/example.com-https-access.log;
error_log /var/log/nginx/example.com-https-error.log;
# Bypass Fossil for the static documentation generated from
# our source code by Doxygen, so it merges into the embedded
# doc URL hierarchy at Fossil’s $ROOT/doc without requiring that
# these generated files actually be stored in the repo. This
# also lets us set aggressive caching on these docs, since
# they rarely change.
location /code/doc/html {
root /var/www/example.com/code/doc/html;
location ~* \.(html|ico|css|js|gif|jpg|png)$ {
add_header Vary Accept-Encoding;
access_log off;
expires 7d;
}
}
# Redirect everything under /code to the Fossil instance
location /code {
include local/code;
# Extended caching for URLs that include unique IDs
location ~ "/(artifact|doc|file|raw)/[0-9a-f]{40,64}" {
add_header Cache-Control "public, max-age=31536000, immutable";
include local/code;
access_log off;
}
# Lesser caching for URLs likely to be quasi-static
location ~* \.(css|gif|ico|js|jpg|png)$ {
add_header Vary Accept-Encoding;
include local/code;
access_log off;
expires 7d;
}
}
}
----
As you can see, this is a pure extension of [the basic nginx service
configuration for SCGI][scgii], showing off a few ideas you might want to
try on your own site, such as static asset proxying.
You also need a `local/code` file containing:
include scgi_params;
scgi_pass 127.0.0.1:12345;
scgi_param SCRIPT_NAME "/code";
We separate that out because nginx refuses to inherit certain settings
between nested location blocks, so rather than repeat them, we extract
them to this separate file and include it from both locations where it’s
needed. You see this above where we set far-future expiration dates on
files served by Fossil via URLs that contain hashes that change when the
content changes. It tells your browser that the content of these URLs
can never change without the URL itself changing, which makes your
Fossil-based site considerably faster.
Similarly, the `local/generic` file referenced above helps us reduce unnecessary
repetition among the multiple sites this configuration hosts:
root /var/www/$host;
listen 80;
listen [::]:80;
charset utf-8;
There are some configuration directives that nginx refuses to substitute
variables into, citing performance considerations, so there is a limit
to how much repetition you can squeeze out this way. One such example
are the `access_log` and `error_log` directives, which follow an obvious
pattern from one host to the next. Sadly, you must tolerate some
repetition across `server { }` blocks when setting up multiple domains
on a single server.
The configuration for `foo.net` is similar.
See [the nginx docs](https://nginx.org/en/docs/) for more ideas.
|
| ︙ | ︙ | |||
279 280 281 282 283 284 285 | [dof2b]: https://www.digitalocean.com/community/tutorials/how-to-protect-an-nginx-server-with-fail2ban-on-ubuntu-14-04 ## <a id="tls"></a> Adding TLS (HTTPS) Support | | | < < | < < < < | | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < | < < | < < | < | < | < < < < < | < < < < < < | < < < < < < < < < < < < < < < < < < < | < | < < | > > | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < | < < < < < < < < < < | < < < | < < < < < < < < < | | | | < < < < | < < < < < < | < < | < < < < < | < < | < < < < | < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < | < < < | | < < | < < | < < < < < | < < < < < < < < < < < < < < < < < | < < < | < < | < < < | < | < < < < < | | | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | < < | | | | | > > | 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 |
[dof2b]: https://www.digitalocean.com/community/tutorials/how-to-protect-an-nginx-server-with-fail2ban-on-ubuntu-14-04
## <a id="tls"></a> Adding TLS (HTTPS) Support
One of the [many ways](../../ssl.wiki) to provide TLS-encrypted HTTP
access (a.k.a. HTTPS) to Fossil is to run it behind a web proxy that
supports TLS. Because one such option is nginx, it’s best to delegate
TLS to it if you were already using nginx for some other reason, such as
static content serving, with only part of the site being served by
Fossil.
The simplest way by far to do this is to use [Let’s Encrypt][LE]’s
[Certbot][CB], which can configure nginx for you and keep its
certificates up to date. You need but follow their [nginx on Ubuntu 20
guide][CBU]. We had trouble with this in the past, but either Certbot
has gotten smarter or our nginx configurations have gotten simpler, so
we have removed the manual instructions we used to have here.
You may wish to include something like this from each `server { }`
block in your configuration to enable TLS in a common, secure way:
```
# Tell nginx to accept TLS-encrypted HTTPS on the standard TCP port.
listen 443 ssl;
listen [::]:443 ssl;
# Reference the TLS cert files produced by Certbot.
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# Load the Let's Encrypt Diffie-Hellman parameters generated for
# this server. Without this, the server is vulnerable to Logjam.
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
# Tighten things down further, per Qualys’ and Certbot’s advice.
ssl_session_cache shared:le_nginx_SSL:1m;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_session_timeout 1440m;
# Offer OCSP certificate stapling.
ssl_stapling on;
ssl_stapling_verify on;
# Enable HSTS.
include local/enable-hsts;
```
The [HSTS] step is optional and should be applied only after due
consideration, since it has the potential to lock users out of your
site if you later change your mind on the TLS configuration.
The `local/enable-hsts` file it references is simply:
```
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
```
It’s a separate file because nginx requires that headers like this be
applied separately for each `location { }` block. We’ve therefore
factored this out so you can `include` it everywhere you need it.
The [OCSP] step is optional, but recommended.
You may find [Qualys’ SSL Server Test][QSLT] helpful in verifying that
you have set all this up correctly, and that the configuration is
strong. We’ve found their [best practices doc][QSLC] to be helpful. As
of this writing, the above configuration yields an A+ rating when run on
Ubuntu 22.04.01 LTS.
[CB]: https://certbot.eff.org/
[CBU]: https://certbot.eff.org/instructions?ws=nginx&os=ubuntufocal
[LE]: https://letsencrypt.org/
[HSTS]: https://www.nginx.com/blog/http-strict-transport-security-hsts-and-nginx/
[OCSP]: https://en.wikipedia.org/wiki/OCSP_stapling
[QSLC]: https://github.com/ssllabs/research/wiki/SSL-and-TLS-Deployment-Best-Practices
[QSLT]: https://www.ssllabs.com/ssltest/
<div style="height:50em" id="this-space-intentionally-left-blank"></div>
*[Return to the top-level Fossil server article.](../)*
|
Changes to www/server/debian/service.md.
1 2 | # Serving via systemd on Debian and Ubuntu | | > > | > > | > | > > | > > > | > | > > > > > > | | > > > > > > > > > | 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 |
# Serving via systemd on Debian and Ubuntu
[`systemd`][sdhome] is the service management framework in all major
in-support versions of Linux. There are multiple ways to run Fossil
under `systemd`.
[sdhome]: https://www.freedesktop.org/wiki/Software/systemd/
[wpa]: https://en.wikipedia.org/wiki/Systemd#Adoption
## Containerized Service
Two of the methods for running [containerized Fossil][cntdoc] integrate
with `systemd`, potentially obviating the more direct methods below:
* If you take [the Podman method][podman] of running containerized
Fossil, it opens the `podman generate systemd` option for you, as
exemplified in [the `fslsrv` script][fslsrv] used on this author’s
public Fossil-based web site. That script pulls its container images
from [my Docker Hub repo][dhrepo] to avoid the need for my public
Fossil server to have build tools and a copy of the Fossil source
tree. You’re welcome to use my images as-is, or you may use these
tools to bounce custom builds up through a separate container image
repo you manage.
* If you’re willing to give up [a lot of features][nsweak] relative to
Podman, and you’re willing to tolerate a lot more manual
administrivia, [the nspawn method][nspawn] has a lot less overhead,
being a direct feature of `systemd` itself.
Both of these options provide [better security][cntsec] than running
Fossil directly under `systemd`, among [other benefits][cntdoc].
[cntdoc]: ../../containers.md
[cntsec]: ../../containers.md#security
[dhrepo]: https://hub.docker.com/r/tangentsoft/fossil
[fslsrv]: https://tangentsoft.com/fossil/dir?name=bin
[nspawn]: ../../containers.md#nspawn
[nsweak]: ../../containers.md#nspawn-weaknesses
[podman]: ../../containers.md#podman
## User Service
A fun thing you can easily do with `systemd` that you can’t directly do
with older technologies like `inetd` and `xinetd` is to set a server up
as a “user” service.
|
| ︙ | ︙ | |||
44 45 46 47 48 49 50 | ``` Unlike with `inetd` and `xinetd`, we don’t need to tell `systemd` which user and group to run this service as, because we’ve installed it under the account we’re logged into, which `systemd` will use as the service’s owner. | > > > | | | | < < | < > > > > | 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 |
```
Unlike with `inetd` and `xinetd`, we don’t need to tell `systemd` which
user and group to run this service as, because we’ve installed it
under the account we’re logged into, which `systemd` will use as the
service’s owner.
The result is essentially [the standalone server method](../any/none.md)
coupled with an intelligent service manager that will start it
automatically in the background on system boot, perform automatic
service restarts with back-off logic, and more, making this much more
robust than the by-hand launches of `fossil` in the platform-independent
Fossil server instructions. The service will stay up until we
explicitly tell it to shut down.
This scheme couples well with [the generic SCGI instructions][scgi] as
it requires a way to run the underlying repository server in the
background. Given that its service port is then proxied by SCGI, it
follows that it doesn’t need to run as a system service. A user service
works perfectly well for this.
Because we’ve set this up as a user service, the commands you give to
manipulate the service vary somewhat from the sort you’re more likely to
find online:
$ systemctl --user daemon-reload
$ systemctl --user enable fossil
|
| ︙ | ︙ | |||
82 83 84 85 86 87 88 89 90 91 92 |
allow background services to continue to run after logout, say:
$ sudo loginctl enable-linger $USER
You can paste the command just like that into your terminal, since
`$USER` will expand to your login name.
### System Service Alternative
| > > | > | > | | | > | | > | > > > > > | > | < < | 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 |
allow background services to continue to run after logout, say:
$ sudo loginctl enable-linger $USER
You can paste the command just like that into your terminal, since
`$USER` will expand to your login name.
[scgi]: ../any/scgi.md
### System Service Alternative
There are some common reasons that you’d have good cause to install
Fossil as a system-level service rather than the prior user-level one:
* You’re using [the new `fossil server --cert` feature][sslsrv] to get
TLS service and want it to listen directly on port 443, rather than be
proxied, as one had to do before Fossil got the ability to act as a
TLS server itself. That requires root privileges, so you can’t run
it as a user-level service.
* You’re proxying Fossil with [nginx](./nginx.md) or similar, allowing
it to bind to high-numbered ports, but because it starts as a system
service, you can’t get Fossil into the same dependency chain to
ensure things start up and shut down in the proper order unless it
*also* runs as a system service.
* You want to make use of Fossil’s [chroot jail feature][cjail], which
requires the server to start as root.
There are just a small set of changes required:
1. Install the unit file to one of the persistent system-level unit
file directories. Typically, these are:
/etc/systemd/system
/lib/systemd/system
2. Add `User` and `Group` directives to the `[Service]` section so
Fossil runs as a normal user, preferably one with access only to
the Fossil repo files, rather than running as `root`.
[sslsrv]: ../../ssl-server.md
[cjail]: ../../chroot.md
## Socket Activation
Another useful method to serve a Fossil repo via `systemd` is via a
socket listener, which `systemd` calls “[socket activation][sa],”
roughly equivalent to [the ancient `inetd` method](../any/inetd.md).
It’s more complicated, but it has some nice properties.
We first need to define the privileged socket listener by writing
`/etc/systemd/system/fossil.socket`:
```dosini
[Unit]
Description=Fossil socket
|
| ︙ | ︙ | |||
161 162 163 164 165 166 167 |
ExecStart=/home/fossil/bin/fossil http repo.fossil
StandardInput=socket
[Install]
WantedBy=multi-user.target
```
| < < | | 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 |
ExecStart=/home/fossil/bin/fossil http repo.fossil
StandardInput=socket
[Install]
WantedBy=multi-user.target
```
Notice that we haven’t told `systemd` which user and group to run Fossil
under. Since this is a system-level service definition, that means it
will run as root, which then causes Fossil to [automatically drop into a
`chroot(2)` jail](../../chroot.md) rooted at the `WorkingDirectory`
we’ve configured above, shortly after each `fossil http` call starts.
The `Restart*` directives we had in the user service configuration above
are unnecessary for this method, since Fossil isn’t supposed to remain
running under it. Each HTTP hit starts one Fossil instance, which
handles that single client’s request and then immediately shuts down.
Next, you need to tell `systemd` to reload its system-level
|
| ︙ | ︙ |
Changes to www/server/index.html.
| ︙ | ︙ | |||
115 116 117 118 119 120 121 | <li><a href="#slist">Socket listener</a> <li><a href="any/none.md">Stand-alone HTTP server</a> <li><a href="any/scgi.md">SCGI</a> <li><a href="#ssh">SSH</a> </ol> <p>All of these methods can serve either a single repository or a | | | 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 | <li><a href="#slist">Socket listener</a> <li><a href="any/none.md">Stand-alone HTTP server</a> <li><a href="any/scgi.md">SCGI</a> <li><a href="#ssh">SSH</a> </ol> <p>All of these methods can serve either a single repository or a directory hierarchy containing multiple repositories.</p> <p>You are not restricted to a single server setup. The same Fossil repository can be served using two or more of the above techniques at the same time. These methods use clean, well-defined, standard interfaces (CGI, SCGI, and HTTP) which allow you to easily migrate from one method to another in response to changes in hosting providers or administrator preferences.</p> |
| ︙ | ︙ | |||
169 170 171 172 173 174 175 | <a href="$ROOT/help?cmd=server"><tt>fossil server</tt></a> command to run a process that listens for incoming HTTP requests on a socket and then dispatches a copy of itself to deal with each incoming request. You can expose Fossil directly to the clients in this way or you can interpose a <a href="https://en.wikipedia.org/wiki/Reverse_proxy">reverse proxy</a> layer between the clients and Fossil.</p> | | | 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 | <a href="$ROOT/help?cmd=server"><tt>fossil server</tt></a> command to run a process that listens for incoming HTTP requests on a socket and then dispatches a copy of itself to deal with each incoming request. You can expose Fossil directly to the clients in this way or you can interpose a <a href="https://en.wikipedia.org/wiki/Reverse_proxy">reverse proxy</a> layer between the clients and Fossil.</p> <h3 id="scgi">SCGI</h3> <p>The Fossil standalone server can also handle <a href="any/scgi.md">SCGI</a>. When the <a href="$ROOT/help?cmd=server"><tt>fossil server</tt></a> command is run with the extra <tt>--scgi</tt> option, it listens for incoming SCGI requests rather than HTTP requests. This allows Fossil to respond to requests from web servers <a href="debian/nginx.md">such as nginx</a> that don't support CGI. SCGI is a simpler protocol to proxy |
| ︙ | ︙ |
Changes to www/server/openbsd/service.wiki.
| ︙ | ︙ | |||
10 11 12 13 14 15 16 17 18 19 20 21 22 23 | #!/bin/ksh daemon="/usr/local/bin/fossil" # fossil executable daemon_user="_fossil" # user to run fossil as daemon_flags="server /home/_fossil/example --repolist --port 8888" # fossil command . /etc/rc.d/rc.subr # pexp="$daemon server .*" # See below. rc_bg=YES # Run in the background, since fossil serve does not daemonize itself rc_cmd $1 </pre></blockquote> <h3>pexp</h3> You may need to uncomment the "pexp=". rc.subr typically finds the daemon process based by matching the process name and argument list. | > | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | #!/bin/ksh daemon="/usr/local/bin/fossil" # fossil executable daemon_user="_fossil" # user to run fossil as daemon_flags="server /home/_fossil/example --repolist --port 8888" # fossil command . /etc/rc.d/rc.subr # pexp="$daemon server .*" # See below. rc_reload=NO # Unsupported by Fossil; 'rcctl reload fossil' kills the process. rc_bg=YES # Run in the background, since fossil serve does not daemonize itself rc_cmd $1 </pre></blockquote> <h3>pexp</h3> You may need to uncomment the "pexp=". rc.subr typically finds the daemon process based by matching the process name and argument list. |
| ︙ | ︙ |
Changes to www/server/whyuseaserver.wiki.
| ︙ | ︙ | |||
10 11 12 13 14 15 16 | to ensure that (in the limit) all participating peers see the same content. <h2>But, a Server Can Be Useful</h2> Fossil does not require a server, but a server can be very useful. Here are a few reasons to set up a Fossil server for your project: | | > | > | > | > | > | > | > | > | > | | | > | 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 |
to ensure that (in the limit) all participating peers see the same content.
<h2>But, a Server Can Be Useful</h2>
Fossil does not require a server, but a server can be very useful.
Here are a few reasons to set up a Fossil server for your project:
1. <b>A server works as a complete project website.</b>
Fossil does more than just version control. It also supports
[../tickets.wiki|trouble-tickets],
[../wikitheory.wiki|wiki],
a [../chat.md|developer chat room], and a [../forum.wiki|forum].
The [../embeddeddoc.wiki|embedded documentation]
feature provides a great mechanism for providing project documentation.
The [../unvers.wiki|unversioned files] feature is a convenient way
to host builds and downloads on the project website.
2. <b>A server gives developers a common point of rendezvous for
syncing their work.</b>
It is possible for developers to synchronize peer-to-peer but
that requires the developers coordinate the sync, which in turn
requires that the developers both want to sync at the same moment.
A server alleviates this time dependency by allowing each developer
to sync whenever it is convenient. For example, a developer may
choose to automatically sync
after each commit and before each update. Developers all stay
in sync with each other without having to interrupt each other
constantly to set up a peer-to-peer sync.
3. <b>A server provides project leaders with up-to-date status.</b>
Project coordinators and BDFLs can click on a link or two at the
central Fossil server for a project and quickly tell what is
going on. They can do this from anywhere — even from their phones
— without needing to actually sync to the device they are using.
4. <b>A server provides automatic off-site backups.</b>
A Fossil server is an automatic remote backup for all the work
going into a project. ([../backup.md | Within limits].)
You can even set up multiple servers at
multiple sites with automatic synchronization between them for
added redundancy. Such a setup means that no work is lost due
to a single machine failure.
5. <b>A server consolidates [https://www.sqlite.org/howtocorrupt.html
| SQLite corruption risk mitigation] to a single point.</b>
The concerns in section 1 of that document assume you have direct
access to the central DB files, which isn't the case when the
server is remote and secure against tampering.
Section 2 is about file locking, which concerns disappear when Fossil's
on the other side of an HTTP boundary and your server is set up
properly.
Sections 3.1, 4 thru 6, and 8 apply to all Fossil configurations,
but setting up a server lets you address the risks
in a single place. Once a given commit is
sync'd to the server, you can be reasonably sure any client-side
corruption can be fixed with a fresh clone. Ultimately, this
is an argument for off-machine backups, which returns us to reason
#4 above.
Sections 3.2 and the entirety of section 7 are no concern with
Fossil at all, since it's primarily written by the creator and
primary maintainer of SQLite, so you can be certain Fossil doesn't
actively pursue coding strategies known to risk database corruption.
For another take on this topic, see the article
"[https://sqlite.org/useovernet.html | SQLite Over a Network,
Caveats and Considerations]". Fossil runs in rollback mode by
default per recommendation #3 at the end of that article, and a
Fossil server operates as a network proxy for the underlying
SQLite repository DB per recommendation #2. This <i>may</i> permit
you to safely switch it into WAL mode (<b>fossil rebuild --wal</b>)
depending on the underlying storage used by the server itself.
6. <b>A server allows [../caps/ | Fossil's RBAC system] to work.</b>
The role-based access control (RBAC) system in Fossil only works
when the remote system is on the other side of an HTTP barrier.
([../caps/#webonly | Details].) If you want its benefits, you need
a Fossil server setup of some kind.
|
Changes to www/server/windows/service.md.
| ︙ | ︙ | |||
44 45 46 47 48 49 50 51 52 53 54 55 56 57 | If you wish to server a directory of repositories, the `fossil winsrv` command requires a slightly different set of options vs. `fossil server`: ``` fossil winsrv create --repository D:/Path/to/Repos --repolist ``` ### <a id='PowerShell'></a>Advanced service installation using PowerShell As great as `fossil winsrv` is, it does not have one to one reflection of all of the `fossil server` [options](/help?cmd=server). When you need to use some of the more advanced options, such as `--https`, `--skin`, or `--extroot`, you will need to use PowerShell to configure and install the Windows service. | > > > > > > > > > > > > | 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 | If you wish to server a directory of repositories, the `fossil winsrv` command requires a slightly different set of options vs. `fossil server`: ``` fossil winsrv create --repository D:/Path/to/Repos --repolist ``` ### Choice of Directory Considerations When the Fossil server will be used at times that files may be locked during virus scanning, it is prudent to arrange that its directory used for temporary files is exempted from such scanning. Ordinarily, this will be a subdirectory named "fossil" in the temporary directory given by the Windows GetTempPath(...) API, [namely](https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-gettemppathw#remarks) the value of the first existing environment variable from `%TMP%`, `%TEMP%`, `%USERPROFILE%`, and `%SystemRoot%`; you can look for their actual values in your system by accessing the `/test_env` webpage. Excluding this subdirectory will avoid certain rare failures where the fossil.exe process is unable to use the directory normally during a scan. ### <a id='PowerShell'></a>Advanced service installation using PowerShell As great as `fossil winsrv` is, it does not have one to one reflection of all of the `fossil server` [options](/help?cmd=server). When you need to use some of the more advanced options, such as `--https`, `--skin`, or `--extroot`, you will need to use PowerShell to configure and install the Windows service. |
| ︙ | ︙ |
Changes to www/settings.wiki.
1 2 3 4 5 6 7 8 9 10 11 12 | <title>Fossil Settings</title> <h2>Using Fossil Settings</h2> 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. | | | | | | | | 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 | <title>Fossil Settings</title> <h2>Using Fossil Settings</h2> 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. <h3 id="repo">Repository settings</h3> 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. <h3 id="versionable">"Versionable" settings</h3> 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 versioned files. These are <tt>clean-glob</tt>, <tt>binary-glob</tt>, <tt>crlf-glob</tt> (and its alias <tt>crnl-glob</tt>), <tt>empty-dirs</tt>, <tt>encoding-glob</tt>, <tt>ignore-glob</tt>, <tt>keep-glob</tt>, <tt>manifest</tt>, and <tt>mimetypes</tt>. The most important is <tt>ignore-glob</tt> which specifies which files should be ignored when looking for unmanaged files with the <tt>extras</tt> command. Because these options can change over time, and the inconvenience of replicating changes, these settings are "versionable". As well as being able to be set using the <tt>settings</tt> command or the web interface, you can create versioned files in the <tt>.fossil-settings</tt> |
| ︙ | ︙ |
Changes to www/shunning.wiki.
| ︙ | ︙ | |||
35 36 37 38 39 40 41 | foil spammers up front], legally problematic check-ins should range from rare to nonexistent, and you have to go way out of your way to force Fossil to insert bad control artifacts. Therefore, before we get to methods of permanently deleting content from a Fossil repos, let's give some alternatives that usually suffice, which don't damage the project's fossil record: | < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > | | | | | | < | 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 |
foil spammers up front], legally problematic check-ins should range from
rare to nonexistent, and you have to go way out of your way to force
Fossil to insert bad control artifacts. Therefore, before we get to
methods of permanently deleting content from a Fossil repos, let's give
some alternatives that usually suffice, which don't damage the project's
fossil record:
* When a forum post or wiki article is "deleted," what actually
happens is that a new empty version is added to the Fossil repository.
The web interface interprets this
as "deleted," but the prior version remains available if you go
digging for it.
* When you close a ticket, it's marked in a way that causes it
to not show up in the normal ticket reports. You usually want to
give it a Resolution such as "Rejected" when this happens, plus
possibly a comment explaining why you're closing it. This is all new
information added to the ticket, not deletion.
* When you <tt>fossil rm</tt> a file, a new manifest is
checked into the repository with the same file list as for the prior
version minus the "removed" file. The file is still present in the
repository; it just isn't part of that version forward on that
branch.
* If you make a bad check-in, you can shunt it off to the side
by amending it to put it on a different branch, then continuing
development on the prior branch:
<br><br>
<code>$ fossil amend abcd1234 --branch BOGUS --hide<br>
$ fossil up trunk</code>
<br><br>
The first command moves check-in ID <tt>abcd1234</tt> (and any
subsequent check-ins on that branch!) to a branch called
<tt>BOGUS</tt>, then hides it so it doesn't show up on the
timeline. You can call this branch anything you like, and you can
re-use the same name as many times as you like. No content is
actually deleted: it's just shunted off to the side and hidden away.
You might find it easier to do this from the Fossil web UI in
the "edit" function for a check-in.
<br><br>
The second command returns to the last good check-in on that branch
so you can continue work from that point.
* When the check-in you want to remove is followed by good
check-ins on the same branch, you can't use the previous method,
because it will move the good check-ins, too. The solution is:
<br><br>
<tt>$ fossil merge --backout abcd1234</tt>
<br><br>
That creates a diff in the check-out directory that backs out the
bad check-in <tt>abcd1234</tt>. You then fix up any merge conflicts,
build, test, etc., then check the reverting change into the
repository. Again, nothing is actually deleted; you're just adding
more information to the repository which corrects a prior
check-in.
<h2>Exception: Non-versioned Content</h2>
It is normal and expected to delete data which is not versioned, such as
usernames and passwords in the user table. The [/help/scrub|fossil scrub]
command will remove all sensitive non-versioned data from a repository.
|
| ︙ | ︙ |
Changes to www/ssl.wiki.
| ︙ | ︙ | |||
15 16 17 18 19 20 21 | identify spoofing, and more. There are two major aspects to this, both of which have to be addressed in different ways. Those are the subjects of the next two major sections. | | < | | | | 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 |
identify spoofing, and more.
There are two major aspects to this, both of which have to be addressed
in different ways. Those are the subjects of the next two major
sections.
<h2 id="client">Client-Side Configuration</h2>
You can build Fossil against [https://www.openssl.org/ |
OpenSSL] to allow it to clone and sync with a remote
Fossil repository via <tt>https</tt> URIs.
<h3 id="openssl-bin">Building Against OpenSSL Automatically</h3>
The <tt>configure</tt> script will attempt to find OpenSSL on your
system automatically. It first tries asking the <tt>pkg-config</tt>
system where the OpenSSL development files are, and if that fails, it
falls back to looking through a list of likely directories.
If it can't find the files it needs, the most common solution is to
install the OpenSSL development package on your system via your OS's
package manager. Examples:
* <b>RHEL & Fedora</b>: <tt>sudo dnf install openssl-devel</tt>
* <b>Debian & Ubuntu</b>: <tt>sudo apt install libssl-dev</tt>
* <b>FreeBSD</b>: <tt>su -c 'pkg install openssl'</tt>
* <b>macOS</b>: <tt>sudo brew install openssl</tt>
* <b>Cygwin</b>: Install <tt>openssl-devel</tt> via Cygwin's
<tt>setup-*.exe</tt> program
The macOS case requires explanation. Apple last shipped OpenSSL
|
| ︙ | ︙ | |||
139 140 141 142 143 144 145 |
<pre>
SSL verification failed: unable to get local issuer certificate
</pre>
Fossil relies on the OpenSSL library to have some way to check a trusted
list of CA signing keys. There are two common ways this fails:
| | | > | | | 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 |
<pre>
SSL verification failed: unable to get local issuer certificate
</pre>
Fossil relies on the OpenSSL library to have some way to check a trusted
list of CA signing keys. There are two common ways this fails:
# The OpenSSL library Fossil is linked to doesn't have a CA
signing key set at all, so that it initially trusts no certificates
at all.
# The OpenSSL library does have a CA cert set, but your Fossil server's
TLS certificate was signed by a CA that isn't in that set.
A common reason to fall into the second trap is that you're using
certificates signed by a local private CA, as often happens in large
enterprises. You can solve this sort of problem by getting your local
CA's signing certificate in PEM format and pointing OpenSSL at it:
<pre>
|
| ︙ | ︙ | |||
222 223 224 225 226 227 228 | password. If you attempt to connect to a server which requests a client certificate, but don't provide one, fossil will show an error message which explains what to do to authenticate with the server. | | | | | | > | | < | 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 | password. If you attempt to connect to a server which requests a client certificate, but don't provide one, fossil will show an error message which explains what to do to authenticate with the server. <h2 id="server">Server-Side Configuration</h2> Fossil's built-in HTTP server got [./ssl-server.md | TLS support] in December 2021, released as version 2.18 in early 2022. Prior to that, system administrators that wanted to add TLS support to a Fossil server had to put it behind a reverse proxy that would do the translation. Since advantages remain for delegating TLS to another layer in the stack, instructions for doing so continue to be included in our documentation, such as: * <a id="stunnel" href="./server/any/stunnel.md">Serving via stunnel</a> * <a id="althttpd" href="./server/any/althttpd.md">Serving via stunnel + althttpd</a> * <a id="nginx" href="./server/debian/nginx.md#tls">Serving via SCGI with nginx on Debian</a> <h2 id="enforcing">Enforcing TLS Access</h2> |
| ︙ | ︙ | |||
271 272 273 274 275 276 277 | "<tt>http</tt>" URIs to Fossil, so Fossil issues a redirect, so the browser fetches the page again, causing Fossil to see an "<tt>http</tt>" URI again, so it issues a redirect...'round and 'round it goes until the web browser detects it's in a redirect loop and gives up. This problem prevents you from getting back into the Admin UI to fix it, but there are several ways to fix it: | | | > | | > | | | | | | 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 |
"<tt>http</tt>" URIs to Fossil, so Fossil issues a redirect, so the browser
fetches the page again, causing Fossil to see an "<tt>http</tt>" URI again, so
it issues a redirect...'round and 'round it goes until the web browser
detects it's in a redirect loop and gives up. This problem prevents you
from getting back into the Admin UI to fix it, but there are several
ways to fix it:
# <b>Reset via CLI.</b> You can turn the setting back off from the
CLI with the command "<tt>fossil -R /path/to/repo.fossil set
redirect-to-https 0</tt>". (Currently doesn't work.)
# <b>Backup first.</b> This setting is stored in the Fossil
repository, so if you make a backup first <i>on the server</i>, you
can restore the repo file if enabling this feature creates a
redirect loop.
# <b>Download, fix, and restore.</b> You can copy the remote
repository file down to a local machine, use <tt>fossil ui</tt> to
fix the setting, and then upload it to the repository server
again.
It's best to enforce TLS-only access at the front-end proxy level
anyway. It not only avoids the problem entirely, it can be significantly
more secure. The [./server/debian/nginx.md#tls | nginx-on-Debian proxy guide] shows one way
to achieve this.
<h2>Terminology Note</h2>
This document is called <tt>ssl.wiki</tt> for historical reasons. The
TLS protocol was originally called SSL, and it went through several
revisions before being replaced by TLS. Years before this writing, SSL
finally became entirely obsolete due to weaknesses in the protocol fixed
in the later TLS series of protocols.
Some people still use the term "SSL" when they actually mean "TLS," but
in the Fossil project, we always use "TLS" except when we must preserve
some sort of historical compatibility, as with this document's name in
order to avoid broken external URLs. The Fossil TLS-related settings
also often use "<tt>ssl</tt>" in their names for the same reason.
This series of protocols is also called "HTTPS" after the URI scheme
used to specify "HTTP over TLS."
|
Changes to www/sync.wiki.
1 2 | <title>The Fossil Sync Protocol</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 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 |
<title>The Fossil Sync Protocol</title>
This document describes the wire protocol used to synchronize
content between two Fossil repositories.
<h2>1.0 Overview</h2>
The global state of a fossil repository consists of an unordered
[./fileformat.wiki|collection of artifacts]. Each artifact is
identified by a cryptographic
hash of its content, expressed as a lower-case hexadecimal string.
Synchronization is the process of sharing artifacts between
repositories so that all repositories have copies of all artifacts. Because
artifacts are unordered, the order in which artifacts are received
is unimportant. It is assumed that the hash names
of artifacts are unique - that every artifact has a different hash.
To a first approximation, synchronization proceeds by sharing lists
of hashes for available artifacts, then sharing the content of artifacts
whose names are missing from one side or the other of the connection.
In practice, a repository might contain millions of artifacts. The list of
hash names for this many artifacts can be large. So optimizations are
employed that usually reduce the number of hashes that need to be
shared to a few dozen.
Each repository also has local state. The local state determines
the web-page formatting preferences, authorized users, ticket formats,
and similar information that varies from one repository to another.
The local state is not usually transferred during a sync. Except,
some local state is transferred during a [/help?cmd=clone|clone]
in order to initialize the local state of the new repository. Also,
an administrator can sync local state using
the [/help?cmd=configuration|config push] and
[/help?cmd=configuration|config pull]
commands.
<h3 id="crdt">1.1 Conflict-Free Replicated Datatypes</h3>
The "bag of artifacts" data model used by Fossil is apparently an
implementation of a particular
[https://en.wikipedia.org/wiki/Conflict-free_replicated_data_type|Conflict-Free
Replicated Datatype (CRDT)] called a "G-Set" or "Grow-only Set". The
academic literature on CRDTs only began to appear in about 2011, and
Fossil predates that research by at least 4 years. But it is nice to
know that theorists have now proven that the underlying data model of
Fossil can provide strongly-consistent replicas using only
peer-to-peer communication and without any kind of central
authority.
If you are already familiar with CRDTs and were wondering if Fossil
used them, the answer is "yes". We just don't call them by that name.
<h2>2.0 Transport</h2>
All communication between client and server is via HTTP requests.
The server is listening for incoming HTTP requests. The client
issues one or more HTTP requests and receives replies for each
request.
The server might be running as an independent server
using the [/help?cmd=server|"fossil server" command], or it
might be launched from inetd or xinetd using the
["fossil http" command|/help?cmd=http]. Or the server might
be [./server/any/cgi.md|launched from CGI] or from
[./server/any/scgi.md|SCGI].
(See "[./server/|How To Configure A Fossil Server]" for details.)
The specifics of how the server listens
for incoming HTTP requests is immaterial to this protocol.
The important point is that the server is listening for requests and
the client is the issuer of the requests.
A single [/help?cmd=push|push],
[/help?cmd=pull|pull], or [/help?cmd=sync|sync]
might involve multiple HTTP requests.
The client maintains state between all requests. But on the server
side, each request is independent. The server does not preserve
any information about the client from one request to the next.
Note: Throughout this article, we use the terms "server" and "client"
to represent the listener and initiator of the interaction, respectively.
Nothing in this protocol requires that the server actually be a back-room
processor housed in a datacenter, nor does the client need to be a desktop
or handheld device. For the purposes of this article "client" simply means
the repository that initiates the conversation and "server" is the repository
that responds. Nothing more.
<h4>2.0.1 HTTPS Transport</h4>
HTTPS differs from HTTP only in that the HTTPS protocol is
encrypted as it travels over the wire. The underlying protocol
is the same. This document describes only the underlying, unencrypted
messages that go client to server and back to client.
Whether or not those messages are encrypted does not come into play
in this document.
Fossil includes built-in
[./ssl-server.md|support for HTTPS encryption] in both client and server.
<h4>2.0.2 SSH Transport</h4>
When doing a sync using an "ssh:..." URL, the same HTTP transport protocol
is used. Fossil simply uses [https://en.wikipedia.org/wiki/Secure_Shell|ssh]
to start an instance of the [/help?cmd=test-http|fossil test-http] command
running on the remote machine. It then sends HTTP requests and gets back HTTP
replies over the SSH connection, rather than sending and receiving over an
internet socket. To see the specific "ssh" command that the Fossil client
runs in order to set up a connection, add either of the the "--httptrace" or
"--sshtrace" options to the "fossil sync" command line.
<h4>2.0.3 FILE Transport</h4>
When doing a sync using a "file:..." URL, the same HTTP protocol is
still used. But instead of sending each HTTP request over a socket or
via SSH, the HTTP request is written into a temporary file. The client
then invokes the [/help?cmd=http|fossil http] command in a subprocess
to process the request and and generate a reply. The client then reads
the HTTP reply out of a temporary file on disk, and deletes the two
temporary files. To see the specific "fossil http" command that is run
in order to implement the "file:" transport, add the "--httptrace"
option to the "fossil sync" command.
<h3>2.1 Server Identification</h3>
The server is identified by a URL argument that accompanies the
push, pull, or sync command on the client. (As a convenience to
users, the URL can be omitted on the client command and the same URL
from the most recent push, pull, or sync will be reused. This saves
typing in the common case where the client does multiple syncs to
the same server.)
The client modifies the URL by appending the method name "<b>/xfer</b>"
to the end. For example, if the URL specified on the client command
line is
<blockquote>
https://fossil-scm.org/fossil
</blockquote>
Then the URL that is really used to do the synchronization will
be:
<blockquote>
https://fossil-scm.org/fossil/xfer
</blockquote>
<h3>2.2 HTTP Request Format</h3>
The client always sends a POST request to the server. The
general format of the POST request is as follows:
<blockquote><pre>
POST /fossil/xfer HTTP/1.0
Host: fossil-scm.hwaci.com:80
Content-Type: application/x-fossil
Content-Length: 4216
<i>content...</i>
</pre></blockquote>
In the example above, the pathname given after the POST keyword
on the first line is a copy of the URL pathname. The Host: parameter
is also taken from the URL. The content type is always either
"application/x-fossil" or "application/x-fossil-debug". The "x-fossil"
content type is the default. The only difference is that "x-fossil"
content is compressed using zlib whereas "x-fossil-debug" is sent
uncompressed.
A typical reply from the server might look something like this:
<blockquote><pre>
HTTP/1.0 200 OK
Date: Mon, 10 Sep 2007 12:21:01 GMT
Connection: close
Cache-control: private
Content-Type: application/x-fossil; charset=US-ASCII
Content-Length: 265
<i>content...</i>
</pre></blockquote>
The content type of the reply is always the same as the content type
of the request.
<h2>3.0 Fossil Synchronization Content</h2>
A synchronization request between a client and server consists of
one or more HTTP requests as described in the previous section. This
section details the "x-fossil" content type.
<h3>3.1 Line-oriented Format</h3>
The x-fossil content type consists of zero or more "cards". Cards
are separated by the newline character ("\n"). Leading and trailing
whitespace on a card is ignored. Blank cards are ignored.
Each card is divided into zero or more space separated tokens.
The first token on each card is the operator. Subsequent tokens
are arguments. The set of operators understood by servers is slightly
different from the operators understood by clients, though the two
are very similar.
<h3>3.2 Login Cards</h3>
Every message from client to server begins with one or more login
cards. Each login card has the following format:
<blockquote>
<b>login</b> <i>userid nonce signature</i>
</blockquote>
The userid is the name of the user that is requesting service
from the server. The nonce is the SHA1 hash of the remainder of
the message - all text that follows the newline character that
terminates the login card. The signature is the SHA1 hash of
the concatenation of the nonce and the users password.
For each login card, the server looks up the user and verifies
that the nonce matches the SHA1 hash of the remainder of the
message. It then checks the signature hash to make sure the
signature matches. If everything
checks out, then the client is granted all privileges of the
specified user.
Privileges are cumulative. There can be multiple successful
login cards. The session privilege is the union of all
privileges from all login cards.
<h3>3.3 File Cards</h3>
Artifacts are transferred using either "file" cards, or "cfile"
or "uvfile" cards.
The name "file" card comes from the fact that most artifacts correspond to
files that are under version control.
The "cfile" name is an abbreviation for "compressed file".
The "uvfile" name is an abbreviation for "unversioned file".
<h4>3.3.1 Ordinary File Cards</h4>
For sync protocols, artifacts are transferred using "file"
cards. File cards come in two different formats depending
on whether the artifact is sent directly or as a
[./delta_format.wiki|delta] from some
other artifact.
<blockquote>
<b>file</b> <i>artifact-id size</i> <b>\n</b> <i>content</i><br>
<b>file</b> <i>artifact-id delta-artifact-id size</i> <b>\n</b> <i>content</i>
</blockquote>
File cards are followed by in-line "payload" data.
The content of the artifact
or the artifact delta is the first <i>size</i> bytes of the
x-fossil content that immediately follow the newline that
terminates the file card.
The first argument of a file card is the ID of the artifact that
is being transferred. The artifact ID is the lower-case hexadecimal
representation of the name hash for the artifact.
The last argument of the file card is the number of bytes of
payload that immediately follow the file card. If the file
card has only two arguments, that means the payload is the
complete content of the artifact. If the file card has three
arguments, then the payload is a
[./delta_format.wiki|delta] and the second argument is
the ID of another artifact that is the source of the delta.
File cards are sent in both directions: client to server and
server to client. A delta might be sent before the source of
the delta, so both client and server should remember deltas
and be able to apply them when their source arrives.
<h4>3.3.2 Compressed File Cards</h4>
A client that sends a clone protocol version "3" or greater will
receive artifacts as "cfile" cards while cloning. This card was
introduced to improve the speed of the transfer of content by sending the
compressed artifact directly from the server database to the client.
Compressed File cards are similar to File cards, sharing the same
in-line "payload" data characteristics and also the same treatment of
direct content or delta content. Cfile cards come in two different formats
depending on whether the artifact is sent directly or as a delta from
some other artifact.
<blockquote>
<b>cfile</b> <i>artifact-id usize csize</i> <b>\n</b> <i>content</i><br>
<b>cfile</b> <i>artifact-id delta-artifact-id usize csize</i> <b>\n</b> <i>content</i><br>
</blockquote>
The first argument of the cfile card is the ID of the artifact that
is being transferred. The artifact ID is the lower-case hexadecimal
representation of the name hash for the artifact. The second argument of
the cfile card is the original size in bytes of the artifact. The last
argument of the cfile card is the number of compressed bytes of payload
that immediately follow the cfile card. If the cfile card has only
three arguments, that means the payload is the complete content of the
artifact. If the cfile card has four arguments, then the payload is a
delta and the second argument is the ID of another artifact that is the
source of the delta and the third argument is the original size of the
delta artifact.
Unlike file cards, cfile cards are only sent in one direction during a
clone from server to client for clone protocol version "3" or greater.
<h4>3.3.3 Private artifacts</h4>
"Private" content consist of artifacts that are not normally synced.
However, private content will be synced when the
the [/help?cmd=sync|fossil sync] command includes the "--private" option.
Private content is marked by a "private" card:
<blockquote>
<b>private</b>
</blockquote>
The private card has no arguments and must directly precede a
file card that contains the private content.
<h4>3.3.4 Unversioned File Cards</h4>
Unversioned content is sent in both directions (client to server and
server to client) using "uvfile" cards in the following format:
<blockquote>
<b>uvfile</b> <i>name mtime hash size flags</i> <b>\n</b> <i>content</i>
</blockquote>
The <i>name</i> field is the name of the unversioned file. The
<i>mtime</i> is the last modification time of the file in seconds
since 1970. The <i>hash</i> field is the hash of the content
for the unversioned file, or "<b>-</b>" for deleted content.
The <i>size</i> field is the (uncompressed) size of the content
in bytes. The <i>flags</i> field is an integer which is interpreted
as an array of bits. The 0x0004 bit of <i>flags</i> indicates that
the <i>content</i> is to be omitted. The content might be omitted if
it is too large to transmit, or if the sender merely wants to update the
modification time of the file without changing the files content.
The <i>content</i> is the (uncompressed) content of the file.
The receiver should only accept the uvfile card if the hash and
size match the content and if the mtime is newer than any existing
instance of the same file held by the receiver. The sender will not
normally transmit a uvfile card unless all these constraints are true,
but the receiver should double-check.
A server will only accept uvfile cards if the login user has
the "y" write-unversioned permission.
Servers send uvfile cards in response to uvgimme cards received from
the client. Clients send uvfile cards when they determine that the server
needs the content based on uvigot cards previously received from the server.
<h3>3.4 Push and Pull Cards</h3>
Among the first cards in a client-to-server message are
the push and pull cards. The push card tells the server that
the client is pushing content. The pull card tells the server
that the client wants to pull content. In the event of a sync,
both cards are sent. The format is as follows:
<blockquote>
<b>push</b> <i>servercode projectcode</i><br>
<b>pull</b> <i>servercode projectcode</i>
</blockquote>
The <i>servercode</i> argument is the repository ID for the
client. The <i>projectcode</i> is the identifier
of the software project that the client repository contains.
The projectcode for the client and server must match in order
for the transaction to proceed.
The server will also send a push card back to the client
during a clone. This is how the client determines what project
code to put in the new repository it is constructing.
The <i>servercode</i> argument is currently unused.
<h3>3.5 Clone Cards</h3>
A clone card works like a pull card in that it is sent from
client to server in order to tell the server that the client
wants to pull content. The clone card comes in two formats. Older
clients use the no-argument format and newer clients use the
two-argument format.
<blockquote>
<b>clone</b><br>
<b>clone</b> <i>protocol-version sequence-number</i>
</blockquote>
<h4>3.5.1 Protocol 3</h4>
The latest clients send a two-argument clone message with a
protocol version of "3". (Future versions of Fossil might use larger
protocol version numbers.) Version "3" of the protocol enhanced version
"2" by introducing the "cfile" card which is intended to speed up clone
operations. Instead of sending "file" cards, the server will send "cfile"
cards
<h4>3.5.2 Protocol 2</h4>
The sequence-number sent is the number
of artifacts received so far. For the first clone message, the
sequence number is 0. The server will respond by sending file
cards for some number of artifacts up to the maximum message size.
The server will also send a single "clone_seqno" card to the client
so that the client can know where the server left off.
<blockquote>
<b>clone_seqno</b> <i>sequence-number</i>
</blockquote>
The clone message in subsequent HTTP requests for the same clone
operation will use the sequence-number from the
clone_seqno of the previous reply.
In response to an initial clone message, the server also sends the client
a push message so that the client can discover the projectcode for
this project.
<h4>3.5.3 Legacy Protocol</h4>
Older clients send a clone card with no argument. The server responds
to a blank clone card by sending an "igot" card for every artifact in the
repository. The client will then issue "gimme" cards to pull down all the
content it needs.
The legacy protocol works well for smaller repositories (50MB with 50,000
artifacts) but is too slow and unwieldy for larger repositories.
The version 2 protocol is an effort to improve performance. Further
performance improvements with higher-numbered clone protocols are
possible in future versions of Fossil.
<h3>3.6 Igot Cards</h3>
An igot card can be sent from either client to server or from
server to client in order to indicate that the sender holds a copy
of a particular artifact. The format is:
<blockquote>
<b>igot</b> <i>artifact-id</i> ?<i>flag</i>?
</blockquote>
The first argument of the igot card is the ID of the artifact that
the sender possesses.
The receiver of an igot card will typically check to see if
it also holds the same artifact and if not it will request the artifact
using a gimme card in either the reply or in the next message.
If the second argument exists and is "1", then the artifact
identified by the first argument is private on the sender and should
be ignored unless a "--private" [/help?cmd=sync|sync] is occurring.
The name "igot" comes from the English slang expression "I got" meaning
"I have".
<h4>3.6.1 Unversioned Igot Cards</h4>
Zero or more "uvigot" cards are sent from server to client when
synchronizing unversioned content. The format of a uvigot card is
as follows:
<blockquote>
<b>uvigot</b> <i>name mtime hash size</i>
</blockquote>
The <i>name</i> argument is the name of an unversioned file.
The <i>mtime</i> is the last modification time of the unversioned file
in seconds since 1970.
The <i>hash</i> is the SHA1 or SHA3-256 hash of the unversioned file
content, or "<b>-</b>" if the file has been deleted.
The <i>size</i> is the uncompressed size of the file in bytes.
When the server sees a "pragma uv-hash" card for which the hash
does not match, it sends uvigot cards for every unversioned file that it
holds. The client will use this information to figure out which
unversioned files need to be synchronized.
The server might also send a uvigot card when it receives a uvgimme card
but its reply message size is already oversized and hence unable to hold
the usual uvfile reply.
When a client receives a "uvigot" card, it checks to see if the
file needs to be transferred from client to server or from server to client.
If a client-to-server transmission is needed, the client schedules that
transfer to occur on a subsequent HTTP request. If a server-to-client
transfer is needed, then the client sends a "uvgimme" card back to the
server to request the file content.
<h3>3.7 Gimme Cards</h3>
A gimme card is sent from either client to server or from server
to client. The gimme card asks the receiver to send a particular
artifact back to the sender. The format of a gimme card is this:
<blockquote>
<b>gimme</b> <i>artifact-id</i>
</blockquote>
The argument to the gimme card is the ID of the artifact that
the sender wants. The receiver will typically respond to a
gimme card by sending a file card in its reply or in the next
message.
The "gimme" name means "give me". The imperative "give me" is
pronounced as if it were a single word "gimme" in some dialects of
English (including the dialect spoken by the original author of Fossil).
<h4>3.7.1 Unversioned Gimme Cards</h4>
Sync synchronizing unversioned content, the client may send "uvgimme"
cards to the server. A uvgimme card requests that the server send
unversioned content to the client. The format of a uvgimme card is
as follows:
<blockquote>
<b>uvgimme</b> <i>name</i>
</blockquote>
The <i>name</i> is the name of the unversioned file found on the
server that the client would like to have. When a server sees a
uvgimme card, it normally responses with a uvfile card, though it might
also send another uvigot card if the HTTP reply is already oversized.
<h3>3.8 Cookie Cards</h3>
A cookie card can be used by a server to record a small amount
of state information on a client. The server sends a cookie to the
client. The client sends the same cookie back to the server on
its next request. The cookie card has a single argument which
is its payload.
<blockquote>
<b>cookie</b> <i>payload</i>
</blockquote>
The client is not required to return the cookie to the server on
its next request. Or the client might send a cookie from a different
server on the next request. So the server must not depend on the
cookie and the server must structure the cookie payload in such
a way that it can tell if the cookie it sees is its own cookie or
a cookie from another server. (Typically the server will embed
its servercode as part of the cookie.)
<h3>3.9 Request-Configuration Cards</h3>
A request-configuration or "reqconfig" card is sent from client to
server in order to request that the server send back "configuration"
data. "Configuration" data is information about users or website
appearance or other administrative details which are not part of the
persistent and versioned state of the project. For example, the "name"
of the project, the default Cascading Style Sheet (CSS) for the web-interface,
and the project logo displayed on the web-interface are all configuration
data elements.
The reqconfig card is normally sent in response to the
"fossil configuration pull" command. The format is as follows:
<blockquote>
<b>reqconfig</b> <i>configuration-name</i>
</blockquote>
As of 2018-06-04, the configuration-name must be one of the
following values:
<table border=0 align="center">
<tr><td valign="top">
<ul>
<li> css
<li> header
|
| ︙ | ︙ | |||
620 621 622 623 624 625 626 | <li> @reportfmt <li> @user <li> @concealed <li> @shun </ul></td></tr> </table> | | | | | | | | | | | | < | < | | < | | | < | | < | | < | < | < < | | | | | | | | | | | | | | | | | | | | | | | | | | 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 |
<li> @reportfmt
<li> @user
<li> @concealed
<li> @shun
</ul></td></tr>
</table>
New configuration-names are likely to be added in future releases of
Fossil. If the server receives a configuration-name that it does not
understand, the entire reqconfig card is silently ignored. The reqconfig
card might also be ignored if the user lacks sufficient privilege to
access the requested information.
The configuration-names that begin with an alphabetic character refer
to values in the "config" table of the server database. For example,
the "logo-image" configuration item refers to the project logo image
that is configured on the Admin page of the [./webui.wiki | web-interface].
The value of the configuration item is returned to the client using a
"config" card.
If the configuration-name begins with "@", that refers to a class of
values instead of a single value. The content of these configuration items
is returned in a "config" card that contains pure SQL text that is
intended to be evaluated by the client.
The @user and @concealed configuration items contain sensitive information
and are ignored for clients without sufficient privilege.
<h3>3.10 Configuration Cards</h3>
A "config" card is used to send configuration information from client
to server (in response to a "fossil configuration push" command) or
from server to client (in response to a "fossil configuration pull" or
"fossil clone" command). The format is as follows:
<blockquote>
<b>config</b> <i>configuration-name size</i> <b>\n</b> <i>content</i>
</blockquote>
The server will only accept a config card if the user has
"Admin" privilege. A client will only accept a config card if
it had sent a corresponding reqconfig card in its request.
The content of the configuration item is used to overwrite the
corresponding configuration data in the receiver.
<h3>3.11 Pragma Cards</h3>
The client may try to influence the behavior of the server by
issuing a pragma card:
<blockquote>
<b>pragma</i> <i>name value...</i>
</blockquote>
The "pragma" card has at least one argument which is the pragma name.
The pragma name defines what the pragma does.
A pragma might have zero or more "value" arguments
depending on the pragma name.
New pragma names may be added to the protocol from time to time
in order to enhance the capabilities of Fossil.
Unknown pragmas are silently ignored, for backwards compatibility.
The following are the known pragma names as of 2019-06-30:
<ol>
<li><b>send-private</b> The send-private pragma instructs the server to send all of its
private artifacts to the client. The server will only obey this
request if the user has the "x" or "Private" privilege.
<li><b>send-catalog</b> The send-catalog pragma instructs the server to transmit igot
cards for every known artifact. This can help the client and server
to get back in synchronization after a prior protocol error. The
"--verily" option to the [/help?cmd=sync|fossil sync] command causes
the send-catalog pragma to be transmitted.
<li><b>uv-hash</b> <i>HASH</i> The uv-hash pragma is sent from client to server to provoke a
synchronization of unversioned content. The <i>HASH</i> is a SHA1
hash of the names, modification times, and individual hashes of all
unversioned files on the client. If the unversioned content hash
from the client does not match the unversioned content hash on the
server, then the server will reply with either a "pragma uv-push-ok"
or "pragma uv-pull-only" card followed by one "uvigot" card for
each unversioned file currently held on the server. The collection
of "uvigot" cards sent in response to a "uv-hash" pragma is called
the "unversioned catalog". The client will used the unversioned
catalog to figure out which files (if any) need to be synchronized
between client and server and send appropriate "uvfile" or "uvgimme"
cards on the next HTTP request.
If a client sends a uv-hash pragma and does not receive back
either a uv-pull-only or uv-push-ok pragma, that means that the
content on the server exactly matches the content on the client and
no further synchronization is required.
<li><b>uv-pull-only</b></i> A server sends the uv-pull-only pragma to the client in response
to a uv-hash pragma with a mismatched content hash argument. This
pragma indicates that there are differences in unversioned content
between the client and server but that content can only be transferred
from server to client. The server is unwilling to accept content from
the client because the client login lacks the "write-unversioned"
permission.
<li><b>uv-push-ok</b></i> A server sends the uv-push-ok pragma to the client in response
to a uv-hash pragma with a mismatched content hash argument. This
pragma indicates that there are differences in unversioned content
between the client and server and that content can be transferred
in either direction. The server is willing to accept content from
the client because the client login has the "write-unversioned"
permission.
<li><b>ci-lock</b> <i>CHECKIN-HASH CLIENT-ID</i> A client sends the "ci-lock" pragma to the server to indicate
that it is about to add a new check-in as a child of the
CHECKIN-HASH check-in and on the same branch as CHECKIN-HASH.
If some other client has already indicated that it was also
trying to commit against CHECKIN-HASH, that indicates that a
fork is about to occur, and the server will reply with
a "ci-lock-fail" pragma (see below). Check-in locks
automatically expire when the check-in actually occurs, or
after a timeout (currently one minute but subject to change).
<li><b>ci-lock-fail</b> <i>LOGIN MTIME</i> When a server receives two or more "ci-lock" pragma messages
for the same check-in but from different clients, the second a
subsequent ci-lock will provoke a ci-lock-fail pragma in the
reply to let the client know that it if continues with the
check-in it will likely generate a fork. The LOGIN and MTIME
arguments are intended to provide information to the client to
help it generate a more useful error message.
<li><b>ci-unlock</b> <i>CLIENT-ID</i> A client sends the "ci-unlock" pragma to the server after
a successful commit. This instructs the server to release
any lock on any check-in previously held by that client.
The ci-unlock pragma helps to avoid false-positive lock warnings
that might arise if a check-in is aborted and then restarted
on a branch.
</ol>
<h3>3.12 Comment Cards</h3>
Any card that begins with "#" (ASCII 0x23) is a comment card and
is silently ignored.
<h3>3.13 Message and Error Cards</h3>
If the server discovers anything wrong with a request, it generates
an error card in its reply. When the client sees the error card,
it displays an error message to the user and aborts the sync
operation. An error card looks like this:
<blockquote>
<b>error</b> <i>error-message</i>
</blockquote>
The error message is English text that is encoded in order to
be a single token.
A space (ASCII 0x20) is represented as "\s" (ASCII 0x5C, 0x73). A
newline (ASCII 0x0a) is "\n" (ASCII 0x6C, x6E). A backslash
(ASCII 0x5C) is represented as two backslashes "\\". Apart from
space and newline, no other whitespace characters nor any
unprintable characters are allowed in
the error message.
The server can also send a message card that also prints a
message on the client console, but which is not an error:
<blockquote>
<b>message</b> <i>message-text</i>
</blockquote>
The message-text uses the same format as an error message.
<h3>3.14 Unknown Cards</h3>
If either the client or the server sees a card that is not
described above, then it generates an error and aborts.
<h2>4.0 Phantoms And Clusters</h2>
When a repository knows that an artifact exists and knows the ID of
that artifact, but it does not know the artifact content, then it stores that
artifact as a "phantom". A repository will typically create a phantom when
it receives an igot card for an artifact that it does not hold or when it
receives a file card that references a delta source that it does not
hold. When a server is generating its reply or when a client is
generating a new request, it will usually send gimme cards for every
phantom that it holds.
A cluster is a special artifact that tells of the existence of other
artifacts. Any artifact in the repository that follows the syntactic rules
of a cluster is considered a cluster.
A cluster is line oriented. Each line of a cluster
is a card. The cards are separated by the newline ("\n") character.
Each card consists of a single character card type, a space, and a
single argument. No extra whitespace and no trailing or leading
whitespace is allowed. All cards in the cluster must occur in
strict lexicographical order.
A cluster consists of one or more "M" cards followed by a single
"Z" card. Each M card holds an argument which is an artifact ID for an
artifact in the repository. The Z card has a single argument which is the
lower-case hexadecimal representation of the MD5 checksum of all
preceding M cards up to and included the newline character that
occurred just before the Z that starts the Z card.
Any artifact that does not match the specifications of a cluster
exactly is not a cluster. There must be no extra whitespace in
the artifact. There must be one or more M cards. There must be a
single Z card with a correct MD5 checksum. And all cards must
be in strict lexicographical order.
<h3>4.1 The Unclustered Table</h3>
Every repository maintains a table named "<b>unclustered</b>"
which records the identity of every artifact and phantom it holds that is not
mentioned in a cluster. The entries in the unclustered table can
be thought of as leaves on a tree of artifacts. Some of the unclustered
artifacts will be other clusters. Those clusters may contain other clusters,
which might contain still more clusters, and so forth. Beginning
with the artifacts in the unclustered table, one can follow the chain
of clusters to find every artifact in the repository.
<h2>5.0 Synchronization Strategies</h2>
<h3>5.1 Pull</h3>
A typical pull operation proceeds as shown below. Details
of the actual implementation may very slightly but the gist of
a pull is captured in the following steps:
<ol>
<li>The client sends login and pull cards.
<li>The client sends a cookie card if it has previously received a cookie.
<li>The client sends gimme cards for every phantom that it holds.
<hr>
<li>The server checks the login password and rejects the session if
|
| ︙ | ︙ | |||
875 876 877 878 879 880 881 | <li>The client adds the content of file cards to its repository. <li>The client creates a phantom for every igot card in the server reply that mentions an artifact that the client does not possess. <li>The client creates a phantom for the delta source of file cards when the delta source is an artifact that the client does not possess. </ol> | | | | | | | | | | | | 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 | <li>The client adds the content of file cards to its repository. <li>The client creates a phantom for every igot card in the server reply that mentions an artifact that the client does not possess. <li>The client creates a phantom for the delta source of file cards when the delta source is an artifact that the client does not possess. </ol> These ten steps represent a single HTTP round-trip request. The first three steps are the processing that occurs on the client to generate the request. The middle four steps are processing that occurs on the server to interpret the request and generate a reply. And the last three steps are the processing that the client does to interpret the reply. During a pull, the client will keep sending HTTP requests until it holds all artifacts that exist on the server. Note that the server tries to limit the size of its reply message to something reasonable (usually about 1MB) so that it might stop sending file cards as described in step (6) if the reply becomes too large. Step (5) is the only way in which new clusters can be created. By only creating clusters on the server, we hope to minimize the amount of overlap between clusters in the common configuration where there is a single server and many clients. The same synchronization protocol will continue to work even if there are multiple servers or if servers and clients sometimes change roles. The only negative effects of these unusual arrangements is that more than the minimum number of clusters might be generated. <h3>5.2 Push</h3> A typical push operation proceeds roughly as shown below. As with a pull, the actual implementation may vary slightly. <ol> <li>The client sends login and push cards. <li>The client sends file cards for any artifacts that it holds that have never before been pushed - artifacts that come from local check-ins. <li>If this is the second or later cycle in a push, then the client sends file cards for any gimme cards that the server sent |
| ︙ | ︙ | |||
927 928 929 930 931 932 933 | it does not possess. <li>The server issues gimme cards for all phantoms. <hr> <li>The client remembers the gimme cards from the server so that it can generate file cards in reply on the next cycle. </ol> | | | | | | | | | | 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 |
it does not possess.
<li>The server issues gimme cards for all phantoms.
<hr>
<li>The client remembers the gimme cards from the server so that it
can generate file cards in reply on the next cycle.
</ol>
As with a pull, the steps of a push operation repeat until the
server knows all artifacts that exist on the client. Also, as with
pull, the client attempts to keep the size of the request from
growing too large by suppressing file cards once the
size of the request reaches 1MB.
<h3 id="sync">5.3 Sync</h3>
A sync is just a pull and a push that happen at the same time.
The first three steps of a pull are combined with the first five steps
of a push. Steps (4) through (7) of a pull are combined with steps
(5) through (8) of a push. And steps (8) through (10) of a pull
are combined with step (9) of a push.
<h3>5.4 Unversioned File Sync</h3>
"Unversioned files" are files held in the repository
where only the most recent version of the file is kept rather than
the entire change history. Unversioned files are intended to be
used to store ephemeral content, such as compiled binaries of the
most recent release.
Unversioned files are identified by name and timestamp (mtime).
Only the most recent version of each file (the version with
the largest mtime value) is retained.
Unversioned files are synchronized using the
[/help?cmd=unversioned|fossil unversioned sync] command.
A schematic of an unversioned file synchronization is as follows:
<ol>
<li>The client sends a "pragma uv-hash" card to the server. The argument
to the uv-hash pragma is a hash of all filesnames, mtimes, and
content hashes for the unversioned files held by the client.
<hr>
<li>If the unversioned content hash from the client matches the unversioned
|
| ︙ | ︙ | |||
979 980 981 982 983 984 985 |
then sends appropriate "uvgimme" or "uvfile" cards back to the
server.
<hr>
<li>The server updates its unversioned file store with received "uvfile"
cards and answers "uvgimme" cards with "uvfile" cards in its reply.
</ol>
| | | | 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 |
then sends appropriate "uvgimme" or "uvfile" cards back to the
server.
<hr>
<li>The server updates its unversioned file store with received "uvfile"
cards and answers "uvgimme" cards with "uvfile" cards in its reply.
</ol>
The last two steps might be repeated multiple
times if there is more unversioned content to be transferred than will
fit comfortably in a single HTTP request.
<h2>6.0 Summary</h2>
Here are the key points of the synchronization protocol:
<ol>
<li>The client sends one or more PUSH HTTP requests to the server.
The request and reply content type is "application/x-fossil".
<li>HTTP request content is compressed using zlib.
<li>The content of request and reply consists of cards with one
card per line.
|
| ︙ | ︙ | |||
1029 1030 1031 1032 1033 1034 1035 | cluster and send igot messages for those artifacts. <li>Repositories keep track of all the phantoms they hold and send gimme messages for those artifacts. </ol> <h2>7.0 Troubleshooting And Debugging Hints</h2> | | | | | | 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 |
cluster and send igot messages for those artifacts.
<li>Repositories keep track of all the phantoms they hold and send
gimme messages for those artifacts.
</ol>
<h2>7.0 Troubleshooting And Debugging Hints</h2>
If you run the [/help?cmd=sync|fossil sync] command
(or [/help?cmd=pull|pull] or [/help?cmd=push|push] or
[/help?cmd=clone|clone]) with the --httptrace option, Fossil
will keep a copy of each HTTP request and reply in files
named:
<ul>
<li> <tt>http-request-</tt><i>N</i><tt>.txt</tt>
<li> <tt>http-reply-</tt><i>N</i><tt>.txt</tt>
</ul>
In the above, <i>N</i> is an integer that increments with each
round-trip. If you are having trouble on the server side,
you can run the "[/help?cmd=test-http|fossil test-http]" command in a
debugger using one the "http-request-N.txt" files as input and
single step through the processing performed by the server.
The "--transport-command CMD" option on [/help?cmd=sync|fossil sync]
(and similar) causes the external program "CMD" to be used to move
the sync message to the server and retrieve the sync reply. The
CMD is given three arguments:
<ol>
<li> The URL of the server
<li> The name of a temporary file that contains the output-bound sync
protocol text, with the HTTP headers
<li> The name of a temporary file into which the CMD should write the
reply sync protocol text, again without any HTTP headers
</ol>
In a complex debugging situation, you can run the command
"fossil sync --transport-command ./debugging_script" where
"debugging_script" is some script of your own that invokes
the anomolous behavior your are trying to debug.
|
Changes to www/th1.md.
| ︙ | ︙ | |||
211 212 213 214 215 216 217 218 219 220 221 222 223 224 | * [searchable](#searchable) * [setParameter](#setParameter) * [setting](#setting) * [stime](#stime) * [styleHeader](#styleHeader) * [styleFooter](#styleFooter) * [styleScript](#styleScript) * [tclEval](#tclEval) * [tclExpr](#tclExpr) * [tclInvoke](#tclInvoke) * [tclIsSafe](#tclIsSafe) * [tclMakeSafe](#tclMakeSafe) * [tclReady](#tclReady) * [trace](#trace) | > | 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 | * [searchable](#searchable) * [setParameter](#setParameter) * [setting](#setting) * [stime](#stime) * [styleHeader](#styleHeader) * [styleFooter](#styleFooter) * [styleScript](#styleScript) * [submenu](#submenu) * [tclEval](#tclEval) * [tclExpr](#tclExpr) * [tclInvoke](#tclInvoke) * [tclIsSafe](#tclIsSafe) * [tclMakeSafe](#tclMakeSafe) * [tclReady](#tclReady) * [trace](#trace) |
| ︙ | ︙ | |||
732 733 734 735 736 737 738 739 740 741 742 743 744 745 | <a id="styleScript"></a>TH1 styleScript Command ------------------------------------------------- * styleScript Render the configured JavaScript for the selected skin. <a id="tclEval"></a>TH1 tclEval Command ----------------------------------------- **This command requires the Tcl integration feature.** * tclEval arg ?arg ...? | > > > > > > > | 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 | <a id="styleScript"></a>TH1 styleScript Command ------------------------------------------------- * styleScript Render the configured JavaScript for the selected skin. <a id="submenu"></a>TH1 submenu Command ----------------------------------------- * submenu link LABEL URL Add hyperlink to the submenu of the current page. <a id="tclEval"></a>TH1 tclEval Command ----------------------------------------- **This command requires the Tcl integration feature.** * tclEval arg ?arg ...? |
| ︙ | ︙ |
Changes to www/unvers.wiki.
1 2 3 4 | <title>Unversioned Content</title> <h1 align="center">Unversioned Content</h1> "Unversioned content" or "unversioned files" are | | | | | | > | | | | | | < | | | < > > > > > > > > > | > | | | | | | > > > > | > > | | | | 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 | <title>Unversioned Content</title> <h1 align="center">Unversioned Content</h1> "Unversioned content" or "unversioned files" are files stored in a Fossil repository without history, meaning it retains the newest version of each such file, and that alone. Though it omits history, Fossil does sync unversioned content between repositories. In the event of a conflict during a sync, it retains the most recent version of each unversioned file, discarding older versions. Unversioned files are useful for storing ephemeral content such as builds or frequently changing web pages. We store the [https://fossil-scm.org/home/uv/download.html|download] page of the self-hosting Fossil repository as unversioned content, for example. <h2>Accessing Unversioned Files</h2> Unversioned files are <u>not</u> a part of a check-out. Unversioned files are intended to be accessible as web pages using URLs of the form: "<tt>https://example.com/cgi-script/<b>uv</b>/<i>FILENAME</i></tt>". In other words, the URI method "<b>uv</b>" (short for "unversioned") followed by the name of the unversioned file will retrieve the content of the file. The MIME type is inferred from the filename suffix. The content of unversioned files can also be retrieved using the [/help?cmd=unversioned|fossil unvers cat <i>FILENAME</i>] command. A list of all unversioned files on a server can be seen using the [/help?cmd=/uvlist|/uvlist] URL. ([/uvlist|example]). <h2>Syncing Unversioned Files</h2> Unversioned content does not sync between repositories by default. One must request it via commands such as: <blockquote><pre> fossil sync <b>-u</b> fossil clone <b>-u</b> <i>URL local-repo-name</i> fossil unversioned sync </pre></blockquote> The [/help?cmd=sync|fossil sync] and [/help?cmd=clone|fossil clone] commands will synchronize unversioned content if and only if they're given the "-u" (or "--unversioned") command-line option. The [/help?cmd=unversioned|fossil unversioned sync] command synchronizes the unversioned content without synchronizing anything else. Notice that the "-u" option does not work on [/help?cmd=push|fossil push] or [/help?cmd=pull|fossil pull]. The "-u" option is only available on "sync" and "clone". A rough equivalent of an unversioned pull would be the [/help?cmd=unversioned|fossil unversioned revert] command. The "unversioned revert" command causes the unversioned content on the local repository to overwritten by the unversioned content found on the remote repository. Beware that because unversioned file sync is an uncommonly dangerous capability — there being no history to revert to in the case of human error — even the all-powerful Fossil "setup" user does not get unversioned file sync capability by default. See [./caps/admin-v-setup.md#dcap | this] for the full details, but the short-and-sweet takeaway is that a user needs the "y" capability on the remote before they can sync unversioned content. Until then, you're allowed to add such files to your local repo, but they will not sync. <h2>Implementation Details</h2> <i>(This section outlines the current implementation of unversioned files. This is not an interface spec and hence subject to change.)</i> Unversioned content is stored in the repository in the "unversioned" table: <blockquote><pre> CREATE TABLE unversioned( uvid INTEGER PRIMARY KEY AUTOINCREMENT, -- unique ID for this file name TEXT UNIQUE, -- Name of the file rcvid INTEGER, -- From whence this file was received mtime DATETIME, -- Last change (seconds since 1970) hash TEXT, -- SHA1 or SHA3-256 hash of uncompressed content sz INTEGER, -- Size of uncompressed content encoding INT, -- 0: plaintext 1: zlib compressed content BLOB -- File content ); </pre></blockquote> Fossil does not create the table ahead of need. If there are no unversioned files in the repository, the "unversioned" table will not exist. Consequently, one simple way to purge all unversioned content from a repository is to run: <blockquote><pre> fossil sql "DROP TABLE unversioned; VACUUM;" </pre></blockquote> Lacking history for unversioned files, Fossil does not attempt delta compression on them. Fossil servers exchange unversioned content whole; it does not attempt to "diff" your local version against the remote and send only the changes. We point this out because one use-case for unversioned content is to send large, frequently-changing files. Appreciate the consequences before making each change. There are two bandwidth-saving measures in "<tt>fossil uv sync</tt>". The first is the regular HTTP payload compression step, done on all syncs. The second is that Fossil sends hash exchanges to determine when it can avoid sending duplicate content over the wire unnecessarily. See the [./sync.wiki|synchronization protocol documentation] for further information. |
Changes to www/wikitheory.wiki.
1 2 3 4 5 6 7 8 | <title>Wiki In Fossil</title> <h2>Introduction</h2> Fossil uses [/wiki_rules | Fossil wiki markup] and/or [/md_rules | Markdown markup] for many things: * Stand-alone wiki pages. * Description and comments in [./bugtheory.wiki | bug reports]. | | > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<title>Wiki In Fossil</title>
<h2>Introduction</h2>
Fossil uses [/wiki_rules | Fossil wiki markup] and/or
[/md_rules | Markdown markup] for many things:
* Stand-alone wiki pages.
* Description and comments in [./bugtheory.wiki | bug reports].
* Check-in comments. (For historical reasons, these must
currently be in fossil-wiki text format.)
* [./embeddeddoc.wiki | Embedded documentation] files whose
name ends in ".wiki" or ".md" or ".markdown".
* [./event.wiki | Technical notes].
* [./forum.wiki | Forum messages].
* Auxiliary notes on check-ins and branches.
The [/wiki_rules | formatting rules for fossil wiki]
|
| ︙ | ︙ | |||
58 59 60 61 62 63 64 | use the exact same markup. Some projects may choose to use both forms of documentation at the same time. Because the same format is used, it is trivial to move a file from wiki to embedded documentation or back again as the project evolves. <h2>Bug-reports and check-in comments and Forum messages</h2> | | | > | | > > > | 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | use the exact same markup. Some projects may choose to use both forms of documentation at the same time. Because the same format is used, it is trivial to move a file from wiki to embedded documentation or back again as the project evolves. <h2>Bug-reports and check-in comments and Forum messages</h2> The comments on check-ins, forum posts, and the text in the descriptions of bug reports both use wiki formatting. Exactly the same set of formatting rules apply. There is never a need to learn one formatting language for documentation and a different markup for bugs or for check-in comments. Minor caveat: check-in messages are currently limited to the fossil-wiki format. <h2 id="assocwiki">Auxiliary notes attached to check-ins or branches</h2> Stand-alone wiki pages with special names "branch/<i>BRANCHNAME</i>" or "checkin/<i>HASH</i>" are associated with the corresponding branch or check-in. The wiki text appears in an "About" section of timelines and info screens. Examples: |
| ︙ | ︙ |