DELETED .dockerignore Index: .dockerignore ================================================================== --- .dockerignore +++ .dockerignore @@ -1,26 +0,0 @@ -_FOSSIL_ -.fslckout -ajax -art -autosetup -bld -compat -debian -fossil -fossil.exe -setup -src -test -tools -win -wbld -win -www -*.a -*.lib -*.log -*.manifest -*.o -*.obj -*.pdb -*.res DELETED .fossil-settings/encoding-glob Index: .fossil-settings/encoding-glob ================================================================== --- .fossil-settings/encoding-glob +++ .fossil-settings/encoding-glob @@ -1,2 +0,0 @@ -compat/zlib/contrib/dotzlib/DotZLib/*.cs -win/fossil.rc Index: .fossil-settings/ignore-glob ================================================================== --- .fossil-settings/ignore-glob +++ .fossil-settings/ignore-glob @@ -1,5 +1,4 @@ compat/openssl* compat/tcl* fossil fossil.exe -win/fossil.exe Index: .fossil-settings/keep-glob ================================================================== --- .fossil-settings/keep-glob +++ .fossil-settings/keep-glob @@ -1,5 +1,4 @@ compat/openssl* compat/tcl* fossil fossil.exe -win/fossil.exe Index: BUILD.txt ================================================================== --- BUILD.txt +++ BUILD.txt @@ -22,11 +22,11 @@ cd win; nmake /f Makefile.msc If you have trouble, or you want to do something fancy, just look at Makefile.classic. There are 6 configuration options that are all well -commented. Instead of editing the Makefile.classic, consider copying +commented. Instead of editing the Makefile.classic, consider copying Makefile.classic to an alternative name such as "GNUMakefile", "BSDMakefile", or "makefile" and editing the copy. BUILDING OUTSIDE THE SOURCE TREE @@ -61,11 +61,11 @@ Do not edit src/main.mk directly. Update src/makemake.tcl and then rerun it. * The *.h header files are automatically generated using a program called "makeheaders". Source code to the makeheaders program is - found in src/makeheaders.c. Documentation is found in + found in src/makeheaders.c. Documentation is found in src/makeheaders.html. * Most *.c source files are preprocessed using a program called "translate". The sources to translate are found in src/translate.c. A header comment in src/translate.c explains in detail what it does. Index: COPYRIGHT-BSD2.txt ================================================================== --- COPYRIGHT-BSD2.txt +++ COPYRIGHT-BSD2.txt @@ -1,31 +1,31 @@ Copyright 2007 D. Richard Hipp. All rights reserved. -Redistribution and use in source and binary forms, with or -without modification, are permitted provided that the +Redistribution and use in source and binary forms, with or +without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above - copyright notice, this list of conditions and the + copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. -THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS -OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS +OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE -OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -The views and conclusions contained in the software and documentation -are those of the authors and contributors and should not be interpreted +The views and conclusions contained in the software and documentation +are those of the authors and contributors and should not be interpreted as representing official policies, either expressed or implied, of anybody else. DELETED Dockerfile Index: Dockerfile ================================================================== --- Dockerfile +++ Dockerfile @@ -1,27 +0,0 @@ -### -# Dockerfile for Fossil -### -FROM fedora:21 - -### Now install some additional parts we will need for the build -RUN yum update -y && yum install -y gcc make zlib-devel openssl-devel tar && yum clean all && groupadd -r fossil -g 433 && useradd -u 431 -r -g fossil -d /opt/fossil -s /sbin/nologin -c "Fossil user" fossil - -### If you want to build "release", change the next line accordingly. -ENV FOSSIL_INSTALL_VERSION trunk - -RUN curl "http://core.tcl.tk/tcl/tarball/tcl-src.tar.gz?name=tcl-src&uuid=release" | tar zx -RUN cd tcl-src/unix && ./configure --prefix=/usr --disable-shared --disable-threads --disable-load && make && make install -RUN curl "http://www.fossil-scm.org/index.html/tarball/fossil-src.tar.gz?name=fossil-src&uuid=${FOSSIL_INSTALL_VERSION}" | tar zx -RUN cd fossil-src && ./configure --disable-lineedit --disable-fusefs --json --with-th1-docs --with-th1-hooks --with-tcl -RUN cd fossil-src && make && strip fossil && cp fossil /usr/bin && cd .. && rm -rf fossil-src && chmod a+rx /usr/bin/fossil && mkdir -p /opt/fossil && chown fossil:fossil /opt/fossil - -### Build is done, remove modules no longer needed -RUN yum remove -y gcc make zlib-devel openssl-devel tar && yum clean all - -USER fossil - -ENV HOME /opt/fossil - -EXPOSE 8080 - -CMD ["/usr/bin/fossil", "server", "--create", "--user", "admin", "/opt/fossil/repository.fossil"] Index: Makefile.classic ================================================================== --- Makefile.classic +++ Makefile.classic @@ -25,40 +25,30 @@ #### The suffix to add to final executable file. When cross-compiling # to windows, make this ".exe". Otherwise leave it blank. # E = -#### C Compile and options for use in building executables that +#### C Compile and options for use in building executables that # will run on the target platform. This is usually the same # as BCC, unless you are cross-compiling. This C compiler builds # the finished binary for fossil. The BCC compiler above is used # for building intermediate code-generator tools. # #TCC = gcc -O6 #TCC = gcc -g -O0 -Wall -fprofile-arcs -ftest-coverage TCC = gcc -g -Os -Wall -# To use the included miniz library -# FOSSIL_ENABLE_MINIZ = 1 -# TCC += -DFOSSIL_ENABLE_MINIZ - # To add support for HTTPS TCC += -DFOSSIL_ENABLE_SSL #### Extra arguments for linking the finished binary. Fossil needs -# to link against the Z-Lib compression library unless the miniz -# library in the source tree is being used. There are no other -# required dependencies. We sometimes add the -static option -# here so that we can build a static executable that will run in -# a chroot jail. -# -ZLIB_LIB.0 = -lz -ZLIB_LIB.1 = -ZLIB_LIB. = $(ZLIB_LIB.0) - -# If using zlib: -LIB = $(ZLIB_LIB.$(FOSSIL_ENABLE_MINIZ)) $(LDFLAGS) +# to link against the Z-Lib compression library. There are no +# other dependencies. We sometimes add the -static option here +# so that we can build a static executable that will run in a +# chroot jail. +# +LIB = -lz $(LDFLAGS) # If using HTTPS: LIB += -lcrypto -lssl #### Tcl shell for use in running the fossil testsuite. If you do not Index: Makefile.in ================================================================== --- Makefile.in +++ Makefile.in @@ -37,14 +37,16 @@ # care about testing the end result, this can be blank. # TCLSH = tclsh LIB = @LDFLAGS@ @EXTRA_LDFLAGS@ @LIBS@ -TCCFLAGS = @EXTRA_CFLAGS@ @CPPFLAGS@ @CFLAGS@ -DHAVE_AUTOCONFIG_H -D_HAVE_SQLITE_CONFIG_H +TCC += @EXTRA_CFLAGS@ @CPPFLAGS@ @CFLAGS@ -DHAVE_AUTOCONFIG_H INSTALLDIR = $(DESTDIR)@prefix@/bin USE_SYSTEM_SQLITE = @USE_SYSTEM_SQLITE@ -FOSSIL_ENABLE_MINIZ = @FOSSIL_ENABLE_MINIZ@ +FOSSIL_ENABLE_TCL = @FOSSIL_ENABLE_TCL@ +FOSSIL_ENABLE_TCL_STUBS = @FOSSIL_ENABLE_TCL_STUBS@ +FOSSIL_ENABLE_TCL_PRIVATE_STUBS = @FOSSIL_ENABLE_TCL_PRIVATE_STUBS@ include $(SRCDIR)/main.mk distclean: clean rm -f autoconfig.h config.log Makefile Index: VERSION ================================================================== --- VERSION +++ VERSION @@ -1,1 +1,1 @@ -1.32 +1.27 Index: auto.def ================================================================== --- auto.def +++ auto.def @@ -2,23 +2,19 @@ use cc cc-lib options { with-openssl:path|auto|none - => {Look for OpenSSL in the given path, or auto or none} - with-miniz=0 => {Use miniz from the source tree} + => {Look for openssl in the given path, or auto or none} with-zlib:path => {Look for zlib in the given path} - with-th1-docs=0 => {Enable TH1 for embedded documentation pages} - with-th1-hooks=0 => {Enable TH1 hooks for commands and web pages} with-tcl:path => {Enable Tcl integration, with Tcl in the specified path} with-tcl-stubs=0 => {Enable Tcl integration via stubs library mechanism} with-tcl-private-stubs=0 => {Enable Tcl integration via private stubs mechanism} internal-sqlite=1 => {Don't use the internal SQLite, use the system one} static=0 => {Link a static executable} lineedit=1 => {Disable line editing} - fusefs=1 => {Disable the Fuse Filesystem} fossil-debug=0 => {Build with fossil debugging enabled} json=0 => {Build with fossil JSON API enabled} } # sqlite wants these types if possible @@ -32,11 +28,11 @@ # Find tclsh for the test suite. Can't yet use jimsh for this. cc-check-progs tclsh define EXTRA_CFLAGS "" define EXTRA_LDFLAGS "" -define USE_SYSTEM_SQLITE 0 +define USE_SYSTEM_SQLITE "" if {![opt-bool internal-sqlite]} { proc find_internal_sqlite {} { # On some systems (slackware), libsqlite3 requires -ldl to link. So @@ -45,17 +41,17 @@ # the code below will append -ldl to LIBS. # foreach extralibs {{} {-ldl}} { # Locate the system SQLite by searching for sqlite3_open(). Then check - # if sqlite3_strglob() can be found as well. If we can find open() but - # not strglob(), then the system SQLite is too old to link against - # fossil. + # if sqlite3_wal_checkpoint() can be found as well. If we can find + # open() but not wal_checkpoint(), then the system SQLite is too old + # to link against fossil. # if {[cc-check-function-in-lib sqlite3_open sqlite3 $extralibs]} { - if {![cc-check-function-in-lib sqlite3_strglob sqlite3 $extralibs]} { - user-error "system sqlite3 too old (require >= 3.7.17)" + if {![cc-check-function-in-lib sqlite3_wal_checkpoint sqlite3 $extralibs]} { + user-error "system sqlite3 too old (require >= 3.7.0)" } # Success. Update symbols and return. # define USE_SYSTEM_SQLITE 1 @@ -68,49 +64,44 @@ find_internal_sqlite } if {[string match *-solaris* [get-define host]]} { - define-append EXTRA_CFLAGS {-D_XOPEN_SOURCE=500 -D__EXTENSIONS__} + define-append EXTRA_CFLAGS -D_XOPEN_SOURCE=500 } if {[opt-bool fossil-debug]} { define-append EXTRA_CFLAGS -DFOSSIL_DEBUG - msg-result "Debugging support enabled" } if {[opt-bool json]} { # Reminder/FIXME (stephan): FOSSIL_ENABLE_JSON # is required in the CFLAGS because json*.c # have #ifdef guards around the whole file without # reading config.h first. define-append EXTRA_CFLAGS -DFOSSIL_ENABLE_JSON define FOSSIL_ENABLE_JSON - msg-result "JSON support enabled" -} - -if {[opt-bool with-th1-docs]} { - define-append EXTRA_CFLAGS -DFOSSIL_ENABLE_TH1_DOCS - define FOSSIL_ENABLE_TH1_DOCS - msg-result "TH1 embedded documentation support enabled" -} - -if {[opt-bool with-th1-hooks]} { - define-append EXTRA_CFLAGS -DFOSSIL_ENABLE_TH1_HOOKS - define FOSSIL_ENABLE_TH1_HOOKS - msg-result "TH1 hooks support enabled" } #if {[opt-bool markdown]} { # # no-op. Markdown is now enabled by default. -# msg-result "Markdown support enabled" #} if {[opt-bool static]} { # XXX: This will not work on all systems. define-append EXTRA_LDFLAGS -static - msg-result "Trying to link statically" +} + +# Check for zlib, using the given location if specified +set zlibpath [opt-val with-zlib] +if {$zlibpath ne ""} { + cc-with [list -cflags "-I$zlibpath -L$zlibpath"] + define-append EXTRA_CFLAGS -I$zlibpath + define-append EXTRA_LDFLAGS -L$zlibpath +} +if {![cc-check-includes zlib.h] || ![cc-check-function-in-lib inflateEnd z]} { + user-error "zlib not found please install it or specify the location with --with-zlib" } set tclpath [opt-val with-tcl] if {$tclpath ne ""} { set tclprivatestubs [opt-bool with-tcl-private-stubs] @@ -169,11 +160,11 @@ define-append EXTRA_CFLAGS $cflags define-append EXTRA_LDFLAGS $tclconfig(TCL_LD_FLAGS) define FOSSIL_ENABLE_TCL } -# Helper for OpenSSL checking +# Helper for openssl checking proc check-for-openssl {msg {cflags {}}} { msg-checking "Checking for $msg..." set rc 0 msg-quiet cc-with [list -cflags $cflags -libs {-lssl -lcrypto}] { if {[cc-check-includes openssl/ssl.h] && [cc-check-functions SSL_new]} { @@ -236,36 +227,17 @@ } else { user-error "OpenSSL not found. Consider --with-openssl=none to disable HTTPS support" } } -if {[opt-bool with-miniz]} { - define FOSSIL_ENABLE_MINIZ 1 - msg-result "Using miniz for compression" -} else { - # Check for zlib, using the given location if specified - set zlibpath [opt-val with-zlib] - if {$zlibpath ne ""} { - cc-with [list -cflags "-I$zlibpath -L$zlibpath"] - define-append EXTRA_CFLAGS -I$zlibpath - define-append EXTRA_LDFLAGS -L$zlibpath - msg-result "Using zlib from $zlibpath" - } - if {![cc-check-includes zlib.h] || ![cc-check-function-in-lib inflateEnd z]} { - user-error "zlib not found please install it or specify the location with --with-zlib" - } -} - if {[opt-bool lineedit]} { # Need readline-compatible line editing cc-with {-includes stdio.h} { if {[cc-check-includes readline/readline.h] && [cc-check-function-in-lib readline readline]} { - define-append EXTRA_CFLAGS -DHAVE_READLINE msg-result "Using readline for line editing" } elseif {[cc-check-includes editline/readline.h] && [cc-check-function-in-lib readline edit]} { define-feature editline - define-append EXTRA_CFLAGS -DHAVE_EDITLINE msg-result "Using editline for line editing" } } } @@ -276,33 +248,15 @@ if {[string match *mingw* [get-define host]]} { define-append LIBS -lwsock32 } } cc-check-function-in-lib iconv iconv -cc-check-functions utime -cc-check-functions usleep -cc-check-functions strchrnul - -# Check for getloadavg(), and if it doesn't exist, define FOSSIL_OMIT_LOAD_AVERAGE -if {![cc-check-functions getloadavg]} { - define FOSSIL_OMIT_LOAD_AVERAGE 1 - msg-result "Load average support unavailable" -} # Check for getpassphrase() for Solaris 10 where getpass() truncates to 10 chars if {![cc-check-functions getpassphrase]} { # Haiku needs this cc-check-function-in-lib getpass bsd } cc-check-function-in-lib dlopen dl -# Check for the FuseFS library -if {[opt-bool fusefs]} { - if {[cc-check-function-in-lib fuse_mount fuse]} { - define FOSSIL_HAVE_FUSEFS 1 - define-append LIBS -lfuse - msg-result "FuseFS support enabled" - } -} - make-template Makefile.in make-config-header autoconfig.h -auto {USE_* FOSSIL_*} Index: autosetup/autosetup ================================================================== --- autosetup/autosetup +++ autosetup/autosetup @@ -925,11 +925,11 @@ } # Load module source in the global scope by executing the given command proc automf_load {args} { if {[catch [list uplevel #0 $args] msg opts] ni {0 2 3}} { - autosetup-full-error [error-dump $msg $opts $::autosetup(debug)] + autosetup-full-error [error-dump $msg $opts] } } # Initial settings set autosetup(exe) $::argv0 @@ -1706,35 +1706,18 @@ return $msg } # Given the return from [catch {...} msg opts], returns an appropriate # error message. A nice one for Jim and a less-nice one for Tcl. -# If 'fulltrace' is set, a full stack trace is provided. -# Otherwise a simple message is provided. +# +# This is designed for developer errors, e.g. in module code # -# This is designed for developer errors, e.g. in module code or auto.def code -# -# -proc error-dump {msg opts fulltrace} { +proc error-dump {msg opts} { if {$::autosetup(istcl)} { - if {$fulltrace} { - return "Error: [dict get $opts -errorinfo]" - } else { - return "Error: $msg" - } - } else { - lassign $opts(-errorinfo) p f l - if {$f ne ""} { - set result "$f:$l: Error: " - } - append result "$msg\n" - if {$fulltrace} { - append result [stackdump $opts(-errorinfo)] - } - - # Remove the trailing newline - string trim $result + return "Error: [dict get $opts -errorinfo]" + } else { + return "Error: $msg\n[stackdump $opts(-errorinfo)]" } } } # ----- module text-formatting ----- @@ -1903,13 +1886,13 @@ # Entry/Exit # if {$autosetup(debug)} { main $argv } -if {[catch {main $argv} msg opts] == 1} { +if {[catch {main $argv} msg] == 1} { show-notices - autosetup-full-error [error-dump $msg $opts $::autosetup(debug)] - if {!$autosetup(debug)} { + puts stderr [error-stacktrace $msg] + if {!$autosetup(debug) && !$autosetup(istcl)} { puts stderr "Try: '[file tail $autosetup(exe)] --debug' for a full stack trace" } exit 1 } Index: autosetup/cc-shared.tcl ================================================================== --- autosetup/cc-shared.tcl +++ autosetup/cc-shared.tcl @@ -94,19 +94,10 @@ define SHOBJ_LDFLAGS -b define SH_CFLAGS +z define SH_LINKFLAGS -Wl,+s define LD_LIBRARY_PATH SHLIB_PATH } - *-*-haiku { - define SHOBJ_CFLAGS "" - define SHOBJ_LDFLAGS -shared - define SH_CFLAGS "" - define SH_LDFLAGS -shared - define SH_LINKFLAGS "" - define SH_SOPREFIX "" - define LD_LIBRARY_PATH LIBRARY_PATH - } } if {![is-defined SHOBJ_LDFLAGS_R]} { define SHOBJ_LDFLAGS_R [get-define SHOBJ_LDFLAGS] } Index: autosetup/cc.tcl ================================================================== --- autosetup/cc.tcl +++ autosetup/cc.tcl @@ -333,11 +333,11 @@ } -libs { # Note that new libraries are added before previous libraries set new($name) [list {*}$value {*}$new($name)] } - -link - -lang - -nooutput { + -link - -lang { set new($name) $value } -source - -sourcefile - -code { # XXX: These probably are only valid directly from cctest set new($name) $value @@ -428,11 +428,10 @@ ## -lang c|c++ Use the C (default) or C++ compiler ## -libs liblist List of libraries to link, e.g. {-ldl -lm} ## -code code Code to compile in the body of main() ## -source code Compile a complete program. Ignore -includes, -declare and -code ## -sourcefile file Shorthand for -source [readfile [get-define srcdir]/$file] -## -nooutput 1 Treat any compiler output (e.g. a warning) as an error # # Unless -source or -sourcefile is specified, the C program looks like: # ## #include /* same for remaining includes in the list */ ## @@ -522,12 +521,11 @@ } writefile $src $lines\n set ok 1 - set err [catch {exec-with-stderr {*}$cmdline} result errinfo] - if {$err || ($opts(-nooutput) && [string length $result])} { + if {[catch {exec-with-stderr {*}$cmdline} result errinfo]} { configlog "Failed: [join $cmdline]" configlog $result configlog "============" configlog "The failed code was:" configlog $lines @@ -673,27 +671,27 @@ } define CCACHE [find-an-executable [get-env CCACHE ccache]] # Initial cctest settings -cc-store-settings {-cflags {} -includes {} -declare {} -link 0 -lang c -libs {} -code {} -nooutput 0} +cc-store-settings {-cflags {} -includes {} -declare {} -link 0 -lang c -libs {} -code {}} set autosetup(cc-include-deps) {} msg-result "C compiler...[get-define CCACHE] [get-define CC] [get-define CFLAGS]" if {[get-define CXX] ne "false"} { msg-result "C++ compiler...[get-define CCACHE] [get-define CXX] [get-define CXXFLAGS]" } msg-result "Build C compiler...[get-define CC_FOR_BUILD]" -# On Darwin, we prefer to use -g0 to avoid creating .dSYM directories -# but some compilers may not support it, so test here. +# On Darwin, we prefer to use -gstabs to avoid creating .dSYM directories +# but some compilers don't support -gstabs, so test for it here. switch -glob -- [get-define host] { *-*-darwin* { - if {[cctest -cflags {-g0}]} { - define cc-default-debug -g0 + if {[cctest -cflags {-gstabs}]} { + define cc-default-debug -gstabs } } } if {![cc-check-includes stdlib.h]} { user-error "Compiler does not work. See config.log" } Index: autosetup/config.guess ================================================================== --- autosetup/config.guess +++ autosetup/config.guess @@ -1,38 +1,44 @@ #! /bin/sh # Attempt to guess a canonical system name. -# Copyright 1992-2014 Free Software Foundation, Inc. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 +# Free Software Foundation, Inc. -timestamp='2014-03-23' +timestamp='2010-09-24' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 3 of the License, or +# the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # 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. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with this program; if not, see . +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA +# 02110-1301, USA. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under -# the same distribution terms that you use for the rest of that -# program. This Exception is an additional permission under section 7 -# of the GNU General Public License, version 3 ("GPLv3"). +# the same distribution terms that you use for the rest of that program. + + +# Originally written by Per Bothner. Please send patches (context +# diff format) to and include a ChangeLog +# entry. # -# Originally written by Per Bothner. +# This script attempts to guess a canonical system name similar to +# config.sub. If it succeeds, it prints the system name on stdout, and +# exits with 0. Otherwise, it exits with 1. # # You can get the latest version of this script from: # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD -# -# Please send patches with a ChangeLog entry to config-patches@gnu.org. - me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] @@ -48,11 +54,13 @@ version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. -Copyright 1992-2014 Free Software Foundation, Inc. +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, +2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free +Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" @@ -82,11 +90,11 @@ if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi -trap 'exit 1' 1 2 15 +trap 'exit 1' HUP INT TERM # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires # temporary files to be created and, as you can see below, it is a # headache to deal with in a portable fashion. @@ -96,11 +104,11 @@ # Portable tmp directory creation inspired by the Autoconf team. set_cc_for_build=' trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; -trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; +trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" HUP INT PIPE TERM ; : ${TMPDIR=/tmp} ; { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; @@ -130,37 +138,16 @@ UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown -case "${UNAME_SYSTEM}" in -Linux|GNU|GNU/*) - # If the system lacks a compiler, then just pick glibc. - # We could probably try harder. - LIBC=gnu - - eval $set_cc_for_build - cat <<-EOF > $dummy.c - #include - #if defined(__UCLIBC__) - LIBC=uclibc - #elif defined(__dietlibc__) - LIBC=dietlibc - #else - LIBC=gnu - #endif - EOF - eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC' | sed 's, ,,g'` - ;; -esac - # Note: order is significant - the case branches are not exclusive. case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or - # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, + # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward # compatibility and a consistent mechanism for selecting the # object file format. @@ -192,11 +179,11 @@ else os=netbsdelf fi ;; *) - os=netbsd + os=netbsd ;; esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # thus, need a distinct triplet. However, they do not need @@ -213,14 +200,10 @@ # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. echo "${machine}-${os}${release}" exit ;; - *:Bitrig:*:*) - UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` - echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE} - exit ;; *:OpenBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} exit ;; *:ekkoBSD:*:*) @@ -239,11 +222,11 @@ case $UNAME_RELEASE in *4.0) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` ;; *5.*) - UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ;; esac # According to Compaq, /usr/sbin/psrinfo has been available on # OSF/1 and Tru64 systems produced since 1995. I hope that # covers most systems running today. This code pipes the CPU @@ -285,14 +268,11 @@ # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` - # Reset EXIT trap before exiting to avoid spurious non-zero exit code. - exitcode=$? - trap '' 0 - exit $exitcode ;; + exit ;; Alpha\ *:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # Should we change UNAME_MACHINE based on the output of uname instead # of the specific Alpha model? echo alpha-pc-interix @@ -314,16 +294,16 @@ exit ;; *:z/VM:*:*) echo s390-ibm-zvmoe exit ;; *:OS400:*:*) - echo powerpc-ibm-os400 + echo powerpc-ibm-os400 exit ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) echo arm-acorn-riscix${UNAME_RELEASE} exit ;; - arm*:riscos:*:*|arm*:RISCOS:*:*) + arm:riscos:*:*|arm:RISCOS:*:*) echo arm-unknown-riscos exit ;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) echo hppa1.1-hitachi-hiuxmpp exit ;; @@ -413,27 +393,27 @@ # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) - echo m68k-atari-mint${UNAME_RELEASE} + echo m68k-atari-mint${UNAME_RELEASE} exit ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} - exit ;; + exit ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) - echo m68k-atari-mint${UNAME_RELEASE} + echo m68k-atari-mint${UNAME_RELEASE} exit ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) - echo m68k-milan-mint${UNAME_RELEASE} - exit ;; + echo m68k-milan-mint${UNAME_RELEASE} + exit ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) - echo m68k-hades-mint${UNAME_RELEASE} - exit ;; + echo m68k-hades-mint${UNAME_RELEASE} + exit ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) - echo m68k-unknown-mint${UNAME_RELEASE} - exit ;; + echo m68k-unknown-mint${UNAME_RELEASE} + exit ;; m68k:machten:*:*) echo m68k-apple-machten${UNAME_RELEASE} exit ;; powerpc:machten:*:*) echo powerpc-apple-machten${UNAME_RELEASE} @@ -499,12 +479,12 @@ exit ;; m88k:*:3*:R3*) echo m88k-motorola-sysv3 exit ;; AViiON:dgux:*:*) - # DG/UX returns AViiON for all architectures - UNAME_PROCESSOR=`/usr/bin/uname -p` + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] then if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ [ ${TARGET_BINARY_INTERFACE}x = x ] then @@ -513,11 +493,11 @@ echo m88k-dg-dguxbcs${UNAME_RELEASE} fi else echo i586-dg-dgux${UNAME_RELEASE} fi - exit ;; + exit ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) echo m88k-dolphin-sysv3 exit ;; M88*:*:R3*:*) # Delta 88k system running SVR3 @@ -613,56 +593,56 @@ 9000/31? ) HP_ARCH=m68000 ;; 9000/[34]?? ) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if [ -x /usr/bin/getconf ]; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` - sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` - case "${sc_cpu_version}" in - 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 - 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 - 532) # CPU_PA_RISC2_0 - case "${sc_kernel_bits}" in - 32) HP_ARCH="hppa2.0n" ;; - 64) HP_ARCH="hppa2.0w" ;; + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` + case "${sc_cpu_version}" in + 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 + 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 + 532) # CPU_PA_RISC2_0 + case "${sc_kernel_bits}" in + 32) HP_ARCH="hppa2.0n" ;; + 64) HP_ARCH="hppa2.0w" ;; '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 - esac ;; - esac + esac ;; + esac fi if [ "${HP_ARCH}" = "" ]; then eval $set_cc_for_build - sed 's/^ //' << EOF >$dummy.c - - #define _HPUX_SOURCE - #include - #include - - int main () - { - #if defined(_SC_KERNEL_BITS) - long bits = sysconf(_SC_KERNEL_BITS); - #endif - long cpu = sysconf (_SC_CPU_VERSION); - - switch (cpu) - { - case CPU_PA_RISC1_0: puts ("hppa1.0"); break; - case CPU_PA_RISC1_1: puts ("hppa1.1"); break; - case CPU_PA_RISC2_0: - #if defined(_SC_KERNEL_BITS) - switch (bits) - { - case 64: puts ("hppa2.0w"); break; - case 32: puts ("hppa2.0n"); break; - default: puts ("hppa2.0"); break; - } break; - #else /* !defined(_SC_KERNEL_BITS) */ - puts ("hppa2.0"); break; - #endif - default: puts ("hppa1.0"); break; - } - exit (0); - } + sed 's/^ //' << EOF >$dummy.c + + #define _HPUX_SOURCE + #include + #include + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } EOF (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac @@ -749,26 +729,26 @@ parisc*:Lites*:*:*) echo hppa1.1-hp-lites exit ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) echo c1-convex-bsd - exit ;; + exit ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi - exit ;; + exit ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) echo c34-convex-bsd - exit ;; + exit ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) echo c38-convex-bsd - exit ;; + exit ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) echo c4-convex-bsd - exit ;; + exit ;; CRAY*Y-MP:*:*:*) echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*[A-Z]90:*:*:*) echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ @@ -788,18 +768,18 @@ *:UNICOS/mp:*:*) echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` - FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` - FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` - echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" - exit ;; + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; 5000:UNIX_System_V:4.*:*) - FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` - FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` - echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` + echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} exit ;; sparc*:BSD/OS:*:*) @@ -807,39 +787,37 @@ exit ;; *:BSD/OS:*:*) echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} exit ;; *:FreeBSD:*:*) - UNAME_PROCESSOR=`/usr/bin/uname -p` - case ${UNAME_PROCESSOR} in + case ${UNAME_MACHINE} in + pc98) + echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; amd64) echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; *) - echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; esac exit ;; i*:CYGWIN*:*) echo ${UNAME_MACHINE}-pc-cygwin exit ;; - *:MINGW64*:*) - echo ${UNAME_MACHINE}-pc-mingw64 - exit ;; *:MINGW*:*) echo ${UNAME_MACHINE}-pc-mingw32 exit ;; - *:MSYS*:*) - echo ${UNAME_MACHINE}-pc-msys - exit ;; + i*:MSYS*:*) + echo ${UNAME_MACHINE}-pc-msys + exit ;; i*:windows32*:*) - # uname -m includes "-pc" on this system. - echo ${UNAME_MACHINE}-mingw32 + # uname -m includes "-pc" on this system. + echo ${UNAME_MACHINE}-mingw32 exit ;; i*:PW*:*) echo ${UNAME_MACHINE}-pc-pw32 exit ;; *:Interix*:*) - case ${UNAME_MACHINE} in + case ${UNAME_MACHINE} in x86) echo i586-pc-interix${UNAME_RELEASE} exit ;; authenticamd | genuineintel | EM64T) echo x86_64-unknown-interix${UNAME_RELEASE} @@ -872,85 +850,74 @@ prep*:SunOS:5.*:*) echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; *:GNU:*:*) # the GNU system - echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` exit ;; *:GNU/*:*:*) # other systems with GNU libc and userland - echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC} + echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu exit ;; i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-minix exit ;; - aarch64:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - exit ;; - aarch64_be:Linux:*:*) - UNAME_MACHINE=aarch64_be - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - exit ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; PCA57) UNAME_MACHINE=alphapca56 ;; EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; - esac + esac objdump --private-headers /bin/sh | grep -q ld.so.1 - if test "$?" = 0 ; then LIBC="gnulibc1" ; fi - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - exit ;; - arc:Linux:*:* | arceb:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi + echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} exit ;; arm*:Linux:*:*) eval $set_cc_for_build if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_EABI__ then - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - else - if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ - | grep -q __ARM_PCS_VFP - then - echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi - else - echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf - fi + echo ${UNAME_MACHINE}-unknown-linux-gnu + else + echo ${UNAME_MACHINE}-unknown-linux-gnueabi fi exit ;; avr32*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; cris:Linux:*:*) - echo ${UNAME_MACHINE}-axis-linux-${LIBC} + echo cris-axis-linux-gnu exit ;; crisv32:Linux:*:*) - echo ${UNAME_MACHINE}-axis-linux-${LIBC} + echo crisv32-axis-linux-gnu exit ;; frv:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - exit ;; - hexagon:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo frv-unknown-linux-gnu exit ;; i*86:Linux:*:*) - echo ${UNAME_MACHINE}-pc-linux-${LIBC} + LIBC=gnu + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #ifdef __dietlibc__ + LIBC=dietlibc + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'` + echo "${UNAME_MACHINE}-pc-linux-${LIBC}" exit ;; ia64:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; m32r*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; m68*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; mips:Linux:*:* | mips64:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU @@ -965,80 +932,71 @@ CPU= #endif #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` - test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; } + test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } ;; - openrisc*:Linux:*:*) - echo or1k-unknown-linux-${LIBC} - exit ;; - or32:Linux:*:* | or1k*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + or32:Linux:*:*) + echo or32-unknown-linux-gnu exit ;; padre:Linux:*:*) - echo sparc-unknown-linux-${LIBC} + echo sparc-unknown-linux-gnu exit ;; parisc64:Linux:*:* | hppa64:Linux:*:*) - echo hppa64-unknown-linux-${LIBC} + echo hppa64-unknown-linux-gnu exit ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in - PA7*) echo hppa1.1-unknown-linux-${LIBC} ;; - PA8*) echo hppa2.0-unknown-linux-${LIBC} ;; - *) echo hppa-unknown-linux-${LIBC} ;; + PA7*) echo hppa1.1-unknown-linux-gnu ;; + PA8*) echo hppa2.0-unknown-linux-gnu ;; + *) echo hppa-unknown-linux-gnu ;; esac exit ;; ppc64:Linux:*:*) - echo powerpc64-unknown-linux-${LIBC} + echo powerpc64-unknown-linux-gnu exit ;; ppc:Linux:*:*) - echo powerpc-unknown-linux-${LIBC} - exit ;; - ppc64le:Linux:*:*) - echo powerpc64le-unknown-linux-${LIBC} - exit ;; - ppcle:Linux:*:*) - echo powerpcle-unknown-linux-${LIBC} + echo powerpc-unknown-linux-gnu exit ;; s390:Linux:*:* | s390x:Linux:*:*) - echo ${UNAME_MACHINE}-ibm-linux-${LIBC} + echo ${UNAME_MACHINE}-ibm-linux exit ;; sh64*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; sh*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; sparc:Linux:*:* | sparc64:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; tile*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo ${UNAME_MACHINE}-tilera-linux-gnu exit ;; vax:Linux:*:*) - echo ${UNAME_MACHINE}-dec-linux-${LIBC} + echo ${UNAME_MACHINE}-dec-linux-gnu exit ;; x86_64:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo x86_64-unknown-linux-gnu exit ;; xtensa*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. echo i386-sequent-sysv4 exit ;; i*86:UNIX_SV:4.2MP:2.*) - # Unixware is an offshoot of SVR4, but it has its own version - # number series starting with 2... - # I am not positive that other SVR4 systems won't match this, + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. - # Use sysv4.2uw... so that sysv4* matches it. + # Use sysv4.2uw... so that sysv4* matches it. echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} exit ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. @@ -1066,11 +1024,11 @@ else echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} fi exit ;; i*86:*:5:[678]*) - # UnixWare 7.x, OpenUNIX and OpenServer 6. + # UnixWare 7.x, OpenUNIX and OpenServer 6. case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac @@ -1094,17 +1052,17 @@ echo ${UNAME_MACHINE}-pc-sysv32 fi exit ;; pc:*:*:*) # Left here for compatibility: - # uname -m prints for DJGPP always 'pc', but it prints nothing about - # the processor, so we play safe by assuming i586. + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i586. # Note: whatever this is, it MUST be the same as what config.sub # prints for the "djgpp" host, or else GDB configury will decide that # this is a cross-build. echo i586-pc-msdosdjgpp - exit ;; + exit ;; Intel:Mach:3*:*) echo i386-pc-mach3 exit ;; paragon:*:*:*) echo i860-intel-osf1 @@ -1135,12 +1093,12 @@ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) - /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ - && { echo i486-ncr-sysv4; exit; } ;; + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4; exit; } ;; NCR*:*:4.2:* | MPRAS*:*:4.2:*) OS_REL='.3' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ @@ -1179,14 +1137,14 @@ echo ${UNAME_MACHINE}-sni-sysv4 else echo ns32k-sni-sysv fi exit ;; - PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort - # says - echo i586-unisys-sysv4 - exit ;; + PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says + echo i586-unisys-sysv4 + exit ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm echo hppa1.1-stratus-sysv4 exit ;; @@ -1208,15 +1166,15 @@ news*:NEWS-OS:6*:*) echo mips-sony-newsos6 exit ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if [ -d /usr/nec ]; then - echo mips-nec-sysv${UNAME_RELEASE} + echo mips-nec-sysv${UNAME_RELEASE} else - echo mips-unknown-sysv${UNAME_RELEASE} + echo mips-unknown-sysv${UNAME_RELEASE} fi - exit ;; + exit ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. echo powerpc-be-beos exit ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. echo powerpc-apple-beos @@ -1225,13 +1183,10 @@ echo i586-pc-beos exit ;; BePC:Haiku:*:*) # Haiku running on Intel PC compatible. echo i586-pc-haiku exit ;; - x86_64:Haiku:*:*) - echo x86_64-unknown-haiku - exit ;; SX-4:SUPER-UX:*:*) echo sx4-nec-superux${UNAME_RELEASE} exit ;; SX-5:SUPER-UX:*:*) echo sx5-nec-superux${UNAME_RELEASE} @@ -1254,35 +1209,23 @@ *:Rhapsody:*:*) echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} exit ;; *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown - eval $set_cc_for_build - if test "$UNAME_PROCESSOR" = unknown ; then - UNAME_PROCESSOR=powerpc - fi - if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then - if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then - if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ - (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ - grep IS_64BIT_ARCH >/dev/null - then - case $UNAME_PROCESSOR in - i386) UNAME_PROCESSOR=x86_64 ;; - powerpc) UNAME_PROCESSOR=powerpc64 ;; - esac - fi - fi - elif test "$UNAME_PROCESSOR" = i386 ; then - # Avoid executing cc on OS X 10.9, as it ships with a stub - # that puts up a graphical alert prompting to install - # developer tools. Any system running Mac OS X 10.7 or - # later (Darwin 11 and later) is required to have a 64-bit - # processor. This is not true of the ARM version of Darwin - # that Apple uses in portable devices. - UNAME_PROCESSOR=x86_64 - fi + case $UNAME_PROCESSOR in + i386) + eval $set_cc_for_build + if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then + if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + UNAME_PROCESSOR="x86_64" + fi + fi ;; + unknown) UNAME_PROCESSOR=powerpc ;; + esac echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} exit ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = "x86"; then @@ -1295,11 +1238,11 @@ echo i386-pc-qnx exit ;; NEO-?:NONSTOP_KERNEL:*:*) echo neo-tandem-nsk${UNAME_RELEASE} exit ;; - NSE-*:NONSTOP_KERNEL:*:*) + NSE-?:NONSTOP_KERNEL:*:*) echo nse-tandem-nsk${UNAME_RELEASE} exit ;; NSR-?:NONSTOP_KERNEL:*:*) echo nsr-tandem-nsk${UNAME_RELEASE} exit ;; @@ -1340,17 +1283,17 @@ exit ;; *:ITS:*:*) echo pdp10-unknown-its exit ;; SEI:*:*:SEIUX) - echo mips-sei-seiux${UNAME_RELEASE} + echo mips-sei-seiux${UNAME_RELEASE} exit ;; *:DragonFly:*:*) echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` exit ;; *:*VMS:*:*) - UNAME_MACHINE=`(uname -p) 2>/dev/null` + UNAME_MACHINE=`(uname -p) 2>/dev/null` case "${UNAME_MACHINE}" in A*) echo alpha-dec-vms ; exit ;; I*) echo ia64-dec-vms ; exit ;; V*) echo vax-dec-vms ; exit ;; esac ;; @@ -1364,14 +1307,162 @@ echo ${UNAME_MACHINE}-pc-rdos exit ;; i*86:AROS:*:*) echo ${UNAME_MACHINE}-pc-aros exit ;; - x86_64:VMkernel:*:*) - echo ${UNAME_MACHINE}-unknown-esx - exit ;; esac + +#echo '(No uname command or uname output not recognized.)' 1>&2 +#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 + +eval $set_cc_for_build +cat >$dummy.c < +# include +#endif +main () +{ +#if defined (sony) +#if defined (MIPSEB) + /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, + I don't know.... */ + printf ("mips-sony-bsd\n"); exit (0); +#else +#include + printf ("m68k-sony-newsos%s\n", +#ifdef NEWSOS4 + "4" +#else + "" +#endif + ); exit (0); +#endif +#endif + +#if defined (__arm) && defined (__acorn) && defined (__unix) + printf ("arm-acorn-riscix\n"); exit (0); +#endif + +#if defined (hp300) && !defined (hpux) + printf ("m68k-hp-bsd\n"); exit (0); +#endif + +#if defined (NeXT) +#if !defined (__ARCHITECTURE__) +#define __ARCHITECTURE__ "m68k" +#endif + int version; + version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; + if (version < 4) + printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); + else + printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); + exit (0); +#endif + +#if defined (MULTIMAX) || defined (n16) +#if defined (UMAXV) + printf ("ns32k-encore-sysv\n"); exit (0); +#else +#if defined (CMU) + printf ("ns32k-encore-mach\n"); exit (0); +#else + printf ("ns32k-encore-bsd\n"); exit (0); +#endif +#endif +#endif + +#if defined (__386BSD__) + printf ("i386-pc-bsd\n"); exit (0); +#endif + +#if defined (sequent) +#if defined (i386) + printf ("i386-sequent-dynix\n"); exit (0); +#endif +#if defined (ns32000) + printf ("ns32k-sequent-dynix\n"); exit (0); +#endif +#endif + +#if defined (_SEQUENT_) + struct utsname un; + + uname(&un); + + if (strncmp(un.version, "V2", 2) == 0) { + printf ("i386-sequent-ptx2\n"); exit (0); + } + if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ + printf ("i386-sequent-ptx1\n"); exit (0); + } + printf ("i386-sequent-ptx\n"); exit (0); + +#endif + +#if defined (vax) +# if !defined (ultrix) +# include +# if defined (BSD) +# if BSD == 43 + printf ("vax-dec-bsd4.3\n"); exit (0); +# else +# if BSD == 199006 + printf ("vax-dec-bsd4.3reno\n"); exit (0); +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# endif +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# else + printf ("vax-dec-ultrix\n"); exit (0); +# endif +#endif + +#if defined (alliant) && defined (i860) + printf ("i860-alliant-bsd\n"); exit (0); +#endif + + exit (1); +} +EOF + +$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + +# Apollos put the system type in the environment. + +test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } + +# Convex versions that predate uname can use getsysinfo(1) + +if [ -x /usr/convex/getsysinfo ] +then + case `getsysinfo -f cpu_type` in + c1*) + echo c1-convex-bsd + exit ;; + c2*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + c34*) + echo c34-convex-bsd + exit ;; + c38*) + echo c38-convex-bsd + exit ;; + c4*) + echo c4-convex-bsd + exit ;; + esac +fi cat >&2 <. +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA +# 02110-1301, USA. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under -# the same distribution terms that you use for the rest of that -# program. This Exception is an additional permission under section 7 -# of the GNU General Public License, version 3 ("GPLv3"). +# the same distribution terms that you use for the rest of that program. -# Please send patches with a ChangeLog entry to config-patches@gnu.org. +# Please send patches to . Submit a context +# diff and a properly formatted GNU ChangeLog entry. # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # Otherwise, we print the canonical config type on stdout and succeed. @@ -66,11 +73,13 @@ Report bugs and patches to ." version="\ GNU config.sub ($timestamp) -Copyright 1992-2014 Free Software Foundation, Inc. +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, +2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free +Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" @@ -114,21 +123,17 @@ # Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). # Here we must recognize all the valid KERNEL-OS combinations. maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ - linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ + linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ knetbsd*-gnu* | netbsd*-gnu* | \ kopensolaris*-gnu* | \ storm-chaos* | os2-emx* | rtmk-nova*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` ;; - android-linux) - os=-linux-android - basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown - ;; *) basic_machine=`echo $1 | sed 's/-[^-]*$//'` if [ $basic_machine != $1 ] then os=`echo $1 | sed 's/.*-/-/'` else os=; fi @@ -147,16 +152,16 @@ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ - -apple | -axis | -knuth | -cray | -microblaze*) + -apple | -axis | -knuth | -cray | -microblaze) os= basic_machine=$1 ;; - -bluegene*) - os=-cnk + -bluegene*) + os=-cnk ;; -sim | -cisco | -oki | -wec | -winbond) os= basic_machine=$1 ;; @@ -168,14 +173,14 @@ ;; -chorusos*) os=-chorusos basic_machine=$1 ;; - -chorusrdb) - os=-chorusrdb + -chorusrdb) + os=-chorusrdb basic_machine=$1 - ;; + ;; -hiux*) os=-hiuxwe2 ;; -sco6) os=-sco5v6 @@ -216,16 +221,10 @@ basic_machine=clipper-intergraph ;; -isc*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; - -lynx*178) - os=-lynxos178 - ;; - -lynx*5) - os=-lynxos5 - ;; -lynx*) os=-lynxos ;; -ptx*) basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` @@ -246,32 +245,24 @@ case $basic_machine in # Recognize the basic CPU types without company name. # Some are omitted here because they have special meanings below. 1750a | 580 \ | a29k \ - | aarch64 | aarch64_be \ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ | am33_2.0 \ - | arc | arceb \ - | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \ - | avr | avr32 \ - | be32 | be64 \ + | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \ | bfin \ - | c4x | c8051 | clipper \ + | c4x | clipper \ | d10v | d30v | dlx | dsp16xx \ - | epiphany \ | fido | fr30 | frv \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ - | hexagon \ | i370 | i860 | i960 | ia64 \ | ip2k | iq2000 \ - | k1om \ - | le32 | le64 \ | lm32 \ | m32c | m32r | m32rle | m68000 | m68k | m88k \ - | maxq | mb | microblaze | microblazeel | mcore | mep | metag \ + | maxq | mb | microblaze | mcore | mep | metag \ | mips | mipsbe | mipseb | mipsel | mipsle \ | mips16 \ | mips64 | mips64el \ | mips64octeon | mips64octeonel \ | mips64orion | mips64orionel \ @@ -281,41 +272,38 @@ | mips64vr4300 | mips64vr4300el \ | mips64vr5000 | mips64vr5000el \ | mips64vr5900 | mips64vr5900el \ | mipsisa32 | mipsisa32el \ | mipsisa32r2 | mipsisa32r2el \ - | mipsisa32r6 | mipsisa32r6el \ | mipsisa64 | mipsisa64el \ | mipsisa64r2 | mipsisa64r2el \ - | mipsisa64r6 | mipsisa64r6el \ | mipsisa64sb1 | mipsisa64sb1el \ | mipsisa64sr71k | mipsisa64sr71kel \ - | mipsr5900 | mipsr5900el \ | mipstx39 | mipstx39el \ | mn10200 | mn10300 \ | moxie \ | mt \ | msp430 \ | nds32 | nds32le | nds32be \ - | nios | nios2 | nios2eb | nios2el \ + | nios | nios2 \ | ns16k | ns32k \ - | open8 | or1k | or1knd | or32 \ + | or32 \ | pdp10 | pdp11 | pj | pjl \ - | powerpc | powerpc64 | powerpc64le | powerpcle \ + | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ | pyramid \ - | rl78 | rx \ + | rx \ | score \ | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ | sh64 | sh64le \ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ - | spu \ - | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ + | spu | strongarm \ + | tahoe | thumb | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ | ubicom32 \ - | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ + | v850 | v850e \ | we32k \ - | x86 | xc16x | xstormy16 | xtensa \ + | x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \ | z8k | z80) basic_machine=$basic_machine-unknown ;; c54x) basic_machine=tic54x-unknown @@ -324,35 +312,21 @@ basic_machine=tic55x-unknown ;; c6x) basic_machine=tic6x-unknown ;; - m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip) + m6811 | m68hc11 | m6812 | m68hc12 | picochip) + # Motorola 68HC11/12. basic_machine=$basic_machine-unknown os=-none ;; m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) ;; ms1) basic_machine=mt-unknown ;; - strongarm | thumb | xscale) - basic_machine=arm-unknown - ;; - xgate) - basic_machine=$basic_machine-unknown - os=-none - ;; - xscaleeb) - basic_machine=armeb-unknown - ;; - - xscaleel) - basic_machine=armel-unknown - ;; - # We use `pc' rather than `unknown' # because (1) that's what they normally are, and # (2) the word "unknown" tends to confuse beginning users. i*86 | x86_64) basic_machine=$basic_machine-pc @@ -363,35 +337,29 @@ exit 1 ;; # Recognize the basic CPU types with company name. 580-* \ | a29k-* \ - | aarch64-* | aarch64_be-* \ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ - | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \ + | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | avr-* | avr32-* \ - | be32-* | be64-* \ | bfin-* | bs2000-* \ | c[123]* | c30-* | [cjt]90-* | c4x-* \ - | c8051-* | clipper-* | craynv-* | cydra-* \ + | clipper-* | craynv-* | cydra-* \ | d10v-* | d30v-* | dlx-* \ | elxsi-* \ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ - | hexagon-* \ | i*86-* | i860-* | i960-* | ia64-* \ | ip2k-* | iq2000-* \ - | k1om-* \ - | le32-* | le64-* \ | lm32-* \ | m32c-* | m32r-* | m32rle-* \ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ - | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \ - | microblaze-* | microblazeel-* \ + | m88110-* | m88k-* | maxq-* | mcore-* | metag-* | microblaze-* \ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ | mips16-* \ | mips64-* | mips64el-* \ | mips64octeon-* | mips64octeonel-* \ | mips64orion-* | mips64orionel-* \ @@ -401,45 +369,39 @@ | mips64vr4300-* | mips64vr4300el-* \ | mips64vr5000-* | mips64vr5000el-* \ | mips64vr5900-* | mips64vr5900el-* \ | mipsisa32-* | mipsisa32el-* \ | mipsisa32r2-* | mipsisa32r2el-* \ - | mipsisa32r6-* | mipsisa32r6el-* \ | mipsisa64-* | mipsisa64el-* \ | mipsisa64r2-* | mipsisa64r2el-* \ - | mipsisa64r6-* | mipsisa64r6el-* \ | mipsisa64sb1-* | mipsisa64sb1el-* \ | mipsisa64sr71k-* | mipsisa64sr71kel-* \ - | mipsr5900-* | mipsr5900el-* \ | mipstx39-* | mipstx39el-* \ | mmix-* \ | mt-* \ | msp430-* \ | nds32-* | nds32le-* | nds32be-* \ - | nios-* | nios2-* | nios2eb-* | nios2el-* \ + | nios-* | nios2-* \ | none-* | np1-* | ns16k-* | ns32k-* \ - | open8-* \ - | or1k*-* \ | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ - | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ + | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ | pyramid-* \ - | rl78-* | romp-* | rs6000-* | rx-* \ + | romp-* | rs6000-* | rx-* \ | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ | sparclite-* \ - | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \ - | tahoe-* \ + | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \ + | tahoe-* | thumb-* \ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ - | tile*-* \ + | tile-* | tilegx-* \ | tron-* \ | ubicom32-* \ - | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ - | vax-* \ + | v850-* | v850e-* | vax-* \ | we32k-* \ - | x86-* | x86_64-* | xc16x-* | xps100-* \ + | x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \ | xstormy16-* | xtensa*-* \ | ymp-* \ | z8k-* | z80-*) ;; # Recognize the basic CPU types without company name, with glob match. @@ -460,11 +422,11 @@ ;; a29khif) basic_machine=a29k-amd os=-udi ;; - abacus) + abacus) basic_machine=abacus-unknown ;; adobe68k) basic_machine=m68010-adobe os=-scout @@ -543,11 +505,11 @@ ;; c90) basic_machine=c90-cray os=-unicos ;; - cegcc) + cegcc) basic_machine=arm-unknown os=-cegcc ;; convex-c1) basic_machine=c1-convex @@ -575,11 +537,11 @@ ;; craynv) basic_machine=craynv-cray os=-unicosmp ;; - cr16 | cr16-*) + cr16) basic_machine=cr16-unknown os=-elf ;; crds | unos) basic_machine=m68k-crds @@ -733,10 +695,11 @@ os=-proelf ;; i370-ibm* | ibm*) basic_machine=i370-ibm ;; +# I'm not sure what "Sysv32" means. Should this be sysv3.2? i*86v32) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv32 ;; i*86v4*) @@ -790,19 +753,15 @@ ;; merlin) basic_machine=ns32k-utek os=-sysv ;; - microblaze*) + microblaze) basic_machine=microblaze-xilinx ;; - mingw64) - basic_machine=x86_64-pc - os=-mingw64 - ;; mingw32) - basic_machine=i686-pc + basic_machine=i386-pc os=-mingw32 ;; mingw32ce) basic_machine=arm-unknown os=-mingw32ce @@ -833,22 +792,18 @@ os=-msdos ;; ms1-*) basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` ;; - msys) - basic_machine=i686-pc - os=-msys - ;; mvs) basic_machine=i370-ibm os=-mvs ;; - nacl) - basic_machine=le32-unknown - os=-nacl - ;; + msys) + basic_machine=i386-pc + os=-msys + ;; ncr3000) basic_machine=i486-ncr os=-sysv4 ;; netbsd386) @@ -909,14 +864,14 @@ os=-nonstopux ;; np1) basic_machine=np1-gould ;; - neo-tandem) + neo-tandem) basic_machine=neo-tandem ;; - nse-tandem) + nse-tandem) basic_machine=nse-tandem ;; nsr-tandem) basic_machine=nsr-tandem ;; @@ -997,14 +952,13 @@ pn) basic_machine=pn-gould ;; power) basic_machine=power-ibm ;; - ppc | ppcbe) basic_machine=powerpc-unknown + ppc) basic_machine=powerpc-unknown ;; - ppc-* | ppcbe-*) - basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppcle | powerpclittle | ppc-le | powerpc-little) basic_machine=powerpcle-unknown ;; ppcle-* | powerpclittle-*) @@ -1025,15 +979,11 @@ ;; pw32) basic_machine=i586-unknown os=-pw32 ;; - rdos | rdos64) - basic_machine=x86_64-pc - os=-rdos - ;; - rdos32) + rdos) basic_machine=i386-pc os=-rdos ;; rom68k) basic_machine=m68k-rom68k @@ -1098,13 +1048,10 @@ ;; stratus) basic_machine=i860-stratus os=-sysv4 ;; - strongarm-* | thumb-*) - basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; sun2) basic_machine=m68000-sun ;; sun2os3) basic_machine=m68000-sun @@ -1157,12 +1104,17 @@ ;; t90) basic_machine=t90-cray os=-unicos ;; + # This must be matched before tile*. + tilegx*) + basic_machine=tilegx-unknown + os=-linux-gnu + ;; tile*) - basic_machine=$basic_machine-unknown + basic_machine=tile-unknown os=-linux-gnu ;; tx39) basic_machine=mipstx39-unknown ;; @@ -1228,13 +1180,10 @@ os=-mingw32 ;; xps | xps100) basic_machine=xps100-honeywell ;; - xscale-* | xscalee[bl]-*) - basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'` - ;; ymp) basic_machine=ymp-cray os=-unicos ;; z8k-*-coff) @@ -1328,15 +1277,15 @@ # Decode manufacturer-specific aliases for certain operating systems. if [ x"$os" != x"" ] then case $os in - # First match some system type aliases - # that might get confused with valid system types. + # First match some system type aliases + # that might get confused with valid system types. # -solaris* is a basic system type, with this one exception. - -auroraux) - os=-auroraux + -auroraux) + os=-auroraux ;; -solaris1 | -solaris1.*) os=`echo $os | sed -e 's|solaris1|sunos4|'` ;; -solaris) @@ -1356,33 +1305,33 @@ # Each alternative MUST END IN A *, to match a version number. # -sysv* is not here because it comes later, after sysvr4. -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ - | -sym* | -kopensolaris* | -plan9* \ + | -sym* | -kopensolaris* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ | -aos* | -aros* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ - | -bitrig* | -openbsd* | -solidbsd* \ + | -openbsd* | -solidbsd* \ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -chorusos* | -chorusrdb* | -cegcc* \ | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ - | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ - | -linux-newlib* | -linux-musl* | -linux-uclibc* \ + | -mingw32* | -linux-gnu* | -linux-android* \ + | -linux-newlib* | -linux-uclibc* \ | -uxpv* | -beos* | -mpeix* | -udk* \ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ - | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* | -tirtos*) + | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) case $basic_machine in x86-* | i*86-*) @@ -1417,11 +1366,11 @@ os=`echo $os | sed -e 's|sunos6|solaris3|'` ;; -opened*) os=-openedition ;; - -os400*) + -os400*) os=-os400 ;; -wince*) os=-wince ;; @@ -1466,11 +1415,11 @@ os=`echo $os | sed -e 's|sinix|sysv|'` ;; -sinix*) os=-sysv4 ;; - -tpf*) + -tpf*) os=-tpf ;; -triton*) os=-sysv3 ;; @@ -1502,18 +1451,21 @@ os=-mint ;; -aros*) os=-aros ;; + -kaos*) + os=-kaos + ;; -zvmoe) os=-zvmoe ;; -dicos*) os=-dicos ;; - -nacl*) - ;; + -nacl*) + ;; -none) ;; *) # Get rid of the `-' at the beginning of $os. os=`echo $os | sed 's/[^-]*-//'` @@ -1532,14 +1484,14 @@ # that MANUFACTURER isn't an operating system. Otherwise, code above # will signal an error saying that MANUFACTURER isn't an operating # system, and we'll never get to this point. case $basic_machine in - score-*) + score-*) os=-elf ;; - spu-*) + spu-*) os=-elf ;; *-acorn) os=-riscix1.2 ;; @@ -1547,18 +1499,12 @@ os=-linux ;; arm*-semi) os=-aout ;; - c4x-* | tic4x-*) - os=-coff - ;; - c8051-*) - os=-elf - ;; - hexagon-*) - os=-elf + c4x-* | tic4x-*) + os=-coff ;; tic54x-*) os=-coff ;; tic55x-*) @@ -1583,15 +1529,18 @@ i386-sun) os=-sunos4.0.2 ;; m68000-sun) os=-sunos3 + # This also exists in the configure program, but was not the + # default. + # os=-sunos4 ;; m68*-cisco) os=-aout ;; - mep-*) + mep-*) os=-elf ;; mips*-cisco) os=-elf ;; @@ -1614,11 +1563,11 @@ os=-haiku ;; *-ibm) os=-aix ;; - *-knuth) + *-knuth) os=-mmixware ;; *-wec) os=-proelf ;; Index: autosetup/jimsh0.c ================================================================== --- autosetup/jimsh0.c +++ autosetup/jimsh0.c @@ -1,6 +1,6 @@ -/* This is single source file, bootstrap version of Jim Tcl. See http://jim.tcl.tk/ */ +/* This is single source file, bootstrap version of Jim Tcl. See http://jim.berlios.de/ */ #define _GNU_SOURCE #define JIM_TCL_COMPAT #define JIM_REFERENCES #define JIM_ANSIC #define JIM_REGEXP @@ -38,26 +38,19 @@ #define TCL_PLATFORM_PLATFORM "unix" #define TCL_PLATFORM_PATH_SEPARATOR ":" #define HAVE_VFORK #define HAVE_WAITPID #define HAVE_ISATTY -#define HAVE_MKSTEMP -#define HAVE_LINK #define HAVE_SYS_TIME_H #define HAVE_DIRENT_H #define HAVE_UNISTD_H #endif -#define JIM_VERSION 76 #ifndef JIM_WIN32COMPAT_H #define JIM_WIN32COMPAT_H -#ifdef __cplusplus -extern "C" { -#endif - #if defined(_WIN32) || defined(WIN32) #define HAVE_DLOPEN void *dlopen(const char *path, int mode); @@ -112,32 +105,17 @@ } DIR; DIR *opendir(const char *name); int closedir(DIR *dir); struct dirent *readdir(DIR *dir); - -#elif defined(__MINGW32__) - -#include -#define strtod __strtod - -#endif - #endif -#ifdef __cplusplus -} -#endif +#endif #endif #ifndef UTF8_UTIL_H #define UTF8_UTIL_H - -#ifdef __cplusplus -extern "C" { -#endif - #define MAX_UTF8_LEN 4 int utf8_fromunicode(char *p, unsigned uc); @@ -146,24 +124,19 @@ #include #define utf8_strlen(S, B) ((B) < 0 ? strlen(S) : (B)) #define utf8_tounicode(S, CP) (*(CP) = (unsigned char)*(S), 1) -#define utf8_getchars(CP, C) (*(CP) = (C), 1) #define utf8_upper(C) toupper(C) #define utf8_title(C) toupper(C) #define utf8_lower(C) tolower(C) #define utf8_index(C, I) (I) #define utf8_charlen(C) 1 #define utf8_prev_len(S, L) 1 #else -#endif - -#ifdef __cplusplus -} #endif #endif #ifndef __JIM__H @@ -212,10 +185,12 @@ #endif #define UCHAR(c) ((unsigned char)(c)) +#define JIM_VERSION 74 + #define JIM_OK 0 #define JIM_ERR 1 #define JIM_RETURN 2 #define JIM_BREAK 3 #define JIM_CONTINUE 4 @@ -225,34 +200,44 @@ #define JIM_EVAL 7 #define JIM_MAX_CALLFRAME_DEPTH 1000 #define JIM_MAX_EVAL_DEPTH 2000 - -#define JIM_PRIV_FLAG_SHIFT 20 - -#define JIM_NONE 0 -#define JIM_ERRMSG 1 -#define JIM_ENUM_ABBREV 2 -#define JIM_UNSHARED 4 -#define JIM_MUSTEXIST 8 +#define JIM_NONE 0 +#define JIM_ERRMSG 1 + +#define JIM_UNSHARED 4 +#define JIM_MUSTEXIST 8 + + +#define JIM_GLOBAL_ONLY 0x100 #define JIM_SUBST_NOVAR 1 #define JIM_SUBST_NOCMD 2 #define JIM_SUBST_NOESC 4 #define JIM_SUBST_FLAG 128 + +#define JIM_NOTUSED(V) ((void) V) + + +#define JIM_ENUM_ABBREV 2 + #define JIM_CASESENS 0 #define JIM_NOCASE 1 #define JIM_PATH_LEN 1024 -#define JIM_NOTUSED(V) ((void) V) +#ifdef JIM_CRLF +#define JIM_NL "\r\n" +#else +#define JIM_NL "\n" +#endif #define JIM_LIBPATH "auto_path" #define JIM_INTERACTIVE "tcl_interactive" @@ -282,22 +267,21 @@ } Jim_HashTableType; typedef struct Jim_HashTable { Jim_HashEntry **table; const Jim_HashTableType *type; - void *privdata; unsigned int size; unsigned int sizemask; unsigned int used; unsigned int collisions; - unsigned int uniq; + void *privdata; } Jim_HashTable; typedef struct Jim_HashTableIterator { Jim_HashTable *ht; - Jim_HashEntry *entry, *nextEntry; int index; + Jim_HashEntry *entry, *nextEntry; } Jim_HashTableIterator; #define JIM_HT_INITIAL_SIZE 16 @@ -306,35 +290,35 @@ if ((ht)->type->valDestructor) \ (ht)->type->valDestructor((ht)->privdata, (entry)->u.val) #define Jim_SetHashVal(ht, entry, _val_) do { \ if ((ht)->type->valDup) \ - (entry)->u.val = (ht)->type->valDup((ht)->privdata, (_val_)); \ + entry->u.val = (ht)->type->valDup((ht)->privdata, _val_); \ else \ - (entry)->u.val = (_val_); \ + entry->u.val = (_val_); \ } while(0) #define Jim_FreeEntryKey(ht, entry) \ if ((ht)->type->keyDestructor) \ (ht)->type->keyDestructor((ht)->privdata, (entry)->key) #define Jim_SetHashKey(ht, entry, _key_) do { \ if ((ht)->type->keyDup) \ - (entry)->key = (ht)->type->keyDup((ht)->privdata, (_key_)); \ + entry->key = (ht)->type->keyDup((ht)->privdata, _key_); \ else \ - (entry)->key = (void *)(_key_); \ + entry->key = (void *)(_key_); \ } while(0) #define Jim_CompareHashKeys(ht, key1, key2) \ (((ht)->type->keyCompare) ? \ - (ht)->type->keyCompare((ht)->privdata, (key1), (key2)) : \ + (ht)->type->keyCompare((ht)->privdata, key1, key2) : \ (key1) == (key2)) -#define Jim_HashKey(ht, key) ((ht)->type->hashFunction(key) + (ht)->uniq) +#define Jim_HashKey(ht, key) (ht)->type->hashFunction(key) #define Jim_GetHashEntryKey(he) ((he)->key) -#define Jim_GetHashEntryVal(he) ((he)->u.val) +#define Jim_GetHashEntryVal(he) ((he)->val) #define Jim_GetHashTableCollisions(ht) ((ht)->collisions) #define Jim_GetHashTableSize(ht) ((ht)->size) #define Jim_GetHashTableUsed(ht) ((ht)->used) @@ -358,19 +342,19 @@ void *ptr1; void *ptr2; } twoPtrValue; struct { - struct Jim_Var *varPtr; unsigned long callFrameId; + struct Jim_Var *varPtr; int global; } varValue; struct { + unsigned long procEpoch; struct Jim_Obj *nsObj; struct Jim_Cmd *cmdPtr; - unsigned long procEpoch; } cmdValue; struct { struct Jim_Obj **ele; int len; @@ -396,12 +380,12 @@ struct Jim_Obj *varNameObjPtr; struct Jim_Obj *indexObjPtr; } dictSubstValue; struct { - void *compre; unsigned flags; + void *compre; } regexpValue; struct { int line; int argc; } scriptLineValue; @@ -470,24 +454,21 @@ struct Jim_CallFrame *next; Jim_Obj *nsObj; Jim_Obj *fileNameObj; int line; Jim_Stack *localCommands; - int tailcall; - struct Jim_Obj *tailcallObj; - struct Jim_Cmd *tailcallCmd; } Jim_CallFrame; typedef struct Jim_Var { Jim_Obj *objPtr; struct Jim_CallFrame *linkFramePtr; } Jim_Var; -typedef int Jim_CmdProc(struct Jim_Interp *interp, int argc, +typedef int (*Jim_CmdProc)(struct Jim_Interp *interp, int argc, Jim_Obj *const *argv); -typedef void Jim_DelCmdProc(struct Jim_Interp *interp, void *privData); +typedef void (*Jim_DelCmdProc)(struct Jim_Interp *interp, void *privData); typedef struct Jim_Cmd { int inUse; @@ -494,12 +475,12 @@ int isproc; struct Jim_Cmd *prevCmd; union { struct { - Jim_CmdProc *cmdProc; - Jim_DelCmdProc *delProc; + Jim_CmdProc cmdProc; + Jim_DelCmdProc delProc; void *privData; } native; struct { Jim_Obj *argListObjPtr; @@ -608,12 +589,16 @@ Jim_Obj *objPtr; Jim_Obj *finalizerCmdNamePtr; char tag[JIM_REFERENCE_TAGLEN+1]; } Jim_Reference; + #define Jim_NewEmptyStringObj(i) Jim_NewStringObj(i, "", 0) + + + #define Jim_FreeHashTableIterator(iter) Jim_Free(iter) #define JIM_EXPORT @@ -624,11 +609,10 @@ JIM_EXPORT char *Jim_StrDupLen(const char *s, int l); JIM_EXPORT char **Jim_GetEnviron(void); JIM_EXPORT void Jim_SetEnviron(char **env); -JIM_EXPORT int Jim_MakeTempFile(Jim_Interp *interp, const char *template); JIM_EXPORT int Jim_Eval(Jim_Interp *interp, const char *script); @@ -756,12 +740,13 @@ JIM_EXPORT int Jim_SetVariableStrWithStr (Jim_Interp *interp, const char *name, const char *val); JIM_EXPORT int Jim_SetVariableLink (Jim_Interp *interp, Jim_Obj *nameObjPtr, Jim_Obj *targetNameObjPtr, Jim_CallFrame *targetCallFrame); -JIM_EXPORT Jim_Obj * Jim_MakeGlobalNamespaceName(Jim_Interp *interp, - Jim_Obj *nameObjPtr); +JIM_EXPORT int Jim_CreateNamespaceVariable(Jim_Interp *interp, + Jim_Obj *varNameObj, Jim_Obj *targetNameObj); +JIM_EXPORT int Jim_DiscardNamespaceVars(Jim_Interp *interp); JIM_EXPORT Jim_Obj * Jim_GetVariable (Jim_Interp *interp, Jim_Obj *nameObjPtr, int flags); JIM_EXPORT Jim_Obj * Jim_GetGlobalVariable (Jim_Interp *interp, Jim_Obj *nameObjPtr, int flags); JIM_EXPORT Jim_Obj * Jim_GetVariableStr (Jim_Interp *interp, @@ -820,11 +805,10 @@ JIM_EXPORT int Jim_DictAddElement(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *keyObjPtr, Jim_Obj *valueObjPtr); JIM_EXPORT int Jim_DictKeys(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *patternObj); JIM_EXPORT int Jim_DictValues(Jim_Interp *interp, Jim_Obj *dictObjPtr, Jim_Obj *patternObjPtr); JIM_EXPORT int Jim_DictSize(Jim_Interp *interp, Jim_Obj *objPtr); -JIM_EXPORT int Jim_DictInfo(Jim_Interp *interp, Jim_Obj *objPtr); JIM_EXPORT int Jim_GetReturnCode (Jim_Interp *interp, Jim_Obj *objPtr, int *intPtr); @@ -848,10 +832,16 @@ double *doublePtr); JIM_EXPORT void Jim_SetDouble(Jim_Interp *interp, Jim_Obj *objPtr, double doubleValue); JIM_EXPORT Jim_Obj * Jim_NewDoubleObj(Jim_Interp *interp, double doubleValue); + +JIM_EXPORT const char * Jim_GetSharedString (Jim_Interp *interp, + const char *str); +JIM_EXPORT void Jim_ReleaseSharedString (Jim_Interp *interp, + const char *str); + JIM_EXPORT void Jim_WrongNumArgs (Jim_Interp *interp, int argc, Jim_Obj *const *argv, const char *msg); JIM_EXPORT int Jim_GetEnum (Jim_Interp *interp, Jim_Obj *objPtr, const char * const *tablePtr, int *indexPtr, const char *name, int flags); @@ -885,20 +875,20 @@ JIM_EXPORT void Jim_HistoryShow(void); JIM_EXPORT int Jim_InitStaticExtensions(Jim_Interp *interp); JIM_EXPORT int Jim_StringToWide(const char *str, jim_wide *widePtr, int base); -JIM_EXPORT int Jim_IsBigEndian(void); - +JIM_EXPORT int Jim_CheckSignal(Jim_Interp *interp); #define Jim_CheckSignal(i) ((i)->signal_level && (i)->sigmask) JIM_EXPORT int Jim_LoadLibrary(Jim_Interp *interp, const char *pathName); JIM_EXPORT void Jim_FreeLoadHandles(Jim_Interp *interp); JIM_EXPORT FILE *Jim_AioFilehandle(Jim_Interp *interp, Jim_Obj *command); + JIM_EXPORT int Jim_IsDict(Jim_Obj *objPtr); JIM_EXPORT int Jim_IsList(Jim_Obj *objPtr); @@ -920,16 +910,16 @@ #define JIM_MODFLAG_HIDDEN 0x0001 #define JIM_MODFLAG_FULLARGV 0x0002 -typedef int jim_subcmd_function(Jim_Interp *interp, int argc, Jim_Obj *const *argv); +typedef int tclmod_cmd_function(Jim_Interp *interp, int argc, Jim_Obj *const *argv); typedef struct { const char *cmd; const char *args; - jim_subcmd_function *function; + tclmod_cmd_function *function; short minargs; short maxargs; unsigned short flags; } jim_subcmd_type; @@ -946,16 +936,22 @@ #endif #ifndef JIMREGEXP_H #define JIMREGEXP_H +#ifndef _JIMAUTOCONF_H +#error Need jimautoconf.h +#endif -#ifdef __cplusplus -extern "C" { -#endif +#if defined(HAVE_REGCOMP) && !defined(JIM_REGEXP) + +#include + +#else #include + typedef struct { int rm_so; int rm_eo; } regmatch_t; @@ -1024,12 +1020,10 @@ int regcomp(regex_t *preg, const char *regex, int cflags); int regexec(regex_t *preg, const char *string, size_t nmatch, regmatch_t pmatch[], int eflags); size_t regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size); void regfree(regex_t *preg); -#ifdef __cplusplus -} #endif #endif int Jim_bootstrapInit(Jim_Interp *interp) { @@ -1051,48 +1045,29 @@ "\n" "\n" "\n" "proc _jimsh_init {} {\n" " rename _jimsh_init {}\n" -" global jim::exe jim::argv0 tcl_interactive auto_path tcl_platform\n" -"\n" -"\n" -" if {[exists jim::argv0]} {\n" -" if {[string match \"*/*\" $jim::argv0]} {\n" -" set jim::exe [file join [pwd] $jim::argv0]\n" -" } else {\n" -" foreach path [split [env PATH \"\"] $tcl_platform(pathSeparator)] {\n" -" set exec [file join [pwd] [string map {\\\\ /} $path] $jim::argv0]\n" -" if {[file executable $exec]} {\n" -" set jim::exe $exec\n" -" break\n" -" }\n" -" }\n" -" }\n" -" }\n" -"\n" -"\n" -" lappend p {*}[split [env JIMLIB {}] $tcl_platform(pathSeparator)]\n" -" if {[exists jim::exe]} {\n" -" lappend p [file dirname $jim::exe]\n" -" }\n" -" lappend p {*}$auto_path\n" -" set auto_path $p\n" -"\n" -" if {$tcl_interactive && [env HOME {}] ne \"\"} {\n" +"\n" +"\n" +" lappend p {*}[split [env JIMLIB {}] $::tcl_platform(pathSeparator)]\n" +" lappend p {*}$::auto_path\n" +" lappend p [file dirname [info nameofexecutable]]\n" +" set ::auto_path $p\n" +"\n" +" if {$::tcl_interactive && [env HOME {}] ne \"\"} {\n" " foreach src {.jimrc jimrc.tcl} {\n" " if {[file exists [env HOME]/$src]} {\n" " uplevel #0 source [env HOME]/$src\n" " break\n" " }\n" " }\n" " }\n" -" return \"\"\n" "}\n" "\n" "if {$tcl_platform(platform) eq \"windows\"} {\n" -" set jim::argv0 [string map {\\\\ /} $jim::argv0]\n" +" set jim_argv0 [string map {\\\\ /} $jim_argv0]\n" "}\n" "\n" "_jimsh_init\n" ); } @@ -1111,15 +1086,10 @@ "\n" "package require readdir\n" "\n" "\n" "proc glob.globdir {dir pattern} {\n" -" if {[file exists $dir/$pattern]} {\n" -"\n" -" return [list $pattern]\n" -" }\n" -"\n" " set result {}\n" " set files [readdir $dir]\n" " lappend files . ..\n" "\n" " foreach name $files {\n" @@ -1175,11 +1145,11 @@ " }\n" "\n" " foreach old $oldexp {\n" " lappend newexp $old$suf\n" " }\n" -" list $rest {*}$newexp\n" +" linsert $newexp 0 $rest\n" "}\n" "\n" "\n" "\n" "proc glob.glob {base pattern} {\n" @@ -1222,11 +1192,10 @@ "\n" "\n" "proc glob {args} {\n" " set nocomplain 0\n" " set base \"\"\n" -" set tails 0\n" "\n" " set n 0\n" " foreach arg $args {\n" " if {[info exists param]} {\n" " set $param $arg\n" @@ -1240,20 +1209,21 @@ " set param base\n" " }\n" " -n* {\n" " set nocomplain 1\n" " }\n" -" -ta* {\n" -" set tails 1\n" +" -t* {\n" +"\n" +" }\n" +"\n" +" -* {\n" +" return -code error \"bad option \\\"$switch\\\": must be -directory, -nocomplain, -tails, or --\"\n" " }\n" " -- {\n" " incr n\n" " break\n" " }\n" -" -* {\n" -" return -code error \"bad option \\\"$arg\\\": must be -directory, -nocomplain, -tails, or --\"\n" -" }\n" " * {\n" " break\n" " }\n" " }\n" " incr n\n" @@ -1267,35 +1237,29 @@ "\n" " set args [lrange $args $n end]\n" "\n" " set result {}\n" " foreach pattern $args {\n" -" set escpattern [string map {\n" +" set pattern [string map {\n" " \\\\\\\\ \\x01 \\\\\\{ \\x02 \\\\\\} \\x03 \\\\, \\x04\n" " } $pattern]\n" -" set patexps [lassign [glob.explode $escpattern] rest]\n" +" set patexps [lassign [glob.explode $pattern] rest]\n" " if {$rest ne \"\"} {\n" " return -code error \"unmatched close brace in glob pattern\"\n" " }\n" " foreach patexp $patexps {\n" " set patexp [string map {\n" " \\x01 \\\\\\\\ \\x02 \\{ \\x03 \\} \\x04 ,\n" " } $patexp]\n" " foreach {realname name} [glob.glob $base $patexp] {\n" -" incr n\n" -" if {$tails} {\n" -" lappend result $name\n" -" } else {\n" -" lappend result [file join $base $name]\n" -" }\n" +" lappend result $name\n" " }\n" " }\n" " }\n" "\n" " if {!$nocomplain && [llength $result] == 0} {\n" -" set s $(([llength $args] > 1) ? \"s\" : \"\")\n" -" return -code error \"no files matched glob pattern$s \\\"[join $args]\\\"\"\n" +" return -code error \"no files matched glob patterns\"\n" " }\n" "\n" " return $result\n" "}\n" ); @@ -1304,12 +1268,10 @@ { if (Jim_PackageProvide(interp, "stdlib", "1.0", JIM_ERRMSG)) return JIM_ERR; return Jim_EvalSource(interp, "stdlib.tcl", 1, -"\n" -"\n" "\n" "proc lambda {arglist args} {\n" " tailcall proc [ref {} function lambda.finalizer] $arglist {*}$args\n" "}\n" "\n" @@ -1335,52 +1297,50 @@ "}\n" "\n" "\n" "\n" "\n" -"proc stacktrace {{skip 0}} {\n" +"proc stacktrace {} {\n" " set trace {}\n" -" incr skip\n" -" foreach level [range $skip [info level]] {\n" -" lappend trace {*}[info frame -$level]\n" +" foreach level [range 1 [info level]] {\n" +" lassign [info frame -$level] p f l\n" +" lappend trace $p $f $l\n" " }\n" " return $trace\n" "}\n" "\n" "\n" "proc stackdump {stacktrace} {\n" -" set lines {}\n" +" set result {}\n" +" set count 0\n" " foreach {l f p} [lreverse $stacktrace] {\n" -" set line {}\n" +" if {$count} {\n" +" append result \\n\n" +" }\n" +" incr count\n" " if {$p ne \"\"} {\n" -" append line \"in procedure '$p' \"\n" +" append result \"in procedure '$p' \"\n" " if {$f ne \"\"} {\n" -" append line \"called \"\n" +" append result \"called \"\n" " }\n" " }\n" " if {$f ne \"\"} {\n" -" append line \"at file \\\"$f\\\", line $l\"\n" -" }\n" -" if {$line ne \"\"} {\n" -" lappend lines $line\n" +" append result \"at file \\\"$f\\\", line $l\"\n" " }\n" " }\n" -" join $lines \\n\n" +" return $result\n" "}\n" "\n" "\n" "\n" "proc errorInfo {msg {stacktrace \"\"}} {\n" " if {$stacktrace eq \"\"} {\n" -"\n" " set stacktrace [info stacktrace]\n" -"\n" -" lappend stacktrace {*}[stacktrace 1]\n" " }\n" " lassign $stacktrace p f l\n" " if {$f ne \"\"} {\n" -" set result \"$f:$l: Error: \"\n" +" set result \"Runtime Error: $f:$l: \"\n" " }\n" " append result \"$msg\\n\"\n" " append result [stackdump $stacktrace]\n" "\n" "\n" @@ -1388,52 +1348,40 @@ "}\n" "\n" "\n" "\n" "proc {info nameofexecutable} {} {\n" -" if {[exists ::jim::exe]} {\n" -" return $::jim::exe\n" +" if {[info exists ::jim_argv0]} {\n" +" if {[string match \"*/*\" $::jim_argv0]} {\n" +" return [file join [pwd] $::jim_argv0]\n" +" }\n" +" foreach path [split [env PATH \"\"] $::tcl_platform(pathSeparator)] {\n" +" set exec [file join [pwd] [string map {\\\\ /} $path] $::jim_argv0]\n" +" if {[file executable $exec]} {\n" +" return $exec\n" +" }\n" +" }\n" " }\n" +" return \"\"\n" "}\n" "\n" "\n" -"proc {dict with} {&dictVar {args key} script} {\n" +"proc {dict with} {dictVar args script} {\n" +" upvar $dictVar dict\n" " set keys {}\n" -" foreach {n v} [dict get $dictVar {*}$key] {\n" +" foreach {n v} [dict get $dict {*}$args] {\n" " upvar $n var_$n\n" " set var_$n $v\n" " lappend keys $n\n" " }\n" " catch {uplevel 1 $script} msg opts\n" -" if {[info exists dictVar] && ([llength $key] == 0 || [dict exists $dictVar {*}$key])} {\n" +" if {[info exists dict] && [dict exists $dict {*}$args]} {\n" " foreach n $keys {\n" " if {[info exists var_$n]} {\n" -" dict set dictVar {*}$key $n [set var_$n]\n" -" } else {\n" -" dict unset dictVar {*}$key $n\n" -" }\n" -" }\n" -" }\n" -" return {*}$opts $msg\n" -"}\n" -"\n" -"\n" -"proc {dict update} {&varName args script} {\n" -" set keys {}\n" -" foreach {n v} $args {\n" -" upvar $v var_$v\n" -" if {[dict exists $varName $n]} {\n" -" set var_$v [dict get $varName $n]\n" -" }\n" -" }\n" -" catch {uplevel 1 $script} msg opts\n" -" if {[info exists varName]} {\n" -" foreach {n v} $args {\n" -" if {[info exists var_$v]} {\n" -" dict set varName $n [set var_$v]\n" -" } else {\n" -" dict unset varName $n\n" +" dict set dict {*}$args $n [set var_$n]\n" +" } else {\n" +" dict unset dict {*}$args $n\n" " }\n" " }\n" " }\n" " return {*}$opts $msg\n" "}\n" @@ -1448,69 +1396,10 @@ " dict set dict $k $v\n" " }\n" " }\n" " return $dict\n" "}\n" -"\n" -"proc {dict replace} {dictionary {args {key value}}} {\n" -" if {[llength ${key value}] % 2} {\n" -" tailcall {dict replace}\n" -" }\n" -" tailcall dict merge $dictionary ${key value}\n" -"}\n" -"\n" -"\n" -"proc {dict lappend} {varName key {args value}} {\n" -" upvar $varName dict\n" -" if {[exists dict] && [dict exists $dict $key]} {\n" -" set list [dict get $dict $key]\n" -" }\n" -" lappend list {*}$value\n" -" dict set dict $key $list\n" -"}\n" -"\n" -"\n" -"proc {dict append} {varName key {args value}} {\n" -" upvar $varName dict\n" -" if {[exists dict] && [dict exists $dict $key]} {\n" -" set str [dict get $dict $key]\n" -" }\n" -" append str {*}$value\n" -" dict set dict $key $str\n" -"}\n" -"\n" -"\n" -"proc {dict incr} {varName key {increment 1}} {\n" -" upvar $varName dict\n" -" if {[exists dict] && [dict exists $dict $key]} {\n" -" set value [dict get $dict $key]\n" -" }\n" -" incr value $increment\n" -" dict set dict $key $value\n" -"}\n" -"\n" -"\n" -"proc {dict remove} {dictionary {args key}} {\n" -" foreach k $key {\n" -" dict unset dictionary $k\n" -" }\n" -" return $dictionary\n" -"}\n" -"\n" -"\n" -"proc {dict values} {dictionary {pattern *}} {\n" -" dict keys [lreverse $dictionary] $pattern\n" -"}\n" -"\n" -"\n" -"proc {dict for} {vars dictionary script} {\n" -" if {[llength $vars] != 2} {\n" -" return -code error \"must have exactly two variable names\"\n" -" }\n" -" dict size $dictionary\n" -" tailcall foreach $vars $dictionary $script\n" -"}\n" ); } int Jim_tclcompatInit(Jim_Interp *interp) { if (Jim_PackageProvide(interp, "tclcompat", "1.0", JIM_ERRMSG)) @@ -1522,13 +1411,11 @@ "\n" "\n" "\n" "\n" "\n" -"\n" "set env [env]\n" -"\n" "\n" "if {[info commands stdout] ne \"\"} {\n" "\n" " foreach p {gets flush close eof seek tell} {\n" " proc $p {chan args} {p} {\n" @@ -1575,10 +1462,51 @@ " }\n" " }\n" " }\n" "}\n" "\n" +"\n" +"proc case {var args} {\n" +"\n" +" if {[lindex $args 0] eq \"in\"} {\n" +" set args [lrange $args 1 end]\n" +" }\n" +"\n" +"\n" +" if {[llength $args] == 1} {\n" +" set args [lindex $args 0]\n" +" }\n" +"\n" +"\n" +" if {[llength $args] % 2 != 0} {\n" +" return -code error \"extra case pattern with no body\"\n" +" }\n" +"\n" +"\n" +" local proc case.checker {value pattern} {\n" +" string match $pattern $value\n" +" }\n" +"\n" +" foreach {value action} $args {\n" +" if {$value eq \"default\"} {\n" +" set do_action $action\n" +" continue\n" +" } elseif {[lsearch -bool -command case.checker $value $var]} {\n" +" set do_action $action\n" +" break\n" +" }\n" +" }\n" +"\n" +" if {[info exists do_action]} {\n" +" set rc [catch [list uplevel 1 $do_action] result opts]\n" +" if {$rc} {\n" +" incr opts(-level)\n" +" }\n" +" return {*}$opts $result\n" +" }\n" +"}\n" +"\n" "\n" "proc fileevent {args} {\n" " tailcall {*}$args\n" "}\n" "\n" @@ -1606,29 +1534,17 @@ " try {\n" " if {$force ni {{} -force}} {\n" " error \"bad option \\\"$force\\\": should be -force\"\n" " }\n" "\n" -" set in [open $source rb]\n" -"\n" -" if {[file exists $target]} {\n" -" if {$force eq \"\"} {\n" -" error \"error copying \\\"$source\\\" to \\\"$target\\\": file already exists\"\n" -" }\n" -"\n" -" if {$source eq $target} {\n" -" return\n" -" }\n" -"\n" -"\n" -" file stat $source ss\n" -" file stat $target ts\n" -" if {$ss(dev) == $ts(dev) && $ss(ino) == $ts(ino) && $ss(ino)} {\n" -" return\n" -" }\n" +" set in [open $source]\n" +"\n" +" if {$force eq \"\" && [file exists $target]} {\n" +" $in close\n" +" error \"error copying \\\"$source\\\" to \\\"$target\\\": file already exists\"\n" " }\n" -" set out [open $target wb]\n" +" set out [open $target w]\n" " $in copyto $out\n" " $out close\n" " } on error {msg opts} {\n" " incr opts(-level)\n" " return {*}$opts $msg\n" @@ -1671,18 +1587,18 @@ " error $error\n" " }\n" "}\n" "\n" "\n" -"local proc pid {{channelId {}}} {\n" -" if {$channelId eq \"\"} {\n" +"local proc pid {{chan {}}} {\n" +" if {$chan eq \"\"} {\n" " tailcall upcall pid\n" " }\n" -" if {[catch {$channelId tell}]} {\n" -" return -code error \"can not find channel named \\\"$channelId\\\"\"\n" +" if {[catch {$chan tell}]} {\n" +" return -code error \"can not find channel named \\\"$chan\\\"\"\n" " }\n" -" if {[catch {$channelId pid} pids]} {\n" +" if {[catch {$chan pid} pids]} {\n" " return \"\"\n" " }\n" " return $pids\n" "}\n" "\n" @@ -1710,11 +1626,11 @@ " }\n" " if {[llength $args] == 0} {\n" " return -code error {wrong # args: should be \"try ?options? script ?argument ...?\"}\n" " }\n" " set args [lassign $args script]\n" -" set code [catch -eval {*}$catchopts {uplevel 1 $script} msg opts]\n" +" set code [catch -eval {*}$catchopts [list uplevel 1 $script] msg opts]\n" "\n" " set handled 0\n" "\n" " foreach {on codes vars script} $args {\n" " switch -- $on \\\n" @@ -1728,16 +1644,16 @@ " if {$optsvar ne \"\"} {\n" " upvar $optsvar hopts\n" " set hopts $opts\n" " }\n" "\n" -" set code [catch {uplevel 1 $script} msg opts]\n" +" set code [catch [list uplevel 1 $script] msg opts]\n" " incr handled\n" " }\n" " } \\\n" " finally {\n" -" set finalcode [catch {uplevel 1 $codes} finalmsg finalopts]\n" +" set finalcode [catch [list uplevel 1 $codes] finalmsg finalopts]\n" " if {$finalcode} {\n" "\n" " set code $finalcode\n" " set msg $finalmsg\n" " set opts $finalopts\n" @@ -1770,26 +1686,24 @@ " file delete $path\n" "}\n" ); } + #include #include #include #include -#ifdef HAVE_UNISTD_H -#include -#include -#endif #if defined(HAVE_SYS_SOCKET_H) && defined(HAVE_SELECT) && defined(HAVE_NETINET_IN_H) && defined(HAVE_NETDB_H) && defined(HAVE_ARPA_INET_H) #include #include #include #include +#include #ifdef HAVE_SYS_UN_H #include #endif #else #define JIM_ANSIC @@ -1821,12 +1735,15 @@ typedef struct AioFile { FILE *fp; Jim_Obj *filename; int type; - int openFlags; + int OpenFlags; int fd; +#ifdef O_NDELAY + int flags; +#endif Jim_Obj *rEvent; Jim_Obj *wEvent; Jim_Obj *eEvent; int addr_family; } AioFile; @@ -1849,22 +1766,29 @@ static void JimAioDelProc(Jim_Interp *interp, void *privData) { AioFile *af = privData; JIM_NOTUSED(interp); + + if (!(af->OpenFlags & AIO_KEEPOPEN)) { + fclose(af->fp); + } Jim_DecrRefCount(interp, af->filename); #ifdef jim_ext_eventloop - Jim_DeleteFileHandler(interp, af->fp, JIM_EVENT_READABLE | JIM_EVENT_WRITABLE | JIM_EVENT_EXCEPTION); + if (af->rEvent) { + Jim_DeleteFileHandler(interp, af->fp); + } + if (af->wEvent) { + Jim_DeleteFileHandler(interp, af->fp); + } + if (af->eEvent) { + Jim_DeleteFileHandler(interp, af->fp); + } #endif - - if (!(af->openFlags & AIO_KEEPOPEN)) { - fclose(af->fp); - } - Jim_Free(af); } static int JimCheckStreamError(Jim_Interp *interp, AioFile *af) { @@ -2111,31 +2035,12 @@ return JIM_OK; } static int aio_cmd_close(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { - if (argc == 3) { -#if !defined(JIM_ANSIC) && defined(HAVE_SHUTDOWN) - static const char * const options[] = { "r", "w", NULL }; - enum { OPT_R, OPT_W, }; - int option; - AioFile *af = Jim_CmdPrivData(interp); - - if (Jim_GetEnum(interp, argv[2], options, &option, NULL, JIM_ERRMSG) != JIM_OK) { - return JIM_ERR; - } - if (shutdown(af->fd, option == OPT_R ? SHUT_RD : SHUT_WR) == 0) { - return JIM_OK; - } - JimAioSetError(interp, NULL); -#else - Jim_SetResultString(interp, "async close not supported", -1); -#endif - return JIM_ERR; - } - - return Jim_DeleteCommand(interp, Jim_String(argv[0])); + Jim_DeleteCommand(interp, Jim_String(argv[0])); + return JIM_OK; } static int aio_cmd_seek(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { AioFile *af = Jim_CmdPrivData(interp); @@ -2182,11 +2087,11 @@ #ifdef O_NDELAY static int aio_cmd_ndelay(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { AioFile *af = Jim_CmdPrivData(interp); - int fmode = fcntl(af->fd, F_GETFL); + int fmode = af->flags; if (argc) { long nb; if (Jim_GetLong(interp, argv[0], &nb) != JIM_OK) { @@ -2196,11 +2101,12 @@ fmode |= O_NDELAY; } else { fmode &= ~O_NDELAY; } - (void)fcntl(af->fd, F_SETFL, fmode); + fcntl(af->fd, F_SETFL, fmode); + af->flags = fmode; } Jim_SetResultInt(interp, (fmode & O_NONBLOCK) ? 1 : 0); return JIM_OK; } #endif @@ -2241,26 +2147,27 @@ } #ifdef jim_ext_eventloop static void JimAioFileEventFinalizer(Jim_Interp *interp, void *clientData) { - Jim_Obj **objPtrPtr = clientData; + Jim_Obj *objPtr = clientData; - Jim_DecrRefCount(interp, *objPtrPtr); - *objPtrPtr = NULL; + Jim_DecrRefCount(interp, objPtr); } static int JimAioFileEventHandler(Jim_Interp *interp, void *clientData, int mask) { - Jim_Obj **objPtrPtr = clientData; + Jim_Obj *objPtr = clientData; - return Jim_EvalObjBackground(interp, *objPtrPtr); + return Jim_EvalObjBackground(interp, objPtr); } static int aio_eventinfo(Jim_Interp *interp, AioFile * af, unsigned mask, Jim_Obj **scriptHandlerObj, int argc, Jim_Obj * const *argv) { + int scriptlen = 0; + if (argc == 0) { if (*scriptHandlerObj) { Jim_SetResult(interp, *scriptHandlerObj); } @@ -2267,25 +2174,27 @@ return JIM_OK; } if (*scriptHandlerObj) { - Jim_DeleteFileHandler(interp, af->fp, mask); + Jim_DeleteFileHandler(interp, af->fp); + *scriptHandlerObj = NULL; } - if (Jim_Length(argv[0]) == 0) { + Jim_GetString(argv[0], &scriptlen); + if (scriptlen == 0) { return JIM_OK; } Jim_IncrRefCount(argv[0]); *scriptHandlerObj = argv[0]; Jim_CreateFileHandler(interp, af->fp, mask, - JimAioFileEventHandler, scriptHandlerObj, JimAioFileEventFinalizer); + JimAioFileEventHandler, *scriptHandlerObj, JimAioFileEventFinalizer); return JIM_OK; } static int aio_cmd_readable(Jim_Interp *interp, int argc, Jim_Obj *const *argv) @@ -2304,11 +2213,11 @@ static int aio_cmd_onexception(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { AioFile *af = Jim_CmdPrivData(interp); - return aio_eventinfo(interp, af, JIM_EVENT_EXCEPTION, &af->eEvent, argc, argv); + return aio_eventinfo(interp, af, JIM_EVENT_EXCEPTION, &af->wEvent, argc, argv); } #endif static const jim_subcmd_type aio_command_table[] = { { "read", @@ -2359,14 +2268,14 @@ 0, 0, }, { "close", - "?r(ead)|w(rite)?", + NULL, aio_cmd_close, 0, - 1, + 0, JIM_MODFLAG_FULLARGV, }, { "seek", "offset ?start|current|end", @@ -2438,32 +2347,30 @@ static int JimAioOpenCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { const char *mode; + const char *filename; if (argc != 2 && argc != 3) { Jim_WrongNumArgs(interp, 1, argv, "filename ?mode?"); return JIM_ERR; } mode = (argc == 3) ? Jim_String(argv[2]) : "r"; + filename = Jim_String(argv[1]); #ifdef jim_ext_tclcompat - { - const char *filename = Jim_String(argv[1]); - - - if (*filename == '|') { - Jim_Obj *evalObj[3]; - - evalObj[0] = Jim_NewStringObj(interp, "::popen", -1); - evalObj[1] = Jim_NewStringObj(interp, filename + 1, -1); - evalObj[2] = Jim_NewStringObj(interp, mode, -1); - - return Jim_EvalObjVector(interp, 3, evalObj); - } + + if (*filename == '|') { + Jim_Obj *evalObj[3]; + + evalObj[0] = Jim_NewStringObj(interp, "popen", -1); + evalObj[1] = Jim_NewStringObj(interp, filename + 1, -1); + evalObj[2] = Jim_NewStringObj(interp, mode, -1); + + return Jim_EvalObjVector(interp, 3, evalObj); } #endif return JimMakeChannel(interp, NULL, -1, argv[1], "aio.handle%ld", 0, mode); } @@ -2470,131 +2377,70 @@ static int JimMakeChannel(Jim_Interp *interp, FILE *fh, int fd, Jim_Obj *filename, const char *hdlfmt, int family, const char *mode) { AioFile *af; char buf[AIO_CMD_LEN]; - int openFlags = 0; + int OpenFlags = 0; - if (fh) { + if (filename == NULL) { filename = Jim_NewStringObj(interp, hdlfmt, -1); - openFlags = AIO_KEEPOPEN; } Jim_IncrRefCount(filename); if (fh == NULL) { -#if !defined(JIM_ANSIC) - if (fd >= 0) { + if (fd < 0) { + fh = fopen(Jim_String(filename), mode); + } + else { fh = fdopen(fd, mode); } - else -#endif - fh = fopen(Jim_String(filename), mode); + } + else { + OpenFlags = AIO_KEEPOPEN; + } - if (fh == NULL) { - JimAioSetError(interp, filename); + if (fh == NULL) { + JimAioSetError(interp, filename); #if !defined(JIM_ANSIC) - if (fd >= 0) { - close(fd); - } + if (fd >= 0) { + close(fd); + } #endif - Jim_DecrRefCount(interp, filename); - return JIM_ERR; - } + Jim_DecrRefCount(interp, filename); + return JIM_ERR; } af = Jim_Alloc(sizeof(*af)); memset(af, 0, sizeof(*af)); af->fp = fh; af->fd = fileno(fh); af->filename = filename; #ifdef FD_CLOEXEC - if ((openFlags & AIO_KEEPOPEN) == 0) { - (void)fcntl(af->fd, F_SETFD, FD_CLOEXEC); + if ((OpenFlags & AIO_KEEPOPEN) == 0) { + fcntl(af->fd, F_SETFD, FD_CLOEXEC); } #endif - af->openFlags = openFlags; + af->OpenFlags = OpenFlags; +#ifdef O_NDELAY + af->flags = fcntl(af->fd, F_GETFL); +#endif af->addr_family = family; snprintf(buf, sizeof(buf), hdlfmt, Jim_GetId(interp)); Jim_CreateCommand(interp, buf, JimAioSubCmdProc, af, JimAioDelProc); - Jim_SetResult(interp, Jim_MakeGlobalNamespaceName(interp, Jim_NewStringObj(interp, buf, -1))); - - return JIM_OK; -} - -#if defined(HAVE_PIPE) || (defined(HAVE_SOCKETPAIR) && defined(HAVE_SYS_UN_H)) -static int JimMakeChannelPair(Jim_Interp *interp, int p[2], Jim_Obj *filename, - const char *hdlfmt, int family, const char *mode[2]) -{ - if (JimMakeChannel(interp, NULL, p[0], filename, hdlfmt, family, mode[0]) == JIM_OK) { - Jim_Obj *objPtr = Jim_NewListObj(interp, NULL, 0); - Jim_ListAppendElement(interp, objPtr, Jim_GetResult(interp)); - - if (JimMakeChannel(interp, NULL, p[1], filename, hdlfmt, family, mode[1]) == JIM_OK) { - Jim_ListAppendElement(interp, objPtr, Jim_GetResult(interp)); - Jim_SetResult(interp, objPtr); - return JIM_OK; - } - } - - - close(p[0]); - close(p[1]); - JimAioSetError(interp, NULL); - return JIM_ERR; -} -#endif - - -int Jim_MakeTempFile(Jim_Interp *interp, const char *template) -{ -#ifdef HAVE_MKSTEMP - int fd; - mode_t mask; - Jim_Obj *filenameObj; - - if (template == NULL) { - const char *tmpdir = getenv("TMPDIR"); - if (tmpdir == NULL || *tmpdir == '\0' || access(tmpdir, W_OK) != 0) { - tmpdir = "/tmp/"; - } - filenameObj = Jim_NewStringObj(interp, tmpdir, -1); - if (tmpdir[0] && tmpdir[strlen(tmpdir) - 1] != '/') { - Jim_AppendString(interp, filenameObj, "/", 1); - } - Jim_AppendString(interp, filenameObj, "tcl.tmp.XXXXXX", -1); - } - else { - filenameObj = Jim_NewStringObj(interp, template, -1); - } - - mask = umask(S_IXUSR | S_IRWXG | S_IRWXO); - - - fd = mkstemp(filenameObj->bytes); - umask(mask); - if (fd < 0) { - JimAioSetError(interp, filenameObj); - Jim_FreeNewObj(interp, filenameObj); - return -1; - } - - Jim_SetResult(interp, filenameObj); - return fd; -#else - Jim_SetResultString(interp, "platform has no tempfile support", -1); - return -1; -#endif -} + Jim_SetResultString(interp, buf, -1); + + return JIM_OK; +} + FILE *Jim_AioFilehandle(Jim_Interp *interp, Jim_Obj *command) { Jim_Cmd *cmdPtr = Jim_GetCommand(interp, command, JIM_ERRMSG); - if (cmdPtr && !cmdPtr->isproc && cmdPtr->u.native.cmdProc == JimAioSubCmdProc) { return ((AioFile *) cmdPtr->u.native.privData)->fp; } Jim_SetResultFormatted(interp, "Not a filehandle: \"%#s\"", command); return NULL; @@ -2615,10 +2461,11 @@ JimMakeChannel(interp, stdout, -1, NULL, "stdout", 0, "w"); JimMakeChannel(interp, stderr, -1, NULL, "stderr", 0, "w"); return JIM_OK; } + #include #include #include @@ -2650,29 +2497,28 @@ return JIM_OK; } Jim_SetResultString(interp, strerror(errno), -1); return JIM_ERR; } - else { - Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0); - - while ((entryPtr = readdir(dirPtr)) != NULL) { - if (entryPtr->d_name[0] == '.') { - if (entryPtr->d_name[1] == '\0') { - continue; - } - if ((entryPtr->d_name[1] == '.') && (entryPtr->d_name[2] == '\0')) - continue; - } - Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, entryPtr->d_name, -1)); - } - closedir(dirPtr); - - Jim_SetResult(interp, listObj); - - return JIM_OK; - } + Jim_SetResultString(interp, strerror(errno), -1); + + Jim_SetResult(interp, Jim_NewListObj(interp, NULL, 0)); + + while ((entryPtr = readdir(dirPtr)) != NULL) { + if (entryPtr->d_name[0] == '.') { + if (entryPtr->d_name[1] == '\0') { + continue; + } + if ((entryPtr->d_name[1] == '.') && (entryPtr->d_name[2] == '\0')) + continue; + } + Jim_ListAppendElement(interp, Jim_GetResult(interp), Jim_NewStringObj(interp, + entryPtr->d_name, -1)); + } + closedir(dirPtr); + + return JIM_OK; } int Jim_readdirInit(Jim_Interp *interp) { if (Jim_PackageProvide(interp, "readdir", "1.0", JIM_ERRMSG)) @@ -2683,14 +2529,10 @@ } #include #include -#if defined(JIM_REGEXP) -#else - #include -#endif static void FreeRegexpInternalRep(Jim_Interp *interp, Jim_Obj *objPtr) { regfree(objPtr->internalRep.regexpValue.compre); Jim_Free(objPtr->internalRep.regexpValue.compre); @@ -3197,16 +3039,10 @@ # ifndef MAXPATHLEN # define MAXPATHLEN JIM_PATH_LEN # endif -#if defined(__MINGW32__) || defined(_MSC_VER) -#define ISWINDOWS 1 -#else -#define ISWINDOWS 0 -#endif - static const char *JimGetFileType(int mode) { if (S_ISREG(mode)) { return "file"; @@ -3240,61 +3076,58 @@ } #endif return "unknown"; } -static void AppendStatElement(Jim_Interp *interp, Jim_Obj *listObj, const char *key, jim_wide value) + +static int set_array_int_value(Jim_Interp *interp, Jim_Obj *container, const char *key, + jim_wide value) { - Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, key, -1)); - Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, value)); + Jim_Obj *nameobj = Jim_NewStringObj(interp, key, -1); + Jim_Obj *valobj = Jim_NewWideObj(interp, value); + + if (Jim_SetDictKeysVector(interp, container, &nameobj, 1, valobj, JIM_ERRMSG) != JIM_OK) { + Jim_FreeObj(interp, nameobj); + Jim_FreeObj(interp, valobj); + return JIM_ERR; + } + return JIM_OK; +} + +static int set_array_string_value(Jim_Interp *interp, Jim_Obj *container, const char *key, + const char *value) +{ + Jim_Obj *nameobj = Jim_NewStringObj(interp, key, -1); + Jim_Obj *valobj = Jim_NewStringObj(interp, value, -1); + + if (Jim_SetDictKeysVector(interp, container, &nameobj, 1, valobj, JIM_ERRMSG) != JIM_OK) { + Jim_FreeObj(interp, nameobj); + Jim_FreeObj(interp, valobj); + return JIM_ERR; + } + return JIM_OK; } static int StoreStatData(Jim_Interp *interp, Jim_Obj *varName, const struct stat *sb) { - - Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0); - - AppendStatElement(interp, listObj, "dev", sb->st_dev); - AppendStatElement(interp, listObj, "ino", sb->st_ino); - AppendStatElement(interp, listObj, "mode", sb->st_mode); - AppendStatElement(interp, listObj, "nlink", sb->st_nlink); - AppendStatElement(interp, listObj, "uid", sb->st_uid); - AppendStatElement(interp, listObj, "gid", sb->st_gid); - AppendStatElement(interp, listObj, "size", sb->st_size); - AppendStatElement(interp, listObj, "atime", sb->st_atime); - AppendStatElement(interp, listObj, "mtime", sb->st_mtime); - AppendStatElement(interp, listObj, "ctime", sb->st_ctime); - Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "type", -1)); - Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, JimGetFileType((int)sb->st_mode), -1)); - - - if (varName) { - Jim_Obj *objPtr = Jim_GetVariable(interp, varName, JIM_NONE); - if (objPtr) { - if (Jim_DictSize(interp, objPtr) < 0) { - - Jim_SetResultFormatted(interp, "can't set \"%#s(dev)\": variable isn't array", varName); - Jim_FreeNewObj(interp, listObj); - return JIM_ERR; - } - - if (Jim_IsShared(objPtr)) - objPtr = Jim_DuplicateObj(interp, objPtr); - - - Jim_ListAppendList(interp, objPtr, listObj); - Jim_DictSize(interp, objPtr); - Jim_InvalidateStringRep(objPtr); - - Jim_FreeNewObj(interp, listObj); - listObj = objPtr; - } - Jim_SetVariable(interp, varName, listObj); - } - - - Jim_SetResult(interp, listObj); + if (set_array_int_value(interp, varName, "dev", sb->st_dev) != JIM_OK) { + Jim_SetResultFormatted(interp, "can't set \"%#s(dev)\": variable isn't array", varName); + return JIM_ERR; + } + set_array_int_value(interp, varName, "ino", sb->st_ino); + set_array_int_value(interp, varName, "mode", sb->st_mode); + set_array_int_value(interp, varName, "nlink", sb->st_nlink); + set_array_int_value(interp, varName, "uid", sb->st_uid); + set_array_int_value(interp, varName, "gid", sb->st_gid); + set_array_int_value(interp, varName, "size", sb->st_size); + set_array_int_value(interp, varName, "atime", sb->st_atime); + set_array_int_value(interp, varName, "mtime", sb->st_mtime); + set_array_int_value(interp, varName, "ctime", sb->st_ctime); + set_array_string_value(interp, varName, "type", JimGetFileType((int)sb->st_mode)); + + + Jim_SetResult(interp, Jim_GetVariable(interp, varName, 0)); return JIM_OK; } static int file_cmd_dirname(Jim_Interp *interp, int argc, Jim_Obj *const *argv) @@ -3308,14 +3141,16 @@ Jim_SetResultString(interp, ".", -1); } else if (p == path) { Jim_SetResultString(interp, "/", -1); } - else if (ISWINDOWS && p[-1] == ':') { +#if defined(__MINGW32__) || defined(_MSC_VER) + else if (p[-1] == ':') { Jim_SetResultString(interp, path, p - path + 1); } +#endif else { Jim_SetResultString(interp, path, p - path); } return JIM_OK; } @@ -3398,14 +3233,16 @@ if (*part == '/') { last = newname; } - else if (ISWINDOWS && strchr(part, ':')) { +#if defined(__MINGW32__) || defined(_MSC_VER) + else if (strchr(part, ':')) { last = newname; } +#endif else if (part[0] == '.') { if (part[1] == '/') { part += 2; len -= 2; } @@ -3430,14 +3267,11 @@ last += len; } if (last > newname + 1 && last[-1] == '/') { - - if (!ISWINDOWS || !(last > newname + 2 && last[-2] == ':')) { - *--last = 0; - } + *--last = 0; } } *last = 0; @@ -3448,11 +3282,14 @@ return JIM_OK; } static int file_access(Jim_Interp *interp, Jim_Obj *filename, int mode) { - Jim_SetResultBool(interp, access(Jim_String(filename), mode) != -1); + const char *path = Jim_String(filename); + int rc = access(path, mode); + + Jim_SetResultBool(interp, rc != -1); return JIM_OK; } static int file_cmd_readable(Jim_Interp *interp, int argc, Jim_Obj *const *argv) @@ -3468,11 +3305,10 @@ static int file_cmd_executable(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { #ifdef X_OK return file_access(interp, argv[0], X_OK); #else - Jim_SetResultBool(interp, 1); return JIM_OK; #endif } @@ -3573,21 +3409,33 @@ argv++; } return JIM_OK; } +#ifdef HAVE_MKSTEMP static int file_cmd_tempfile(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { - int fd = Jim_MakeTempFile(interp, (argc >= 1) ? Jim_String(argv[0]) : NULL); + int fd; + char *filename; + const char *template = "/tmp/tcl.tmp.XXXXXX"; + if (argc >= 1) { + template = Jim_String(argv[0]); + } + filename = Jim_StrDup(template); + + fd = mkstemp(filename); if (fd < 0) { + Jim_SetResultString(interp, "Failed to create tempfile", -1); return JIM_ERR; } close(fd); + Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, filename, -1)); return JIM_OK; } +#endif static int file_cmd_rename(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { const char *source; const char *dest; @@ -3618,48 +3466,10 @@ } return JIM_OK; } -#if defined(HAVE_LINK) && defined(HAVE_SYMLINK) -static int file_cmd_link(Jim_Interp *interp, int argc, Jim_Obj *const *argv) -{ - int ret; - const char *source; - const char *dest; - static const char * const options[] = { "-hard", "-symbolic", NULL }; - enum { OPT_HARD, OPT_SYMBOLIC, }; - int option = OPT_HARD; - - if (argc == 3) { - if (Jim_GetEnum(interp, argv[0], options, &option, NULL, JIM_ENUM_ABBREV | JIM_ERRMSG) != JIM_OK) { - return JIM_ERR; - } - argv++; - argc--; - } - - dest = Jim_String(argv[0]); - source = Jim_String(argv[1]); - - if (option == OPT_HARD) { - ret = link(source, dest); - } - else { - ret = symlink(source, dest); - } - - if (ret != 0) { - Jim_SetResultFormatted(interp, "error linking \"%#s\" to \"%#s\": %s", argv[0], argv[1], - strerror(errno)); - return JIM_ERR; - } - - return JIM_OK; -} -#endif - static int file_stat(Jim_Interp *interp, Jim_Obj *filename, struct stat *sb) { const char *path = Jim_String(filename); if (stat(path, sb) == -1) { @@ -3667,11 +3477,14 @@ return JIM_ERR; } return JIM_OK; } -#ifdef HAVE_LSTAT +#ifndef HAVE_LSTAT +#define lstat stat +#endif + static int file_lstat(Jim_Interp *interp, Jim_Obj *filename, struct stat *sb) { const char *path = Jim_String(filename); if (lstat(path, sb) == -1) { @@ -3678,13 +3491,10 @@ Jim_SetResultFormatted(interp, "could not read \"%#s\": %s", filename, strerror(errno)); return JIM_ERR; } return JIM_OK; } -#else -#define file_lstat file_stat -#endif static int file_cmd_atime(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { struct stat sb; @@ -3809,32 +3619,28 @@ } Jim_SetResultString(interp, JimGetFileType((int)sb.st_mode), -1); return JIM_OK; } -#ifdef HAVE_LSTAT static int file_cmd_lstat(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { struct stat sb; if (file_lstat(interp, argv[0], &sb) != JIM_OK) { return JIM_ERR; } - return StoreStatData(interp, argc == 2 ? argv[1] : NULL, &sb); + return StoreStatData(interp, argv[1], &sb); } -#else -#define file_cmd_lstat file_cmd_stat -#endif static int file_cmd_stat(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { struct stat sb; if (file_stat(interp, argv[0], &sb) != JIM_OK) { return JIM_ERR; } - return StoreStatData(interp, argc == 2 ? argv[1] : NULL, &sb); + return StoreStatData(interp, argv[1], &sb); } static const jim_subcmd_type file_command_table[] = { { "atime", "name", @@ -3939,33 +3745,26 @@ file_cmd_mkdir, 1, -1, }, +#ifdef HAVE_MKSTEMP { "tempfile", "?template?", file_cmd_tempfile, 0, 1, }, +#endif { "rename", "?-force? source dest", file_cmd_rename, 2, 3, }, -#if defined(HAVE_LINK) && defined(HAVE_SYMLINK) - { "link", - "?-symbolic|-hard? newname target", - file_cmd_link, - 2, - 3, - - }, -#endif #if defined(HAVE_READLINK) { "readlink", "name", file_cmd_readlink, 1, @@ -3979,20 +3778,20 @@ 1, 1, }, { "stat", - "name ?var?", + "name var", file_cmd_stat, - 1, + 2, 2, }, { "lstat", - "name ?var?", + "name var", file_cmd_lstat, - 1, + 2, 2, }, { "type", "name", @@ -4048,28 +3847,30 @@ return JIM_OK; } static int Jim_PwdCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { - char *cwd = Jim_Alloc(MAXPATHLEN); + const int cwd_len = 2048; + char *cwd = malloc(cwd_len); - if (getcwd(cwd, MAXPATHLEN) == NULL) { + if (getcwd(cwd, cwd_len) == NULL) { Jim_SetResultString(interp, "Failed to get pwd", -1); - Jim_Free(cwd); return JIM_ERR; } - else if (ISWINDOWS) { +#if defined(__MINGW32__) || defined(_MSC_VER) + { char *p = cwd; while ((p = strchr(p, '\\')) != NULL) { *p++ = '/'; } } +#endif Jim_SetResultString(interp, cwd, -1); - Jim_Free(cwd); + free(cwd); return JIM_OK; } int Jim_fileInit(Jim_Interp *interp) { @@ -4134,11 +3935,10 @@ int Jim_execInit(Jim_Interp *interp) { if (Jim_PackageProvide(interp, "exec", "1.0", JIM_ERRMSG)) return JIM_ERR; - Jim_CreateCommand(interp, "exec", Jim_ExecCmd, NULL, NULL); return JIM_OK; } #else @@ -4178,11 +3978,10 @@ static int JimErrno(void); #else #include #include #include - #include typedef int fdtype; typedef int pidtype; #define JimPipe pipe #define JimErrno() errno @@ -4206,11 +4005,11 @@ static void JimRestoreEnv(char **env); static int JimCreatePipeline(Jim_Interp *interp, int argc, Jim_Obj *const *argv, pidtype **pidArrayPtr, fdtype *inPipePtr, fdtype *outPipePtr, fdtype *errFilePtr); static void JimDetachPids(Jim_Interp *interp, int numPids, const pidtype *pidPtr); static int JimCleanupChildren(Jim_Interp *interp, int numPids, pidtype *pidPtr, fdtype errorId); -static fdtype JimCreateTemp(Jim_Interp *interp, const char *contents, int len); +static fdtype JimCreateTemp(Jim_Interp *interp, const char *contents); static fdtype JimOpenForWrite(const char *filename, int append); static int JimRewindFd(fdtype fd); static void Jim_SetResultErrno(Jim_Interp *interp, const char *msg) { @@ -4252,13 +4051,24 @@ } Jim_RemoveTrailingNewline(strObj); fclose(fh); return JIM_OK; } + +static void JimTrimTrailingNewline(Jim_Interp *interp) +{ + int len; + const char *p = Jim_GetString(Jim_GetResult(interp), &len); + + if (len > 0 && p[len - 1] == '\n') { + Jim_SetResultString(interp, p, len - 1); + } +} static char **JimBuildEnv(Jim_Interp *interp) { +#if defined(jim_ext_tclcompat) int i; int size; int num; int n; char **envptr; @@ -4272,11 +4082,10 @@ num = Jim_ListLength(interp, objPtr); if (num % 2) { - num--; } size = Jim_Length(objPtr) + 2; envptr = Jim_Alloc(sizeof(*envptr) * (num / 2 + 1) + size); @@ -4299,17 +4108,22 @@ } envptr[n] = NULL; *envdata = 0; return envptr; +#else + return Jim_GetEnviron(); +#endif } static void JimFreeEnv(char **env, char **original_environ) { +#ifdef jim_ext_tclcompat if (env != original_environ) { Jim_Free(env); } +#endif } static int JimCheckWaitStatus(Jim_Interp *interp, pidtype pid, int waitStatus) { Jim_Obj *errorCode = Jim_NewListObj(interp, NULL, 0); @@ -4358,19 +4172,19 @@ } struct WaitInfo { - pidtype pid; + pidtype pid; int status; int flags; }; struct WaitInfoTable { - struct WaitInfo *info; - int size; - int used; + struct WaitInfo *info; + int size; + int used; }; #define WI_DETACHED 2 @@ -4393,12 +4207,14 @@ return table; } static int Jim_ExecCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { - fdtype outputId; - fdtype errorId; + fdtype outputId; /* File id for output pipe. -1 + * means command overrode. */ + fdtype errorId; /* File id for temporary file + * containing error output. */ pidtype *pidPtr; int numPids, result; if (argc > 1 && Jim_CompareStringImmediate(interp, argv[argc - 1], "&")) { Jim_Obj *listObj; @@ -4445,32 +4261,26 @@ static void JimReapDetachedPids(struct WaitInfoTable *table) { struct WaitInfo *waitPtr; int count; - int dest; if (!table) { return; } - waitPtr = table->info; - dest = 0; - for (count = table->used; count > 0; waitPtr++, count--) { + for (waitPtr = table->info, count = table->used; count > 0; waitPtr++, count--) { if (waitPtr->flags & WI_DETACHED) { int status; pidtype pid = JimWaitPid(waitPtr->pid, &status, WNOHANG); - if (pid == waitPtr->pid) { - + if (pid != JIM_BAD_PID) { + if (waitPtr != &table->info[table->used - 1]) { + *waitPtr = table->info[table->used - 1]; + } table->used--; - continue; } } - if (waitPtr != &table->info[dest]) { - table->info[dest] = *waitPtr; - } - dest++; } } static pidtype JimWaitForProcess(struct WaitInfoTable *table, pidtype pid, int *statusPtr) { @@ -4492,10 +4302,11 @@ } return JIM_BAD_PID; } + static void JimDetachPids(Jim_Interp *interp, int numPids, const pidtype *pidPtr) { int j; struct WaitInfoTable *table = Jim_CmdPrivData(interp); @@ -4536,11 +4347,10 @@ int cmdCount; /* Count of number of distinct commands * found in argc/argv. */ const char *input = NULL; /* Describes input for pipeline, depending * on "inputFile". NULL means take input * from stdin/pipe. */ - int input_len = 0; #define FILE_NAME 0 #define FILE_APPEND 1 #define FILE_HANDLE 2 #define FILE_TEXT 3 @@ -4602,20 +4412,19 @@ if (arg[0] == '<') { inputFile = FILE_NAME; input = arg + 1; if (*input == '<') { inputFile = FILE_TEXT; - input_len = Jim_Length(argv[i]) - 2; input++; } else if (*input == '@') { inputFile = FILE_HANDLE; input++; } if (!*input && ++i < argc) { - input = Jim_GetString(argv[i], &input_len); + input = Jim_String(argv[i]); } } else if (arg[0] == '>') { int dup_error = 0; @@ -4689,11 +4498,11 @@ save_environ = JimSaveEnv(JimBuildEnv(interp)); if (input != NULL) { if (inputFile == FILE_TEXT) { - inputId = JimCreateTemp(interp, input, input_len); + inputId = JimCreateTemp(interp, input); if (inputId == JIM_BAD_FD) { goto error; } } else if (inputFile == FILE_HANDLE) { @@ -4778,11 +4587,11 @@ goto error; } } } else if (errFilePtr != NULL) { - errorId = JimCreateTemp(interp, NULL, 0); + errorId = JimCreateTemp(interp, NULL); if (errorId == JIM_BAD_FD) { goto error; } *errFilePtr = JimDupFd(errorId); } @@ -4815,24 +4624,28 @@ goto error; } outputId = pipeIds[1]; } - - if (pipe_dup_err) { - errorId = outputId; - } - #ifdef __MINGW32__ pid = JimStartWinProcess(interp, &arg_array[firstArg], save_environ ? save_environ[0] : NULL, inputId, outputId, errorId); if (pid == JIM_BAD_PID) { Jim_SetResultFormatted(interp, "couldn't exec \"%s\"", arg_array[firstArg]); goto error; } #else + if (table->info == NULL) { + (void)signal(SIGPIPE, SIG_IGN); + } + + + if (pipe_dup_err) { + errorId = outputId; + } + pid = vfork(); if (pid < 0) { Jim_SetResultErrno(interp, "couldn't fork child process"); goto error; } @@ -4845,17 +4658,14 @@ for (i = 3; (i <= outputId) || (i <= inputId) || (i <= errorId); i++) { close(i); } - - (void)signal(SIGPIPE, SIG_DFL); - execvpe(arg_array[firstArg], &arg_array[firstArg], Jim_GetEnviron()); - fprintf(stderr, "couldn't exec \"%s\"\n", arg_array[firstArg]); + fprintf(stderr, "couldn't exec \"%s\"", arg_array[firstArg]); _exit(127); } #endif @@ -4957,24 +4767,19 @@ if (JimAppendStreamToString(interp, errorId, Jim_GetResult(interp)) != JIM_OK) { result = JIM_ERR; } } - Jim_RemoveTrailingNewline(Jim_GetResult(interp)); + JimTrimTrailingNewline(interp); return result; } int Jim_execInit(Jim_Interp *interp) { if (Jim_PackageProvide(interp, "exec", "1.0", JIM_ERRMSG)) return JIM_ERR; - -#ifdef SIGPIPE - (void)signal(SIGPIPE, SIG_IGN); -#endif - Jim_CreateCommand(interp, "exec", Jim_ExecCmd, JimAllocWaitInfoTable(), JimFreeWaitInfoTable); return JIM_OK; } #if defined(__MINGW32__) @@ -5148,11 +4953,11 @@ *status = ret; CloseHandle(pid); return pid; } -static HANDLE JimCreateTemp(Jim_Interp *interp, const char *contents, int len) +static HANDLE JimCreateTemp(Jim_Interp *interp, const char *contents) { char name[MAX_PATH]; HANDLE handle; if (!GetTempPath(MAX_PATH, name) || !GetTempFileName(name, "JIM", 0, name)) { @@ -5172,11 +4977,11 @@ FILE *fh = JimFdOpenForWrite(JimDupFd(handle)); if (fh == NULL) { goto error; } - if (fwrite(contents, len, 1, fh) != 1) { + if (fwrite(contents, strlen(contents), 1, fh) != 1) { fclose(fh); goto error; } fseek(fh, 0, SEEK_SET); fclose(fh); @@ -5299,26 +5104,28 @@ { STARTUPINFO startInfo; PROCESS_INFORMATION procInfo; HANDLE hProcess, h; char execPath[MAX_PATH]; + char *originalName; pidtype pid = JIM_BAD_PID; Jim_Obj *cmdLineObj; if (JimWinFindExecutable(argv[0], execPath) < 0) { return JIM_BAD_PID; } + originalName = argv[0]; argv[0] = execPath; hProcess = GetCurrentProcess(); cmdLineObj = JimWinBuildCommandLine(interp, argv); ZeroMemory(&startInfo, sizeof(startInfo)); startInfo.cb = sizeof(startInfo); startInfo.dwFlags = STARTF_USESTDHANDLES; - startInfo.hStdInput = INVALID_HANDLE_VALUE; + startInfo.hStdInput = INVALID_HANDLE_VALUE; startInfo.hStdOutput= INVALID_HANDLE_VALUE; startInfo.hStdError = INVALID_HANDLE_VALUE; if (inputId == JIM_BAD_FD) { if (CreatePipe(&startInfo.hStdInput, &h, JimStdSecAttrs(), 0) != FALSE) { @@ -5389,24 +5196,28 @@ static int JimRewindFd(int fd) { return lseek(fd, 0L, SEEK_SET); } -static int JimCreateTemp(Jim_Interp *interp, const char *contents, int len) -{ - int fd = Jim_MakeTempFile(interp, NULL); - - if (fd != JIM_BAD_FD) { - unlink(Jim_String(Jim_GetResult(interp))); - if (contents) { - if (write(fd, contents, len) != len) { - Jim_SetResultErrno(interp, "couldn't write temp file"); - close(fd); - return -1; - } - lseek(fd, 0L, SEEK_SET); - } +static int JimCreateTemp(Jim_Interp *interp, const char *contents) +{ + char inName[] = "/tmp/tcl.tmp.XXXXXX"; + + int fd = mkstemp(inName); + if (fd == JIM_BAD_FD) { + Jim_SetResultErrno(interp, "couldn't create temp file"); + return -1; + } + unlink(inName); + if (contents) { + int length = strlen(contents); + if (write(fd, contents, length) != length) { + Jim_SetResultErrno(interp, "couldn't write temp file"); + close(fd); + return -1; + } + lseek(fd, 0L, SEEK_SET); } return fd; } static char **JimSaveEnv(char **env) @@ -5421,10 +5232,11 @@ JimFreeEnv(Jim_GetEnviron(), env); Jim_SetEnviron(env); } #endif #endif + #ifndef _XOPEN_SOURCE #define _XOPEN_SOURCE 500 #endif @@ -5444,11 +5256,11 @@ char buf[100]; time_t t; long seconds; - const char *format = "%a %b %d %H:%M:%S %Z %Y"; + const char *format = "%a %b %d %H:%M:%S %Z %Y"; if (argc == 2 || (argc == 3 && !Jim_CompareStringImmediate(interp, argv[1], "-format"))) { return -1; } @@ -5459,14 +5271,11 @@ if (Jim_GetLong(interp, argv[0], &seconds) != JIM_OK) { return JIM_ERR; } t = seconds; - if (strftime(buf, sizeof(buf), format, localtime(&t)) == 0) { - Jim_SetResultString(interp, "format string too long", -1); - return JIM_ERR; - } + strftime(buf, sizeof(buf), format, localtime(&t)); Jim_SetResultString(interp, buf, -1); return JIM_OK; } @@ -5581,10 +5390,11 @@ return JIM_ERR; Jim_CreateCommand(interp, "clock", Jim_SubCmdProc, (void *)clock_command_table, NULL); return JIM_OK; } + #include #include #include #include @@ -5599,29 +5409,33 @@ } static int array_cmd_get(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { Jim_Obj *objPtr = Jim_GetVariable(interp, argv[0], JIM_NONE); - Jim_Obj *patternObj; if (!objPtr) { return JIM_OK; } - patternObj = (argc == 1) ? NULL : argv[1]; - - - if (patternObj == NULL || Jim_CompareStringImmediate(interp, patternObj, "*")) { - if (Jim_IsList(objPtr) && Jim_ListLength(interp, objPtr) % 2 == 0) { - - Jim_SetResult(interp, objPtr); - return JIM_OK; - } + if (argc == 1 || Jim_CompareStringImmediate(interp, argv[1], "*")) { + + if (Jim_IsList(objPtr)) { + if (Jim_ListLength(interp, objPtr) % 2 != 0) { + + return JIM_ERR; + } + } + else if (Jim_DictSize(interp, objPtr) < 0) { + + return JIM_ERR; + } + Jim_SetResult(interp, objPtr); + return JIM_OK; } - return Jim_DictValues(interp, objPtr, patternObj); + return Jim_DictValues(interp, objPtr, argv[1]); } static int array_cmd_names(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { Jim_Obj *objPtr = Jim_GetVariable(interp, argv[0], JIM_NONE); @@ -5647,15 +5461,10 @@ return JIM_OK; } objPtr = Jim_GetVariable(interp, argv[0], JIM_NONE); - if (objPtr == NULL) { - - return JIM_OK; - } - if (Jim_DictPairs(interp, objPtr, &dictValuesObj, &len) != JIM_OK) { return JIM_ERR; } @@ -5689,20 +5498,10 @@ Jim_SetResultInt(interp, len); return JIM_OK; } -static int array_cmd_stat(Jim_Interp *interp, int argc, Jim_Obj *const *argv) -{ - Jim_Obj *objPtr = Jim_GetVariable(interp, argv[0], JIM_NONE); - if (objPtr) { - return Jim_DictInfo(interp, objPtr); - } - Jim_SetResultFormatted(interp, "\"%#s\" isn't an array", argv[0], NULL); - return JIM_ERR; -} - static int array_cmd_set(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { int i; int len; Jim_Obj *listObj = argv[1]; @@ -5717,13 +5516,10 @@ dictObj = Jim_GetVariable(interp, argv[0], JIM_UNSHARED); if (!dictObj) { return Jim_SetVariable(interp, argv[0], listObj); } - else if (Jim_DictSize(interp, dictObj) < 0) { - return JIM_ERR; - } if (Jim_IsShared(dictObj)) { dictObj = Jim_DuplicateObj(interp, dictObj); } @@ -5773,17 +5569,10 @@ array_cmd_size, 1, 1, }, - { "stat", - "arrayName", - array_cmd_stat, - 1, - 1, - - }, { "unset", "arrayName ?pattern?", array_cmd_unset, 1, 2, @@ -5825,10 +5614,11 @@ Jim_arrayInit(interp); Jim_stdlibInit(interp); Jim_tclcompatInit(interp); return JIM_OK; } + #define JIM_OPTIMIZATION #include #include @@ -5882,26 +5672,26 @@ #define JIM_DEBUG_COMMAND #define JIM_DEBUG_PANIC #endif - #define JIM_INTEGER_SPACE 24 const char *jim_tt_name(int type); #ifdef JIM_DEBUG_PANIC -static void JimPanicDump(int fail_condition, const char *fmt, ...); +static void JimPanicDump(int panic_condition, const char *fmt, ...); #define JimPanic(X) JimPanicDump X #else #define JimPanic(X) #endif static char JimEmptyStringRep[] = ""; -static void JimFreeCallFrame(Jim_Interp *interp, Jim_CallFrame *cf, int action); +static void JimChangeCallFrameId(Jim_Interp *interp, Jim_CallFrame *cf); +static void JimFreeCallFrame(Jim_Interp *interp, Jim_CallFrame *cf, int flags); static int ListSetIndex(Jim_Interp *interp, Jim_Obj *listPtr, int listindex, Jim_Obj *newObjPtr, int flags); static int JimDeleteLocalProcs(Jim_Interp *interp, Jim_Stack *localCommands); static Jim_Obj *JimExpandDictSugar(Jim_Interp *interp, Jim_Obj *objPtr); static void SetDictSubstFromAny(Jim_Interp *interp, Jim_Obj *objPtr); @@ -6147,10 +5937,44 @@ n = utf8_strlen(s2, n); } return n; } #endif + +static int JimWideToString(char *buf, jim_wide wideValue) +{ + int pos = 0; + + if (wideValue == 0) { + buf[pos++] = '0'; + } + else { + char tmp[JIM_INTEGER_SPACE]; + int num = 0; + int i; + + if (wideValue < 0) { + buf[pos++] = '-'; + + i = wideValue % 10; + tmp[num++] = (i > 0) ? (10 - i) : -i; + wideValue /= -10; + } + + while (wideValue) { + tmp[num++] = wideValue % 10; + wideValue /= 10; + } + + for (i = 0; i < num; i++) { + buf[pos++] = '0' + tmp[num - i - 1]; + } + } + buf[pos] = 0; + + return pos; +} static int JimCheckConversion(const char *str, const char *endptr) { if (str[0] == '\0' || str == endptr) { return JIM_ERR; @@ -6205,12 +6029,11 @@ if (str[i] != '-' && str[i] != '+' && !isspace(UCHAR(str[i]))) { return i; } - *base = 10; - return 0; + return 10; } static long jim_strtol(const char *str, char **endptr) { int sign; @@ -6261,10 +6084,46 @@ *widePtr = jim_strtoull(str, &endptr); } return JimCheckConversion(str, endptr); } + +int Jim_DoubleToString(char *buf, double doubleValue) +{ + int len; + int i; + + len = sprintf(buf, "%.12g", doubleValue); + + + for (i = 0; i < len; i++) { + if (buf[i] == '.' || buf[i] == 'e') { +#if defined(JIM_SPRINTF_DOUBLE_NEEDS_FIX) + char *e = strchr(buf, 'e'); + if (e && (e[1] == '-' || e[1] == '+') && e[2] == '0') { + + e += 2; + memmove(e, e + 1, len - (e - buf)); + return len - 1; + } +#endif + return len; + } + + if (buf[i] == 'i' || buf[i] == 'I' || buf[i] == 'n' || buf[i] == 'N') { + buf[i] = toupper(UCHAR(buf[i])); + buf[i + 3] = 0; + return i + 3; + } + } + + buf[i++] = '.'; + buf[i++] = '0'; + buf[i] = '\0'; + + return i; +} int Jim_StringToDouble(const char *str, double *doublePtr) { char *endptr; @@ -6287,23 +6146,23 @@ } return res; } #ifdef JIM_DEBUG_PANIC -static void JimPanicDump(int condition, const char *fmt, ...) +void JimPanicDump(int condition, const char *fmt, ...) { va_list ap; if (!condition) { return; } va_start(ap, fmt); - fprintf(stderr, "\nJIM INTERPRETER PANIC: "); + fprintf(stderr, JIM_NL "JIM INTERPRETER PANIC: "); vfprintf(stderr, fmt, ap); - fprintf(stderr, "\n\n"); + fprintf(stderr, JIM_NL JIM_NL); va_end(ap); #ifdef HAVE_BACKTRACE { void *array[40]; @@ -6311,13 +6170,13 @@ char **strings; size = backtrace(array, 40); strings = backtrace_symbols(array, size); for (i = 0; i < size; i++) - fprintf(stderr, "[backtrace] %s\n", strings[i]); - fprintf(stderr, "[backtrace] Include the above lines and the output\n"); - fprintf(stderr, "[backtrace] of 'nm ' in the bug report.\n"); + fprintf(stderr, "[backtrace] %s" JIM_NL, strings[i]); + fprintf(stderr, "[backtrace] Include the above lines and the output" JIM_NL); + fprintf(stderr, "[backtrace] of 'nm ' in the bug report." JIM_NL); } #endif exit(1); } @@ -6392,23 +6251,17 @@ return h; } - static void JimResetHashTable(Jim_HashTable *ht) { ht->table = NULL; ht->size = 0; ht->sizemask = 0; ht->used = 0; ht->collisions = 0; -#ifdef JIM_RANDOMISE_HASH - ht->uniq = (rand() ^ time(NULL) ^ clock()); -#else - ht->uniq = 0; -#endif } static void JimInitHashTableIterator(Jim_HashTable *ht, Jim_HashTableIterator *iter) { iter->ht = ht; @@ -6446,12 +6299,10 @@ Jim_InitHashTable(&n, ht->type, ht->privdata); n.size = realsize; n.sizemask = realsize - 1; n.table = Jim_Alloc(realsize * sizeof(Jim_HashEntry *)); - - n.uniq = ht->uniq; memset(n.table, 0, realsize * sizeof(Jim_HashEntry *)); n.used = ht->used; @@ -6504,27 +6355,20 @@ int existed; Jim_HashEntry *entry; entry = JimInsertHashEntry(ht, key, 1); if (entry->key) { - if (ht->type->valDestructor && ht->type->valDup) { - void *newval = ht->type->valDup(ht->privdata, val); - ht->type->valDestructor(ht->privdata, entry->u.val); - entry->u.val = newval; - } - else { - Jim_FreeEntryVal(ht, entry); - Jim_SetHashVal(ht, entry, val); - } + + Jim_FreeEntryVal(ht, entry); existed = 1; } else { Jim_SetHashKey(ht, entry, key); - Jim_SetHashVal(ht, entry, val); existed = 0; } + Jim_SetHashVal(ht, entry, val); return existed; } @@ -6689,11 +6533,11 @@ return Jim_GenHashFunction(key, strlen(key)); } static void *JimStringCopyHTDup(void *privdata, const void *key) { - return Jim_StrDup(key); + return strdup(key); } static int JimStringCopyHTKeyCompare(void *privdata, const void *key1, const void *key2) { return strcmp(key1, key2) == 0; @@ -6789,11 +6633,11 @@ freeFunc(stack->vector[i]); } -#define JIM_TT_NONE 0 +#define JIM_TT_NONE 0 #define JIM_TT_STR 1 #define JIM_TT_ESC 2 #define JIM_TT_VAR 3 #define JIM_TT_DICTSUGAR 4 #define JIM_TT_CMD 5 @@ -6822,15 +6666,10 @@ #define JIM_PS_DEF 0 #define JIM_PS_QUOTE 1 #define JIM_PS_DICTSUGAR 2 -struct JimParseMissing { - int ch; - int line; -}; - struct JimParserCtx { const char *p; int len; int linenr; @@ -6839,11 +6678,17 @@ int tline; int tt; int eof; int state; int comment; - struct JimParseMissing missing; + char missing; + int missingline; +}; + +struct JimParseResult { + char missing; + int line; }; static int JimParseScript(struct JimParserCtx *pc); static int JimParseSep(struct JimParserCtx *pc); static int JimParseEol(struct JimParserCtx *pc); @@ -6853,10 +6698,11 @@ static int JimParseBrace(struct JimParserCtx *pc); static int JimParseStr(struct JimParserCtx *pc); static int JimParseComment(struct JimParserCtx *pc); static void JimParseSubCmd(struct JimParserCtx *pc); static int JimParseSubQuote(struct JimParserCtx *pc); +static void JimParseSubCmd(struct JimParserCtx *pc); static Jim_Obj *JimParserGetTokenObj(Jim_Interp *interp, struct JimParserCtx *pc); static void JimParserInit(struct JimParserCtx *pc, const char *prg, int len, int linenr) { pc->p = prg; @@ -6867,12 +6713,12 @@ pc->tt = JIM_TT_NONE; pc->eof = 0; pc->state = JIM_PS_DEF; pc->linenr = linenr; pc->comment = 1; - pc->missing.ch = ' '; - pc->missing.line = linenr; + pc->missing = ' '; + pc->missingline = linenr; } static int JimParseScript(struct JimParserCtx *pc) { while (1) { @@ -7004,12 +6850,12 @@ break; } pc->p++; pc->len--; } - pc->missing.ch = '{'; - pc->missing.line = pc->tline; + pc->missing = '{'; + pc->missingline = pc->tline; pc->tend = pc->p - 1; } static int JimParseSubQuote(struct JimParserCtx *pc) { @@ -7051,12 +6897,12 @@ break; } pc->p++; pc->len--; } - pc->missing.ch = '"'; - pc->missing.line = line; + pc->missing = '"'; + pc->missingline = line; pc->tend = pc->p - 1; return tt; } static void JimParseSubCmd(struct JimParserCtx *pc) @@ -7110,12 +6956,12 @@ } startofword = isspace(UCHAR(*pc->p)); pc->p++; pc->len--; } - pc->missing.ch = '['; - pc->missing.line = line; + pc->missing = '['; + pc->missingline = line; pc->tend = pc->p - 1; } static int JimParseBrace(struct JimParserCtx *pc) { @@ -7255,19 +7101,19 @@ if (*pc->p == '"') { pc->state = JIM_PS_QUOTE; pc->p++; pc->len--; - pc->missing.line = pc->tline; + pc->missingline = pc->tline; } } pc->tstart = pc->p; pc->tline = pc->linenr; while (1) { if (pc->len == 0) { if (pc->state == JIM_PS_QUOTE) { - pc->missing.ch = '"'; + pc->missing = '"'; } pc->tend = pc->p - 1; pc->tt = JIM_TT_ESC; return JIM_OK; } @@ -7283,14 +7129,10 @@ pc->linenr++; } pc->p++; pc->len--; } - else if (pc->len == 1) { - - pc->missing.ch = '\\'; - } break; case '(': if (pc->len > 1 && pc->p[1] != '$') { break; @@ -7347,26 +7189,17 @@ } static int JimParseComment(struct JimParserCtx *pc) { while (*pc->p) { - if (*pc->p == '\\') { - pc->p++; - pc->len--; - if (pc->len == 0) { - pc->missing.ch = '\\'; - return JIM_OK; - } - if (*pc->p == '\n') { - pc->linenr++; - } - } - else if (*pc->p == '\n') { - pc->p++; - pc->len--; - pc->linenr++; - break; + if (*pc->p == '\n') { + pc->linenr++; + if (*(pc->p - 1) != '\\') { + pc->p++; + pc->len--; + return JIM_OK; + } } pc->p++; pc->len--; } return JIM_OK; @@ -7584,13 +7417,13 @@ JimParserInit(&parser, s, len, 1); while (!parser.eof) { JimParseScript(&parser); } if (stateCharPtr) { - *stateCharPtr = parser.missing.ch; + *stateCharPtr = parser.missing; } - return parser.missing.ch == ' '; + return parser.missing == ' '; } static int JimParseListSep(struct JimParserCtx *pc); static int JimParseListStr(struct JimParserCtx *pc); static int JimParseListQuote(struct JimParserCtx *pc); @@ -7748,21 +7581,17 @@ objPtr->prevObjPtr->nextObjPtr = objPtr->nextObjPtr; if (objPtr->nextObjPtr) objPtr->nextObjPtr->prevObjPtr = objPtr->prevObjPtr; if (interp->liveList == objPtr) interp->liveList = objPtr->nextObjPtr; -#ifdef JIM_DISABLE_OBJECT_POOL - Jim_Free(objPtr); -#else objPtr->prevObjPtr = NULL; objPtr->nextObjPtr = interp->freeList; if (interp->freeList) interp->freeList->prevObjPtr = objPtr; interp->freeList = objPtr; objPtr->refCount = -1; -#endif } void Jim_InvalidateStringRep(Jim_Obj *objPtr) { @@ -7837,23 +7666,16 @@ const char *Jim_String(Jim_Obj *objPtr) { if (objPtr->bytes == NULL) { - JimPanic((objPtr->typePtr == NULL, "UpdateStringProc called against typeless value.")); JimPanic((objPtr->typePtr->updateStringProc == NULL, "UpdateStringProc called against '%s' type.", objPtr->typePtr->name)); objPtr->typePtr->updateStringProc(objPtr); } return objPtr->bytes; } -static void JimSetStringBytes(Jim_Obj *objPtr, const char *str) -{ - objPtr->bytes = Jim_StrDup(str); - objPtr->length = strlen(str); -} - static void FreeDictSubstInternalRep(Jim_Interp *interp, Jim_Obj *objPtr); static void DupDictSubstInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr); static const Jim_ObjType dictSubstObjType = { "dict-substitution", @@ -7890,10 +7712,11 @@ static void DupStringInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr) { JIM_NOTUSED(interp); dupPtr->internalRep.strValue.maxLength = srcPtr->length; + dupPtr->internalRep.strValue.charLength = srcPtr->internalRep.strValue.charLength; } static int SetStringFromAny(Jim_Interp *interp, Jim_Obj *objPtr) { @@ -7938,17 +7761,18 @@ if (len == -1) len = strlen(s); if (len == 0) { objPtr->bytes = JimEmptyStringRep; + objPtr->length = 0; } else { objPtr->bytes = Jim_Alloc(len + 1); + objPtr->length = len; memcpy(objPtr->bytes, s, len); objPtr->bytes[len] = '\0'; } - objPtr->length = len; objPtr->typePtr = NULL; return objPtr; } @@ -7976,11 +7800,11 @@ Jim_Obj *Jim_NewStringObjNoAlloc(Jim_Interp *interp, char *s, int len) { Jim_Obj *objPtr = Jim_NewObj(interp); objPtr->bytes = s; - objPtr->length = (len == -1) ? strlen(s) : len; + objPtr->length = len == -1 ? strlen(s) : len; objPtr->typePtr = NULL; return objPtr; } static void StringAppendString(Jim_Obj *objPtr, const char *str, int len) @@ -8005,17 +7829,17 @@ } objPtr->internalRep.strValue.maxLength = needlen; } memcpy(objPtr->bytes + objPtr->length, str, len); objPtr->bytes[objPtr->length + len] = '\0'; - if (objPtr->internalRep.strValue.charLength >= 0) { objPtr->internalRep.strValue.charLength += utf8_strlen(objPtr->bytes + objPtr->length, len); } objPtr->length += len; } + void Jim_AppendString(Jim_Interp *interp, Jim_Obj *objPtr, const char *str, int len) { JimPanic((Jim_IsShared(objPtr), "Jim_AppendString called with shared object")); SetStringFromAny(interp, objPtr); @@ -8023,11 +7847,13 @@ } void Jim_AppendObj(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *appendObjPtr) { int len; - const char *str = Jim_GetString(appendObjPtr, &len); + const char *str; + + str = Jim_GetString(appendObjPtr, &len); Jim_AppendString(interp, objPtr, str, len); } void Jim_AppendStrings(Jim_Interp *interp, Jim_Obj *objPtr, ...) { @@ -8034,11 +7860,11 @@ va_list ap; SetStringFromAny(interp, objPtr); va_start(ap, objPtr); while (1) { - const char *s = va_arg(ap, const char *); + char *s = va_arg(ap, char *); if (s == NULL) break; Jim_AppendString(interp, objPtr, s, -1); } @@ -8045,20 +7871,20 @@ va_end(ap); } int Jim_StringEqObj(Jim_Obj *aObjPtr, Jim_Obj *bObjPtr) { - if (aObjPtr == bObjPtr) { + const char *aStr, *bStr; + int aLen, bLen; + + if (aObjPtr == bObjPtr) return 1; - } - else { - int Alen, Blen; - const char *sA = Jim_GetString(aObjPtr, &Alen); - const char *sB = Jim_GetString(bObjPtr, &Blen); - - return Alen == Blen && memcmp(sA, sB, Alen) == 0; - } + aStr = Jim_GetString(aObjPtr, &aLen); + bStr = Jim_GetString(bObjPtr, &bLen); + if (aLen != bLen) + return 0; + return JimStringCompare(aStr, aLen, bStr, bLen) == 0; } int Jim_StringMatchObj(Jim_Interp *interp, Jim_Obj *patternObjPtr, Jim_Obj *objPtr, int nocase) { return JimGlobMatch(Jim_String(patternObjPtr), Jim_String(objPtr), nocase); @@ -8219,11 +8045,11 @@ static void JimStrCopyUpperLower(char *dest, const char *str, int uc) { while (*str) { int c; str += utf8_tounicode(str, &c); - dest += utf8_getchars(dest, uc ? utf8_upper(c) : utf8_lower(c)); + dest += utf8_fromunicode(dest, uc ? utf8_upper(c) : utf8_lower(c)); } *dest = 0; } static Jim_Obj *JimStringToLower(Jim_Interp *interp, Jim_Obj *strObjPtr) @@ -8279,11 +8105,11 @@ len *= 2; #endif buf = p = Jim_Alloc(len + 1); str += utf8_tounicode(str, &c); - p += utf8_getchars(p, utf8_title(c)); + p += utf8_fromunicode(p, utf8_title(c)); JimStrCopyUpperLower(p, str, 0); return Jim_NewStringObjNoAlloc(interp, buf, -1); } @@ -8386,11 +8212,10 @@ if (nontrim == NULL) { return Jim_NewEmptyStringObj(interp); } if (nontrim == strObjPtr->bytes + len) { - return strObjPtr; } if (Jim_IsShared(strObjPtr)) { strObjPtr = Jim_NewStringObj(interp, strObjPtr->bytes, (nontrim - strObjPtr->bytes)); @@ -8410,29 +8235,20 @@ Jim_Obj *objPtr = JimStringTrimLeft(interp, strObjPtr, trimcharsObjPtr); strObjPtr = JimStringTrimRight(interp, objPtr, trimcharsObjPtr); - - if (objPtr != strObjPtr && objPtr->refCount == 0) { + if (objPtr != strObjPtr) { - Jim_FreeNewObj(interp, objPtr); + Jim_IncrRefCount(objPtr); + Jim_DecrRefCount(interp, objPtr); } return strObjPtr; } -#ifdef HAVE_ISASCII -#define jim_isascii isascii -#else -static int jim_isascii(int c) -{ - return !(c & ~0x7f); -} -#endif - static int JimStringIs(Jim_Interp *interp, Jim_Obj *strObjPtr, Jim_Obj *strClass, int strict) { static const char * const strclassnames[] = { "integer", "alpha", "alnum", "ascii", "digit", "double", "lower", "upper", "space", "xdigit", @@ -8454,32 +8270,32 @@ return JIM_ERR; } str = Jim_GetString(strObjPtr, &len); if (len == 0) { - Jim_SetResultBool(interp, !strict); + Jim_SetResultInt(interp, !strict); return JIM_OK; } switch (strclass) { case STR_IS_INTEGER: { jim_wide w; - Jim_SetResultBool(interp, JimGetWideNoErr(interp, strObjPtr, &w) == JIM_OK); + Jim_SetResultInt(interp, JimGetWideNoErr(interp, strObjPtr, &w) == JIM_OK); return JIM_OK; } case STR_IS_DOUBLE: { double d; - Jim_SetResultBool(interp, Jim_GetDouble(interp, strObjPtr, &d) == JIM_OK && errno != ERANGE); + Jim_SetResultInt(interp, Jim_GetDouble(interp, strObjPtr, &d) == JIM_OK && errno != ERANGE); return JIM_OK; } case STR_IS_ALPHA: isclassfunc = isalpha; break; case STR_IS_ALNUM: isclassfunc = isalnum; break; - case STR_IS_ASCII: isclassfunc = jim_isascii; break; + case STR_IS_ASCII: isclassfunc = isascii; break; case STR_IS_DIGIT: isclassfunc = isdigit; break; case STR_IS_LOWER: isclassfunc = islower; break; case STR_IS_UPPER: isclassfunc = isupper; break; case STR_IS_SPACE: isclassfunc = isspace; break; case STR_IS_XDIGIT: isclassfunc = isxdigit; break; @@ -8491,15 +8307,15 @@ return JIM_ERR; } for (i = 0; i < len; i++) { if (!isclassfunc(str[i])) { - Jim_SetResultBool(interp, 0); + Jim_SetResultInt(interp, 0); return JIM_OK; } } - Jim_SetResultBool(interp, 1); + Jim_SetResultInt(interp, 1); return JIM_OK; } @@ -8511,19 +8327,17 @@ JIM_TYPE_REFERENCES, }; int Jim_CompareStringImmediate(Jim_Interp *interp, Jim_Obj *objPtr, const char *str) { - if (objPtr->typePtr == &comparedStringObjType && objPtr->internalRep.ptr == str) { + if (objPtr->typePtr == &comparedStringObjType && objPtr->internalRep.ptr == str) return 1; - } else { const char *objStr = Jim_String(objPtr); if (strcmp(str, objStr) != 0) return 0; - if (objPtr->typePtr != &comparedStringObjType) { Jim_FreeIntRep(interp, objPtr); objPtr->typePtr = &comparedStringObjType; } objPtr->internalRep.ptr = (char *)str; @@ -8565,23 +8379,24 @@ static void JimSetSourceInfo(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *fileNameObj, int lineNumber) { JimPanic((Jim_IsShared(objPtr), "JimSetSourceInfo called with shared object")); - JimPanic((objPtr->typePtr != NULL, "JimSetSourceInfo called with typed object")); + JimPanic((objPtr->typePtr == &sourceObjType, "JimSetSourceInfo called with non-source object")); Jim_IncrRefCount(fileNameObj); objPtr->internalRep.sourceValue.fileNameObj = fileNameObj; objPtr->internalRep.sourceValue.lineNumber = lineNumber; objPtr->typePtr = &sourceObjType; } + static const Jim_ObjType scriptLineObjType = { "scriptline", NULL, NULL, NULL, - JIM_NONE, + 0, }; static Jim_Obj *JimNewScriptLineObj(Jim_Interp *interp, int argc, int line) { Jim_Obj *objPtr; @@ -8597,15 +8412,16 @@ objPtr->internalRep.scriptLineValue.argc = argc; objPtr->internalRep.scriptLineValue.line = line; return objPtr; } + +#define JIM_CMDSTRUCT_EXPAND -1 static void FreeScriptInternalRep(Jim_Interp *interp, Jim_Obj *objPtr); static void DupScriptInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr); -static void JimSetScriptFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr); -static int JimParseCheckMissing(Jim_Interp *interp, int ch); +static int SetScriptFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr, struct JimParseResult *result); static const Jim_ObjType scriptObjType = { "script", FreeScriptInternalRep, DupScriptInternalRep, @@ -8613,34 +8429,34 @@ JIM_TYPE_REFERENCES, }; typedef struct ScriptToken { - Jim_Obj *objPtr; int type; + Jim_Obj *objPtr; } ScriptToken; typedef struct ScriptObj { - ScriptToken *token; - Jim_Obj *fileNameObj; int len; + ScriptToken *token; int substFlags; int inUse; /* Used to share a ScriptObj. Currently only used by Jim_EvalObj() as protection against shimmering of the currently evaluated object. */ + Jim_Obj *fileNameObj; int firstline; int linenr; - int missing; } ScriptObj; void FreeScriptInternalRep(Jim_Interp *interp, Jim_Obj *objPtr) { int i; struct ScriptObj *script = (void *)objPtr->internalRep.ptr; - if (--script->inUse != 0) + script->inUse--; + if (script->inUse != 0) return; for (i = 0; i < script->len; i++) { Jim_DecrRefCount(interp, script->token[i].objPtr); } Jim_Free(script->token); @@ -8651,10 +8467,11 @@ void DupScriptInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr) { JIM_NOTUSED(interp); JIM_NOTUSED(srcPtr); + dupPtr->typePtr = NULL; } typedef struct { @@ -8849,11 +8666,11 @@ token--; } script->len = token - script->token; - JimPanic((script->len >= count, "allocated script array is too short")); + assert(script->len < count); #ifdef DEBUG_SHOW_SCRIPT printf("==== Script (%s) ====\n", Jim_String(script->fileNameObj)); for (i = 0; i < script->len; i++) { const ScriptToken *t = &script->token[i]; @@ -8861,35 +8678,10 @@ } #endif } -static int JimParseCheckMissing(Jim_Interp *interp, int ch) -{ - const char *msg; - - switch (ch) { - case '\\': - case ' ': - return JIM_OK; - - case '[': - msg = "unmatched \"[\""; - break; - case '{': - msg = "missing close-brace"; - break; - case '"': - default: - msg = "missing quote"; - break; - } - - Jim_SetResultString(interp, msg, -1); - return JIM_ERR; -} - static void SubstObjAddTokens(Jim_Interp *interp, struct ScriptObj *script, ParseTokenList *tokenlist) { int i; struct ScriptToken *token; @@ -8907,11 +8699,11 @@ } script->len = i; } -static void JimSetScriptFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr) +static int SetScriptFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr, struct JimParseResult *result) { int scriptTextLen; const char *scriptText = Jim_GetString(objPtr, &scriptTextLen); struct JimParserCtx parser; struct ScriptObj *script; @@ -8930,10 +8722,16 @@ while (!parser.eof) { JimParseScript(&parser); ScriptAddToken(&tokenlist, parser.tstart, parser.tend - parser.tstart + 1, parser.tt, parser.tline); } + if (result && parser.missing != ' ') { + ScriptTokenListFree(&tokenlist); + result->missing = parser.missing; + result->line = parser.missingline; + return JIM_ERR; + } ScriptAddToken(&tokenlist, scriptText + scriptTextLen, 0, JIM_TT_EOF, 0); @@ -8945,12 +8743,10 @@ } else { script->fileNameObj = interp->emptyObj; } Jim_IncrRefCount(script->fileNameObj); - script->missing = parser.missing.ch; - script->linenr = parser.missing.line; ScriptObjAddTokens(interp, script, &tokenlist); ScriptTokenListFree(&tokenlist); @@ -8957,37 +8753,26 @@ Jim_FreeIntRep(interp, objPtr); Jim_SetIntRepPtr(objPtr, script); objPtr->typePtr = &scriptObjType; + + return JIM_OK; } -static void JimAddErrorToStack(Jim_Interp *interp, ScriptObj *script); - -ScriptObj *JimGetScript(Jim_Interp *interp, Jim_Obj *objPtr) +ScriptObj *Jim_GetScript(Jim_Interp *interp, Jim_Obj *objPtr) { if (objPtr == interp->emptyObj) { objPtr = interp->nullScriptObj; } if (objPtr->typePtr != &scriptObjType || ((struct ScriptObj *)Jim_GetIntRepPtr(objPtr))->substFlags) { - JimSetScriptFromAny(interp, objPtr); - } - - return (ScriptObj *)Jim_GetIntRepPtr(objPtr); -} - -static int JimScriptValid(Jim_Interp *interp, ScriptObj *script) -{ - if (JimParseCheckMissing(interp, script->missing) == JIM_ERR) { - JimAddErrorToStack(interp, script); - return 0; - } - return 1; -} - + SetScriptFromAny(interp, objPtr, NULL); + } + return (ScriptObj *) Jim_GetIntRepPtr(objPtr); +} static void JimIncrCmdRefCount(Jim_Cmd *cmdPtr) { cmdPtr->inUse++; } @@ -9066,26 +8851,10 @@ Jim_AppendStrings(interp, nsObj, "::", name, NULL); } return nsObj; } -Jim_Obj *Jim_MakeGlobalNamespaceName(Jim_Interp *interp, Jim_Obj *nameObjPtr) -{ - Jim_Obj *resultObj; - - const char *name = Jim_String(nameObjPtr); - if (name[0] == ':' && name[1] == ':') { - return nameObjPtr; - } - Jim_IncrRefCount(nameObjPtr); - resultObj = Jim_NewStringObj(interp, "::", -1); - Jim_AppendObj(interp, resultObj, nameObjPtr); - Jim_DecrRefCount(interp, nameObjPtr); - - return resultObj; -} - static const char *JimQualifyName(Jim_Interp *interp, const char *name, Jim_Obj **objPtrPtr) { Jim_Obj *objPtr = interp->emptyObj; if (name[0] == ':' && name[1] == ':') { @@ -9108,15 +8877,10 @@ #else #define JimQualifyName(INTERP, NAME, DUMMY) (((NAME)[0] == ':' && (NAME)[1] == ':') ? (NAME) + 2 : (NAME)) #define JimFreeQualifiedName(INTERP, DUMMY) (void)(DUMMY) - -Jim_Obj *Jim_MakeGlobalNamespaceName(Jim_Interp *interp, Jim_Obj *nameObjPtr) -{ - return nameObjPtr; -} #endif static int JimCreateCommand(Jim_Interp *interp, const char *name, Jim_Cmd *cmd) { Jim_HashEntry *he = Jim_FindHashEntry(&interp->commands, name); @@ -9125,12 +8889,12 @@ Jim_InterpIncrProcEpoch(interp); } if (he && interp->local) { - cmd->prevCmd = Jim_GetHashEntryVal(he); - Jim_SetHashVal(&interp->commands, he, cmd); + cmd->prevCmd = he->u.val; + he->u.val = cmd; } else { if (he) { Jim_DeleteHashEntry(&interp->commands, name); @@ -9169,19 +8933,19 @@ } cmdPtr->u.proc.staticVars = Jim_Alloc(sizeof(Jim_HashTable)); Jim_InitHashTable(cmdPtr->u.proc.staticVars, &JimVariablesHashTableType, interp); for (i = 0; i < len; i++) { - Jim_Obj *objPtr, *initObjPtr, *nameObjPtr; + Jim_Obj *objPtr = NULL, *initObjPtr = NULL, *nameObjPtr = NULL; Jim_Var *varPtr; int subLen; - objPtr = Jim_ListGetIndex(interp, staticsListObjPtr, i); + Jim_ListIndex(interp, staticsListObjPtr, i, &objPtr, JIM_NONE); subLen = Jim_ListLength(interp, objPtr); if (subLen == 1 || subLen == 2) { - nameObjPtr = Jim_ListGetIndex(interp, objPtr, 0); + Jim_ListIndex(interp, objPtr, 0, &nameObjPtr, JIM_NONE); if (subLen == 1) { initObjPtr = Jim_GetVariable(interp, nameObjPtr, JIM_NONE); if (initObjPtr == NULL) { Jim_SetResultFormatted(interp, "variable for initialization of static \"%#s\" not found in the local context", @@ -9188,11 +8952,11 @@ nameObjPtr); return JIM_ERR; } } else { - initObjPtr = Jim_ListGetIndex(interp, objPtr, 1); + Jim_ListIndex(interp, objPtr, 1, &initObjPtr, JIM_NONE); } if (JimValidName(interp, "static variable", nameObjPtr) != JIM_OK) { return JIM_ERR; } @@ -9274,11 +9038,11 @@ Jim_Obj *nameObjPtr; Jim_Obj *defaultObjPtr; int len; - argPtr = Jim_ListGetIndex(interp, argListObjPtr, i); + Jim_ListIndex(interp, argListObjPtr, i, &argPtr, JIM_NONE); len = Jim_ListLength(interp, argPtr); if (len == 0) { Jim_SetResultString(interp, "argument with no name", -1); err: JimDecrCmdRefCount(interp, cmdPtr); @@ -9289,12 +9053,12 @@ goto err; } if (len == 2) { - nameObjPtr = Jim_ListGetIndex(interp, argPtr, 0); - defaultObjPtr = Jim_ListGetIndex(interp, argPtr, 1); + Jim_ListIndex(interp, argPtr, 0, &nameObjPtr, JIM_NONE); + Jim_ListIndex(interp, argPtr, 1, &defaultObjPtr, JIM_NONE); } else { nameObjPtr = argPtr; defaultObjPtr = NULL; @@ -9368,11 +9132,11 @@ else if (Jim_FindHashEntry(&interp->commands, fqnew)) { Jim_SetResultFormatted(interp, "can't rename to \"%s\": command already exists", newName); } else { - cmdPtr = Jim_GetHashEntryVal(he); + cmdPtr = he->u.val; JimIncrCmdRefCount(cmdPtr); JimUpdateProcNamespace(interp, cmdPtr, fqnew); Jim_AddHashEntry(&interp->commands, fqnew, cmdPtr); @@ -9453,11 +9217,11 @@ return NULL; } #ifdef jim_ext_namespace found: #endif - cmd = Jim_GetHashEntryVal(he); + cmd = (Jim_Cmd *)he->u.val; Jim_FreeIntRep(interp, objPtr); objPtr->typePtr = &commandObjType; objPtr->internalRep.cmdValue.procEpoch = interp->procEpoch; @@ -9559,11 +9323,11 @@ Jim_FreeIntRep(interp, objPtr); objPtr->typePtr = &variableObjType; objPtr->internalRep.varValue.callFrameId = framePtr->id; - objPtr->internalRep.varValue.varPtr = Jim_GetHashEntryVal(he); + objPtr->internalRep.varValue.varPtr = he->u.val; objPtr->internalRep.varValue.global = global; return JIM_OK; } @@ -9877,11 +9641,11 @@ } retval = Jim_DeleteHashEntry(&framePtr->vars, name); if (retval == JIM_OK) { - framePtr->id = interp->callFrameEpoch++; + JimChangeCallFrameId(interp, framePtr); } } } if (retval != JIM_OK && (flags & JIM_ERRMSG)) { Jim_SetResultFormatted(interp, "can't unset \"%#s\": no such variable", nameObjPtr); @@ -9961,17 +9725,28 @@ return NULL; } ret = Jim_DictKey(interp, dictObjPtr, keyObjPtr, &resObjPtr, JIM_NONE); if (ret != JIM_OK) { - Jim_SetResultFormatted(interp, - "can't read \"%#s(%#s)\": %s array", varObjPtr, keyObjPtr, - ret < 0 ? "variable isn't" : "no such element in"); + resObjPtr = NULL; + if (ret < 0) { + Jim_SetResultFormatted(interp, + "can't read \"%#s(%#s)\": variable isn't array", varObjPtr, keyObjPtr); + } + else { + Jim_SetResultFormatted(interp, + "can't read \"%#s(%#s)\": no such element in array", varObjPtr, keyObjPtr); + } } else if ((flags & JIM_UNSHARED) && Jim_IsShared(dictObjPtr)) { + dictObjPtr = Jim_DuplicateObj(interp, dictObjPtr); + if (Jim_SetVariable(interp, varObjPtr, dictObjPtr) != JIM_OK) { + + JimPanic((1, "SetVariable failed for JIM_UNSHARED")); + } - Jim_SetVariable(interp, varObjPtr, Jim_DuplicateObj(interp, dictObjPtr)); + Jim_DictKey(interp, dictObjPtr, keyObjPtr, &resObjPtr, JIM_NONE); } return resObjPtr; } @@ -10068,67 +9843,68 @@ Jim_CallFrame *cf; if (interp->freeFramesList) { cf = interp->freeFramesList; interp->freeFramesList = cf->next; - - cf->argv = NULL; - cf->argc = 0; - cf->procArgsObjPtr = NULL; - cf->procBodyObjPtr = NULL; - cf->next = NULL; - cf->staticVars = NULL; - cf->localCommands = NULL; - cf->tailcall = 0; - cf->tailcallObj = NULL; - cf->tailcallCmd = NULL; } else { cf = Jim_Alloc(sizeof(*cf)); - memset(cf, 0, sizeof(*cf)); - - Jim_InitHashTable(&cf->vars, &JimVariablesHashTableType, interp); + cf->vars.table = NULL; } cf->id = interp->callFrameEpoch++; cf->parent = parent; cf->level = parent ? parent->level + 1 : 0; + cf->argv = NULL; + cf->argc = 0; + cf->procArgsObjPtr = NULL; + cf->procBodyObjPtr = NULL; + cf->next = NULL; + cf->staticVars = NULL; + cf->localCommands = NULL; + cf->nsObj = nsObj; Jim_IncrRefCount(nsObj); - + if (cf->vars.table == NULL) + Jim_InitHashTable(&cf->vars, &JimVariablesHashTableType, interp); return cf; } + +static void JimChangeCallFrameId(Jim_Interp *interp, Jim_CallFrame *cf) +{ + cf->id = interp->callFrameEpoch++; +} + static int JimDeleteLocalProcs(Jim_Interp *interp, Jim_Stack *localCommands) { if (localCommands) { Jim_Obj *cmdNameObj; while ((cmdNameObj = Jim_StackPop(localCommands)) != NULL) { Jim_HashEntry *he; Jim_Obj *fqObjName; - Jim_HashTable *ht = &interp->commands; const char *fqname = JimQualifyName(interp, Jim_String(cmdNameObj), &fqObjName); - he = Jim_FindHashEntry(ht, fqname); + he = Jim_FindHashEntry(&interp->commands, fqname); if (he) { - Jim_Cmd *cmd = Jim_GetHashEntryVal(he); + Jim_Cmd *cmd = he->u.val; if (cmd->prevCmd) { Jim_Cmd *prevCmd = cmd->prevCmd; cmd->prevCmd = NULL; JimDecrCmdRefCount(interp, cmd); - Jim_SetHashVal(ht, he, prevCmd); + he->u.val = prevCmd; } else { - Jim_DeleteHashEntry(ht, fqname); + Jim_DeleteHashEntry(&interp->commands, fqname); Jim_InterpIncrProcEpoch(interp); } } Jim_DecrRefCount(interp, cmdNameObj); JimFreeQualifiedName(interp, fqObjName); @@ -10138,45 +9914,47 @@ } return JIM_OK; } -#define JIM_FCF_FULL 0 -#define JIM_FCF_REUSE 1 -static void JimFreeCallFrame(Jim_Interp *interp, Jim_CallFrame *cf, int action) - { - JimDeleteLocalProcs(interp, cf->localCommands); - +#define JIM_FCF_NONE 0 +#define JIM_FCF_NOHT 1 +static void JimFreeCallFrame(Jim_Interp *interp, Jim_CallFrame *cf, int flags) +{ if (cf->procArgsObjPtr) Jim_DecrRefCount(interp, cf->procArgsObjPtr); if (cf->procBodyObjPtr) Jim_DecrRefCount(interp, cf->procBodyObjPtr); Jim_DecrRefCount(interp, cf->nsObj); - if (action == JIM_FCF_FULL || cf->vars.size != JIM_HT_INITIAL_SIZE) + if (!(flags & JIM_FCF_NOHT)) Jim_FreeHashTable(&cf->vars); else { int i; Jim_HashEntry **table = cf->vars.table, *he; for (i = 0; i < JIM_HT_INITIAL_SIZE; i++) { he = table[i]; while (he != NULL) { Jim_HashEntry *nextEntry = he->next; - Jim_Var *varPtr = Jim_GetHashEntryVal(he); + Jim_Var *varPtr = (void *)he->u.val; Jim_DecrRefCount(interp, varPtr->objPtr); - Jim_Free(Jim_GetHashEntryKey(he)); - Jim_Free(varPtr); + Jim_Free(he->u.val); + Jim_Free((void *)he->key); Jim_Free(he); table[i] = NULL; he = nextEntry; } } cf->vars.used = 0; } + + JimDeleteLocalProcs(interp, cf->localCommands); + cf->next = interp->freeFramesList; interp->freeFramesList = cf; + } #ifdef JIM_REFERENCES @@ -10253,16 +10031,21 @@ NULL, UpdateStringOfReference, JIM_TYPE_REFERENCES, }; -static void UpdateStringOfReference(struct Jim_Obj *objPtr) +void UpdateStringOfReference(struct Jim_Obj *objPtr) { + int len; char buf[JIM_REFERENCE_SPACE + 1]; + Jim_Reference *refPtr; - JimFormatReference(buf, objPtr->internalRep.refValue.refPtr, objPtr->internalRep.refValue.id); - JimSetStringBytes(objPtr, buf); + refPtr = objPtr->internalRep.refValue.refPtr; + len = JimFormatReference(buf, refPtr, objPtr->internalRep.refValue.id); + objPtr->bytes = Jim_Alloc(len + 1); + memcpy(objPtr->bytes, buf, len + 1); + objPtr->length = len; } static int isrefchar(int c) { return (c == '_' || isalnum(c)); @@ -10313,11 +10096,11 @@ he = Jim_FindHashEntry(&interp->references, &value); if (he == NULL) { Jim_SetResultFormatted(interp, "invalid reference id \"%#s\"", objPtr); return JIM_ERR; } - refPtr = Jim_GetHashEntryVal(he); + refPtr = he->u.val; Jim_FreeIntRep(interp, objPtr); objPtr->typePtr = &referenceObjType; objPtr->internalRep.refValue.id = value; objPtr->internalRep.refValue.refPtr = refPtr; @@ -10430,11 +10213,11 @@ Jim_Collect(interp); } } #endif -int Jim_IsBigEndian(void) +static int JimIsBigEndian(void) { union { unsigned short s; unsigned char c[2]; } uval = {0x0102}; @@ -10486,30 +10269,23 @@ Jim_SetVariableStrWithStr(i, JIM_INTERACTIVE, "0"); Jim_SetVariableStrWithStr(i, "tcl_platform(os)", TCL_PLATFORM_OS); Jim_SetVariableStrWithStr(i, "tcl_platform(platform)", TCL_PLATFORM_PLATFORM); Jim_SetVariableStrWithStr(i, "tcl_platform(pathSeparator)", TCL_PLATFORM_PATH_SEPARATOR); - Jim_SetVariableStrWithStr(i, "tcl_platform(byteOrder)", Jim_IsBigEndian() ? "bigEndian" : "littleEndian"); + Jim_SetVariableStrWithStr(i, "tcl_platform(byteOrder)", JimIsBigEndian() ? "bigEndian" : "littleEndian"); Jim_SetVariableStrWithStr(i, "tcl_platform(threaded)", "0"); Jim_SetVariableStr(i, "tcl_platform(pointerSize)", Jim_NewIntObj(i, sizeof(void *))); Jim_SetVariableStr(i, "tcl_platform(wordSize)", Jim_NewIntObj(i, sizeof(jim_wide))); return i; } void Jim_FreeInterp(Jim_Interp *i) { - Jim_CallFrame *cf, *cfx; - + Jim_CallFrame *cf = i->framePtr, *prevcf, *nextcf; Jim_Obj *objPtr, *nextObjPtr; - - for (cf = i->framePtr; cf; cf = cfx) { - cfx = cf->parent; - JimFreeCallFrame(i, cf, JIM_FCF_FULL); - } - Jim_DecrRefCount(i, i->emptyObj); Jim_DecrRefCount(i, i->trueObj); Jim_DecrRefCount(i, i->falseObj); Jim_DecrRefCount(i, i->result); Jim_DecrRefCount(i, i->stackTrace); @@ -10524,54 +10300,61 @@ #endif Jim_FreeHashTable(&i->packages); Jim_Free(i->prngState); Jim_FreeHashTable(&i->assocData); -#ifdef JIM_MAINTAINER + + while (cf) { + prevcf = cf->parent; + JimFreeCallFrame(i, cf, JIM_FCF_NONE); + cf = prevcf; + } if (i->liveList != NULL) { objPtr = i->liveList; - printf("\n-------------------------------------\n"); - printf("Objects still in the free list:\n"); + printf(JIM_NL "-------------------------------------" JIM_NL); + printf("Objects still in the free list:" JIM_NL); while (objPtr) { const char *type = objPtr->typePtr ? objPtr->typePtr->name : "string"; if (objPtr->bytes && strlen(objPtr->bytes) > 20) { - printf("%p (%d) %-10s: '%.20s...'\n", + printf("%p (%d) %-10s: '%.20s...'" JIM_NL, (void *)objPtr, objPtr->refCount, type, objPtr->bytes); } else { - printf("%p (%d) %-10s: '%s'\n", + printf("%p (%d) %-10s: '%s'" JIM_NL, (void *)objPtr, objPtr->refCount, type, objPtr->bytes ? objPtr->bytes : "(null)"); } if (objPtr->typePtr == &sourceObjType) { - printf("FILE %s LINE %d\n", + printf("FILE %s LINE %d" JIM_NL, Jim_String(objPtr->internalRep.sourceValue.fileNameObj), objPtr->internalRep.sourceValue.lineNumber); } objPtr = objPtr->nextObjPtr; } - printf("-------------------------------------\n\n"); + printf("-------------------------------------" JIM_NL JIM_NL); JimPanic((1, "Live list non empty freeing the interpreter! Leak?")); } -#endif - objPtr = i->freeList; while (objPtr) { nextObjPtr = objPtr->nextObjPtr; Jim_Free(objPtr); objPtr = nextObjPtr; } - - for (cf = i->freeFramesList; cf; cf = cfx) { - cfx = cf->next; - if (cf->vars.table) - Jim_FreeHashTable(&cf->vars); + cf = i->freeFramesList; + while (cf) { + nextcf = cf->next; + if (cf->vars.table != NULL) + Jim_Free(cf->vars.table); Jim_Free(cf); + cf = nextcf; } +#ifdef jim_ext_load + Jim_FreeLoadHandles(i); +#endif Jim_Free(i); } @@ -10666,15 +10449,22 @@ interp->stackTrace = stackTraceObj; interp->errorFlag = 1; len = Jim_ListLength(interp, interp->stackTrace); if (len >= 3) { - if (Jim_Length(Jim_ListGetIndex(interp, interp->stackTrace, len - 2)) == 0) { + Jim_Obj *filenameObj; + + Jim_ListIndex(interp, interp->stackTrace, len - 2, &filenameObj, JIM_NONE); + + Jim_GetString(filenameObj, &len); + + if (!Jim_Length(filenameObj)) { interp->addStackTrace = 1; } } } + static void JimAppendStackTrace(Jim_Interp *interp, const char *procname, Jim_Obj *fileNameObj, int linenr) { if (strcmp(procname, "unknown") == 0) { @@ -10695,15 +10485,14 @@ if (!*procname && Jim_Length(fileNameObj)) { int len = Jim_ListLength(interp, interp->stackTrace); if (len >= 3) { - Jim_Obj *objPtr = Jim_ListGetIndex(interp, interp->stackTrace, len - 3); - if (Jim_Length(objPtr)) { + Jim_Obj *objPtr; + if (Jim_ListIndex(interp, interp->stackTrace, len - 3, &objPtr, JIM_NONE) == JIM_OK && Jim_Length(objPtr)) { - objPtr = Jim_ListGetIndex(interp, interp->stackTrace, len - 2); - if (Jim_Length(objPtr) == 0) { + if (Jim_ListIndex(interp, interp->stackTrace, len - 2, &objPtr, JIM_NONE) == JIM_OK && !Jim_Length(objPtr)) { ListSetIndex(interp, interp->stackTrace, len - 2, fileNameObj, 0); ListSetIndex(interp, interp->stackTrace, len - 1, Jim_NewIntObj(interp, linenr), 0); return; } @@ -10729,11 +10518,12 @@ void *Jim_GetAssocData(Jim_Interp *interp, const char *key) { Jim_HashEntry *entryPtr = Jim_FindHashEntry(&interp->assocData, key); if (entryPtr != NULL) { - AssocDataValue *assocEntryPtr = Jim_GetHashEntryVal(entryPtr); + AssocDataValue *assocEntryPtr = (AssocDataValue *) entryPtr->u.val; + return assocEntryPtr->data; } return NULL; } @@ -10767,44 +10557,20 @@ }; static void UpdateStringOfInt(struct Jim_Obj *objPtr) { + int len; char buf[JIM_INTEGER_SPACE + 1]; - jim_wide wideValue = JimWideValue(objPtr); - int pos = 0; - - if (wideValue == 0) { - buf[pos++] = '0'; - } - else { - char tmp[JIM_INTEGER_SPACE]; - int num = 0; - int i; - - if (wideValue < 0) { - buf[pos++] = '-'; - i = wideValue % 10; - tmp[num++] = (i > 0) ? (10 - i) : -i; - wideValue /= -10; - } - - while (wideValue) { - tmp[num++] = wideValue % 10; - wideValue /= 10; - } - - for (i = 0; i < num; i++) { - buf[pos++] = '0' + tmp[num - i - 1]; - } - } - buf[pos] = 0; - - JimSetStringBytes(objPtr, buf); -} - -static int SetIntFromAny(Jim_Interp *interp, Jim_Obj *objPtr, int flags) + + len = JimWideToString(buf, JimWideValue(objPtr)); + objPtr->bytes = Jim_Alloc(len + 1); + memcpy(objPtr->bytes, buf, len + 1); + objPtr->length = len; +} + +int SetIntFromAny(Jim_Interp *interp, Jim_Obj *objPtr, int flags) { jim_wide wideValue; const char *str; if (objPtr->typePtr == &coercedDoubleObjType) { @@ -10892,65 +10658,22 @@ NULL, UpdateStringOfDouble, JIM_TYPE_NONE, }; -#ifndef HAVE_ISNAN -#undef isnan -#define isnan(X) ((X) != (X)) -#endif -#ifndef HAVE_ISINF -#undef isinf -#define isinf(X) (1.0 / (X) == 0.0) -#endif - -static void UpdateStringOfDouble(struct Jim_Obj *objPtr) -{ - double value = objPtr->internalRep.doubleValue; - - if (isnan(value)) { - JimSetStringBytes(objPtr, "NaN"); - return; - } - if (isinf(value)) { - if (value < 0) { - JimSetStringBytes(objPtr, "-Inf"); - } - else { - JimSetStringBytes(objPtr, "Inf"); - } - return; - } - { - char buf[JIM_DOUBLE_SPACE + 1]; - int i; - int len = sprintf(buf, "%.12g", value); - - - for (i = 0; i < len; i++) { - if (buf[i] == '.' || buf[i] == 'e') { -#if defined(JIM_SPRINTF_DOUBLE_NEEDS_FIX) - char *e = strchr(buf, 'e'); - if (e && (e[1] == '-' || e[1] == '+') && e[2] == '0') { - - e += 2; - memmove(e, e + 1, len - (e - buf)); - } -#endif - break; - } - } - if (buf[i] == '\0') { - buf[i++] = '.'; - buf[i++] = '0'; - buf[i] = '\0'; - } - JimSetStringBytes(objPtr, buf); - } -} - -static int SetDoubleFromAny(Jim_Interp *interp, Jim_Obj *objPtr) +void UpdateStringOfDouble(struct Jim_Obj *objPtr) +{ + int len; + char buf[JIM_DOUBLE_SPACE + 1]; + + len = Jim_DoubleToString(buf, objPtr->internalRep.doubleValue); + objPtr->bytes = Jim_Alloc(len + 1); + memcpy(objPtr->bytes, buf, len + 1); + objPtr->length = len; +} + +int SetDoubleFromAny(Jim_Interp *interp, Jim_Obj *objPtr) { double doubleValue; jim_wide wideValue; const char *str; @@ -10979,11 +10702,11 @@ return JIM_OK; } else { if (Jim_StringToDouble(str, &doubleValue) != JIM_OK) { - Jim_SetResultFormatted(interp, "expected floating-point number but got \"%#s\"", objPtr); + Jim_SetResultFormatted(interp, "expected number but got \"%#s\"", objPtr); return JIM_ERR; } Jim_FreeIntRep(interp, objPtr); } @@ -11158,15 +10881,15 @@ return JIM_ELESTR_SIMPLE; } return JIM_ELESTR_QUOTE; } -static int BackslashQuoteString(const char *s, int len, char *q) +static int BackslashQuoteString(const char *s, char *q) { char *p = q; - while (len--) { + while (*s) { switch (*s) { case ' ': case '$': case '"': case '[': @@ -11278,11 +11001,11 @@ case JIM_ELESTR_QUOTE: if (i == 0 && strRep[0] == '#') { *p++ = '\\'; realLength++; } - qlen = BackslashQuoteString(strRep, len, p); + qlen = BackslashQuoteString(strRep, p); p += qlen; realLength += qlen; break; } @@ -11314,11 +11037,11 @@ if (objPtr->typePtr == &listObjType) { return JIM_OK; } - if (Jim_IsDict(objPtr) && objPtr->bytes == NULL) { + if (Jim_IsDict(objPtr) && !Jim_IsShared(objPtr)) { Jim_Obj **listObjPtrPtr; int len; int i; listObjPtrPtr = JimDictPairs(objPtr, &len); @@ -11418,17 +11141,15 @@ Jim_Interp *interp; enum { JIM_LSORT_ASCII, JIM_LSORT_NOCASE, JIM_LSORT_INTEGER, - JIM_LSORT_REAL, JIM_LSORT_COMMAND } type; int order; int index; int indexed; - int unique; int (*subfn)(Jim_Obj **, Jim_Obj **); }; static struct lsort_info *sort_info; @@ -11464,27 +11185,10 @@ } return JimSign(lhs - rhs) * sort_info->order; } -static int ListSortReal(Jim_Obj **lhsObj, Jim_Obj **rhsObj) -{ - double lhs = 0, rhs = 0; - - if (Jim_GetDouble(sort_info->interp, *lhsObj, &lhs) != JIM_OK || - Jim_GetDouble(sort_info->interp, *rhsObj, &rhs) != JIM_OK) { - longjmp(sort_info->jmpbuf, JIM_ERR); - } - if (lhs == rhs) { - return 0; - } - if (lhs > rhs) { - return sort_info->order; - } - return -sort_info->order; -} - static int ListSortCommand(Jim_Obj **lhsObj, Jim_Obj **rhsObj) { Jim_Obj *compare_script; int rc; @@ -11502,34 +11206,10 @@ } return JimSign(ret) * sort_info->order; } -static void ListRemoveDuplicates(Jim_Obj *listObjPtr, int (*comp)(Jim_Obj **lhs, Jim_Obj **rhs)) -{ - int src; - int dst = 0; - Jim_Obj **ele = listObjPtr->internalRep.listValue.ele; - - for (src = 1; src < listObjPtr->internalRep.listValue.len; src++) { - if (comp(&ele[dst], &ele[src]) == 0) { - - Jim_DecrRefCount(sort_info->interp, ele[dst]); - } - else { - - dst++; - } - ele[dst] = ele[src]; - } - - ele[++dst] = ele[src]; - - - listObjPtr->internalRep.listValue.len = dst; -} - static int ListSortElements(Jim_Interp *interp, Jim_Obj *listObjPtr, struct lsort_info *info) { struct lsort_info *prev_info; @@ -11537,11 +11217,11 @@ int (*fn) (Jim_Obj **, Jim_Obj **); Jim_Obj **vector; int len; int rc; - JimPanic((Jim_IsShared(listObjPtr), "ListSortElements called with shared object")); + JimPanic((Jim_IsShared(listObjPtr), "Jim_ListSortElements called with shared object")); SetListFromAny(interp, listObjPtr); prev_info = sort_info; sort_info = info; @@ -11556,13 +11236,10 @@ fn = ListSortStringNoCase; break; case JIM_LSORT_INTEGER: fn = ListSortInteger; break; - case JIM_LSORT_REAL: - fn = ListSortReal; - break; case JIM_LSORT_COMMAND: fn = ListSortCommand; break; default: fn = NULL; @@ -11575,17 +11252,12 @@ fn = ListSortIndexHelper; } if ((rc = setjmp(info->jmpbuf)) == 0) { qsort(vector, len, sizeof(Jim_Obj *), (qsort_comparator *) fn); - - if (info->unique && len > 1) { - ListRemoveDuplicates(listObjPtr, fn); - } - - Jim_InvalidateStringRep(listObjPtr); } + Jim_InvalidateStringRep(listObjPtr); sort_info = prev_info; return rc; } @@ -11710,11 +11382,11 @@ listPtr->internalRep.listValue.ele[idx] = newObjPtr; Jim_IncrRefCount(newObjPtr); return JIM_OK; } -int Jim_ListSetIndex(Jim_Interp *interp, Jim_Obj *varNamePtr, +int Jim_SetListIndex(Jim_Interp *interp, Jim_Obj *varNamePtr, Jim_Obj *const *indexv, int indexc, Jim_Obj *newObjPtr) { Jim_Obj *varObjPtr, *objPtr, *listObjPtr; int shared, i, idx; @@ -11758,11 +11430,14 @@ int i; int listLen = Jim_ListLength(interp, listObjPtr); Jim_Obj *resObjPtr = Jim_NewEmptyStringObj(interp); for (i = 0; i < listLen; ) { - Jim_AppendObj(interp, resObjPtr, Jim_ListGetIndex(interp, listObjPtr, i)); + Jim_Obj *objPtr; + + Jim_ListIndex(interp, listObjPtr, i, &objPtr, JIM_NONE); + Jim_AppendObj(interp, resObjPtr, objPtr); if (++i != listLen) { Jim_AppendString(interp, resObjPtr, joinStr, joinStrLen); } } return resObjPtr; @@ -11788,42 +11463,43 @@ int len = 0, objLen; char *bytes, *p; for (i = 0; i < objc; i++) { - len += Jim_Length(objv[i]); + Jim_GetString(objv[i], &objLen); + len += objLen; } if (objc) len += objc - 1; p = bytes = Jim_Alloc(len + 1); for (i = 0; i < objc; i++) { const char *s = Jim_GetString(objv[i], &objLen); - while (objLen && isspace(UCHAR(*s))) { + while (objLen && (*s == ' ' || *s == '\t' || *s == '\n')) { s++; objLen--; len--; } - while (objLen && isspace(UCHAR(s[objLen - 1]))) { + while (objLen && (s[objLen - 1] == ' ' || + s[objLen - 1] == '\n' || s[objLen - 1] == '\t')) { if (objLen > 1 && s[objLen - 2] == '\\') { break; } objLen--; len--; } memcpy(p, s, objLen); p += objLen; - if (i + 1 != objc) { - if (objLen) - *p++ = ' '; - else { - len--; - } + if (objLen && i + 1 != objc) { + *p++ = ' '; + } + else if (i + 1 != objc) { + len--; } } *p = '\0'; return Jim_NewStringObjNoAlloc(interp, bytes, len); } @@ -11864,25 +11540,19 @@ static int JimObjectHTKeyCompare(void *privdata, const void *key1, const void *key2) { return Jim_StringEqObj((Jim_Obj *)key1, (Jim_Obj *)key2); } -static void *JimObjectHTKeyValDup(void *privdata, const void *val) -{ - Jim_IncrRefCount((Jim_Obj *)val); - return (void *)val; -} - static void JimObjectHTKeyValDestructor(void *interp, void *val) { Jim_DecrRefCount(interp, (Jim_Obj *)val); } static const Jim_HashTableType JimDictHashTableType = { JimObjectHTHashFunction, - JimObjectHTKeyValDup, - JimObjectHTKeyValDup, + NULL, + NULL, JimObjectHTKeyCompare, JimObjectHTKeyValDestructor, JimObjectHTKeyValDestructor }; @@ -11915,11 +11585,16 @@ if (ht->size != 0) Jim_ExpandHashTable(dupHt, ht->size); JimInitHashTableIterator(ht, &htiter); while ((he = Jim_NextHashEntry(&htiter)) != NULL) { - Jim_AddHashEntry(dupHt, he->key, he->u.val); + const Jim_Obj *keyObjPtr = he->key; + Jim_Obj *valObjPtr = he->u.val; + + Jim_IncrRefCount((Jim_Obj *)keyObjPtr); + Jim_IncrRefCount(valObjPtr); + Jim_AddHashEntry(dupHt, keyObjPtr, valObjPtr); } dupPtr->internalRep.ptr = dupHt; dupPtr->typePtr = &dictObjType; } @@ -11937,12 +11612,12 @@ objv = Jim_Alloc((ht->used * 2) * sizeof(Jim_Obj *)); JimInitHashTableIterator(ht, &htiter); i = 0; while ((he = Jim_NextHashEntry(&htiter)) != NULL) { - objv[i++] = Jim_GetHashEntryKey(he); - objv[i++] = Jim_GetHashEntryVal(he); + objv[i++] = (Jim_Obj *)he->key; + objv[i++] = he->u.val; } *len = i; return objv; } @@ -11950,11 +11625,10 @@ { int len; Jim_Obj **objv = JimDictPairs(objPtr, &len); - JimMakeListStringRep(objPtr, objv, len); Jim_Free(objv); } @@ -11964,13 +11638,11 @@ if (objPtr->typePtr == &dictObjType) { return JIM_OK; } - if (Jim_IsList(objPtr) && Jim_IsShared(objPtr)) { - Jim_String(objPtr); - } + Jim_String(objPtr); listlen = Jim_ListLength(interp, objPtr); if (listlen % 2) { Jim_SetResultString(interp, "missing value to go with key", -1); @@ -11983,14 +11655,28 @@ ht = Jim_Alloc(sizeof(*ht)); Jim_InitHashTable(ht, &JimDictHashTableType, interp); for (i = 0; i < listlen; i += 2) { - Jim_Obj *keyObjPtr = Jim_ListGetIndex(interp, objPtr, i); - Jim_Obj *valObjPtr = Jim_ListGetIndex(interp, objPtr, i + 1); + Jim_Obj *keyObjPtr; + Jim_Obj *valObjPtr; - Jim_ReplaceHashEntry(ht, keyObjPtr, valObjPtr); + Jim_ListIndex(interp, objPtr, i, &keyObjPtr, JIM_NONE); + Jim_ListIndex(interp, objPtr, i + 1, &valObjPtr, JIM_NONE); + + Jim_IncrRefCount(keyObjPtr); + Jim_IncrRefCount(valObjPtr); + + if (Jim_AddHashEntry(ht, keyObjPtr, valObjPtr) != JIM_OK) { + Jim_HashEntry *he; + + he = Jim_FindHashEntry(ht, keyObjPtr); + Jim_DecrRefCount(interp, keyObjPtr); + + Jim_DecrRefCount(interp, (Jim_Obj *)he->u.val); + he->u.val = valObjPtr; + } } Jim_FreeIntRep(interp, objPtr); objPtr->typePtr = &dictObjType; objPtr->internalRep.ptr = ht; @@ -12007,23 +11693,31 @@ Jim_HashTable *ht = objPtr->internalRep.ptr; if (valueObjPtr == NULL) { return Jim_DeleteHashEntry(ht, keyObjPtr); } - Jim_ReplaceHashEntry(ht, keyObjPtr, valueObjPtr); + Jim_IncrRefCount(keyObjPtr); + Jim_IncrRefCount(valueObjPtr); + if (Jim_ReplaceHashEntry(ht, keyObjPtr, valueObjPtr)) { + + Jim_DecrRefCount(interp, keyObjPtr); + } return JIM_OK; } int Jim_DictAddElement(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *keyObjPtr, Jim_Obj *valueObjPtr) { + int retcode; + JimPanic((Jim_IsShared(objPtr), "Jim_DictAddElement called with shared object")); if (SetDictFromAny(interp, objPtr) != JIM_OK) { return JIM_ERR; } + retcode = DictAddElement(interp, objPtr, keyObjPtr, valueObjPtr); Jim_InvalidateStringRep(objPtr); - return DictAddElement(interp, objPtr, keyObjPtr, valueObjPtr); + return retcode; } Jim_Obj *Jim_NewDictObj(Jim_Interp *interp, Jim_Obj *const *elements, int len) { Jim_Obj *objPtr; @@ -12150,11 +11844,10 @@ } objPtr = Jim_NewDictObj(interp, NULL, 0); DictAddElement(interp, dictObjPtr, keyv[i], objPtr); } } - Jim_InvalidateStringRep(objPtr); Jim_InvalidateStringRep(varObjPtr); if (Jim_SetVariable(interp, varNamePtr, varObjPtr) != JIM_OK) { goto err; } @@ -12176,29 +11869,28 @@ NULL, UpdateStringOfIndex, JIM_TYPE_NONE, }; -static void UpdateStringOfIndex(struct Jim_Obj *objPtr) -{ - if (objPtr->internalRep.intValue == -1) { - JimSetStringBytes(objPtr, "end"); - } - else { - char buf[JIM_INTEGER_SPACE + 1]; - if (objPtr->internalRep.intValue >= 0) { - sprintf(buf, "%d", objPtr->internalRep.intValue); - } - else { - - sprintf(buf, "end%d", objPtr->internalRep.intValue + 1); - } - JimSetStringBytes(objPtr, buf); - } -} - -static int SetIndexFromAny(Jim_Interp *interp, Jim_Obj *objPtr) +void UpdateStringOfIndex(struct Jim_Obj *objPtr) +{ + int len; + char buf[JIM_INTEGER_SPACE + 1]; + + if (objPtr->internalRep.intValue >= 0) + len = sprintf(buf, "%d", objPtr->internalRep.intValue); + else if (objPtr->internalRep.intValue == -1) + len = sprintf(buf, "end"); + else { + len = sprintf(buf, "end%d", objPtr->internalRep.intValue + 1); + } + objPtr->bytes = Jim_Alloc(len + 1); + memcpy(objPtr->bytes, buf, len + 1); + objPtr->length = len; +} + +int SetIndexFromAny(Jim_Interp *interp, Jim_Obj *objPtr) { int idx, end = 0; const char *str; char *endptr; @@ -12266,17 +11958,14 @@ { if (objPtr->typePtr == &intObjType) { jim_wide val = JimWideValue(objPtr); - if (val < 0) - *indexPtr = -INT_MAX; - else if (val > INT_MAX) - *indexPtr = INT_MAX; - else - *indexPtr = (int)val; - return JIM_OK; + if (!(val < LONG_MIN) && !(val > LONG_MAX)) { + *indexPtr = (val < 0) ? -INT_MAX : (long)val;; + return JIM_OK; + } } if (objPtr->typePtr != &indexObjType && SetIndexFromAny(interp, objPtr) == JIM_ERR) return JIM_ERR; *indexPtr = objPtr->internalRep.intValue; return JIM_OK; @@ -12296,10 +11985,12 @@ NULL }; #define jimReturnCodesSize (sizeof(jimReturnCodes)/sizeof(*jimReturnCodes)) +static int SetReturnCodeFromAny(Jim_Interp *interp, Jim_Obj *objPtr); + static const Jim_ObjType returnCodeObjType = { "return-code", NULL, NULL, NULL, @@ -12314,11 +12005,11 @@ else { return jimReturnCodes[code]; } } -static int SetReturnCodeFromAny(Jim_Interp *interp, Jim_Obj *objPtr) +int SetReturnCodeFromAny(Jim_Interp *interp, Jim_Obj *objPtr) { int returnCode; jim_wide wideValue; @@ -12409,11 +12100,10 @@ JIM_EXPROP_UNARYPLUS, JIM_EXPROP_FUNC_FIRST, JIM_EXPROP_FUNC_INT = JIM_EXPROP_FUNC_FIRST, - JIM_EXPROP_FUNC_WIDE, JIM_EXPROP_FUNC_ABS, JIM_EXPROP_FUNC_DOUBLE, JIM_EXPROP_FUNC_ROUND, JIM_EXPROP_FUNC_RAND, JIM_EXPROP_FUNC_SRAND, @@ -12467,22 +12157,24 @@ return e->stack[--e->stacklen]; } static int JimExprOpNumUnary(Jim_Interp *interp, struct JimExprState *e) { - int intresult = 1; + int intresult = 0; int rc = JIM_OK; Jim_Obj *A = ExprPop(e); double dA, dC = 0; jim_wide wA, wC = 0; if ((A->typePtr != &doubleObjType || A->bytes) && JimGetWideNoErr(interp, A, &wA) == JIM_OK) { + intresult = 1; + switch (e->opcode) { case JIM_EXPROP_FUNC_INT: - case JIM_EXPROP_FUNC_WIDE: + wC = wA; + break; case JIM_EXPROP_FUNC_ROUND: - case JIM_EXPROP_UNARYPLUS: wC = wA; break; case JIM_EXPROP_FUNC_DOUBLE: dC = wA; intresult = 0; @@ -12490,10 +12182,13 @@ case JIM_EXPROP_FUNC_ABS: wC = wA >= 0 ? wA : -wA; break; case JIM_EXPROP_UNARYMINUS: wC = -wA; + break; + case JIM_EXPROP_UNARYPLUS: + wC = wA; break; case JIM_EXPROP_NOT: wC = !wA; break; default: @@ -12501,31 +12196,32 @@ } } else if ((rc = Jim_GetDouble(interp, A, &dA)) == JIM_OK) { switch (e->opcode) { case JIM_EXPROP_FUNC_INT: - case JIM_EXPROP_FUNC_WIDE: wC = dA; + intresult = 1; break; case JIM_EXPROP_FUNC_ROUND: wC = dA < 0 ? (dA - 0.5) : (dA + 0.5); + intresult = 1; break; case JIM_EXPROP_FUNC_DOUBLE: - case JIM_EXPROP_UNARYPLUS: dC = dA; - intresult = 0; break; case JIM_EXPROP_FUNC_ABS: dC = dA >= 0 ? dA : -dA; - intresult = 0; break; case JIM_EXPROP_UNARYMINUS: dC = -dA; - intresult = 0; + break; + case JIM_EXPROP_UNARYPLUS: + dC = dA; break; case JIM_EXPROP_NOT: wC = !dA; + intresult = 1; break; default: abort(); } } @@ -12736,11 +12432,11 @@ static int JimExprOpBin(Jim_Interp *interp, struct JimExprState *e) { - int intresult = 1; + int intresult = 0; int rc = JIM_OK; double dA, dB, dC = 0; jim_wide wA, wB, wC = 0; Jim_Obj *B = ExprPop(e); @@ -12749,10 +12445,12 @@ if ((A->typePtr != &doubleObjType || A->bytes) && (B->typePtr != &doubleObjType || B->bytes) && JimGetWideNoErr(interp, A, &wA) == JIM_OK && JimGetWideNoErr(interp, B, &wB) == JIM_OK) { + + intresult = 1; switch (e->opcode) { case JIM_EXPROP_POW: case JIM_EXPROP_FUNC_POW: wC = JimPowWide(wA, wB); @@ -12803,11 +12501,10 @@ default: abort(); } } else if (Jim_GetDouble(interp, A, &dA) == JIM_OK && Jim_GetDouble(interp, B, &dB) == JIM_OK) { - intresult = 0; switch (e->opcode) { case JIM_EXPROP_POW: case JIM_EXPROP_FUNC_POW: #ifdef JIM_MATH_FUNCTIONS dC = pow(dA, dB); @@ -12868,10 +12565,12 @@ else { int i = Jim_StringCompareObj(interp, A, B, 0); + + intresult = 1; switch (e->opcode) { case JIM_EXPROP_LT: wC = i < 0; break; @@ -12916,11 +12615,15 @@ int listlen; int i; listlen = Jim_ListLength(interp, listObjPtr); for (i = 0; i < listlen; i++) { - if (Jim_StringEqObj(Jim_ListGetIndex(interp, listObjPtr, i), valObj)) { + Jim_Obj *objPtr; + + Jim_ListIndex(interp, listObjPtr, i, &objPtr, JIM_NONE); + + if (Jim_StringEqObj(objPtr, valObj)) { return 1; } } return 0; } @@ -12932,16 +12635,23 @@ jim_wide wC; switch (e->opcode) { case JIM_EXPROP_STREQ: - case JIM_EXPROP_STRNE: - wC = Jim_StringEqObj(A, B); - if (e->opcode == JIM_EXPROP_STRNE) { - wC = !wC; + case JIM_EXPROP_STRNE: { + int Alen, Blen; + const char *sA = Jim_GetString(A, &Alen); + const char *sB = Jim_GetString(B, &Blen); + + if (e->opcode == JIM_EXPROP_STREQ) { + wC = (Alen == Blen && memcmp(sA, sB, Alen) == 0); + } + else { + wC = (Alen != Blen || memcmp(sA, sB, Alen) != 0); } break; + } case JIM_EXPROP_STRIN: wC = JimSearchList(interp, B, A); break; case JIM_EXPROP_STRNI: wC = !JimSearchList(interp, B, A); @@ -13113,99 +12823,96 @@ LAZY_OP, LAZY_LEFT, LAZY_RIGHT }; -#define OPRINIT(N, P, A, F) {N, F, P, A, LAZY_NONE, sizeof(N) - 1} -#define OPRINIT_LAZY(N, P, A, F, L) {N, F, P, A, L, sizeof(N) - 1} +#define OPRINIT(N, P, A, F, L) {N, F, P, A, L, sizeof(N) - 1} static const struct Jim_ExprOperator Jim_ExprOperators[] = { - OPRINIT("*", 110, 2, JimExprOpBin), - OPRINIT("/", 110, 2, JimExprOpBin), - OPRINIT("%", 110, 2, JimExprOpIntBin), - - OPRINIT("-", 100, 2, JimExprOpBin), - OPRINIT("+", 100, 2, JimExprOpBin), - - OPRINIT("<<", 90, 2, JimExprOpIntBin), - OPRINIT(">>", 90, 2, JimExprOpIntBin), - - OPRINIT("<<<", 90, 2, JimExprOpIntBin), - OPRINIT(">>>", 90, 2, JimExprOpIntBin), - - OPRINIT("<", 80, 2, JimExprOpBin), - OPRINIT(">", 80, 2, JimExprOpBin), - OPRINIT("<=", 80, 2, JimExprOpBin), - OPRINIT(">=", 80, 2, JimExprOpBin), - - OPRINIT("==", 70, 2, JimExprOpBin), - OPRINIT("!=", 70, 2, JimExprOpBin), - - OPRINIT("&", 50, 2, JimExprOpIntBin), - OPRINIT("^", 49, 2, JimExprOpIntBin), - OPRINIT("|", 48, 2, JimExprOpIntBin), - - OPRINIT_LAZY("&&", 10, 2, NULL, LAZY_OP), - OPRINIT_LAZY(NULL, 10, 2, JimExprOpAndLeft, LAZY_LEFT), - OPRINIT_LAZY(NULL, 10, 2, JimExprOpAndOrRight, LAZY_RIGHT), - - OPRINIT_LAZY("||", 9, 2, NULL, LAZY_OP), - OPRINIT_LAZY(NULL, 9, 2, JimExprOpOrLeft, LAZY_LEFT), - OPRINIT_LAZY(NULL, 9, 2, JimExprOpAndOrRight, LAZY_RIGHT), - - OPRINIT_LAZY("?", 5, 2, JimExprOpNull, LAZY_OP), - OPRINIT_LAZY(NULL, 5, 2, JimExprOpTernaryLeft, LAZY_LEFT), - OPRINIT_LAZY(NULL, 5, 2, JimExprOpNull, LAZY_RIGHT), - - OPRINIT_LAZY(":", 5, 2, JimExprOpNull, LAZY_OP), - OPRINIT_LAZY(NULL, 5, 2, JimExprOpColonLeft, LAZY_LEFT), - OPRINIT_LAZY(NULL, 5, 2, JimExprOpNull, LAZY_RIGHT), - - OPRINIT("**", 250, 2, JimExprOpBin), - - OPRINIT("eq", 60, 2, JimExprOpStrBin), - OPRINIT("ne", 60, 2, JimExprOpStrBin), - - OPRINIT("in", 55, 2, JimExprOpStrBin), - OPRINIT("ni", 55, 2, JimExprOpStrBin), - - OPRINIT("!", 150, 1, JimExprOpNumUnary), - OPRINIT("~", 150, 1, JimExprOpIntUnary), - OPRINIT(NULL, 150, 1, JimExprOpNumUnary), - OPRINIT(NULL, 150, 1, JimExprOpNumUnary), - - - - OPRINIT("int", 200, 1, JimExprOpNumUnary), - OPRINIT("wide", 200, 1, JimExprOpNumUnary), - OPRINIT("abs", 200, 1, JimExprOpNumUnary), - OPRINIT("double", 200, 1, JimExprOpNumUnary), - OPRINIT("round", 200, 1, JimExprOpNumUnary), - OPRINIT("rand", 200, 0, JimExprOpNone), - OPRINIT("srand", 200, 1, JimExprOpIntUnary), + OPRINIT("*", 110, 2, JimExprOpBin, LAZY_NONE), + OPRINIT("/", 110, 2, JimExprOpBin, LAZY_NONE), + OPRINIT("%", 110, 2, JimExprOpIntBin, LAZY_NONE), + + OPRINIT("-", 100, 2, JimExprOpBin, LAZY_NONE), + OPRINIT("+", 100, 2, JimExprOpBin, LAZY_NONE), + + OPRINIT("<<", 90, 2, JimExprOpIntBin, LAZY_NONE), + OPRINIT(">>", 90, 2, JimExprOpIntBin, LAZY_NONE), + + OPRINIT("<<<", 90, 2, JimExprOpIntBin, LAZY_NONE), + OPRINIT(">>>", 90, 2, JimExprOpIntBin, LAZY_NONE), + + OPRINIT("<", 80, 2, JimExprOpBin, LAZY_NONE), + OPRINIT(">", 80, 2, JimExprOpBin, LAZY_NONE), + OPRINIT("<=", 80, 2, JimExprOpBin, LAZY_NONE), + OPRINIT(">=", 80, 2, JimExprOpBin, LAZY_NONE), + + OPRINIT("==", 70, 2, JimExprOpBin, LAZY_NONE), + OPRINIT("!=", 70, 2, JimExprOpBin, LAZY_NONE), + + OPRINIT("&", 50, 2, JimExprOpIntBin, LAZY_NONE), + OPRINIT("^", 49, 2, JimExprOpIntBin, LAZY_NONE), + OPRINIT("|", 48, 2, JimExprOpIntBin, LAZY_NONE), + + OPRINIT("&&", 10, 2, NULL, LAZY_OP), + OPRINIT(NULL, 10, 2, JimExprOpAndLeft, LAZY_LEFT), + OPRINIT(NULL, 10, 2, JimExprOpAndOrRight, LAZY_RIGHT), + + OPRINIT("||", 9, 2, NULL, LAZY_OP), + OPRINIT(NULL, 9, 2, JimExprOpOrLeft, LAZY_LEFT), + OPRINIT(NULL, 9, 2, JimExprOpAndOrRight, LAZY_RIGHT), + + OPRINIT("?", 5, 2, JimExprOpNull, LAZY_OP), + OPRINIT(NULL, 5, 2, JimExprOpTernaryLeft, LAZY_LEFT), + OPRINIT(NULL, 5, 2, JimExprOpNull, LAZY_RIGHT), + + OPRINIT(":", 5, 2, JimExprOpNull, LAZY_OP), + OPRINIT(NULL, 5, 2, JimExprOpColonLeft, LAZY_LEFT), + OPRINIT(NULL, 5, 2, JimExprOpNull, LAZY_RIGHT), + + OPRINIT("**", 250, 2, JimExprOpBin, LAZY_NONE), + + OPRINIT("eq", 60, 2, JimExprOpStrBin, LAZY_NONE), + OPRINIT("ne", 60, 2, JimExprOpStrBin, LAZY_NONE), + + OPRINIT("in", 55, 2, JimExprOpStrBin, LAZY_NONE), + OPRINIT("ni", 55, 2, JimExprOpStrBin, LAZY_NONE), + + OPRINIT("!", 150, 1, JimExprOpNumUnary, LAZY_NONE), + OPRINIT("~", 150, 1, JimExprOpIntUnary, LAZY_NONE), + OPRINIT(NULL, 150, 1, JimExprOpNumUnary, LAZY_NONE), + OPRINIT(NULL, 150, 1, JimExprOpNumUnary, LAZY_NONE), + + + + OPRINIT("int", 200, 1, JimExprOpNumUnary, LAZY_NONE), + OPRINIT("abs", 200, 1, JimExprOpNumUnary, LAZY_NONE), + OPRINIT("double", 200, 1, JimExprOpNumUnary, LAZY_NONE), + OPRINIT("round", 200, 1, JimExprOpNumUnary, LAZY_NONE), + OPRINIT("rand", 200, 0, JimExprOpNone, LAZY_NONE), + OPRINIT("srand", 200, 1, JimExprOpIntUnary, LAZY_NONE), #ifdef JIM_MATH_FUNCTIONS - OPRINIT("sin", 200, 1, JimExprOpDoubleUnary), - OPRINIT("cos", 200, 1, JimExprOpDoubleUnary), - OPRINIT("tan", 200, 1, JimExprOpDoubleUnary), - OPRINIT("asin", 200, 1, JimExprOpDoubleUnary), - OPRINIT("acos", 200, 1, JimExprOpDoubleUnary), - OPRINIT("atan", 200, 1, JimExprOpDoubleUnary), - OPRINIT("sinh", 200, 1, JimExprOpDoubleUnary), - OPRINIT("cosh", 200, 1, JimExprOpDoubleUnary), - OPRINIT("tanh", 200, 1, JimExprOpDoubleUnary), - OPRINIT("ceil", 200, 1, JimExprOpDoubleUnary), - OPRINIT("floor", 200, 1, JimExprOpDoubleUnary), - OPRINIT("exp", 200, 1, JimExprOpDoubleUnary), - OPRINIT("log", 200, 1, JimExprOpDoubleUnary), - OPRINIT("log10", 200, 1, JimExprOpDoubleUnary), - OPRINIT("sqrt", 200, 1, JimExprOpDoubleUnary), - OPRINIT("pow", 200, 2, JimExprOpBin), + OPRINIT("sin", 200, 1, JimExprOpDoubleUnary, LAZY_NONE), + OPRINIT("cos", 200, 1, JimExprOpDoubleUnary, LAZY_NONE), + OPRINIT("tan", 200, 1, JimExprOpDoubleUnary, LAZY_NONE), + OPRINIT("asin", 200, 1, JimExprOpDoubleUnary, LAZY_NONE), + OPRINIT("acos", 200, 1, JimExprOpDoubleUnary, LAZY_NONE), + OPRINIT("atan", 200, 1, JimExprOpDoubleUnary, LAZY_NONE), + OPRINIT("sinh", 200, 1, JimExprOpDoubleUnary, LAZY_NONE), + OPRINIT("cosh", 200, 1, JimExprOpDoubleUnary, LAZY_NONE), + OPRINIT("tanh", 200, 1, JimExprOpDoubleUnary, LAZY_NONE), + OPRINIT("ceil", 200, 1, JimExprOpDoubleUnary, LAZY_NONE), + OPRINIT("floor", 200, 1, JimExprOpDoubleUnary, LAZY_NONE), + OPRINIT("exp", 200, 1, JimExprOpDoubleUnary, LAZY_NONE), + OPRINIT("log", 200, 1, JimExprOpDoubleUnary, LAZY_NONE), + OPRINIT("log10", 200, 1, JimExprOpDoubleUnary, LAZY_NONE), + OPRINIT("sqrt", 200, 1, JimExprOpDoubleUnary, LAZY_NONE), + OPRINIT("pow", 200, 2, JimExprOpBin, LAZY_NONE), #endif }; #undef OPRINIT -#undef OPRINIT_LAZY #define JIM_EXPR_OPERATORS_NUM \ (sizeof(Jim_ExprOperators)/sizeof(struct Jim_ExprOperator)) static int JimParseExpression(struct JimParserCtx *pc) @@ -13217,16 +12924,13 @@ } pc->p++; pc->len--; } - - pc->tline = pc->linenr; - pc->tstart = pc->p; - if (pc->len == 0) { - pc->tend = pc->p; + pc->tstart = pc->tend = pc->p; + pc->tline = pc->linenr; pc->tt = JIM_TT_EOL; pc->eof = 1; return JIM_OK; } switch (*(pc->p)) { @@ -13237,11 +12941,12 @@ pc->tt = JIM_TT_SUBEXPR_END; goto singlechar; case ',': pc->tt = JIM_TT_SUBEXPR_COMMA; singlechar: - pc->tend = pc->p; + pc->tstart = pc->tend = pc->p; + pc->tline = pc->linenr; pc->p++; pc->len--; break; case '[': return JimParseCmd(pc); @@ -13287,44 +12992,82 @@ return JIM_OK; } static int JimParseExprNumber(struct JimParserCtx *pc) { - char *end; + int allowdot = 1; + int base = 10; pc->tt = JIM_TT_EXPR_INT; - - jim_strtoull(pc->p, (char **)&pc->p); - - if (strchr("eENnIi.", *pc->p) || pc->p == pc->tstart) { - if (strtod(pc->tstart, &end)) { } - if (end == pc->tstart) - return JIM_ERR; - if (end > pc->p) { - + pc->tstart = pc->p; + pc->tline = pc->linenr; + + + if (pc->p[0] == '0') { + switch (pc->p[1]) { + case 'x': + case 'X': + base = 16; + allowdot = 0; + pc->p += 2; + pc->len -= 2; + break; + case 'o': + case 'O': + base = 8; + allowdot = 0; + pc->p += 2; + pc->len -= 2; + break; + case 'b': + case 'B': + base = 2; + allowdot = 0; + pc->p += 2; + pc->len -= 2; + break; + } + } + + while (isdigit(UCHAR(*pc->p)) + || (base == 16 && isxdigit(UCHAR(*pc->p))) + || (base == 8 && *pc->p >= '0' && *pc->p <= '7') + || (base == 2 && (*pc->p == '0' || *pc->p == '1')) + || (allowdot && *pc->p == '.') + ) { + if (*pc->p == '.') { + allowdot = 0; + pc->tt = JIM_TT_EXPR_DOUBLE; + } + pc->p++; + pc->len--; + if (base == 10 && (*pc->p == 'e' || *pc->p == 'E') && (pc->p[1] == '-' || pc->p[1] == '+' + || isdigit(UCHAR(pc->p[1])))) { + pc->p += 2; + pc->len -= 2; pc->tt = JIM_TT_EXPR_DOUBLE; - pc->p = end; } } pc->tend = pc->p - 1; - pc->len -= (pc->p - pc->tstart); return JIM_OK; } static int JimParseExprIrrational(struct JimParserCtx *pc) { - const char *irrationals[] = { "NaN", "nan", "NAN", "Inf", "inf", "INF", NULL }; - int i; - - for (i = 0; irrationals[i]; i++) { - const char *irr = irrationals[i]; - - if (strncmp(irr, pc->p, 3) == 0) { - pc->p += 3; - pc->len -= 3; - pc->tend = pc->p - 1; + const char *Tokens[] = { "NaN", "nan", "NAN", "Inf", "inf", "INF", NULL }; + const char **token; + + for (token = Tokens; *token != NULL; token++) { + int len = strlen(*token); + + if (strncmp(*token, pc->p, len) == 0) { + pc->tstart = pc->p; + pc->tend = pc->p + len - 1; + pc->p += len; + pc->len -= len; + pc->tline = pc->linenr; pc->tt = JIM_TT_EXPR_DOUBLE; return JIM_OK; } } return JIM_ERR; @@ -13364,13 +13107,15 @@ } if (*p != '(') { return JIM_ERR; } } + pc->tstart = pc->p; pc->tend = pc->p + bestLen - 1; pc->p += bestLen; pc->len -= bestLen; + pc->tline = pc->linenr; pc->tt = bestIdx; return JIM_OK; } @@ -13868,24 +13613,18 @@ } #ifdef DEBUG_SHOW_EXPR_TOKENS { int i; - printf("==== Expr Tokens (%s) ====\n", Jim_String(fileNameObj)); + printf("==== Expr Tokens ====\n"); for (i = 0; i < tokenlist.count; i++) { printf("[%2d]@%d %s '%.*s'\n", i, tokenlist.list[i].line, jim_tt_name(tokenlist.list[i].type), tokenlist.list[i].len, tokenlist.list[i].token); } } #endif - if (JimParseCheckMissing(interp, parser.missing.ch) == JIM_ERR) { - ScriptTokenListFree(&tokenlist); - Jim_DecrRefCount(interp, fileNameObj); - return JIM_ERR; - } - expr = ExprCreateByteCode(interp, &tokenlist, fileNameObj); ScriptTokenListFree(&tokenlist); @@ -13932,24 +13671,10 @@ } } return (ExprByteCode *) Jim_GetIntRepPtr(objPtr); } -#ifdef JIM_OPTIMIZATION -static Jim_Obj *JimExprIntValOrVar(Jim_Interp *interp, const ScriptToken *token) -{ - if (token->type == JIM_TT_EXPR_INT) - return token->objPtr; - else if (token->type == JIM_TT_VAR) - return Jim_GetVariable(interp, token->objPtr, JIM_NONE); - else if (token->type == JIM_TT_DICTSUGAR) - return JimExpandDictSugar(interp, token->objPtr); - else - return NULL; -} -#endif - #define JIM_EE_STATICSTACK_LEN 10 int Jim_EvalExpression(Jim_Interp *interp, Jim_Obj *exprObjPtr, Jim_Obj **exprResultPtrPtr) { ExprByteCode *expr; @@ -13968,69 +13693,102 @@ Jim_Obj *objPtr; switch (expr->len) { case 1: - objPtr = JimExprIntValOrVar(interp, &expr->token[0]); - if (objPtr) { - Jim_IncrRefCount(objPtr); - *exprResultPtrPtr = objPtr; + if (expr->token[0].type == JIM_TT_EXPR_INT) { + *exprResultPtrPtr = expr->token[0].objPtr; + Jim_IncrRefCount(*exprResultPtrPtr); return JIM_OK; + } + if (expr->token[0].type == JIM_TT_VAR) { + objPtr = Jim_GetVariable(interp, expr->token[0].objPtr, JIM_ERRMSG); + if (objPtr) { + *exprResultPtrPtr = objPtr; + Jim_IncrRefCount(*exprResultPtrPtr); + return JIM_OK; + } } break; case 2: - if (expr->token[1].type == JIM_EXPROP_NOT) { - objPtr = JimExprIntValOrVar(interp, &expr->token[0]); + if (expr->token[1].type == JIM_EXPROP_NOT && expr->token[0].type == JIM_TT_VAR) { + jim_wide wideValue; - if (objPtr && JimIsWide(objPtr)) { - *exprResultPtrPtr = JimWideValue(objPtr) ? interp->falseObj : interp->trueObj; + objPtr = Jim_GetVariable(interp, expr->token[0].objPtr, JIM_NONE); + if (objPtr && JimIsWide(objPtr) + && Jim_GetWide(interp, objPtr, &wideValue) == JIM_OK) { + *exprResultPtrPtr = wideValue ? interp->falseObj : interp->trueObj; Jim_IncrRefCount(*exprResultPtrPtr); return JIM_OK; } } break; case 3: - objPtr = JimExprIntValOrVar(interp, &expr->token[0]); - if (objPtr && JimIsWide(objPtr)) { - Jim_Obj *objPtr2 = JimExprIntValOrVar(interp, &expr->token[1]); - if (objPtr2 && JimIsWide(objPtr2)) { - jim_wide wideValueA = JimWideValue(objPtr); - jim_wide wideValueB = JimWideValue(objPtr2); - int cmpRes; - switch (expr->token[2].type) { - case JIM_EXPROP_LT: - cmpRes = wideValueA < wideValueB; - break; - case JIM_EXPROP_LTE: - cmpRes = wideValueA <= wideValueB; - break; - case JIM_EXPROP_GT: - cmpRes = wideValueA > wideValueB; - break; - case JIM_EXPROP_GTE: - cmpRes = wideValueA >= wideValueB; - break; - case JIM_EXPROP_NUMEQ: - cmpRes = wideValueA == wideValueB; - break; - case JIM_EXPROP_NUMNE: - cmpRes = wideValueA != wideValueB; - break; - default: - goto noopt; - } - *exprResultPtrPtr = cmpRes ? interp->trueObj : interp->falseObj; - Jim_IncrRefCount(*exprResultPtrPtr); - return JIM_OK; - } - } - break; - } - } -noopt: + if (expr->token[0].type == JIM_TT_VAR && (expr->token[1].type == JIM_TT_EXPR_INT + || expr->token[1].type == JIM_TT_VAR)) { + switch (expr->token[2].type) { + case JIM_EXPROP_LT: + case JIM_EXPROP_LTE: + case JIM_EXPROP_GT: + case JIM_EXPROP_GTE: + case JIM_EXPROP_NUMEQ: + case JIM_EXPROP_NUMNE:{ + + jim_wide wideValueA; + jim_wide wideValueB; + + objPtr = Jim_GetVariable(interp, expr->token[0].objPtr, JIM_NONE); + if (objPtr && JimIsWide(objPtr) + && Jim_GetWide(interp, objPtr, &wideValueA) == JIM_OK) { + if (expr->token[1].type == JIM_TT_VAR) { + objPtr = + Jim_GetVariable(interp, expr->token[1].objPtr, + JIM_NONE); + } + else { + objPtr = expr->token[1].objPtr; + } + if (objPtr && JimIsWide(objPtr) + && Jim_GetWide(interp, objPtr, &wideValueB) == JIM_OK) { + int cmpRes; + + switch (expr->token[2].type) { + case JIM_EXPROP_LT: + cmpRes = wideValueA < wideValueB; + break; + case JIM_EXPROP_LTE: + cmpRes = wideValueA <= wideValueB; + break; + case JIM_EXPROP_GT: + cmpRes = wideValueA > wideValueB; + break; + case JIM_EXPROP_GTE: + cmpRes = wideValueA >= wideValueB; + break; + case JIM_EXPROP_NUMEQ: + cmpRes = wideValueA == wideValueB; + break; + case JIM_EXPROP_NUMNE: + cmpRes = wideValueA != wideValueB; + break; + default: + cmpRes = 0; + } + *exprResultPtrPtr = + cmpRes ? interp->trueObj : interp->falseObj; + Jim_IncrRefCount(*exprResultPtrPtr); + return JIM_OK; + } + } + } + } + } + break; + } + } #endif expr->inUse++; @@ -14199,13 +13957,16 @@ memcpy(newVec, srcPtr->internalRep.ptr, size); dupPtr->internalRep.ptr = newVec; dupPtr->typePtr = &scanFmtStringObjType; } -static void UpdateStringOfScanFmt(Jim_Obj *objPtr) +void UpdateStringOfScanFmt(Jim_Obj *objPtr) { - JimSetStringBytes(objPtr, ((ScanFmtStringObj *) objPtr->internalRep.ptr)->stringRep); + char *bytes = ((ScanFmtStringObj *) objPtr->internalRep.ptr)->stringRep; + + objPtr->bytes = Jim_StrDup(bytes); + objPtr->length = strlen(bytes); } static int SetScanFmtFromAny(Jim_Interp *interp, Jim_Obj *objPtr) { @@ -14415,10 +14176,11 @@ Jim_Obj *tmpObj = NULL; *valObjPtr = 0; if (descr->prefix) { + for (i = 0; pos < strLen && descr->prefix[i]; ++i) { if (isspace(UCHAR(descr->prefix[i]))) while (pos < strLen && isspace(UCHAR(str[pos]))) ++pos; @@ -14755,54 +14517,33 @@ } static int JimInvokeCommand(Jim_Interp *interp, int objc, Jim_Obj *const *objv) { int retcode; - Jim_Cmd *cmdPtr; - -#if 0 - printf("invoke"); - int j; - for (j = 0; j < objc; j++) { - printf(" '%s'", Jim_String(objv[j])); - } - printf("\n"); -#endif - - if (interp->framePtr->tailcallCmd) { - - cmdPtr = interp->framePtr->tailcallCmd; - interp->framePtr->tailcallCmd = NULL; - } - else { - cmdPtr = Jim_GetCommand(interp, objv[0], JIM_ERRMSG); - if (cmdPtr == NULL) { - return JimUnknown(interp, objc, objv); - } - JimIncrCmdRefCount(cmdPtr); - } - + Jim_Cmd *cmdPtr = Jim_GetCommand(interp, objv[0], JIM_ERRMSG); + + if (cmdPtr == NULL) { + return JimUnknown(interp, objc, objv); + } if (interp->evalDepth == interp->maxEvalDepth) { Jim_SetResultString(interp, "Infinite eval recursion", -1); - retcode = JIM_ERR; - goto out; + return JIM_ERR; } interp->evalDepth++; + JimIncrCmdRefCount(cmdPtr); Jim_SetEmptyResult(interp); if (cmdPtr->isproc) { retcode = JimCallProcedure(interp, cmdPtr, objc, objv); } else { interp->cmdPrivData = cmdPtr->u.native.privData; retcode = cmdPtr->u.native.cmdProc(interp, objc, objv); } - interp->evalDepth--; - -out: JimDecrCmdRefCount(interp, cmdPtr); + interp->evalDepth--; return retcode; } int Jim_EvalObjVector(Jim_Interp *interp, int objc, Jim_Obj *const *objv) @@ -14832,13 +14573,15 @@ ret = Jim_EvalObjVector(interp, objc + 1, nargv); Jim_Free(nargv); return ret; } -static void JimAddErrorToStack(Jim_Interp *interp, ScriptObj *script) +static void JimAddErrorToStack(Jim_Interp *interp, int retcode, ScriptObj *script) { - if (!interp->errorFlag) { + int rc = retcode; + + if (rc == JIM_ERR && !interp->errorFlag) { interp->errorFlag = 1; Jim_IncrRefCount(script->fileNameObj); Jim_DecrRefCount(interp, interp->errorFileNameObj); interp->errorFileNameObj = script->fileNameObj; @@ -14848,11 +14591,11 @@ interp->addStackTrace++; } - if (interp->addStackTrace > 0) { + if (rc == JIM_ERR && interp->addStackTrace > 0) { JimAppendStackTrace(interp, Jim_String(interp->errorProc), script->fileNameObj, script->linenr); if (Jim_Length(script->fileNameObj)) { @@ -14860,10 +14603,16 @@ } Jim_DecrRefCount(interp, interp->errorProc); interp->errorProc = interp->emptyObj; Jim_IncrRefCount(interp->errorProc); + } + else if (rc == JIM_RETURN && interp->returnCode == JIM_ERR) { + + } + else { + interp->addStackTrace = 0; } } static int JimSubstOneToken(Jim_Interp *interp, const ScriptToken *token, Jim_Obj **objPtrPtr) { @@ -14973,15 +14722,10 @@ objPtr->typePtr = &interpolatedObjType; objPtr->internalRep.dictSubstValue.varNameObjPtr = token[0].objPtr; objPtr->internalRep.dictSubstValue.indexObjPtr = intv[2]; Jim_IncrRefCount(intv[2]); } - else if (tokens && intv[0] && intv[0]->typePtr == &sourceObjType) { - - JimSetSourceInfo(interp, objPtr, intv[0]->internalRep.sourceValue.fileNameObj, intv[0]->internalRep.sourceValue.lineNumber); - } - s = objPtr->bytes = Jim_Alloc(totlen + 1); objPtr->length = totlen; for (i = 0; i < tokens; i++) { if (intv[i]) { @@ -15002,12 +14746,10 @@ static int JimEvalObjList(Jim_Interp *interp, Jim_Obj *listPtr) { int retcode = JIM_OK; - JimPanic((Jim_IsList(listPtr) == 0, "JimEvalObjList() invoked on non-list.")); - if (listPtr->internalRep.listValue.len) { Jim_IncrRefCount(listPtr); retcode = JimInvokeCommand(interp, listPtr->internalRep.listValue.len, listPtr->internalRep.listValue.ele); @@ -15034,15 +14776,11 @@ if (Jim_IsList(scriptObjPtr) && scriptObjPtr->bytes == NULL) { return JimEvalObjList(interp, scriptObjPtr); } Jim_IncrRefCount(scriptObjPtr); - script = JimGetScript(interp, scriptObjPtr); - if (!JimScriptValid(interp, script)) { - Jim_DecrRefCount(interp, scriptObjPtr); - return JIM_ERR; - } + script = Jim_GetScript(interp, scriptObjPtr); Jim_SetEmptyResult(interp); token = script->token; @@ -15201,18 +14939,11 @@ argv = sargv; } } - if (retcode == JIM_ERR) { - JimAddErrorToStack(interp, script); - } - - else if (retcode != JIM_RETURN || interp->returnCode != JIM_ERR) { - - interp->addStackTrace = 0; - } + JimAddErrorToStack(interp, retcode, script); interp->currentScriptObj = prevScriptObj; Jim_FreeIntRep(interp, scriptObjPtr); @@ -15320,20 +15051,26 @@ retcode = Jim_EvalObj(interp, scriptObj); } interp->framePtr = interp->framePtr->parent; - JimFreeCallFrame(interp, callFramePtr, JIM_FCF_REUSE); + if (callFramePtr->vars.size != JIM_HT_INITIAL_SIZE) { + JimFreeCallFrame(interp, callFramePtr, JIM_FCF_NONE); + } + else { + JimFreeCallFrame(interp, callFramePtr, JIM_FCF_NOHT); + } return retcode; } #endif static int JimCallProcedure(Jim_Interp *interp, Jim_Cmd *cmd, int argc, Jim_Obj *const *argv) { Jim_CallFrame *callFramePtr; int i, d, retcode, optargs; + Jim_Stack *localCommands; ScriptObj *script; if (argc - 1 < cmd->u.proc.reqArity || (cmd->u.proc.argsPos < 0 && argc - 1 > cmd->u.proc.reqArity + cmd->u.proc.optArity)) { @@ -15359,11 +15096,11 @@ callFramePtr->procArgsObjPtr = cmd->u.proc.argListObjPtr; callFramePtr->procBodyObjPtr = cmd->u.proc.bodyObjPtr; callFramePtr->staticVars = cmd->u.proc.staticVars; - script = JimGetScript(interp, interp->currentScriptObj); + script = Jim_GetScript(interp, interp->currentScriptObj); callFramePtr->fileNameObj = script->fileNameObj; callFramePtr->line = script->linenr; Jim_IncrRefCount(cmd->u.proc.argListObjPtr); Jim_IncrRefCount(cmd->u.proc.bodyObjPtr); @@ -15413,42 +15150,37 @@ retcode = Jim_EvalObj(interp, cmd->u.proc.bodyObjPtr); badargset: - + + localCommands = callFramePtr->localCommands; + callFramePtr->localCommands = NULL; + interp->framePtr = interp->framePtr->parent; - JimFreeCallFrame(interp, callFramePtr, JIM_FCF_REUSE); - - if (interp->framePtr->tailcallObj) { - - if (interp->framePtr->tailcall++ == 0) { - - do { - Jim_Obj *tailcallObj = interp->framePtr->tailcallObj; - - interp->framePtr->tailcallObj = NULL; - - if (retcode == JIM_EVAL) { - retcode = Jim_EvalObjList(interp, tailcallObj); - if (retcode == JIM_RETURN) { - interp->returnLevel++; - } - } - Jim_DecrRefCount(interp, tailcallObj); - } while (interp->framePtr->tailcallObj); - - - if (interp->framePtr->tailcallCmd) { - JimDecrCmdRefCount(interp, interp->framePtr->tailcallCmd); - interp->framePtr->tailcallCmd = NULL; - } - } - interp->framePtr->tailcall--; - } - + if (callFramePtr->vars.size != JIM_HT_INITIAL_SIZE) { + JimFreeCallFrame(interp, callFramePtr, JIM_FCF_NONE); + } + else { + JimFreeCallFrame(interp, callFramePtr, JIM_FCF_NOHT); + } + + + while (retcode == JIM_EVAL) { + Jim_Obj *resultScriptObjPtr = Jim_GetResult(interp); + + Jim_IncrRefCount(resultScriptObjPtr); + + JimPanic((!Jim_IsList(resultScriptObjPtr), "tailcall (JIM_EVAL) returned non-list")); + + retcode = JimEvalObjList(interp, resultScriptObjPtr); + if (retcode == JIM_RETURN) { + interp->returnLevel++; + } + Jim_DecrRefCount(interp, resultScriptObjPtr); + } if (retcode == JIM_RETURN) { if (--interp->returnLevel <= 0) { retcode = interp->returnCode; interp->returnCode = JIM_OK; @@ -15460,10 +15192,13 @@ Jim_DecrRefCount(interp, interp->errorProc); interp->errorProc = argv[0]; Jim_IncrRefCount(interp->errorProc); } + + JimDeleteLocalProcs(interp, localCommands); + return retcode; } int Jim_EvalSource(Jim_Interp *interp, const char *filename, int lineno, const char *script) { @@ -15531,10 +15266,11 @@ Jim_Obj *scriptObjPtr; Jim_Obj *prevScriptObj; struct stat sb; int retcode; int readlen; + struct JimParseResult result; if (stat(filename, &sb) != 0 || (fp = fopen(filename, "rt")) == NULL) { Jim_SetResultFormatted(interp, "couldn't read file \"%s\": %s", filename, strerror(errno)); return JIM_ERR; } @@ -15556,10 +15292,36 @@ scriptObjPtr = Jim_NewStringObjNoAlloc(interp, buf, readlen); JimSetSourceInfo(interp, scriptObjPtr, Jim_NewStringObj(interp, filename, -1), 1); Jim_IncrRefCount(scriptObjPtr); + + if (SetScriptFromAny(interp, scriptObjPtr, &result) == JIM_ERR) { + const char *msg; + char linebuf[20]; + + switch (result.missing) { + case '[': + msg = "unmatched \"[\""; + break; + case '{': + msg = "missing close-brace"; + break; + case '"': + default: + msg = "missing quote"; + break; + } + + snprintf(linebuf, sizeof(linebuf), "%d", result.line); + + Jim_SetResultFormatted(interp, "%s in \"%s\" at line %s", + msg, filename, linebuf); + Jim_DecrRefCount(interp, scriptObjPtr); + return JIM_ERR; + } + prevScriptObj = interp->currentScriptObj; interp->currentScriptObj = scriptObjPtr; retcode = Jim_EvalObj(interp, scriptObjPtr); @@ -15718,11 +15480,11 @@ } typedef void JimHashtableIteratorCallbackType(Jim_Interp *interp, Jim_Obj *listObjPtr, Jim_HashEntry *he, int type); -#define JimTrivialMatch(pattern) (strpbrk((pattern), "*[?\\") == NULL) +#define JimTrivialMatch(pattern) (strpbrk((pattern), "*[?\\") == NULL) static Jim_Obj *JimHashtablePatternMatch(Jim_Interp *interp, Jim_HashTable *ht, Jim_Obj *patternObjPtr, JimHashtableIteratorCallbackType *callback, int type) { Jim_HashEntry *he; @@ -15753,11 +15515,11 @@ #define JIM_CMDLIST_CHANNELS 2 static void JimCommandMatch(Jim_Interp *interp, Jim_Obj *listObjPtr, Jim_HashEntry *he, int type) { - Jim_Cmd *cmdPtr = Jim_GetHashEntryVal(he); + Jim_Cmd *cmdPtr = (Jim_Cmd *)he->u.val; Jim_Obj *objPtr; if (type == JIM_CMDLIST_PROCS && !cmdPtr->isproc) { return; @@ -15786,11 +15548,11 @@ #define JIM_VARLIST_VALUES 0x1000 static void JimVariablesMatch(Jim_Interp *interp, Jim_Obj *listObjPtr, Jim_HashEntry *he, int type) { - Jim_Var *varPtr = Jim_GetHashEntryVal(he); + Jim_Var *varPtr = (Jim_Var *)he->u.val; if (type != JIM_VARLIST_LOCALS || varPtr->linkFramePtr == NULL) { Jim_ListAppendElement(interp, listObjPtr, Jim_NewStringObj(interp, he->key, -1)); if (type & JIM_VARLIST_VALUES) { Jim_ListAppendElement(interp, listObjPtr, varPtr->objPtr); @@ -16105,14 +15867,14 @@ Jim_Obj *objPtr; int cmpOffset; expr = JimGetExpression(interp, argv[2]); - incrScript = JimGetScript(interp, argv[3]); + incrScript = Jim_GetScript(interp, argv[3]); - if (incrScript == NULL || incrScript->len != 3 || !expr || expr->len != 3) { + if (incrScript->len != 3 || !expr || expr->len != 3) { goto evalstart; } if (incrScript->token[1].type != JIM_TT_ESC || expr->token[0].type != JIM_TT_VAR || @@ -16331,11 +16093,11 @@ } static int JimForeachMapHelper(Jim_Interp *interp, int argc, Jim_Obj *const *argv, int doMap) { - int result = JIM_OK; + int result = JIM_ERR; int i, numargs; Jim_ListIter twoiters[2]; Jim_ListIter *iters; Jim_Obj *script; Jim_Obj *resultObj; @@ -16354,17 +16116,14 @@ iters = Jim_Alloc(numargs * sizeof(*iters)); } for (i = 0; i < numargs; i++) { JimListIterInit(&iters[i], argv[i + 1]); if (i % 2 == 0 && JimListIterDone(interp, &iters[i])) { - result = JIM_ERR; + Jim_SetResultString(interp, "foreach varlist is empty", -1); + return JIM_ERR; } } - if (result != JIM_OK) { - Jim_SetResultString(interp, "foreach varlist is empty", -1); - return result; - } if (doMap) { resultObj = Jim_NewListObj(interp, NULL, 0); } else { @@ -16676,12 +16435,12 @@ { Jim_Obj *objPtr, *listObjPtr; int i; int idx; - if (argc < 2) { - Jim_WrongNumArgs(interp, 1, argv, "list ?index ...?"); + if (argc < 3) { + Jim_WrongNumArgs(interp, 1, argv, "list index ?...?"); return JIM_ERR; } objPtr = argv[1]; Jim_IncrRefCount(objPtr); for (i = 2; i < argc; i++) { @@ -16793,13 +16552,14 @@ Jim_IncrRefCount(commandObj); } listlen = Jim_ListLength(interp, argv[0]); for (i = 0; i < listlen; i++) { + Jim_Obj *objPtr; int eq = 0; - Jim_Obj *objPtr = Jim_ListGetIndex(interp, argv[0], i); + Jim_ListIndex(interp, argv[0], i, &objPtr, JIM_NONE); switch (opt_match) { case OPT_EXACT: eq = Jim_StringCompareObj(interp, argv[1], objPtr, opt_nocase) == 0; break; @@ -16989,27 +16749,29 @@ if (argc < 3) { Jim_WrongNumArgs(interp, 1, argv, "listVar ?index...? newVal"); return JIM_ERR; } else if (argc == 3) { - if (Jim_SetVariable(interp, argv[1], argv[2]) != JIM_OK) return JIM_ERR; Jim_SetResult(interp, argv[2]); return JIM_OK; } - return Jim_ListSetIndex(interp, argv[1], argv + 2, argc - 3, argv[argc - 1]); + if (Jim_SetListIndex(interp, argv[1], argv + 2, argc - 3, argv[argc - 1]) + == JIM_ERR) + return JIM_ERR; + return JIM_OK; } static int Jim_LsortCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const argv[]) { static const char * const options[] = { - "-ascii", "-nocase", "-increasing", "-decreasing", "-command", "-integer", "-real", "-index", "-unique", NULL + "-ascii", "-nocase", "-increasing", "-decreasing", "-command", "-integer", "-index", NULL }; enum - { OPT_ASCII, OPT_NOCASE, OPT_INCREASING, OPT_DECREASING, OPT_COMMAND, OPT_INTEGER, OPT_REAL, OPT_INDEX, OPT_UNIQUE }; + { OPT_ASCII, OPT_NOCASE, OPT_INCREASING, OPT_DECREASING, OPT_COMMAND, OPT_INTEGER, OPT_INDEX }; Jim_Obj *resObj; int i; int retCode; struct lsort_info info; @@ -17020,18 +16782,17 @@ } info.type = JIM_LSORT_ASCII; info.order = 1; info.indexed = 0; - info.unique = 0; info.command = NULL; info.interp = interp; for (i = 1; i < (argc - 1); i++) { int option; - if (Jim_GetEnum(interp, argv[i], options, &option, NULL, JIM_ENUM_ABBREV | JIM_ERRMSG) + if (Jim_GetEnum(interp, argv[i], options, &option, NULL, JIM_ERRMSG) != JIM_OK) return JIM_ERR; switch (option) { case OPT_ASCII: info.type = JIM_LSORT_ASCII; @@ -17040,22 +16801,16 @@ info.type = JIM_LSORT_NOCASE; break; case OPT_INTEGER: info.type = JIM_LSORT_INTEGER; break; - case OPT_REAL: - info.type = JIM_LSORT_REAL; - break; case OPT_INCREASING: info.order = 1; break; case OPT_DECREASING: info.order = -1; break; - case OPT_UNIQUE: - info.unique = 1; - break; case OPT_COMMAND: if (i >= (argc - 2)) { Jim_SetResultString(interp, "\"-command\" option must be followed by comparison command", -1); return JIM_ERR; } @@ -17092,11 +16847,11 @@ { Jim_Obj *stringObjPtr; int i; if (argc < 2) { - Jim_WrongNumArgs(interp, 1, argv, "varName ?value ...?"); + Jim_WrongNumArgs(interp, 1, argv, "varName ?value value ...?"); return JIM_ERR; } if (argc == 2) { stringObjPtr = Jim_GetVariable(interp, argv[1], JIM_ERRMSG); if (!stringObjPtr) @@ -17141,11 +16896,11 @@ static int Jim_EvalCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { int rc; if (argc < 2) { - Jim_WrongNumArgs(interp, 1, argv, "arg ?arg ...?"); + Jim_WrongNumArgs(interp, 1, argv, "script ?...?"); return JIM_ERR; } if (argc == 2) { rc = Jim_EvalObj(interp, argv[1]); @@ -17165,20 +16920,20 @@ static int Jim_UplevelCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { if (argc >= 2) { int retcode; Jim_CallFrame *savedCallFrame, *targetCallFrame; - int savedTailcall; + Jim_Obj *objPtr; const char *str; savedCallFrame = interp->framePtr; str = Jim_String(argv[1]); if ((str[0] >= '0' && str[0] <= '9') || str[0] == '#') { - targetCallFrame = Jim_GetCallFrameByLevel(interp, argv[1]); + targetCallFrame =Jim_GetCallFrameByLevel(interp, argv[1]); argc--; argv++; } else { targetCallFrame = Jim_GetCallFrameByLevel(interp, NULL); @@ -17185,25 +16940,25 @@ } if (targetCallFrame == NULL) { return JIM_ERR; } if (argc < 2) { - Jim_WrongNumArgs(interp, 1, argv - 1, "?level? command ?arg ...?"); + argv--; + Jim_WrongNumArgs(interp, 1, argv, "?level? command ?arg ...?"); return JIM_ERR; } interp->framePtr = targetCallFrame; - - savedTailcall = interp->framePtr->tailcall; - interp->framePtr->tailcall = 0; if (argc == 2) { retcode = Jim_EvalObj(interp, argv[1]); } else { - retcode = Jim_EvalObj(interp, Jim_ConcatObj(interp, argc - 1, argv + 1)); + objPtr = Jim_ConcatObj(interp, argc - 1, argv + 1); + Jim_IncrRefCount(objPtr); + retcode = Jim_EvalObj(interp, objPtr); + Jim_DecrRefCount(interp, objPtr); } - interp->framePtr->tailcall = savedTailcall; interp->framePtr = savedCallFrame; return retcode; } else { Jim_WrongNumArgs(interp, 1, argv, "?level? command ?arg ...?"); @@ -17314,49 +17069,22 @@ } static int Jim_TailcallCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { - if (interp->framePtr->level == 0) { - Jim_SetResultString(interp, "tailcall can only be called from a proc or lambda", -1); - return JIM_ERR; - } - else if (argc >= 2) { - - Jim_CallFrame *cf = interp->framePtr->parent; - - Jim_Cmd *cmdPtr = Jim_GetCommand(interp, argv[1], JIM_ERRMSG); - if (cmdPtr == NULL) { - return JIM_ERR; - } - - JimPanic((cf->tailcallCmd != NULL, "Already have a tailcallCmd")); - - - JimIncrCmdRefCount(cmdPtr); - cf->tailcallCmd = cmdPtr; - - - JimPanic((cf->tailcallObj != NULL, "Already have a tailcallobj")); - - cf->tailcallObj = Jim_NewListObj(interp, argv + 1, argc - 1); - Jim_IncrRefCount(cf->tailcallObj); - - - return JIM_EVAL; - } - return JIM_OK; + Jim_SetResult(interp, Jim_NewListObj(interp, argv + 1, argc - 1)); + return JIM_EVAL; } static int JimAliasCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { Jim_Obj *cmdList; Jim_Obj *prefixListObj = Jim_CmdPrivData(interp); cmdList = Jim_DuplicateObj(interp, prefixListObj); - Jim_ListInsertElements(interp, cmdList, Jim_ListLength(interp, cmdList), argc - 1, argv + 1); + ListInsertElements(cmdList, -1, argc - 1, argv + 1); return JimEvalObjList(interp, cmdList); } static void JimAliasCmdDelete(Jim_Interp *interp, void *privData) @@ -17431,15 +17159,10 @@ static int Jim_LocalCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { int retcode; - if (argc < 2) { - Jim_WrongNumArgs(interp, 1, argv, "cmd ?args ...?"); - return JIM_ERR; - } - interp->local++; retcode = Jim_EvalObjVector(interp, argc - 1, argv + 1); interp->local--; @@ -17631,11 +17354,11 @@ for (i = 0; i < numMaps; i += 2) { Jim_Obj *objPtr; const char *k; int kl; - objPtr = Jim_ListGetIndex(interp, mapListObjPtr, i); + Jim_ListIndex(interp, mapListObjPtr, i, &objPtr, JIM_NONE); k = Jim_String(objPtr); kl = Jim_Utf8Length(interp, objPtr); if (strLen >= kl && kl) { int rc; @@ -17643,11 +17366,12 @@ if (rc == 0) { if (noMatchStart) { Jim_AppendString(interp, resultObjPtr, noMatchStart, str - noMatchStart); noMatchStart = NULL; } - Jim_AppendObj(interp, resultObjPtr, Jim_ListGetIndex(interp, mapListObjPtr, i + 1)); + Jim_ListIndex(interp, mapListObjPtr, i + 1, &objPtr, JIM_NONE); + Jim_AppendObj(interp, resultObjPtr, objPtr); str += utf8_index(str, kl); strLen -= kl; break; } } @@ -17672,17 +17396,17 @@ int len; int opt_case = 1; int option; static const char * const options[] = { "bytelength", "length", "compare", "match", "equal", "is", "byterange", "range", "replace", - "map", "repeat", "reverse", "index", "first", "last", "cat", + "map", "repeat", "reverse", "index", "first", "last", "trim", "trimleft", "trimright", "tolower", "toupper", "totitle", NULL }; enum { OPT_BYTELENGTH, OPT_LENGTH, OPT_COMPARE, OPT_MATCH, OPT_EQUAL, OPT_IS, OPT_BYTERANGE, OPT_RANGE, OPT_REPLACE, - OPT_MAP, OPT_REPEAT, OPT_REVERSE, OPT_INDEX, OPT_FIRST, OPT_LAST, OPT_CAT, + OPT_MAP, OPT_REPEAT, OPT_REVERSE, OPT_INDEX, OPT_FIRST, OPT_LAST, OPT_TRIM, OPT_TRIMLEFT, OPT_TRIMRIGHT, OPT_TOLOWER, OPT_TOUPPER, OPT_TOTITLE }; static const char * const nocase_options[] = { "-nocase", NULL }; @@ -17712,29 +17436,10 @@ len = Jim_Length(argv[2]); } Jim_SetResultInt(interp, len); return JIM_OK; - case OPT_CAT:{ - Jim_Obj *objPtr; - if (argc == 3) { - - objPtr = argv[2]; - } - else { - int i; - - objPtr = Jim_NewStringObj(interp, "", 0); - - for (i = 2; i < argc; i++) { - Jim_AppendObj(interp, objPtr, argv[i]); - } - } - Jim_SetResult(interp, objPtr); - return JIM_OK; - } - case OPT_COMPARE: case OPT_EQUAL: { long opt_length = -1; @@ -18146,17 +17851,15 @@ exitCode = JIM_SIGNAL; } else { exitCode = Jim_EvalObj(interp, argv[0]); - - interp->errorFlag = 0; } interp->signal_level -= sig; - if (exitCode >= 0 && exitCode < max_ignore_code && (((unsigned jim_wide)1 << exitCode) & ignore_mask)) { + if (exitCode >= 0 && exitCode < max_ignore_code && ((1 << exitCode) & ignore_mask)) { return exitCode; } if (sig && exitCode == JIM_SIGNAL) { @@ -18306,11 +18009,11 @@ listObjPtr = Jim_NewListObj(interp, NULL, 0); JimInitHashTableIterator(&interp->references, &htiter); while ((he = Jim_NextHashEntry(&htiter)) != NULL) { char buf[JIM_REFERENCE_SPACE + 1]; - Jim_Reference *refPtr = Jim_GetHashEntryVal(he); + Jim_Reference *refPtr = he->u.val; const unsigned long *refId = he->key; JimFormatReference(buf, refPtr, *refId); Jim_ListAppendElement(interp, listObjPtr, Jim_NewStringObj(interp, buf, -1)); } @@ -18340,11 +18043,11 @@ static void JimDictMatchKeys(Jim_Interp *interp, Jim_Obj *listObjPtr, Jim_HashEntry *he, int type) { Jim_ListAppendElement(interp, listObjPtr, (Jim_Obj *)he->key); if (type & JIM_DICTMATCH_VALUES) { - Jim_ListAppendElement(interp, listObjPtr, Jim_GetHashEntryVal(he)); + Jim_ListAppendElement(interp, listObjPtr, (Jim_Obj *)he->u.val); } } static Jim_Obj *JimDictPatternMatch(Jim_Interp *interp, Jim_HashTable *ht, Jim_Obj *patternObjPtr, JimDictMatchCallbackType *callback, int type) @@ -18389,65 +18092,21 @@ return -1; } return ((Jim_HashTable *)objPtr->internalRep.ptr)->used; } -int Jim_DictInfo(Jim_Interp *interp, Jim_Obj *objPtr) -{ - Jim_HashTable *ht; - unsigned int i; - - if (SetDictFromAny(interp, objPtr) != JIM_OK) { - return JIM_ERR; - } - - ht = (Jim_HashTable *)objPtr->internalRep.ptr; - - - printf("%d entries in table, %d buckets\n", ht->used, ht->size); - - for (i = 0; i < ht->size; i++) { - Jim_HashEntry *he = ht->table[i]; - - if (he) { - printf("%d: ", i); - - while (he) { - printf(" %s", Jim_String(he->key)); - he = he->next; - } - printf("\n"); - } - } - return JIM_OK; -} - -static int Jim_EvalEnsemble(Jim_Interp *interp, const char *basecmd, const char *subcmd, int argc, Jim_Obj *const *argv) -{ - Jim_Obj *prefixObj = Jim_NewStringObj(interp, basecmd, -1); - - Jim_AppendString(interp, prefixObj, " ", 1); - Jim_AppendString(interp, prefixObj, subcmd, -1); - - return Jim_EvalObjPrefix(interp, prefixObj, argc, argv); -} - static int Jim_DictCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { Jim_Obj *objPtr; int option; static const char * const options[] = { - "create", "get", "set", "unset", "exists", "keys", "size", "info", - "merge", "with", "append", "lappend", "incr", "remove", "values", "for", - "replace", "update", NULL + "create", "get", "set", "unset", "exists", "keys", "merge", "size", "with", NULL }; enum { - OPT_CREATE, OPT_GET, OPT_SET, OPT_UNSET, OPT_EXISTS, OPT_KEYS, OPT_SIZE, OPT_INFO, - OPT_MERGE, OPT_WITH, OPT_APPEND, OPT_LAPPEND, OPT_INCR, OPT_REMOVE, OPT_VALUES, OPT_FOR, - OPT_REPLACE, OPT_UPDATE, + OPT_CREATE, OPT_GET, OPT_SET, OPT_UNSET, OPT_EXIST, OPT_KEYS, OPT_MERGE, OPT_SIZE, OPT_WITH, }; if (argc < 2) { Jim_WrongNumArgs(interp, 1, argv, "subcommand ?arguments ...?"); return JIM_ERR; @@ -18458,11 +18117,11 @@ } switch (option) { case OPT_GET: if (argc < 3) { - Jim_WrongNumArgs(interp, 2, argv, "dictionary ?key ...?"); + Jim_WrongNumArgs(interp, 2, argv, "varName ?key ...?"); return JIM_ERR; } if (Jim_DictKeysVector(interp, argv[2], argv + 3, argc - 3, &objPtr, JIM_ERRMSG) != JIM_OK) { return JIM_ERR; @@ -18475,87 +18134,82 @@ Jim_WrongNumArgs(interp, 2, argv, "varName key ?key ...? value"); return JIM_ERR; } return Jim_SetDictKeysVector(interp, argv[2], argv + 3, argc - 4, argv[argc - 1], JIM_ERRMSG); - case OPT_EXISTS: - if (argc < 4) { - Jim_WrongNumArgs(interp, 2, argv, "dictionary key ?key ...?"); + case OPT_EXIST: + if (argc < 3) { + Jim_WrongNumArgs(interp, 2, argv, "varName ?key ...?"); return JIM_ERR; } - else { - int rc = Jim_DictKeysVector(interp, argv[2], argv + 3, argc - 3, &objPtr, JIM_ERRMSG); - if (rc < 0) { - return JIM_ERR; - } - Jim_SetResultBool(interp, rc == JIM_OK); - return JIM_OK; - } + Jim_SetResultBool(interp, Jim_DictKeysVector(interp, argv[2], argv + 3, argc - 3, + &objPtr, JIM_ERRMSG) == JIM_OK); + return JIM_OK; case OPT_UNSET: if (argc < 4) { Jim_WrongNumArgs(interp, 2, argv, "varName key ?key ...?"); return JIM_ERR; } - if (Jim_SetDictKeysVector(interp, argv[2], argv + 3, argc - 3, NULL, 0) != JIM_OK) { - return JIM_ERR; - } - return JIM_OK; + return Jim_SetDictKeysVector(interp, argv[2], argv + 3, argc - 3, NULL, JIM_NONE); case OPT_KEYS: if (argc != 3 && argc != 4) { - Jim_WrongNumArgs(interp, 2, argv, "dictionary ?pattern?"); + Jim_WrongNumArgs(interp, 2, argv, "dictVar ?pattern?"); return JIM_ERR; } return Jim_DictKeys(interp, argv[2], argc == 4 ? argv[3] : NULL); - case OPT_SIZE: + case OPT_SIZE: { + int size; + if (argc != 3) { - Jim_WrongNumArgs(interp, 2, argv, "dictionary"); + Jim_WrongNumArgs(interp, 2, argv, "dictVar"); return JIM_ERR; } - else if (Jim_DictSize(interp, argv[2]) < 0) { + + size = Jim_DictSize(interp, argv[2]); + if (size < 0) { return JIM_ERR; } - Jim_SetResultInt(interp, Jim_DictSize(interp, argv[2])); + Jim_SetResultInt(interp, size); return JIM_OK; + } case OPT_MERGE: if (argc == 2) { return JIM_OK; } - if (Jim_DictSize(interp, argv[2]) < 0) { + else if (SetDictFromAny(interp, argv[2]) != JIM_OK) { + return JIM_ERR; + } + else { + return Jim_EvalPrefix(interp, "dict merge", argc - 2, argv + 2); + } + + case OPT_WITH: + if (argc < 4) { + Jim_WrongNumArgs(interp, 2, argv, "dictVar ?key ...? script"); + return JIM_ERR; + } + else if (Jim_GetVariable(interp, argv[2], JIM_ERRMSG) == NULL) { return JIM_ERR; } - - break; - - case OPT_UPDATE: - if (argc < 6 || argc % 2) { - - argc = 2; - } - break; + else { + return Jim_EvalPrefix(interp, "dict with", argc - 2, argv + 2); + } case OPT_CREATE: if (argc % 2) { Jim_WrongNumArgs(interp, 2, argv, "?key value ...?"); return JIM_ERR; } objPtr = Jim_NewDictObj(interp, argv + 2, argc - 2); Jim_SetResult(interp, objPtr); return JIM_OK; - - case OPT_INFO: - if (argc != 3) { - Jim_WrongNumArgs(interp, 2, argv, "dictionary"); - return JIM_ERR; - } - return Jim_DictInfo(interp, argv[2]); - } - - return Jim_EvalEnsemble(interp, "dict", options[option], argc - 2, argv + 2); + } + return JIM_ERR; } static int Jim_SubstCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { @@ -18613,11 +18267,11 @@ }; enum { INFO_BODY, INFO_STATICS, INFO_COMMANDS, INFO_PROCS, INFO_CHANNELS, INFO_EXISTS, INFO_GLOBALS, INFO_LEVEL, INFO_FRAME, INFO_LOCALS, INFO_VARS, INFO_VERSION, INFO_PATCHLEVEL, INFO_COMPLETE, INFO_ARGS, INFO_HOSTNAME, INFO_SCRIPT, INFO_SOURCE, INFO_STACKTRACE, INFO_NAMEOFEXECUTABLE, - INFO_RETURNCODES, INFO_REFERENCES, INFO_ALIAS, + INFO_RETURNCODES, INFO_REFERENCES, INFO_ALIAS }; #ifdef jim_ext_namespace int nons = 0; @@ -18713,47 +18367,38 @@ case INFO_SCRIPT: if (argc != 2) { Jim_WrongNumArgs(interp, 2, argv, ""); return JIM_ERR; } - Jim_SetResult(interp, JimGetScript(interp, interp->currentScriptObj)->fileNameObj); + Jim_SetResult(interp, Jim_GetScript(interp, interp->currentScriptObj)->fileNameObj); break; case INFO_SOURCE:{ - jim_wide line; + int line; Jim_Obj *resObjPtr; Jim_Obj *fileNameObj; - if (argc != 3 && argc != 5) { - Jim_WrongNumArgs(interp, 2, argv, "source ?filename line?"); - return JIM_ERR; - } - if (argc == 5) { - if (Jim_GetWide(interp, argv[4], &line) != JIM_OK) { - return JIM_ERR; - } - resObjPtr = Jim_NewStringObj(interp, Jim_String(argv[2]), Jim_Length(argv[2])); - JimSetSourceInfo(interp, resObjPtr, argv[3], line); - } - else { - if (argv[2]->typePtr == &sourceObjType) { - fileNameObj = argv[2]->internalRep.sourceValue.fileNameObj; - line = argv[2]->internalRep.sourceValue.lineNumber; - } - else if (argv[2]->typePtr == &scriptObjType) { - ScriptObj *script = JimGetScript(interp, argv[2]); - fileNameObj = script->fileNameObj; - line = script->firstline; - } - else { - fileNameObj = interp->emptyObj; - line = 1; - } - resObjPtr = Jim_NewListObj(interp, NULL, 0); - Jim_ListAppendElement(interp, resObjPtr, fileNameObj); - Jim_ListAppendElement(interp, resObjPtr, Jim_NewIntObj(interp, line)); - } + if (argc != 3) { + Jim_WrongNumArgs(interp, 2, argv, "source"); + return JIM_ERR; + } + if (argv[2]->typePtr == &sourceObjType) { + fileNameObj = argv[2]->internalRep.sourceValue.fileNameObj; + line = argv[2]->internalRep.sourceValue.lineNumber; + } + else if (argv[2]->typePtr == &scriptObjType) { + ScriptObj *script = Jim_GetScript(interp, argv[2]); + fileNameObj = script->fileNameObj; + line = script->firstline; + } + else { + fileNameObj = interp->emptyObj; + line = 1; + } + resObjPtr = Jim_NewListObj(interp, NULL, 0); + Jim_ListAppendElement(interp, resObjPtr, fileNameObj); + Jim_ListAppendElement(interp, resObjPtr, Jim_NewIntObj(interp, line)); Jim_SetResult(interp, resObjPtr); break; } case INFO_STACKTRACE: @@ -19402,11 +19047,11 @@ } } static const struct { const char *name; - Jim_CmdProc *cmdProc; + Jim_CmdProc cmdProc; } Jim_CoreCommandsTable[] = { {"alias", Jim_AliasCoreCommand}, {"set", Jim_SetCoreCommand}, {"unset", Jim_UnsetCoreCommand}, {"puts", Jim_PutsCoreCommand}, @@ -19635,12 +19280,10 @@ len += extra; buf = Jim_Alloc(len + 1); len = snprintf(buf, len + 1, format, params[0], params[1], params[2], params[3], params[4]); - va_end(args); - Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, buf, len)); } #ifndef jim_ext_package @@ -19887,373 +19530,344 @@ #include #include +#define JIM_UTF_MAX 3 #define JIM_INTEGER_SPACE 24 #define MAX_FLOAT_WIDTH 320 Jim_Obj *Jim_FormatString(Jim_Interp *interp, Jim_Obj *fmtObjPtr, int objc, Jim_Obj *const *objv) { const char *span, *format, *formatEnd, *msg; int numBytes = 0, objIndex = 0, gotXpg = 0, gotSequential = 0; static const char * const mixedXPG = - "cannot mix \"%\" and \"%n$\" conversion specifiers"; + "cannot mix \"%\" and \"%n$\" conversion specifiers"; static const char * const badIndex[2] = { - "not enough arguments for all format specifiers", - "\"%n$\" argument index out of range" + "not enough arguments for all format specifiers", + "\"%n$\" argument index out of range" }; int formatLen; Jim_Obj *resultPtr; char *num_buffer = NULL; int num_buffer_size = 0; span = format = Jim_GetString(fmtObjPtr, &formatLen); formatEnd = format + formatLen; - resultPtr = Jim_NewEmptyStringObj(interp); + resultPtr = Jim_NewStringObj(interp, "", 0); while (format != formatEnd) { - char *end; - int gotMinus, sawFlag; - int gotPrecision, useShort; - long width, precision; - int newXpg; - int ch; - int step; - int doubleType; - char pad = ' '; - char spec[2*JIM_INTEGER_SPACE + 12]; - char *p; - - int formatted_chars; - int formatted_bytes; - const char *formatted_buf; - - step = utf8_tounicode(format, &ch); - format += step; - if (ch != '%') { - numBytes += step; - continue; - } - if (numBytes) { - Jim_AppendString(interp, resultPtr, span, numBytes); - numBytes = 0; - } - - - step = utf8_tounicode(format, &ch); - if (ch == '%') { - span = format; - numBytes = step; - format += step; - continue; - } - - - newXpg = 0; - if (isdigit(ch)) { - int position = strtoul(format, &end, 10); - if (*end == '$') { - newXpg = 1; - objIndex = position - 1; - format = end + 1; - step = utf8_tounicode(format, &ch); - } - } - if (newXpg) { - if (gotSequential) { - msg = mixedXPG; - goto errorMsg; - } - gotXpg = 1; - } else { - if (gotXpg) { - msg = mixedXPG; - goto errorMsg; - } - gotSequential = 1; - } - if ((objIndex < 0) || (objIndex >= objc)) { - msg = badIndex[gotXpg]; - goto errorMsg; - } - - p = spec; - *p++ = '%'; - - gotMinus = 0; - sawFlag = 1; - do { - switch (ch) { - case '-': - gotMinus = 1; - break; - case '0': - pad = ch; - break; - case ' ': - case '+': - case '#': - break; - default: - sawFlag = 0; - continue; - } - *p++ = ch; - format += step; - step = utf8_tounicode(format, &ch); - } while (sawFlag); - - - width = 0; - if (isdigit(ch)) { - width = strtoul(format, &end, 10); - format = end; - step = utf8_tounicode(format, &ch); - } else if (ch == '*') { - if (objIndex >= objc - 1) { - msg = badIndex[gotXpg]; - goto errorMsg; - } - if (Jim_GetLong(interp, objv[objIndex], &width) != JIM_OK) { - goto error; - } - if (width < 0) { - width = -width; - if (!gotMinus) { - *p++ = '-'; - gotMinus = 1; - } - } - objIndex++; - format += step; - step = utf8_tounicode(format, &ch); - } - - - gotPrecision = precision = 0; - if (ch == '.') { - gotPrecision = 1; - format += step; - step = utf8_tounicode(format, &ch); - } - if (isdigit(ch)) { - precision = strtoul(format, &end, 10); - format = end; - step = utf8_tounicode(format, &ch); - } else if (ch == '*') { - if (objIndex >= objc - 1) { - msg = badIndex[gotXpg]; - goto errorMsg; - } - if (Jim_GetLong(interp, objv[objIndex], &precision) != JIM_OK) { - goto error; - } - - - if (precision < 0) { - precision = 0; - } - objIndex++; - format += step; - step = utf8_tounicode(format, &ch); - } - - - useShort = 0; - if (ch == 'h') { - useShort = 1; - format += step; - step = utf8_tounicode(format, &ch); - } else if (ch == 'l') { - - format += step; - step = utf8_tounicode(format, &ch); - if (ch == 'l') { - format += step; - step = utf8_tounicode(format, &ch); - } - } - - format += step; - span = format; - - - if (ch == 'i') { - ch = 'd'; - } - - doubleType = 0; - - switch (ch) { - case '\0': - msg = "format string ended in middle of field specifier"; - goto errorMsg; - case 's': { - formatted_buf = Jim_GetString(objv[objIndex], &formatted_bytes); - formatted_chars = Jim_Utf8Length(interp, objv[objIndex]); - if (gotPrecision && (precision < formatted_chars)) { - - formatted_chars = precision; - formatted_bytes = utf8_index(formatted_buf, precision); - } - break; - } - case 'c': { - jim_wide code; - - if (Jim_GetWide(interp, objv[objIndex], &code) != JIM_OK) { - goto error; - } - - formatted_bytes = utf8_getchars(spec, code); - formatted_buf = spec; - formatted_chars = 1; - break; - } - case 'b': { - unsigned jim_wide w; - int length; - int i; - int j; - - if (Jim_GetWide(interp, objv[objIndex], (jim_wide *)&w) != JIM_OK) { - goto error; - } - length = sizeof(w) * 8; - - - - if (num_buffer_size < length + 1) { - num_buffer_size = length + 1; - num_buffer = Jim_Realloc(num_buffer, num_buffer_size); - } - - j = 0; - for (i = length; i > 0; ) { - i--; - if (w & ((unsigned jim_wide)1 << i)) { - num_buffer[j++] = '1'; - } - else if (j || i == 0) { - num_buffer[j++] = '0'; - } - } - num_buffer[j] = 0; - formatted_chars = formatted_bytes = j; - formatted_buf = num_buffer; - break; - } - - case 'e': - case 'E': - case 'f': - case 'g': - case 'G': - doubleType = 1; - - case 'd': - case 'u': - case 'o': - case 'x': - case 'X': { - jim_wide w; - double d; - int length; - - - if (width) { - p += sprintf(p, "%ld", width); - } - if (gotPrecision) { - p += sprintf(p, ".%ld", precision); - } - - - if (doubleType) { - if (Jim_GetDouble(interp, objv[objIndex], &d) != JIM_OK) { - goto error; - } - length = MAX_FLOAT_WIDTH; - } - else { - if (Jim_GetWide(interp, objv[objIndex], &w) != JIM_OK) { - goto error; - } - length = JIM_INTEGER_SPACE; - if (useShort) { - if (ch == 'd') { - w = (short)w; - } - else { - w = (unsigned short)w; - } - } - *p++ = 'l'; -#ifdef HAVE_LONG_LONG - if (sizeof(long long) == sizeof(jim_wide)) { - *p++ = 'l'; - } -#endif - } - - *p++ = (char) ch; - *p = '\0'; - - - if (width > length) { - length = width; - } - if (gotPrecision) { - length += precision; - } - - - if (num_buffer_size < length + 1) { - num_buffer_size = length + 1; - num_buffer = Jim_Realloc(num_buffer, num_buffer_size); - } - - if (doubleType) { - snprintf(num_buffer, length + 1, spec, d); - } - else { - formatted_bytes = snprintf(num_buffer, length + 1, spec, w); - } - formatted_chars = formatted_bytes = strlen(num_buffer); - formatted_buf = num_buffer; - break; - } - - default: { - - spec[0] = ch; - spec[1] = '\0'; - Jim_SetResultFormatted(interp, "bad field specifier \"%s\"", spec); - goto error; - } - } - - if (!gotMinus) { - while (formatted_chars < width) { - Jim_AppendString(interp, resultPtr, &pad, 1); - formatted_chars++; - } - } - - Jim_AppendString(interp, resultPtr, formatted_buf, formatted_bytes); - - while (formatted_chars < width) { - Jim_AppendString(interp, resultPtr, &pad, 1); - formatted_chars++; - } - - objIndex += gotSequential; - } - if (numBytes) { - Jim_AppendString(interp, resultPtr, span, numBytes); + char *end; + int gotMinus, sawFlag; + int gotPrecision, useShort; + long width, precision; + int newXpg; + int ch; + int step; + int doubleType; + char pad = ' '; + char spec[2*JIM_INTEGER_SPACE + 12]; + char *p; + + int formatted_chars; + int formatted_bytes; + const char *formatted_buf; + + step = utf8_tounicode(format, &ch); + format += step; + if (ch != '%') { + numBytes += step; + continue; + } + if (numBytes) { + Jim_AppendString(interp, resultPtr, span, numBytes); + numBytes = 0; + } + + + step = utf8_tounicode(format, &ch); + if (ch == '%') { + span = format; + numBytes = step; + format += step; + continue; + } + + + newXpg = 0; + if (isdigit(ch)) { + int position = strtoul(format, &end, 10); + if (*end == '$') { + newXpg = 1; + objIndex = position - 1; + format = end + 1; + step = utf8_tounicode(format, &ch); + } + } + if (newXpg) { + if (gotSequential) { + msg = mixedXPG; + goto errorMsg; + } + gotXpg = 1; + } else { + if (gotXpg) { + msg = mixedXPG; + goto errorMsg; + } + gotSequential = 1; + } + if ((objIndex < 0) || (objIndex >= objc)) { + msg = badIndex[gotXpg]; + goto errorMsg; + } + + p = spec; + *p++ = '%'; + + gotMinus = 0; + sawFlag = 1; + do { + switch (ch) { + case '-': + gotMinus = 1; + break; + case '0': + pad = ch; + break; + case ' ': + case '+': + case '#': + break; + default: + sawFlag = 0; + continue; + } + *p++ = ch; + format += step; + step = utf8_tounicode(format, &ch); + } while (sawFlag); + + + width = 0; + if (isdigit(ch)) { + width = strtoul(format, &end, 10); + format = end; + step = utf8_tounicode(format, &ch); + } else if (ch == '*') { + if (objIndex >= objc - 1) { + msg = badIndex[gotXpg]; + goto errorMsg; + } + if (Jim_GetLong(interp, objv[objIndex], &width) != JIM_OK) { + goto error; + } + if (width < 0) { + width = -width; + if (!gotMinus) { + *p++ = '-'; + gotMinus = 1; + } + } + objIndex++; + format += step; + step = utf8_tounicode(format, &ch); + } + + + gotPrecision = precision = 0; + if (ch == '.') { + gotPrecision = 1; + format += step; + step = utf8_tounicode(format, &ch); + } + if (isdigit(ch)) { + precision = strtoul(format, &end, 10); + format = end; + step = utf8_tounicode(format, &ch); + } else if (ch == '*') { + if (objIndex >= objc - 1) { + msg = badIndex[gotXpg]; + goto errorMsg; + } + if (Jim_GetLong(interp, objv[objIndex], &precision) != JIM_OK) { + goto error; + } + + + if (precision < 0) { + precision = 0; + } + objIndex++; + format += step; + step = utf8_tounicode(format, &ch); + } + + + useShort = 0; + if (ch == 'h') { + useShort = 1; + format += step; + step = utf8_tounicode(format, &ch); + } else if (ch == 'l') { + + format += step; + step = utf8_tounicode(format, &ch); + if (ch == 'l') { + format += step; + step = utf8_tounicode(format, &ch); + } + } + + format += step; + span = format; + + + if (ch == 'i') { + ch = 'd'; + } + + doubleType = 0; + + switch (ch) { + case '\0': + msg = "format string ended in middle of field specifier"; + goto errorMsg; + case 's': { + formatted_buf = Jim_GetString(objv[objIndex], &formatted_bytes); + formatted_chars = Jim_Utf8Length(interp, objv[objIndex]); + if (gotPrecision && (precision < formatted_chars)) { + + formatted_chars = precision; + formatted_bytes = utf8_index(formatted_buf, precision); + } + break; + } + case 'c': { + jim_wide code; + + if (Jim_GetWide(interp, objv[objIndex], &code) != JIM_OK) { + goto error; + } + + formatted_bytes = utf8_fromunicode(spec, code); + formatted_buf = spec; + formatted_chars = 1; + break; + } + + case 'e': + case 'E': + case 'f': + case 'g': + case 'G': + doubleType = 1; + + case 'd': + case 'u': + case 'o': + case 'x': + case 'X': { + jim_wide w; + double d; + int length; + + + if (width) { + p += sprintf(p, "%ld", width); + } + if (gotPrecision) { + p += sprintf(p, ".%ld", precision); + } + + + if (doubleType) { + if (Jim_GetDouble(interp, objv[objIndex], &d) != JIM_OK) { + goto error; + } + length = MAX_FLOAT_WIDTH; + } + else { + if (Jim_GetWide(interp, objv[objIndex], &w) != JIM_OK) { + goto error; + } + length = JIM_INTEGER_SPACE; + if (useShort) { + *p++ = 'h'; + if (ch == 'd') { + w = (short)w; + } + else { + w = (unsigned short)w; + } + } + else { + *p++ = 'l'; +#ifdef HAVE_LONG_LONG + if (sizeof(long long) == sizeof(jim_wide)) { + *p++ = 'l'; + } +#endif + } + } + + *p++ = (char) ch; + *p = '\0'; + + + if (width > length) { + length = width; + } + if (gotPrecision) { + length += precision; + } + + + if (num_buffer_size < length + 1) { + num_buffer_size = length + 1; + num_buffer = Jim_Realloc(num_buffer, num_buffer_size); + } + + if (doubleType) { + snprintf(num_buffer, length + 1, spec, d); + } + else { + formatted_bytes = snprintf(num_buffer, length + 1, spec, w); + } + formatted_chars = formatted_bytes = strlen(num_buffer); + formatted_buf = num_buffer; + break; + } + + default: { + + spec[0] = ch; + spec[1] = '\0'; + Jim_SetResultFormatted(interp, "bad field specifier \"%s\"", spec); + goto error; + } + } + + if (!gotMinus) { + while (formatted_chars < width) { + Jim_AppendString(interp, resultPtr, &pad, 1); + formatted_chars++; + } + } + + Jim_AppendString(interp, resultPtr, formatted_buf, formatted_bytes); + + while (formatted_chars < width) { + Jim_AppendString(interp, resultPtr, &pad, 1); + formatted_chars++; + } + + objIndex += gotSequential; + } + if (numBytes) { + Jim_AppendString(interp, resultPtr, span, numBytes); } Jim_Free(num_buffer); return resultPtr; @@ -20262,22 +19876,21 @@ error: Jim_FreeNewObj(interp, resultPtr); Jim_Free(num_buffer); return NULL; } - - -#if defined(JIM_REGEXP) #include #include #include #include +#if !defined(HAVE_REGCOMP) || defined(JIM_REGEXP) + + #define REG_MAX_PAREN 100 - #define END 0 #define BOL 1 #define EOL 2 @@ -20286,27 +19899,23 @@ #define ANYBUT 5 #define BRANCH 6 #define BACK 7 #define EXACTLY 8 #define NOTHING 9 -#define REP 10 +#define REP 10 #define REPMIN 11 #define REPX 12 #define REPXMIN 13 #define WORDA 15 #define WORDZ 16 - -#define OPENNC 1000 -#define OPEN 1001 - - - - -#define CLOSENC 2000 -#define CLOSE 2001 +#define OPENNC 19 +#define OPEN 20 + +#define CLOSE (OPEN+REG_MAX_PAREN+1) #define CLOSE_END (CLOSE+REG_MAX_PAREN) +#define CLOSENC (CLOSE-1) #define REG_MAGIC 0xFADED00D #define OP(preg, p) (preg->program[p]) @@ -20316,15 +19925,15 @@ #define FAIL(R,M) { (R)->err = (M); return (M); } #define ISMULT(c) ((c) == '*' || (c) == '+' || (c) == '?' || (c) == '{') -#define META "^$.[()|?{+*" +#define META "^$.[()|?{+*" -#define HASWIDTH 1 -#define SIMPLE 2 -#define SPSTART 4 +#define HASWIDTH 01 +#define SIMPLE 02 +#define SPSTART 04 #define WORST 0 #define MAX_REP_COUNT 1000000 static int reg(regex_t *preg, int paren , int *flagp ); @@ -20333,13 +19942,13 @@ static int regatom(regex_t *preg, int *flagp ); static int regnode(regex_t *preg, int op ); static int regnext(regex_t *preg, int p ); static void regc(regex_t *preg, int b ); static int reginsert(regex_t *preg, int op, int size, int opnd ); -static void regtail(regex_t *preg, int p, int val); +static void regtail_(regex_t *preg, int p, int val, int line ); static void regoptail(regex_t *preg, int p, int val ); -static int regopsize(regex_t *preg, int p ); +#define regtail(PREG, P, VAL) regtail_(PREG, P, VAL, __LINE__) static int reg_range_find(const int *string, int c); static const char *str_find(const char *string, int c, int nocase); static int prefix_cmp(const int *prog, int proglen, const char *string, int nocase); @@ -20376,10 +19985,13 @@ FAIL(preg, REG_ERR_NULL_ARGUMENT); preg->cflags = cflags; preg->regparse = exp; + + preg->program = NULL; + preg->proglen = 0; preg->proglen = (strlen(exp) + 1) * 5; preg->program = malloc(preg->proglen * sizeof(int)); if (preg->program == NULL) @@ -20540,10 +20152,11 @@ { int ret; char op; int next; int flags; + int chain = 0; int min; int max; ret = regatom(preg, &flags); if (ret == 0) @@ -20622,11 +20235,11 @@ if (ISMULT(*preg->regparse)) { preg->err = REG_ERR_NESTED_COUNT; return 0; } - return ret; + return chain ? chain : ret; } static void reg_addrange(regex_t *preg, int lower, int upper) { if (lower > upper) { @@ -20716,11 +20329,10 @@ break; case 'U': if ((n = parse_hex(s, 8, ch)) > 0) { s += n; } - break; case 'x': if ((n = parse_hex(s, 2, ch)) > 0) { s += n; } break; @@ -20965,11 +20577,10 @@ static int regnode(regex_t *preg, int op) { reg_grow(preg, 2); - preg->program[preg->p++] = op; preg->program[preg->p++] = 0; return preg->p - 2; @@ -20995,11 +20606,11 @@ preg->p += size; return opnd + size; } -static void regtail(regex_t *preg, int p, int val) +static void regtail_(regex_t *preg, int p, int val, int line ) { int scan; int temp; int offset; @@ -21058,16 +20669,36 @@ preg->pmatch = pmatch; preg->nmatch = nmatch; preg->start = string; - for (scan = OPERAND(1); scan != 0; scan += regopsize(preg, scan)) { - int op = OP(preg, scan); - if (op == END) - break; - if (op == REPX || op == REPXMIN) + for (scan = OPERAND(1); scan != 0; ) { + switch (OP(preg, scan)) { + case REP: + case REPMIN: + case REPX: + case REPXMIN: preg->program[scan + 4] = 0; + scan += 5; + break; + + case ANYOF: + case ANYBUT: + case EXACTLY: + scan += 2; + while (preg->program[scan++]) { + } + break; + + case END: + scan = 0; + break; + + default: + scan += 2; + break; + } } if (preg->regmust != 0) { s = string; @@ -21319,11 +20950,10 @@ static int regmatch(regex_t *preg, int prog) { int scan; int next; - const char *save; scan = prog; #ifdef DEBUG if (scan != 0 && regnarrate) @@ -21408,24 +21038,27 @@ break; case NOTHING: break; case BACK: break; - case BRANCH: - if (OP(preg, next) != BRANCH) - next = OPERAND(scan); - else { - do { - save = preg->reginput; - if (regmatch(preg, OPERAND(scan))) { - return(1); - } - preg->reginput = save; - scan = regnext(preg, scan); - } while (scan != 0 && OP(preg, scan) == BRANCH); - return(0); - + case BRANCH: { + const char *save; + + if (OP(preg, next) != BRANCH) + next = OPERAND(scan); + else { + do { + save = preg->reginput; + if (regmatch(preg, OPERAND(scan))) { + return(1); + } + preg->reginput = save; + scan = regnext(preg, scan); + } while (scan != 0 && OP(preg, scan) == BRANCH); + return(0); + + } } break; case REP: case REPMIN: return regmatchsimplerepeat(preg, scan, OP(preg, scan) == REPMIN); @@ -21433,35 +21066,43 @@ case REPX: case REPXMIN: return regmatchrepeat(preg, scan, OP(preg, scan) == REPXMIN); case END: - return 1; + return(1); + break; case OPENNC: case CLOSENC: - return regmatch(preg, next); + if (regmatch(preg, next)) { + return 1; + } + return 0; default: if (OP(preg, scan) >= OPEN+1 && OP(preg, scan) < CLOSE_END) { + const char *save; + save = preg->reginput; + if (regmatch(preg, next)) { + int no; if (OP(preg, scan) < CLOSE) { - int no = OP(preg, scan) - OPEN; + no = OP(preg, scan) - OPEN; if (no < preg->nmatch && preg->pmatch[no].rm_so == -1) { preg->pmatch[no].rm_so = save - preg->start; } } else { - int no = OP(preg, scan) - CLOSE; + no = OP(preg, scan) - CLOSE; if (no < preg->nmatch && preg->pmatch[no].rm_eo == -1) { preg->pmatch[no].rm_eo = save - preg->start; } } return(1); - } - return(0); + } else + return(0); } return REG_ERR_INTERNAL; } scan = next; @@ -21541,32 +21182,10 @@ return(p-offset); else return(p+offset); } -static int regopsize(regex_t *preg, int p ) -{ - - switch (OP(preg, p)) { - case REP: - case REPMIN: - case REPX: - case REPXMIN: - return 5; - - case ANYOF: - case ANYBUT: - case EXACTLY: { - int s = p + 2; - while (preg->program[s++]) { - } - return s - p; - } - } - return 2; -} - size_t regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size) { static const char *error_strings[] = { "success", @@ -21740,24 +21359,19 @@ char *Jim_HistoryGetline(const char *prompt) { #ifdef USE_LINENOISE return linenoise(prompt); #else - int len; char *line = malloc(MAX_LINE_LEN); fputs(prompt, stdout); fflush(stdout); if (fgets(line, MAX_LINE_LEN, stdin) == NULL) { free(line); return NULL; } - len = strlen(line); - if (len && line[len - 1] == '\n') { - line[len - 1] = '\0'; - } return line; #endif } void Jim_HistoryLoad(const char *filename) @@ -21808,11 +21422,11 @@ snprintf(history_file, history_len, "%s/.jim_history", home); Jim_HistoryLoad(history_file); } #endif - printf("Welcome to Jim version %d.%d\n", + printf("Welcome to Jim version %d.%d" JIM_NL, JIM_VERSION / 100, JIM_VERSION % 100); Jim_SetVariableStrWithStr(interp, JIM_INTERACTIVE, "1"); while (1) { Jim_Obj *scriptObjPtr; @@ -21921,16 +21535,10 @@ Jim_SetVariableStr(interp, "argv", listObj); Jim_SetVariableStr(interp, "argc", Jim_NewIntObj(interp, argc)); } -static void JimPrintErrorMessage(Jim_Interp *interp) -{ - Jim_MakeErrorMessage(interp); - fprintf(stderr, "%s\n", Jim_String(Jim_GetResult(interp))); -} - int main(int argc, char *const argv[]) { int retcode; Jim_Interp *interp; @@ -21943,20 +21551,22 @@ interp = Jim_CreateInterp(); Jim_RegisterCoreCommands(interp); if (Jim_InitStaticExtensions(interp) != JIM_OK) { - JimPrintErrorMessage(interp); + Jim_MakeErrorMessage(interp); + fprintf(stderr, "%s\n", Jim_String(Jim_GetResult(interp))); } - Jim_SetVariableStrWithStr(interp, "jim::argv0", argv[0]); + Jim_SetVariableStrWithStr(interp, "jim_argv0", argv[0]); Jim_SetVariableStrWithStr(interp, JIM_INTERACTIVE, argc == 1 ? "1" : "0"); retcode = Jim_initjimshInit(interp); if (argc == 1) { if (retcode == JIM_ERR) { - JimPrintErrorMessage(interp); + Jim_MakeErrorMessage(interp); + fprintf(stderr, "%s\n", Jim_String(Jim_GetResult(interp))); } if (retcode != JIM_EXIT) { JimSetArgv(interp, 0, NULL); retcode = Jim_InteractivePrompt(interp); } @@ -21973,11 +21583,12 @@ Jim_SetVariableStr(interp, "argv0", Jim_NewStringObj(interp, argv[1], -1)); JimSetArgv(interp, argc - 2, argv + 2); retcode = Jim_EvalFile(interp, argv[1]); } if (retcode == JIM_ERR) { - JimPrintErrorMessage(interp); + Jim_MakeErrorMessage(interp); + fprintf(stderr, "%s\n", Jim_String(Jim_GetResult(interp))); } } if (retcode == JIM_EXIT) { retcode = Jim_GetExitCode(interp); } Index: autosetup/local.tcl ================================================================== --- autosetup/local.tcl +++ autosetup/local.tcl @@ -26,200 +26,5 @@ set tclconfig($name) [string trim $value '] } } return [array get tclconfig] } - -# The complex extension checking is done here. - -global withinfo -global extdb - -# Final determination of module status -dict set extdb status {} - -# Returns 1 if the extension has the attribute -proc ext-has {ext attr} { - expr {$attr in [dict get $::extdb attrs $ext]} -} - -# Returns an entry from the extension 'info' table, or $default otherwise -proc ext-get {ext key {default {}}} { - if {[dict exists $::extdb info $ext $key]} { - return [dict get $::extdb info $ext $key] - } else { - return $default - } -} - -# Set the status of the extension to the given value, and returns the value -proc ext-set-status {ext value} { - dict set ::extdb status $ext $value - return $value -} - -# Returns the status of the extension, or ? if unknown -proc ext-get-status {ext} { - if {[dict exists $::extdb status $ext]} { - return [dict get $::extdb status $ext] - } - return ? -} - -proc check-extension-status {ext required} { - global withinfo - - set status [ext-get-status $ext] - - if {$ext in $withinfo(without)} { - # Disabled without further ado - msg-result "Extension $ext...disabled" - return [ext-set-status $ext n] - } - - if {$status in {m y n}} { - return $status - } - - # required is "required" if this extension *must* be enabled - # required is "wanted" if it is not fatal for this extension - # not to be enabled - - array set depinfo {m 0 y 0 n 0} - - # Check direct dependencies - if [ext-get $ext check 1] { - # "check" conditions are met - } else { - # not met - incr depinfo(n) - } - - if {$depinfo(n) == 0} { - # Now extension dependencies - foreach i [ext-get $ext dep] { - set status [check-extension-status $i $required] - #puts "$ext: dep $i $required => $status" - incr depinfo($status) - if {$depinfo(n)} { - break - } - } - } - - #parray depinfo - - if {$depinfo(n)} { - msg-checking "Extension $ext..." - if {$required eq "required"} { - user-error "dependencies not met" - } - msg-result "disabled (dependencies)" - return [ext-set-status $ext n] - } - - # Selected as a module? - if {$ext in $withinfo(mod)} { - if {[ext-has $ext tcl]} { - # Easy, a Tcl module - msg-result "Extension $ext...tcl" - } elseif {[ext-has $ext static]} { - user-error "Extension $ext can't be a module" - } else { - msg-result "Extension $ext...module" - foreach i [ext-get $ext libdep] { - define-append LDLIBS_$ext [get-define $i ""] - } - } - return [ext-set-status $ext m] - } - - # Selected as a static extension? - if {[ext-has $ext shared]} { - user-error "Extension $ext can only be selected as a module" - } elseif {$ext in $withinfo(ext) || $required eq "$required"} { - msg-result "Extension $ext...enabled" - } elseif {$ext in $withinfo(maybe)} { - msg-result "Extension $ext...enabled (default)" - } else { - # Could be selected, but isn't (yet) - return [ext-set-status $ext x] - } - foreach i [ext-get $ext libdep] { - define-append LDLIBS [get-define $i ""] - } - return [ext-set-status $ext y] -} - -# Examines the user options (the $withinfo array) -# and the extension database ($extdb) to determine -# what is selected, and in what way. -# -# The results are available via ext-get-status -# And a dictionary is returned containing four keys: -# static-c extensions which are static C -# static-tcl extensions which are static Tcl -# module-c extensions which are C modules -# module-tcl extensions which are Tcl modules -proc check-extensions {} { - global extdb withinfo - - # Check valid extension names - foreach i [concat $withinfo(ext) $withinfo(mod)] { - if {![dict exists $extdb attrs $i]} { - user-error "Unknown extension: $i" - } - } - - set extlist [lsort [dict keys [dict get $extdb attrs]]] - - set withinfo(maybe) {} - - # Now work out the default status. We have. - # normal case, include !optional if possible - # --without=default, don't include optional - if {$withinfo(nodefault)} { - lappend withinfo(maybe) stdlib - } else { - foreach i $extlist { - if {![ext-has $i optional]} { - lappend withinfo(maybe) $i - } - } - } - - foreach i $extlist { - define LDLIBS_$i "" - } - - foreach i [concat $withinfo(ext) $withinfo(mod)] { - check-extension-status $i required - } - foreach i $withinfo(maybe) { - check-extension-status $i wanted - } - - array set extinfo {static-c {} static-tcl {} module-c {} module-tcl {}} - - foreach i $extlist { - set status [ext-get-status $i] - set tcl [ext-has $i tcl] - switch $status,$tcl { - y,1 { - define jim_ext_$i - lappend extinfo(static-tcl) $i - } - y,0 { - define jim_ext_$i - lappend extinfo(static-c) $i - # If there are any static C++ extensions, jimsh must be linked using - # the C++ compiler - if {[ext-has $i cpp]} { - define HAVE_CXX_EXTENSIONS - } - } - m,1 { lappend extinfo(module-tcl) $i } - m,0 { lappend extinfo(module-c) $i } - } - } - return [array get extinfo] -} DELETED fossil.1 Index: fossil.1 ================================================================== --- fossil.1 +++ fossil.1 @@ -1,100 +0,0 @@ -.TH FOSSIL "1" "February 2015" "http://fossil-scm.org" "User Commands" -.SH NAME -fossil \- Distributed Version Control System -.SH SYNOPSIS -.B fossil -\fIhelp\fR -.br -.B fossil -\fIhelp COMMAND\fR -.br -.B fossil -\fICOMMAND [OPTIONS]\fR -.SH DESCRIPTION -Fossil is a distributed version control system (DVCS) with built-in -wiki, ticket tracker, CGI/http interface, and http server. - -.SH Common COMMANDs: - -add clean import pull stash -.br -addremove clone info purge status -.br -all commit init push sync -.br -annotate diff json rebuild tag -.br -bisect export ls remote-url timeline -.br -blame extras merge revert ui -.br -branch finfo mv rm undo -.br -bundle fusefs open rss unpublish -.br -cat gdiff praise settings update -.br -changes help publish sqlite3 version - -.SH FEATURES - -Features as described on the fossil home page. - -.HP -1. -.B Integrated Bug Tracking, Wiki, & Technotes -- In addition to doing distributed version control like Git and -Mercurial, Fossil also supports bug tracking, wiki, and technotes. - -.HP -2. -.B Built-in Web Interface -- Fossil has a built-in and intuitive web interface that promotes -project situational awareness. Type "fossil ui" and Fossil automatically -opens a web browser to a page that shows detailed graphical history and -status information on that project. - -.HP -3. -.B Self-Contained -- Fossil is a single self-contained stand-alone executable. To install, -simply download a precompiled binary for Linux, Mac, OpenBSD, or Windows -and put it on your $PATH. Easy-to-compile source code is available for -users on other platforms. - -.HP -4. -.B Simple Networking -- No custom protocols or TCP ports. Fossil uses plain old HTTP (or HTTPS -or SSH) for all network communications, so it works fine from behind -restrictive firewalls, including proxies. The protocol is bandwidth -efficient to the point that Fossil can be used comfortably over dial-up. - -.HP -5. -.B CGI/SCGI Enabled -- No server is required, but if you want to set one up, Fossil supports -four simple server configurations. - -.HP -6. -.B Autosync -- Fossil supports "autosync" mode which helps to keep projects moving -forward by reducing the amount of needless forking and merging often -associated with distributed projects. - -.HP -7. -.B Robust & Reliable -- Fossil stores content using an enduring file format in an SQLite -database so that transactions are atomic even if interrupted by a -power loss or system crash. Automatic self-checks verify that all -aspects of the repository are consistent prior to each commit. In -over seven years of operation, no work has ever been lost after -having been committed to a Fossil repository. - -.SH DOCUMENTATION -http://www.fossil-scm.org/ -.br -.B fossil -\fIui\fR ADDED fossil.nsi Index: fossil.nsi ================================================================== --- fossil.nsi +++ fossil.nsi @@ -0,0 +1,59 @@ +; example2.nsi +; +; This script is based on example1.nsi, but adds uninstall support +; and (optionally) start menu shortcuts. +; +; It will install notepad.exe into a directory that the user selects, +; + +; The name of the installer +Name "Fossil" + +; The file to write +OutFile "fossil-setup.exe" + +; The default installation directory +InstallDir $PROGRAMFILES\Fossil +; Registry key to check for directory (so if you install again, it will +; overwrite the old one automatically) +InstallDirRegKey HKLM SOFTWARE\Fossil "Install_Dir" + +; The text to prompt the user to enter a directory +ComponentText "This will install fossil on your computer." +; The text to prompt the user to enter a directory +DirText "Choose a directory to install in to:" + +; The stuff to install +Section "Fossil (required)" + ; Set output path to the installation directory. + SetOutPath $INSTDIR + ; Put file there + File ".\fossil.exe" + ; Write the installation path into the registry + WriteRegStr HKLM SOFTWARE\Fossil "Install_Dir" "$INSTDIR" + ; Write the uninstall keys for Windows + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Fossil" "DisplayName" "Fossil (remove only)" + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Fossil" "UninstallString" '"$INSTDIR\uninstall.exe"' + WriteUninstaller "uninstall.exe" +SectionEnd + + +; uninstall stuff + +UninstallText "This will uninstall fossil. Hit next to continue." + +; special uninstall section. +Section "Uninstall" + ; remove registry keys + DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Fossil" + DeleteRegKey HKLM SOFTWARE\Fossil + ; remove files + Delete $INSTDIR\fossil.exe + ; MUST REMOVE UNINSTALLER, too + Delete $INSTDIR\uninstall.exe + ; remove shortcuts, if any. + RMDir "$SMPROGRAMS\Fossil" + RMDir "$INSTDIR" +SectionEnd + +; eof DELETED setup/fossil.iss Index: setup/fossil.iss ================================================================== --- setup/fossil.iss +++ setup/fossil.iss @@ -1,49 +0,0 @@ -; -; Copyright (c) 2014 D. Richard Hipp -; -; 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/ -; - -[Setup] -ArchitecturesAllowed=x86 x64 -AlwaysShowComponentsList=false -AppCopyright=Copyright (c) D. Richard Hipp. All rights reserved. -AppID={{f1c25a1f-3954-4e1a-ac36-4314c52f057c} -AppName=Fossil -AppPublisher=Fossil Development Team -AppPublisherURL=https://www.fossil-scm.org/ -AppSupportURL=https://www.fossil-scm.org/ -AppUpdatesURL=https://www.fossil-scm.org/ -AppVerName=Fossil v{#AppVersion} -AppVersion={#AppVersion} -AppComments=Simple, high-reliability, distributed software configuration management system. -AppReadmeFile=https://www.fossil-scm.org/index.html/doc/tip/www/quickstart.wiki -DefaultDirName={pf}\Fossil -DefaultGroupName=Fossil -OutputBaseFilename=fossil-win32-{#AppVersion} -OutputManifestFile=fossil-win32-{#AppVersion}-manifest.txt -SetupLogging=true -UninstallFilesDir={app}\uninstall -VersionInfoVersion={#AppVersion} - -[Components] -Name: Application; Description: Core application.; Types: custom compact full; Flags: fixed - -[Dirs] -Name: {app}\bin - -[Files] -Components: Application; Source: ..\fossil.exe; DestDir: {app}\bin; Flags: restartreplace uninsrestartdelete - -[Registry] -Components: Application; Root: HKLM32; SubKey: Software\Fossil; ValueType: string; ValueName: Install_Dir; ValueData: {app}; Flags: uninsdeletekeyifempty uninsdeletevalue DELETED setup/fossil.nsi Index: setup/fossil.nsi ================================================================== --- setup/fossil.nsi +++ setup/fossil.nsi @@ -1,59 +0,0 @@ -; example2.nsi -; -; This script is based on example1.nsi, but adds uninstall support -; and (optionally) start menu shortcuts. -; -; It will install notepad.exe into a directory that the user selects, -; - -; The name of the installer -Name "Fossil" - -; The file to write -OutFile "fossil-setup.exe" - -; The default installation directory -InstallDir $PROGRAMFILES\Fossil -; Registry key to check for directory (so if you install again, it will -; overwrite the old one automatically) -InstallDirRegKey HKLM SOFTWARE\Fossil "Install_Dir" - -; The text to prompt the user to enter a directory -ComponentText "This will install fossil on your computer." -; The text to prompt the user to enter a directory -DirText "Choose a directory to install in to:" - -; The stuff to install -Section "Fossil (required)" - ; Set output path to the installation directory. - SetOutPath $INSTDIR - ; Put file there - File "..\fossil.exe" - ; Write the installation path into the registry - WriteRegStr HKLM SOFTWARE\Fossil "Install_Dir" "$INSTDIR" - ; Write the uninstall keys for Windows - WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Fossil" "DisplayName" "Fossil (remove only)" - WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Fossil" "UninstallString" '"$INSTDIR\uninstall.exe"' - WriteUninstaller "uninstall.exe" -SectionEnd - - -; uninstall stuff - -UninstallText "This will uninstall fossil. Hit next to continue." - -; special uninstall section. -Section "Uninstall" - ; remove registry keys - DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Fossil" - DeleteRegKey HKLM SOFTWARE\Fossil - ; remove files - Delete $INSTDIR\fossil.exe - ; MUST REMOVE UNINSTALLER, too - Delete $INSTDIR\uninstall.exe - ; remove shortcuts, if any. - RMDir "$SMPROGRAMS\Fossil" - RMDir "$INSTDIR" -SectionEnd - -; eof DELETED skins/README.md Index: skins/README.md ================================================================== --- skins/README.md +++ skins/README.md @@ -1,45 +0,0 @@ -Built-in Skins -============== - -Each subdirectory under this folder describes a built-in "skin". -There are four files in each subdirectory for the CSS, the "details" -file, the footer, and the header for that skin. - -To improve an existing built-in skin, simply edit the appropriate -files and recompile. - -To add a new skin: - - 1. Create a new subdirectory under skins/. (The new directory is - 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 and skins/newskin/header.txt. - Be sure to "fossil add" these files. - - 3. Go to the src/ 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. - -Development Hints ------------------ - -One way to develop a new skin is to copy the baseline files (css.txt, -details.txt, footer.txt, and header.txt) into a working directory $WORKDIR -then launch Fossil with a command-line option "--skin $WORKDIR". Example: - - cp -r skins/default newskin - fossil ui --skin ./newskin - -When the argument to --skin contains one or more '/' characters, the -appropriate skin files are read from disk from the directory specified. -So after launching fossil as shown above, you can edit the newskin/css.txt, -newskin/details.txt, newskin/footer.txt, and newskin/header.txt files using -your favorite text editor, then press Reload on your browser to see -immediate results. DELETED skins/aht/details.txt Index: skins/aht/details.txt ================================================================== --- skins/aht/details.txt +++ skins/aht/details.txt @@ -1,4 +0,0 @@ -timeline-arrowheads: 1 -timeline-circle-nodes: 0 -timeline-color-graph-lines: 0 -white-foreground: 0 DELETED skins/black_and_white/css.txt Index: skins/black_and_white/css.txt ================================================================== --- skins/black_and_white/css.txt +++ skins/black_and_white/css.txt @@ -1,177 +0,0 @@ -/* General settings for the entire page */ -body { - margin:0px 0px 0px 0px; - padding:0px; - font-family:verdana, arial, helvetica, "sans serif"; - color:#333; - background-color:white; - -moz-text-size-adjust: none; - -webkit-text-size-adjust: none; - -mx-text-size-adjust: none; -} - -/* consistent colours */ -h2 { - color: #333; -} -h3 { - color: #333; -} - -/* The project logo in the upper left-hand corner of each page */ -div.logo { - display: table-cell; - text-align: left; - vertical-align: bottom; - font-weight: bold; - color: #333; - white-space: nowrap; -} - -/* The page title centered at the top of each page */ -div.title { - display: table-cell; - font-size: 2em; - font-weight: bold; - text-align: center; - color: #333; - vertical-align: bottom; - width: 100%; -} - -/* The login status message in the top right-hand corner */ -div.status { - display: table-cell; - padding-right: 10px; - text-align: right; - vertical-align: bottom; - padding-bottom: 5px; - color: #333; - font-size: 0.8em; - font-weight: bold; - white-space: nowrap; -} - -/* The header across the top of the page */ -div.header { - margin:10px 0px 10px 0px; - padding:1px 0px 0px 20px; - border-style:solid; - border-color:black; - border-width:1px 0px; - background-color:#eee; -} - -/* The main menu bar that appears at the top left of the page beneath -** the header. Width must be co-ordinated with the container below */ -div.mainmenu { - float: left; - margin-left: 10px; - margin-right: 10px; - font-size: 0.9em; - font-weight: bold; - padding:5px; - background-color:#eee; - border:1px solid #999; - width:8em; -} - -/* Main menu is now a list */ -div.mainmenu ul { - padding: 0; - list-style:none; -} -div.mainmenu a, div.mainmenu a:visited{ - padding: 1px 10px 1px 10px; - color: #333; - text-decoration: none; -} -div.mainmenu a:hover { - color: #eee; - background-color: #333; -} - -/* Container for the sub-menu and content so they don't spread -** out underneath the main menu */ -#container { - padding-left: 9em; -} - -/* The submenu bar that *sometimes* appears below the main menu */ -div.submenu, div.sectionmenu { - padding: 3px 10px 3px 10px; - font-size: 0.9em; - text-align: center; - border:1px solid #999; - border-width:1px 0px; - background-color: #eee; - color: #333; -} -div.submenu a, div.submenu a:visited, div.sectionmenu>a.button:link, -div.sectionmenu>a.button:visited { - padding: 3px 10px 3px 10px; - color: #333; - text-decoration: none; -} -div.submenu a:hover, div.sectionmenu>a.button:hover { - color: #eee; - background-color: #333; -} - -/* All page content from the bottom of the menu or submenu down to -** the footer */ -div.content { - padding: 2ex 1ex 0ex 2ex; -} - -/* Some pages have section dividers */ -div.section { - margin-bottom: 0px; - margin-top: 1em; - padding: 1px 1px 1px 1px; - font-size: 1.2em; - font-weight: bold; - border-style:solid; - border-color:#999; - border-width:1px 0px; - background-color: #eee; - color: #333; - white-space: nowrap; -} - -/* The "Date" that occurs on the left hand side of timelines */ -div.divider { - background: #eee; - border: 2px #999 solid; - font-size: 1em; font-weight: normal; - padding: .25em; - margin: .2em 0 .2em 0; - float: left; - clear: left; - color: #333; - white-space: nowrap; -} - -/* The footer at the very bottom of the page */ -div.footer { - font-size: 0.8em; - margin-top: 12px; - padding: 5px 10px 5px 10px; - text-align: right; - background-color: #eee; - color: #555; -} - -/* blocks */ -pre.verbatim { - background-color: #f5f5f5; - padding: 0.5em; - white-space: pre-wrap; -} - -/* The label/value pairs on (for example) the ci page */ -table.label-value th { - vertical-align: top; - text-align: right; - padding: 0.2ex 2ex; -} DELETED skins/black_and_white/details.txt Index: skins/black_and_white/details.txt ================================================================== --- skins/black_and_white/details.txt +++ skins/black_and_white/details.txt @@ -1,4 +0,0 @@ -timeline-arrowheads: 1 -timeline-circle-nodes: 0 -timeline-color-graph-lines: 0 -white-foreground: 0 DELETED skins/black_and_white/footer.txt Index: skins/black_and_white/footer.txt ================================================================== --- skins/black_and_white/footer.txt +++ skins/black_and_white/footer.txt @@ -1,4 +0,0 @@ - - DELETED skins/black_and_white/header.txt Index: skins/black_and_white/header.txt ================================================================== --- skins/black_and_white/header.txt +++ skins/black_and_white/header.txt @@ -1,54 +0,0 @@ - - - -$<project_name>: $<title> - - - - -
- -
$</div> - <div class="status"><th1> - if {[info exists login]} { - puts "Logged in as $login" - } else { - puts "Not logged in" - } - </th1></div> -</div> -<div class="mainmenu"> -<th1> -html "<a href='$home$index_page'>Home</a>\n" -if {[anycap jor]} { - html "<a href='$home/timeline'>Timeline</a>\n" -} -if {[anoncap oh]} { - html "<a href='$home/tree?ci=tip'>Files</a>\n" -} -if {[anoncap o]} { - html "<a href='$home/brlist'>Branches</a>\n" - html "<a href='$home/taglist'>Tags</a>\n" -} -if {[anoncap r]} { - html "<a href='$home/ticket'>Tickets</a>\n" -} -if {[anoncap j]} { - html "<a href='$home/wiki'>Wiki</a>\n" -} -if {[hascap s]} { - html "<a href='$home/setup'>Admin</a>\n" -} elseif {[hascap a]} { - html "<a href='$home/setup_ulist'>Users</a>\n" -} -if {[info exists login]} { - html "<a href='$home/login'>Logout</a>\n" -} else { - html "<a href='$home/login'>Login</a>\n" -} -</th1></ul></div> DELETED skins/blitz/README.md Index: skins/blitz/README.md ================================================================== --- skins/blitz/README.md +++ skins/blitz/README.md @@ -1,13 +0,0 @@ -## Blitz Theme - -Contributed by James Moger (james.moger@gitblit.com) - -This theme is inspired by my own project, [Gitblit](http://gitblit.com), and offered to the Fossil project. - -This theme embeds & uses an unmodified copy of [Normalize 3.0.2](https://necolas.github.io/normalize.css/) which is distributed under an [MIT license](https://github.com/necolas/normalize.css/blob/master/LICENSE.md). - -This theme uses half of a heavily-modified version of [Skeleton](http://getskeleton.com) which is distributed under an [MIT license](https://github.com/dhg/Skeleton/blob/master/LICENSE.md). None of the responsive elements (media queries) are included at this time. - -The font used in the included Fossil logo image is [Trillium Web Light](http://www.google.com/fonts/specimen/Titillium+Web) @ 48px HTML color code #456a7a. - -The RSS feed icon is sourced from [Font-Awesome](https://fortawesome.github.io/Font-Awesome/icons) by Dave Gandy and is distributed under the [SIL OFL 1.1 ](http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=OFL) license. DELETED skins/blitz/arrow_project.png Index: skins/blitz/arrow_project.png ================================================================== --- skins/blitz/arrow_project.png +++ skins/blitz/arrow_project.png cannot compute difference between binary files DELETED skins/blitz/css.txt Index: skins/blitz/css.txt ================================================================== --- skins/blitz/css.txt +++ skins/blitz/css.txt @@ -1,1237 +0,0 @@ -/*! normalize.css v3.0.2 | MIT License | git.io/normalize */ - -/** - * 1. Set default font family to sans-serif. - * 2. Prevent iOS text size adjust after orientation change, without disabling - * user zoom. - */ - -html { - font-family: sans-serif; /* 1 */ - -ms-text-size-adjust: 100%; /* 2 */ - -webkit-text-size-adjust: 100%; /* 2 */ -} - -/** - * Remove default margin. - */ - -body { - margin: 0; -} - -/* HTML5 display definitions - ========================================================================== */ - -/** - * Correct `block` display not defined for any HTML5 element in IE 8/9. - * Correct `block` display not defined for `details` or `summary` in IE 10/11 - * and Firefox. - * Correct `block` display not defined for `main` in IE 11. - */ - -article, -aside, -details, -figcaption, -figure, -footer, -header, -hgroup, -main, -menu, -nav, -section, -summary { - display: block; -} - -/** - * 1. Correct `inline-block` display not defined in IE 8/9. - * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera. - */ - -audio, -canvas, -progress, -video { - display: inline-block; /* 1 */ - vertical-align: baseline; /* 2 */ -} - -/** - * Prevent modern browsers from displaying `audio` without controls. - * Remove excess height in iOS 5 devices. - */ - -audio:not([controls]) { - display: none; - height: 0; -} - -/** - * Address `[hidden]` styling not present in IE 8/9/10. - * Hide the `template` element in IE 8/9/11, Safari, and Firefox < 22. - */ - -[hidden], -template { - display: none; -} - -/* Links - ========================================================================== */ - -/** - * Remove the gray background color from active links in IE 10. - */ - -a { - background-color: transparent; -} - -/** - * Improve readability when focused and also mouse hovered in all browsers. - */ - -a:active, -a:hover { - outline: 0; -} - -/* Text-level semantics - ========================================================================== */ - -/** - * Address styling not present in IE 8/9/10/11, Safari, and Chrome. - */ - -abbr[title] { - border-bottom: 1px dotted; -} - -/** - * Address style set to `bolder` in Firefox 4+, Safari, and Chrome. - */ - -b, -strong { - font-weight: bold; -} - -/** - * Address styling not present in Safari and Chrome. - */ - -dfn { - font-style: italic; -} - -/** - * Address variable `h1` font-size and margin within `section` and `article` - * contexts in Firefox 4+, Safari, and Chrome. - */ - -h1 { - font-size: 2em; - margin: 0.67em 0; -} - -/** - * Address styling not present in IE 8/9. - */ - -mark { - background: #ff0; - color: #000; -} - -/** - * Address inconsistent and variable font size in all browsers. - */ - -small { - font-size: 80%; -} - -/** - * Prevent `sub` and `sup` affecting `line-height` in all browsers. - */ - -sub, -sup { - font-size: 75%; - line-height: 0; - position: relative; - vertical-align: baseline; -} - -sup { - top: -0.5em; -} - -sub { - bottom: -0.25em; -} - -/* Embedded content - ========================================================================== */ - -/** - * Remove border when inside `a` element in IE 8/9/10. - */ - -img { - border: 0; -} - -/** - * Correct overflow not hidden in IE 9/10/11. - */ - -svg:not(:root) { - overflow: hidden; -} - -/* Grouping content - ========================================================================== */ - -/** - * Address margin not present in IE 8/9 and Safari. - */ - -figure { - margin: 1em 40px; -} - -/** - * Address differences between Firefox and other browsers. - */ - -hr { - -moz-box-sizing: content-box; - box-sizing: content-box; - height: 0; -} - -/** - * Contain overflow in all browsers. - */ - -pre { - overflow: auto; -} - -/** - * Address odd `em`-unit font size rendering in all browsers. - */ - -code, -kbd, -pre, -samp { - font-family: monospace, monospace; - font-size: 1em; -} - -/* Forms - ========================================================================== */ - -/** - * Known limitation: by default, Chrome and Safari on OS X allow very limited - * styling of `select`, unless a `border` property is set. - */ - -/** - * 1. Correct color not being inherited. - * Known issue: affects color of disabled elements. - * 2. Correct font properties not being inherited. - * 3. Address margins set differently in Firefox 4+, Safari, and Chrome. - */ - -button, -input, -optgroup, -select, -textarea { - color: inherit; /* 1 */ - font: inherit; /* 2 */ - margin: 0; /* 3 */ -} - -/** - * Address `overflow` set to `hidden` in IE 8/9/10/11. - */ - -button { - overflow: visible; -} - -/** - * Address inconsistent `text-transform` inheritance for `button` and `select`. - * All other form control elements do not inherit `text-transform` values. - * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera. - * Correct `select` style inheritance in Firefox. - */ - -button, -select { - text-transform: none; -} - -/** - * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` - * and `video` controls. - * 2. Correct inability to style clickable `input` types in iOS. - * 3. Improve usability and consistency of cursor style between image-type - * `input` and others. - */ - -button, -html input[type="button"], /* 1 */ -input[type="reset"], -input[type="submit"] { - -webkit-appearance: button; /* 2 */ - cursor: pointer; /* 3 */ -} - -/** - * Re-set default cursor for disabled elements. - */ - -button[disabled], -html input[disabled] { - cursor: default; -} - -/** - * Remove inner padding and border in Firefox 4+. - */ - -button::-moz-focus-inner, -input::-moz-focus-inner { - border: 0; - padding: 0; -} - -/** - * Address Firefox 4+ setting `line-height` on `input` using `!important` in - * the UA stylesheet. - */ - -input { - line-height: normal; -} - -/** - * It's recommended that you don't attempt to style these elements. - * Firefox's implementation doesn't respect box-sizing, padding, or width. - * - * 1. Address box sizing set to `content-box` in IE 8/9/10. - * 2. Remove excess padding in IE 8/9/10. - */ - -input[type="checkbox"], -input[type="radio"] { - box-sizing: border-box; /* 1 */ - padding: 0; /* 2 */ -} - -/** - * Fix the cursor style for Chrome's increment/decrement buttons. For certain - * `font-size` values of the `input`, it causes the cursor style of the - * decrement button to change from `default` to `text`. - */ - -input[type="number"]::-webkit-inner-spin-button, -input[type="number"]::-webkit-outer-spin-button { - height: auto; -} - -/** - * 1. Address `appearance` set to `searchfield` in Safari and Chrome. - * 2. Address `box-sizing` set to `border-box` in Safari and Chrome - * (include `-moz` to future-proof). - */ - -input[type="search"] { - -webkit-appearance: textfield; /* 1 */ - -moz-box-sizing: content-box; - -webkit-box-sizing: content-box; /* 2 */ - box-sizing: content-box; -} - -/** - * Remove inner padding and search cancel button in Safari and Chrome on OS X. - * Safari (but not Chrome) clips the cancel button when the search input has - * padding (and `textfield` appearance). - */ - -input[type="search"]::-webkit-search-cancel-button, -input[type="search"]::-webkit-search-decoration { - -webkit-appearance: none; -} - -/** - * Define consistent border, margin, and padding. - */ - -fieldset { - border: 1px solid #c0c0c0; - margin: 0 2px; - padding: 0.35em 0.625em 0.75em; -} - -/** - * 1. Correct `color` not being inherited in IE 8/9/10/11. - * 2. Remove padding so people aren't caught out if they zero out fieldsets. - */ - -legend { - border: 0; /* 1 */ - padding: 0; /* 2 */ -} - -/** - * Remove default vertical scrollbar in IE 8/9/10/11. - */ - -textarea { - overflow: auto; -} - -/** - * Don't inherit the `font-weight` (applied by a rule above). - * NOTE: the default cannot safely be changed in Chrome and Safari on OS X. - */ - -optgroup { - font-weight: bold; -} - -/* Tables - ========================================================================== */ - -/** - * Remove most spacing between table cells. - */ - -table { - border-collapse: collapse; - border-spacing: 0; -} - -td, -th { - padding: 0; -} - - -/* - * Blitz - * - * Skin inspired by Gitblit with heavily-modified excerpts from Skeleton 2.0.4. - * Blitz is authored by james.moger@gitblit.com. - * - * Skeleton is authored by Dave Gamache and is distributed under the MIT license. - * http://getskeleton.com - * -––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ - -html { - /* 62.5% so that the REM values are base 10px. */ - /* 1.5rem = 15px */ - font-size: 62.5%; -} - -/* Typography -––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ -h1, h2, h3, h4, h5, h6 { - margin: 0; - margin-bottom: 1rem; - font-weight: 700; -} - -h1 { font-size: 3.0rem; line-height: 1.2; } -h2 { font-size: 2.6rem; line-height: 1.25; } -h3 { font-size: 2.4rem; line-height: 1.3; } -h4 { font-size: 2.0rem; line-height: 1.35; } -h5 { font-size: 1.6rem; line-height: 1.5; } -h6 { font-size: 1.4rem; line-height: 1.6; } - -h1 small, h2 small, h3 small, h4 small, h5 small, h6 small { - font-size: 0.75em; - font-weight: 400; - color: #ccc; -} - -pre, code { - font-size: 1.2rem; -} - -body { - font-size: 1.4em; /* currently ems cause chrome bug misinterpreting rems on body element */ - line-height: 1.5; - font-weight: 400; - font-family: "HelveticaNeue", "Helvetica Neue", Helvetica, Arial, sans-serif; - color: #333; - background-color: #f8f8f8; -} - -/* Spacing -––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ -button, -.button { - margin-bottom: 1rem; -} - -input, -textarea, -select, -fieldset, -pre, -blockquote, -dl, -figure, -table, -p, -ul, -ol { - margin-bottom: 1rem; -} - -p { - margin-top: 0; -} - -hr { - margin-top: 3rem; - margin-bottom: 3.5rem; - border-width: 0; - border-top: 1px solid #ccc; -} - - -/* Buttons -––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ -.button, -button, -input[type="button"], -input[type="reset"], -input[type="submit"] { - display: inline-block; - height: 3.3rem; - padding: 0 2.2rem; - color: #555 !important; - text-align: center; - font-size: 1.1rem; - font-weight: 700; - line-height: 3.3rem; - letter-spacing: .08rem; - text-transform: uppercase; - text-decoration: none; - white-space: nowrap; - background-color: transparent; - border-radius: 4px; - border: 1px solid #ccc; - cursor: pointer; - box-sizing: border-box; -} - -.button:hover, -button:hover, -input[type="button"]:hover, -input[type="reset"]:hover, -.button:focus, -button:focus, -input[type="button"]:focus, -input[type="reset"]:focus { - color: #444 !important; - background-color: #eee; - border-color: #aaa; - outline: 0; -} - -input[type="submit"] { - color: white !important; - background-color: #446979; - border-color: #446979; -} - -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"], -input[type="tel"], -input[type="url"], -input[type="password"], -textarea, -select { - height: 3.3rem; - padding: 6px 10px; - background-color: #fff; - border: 1px solid #ddd; - border-radius: 4px; - box-shadow: none; - box-sizing: border-box; -} - -/* Removes awkward default styles on some inputs for iOS */ -input[type="email"], -input[type="number"], -input[type="search"], -input[type="text"], -input[type="tel"], -input[type="url"], -input[type="password"], -textarea { - -webkit-appearance: none; - -moz-appearance: none; - appearance: none; -} - -textarea { - height: inherit; - min-height: 65px; - padding-top: 6px; - padding-bottom: 6px; -} - -input[type="email"]:focus, -input[type="number"]:focus, -input[type="search"]:focus, -input[type="text"]:focus, -input[type="tel"]:focus, -input[type="url"]:focus, -input[type="password"]:focus, -textarea:focus, -select:focus { - border: 1px solid #aaa; - outline: 0; -} - -label, -legend { - display: block; - margin-bottom: .5rem; - font-weight: 700; -} - -fieldset { - padding: 0; - border-width: 0; -} - -input[type="checkbox"], -input[type="radio"] { - display: inline; -} - - -/* Links -––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ -a { - color: #446979; - text-decoration: none; -} - -a:hover { - text-decoration: underline; -} - - -/* Lists -––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ -ul { - list-style: square; -} - -ol { - list-style: decimal; -} - -ol, ul { - padding-left: 3rem; - margin-top: 0; -} - -li { - margin-bottom: 0.5rem; -} - - -/* Nested Lists -––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ -ul ul, -ul ol, -ol ol, -ol ul { - margin: 1rem 0 1rem 2rem; -} - - -/* Code -––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ -code, kbd { - padding: .2rem .5rem; - margin: 0 .2rem; - white-space: nowrap; - background: #f8f8f8; - border: 1px solid #ccc; - border-radius: 4px; -} - -pre > code { - display: block; - padding: 1rem 1.5rem; - white-space: pre; -} - -pre.verbatim { - background-color: inherit; - white-space: pre-wrap; -} - - -/* Blockquote -––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ -blockquote { - padding: 0px 20px; - margin: 0 0 20px; - border-left: 4px solid #ccc; -} - - -/* Tables -––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ -th, -td { - padding: 6px 5px; - text-align: left; - border-bottom: 1px solid #ddd; } -th:first-child, -td:first-child { - padding-left: 0; } -th:last-child, -td:last-child { - padding-right: 0; } - - -/* - * Blitz Page Layout Design - * - * html > body > header > container > mainmenu - * middle > container > submenu & content - * footer > container > generation stats, fossil logo, version - * - ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ - - -/* Container - * Represents the usable layout space for header, middle, and footer. -––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ -.container { - position: relative; - width: 100%; - max-width: 900px; - margin: 0 auto; - box-sizing: border-box; -} - - -/* Header - * Div displayed at the top of every page. -––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ -.header { - color: #666; - font-weight: 400; - padding-top: 10px; - border-width: 0px; - border-top: 4px solid #446979; - border-bottom: 1px solid #ccc; -} - -.header .logo { - display: inline-block; -} - -.header .login { - padding-top: 2px; - text-align: right; -} - -.header .login .button { - margin: 0; -} - -.header h1 { - margin: 0px; - color: #666; - display: inline-block; -} - -.header .logo h1 { - display: inline-block; -} - -.header .title h1 { - padding-bottom: 10px; -} - -.header h1 small, .header h2 small { - color: #888; -} - -.header a.rss { - display: inline-block; - padding: 10px 15px; - background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3wMNDhwn05VjawAAABl0RVh0Q29tbWVudABDcmVhdGVkIHdpdGggR0lNUFeBDhcAAAGlSURBVDjLrdPfb8xREAXwT7tIl+paVNaPJghCKC8kXv0XXvyNXsRfwYPQJqVKiqykWFVZXd12vcxNJtduUtJJvrm7984998ycMxxwNGI9jPs4j7nY+/U/gIdiPYO71dk21rCE7r8ybOHGmMfmcRNnsbEf1gXwNzqYSXs5WljEMXzAaBLg1Ji9Js7hOi6OeeAznqC/X8AcMyHWYpX7E4/Rm1QyHMdefCWGeI/VcMDR2D8S7Fci5y/AeTzCPVyLi1sYJAut4BTaiX0n9kc14MmkcjPY3I5LXezGtxqKtyJ3Lir6VAM2AmCq6m8Hl6PsQTB5hyvxmMhZxk4G3MZLfAwLtdNZM9rwOs528TVVNB3ga7UoQ2wGmyWciFaU0VwIJiP8iL6Xfp7GK+w0JthliDep8UKonTSGvbBTaU8f3QzYxgPcCsBvWK9E6OBFCNGPVjTTqC430p+H6fLVGLGtmIw7SbwevqT+XkgVPJ9Otpmtyl6I9XswLXEp/d6oPN0ugJu14xMLob4kgPRYjtkCOMDTUG+AZ3ibEtfDLorfEmAB3UuTdXDxBzUUZV+B82aLAAAAAElFTkSuQmCC); - background-position: center center; - background-repeat: no-repeat; -} - - -/* Middle - * Center div displayed between header and footer. Contains per-page content. -––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ -.middle { - background-color: white; - padding-bottom: 20px; - max-width: 100%; - box-sizing: border-box; -} - - -/* Content - * Displayed below submenu within the middle div. -––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ -.content { - padding-top: 15px; -} - -.content a { - color: #002060; -} - - -/* Footer - * Displayed after the middle div and forms the page bottom. -––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ -.footer { - padding: 10px 0 60px; - border-top: 1px solid #ccc; - background-color: #f8f8f8; - background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAABGCAQAAADxl9ugAAAAAmJLR0QA/4ePzL8AAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQffAwkQBRPw+yfrAAAAPHRFWHRDb21tZW50ACBJbWFnZSBnZW5lcmF0ZWQgYnkgRVNQIEdob3N0c2NyaXB0IChkZXZpY2U9cG5tcmF3KQqV01S1AAANg0lEQVRo3s2aa3RVRZbH/3tXnftIbhJCeJMXyEsNCsgrSBzAYXyt0YVj2zSOonbLqNNO+25FB2kdoBVdrp6l09P2NNpOL/ExSrtUdGRU5JEQgggCggIhQIBAIIGQ5N57TlXt+ZAICY+AGCT76zlV91dVe+/a+38uDQ7dYmrxw41QocJuni28vWTedEa7Gd9iatplos7Y2mfDRED6A2G0I2At6AdPIiA84HgbLhx1o9QX9Zoh7QjYHpOkYJYrfNyOKH0O/f2FJpfkSRmMCNqDk9rDXwTAuxK7h3uFf7vXxC6QVO8w19taNOT4Y0wu1sCdW0AA6IZ73bCUaI/GHuqnsJqcEqVrzSo+wNtLdgAPsz6jeVURtQ9gA8bQT8xztW7X2u3I4G6UdA0cohxcSAN7nt939/zDQzl0LnfwaLpxqFT/i7w7XLYXhoUQ+YFW3pJlC0/nt6jZZb4zjXY2AaGXvQOz/gMY09NM4C6ixRL7OU3PTm4ORdiIjyLsJvq1Z28Hj5rBM82xMTqPuhHznmU72vq12W5M3+LykQWUW9pirzXOmmk8wjE87kb8HPmSKlY+wY62R9jhI69xf/AmYiEfiXs+e4CCAZiDUc9wP6cRIJn8tq23PQClbwap9Ivk7usiGj/CDs5xl3Qe/EiQCEWsgXLlq8sfamM73osMna43ef/pfm731Hsxv+Z00ozFzaJpF+gMrsNB2BwL3cGpSsNRWHbmvTQNiTbev9q4xXszMLzqpdgDNjxv/YjmvHlSQIc5brl8nrqT5pllMpHM9wRc4gU3oC8JyDLt8P78ZLyM2lrmAeTg5YrKdf1S1N9QTs6At1YM49DJo1gwWy7uE5kKBQHbler9K8R+L8API2qmFoDY7ejxpxGJxtMctyZcfYvJDYX4i5LXp/MJAS2edkM6edNUDuLNOdMDmz913bIw8RidKO/1w+3NQfePbHQjdbd/NKOjbq7UqQOmYtXb/+BdbGc4AJjPX53CXe6UGweYWxUR8N8rNkzn4wAFc9yYPvGbI+mttoycpo14fWbD0hZv+njOAcBl6Yl8jiEMbSKhqGPypZ5N0B2kDxrjOjF0QuI2oRqj2z6rAebx5pNiRrEo0jhV9wFkP//xpkPHAU6UGdnBLyR8jMOQs6xwcMAznVys+Uqa5YCCnilFkuVSkeKlGKfDED8JaI+VifMWR9LPC/u+UkoZA6edOezVu83pny4yD6qQnCxhDzk/MhUED+8PWHJMkAgWROvvQoxOcEdayynVY9/5tIgAwsfIvaD3XaFx6M6ddMx3WlurCGICiAIhMLxB1VM+wQRMDOeYjHCUMum85OW909/acOlJgqaI3qrulU9dYGlgzVI1tsVrETzlOt3MeUGCudVoCgJmAhFU78F+6Usu0V39iylSHCRZMROM0do5pUDWQamEPZTy5oqyXVt77bG94HGEyTkCE8BsjLOcl11Uvf7V+qvIP86jgWH8zhc9LpKYU7qRhH5NTRknwFw3+jpMQCIItG69PCLfZ1YKAMlS/7PQDCc2qbRzSjET4slINBAvhsPxjarKKy/9FhjZG8Ol4tINi/uFzkcfl8sEnwExATGRY73Ze2VpAHxHoPFki7r2iljN3a6LqqOxnZ+vXUBNwTF6uL0e0Nr3tSYWpqNhQtaIaA0A1oZftuf5Y1xmCMRO2IM1VXqf3aYr5IDXODTx7+43PAjPFcit1MANeHfFxuFpSFW9TbbORpaNEqt6/5tIoxuBOO049NHXNTN5lFwlE3o09JUMlWKdSmJ/UC8TvRwqjNzoVwNIw3upcluyq4hSAq3Idyt5HOyRIDGuGdA42un+6wv/Cq7sFA1F/B4N/5MEgL/yOsSPlFSMOzD5JhkMEQ8l8u41Job7hVoExsiRNMU1Biac4oqD92Np8Xt0BgUiEOeIHLyobbQb9U/8fSAItsFdJv1wECASB5L92xb2yefcE3Q+jgsof//m3+PO2i7YhgV0HisAK48UnE03EaT67axMyjMNXpFkf/za8r3VPP2I46Ri+aYDW0z3SMT6NJb62wPiJEFhEoFCYIhNoyS4VF1CBKArPu6MKWysBZhFVFrD7yri2VkuR4QZAIkTMAOAiDIY9KvFQ3gVPqXVFD9JSbSS3vP7b/QzKY8SlO6G5e2fv/dozvDxciKvCqOYrIURT/XU2+0SKrdVqtpVojz4Sq1Vi1duV0UE+PSEy33AhRRZAzDDc4vXrB1xKU0gRUR0LCCRi/be8XZ12/0M41Ka5K/5JjA80PlQKMjfeVVN9ZG0NZbmH8xf5Y8nJxIKmYC7SmLlexeVp2wKb+y++f6KZ3c/03g+qSISPONGDqHRZOk7QGde6XsrjTP+kXTTCpCVGErZteZUDRdhD3Ls65tz64J85ZGyQ0tXDAzckadFlOtv+ZQLoYMgHHaGcrJ7fb56inR3WVJJRVTdVM3kQSh5r1hjlbIGIKVX6ammE1vnmImh4Y4BZHGcvmvx5XQ6BcRIfnPHxV82ZnFUYsh+bWXLzMuwquGwCnvdBUTkqHcPmb+l5cJZcKervlwc8N04sbYwSJC1tsnneemJqh32LksZflr1SUh+pT6q+/ov/krztitDq1s4hP1p7mbfuFfkEKJgSejLh/Wa7Y5GJsdQmEYDoVocDCvnLCvnwPDMzOK/uiVoPS8IxoQi409D2xAU4Hd2xE2DZ3gjvcpVZY+0iqgAbFh7F9grp84xf5D6QFOE/rYo1vto4z6ZVg/COHKAiGJrACaljNHaiaqTp0NeXlr37Ydz/ahSLY9YzLIPMzlxSrxMzM/ochfnO8UHvJJpgTnm+UE5GKMeOu3LrLJPd32+Z1FamfczKli36jzTtHplvPg46o2WgNwEaOqoTk8Jxsu4+vGUruDkCCCJkg171g2ntqMkjrmuYUBwG7LglIq/U7Zr1HEjJrtiay9imIzsqt37gb4/RSZlSsP88iZf5T3kX2xOuBEck2yp13F32NbDuZbHqSjwFrzJbeP5eN6NHOJuoQyXRIZ7Y+3Gh08wohjpW/VOkFMyqagHILnOSAOuflh1bqKggew524Zs1ex+R6cmz1W7Z6clvzzF8T7rLsvnSfBgJVO9cN+ax4/IRwazZLZrqmOSWJjAR0hCdFc/F2AtToTos34POQHAkVw2Sp2m7EKwOEyLVj59w6EtpyjdFYSCCYhaC0n9fcmmr5pb8QBrQl0wqn/hNc82J8Rfc8lWVwVGwLeNDVPTdW30+KZN0Sab5JTBqOBBowIHzeZVJcBjXHdKXfQp93+DgwuIgy9QtqJ8evPhOtRRzZi30iKfBZPxQVNhofDP6sUXh05zA5MH+WKdpAgAJ/lAChqhyQmd5HgFChFoMvar0AaKq8qSGmA6o03lVFCEqx1Q0Ce0075hkgvW93EPNeMZ3Cl93eRl5Q8GVjoBs1tUN1l/rvkn1VOuNXUIAyATv6zz3bXPEo3t7N/L6bBirfV0MimktOclgnDUJHiTWxo9oJOZQT/TDUk0nIYfFODFaMMN4WFqbnEl8BzXtlBX++ATr2KW3eC9kbg/9d2l6/qmdxrq9bdRkBwMtrgd+lpkpxwyWSwAkvRKSfl0phf4l+6acGVeak6QQbCJYH/Gwci+zPi/+oMFEJpLdTDfQ8IpTTl8r/lkQuniX3oR98mjX65sJQZ0wYNu1NU0wZ8RjSUf0Qo22aCU1oAoCazTFe5bdZ1pVIqcv2B12XSm6awxCFNaichCr1I1auDOQFvKxzQHFD4mexGXNfds/PoYB+iMhxzwIC8vcJe7HKVIrBEoLRQkuVL+Ii70lDlMUOR/uHrJdNaAwXo82orksR8gfVUAGFkgy5JfhKdEKncelwhq8SinwMeidX+303VHuvOgCGSRRF2o6vb6FyKmQTGRNTraQt1qJ6EaAPA4V22MYH20wXx+aCyfKFvFAcymiYfCh/YhSQZACFHpBB/l6On2l0s/AgTBWdIHHbpIulzfWDbvAW4r3gPUIwWZ0lW6SoaE0AgDYG6Six0R4OjgWRMwGUAVHuUz+SS2iNQ+XSMAvKqzrLCemdtUo3ifWhpoTi7b/RSfVRH9zBc2y43umXVgtImf3R08c7zCIeYpVoPOtoh+ZjYEhd3kWtV4IHSldEjAV7U/ATHxig89Tx0QUFCtvUJisxnNknuHArSY4+xtNuk4ZQWai4wOBThJRqZJvhYXtptnNTVAHQnQYbT4k7QI6/Vd6w6f/U9h39cUgEg+BCG3rk/AHQ9wlhsz1IUCI3tRPrDVtdlhzO9rxPNke+nuXR0TUIdAMOrDlkJshwEM4QId98C8vKTmUUJHAwww03VNT8ny9hd/cJ9qCaU7QnrpjXvcsKuT6W7VdcvHc+sq95wDCuZILxp9t+TZJWVL/56PPdJzDhjDhG75UyUrsXXtBw9z/PjAObd3729leA++mTOldO07dyl9ghbmnALmYpjybndhO3/VV/dx9IQdlj53YQEAo2din3p1cv1VfDIF8EfvSdJQSZvU3ljGJJOvNuH94kOPs22jwWq3P5edTryG8G/OdtsxOPiZd6O1ppTeK0n43Hb/9yPuYBhPuFFXumEq3231S+ibL/e+yhtP2Zz+iD74hCu83vblr+W1yJ5LgguxmzedRu/8//AUSaqMTR1xAAAAAElFTkSuQmCC); - background-repeat: no-repeat; - background-position: center top 10px; -} - -.footer a { - color: #3b5c6b; -} - - -/* Main Menu - * Displayed in header, contains repository links. -––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ -.mainmenu { - clear:both; -} - -.mainmenu ul { - list-style: none outside; - display: block; - position: relative; - border-top: 1px solid #ccc; - padding: 0; -} - -.mainmenu li { - outline: 0; - display: block; - float: left; - margin: 0; -} - -.mainmenu li.active { - background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAAJCAYAAADU6McMAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEQAACxEBf2RfkQAAAAd0SU1FB90FDxEXAZ2XRzAAAABJSURBVCjPY2CgBzhz5sx/QmoYiTXAxMSEkWRDsLkAl0GMpHoBm0EoAlu3bmUQFxcnGAboBjEhc4gxAJtLGUmJBVwuYiTXAGSDAIx5IBObnuVxAAAAAElFTkSuQmCC); - background-repeat: no-repeat; - background-position: center bottom; -} - -.mainmenu li a { - color: #3b5c6b; - display: block; - padding: 10px 15px; -} - -.mainmenu li.active a { - font-weight: bold; -} - -.mainmenu li:hover { - background-color: #eee; -} - - -/* Submenu - * Displayed in the middle div. Contains page-specific form controls. -––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ -.submenu { - padding: 10px 0px; - border-bottom: 1px solid #ddd; -} - -.submenu input, .submenu select { - margin: 0 0 0 5px; -} - -.submenu a { - color: #3b5c6b; - padding: 5px 15px; - text-decoration: none; - border: 1px solid transparent; - border-radius: 5px; -} - -.submenu a:hover { - border: 1px solid #ccc; -} - - -/* Section - * Cap/header to distinguish a section. Displayed within a content div. -––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ -.section { - font-weight: bold; - background-color: #f5f5f5; - border: 1px solid #ccc; - padding: 9px 10px 10px; - margin: 10px 0; -} - - -/* Section Menu - * Div of buttons/links, displayed with a section div within a content div. -––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ -.sectionmenu { - border: 1px solid #ccc; - border-top: 0; - margin-top: -10px; - margin-bottom: 10px; - padding: 5px; - text-align: center; -} -.sectionmenu a { - display: inline-block; - margin-top: 5px; - margin-right: 1em; -} - - -/* File browser - * 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; - padding-top: 2px; -} - -ul.browser li.file { - background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QAVQBVAFV4xrLkAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3wMLExMaPfBcSgAAAFNJREFUOMvtkzEOwDAIA02VL5pHwiOTJZFQmkqFOTex+CwPCCYkAaDjB+4u65ZdYGafQVV9SR4kWQUke0mwS1o2HGcAQKs0R1lpQuQKruD4jVnBAG/cGRqf0U66AAAAAElFTkSuQmCC); - background-repeat: no-repeat; - background-position: 0px center; - padding-left: 22px; - padding-top: 2px; -} - -div.filetreeline { - display: table; - width: 100%; - white-space: nowrap; -} - -/* tree-view top-level list */ -.filetree > ul { - display: inline-block; -} - -/* tree-view lists */ -.filetree ul { - margin: 0; - padding: 0; - list-style: none; -} -/* tree-view collapsed list */ -.filetree ul.collapsed { - display: none; -} -/* tree-view lists below the root */ -.filetree ul ul { - position: relative; - margin: 0 0 0 21px; -} -/* tree-view lists items */ -.filetree li { - position: relative; - margin: 0; - padding: 0; -} -/* tree-view node lines */ -.filetree li li:before { - content: ''; - position: absolute; - top: -.8em; - left: -14px; - width: 16px; - height: 1.5em; - border-left: 1px solid #ccc; - border-bottom: 1px solid #ccc; -} -/* tree-view directory lines */ -.filetree li > ul:before { - content: ''; - position: absolute; - top: -1.5em; - bottom: 0; - left: -35px; - border-left: 1px solid #ccc; -} -/* hide lines for last-child directories */ -.filetree li.last > ul:before { - display: none; -} - -.filetree a { - position: relative; - z-index: 1; - display: table-cell; - min-height: 16px; - padding-left: 22px; - background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QAVQBVAFV4xrLkAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3wMLExMaPfBcSgAAAFNJREFUOMvtkzEOwDAIA02VL5pHwiOTJZFQmkqFOTex+CwPCCYkAaDjB+4u65ZdYGafQVV9SR4kWQUke0mwS1o2HGcAQKs0R1lpQuQKruD4jVnBAG/cGRqf0U66AAAAAElFTkSuQmCC); - background-position: center left; - background-repeat: no-repeat; -} - -.filetree .dir > div.filetreeline > a { - background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QAVQBVAFV4xrLkAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3wMLExABnLjGZQAAAEFJREFUOMtjYKAQMIaGhv4npGj16tWMuORYGBgYGOZW+eDUnNy2Ba/hLMQ4E58rCRpAyHVMlAbiqAGjBhCdmWgKAHp4Dh0ZusP3AAAAAElFTkSuQmCC); -} - - -/* Label-Value table - * Displayed on the Check-in & Admin pages. -––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ -table.label-value th { - vertical-align: middle; -} - - -/* Branches table -––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ -.brlist table td { - padding: 5px; -} - - -/* Timeline - * Displays chronologically-ordered check-ins with a branch graph. -––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ -tr.timelineCurrent { - border-left: 2px solid orange; - background-color: #ffc; -} - -tr.timelineSelected { - border-left: 2px solid orange; - background-color: #ffffe8; -} - -tr.timelineCurrent td.timelineTableCell { -} - -tr.timelineSpacer { -} - -div.timelineDate { - font-weight: bold; - white-space: nowrap; -} - -a.timelineHistLink { - text-transform: lowercase; -} - -span.timelineComment { - padding: 0px 5px; -} - - -/* Login/Loguot -––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ -table.login_out { -} - -table.login_out .login_out_label { - font-weight: 700; - text-align: right; -} - -table.login_out td { - border: 0; -} - - -/* Diff displays -––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ -pre.udiff, table.sbsdiffcols { - width: 100%; - overflow: auto; - border: 1px solid #ccc; - padding: 5px; - font-size: 1rem; -} - -pre.udiff:focus, table.sbsdiffcols:focus { - outline: none; -} - - -/* Ticket Reports -––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ -table.report { - width: 100%; - cursor: auto; - border-radius: 4px; - border: 1px solid #ccc; - margin: 0 0 1em 0; -} - -.report td, .report th { - border: 0; - font-size: .9em; - padding: 5px; -} - -.report th { - cursor: pointer; -} - -.report thead+tbody tr:hover { - background-color: #f5f9fc !important; -} - - -/* Ticket page -––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ -table.tktDsp { - border-top: 1px solid #ccc; - border-left: 1px solid #ccc; - width: 100%; - margin: 15px 0px 10px 0px; -} - -td.tktDspLabel, td.tktDescLabel { - width: 70px; - text-align: right; - overflow: hidden; - font-weight: 700; - padding: 10px; - background-color: #f8f8f8; -} - -td.tktDescLabel { - vertical-align: top; -} - -td.tktDspValue, td.tktDescValue { - text-align: left; - vertical-align: top; - border: 1px solid #ccc; - padding: 10px; -} - -td.tktDspValue pre, td.tktDescValue pre, -td.tktDspValue code, td.tktDescValue code { - white-space: pre-wrap; -} - -div.tktComments { - width: 100%; - margin: 30px 0px 10px 0px; -} - -div.tktComment { -} - -div.tktCommentHeader { - border: 1px solid #ccc; - background-color: #f8f8f8; - padding: 10px 10px; - margin-bottom: 10px; -} - -span.tktCommentLogin { - display: inline-block; - font-weight: 700; - color: #002060; -} - -div.tktCommentBody { - margin: 10px 40px 30px; -} - - -/* User setup table -––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ -td.usetupEditLabel { - font-weight: 700; -} - - -/* Utilities -––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ -.full-width { - width: 100%; - box-sizing: border-box; -} - -.max-full-width { - max-width: 100%; - box-sizing: border-box; -} - -.pull-right { - float: right; -} - -.pull-left { - float: left; -} - -/* Clearing -––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ -.container:after, -.mainmenu:after, -.row:after, -.u-cf { - content: ""; - display: table; - clear: both; -} DELETED skins/blitz/details.txt Index: skins/blitz/details.txt ================================================================== --- skins/blitz/details.txt +++ skins/blitz/details.txt @@ -1,4 +0,0 @@ -timeline-arrowheads: 0 -timeline-circle-nodes: 1 -timeline-color-graph-lines: 1 -white-foreground: 0 DELETED skins/blitz/dir.png Index: skins/blitz/dir.png ================================================================== --- skins/blitz/dir.png +++ skins/blitz/dir.png cannot compute difference between binary files DELETED skins/blitz/file.png Index: skins/blitz/file.png ================================================================== --- skins/blitz/file.png +++ skins/blitz/file.png cannot compute difference between binary files DELETED skins/blitz/footer.txt Index: skins/blitz/footer.txt ================================================================== --- skins/blitz/footer.txt +++ skins/blitz/footer.txt @@ -1,12 +0,0 @@ - </div> <!-- end div container --> - </div> <!-- end div middle max-full-width --> - <div class="footer"> - <div class="container"> - <div class="pull-right"> - <a href="http://fossil-scm.org">Fossil version $manifest_version $manifest_date</a> - </div> - This page was generated in about <th1>puts [expr {([utime]+[stime]+1000)/1000*0.001}]</th1>s - </div> - </div> - </body> -</html> DELETED skins/blitz/fossil_100.png Index: skins/blitz/fossil_100.png ================================================================== --- skins/blitz/fossil_100.png +++ skins/blitz/fossil_100.png cannot compute difference between binary files DELETED skins/blitz/fossil_80_reversed_darkcyan.png Index: skins/blitz/fossil_80_reversed_darkcyan.png ================================================================== --- skins/blitz/fossil_80_reversed_darkcyan.png +++ skins/blitz/fossil_80_reversed_darkcyan.png cannot compute difference between binary files DELETED skins/blitz/fossil_80_reversed_darkcyan_text.png Index: skins/blitz/fossil_80_reversed_darkcyan_text.png ================================================================== --- skins/blitz/fossil_80_reversed_darkcyan_text.png +++ skins/blitz/fossil_80_reversed_darkcyan_text.png cannot compute difference between binary files DELETED skins/blitz/header.txt Index: skins/blitz/header.txt ================================================================== --- skins/blitz/header.txt +++ skins/blitz/header.txt @@ -1,80 +0,0 @@ -<html> - <head> - <base href="$baseurl/$current_page" /> - <title>$<project_name>: $<title> - - - - - -
-
- - - - - - - -
-
-
-
DELETED skins/blitz/rss_20.png Index: skins/blitz/rss_20.png ================================================================== --- skins/blitz/rss_20.png +++ skins/blitz/rss_20.png cannot compute difference between binary files DELETED skins/blitz/ticket.txt Index: skins/blitz/ticket.txt ================================================================== --- skins/blitz/ticket.txt +++ skins/blitz/ticket.txt @@ -1,115 +0,0 @@ -

$</h4> -<table class="tktDsp"> -<tr><td class="tktDspLabel">Ticket UUID</td> -<th1> -if {[info exists tkt_uuid]} { - if {[hascap s]} { - html "<td class='tktDspValue' colspan='3'>$tkt_uuid " - html "($tkt_id)</td></tr>\n" - } else { - html "<td class='tktDspValue' colspan='3'>$tkt_uuid</td></tr>\n" - } -} else { - if {[hascap s]} { - html "<td class='tktDspValue' colspan='3'>Deleted " - html "(0)</td></tr>\n" - } else { - html "<td class='tktDspValue' colspan='3'>Deleted</td></tr>\n" - } -} -</th1> -<tr><td class="tktDspLabel">Status</td><td class="tktDspValue"> -$<status> -</td> -<td class="tktDspLabel">Type</td><td class="tktDspValue"> -$<type> -</td></tr> -<tr><td class="tktDspLabel">Severity</td><td class="tktDspValue"> -$<severity> -</td> -<td class="tktDspLabel">Priority</td><td class="tktDspValue"> -$<priority> -</td></tr> -<tr><td class="tktDspLabel">Subsystem</td><td class="tktDspValue"> -$<subsystem> -</td> -<td class="tktDspLabel">Resolution</td><td class="tktDspValue"> -$<resolution> -</td></tr> -<tr><td class="tktDspLabel">Last Modified</td><td class="tktDspValue"> -<th1> -if {[info exists tkt_datetime]} { - html $tkt_datetime -} -</th1> -</td> -<th1>enable_output [hascap e]</th1> - <td class="tktDspLabel">Contact</td><td class="tktDspValue"> - $<private_contact> - </td> -<th1>enable_output 1</th1> -</tr> -<tr><td class="tktDspLabel">Version Found In</td> -<td colspan="3" valign="top" class="tktDspValue"> -$<foundin> -</td></tr> - -<th1> -if {[info exists comment]} { - if {[string length $comment]>10} { - html { - <tr> - <td class="tktDescLabel">Description</td> - <td class="tktDescValue" colspan="3"> - } - if {[info exists plaintext]} { - set r [randhex] - wiki "<verbatim-$r links>\n$comment\n</verbatim-$r>" - } else { - wiki $comment - } - html "</td></tr>\n" - } -} -</th1> -</table> - -<div class="tktComments"> -<th1> -set seenRow 0 -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 eq "0"} { - html "<h5>User Comments</h5>\n" - set seenRow 1 - } - html "<div class='tktComment'>\n" - html "<div class='tktCommentHeader'>\n" - html "<div class='pull-right'>$xdate</div>\n" - html "<span class='tktCommentLogin'>[htmlize $xlogin]</span>" - if {$xlogin ne $xusername && [string length $xusername]>0} { - html " (claiming to be <span class='tktCommentLogin'>[htmlize $xusername]</span>)" - } - html " commented</div>\n" - html "<div class='tktCommentBody'>\n" - if {$alwaysPlaintext || $xmimetype eq "text/plain"} { - set r [randhex] - if {$xmimetype ne "text/plain"} {html "([htmlize $xmimetype])\n"} - wiki "<verbatim-$r>[string trimright $xcomment]</verbatim-$r>\n" - } elseif {$xmimetype eq "text/x-fossil-wiki"} { - wiki "<p>\n[string trimright $xcomment]\n</p>\n" - } elseif {$xmimetype eq "text/html"} { - wiki "<p><nowiki>\n[string trimright $xcomment]\n</nowiki></p>\n" - } else { - set r [randhex] - wiki "<verbatim-$r links>[string trimright $xcomment]</verbatim-$r>\n" - } - html "</div><!-- end comment body -->\n" - html "</div><!-- end comment -->\n" -} -</th1> -</div> DELETED skins/blitz_no_logo/README.md Index: skins/blitz_no_logo/README.md ================================================================== --- skins/blitz_no_logo/README.md +++ skins/blitz_no_logo/README.md @@ -1,13 +0,0 @@ -## Blitz Theme (no logo) - -Contributed by James Moger (james.moger@gitblit.com) - -This theme is inspired by my own project, [Gitblit](http://gitblit.com), and offered to the Fossil project. - -This theme embeds & uses an unmodified copy of [Normalize 3.0.2](https://necolas.github.io/normalize.css/) which is distributed under an [MIT license](https://github.com/necolas/normalize.css/blob/master/LICENSE.md). - -This theme uses half of a heavily-modified version of [Skeleton](http://getskeleton.com) which is distributed under an [MIT license](https://github.com/dhg/Skeleton/blob/master/LICENSE.md). None of the responsive elements (media queries) are included at this time. - -The font used in the included Fossil logo image is [Trillium Web Light](http://www.google.com/fonts/specimen/Titillium+Web) @ 48px HTML color code #456a7a. - -The RSS feed icon is sourced from [Font-Awesome](https://fortawesome.github.io/Font-Awesome/icons) by Dave Gandy and is distributed under the [SIL OFL 1.1 ](http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=OFL) license. DELETED skins/blitz_no_logo/css.txt Index: skins/blitz_no_logo/css.txt ================================================================== --- skins/blitz_no_logo/css.txt +++ skins/blitz_no_logo/css.txt @@ -1,1237 +0,0 @@ -/*! normalize.css v3.0.2 | MIT License | git.io/normalize */ - -/** - * 1. Set default font family to sans-serif. - * 2. Prevent iOS text size adjust after orientation change, without disabling - * user zoom. - */ - -html { - font-family: sans-serif; /* 1 */ - -ms-text-size-adjust: 100%; /* 2 */ - -webkit-text-size-adjust: 100%; /* 2 */ -} - -/** - * Remove default margin. - */ - -body { - margin: 0; -} - -/* HTML5 display definitions - ========================================================================== */ - -/** - * Correct `block` display not defined for any HTML5 element in IE 8/9. - * Correct `block` display not defined for `details` or `summary` in IE 10/11 - * and Firefox. - * Correct `block` display not defined for `main` in IE 11. - */ - -article, -aside, -details, -figcaption, -figure, -footer, -header, -hgroup, -main, -menu, -nav, -section, -summary { - display: block; -} - -/** - * 1. Correct `inline-block` display not defined in IE 8/9. - * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera. - */ - -audio, -canvas, -progress, -video { - display: inline-block; /* 1 */ - vertical-align: baseline; /* 2 */ -} - -/** - * Prevent modern browsers from displaying `audio` without controls. - * Remove excess height in iOS 5 devices. - */ - -audio:not([controls]) { - display: none; - height: 0; -} - -/** - * Address `[hidden]` styling not present in IE 8/9/10. - * Hide the `template` element in IE 8/9/11, Safari, and Firefox < 22. - */ - -[hidden], -template { - display: none; -} - -/* Links - ========================================================================== */ - -/** - * Remove the gray background color from active links in IE 10. - */ - -a { - background-color: transparent; -} - -/** - * Improve readability when focused and also mouse hovered in all browsers. - */ - -a:active, -a:hover { - outline: 0; -} - -/* Text-level semantics - ========================================================================== */ - -/** - * Address styling not present in IE 8/9/10/11, Safari, and Chrome. - */ - -abbr[title] { - border-bottom: 1px dotted; -} - -/** - * Address style set to `bolder` in Firefox 4+, Safari, and Chrome. - */ - -b, -strong { - font-weight: bold; -} - -/** - * Address styling not present in Safari and Chrome. - */ - -dfn { - font-style: italic; -} - -/** - * Address variable `h1` font-size and margin within `section` and `article` - * contexts in Firefox 4+, Safari, and Chrome. - */ - -h1 { - font-size: 2em; - margin: 0.67em 0; -} - -/** - * Address styling not present in IE 8/9. - */ - -mark { - background: #ff0; - color: #000; -} - -/** - * Address inconsistent and variable font size in all browsers. - */ - -small { - font-size: 80%; -} - -/** - * Prevent `sub` and `sup` affecting `line-height` in all browsers. - */ - -sub, -sup { - font-size: 75%; - line-height: 0; - position: relative; - vertical-align: baseline; -} - -sup { - top: -0.5em; -} - -sub { - bottom: -0.25em; -} - -/* Embedded content - ========================================================================== */ - -/** - * Remove border when inside `a` element in IE 8/9/10. - */ - -img { - border: 0; -} - -/** - * Correct overflow not hidden in IE 9/10/11. - */ - -svg:not(:root) { - overflow: hidden; -} - -/* Grouping content - ========================================================================== */ - -/** - * Address margin not present in IE 8/9 and Safari. - */ - -figure { - margin: 1em 40px; -} - -/** - * Address differences between Firefox and other browsers. - */ - -hr { - -moz-box-sizing: content-box; - box-sizing: content-box; - height: 0; -} - -/** - * Contain overflow in all browsers. - */ - -pre { - overflow: auto; -} - -/** - * Address odd `em`-unit font size rendering in all browsers. - */ - -code, -kbd, -pre, -samp { - font-family: monospace, monospace; - font-size: 1em; -} - -/* Forms - ========================================================================== */ - -/** - * Known limitation: by default, Chrome and Safari on OS X allow very limited - * styling of `select`, unless a `border` property is set. - */ - -/** - * 1. Correct color not being inherited. - * Known issue: affects color of disabled elements. - * 2. Correct font properties not being inherited. - * 3. Address margins set differently in Firefox 4+, Safari, and Chrome. - */ - -button, -input, -optgroup, -select, -textarea { - color: inherit; /* 1 */ - font: inherit; /* 2 */ - margin: 0; /* 3 */ -} - -/** - * Address `overflow` set to `hidden` in IE 8/9/10/11. - */ - -button { - overflow: visible; -} - -/** - * Address inconsistent `text-transform` inheritance for `button` and `select`. - * All other form control elements do not inherit `text-transform` values. - * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera. - * Correct `select` style inheritance in Firefox. - */ - -button, -select { - text-transform: none; -} - -/** - * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` - * and `video` controls. - * 2. Correct inability to style clickable `input` types in iOS. - * 3. Improve usability and consistency of cursor style between image-type - * `input` and others. - */ - -button, -html input[type="button"], /* 1 */ -input[type="reset"], -input[type="submit"] { - -webkit-appearance: button; /* 2 */ - cursor: pointer; /* 3 */ -} - -/** - * Re-set default cursor for disabled elements. - */ - -button[disabled], -html input[disabled] { - cursor: default; -} - -/** - * Remove inner padding and border in Firefox 4+. - */ - -button::-moz-focus-inner, -input::-moz-focus-inner { - border: 0; - padding: 0; -} - -/** - * Address Firefox 4+ setting `line-height` on `input` using `!important` in - * the UA stylesheet. - */ - -input { - line-height: normal; -} - -/** - * It's recommended that you don't attempt to style these elements. - * Firefox's implementation doesn't respect box-sizing, padding, or width. - * - * 1. Address box sizing set to `content-box` in IE 8/9/10. - * 2. Remove excess padding in IE 8/9/10. - */ - -input[type="checkbox"], -input[type="radio"] { - box-sizing: border-box; /* 1 */ - padding: 0; /* 2 */ -} - -/** - * Fix the cursor style for Chrome's increment/decrement buttons. For certain - * `font-size` values of the `input`, it causes the cursor style of the - * decrement button to change from `default` to `text`. - */ - -input[type="number"]::-webkit-inner-spin-button, -input[type="number"]::-webkit-outer-spin-button { - height: auto; -} - -/** - * 1. Address `appearance` set to `searchfield` in Safari and Chrome. - * 2. Address `box-sizing` set to `border-box` in Safari and Chrome - * (include `-moz` to future-proof). - */ - -input[type="search"] { - -webkit-appearance: textfield; /* 1 */ - -moz-box-sizing: content-box; - -webkit-box-sizing: content-box; /* 2 */ - box-sizing: content-box; -} - -/** - * Remove inner padding and search cancel button in Safari and Chrome on OS X. - * Safari (but not Chrome) clips the cancel button when the search input has - * padding (and `textfield` appearance). - */ - -input[type="search"]::-webkit-search-cancel-button, -input[type="search"]::-webkit-search-decoration { - -webkit-appearance: none; -} - -/** - * Define consistent border, margin, and padding. - */ - -fieldset { - border: 1px solid #c0c0c0; - margin: 0 2px; - padding: 0.35em 0.625em 0.75em; -} - -/** - * 1. Correct `color` not being inherited in IE 8/9/10/11. - * 2. Remove padding so people aren't caught out if they zero out fieldsets. - */ - -legend { - border: 0; /* 1 */ - padding: 0; /* 2 */ -} - -/** - * Remove default vertical scrollbar in IE 8/9/10/11. - */ - -textarea { - overflow: auto; -} - -/** - * Don't inherit the `font-weight` (applied by a rule above). - * NOTE: the default cannot safely be changed in Chrome and Safari on OS X. - */ - -optgroup { - font-weight: bold; -} - -/* Tables - ========================================================================== */ - -/** - * Remove most spacing between table cells. - */ - -table { - border-collapse: collapse; - border-spacing: 0; -} - -td, -th { - padding: 0; -} - - -/* - * Blitz - * - * Skin inspired by Gitblit with heavily-modified excerpts from Skeleton 2.0.4. - * Blitz is authored by james.moger@gitblit.com. - * - * Skeleton is authored by Dave Gamache and is distributed under the MIT license. - * http://getskeleton.com - * -––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ - -html { - /* 62.5% so that the REM values are base 10px. */ - /* 1.5rem = 15px */ - font-size: 62.5%; -} - -/* Typography -––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ -h1, h2, h3, h4, h5, h6 { - margin: 0; - margin-bottom: 1rem; - font-weight: 700; -} - -h1 { font-size: 3.0rem; line-height: 1.2; } -h2 { font-size: 2.6rem; line-height: 1.25; } -h3 { font-size: 2.4rem; line-height: 1.3; } -h4 { font-size: 2.0rem; line-height: 1.35; } -h5 { font-size: 1.6rem; line-height: 1.5; } -h6 { font-size: 1.4rem; line-height: 1.6; } - -h1 small, h2 small, h3 small, h4 small, h5 small, h6 small { - font-size: 0.75em; - font-weight: 400; - color: #ccc; -} - -pre, code { - font-size: 1.2rem; -} - -body { - font-size: 1.4em; /* currently ems cause chrome bug misinterpreting rems on body element */ - line-height: 1.5; - font-weight: 400; - font-family: "HelveticaNeue", "Helvetica Neue", Helvetica, Arial, sans-serif; - color: #333; - background-color: #f8f8f8; -} - -/* Spacing -––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ -button, -.button { - margin-bottom: 1rem; -} - -input, -textarea, -select, -fieldset, -pre, -blockquote, -dl, -figure, -table, -p, -ul, -ol { - margin-bottom: 1rem; -} - -p { - margin-top: 0; -} - -hr { - margin-top: 3rem; - margin-bottom: 3.5rem; - border-width: 0; - border-top: 1px solid #ccc; -} - - -/* Buttons -––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ -.button, -button, -input[type="button"], -input[type="reset"], -input[type="submit"] { - display: inline-block; - height: 3.3rem; - padding: 0 2.2rem; - color: #555 !important; - text-align: center; - font-size: 1.1rem; - font-weight: 700; - line-height: 3.3rem; - letter-spacing: .08rem; - text-transform: uppercase; - text-decoration: none; - white-space: nowrap; - background-color: transparent; - border-radius: 4px; - border: 1px solid #ccc; - cursor: pointer; - box-sizing: border-box; -} - -.button:hover, -button:hover, -input[type="button"]:hover, -input[type="reset"]:hover, -.button:focus, -button:focus, -input[type="button"]:focus, -input[type="reset"]:focus { - color: #444 !important; - background-color: #eee; - border-color: #aaa; - outline: 0; -} - -input[type="submit"] { - color: white !important; - background-color: #446979; - border-color: #446979; -} - -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"], -input[type="tel"], -input[type="url"], -input[type="password"], -textarea, -select { - height: 3.3rem; - padding: 6px 10px; - background-color: #fff; - border: 1px solid #ddd; - border-radius: 4px; - box-shadow: none; - box-sizing: border-box; -} - -/* Removes awkward default styles on some inputs for iOS */ -input[type="email"], -input[type="number"], -input[type="search"], -input[type="text"], -input[type="tel"], -input[type="url"], -input[type="password"], -textarea { - -webkit-appearance: none; - -moz-appearance: none; - appearance: none; -} - -textarea { - height: inherit; - min-height: 65px; - padding-top: 6px; - padding-bottom: 6px; -} - -input[type="email"]:focus, -input[type="number"]:focus, -input[type="search"]:focus, -input[type="text"]:focus, -input[type="tel"]:focus, -input[type="url"]:focus, -input[type="password"]:focus, -textarea:focus, -select:focus { - border: 1px solid #aaa; - outline: 0; -} - -label, -legend { - display: block; - margin-bottom: .5rem; - font-weight: 700; -} - -fieldset { - padding: 0; - border-width: 0; -} - -input[type="checkbox"], -input[type="radio"] { - display: inline; -} - - -/* Links -––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ -a { - color: #446979; - text-decoration: none; -} - -a:hover { - text-decoration: underline; -} - - -/* Lists -––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ -ul { - list-style: square; -} - -ol { - list-style: decimal; -} - -ol, ul { - padding-left: 3rem; - margin-top: 0; -} - -li { - margin-bottom: 0.5rem; -} - - -/* Nested Lists -––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ -ul ul, -ul ol, -ol ol, -ol ul { - margin: 1rem 0 1rem 2rem; -} - - -/* Code -––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ -code, kbd { - padding: .2rem .5rem; - margin: 0 .2rem; - white-space: nowrap; - background: #f8f8f8; - border: 1px solid #ccc; - border-radius: 4px; -} - -pre > code { - display: block; - padding: 1rem 1.5rem; - white-space: pre; -} - -pre.verbatim { - background-color: inherit; - white-space: pre-wrap; -} - - -/* Blockquote -––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ -blockquote { - padding: 0px 20px; - margin: 0 0 20px; - border-left: 4px solid #ccc; -} - - -/* Tables -––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ -th, -td { - padding: 6px 5px; - text-align: left; - border-bottom: 1px solid #ddd; } -th:first-child, -td:first-child { - padding-left: 0; } -th:last-child, -td:last-child { - padding-right: 0; } - - -/* - * Blitz Page Layout Design - * - * html > body > header > container > mainmenu - * middle > container > submenu & content - * footer > container > generation stats, fossil logo, version - * - ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ - - -/* Container - * Represents the usable layout space for header, middle, and footer. -––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ -.container { - position: relative; - width: 100%; - max-width: 900px; - margin: 0 auto; - box-sizing: border-box; -} - - -/* Header - * Div displayed at the top of every page. -––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ -.header { - color: #666; - font-weight: 400; - padding-top: 10px; - border-width: 0px; - border-top: 4px solid #446979; - border-bottom: 1px solid #ccc; -} - -.header .logo { - display: inline-block; -} - -.header .login { - padding-top: 2px; - text-align: right; -} - -.header .login .button { - margin: 0; -} - -.header h1 { - margin: 0px; - color: #666; - display: inline-block; -} - -.header .logo h1 { - display: inline-block; -} - -.header .title h1 { - padding-bottom: 10px; -} - -.header h1 small, .header h2 small, .header .login { - color: #888; -} - -.header a.rss { - display: inline-block; - padding: 10px 15px; - background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3wMNDhwn05VjawAAABl0RVh0Q29tbWVudABDcmVhdGVkIHdpdGggR0lNUFeBDhcAAAGlSURBVDjLrdPfb8xREAXwT7tIl+paVNaPJghCKC8kXv0XXvyNXsRfwYPQJqVKiqykWFVZXd12vcxNJtduUtJJvrm7984998ycMxxwNGI9jPs4j7nY+/U/gIdiPYO71dk21rCE7r8ybOHGmMfmcRNnsbEf1gXwNzqYSXs5WljEMXzAaBLg1Ji9Js7hOi6OeeAznqC/X8AcMyHWYpX7E4/Rm1QyHMdefCWGeI/VcMDR2D8S7Fci5y/AeTzCPVyLi1sYJAut4BTaiX0n9kc14MmkcjPY3I5LXezGtxqKtyJ3Lir6VAM2AmCq6m8Hl6PsQTB5hyvxmMhZxk4G3MZLfAwLtdNZM9rwOs528TVVNB3ga7UoQ2wGmyWciFaU0VwIJiP8iL6Xfp7GK+w0JthliDep8UKonTSGvbBTaU8f3QzYxgPcCsBvWK9E6OBFCNGPVjTTqC430p+H6fLVGLGtmIw7SbwevqT+XkgVPJ9Otpmtyl6I9XswLXEp/d6oPN0ugJu14xMLob4kgPRYjtkCOMDTUG+AZ3ibEtfDLorfEmAB3UuTdXDxBzUUZV+B82aLAAAAAElFTkSuQmCC); - background-position: center center; - background-repeat: no-repeat; -} - - -/* Middle - * Center div displayed between header and footer. Contains per-page content. -––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ -.middle { - background-color: white; - padding-bottom: 20px; - max-width: 100%; - box-sizing: border-box; -} - - -/* Content - * Displayed below submenu within the middle div. -––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ -.content { - padding-top: 15px; -} - -.content a { - color: #002060; -} - - -/* Footer - * Displayed after the middle div and forms the page bottom. -––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ -.footer { - padding: 10px 0 60px; - border-top: 1px solid #ccc; - background-color: #f8f8f8; - background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAABGCAQAAADxl9ugAAAAAmJLR0QA/4ePzL8AAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQffAwkQBRPw+yfrAAAAPHRFWHRDb21tZW50ACBJbWFnZSBnZW5lcmF0ZWQgYnkgRVNQIEdob3N0c2NyaXB0IChkZXZpY2U9cG5tcmF3KQqV01S1AAANg0lEQVRo3s2aa3RVRZbH/3tXnftIbhJCeJMXyEsNCsgrSBzAYXyt0YVj2zSOonbLqNNO+25FB2kdoBVdrp6l09P2NNpOL/ExSrtUdGRU5JEQgggCggIhQIBAIIGQ5N57TlXt+ZAICY+AGCT76zlV91dVe+/a+38uDQ7dYmrxw41QocJuni28vWTedEa7Gd9iatplos7Y2mfDRED6A2G0I2At6AdPIiA84HgbLhx1o9QX9Zoh7QjYHpOkYJYrfNyOKH0O/f2FJpfkSRmMCNqDk9rDXwTAuxK7h3uFf7vXxC6QVO8w19taNOT4Y0wu1sCdW0AA6IZ73bCUaI/GHuqnsJqcEqVrzSo+wNtLdgAPsz6jeVURtQ9gA8bQT8xztW7X2u3I4G6UdA0cohxcSAN7nt939/zDQzl0LnfwaLpxqFT/i7w7XLYXhoUQ+YFW3pJlC0/nt6jZZb4zjXY2AaGXvQOz/gMY09NM4C6ixRL7OU3PTm4ORdiIjyLsJvq1Z28Hj5rBM82xMTqPuhHznmU72vq12W5M3+LykQWUW9pirzXOmmk8wjE87kb8HPmSKlY+wY62R9jhI69xf/AmYiEfiXs+e4CCAZiDUc9wP6cRIJn8tq23PQClbwap9Ivk7usiGj/CDs5xl3Qe/EiQCEWsgXLlq8sfamM73osMna43ef/pfm731Hsxv+Z00ozFzaJpF+gMrsNB2BwL3cGpSsNRWHbmvTQNiTbev9q4xXszMLzqpdgDNjxv/YjmvHlSQIc5brl8nrqT5pllMpHM9wRc4gU3oC8JyDLt8P78ZLyM2lrmAeTg5YrKdf1S1N9QTs6At1YM49DJo1gwWy7uE5kKBQHbler9K8R+L8API2qmFoDY7ejxpxGJxtMctyZcfYvJDYX4i5LXp/MJAS2edkM6edNUDuLNOdMDmz913bIw8RidKO/1w+3NQfePbHQjdbd/NKOjbq7UqQOmYtXb/+BdbGc4AJjPX53CXe6UGweYWxUR8N8rNkzn4wAFc9yYPvGbI+mttoycpo14fWbD0hZv+njOAcBl6Yl8jiEMbSKhqGPypZ5N0B2kDxrjOjF0QuI2oRqj2z6rAebx5pNiRrEo0jhV9wFkP//xpkPHAU6UGdnBLyR8jMOQs6xwcMAznVys+Uqa5YCCnilFkuVSkeKlGKfDED8JaI+VifMWR9LPC/u+UkoZA6edOezVu83pny4yD6qQnCxhDzk/MhUED+8PWHJMkAgWROvvQoxOcEdayynVY9/5tIgAwsfIvaD3XaFx6M6ddMx3WlurCGICiAIhMLxB1VM+wQRMDOeYjHCUMum85OW909/acOlJgqaI3qrulU9dYGlgzVI1tsVrETzlOt3MeUGCudVoCgJmAhFU78F+6Usu0V39iylSHCRZMROM0do5pUDWQamEPZTy5oqyXVt77bG94HGEyTkCE8BsjLOcl11Uvf7V+qvIP86jgWH8zhc9LpKYU7qRhH5NTRknwFw3+jpMQCIItG69PCLfZ1YKAMlS/7PQDCc2qbRzSjET4slINBAvhsPxjarKKy/9FhjZG8Ol4tINi/uFzkcfl8sEnwExATGRY73Ze2VpAHxHoPFki7r2iljN3a6LqqOxnZ+vXUBNwTF6uL0e0Nr3tSYWpqNhQtaIaA0A1oZftuf5Y1xmCMRO2IM1VXqf3aYr5IDXODTx7+43PAjPFcit1MANeHfFxuFpSFW9TbbORpaNEqt6/5tIoxuBOO049NHXNTN5lFwlE3o09JUMlWKdSmJ/UC8TvRwqjNzoVwNIw3upcluyq4hSAq3Idyt5HOyRIDGuGdA42un+6wv/Cq7sFA1F/B4N/5MEgL/yOsSPlFSMOzD5JhkMEQ8l8u41Job7hVoExsiRNMU1Biac4oqD92Np8Xt0BgUiEOeIHLyobbQb9U/8fSAItsFdJv1wECASB5L92xb2yefcE3Q+jgsof//m3+PO2i7YhgV0HisAK48UnE03EaT67axMyjMNXpFkf/za8r3VPP2I46Ri+aYDW0z3SMT6NJb62wPiJEFhEoFCYIhNoyS4VF1CBKArPu6MKWysBZhFVFrD7yri2VkuR4QZAIkTMAOAiDIY9KvFQ3gVPqXVFD9JSbSS3vP7b/QzKY8SlO6G5e2fv/dozvDxciKvCqOYrIURT/XU2+0SKrdVqtpVojz4Sq1Vi1duV0UE+PSEy33AhRRZAzDDc4vXrB1xKU0gRUR0LCCRi/be8XZ12/0M41Ka5K/5JjA80PlQKMjfeVVN9ZG0NZbmH8xf5Y8nJxIKmYC7SmLlexeVp2wKb+y++f6KZ3c/03g+qSISPONGDqHRZOk7QGde6XsrjTP+kXTTCpCVGErZteZUDRdhD3Ls65tz64J85ZGyQ0tXDAzckadFlOtv+ZQLoYMgHHaGcrJ7fb56inR3WVJJRVTdVM3kQSh5r1hjlbIGIKVX6ammE1vnmImh4Y4BZHGcvmvx5XQ6BcRIfnPHxV82ZnFUYsh+bWXLzMuwquGwCnvdBUTkqHcPmb+l5cJZcKervlwc8N04sbYwSJC1tsnneemJqh32LksZflr1SUh+pT6q+/ov/krztitDq1s4hP1p7mbfuFfkEKJgSejLh/Wa7Y5GJsdQmEYDoVocDCvnLCvnwPDMzOK/uiVoPS8IxoQi409D2xAU4Hd2xE2DZ3gjvcpVZY+0iqgAbFh7F9grp84xf5D6QFOE/rYo1vto4z6ZVg/COHKAiGJrACaljNHaiaqTp0NeXlr37Ydz/ahSLY9YzLIPMzlxSrxMzM/ochfnO8UHvJJpgTnm+UE5GKMeOu3LrLJPd32+Z1FamfczKli36jzTtHplvPg46o2WgNwEaOqoTk8Jxsu4+vGUruDkCCCJkg171g2ntqMkjrmuYUBwG7LglIq/U7Zr1HEjJrtiay9imIzsqt37gb4/RSZlSsP88iZf5T3kX2xOuBEck2yp13F32NbDuZbHqSjwFrzJbeP5eN6NHOJuoQyXRIZ7Y+3Gh08wohjpW/VOkFMyqagHILnOSAOuflh1bqKggew524Zs1ex+R6cmz1W7Z6clvzzF8T7rLsvnSfBgJVO9cN+ax4/IRwazZLZrqmOSWJjAR0hCdFc/F2AtToTos34POQHAkVw2Sp2m7EKwOEyLVj59w6EtpyjdFYSCCYhaC0n9fcmmr5pb8QBrQl0wqn/hNc82J8Rfc8lWVwVGwLeNDVPTdW30+KZN0Sab5JTBqOBBowIHzeZVJcBjXHdKXfQp93+DgwuIgy9QtqJ8evPhOtRRzZi30iKfBZPxQVNhofDP6sUXh05zA5MH+WKdpAgAJ/lAChqhyQmd5HgFChFoMvar0AaKq8qSGmA6o03lVFCEqx1Q0Ce0075hkgvW93EPNeMZ3Cl93eRl5Q8GVjoBs1tUN1l/rvkn1VOuNXUIAyATv6zz3bXPEo3t7N/L6bBirfV0MimktOclgnDUJHiTWxo9oJOZQT/TDUk0nIYfFODFaMMN4WFqbnEl8BzXtlBX++ATr2KW3eC9kbg/9d2l6/qmdxrq9bdRkBwMtrgd+lpkpxwyWSwAkvRKSfl0phf4l+6acGVeak6QQbCJYH/Gwci+zPi/+oMFEJpLdTDfQ8IpTTl8r/lkQuniX3oR98mjX65sJQZ0wYNu1NU0wZ8RjSUf0Qo22aCU1oAoCazTFe5bdZ1pVIqcv2B12XSm6awxCFNaichCr1I1auDOQFvKxzQHFD4mexGXNfds/PoYB+iMhxzwIC8vcJe7HKVIrBEoLRQkuVL+Ii70lDlMUOR/uHrJdNaAwXo82orksR8gfVUAGFkgy5JfhKdEKncelwhq8SinwMeidX+303VHuvOgCGSRRF2o6vb6FyKmQTGRNTraQt1qJ6EaAPA4V22MYH20wXx+aCyfKFvFAcymiYfCh/YhSQZACFHpBB/l6On2l0s/AgTBWdIHHbpIulzfWDbvAW4r3gPUIwWZ0lW6SoaE0AgDYG6Six0R4OjgWRMwGUAVHuUz+SS2iNQ+XSMAvKqzrLCemdtUo3ifWhpoTi7b/RSfVRH9zBc2y43umXVgtImf3R08c7zCIeYpVoPOtoh+ZjYEhd3kWtV4IHSldEjAV7U/ATHxig89Tx0QUFCtvUJisxnNknuHArSY4+xtNuk4ZQWai4wOBThJRqZJvhYXtptnNTVAHQnQYbT4k7QI6/Vd6w6f/U9h39cUgEg+BCG3rk/AHQ9wlhsz1IUCI3tRPrDVtdlhzO9rxPNke+nuXR0TUIdAMOrDlkJshwEM4QId98C8vKTmUUJHAwww03VNT8ny9hd/cJ9qCaU7QnrpjXvcsKuT6W7VdcvHc+sq95wDCuZILxp9t+TZJWVL/56PPdJzDhjDhG75UyUrsXXtBw9z/PjAObd3729leA++mTOldO07dyl9ghbmnALmYpjybndhO3/VV/dx9IQdlj53YQEAo2din3p1cv1VfDIF8EfvSdJQSZvU3ljGJJOvNuH94kOPs22jwWq3P5edTryG8G/OdtsxOPiZd6O1ppTeK0n43Hb/9yPuYBhPuFFXumEq3231S+ibL/e+yhtP2Zz+iD74hCu83vblr+W1yJ5LgguxmzedRu/8//AUSaqMTR1xAAAAAElFTkSuQmCC); - background-repeat: no-repeat; - background-position: center top 10px; -} - -.footer a { - color: #3b5c6b; -} - - -/* Main Menu - * Displayed in header, contains repository links. -––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ -.mainmenu { - clear:both; -} - -.mainmenu ul { - list-style: none outside; - display: block; - position: relative; - border-top: 1px solid #ccc; - padding: 0; -} - -.mainmenu li { - outline: 0; - display: block; - float: left; - margin: 0; -} - -.mainmenu li.active { - background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAAJCAYAAADU6McMAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEQAACxEBf2RfkQAAAAd0SU1FB90FDxEXAZ2XRzAAAABJSURBVCjPY2CgBzhz5sx/QmoYiTXAxMSEkWRDsLkAl0GMpHoBm0EoAlu3bmUQFxcnGAboBjEhc4gxAJtLGUmJBVwuYiTXAGSDAIx5IBObnuVxAAAAAElFTkSuQmCC); - background-repeat: no-repeat; - background-position: center bottom; -} - -.mainmenu li a { - color: #3b5c6b; - display: block; - padding: 10px 15px; -} - -.mainmenu li.active a { - font-weight: bold; -} - -.mainmenu li:hover { - background-color: #eee; -} - - -/* Submenu - * Displayed in the middle div. Contains page-specific form controls. -––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ -.submenu { - padding: 10px 0px; - border-bottom: 1px solid #ddd; -} - -.submenu input, .submenu select { - margin: 0 0 0 5px; -} - -.submenu a { - color: #3b5c6b; - padding: 5px 15px; - text-decoration: none; - border: 1px solid transparent; - border-radius: 5px; -} - -.submenu a:hover { - border: 1px solid #ccc; -} - - -/* Section - * Cap/header to distinguish a section. Displayed within a content div. -––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ -.section { - font-weight: bold; - background-color: #f5f5f5; - border: 1px solid #ccc; - padding: 9px 10px 10px; - margin: 10px 0; -} - - -/* Section Menu - * Div of buttons/links, displayed with a section div within a content div. -––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ -.sectionmenu { - border: 1px solid #ccc; - border-top: 0; - margin-top: -10px; - margin-bottom: 10px; - padding: 5px; - text-align: center; -} -.sectionmenu a { - display: inline-block; - margin-top: 5px; - margin-right: 1em; -} - - -/* File browser - * 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; - padding-top: 2px; -} - -ul.browser li.file { - background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QAVQBVAFV4xrLkAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3wMLExMaPfBcSgAAAFNJREFUOMvtkzEOwDAIA02VL5pHwiOTJZFQmkqFOTex+CwPCCYkAaDjB+4u65ZdYGafQVV9SR4kWQUke0mwS1o2HGcAQKs0R1lpQuQKruD4jVnBAG/cGRqf0U66AAAAAElFTkSuQmCC); - background-repeat: no-repeat; - background-position: 0px center; - padding-left: 22px; - padding-top: 2px; -} - -div.filetreeline { - display: table; - width: 100%; - white-space: nowrap; -} - -/* tree-view top-level list */ -.filetree > ul { - display: inline-block; -} - -/* tree-view lists */ -.filetree ul { - margin: 0; - padding: 0; - list-style: none; -} -/* tree-view collapsed list */ -.filetree ul.collapsed { - display: none; -} -/* tree-view lists below the root */ -.filetree ul ul { - position: relative; - margin: 0 0 0 21px; -} -/* tree-view lists items */ -.filetree li { - position: relative; - margin: 0; - padding: 0; -} -/* tree-view node lines */ -.filetree li li:before { - content: ''; - position: absolute; - top: -.8em; - left: -14px; - width: 16px; - height: 1.5em; - border-left: 1px solid #ccc; - border-bottom: 1px solid #ccc; -} -/* tree-view directory lines */ -.filetree li > ul:before { - content: ''; - position: absolute; - top: -1.5em; - bottom: 0; - left: -35px; - border-left: 1px solid #ccc; -} -/* hide lines for last-child directories */ -.filetree li.last > ul:before { - display: none; -} - -.filetree a { - position: relative; - z-index: 1; - display: table-cell; - min-height: 16px; - padding-left: 22px; - background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QAVQBVAFV4xrLkAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3wMLExMaPfBcSgAAAFNJREFUOMvtkzEOwDAIA02VL5pHwiOTJZFQmkqFOTex+CwPCCYkAaDjB+4u65ZdYGafQVV9SR4kWQUke0mwS1o2HGcAQKs0R1lpQuQKruD4jVnBAG/cGRqf0U66AAAAAElFTkSuQmCC); - background-position: center left; - background-repeat: no-repeat; -} - -.filetree .dir > div.filetreeline > a { - background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QAVQBVAFV4xrLkAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3wMLExABnLjGZQAAAEFJREFUOMtjYKAQMIaGhv4npGj16tWMuORYGBgYGOZW+eDUnNy2Ba/hLMQ4E58rCRpAyHVMlAbiqAGjBhCdmWgKAHp4Dh0ZusP3AAAAAElFTkSuQmCC); -} - - -/* Label-Value table - * Displayed on the Check-in & Admin pages. -––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ -table.label-value th { - vertical-align: middle; -} - - -/* Branches table -––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ -.brlist table td { - padding: 5px; -} - - -/* Timeline - * Displays chronologically-ordered check-ins with a branch graph. -––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ -tr.timelineCurrent { - border-left: 2px solid orange; - background-color: #ffc; -} - -tr.timelineSelected { - border-left: 2px solid orange; - background-color: #ffffe8; -} - -tr.timelineCurrent td.timelineTableCell { -} - -tr.timelineSpacer { -} - -div.timelineDate { - font-weight: bold; - white-space: nowrap; -} - -a.timelineHistLink { - text-transform: lowercase; -} - -span.timelineComment { - padding: 0px 5px; -} - - -/* Login/Loguot -––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ -table.login_out { -} - -table.login_out .login_out_label { - font-weight: 700; - text-align: right; -} - -table.login_out td { - border: 0; -} - - -/* Diff displays -––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ -pre.udiff, table.sbsdiffcols { - width: 100%; - overflow: auto; - border: 1px solid #ccc; - padding: 0px 5px; - font-size: 1rem; -} - -pre.udiff:focus, table.sbsdiffcols:focus { - outline: none; -} - - -/* Ticket Reports -––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ -table.report { - width: 100%; - cursor: auto; - border-radius: 4px; - border: 1px solid #ccc; - margin: 0 0 1em 0; -} - -.report td, .report th { - border: 0; - font-size: .9em; - padding: 5px; -} - -.report th { - cursor: pointer; -} - -.report thead+tbody tr:hover { - background-color: #f5f9fc !important; -} - - -/* Ticket page -––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ -table.tktDsp { - border-top: 1px solid #ccc; - border-left: 1px solid #ccc; - width: 100%; - margin: 15px 0px 10px 0px; -} - -td.tktDspLabel, td.tktDescLabel { - width: 70px; - text-align: right; - overflow: hidden; - font-weight: 700; - padding: 10px; - background-color: #f8f8f8; -} - -td.tktDescLabel { - vertical-align: top; -} - -td.tktDspValue, td.tktDescValue { - text-align: left; - vertical-align: top; - border: 1px solid #ccc; - padding: 10px; -} - -td.tktDspValue pre, td.tktDescValue pre, -td.tktDspValue code, td.tktDescValue code { - white-space: pre-wrap; -} - -div.tktComments { - width: 100%; - margin: 30px 0px 10px 0px; -} - -div.tktComment { -} - -div.tktCommentHeader { - border: 1px solid #ccc; - background-color: #f8f8f8; - padding: 10px 10px; - margin-bottom: 10px; -} - -span.tktCommentLogin { - display: inline-block; - font-weight: 700; - color: #002060; -} - -div.tktCommentBody { - margin: 10px 40px 30px; -} - - -/* User setup table -––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ -td.usetupEditLabel { - font-weight: 700; -} - - -/* Utilities -––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ -.full-width { - width: 100%; - box-sizing: border-box; -} - -.max-full-width { - max-width: 100%; - box-sizing: border-box; -} - -.pull-right { - float: right; -} - -.pull-left { - float: left; -} - -/* Clearing -––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ -.container:after, -.mainmenu:after, -.row:after, -.u-cf { - content: ""; - display: table; - clear: both; -} DELETED skins/blitz_no_logo/details.txt Index: skins/blitz_no_logo/details.txt ================================================================== --- skins/blitz_no_logo/details.txt +++ skins/blitz_no_logo/details.txt @@ -1,4 +0,0 @@ -timeline-arrowheads: 0 -timeline-circle-nodes: 1 -timeline-color-graph-lines: 1 -white-foreground: 0 DELETED skins/blitz_no_logo/footer.txt Index: skins/blitz_no_logo/footer.txt ================================================================== --- skins/blitz_no_logo/footer.txt +++ skins/blitz_no_logo/footer.txt @@ -1,12 +0,0 @@ - </div> <!-- end div container --> - </div> <!-- end div middle max-full-width --> - <div class="footer"> - <div class="container"> - <div class="pull-right"> - <a href="http://fossil-scm.org">Fossil version $manifest_version $manifest_date</a> - </div> - This page was generated in about <th1>puts [expr {([utime]+[stime]+1000)/1000*0.001}]</th1>s - </div> - </div> - </body> -</html> DELETED skins/blitz_no_logo/header.txt Index: skins/blitz_no_logo/header.txt ================================================================== --- skins/blitz_no_logo/header.txt +++ skins/blitz_no_logo/header.txt @@ -1,77 +0,0 @@ -<html> - <head> - <base href="$baseurl/$current_page" /> - <title>$<project_name>: $<title> - - - - - -
-
- - -
-

$ - - if {[anycap jor]} { - html "" - } - -  $</small></h1> - </div> - - <!-- Main Menu --> - <div class="mainmenu"> - <ul> - <th1> -proc menulink {url name} { - upvar current_page current - upvar home home - if {[string range $url 0 [string length $current]] eq "/$current"} { - html "<li class='active'>" - } else { - html "<li>" - } - html "<a href='$home$url'>$name</a></li>\n" -} -menulink $index_page Home -if {[anycap jor]} { - menulink /timeline Timeline -} -if {[hascap oh]} { - menulink /dir?ci=tip Files -} -if {[hascap o]} { - menulink /brlist Branches - menulink /taglist Tags -} -if {[hascap r]} { - menulink /ticket Tickets -} -if {[hascap j]} { - menulink /wiki Wiki -} -if {[hascap o]} { - menulink /help Help - } -if {[hascap s]} { - menulink /setup Admin -} elseif {[hascap a]} { - menulink /setup_ulist Users -} - </th1> - </ul> - </div> <!-- end div mainmenu --> - </div> <!-- end div container --> - </div> <!-- end div header --> - <div class="middle max-full-width"> - <div class="container"> DELETED skins/blitz_no_logo/ticket.txt Index: skins/blitz_no_logo/ticket.txt ================================================================== --- skins/blitz_no_logo/ticket.txt +++ skins/blitz_no_logo/ticket.txt @@ -1,115 +0,0 @@ -<h4>$<title></h4> -<table class="tktDsp"> -<tr><td class="tktDspLabel">Ticket UUID</td> -<th1> -if {[info exists tkt_uuid]} { - if {[hascap s]} { - html "<td class='tktDspValue' colspan='3'>$tkt_uuid " - html "($tkt_id)</td></tr>\n" - } else { - html "<td class='tktDspValue' colspan='3'>$tkt_uuid</td></tr>\n" - } -} else { - if {[hascap s]} { - html "<td class='tktDspValue' colspan='3'>Deleted " - html "(0)</td></tr>\n" - } else { - html "<td class='tktDspValue' colspan='3'>Deleted</td></tr>\n" - } -} -</th1> -<tr><td class="tktDspLabel">Status</td><td class="tktDspValue"> -$<status> -</td> -<td class="tktDspLabel">Type</td><td class="tktDspValue"> -$<type> -</td></tr> -<tr><td class="tktDspLabel">Severity</td><td class="tktDspValue"> -$<severity> -</td> -<td class="tktDspLabel">Priority</td><td class="tktDspValue"> -$<priority> -</td></tr> -<tr><td class="tktDspLabel">Subsystem</td><td class="tktDspValue"> -$<subsystem> -</td> -<td class="tktDspLabel">Resolution</td><td class="tktDspValue"> -$<resolution> -</td></tr> -<tr><td class="tktDspLabel">Last Modified</td><td class="tktDspValue"> -<th1> -if {[info exists tkt_datetime]} { - html $tkt_datetime -} -</th1> -</td> -<th1>enable_output [hascap e]</th1> - <td class="tktDspLabel">Contact</td><td class="tktDspValue"> - $<private_contact> - </td> -<th1>enable_output 1</th1> -</tr> -<tr><td class="tktDspLabel">Version Found In</td> -<td colspan="3" valign="top" class="tktDspValue"> -$<foundin> -</td></tr> - -<th1> -if {[info exists comment]} { - if {[string length $comment]>10} { - html { - <tr> - <td class="tktDescLabel">Description</td> - <td class="tktDescValue" colspan="3"> - } - if {[info exists plaintext]} { - set r [randhex] - wiki "<verbatim-$r links>\n$comment\n</verbatim-$r>" - } else { - wiki $comment - } - html "</td></tr>\n" - } -} -</th1> -</table> - -<div class="tktComments"> -<th1> -set seenRow 0 -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 eq "0"} { - html "<h5>User Comments</h5>\n" - set seenRow 1 - } - html "<div class='tktComment'>\n" - html "<div class='tktCommentHeader'>\n" - html "<div class='pull-right'>$xdate</div>\n" - html "<span class='tktCommentLogin'>[htmlize $xlogin]</span>" - if {$xlogin ne $xusername && [string length $xusername]>0} { - html " (claiming to be <span class='tktCommentLogin'>[htmlize $xusername]</span>)" - } - html " commented</div>\n" - html "<div class='tktCommentBody'>\n" - if {$alwaysPlaintext || $xmimetype eq "text/plain"} { - set r [randhex] - if {$xmimetype ne "text/plain"} {html "([htmlize $xmimetype])\n"} - wiki "<verbatim-$r>[string trimright $xcomment]</verbatim-$r>\n" - } elseif {$xmimetype eq "text/x-fossil-wiki"} { - wiki "<p>\n[string trimright $xcomment]\n</p>\n" - } elseif {$xmimetype eq "text/html"} { - wiki "<p><nowiki>\n[string trimright $xcomment]\n</nowiki></p>\n" - } else { - set r [randhex] - wiki "<verbatim-$r links>[string trimright $xcomment]</verbatim-$r>\n" - } - html "</div><!-- end comment body -->\n" - html "</div><!-- end comment -->\n" -} -</th1> -</div> DELETED skins/default/README.md Index: skins/default/README.md ================================================================== --- skins/default/README.md +++ skins/default/README.md @@ -1,5 +0,0 @@ -This skin was contributed by Étienne Deparis. - -On 2015-03-14 this skin was promoted from an option to the default, which -involved moving it from its original home in the skins/etienne1 directory -into skins/default. DELETED skins/default/css.txt Index: skins/default/css.txt ================================================================== --- skins/default/css.txt +++ skins/default/css.txt @@ -1,200 +0,0 @@ -body { - margin: 0 auto; - min-width: 800px; - padding: 0px 20px; - background-color: white; - font-family: sans-serif; - font-size:14pt; - -moz-text-size-adjust: none; - -webkit-text-size-adjust: none; - -mx-text-size-adjust: none; -} - -a { - color: #4183C4; - text-decoration: none; -} -a:hover { - color: #4183C4; - text-decoration: underline; -} - -hr { - color: #eee; -} - -.title { - color: #4183C4; - float:left; - padding-top: 30px; - padding-bottom: 10px; -} -.title h1 { - display:inline; -} -.title h1:after { - content: " / "; - color: #777; - font-weight: normal; -} - -.content h1 { - font-size: 1.25em; -} -.content h2 { - font-size: 1.15em; -} -.content h2 { - font-size: 1.05em; - font-weight: bold; -} - -.section { - font-size: 1em; - font-weight: bold; - background-color: #f5f5f5; - border: 1px solid #d8d8d8; - border-radius: 3px 3px 0 0; - padding: 9px 10px 10px; - margin: 10px 0; -} - -.sectionmenu { - border: 1px solid #d8d8d8; - border-radius: 0 0 3px 3px; - border-top: 0; - margin-top: -10px; - margin-bottom: 10px; - padding: 10px; -} -.sectionmenu a { - display: inline-block; - margin-right: 1em; -} - -.status { - float:right; - font-size:.7em; - padding-top:50px; -} - -.mainmenu { - font-size:.8em; - clear:both; - padding:10px; - background:#eaeaea linear-gradient(#fafafa, #eaeaea) repeat-x; - border:1px solid #eaeaea; - border-radius:5px; -} - -.mainmenu a { - padding: 10px 20px; - text-decoration:none; - color: #777; - border-right:1px solid #eaeaea; -} -.mainmenu a.active, -.mainmenu a:hover { - color: #000; - border-bottom:2px solid #D26911; -} - -.submenu { - font-size: .7em; - margin-top: 10px; - padding: 10px; - border-bottom: 1px solid #ccc; -} - -.submenu a { - padding: 10px 11px; - text-decoration:none; - color: #777; -} - -.submenu a:hover { - padding: 6px 10px; - border: 1px solid #ccc; - border-radius: 5px; - color: #000; -} - -.content { - padding-top: 10px; - font-size:.8em; - color: #444; -} - -.udiff, .sbsdiff { - font-size: .85em !important; - overflow: auto; - border: 1px solid #ccc; - border-radius: 5px; -} -.content blockquote { - padding: 0 15px; -} - -table.report { - cursor: auto; - border-radius: 5px; - border: 1px solid #ccc; - margin: 1em 0; -} -.report td, .report th { - border: 0; - font-size: .8em; - padding: 10px; -} -.report td:first-child { - border-top-left-radius: 5px; -} -.report tbody tr:last-child td:first-child { - border-bottom-left-radius: 5px; -} -.report td:last-child { - border-top-right-radius: 5px; -} -.report tbody tr:last-child { - border-bottom-left-radius: 5px; - border-bottom-right-radius: 5px; -} -.report tbody tr:last-child td:last-child { - border-bottom-right-radius: 5px; -} -.report th { - cursor: pointer; -} -.report thead+tbody tr:hover { - background-color: #f5f9fc !important; -} - -td.tktDspLabel { - width: 70px; - text-align: right; - overflow: hidden; -} -td.tktDspValue { - text-align: left; - vertical-align: top; - background-color: #f8f8f8; - border: 1px solid #ccc; -} -td.tktDspValue pre { - white-space: pre-wrap; -} - -.footer { - border-top: 1px solid #ccc; - padding: 10px; - font-size:.7em; - margin-top: 10px; - color: #ccc; -} -div.timelineDate { - font-weight: bold; - white-space: nowrap; -} -span.submenuctrl, span.submenuctrl input, select.submenuctrl { - color: #777; -} DELETED skins/default/details.txt Index: skins/default/details.txt ================================================================== --- skins/default/details.txt +++ skins/default/details.txt @@ -1,4 +0,0 @@ -timeline-arrowheads: 1 -timeline-circle-nodes: 0 -timeline-color-graph-lines: 0 -white-foreground: 0 DELETED skins/default/footer.txt Index: skins/default/footer.txt ================================================================== --- skins/default/footer.txt +++ skins/default/footer.txt @@ -1,6 +0,0 @@ -<div class="footer"> -This page was generated in about -<th1>puts [expr {([utime]+[stime]+1000)/1000*0.001}]</th1>s by -Fossil version $manifest_version $manifest_date -</div> -</body></html> DELETED skins/default/header.txt Index: skins/default/header.txt ================================================================== --- skins/default/header.txt +++ skins/default/header.txt @@ -1,56 +0,0 @@ -<html> - <head> - <base href="$baseurl/$current_page" /> - <title>$<project_name>: $<title> - - - - - -
-

$

$</div> - <div class="status"><th1> - if {[info exists login]} { - html "$login — <a href='$home/login'>Logout</a>\n" - } else { - html "<a href='$home/login'>Login</a>\n" - } - </th1></div> - </div> - - <div class="mainmenu"> -<th1> -proc menulink {url name} { - upvar current_page current - upvar home home - if {[string range $url 0 [string length $current]] eq "/$current"} { - html "<a href='$home$url' class='active'>$name</a>\n" - } else { - html "<a href='$home$url'>$name</a>\n" - } -} -menulink $index_page Home -if {[anycap jor]} { - menulink /timeline Timeline -} -if {[hascap oh]} { - menulink /dir?ci=tip Files -} -if {[hascap o]} { - menulink /brlist Branches - menulink /taglist Tags -} -if {[hascap r]} { - menulink /ticket Tickets -} -if {[hascap j]} { - menulink /wiki Wiki -} -if {[hascap s]} { - menulink /setup Admin -} elseif {[hascap a]} { - menulink /setup_ulist Users -} -</th1></div> DELETED skins/eagle/README.md Index: skins/eagle/README.md ================================================================== --- skins/eagle/README.md +++ skins/eagle/README.md @@ -1,4 +0,0 @@ -For this skin to look exactly as it was intended to, the **white-foreground** -setting should be enabled. - -This skin was contributed by Joe Mistachkin. DELETED skins/eagle/css.txt Index: skins/eagle/css.txt ================================================================== --- skins/eagle/css.txt +++ skins/eagle/css.txt @@ -1,291 +0,0 @@ -/* General settings for the entire page */ -body { - margin: 0ex 1ex; - padding: 0px; - background-color: #485D7B; - font-family: sans-serif; - color: white; - -moz-text-size-adjust: none; - -webkit-text-size-adjust: none; - -mx-text-size-adjust: none; -} - -/* The project logo in the upper left-hand corner of each page */ -div.logo { - display: table-cell; - text-align: center; - vertical-align: bottom; - font-weight: bold; - color: white; - padding: 5 0 5 0em; - white-space: nowrap; -} - -/* The page title centered at the top of each page */ -div.title { - display: table-cell; - font-size: 2em; - font-weight: bold; - text-align: left; - padding: 0 0 0 1em; - color: white; - vertical-align: bottom; - width: 100%; -} - -/* The login status message in the top right-hand corner */ -div.status { - display: table-cell; - text-align: right; - vertical-align: bottom; - color: white; - font-size: 0.8em; - font-weight: bold; - min-width: 200px; - white-space: nowrap; -} - -/* The header across the top of the page */ -div.header { - display: table; - width: 100%; -} - -/* The main menu bar that appears at the top of the page beneath -** the header */ -div.mainmenu { - padding: 5px 10px 5px 10px; - font-size: 0.9em; - font-weight: bold; - text-align: center; - letter-spacing: 1px; - background-color: #76869D; - border-top-left-radius: 8px; - border-top-right-radius: 8px; - color: white; -} - -/* The submenu bar that *sometimes* appears below the main menu */ -div.submenu, div.sectionmenu { - padding: 3px 10px 3px 0px; - font-size: 0.9em; - font-weight: bold; - text-align: center; - background-color: #485D7B; - color: white; -} -div.mainmenu a, div.mainmenu a:visited, div.submenu a, div.submenu a:visited, -div.sectionmenu>a.button:link, div.sectionmenu>a.button:visited { - padding: 3px 10px 3px 10px; - color: white; - text-decoration: none; -} -div.mainmenu a:hover, div.submenu a:hover, div.sectionmenu>a.button:hover { - text-decoration: underline; -} - -/* All page content from the bottom of the menu or submenu down to -** the footer */ -div.content { - padding: 0ex 1ex 0ex 2ex; -} - -/* Some pages have section dividers */ -div.section { - margin-bottom: 0px; - margin-top: 1em; - padding: 1px 1px 1px 1px; - font-size: 1.2em; - font-weight: bold; - background-color: #485D7B; - color: white; - white-space: nowrap; -} - -/* The "Date" that occurs on the left hand side of timelines */ -div.divider { - background: #9DB0CC; - color: white; - border: 2px white solid; - font-size: 1em; font-weight: normal; - padding: .25em; - margin: .2em 0 .2em 0; - float: left; - clear: left; - white-space: nowrap; -} - -/* The footer at the very bottom of the page */ -div.footer { - clear: both; - font-size: 0.8em; - margin-top: 12px; - padding: 5px 10px 5px 10px; - text-align: right; - background-color: #485D7B; - border-bottom-left-radius: 8px; - border-bottom-right-radius: 8px; - color: white; -} - -/* Hyperlink colors in the footer */ -a { color: white; } -a:link { color: white; } -a:visited { color: white; } -a:hover { color: #9DB0CC; } - -/* verbatim blocks */ -pre.verbatim { - background-color: #485D7B; - color: white; - padding: 0.5em; - white-space: pre-wrap; -} - -/* The label/value pairs on (for example) the ci page */ -table.label-value th { - vertical-align: top; - text-align: right; - padding: 0.2ex 2ex; -} - -/* The nomenclature sidebox for branches,.. */ -div.sidebox { - float: right; - background-color: #485D7B; - border-width: medium; - border-style: double; - margin: 10px; -} - -/* the format for the timeline data table */ -table.timelineTable { - cellspacing: 0; - border: 0; - cellpadding: 0; - font-family: "courier new"; - border-collapse: collapse; -} - -tr.timelineSelected { - background-color: #7EA2D9; -} - -/* Side-by-side diff */ -table.sbsdiff { - background-color: #485D7B; - font-family: fixed, Dejavu Sans Mono, Monaco, Lucida Console, monospace; - font-size: 8pt; - border-collapse:collapse; - white-space: pre; - width: 98%; - border: 1px #000 dashed; - margin-left: auto; - margin-right: auto; -} - -/* format for the layout table, used for the captcha display */ -table.captcha { - margin: auto; - padding: 10px; - border-width: 4px; - border-style: double; - border-color: white; -} - -/* format for the user list table on the user setup page */ -table.usetupUserList { - outline-style: double; - outline-width: 1px; - outline-color: white; - padding: 10px; -} - -/* color for capabilities, inherited by reader */ -span.ueditInheritReader { - color: white; -} - -/* format for values on ticket display page */ -td.tktDspValue { - text-align: left; - vertical-align: top; - background-color: #485D7B; -} - -/* format for example table cells on the report edit page */ -td.rpteditex { - border-width: thin; - border-color: white; - border-style: solid; -} - -/* List of files in a timeline */ -ul.filelist { - margin-top: 3px; - line-height: 100%; -} - -/* side-by-side diff display */ -div.sbsdiff { - font-family: monospace; - font-size: smaller; - white-space: pre; -} - -/* context diff display */ -div.udiff { - font-family: monospace; - white-space: pre; -} - -/* changes in a diff */ -span.diffchng { - background-color: rgb(170, 170, 140); -} - -/* added code in a diff */ -span.diffadd { - background-color: rgb(100, 200, 100); -} - -/* deleted in a diff */ -span.diffrm { - background-color: rgb(230, 110, 110); -} - -/* suppressed lines in a diff */ -span.diffhr { - display: inline-block; - margin: .5em 0 1em; - color: rgb(150, 150, 140); -} - -/* line numbers in a diff */ -span.diffln { - color: white; -} - -#canvas { - background-color: #485D7B; -} - -.fileage tr:hover { - background-color: #7EA2D9; -} - -.fileage td { - font-family: "courier new"; -} - -div.filetreeline:hover { - background-color: #7EA2D9; -} - -div.selectedText { - background-color: #7EA2D9; -} - -.statistics-report-graph-line { - background-color: #7EA2D9; -} DELETED skins/eagle/details.txt Index: skins/eagle/details.txt ================================================================== --- skins/eagle/details.txt +++ skins/eagle/details.txt @@ -1,4 +0,0 @@ -timeline-arrowheads: 1 -timeline-circle-nodes: 0 -timeline-color-graph-lines: 0 -white-foreground: 1 DELETED skins/eagle/footer.txt Index: skins/eagle/footer.txt ================================================================== --- skins/eagle/footer.txt +++ skins/eagle/footer.txt @@ -1,25 +0,0 @@ -<div class="footer"> - <th1> - proc getTclVersion {} { - if {[catch {tclEval info patchlevel} tclVersion] == 0} { - return "<a href=\"http://www.tcl.tk/\">Tcl</a> version $tclVersion" - } - return "" - } - proc getVersion { version } { - set length [string length $version] - return [string range $version 1 [expr {$length - 2}]] - } - set version [getVersion $manifest_version] - set tclVersion [getTclVersion] - set fossilUrl https://www.fossil-scm.org - set fossilDate [string range $manifest_date 0 9]T[string range $manifest_date 11 end] - </th1> - This page was generated in about - <th1>puts [expr {([utime]+[stime]+1000)/1000*0.001}]</th1>s by - <a href="$fossilUrl/">Fossil</a> - version $release_version $tclVersion - <a href="$fossilUrl/index.html/info/$version">$manifest_version</a> - <a href="$fossilUrl/index.html/timeline?c=$fossilDate&y=ci">$manifest_date</a> -</div> -</body></html> DELETED skins/eagle/header.txt Index: skins/eagle/header.txt ================================================================== --- skins/eagle/header.txt +++ skins/eagle/header.txt @@ -1,138 +0,0 @@ -<html> -<head> -<base href="$baseurl/$current_page" /> -<title>$<project_name>: $<title> - - - - -
- -
$</div> - <div class="status"><nobr><th1> - if {[info exists login]} { - puts "Logged in as $login" - } else { - puts "Not logged in" - } - </th1></nobr><small><div id="clock"></div></small></div> -</div> -<script> -function updateClock(){ - var e = document.getElementById("clock"); - if(e){ - var d = new Date(); - function f(n) { - return n < 10 ? '0' + n : n; - } - e.innerHTML = d.getUTCFullYear()+ '-' + - f(d.getUTCMonth() + 1) + '-' + - f(d.getUTCDate()) + ' ' + - f(d.getUTCHours()) + ':' + - f(d.getUTCMinutes()); - setTimeout("updateClock();",(60-d.getUTCSeconds())*1000); - } -} -updateClock(); -</script> -<div class="mainmenu"> -<th1> -proc menulink {url name} { - upvar home home - html "<a href='$home$url'>$name</a>\n" -} -menulink $index_page Home -menulink /help Help -if {[anycap jor]} { - menulink /timeline Timeline -} -if {[anoncap oh]} { - menulink /dir?ci=tip Files -} -if {[anoncap o]} { - menulink /brlist Branches - menulink /taglist Tags -} -if {[anoncap r]} { - menulink /ticket Tickets -} -if {[anoncap j]} { - menulink /wiki Wiki -} -if {[hascap s]} { - menulink /setup Admin -} elseif {[hascap a]} { - menulink /setup_ulist Users -} -if {[info exists login]} { - menulink /login Logout -} else { - menulink /login Login -} -</th1></div> DELETED skins/enhanced1/css.txt Index: skins/enhanced1/css.txt ================================================================== --- skins/enhanced1/css.txt +++ skins/enhanced1/css.txt @@ -1,148 +0,0 @@ -/* General settings for the entire page */ -body { - margin: 0ex 1ex; - padding: 0px; - background-color: white; - font-family: sans-serif; - -moz-text-size-adjust: none; - -webkit-text-size-adjust: none; - -mx-text-size-adjust: none; -} - -/* The project logo in the upper left-hand corner of each page */ -div.logo { - display: table-cell; - text-align: center; - vertical-align: bottom; - font-weight: bold; - color: #558195; - min-width: 200px; - white-space: nowrap; -} - -/* The page title centered at the top of each page */ -div.title { - display: table-cell; - font-size: 2em; - font-weight: bold; - text-align: center; - padding: 0 0 0 1em; - color: #558195; - vertical-align: bottom; - width: 100%; -} - -/* The login status message in the top right-hand corner */ -div.status { - display: table-cell; - text-align: right; - vertical-align: bottom; - color: #558195; - font-size: 0.8em; - font-weight: bold; - min-width: 200px; - white-space: nowrap; -} - -/* The header across the top of the page */ -div.header { - display: table; - width: 100%; -} - -/* The main menu bar that appears at the top of the page beneath -** the header */ -div.mainmenu { - padding: 5px 10px 5px 10px; - font-size: 0.9em; - font-weight: bold; - text-align: center; - letter-spacing: 1px; - background-color: #558195; - border-top-left-radius: 8px; - border-top-right-radius: 8px; - color: white; -} - -/* The submenu bar that *sometimes* appears below the main menu */ -div.submenu, div.sectionmenu { - padding: 3px 10px 3px 0px; - font-size: 0.9em; - text-align: center; - background-color: #456878; - color: white; -} -div.mainmenu a, div.mainmenu a:visited, div.submenu a, div.submenu a:visited, -div.sectionmenu>a.button:link, div.sectionmenu>a.button:visited { - padding: 3px 10px 3px 10px; - color: white; - text-decoration: none; -} -div.mainmenu a:hover, div.submenu a:hover, div.sectionmenu>a.button:hover { - color: #558195; - background-color: white; -} - -/* All page content from the bottom of the menu or submenu down to -** the footer */ -div.content { - padding: 0ex 1ex 1ex 1ex; - border: solid #aaa; - border-width: 1px; -} - -/* Some pages have section dividers */ -div.section { - margin-bottom: 0px; - margin-top: 1em; - padding: 1px 1px 1px 1px; - font-size: 1.2em; - font-weight: bold; - background-color: #558195; - color: white; - white-space: nowrap; -} - -/* The "Date" that occurs on the left hand side of timelines */ -div.divider { - background: #a1c4d4; - border: 2px #558195 solid; - font-size: 1em; font-weight: normal; - padding: .25em; - margin: .2em 0 .2em 0; - float: left; - clear: left; - white-space: nowrap; -} - -/* The footer at the very bottom of the page */ -div.footer { - clear: both; - font-size: 0.8em; - padding: 5px 10px 5px 10px; - text-align: right; - background-color: #558195; - border-bottom-left-radius: 8px; - border-bottom-right-radius: 8px; - color: white; -} - -/* Hyperlink colors in the footer */ -div.footer a { color: white; } -div.footer a:link { color: white; } -div.footer a:visited { color: white; } -div.footer a:hover { background-color: white; color: #558195; } - -/* verbatim blocks */ -pre.verbatim { - background-color: #f5f5f5; - padding: 0.5em; - white-space: pre-wrap; -} - -/* The label/value pairs on (for example) the ci page */ -table.label-value th { - vertical-align: top; - text-align: right; - padding: 0.2ex 2ex; -} DELETED skins/enhanced1/details.txt Index: skins/enhanced1/details.txt ================================================================== --- skins/enhanced1/details.txt +++ skins/enhanced1/details.txt @@ -1,4 +0,0 @@ -timeline-arrowheads: 1 -timeline-circle-nodes: 0 -timeline-color-graph-lines: 0 -white-foreground: 0 DELETED skins/enhanced1/footer.txt Index: skins/enhanced1/footer.txt ================================================================== --- skins/enhanced1/footer.txt +++ skins/enhanced1/footer.txt @@ -1,25 +0,0 @@ -<div class="footer"> - <th1> - proc getTclVersion {} { - if {[catch {tclEval info patchlevel} tclVersion] == 0} { - return "<a href=\"http://www.tcl.tk/\">Tcl</a> version $tclVersion" - } - return "" - } - proc getVersion { version } { - set length [string length $version] - return [string range $version 1 [expr {$length - 2}]] - } - set version [getVersion $manifest_version] - set tclVersion [getTclVersion] - set fossilUrl https://www.fossil-scm.org - set fossilDate [string range $manifest_date 0 9]T[string range $manifest_date 11 end] - </th1> - This page was generated in about - <th1>puts [expr {([utime]+[stime]+1000)/1000*0.001}]</th1>s by - <a href="$fossilUrl/">Fossil</a> - version $release_version $tclVersion - <a href="$fossilUrl/index.html/info/$version">$manifest_version</a> - <a href="$fossilUrl/index.html/timeline?c=$fossilDate&y=ci">$manifest_date</a> -</div> -</body></html> DELETED skins/enhanced1/header.txt Index: skins/enhanced1/header.txt ================================================================== --- skins/enhanced1/header.txt +++ skins/enhanced1/header.txt @@ -1,138 +0,0 @@ -<html> -<head> -<base href="$baseurl/$current_page" /> -<title>$<project_name>: $<title> - - - - -
- -
$</div> - <div class="status"><th1> - if {[info exists login]} { - puts "Logged in as $login" - } else { - puts "Not logged in" - } - </th1></nobr><small><div id="clock"></div></small></div> -</div> -<script> -function updateClock(){ - var e = document.getElementById("clock"); - if(e){ - var d = new Date(); - function f(n) { - return n < 10 ? '0' + n : n; - } - e.innerHTML = d.getUTCFullYear()+ '-' + - f(d.getUTCMonth() + 1) + '-' + - f(d.getUTCDate()) + ' ' + - f(d.getUTCHours()) + ':' + - f(d.getUTCMinutes()); - setTimeout("updateClock();",(60-d.getUTCSeconds())*1000); - } -} -updateClock(); -</script> -<div class="mainmenu"> -<th1> -proc menulink {url name} { - upvar home home - html "<a href='$home$url'>$name</a>\n" -} -menulink $index_page Home -menulink /help Help -if {[anycap jor]} { - menulink /timeline Timeline -} -if {[anoncap oh]} { - menulink /dir?ci=tip Files -} -if {[anoncap o]} { - menulink /brlist Branches - menulink /taglist Tags -} -if {[anoncap r]} { - menulink /ticket Tickets -} -if {[anoncap j]} { - menulink /wiki Wiki -} -if {[hascap s]} { - menulink /setup Admin -} elseif {[hascap a]} { - menulink /setup_ulist Users -} -if {[info exists login]} { - menulink /login Logout -} else { - menulink /login Login -} -</th1></div> DELETED skins/khaki/css.txt Index: skins/khaki/css.txt ================================================================== --- skins/khaki/css.txt +++ skins/khaki/css.txt @@ -1,146 +0,0 @@ -/* General settings for the entire page */ -body { - margin: 0ex 0ex; - padding: 0px; - background-color: #fef3bc; - font-family: sans-serif; - -moz-text-size-adjust: none; - -webkit-text-size-adjust: none; - -mx-text-size-adjust: none; -} - -/* The project logo in the upper left-hand corner of each page */ -div.logo { - display: inline; - text-align: center; - vertical-align: bottom; - font-weight: bold; - font-size: 2.5em; - color: #a09048; - white-space: nowrap; -} - -/* The page title centered at the top of each page */ -div.title { - display: table-cell; - font-size: 2em; - font-weight: bold; - text-align: left; - padding: 0 0 0 5px; - color: #a09048; - vertical-align: bottom; - width: 100%; -} - -/* The login status message in the top right-hand corner */ -div.status { - display: table-cell; - text-align: right; - vertical-align: bottom; - color: #a09048; - padding: 5px 5px 0 0; - font-size: 0.8em; - font-weight: bold; - white-space: nowrap; -} - -/* The header across the top of the page */ -div.header { - display: table; - width: 100%; -} - -/* The main menu bar that appears at the top of the page beneath -** the header */ -div.mainmenu { - padding: 5px 10px 5px 10px; - font-size: 0.9em; - font-weight: bold; - text-align: center; - letter-spacing: 1px; - background-color: #a09048; - color: black; -} - -/* The submenu bar that *sometimes* appears below the main menu */ -div.submenu, div.sectionmenu { - padding: 3px 10px 3px 0px; - font-size: 0.9em; - text-align: center; - background-color: #c0af58; - color: white; -} -div.mainmenu a, div.mainmenu a:visited, div.submenu a, div.submenu a:visited, -div.sectionmenu>a.button:link, div.sectionmenu>a.button:visited { - padding: 3px 10px 3px 10px; - color: white; - text-decoration: none; -} -div.mainmenu a:hover, div.submenu a:hover, div.sectionmenu>a.button:hover { - color: #a09048; - background-color: white; -} - -/* All page content from the bottom of the menu or submenu down to -** the footer */ -div.content { - padding: 1ex 5px; -} -div.content a { color: #706532; } -div.content a:link { color: #706532; } -div.content a:visited { color: #704032; } -div.content a:hover { background-color: white; color: #706532; } - -/* Some pages have section dividers */ -div.section { - margin-bottom: 0px; - margin-top: 1em; - padding: 3px 3px 0 3px; - font-size: 1.2em; - font-weight: bold; - background-color: #a09048; - color: white; - white-space: nowrap; -} - -/* The "Date" that occurs on the left hand side of timelines */ -div.divider { - background: #e1d498; - border: 2px #a09048 solid; - font-size: 1em; font-weight: normal; - padding: .25em; - margin: .2em 0 .2em 0; - float: left; - clear: left; - white-space: nowrap; -} - -/* The footer at the very bottom of the page */ -div.footer { - font-size: 0.8em; - margin-top: 12px; - padding: 5px 10px 5px 10px; - text-align: right; - background-color: #a09048; - color: white; -} - -/* Hyperlink colors */ -div.footer a { color: white; } -div.footer a:link { color: white; } -div.footer a:visited { color: white; } -div.footer a:hover { background-color: white; color: #558195; } - -/* <verbatim> blocks */ -pre.verbatim { - background-color: #f5f5f5; - padding: 0.5em; - white-space: pre-wrap; -} - -/* The label/value pairs on (for example) the ci page */ -table.label-value th { - vertical-align: top; - text-align: right; - padding: 0.2ex 2ex; -} DELETED skins/khaki/details.txt Index: skins/khaki/details.txt ================================================================== --- skins/khaki/details.txt +++ skins/khaki/details.txt @@ -1,4 +0,0 @@ -timeline-arrowheads: 1 -timeline-circle-nodes: 0 -timeline-color-graph-lines: 0 -white-foreground: 0 DELETED skins/khaki/footer.txt Index: skins/khaki/footer.txt ================================================================== --- skins/khaki/footer.txt +++ skins/khaki/footer.txt @@ -1,4 +0,0 @@ -<div class="footer"> -Fossil version $manifest_version $manifest_date -</div> -</body></html> DELETED skins/khaki/header.txt Index: skins/khaki/header.txt ================================================================== --- skins/khaki/header.txt +++ skins/khaki/header.txt @@ -1,52 +0,0 @@ -<html> -<head> -<base href="$baseurl/$current_page" /> -<title>$<project_name>: $<title> - - - - -
-
$</div> - <div class="status"> - <div class="logo">$<project_name></div><br/> - <th1> - if {[info exists login]} { - puts "Logged in as $login" - } else { - puts "Not logged in" - } - </th1></div> -</div> -<div class="mainmenu"> -<th1> -html "<a href='$home$index_page'>Home</a>\n" -if {[anycap jor]} { - html "<a href='$home/timeline'>Timeline</a>\n" -} -if {[anoncap oh]} { - html "<a href='$home/tree?ci=tip'>Files</a>\n" -} -if {[anoncap o]} { - html "<a href='$home/brlist'>Branches</a>\n" - html "<a href='$home/taglist'>Tags</a>\n" -} -if {[anoncap r]} { - html "<a href='$home/ticket'>Tickets</a>\n" -} -if {[anoncap j]} { - html "<a href='$home/wiki'>Wiki</a>\n" -} -if {[hascap s]} { - html "<a href='$home/setup'>Admin</a>\n" -} elseif {[hascap a]} { - html "<a href='$home/setup_ulist'>Users</a>\n" -} -if {[info exists login]} { - html "<a href='$home/login'>Logout</a>\n" -} else { - html "<a href='$home/login'>Login</a>\n" -} -</th1></div> DELETED skins/original/css.txt Index: skins/original/css.txt ================================================================== --- skins/original/css.txt +++ skins/original/css.txt @@ -1,148 +0,0 @@ -/* General settings for the entire page */ -body { - margin: 0ex 1ex; - padding: 0px; - background-color: white; - font-family: sans-serif; - -moz-text-size-adjust: none; - -webkit-text-size-adjust: none; - -mx-text-size-adjust: none; -} - -/* The project logo in the upper left-hand corner of each page */ -div.logo { - display: table-cell; - text-align: center; - vertical-align: bottom; - font-weight: bold; - color: #558195; - min-width: 200px; - white-space: nowrap; -} - -/* The page title centered at the top of each page */ -div.title { - display: table-cell; - font-size: 2em; - font-weight: bold; - text-align: center; - padding: 0 0 0 1em; - color: #558195; - vertical-align: bottom; - width: 100%; -} - -/* The login status message in the top right-hand corner */ -div.status { - display: table-cell; - text-align: right; - vertical-align: bottom; - color: #558195; - font-size: 0.8em; - font-weight: bold; - min-width: 200px; - white-space: nowrap; -} - -/* The header across the top of the page */ -div.header { - display: table; - width: 100%; -} - -/* The main menu bar that appears at the top of the page beneath -** the header */ -div.mainmenu { - padding: 5px 10px 5px 10px; - font-size: 0.9em; - font-weight: bold; - text-align: center; - letter-spacing: 1px; - background-color: #558195; - border-top-left-radius: 8px; - border-top-right-radius: 8px; - color: white; -} - -/* The submenu bar that *sometimes* appears below the main menu */ -div.submenu, div.sectionmenu { - padding: 3px 10px 3px 0px; - font-size: 0.9em; - text-align: center; - background-color: #456878; - color: white; -} -div.mainmenu a, div.mainmenu a:visited, div.submenu a, div.submenu a:visited, -div.sectionmenu>a.button:link, div.sectionmenu>a.button:visited { - padding: 3px 10px 3px 10px; - color: white; - text-decoration: none; -} -div.mainmenu a:hover, div.submenu a:hover, div.sectionmenu>a.button:hover { - color: #558195; - background-color: white; -} - -/* All page content from the bottom of the menu or submenu down to -** the footer */ -div.content { - padding: 0ex 1ex 1ex 1ex; - border: solid #aaa; - border-width: 1px; -} - -/* Some pages have section dividers */ -div.section { - margin-bottom: 0px; - margin-top: 1em; - padding: 1px 1px 1px 1px; - font-size: 1.2em; - font-weight: bold; - background-color: #558195; - color: white; - white-space: nowrap; -} - -/* The "Date" that occurs on the left hand side of timelines */ -div.divider { - background: #a1c4d4; - border: 2px #558195 solid; - font-size: 1em; font-weight: normal; - padding: .25em; - margin: .2em 0 .2em 0; - float: left; - clear: left; - white-space: nowrap; -} - -/* The footer at the very bottom of the page */ -div.footer { - clear: both; - font-size: 0.8em; - padding: 5px 10px 5px 10px; - text-align: right; - background-color: #558195; - border-bottom-left-radius: 8px; - border-bottom-right-radius: 8px; - color: white; -} - -/* Hyperlink colors in the footer */ -div.footer a { color: white; } -div.footer a:link { color: white; } -div.footer a:visited { color: white; } -div.footer a:hover { background-color: white; color: #558195; } - -/* verbatim blocks */ -pre.verbatim { - background-color: #f5f5f5; - padding: 0.5em; - white-space: pre-wrap; -} - -/* The label/value pairs on (for example) the ci page */ -table.label-value th { - vertical-align: top; - text-align: right; - padding: 0.2ex 2ex; -} DELETED skins/original/details.txt Index: skins/original/details.txt ================================================================== --- skins/original/details.txt +++ skins/original/details.txt @@ -1,4 +0,0 @@ -timeline-arrowheads: 1 -timeline-circle-nodes: 0 -timeline-color-graph-lines: 0 -white-foreground: 0 DELETED skins/original/footer.txt Index: skins/original/footer.txt ================================================================== --- skins/original/footer.txt +++ skins/original/footer.txt @@ -1,6 +0,0 @@ -<div class="footer"> -This page was generated in about -<th1>puts [expr {([utime]+[stime]+1000)/1000*0.001}]</th1>s by -Fossil version $manifest_version $manifest_date -</div> -</body></html> DELETED skins/original/header.txt Index: skins/original/header.txt ================================================================== --- skins/original/header.txt +++ skins/original/header.txt @@ -1,53 +0,0 @@ -<html> -<head> -<base href="$baseurl/$current_page" /> -<title>$<project_name>: $<title> - - - - -
- -
$
$</div> - <div class="status"><th1> - if {[info exists login]} { - puts "Logged in as $login" - } else { - puts "Not logged in" - } - </th1></div> -</div> -<div class="mainmenu"> -<th1> -html "<a href='$home$index_page'>Home</a>\n" -if {[anycap jor]} { - html "<a href='$home/timeline'>Timeline</a>\n" -} -if {[anoncap oh]} { - html "<a href='$home/tree?ci=tip'>Files</a>\n" -} -if {[anoncap o]} { - html "<a href='$home/brlist'>Branches</a>\n" - html "<a href='$home/taglist'>Tags</a>\n" -} -if {[anoncap r]} { - html "<a href='$home/ticket'>Tickets</a>\n" -} -if {[anoncap j]} { - html "<a href='$home/wiki'>Wiki</a>\n" -} -if {[hascap s]} { - html "<a href='$home/setup'>Admin</a>\n" -} elseif {[hascap a]} { - html "<a href='$home/setup_ulist'>Users</a>\n" -} -if {[info exists login]} { - html "<a href='$home/login'>Logout</a>\n" -} else { - html "<a href='$home/login'>Login</a>\n" -} -</th1></div> DELETED skins/plain_gray/css.txt Index: skins/plain_gray/css.txt ================================================================== --- skins/plain_gray/css.txt +++ skins/plain_gray/css.txt @@ -1,142 +0,0 @@ -/* General settings for the entire page */ -body { - margin: 0ex 1ex; - padding: 0px; - background-color: white; - font-family: sans-serif; - -moz-text-size-adjust: none; - -webkit-text-size-adjust: none; - -mx-text-size-adjust: none; -} - -/* The project logo in the upper left-hand corner of each page */ -div.logo { - display: table-row; - text-align: center; - /* vertical-align: bottom;*/ - font-size: 2em; - font-weight: bold; - background-color: #707070; - color: #ffffff; - min-width: 200px; - white-space: nowrap; -} - -/* The page title centered at the top of each page */ -div.title { - display: table-cell; - font-size: 1.5em; - font-weight: bold; - text-align: center; - padding: 0 0 0 10px; - color: #404040; - vertical-align: bottom; - width: 100%; -} - -/* The login status message in the top right-hand corner */ -div.status { - display: table-cell; - text-align: right; - vertical-align: bottom; - color: #404040; - font-size: 0.8em; - font-weight: bold; - min-width: 200px; - white-space: nowrap; -} - -/* The header across the top of the page */ -div.header { - display: table; - width: 100%; -} - -/* The main menu bar that appears at the top of the page beneath -** the header */ -div.mainmenu { - padding: 5px 10px 5px 10px; - font-size: 0.9em; - font-weight: bold; - text-align: center; - letter-spacing: 1px; - background-color: #404040; - color: white; -} - -/* The submenu bar that *sometimes* appears below the main menu */ -div.submenu, div.sectionmenu { - padding: 3px 10px 3px 0px; - font-size: 0.9em; - text-align: center; - background-color: #606060; - color: white; -} -div.mainmenu a, div.mainmenu a:visited, div.submenu a, div.submenu a:visited, -div.sectionmenu>a.button:link, div.sectionmenu>a.button:visited { - padding: 3px 10px 3px 10px; - color: white; - text-decoration: none; -} -div.mainmenu a:hover, div.submenu a:hover, div.sectionmenu>a.button:hover { - color: #404040; - background-color: white; -} - -/* All page content from the bottom of the menu or submenu down to -** the footer */ -div.content { - padding: 0ex 0ex 0ex 0ex; -} -/* Hyperlink colors */ -div.content a { color: #604000; } -div.content a:link { color: #604000;} -div.content a:visited { color: #600000; } - -/* <verbatim> blocks */ -pre.verbatim { - background-color: #ffffff; - padding: 0.5em; - white-space: pre-wrap; -} - -/* Some pages have section dividers */ -div.section { - margin-bottom: 0px; - margin-top: 1em; - padding: 1px 1px 1px 1px; - font-size: 1.2em; - font-weight: bold; - background-color: #404040; - color: white; - white-space: nowrap; -} - -/* The "Date" that occurs on the left hand side of timelines */ -div.divider { - background: #a0a0a0; - border: 2px #505050 solid; - font-size: 1em; font-weight: normal; - padding: .25em; - margin: .2em 0 .2em 0; - float: left; - clear: left; - white-space: nowrap; -} - -/* The footer at the very bottom of the page */ -div.footer { - font-size: 0.8em; - margin-top: 12px; - padding: 5px 10px 5px 10px; - text-align: right; - background-color: #404040; - color: white; -} - -/* The label/value pairs on (for example) the vinfo page */ -table.label-value th { - vertical-align: top; - text-align: right; - padding: 0.2ex 2ex; -} DELETED skins/plain_gray/details.txt Index: skins/plain_gray/details.txt ================================================================== --- skins/plain_gray/details.txt +++ skins/plain_gray/details.txt @@ -1,4 +0,0 @@ -timeline-arrowheads: 1 -timeline-circle-nodes: 0 -timeline-color-graph-lines: 0 -white-foreground: 0 DELETED skins/plain_gray/footer.txt Index: skins/plain_gray/footer.txt ================================================================== --- skins/plain_gray/footer.txt +++ skins/plain_gray/footer.txt @@ -1,4 +0,0 @@ -<div class="footer"> -Fossil version $manifest_version $manifest_date -</div> -</body></html> DELETED skins/plain_gray/header.txt Index: skins/plain_gray/header.txt ================================================================== --- skins/plain_gray/header.txt +++ skins/plain_gray/header.txt @@ -1,50 +0,0 @@ -<html> -<head> -<base href="$baseurl/$current_page" /> -<title>$<project_name>: $<title> - - - - -
-
$
$</div> - <div class="status"><th1> - if {[info exists login]} { - puts "Logged in as $login" - } else { - puts "Not logged in" - } - </th1></div> -</div> -<div class="mainmenu"> -<th1> -html "<a href='$home$index_page'>Home</a>\n" -if {[anycap jor]} { - html "<a href='$home/timeline'>Timeline</a>\n" -} -if {[anoncap oh]} { - html "<a href='$home/tree?ci=tip'>Files</a>\n" -} -if {[anoncap o]} { - html "<a href='$home/brlist'>Branches</a>\n" - html "<a href='$home/taglist'>Tags</a>\n" -} -if {[anoncap r]} { - html "<a href='$home/ticket'>Tickets</a>\n" -} -if {[anoncap j]} { - html "<a href='$home/wiki'>Wiki</a>\n" -} -if {[hascap s]} { - html "<a href='$home/setup'>Admin</a>\n" -} elseif {[hascap a]} { - html "<a href='$home/setup_ulist'>Users</a>\n" -} -if {[info exists login]} { - html "<a href='$home/login'>Logout</a>\n" -} else { - html "<a href='$home/login'>Login</a>\n" -} -</th1></div> DELETED skins/rounded1/css.txt Index: skins/rounded1/css.txt ================================================================== --- skins/rounded1/css.txt +++ skins/rounded1/css.txt @@ -1,197 +0,0 @@ -/* General settings for the entire page */ -html { - min-height: 100%; -} -body { - margin: 0ex 1ex; - padding: 0px; - background-color: white; - color: #333; - font-family: Verdana, sans-serif; - font-size: 0.8em; - -moz-text-size-adjust: none; - -webkit-text-size-adjust: none; - -mx-text-size-adjust: none; -} - -/* The project logo in the upper left-hand corner of each page */ -div.logo { - display: table-cell; - text-align: right; - vertical-align: bottom; - font-weight: normal; - white-space: nowrap; -} - -/* Widths */ -div.header, div.mainmenu, div.submenu, div.content, div.footer { - max-width: 900px; - margin: auto; - padding: 3px 20px 3px 20px; - clear: both; -} - -/* The page title at the top of each page */ -div.title { - display: table-cell; - padding-left: 10px; - font-size: 2em; - margin: 10px 0 10px -20px; - vertical-align: bottom; - text-align: left; - width: 80%; - font-family: Verdana, sans-serif; - font-weight: bold; - color: #558195; - text-shadow: 0px 2px 2px #999999; -} - -/* The login status message in the top right-hand corner */ -div.status { - display: table-cell; - text-align: right; - vertical-align: bottom; - color: #333; - margin-right: -20px; - white-space: nowrap; -} - -/* The main menu bar that appears at the top of the page beneath - ** the header */ -div.mainmenu { - text-align: center; - color: white; - border-top-left-radius: 5px; - border-top-right-radius: 5px; - vertical-align: middle; - padding-top: 8px; - padding-bottom: 8px; - background-color: #446979; - box-shadow: 0px 3px 4px #333333; -} - -/* The submenu bar that *sometimes* appears below the main menu */ -div.submenu { - padding-top:10px; - padding-bottom:0; - text-align: right; - color: #000; - background-color: #fff; - height: 1.5em; - vertical-align:middle; - box-shadow: 0px 3px 4px #999; -} -div.mainmenu a, div.mainmenu a:visited { - padding: 3px 10px 3px 10px; - color: white; - text-decoration: none; -} -div.submenu a, div.submenu a:visited, a.button, -div.sectionmenu>a.button:link, div.sectionmenu>a.button:visited { - padding: 2px 8px; - color: #000; - font-family: Arial; - text-decoration: none; - margin:auto; - border-radius: 5px; - background-color: #e0e0e0; - text-shadow: 0px -1px 0px #eee; - border: 1px solid #000; -} - -div.mainmenu a:hover { - color: #000; - background-color: white; -} - -div.submenu a:hover, div.sectionmenu>a.button:hover { - background-color: #c0c0c0; -} - -/* All page content from the bottom of the menu or submenu down to - ** the footer */ -div.content { - background-color: #fff; - box-shadow: 0px 3px 4px #999; - border-bottom-right-radius: 5px; - border-bottom-left-radius: 5px; - padding-bottom: 1em; - min-height:40%; -} - - -/* Some pages have section dividers */ -div.section { - margin-bottom: 0.5em; - margin-top: 1em; - margin-right: auto; - padding: 1px 1px 1px 1px; - font-size: 1.2em; - font-weight: bold; - text-align: center; - color: white; - border-radius: 5px; - background-color: #446979; - box-shadow: 0px 3px 4px #333333; - white-space: nowrap; -} - -/* The "Date" that occurs on the left hand side of timelines */ -div.divider { - font-size: 1.2em; - font-family: Georgia, serif; - font-weight: bold; - margin-top: 1em; - white-space: nowrap; -} - -/* The footer at the very bottom of the page */ -div.footer { - font-size: 0.9em; - text-align: right; - margin-bottom: 1em; - color: #666; -} - -/* Hyperlink colors in the footer */ -div.footer a { color: white; } -div.footer a:link { color: white; } -div.footer a:visited { color: white; } -div.footer a:hover { background-color: white; color: #558195; } - -/* <verbatim> blocks */ -pre.verbatim, blockquote pre { - font-family: Dejavu Sans Mono, Monaco, Lucida Console, monospace; - background-color: #f3f3f3; - padding: 0.5em; - white-space: pre-wrap; -} - -blockquote pre { - border: 1px #000 dashed; -} - -/* The label/value pairs on (for example) the ci page */ -table.label-value th { - vertical-align: top; - text-align: right; - padding: 0.2ex 2ex; -} - -table.report tr th { - padding: 3px 5px; - text-transform: capitalize; - cursor: pointer; -} - -table.report tr td { - padding: 3px 5px; -} - -textarea { - font-size: 1em; -} - -.fullsize-text { - font-size: 1.25em; -} DELETED skins/rounded1/details.txt Index: skins/rounded1/details.txt ================================================================== --- skins/rounded1/details.txt +++ skins/rounded1/details.txt @@ -1,4 +0,0 @@ -timeline-arrowheads: 1 -timeline-circle-nodes: 0 -timeline-color-graph-lines: 0 -white-foreground: 0 DELETED skins/rounded1/footer.txt Index: skins/rounded1/footer.txt ================================================================== --- skins/rounded1/footer.txt +++ skins/rounded1/footer.txt @@ -1,4 +0,0 @@ -<div class="footer"> -Fossil version $manifest_version $manifest_date -</div> -</body></html> DELETED skins/rounded1/header.txt Index: skins/rounded1/header.txt ================================================================== --- skins/rounded1/header.txt +++ skins/rounded1/header.txt @@ -1,54 +0,0 @@ -<html> -<head> -<base href="$baseurl/$current_page" /> -<title>$<project_name>: $<title> - - - - -
- -
$</div> - <div class="status"><th1> - if {[info exists login]} { - puts "Logged in as $login" - } else { - puts "Not logged in" - } - </th1></div> -</div> -<div class="mainmenu"> -<th1> -html "<a href='$home$index_page'>Home</a>\n" -if {[anycap jor]} { - html "<a href='$home/timeline'>Timeline</a>\n" -} -if {[anoncap oh]} { - html "<a href='$home/tree?ci=tip'>Files</a>\n" -} -if {[anoncap o]} { - html "<a href='$home/brlist'>Branches</a>\n" - html "<a href='$home/taglist'>Tags</a>\n" -} -if {[anoncap r]} { - html "<a href='$home/ticket'>Tickets</a>\n" -} -if {[anoncap j]} { - html "<a href='$home/wiki'>Wiki</a>\n" -} -if {[hascap s]} { - html "<a href='$home/setup'>Admin</a>\n" -} elseif {[hascap a]} { - html "<a href='$home/setup_ulist'>Users</a>\n" -} -if {[info exists login]} { - html "<a href='$home/login'>Logout</a>\n" -} else { - html "<a href='$home/login'>Login</a>\n" -} -</th1></div> DELETED skins/xekri/README.md Index: skins/xekri/README.md ================================================================== --- skins/xekri/README.md +++ skins/xekri/README.md @@ -1,2 +0,0 @@ -"xekri" is a Lojban word that means "extermely dark-colored". -This skin was contributed by Andrew Moore. DELETED skins/xekri/css.txt Index: skins/xekri/css.txt ================================================================== --- skins/xekri/css.txt +++ skins/xekri/css.txt @@ -1,1032 +0,0 @@ -/****************************************************************************** - * Xekri - * - * To adjust the width of the contents for this skin, look for the "max-width" - * property and change its value. (It's in the "Main Area" section) The value - * determines how much of the browser window to use. Some like 100%, so that - * the entire window is used. Others prefer 80%, which makes the contents - * easier to read for them. - */ - - -/************************************** - * General HTML - */ - -html { - background-color: #333; - color: #eee; - font-family: Monospace; - font-size: 1em; - min-height: 100%; -} - -body { - margin: 0; - padding: 0; - -moz-text-size-adjust: none; - -ms-text-size-adjust: none; - -webkit-text-size-adjust: none; -} - -a { - color: #07e; -} - -a:hover { - font-weight: bold; -} - -blockquote pre { - border: 1px dashed #ee0; -} - -blockquote pre, pre.verbatim { - background-color: #000; - border-radius: 0.75rem; - padding: 0.5rem; - white-space: pre-wrap; -} - -input[type="password"], input[type="text"], textarea { - background-color: #111; - color: #fff; - font-size: 1rem; -} - -h1 { - font-size: 2rem; -} - -h2 { - font-size: 1.5rem; -} - -h3 { - font-size: 1.25rem; -} - -span[style^=background-color] { - color: #000; -} - -td[style^=background-color] { - color: #000; -} - - -/************************************** - * Main Area - */ - -div.header, div.mainmenu, div.submenu, div.content, div.footer { - clear: both; - margin: 0 auto; - max-width: 90%; - padding: 0.25rem 1rem; -} - - -/************************************** - * Main Area: Header - */ - -div.header { - margin: 0.5rem auto 0 auto; -} - -div.logo img { - float: left; - padding: 0; - box-shadow: 3px 3px 1px #000; - margin: 0 6px 6px 0; -} - -div.logo br { - display: none; -} - -div.logo nobr { - color: #eee; - font-size: 1.2rem; - font-weight: bold; - padding: 0; - text-shadow: 3px 3px 1px #000; - vertical-align: top; - white-space: nowrap; -} - -div.title { - color: #07e; - font-family: Verdana, sans-serif; - font-weight: bold; - font-size: 2.5rem; - padding: 0.5rem; - text-align: center; - text-shadow: 3px 3px 1px #000; -} - -div.status { - color: #ee0; - font-size: 1rem; - padding: 0.25rem; - text-align: right; - text-shadow: 2px 2px 1px #000; -} - - -/************************************** - * Main Area: Global Menu - */ - -div.mainmenu, div.submenu { - background-color: #080; - border-radius: 1rem 1rem 0 0; - box-shadow: 3px 4px 1px #000; - color: #000; - font-weight: bold; - font-size: 1.1rem; - text-align: center; -} - -div.mainmenu { - padding-top: 0.33rem; - padding-bottom: 0.25rem; -} - -div.submenu { - border-top: 1px solid #0a0; - border-radius: 0; - display: block; -} - -div.mainmenu a, div.submenu a { - color: #000; - padding: 0 0.75rem; - text-decoration: none; -} - -div.mainmenu a:hover, div.submenu a:hover { - color: #fff; - text-shadow: 0px 0px 6px #0f0; -} - -div.submenu * { - margin: 0 0.5rem; - vertical-align: middle; -} - -div.submenu select, div.submenu input { - background-color: #222; - border: 1px inset #080; - color: #eee; - cursor: pointer; - font-size: 0.9rem; -} - -div.submenu select { - height: 1.75rem; -} - -/************************************** - * Main Area: Content - */ - -div.content { - background-color: #222; - border-radius: 0 0 1rem 1rem; - box-shadow: 3px 3px 1px #000; - min-height:40%; - padding-bottom: 1rem; - padding-top: 0.5rem; -} - -div.content table[bgcolor="white"] { - color: #000; -} - -/************************************** - * Main Area: Footer - */ - -div.footer { - color: #ee0; - font-size: 0.75rem; - padding: 0; - text-align: right; - width: 75%; -} - - -div.footer div { - background-color: #222; - box-shadow: 3px 3px 1px #000; - border-radius: 0 0 1rem 1rem; - margin: 0 0 10px 0; - padding: 0.5rem 0.75rem; -} - -div.footer div.page-time { - float: left; -} - -div.footer div.fossil-info { - float: right; -} - -div.footer a, div.footer a:link, div.footer a:visited { - color: #ee0; -} - -div.footer a:hover { - color: #fff; - text-shadow: 0px 0px 6px #ee0; -} - - -/************************************** - * Check-in - */ - -table.label-value th { - vertical-align: top; - text-align: right; - padding: 0.1rem 1rem; -} - - -/************************************** - * Diffs - */ - -/* Code Added */ -span.diffadd { - background-color: #7f7; - color: #000; -} - -/* Code Changed */ -span.diffchng { - background-color: #77f; - color: #000; -} - -/* Code Deleted */ -span.diffrm { - background-color: #f77; - color: #000; -} - - -/************************************** - * Diffs : Side-By-Side - */ - -/* display (column-based) */ -table.sbsdiffcols { - border-spacing: 0; - font-size: 0.85rem; - width: 90%; -} - -table.sbsdiffcols pre { - border: 0; - margin: 0; - padding: 0; -} - -table.sbsdiffcols td { - padding: 0; - vertical-align: top; -} - -/* line number column */ -div.difflncol { - color: #ee0; - padding-right: 0.75em; - text-align: right; -} - -/* diff text column */ -div.difftxtcol { - background-color: #111; - overflow-x: auto; - width: 45em; -} - -/* suppressed lines */ -span.diffhr { - display: inline-block; - margin-bottom: 0.75em; - color: #ff0; -} - -/* diff marker column */ -div.diffmkrcol { - padding: 0 0.5em; -} - - -/************************************** - * Diffs : Unified - */ - -pre.udiff { - background-color: #111; -} - -/* line numbers */ -span.diffln { - background-color: #222; - color: #ee0; -} - - -/************************************** - * File List : Flat - */ - -table.browser { - width: 100%; - border: 0; -} - -td.browser { - width: 24%; - vertical-align: top; -} - -ul.browser { - margin: 0.5rem; - padding: 0.5rem; - white-space: nowrap; -} - -ul.browser li.dir { - font-style: italic -} - - -/************************************** - * File List : Age - */ - -.fileage tr:hover td { - background-color: #225; -} - - -/************************************** - * File List : Tree - */ - -.filetree { - line-height: 1.5; - margin: 1rem 0; -} - -/* list */ -.filetree ul { - list-style: none; - margin: 0; - padding: 0; -} - -/* collapsed list */ -.filetree ul.collapsed { - display: none; -} - -/* lists below the root */ -.filetree ul ul { - margin: 0 0 0 21px; - position: relative; -} - -/* lists items */ -.filetree li { - margin: 0; - padding: 0; - position: relative; -} - -/* node lines */ -.filetree li li:before { - border-bottom: 2px solid #000; - border-left: 2px solid #000; - content: ''; - height: 1.5rem; - left: -14px; - position: absolute; - top: -0.8rem; - width: 14px; -} - -/* directory lines */ -.filetree li > ul:before { - border-left: 2px solid #000; - bottom: 0; - content: ''; - left: -35px; - position: absolute; - top: -1.5rem; -} - -/* hide lines for last-child directories */ -.filetree li.last > ul:before { - display: none; -} - -.filetree a { - background-image: url(data:image/gif;base64,R0lGODlhEAAQAJEAAP\/\/\/yEhIf\/\/\/wAAACH5BAEHAAIALAAAAAAQABAAAAIvlIKpxqcfmgOUvoaqDSCxrEEfF14GqFXImJZsu73wepJzVMNxrtNTj3NATMKhpwAAOw==); - background-position: center left; - background-repeat: no-repeat; - display: inline-block; - min-height: 16px; - padding-left: 21px; - position: relative; - z-index: 1; -} - -.filetree .dir > a { - background-image: url(data:image/gif;base64,R0lGODlhEAAQAJEAAP/WVCIiIv\/\/\/wAAACH5BAEHAAIALAAAAAAQABAAAAInlI9pwa3XYniCgQtkrAFfLXkiFo1jaXpo+jUs6b5Z/K4siDu5RPUFADs=); - font-style: italic -} - -.filetreeline:hover { - color: #000; - font-weight: bold; -} - -.filetreeline .filetreeage { - padding-right: 0.5rem; -} - -/************************************** - * Logout - */ - -span.loginError { - color: #f00; -} - -table.login_out { - margin: 10px; - text-align: left; -} - -td.login_out_label { - text-align: center; -} - -div.captcha { - padding: 1rem; - text-align: center; -} - -table.captcha { - background-color: #111; - border-color: #111; - border-style: inset; - border-width: 2px; - margin: auto; - padding: 0.5rem; -} - -table.captcha pre { - color: #ee0; -} - - -/************************************** - * Statistics Reports - */ - -.statistics-report-graph-line { - background-color: #22e; -} - -.statistics-report-table-events th { - padding: 0 1rem; -} - -.statistics-report-table-events td { - padding: 0.1rem 1rem; -} - -.statistics-report-row-year { - color: #ee0; - text-align: left; -} - -.statistics-report-week-number-label { - font-size: 0.8rem; - text-align: right; -} - -.statistics-report-week-of-year-list { - font-size: 0.8rem; -} - - -/************************************** - * Search - */ - -.searchResult .snippet mark { - color: #ee0; -} - - -/************************************** - * Sections - */ - -div.section, div.sectionmenu { - color: #2ee; - background-color: #22c; - border-radius: 0 3rem; - box-shadow: 2px 2px #000; - display: flex; - font-size: 1.1rem; - font-weight: bold; - justify-content: space-around; - margin: 1.2rem auto 0.75rem auto; - padding: 0.2rem; - text-align: center; -} - -div.sectionmenu { - border-radius: 0 0 3rem 3rem; - margin-top: -0.75rem; - width: 75%; -} - -div.sectionmenu > a:link, div.sectionmenu > a:visited { - color: #000; - text-decoration: none; -} - -div.sectionmenu > a:hover { - color: #eee; - text-shadow: 0px 0px 6px #eee; -} - - -/************************************** - * Sidebox - */ - -div.sidebox { - background-color: #333; - border-radius: 0.5rem; - box-shadow: 3px 3px 1px #000; - float: right; - margin: 1rem 0.5rem; - padding: 0.5rem; -} - -div.sidebox ol { - margin: 0 0 0.5rem 2.5rem; - padding: 0 0; -} - -div.sidebox ol li { - margin-top: 0.75rem; -} - -div.sideboxTitle { - background-color: #ee0; - border-radius: 0.5rem 0.5rem 0 0; - color: #000; - font-weight: bold; - margin: -0.5rem -0.5rem 0 -0.5rem; - padding: 0.25rem; - text-align: center; -} - -div.sideboxDescribed { - display: inline; -} - -/* --- Untested : Begin --- */ -/* The defined element in sideboxes for branches,.. */ -span.disabled { - color: #f00; -} -/* --- Untested : End --- */ - - -/************************************** - * Tag - */ - -/* --- Untested : Begin --- */ -/* the format for the tag links */ -a.tagLink { -} -/* the format for the tag display(no history permission!) */ -span.tagDsp { - font-weight: bold; -} -/* the format for fixed/canceled tags,.. */ -span.infoTagCancelled { - font-weight: bold; - text-decoration: line-through; -} -/* --- Untested : End --- */ - - -/************************************** - * Ticket - */ - -table.report { - color: #000; - border: 1px solid #999; - border-collapse: collapse; - margin: 1rem 0; -} - -table.report tr th { - color: #eee; - padding: 3px 5px; - text-transform : capitalize; -} - -table.report tr td { - padding: 3px 5px; -} - -/* example ticket colors */ -table.rpteditex { - border-collapse: collapse; - border-spacing: 0; - color: #000; - float: right; - margin: 0; - padding: 0; - text-align: center; - width: 125px; -} - -td.rpteditex { - border-color: #000; - border-style: solid; - border-width: thin; -} - -#reportTable { -} - -/* format for labels on ticket display page */ -td.tktDspLabel { - text-align: right; -} - -/* format for values on ticket display page */ -td.tktDspValue { - background-color: #111; - text-align: left; - vertical-align: top; -} - -/* format for ticket error messages */ -span.tktError { - color: #f00; - font-weight: bold; -} - - -/************************************** - * Timeline - */ - -#canvas { - color: #000; - background-color: #fff; -} - -div.divider { - color: #ee0; - font-size: 1.2rem; - font-weight: bold; - margin-top: 1rem; - white-space: nowrap; -} - -/* The suppressed duplicates lines in timeline, .. */ -span.timelineDisabled { - font-size: 0.5rem; - font-style: italic; -} - -/* the format for the timeline data table */ -table.timelineTable { - border: 0; -} - -/* The row in the timeline table that contains the entry of interest */ -tr.timelineSelected { - border: 1px solid #eee; - border-radius: 1rem; -} - -tr.timelineSelected td.timelineTime -, tr.timelineSelected td.timelineTableCell { - background-color: #333; - box-shadow: 2px 2px 1px #000; - padding: 0.5rem; -} - -tr.timelineSelected td.timelineTime { - border-radius: 1rem 0 0 1rem; -} - -tr.timelineSelected td.timelineTableCell { - border-radius: 0 1rem 1rem 0; -} - -/* the format for the timeline data cells */ -td.timelineTableCell { - padding: 0.3rem; - text-align: left; - vertical-align: top; -} - -td.timelineTableCell[style] { - color: #000; -} - -/* the format for the timeline data cell of the current checkout */ -tr.timelineCurrent td.timelineTableCell { - border: 0; - border-radius: 1em 0em; -} - -/* the format for the timeline leaf marks */ -span.timelineLeaf { - font-weight: bold; -} - -/* the format for the timeline version links */ -a.timelineHistLink { -} - -/* the format for the timeline version display(no history permission!) */ -span.timelineHistDsp { - font-weight: bold; -} - -/* the format for the timeline time display */ -td.timelineTime { - text-align: right; - vertical-align: top; - white-space: nowrap; -} - -/* the format for the grap placeholder cells in timelines */ -td.timelineGraph { - text-align: left; - vertical-align: top; - width: 20px; -} - - -/************************************** - * User Edit - */ - -/* layout definition for the capabilities box on the user edit detail page */ -div.ueditCapBox { - float: left; - margin: 0 20px 20px 0; -} - -/* format of the label cells in the detailed user edit page */ -td.usetupEditLabel { - text-align: right; - vertical-align: top; - white-space: nowrap; -} - -/* color for capabilities, inherited by nobody */ -span.ueditInheritNobody { - color: #0f0; -} - -/* color for capabilities, inherited by developer */ -span.ueditInheritDeveloper { - color: #f00; -} - -/* color for capabilities, inherited by reader */ -span.ueditInheritReader { - color: black; -} - -/* color for capabilities, inherited by anonymous */ -span.ueditInheritAnonymous { - color: #00f; -} - -/* format for capabilities */ -span.capability { - font-weight: bold; -} - -/* format for different user types */ -span.usertype { - font-weight: bold; -} - -span.usertype:before { - content:"'"; -} - -span.usertype:after { - content:"'"; -} - - -/************************************** - * User List - */ - -table.usetupLayoutTable { - margin: 0.5rem; - outline-style: none; - padding: 0; -} - -td.usetupColumnLayout { - vertical-align: top -} - -td.usetupColumnLayout ol th { - padding: 0 0.75rem 0.5rem 0; -} - -span.note { - color: #ee0; - font-weight: bold; -} - -table.usetupUserList { - margin: 0.5rem; -} - -.usetupListUser { - padding-right: 20px; - text-align: right; -} - -.usetupListCap { - padding-right: 15px; - text-align: center; -} - -.usetupListCon { - text-align: left; -} - - -/************************************** - * Wiki - */ - -span.wikiError { - font-weight: bold; - color: #f00; -} - -/* the format for fixed/cancelled tags */ -span.wikiTagCancelled { - text-decoration: line-through; -} - - -/************************************** - * Did not encounter these - */ - -/* selected lines of text within a linenumbered artifact display */ -div.selectedText { - font-weight: bold; - color: #00f; - background-color: #d5d5ff; - border: 1px #00f solid; -} - -/* format for missing privileges note on user setup page */ -p.missingPriv { - color: #00f; -} - -/* format for leading text in wikirules definitions */ -span.wikiruleHead { - font-weight: bold; -} - - -/* format for user color input on checkin edit page */ -input.checkinUserColor { - /* no special definitions, class defined, to enable color pickers, - * f.e.: - * ** add the color picker found at http:jscolor.com as java script - * include - * ** to the header and configure the java script file with - * ** 1. use as bindClass :checkinUserColor - * ** 2. change the default hash adding behaviour to ON - * ** or change the class defition of element identified by - * id="clrcust" - * ** to a standard jscolor definition with java script in the footer. - * */ -} - -/* format for end of content area, to be used to clear page flow. */ -div.endContent { - clear: both; -} - -/* format for general errors */ -p.generalError { - color: #f00; -} - -/* format for tktsetup errors */ -p.tktsetupError { - color: #f00; - font-weight: bold; -} -/* format for xfersetup errors */ -p.xfersetupError { - color: #f00; - font-weight: bold; -} -/* format for th script errors */ -p.thmainError { - color: #f00; - font-weight: bold; -} -/* format for th script trace messages */ -span.thTrace { - color: #f00; -} -/* format for report configuration errors */ -p.reportError { - color: #f00; - font-weight: bold; -} -/* format for report configuration errors */ -blockquote.reportError { - color: #f00; - font-weight: bold; -} -/* format for artifact lines, no longer shunned */ -p.noMoreShun { - color: #00f; -} -/* format for artifact lines beeing shunned */ -p.shunned { - color: #00f; -} -/* a broken hyperlink */ -span.brokenlink { - color: #f00; -} -/* List of files in a timeline */ -ul.filelist { - margin-top: 3px; - line-height: 100%; -} -/* Moderation Pending message on timeline */ -span.modpending { - color: #b30; - font-style: italic; -} -/* format for textarea labels */ -span.textareaLabel { - font-weight: bold; -} -/* format for th1 script results */ -pre.th1result { - white-space: pre-wrap; - word-wrap: break-word; -} -/* format for th1 script errors */ -pre.th1error { - white-space: pre-wrap; - word-wrap: break-word; - color: #f00; -} - -/* even table row color */ -tr.row0 { - /* use default */ -} -/* odd table row color */ -tr.row1 { - /* Use default */ -} - DELETED skins/xekri/details.txt Index: skins/xekri/details.txt ================================================================== --- skins/xekri/details.txt +++ skins/xekri/details.txt @@ -1,4 +0,0 @@ -timeline-arrowheads: 1 -timeline-circle-nodes: 0 -timeline-color-graph-lines: 0 -white-foreground: 0 DELETED skins/xekri/footer.txt Index: skins/xekri/footer.txt ================================================================== --- skins/xekri/footer.txt +++ skins/xekri/footer.txt @@ -1,11 +0,0 @@ -</div> -<div class="footer"> -<div class="page-time"> -Generated in <th1>puts [expr {([utime]+[stime]+1000)/1000*0.001}]</th1>s -</div> -<div class="fossil-info"> -Fossil v$release_version $manifest_version -</div> -</div> -</body> -</html> DELETED skins/xekri/header.txt Index: skins/xekri/header.txt ================================================================== --- skins/xekri/header.txt +++ skins/xekri/header.txt @@ -1,142 +0,0 @@ -<html> -<head> -<base href="$baseurl/$current_page" /> -<title>$<project_name>: $<title> - - - - -
- -
$</div> - <div class="status"><nobr><th1> - if {[info exists login]} { - puts "Logged in as $login" - } else { - puts "Not logged in" - } - </th1></nobr><small><div id="clock"></div></small></div> -</div> -<script> -function updateClock(){ - var e = document.getElementById("clock"); - if(e){ - var d = new Date(); - function f(n) { - return n < 10 ? '0' + n : n; - } - e.innerHTML = d.getUTCFullYear()+ '-' + - f(d.getUTCMonth() + 1) + '-' + - f(d.getUTCDate()) + ' ' + - f(d.getUTCHours()) + ':' + - f(d.getUTCMinutes()); - setTimeout("updateClock();",(60-d.getUTCSeconds())*1000); - } -} -updateClock(); -</script> -<div class="mainmenu"> -<th1> -proc menulink {url name} { - upvar current_page current - upvar home home - if {[string range $url 0 [string length $current]] eq "/$current"} { - html "<a href='$home$url' class='active'>$name</a>\n" - } else { - html "<a href='$home$url'>$name</a>\n" - } -} -menulink $index_page Home -if {[anycap jor]} { - menulink /timeline Timeline -} -if {[anoncap oh]} { - menulink /dir?ci=tip Files -} -if {[anoncap o]} { - menulink /brlist Branches - menulink /taglist Tags -} -if {[anoncap r]} { - menulink /ticket Tickets -} -if {[anoncap j]} { - menulink /wiki Wiki -} -if {[hascap s]} { - menulink /setup Admin -} elseif {[hascap a]} { - menulink /setup_ulist Users -} -if {[info exists login]} { - menulink /login Logout -} else { - menulink /login Login -} -</th1></div> Index: src/add.c ================================================================== --- src/add.c +++ src/add.c @@ -25,11 +25,11 @@ #include "cygsup.h" /* ** This routine returns the names of files in a working checkout that ** are created by Fossil itself, and hence should not be added, deleted, -** or merge, and should be omitted from "clean" and "extras" lists. +** or merge, and should be omitted from "clean" and "extra" 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){ @@ -44,11 +44,11 @@ ".fslckout", ".fslckout-journal", ".fslckout-wal", ".fslckout-shm", - /* The use of ".fos" as the name of the checkout database is + /* The use of ".fos" as the name of the checkout database is ** deprecated. Use ".fslckout" instead. At some point, the following ** entries should be removed. 2012-02-04 */ ".fos", ".fos-journal", ".fos-wal", @@ -123,14 +123,10 @@ */ void test_reserved_names(void){ int i; const char *z; int omitRepo = find_option("omitrepo",0,0)!=0; - - /* We should be done with options.. */ - verify_all_options(); - db_must_be_within_tree(); for(i=0; (z = fossil_reserved_name(i, omitRepo))!=0; i++){ fossil_print("%3d: %s\n", i, z); } fossil_print("ALL: (%s)\n", fossil_all_reserved_names(omitRepo)); @@ -153,15 +149,14 @@ " WHERE pathname=%Q %s", zPath, filename_collation()) ){ db_multi_exec("UPDATE vfile SET deleted=0" " WHERE pathname=%Q %s", zPath, filename_collation()); }else{ char *zFullname = mprintf("%s%s", g.zLocalRoot, zPath); - int isExe = file_wd_isexe(zFullname); db_multi_exec( "INSERT INTO vfile(vid,deleted,rid,mrid,pathname,isexe,islink)" "VALUES(%d,0,0,0,%Q,%d,%d)", - vid, zPath, isExe, file_wd_islink(0)); + vid, zPath, file_wd_isexe(zFullname), file_wd_islink(zFullname)); fossil_free(zFullname); } if( db_changes() ){ fossil_print("ADDED %s\n", zPath); return 1; @@ -182,11 +177,11 @@ int i; /* Loop counter */ const char *zReserved; /* Name of a reserved file */ Blob repoName; /* Treename of the repository */ Stmt loop; /* SQL to loop over all files to add */ int (*xCmp)(const char*,const char*); - + if( !file_tree_name(g.zRepositoryName, &repoName, 0) ){ blob_zero(&repoName); zRepo = ""; }else{ zRepo = blob_str(&repoName); @@ -227,28 +222,23 @@ ** 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 files matching patterns from the +** --case-sensitive <BOOL> override case-sensitive setting +** --dotfiles include files beginning with a dot (".") +** --ignore <CSG> ignore files matching patterns from the ** comma separated list of glob patterns. -** --clean <CSG> Also ignore files matching patterns from +** --clean <CSG> also ignore files matching patterns from ** the comma separated list of glob patterns. -** +** ** See also: addremove, rm */ void add_cmd(void){ int i; /* Loop counter */ int vid; /* Currently checked out version */ @@ -255,47 +245,39 @@ 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; zCleanFlag = find_option("clean",0,1); zIgnoreFlag = find_option("ignore",0,1); - forceFlag = find_option("force","f",0)!=0; if( find_option("dotfiles",0,0)!=0 ) scanFlags |= SCAN_ALL; - - /* We should be done with options.. */ - verify_all_options(); - + capture_case_sensitive_option(); db_must_be_within_tree(); if( zCleanFlag==0 ){ zCleanFlag = db_get("clean-glob", 0); } if( zIgnoreFlag==0 ){ zIgnoreFlag = db_get("ignore-glob", 0); } - if( db_get_boolean("dotfiles", 0) ) scanFlags |= SCAN_ALL; vid = db_lget_int("checkout",0); + if( vid==0 ){ + fossil_fatal("no checkout to add to"); + } db_begin_transaction(); db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY %s)", filename_collation()); pClean = glob_create(zCleanFlag); pIgnore = glob_create(zIgnoreFlag); nRoot = strlen(g.zLocalRoot); - + /* 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; - /* file_tree_name() throws a fatal error if g.argv[i] is outside of the - ** checkout. */ - file_tree_name(g.argv[i], &fullName, 1); - blob_reset(&fullName); - file_canonical_name(g.argv[i], &fullName, 0); zName = blob_str(&fullName); isDir = file_wd_isdir(zName); if( isDir==1 ){ vfile_scan(&fullName, nRoot-1, scanFlags, pClean, pIgnore); @@ -303,25 +285,10 @@ fossil_warning("not found: %s", zName); }else if( file_access(zName, R_OK) ){ fossil_fatal("cannot open %s", zName); }else{ char *zTreeName = &zName[nRoot]; - if( !forceFlag && glob_match(pIgnore, zTreeName) ){ - Blob ans; - char cReply; - char *prompt = mprintf("file \"%s\" matches \"ignore-glob\". " - "Add it (a=all/y/N)? ", zTreeName); - prompt_user(prompt, &ans); - cReply = blob_str(&ans)[0]; - blob_reset(&ans); - if( cReply=='a' || cReply=='A' ){ - forceFlag = 1; - }else if( cReply!='y' && cReply!='Y' ){ - blob_reset(&fullName); - continue; - } - } db_multi_exec( "INSERT OR IGNORE INTO sfile(x) VALUES(%Q)", zTreeName ); } @@ -334,34 +301,37 @@ db_end_transaction(0); } /* ** COMMAND: rm -** COMMAND: delete -** COMMAND: forget* +** COMMAND: delete* ** -** Usage: %fossil rm|delete|forget FILE1 ?FILE2 ...? +** Usage: %fossil rm FILE1 ?FILE2 ...? +** or: %fossil delete FILE1 ?FILE2 ...? ** ** Remove one or more files or directories from the repository. ** ** This command does NOT remove the files from disk. It just marks the ** files as no longer being part of the project. In other words, future ** changes to the named files will not be versioned. ** ** Options: -** --case-sensitive <BOOL> Override the case-sensitive setting. +** --case-sensitive <BOOL> override case-sensitive setting ** ** See also: addremove, add */ void delete_cmd(void){ int i; + int vid; Stmt loop; - /* We should be done with options.. */ - verify_all_options(); - + capture_case_sensitive_option(); db_must_be_within_tree(); + vid = db_lget_int("checkout", 0); + if( vid==0 ){ + fossil_fatal("no checkout to remove from"); + } db_begin_transaction(); db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY %s)", filename_collation()); for(i=2; i<g.argc; i++){ Blob treeName; @@ -378,11 +348,11 @@ zTreeName, filename_collation(), zTreeName, filename_collation(), zTreeName, filename_collation() ); blob_reset(&treeName); } - + db_prepare(&loop, "SELECT x FROM sfile"); while( db_step(&loop)==SQLITE_ROW ){ fossil_print("DELETED %s\n", db_column_text(&loop, 0)); } db_finalize(&loop); @@ -444,13 +414,12 @@ #endif caseSensitive = db_get_boolean("case-sensitive",caseSensitive); } if( !caseSensitive && g.localOpen ){ db_multi_exec( - "CREATE INDEX IF NOT EXISTS %s.vfile_nocase" - " ON vfile(pathname COLLATE nocase)", - db_name("localdb") + "CREATE INDEX IF NOT EXISTS vfile_nocase" + " ON vfile(pathname COLLATE nocase)" ); } } return caseSensitive; } @@ -473,11 +442,11 @@ ** ** Do all necessary "add" and "rm" commands to synchronize the repository ** with the content of the working checkout: ** ** * All files in the checkout but not in the repository (that is, -** all files displayed using the "extras" command) are added as +** all files displayed using the "extra" command) are added as ** if by the "add" command. ** ** * All files in the repository but missing from the checkout (that is, ** all files that show as MISSING with the "status" command) are ** removed as if by the "rm" command. @@ -491,23 +460,22 @@ ** 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. +** 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 files matching patterns from the +** +** Options: +** --case-sensitive <BOOL> override case-sensitive setting +** --dotfiles include files beginning with a dot (".") +** --ignore <CSG> ignore files matching patterns from the ** comma separated list of glob patterns. -** --clean <CSG> Also ignore files matching patterns from +** --clean <CSG> also ignore files matching patterns from ** the comma separated list of glob patterns. -** -n|--dry-run If given, display instead of run actions. +** -n|--dry-run If given, display instead of run actions ** ** See also: add, rm */ void addremove_cmd(void){ Blob path; @@ -523,26 +491,25 @@ Glob *pIgnore, *pClean; if( !dryRunFlag ){ dryRunFlag = find_option("test",0,0)!=0; /* deprecated */ } - - /* We should be done with options.. */ - verify_all_options(); - + capture_case_sensitive_option(); db_must_be_within_tree(); if( zCleanFlag==0 ){ zCleanFlag = db_get("clean-glob", 0); } if( zIgnoreFlag==0 ){ zIgnoreFlag = db_get("ignore-glob", 0); } - if( db_get_boolean("dotfiles", 0) ) scanFlags |= SCAN_ALL; vid = db_lget_int("checkout",0); + if( vid==0 ){ + fossil_fatal("no checkout to add to"); + } db_begin_transaction(); - /* step 1: + /* step 1: ** Populate the temp table "sfile" with the names of all unmanaged ** files currently in the check-out, except for files that match the ** --ignore or ignore-glob patterns and dot-files. Then add all of ** the files in the sfile temp table to the set of managed files. */ @@ -564,12 +531,12 @@ " WHERE NOT deleted" " ORDER BY 1", g.zLocalRoot ); while( db_step(&q)==SQLITE_ROW ){ - const char *zFile; - const char *zPath; + const char * zFile; + const char * zPath; zFile = db_column_text(&q, 0); zPath = db_column_text(&q, 1); if( !file_wd_isfile_or_link(zPath) ){ if( !dryRunFlag ){ @@ -590,21 +557,17 @@ /* ** Rename a single file. ** ** The original name of the file is zOrig. The new filename is zNew. */ -static void mv_one_file( - int vid, - const char *zOrig, - const char *zNew -){ +static void mv_one_file(int vid, const char *zOrig, const char *zNew){ int x = db_int(-1, "SELECT deleted FROM vfile WHERE pathname=%Q %s", - zNew, filename_collation()); + zNew, filename_collation()); if( x>=0 ){ if( x==0 ){ fossil_fatal("cannot rename '%s' to '%s' since another file named '%s'" - " is currently under management", zOrig, zNew, zNew); + " is currently under management", zOrig, zNew, zNew); }else{ fossil_fatal("cannot rename '%s' to '%s' since the delete of '%s' has " "not yet been committed", zOrig, zNew, zNew); } } @@ -625,14 +588,14 @@ ** Move or rename one or more files or directories within the repository tree. ** You can either rename a file or directory or move it to another subdirectory. ** ** This command does NOT rename or move the files on disk. This command merely ** records the fact that filenames have changed so that appropriate notations -** can be made at the next commit/check-in. +** can be made at the next commit/checkin. ** ** Options: -** --case-sensitive <BOOL> Override the case-sensitive setting. +** --case-sensitive <BOOL> override case-sensitive setting ** ** See also: changes, status */ void mv_cmd(void){ int i; @@ -639,15 +602,12 @@ int vid; char *zDest; Blob dest; Stmt q; + capture_case_sensitive_option(); db_must_be_within_tree(); - - /* We should be done with options.. */ - verify_all_options(); - vid = db_lget_int("checkout", 0); if( vid==0 ){ fossil_fatal("no checkout rename files in"); } if( g.argc<4 ){ @@ -716,13 +676,5 @@ mv_one_file(vid, zFrom, zTo); } db_finalize(&q); db_end_transaction(0); } - -/* -** Function for stash_apply to be able to restore a file and indicate -** newly ADDED state. -*/ -int stash_add_files_in_sfile(int vid){ - return add_files_in_sfile(vid); -} Index: src/allrepo.c ================================================================== --- src/allrepo.c +++ src/allrepo.c @@ -58,29 +58,19 @@ } } static void collect_argument_value(Blob *pExtra, const char *zArg){ const char *zValue = find_option(zArg, 0, 1); if( zValue ){ - if( zValue[0] ){ - blob_appendf(pExtra, " --%s %s", zArg, zValue); - }else{ - blob_appendf(pExtra, " --%s \"\"", zArg); - } - } -} -static void collect_argv(Blob *pExtra, int iStart){ - int i; - for(i=iStart; i<g.argc; i++){ - blob_appendf(pExtra, " %s", g.argv[i]); + blob_appendf(pExtra, " --%s %s", zArg, zValue); } } /* ** COMMAND: all ** -** Usage: %fossil all SUBCOMMAND ... +** Usage: %fossil all (changes|ignore|list|ls|pull|push|rebuild|sync) ** ** The ~/.fossil file records the location of all repositories for a ** user. This command performs certain operations on all repositories ** that can be useful before or after a period of disconnected operation. ** @@ -87,75 +77,33 @@ ** On Win32 systems, the file is named "_fossil" and is located in ** %LOCALAPPDATA%, %APPDATA% or %HOMEPATH%. ** ** Available operations are: ** -** changes Shows all local checkouts that have uncommitted changes. -** This operation has no additional options. -** -** clean Delete all "extra" files in all local checkouts. 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 checkouts 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. -** -** dbstat Run the "dbstat" command on all repositories. -** -** extras Shows "extra" files from all local checkouts. 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. -** -** info Run the "info" command on all repositories. -** -** pull Run a "pull" operation on all repositories. Only the -** --verbose option is 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 and -** --randomize options are not supported. -** -** sync Run a "sync" on all repositories. Only the --verbose -** option is supported. -** -** setting Run the "setting", "set", or "unset" commands on all -** set repositories. These command are particularly useful in -** unset conjunction with the "max-loadavg" setting which cannot -** otherwise be set globally. -** -** 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 sometime 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 checkouts to be ignored instead. -** -** list | ls Display the location of all repositories. The -c|--ckout -** option causes all local checkouts to be listed instead. +** changes Shows all local checkouts that have uncommitted changes +** +** ignore Arguments are repositories that should be ignored +** by subsequent list, pull, push, rebuild, and sync. +** The -c|--ckout option causes the listed local checkouts +** to be ignored instead. +** +** list | ls Display the location of all repositories. +** The -c|--ckout option causes all local checkouts to be +** list instead. +** +** pull Run a "pull" operation on all repositories +** +** push Run a "push" on all repositories +** +** rebuild Rebuild on all repositories +** +** sync Run a "sync" on all repositories ** ** 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: -** --showfile Show the repository or checkout being operated upon. -** --dontstop Continue with other repositories even after an error. -** --dry-run If given, display instead of run actions. +** 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. */ void all_cmd(void){ int n; Stmt q; const char *zCmd; @@ -164,70 +112,30 @@ char *zQFilename; Blob extra; int useCheckouts = 0; int quiet = 0; int dryRunFlag = 0; - int showFile = find_option("showfile",0,0)!=0; int stopOnError = find_option("dontstop",0,0)==0; int rc; - int rowCount, i = 0; - char **azFilename = 0; - char **azTag = 0; - int nToDel = 0; - int showLabel = 0; - + Bag outOfDate; + dryRunFlag = find_option("dry-run","n",0)!=0; if( !dryRunFlag ){ dryRunFlag = find_option("test",0,0)!=0; /* deprecated */ } if( g.argc<3 ){ - usage("SUBCOMMAND ..."); + usage("changes|ignore|list|ls|pull|push|rebuild|sync"); } n = strlen(g.argv[2]); db_open_config(1); blob_zero(&extra); zCmd = g.argv[2]; - if( !login_is_nobody() ) blob_appendf(&extra, " -U %s", g.zLogin); + if( g.zLogin ) blob_appendf(&extra, " -U %s", g.zLogin); if( strncmp(zCmd, "list", n)==0 || strncmp(zCmd,"ls",n)==0 ){ zCmd = "list"; useCheckouts = find_option("ckout","c",0)!=0; - }else if( strncmp(zCmd, "clean", n)==0 ){ - zCmd = "clean --chdir"; - collect_argument(&extra, "allckouts",0); - collect_argument_value(&extra, "case-sensitive"); - collect_argument_value(&extra, "clean"); - collect_argument(&extra, "dirsonly",0); - collect_argument(&extra, "dotfiles",0); - collect_argument(&extra, "emptydirs",0); - collect_argument(&extra, "force","f"); - collect_argument_value(&extra, "ignore"); - collect_argument_value(&extra, "keep"); - collect_argument(&extra, "temp",0); - collect_argument(&extra, "verbose","v"); - collect_argument(&extra, "whatif",0); - useCheckouts = 1; - }else if( strncmp(zCmd, "dbstat", n)==0 ){ - zCmd = "dbstat --omit-version-info -R"; - showLabel = 1; - quiet = 1; - collect_argument(&extra, "brief", "b"); - collect_argument(&extra, "db-check", 0); - }else if( strncmp(zCmd, "extras", n)==0 ){ - if( showFile ){ - zCmd = "extras --chdir"; - }else{ - zCmd = "extras --header --chdir"; - } - collect_argument(&extra, "abs-paths",0); - collect_argument_value(&extra, "case-sensitive"); - collect_argument(&extra, "dotfiles",0); - collect_argument_value(&extra, "ignore"); - collect_argument(&extra, "rel-paths",0); - useCheckouts = 1; - stopOnError = 0; - quiet = 1; }else if( strncmp(zCmd, "push", n)==0 ){ zCmd = "push -autourl -R"; collect_argument(&extra, "verbose","v"); }else if( strncmp(zCmd, "pull", n)==0 ){ zCmd = "pull -autourl -R"; @@ -241,22 +149,10 @@ collect_argument(&extra, "vacuum",0); collect_argument(&extra, "deanalyze",0); 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( strncmp(zCmd, "setting", n)==0 ){ - zCmd = "setting -R"; - collect_argv(&extra, 3); - }else if( strncmp(zCmd, "unset", n)==0 ){ - zCmd = "unset -R"; - collect_argv(&extra, 3); - }else if( strncmp(zCmd, "fts-config", n)==0 ){ - zCmd = "fts-config -R"; - collect_argv(&extra, 3); }else if( strncmp(zCmd, "sync", n)==0 ){ zCmd = "sync -autourl -R"; collect_argument(&extra, "verbose","v"); }else if( strncmp(zCmd, "test-integrity", n)==0 ){ collect_argument(&extra, "parse", 0); @@ -271,118 +167,66 @@ useCheckouts = 1; stopOnError = 0; quiet = 1; }else if( strncmp(zCmd, "ignore", n)==0 ){ int j; - Blob fn = BLOB_INITIALIZER; - Blob sql = BLOB_INITIALIZER; - useCheckouts = find_option("ckout","c",0)!=0; - verify_all_options(); - db_begin_transaction(); - for(j=3; j<g.argc; j++, blob_reset(&sql), blob_reset(&fn)){ - file_canonical_name(g.argv[j], &fn, 0); - blob_append_sql(&sql, - "DELETE FROM global_config WHERE name GLOB '%s:%q'", - useCheckouts?"ckout":"repo", blob_str(&fn) - ); - if( dryRunFlag ){ - fossil_print("%s\n", blob_sql_text(&sql)); - }else{ - db_multi_exec("%s", blob_sql_text(&sql)); - } - } - db_end_transaction(0); - return; - }else if( strncmp(zCmd, "add", n)==0 ){ - int j; - Blob fn = BLOB_INITIALIZER; - Blob sql = BLOB_INITIALIZER; - verify_all_options(); - db_begin_transaction(); - for(j=3; j<g.argc; j++, blob_reset(&fn), blob_reset(&sql)){ - sqlite3 *db; - int rc; - const char *z; - file_canonical_name(g.argv[j], &fn, 0); - z = blob_str(&fn); - if( !file_isfile(z) ) continue; - rc = sqlite3_open(z, &db); - if( rc!=SQLITE_OK ){ sqlite3_close(db); continue; } - rc = sqlite3_exec(db, "SELECT rcvid FROM blob, delta LIMIT 1", 0, 0, 0); - sqlite3_close(db); - if( rc!=SQLITE_OK ) continue; - blob_append_sql(&sql, - "INSERT INTO global_config(name,value)VALUES('repo:%q',1)", z - ); - if( dryRunFlag ){ - fossil_print("%s\n", blob_sql_text(&sql)); - }else{ - db_multi_exec("%s", blob_sql_text(&sql)); - } - } - db_end_transaction(0); - return; - }else if( strncmp(zCmd, "info", n)==0 ){ - zCmd = "info"; - showLabel = 1; - quiet = 1; - }else{ - fossil_fatal("\"all\" subcommand should be one of: " - "add changes clean dbstat extras fts-config ignore " - "info list ls pull push rebuild setting sync unset"); - } - verify_all_options(); - zFossil = quoteFilename(g.nameOfExe); - 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" - " FROM global_config" - " WHERE substr(name, 1, 6)=='ckout:'" - " ORDER BY 1" - ); - }else{ - db_multi_exec( - "INSERT INTO repolist " - "SELECT DISTINCT substr(name, 6), name COLLATE nocase" - " FROM global_config" - " WHERE substr(name, 1, 5)=='repo:'" - " ORDER BY 1" - ); - } - db_prepare(&q, "SELECT name, tag FROM repolist ORDER BY 1"); - rowCount = db_all_column_text(&q, 0, &azFilename, 1, &azTag); - db_finalize(&q); - db_multi_exec("CREATE TEMP TABLE todel(x TEXT)"); - while( i<rowCount ){ - const char *zFilename = azFilename[i]; - const char *zTag = azTag[i]; - if( file_access(zFilename, F_OK) - || !file_is_canonical(zFilename) - || (useCheckouts && file_isdir(zFilename)!=1) - ){ - db_multi_exec("INSERT INTO todel VALUES(%Q)", zTag); - nToDel++; - i++; continue; - } - if( zCmd[0]=='l' ){ - fossil_print("%s\n", zFilename); - i++; continue; - }else if( showFile ){ - fossil_print("%s: %s\n", useCheckouts ? "checkout" : "repository", - zFilename); + useCheckouts = find_option("ckout","c",0)!=0; + verify_all_options(); + db_begin_transaction(); + for(j=3; j<g.argc; j++){ + char *zSql = mprintf("DELETE FROM global_config" + " WHERE name GLOB '%s:%q'", + useCheckouts?"ckout":"repo", g.argv[j]); + if( dryRunFlag ){ + fossil_print("%s\n", zSql); + }else{ + db_multi_exec("%s", zSql); + } + fossil_free(zSql); + } + db_end_transaction(0); + return; + }else{ + fossil_fatal("\"all\" subcommand should be one of: " + "changes ignore list ls push pull rebuild sync"); + } + verify_all_options(); + zFossil = quoteFilename(g.nameOfExe); + if( useCheckouts ){ + db_prepare(&q, + "SELECT substr(name, 7) COLLATE nocase, max(rowid)" + " FROM global_config" + " WHERE substr(name, 1, 6)=='ckout:'" + " GROUP BY 1 ORDER BY 1" + ); + }else{ + db_prepare(&q, + "SELECT substr(name, 6) COLLATE nocase, max(rowid)" + " FROM global_config" + " WHERE substr(name, 1, 5)=='repo:'" + " GROUP BY 1 ORDER BY 1" + ); + } + bag_init(&outOfDate); + while( db_step(&q)==SQLITE_ROW ){ + const char *zFilename = db_column_text(&q, 0); + int rowid = db_column_int(&q, 1); + if( file_access(zFilename, 0) || !file_is_canonical(zFilename) ){ + bag_insert(&outOfDate, rowid); + continue; + } + if( useCheckouts && file_isdir(zFilename)!=1 ){ + bag_insert(&outOfDate, rowid); + continue; + } + if( zCmd[0]=='l' ){ + fossil_print("%s\n", zFilename); + continue; } zQFilename = quoteFilename(zFilename); zSyscmd = mprintf("%s %s %s%s", zFossil, zCmd, zQFilename, blob_str(&extra)); - if( showLabel ){ - int len = (int)strlen(zFilename); - int nStar = 80 - (len + 15); - if( nStar<2 ) nStar = 1; - fossil_print("%.13c %s %.*c\n", '*', zFilename, nStar, '*'); - } if( !quiet || dryRunFlag ){ fossil_print("%s\n", zSyscmd); fflush(stdout); } rc = dryRunFlag ? 0 : fossil_system(zSyscmd); @@ -389,24 +233,30 @@ free(zSyscmd); free(zQFilename); if( stopOnError && rc ){ break; } - i++; } - db_all_column_free(rowCount, &azFilename); - db_all_column_free(rowCount, &azTag); - assert( !azFilename ); - assert( !azTag ); - + db_finalize(&q); + /* If any repositories whose names appear in the ~/.fossil file could not ** be found, remove those names from the ~/.fossil file. */ - if( nToDel>0 ){ - const char *zSql = "DELETE FROM global_config WHERE name IN toDel"; + if( bag_count(&outOfDate)>0 ){ + Blob sql; + char *zSep = "("; + int rowid; + blob_zero(&sql); + blob_appendf(&sql, "DELETE FROM global_config WHERE rowid IN "); + for(rowid=bag_first(&outOfDate); rowid>0; rowid=bag_next(&outOfDate,rowid)){ + blob_appendf(&sql, "%s%d", zSep, rowid); + zSep = ","; + } + blob_appendf(&sql, ")"); if( dryRunFlag ){ - fossil_print("%s\n", zSql); + fossil_print("%s\n", blob_str(&sql)); }else{ - db_multi_exec("%s", zSql /*safe-for-%s*/ ); + db_multi_exec(blob_str(&sql)); } + blob_reset(&sql); } } Index: src/attach.c ================================================================== --- src/attach.c +++ src/attach.c @@ -29,11 +29,11 @@ ** ** List attachments. ** Either one of tkt= or page= are supplied or neither. If neither ** are given, all attachments are listed. If one is given, only ** attachments for the designated ticket or wiki page are shown. -** TICKETUUID must be complete +** TICKETUUID must be complete */ void attachlist_page(void){ const char *zPage = P("page"); const char *zTkt = P("tkt"); Blob sql; @@ -40,34 +40,31 @@ Stmt q; if( zPage && zTkt ) zTkt = 0; login_check_credentials(); blob_zero(&sql); - blob_append_sql(&sql, - "SELECT datetime(mtime%s), src, target, filename," + blob_append(&sql, + "SELECT datetime(mtime,'localtime'), src, target, filename," " comment, user," " (SELECT uuid FROM blob WHERE rid=attachid), attachid" " FROM attachment", - timeline_utc() + -1 ); if( zPage ){ - if( g.perm.RdWiki==0 ){ login_needed(g.anon.RdWiki); return; } + if( g.perm.RdWiki==0 ) login_needed(); style_header("Attachments To %h", zPage); - blob_append_sql(&sql, " WHERE target=%Q", zPage); + blob_appendf(&sql, " WHERE target=%Q", zPage); }else if( zTkt ){ - if( g.perm.RdTkt==0 ){ login_needed(g.anon.RdTkt); return; } - style_header("Attachments To Ticket %S", zTkt); - blob_append_sql(&sql, " WHERE target GLOB '%q*'", zTkt); + if( g.perm.RdTkt==0 ) login_needed(); + style_header("Attachments To Ticket %.10s", zTkt); + blob_appendf(&sql, " WHERE target GLOB '%q*'", zTkt); }else{ - if( g.perm.RdTkt==0 && g.perm.RdWiki==0 ){ - login_needed(g.anon.RdTkt || g.anon.RdWiki); - return; - } + if( g.perm.RdTkt==0 && g.perm.RdWiki==0 ) login_needed(); style_header("All Attachments"); } - blob_append_sql(&sql, " ORDER BY mtime DESC"); - db_prepare(&q, "%s", blob_sql_text(&sql)); + blob_appendf(&sql, " ORDER BY mtime DESC"); + db_prepare(&q, "%s", blob_str(&sql)); @ <ol> while( db_step(&q)==SQLITE_ROW ){ const char *zDate = db_column_text(&q, 0); const char *zSrc = db_column_text(&q, 1); const char *zTarget = db_column_text(&q, 2); @@ -78,11 +75,11 @@ int attachid = db_column_int(&q, 7); const char *zDispUser = zUser && zUser[0] ? zUser : "anonymous"; int i; char *zUrlTail; for(i=0; zFilename[i]; i++){ - if( zFilename[i]=='/' && zFilename[i+1]!=0 ){ + if( zFilename[i]=='/' && zFilename[i+1]!=0 ){ zFilename = &zFilename[i+1]; i = -1; } } if( strlen(zTarget)==UUID_SIZE && validate16(zTarget,UUID_SIZE) ){ @@ -89,31 +86,31 @@ zUrlTail = mprintf("tkt=%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> + @ Attachment %z(href("%R/ainfo/%s",zUuid))%S(zUuid)</a> if( moderation_pending(attachid) ){ @ <span class="modpending">*** Awaiting Moderator Approval ***</span> } - @ <br><a href="%R/attachview?%s(zUrlTail)">%h(zFilename)</a> - @ [<a href="%R/attachdownload/%t(zFilename)?%s(zUrlTail)">download</a>]<br /> + @ <br><a href="/attachview?%s(zUrlTail)">%h(zFilename)</a> + @ [<a href="/attachdownload/%t(zFilename)?%s(zUrlTail)">download</a>]<br /> if( zComment ) while( fossil_isspace(zComment[0]) ) zComment++; if( zComment && zComment[0] ){ - @ %!W(zComment)<br /> + @ %!w(zComment)<br /> } if( zPage==0 && zTkt==0 ){ if( zSrc==0 || zSrc[0]==0 ){ zSrc = "Deleted from"; }else { zSrc = "Added to"; } if( strlen(zTarget)==UUID_SIZE && validate16(zTarget, UUID_SIZE) ){ - @ %s(zSrc) ticket <a href="%R/tktview?name=%s(zTarget)"> + @ %s(zSrc) ticket <a href="%s(g.zTop)/tktview?name=%s(zTarget)"> @ %S(zTarget)</a> }else{ - @ %s(zSrc) wiki page <a href="%R/wiki?name=%t(zTarget)"> + @ %s(zSrc) wiki page <a href="%s(g.zTop)/wiki?name=%t(zTarget)"> @ %h(zTarget)</a> } }else{ if( zSrc==0 || zSrc[0]==0 ){ @ Deleted @@ -153,14 +150,14 @@ if( zPage && zTkt ) zTkt = 0; if( zFile==0 ) fossil_redirect_home(); login_check_credentials(); if( zPage ){ - if( g.perm.RdWiki==0 ){ login_needed(g.anon.RdWiki); return; } + if( g.perm.RdWiki==0 ) login_needed(); zTarget = zPage; }else if( zTkt ){ - if( g.perm.RdTkt==0 ){ login_needed(g.anon.RdTkt); return; } + if( g.perm.RdTkt==0 ) login_needed(); zTarget = zTkt; }else{ fossil_redirect_home(); } if( attachid>0 ){ @@ -217,11 +214,11 @@ }else{ rid = content_put(pAttach); db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d);", rid); db_multi_exec("INSERT OR IGNORE INTO unclustered VALUES(%d);", rid); } - manifest_crosslink(rid, pAttach, MC_NONE); + manifest_crosslink(rid, pAttach); } /* ** WEBPAGE: attachadd @@ -246,33 +243,27 @@ if( P("cancel") ) cgi_redirect(zFrom); if( zPage && zTkt ) fossil_redirect_home(); if( zPage==0 && zTkt==0 ) fossil_redirect_home(); login_check_credentials(); if( zPage ){ - if( g.perm.ApndWiki==0 || g.perm.Attach==0 ){ - login_needed(g.anon.ApndWiki && g.anon.Attach); - return; - } + if( g.perm.ApndWiki==0 || g.perm.Attach==0 ) login_needed(); if( !db_exists("SELECT 1 FROM tag WHERE tagname='wiki-%q'", zPage) ){ fossil_redirect_home(); } zTarget = zPage; - zTargetType = mprintf("Wiki Page <a href=\"%R/wiki?name=%h\">%h</a>", - zPage, zPage); + zTargetType = mprintf("Wiki Page <a href=\"%s/wiki?name=%h\">%h</a>", + g.zTop, zPage, zPage); }else{ - if( g.perm.ApndTkt==0 || g.perm.Attach==0 ){ - login_needed(g.anon.ApndTkt && g.anon.Attach); - return; - } + if( g.perm.ApndTkt==0 || g.perm.Attach==0 ) login_needed(); if( !db_exists("SELECT 1 FROM tag WHERE tagname='tkt-%q'", zTkt) ){ - zTkt = db_text(0, "SELECT substr(tagname,5) FROM tag" + zTkt = db_text(0, "SELECT substr(tagname,5) FROM tag" " WHERE tagname GLOB 'tkt-%q*'", zTkt); if( zTkt==0 ) fossil_redirect_home(); } zTarget = zTkt; - zTargetType = mprintf("Ticket <a href=\"%R/tktview/%s\">%S</a>", - zTkt, zTkt); + zTargetType = mprintf("Ticket <a href=\"%s/tktview/%S\">%S</a>", + g.zTop, zTkt, zTkt); } if( zFrom==0 ) zFrom = mprintf("%s/home", g.zTop); if( P("cancel") ){ cgi_redirect(zFrom); } @@ -297,12 +288,12 @@ if( pManifest ){ blob_compress(&content, &content); addCompress = 1; } needModerator = - (zTkt!=0 && ticket_need_moderation(0)) || - (zPage!=0 && wiki_need_moderation(0)); + (zTkt!=0 && g.perm.ModTkt==0 && db_get_boolean("modreq-tkt",0)==1) || + (zPage!=0 && g.perm.ModWiki==0 && db_get_boolean("modreq-wiki",0)==1); rid = content_put_ex(&content, 0, 0, 0, needModerator); zUUID = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); blob_zero(&manifest); for(i=n=0; zName[i]; i++){ if( zName[i]=='/' || zName[i]=='\\' ) n = i; @@ -318,11 +309,11 @@ if( n>0 ){ blob_appendf(&manifest, "C %#F\n", n, zComment); } zDate = date_in_standard_format("now"); blob_appendf(&manifest, "D %s\n", zDate); - blob_appendf(&manifest, "U %F\n", login_name()); + blob_appendf(&manifest, "U %F\n", g.zLogin ? g.zLogin : "nobody"); md5sum_blob(&manifest, &cksum); blob_appendf(&manifest, "Z %b\n", &cksum); attach_put(&manifest, rid, needModerator); assert( blob_is_reset(&manifest) ); db_end_transaction(0); @@ -374,26 +365,21 @@ int modPending; /* True if awaiting moderation */ const char *zModAction; /* Moderation action or NULL */ int isModerator; /* TRUE if user is the moderator */ const char *zMime; /* MIME Type */ Blob attach; /* Content of the attachment */ - int fShowContent = 0; - const char *zLn = P("ln"); login_check_credentials(); - if( !g.perm.RdTkt && !g.perm.RdWiki ){ - login_needed(g.anon.RdTkt || g.anon.RdWiki); - return; - } + if( !g.perm.RdTkt && !g.perm.RdWiki ){ login_needed(); 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 0 /* Shunning here needs to get both the attachment control artifact and ** the object that is attached. */ if( g.perm.Admin ){ - if( db_exists("SELECT 1 FROM shun WHERE uuid='%q'", zUuid) ){ + if( db_exists("SELECT 1 FROM shun WHERE uuid='%s'", zUuid) ){ style_submenu_element("Unshun","Unshun", "%s/shun?uuid=%s&sub=1", g.zTop, zUuid); }else{ style_submenu_element("Shun","Shun", "%s/shun?shun=%s#addshun", g.zTop, zUuid); @@ -402,26 +388,24 @@ #endif pAttach = manifest_get(rid, CFTYPE_ATTACHMENT, 0); if( pAttach==0 ) fossil_redirect_home(); zTarget = pAttach->zAttachTarget; zSrc = pAttach->zAttachSrc; - ridSrc = db_int(0,"SELECT rid FROM blob WHERE uuid='%q'", zSrc); + ridSrc = db_int(0,"SELECT rid FROM blob WHERE uuid='%s'", zSrc); zName = pAttach->zAttachName; zDesc = pAttach->zComment; - zMime = mimetype_from_name(zName); - fShowContent = zMime ? strncmp(zMime,"text/", 5)==0 : 0; if( validate16(zTarget, strlen(zTarget)) - && db_exists("SELECT 1 FROM ticket WHERE tkt_uuid='%q'", zTarget) + && db_exists("SELECT 1 FROM ticket WHERE tkt_uuid='%s'", zTarget) ){ zTktUuid = zTarget; - if( !g.perm.RdTkt ){ login_needed(g.anon.RdTkt); return; } + if( !g.perm.RdTkt ){ login_needed(); return; } if( g.perm.WrTkt ){ style_submenu_element("Delete","Delete","%R/ainfo/%s?del", zUuid); } }else if( db_exists("SELECT 1 FROM tag WHERE tagname='wiki-%q'",zTarget) ){ zWikiName = zTarget; - if( !g.perm.RdWiki ){ login_needed(g.anon.RdWiki); return; } + if( !g.perm.RdWiki ){ login_needed(); return; } if( g.perm.WrWiki ){ style_submenu_element("Delete","Delete","%R/ainfo/%s?del", zUuid); } } zDate = db_text(0, "SELECT datetime(%.12f)", pAttach->rDate); @@ -443,36 +427,36 @@ zFile += n; if( zFile[0]==0 ) zFile = "unknown"; blob_appendf(&manifest, "A %F %F\n", zFile, zTarget); zDate = date_in_standard_format("now"); blob_appendf(&manifest, "D %s\n", zDate); - blob_appendf(&manifest, "U %F\n", login_name()); + blob_appendf(&manifest, "U %F\n", g.zLogin ? g.zLogin : "nobody"); md5sum_blob(&manifest, &cksum); blob_appendf(&manifest, "Z %b\n", &cksum); rid = content_put(&manifest); - manifest_crosslink(rid, &manifest, MC_NONE); + manifest_crosslink(rid, &manifest); db_end_transaction(0); @ <p>The attachment below has been deleted.</p> } if( P("del") && ((zTktUuid && g.perm.WrTkt) || (zWikiName && g.perm.WrWiki)) ){ - form_begin(0, "%R/ainfo/%!S", zUuid); + form_begin(0, "%R/ainfo/%s", zUuid); @ <p>Confirm you want to delete the attachment shown below. @ <input type="submit" name="confirm" value="Confirm"> @ </form> } - isModerator = g.perm.Admin || + isModerator = g.perm.Admin || (zTktUuid && g.perm.ModTkt) || (zWikiName && g.perm.ModWiki); if( isModerator && (zModAction = P("modaction"))!=0 ){ if( strcmp(zModAction,"delete")==0 ){ moderation_disapprove(rid); if( zTktUuid ){ - cgi_redirectf("%R/tktview/%!S", zTktUuid); + cgi_redirectf("%R/tktview/%s", zTktUuid); }else{ cgi_redirectf("%R/wiki?name=%t", zWikiName); } return; } @@ -479,21 +463,16 @@ if( strcmp(zModAction,"approve")==0 ){ moderation_approve(rid); } } style_header("Attachment Details"); - style_submenu_element("Raw", "Raw", "%R/artifact/%s", zUuid); - if(fShowContent){ - style_submenu_element("Line Numbers", "Line Numbers", - "%R/ainfo/%s%s",zUuid, - ((zLn&&*zLn) ? "" : "?ln=0")); - } + style_submenu_element("Raw", "Raw", "%R/artifact/%S", 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> + @ <td>%z(href("%R/artifact/%s",zUuid))%s(zUuid)</a> if( g.perm.Setup ){ @ (%d(rid)) } modPending = moderation_pending(rid); if( modPending ){ @@ -515,16 +494,17 @@ @ <td>%z(href("%R/artifact/%s",zSrc))%s(zSrc)</a> if( g.perm.Setup ){ @ (%d(ridSrc)) } @ <tr><th>Filename:</th><td>%h(zName)</td></tr> + zMime = mimetype_from_name(zName); if( g.perm.Setup ){ @ <tr><th>MIME-Type:</th><td>%h(zMime)</td></tr> } @ <tr><th valign="top">Description:</th><td valign="top">%h(zDesc)</td></tr> @ </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"> @@ -537,12 +517,13 @@ } @ <div class="section">Content Appended</div> @ <blockquote> blob_zero(&attach); - if( fShowContent ){ + if( zMime==0 || strncmp(zMime,"text/", 5)==0 ){ const char *z; + const char *zLn = P("ln"); content_get(ridSrc, &attach); blob_to_utf8_no_bom(&attach, 0); z = blob_str(&attach); if( zLn ){ output_text_with_line_numbers(z, zLn); @@ -550,12 +531,12 @@ @ <pre> @ %h(z) @ </pre> } }else if( strncmp(zMime, "image/", 6)==0 ){ - @ <img src="%R/raw/%s(zSrc)?m=%s(zMime)"></img> - style_submenu_element("Image", "Image", "%R/raw/%s?m=%s", zSrc, zMime); + @ <img src="%R/raw/%S(zSrc)?m=%s(zMime)"></img> + style_submenu_element("Image", "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> @@ -572,16 +553,16 @@ const char *zHeader /* Header to display with attachments */ ){ int cnt = 0; Stmt q; db_prepare(&q, - "SELECT datetime(mtime%s), filename, user," + "SELECT datetime(mtime,'localtime'), filename, user," " (SELECT uuid FROM blob WHERE rid=attachid), src" " FROM attachment" " WHERE isLatest AND src!='' AND target=%Q" - " ORDER BY mtime DESC", - timeline_utc(), zTarget + " ORDER BY mtime DESC", + zTarget ); while( db_step(&q)==SQLITE_ROW ){ const char *zDate = db_column_text(&q, 0); const char *zFile = db_column_text(&q, 1); const char *zUser = db_column_text(&q, 2); @@ -591,17 +572,17 @@ if( cnt==0 ){ @ %s(zHeader) } cnt++; @ <li> - @ %z(href("%R/artifact/%!S",zSrc))%h(zFile)</a> + @ %z(href("%R/artifact/%s",zSrc))%h(zFile)</a> @ added by %h(zDispUser) on hyperlink_to_date(zDate, "."); - @ [%z(href("%R/ainfo/%!S",zUuid))details</a>] + @ [%z(href("%R/ainfo/%s",zUuid))details</a>] @ </li> } if( cnt ){ @ </ul> } db_finalize(&q); - + } Index: src/bag.c ================================================================== --- src/bag.c +++ src/bag.c @@ -75,11 +75,11 @@ /* ** Change the size of the hash table on a bag so that ** it contains N slots ** ** Completely reconstruct the hash table from scratch. Deleted -** entries (indicated by a -1) are removed. When finished, it +** entries (indicated by a -1) are removed. When finished, it ** should be the case that p->cnt==p->used. */ static void bag_resize(Bag *p, int newSize){ int i; Bag old; Index: src/bisect.c ================================================================== --- src/bisect.c +++ src/bisect.c @@ -206,12 +206,12 @@ "SELECT bilog.seq, bilog.stat," " substr(blob.uuid,1,16), datetime(event.mtime)" " FROM bilog, blob, event" " WHERE blob.rid=bilog.rid AND event.objid=bilog.rid" " AND event.type='ci'" - " ORDER BY %s bilog.rowid ASC", - (sortByCkinTime ? "event.mtime DESC, " : "") + " ORDER BY %s", + (sortByCkinTime ? "event.mtime DESC" : "bilog.rowid ASC") ); while( db_step(&q)==SQLITE_ROW ){ fossil_print("%3d %-7s %s %s\n", db_column_int(&q, 0), db_column_text(&q, 1), @@ -370,11 +370,11 @@ g.argv[2] = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", pMid->rid); g.argc = 3; g.fNoSync = 1; update_cmd(); } - + if( strncmp(zDisplay,"chart",m)==0 ){ bisect_chart(1); }else if( strncmp(zDisplay, "log", m)==0 ){ bisect_chart(0); }else if( strncmp(zDisplay, "status", m)==0 ){ @@ -390,17 +390,17 @@ for(i=0; i<sizeof(aBisectOption)/sizeof(aBisectOption[0]); i++){ char *z = mprintf("bisect-%s", aBisectOption[i].zName); fossil_print(" %-15s %-6s ", aBisectOption[i].zName, db_lget(z, (char*)aBisectOption[i].zDefault)); fossil_free(z); - comment_print(aBisectOption[i].zDesc, 0, 27, -1, g.comFmtFlags); + comment_print(aBisectOption[i].zDesc, 27, 79); } }else if( g.argc==4 || g.argc==5 ){ unsigned int i; n = strlen(g.argv[3]); for(i=0; i<sizeof(aBisectOption)/sizeof(aBisectOption[0]); i++){ - if( strncmp(g.argv[3], aBisectOption[i].zName, n)==0 ){ + if( memcmp(g.argv[3], aBisectOption[i].zName, n)==0 ){ char *z = mprintf("bisect-%s", aBisectOption[i].zName); if( g.argc==5 ){ db_lset(z, g.argv[4]); } fossil_print("%s\n", db_lget(z, (char*)aBisectOption[i].zDefault)); Index: src/blob.c ================================================================== --- src/blob.c +++ src/blob.c @@ -17,21 +17,12 @@ ** ** A Blob is a variable-length containers for arbitrary string ** or binary data. */ #include "config.h" -#if defined(FOSSIL_ENABLE_MINIZ) -# define MINIZ_HEADER_FILE_ONLY -# include "miniz.c" -#else -# include <zlib.h> -#endif +#include <zlib.h> #include "blob.h" -#if defined(_WIN32) -#include <fcntl.h> -#include <io.h> -#endif #if INTERFACE /* ** A Blob can hold a string or a binary object of arbitrary size. The ** size changes as necessary. @@ -38,20 +29,14 @@ */ struct Blob { unsigned int nUsed; /* Number of bytes used in aData[] */ unsigned int nAlloc; /* Number of bytes allocated for aData[] */ unsigned int iCursor; /* Next character of input to parse */ - unsigned int blobFlags; /* One or more BLOBFLAG_* bits */ char *aData; /* Where the information is stored */ void (*xRealloc)(Blob*, unsigned int); /* Function to reallocate the buffer */ }; -/* -** Allowed values for Blob.blobFlags -*/ -#define BLOBFLAG_NotSQL 0x0001 /* Non-SQL text */ - /* ** The current size of a Blob */ #define blob_size(X) ((X)->nUsed) @@ -158,11 +143,10 @@ free(pBlob->aData); pBlob->aData = 0; pBlob->nAlloc = 0; pBlob->nUsed = 0; pBlob->iCursor = 0; - pBlob->blobFlags = 0; }else if( newSize>pBlob->nAlloc || newSize<pBlob->nAlloc-4000 ){ char *pNew = fossil_realloc(pBlob->aData, newSize); pBlob->aData = pNew; pBlob->nAlloc = newSize; if( pBlob->nUsed>pBlob->nAlloc ){ @@ -173,11 +157,11 @@ /* ** An initializer for Blobs */ #if INTERFACE -#define BLOB_INITIALIZER {0,0,0,0,0,blobReallocMalloc} +#define BLOB_INITIALIZER {0,0,0,0,blobReallocMalloc} #endif const Blob empty_blob = BLOB_INITIALIZER; /* ** A reallocation function for when the initial string is in unmanaged @@ -228,11 +212,10 @@ }else{ if( size<=0 ) size = strlen(zData); pBlob->nUsed = pBlob->nAlloc = size; pBlob->aData = (char*)zData; pBlob->iCursor = 0; - pBlob->blobFlags = 0; pBlob->xRealloc = blobReallocStatic; } } /* @@ -241,19 +224,10 @@ */ void blob_set(Blob *pBlob, const char *zStr){ blob_init(pBlob, zStr, -1); } -/* -** Initialize a blob to a nul-terminated string obtained from fossil_malloc(). -** The blob will take responsibility for freeing the string. -*/ -void blob_set_dynamic(Blob *pBlob, char *zStr){ - blob_init(pBlob, zStr, -1); - pBlob->xRealloc = blobReallocMalloc; -} - /* ** Initialize a blob to an empty string. */ void blob_zero(Blob *pBlob){ static const char zEmpty[] = ""; @@ -260,11 +234,10 @@ assert_blob_is_reset(pBlob); pBlob->nUsed = 0; pBlob->nAlloc = 1; pBlob->aData = (char*)zEmpty; pBlob->iCursor = 0; - pBlob->blobFlags = 0; pBlob->xRealloc = blobReallocStatic; } /* ** Append text or data to the end of a blob. @@ -305,24 +278,10 @@ if( p->aData[p->nUsed]!=0 ){ blob_materialize(p); } return p->aData; } - -/* -** Return a pointer to a null-terminated string for a blob that has -** been created using blob_append_sql() and not blob_appendf(). If -** text was ever added using blob_appendf() then throw an error. -*/ -char *blob_sql_text(Blob *p){ - blob_is_init(p); - if( (p->blobFlags & BLOBFLAG_NotSQL) ){ - fossil_fatal("Internal error: Use of blob_appendf() to construct SQL text"); - } - return blob_str(p); -} - /* ** Return a pointer to a null-terminated string for a blob. ** ** WARNING: If the blob is ephemeral, it might cause a '\000' @@ -698,25 +657,13 @@ return i; } /* ** Do printf-style string rendering and append the results to a blob. -** -** The blob_appendf() version sets the BLOBFLAG_NotSQL bit in Blob.blobFlags -** whereas blob_append_sql() does not. */ void blob_appendf(Blob *pBlob, const char *zFormat, ...){ if( pBlob ){ - va_list ap; - va_start(ap, zFormat); - vxprintf(pBlob, zFormat, ap); - va_end(ap); - pBlob->blobFlags |= BLOBFLAG_NotSQL; - } -} -void blob_append_sql(Blob *pBlob, const char *zFormat, ...){ - if( pBlob ){ va_list ap; va_start(ap, zFormat); vxprintf(pBlob, zFormat, ap); va_end(ap); } @@ -753,11 +700,11 @@ ** Initialize a blob to be the content of a file. If the filename ** is blank or "-" then read from standard input. ** ** Any prior content of the blob is discarded, not freed. ** -** Return the number of bytes read. Calls fossil_fatal() on error (i.e. +** Return the number of bytes read. Calls fossil_fatal() error (i.e. ** it exit()s and does not return). */ int blob_read_from_file(Blob *pBlob, const char *zFilename){ int size, got; FILE *in; @@ -827,26 +774,51 @@ nWrote = blob_size(pBlob); #if defined(_WIN32) if( fossil_utf8_to_console(blob_buffer(pBlob), nWrote, 0) >= 0 ){ return nWrote; } - fflush(stdout); - _setmode(_fileno(stdout), _O_BINARY); #endif fwrite(blob_buffer(pBlob), 1, nWrote, stdout); -#if defined(_WIN32) - fflush(stdout); - _setmode(_fileno(stdout), _O_TEXT); -#endif }else{ - file_mkfolder(zFilename, 1); - out = fossil_fopen(zFilename, "wb"); + int i, nName; + char *zName, zBuf[1000]; + + nName = strlen(zFilename); + if( nName>=sizeof(zBuf) ){ + zName = mprintf("%s", zFilename); + }else{ + zName = zBuf; + memcpy(zName, zFilename, nName+1); + } + nName = file_simplify_name(zName, nName, 0); + for(i=1; i<nName; i++){ + if( zName[i]=='/' ){ + zName[i] = 0; +#if defined(_WIN32) || defined(__CYGWIN__) + /* + ** On Windows, local path looks like: C:/develop/project/file.txt + ** The if stops us from trying to create a directory of a drive letter + ** C: in this example. + */ + if( !(i==2 && zName[1]==':') ){ +#endif + if( file_mkdir(zName, 1) && file_isdir(zName)!=1 ){ + fossil_fatal_recursive("unable to create directory %s", zName); + return 0; + } +#if defined(_WIN32) || defined(__CYGWIN__) + } +#endif + zName[i] = '/'; + } + } + out = fossil_fopen(zName, "wb"); if( out==0 ){ - fossil_fatal_recursive("unable to open file \"%s\" for writing", - zFilename); + fossil_fatal_recursive("unable to open file \"%s\" for writing", zName); return 0; } + if( zName!=zBuf ) free(zName); blob_is_init(pBlob); nWrote = fwrite(blob_buffer(pBlob), 1, blob_size(pBlob), out); fclose(out); if( nWrote!=blob_size(pBlob) ){ fossil_fatal_recursive("short write: %d of %d bytes to %s", nWrote, @@ -1055,65 +1027,10 @@ } z[j] = 0; p->nUsed = j; } -/* -** Convert blob from cp1252 to UTF-8. As cp1252 is a superset -** of iso8859-1, this is useful on UNIX as well. -** -** This table contains the character translations for 0x80..0xA0. -*/ - -static const unsigned short cp1252[32] = { - 0x20ac, 0x81, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, - 0x02C6, 0x2030, 0x0160, 0x2039, 0x0152, 0x8D, 0x017D, 0x8F, - 0x90, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, - 0x2DC, 0x2122, 0x0161, 0x203A, 0x0153, 0x9D, 0x017E, 0x0178 -}; - -void blob_cp1252_to_utf8(Blob *p){ - unsigned char *z = (unsigned char *)p->aData; - int j = p->nUsed; - int i, n; - for(i=n=0; i<j; i++){ - if( z[i]>=0x80 ){ - if( (z[i]<0xa0) && (cp1252[z[i]&0x1f]>=0x800) ){ - n++; - } - n++; - } - } - j += n; - if( j>=p->nAlloc ){ - blob_resize(p, j); - z = (unsigned char *)p->aData; - } - p->nUsed = j; - z[j] = 0; - while( j>i ){ - if( z[--i]>=0x80 ){ - if( z[i]<0xa0 ){ - unsigned short sym = cp1252[z[i]&0x1f]; - if( sym>=0x800 ){ - z[--j] = 0x80 | (sym&0x3f); - z[--j] = 0x80 | ((sym>>6)&0x3f); - z[--j] = 0xe0 | (sym>>12); - }else{ - z[--j] = 0x80 | (sym&0x3f); - z[--j] = 0xc0 | (sym>>6); - } - }else{ - z[--j] = 0x80 | (z[i]&0x3f); - z[--j] = 0xC0 | (z[i]>>6); - } - }else{ - z[--j] = z[i]; - } - } -} - /* ** Shell-escape the given string. Append the result to a blob. */ void shell_escape(Blob *pBlob, const char *zIn){ int n = blob_size(pBlob); @@ -1178,18 +1095,21 @@ ** to be UTF-8 already, so no conversion is done. */ void blob_to_utf8_no_bom(Blob *pBlob, int useMbcs){ char *zUtf8; int bomSize = 0; +#if defined(_WIN32) || defined(__CYGWIN__) int bomReverse = 0; +#endif if( starts_with_utf8_bom(pBlob, &bomSize) ){ struct Blob temp; zUtf8 = blob_str(pBlob) + bomSize; blob_zero(&temp); blob_append(&temp, zUtf8, -1); blob_swap(pBlob, &temp); blob_reset(&temp); +#if defined(_WIN32) || defined(__CYGWIN__) }else if( starts_with_utf16_bom(pBlob, &bomSize, &bomReverse) ){ zUtf8 = blob_buffer(pBlob); if( bomReverse ){ /* Found BOM, but with reversed bytes */ unsigned int i = blob_size(pBlob); @@ -1202,17 +1122,18 @@ } /* Make sure the blob contains two terminating 0-bytes */ blob_append(pBlob, "", 1); zUtf8 = blob_str(pBlob) + bomSize; zUtf8 = fossil_unicode_to_utf8(zUtf8); - blob_set_dynamic(pBlob, zUtf8); - }else if( useMbcs && invalid_utf8(pBlob) ){ -#if defined(_WIN32) || defined(__CYGWIN__) + blob_zero(pBlob); + blob_append(pBlob, zUtf8, -1); + fossil_unicode_free(zUtf8); +#endif /* _WIN32 || __CYGWIN__ */ +#if defined(_WIN32) + }else if( useMbcs ){ zUtf8 = fossil_mbcs_to_utf8(blob_str(pBlob)); blob_reset(pBlob); blob_append(pBlob, zUtf8, -1); fossil_mbcs_free(zUtf8); -#else - blob_cp1252_to_utf8(pBlob); #endif /* _WIN32 */ } } Index: src/branch.c ================================================================== --- src/branch.c +++ src/branch.c @@ -51,12 +51,11 @@ verify_all_options(); if( g.argc<5 ){ usage("new BRANCH-NAME BASIS ?OPTIONS?"); } db_find_and_open_repository(0, 0); - noSign = db_get_boolean("omitsign", 0)|noSign; - if( db_get_boolean("clearsign", 0)==0 ){ noSign = 1; } + noSign = db_get_int("omitsign", 0)|noSign; /* fossil branch new name */ zBranch = g.argv[3]; if( zBranch==0 || zBranch[0]==0 ){ fossil_fatal("branch name cannot be empty"); @@ -134,16 +133,17 @@ const char *zTag = db_column_text(&q, 0); blob_appendf(&branch, "T -%F *\n", zTag); } db_finalize(&q); - blob_appendf(&branch, "U %F\n", zUserOvrd ? zUserOvrd : login_name()); + blob_appendf(&branch, "U %F\n", zUserOvrd ? zUserOvrd : g.zLogin); md5sum_blob(&branch, &mcksum); blob_appendf(&branch, "Z %b\n", &mcksum); if( !noSign && clearsign(&branch, &branch) ){ Blob ans; char cReply; + blob_zero(&ans); prompt_user("unable to sign manifest. continue (y/N)? ", &ans); cReply = blob_str(&ans)[0]; if( cReply!='y' && cReply!='Y'){ db_end_transaction(1); fossil_exit(1); @@ -153,12 +153,12 @@ brid = content_put_ex(&branch, 0, 0, 0, isPrivate); if( brid==0 ){ fossil_fatal("trouble committing manifest: %s", g.zErrMsg); } db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", brid); - if( manifest_crosslink(brid, &branch, MC_PERMIT_HOOKS)==0 ){ - fossil_fatal("%s\n", g.zErrMsg); + if( manifest_crosslink(brid, &branch)==0 ){ + fossil_fatal("unable to install new manifest"); } assert( blob_is_reset(&branch) ); content_deltify(rootid, brid, 0); zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", brid); fossil_print("New branch: %s\n", zUuid); @@ -176,70 +176,50 @@ /* Commit */ db_end_transaction(0); /* Do an autosync push, if requested */ - if( !isPrivate ) autosync_loop(SYNC_PUSH, db_get_int("autosync-tries", 1)); -} - -#if INTERFACE -/* -** Allows bits in the mBplqFlags parameter to branch_prepare_list_query(). -*/ -#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_MTIME 0x004 /* Include lastest check-in time */ -#dfeine BRL_ORDERBY_MTIME 0x008 /* Sort by MTIME. (otherwise sort by name)*/ - -#endif /* INTERFACE */ + if( !isPrivate ) autosync(SYNC_PUSH); +} /* ** Prepare a query that will list branches. ** ** If (which<0) then the query pulls only closed branches. If ** (which>0) then the query pulls all (closed and opened) ** branches. Else the query pulls currently-opened branches. */ -void branch_prepare_list_query(Stmt *pQuery, int brFlags){ - switch( brFlags & BRL_OPEN_CLOSED_MASK ){ - case BRL_CLOSED_ONLY: { - db_prepare(pQuery, - "SELECT value FROM tagxref" - " WHERE tagid=%d AND value NOT NULL " - "EXCEPT " - "SELECT value FROM tagxref" - " WHERE tagid=%d" - " AND rid IN leaf" - " AND NOT %z" - " ORDER BY value COLLATE nocase /*sort*/", - TAG_BRANCH, TAG_BRANCH, leaf_is_closed_sql("tagxref.rid") - ); - break; - } - case BRL_BOTH: { - db_prepare(pQuery, - "SELECT DISTINCT value FROM tagxref" - " WHERE tagid=%d AND value NOT NULL" - " AND rid IN leaf" - " ORDER BY value COLLATE nocase /*sort*/", - TAG_BRANCH - ); - break; - } - case BRL_OPEN_ONLY: { - db_prepare(pQuery, - "SELECT DISTINCT value FROM tagxref" - " WHERE tagid=%d AND value NOT NULL" - " AND rid IN leaf" - " AND NOT %z" - " ORDER BY value COLLATE nocase /*sort*/", - TAG_BRANCH, leaf_is_closed_sql("tagxref.rid") - ); - break; - } +void branch_prepare_list_query(Stmt *pQuery, int which ){ + if( which < 0 ){ + db_prepare(pQuery, + "SELECT value FROM tagxref" + " WHERE tagid=%d AND value NOT NULL " + "EXCEPT " + "SELECT value FROM tagxref" + " WHERE tagid=%d" + " AND rid IN leaf" + " AND NOT %z" + " ORDER BY value COLLATE nocase /*sort*/", + TAG_BRANCH, TAG_BRANCH, leaf_is_closed_sql("tagxref.rid") + ); + }else if( which>0 ){ + db_prepare(pQuery, + "SELECT DISTINCT value FROM tagxref" + " WHERE tagid=%d AND value NOT NULL" + " AND rid IN leaf" + " ORDER BY value COLLATE nocase /*sort*/", + TAG_BRANCH + ); + }else{ + db_prepare(pQuery, + "SELECT DISTINCT value FROM tagxref" + " WHERE tagid=%d AND value NOT NULL" + " AND rid IN leaf" + " AND NOT %z" + " ORDER BY value COLLATE nocase /*sort*/", + TAG_BRANCH, leaf_is_closed_sql("tagxref.rid") + ); } } /* @@ -272,28 +252,30 @@ */ void branch_cmd(void){ int n; const char *zCmd = "list"; db_find_and_open_repository(0, 0); + if( g.argc<2 ){ + usage("new|list|ls ..."); + } if( g.argc>=3 ) zCmd = g.argv[2]; n = strlen(zCmd); if( strncmp(zCmd,"new",n)==0 ){ branch_new(); }else if( (strncmp(zCmd,"list",n)==0)||(strncmp(zCmd, "ls", n)==0) ){ Stmt q; int vid; char *zCurrent = 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; + int showAll = find_option("all","a",0)!=0; + int showClosed = find_option("closed","c",0)!=0; 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); + branch_prepare_list_query(&q, showAll?1:(showClosed?-1:0)); while( db_step(&q)==SQLITE_ROW ){ const char *zBr = db_column_text(&q, 0); int isCur = zCurrent!=0 && fossil_strcmp(zCurrent,zBr)==0; fossil_print("%s%s\n", (isCur ? "* " : " "), zBr); } @@ -302,130 +284,35 @@ fossil_fatal("branch subcommand should be one of: " "new list ls"); } } -static const char brlistQuery[] = -@ SELECT -@ tagxref.value, -@ max(event.mtime), -@ EXISTS(SELECT 1 FROM tagxref AS tx -@ WHERE tx.rid=tagxref.rid -@ AND tx.tagid=(SELECT tagid FROM tag WHERE tagname='closed') -@ AND tx.tagtype>0), -@ (SELECT tagxref.value -@ FROM plink CROSS JOIN tagxref -@ WHERE plink.pid=event.objid -@ AND tagxref.rid=plink.cid -@ AND tagxref.tagid=(SELECT tagid FROM tag WHERE tagname='branch') -@ AND tagtype>0), -@ count(*), -@ (SELECT uuid FROM blob WHERE rid=tagxref.rid) -@ FROM tagxref, tag, event -@ WHERE tagxref.tagid=tag.tagid -@ AND tagxref.tagtype>0 -@ AND tag.tagname='branch' -@ AND event.objid=tagxref.rid -@ GROUP BY 1 -@ ORDER BY 2 DESC; -; - -/* -** This is the new-style branch-list page that shows the branch names -** together with their ages (time of last check-in) and whether or not -** they are closed or merged to another branch. -** -** Control jumps to this routine from brlist_page() (the /brlist handler) -** if there are no query parameters. -*/ -static void new_brlist_page(void){ - Stmt q; - double rNow; - login_check_credentials(); - if( !g.perm.Read ){ login_needed(g.anon.Read); return; } - style_header("Branches"); - style_adunit_config(ADUNIT_RIGHT_OK); - login_anonymous_available(); - - db_prepare(&q, brlistQuery/*works-like:""*/); - rNow = db_double(0.0, "SELECT julianday('now')"); - @ <div class="brlist"><table id="branchlisttable"> - @ <thead><tr> - @ <th>Branch Name</th> - @ <th>Age</th> - @ <th>Check-ins</th> - @ <th>Status</th> - @ <th>Resolution</th> - @ </tr></thead><tbody> - while( db_step(&q)==SQLITE_ROW ){ - const char *zBranch = db_column_text(&q, 0); - double rMtime = db_column_double(&q, 1); - int isClosed = db_column_int(&q, 2); - const char *zMergeTo = db_column_text(&q, 3); - int nCkin = db_column_int(&q, 4); - const char *zLastCkin = db_column_text(&q, 5); - char *zAge = human_readable_age(rNow - rMtime); - sqlite3_int64 iMtime = (sqlite3_int64)(rMtime*86400.0); - if( zMergeTo && zMergeTo[0]==0 ) zMergeTo = 0; - @ <tr> - @ <td>%z(href("%R/timeline?n=100&r=%T",zBranch))%h(zBranch)</a></td> - @ <td data-sortkey="%016llx(-iMtime)">%s(zAge)</td> - @ <td>%d(nCkin)</td> - fossil_free(zAge); - @ <td>%s(isClosed?"closed":"")</td> - if( zMergeTo ){ - @ <td>merged into - @ %z(href("%R/timeline?f=%!S",zLastCkin))%h(zMergeTo)</a></td> - }else{ - @ <td></td> - } - @ </tr> - } - @ </tbody></table></div> - db_finalize(&q); - output_table_sorting_javascript("branchlisttable","tkNtt",2); - style_footer(); -} - /* ** WEBPAGE: brlist -** Show a list of branches -** Query parameters: ** -** all Show all branches -** closed Show only closed branches -** open Show only open branches (default behavior) -** colortest Show all branches with automatic color +** Show a timeline of all branches */ void brlist_page(void){ Stmt q; int cnt; int showClosed = P("closed")!=0; int showAll = P("all")!=0; - int showOpen = P("open")!=0; int colorTest = P("colortest")!=0; - int brFlags = BRL_OPEN_ONLY; - 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( !g.perm.Read ){ login_needed(); return; } if( colorTest ){ showClosed = 0; showAll = 1; } - if( showAll ) brFlags = BRL_BOTH; - if( showClosed ) brFlags = BRL_CLOSED_ONLY; - style_header("%s", showClosed ? "Closed Branches" : - showAll ? "All Branches" : "Open Branches"); + style_header(showClosed ? "Closed Branches" : + showAll ? "All Branches" : "Open Branches"); style_submenu_element("Timeline", "Timeline", "brtimeline"); if( showClosed ){ style_submenu_element("All", "All", "brlist?all"); - style_submenu_element("Open","Open","brlist?open"); + style_submenu_element("Open","Open","brlist"); }else if( showAll ){ style_submenu_element("Closed", "Closed", "brlist?closed"); style_submenu_element("Open","Open","brlist"); }else{ style_submenu_element("All", "All", "brlist?all"); @@ -435,11 +322,10 @@ style_submenu_element("Color-Test", "Color-Test", "brlist?colortest"); }else{ style_submenu_element("All", "All", "brlist?all"); } login_anonymous_available(); -#if 0 style_sidebox_begin("Nomenclature:", "33%"); @ <ol> @ <li> An <div class="sideboxDescribed">%z(href("brlist")) @ open branch</a></div> is a branch that has one or more @ <div class="sideboxDescribed">%z(href("leaves"))open leaves.</a></div> @@ -448,26 +334,25 @@ @ <li> A <div class="sideboxDescribed">%z(href("brlist?closed")) @ closed branch</a></div> is a branch with only @ <div class="sideboxDescribed">%z(href("leaves?closed")) @ closed leaves</a></div>. @ Closed branches are fixed and do not change (unless they are first - @ reopened).</li> + @ reopened)</li> @ </ol> style_sidebox_end(); -#endif - branch_prepare_list_query(&q, brFlags); + branch_prepare_list_query(&q, showAll?1:(showClosed?-1: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( showAll ){ + @ <h2>All Branches:</h2> }else if( showClosed ){ @ <h2>Closed Branches:</h2> - }else if( showAll ){ - @ <h2>All Branches:</h2> }else{ @ <h2>Open Branches:</h2> } @ <ul> cnt++; @@ -475,17 +360,23 @@ if( colorTest ){ const char *zColor = hash_color(zBr); @ <li><span style="background-color: %s(zColor)"> @ %h(zBr) → %s(zColor)</span></li> }else{ - @ <li>%z(href("%R/timeline?r=%T&n=200",zBr))%h(zBr)</a></li> + @ <li>%z(href("%R/timeline?r=%T",zBr))%h(zBr)</a></li> } } if( cnt ){ @ </ul> } db_finalize(&q); + @ <script type="text/JavaScript"> + @ function xin(id){ + @ } + @ function xout(id){ + @ } + @ </script> style_footer(); } /* ** This routine is called while for each check-in that is rendered by @@ -503,11 +394,11 @@ " AND tag.tagname GLOB 'sym-*'", rid ); while( db_step(&q)==SQLITE_ROW ){ const char *zTagName = db_column_text(&q, 0); - @ %z(href("%R/timeline?r=%T&n=200",zTagName))[timeline]</a> + @ %z(href("%R/timeline?r=%T",zTagName))[timeline]</a> } db_finalize(&q); } /* @@ -517,11 +408,11 @@ */ void brtimeline_page(void){ Stmt q; login_check_credentials(); - if( !g.perm.Read ){ login_needed(g.anon.Read); return; } + if( !g.perm.Read ){ login_needed(); return; } style_header("Branches"); style_submenu_element("List", "List", "brlist"); login_anonymous_available(); @ <h2>The initial check-in for each branch:</h2> @@ -529,9 +420,15 @@ "%s AND blob.rid IN (SELECT rid FROM tagxref" " WHERE tagtype>0 AND tagid=%d AND srcid!=0)" " ORDER BY event.mtime DESC", timeline_query_for_www(), TAG_BRANCH ); - www_print_timeline(&q, 0, 0, 0, 0, brtimeline_extra); + www_print_timeline(&q, 0, 0, 0, brtimeline_extra); db_finalize(&q); + @ <script type="text/JavaScript"> + @ function xin(id){ + @ } + @ function xout(id){ + @ } + @ </script> style_footer(); } Index: src/browse.c ================================================================== --- src/browse.c +++ src/browse.c @@ -71,29 +71,23 @@ ** There is no hyperlink on the file element of the path. ** ** The computed string is appended to the pOut blob. pOut should ** have already been initialized. */ -void hyperlinked_path( - const char *zPath, /* Path to render */ - Blob *pOut, /* Write into this blob */ - const char *zCI, /* check-in name, or NULL */ - const char *zURI, /* "dir" or "tree" */ - const char *zREx /* Extra query parameters */ -){ +void hyperlinked_path(const char *zPath, Blob *pOut, const char *zCI){ int i, j; char *zSep = ""; for(i=0; zPath[i]; i=j){ for(j=i; zPath[j] && zPath[j]!='/'; j++){} if( zPath[j] && g.perm.Hyperlink ){ if( zCI ){ - char *zLink = href("%R/%s?name=%#T%s&ci=%!S", zURI, j, zPath, zREx,zCI); + char *zLink = href("%R/dir?ci=%S&name=%#T", zCI, j, zPath); blob_appendf(pOut, "%s%z%#h</a>", zSep, zLink, j-i, &zPath[i]); }else{ - char *zLink = href("%R/%s?name=%#T%s", zURI, j, zPath, zREx); + char *zLink = href("%R/dir?name=%#T", j, zPath); blob_appendf(pOut, "%s%z%#h</a>", zSep, zLink, j-i, &zPath[i]); } }else{ blob_appendf(pOut, "%s%#h", zSep, j-i, &zPath[i]); @@ -107,11 +101,11 @@ /* ** WEBPAGE: dir ** ** Query parameters: ** -** name=PATH Directory to display. Optional. Top-level if missing +** name=PATH Directory to display. Required. ** ci=LABEL Show only files in this check-in. Optional. */ void page_dir(void){ char *zD = fossil_strdup(P("name")); int nD = zD ? strlen(zD)+1 : 0; @@ -124,24 +118,18 @@ int rid = 0; char *zUuid = 0; Blob dirname; Manifest *pM = 0; const char *zSubdirLink; - int linkTrunk = 1; - int linkTip = 1; - HQuery sURI; + int linkTrunk = 1, linkTip = 1; - if( strcmp(PD("type","flat"),"tree")==0 ){ page_tree(); return; } login_check_credentials(); - if( !g.perm.Read ){ login_needed(g.anon.Read); return; } + if( !g.perm.Read ){ login_needed(); return; } while( nD>1 && zD[nD-2]=='/' ){ zD[(--nD)-1] = 0; } style_header("File List"); - style_adunit_config(ADUNIT_RIGHT_OK); sqlite3_create_function(g.db, "pathelement", 2, SQLITE_UTF8, 0, pathelementFunc, 0, 0); - url_initialize(&sURI, "dir"); - cgi_query_parameters_to_url(&sURI); /* 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 @@ -162,43 +150,49 @@ /* Compute the title of the page */ blob_zero(&dirname); if( zD ){ blob_append(&dirname, "in directory ", -1); - hyperlinked_path(zD, &dirname, zCI, "dir", ""); + hyperlinked_path(zD, &dirname, zCI); zPrefix = mprintf("%s/", zD); - style_submenu_element("Top-Level", "Top-Level", "%s", - url_render(&sURI, "name", 0, 0, 0)); + if( linkTrunk ){ + style_submenu_element("Trunk", "Trunk", "%R/dir?name=%t&ci=trunk", + zD); + } + if ( linkTip ){ + style_submenu_element("Tip", "Tip", "%R/dir?name=%t&ci=tip", zD); + } }else{ blob_append(&dirname, "in the top-level directory", -1); zPrefix = ""; - } - if( linkTrunk ){ - style_submenu_element("Trunk", "Trunk", "%s", - url_render(&sURI, "ci", "trunk", 0, 0)); - } - if( linkTip ){ - style_submenu_element("Tip", "Tip", "%s", - url_render(&sURI, "ci", "tip", 0, 0)); + if( linkTrunk ){ + style_submenu_element("Trunk", "Trunk", "%R/dir?ci=trunk"); + } + if ( linkTip ){ + style_submenu_element("Tip", "Tip", "%R/dir?ci=tip"); + } } if( zCI ){ - @ <h2>Files of check-in [%z(href("vinfo?name=%!S",zUuid))%S(zUuid)</a>] + char zShort[20]; + memcpy(zShort, zUuid, 10); + zShort[10] = 0; + @ <h2>Files of check-in [%z(href("vinfo?name=%T",zUuid))%s(zShort)</a>] @ %s(blob_str(&dirname))</h2> - zSubdirLink = mprintf("%R/dir?ci=%!S&name=%T", zUuid, zPrefix); - if( nD==0 ){ - style_submenu_element("File Ages", "File Ages", "%R/fileage?name=%!S", + zSubdirLink = mprintf("%R/dir?ci=%S&name=%T", zUuid, zPrefix); + if( zD ){ + style_submenu_element("Top", "Top", "%R/dir?ci=%S", zUuid); + style_submenu_element("All", "All", "%R/dir?name=%t", zD); + }else{ + style_submenu_element("All", "All", "%R/dir"); + style_submenu_element("File Ages", "File Ages", "%R/fileage?name=%S", zUuid); } }else{ @ <h2>The union of all files from all check-ins @ %s(blob_str(&dirname))</h2> zSubdirLink = mprintf("%R/dir?name=%T", zPrefix); } - style_submenu_element("All", "All", "%s", - url_render(&sURI, "ci", 0, 0, 0)); - style_submenu_element("Tree-View", "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 @@ -281,11 +275,11 @@ @ <li class="dir">%z(href("%s%T",zSubdirLink,zFN))%h(zFN)</a></li> }else{ const char *zLink; if( zCI ){ const char *zUuid = db_column_text(&q, 1); - zLink = href("%R/artifact/%!S",zUuid); + zLink = href("%R/artifact/%s",zUuid); }else{ zLink = href("%R/finfo?name=%T%T",zPrefix,zFN); } @ <li class="%z(fileext_class(zFN))">%z(zLink)%h(zFN)</a></li> } @@ -294,569 +288,10 @@ manifest_destroy(pM); @ </ul></td></tr></table> style_footer(); } -/* -** Objects used by the "tree" webpage. -*/ -typedef struct FileTreeNode FileTreeNode; -typedef struct FileTree FileTree; - -/* -** A single line of the file hierarchy -*/ -struct FileTreeNode { - FileTreeNode *pNext; /* Next entry in an ordered list of them all */ - FileTreeNode *pParent; /* Directory containing this entry */ - 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; /* SHA1 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 -*/ -struct FileTree { - FileTreeNode *pFirst; /* First line of the list */ - FileTreeNode *pLast; /* Last line of the list */ - FileTreeNode *pLastTop; /* Last top-level node */ -}; - -/* -** Add one or more new FileTreeNodes to the FileTree object so that the -** leaf object zPathname is at the end of the node list. -** -** The caller invokes this routine once for each leaf node (each file -** as opposed to each directory). This routine fills in any missing -** intermediate nodes automatically. -** -** When constructing a list of FileTreeNodes, all entries that have -** 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, /* UUID of the file. Might be NULL. */ - double mtime /* Modification time for this entry */ -){ - 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]!='/' ) - ){ - pParent = pParent->pParent; - } - i = pParent ? pParent->nFullName+1 : 0; - while( zPath[i] ){ - FileTreeNode *pNew; - int iStart = i; - int nByte; - while( zPath[i] && zPath[i]!='/' ){ i++; } - nByte = sizeof(*pNew) + i + 1; - if( zUuid!=0 && zPath[i]==0 ) nByte += UUID_SIZE+1; - pNew = fossil_malloc( nByte ); - memset(pNew, 0, sizeof(*pNew)); - pNew->zFullName = (char*)&pNew[1]; - memcpy(pNew->zFullName, zPath, i); - pNew->zFullName[i] = 0; - pNew->nFullName = i; - if( zUuid!=0 && zPath[i]==0 ){ - pNew->zUuid = pNew->zFullName + i + 1; - memcpy(pNew->zUuid, zUuid, UUID_SIZE+1); - } - pNew->zName = pNew->zFullName + iStart; - if( pTree->pLast ){ - pTree->pLast->pNext = pNew; - }else{ - pTree->pFirst = pNew; - } - pTree->pLast = pNew; - pNew->pParent = pParent; - if( pParent ){ - if( pParent->pChild ){ - pParent->pLastChild->pSibling = pNew; - }else{ - pParent->pChild = pNew; - } - 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 -** mtime (larger numbers first) and then by zName (smaller names first). -** -** Return negative if pLeft<pRight. -** Return positive if pLeft>pRight. -** Return zero if pLeft==pRight. -*/ -static int compareNodes(FileTreeNode *pLeft, FileTreeNode *pRight){ - if( pLeft->mtime>pRight->mtime ) return -1; - if( pLeft->mtime<pRight->mtime ) 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; - pEnd = &base; - while( pLeft && pRight ){ - if( compareNodes(pLeft,pRight)<=0 ){ - pEnd = pEnd->pSibling = pLeft; - pLeft = pLeft->pSibling; - }else{ - pEnd = pEnd->pSibling = pRight; - pRight = pRight->pSibling; - } - } - if( pLeft ){ - pEnd->pSibling = pLeft; - }else{ - pEnd->pSibling = pRight; - } - return base.pSibling; -} - -/* Sort a list of FileTreeNode objects in mtime order. */ -static FileTreeNode *sortNodesByMtime(FileTreeNode *p){ - FileTreeNode *a[30]; - FileTreeNode *pX; - int i; - - memset(a, 0, sizeof(a)); - while( p ){ - pX = p; - p = pX->pSibling; - pX->pSibling = 0; - for(i=0; i<count(a)-1 && a[i]!=0; i++){ - pX = mergeNodes(a[i], pX); - a[i] = 0; - } - a[i] = mergeNodes(a[i], pX); - } - pX = 0; - for(i=0; i<count(a); i++){ - pX = mergeNodes(a[i], pX); - } - return pX; -} - -/* Sort an entire FileTreeNode tree by mtime -** -** This routine invalidates the following fields: -** -** FileTreeNode.pLastChild -** FileTreeNode.pNext -** -** Use relinkTree to reconnect the pNext pointers. -*/ -static FileTreeNode *sortTreeByMtime(FileTreeNode *p){ - FileTreeNode *pX; - for(pX=p; pX; pX=pX->pSibling){ - if( pX->pChild ) pX->pChild = sortTreeByMtime(pX->pChild); - } - return sortNodesByMtime(p); -} - -/* Reconstruct the FileTree by reconnecting the FileTreeNode.pNext -** fields in sequential order. -*/ -static void relinkTree(FileTree *pTree, FileTreeNode *pRoot){ - while( pRoot ){ - if( pTree->pLast ){ - pTree->pLast->pNext = pRoot; - }else{ - pTree->pFirst = pRoot; - } - pTree->pLast = pRoot; - if( pRoot->pChild ) relinkTree(pTree, pRoot->pChild); - pRoot = pRoot->pSibling; - } - if( pTree->pLast ) pTree->pLast->pNext = 0; -} - - -/* -** WEBPAGE: tree -** -** 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. -** expand Begin with the tree fully expanded. -** nofiles Show directories (folders) only. Omit files. -** mtime Order directory elements by decreasing mtime -*/ -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 nFile = 0; /* Number of files (or folders with "nofiles") */ - 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 */ - FileTree sTree; /* The complete tree of files */ - HQuery sURI; /* Hyperlink */ - int startExpanded; /* True to start out with the tree expanded */ - int showDirOnly; /* Show directories only. Omit files */ - int nDir = 0; /* Number of directories. Used for ID attributes */ - char *zProjectName = db_get("project-name", 0); - - if( strcmp(PD("type","flat"),"flat")==0 ){ page_dir(); return; } - memset(&sTree, 0, sizeof(sTree)); - login_check_credentials(); - if( !g.perm.Read ){ login_needed(g.anon.Read); return; } - while( nD>1 && zD[nD-2]=='/' ){ zD[(--nD)-1] = 0; } - sqlite3_create_function(g.db, "pathelement", 2, SQLITE_UTF8, 0, - pathelementFunc, 0, 0); - url_initialize(&sURI, "tree"); - cgi_query_parameters_to_url(&sURI); - if( PB("nofiles") ){ - showDirOnly = 1; - style_header("Folder Hierarchy"); - }else{ - showDirOnly = 0; - style_header("File Tree"); - } - style_adunit_config(ADUNIT_RIGHT_OK); - if( PB("expand") ){ - startExpanded = 1; - }else{ - startExpanded = 0; - } - - /* 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. - */ - 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); - rNow = db_double(0.0, "SELECT mtime FROM event WHERE objid=%d", rid); - zNow = db_text("", "SELECT datetime(mtime,'localtime')" - " FROM event WHERE objid=%d", rid); - }else{ - zCI = 0; - } - } - if( zCI==0 ){ - rNow = db_double(0.0, "SELECT max(mtime) FROM event"); - zNow = db_text("", "SELECT datetime(max(mtime),'localtime') FROM event"); - } - - /* Compute the title of the page */ - blob_zero(&dirname); - if( zD ){ - blob_append(&dirname, "within directory ", -1); - hyperlinked_path(zD, &dirname, zCI, "tree", zREx); - if( zRE ) blob_appendf(&dirname, " matching \"%s\"", zRE); - style_submenu_element("Top-Level", "Top-Level", "%s", - url_render(&sURI, "name", 0, 0, 0)); - }else{ - if( zRE ){ - blob_appendf(&dirname, "matching \"%s\"", zRE); - } - } - style_submenu_binary("mtime","Sort By Time","Sort By Filename", 0); - if( zCI ){ - style_submenu_element("All", "All", "%s", - url_render(&sURI, "ci", 0, 0, 0)); - if( nD==0 && !showDirOnly ){ - style_submenu_element("File Ages", "File Ages", "%R/fileage?name=%s", - zUuid); - } - } - if( linkTrunk ){ - style_submenu_element("Trunk", "Trunk", "%s", - url_render(&sURI, "ci", "trunk", 0, 0)); - } - if( linkTip ){ - style_submenu_element("Tip", "Tip", "%s", - url_render(&sURI, "ci", "tip", 0, 0)); - } - style_submenu_element("Flat-View", "Flat-View", "%s", - url_render(&sURI, "type", "flat", 0, 0)); - - /* Compute the file hierarchy. - */ - if( zCI ){ - Stmt q; - compute_fileage(rid, 0); - db_prepare(&q, - "SELECT filename.name, blob.uuid, 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 nocase;" - ); - while( db_step(&q)==SQLITE_ROW ){ - const char *zFile = db_column_text(&q,0); - const char *zUuid = db_column_text(&q,1); - double mtime = db_column_double(&q,2); - 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); - nFile++; - } - db_finalize(&q); - }else{ - Stmt q; - db_prepare(&q, - "SELECT filename.name, blob.uuid, max(event.mtime)\n" - " FROM filename, mlink, blob, event\n" - " WHERE mlink.fnid=filename.fnid\n" - " AND event.objid=mlink.mid\n" - " AND blob.rid=mlink.fid\n" - " GROUP BY 1 ORDER BY 1 COLLATE nocase"); - while( db_step(&q)==SQLITE_ROW ){ - const char *zName = db_column_text(&q, 0); - const char *zUuid = db_column_text(&q,1); - double mtime = db_column_double(&q,2); - 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); - nFile++; - } - db_finalize(&q); - } - - if( showDirOnly ){ - for(nFile=0, p=sTree.pFirst; p; p=p->pNext){ - if( p->pChild!=0 && p->nFullName>nD ) nFile++; - } - zObjType = "Folders"; - style_submenu_element("Files","Files","%s", - url_render(&sURI,"nofiles",0,0,0)); - }else{ - zObjType = "Files"; - style_submenu_element("Folders","Folders","%s", - url_render(&sURI,"nofiles","1",0,0)); - } - - if( zCI ){ - @ <h2>%s(zObjType) from - if( sqlite3_strnicmp(zCI, zUuid, (int)strlen(zCI))!=0 ){ - @ "%h(zCI)" - } - @ [%z(href("vinfo?name=%!S",zUuid))%S(zUuid)</a>] %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( useMtime ){ - @ sorted by modification time</h2> - }else{ - @ sorted by filename</h2> - } - - - /* Generate tree of lists. - ** - ** Each file and directory is a list element: <li>. Files have class=file - ** and if the filename as the suffix "xyz" the file also has class=file-xyz. - ** Directories have class=dir. The directory specfied by the name= query - ** parameter (or the top-level directory if there is no name= query parameter) - ** adds class=subdir. - ** - ** The <li> element for directories also contains a sublist <ul> - ** for the contents of that directory. - */ - @ <div class="filetree"><ul> - if( nD ){ - @ <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">%s(zNow)</div> - } - @ </div> - @ <ul> - if( useMtime ){ - p = sortTreeByMtime(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 = 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> - if( startExpanded || 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/artifact/%!S",p->zUuid); - }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> - } - if( p->pSibling==0 ){ - int nClose = p->iLevel - (p->pNext ? p->pNext->iLevel : 0); - while( nClose-- > 0 ){ - @ </ul> - } - } - } - @ </ul> - @ </ul></div> - @ <script>(function(){ - @ function isExpanded(ul){ - @ return ul.className==''; - @ } - @ - @ function toggleDir(ul, useInitValue){ - @ if( !useInitValue ){ - @ expandMap[ul.id] = !isExpanded(ul); - @ history.replaceState(expandMap, ''); - @ } - @ ul.className = expandMap[ul.id] ? '' : 'collapsed'; - @ } - @ - @ function toggleAll(tree, useInitValue){ - @ var lists = tree.querySelectorAll('.subdir > ul > li ul'); - @ if( !useInitValue ){ - @ var expand = true; /* Default action: make all sublists visible */ - @ for( var i=0; lists[i]; i++ ){ - @ if( isExpanded(lists[i]) ){ - @ expand = false; /* Any already visible - make them all hidden */ - @ break; - @ } - @ } - @ expandMap = {'*': expand}; - @ history.replaceState(expandMap, ''); - @ } - @ var className = expandMap['*'] ? '' : 'collapsed'; - @ for( var i=0; lists[i]; i++ ){ - @ lists[i].className = className; - @ } - @ } - @ - @ function checkState(){ - @ expandMap = history.state || {}; - @ if( '*' in expandMap ) toggleAll(outer_ul, true); - @ for( var id in expandMap ){ - @ if( id!=='*' ) toggleDir(gebi(id), true); - @ } - @ } - @ - @ function belowSubdir(node){ - @ do{ - @ node = node.parentNode; - @ if( node==subdir ) return true; - @ } while( node && node!=outer_ul ); - @ return false; - @ } - @ - @ var history = window.history || {}; - @ if( !history.replaceState ) history.replaceState = function(){}; - @ var outer_ul = document.querySelector('.filetree > ul'); - @ var subdir = outer_ul.querySelector('.subdir'); - @ var expandMap = {}; - @ checkState(); - @ outer_ul.onclick = function(e){ - @ e = e || window.event; - @ var a = e.target || e.srcElement; - @ if( a.nodeName!='A' ) return true; - @ if( a.parentNode.parentNode==subdir ){ - @ toggleAll(outer_ul); - @ return false; - @ } - @ if( !belowSubdir(a) ) return true; - @ var ul = a.parentNode.nextSibling; - @ while( ul && ul.nodeName!='UL' ) ul = ul.nextSibling; - @ if( !ul ) return true; /* This is a file link, not a directory */ - @ toggleDir(ul); - @ return false; - @ } - @ }())</script> - style_footer(); - - /* We could free memory used by sTree here if we needed to. But - ** the process is about to exit, so doing so would not really accomplish - ** anything useful. */ -} - /* ** Return a CSS class name based on the given filename's extension. ** Result must be freed by the caller. **/ const char *fileext_class(const char *zFilename){ @@ -864,235 +299,162 @@ const char *zExt = strrchr(zFilename, '.'); int isExt = zExt && zExt!=zFilename && zExt[1]; int i; for( i=1; isExt && zExt[i]; i++ ) isExt &= fossil_isalnum(zExt[i]); if( isExt ){ - zClass = mprintf("file file-%s", zExt+1); - for( i=5; zClass[i]; i++ ) zClass[i] = fossil_tolower(zClass[i]); + zClass = mprintf("file-%s", zExt+1); + for ( i=5; zClass[i]; i++ ) zClass[i] = fossil_tolower(zClass[i]); }else{ zClass = mprintf("file"); } return zClass; } -/* -** SQL used to compute the age of all files in check-in :ckin whose -** names match :glob -*/ -static const char zComputeFileAgeSetup[] = -@ CREATE TABLE IF NOT EXISTS temp.fileage( -@ fnid INTEGER PRIMARY KEY, -@ fid INTEGER, -@ mid INTEGER, -@ mtime DATETIME, -@ pathname TEXT -@ ); -@ CREATE VIRTUAL TABLE IF NOT EXISTS temp.foci USING files_of_checkin; -; - -static const char zComputeFileAgeRun[] = -@ WITH RECURSIVE -@ ckin(x,m) AS (SELECT objid, mtime FROM event WHERE objid=:ckin -@ UNION -@ SELECT plink.pid, event.mtime -@ FROM ckin, plink, event -@ WHERE plink.cid=ckin.x AND event.objid=plink.pid -@ ORDER BY 2 DESC) -@ INSERT OR IGNORE INTO fileage(fnid, fid, mid, mtime, pathname) -@ SELECT filename.fnid, mlink.fid, mlink.mid, event.mtime, filename.name -@ FROM foci, filename, blob, mlink, event -@ WHERE foci.checkinID=:ckin -@ AND foci.filename GLOB :glob -@ AND filename.name=foci.filename -@ AND blob.uuid=foci.uuid -@ AND mlink.fid=blob.rid -@ AND mlink.fid!=mlink.pid -@ AND mlink.mid IN (SELECT x FROM ckin) -@ AND event.objid=mlink.mid -@ ORDER BY event.mtime ASC; -; - /* ** Look at all file containing in the version "vid". Construct a ** temporary table named "fileage" that contains the file-id for each ** files, the pathname, the check-in where the file was added, and the -** mtime on that check-in. If zGlob and *zGlob then only files matching -** the given glob are computed. -*/ -int compute_fileage(int vid, const char* zGlob){ - Stmt q; - db_multi_exec(zComputeFileAgeSetup /*works-like:"constant"*/); - db_prepare(&q, zComputeFileAgeRun /*works-like:"constant"*/); - db_bind_int(&q, ":ckin", vid); - db_bind_text(&q, ":glob", zGlob && zGlob[0] ? zGlob : "*"); - db_exec(&q); - db_finalize(&q); - return 0; -} - -/* -** Render the number of days in rAge as a more human-readable time span. -** Different units (seconds, minutes, hours, days, months, years) are -** selected depending on the magnitude of rAge. -** -** The string returned is obtained from fossil_malloc() and should be -** freed by the caller. -*/ -char *human_readable_age(double rAge){ - if( rAge*86400.0<120 ){ - if( rAge*86400.0<1.0 ){ - return mprintf("current"); - }else{ - return mprintf("%d seconds", (int)(rAge*86400.0)); - } - }else if( rAge*1440.0<90 ){ - return mprintf("%.1f minutes", rAge*1440.0); - }else if( rAge*24.0<36 ){ - return mprintf("%.1f hours", rAge*24.0); - }else if( rAge<365.0 ){ - return mprintf("%.1f days", rAge); - }else{ - return mprintf("%.2f years", rAge/365.0); - } -} - -/* -** COMMAND: test-fileage -** -** Usage: %fossil test-fileage CHECKIN -*/ -void test_fileage_cmd(void){ - int mid; - Stmt q; - const char *zGlob = find_option("glob",0,1); - db_find_and_open_repository(0,0); - verify_all_options(); - if( g.argc!=3 ) usage("test-fileage CHECKIN"); - mid = name_to_typed_rid(g.argv[2],"ci"); - compute_fileage(mid, zGlob); - db_prepare(&q, - "SELECT fid, mid, julianday('now') - mtime, pathname" - " FROM fileage" - ); - while( db_step(&q)==SQLITE_ROW ){ - char *zAge = human_readable_age(db_column_double(&q,2)); - fossil_print("%8d %8d %16s %s\n", - db_column_int(&q,0), - db_column_int(&q,1), - zAge, - db_column_text(&q,3)); - fossil_free(zAge); - } - db_finalize(&q); +** mtime on that checkin. +*/ +int compute_fileage(int vid){ + Manifest *pManifest; + ManifestFile *pFile; + int nFile = 0; + double vmtime; + Stmt ins; + Stmt q1, q2, q3; + Stmt upd; + db_multi_exec( + /*"DROP TABLE IF EXISTS temp.fileage;"*/ + "CREATE TEMP TABLE fileage(" + " fid INTEGER," + " mid INTEGER," + " mtime DATETIME," + " pathname TEXT" + ");" + "CREATE INDEX fileage_fid ON fileage(fid);" + ); + pManifest = manifest_get(vid, CFTYPE_MANIFEST, 0); + if( pManifest==0 ) return 1; + manifest_file_rewind(pManifest); + db_prepare(&ins, + "INSERT INTO temp.fileage(fid, pathname)" + " SELECT rid, :path FROM blob WHERE uuid=:uuid" + ); + while( (pFile = manifest_file_next(pManifest, 0))!=0 ){ + db_bind_text(&ins, ":uuid", pFile->zUuid); + db_bind_text(&ins, ":path", pFile->zName); + db_step(&ins); + db_reset(&ins); + nFile++; + } + db_finalize(&ins); + manifest_destroy(pManifest); + db_prepare(&q1,"SELECT fid FROM mlink WHERE mid=:mid"); + db_prepare(&upd, "UPDATE fileage SET mid=:mid, mtime=:vmtime" + " WHERE fid=:fid AND mid IS NULL"); + db_prepare(&q2,"SELECT pid FROM plink WHERE cid=:vid AND isprim"); + db_prepare(&q3,"SELECT mtime FROM event WHERE objid=:vid"); + while( nFile>0 && vid>0 ){ + db_bind_int(&q3, ":vid", vid); + if( db_step(&q3)==SQLITE_ROW ){ + vmtime = db_column_double(&q3, 0); + }else{ + break; + } + db_reset(&q3); + db_bind_int(&q1, ":mid", vid); + db_bind_int(&upd, ":mid", vid); + db_bind_double(&upd, ":vmtime", vmtime); + while( db_step(&q1)==SQLITE_ROW ){ + db_bind_int(&upd, ":fid", db_column_int(&q1, 0)); + db_step(&upd); + nFile -= db_changes(); + db_reset(&upd); + } + db_reset(&q1); + db_bind_int(&q2, ":vid", vid); + if( db_step(&q2)!=SQLITE_ROW ) break; + vid = db_column_int(&q2, 0); + db_reset(&q2); + } + db_finalize(&q1); + db_finalize(&upd); + db_finalize(&q2); + db_finalize(&q3); + return 0; } /* ** WEBPAGE: fileage ** ** Parameters: -** name=VERSION Selects the check-in version (default=tip). -** glob=STRING Only shows files matching this glob pattern -** (e.g. *.c or *.txt). -** showid Show RID values for debugging +** name=VERSION */ void fileage_page(void){ int rid; const char *zName; - const char *zGlob; - const char *zUuid; - const char *zNow; /* Time of check-in */ - int showId = PB("showid"); - Stmt q1, q2; + char *zBaseTime; + Stmt q; double baseTime; + int lastMid = -1; + login_check_credentials(); - if( !g.perm.Read ){ login_needed(g.anon.Read); return; } + if( !g.perm.Read ){ login_needed(); return; } zName = P("name"); if( zName==0 ) zName = "tip"; rid = symbolic_name_to_rid(zName, "ci"); if( rid==0 ){ fossil_fatal("not a valid check-in: %s", zName); } - zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid); - baseTime = db_double(0.0,"SELECT mtime FROM event WHERE objid=%d", rid); - zNow = db_text("", "SELECT datetime(mtime,'localtime') FROM event" - " WHERE objid=%d", rid); - style_submenu_element("Tree-View", "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);"); - - @ <h2>Files in - @ %z(href("%R/info/%!S",zUuid))[%S(zUuid)]</a> - if( zGlob && zGlob[0] ){ - @ that match "%h(zGlob)" and - } - @ ordered by check-in time</h2> - @ - @ <p>Times are relative to the check-in time for - @ %z(href("%R/ci/%!S",zUuid))[%S(zUuid)]</a> which is - @ %z(href("%R/timeline?c=%t",zNow))%s(zNow)</a>.</p> - @ - @ <div class='fileage'><table> - @ <tr><th>Time</th><th>Files</th><th>Check-in</th></tr> - db_prepare(&q1, - "SELECT event.mtime, event.objid, blob.uuid,\n" - " coalesce(event.ecomment,event.comment),\n" - " coalesce(event.euser,event.user),\n" - " coalesce((SELECT value FROM tagxref\n" - " WHERE tagtype>0 AND tagid=%d\n" - " AND rid=event.objid),'trunk')\n" - " FROM event, blob\n" - " WHERE event.objid IN (SELECT mid FROM fileage)\n" - " AND blob.rid=event.objid\n" - " ORDER BY event.mtime DESC;", - TAG_BRANCH - ); - db_prepare(&q2, - "SELECT blob.uuid, filename.name, fileage.fid\n" - " FROM fileage, blob, filename\n" - " WHERE fileage.mid=:mid AND filename.fnid=fileage.fnid" - " AND blob.rid=fileage.fid;" - ); - while( db_step(&q1)==SQLITE_ROW ){ - double age = baseTime - db_column_double(&q1, 0); - int mid = db_column_int(&q1, 1); - const char *zUuid = db_column_text(&q1, 2); - const char *zComment = db_column_text(&q1, 3); - const char *zUser = db_column_text(&q1, 4); - const char *zBranch = db_column_text(&q1, 5); - char *zAge = human_readable_age(age); - @ <tr><td>%s(zAge)</td> - @ <td> - db_bind_int(&q2, ":mid", mid); - while( db_step(&q2)==SQLITE_ROW ){ - const char *zFUuid = db_column_text(&q2,0); - const char *zFile = db_column_text(&q2,1); - int fid = db_column_int(&q2,2); - if( showId ){ - @ %z(href("%R/artifact/%!S",zFUuid))%h(zFile)</a> (%d(fid))<br> - }else{ - @ %z(href("%R/artifact/%!S",zFUuid))%h(zFile)</a><br> - } - } - db_reset(&q2); - @ </td> - @ <td> - @ %z(href("%R/info/%!S",zUuid))[%S(zUuid)]</a> - if( showId ){ - @ (%d(mid)) - } - @ %W(zComment) (user: - @ %z(href("%R/timeline?u=%t&c=%!S&nd&n=200",zUser,zUuid))%h(zUser)</a>, - @ branch: - @ %z(href("%R/timeline?r=%t&c=%!S&nd&n=200",zBranch,zUuid))%h(zBranch)</a>) - @ </td></tr> - @ - fossil_free(zAge); - } - @ </table></div> - db_finalize(&q1); - db_finalize(&q2); + style_header("File Ages", zName); + compute_fileage(rid); + baseTime = db_double(0.0, "SELECT mtime FROM event WHERE objid=%d", rid); + zBaseTime = db_text("","SELECT datetime(%.20g,'localtime')", baseTime); + @ <h2>File Ages For Check-in + @ %z(href("%R/info?name=%T",zName))%h(zName)</a></h2> + @ + @ <p>The times given are relative to + @ %z(href("%R/timeline?c=%T",zBaseTime))%s(zBaseTime)</a>, which is the + @ check-in time for + @ %z(href("%R/info?name=%T",zName))%h(zName)</a></p> + @ + @ <table border=0 cellspacing=0 cellpadding=0> + db_prepare(&q, + "SELECT mtime, (SELECT uuid FROM blob WHERE rid=fid), mid, pathname" + " FROM fileage" + " ORDER BY mtime DESC, mid, pathname" + ); + while( db_step(&q)==SQLITE_ROW ){ + double age = baseTime - db_column_double(&q, 0); + int mid = db_column_int(&q, 2); + const char *zFUuid = db_column_text(&q, 1); + char zAge[200]; + if( lastMid!=mid ){ + @ <tr><td colspan=3><hr></tr> + lastMid = mid; + if( age*86400.0<120 ){ + sqlite3_snprintf(sizeof(zAge), zAge, "%d seconds", (int)(age*86400.0)); + }else if( age*1440.0<90 ){ + sqlite3_snprintf(sizeof(zAge), zAge, "%.1f minutes", age*1440.0); + }else if( age*24.0<36 ){ + sqlite3_snprintf(sizeof(zAge), zAge, "%.1f hours", age*24.0); + }else if( age<365.0 ){ + sqlite3_snprintf(sizeof(zAge), zAge, "%.1f days", age); + }else{ + sqlite3_snprintf(sizeof(zAge), zAge, "%.2f years", age/365.0); + } + }else{ + zAge[0] = 0; + } + @ <tr> + @ <td>%s(zAge) + @ <td width="25"> + @ <td>%z(href("%R/artifact/%S?ln", zFUuid))%h(db_column_text(&q, 3))</a> + @ </tr> + @ + } + @ <tr><td colspan=3><hr></tr> + @ </table> + db_finalize(&q); style_footer(); } DELETED src/builtin.c Index: src/builtin.c ================================================================== --- src/builtin.c +++ src/builtin.c @@ -1,89 +0,0 @@ -/* -** Copyright (c) 2014 D. Richard Hipp -** -** 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/ -** -******************************************************************************* -** -** This file contains built-in string and BLOB resources packaged as -** byte arrays. -*/ -#include "config.h" -#include "builtin.h" -#include <assert.h> - -/* -** The resources provided by this file are packaged by the "mkbuiltin.c" -** utility program during the built process and stored in the -** builtin_data.h file. Include that information here: -*/ -#include "builtin_data.h" - -/* -** Return a pointer to built-in content -*/ -const unsigned char *builtin_file(const char *zFilename, int *piSize){ - int lwr, upr, i, c; - lwr = 0; - upr = sizeof(aBuiltinFiles)/sizeof(aBuiltinFiles[0]) - 1; - while( upr>=lwr ){ - i = (upr+lwr)/2; - c = strcmp(aBuiltinFiles[i].zName,zFilename); - if( c<0 ){ - lwr = i+1; - }else if( c>0 ){ - upr = i-1; - }else{ - if( piSize ) *piSize = aBuiltinFiles[i].nByte; - return aBuiltinFiles[i].pData; - } - } - if( piSize ) *piSize = 0; - return 0; -} -const char *builtin_text(const char *zFilename){ - return (char*)builtin_file(zFilename, 0); -} - -/* -** COMMAND: test-builtin-list -** -** List the names and sizes of all built-in resources -*/ -void test_builtin_list(void){ - int i; - for(i=0; i<sizeof(aBuiltinFiles)/sizeof(aBuiltinFiles[0]); i++){ - fossil_print("%-30s %6d\n", aBuiltinFiles[i].zName,aBuiltinFiles[i].nByte); - } -} - -/* -** COMMAND: test-builtin-get -** -** Usage: %fossil test-builtin-get NAME ?OUTPUT-FILE? -*/ -void test_builtin_get(void){ - const unsigned char *pData; - int nByte; - Blob x; - if( g.argc!=3 && g.argc!=4 ){ - usage("NAME ?OUTPUT-FILE?"); - } - pData = builtin_file(g.argv[2], &nByte); - if( pData==0 ){ - fossil_fatal("no such built-in file: [%s]", g.argv[2]); - } - blob_init(&x, (const char*)pData, nByte); - blob_write_to_file(&x, g.argc==4 ? g.argv[3] : "-"); - blob_reset(&x); -} DELETED src/bundle.c Index: src/bundle.c ================================================================== --- src/bundle.c +++ src/bundle.c @@ -1,818 +0,0 @@ -/* -** Copyright (c) 2014 D. Richard Hipp -** -** 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/ -** -******************************************************************************* -** -** This file contains code used to implement and manage a "bundle" file. -*/ -#include "config.h" -#include "bundle.h" -#include <assert.h> - -/* -** SQL code used to initialize the schema of a bundle. -** -** The bblob.delta field can be an integer, a text string, or NULL. -** If an integer, then the corresponding blobid is the delta basis. -** If a text string, then that string is a SHA1 hash for the delta -** basis, which is presumably in the master repository. If NULL, then -** data contains contain without delta compression. -*/ -static const char zBundleInit[] = -@ CREATE TABLE IF NOT EXISTS "%w".bconfig( -@ bcname TEXT, -@ bcvalue ANY -@ ); -@ CREATE TABLE IF NOT EXISTS "%w".bblob( -@ blobid INTEGER PRIMARY KEY, -- Blob ID -@ uuid TEXT NOT NULL, -- SHA1 hash of expanded blob -@ sz INT NOT NULL, -- Size of blob after expansion -@ delta ANY, -- Delta compression basis, or NULL -@ notes TEXT, -- Description of content -@ data BLOB -- compressed content -@ ); -; - -/* -** Attach a bundle file to the current database connection using the -** attachment name zBName. -*/ -static void bundle_attach_file( - const char *zFile, /* Name of the file that contains the bundle */ - const char *zBName, /* Attachment name */ - int doInit /* Initialize a new bundle, if true */ -){ - int rc; - char *zErrMsg = 0; - char *zSql; - if( !doInit && file_size(zFile)<0 ){ - fossil_fatal("no such file: %s", zFile); - } - assert( g.db ); - zSql = sqlite3_mprintf("ATTACH %Q AS %Q", zFile, zBName); - if( zSql==0 ) fossil_fatal("out of memory"); - rc = sqlite3_exec(g.db, zSql, 0, 0, &zErrMsg); - sqlite3_free(zSql); - if( rc!=SQLITE_OK || zErrMsg ){ - if( zErrMsg==0 ) zErrMsg = (char*)sqlite3_errmsg(g.db); - fossil_fatal("not a valid bundle: %s", zFile); - } - if( doInit ){ - db_multi_exec(zBundleInit /*works-like:"%w%w"*/, zBName, zBName); - }else{ - sqlite3_stmt *pStmt; - zSql = sqlite3_mprintf("SELECT bcname, bcvalue" - " FROM \"%w\".bconfig", zBName); - if( zSql==0 ) fossil_fatal("out of memory"); - rc = sqlite3_prepare(g.db, zSql, -1, &pStmt, 0); - if( rc ) fossil_fatal("not a valid bundle: %s", zFile); - sqlite3_free(zSql); - sqlite3_finalize(pStmt); - zSql = sqlite3_mprintf("SELECT blobid, uuid, sz, delta, notes, data" - " FROM \"%w\".bblob", zBName); - if( zSql==0 ) fossil_fatal("out of memory"); - rc = sqlite3_prepare(g.db, zSql, -1, &pStmt, 0); - if( rc ) fossil_fatal("not a valid bundle: %s", zFile); - sqlite3_free(zSql); - sqlite3_finalize(pStmt); - } -} - -/* -** fossil bundle ls BUNDLE ?OPTIONS? -** -** Display the content of a bundle in human-readable form. -*/ -static void bundle_ls_cmd(void){ - Stmt q; - sqlite3_int64 sumSz = 0; - sqlite3_int64 sumLen = 0; - int bDetails = find_option("details","l",0)!=0; - verify_all_options(); - if( g.argc!=4 ) usage("ls BUNDLE ?OPTIONS?"); - bundle_attach_file(g.argv[3], "b1", 0); - db_prepare(&q, - "SELECT bcname, bcvalue FROM bconfig" - " WHERE typeof(bcvalue)='text'" - " AND bcvalue NOT GLOB char(0x2a,0x0a,0x2a);" - ); - while( db_step(&q)==SQLITE_ROW ){ - 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, 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), - db_column_int(&q,3), - db_column_int(&q,4), - db_column_text(&q,5)); - sumSz += db_column_int(&q,3); - sumLen += db_column_int(&q,4); - } - db_finalize(&q); - fossil_print("%27s %8lld %8lld\n", "Total:", sumSz, sumLen); - }else{ - db_prepare(&q, - "SELECT substr(uuid,1,16), notes FROM bblob" - ); - while( db_step(&q)==SQLITE_ROW ){ - fossil_print("%16s %s\n", - db_column_text(&q,0), - db_column_text(&q,1)); - } - db_finalize(&q); - } -} - -/* -** Implement the "fossil bundle append BUNDLE FILE..." command. Add -** the named files into the BUNDLE. Create the BUNDLE if it does not -** alraedy exist. -*/ -static void bundle_append_cmd(void){ - Blob content, hash; - int i; - Stmt q; - - verify_all_options(); - bundle_attach_file(g.argv[3], "b1", 1); - db_prepare(&q, - "INSERT INTO bblob(blobid, uuid, sz, delta, data, notes) " - "VALUES(NULL, $uuid, $sz, NULL, $data, $filename)"); - db_begin_transaction(); - for(i=4; i<g.argc; i++){ - int sz; - blob_read_from_file(&content, g.argv[i]); - sz = blob_size(&content); - sha1sum_blob(&content, &hash); - blob_compress(&content, &content); - db_bind_text(&q, "$uuid", blob_str(&hash)); - db_bind_int(&q, "$sz", sz); - db_bind_blob(&q, "$data", &content); - db_bind_text(&q, "$filename", g.argv[i]); - db_step(&q); - db_reset(&q); - blob_reset(&content); - blob_reset(&hash); - } - db_end_transaction(0); - db_finalize(&q); -} - -/* -** Identify a subsection of the check-in tree using command-line switches. -** There must be one of the following switch available: -** -** --branch BRANCHNAME All check-ins on the most recent -** instance of BRANCHNAME -** --from TAG1 [--to TAG2] Check-in TAG1 and all primary descendants -** up to and including TAG2 -** --checkin TAG Check-in TAG only -** -** Store the RIDs for all applicable check-ins in the zTab table that -** should already exist. Invoke fossil_fatal() if any kind of error is -** seen. -*/ -void subtree_from_arguments(const char *zTab){ - const char *zBr; - const char *zFrom; - const char *zTo; - const char *zCkin; - int rid = 0, endRid; - - zBr = find_option("branch",0,1); - zFrom = find_option("from",0,1); - zTo = find_option("to",0,1); - zCkin = find_option("checkin",0,1); - if( zCkin ){ - if( zFrom ) fossil_fatal("cannot use both --checkin and --from"); - if( zBr ) fossil_fatal("cannot use both --checkin and --branch"); - rid = symbolic_name_to_rid(zCkin, "ci"); - endRid = rid; - }else{ - endRid = zTo ? name_to_typed_rid(zTo, "ci") : 0; - } - if( zFrom ){ - rid = name_to_typed_rid(zFrom, "ci"); - }else if( zBr ){ - rid = name_to_typed_rid(zBr, "br"); - }else if( zCkin==0 ){ - fossil_fatal("need one of: --branch, --from, --checkin"); - } - db_multi_exec("INSERT OR IGNORE INTO \"%w\" VALUES(%d)", zTab, rid); - if( rid!=endRid ){ - Blob sql; - blob_zero(&sql); - blob_appendf(&sql, - "WITH RECURSIVE child(rid) AS (VALUES(%d) UNION ALL " - " SELECT cid FROM plink, child" - " WHERE plink.pid=child.rid" - " AND plink.isPrim", rid); - if( endRid>0 ){ - double endTime = db_double(0.0, "SELECT mtime FROM event WHERE objid=%d", - endRid); - blob_appendf(&sql, - " AND child.rid!=%d" - " AND (SELECT mtime FROM event WHERE objid=plink.cid)<=%.17g", - endRid, endTime - ); - } - if( zBr ){ - blob_appendf(&sql, - " AND EXISTS(SELECT 1 FROM tagxref" - " WHERE tagid=%d AND tagtype>0" - " AND value=%Q and rid=plink.cid)", - TAG_BRANCH, zBr); - } - blob_appendf(&sql, ") INSERT OR IGNORE INTO \"%w\" SELECT rid FROM child;", - zTab); - db_multi_exec("%s", blob_str(&sql)/*safe-for-%s*/); - } -} - -/* -** COMMAND: test-subtree -** -** Usage: %fossil test-subtree ?OPTIONS? -** -** Show the subset of check-ins that match the supplied options. This -** command is used to test the subtree_from_options() subroutine in the -** implementation and does not really have any other practical use that -** we know of. -** -** Options: -** --branch BRANCH Include only check-ins on BRANCH -** --from TAG Start the subtree at TAG -** --to TAG End the subtree at TAG -** --checkin TAG The subtree is the single check-in TAG -** --all Include FILE and TAG artifacts -** --exclusive Include FILES exclusively on check-ins -*/ -void test_subtree_cmd(void){ - int bAll = find_option("all",0,0)!=0; - int bExcl = find_option("exclusive",0,0)!=0; - db_find_and_open_repository(0,0); - db_begin_transaction(); - db_multi_exec("CREATE TEMP TABLE tobundle(rid INTEGER PRIMARY KEY);"); - subtree_from_arguments("tobundle"); - verify_all_options(); - if( bAll ) find_checkin_associates("tobundle",bExcl); - describe_artifacts_to_stdout("IN tobundle", 0); - db_end_transaction(1); -} - -/* fossil bundle export BUNDLE ?OPTIONS? -** -** OPTIONS: -** --branch BRANCH --from TAG --to TAG -** --checkin TAG -** --standalone -*/ -static void bundle_export_cmd(void){ - int bStandalone = find_option("standalone",0,0)!=0; - int mnToBundle; /* Minimum RID in the bundle */ - Stmt q; - - /* Decode the arguments (like --branch) that specify which artifacts - ** should be in the bundle */ - db_multi_exec("CREATE TEMP TABLE tobundle(rid INTEGER PRIMARY KEY);"); - subtree_from_arguments("tobundle"); - find_checkin_associates("tobundle", 0); - verify_all_options(); - describe_artifacts("IN tobundle"); - - if( g.argc!=4 ) usage("export BUNDLE ?OPTIONS?"); - /* Create the new bundle */ - bundle_attach_file(g.argv[3], "b1", 1); - db_begin_transaction(); - - /* Add 'mtime' and 'project-code' entries to the bconfig table */ - db_multi_exec( - "INSERT INTO bconfig(bcname,bcvalue)" - " VALUES('mtime',datetime('now'));" - ); - db_multi_exec( - "INSERT INTO bconfig(bcname,bcvalue)" - " SELECT name, value FROM config" - " WHERE name IN ('project-code');" - ); - - /* Directly copy content from the repository into the bundle as long - ** as the repository content is a delta from some other artifact that - ** is also in the bundle. - */ - db_multi_exec( - "REPLACE INTO bblob(blobid,uuid,sz,delta,data,notes) " - " SELECT" - " tobundle.rid," - " blob.uuid," - " blob.size," - " delta.srcid," - " blob.content," - " (SELECT summary FROM description WHERE rid=blob.rid)" - " FROM tobundle, blob, delta" - " WHERE blob.rid=tobundle.rid" - " AND delta.rid=tobundle.rid" - " AND delta.srcid IN tobundle;" - ); - - /* For all the remaining artifacts, we need to construct their deltas - ** manually. - */ - mnToBundle = db_int(0,"SELECT min(rid) FROM tobundle"); - db_prepare(&q, - "SELECT rid FROM tobundle" - " WHERE rid NOT IN (SELECT blobid FROM bblob)" - " ORDER BY +rid;" - ); - while( db_step(&q)==SQLITE_ROW ){ - Blob content; - int rid = db_column_int(&q,0); - int deltaFrom = 0; - - /* Get the raw, uncompressed content of the artifact into content */ - content_get(rid, &content); - - /* Try to find another artifact, not within the bundle, that is a - ** plausible candidate for being a delta basis for the content. Set - ** deltaFrom to the RID of that other artifact. Leave deltaFrom set - ** to zero if the content should not be delta-compressed - */ - if( !bStandalone ){ - if( db_exists("SELECT 1 FROM plink WHERE cid=%d",rid) ){ - deltaFrom = db_int(0, - "SELECT max(cid) FROM plink" - " WHERE cid<%d", mnToBundle); - }else{ - deltaFrom = db_int(0, - "SELECT max(fid) FROM mlink" - " WHERE fnid=(SELECT fnid FROM mlink WHERE fid=%d)" - " AND fid<%d", rid, mnToBundle); - } - } - - /* Try to insert the insert the artifact as a delta - */ - if( deltaFrom ){ - Blob basis, delta; - content_get(deltaFrom, &basis); - blob_delta_create(&basis, &content, &delta); - if( blob_size(&delta)>0.9*blob_size(&content) ){ - deltaFrom = 0; - }else{ - Stmt ins; - blob_compress(&delta, &delta); - db_prepare(&ins, - "REPLACE INTO bblob(blobid,uuid,sz,delta,data,notes)" - " SELECT %d, uuid, size, (SELECT uuid FROM blob WHERE rid=%d)," - " :delta, (SELECT summary FROM description WHERE rid=blob.rid)" - " FROM blob WHERE rid=%d", rid, deltaFrom, rid); - db_bind_blob(&ins, ":delta", &delta); - db_step(&ins); - db_finalize(&ins); - } - blob_reset(&basis); - blob_reset(&delta); - } - - /* If unable to insert the artifact as a delta, insert full-text */ - if( deltaFrom==0 ){ - Stmt ins; - blob_compress(&content, &content); - db_prepare(&ins, - "REPLACE INTO bblob(blobid,uuid,sz,delta,data,notes)" - " SELECT rid, uuid, size, NULL, :content," - " (SELECT summary FROM description WHERE rid=blob.rid)" - " FROM blob WHERE rid=%d", rid); - db_bind_blob(&ins, ":content", &content); - db_step(&ins); - db_finalize(&ins); - } - blob_reset(&content); - } - db_finalize(&q); - - db_end_transaction(0); -} - - -/* -** There is a TEMP table bix(blobid,delta) containing a set of purgeitems -** that need to be transferred to the BLOB table. This routine does -** all items that have srcid=iSrc. The pBasis blob holds the content -** of the source document if iSrc>0. -*/ -static void bundle_import_elements(int iSrc, Blob *pBasis, int isPriv){ - Stmt q; - static Bag busy; - assert( pBasis!=0 || iSrc==0 ); - if( iSrc>0 ){ - if( bag_find(&busy, iSrc) ){ - fossil_fatal("delta loop while uncompressing bundle artifacts"); - } - bag_insert(&busy, iSrc); - } - db_prepare(&q, - "SELECT uuid, data, bblob.delta, bix.blobid" - " FROM bix, bblob" - " WHERE bix.delta=%d" - " AND bix.blobid=bblob.blobid;", - iSrc - ); - while( db_step(&q)==SQLITE_ROW ){ - Blob h1, h2, c1, c2; - int rid; - blob_zero(&h1); - db_column_blob(&q, 0, &h1); - blob_zero(&c1); - db_column_blob(&q, 1, &c1); - blob_uncompress(&c1, &c1); - blob_zero(&c2); - if( db_column_type(&q,2)==SQLITE_TEXT && db_column_bytes(&q,2)==40 ){ - Blob basis; - rid = db_int(0,"SELECT rid FROM blob WHERE uuid=%Q", - db_column_text(&q,2)); - content_get(rid, &basis); - blob_delta_apply(&basis, &c1, &c2); - blob_reset(&basis); - blob_reset(&c1); - }else if( pBasis ){ - blob_delta_apply(pBasis, &c1, &c2); - blob_reset(&c1); - }else{ - c2 = c1; - } - sha1sum_blob(&c2, &h2); - if( blob_compare(&h1, &h2)!=0 ){ - fossil_fatal("SHA1 hash mismatch - wanted %s, got %s", - blob_str(&h1), blob_str(&h2)); - } - blob_reset(&h2); - rid = content_put_ex(&c2, blob_str(&h1), 0, 0, isPriv); - if( rid==0 ){ - fossil_fatal("%s", g.zErrMsg); - }else{ - if( !isPriv ) content_make_public(rid); - content_get(rid, &c1); - manifest_crosslink(rid, &c1, MC_NO_ERRORS); - db_multi_exec("INSERT INTO got(rid) VALUES(%d)",rid); - } - bundle_import_elements(db_column_int(&q,3), &c2, isPriv); - blob_reset(&c2); - } - db_finalize(&q); - if( iSrc>0 ) bag_remove(&busy, iSrc); -} - -/* -** Extract an item from content from the bundle -*/ -static void bundle_extract_item( - int blobid, /* ID of the item to extract */ - Blob *pOut /* Write the content into this blob */ -){ - Stmt q; - Blob x, basis, h1, h2; - static Bag busy; - - db_prepare(&q, "SELECT uuid, delta, data FROM bblob" - " WHERE blobid=%d", blobid); - if( db_step(&q)!=SQLITE_ROW ){ - db_finalize(&q); - fossil_fatal("no such item: %d", blobid); - } - if( bag_find(&busy, blobid) ) fossil_fatal("delta loop"); - blob_zero(&x); - db_column_blob(&q, 2, &x); - blob_uncompress(&x, &x); - if( db_column_type(&q,1)==SQLITE_INTEGER ){ - bundle_extract_item(db_column_int(&q,1), &basis); - blob_delta_apply(&basis, &x, pOut); - blob_reset(&basis); - blob_reset(&x); - }else if( db_column_type(&q,1)==SQLITE_TEXT ){ - int rid = db_int(0, "SELECT rid FROM blob WHERE uuid=%Q", - db_column_text(&q,1)); - if( rid==0 ){ - fossil_fatal("cannot find delta basis %s", db_column_text(&q,1)); - } - content_get(rid, &basis); - db_column_blob(&q, 2, &x); - blob_delta_apply(&basis, &x, pOut); - blob_reset(&basis); - blob_reset(&x); - }else{ - *pOut = x; - } - blob_zero(&h1); - db_column_blob(&q, 0, &h1); - sha1sum_blob(pOut, &h2); - if( blob_compare(&h1, &h2)!=0 ){ - fossil_fatal("SHA1 hash mismatch - wanted %s, got %s", - blob_str(&h1), blob_str(&h2)); - } - blob_reset(&h1); - blob_reset(&h2); - bag_remove(&busy, blobid); - db_finalize(&q); -} - -/* fossil bundle cat BUNDLE UUID... -** -** Write elements of a bundle on standard output -*/ -static void bundle_cat_cmd(void){ - int i; - Blob x; - verify_all_options(); - if( g.argc<5 ) usage("cat BUNDLE UUID..."); - bundle_attach_file(g.argv[3], "b1", 1); - blob_zero(&x); - for(i=4; i<g.argc; i++){ - int blobid = db_int(0,"SELECT blobid FROM bblob WHERE uuid LIKE '%q%%'", - g.argv[i]); - if( blobid==0 ){ - fossil_fatal("no such artifact in bundle: %s", g.argv[i]); - } - bundle_extract_item(blobid, &x); - blob_write_to_file(&x, "-"); - blob_reset(&x); - } -} - - -/* fossil bundle import BUNDLE ?OPTIONS? -** -** Attempt to import the changes contained in BUNDLE. Make the change -** private so that they do not sync. -** -** OPTIONS: -** --force Import even if the project-code does not match -** --publish Imported changes are not private -*/ -static void bundle_import_cmd(void){ - int forceFlag = find_option("force","f",0)!=0; - int isPriv = find_option("publish",0,0)==0; - char *zMissingDeltas; - verify_all_options(); - if ( g.argc!=4 ) usage("import BUNDLE ?OPTIONS?"); - bundle_attach_file(g.argv[3], "b1", 1); - - /* Only import a bundle that was generated from a repo with the same - ** project code, unless the --force flag is true */ - if( !forceFlag ){ - if( !db_exists("SELECT 1 FROM config, bconfig" - " WHERE config.name='project-code'" - " AND bconfig.bcname='project-code'" - " AND config.value=bconfig.bcvalue;") - ){ - fossil_fatal("project-code in the bundle does not match the " - "repository project code. (override with --force)."); - } - } - - /* 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 length(delta)=40" - " AND NOT EXISTS(SELECT 1 FROM blob WHERE uuid=bblob.delta)"); - if( zMissingDeltas && zMissingDeltas[0] ){ - fossil_fatal("delta basis artifacts not found in repository: %s", - zMissingDeltas); - } - - db_begin_transaction(); - db_multi_exec( - "CREATE TEMP TABLE bix(" - " blobid INTEGER PRIMARY KEY," - " delta INTEGER" - ");" - "CREATE INDEX bixdelta ON bix(delta);" - "INSERT INTO bix(blobid,delta)" - " SELECT blobid," - " CASE WHEN typeof(delta)=='integer'" - " THEN delta ELSE 0 END" - " FROM bblob" - " WHERE NOT EXISTS(SELECT 1 FROM blob WHERE uuid=bblob.uuid AND size>=0);" - "CREATE TEMP TABLE got(rid INTEGER PRIMARY KEY ON CONFLICT IGNORE);" - ); - manifest_crosslink_begin(); - bundle_import_elements(0, 0, isPriv); - manifest_crosslink_end(0); - describe_artifacts_to_stdout("IN got", "Imported content:"); - db_end_transaction(0); -} - -/* fossil bundle purge BUNDLE -** -** Try to undo a prior "bundle import BUNDLE". -** -** If the --force option is omitted, then this will only work if -** there have been no check-ins or tags added that use the import. -** -** This routine never removes content that is not already in the bundle -** so the bundle serves as a backup. The purge can be undone using -** "fossil bundle import BUNDLE". -*/ -static void bundle_purge_cmd(void){ - int bForce = find_option("force",0,0)!=0; - int bTest = find_option("test",0,0)!=0; /* Undocumented --test option */ - const char *zFile = g.argv[3]; - verify_all_options(); - if ( g.argc!=4 ) usage("purge BUNDLE ?OPTIONS?"); - bundle_attach_file(zFile, "b1", 0); - db_begin_transaction(); - - /* Find all check-ins of the bundle */ - db_multi_exec( - "CREATE TEMP TABLE ok(rid INTEGER PRIMARY KEY);" - "INSERT OR IGNORE INTO ok SELECT blob.rid FROM bblob, blob, plink" - " WHERE bblob.uuid=blob.uuid" - " AND plink.cid=blob.rid;" - ); - - /* Check to see if new check-ins have been committed to check-ins in - ** the bundle. Do not allow the purge if that is true and if --force - ** is omitted. - */ - if( !bForce ){ - Stmt q; - int n = 0; - db_prepare(&q, - "SELECT cid FROM plink WHERE pid IN ok AND cid NOT IN ok" - ); - while( db_step(&q)==SQLITE_ROW ){ - whatis_rid(db_column_int(&q,0),0); - fossil_print("%.78c\n", '-'); - n++; - } - db_finalize(&q); - if( n>0 ){ - fossil_fatal("check-ins above are derived from check-ins in the bundle."); - } - } - - /* Find all files associated with those check-ins that are used - ** nowhere else. */ - find_checkin_associates("ok", 1); - - /* Check to see if any associated files are not in the bundle. Issue - ** an error if there are any, unless --force is used. - */ - if( !bForce ){ - db_multi_exec( - "CREATE TEMP TABLE err1(rid INTEGER PRIMARY KEY);" - "INSERT INTO err1 " - " SELECT blob.rid FROM ok CROSS JOIN blob" - " WHERE blob.rid=ok.rid" - " AND blob.uuid NOT IN (SELECT uuid FROM bblob);" - ); - if( db_changes() ){ - describe_artifacts_to_stdout("IN err1", 0); - fossil_fatal("artifacts above associated with bundle check-ins " - " are not in the bundle"); - }else{ - db_multi_exec("DROP TABLE err1;"); - } - } - - if( bTest ){ - describe_artifacts_to_stdout( - "IN (SELECT blob.rid FROM ok, blob, bblob" - " WHERE blob.rid=ok.rid AND blob.uuid=bblob.uuid)", - "Purged artifacts found in the bundle:"); - describe_artifacts_to_stdout( - "IN (SELECT blob.rid FROM ok, blob" - " WHERE blob.rid=ok.rid " - " AND blob.uuid NOT IN (SELECT uuid FROM bblob))", - "Purged artifacts NOT in the bundle:"); - describe_artifacts_to_stdout( - "IN (SELECT blob.rid FROM bblob, blob" - " WHERE blob.uuid=bblob.uuid " - " AND blob.rid NOT IN ok)", - "Artifacts in the bundle but not purged:"); - }else{ - purge_artifact_list("ok",0,0); - } - db_end_transaction(0); -} - -/* -** COMMAND: bundle -** -** Usage: %fossil bundle SUBCOMMAND ARGS... -** -** fossil bundle append BUNDLE FILE... -** -** Add files named on the command line to BUNDLE. This subcommand has -** little practical use and is mostly intended for testing. -** -** fossil bundle cat BUNDLE UUID... -** -** Extract one or more artifacts from the bundle and write them -** consecutively on standard output. This subcommand was designed -** for testing and introspection of bundles and is not something -** commonly used. -** -** fossil bundle export BUNDLE ?OPTIONS? -** -** Generate a new bundle, in the file named BUNDLE, that contains a -** subset of the check-ins in the repository (usually a single branch) -** described by the --branch, --from, --to, and/or --checkin options, -** at least one of which is required. If BUNDLE already exists, the -** specified content is added to the bundle. -** -** --branch BRANCH Package all check-ins on BRANCH. -** --from TAG1 --to TAG2 Package check-ins between TAG1 and TAG2. -** --checkin TAG Package the single check-in TAG -** --standalone Do no use delta-encoding against -** artifacts not in the bundle -** -** fossil bundle extend BUNDLE -** -** The BUNDLE must already exist. This subcommand adds to the bundle -** any check-ins that are descendants of check-ins already in the bundle, -** and any tags that apply to artifacts in the bundle. -** -** fossil bundle import BUNDLE ?--publish? -** -** Import all content from BUNDLE into the repository. By default, the -** imported files are private and will not sync. Use the --publish -** option makes the import public. -** -** fossil bundle ls BUNDLE -** -** List the contents of BUNDLE on standard output -** -** fossil bundle purge BUNDLE -** -** Remove from the repository all files that are used exclusively -** by check-ins in BUNDLE. This has the effect of undoing a -** "fossil bundle import". -** -** SUMMARY: -** fossil bundle append BUNDLE FILE... Add files to BUNDLE -** fossil bundle cat BUNDLE UUID... Extract file from BUNDLE -** fossil bundle export BUNDLE ?OPTIONS? Create a new BUNDLE -** --branch BRANCH --from TAG1 --to TAG2 Check-ins to include -** --checkin TAG Use only check-in TAG -** --standalone Omit dependencies -** fossil bundle extend BUNDLE Update with newer content -** fossil bundle import BUNDLE ?OPTIONS? Import a bundle -** --publish Publish the import -** --force Cross-repo import -** fossil bundle ls BUNDLE List content of a bundle -** fossil bundle purge BUNDLE Undo an import -** -** See also: publish -*/ -void bundle_cmd(void){ - const char *zSubcmd; - int n; - if( g.argc<4 ) usage("SUBCOMMAND BUNDLE ?OPTIONS?"); - zSubcmd = g.argv[2]; - db_find_and_open_repository(0,0); - n = (int)strlen(zSubcmd); - if( strncmp(zSubcmd, "append", n)==0 ){ - bundle_append_cmd(); - }else if( strncmp(zSubcmd, "cat", n)==0 ){ - bundle_cat_cmd(); - }else if( strncmp(zSubcmd, "export", n)==0 ){ - bundle_export_cmd(); - }else if( strncmp(zSubcmd, "extend", n)==0 ){ - fossil_fatal("not yet implemented"); - }else if( strncmp(zSubcmd, "import", n)==0 ){ - bundle_import_cmd(); - }else if( strncmp(zSubcmd, "ls", n)==0 ){ - bundle_ls_cmd(); - }else if( strncmp(zSubcmd, "purge", n)==0 ){ - bundle_purge_cmd(); - }else{ - fossil_fatal("unknown subcommand for bundle: %s", zSubcmd); - } -} DELETED src/cache.c Index: src/cache.c ================================================================== --- src/cache.c +++ src/cache.c @@ -1,402 +0,0 @@ -/* -** Copyright (c) 2014 D. Richard Hipp -** -** 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@sqlite.org -** -******************************************************************************* -** -** This file implements a cache for expense operations such as -** /zip and /tarball. -*/ -#include "config.h" -#include <sqlite3.h> -#include "cache.h" - -/* -** Construct the name of the repository cache file -*/ -static char *cacheName(void){ - int i; - int n; - - if( g.zRepositoryName==0 ) return 0; - n = (int)strlen(g.zRepositoryName); - for(i=n-1; i>=0; i--){ - if( g.zRepositoryName[i]=='/' ){ i = n; break; } - if( g.zRepositoryName[i]=='.' ) break; - } - if( i<0 ) i = n; - return mprintf("%.*s.cache", i, g.zRepositoryName); -} - -/* -** Attempt to open the cache database, if such a database exists. -** Make sure the cache table exists within that database. -*/ -static sqlite3 *cacheOpen(int bForce){ - char *zDbName; - sqlite3 *db = 0; - int rc; - i64 sz; - - zDbName = cacheName(); - if( zDbName==0 ) return 0; - if( bForce==0 ){ - sz = file_size(zDbName); - if( sz<=0 ){ - fossil_free(zDbName); - return 0; - } - } - rc = sqlite3_open(zDbName, &db); - fossil_free(zDbName); - if( rc ){ - sqlite3_close(db); - return 0; - } - rc = sqlite3_exec(db, - "PRAGMA page_size=8192;" - "CREATE TABLE IF NOT EXISTS blob(id INTEGER PRIMARY KEY, data BLOB);" - "CREATE TABLE IF NOT EXISTS cache(" - "key TEXT PRIMARY KEY," /* Key used to access the cache */ - "id INT REFERENCES blob," /* The cache content */ - "sz INT," /* Size of content in bytes */ - "tm INT," /* Last access time (unix timestampe) */ - "nref INT" /* Number of uses */ - ");" - "CREATE TRIGGER IF NOT EXISTS cacheDel AFTER DELETE ON cache BEGIN" - " DELETE FROM blob WHERE id=OLD.id;" - "END;", - 0, 0, 0); - if( rc!=SQLITE_OK ){ - sqlite3_close(db); - return 0; - } - return db; -} - -/* -** Attempt to construct a prepared statement for the cache database. -*/ -static sqlite3_stmt *cacheStmt(sqlite3 *db, const char *zSql){ - sqlite3_stmt *pStmt = 0; - int rc; - - rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); - if( rc ){ - sqlite3_finalize(pStmt); - pStmt = 0; - } - return pStmt; -} - -/* -** This routine implements an SQL function that renders a large integer -** compactly: ex: 12.3MB -*/ -static void cache_sizename( - sqlite3_context *context, - int argc, - sqlite3_value **argv -){ - char zBuf[30]; - double v, x; - assert( argc==1 ); - v = sqlite3_value_double(argv[0]); - x = v<0.0 ? -v : v; - if( x>=1e9 ){ - sqlite3_snprintf(sizeof(zBuf), zBuf, "%.1fGB", v/1e9); - }else if( x>=1e6 ){ - sqlite3_snprintf(sizeof(zBuf), zBuf, "%.1fMB", v/1e6); - }else if( x>=1e3 ){ - sqlite3_snprintf(sizeof(zBuf), zBuf, "%.1fKB", v/1e3); - }else{ - sqlite3_snprintf(sizeof(zBuf), zBuf, "%gB", v); - } - sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT); -} - -/* -** Register the sizename() SQL function with the SQLite database -** connection. -*/ -static void cache_register_sizename(sqlite3 *db){ - sqlite3_create_function(db, "sizename", 1, SQLITE_UTF8, 0, - cache_sizename, 0, 0); -} - -/* -** Attempt to write pContent into the cache. If the cache file does -** not exist, then this routine is a no-op. Older cache entries might -** be deleted. -*/ -void cache_write(Blob *pContent, const char *zKey){ - sqlite3 *db; - sqlite3_stmt *pStmt; - int rc = 0; - int nKeep; - - db = cacheOpen(0); - if( db==0 ) return; - sqlite3_busy_timeout(db, 10000); - sqlite3_exec(db, "BEGIN IMMEDIATE", 0, 0, 0); - pStmt = cacheStmt(db, "INSERT INTO blob(data) VALUES(?1)"); - if( pStmt==0 ) goto cache_write_end; - sqlite3_bind_blob(pStmt, 1, blob_buffer(pContent), blob_size(pContent), - SQLITE_STATIC); - if( sqlite3_step(pStmt)!=SQLITE_DONE ) goto cache_write_end; - sqlite3_finalize(pStmt); - pStmt = cacheStmt(db, - "INSERT OR IGNORE INTO cache(key,sz,tm,nref,id)" - "VALUES(?1,?2,strftime('%s','now'),1,?3)" - ); - if( pStmt==0 ) goto cache_write_end; - sqlite3_bind_text(pStmt, 1, zKey, -1, SQLITE_STATIC); - sqlite3_bind_int(pStmt, 2, blob_size(pContent)); - sqlite3_bind_int(pStmt, 3, sqlite3_last_insert_rowid(db)); - if( sqlite3_step(pStmt)!=SQLITE_DONE) goto cache_write_end; - rc = sqlite3_changes(db); - - /* If the write was successful, truncate the cache to keep at most - ** max-cache-entry entries in the cache */ - if( rc ){ - nKeep = db_get_int("max-cache-entry",10); - sqlite3_finalize(pStmt); - pStmt = cacheStmt(db, - "DELETE FROM cache WHERE rowid IN (" - "SELECT rowid FROM cache ORDER BY tm DESC" - " LIMIT -1 OFFSET ?1)"); - if( pStmt ){ - sqlite3_bind_int(pStmt, 1, nKeep); - sqlite3_step(pStmt); - } - } - -cache_write_end: - sqlite3_finalize(pStmt); - sqlite3_exec(db, rc ? "COMMIT" : "ROLLBACK", 0, 0, 0); - sqlite3_close(db); -} - -/* -** Attempt to read content out of the cache with the given zKey. Return -** non-zero on success and zero if unable to locate the content. -** -** Possible reasons for returning zero: -** (1) This server does not implement a cache -** (2) The requested element is not in the cache -*/ -int cache_read(Blob *pContent, const char *zKey){ - sqlite3 *db; - sqlite3_stmt *pStmt; - int rc = 0; - - db = cacheOpen(0); - if( db==0 ) return 0; - sqlite3_busy_timeout(db, 10000); - sqlite3_exec(db, "BEGIN IMMEDIATE", 0, 0, 0); - pStmt = cacheStmt(db, - "SELECT blob.data FROM cache, blob" - " WHERE cache.key=?1 AND cache.id=blob.id"); - if( pStmt==0 ) goto cache_read_done; - sqlite3_bind_text(pStmt, 1, zKey, -1, SQLITE_STATIC); - if( sqlite3_step(pStmt)==SQLITE_ROW ){ - blob_append(pContent, sqlite3_column_blob(pStmt, 0), - sqlite3_column_bytes(pStmt, 0)); - rc = 1; - sqlite3_reset(pStmt); - pStmt = cacheStmt(db, - "UPDATE cache SET nref=nref+1, tm=strftime('%s','now')" - " WHERE key=?1"); - if( pStmt ){ - sqlite3_bind_text(pStmt, 1, zKey, -1, SQLITE_STATIC); - sqlite3_step(pStmt); - } - } - sqlite3_finalize(pStmt); -cache_read_done: - sqlite3_exec(db, "COMMIT", 0, 0, 0); - sqlite3_close(db); - return rc; -} - -/* -** Create a cache database for the current repository if no such -** database already exists. -*/ -void cache_initialize(void){ - sqlite3_close(cacheOpen(1)); -} - -/* -** COMMAND: cache* -** Usage: %fossil cache SUBCOMMAND -** -** Manage the cache used for potentially expensive web pages such as -** /zip and /tarball. SUBCOMMAND an be: -** -** clear Remove all entries from the cache. -** -** init Create the cache file if it does not already exists. -** -** list|ls List the keys and content sizes and other stats for -** all entries currently in the cache -** -** status Show a summary of cache status. -** -** The cache is stored in a file that is distinct from the repository -** but that is held in the same directory as the repository. To cache -** file can be deleted in order to completely disable the cache. -*/ -void cache_cmd(void){ - const char *zCmd; - int nCmd; - sqlite3 *db; - sqlite3_stmt *pStmt; - - db_find_and_open_repository(0,0); - zCmd = g.argc>=3 ? g.argv[2] : ""; - nCmd = (int)strlen(zCmd); - if( nCmd<=1 ){ - fossil_fatal("Usage: %s cache SUBCOMMAND", g.argv[0]); - } - if( strncmp(zCmd, "init", nCmd)==0 ){ - db = cacheOpen(0); - sqlite3_close(db); - if( db ){ - fossil_print("cache already exists in file %z\n", cacheName()); - }else{ - db = cacheOpen(1); - sqlite3_close(db); - if( db ){ - fossil_print("cache created in file %z\n", cacheName()); - }else{ - fossil_fatal("unable to create cache file %z", cacheName()); - } - } - }else if( strncmp(zCmd, "clear", nCmd)==0 ){ - db = cacheOpen(0); - if( db ){ - sqlite3_exec(db, "DELETE FROM cache; DELETE FROM blob; VACUUM;",0,0,0); - sqlite3_close(db); - fossil_print("cache cleared\n"); - }else{ - fossil_print("nothing to clear; cache does not exist\n"); - } - }else if(( strncmp(zCmd, "list", nCmd)==0 ) || ( strncmp(zCmd, "ls", nCmd)==0 )){ - db = cacheOpen(0); - if( db==0 ){ - fossil_print("cache does not exist\n"); - }else{ - int nEntry = 0; - char *zDbName = cacheName(); - cache_register_sizename(db); - pStmt = cacheStmt(db, - "SELECT key, sizename(sz), nRef, datetime(tm,'unixepoch')" - " FROM cache" - " ORDER BY tm DESC" - ); - if( pStmt ){ - while( sqlite3_step(pStmt)==SQLITE_ROW ){ - fossil_print("%s %4d %8s %s\n", - sqlite3_column_text(pStmt, 3), - sqlite3_column_int(pStmt, 2), - sqlite3_column_text(pStmt, 1), - sqlite3_column_text(pStmt, 0)); - nEntry++; - } - sqlite3_finalize(pStmt); - } - sqlite3_close(db); - fossil_print("Entries: %d Cache-file Size: %lld\n", - nEntry, file_size(zDbName)); - fossil_free(zDbName); - } - }else if( strncmp(zCmd, "status", nCmd)==0 ){ - fossil_print("TBD...\n"); - }else{ - fossil_fatal("Unknown subcommand \"%s\"." - " Should be one of: clear init list status", zCmd); - } -} - -/* -** WEBPAGE: cachestat -** -** Show information about the webpage cache -*/ -void cache_page(void){ - sqlite3 *db; - sqlite3_stmt *pStmt; - char zBuf[100]; - - login_check_credentials(); - if( !g.perm.Setup ){ login_needed(0); return; } - style_header("Web Cache Status"); - db = cacheOpen(0); - if( db==0 ){ - @ The web-page cache is disabled for this repository - }else{ - char *zDbName = cacheName(); - cache_register_sizename(db); - pStmt = cacheStmt(db, - "SELECT key, sizename(sz), nRef, datetime(tm,'unixepoch')" - " FROM cache" - " ORDER BY tm DESC" - ); - if( pStmt ){ - @ <ol> - while( sqlite3_step(pStmt)==SQLITE_ROW ){ - const unsigned char *zName = sqlite3_column_text(pStmt,0); - @ <li><p>%z(href("%R/cacheget?key=%T",zName))%h(zName)</a><br> - @ size: %s(sqlite3_column_text(pStmt,1)) - @ hit-count: %d(sqlite3_column_int(pStmt,2)) - @ last-access: %s(sqlite3_column_text(pStmt,3))</p></li> - } - sqlite3_finalize(pStmt); - @ </ol> - } - zDbName = cacheName(); - bigSizeName(sizeof(zBuf), zBuf, file_size(zDbName)); - @ <p>cache-file name: %h(zDbName)</p> - @ <p>cache-file size: %s(zBuf)</p> - fossil_free(zDbName); - sqlite3_close(db); - } - style_footer(); -} - -/* -** WEBPAGE: cacheget -** -** Usage: /cacheget?key=KEY -** -** Download a single entry for the cache, identified by KEY. -** This page is normally a hyperlink from the /cachestat page. -*/ -void cache_getpage(void){ - const char *zKey; - Blob content; - - login_check_credentials(); - if( !g.perm.Setup ){ login_needed(0); return; } - zKey = PD("key",""); - blob_zero(&content); - if( cache_read(&content, zKey)==0 ){ - style_header("Cache Download Error"); - @ The cache does not contain any entry with this key: "%h(zKey)" - style_footer(); - return; - } - cgi_set_content(&content); - cgi_set_content_type("application/x-compressed"); -} Index: src/captcha.c ================================================================== --- src/captcha.c +++ src/captcha.c @@ -17,22 +17,22 @@ ** ** This file contains code to a simple text-based CAPTCHA. Though easily ** defeated by a sophisticated attacker, this CAPTCHA does at least make ** scripting attacks more difficult. */ -#include "config.h" #include <assert.h> +#include "config.h" #include "captcha.h" #if INTERFACE #define CAPTCHA 3 /* Which captcha rendering to use */ #endif /* ** Convert a hex digit into a value between 0 and 15 */ -int hex_digit_value(char c){ +static int hexValue(char c){ if( c>='0' && c<='9' ){ return c - '0'; }else if( c>='a' && c<='f' ){ return c - 'a' + 10; }else if( c>='A' && c<='F' ){ @@ -75,11 +75,11 @@ int i, j, k, m; k = 0; for(i=0; i<6; i++){ for(j=0; zPw[j]; j++){ - unsigned char v = hex_digit_value(zPw[j]); + unsigned char v = hexValue(zPw[j]); v = (aFont1[v] >> ((5-i)*4)) & 0xf; for(m=8; m>=1; m = m>>1){ if( v & m ){ z[k++] = 'X'; z[k++] = 'X'; @@ -92,11 +92,11 @@ z[k++] = ' '; } z[k++] = '\n'; } z[k] = 0; - return z; + return z; } #endif /* CAPTCHA==1 */ #if CAPTCHA==2 @@ -148,11 +148,11 @@ "|__ |", " / / ", " /_/ ", /* 8 */ - " ___ ", + " ___ ", "( _ )", "/ _ \\", "\\___/", /* 9 */ @@ -209,20 +209,20 @@ const char *zChar; k = 0; for(i=0; i<4; i++){ for(j=0; zPw[j]; j++){ - unsigned char v = hex_digit_value(zPw[j]); + unsigned char v = hexValue(zPw[j]); zChar = azFont2[4*v + i]; for(m=0; zChar[m]; m++){ z[k++] = zChar[m]; } } z[k++] = '\n'; } z[k] = 0; - return z; + return z; } #endif /* CAPTCHA==2 */ #if CAPTCHA==3 static const char *const azFont3[] = { @@ -231,123 +231,123 @@ " / _ \\ ", "| | | |", "| | | |", "| |_| |", " \\___/ ", - + /* 1 */ " __ ", "/_ |", " | |", " | |", " | |", " |_|", - + /* 2 */ " ___ ", "|__ \\ ", " ) |", " / / ", " / /_ ", "|____|", - + /* 3 */ " ____ ", "|___ \\ ", " __) |", " |__ < ", " ___) |", "|____/ ", - + /* 4 */ " _ _ ", "| || | ", "| || |_ ", "|__ _|", " | | ", " |_| ", - + /* 5 */ " _____ ", "| ____|", "| |__ ", "|___ \\ ", " ___) |", "|____/ ", - + /* 6 */ " __ ", " / / ", " / /_ ", "| '_ \\ ", "| (_) |", " \\___/ ", - + /* 7 */ " ______ ", "|____ |", " / / ", " / / ", " / / ", " /_/ ", - + /* 8 */ " ___ ", " / _ \\ ", "| (_) |", " > _ < ", "| (_) |", " \\___/ ", - + /* 9 */ " ___ ", " / _ \\ ", "| (_) |", " \\__, |", " / / ", " /_/ ", - + /* A */ " ", " /\\ ", " / \\ ", " / /\\ \\ ", " / ____ \\ ", "/_/ \\_\\", - + /* B */ " ____ ", "| _ \\ ", "| |_) |", "| _ < ", "| |_) |", "|____/ ", - + /* C */ " _____ ", " / ____|", "| | ", "| | ", "| |____ ", " \\_____|", - + /* D */ " _____ ", "| __ \\ ", "| | | |", "| | | |", "| |__| |", "|_____/ ", - + /* E */ " ______ ", "| ____|", "| |__ ", "| __| ", "| |____ ", "|______|", - + /* F */ " ______ ", "| ____|", "| |__ ", "| __| ", @@ -369,11 +369,11 @@ k = 0; for(i=0; i<6; i++){ x = 0; for(j=0; zPw[j]; j++){ - unsigned char v = hex_digit_value(zPw[j]); + unsigned char v = hexValue(zPw[j]); x = (x<<4) + v; switch( x ){ case 0x7a: case 0xfa: y = 3; @@ -408,11 +408,11 @@ } } z[k++] = '\n'; } z[k] = 0; - return z; + return z; } #endif /* CAPTCHA==3 */ /* ** COMMAND: test-captcha @@ -448,11 +448,11 @@ /* ** Translate a captcha seed value into the captcha password string. ** The returned string is static and overwritten on each call to ** this function. */ -const char *captcha_decode(unsigned int seed){ +char const *captcha_decode(unsigned int seed){ const char *zSecret; const char *z; Blob b; static char zRes[20]; @@ -478,15 +478,16 @@ ** Return true if a CAPTCHA is required for editing wiki or tickets or for ** adding attachments. ** ** A CAPTCHA is required in those cases if the user is not logged in (if they ** are user "nobody") and if the "require-captcha" setting is true. The -** "require-captcha" setting is controlled on the Admin/Access page. It +** "require-captcha" setting is controlled on the Admin/Access page. It ** defaults to true. */ int captcha_needed(void){ - return login_is_nobody() && db_get_boolean("require-captcha", 1); + if( g.zLogin!=0 ) return 0; + return db_get_boolean("require-captcha", 1); } /* ** If a captcha is required but the correct captcha code is not supplied ** in the query parameters, then return false (0). @@ -517,11 +518,11 @@ char c = zEntered[i]; if( c>='A' && c<='F' ) c += 'a' - 'A'; if( c=='O' ) c = '0'; z[i] = c; } - if( strncmp(zDecode,z,8)!=0 ) return 0; + if( memcmp(zDecode,z,8)!=0 ) return 0; return 1; } /* ** Generate a captcha display together with the necessary hidden parameter Index: src/cgi.c ================================================================== --- src/cgi.c +++ src/cgi.c @@ -52,26 +52,18 @@ */ #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) /* ** Destinations for output text. */ #define CGI_HEADER 0 #define CGI_BODY 1 -/* -** Flags for SSH HTTP clients -*/ -#define CGI_SSH_CLIENT 0x0001 /* Client is SSH */ -#define CGI_SSH_COMPAT 0x0002 /* Compat for old SSH transport */ -#define CGI_SSH_FOSSIL 0x0004 /* Use new Fossil SSH transport */ - #endif /* INTERFACE */ /* ** The HTTP reply is generated in two pieces: the header and the body. ** These pieces are generated separately because they are not necessary @@ -109,13 +101,10 @@ ** if it does and false if it does not. */ int cgi_header_contains(const char *zNeedle){ return strstr(blob_str(&cgiContent[0]), zNeedle)!=0; } -int cgi_body_contains(const char *zNeedle){ - return strstr(blob_str(&cgiContent[1]), zNeedle)!=0; -} /* ** Append reply content to what already exists. */ void cgi_append_content(const char *zData, int nAmt){ @@ -270,25 +259,15 @@ zTok = strtok_r(0, ",\"",&zPos)){} fossil_free(zBuf); if(zTok) return 1; } } - + return 0; } #endif -/* -** Return true if the response should be sent with Content-Encoding: gzip. -*/ -static int is_gzippable(void){ - if( strstr(PD("HTTP_ACCEPT_ENCODING", ""), "gzip")==0 ) return 0; - return strncmp(zContentType, "text/", 5)==0 - || sqlite3_strglob("application/*xml", zContentType)==0 - || sqlite3_strglob("application/*javascript", zContentType)==0; -} - /* ** Do a normal HTTP reply */ void cgi_reply(void){ int total_size; @@ -310,11 +289,10 @@ if( g.fullHttpReply ){ fprintf(g.httpOut, "HTTP/1.0 %d %s\r\n", iReplyStatus, zReplyStatus); fprintf(g.httpOut, "Date: %s\r\n", cgi_rfc822_datestamp(time(0))); fprintf(g.httpOut, "Connection: close\r\n"); - fprintf(g.httpOut, "X-UA-Compatible: IE=edge\r\n"); }else{ fprintf(g.httpOut, "Status: %d %s\r\n", iReplyStatus, zReplyStatus); } if( blob_size(&extraHeader)>0 ){ @@ -346,11 +324,13 @@ ** case of most /getfile calls for specific versions, the only way the ** content changes is if someone breaks the SCM. And if that happens, a ** stale cache is the least of the problem. So we provide an Expires ** header set to a reasonable period (default: one week). */ - fprintf(g.httpOut, "Cache-control: max-age=28800\r\n"); + /*time_t expires = time(0) + atoi(db_config("constant_expires","604800"));*/ + time_t expires = time(0) + 604800; + fprintf(g.httpOut, "Expires: %s\r\n", cgi_rfc822_datestamp(expires)); }else{ fprintf(g.httpOut, "Cache-control: no-cache\r\n"); } /* Content intended for logged in users should only be cached in @@ -361,22 +341,10 @@ cgi_combine_header_and_body(); blob_compress(&cgiContent[0], &cgiContent[0]); } if( iReplyStatus != 304 ) { - if( is_gzippable() ){ - int i; - gzip_begin(0); - for( i=0; i<2; i++ ){ - int size = blob_size(&cgiContent[i]); - if( size>0 ) gzip_step(blob_buffer(&cgiContent[i]), size); - blob_reset(&cgiContent[i]); - } - gzip_finish(&cgiContent[0]); - fprintf(g.httpOut, "Content-Encoding: gzip\r\n"); - fprintf(g.httpOut, "Vary: Accept-Encoding\r\n"); - } total_size = blob_size(&cgiContent[0]) + blob_size(&cgiContent[1]); fprintf(g.httpOut, "Content-Length: %d\r\n", total_size); }else{ total_size = 0; } @@ -437,12 +405,11 @@ 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 */ + int isQP; /* True for query parameters */ } *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 @@ -465,11 +432,10 @@ 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; } /* @@ -494,30 +460,19 @@ return; } } cgi_set_parameter_nocopy(zName, zValue, 0); } -void cgi_replace_query_parameter(const char *zName, const char *zValue){ - int i; - for(i=0; i<nUsedQP; i++){ - if( fossil_strcmp(aParamQP[i].zName,zName)==0 ){ - aParamQP[i].zValue = zValue; - assert( aParamQP[i].isQP ); - return; - } - } - cgi_set_parameter_nocopy(zName, zValue, 1); -} /* ** Add a query parameter. The zName portion is fixed but a copy ** must be made of zValue. */ void cgi_setenv(const char *zName, const char *zValue){ cgi_set_parameter_nocopy(zName, mprintf("%s",zValue), 0); } - + /* ** Add a list of query parameters or cookies to the parameter set. ** ** Each parameter is of the form NAME=VALUE. Both the NAME and the @@ -631,11 +586,11 @@ break; } } *pz = &z[i]; get_line_from_string(pz, pLen); - return z; + return z; } /* ** Tokenize a line of text into as many as nArg tokens. Make ** azArg[] point to the start of each token. @@ -738,11 +693,11 @@ cgi_set_parameter_nocopy(mprintf("%s:mimetype",zName), z, 1); } } } } - } + } } #ifdef FOSSIL_ENABLE_JSON /* @@ -766,11 +721,11 @@ else { CgiPostReadState * st = (CgiPostReadState *)state; if( st->pos >= st->len ){ *n = 0; return 0; - }else if( !*n || ((st->pos + *n) > st->len) ){ + } else if( !*n || ((st->pos + *n) > st->len) ){ return cson_rc.RangeError; }else{ unsigned int rsz = (unsigned int)fread( dest, 1, *n, st->fh ); if( ! rsz ){ *n = rsz; @@ -868,50 +823,26 @@ /* ** Initialize the query parameter database. Information is pulled from ** the QUERY_STRING environment variable (if it exists), from standard ** input if there is POST data, and from HTTP_COOKIE. -** -** REQUEST_URI, PATH_INFO, and SCRIPT_NAME are related as follows: -** -** REQUEST_URI == SCRIPT_NAME + PATH_INFO -** -** Where "+" means concatenate. Fossil requires SCRIPT_NAME. If -** REQUEST_URI is provided but PATH_INFO is not, then PATH_INFO is -** computed from REQUEST_URI and SCRIPT_NAME. If PATH_INFO is provided -** but REQUEST_URI is not, then compute REQUEST_URI from PATH_INFO and -** SCRIPT_NAME. If neither REQUEST_URI nor PATH_INFO are provided, then -** assume that PATH_INFO is an empty string and set REQUEST_URI equal -** to PATH_INFO. -** -** SCGI typically omits PATH_INFO. CGI sometimes omits REQUEST_URI and -** PATH_INFO when it is empty. */ void cgi_init(void){ char *z; const char *zType; int len; const char *zRequestUri = cgi_parameter("REQUEST_URI",0); const char *zScriptName = cgi_parameter("SCRIPT_NAME",0); - const char *zPathInfo = cgi_parameter("PATH_INFO",0); #ifdef FOSSIL_ENABLE_JSON json_main_bootstrap(); #endif g.isHTTP = 1; cgi_destination(CGI_BODY); + if( zRequestUri==0 ) malformed_request("missing REQUEST_URI"); if( zScriptName==0 ) malformed_request("missing SCRIPT_NAME"); - if( zRequestUri==0 ){ - const char *z = zPathInfo; - if( zPathInfo==0 ){ - malformed_request("missing PATH_INFO and/or REQUEST_URI"); - } - if( z[0]=='/' ) z++; - zRequestUri = mprintf("%s/%s", zScriptName, z); - cgi_set_parameter("REQUEST_URI", zRequestUri); - } - if( zPathInfo==0 ){ + if( cgi_parameter("PATH_INFO",0)==0 ){ int i, j; for(i=0; zRequestUri[i]==zScriptName[i] && zRequestUri[i]; i++){} for(j=i; zRequestUri[j] && zRequestUri[j]!='?'; j++){} cgi_set_parameter("PATH_INFO", mprintf("%.*s", j-i, zRequestUri+i)); } @@ -919,11 +850,11 @@ z = (char*)P("HTTP_COOKIE"); if( z ){ z = mprintf("%s",z); add_param_list(z, ';'); } - + z = (char*)P("QUERY_STRING"); if( z ){ z = mprintf("%s",z); add_param_list(z, '&'); } @@ -935,11 +866,11 @@ len = atoi(PD("CONTENT_LENGTH", "0")); g.zContentType = zType = P("CONTENT_TYPE"); blob_zero(&g.cgiIn); if( len>0 && zType ){ - if( fossil_strcmp(zType,"application/x-www-form-urlencoded")==0 + if( fossil_strcmp(zType,"application/x-www-form-urlencoded")==0 || strncmp(zType,"multipart/form-data",19)==0 ){ z = fossil_malloc( len+1 ); len = fread(z, 1, len, g.httpIn); z[len] = 0; cgi_trace(z); @@ -965,11 +896,11 @@ /* FIXMEs: - See if fossil really needs g.cgiIn to be set for this purpose (i don't think it does). If it does then fill g.cgiIn and refactor to parse the JSON from there. - + - After parsing POST JSON, copy the "first layer" of keys/values to cgi_setenv(), honoring the upper-case distinction used in add_param_list(). However... - If we do that then we might get a disconnect in precedence of @@ -1079,20 +1010,10 @@ for(i=0; zOut[i]; i++){} while( i>0 && fossil_isspace(zOut[i-1]) ) zOut[--i] = 0; return zOut; } -/* -** Return true if the CGI parameter zName exists and is not equal to 0, -** or "no" or "off". -*/ -int cgi_parameter_boolean(const char *zName){ - const char *zIn = cgi_parameter(zName, 0); - if( zIn==0 ) return 0; - return zIn[0]==0 || is_truth(zIn); -} - /* ** Return the name of the i-th CGI parameter. Return NULL if there ** are fewer than i registered CGI parameters. */ const char *cgi_parameter_name(int i){ @@ -1166,52 +1087,24 @@ cgi_printf("%h = %h <br />\n", zName, aParamQP[i].zValue); } } /* -** Export all untagged query parameters (but not cookies or environment -** variables) as hidden values of a form. +** Export all query parameters (but not cookies or environment variables) +** as hidden values of a form. */ void cgi_query_parameters_to_hidden(void){ int i; const char *zN, *zV; for(i=0; i<nUsedQP; i++){ - if( aParamQP[i].isQP==0 || aParamQP[i].cTag ) continue; + if( aParamQP[i].isQP==0 ) continue; zN = aParamQP[i].zName; zV = aParamQP[i].zValue; @ <input type="hidden" name="%h(zN)" value="%h(zV)"> } } -/* -** Export all untagged query parameters (but not cookies or environment -** variables) to the HQuery object. -*/ -void cgi_query_parameters_to_url(HQuery *p){ - int i; - for(i=0; i<nUsedQP; i++){ - if( aParamQP[i].isQP==0 || aParamQP[i].cTag ) continue; - url_add_parameter(p, aParamQP[i].zName, aParamQP[i].zValue); - } -} - -/* -** Tag query parameter zName so that it is not exported by -** cgi_query_parameters_to_hidden(). Or if zName==0, then -** untag all query parameters. -*/ -void cgi_tag_query_parameter(const char *zName){ - int i; - if( zName==0 ){ - for(i=0; i<nUsedQP; i++) aParamQP[i].cTag = 0; - }else{ - for(i=0; i<nUsedQP; i++){ - if( strcmp(zName,aParamQP[i].zName)==0 ) aParamQP[i].cTag = 1; - } - } -} - /* ** This routine works like "printf" except that it has the ** extra formatting capabilities such as %h and %t. */ void cgi_printf(const char *zFormat, ...){ @@ -1279,11 +1172,11 @@ ** loaded into g.zIpAddr. */ static const char *cgi_accept_forwarded_for(const char *z){ int i; if( fossil_strcmp(g.zIpAddr, "127.0.0.1")!=0 ) return 0; - + i = strlen(z)-1; while( i>=0 && z[i]!=',' && !fossil_isspace(z[i]) ) i--; return &z[++i]; } @@ -1351,20 +1244,20 @@ for(i=0; zToken[i] && zToken[i]!='?'; i++){} if( zToken[i] ) zToken[i++] = 0; cgi_setenv("PATH_INFO", zToken); cgi_setenv("QUERY_STRING", &zToken[i]); if( zIpAddr==0 && - getpeername(fileno(g.httpIn), (struct sockaddr*)&remoteName, + getpeername(fileno(g.httpIn), (struct sockaddr*)&remoteName, &size)>=0 ){ zIpAddr = inet_ntoa(remoteName.sin_addr); } - if( zIpAddr ){ + if( zIpAddr ){ cgi_setenv("REMOTE_ADDR", zIpAddr); g.zIpAddr = mprintf("%s", zIpAddr); } - + /* Get all the optional fields that follow the first line. */ while( fgets(zLine,sizeof(zLine),g.httpIn) ){ char *zFieldName; char *zVal; @@ -1378,13 +1271,11 @@ while( i>0 && fossil_isspace(zVal[i-1]) ){ i--; } zVal[i] = 0; for(i=0; zFieldName[i]; i++){ zFieldName[i] = fossil_tolower(zFieldName[i]); } - if( fossil_strcmp(zFieldName,"accept-encoding:")==0 ){ - cgi_setenv("HTTP_ACCEPT_ENCODING", zVal); - }else if( fossil_strcmp(zFieldName,"content-length:")==0 ){ + if( fossil_strcmp(zFieldName,"content-length:")==0 ){ cgi_setenv("CONTENT_LENGTH", zVal); }else if( fossil_strcmp(zFieldName,"content-type:")==0 ){ cgi_setenv("CONTENT_TYPE", zVal); }else if( fossil_strcmp(zFieldName,"cookie:")==0 ){ cgi_setenv("HTTP_COOKIE", zVal); @@ -1394,12 +1285,14 @@ cgi_setenv("HTTP_HOST", zVal); }else if( fossil_strcmp(zFieldName,"if-none-match:")==0 ){ cgi_setenv("HTTP_IF_NONE_MATCH", zVal); }else if( fossil_strcmp(zFieldName,"if-modified-since:")==0 ){ cgi_setenv("HTTP_IF_MODIFIED_SINCE", zVal); +#if 0 }else if( fossil_strcmp(zFieldName,"referer:")==0 ){ cgi_setenv("HTTP_REFERER", zVal); +#endif }else if( fossil_strcmp(zFieldName,"user-agent:")==0 ){ cgi_setenv("HTTP_USER_AGENT", zVal); }else if( fossil_strcmp(zFieldName,"x-forwarded-for:")==0 ){ const char *zIpAddr = cgi_accept_forwarded_for(zVal); if( zIpAddr!=0 ){ @@ -1410,234 +1303,10 @@ } cgi_init(); cgi_trace(0); } -/* -** This routine handles a single HTTP request from an SSH client which is -** coming in on g.httpIn and which replies on g.httpOut -** -** Once all the setup is finished, this procedure returns -** and subsequent code handles the actual generation of the webpage. -** -** It is called in a loop so some variables will need to be replaced -*/ -void cgi_handle_ssh_http_request(const char *zIpAddr){ - static int nCycles = 0; - static char *zCmd = 0; - char *z, *zToken; - const char *zType = 0; - int i, content_length = 0; - char zLine[2000]; /* A single line of input. */ - - if( zIpAddr ){ - if( nCycles==0 ){ - cgi_setenv("REMOTE_ADDR", zIpAddr); - g.zIpAddr = mprintf("%s", zIpAddr); - } - }else{ - fossil_panic("missing SSH IP address"); - } - if( fgets(zLine, sizeof(zLine),g.httpIn)==0 ){ - malformed_request("missing HTTP header"); - } - cgi_trace(zLine); - zToken = extract_token(zLine, &z); - if( zToken==0 ){ - malformed_request("malformed HTTP header"); - } - - if( fossil_strcmp(zToken, "echo")==0 ){ - /* start looking for probes to complete transport_open */ - zCmd = cgi_handle_ssh_probes(zLine, sizeof(zLine), z, zToken); - if( fgets(zLine, sizeof(zLine),g.httpIn)==0 ){ - malformed_request("missing HTTP header"); - } - cgi_trace(zLine); - zToken = extract_token(zLine, &z); - if( zToken==0 ){ - malformed_request("malformed HTTP header"); - } - }else if( zToken && strlen(zToken)==0 && zCmd ){ - /* transport_flip request and continued transport_open */ - cgi_handle_ssh_transport(zCmd); - if( fgets(zLine, sizeof(zLine),g.httpIn)==0 ){ - malformed_request("missing HTTP header"); - } - cgi_trace(zLine); - zToken = extract_token(zLine, &z); - if( zToken==0 ){ - malformed_request("malformed HTTP header"); - } - } - - if( fossil_strcmp(zToken,"GET")!=0 && fossil_strcmp(zToken,"POST")!=0 - && fossil_strcmp(zToken,"HEAD")!=0 ){ - malformed_request("unsupported HTTP method"); - } - - if( nCycles==0 ){ - cgi_setenv("GATEWAY_INTERFACE","CGI/1.0"); - cgi_setenv("REQUEST_METHOD",zToken); - } - - zToken = extract_token(z, &z); - if( zToken==0 ){ - malformed_request("malformed URL in HTTP header"); - } - if( nCycles==0 ){ - cgi_setenv("REQUEST_URI", zToken); - cgi_setenv("SCRIPT_NAME", ""); - } - - for(i=0; zToken[i] && zToken[i]!='?'; i++){} - if( zToken[i] ) zToken[i++] = 0; - if( nCycles==0 ){ - cgi_setenv("PATH_INFO", zToken); - }else{ - cgi_replace_parameter("PATH_INFO", mprintf("%s",zToken)); - } - - /* Get all the optional fields that follow the first line. - */ - while( fgets(zLine,sizeof(zLine),g.httpIn) ){ - char *zFieldName; - char *zVal; - - cgi_trace(zLine); - zFieldName = extract_token(zLine,&zVal); - if( zFieldName==0 || *zFieldName==0 ) break; - while( fossil_isspace(*zVal) ){ zVal++; } - i = strlen(zVal); - while( i>0 && fossil_isspace(zVal[i-1]) ){ i--; } - zVal[i] = 0; - for(i=0; zFieldName[i]; i++){ - zFieldName[i] = fossil_tolower(zFieldName[i]); - } - if( fossil_strcmp(zFieldName,"content-length:")==0 ){ - content_length = atoi(zVal); - }else if( fossil_strcmp(zFieldName,"content-type:")==0 ){ - g.zContentType = zType = mprintf("%s", zVal); - }else if( fossil_strcmp(zFieldName,"host:")==0 ){ - if( nCycles==0 ){ - cgi_setenv("HTTP_HOST", zVal); - } - }else if( fossil_strcmp(zFieldName,"user-agent:")==0 ){ - if( nCycles==0 ){ - cgi_setenv("HTTP_USER_AGENT", zVal); - } - }else if( fossil_strcmp(zFieldName,"x-fossil-transport:")==0 ){ - if( fossil_strnicmp(zVal, "ssh", 3)==0 ){ - if( nCycles==0 ){ - g.fSshClient |= CGI_SSH_FOSSIL; - g.fullHttpReply = 0; - } - } - } - } - - if( nCycles==0 ){ - if( ! ( g.fSshClient & CGI_SSH_FOSSIL ) ){ - /* did not find new fossil ssh transport */ - g.fSshClient &= ~CGI_SSH_CLIENT; - g.fullHttpReply = 1; - cgi_replace_parameter("REMOTE_ADDR", "127.0.0.1"); - } - } - - cgi_reset_content(); - cgi_destination(CGI_BODY); - - if( content_length>0 && zType ){ - blob_zero(&g.cgiIn); - if( fossil_strcmp(zType, "application/x-fossil")==0 ){ - blob_read_from_channel(&g.cgiIn, g.httpIn, content_length); - blob_uncompress(&g.cgiIn, &g.cgiIn); - }else if( fossil_strcmp(zType, "application/x-fossil-debug")==0 ){ - blob_read_from_channel(&g.cgiIn, g.httpIn, content_length); - }else if( fossil_strcmp(zType, "application/x-fossil-uncompressed")==0 ){ - blob_read_from_channel(&g.cgiIn, g.httpIn, content_length); - } - } - cgi_trace(0); - nCycles++; -} - -/* -** This routine handles the old fossil SSH probes -*/ -char *cgi_handle_ssh_probes(char *zLine, int zSize, char *z, char *zToken){ - /* Start looking for probes */ - while( fossil_strcmp(zToken, "echo")==0 ){ - zToken = extract_token(z, &z); - if( zToken==0 ){ - malformed_request("malformed probe"); - } - if( fossil_strncmp(zToken, "test", 4)==0 || - fossil_strncmp(zToken, "probe-", 6)==0 ){ - fprintf(g.httpOut, "%s\n", zToken); - fflush(g.httpOut); - }else{ - malformed_request("malformed probe"); - } - if( fgets(zLine, zSize, g.httpIn)==0 ){ - malformed_request("malformed probe"); - } - cgi_trace(zLine); - zToken = extract_token(zLine, &z); - if( zToken==0 ){ - malformed_request("malformed probe"); - } - } - - /* Got all probes now first transport_open is completed - ** so return the command that was requested - */ - g.fSshClient |= CGI_SSH_COMPAT; - return mprintf("%s", zToken); -} - -/* -** This routine handles the old fossil SSH transport_flip -** and transport_open communications if detected. -*/ -void cgi_handle_ssh_transport(const char *zCmd){ - char *z, *zToken; - char zLine[2000]; /* A single line of input. */ - - /* look for second newline of transport_flip */ - if( fgets(zLine, sizeof(zLine),g.httpIn)==0 ){ - malformed_request("incorrect transport_flip"); - } - cgi_trace(zLine); - zToken = extract_token(zLine, &z); - if( zToken && strlen(zToken)==0 ){ - /* look for path to fossil */ - if( fgets(zLine, sizeof(zLine),g.httpIn)==0 ){ - if( zCmd==0 ){ - malformed_request("missing fossil command"); - }else{ - /* no new command so exit */ - fossil_exit(0); - } - } - cgi_trace(zLine); - zToken = extract_token(zLine, &z); - if( zToken==0 ){ - malformed_request("malformed fossil command"); - } - /* see if we've seen the command */ - if( zCmd && zCmd[0] && fossil_strcmp(zToken, zCmd)==0 ){ - return; - }else{ - malformed_request("transport_open failed"); - } - }else{ - malformed_request("transport_flip failed"); - } -} - /* ** This routine handles a single SCGI request which is coming in on ** g.httpIn and which replies on g.httpOut ** ** The SCGI request is read from g.httpIn and is used to initialize @@ -1649,14 +1318,15 @@ void cgi_handle_scgi_request(void){ char *zHdr; char *zToFree; int nHdr = 0; int nRead; - int c, n, m; + int n, m; + char c; - while( (c = fgetc(g.httpIn))!=EOF && fossil_isdigit((char)c) ){ - nHdr = nHdr*10 + (char)c - '0'; + while( (c = fgetc(g.httpIn))!=EOF && fossil_isdigit(c) ){ + nHdr = nHdr*10 + c - '0'; } if( nHdr<16 ) malformed_request("SCGI header too short"); zToFree = zHdr = fossil_malloc(nHdr); nRead = (int)fread(zHdr, 1, nHdr, g.httpIn); if( nRead<nHdr ) malformed_request("cannot read entire SCGI header"); @@ -1674,18 +1344,15 @@ cgi_init(); } #if INTERFACE -/* +/* ** Bitmap values for the flags parameter to cgi_http_server(). */ #define HTTP_SERVER_LOCALHOST 0x0001 /* Bind to 127.0.0.1 only */ #define HTTP_SERVER_SCGI 0x0002 /* SCGI instead of HTTP */ -#define HTTP_SERVER_HAD_REPOSITORY 0x0004 /* Was the repository open? */ -#define HTTP_SERVER_HAD_CHECKOUT 0x0008 /* Was a checkout open? */ -#define HTTP_SERVER_REPOLIST 0x0010 /* Allow repo listing */ #endif /* INTERFACE */ /* ** Maximum number of child processes that we can have running @@ -1762,19 +1429,20 @@ " port in the range %d..%d", mnPort, mxPort); } } if( iPort>mxPort ) return 1; listen(listener,10); - fossil_print("Listening for %s requests on TCP port %d\n", - (flags & HTTP_SERVER_SCGI)!=0?"SCGI":"HTTP", iPort); - fflush(stdout); + if( iPort>mnPort ){ + fossil_print("Listening for %s requests on TCP port %d\n", + (flags & HTTP_SERVER_SCGI)!=0?"SCGI":"HTTP", iPort); + fflush(stdout); + } if( zBrowser ){ - assert( strstr(zBrowser,"%d")!=0 ); - zBrowser = mprintf(zBrowser /*works-like:"%d"*/, iPort); + zBrowser = mprintf(zBrowser, iPort); #if defined(__CYGWIN__) /* On Cygwin, we can do better than "echo" */ - if( strncmp(zBrowser, "echo ", 5)==0 ){ + if( memcmp(zBrowser, "echo ", 5)==0 ){ wchar_t *wUrl = fossil_utf8_to_unicode(zBrowser+5); wUrl[wcslen(wUrl)-2] = 0; /* Strip terminating " &" */ if( (size_t)ShellExecuteW(0, L"open", wUrl, 0, 0, 1)<33 ){ fossil_warning("cannot start browser\n"); } @@ -1809,11 +1477,11 @@ fd = dup(connection); if( fd!=0 ) nErr++; close(1); fd = dup(connection); if( fd!=1 ) nErr++; - if( !g.fAnyTrace ){ + if( !g.fHttpTrace && !g.fSqlTrace ){ close(2); fd = dup(connection); if( fd!=2 ) nErr++; } close(connection); @@ -1824,11 +1492,11 @@ /* Bury dead children */ while( waitpid(0, 0, WNOHANG)>0 ){ nchildren--; } } - /* NOT REACHED */ + /* NOT REACHED */ fossil_exit(1); #endif /* NOT REACHED */ return 0; } @@ -1912,11 +1580,11 @@ p->tm_mon %= 12; } isLeapYr = p->tm_year%4==0 && (p->tm_year%100!=0 || (p->tm_year+300)%400==0); p->tm_yday = priorDays[p->tm_mon] + p->tm_mday - 1; if( isLeapYr && p->tm_mon>1 ) p->tm_yday++; - nDay = (p->tm_year-70)*365 + (p->tm_year-69)/4 -p->tm_year/100 + + nDay = (p->tm_year-70)*365 + (p->tm_year-69)/4 -p->tm_year/100 + (p->tm_year+300)/400 + p->tm_yday; t = ((nDay*24 + p->tm_hour)*60 + p->tm_min)*60 + p->tm_sec; return t; } @@ -1932,23 +1600,5 @@ cgi_set_status(304,"Not Modified"); cgi_reset_content(); cgi_reply(); fossil_exit(0); } - -/* -** Check to see if the remote client is SSH and return -** its IP or return default -*/ -const char *cgi_ssh_remote_addr(const char *zDefault){ - char *zIndex; - const char *zSshConn = fossil_getenv("SSH_CONNECTION"); - - if( zSshConn && zSshConn[0] ){ - char *zSshClient = mprintf("%s",zSshConn); - if( (zIndex = strchr(zSshClient,' '))!=0 ){ - zSshClient[zIndex-zSshClient] = '\0'; - return zSshClient; - } - } - return zDefault; -} Index: src/checkin.c ================================================================== --- src/checkin.c +++ src/checkin.c @@ -52,25 +52,23 @@ zName = blob_str(&fname); if( fossil_strcmp(zName, ".")==0 ) { blob_reset(&where); break; } - blob_append_sql(&where, - " %s (pathname=%Q %s) " - "OR (pathname>'%q/' %s AND pathname<'%q0' %s)", - (blob_size(&where)>0) ? "OR" : "AND", zName, - filename_collation(), zName, filename_collation(), - zName, filename_collation() - ); + blob_appendf(&where, " %s (pathname=%Q %s) " + "OR (pathname>'%q/' %s AND pathname<'%q0' %s)", + (blob_size(&where)>0) ? "OR" : "AND", zName, + filename_collation(), zName, filename_collation(), + zName, filename_collation()); } db_prepare(&q, "SELECT pathname, deleted, chnged, rid, coalesce(origname!=pathname,0)" " FROM vfile " " WHERE is_selected(id) %s" - " AND (chnged OR deleted OR rid=0 OR pathname!=origname) ORDER BY 1 /*scan*/", - blob_sql_text(&where) + " AND (chnged OR deleted OR rid=0 OR pathname!=origname) ORDER BY 1", + blob_str(&where) ); blob_zero(&rewrittenPathname); while( db_step(&q)==SQLITE_ROW ){ const char *zPathname = db_column_text(&q,0); const char *zDisplayName = zPathname; @@ -88,11 +86,11 @@ } blob_append(report, zPrefix, nPrefix); if( isDeleted ){ blob_appendf(report, "DELETED %s\n", zDisplayName); }else if( !file_wd_isfile_or_link(zFullName) ){ - if( file_access(zFullName, F_OK)==0 ){ + if( file_access(zFullName, 0)==0 ){ blob_appendf(report, "NOT_A_FILE %s\n", zDisplayName); if( missingIsFatal ){ fossil_warning("not a file: %s", zDisplayName); nErr++; } @@ -103,10 +101,12 @@ nErr++; } } }else if( isNew ){ blob_appendf(report, "ADDED %s\n", zDisplayName); + }else if( isDeleted ){ + blob_appendf(report, "DELETED %s\n", zDisplayName); }else if( isChnged ){ if( isChnged==2 ){ blob_appendf(report, "UPDATED_BY_MERGE %s\n", zDisplayName); }else if( isChnged==3 ){ blob_appendf(report, "ADDED_BY_MERGE %s\n", zDisplayName); @@ -160,35 +160,10 @@ if( absPathOption ){ relativePaths = 0; } if( relPathOption ){ relativePaths = 1; } return relativePaths; } -void print_changes( - int useSha1sum, /* Verify file status using SHA1 hashing rather - than relying on file mtimes. */ - int showHdr, /* Identify the repository if there are changes */ - int verboseFlag, /* Say "(none)" if there are no changes */ - int cwdRelative /* Report relative to the current working dir */ -){ - Blob report; - int vid; - blob_zero(&report); - - vid = db_lget_int("checkout", 0); - vfile_check_signature(vid, useSha1sum ? CKSIG_SHA1 : 0); - status_report(&report, "", 0, cwdRelative); - if( verboseFlag && blob_size(&report)==0 ){ - blob_append(&report, " (none)\n", -1); - } - if( showHdr && blob_size(&report)>0 ){ - fossil_print("Changes for %s at %s:\n", db_get("project-name","???"), - g.zLocalRoot); - } - blob_write_to_file(&report, "-"); - blob_reset(&report); -} - /* ** COMMAND: changes ** ** Usage: %fossil changes ?OPTIONS? ** @@ -204,24 +179,34 @@ ** --sha1sum Verify file status using SHA1 hashing rather ** than relying on file mtimes. ** --header Identify the repository if there are changes ** -v|--verbose Say "(none)" if there are no changes ** -** See also: extras, ls, status +** See also: extra, ls, status */ void changes_cmd(void){ + Blob report; + int vid; int useSha1sum = find_option("sha1sum", 0, 0)!=0; int showHdr = find_option("header",0,0)!=0; int verboseFlag = find_option("verbose","v",0)!=0; int cwdRelative = 0; db_must_be_within_tree(); cwdRelative = determine_cwd_relative_option(); - - /* We should be done with options.. */ - verify_all_options(); - - print_changes(useSha1sum, showHdr, verboseFlag, cwdRelative); + blob_zero(&report); + vid = db_lget_int("checkout", 0); + vfile_check_signature(vid, useSha1sum ? CKSIG_SHA1 : 0); + status_report(&report, "", 0, cwdRelative); + if( verboseFlag && blob_size(&report)==0 ){ + blob_append(&report, " (none)\n", -1); + } + if( showHdr && blob_size(&report)>0 ){ + fossil_print("Changes for %s at %s:\n", db_get("project-name","???"), + g.zLocalRoot); + } + blob_write_to_file(&report, "-"); + blob_reset(&report); } /* ** COMMAND: status ** @@ -238,25 +223,16 @@ ** --rel-paths Display pathnames relative to the current working ** directory. ** --sha1sum Verify file status using SHA1 hashing rather ** than relying on file mtimes. ** -** See also: changes, extras, ls +** See also: changes, extra, ls */ void status_cmd(void){ int vid; - int useSha1sum = find_option("sha1sum", 0, 0)!=0; - int showHdr = find_option("header",0,0)!=0; - int verboseFlag = find_option("verbose","v",0)!=0; - int cwdRelative = 0; db_must_be_within_tree(); /* 012345678901234 */ - cwdRelative = determine_cwd_relative_option(); - - /* We should be done with options.. */ - verify_all_options(); - fossil_print("repository: %s\n", db_repository_filename()); fossil_print("local-root: %s\n", g.zLocalRoot); if( g.zConfigDbName ){ fossil_print("config-db: %s\n", g.zConfigDbName); } @@ -263,136 +239,46 @@ vid = db_lget_int("checkout", 0); if( vid ){ show_common_info(vid, "checkout:", 1, 1); } db_record_repository_filename(0); - print_changes(useSha1sum, showHdr, verboseFlag, cwdRelative); -} - -/* -** Take care of -r version of ls command -*/ -static void ls_cmd_rev( - const char *zRev, /* Revision string given */ - int verboseFlag, /* Verbose flag given */ - int showAge, /* Age flag given */ - int timeOrder /* Order by time flag given */ -){ - Stmt q; - char *zOrderBy = "pathname COLLATE nocase"; - char *zName; - Blob where; - int rid; - int i; - - /* Handle given file names */ - blob_zero(&where); - for(i=2; i<g.argc; i++){ - Blob fname; - file_tree_name(g.argv[i], &fname, 1); - zName = blob_str(&fname); - if( fossil_strcmp(zName, ".")==0 ) { - blob_reset(&where); - break; - } - blob_append_sql(&where, - " %s (pathname=%Q %s) " - "OR (pathname>'%q/' %s AND pathname<'%q0' %s)", - (blob_size(&where)>0) ? "OR" : "AND (", zName, - filename_collation(), zName, filename_collation(), - zName, filename_collation() - ); - } - if( blob_size(&where)>0 ){ - blob_append_sql(&where, ")"); - } - - rid = symbolic_name_to_rid(zRev, "ci"); - if( rid==0 ){ - fossil_fatal("not a valid check-in: %s", zRev); - } - - if( timeOrder ){ - zOrderBy = "mtime DESC"; - } - - compute_fileage(rid,0); - db_prepare(&q, - "SELECT datetime(fileage.mtime, 'localtime'), fileage.pathname,\n" - " blob.size\n" - " FROM fileage, blob\n" - " WHERE blob.rid=fileage.fid %s\n" - " ORDER BY %s;", blob_sql_text(&where), zOrderBy /*safe-for-%s*/ - ); - blob_reset(&where); - - while( db_step(&q)==SQLITE_ROW ){ - const char *zTime = db_column_text(&q,0); - const char *zFile = db_column_text(&q,1); - int size = db_column_int(&q,2); - if( verboseFlag ){ - fossil_print("%s %7d %s\n", zTime, size, zFile); - }else if( showAge ){ - fossil_print("%s %s\n", zTime, zFile); - }else{ - fossil_print("%s\n", zFile); - } - } - db_finalize(&q); + changes_cmd(); } /* ** COMMAND: ls ** -** Usage: %fossil ls ?OPTIONS? ?FILENAMES? +** Usage: %fossil ls ?OPTIONS? ?VERSION? ?FILENAMES? ** ** Show the names of all files in the current checkout. The -v provides ** extra information about each file. If FILENAMES are included, only ** the files listed (or their children if they are directories) are shown. ** -** If -r is given a specific check-in is listed. In this case -R can be -** given to query another repository. -** ** 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 FILE Extract info from repository FILE +** --age Show when each file was committed +** -v|--verbose Provide extra information about each file. ** -** See also: changes, extras, status +** See also: changes, extra, status */ void ls_cmd(void){ int vid; Stmt q; int verboseFlag; int showAge; - int timeOrder; char *zOrderBy = "pathname"; Blob where; int i; const char *zName; - const char *zRev; verboseFlag = find_option("verbose","v", 0)!=0; if( !verboseFlag ){ verboseFlag = find_option("l","l", 0)!=0; /* deprecated */ } showAge = find_option("age",0,0)!=0; - zRev = find_option("r","r",1); - timeOrder = find_option("t","t",0)!=0; - - if( zRev!=0 ){ - db_find_and_open_repository(0, 0); - verify_all_options(); - ls_cmd_rev(zRev,verboseFlag,showAge,timeOrder); - return; - } - db_must_be_within_tree(); vid = db_lget_int("checkout", 0); - if( timeOrder ){ + if( find_option("t","t",0)!=0 ){ if( showAge ){ zOrderBy = mprintf("checkin_mtime(%d,rid) DESC", vid); }else{ zOrderBy = "mtime DESC"; } @@ -405,32 +291,29 @@ zName = blob_str(&fname); if( fossil_strcmp(zName, ".")==0 ) { blob_reset(&where); break; } - blob_append_sql(&where, - " %s (pathname=%Q %s) " - "OR (pathname>'%q/' %s AND pathname<'%q0' %s)", - (blob_size(&where)>0) ? "OR" : "WHERE", zName, - filename_collation(), zName, filename_collation(), - zName, filename_collation() - ); + blob_appendf(&where, " %s (pathname=%Q %s) " + "OR (pathname>'%q/' %s AND pathname<'%q0' %s)", + (blob_size(&where)>0) ? "OR" : "WHERE", zName, + filename_collation(), zName, filename_collation(), + zName, filename_collation()); } vfile_check_signature(vid, 0); if( showAge ){ db_prepare(&q, "SELECT pathname, deleted, rid, chnged, coalesce(origname!=pathname,0)," - " datetime(checkin_mtime(%d,rid),'unixepoch'%s)" + " datetime(checkin_mtime(%d,rid),'unixepoch','localtime')" " FROM vfile %s" - " ORDER BY %s", - vid, timeline_utc(), blob_sql_text(&where), zOrderBy /*safe-for-%s*/ + " ORDER BY %s", vid, blob_str(&where), zOrderBy ); }else{ db_prepare(&q, "SELECT pathname, deleted, rid, chnged, coalesce(origname!=pathname,0)" " FROM vfile %s" - " ORDER BY %s", blob_sql_text(&where), zOrderBy /*safe-for-%s*/ + " ORDER BY %s", blob_str(&where), zOrderBy ); } blob_reset(&where); while( db_step(&q)==SQLITE_ROW ){ const char *zPathname = db_column_text(&q,0); @@ -444,11 +327,11 @@ if( isNew ){ type = "ADDED "; }else if( isDeleted ){ type = "DELETED "; }else if( !file_wd_isfile_or_link(zFullName) ){ - if( file_access(zFullName, F_OK)==0 ){ + if( file_access(zFullName, 0)==0 ){ type = "NOT_A_FILE "; }else{ type = "MISSING "; } }else if( chnged ){ @@ -550,36 +433,29 @@ ** ** Options: ** --abs-paths Display absolute pathnames. ** --case-sensitive <BOOL> override case-sensitive setting ** --dotfiles include files beginning with a dot (".") -** --header Identify the repository if there are extras ** --ignore <CSG> ignore files matching patterns from the argument ** --rel-paths Display pathnames relative to the current working ** directory. ** ** See also: changes, clean, status */ -void extras_cmd(void){ +void extra_cmd(void){ Stmt q; const char *zIgnoreFlag = find_option("ignore",0,1); unsigned scanFlags = find_option("dotfiles",0,0)!=0 ? SCAN_ALL : 0; - int showHdr = find_option("header",0,0)!=0; int cwdRelative = 0; Glob *pIgnore; Blob rewrittenPathname; const char *zPathname, *zDisplayName; if( find_option("temp",0,0)!=0 ) scanFlags |= SCAN_TEMP; + capture_case_sensitive_option(); db_must_be_within_tree(); cwdRelative = determine_cwd_relative_option(); - - if( db_get_boolean("dotfiles", 0) ) scanFlags |= SCAN_ALL; - - /* We should be done with options.. */ - verify_all_options(); - if( zIgnoreFlag==0 ){ zIgnoreFlag = db_get("ignore-glob", 0); } pIgnore = glob_create(zIgnoreFlag); locate_unmanaged_files(g.argc-2, g.argv+2, scanFlags, pIgnore, 0); @@ -590,11 +466,10 @@ " ORDER BY 1", fossil_all_reserved_names(0) ); db_multi_exec("DELETE FROM sfile WHERE x IN (SELECT pathname FROM vfile)"); blob_zero(&rewrittenPathname); - g.allowSymlinks = 1; /* Report on symbolic links */ while( db_step(&q)==SQLITE_ROW ){ zDisplayName = zPathname = db_column_text(&q, 0); if( cwdRelative ) { char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname); file_relative_name(zFullName, &rewrittenPathname, 0); @@ -602,15 +477,10 @@ zDisplayName = blob_str(&rewrittenPathname); if( zDisplayName[0]=='.' && zDisplayName[1]=='/' ){ zDisplayName += 2; /* no unnecessary ./ prefix */ } } - if( showHdr ){ - showHdr = 0; - fossil_print("Extras for %s at %s:\n", db_get("project-name","???"), - g.zLocalRoot); - } fossil_print("%s\n", zDisplayName); } blob_reset(&rewrittenPathname); db_finalize(&q); } @@ -656,11 +526,10 @@ ** argument. Matching files, if any, are removed ** prior to checking for any empty directories; ** therefore, directories that contain only files ** that were removed will be removed as well. ** -f|--force Remove files without prompting. -** --verily Shorthand for: -f --emptydirs --dotfiles ** --clean <CSG> Never prompt for files matching this ** comma separated list of glob patterns. ** --ignore <CSG> Ignore files matching patterns from the ** comma separated list of glob patterns. ** --keep <CSG> Keep files matching this comma separated @@ -667,11 +536,11 @@ ** list of glob patterns. ** -n|--dry-run If given, display instead of run actions. ** --temp Remove only Fossil-generated temporary files. ** -v|--verbose Show all files as they are removed. ** -** See also: addremove, extras, status +** See also: addremove, extra, status */ void clean_cmd(void){ int allFileFlag, allDirFlag, dryRunFlag, verboseFlag; int emptyDirsFlag, dirsOnlyFlag; unsigned scanFlags = 0; @@ -681,13 +550,10 @@ dryRunFlag = find_option("dry-run","n",0)!=0; if( !dryRunFlag ){ dryRunFlag = find_option("test",0,0)!=0; /* deprecated */ } - if( !dryRunFlag ){ - dryRunFlag = find_option("whatif",0,0)!=0; - } allFileFlag = allDirFlag = find_option("force","f",0)!=0; dirsOnlyFlag = find_option("dirsonly",0,0)!=0; emptyDirsFlag = find_option("emptydirs","d",0)!=0 || dirsOnlyFlag; if( find_option("dotfiles",0,0)!=0 ) scanFlags |= SCAN_ALL; if( find_option("temp",0,0)!=0 ) scanFlags |= SCAN_TEMP; @@ -694,36 +560,30 @@ if( find_option("allckouts",0,0)!=0 ) scanFlags |= SCAN_NESTED; zIgnoreFlag = find_option("ignore",0,1); verboseFlag = find_option("verbose","v",0)!=0; zKeepFlag = find_option("keep",0,1); zCleanFlag = find_option("clean",0,1); + capture_case_sensitive_option(); db_must_be_within_tree(); - if( find_option("verily",0,0)!=0 ){ - allFileFlag = allDirFlag = 1; - emptyDirsFlag = 1; - scanFlags |= SCAN_ALL; - } if( zIgnoreFlag==0 ){ zIgnoreFlag = db_get("ignore-glob", 0); } if( zKeepFlag==0 ){ zKeepFlag = db_get("keep-glob", 0); } if( zCleanFlag==0 ){ zCleanFlag = db_get("clean-glob", 0); } - if( db_get_boolean("dotfiles", 0) ) scanFlags |= SCAN_ALL; verify_all_options(); pIgnore = glob_create(zIgnoreFlag); pKeep = glob_create(zKeepFlag); pClean = glob_create(zCleanFlag); nRoot = (int)strlen(g.zLocalRoot); - g.allowSymlinks = 1; /* Find symlinks too */ if( !dirsOnlyFlag ){ Stmt q; Blob repo; - locate_unmanaged_files(g.argc-2, g.argv+2, scanFlags, pIgnore, 0); + locate_unmanaged_files(g.argc-2, g.argv+2, scanFlags, pIgnore, pKeep); db_prepare(&q, "SELECT %Q || x FROM sfile" " WHERE x NOT IN (%s)" " ORDER BY 1", g.zLocalRoot, fossil_all_reserved_names(0) @@ -732,22 +592,16 @@ db_multi_exec("DELETE FROM sfile WHERE x=%B", &repo); } db_multi_exec("DELETE FROM sfile WHERE x IN (SELECT pathname FROM vfile)"); while( db_step(&q)==SQLITE_ROW ){ const char *zName = db_column_text(&q, 0); - if( glob_match(pKeep, zName+nRoot) ){ - if( verboseFlag ){ - fossil_print("KEPT file \"%s\" not removed (due to --keep" - " or \"keep-glob\")\n", zName+nRoot); - } - continue; - } if( !allFileFlag && !dryRunFlag && !glob_match(pClean, zName+nRoot) ){ Blob ans; char cReply; char *prompt = mprintf("Remove unmanaged file \"%s\" (a=all/y/N)? ", zName+nRoot); + blob_zero(&ans); prompt_user(prompt, &ans); cReply = blob_str(&ans)[0]; if( cReply=='a' || cReply=='A' ){ allFileFlag = 1; }else if( cReply!='y' && cReply!='Y' ){ @@ -769,33 +623,27 @@ if( emptyDirsFlag ){ Glob *pEmptyDirs = glob_create(db_get("empty-dirs", 0)); Stmt q; Blob root; blob_init(&root, g.zLocalRoot, nRoot - 1); - vfile_dir_scan(&root, blob_size(&root), scanFlags, pIgnore, - pEmptyDirs, 0); + vfile_dir_scan(&root, blob_size(&root), scanFlags, pIgnore, pKeep, + pEmptyDirs); blob_reset(&root); db_prepare(&q, "SELECT %Q || x FROM dscan_temp" " WHERE x NOT IN (%s) AND y = 0" " ORDER BY 1 DESC", g.zLocalRoot, fossil_all_reserved_names(0) ); while( db_step(&q)==SQLITE_ROW ){ const char *zName = db_column_text(&q, 0); - if( glob_match(pKeep, zName+nRoot) ){ - if( verboseFlag ){ - fossil_print("KEPT directory \"%s\" not removed (due to --keep" - " or \"keep-glob\")\n", zName+nRoot); - } - continue; - } if( !allDirFlag && !dryRunFlag && !glob_match(pClean, zName+nRoot) ){ Blob ans; char cReply; char *prompt = mprintf("Remove empty directory \"%s\" (a=all/y/N)? ", zName+nRoot); + blob_zero(&ans); prompt_user(prompt, &ans); cReply = blob_str(&ans)[0]; if( cReply=='a' || cReply=='A' ){ allDirFlag = 1; }else if( cReply!='y' && cReply!='Y' ){ @@ -949,48 +797,28 @@ #else blob_init(&prompt, zInit, -1); #endif blob_append(&prompt, "\n" - "# Enter a commit message for this check-in. Lines beginning with # are ignored.\n" + "# Enter comments on this check-in. Lines beginning with # are ignored.\n" "#\n", -1 ); - blob_appendf(&prompt, "# user: %s\n", p->zUserOvrd ? p->zUserOvrd : login_name()); + blob_appendf(&prompt, "# user: %s\n", p->zUserOvrd ? p->zUserOvrd : g.zLogin); if( p->zBranch && p->zBranch[0] ){ blob_appendf(&prompt, "# tags: %s\n#\n", p->zBranch); }else{ char *zTags = info_tags_of_checkin(parent_rid, 1); - if( zTags || p->azTag ){ - blob_append(&prompt, "# tags: ", 8); - if(zTags){ - blob_appendf(&prompt, "%z%s", zTags, p->azTag ? ", " : ""); - } - if(p->azTag){ - int i = 0; - for( ; p->azTag[i]; ++i ){ - blob_appendf(&prompt, "%s%s", p->azTag[i], - p->azTag[i+1] ? ", " : ""); - } - } - blob_appendf(&prompt, "\n#\n"); - } + if( zTags ) blob_appendf(&prompt, "# tags: %z\n#\n", zTags); } status_report(&prompt, "# ", 1, 0); if( g.markPrivate ){ blob_append(&prompt, "# PRIVATE BRANCH: This check-in will be private and will not sync to\n" "# repositories.\n" "#\n", -1 ); } - if( p->integrateFlag ){ - blob_append(&prompt, - "#\n" - "# All merged-in branches will be closed due to the --integrate flag\n" - "#\n", -1 - ); - } prompt_for_user_comment(pComment, &prompt); blob_reset(&prompt); } /* @@ -1014,12 +842,14 @@ assert( g.aCommitFile==0 ); if( g.argc>2 ){ int ii, jj=0; Blob fname; Stmt q; + const char *zCollate; Bag toCommit; + zCollate = filename_collation(); blob_zero(&fname); bag_init(&toCommit); for(ii=2; ii<g.argc; ii++){ int cnt = 0; file_tree_name(g.argv[ii], &fname, 1); @@ -1028,12 +858,12 @@ return result; } db_prepare(&q, "SELECT id FROM vfile WHERE pathname=%Q %s" " OR (pathname>'%q/' %s AND pathname<'%q0' %s)", - blob_str(&fname), filename_collation(), blob_str(&fname), - filename_collation(), blob_str(&fname), filename_collation()); + blob_str(&fname), zCollate, blob_str(&fname), + zCollate, blob_str(&fname), zCollate); while( db_step(&q)==SQLITE_ROW ){ cnt++; bag_insert(&toCommit, db_column_int(&q, 0)); } db_finalize(&q); @@ -1069,11 +899,11 @@ " WHERE datetime(mtime)>=%Q" " AND type='ci' AND objid=%d", zDate, rid ); if( b ){ - fossil_fatal("ancestor check-in [%S] (%s) is not older (clock skew?)" + fossil_fatal("ancestor check-in [%.10s] (%s) is not older (clock skew?)" " Use --allow-older to override.", zUuid, zDate); } #endif } @@ -1122,14 +952,13 @@ struct CheckinInfo { Blob *pComment; /* Check-in comment text */ const char *zMimetype; /* Mimetype of check-in command. May be NULL */ int verifyDate; /* Verify that child is younger */ int closeFlag; /* Close the branch being committed */ - int integrateFlag; /* Close merged-in branches */ Blob *pCksum; /* Repository checksum. May be 0 */ const char *zDateOvrd; /* Date override. If 0 then use 'now' */ - const char *zUserOvrd; /* User override. If 0 then use login_name() */ + const char *zUserOvrd; /* User override. If 0 then use g.zLogin */ const char *zBranch; /* Branch name. May be 0 */ const char *zColor; /* One-time background color. May be 0 */ const char *zBrClr; /* Persistent branch color. May be 0 */ const char **azTag; /* Tags to apply to this check-in */ }; @@ -1145,11 +974,11 @@ int vid, /* BLOB.id for the parent check-in */ CheckinInfo *p, /* Information about the check-in */ int *pnFBcard /* OUT: Number of generated B- and F-cards */ ){ char *zDate; /* Date of the check-in */ - char *zParentUuid = 0; /* UUID of parent check-in */ + char *zParentUuid; /* UUID of parent check-in */ Blob filename; /* A single filename */ int nBasename; /* Size of base filename */ Stmt q; /* Various queries */ Blob mcksum; /* Manifest checksum */ ManifestFile *pFile; /* File from the baseline */ @@ -1158,19 +987,11 @@ const char *zColor; /* Modified value of p->zColor */ assert( pBaseline==0 || pBaseline->zBaseline==0 ); assert( pBaseline==0 || zBaselineUuid!=0 ); 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 checkout/repo mismatch.", vid); - } - } + zParentUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", vid); if( pBaseline ){ blob_appendf(pOut, "B %s\n", zBaselineUuid); manifest_file_rewind(pBaseline); pFile = manifest_file_next(pBaseline, 0); nFBcard++; @@ -1261,30 +1082,28 @@ nFBcard++; } if( p->zMimetype && p->zMimetype[0] ){ blob_appendf(pOut, "N %F\n", p->zMimetype); } - if( vid ){ - blob_appendf(pOut, "P %s", zParentUuid); - if( p->verifyDate ) checkin_verify_younger(vid, zParentUuid, zDate); - free(zParentUuid); - db_prepare(&q, "SELECT merge FROM vmerge WHERE id=0 OR id<-2"); - while( db_step(&q)==SQLITE_ROW ){ - char *zMergeUuid; - int mid = db_column_int(&q, 0); - if( (!g.markPrivate && content_is_private(mid)) || (mid == vid) ) continue; - zMergeUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", mid); - if( zMergeUuid ){ - blob_appendf(pOut, " %s", zMergeUuid); - if( p->verifyDate ) checkin_verify_younger(mid, zMergeUuid, zDate); - free(zMergeUuid); - } - } - db_finalize(&q); - blob_appendf(pOut, "\n"); - } + blob_appendf(pOut, "P %s", zParentUuid); + if( p->verifyDate ) checkin_verify_younger(vid, zParentUuid, zDate); + free(zParentUuid); + db_prepare(&q, "SELECT merge FROM vmerge WHERE id=0 OR id<-2"); + while( db_step(&q)==SQLITE_ROW ){ + char *zMergeUuid; + int mid = db_column_int(&q, 0); + if( (!g.markPrivate && content_is_private(mid)) || (mid == vid) ) continue; + zMergeUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", mid); + if( zMergeUuid ){ + blob_appendf(pOut, " %s", zMergeUuid); + if( p->verifyDate ) checkin_verify_younger(mid, zMergeUuid, zDate); + free(zMergeUuid); + } + } + db_finalize(&q); free(zDate); + blob_appendf(pOut, "\n"); db_prepare(&q, "SELECT CASE vmerge.id WHEN -1 THEN '+' ELSE '-' END || blob.uuid, merge" " FROM vmerge, blob" " WHERE (vmerge.id=-1 OR vmerge.id=-2)" @@ -1316,12 +1135,11 @@ } if( p->closeFlag ){ blob_appendf(pOut, "T +closed *\n"); } db_prepare(&q, "SELECT uuid,merge FROM vmerge JOIN blob ON merge=rid" - " WHERE id %s ORDER BY 1", - p->integrateFlag ? "IN(0,-4)" : "=(-4)"); + " WHERE id=-4 ORDER BY 1"); while( db_step(&q)==SQLITE_ROW ){ const char *zIntegrateUuid = db_column_text(&q, 0); int rid = db_column_int(&q, 1); if( is_a_leaf(rid) && !db_exists("SELECT 1 FROM tagxref " " WHERE tagid=%d AND rid=%d AND tagtype>0", TAG_CLOSED, rid)){ @@ -1351,11 +1169,11 @@ const char *zBrTag = db_column_text(&q, 0); blob_appendf(pOut, "T -%F *\n", zBrTag); } db_finalize(&q); } - blob_appendf(pOut, "U %F\n", p->zUserOvrd ? p->zUserOvrd : login_name()); + blob_appendf(pOut, "U %F\n", p->zUserOvrd ? p->zUserOvrd : g.zLogin); md5sum_blob(pOut, &mcksum); blob_appendf(pOut, "Z %b\n", &mcksum); if( pnFBcard ) *pnFBcard = nFBcard; } @@ -1380,11 +1198,10 @@ 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 byte-sequence which is invalid for 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; @@ -1391,19 +1208,16 @@ fUnicode = could_be_utf16(p, &bReverse); if( fUnicode ){ lookFlags = looks_like_utf16(p, bReverse, LOOK_NUL); }else{ lookFlags = looks_like_utf8(p, LOOK_NUL); - if( !(lookFlags & LOOK_BINARY) && invalid_utf8(p) ){ - fHasInvalidUtf8 = 1; - } } fHasAnyCr = (lookFlags & LOOK_CR); fBinary = (lookFlags & LOOK_BINARY); fHasLoneCrOnly = ((lookFlags & LOOK_EOL) == LOOK_LONE_CR); fHasCrLfOnly = ((lookFlags & LOOK_EOL) == LOOK_CRLF); - if( fUnicode || fHasAnyCr || fBinary || fHasInvalidUtf8){ + if( fUnicode || fHasAnyCr || fBinary ){ const char *zWarning; const char *zDisable; const char *zConvert = "c=convert/"; Blob ans; char cReply; @@ -1432,16 +1246,10 @@ zWarning = "CR/NL line endings and Unicode"; }else{ zWarning = "mixed line endings and Unicode"; } zDisable = "\"crnl-glob\" and \"encoding-glob\" settings"; - }else if( fHasInvalidUtf8 ){ - if( encodingOk ){ - return 0; /* We don't want encoding warnings for this file. */ - } - zWarning = "invalid UTF-8"; - zDisable = "\"encoding-glob\" setting"; }else if( fHasAnyCr ){ if( crnlOk ){ return 0; /* We don't want CR/NL warnings for this file. */ } if( fHasLoneCrOnly ){ @@ -1455,13 +1263,17 @@ }else{ if( encodingOk ){ return 0; /* We don't want encoding warnings for this file. */ } zWarning = "Unicode"; +#if !defined(_WIN32) && !defined(__CYGWIN__) + zConvert = ""; /* On Unix, we cannot easily convert Unicode files. */ +#endif zDisable = "\"encoding-glob\" setting"; } file_relative_name(zFilename, &fname, 0); + blob_zero(&ans); zMsg = mprintf( "%s contains %s. Use --no-warnings or the %s to disable this warning.\n" "Commit anyhow (a=all/%sy/N)? ", blob_str(&fname), zWarning, zDisable, zConvert); prompt_user(zMsg, &ans); @@ -1473,27 +1285,21 @@ char *zOrig = file_newname(zFilename, "original", 1); FILE *f; blob_write_to_file(p, zOrig); fossil_free(zOrig); f = fossil_fopen(zFilename, "wb"); - if( f==0 ){ - fossil_warning("cannot open %s for writing", zFilename); - }else{ - if( fUnicode ) { - int bomSize; - const unsigned char *bom = get_utf8_bom(&bomSize); - fwrite(bom, 1, bomSize, f); - blob_to_utf8_no_bom(p, 0); - }else if( fHasInvalidUtf8 ){ - blob_cp1252_to_utf8(p); - } - if( fHasAnyCr ){ - blob_to_lf_only(p); - } - fwrite(blob_buffer(p), 1, blob_size(p), f); - fclose(f); - } + if( fUnicode ) { + int bomSize; + const unsigned char *bom = get_utf8_bom(&bomSize); + fwrite(bom, 1, bomSize, f); + blob_to_utf8_no_bom(p, 0); + } + if( fHasAnyCr ){ + blob_to_lf_only(p); + } + fwrite(blob_buffer(p), 1, blob_size(p), f); + fclose(f); return 1; }else if( cReply!='y' && cReply!='Y' ){ fossil_fatal("Abandoning commit due to %s in %s", zWarning, blob_str(&fname)); } @@ -1534,11 +1340,11 @@ ** passed to the --branch option. ** ** Use the --branchcolor option followed by a color name (ex: ** '#ffc0c0') to specify the background color of entries in the new ** branch when shown in the web timeline interface. The use of -** the --branchcolor option is not recommended. Instead, let Fossil +** the --branchcolor option is not recommend. Instead, let Fossil ** choose the branch color automatically. ** ** The --bgcolor option works like --branchcolor but only sets the ** background color for a single check-in. Subsequent check-ins revert ** to the default color. @@ -1555,21 +1361,14 @@ ** unless the interactive user chooses to proceed. If there is no ** interactive user or these warnings should be skipped for some other ** reason, the --no-warnings option may be used. A check-in is not ** allowed against a closed leaf. ** -** If a commit message is blank, you will be prompted: -** ("continue (y/N)?") to confirm you really want to commit with a -** blank commit message. The default value is "N", do not commit. -** ** The --private option creates a private check-in that is never synced. ** Children of private check-ins are automatically private. ** -** The --tag option applies the symbolic tag name to the check-in. -** -** The --sha1sum option detects edited files by computing each file's -** SHA1 hash rather than just checking for changes to its size or mtime. +** the --tag option applies the symbolic tag name to the check-in. ** ** Options: ** --allow-conflict allow unresolved merge conflicts ** --allow-empty allow a commit with no changes ** --allow-fork allow the commit to fork @@ -1578,23 +1377,20 @@ ** --bgcolor COLOR apply COLOR to this one check-in only ** --branch NEW-BRANCH-NAME check in to this new branch ** --branchcolor COLOR apply given COLOR to the branch ** --close close the branch being committed ** --delta use a delta manifest in the commit process -** --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 ** --no-warnings omit all warnings about file contents ** --nosign do not attempt to sign this commit with gpg ** --private do not sync changes and their descendants -** --sha1sum verify file status using SHA1 hashing rather -** than relying on file mtimes -** --tag TAG-NAME assign given tag TAG-NAME to the check-in +** --tag TAG-NAME assign given tag TAG-NAME to the checkin ** -** See also: branch, changes, checkout, extras, sync +** See also: branch, changes, checkout, extra, sync */ void commit_cmd(void){ int hasChanges; /* True if unsaved changes exist */ int vid; /* blob-id of parent version */ int nrid; /* blob-id of a modified file */ @@ -1601,11 +1397,10 @@ int nvid; /* Blob-id of the new check-in */ Blob comment; /* Check-in comment */ const char *zComment; /* Check-in comment */ Stmt q; /* Various queries */ char *zUuid; /* UUID of the new check-in */ - int useSha1sum = 0; /* True to verify file status using SHA1 hashing */ int noSign = 0; /* True to omit signing the manifest using GPG */ int isAMerge = 0; /* True if checking in a merge */ int noWarningFlag = 0; /* True if skipping all warnings */ int forceFlag = 0; /* Undocumented: Disables all checks */ int forceDelta = 0; /* Force a delta-manifest */ @@ -1633,11 +1428,10 @@ Blob ans; char cReply; memset(&sCiInfo, 0, sizeof(sCiInfo)); url_proxy_options(); - useSha1sum = find_option("sha1sum", 0, 0)!=0; noSign = find_option("nosign",0,0)!=0; forceDelta = find_option("delta",0,0)!=0; forceBaseline = find_option("baseline",0,0)!=0; if( forceDelta && forceBaseline ){ fossil_fatal("cannot use --delta and --baseline together"); @@ -1655,11 +1449,10 @@ noWarningFlag = find_option("no-warnings", 0, 0)!=0; sCiInfo.zBranch = find_option("branch","b",1); sCiInfo.zColor = find_option("bgcolor",0,1); sCiInfo.zBrClr = find_option("branchcolor",0,1); sCiInfo.closeFlag = find_option("close",0,0)!=0; - sCiInfo.integrateFlag = find_option("integrate",0,0)!=0; sCiInfo.zMimetype = find_option("mimetype",0,1); while( (zTag = find_option("tag",0,1))!=0 ){ if( zTag[0]==0 ) continue; sCiInfo.azTag = fossil_realloc((void*)sCiInfo.azTag, sizeof(char*)*(nTag+2)); sCiInfo.azTag[nTag++] = zTag; @@ -1699,21 +1492,20 @@ forceBaseline = 1; } /* Get the ID of the parent manifest artifact */ vid = db_lget_int("checkout", 0); - if( vid==0 ){ - useCksum = 1; - }else if( content_is_private(vid) ){ + if( content_is_private(vid) ){ g.markPrivate = 1; } /* ** Autosync if autosync is enabled and this is not a private check-in. */ if( !g.markPrivate ){ - if( autosync_loop(SYNC_PULL, db_get_int("autosync-tries", 1)) ){ + if( autosync(SYNC_PULL) ){ + blob_zero(&ans); prompt_user("continue in spite of sync failure (y/N)? ", &ans); cReply = blob_str(&ans)[0]; if( cReply!='y' && cReply!='Y' ){ fossil_exit(1); } @@ -1722,10 +1514,11 @@ /* Require confirmation to continue with the check-in if there is ** clock skew */ if( g.clockSkewSeen ){ + blob_zero(&ans); prompt_user("continue in spite of time skew (y/N)? ", &ans); cReply = blob_str(&ans)[0]; if( cReply!='y' && cReply!='Y' ){ fossil_exit(1); } @@ -1740,13 +1533,14 @@ ** 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. */ if( select_commit_files() ){ + blob_zero(&ans); prompt_user("continue (y/N)? ", &ans); cReply = blob_str(&ans)[0]; - if( cReply!='y' && cReply!='Y' ) fossil_exit(1); + if( cReply!='y' && cReply!='Y' ) fossil_exit(1);; } isAMerge = db_exists("SELECT 1 FROM vmerge WHERE id=0 OR id<-2"); if( g.aCommitFile && isAMerge ){ fossil_fatal("cannot do a partial commit of a merge"); } @@ -1779,11 +1573,11 @@ */ if( !db_exists("SELECT 1 FROM user WHERE login=%Q", g.zLogin) ){ fossil_fatal("no such user: %s", g.zLogin); } - hasChanges = unsaved_changes(useSha1sum ? CKSIG_SHA1 : 0); + hasChanges = unsaved_changes(); db_begin_transaction(); db_record_repository_filename(0); if( hasChanges==0 && !isAMerge && !allowEmpty && !forceFlag ){ fossil_fatal("nothing has changed; use --allow-empty to override"); } @@ -1805,42 +1599,23 @@ } /* ** Do not allow a commit that will cause a fork unless the --allow-fork ** or --force flags is used, or unless this is a private check-in. - ** The initial commit MUST have tags "trunk" and "sym-trunk". */ - if( !vid ){ - if( sCiInfo.zBranch==0 ){ - if( allowFork==0 && forceFlag==0 && g.markPrivate==0 - && db_exists("SELECT 1 from event where type='ci'") ){ - fossil_fatal("would fork. \"update\" first or use --allow-fork."); - } - sCiInfo.zBranch = db_get("main-branch", "trunk"); - } - }else if( sCiInfo.zBranch==0 && allowFork==0 && forceFlag==0 + if( sCiInfo.zBranch==0 && allowFork==0 && forceFlag==0 && g.markPrivate==0 && !is_a_leaf(vid) ){ fossil_fatal("would fork. \"update\" first or use --allow-fork."); } /* - ** Do not allow a commit against a closed leaf unless the commit - ** ends up on a different branch. + ** Do not allow a commit against a closed leaf */ - if( - /* parent check-in has the "closed" tag... */ - db_exists("SELECT 1 FROM tagxref" + if( db_exists("SELECT 1 FROM tagxref" " WHERE tagid=%d AND rid=%d AND tagtype>0", - TAG_CLOSED, vid) - /* ... and the new check-in has no --branch option or the --branch - ** option does not actually change the branch */ - && (sCiInfo.zBranch==0 - || db_exists("SELECT 1 FROM tagxref" - " WHERE tagid=%d AND rid=%d AND tagtype>0" - " AND value=%Q", TAG_BRANCH, vid, sCiInfo.zBranch)) - ){ + TAG_CLOSED, vid) ){ fossil_fatal("cannot commit against a closed leaf"); } if( useCksum ) vfile_aggregate_checksum_disk(vid, &cksum1); if( zComment ){ @@ -1854,18 +1629,20 @@ blob_zero(&comment); }else{ char *zInit = db_text(0, "SELECT value FROM vvar WHERE name='ci-comment'"); prepare_commit_comment(&comment, zInit, &sCiInfo, vid); if( zInit && zInit[0] && fossil_strcmp(zInit, blob_str(&comment))==0 ){ + blob_zero(&ans); prompt_user("unchanged check-in comment. continue (y/N)? ", &ans); cReply = blob_str(&ans)[0]; - if( cReply!='y' && cReply!='Y' ) fossil_exit(1); + if( cReply!='y' && cReply!='Y' ) fossil_exit(1);; } free(zInit); } if( blob_size(&comment)==0 ){ if( !dryRunFlag ){ + blob_zero(&ans); prompt_user("empty check-in comment. continue (y/N)? ", &ans); cReply = blob_str(&ans)[0]; if( cReply!='y' && cReply!='Y' ){ fossil_exit(1); } @@ -1966,11 +1743,11 @@ if( pBaseline ){ Blob delta; create_manifest(&delta, zBaselineUuid, pBaseline, vid, &sCiInfo, &szD); /* ** At this point, two manifests have been constructed, either of - ** which would work for this check-in. The first manifest (held + ** which would work for this checkin. The first manifest (held ** in the "manifest" variable) is a baseline manifest and the second ** (held in variable named "delta") is a delta manifest. The ** question now is: which manifest should we use? ** ** Let B be the number of F-cards in the baseline manifest and @@ -1994,10 +1771,11 @@ }else if( forceDelta ){ fossil_fatal("unable to find a baseline-manifest for the delta"); } } if( !noSign && !g.markPrivate && clearsign(&manifest, &manifest) ){ + blob_zero(&ans); prompt_user("unable to sign manifest. continue (y/N)? ", &ans); cReply = blob_str(&ans)[0]; if( cReply!='y' && cReply!='Y' ){ fossil_exit(1); } @@ -2020,14 +1798,11 @@ nvid = content_put(&manifest); if( nvid==0 ){ fossil_fatal("trouble committing manifest: %s", g.zErrMsg); } db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", nvid); - if( manifest_crosslink(nvid, &manifest, - dryRunFlag ? MC_NONE : MC_PERMIT_HOOKS)==0 ){ - fossil_fatal("%s\n", g.zErrMsg); - } + manifest_crosslink(nvid, &manifest); assert( blob_is_reset(&manifest) ); content_deltify(vid, nvid, 0); zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", nvid); db_prepare(&q, "SELECT uuid,merge FROM vmerge JOIN blob ON merge=rid" @@ -2064,11 +1839,11 @@ ); db_lset_int("checkout", nvid); if( useCksum ){ /* Verify that the repository checksum matches the expected checksum - ** calculated before the check-in started (and stored as the R record + ** calculated before the checkin 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); @@ -2108,11 +1883,11 @@ exit(1); } db_end_transaction(0); if( !g.markPrivate ){ - autosync_loop(SYNC_PUSH|SYNC_PULL, db_get_int("autosync-tries", 1)); + autosync(SYNC_PUSH|SYNC_PULL); } if( count_nonbranch_children(vid)>1 ){ fossil_print("**** warning: a fork has occurred *****\n"); } } Index: src/checkout.c ================================================================== --- src/checkout.c +++ src/checkout.c @@ -26,28 +26,29 @@ ** Check to see if there is an existing checkout that has been ** modified. Return values: ** ** 0: There is an existing checkout but it is unmodified ** 1: There is a modified checkout - there are unsaved changes +** 2: There is no existing checkout */ -int unsaved_changes(unsigned int cksigFlags){ +int unsaved_changes(void){ int vid; db_must_be_within_tree(); vid = db_lget_int("checkout",0); - vfile_check_signature(vid, cksigFlags|CKSIG_ENOTFILE); + if( vid==0 ) return 2; + vfile_check_signature(vid, CKSIG_ENOTFILE); return db_exists("SELECT 1 FROM vfile WHERE chnged" " OR coalesce(origname!=pathname,0)"); } /* ** Undo the current check-out. Unlink all files from the disk. ** Clear the VFILE table. */ void uncheckout(int vid){ - if( vid>0 ){ - vfile_unlink(vid); - } + if( vid==0 ) return; + vfile_unlink(vid); db_multi_exec("DELETE FROM vfile WHERE vid=%d", vid); } /* @@ -54,28 +55,26 @@ ** Given the abbreviated UUID name of a version, load the content of that ** version in the VFILE table. Return the VID for the version. ** ** If anything goes wrong, panic. */ -int load_vfile(const char *zName, int forceMissingFlag){ +int load_vfile(const char *zName){ Blob uuid; int vid; blob_init(&uuid, zName, -1); if( name_to_uuid(&uuid, 1, "ci") ){ - fossil_fatal("%s", g.zErrMsg); + fossil_fatal(g.zErrMsg); } vid = db_int(0, "SELECT rid FROM blob WHERE uuid=%B", &uuid); 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)); + fossil_fatal("object [%.10s] is not a check-in", blob_str(&uuid)); } - if( load_vfile_from_rid(vid) && !forceMissingFlag ){ - fossil_fatal("missing content, unable to checkout"); - }; + load_vfile_from_rid(vid); return vid; } /* ** Set or clear the vfile.isexe flag for a file. @@ -137,15 +136,14 @@ if( db_get_boolean("manifest",0) ){ blob_zero(&manifest); content_get(vid, &manifest); zManFile = mprintf("%smanifest", g.zLocalRoot); + blob_write_to_file(&manifest, zManFile); + free(zManFile); blob_zero(&hash); sha1sum_blob(&manifest, &hash); - sterilize_manifest(&manifest); - blob_write_to_file(&manifest, zManFile); - free(zManFile); zManFile = mprintf("%smanifest.uuid", g.zLocalRoot); blob_append(&hash, "\n", 1); blob_write_to_file(&hash, zManFile); free(zManFile); blob_reset(&hash); @@ -159,11 +157,11 @@ zManFile = mprintf("%smanifest.uuid", g.zLocalRoot); file_delete(zManFile); free(zManFile); } } - + } /* ** COMMAND: checkout* ** COMMAND: co* @@ -177,43 +175,36 @@ ** leaves files on disk unchanged, except the manifest and manifest.uuid ** files. ** ** The --latest flag can be used in place of VERSION to checkout the ** latest version in the repository. -** +** ** Options: -** --force Ignore edited files in the current checkout -** --keep Only update the manifest and manifest.uuid files -** --force-missing Force checkout even if content is missing +** --force Ignore edited files in the current checkout +** --keep Only update the manifest and manifest.uuid files ** ** See also: update */ void checkout_cmd(void){ int forceFlag; /* Force checkout even if edits exist */ - int forceMissingFlag; /* Force checkout even if missing content */ int keepFlag; /* Do not change any files on disk */ int latestFlag; /* Checkout the latest version */ char *zVers; /* Version to checkout */ int promptFlag; /* True to prompt before overwriting */ int vid, prior; Blob cksum1, cksum1b, cksum2; - + db_must_be_within_tree(); db_begin_transaction(); forceFlag = find_option("force","f",0)!=0; - forceMissingFlag = find_option("force-missing",0,0)!=0; keepFlag = find_option("keep",0,0)!=0; latestFlag = find_option("latest",0,0)!=0; promptFlag = find_option("prompt",0,0)!=0 || forceFlag==0; - - /* 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) ){ + if( !forceFlag && unsaved_changes()==1 ){ fossil_fatal("there are unsaved changes in the current checkout"); } if( forceFlag ){ db_multi_exec("DELETE FROM vfile"); prior = 0; @@ -229,16 +220,16 @@ zVers = db_text(0, "SELECT uuid FROM event, blob" " WHERE event.objid=blob.rid AND event.type='ci'" " ORDER BY event.mtime DESC"); } if( zVers==0 ){ - return; + fossil_fatal("cannot locate \"latest\" checkout"); } }else{ zVers = g.argv[2]; } - vid = load_vfile(zVers, forceMissingFlag); + vid = load_vfile(zVers); if( prior==vid ){ return; } if( !keepFlag ){ uncheckout(prior); @@ -297,27 +288,22 @@ ** 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) ){ + if( !forceFlag && unsaved_changes()==1 ){ fossil_fatal("there are unsaved changes in the current checkout"); } if( !forceFlag - && db_table_exists("localdb","stash") + && db_exists("SELECT 1 FROM %s.sqlite_master WHERE name='stash'", + db_name("localdb")) && db_exists("SELECT 1 FROM %s.stash", db_name("localdb")) ){ fossil_fatal("closing the checkout will delete your stash"); } if( db_is_writeable("repository") ){ - char *zUnset = mprintf("ckout:%q", g.zLocalRoot); - db_unset(zUnset, 1); - fossil_free(zUnset); + db_multi_exec("DELETE FROM config WHERE name='ckout:%q'", g.zLocalRoot); } unlink_local_database(1); db_close(1); unlink_local_database(0); } Index: src/clone.c ================================================================== --- src/clone.c +++ src/clone.c @@ -83,11 +83,11 @@ ** COMMAND: clone ** ** Usage: %fossil clone ?OPTIONS? URL FILENAME ** ** Make a clone of a repository specified by URL in the local -** file named FILENAME. +** file named FILENAME. ** ** URL must be in one of the following form: ([...] mean optional) ** HTTP/HTTPS protocol: ** http[s]://[userid[:password]@]host[:port][/path] ** @@ -96,65 +96,50 @@ ** [?fossil=path/to/fossil.exe] ** ** Filesystem: ** [file://]path/to/repo.fossil ** -** Note: For ssh and filesystem, path must have an extra leading +** Note: For ssh and filesystem, path must have an extra leading ** '/' to use an absolute path. ** ** By default, your current login name is used to create the default ** admin user. This can be overridden using the -A|--admin-user ** parameter. ** ** Options: ** --admin-user|-A USERNAME Make USERNAME the administrator -** --once Don't save url. -** --private Also clone private branches +** --private Also clone private branches ** --ssl-identity=filename Use the SSL identity if requested by the server -** --ssh-command|-c 'command' Use this SSH command -** --httpauth|-B 'user:pass' Add HTTP Basic Authorization to requests -** --verbose Show more statistics in output ** ** See also: init */ void clone_cmd(void){ char *zPassword; const char *zDefaultUser; /* Optional name of the default user */ - const char *zHttpAuth; /* HTTP Authorization user:pass information */ - int nErr = 0; - int urlFlags = URL_PROMPT_PW | URL_REMEMBER; - int syncFlags = SYNC_CLONE; - - /* Also clone private branches */ - if( find_option("private",0,0)!=0 ) syncFlags |= SYNC_PRIVATE; - if( find_option("once",0,0)!=0) urlFlags &= ~URL_REMEMBER; - if( find_option("verbose",0,0)!=0) syncFlags |= SYNC_VERBOSE; - zHttpAuth = find_option("httpauth","B",1); - zDefaultUser = find_option("admin-user","A",1); - clone_ssh_find_options(); - url_proxy_options(); - - /* We should be done with options.. */ - verify_all_options(); - + int nErr = 0; + int bPrivate = 0; /* Also clone private branches */ + + if( find_option("private",0,0)!=0 ) bPrivate = SYNC_PRIVATE; + url_proxy_options(); if( g.argc < 4 ){ usage("?OPTIONS? FILE-OR-URL NEW-REPOSITORY"); } db_open_config(0); - if( -1 != file_size(g.argv[3]) ){ + if( file_size(g.argv[3])>0 ){ fossil_fatal("file already exists: %s", g.argv[3]); } - url_parse(g.argv[2], urlFlags); - if( zDefaultUser==0 && g.url.user!=0 ) zDefaultUser = g.url.user; - if( g.url.isFile ){ - file_copy(g.url.name, g.argv[3]); + zDefaultUser = find_option("admin-user","A",1); + + url_parse(g.argv[2], URL_PROMPT_PW|URL_ASK_REMEMBER_PW); + if( g.urlIsFile ){ + file_copy(g.urlName, g.argv[3]); db_close(1); db_open_repository(g.argv[3]); db_record_repository_filename(g.argv[3]); url_remember(); - if( !(syncFlags & SYNC_PRIVATE) ) delete_private_content(); + if( !bPrivate ) delete_private_content(); shun_artifacts(); db_create_default_users(1, zDefaultUser); if( zDefaultUser ){ g.zLogin = zDefaultUser; }else{ @@ -164,16 +149,14 @@ }else{ db_create_repository(g.argv[3]); db_open_repository(g.argv[3]); db_begin_transaction(); db_record_repository_filename(g.argv[3]); - db_initial_setup(0, 0, zDefaultUser); + db_initial_setup(0, 0, zDefaultUser, 0); user_select(); db_set("content-schema", CONTENT_SCHEMA, 0); - db_set("aux-schema", AUX_SCHEMA_MAX, 0); - db_set("rebuilt", get_version(), 0); - remember_or_get_http_auth(zHttpAuth, urlFlags & URL_REMEMBER, g.argv[2]); + db_set("aux-schema", AUX_SCHEMA, 0); url_remember(); if( g.zSSLIdentity!=0 ){ /* If the --ssl-identity option was specified, store it as a setting */ Blob fn; blob_zero(&fn); @@ -182,17 +165,15 @@ blob_reset(&fn); } db_multi_exec( "REPLACE INTO config(name,value,mtime)" " VALUES('server-code', lower(hex(randomblob(20))), now());" - "DELETE FROM config WHERE name='project-code';" ); url_enable_proxy(0); - clone_ssh_db_set_options(); url_get_password_if_needed(); g.xlinkClusterOnly = 1; - nErr = client_sync(syncFlags,CONFIGSET_ALL,0); + nErr = client_sync(SYNC_CLONE | bPrivate,CONFIGSET_ALL,0); g.xlinkClusterOnly = 0; verify_cancel(); db_end_transaction(0); db_close(1); if( nErr ){ @@ -202,89 +183,10 @@ db_open_repository(g.argv[3]); } db_begin_transaction(); fossil_print("Rebuilding repository meta-data...\n"); rebuild_db(0, 1, 0); - fossil_print("Extra delta compression... "); fflush(stdout); - extra_deltification(); - db_end_transaction(0); - fossil_print("\nVacuuming 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_multi_exec("VACUUM"); - fossil_print("\nproject-id: %s\n", db_get("project-code", 0)); - fossil_print("server-id: %s\n", db_get("server-code", 0)); + fossil_print("project-id: %s\n", db_get("project-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); -} - -/* -** If user chooses to use HTTP Authentication over unencrypted HTTP, -** remember decision. Otherwise, if the URL is being changed and no -** preference has been indicated, err on the safe side and revert the -** decision. Set the global preference if the URL is not being changed. -*/ -void remember_or_get_http_auth( - const char *zHttpAuth, /* Credentials in the form "user:password" */ - int fRemember, /* True to remember credentials for later reuse */ - const char *zUrl /* URL for which these credentials apply */ -){ - char *zKey = mprintf("http-auth:%s", g.url.canonical); - if( zHttpAuth && zHttpAuth[0] ){ - g.zHttpAuth = mprintf("%s", zHttpAuth); - } - if( fRemember ){ - if( g.zHttpAuth && g.zHttpAuth[0] ){ - set_httpauth(g.zHttpAuth); - }else if( zUrl && zUrl[0] ){ - db_unset(zKey, 0); - }else{ - g.zHttpAuth = get_httpauth(); - } - }else if( g.zHttpAuth==0 && zUrl==0 ){ - g.zHttpAuth = get_httpauth(); - } - free(zKey); -} - -/* -** Get the HTTP Authorization preference from db. -*/ -char *get_httpauth(void){ - char *zKey = mprintf("http-auth:%s", g.url.canonical); - char * rc = unobscure(db_get(zKey, 0)); - free(zKey); - return rc; -} - -/* -** Set the HTTP Authorization preference in db. -*/ -void set_httpauth(const char *zHttpAuth){ - char *zKey = mprintf("http-auth:%s", g.url.canonical); - db_set(zKey, obscure(zHttpAuth), 0); - free(zKey); -} - -/* -** Look for SSH clone command line options and setup in globals. -*/ -void clone_ssh_find_options(void){ - const char *zSshCmd; /* SSH command string */ - - zSshCmd = find_option("ssh-command","c",1); - if( zSshCmd && zSshCmd[0] ){ - g.zSshCmd = mprintf("%s", zSshCmd); - } -} - -/* -** Set SSH options discovered in global variables (set from command line -** options). -*/ -void clone_ssh_db_set_options(void){ - if( g.zSshCmd && g.zSshCmd[0] ){ - db_set("ssh-command", g.zSshCmd, 0); - } + db_end_transaction(0); } DELETED src/codecheck1.c Index: src/codecheck1.c ================================================================== --- src/codecheck1.c +++ src/codecheck1.c @@ -1,564 +0,0 @@ -/* -** Copyright (c) 2014 D. Richard Hipp -** -** 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/ -** -******************************************************************************* -** -** This program reads Fossil source code files and tries to verify that -** printf-style format strings are correct. -** -** This program implements a compile-time validation step on the Fossil -** source code. Running this program is entirely optional. Its role is -** similar to the -Wall compiler switch on gcc, or the scan-build utility -** of clang, or other static analyzers. The purpose is to try to identify -** problems in the source code at compile-time. The difference is that this -** static checker is specifically designed for the particular printf formatter -** implementation used by Fossil. -** -** 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, warn about the use of %s -** which might allow SQL injection. -*/ -#include <stdio.h> -#include <stdlib.h> -#include <ctype.h> -#include <string.h> -#include <assert.h> - -/* -** Malloc, aborting if it fails. -*/ -void *safe_malloc(int nByte){ - void *x = malloc(nByte); - if( x==0 ){ - fprintf(stderr, "failed to allocate %d bytes\n", nByte); - exit(1); - } - return x; -} -void *safe_realloc(void *pOld, int nByte){ - void *x = realloc(pOld, nByte); - if( x==0 ){ - fprintf(stderr, "failed to allocate %d bytes\n", nByte); - exit(1); - } - return x; -} - -/* -** Read the entire content of the file named zFilename into memory obtained -** from malloc(). Add a zero-terminator to the end. -** Return a pointer to that memory. -*/ -static char *read_file(const char *zFilename){ - FILE *in; - char *z; - int nByte; - int got; - in = fopen(zFilename, "rb"); - if( in==0 ){ - return 0; - } - fseek(in, 0, SEEK_END); - nByte = ftell(in); - fseek(in, 0, SEEK_SET); - z = safe_malloc( nByte+1 ); - got = fread(z, 1, nByte, in); - z[got] = 0; - fclose(in); - return z; -} - -/* -** When parsing the input file, the following token types are recognized. -*/ -#define TK_SPACE 1 /* Whitespace or comments */ -#define TK_ID 2 /* An identifier */ -#define TK_STR 3 /* A string literal in double-quotes */ -#define TK_OTHER 4 /* Any other token */ -#define TK_EOF 99 /* End of file */ - -/* -** Determine the length and type of the token beginning at z[0] -*/ -static int token_length(const char *z, int *pType, int *pLN){ - int i; - if( z[0]==0 ){ - *pType = TK_EOF; - return 0; - } - if( z[0]=='"' || z[0]=='\'' ){ - for(i=1; z[i] && z[i]!=z[0]; i++){ - if( z[i]=='\\' && z[i+1]!=0 ){ - if( z[i+1]=='\n' ) (*pLN)++; - i++; - } - } - if( z[i]!=0 ) i++; - *pType = z[0]=='"' ? TK_STR : TK_OTHER; - return i; - } - if( isalnum(z[0]) || z[0]=='_' ){ - for(i=1; isalnum(z[i]) || z[i]=='_'; i++){} - *pType = isalpha(z[0]) || z[0]=='_' ? TK_ID : TK_OTHER; - return i; - } - if( isspace(z[0]) ){ - if( z[0]=='\n' ) (*pLN)++; - for(i=1; isspace(z[i]); i++){ - if( z[i]=='\n' ) (*pLN)++; - } - *pType = TK_SPACE; - return i; - } - if( z[0]=='/' && z[1]=='*' ){ - for(i=2; z[i] && (z[i]!='*' || z[i+1]!='/'); i++){ - if( z[i]=='\n' ) (*pLN)++; - } - if( z[i] ) i += 2; - *pType = TK_SPACE; - return i; - } - if( z[0]=='/' && z[1]=='/' ){ - for(i=2; z[i] && z[i]!='\n'; i++){} - if( z[i] ){ - (*pLN)++; - i++; - } - *pType = TK_SPACE; - return i; - } - *pType = TK_OTHER; - return 1; -} - -/* -** Return the next non-whitespace token -*/ -const char *next_non_whitespace(const char *z, int *pLen, int *pType){ - int len; - int eType; - int ln = 0; - while( (len = token_length(z, &eType, &ln))>0 && eType==TK_SPACE ){ - z += len; - } - *pLen = len; - *pType = eType; - return z; -} - -/* -** Return index into z[] for the first balanced TK_OTHER token with -** value cValue. -*/ -static int distance_to(const char *z, char cVal){ - int len; - int dist = 0; - int eType; - int nNest = 0; - int ln = 0; - while( z[0] && (len = token_length(z, &eType, &ln))>0 ){ - if( eType==TK_OTHER ){ - if( z[0]==cVal && nNest==0 ){ - break; - }else if( z[0]=='(' ){ - nNest++; - }else if( z[0]==')' ){ - nNest--; - } - } - dist += len; - z += len; - } - return dist; -} - -/* -** Return the first non-whitespace characters in z[] -*/ -static const char *skip_space(const char *z){ - while( isspace(z[0]) ){ z++; } - return z; -} - -/* -** Return true if the input is a string literal. -*/ -static int is_string_lit(const char *z){ - int nu1, nu2; - z = next_non_whitespace(z, &nu1, &nu2); - return z[0]=='"'; -} - -/* -** Return true if the input is an expression of string literals: -** -** EXPR ? "..." : "..." -*/ -static int is_string_expr(const char *z){ - int len = 0, eType; - const char *zOrig = z; - len = distance_to(z, '?'); - if( z[len]==0 && skip_space(z)[0]=='(' ){ - z = skip_space(z) + 1; - len = distance_to(z, '?'); - } - z += len; - if( z[0]=='?' ){ - z++; - z = next_non_whitespace(z, &len, &eType); - if( eType==TK_STR ){ - z += len; - z = next_non_whitespace(z, &len, &eType); - if( eType==TK_OTHER && z[0]==':' ){ - z += len; - z = next_non_whitespace(z, &len, &eType); - if( eType==TK_STR ){ - z += len; - z = next_non_whitespace(z, &len, &eType); - if( eType==TK_EOF ) return 1; - if( eType==TK_OTHER && z[0]==')' && skip_space(zOrig)[0]=='(' ){ - z += len; - z = next_non_whitespace(z, &len, &eType); - if( eType==TK_EOF ) return 1; - } - } - } - } - } - return 0; -} - -/* -** A list of functions that return strings that are safe to insert into -** SQL using %s. -*/ -static const char *azSafeFunc[] = { - "filename_collation", - "db_name", - "timeline_utc", - "leaf_is_closed_sql", - "timeline_query_for_www", - "timeline_query_for_tty", - "blob_sql_text", - "glob_expr", - "fossil_all_reserved_names", - "configure_inop_rhs", - "db_setting_inop_rhs", -}; - -/* -** Return true if the input is an argument that is safe to use with %s -** while building an SQL statement. -*/ -static int is_s_safe(const char *z){ - int len, eType; - int i; - - /* A string literal is safe for use with %s */ - if( is_string_lit(z) ) return 1; - - /* Certain functions are guaranteed to return a string that is safe - ** for use with %s */ - z = next_non_whitespace(z, &len, &eType); - for(i=0; i<sizeof(azSafeFunc)/sizeof(azSafeFunc[0]); i++){ - if( eType==TK_ID - && strncmp(z, azSafeFunc[i], len)==0 - && strlen(azSafeFunc[i])==len - ){ - return 1; - } - } - - /* Expressions of the form: EXPR ? "..." : "...." can count as - ** a string literal. */ - if( is_string_expr(z) ) return 1; - - /* If the "safe-for-%s" comment appears in the argument, then - ** let it through */ - if( strstr(z, "/*safe-for-%s*/")!=0 ) return 1; - - return 0; -} - -/* -** Processing flags -*/ -#define FMT_NO_S 0x00001 /* Do not allow %s substitutions */ - -/* -** A list of internal Fossil interfaces that take a printf-style format -** string. -*/ -struct { - const char *zFName; /* Name of the function */ - int iFmtArg; /* Index of format argument. Leftmost is 1. */ - unsigned fmtFlags; /* Processing flags */ -} aFmtFunc[] = { - { "admin_log", 1, 0 }, - { "blob_append_sql", 2, FMT_NO_S }, - { "blob_appendf", 2, 0 }, - { "cgi_panic", 1, 0 }, - { "cgi_redirectf", 1, 0 }, - { "db_blob", 2, FMT_NO_S }, - { "db_double", 2, FMT_NO_S }, - { "db_err", 1, 0 }, - { "db_exists", 1, FMT_NO_S }, - { "db_int", 2, FMT_NO_S }, - { "db_int64", 2, FMT_NO_S }, - { "db_multi_exec", 1, FMT_NO_S }, - { "db_optional_sql", 2, FMT_NO_S }, - { "db_prepare", 2, FMT_NO_S }, - { "db_prepare_ignore_error", 2, FMT_NO_S }, - { "db_static_prepare", 2, FMT_NO_S }, - { "db_text", 2, FMT_NO_S }, - { "form_begin", 2, 0 }, - { "fossil_error", 2, 0 }, - { "fossil_errorlog", 1, 0 }, - { "fossil_fatal", 1, 0 }, - { "fossil_fatal_recursive", 1, 0 }, - { "fossil_panic", 1, 0 }, - { "fossil_print", 1, 0 }, - { "fossil_trace", 1, 0 }, - { "fossil_warning", 1, 0 }, - { "href", 1, 0 }, - { "json_new_string_f", 1, 0 }, - { "mprintf", 1, 0 }, - { "socket_set_errmsg", 1, 0 }, - { "ssl_set_errmsg", 1, 0 }, - { "style_header", 1, 0 }, - { "style_set_current_page", 1, 0 }, - { "webpage_error", 1, 0 }, - { "xhref", 2, 0 }, -}; - -/* -** Determine if the indentifier zIdent of length nIndent is a Fossil -** internal interface that uses a printf-style argument. Return zero if not. -** Return the index of the format string if true with the left-most -** argument having an index of 1. -*/ -static int isFormatFunc(const char *zIdent, int nIdent, unsigned *pFlags){ - int upr, lwr; - lwr = 0; - upr = sizeof(aFmtFunc)/sizeof(aFmtFunc[0]) - 1; - while( lwr<=upr ){ - unsigned x = (lwr + upr)/2; - int c = strncmp(zIdent, aFmtFunc[x].zFName, nIdent); - if( c==0 ){ - if( aFmtFunc[x].zFName[nIdent]==0 ){ - *pFlags = aFmtFunc[x].fmtFlags; - return aFmtFunc[x].iFmtArg; - } - c = -1; - } - if( c<0 ){ - upr = x - 1; - }else{ - lwr = x + 1; - } - } - *pFlags = 0; - return 0; -} - -/* -** Return the expected number of arguments for the format string. -** Return -1 if the value cannot be computed. -** -** For each argument less than nType, store the conversion character -** for that argument in cType[i]. -*/ -static int formatArgCount(const char *z, int nType, char *cType){ - int nArg = 0; - int i, k; - int len; - int eType; - int ln = 0; - while( z[0] ){ - len = token_length(z, &eType, &ln); - if( eType==TK_STR ){ - for(i=1; i<len-1; i++){ - if( z[i]!='%' ) continue; - if( z[i+1]=='%' ){ i++; continue; } - for(k=i+1; k<len && !isalpha(z[k]); k++){ - if( z[k]=='*' || z[k]=='#' ){ - if( nArg<nType ) cType[nArg] = z[k]; - nArg++; - } - } - if( z[k]!='R' ){ - if( nArg<nType ) cType[nArg] = z[k]; - nArg++; - } - } - } - z += len; - } - return nArg; -} - -/* -** The function call that begins at zFCall[0] (which is on line lnFCall of the -** original file) is a function that uses a printf-style format string -** on argument number fmtArg. It has processings flags fmtFlags. Do -** compile-time checking on this function, output any errors, and return -** the number of errors. -*/ -static int checkFormatFunc( - const char *zFilename, /* Name of the file being processed */ - const char *zFCall, /* Pointer to start of function call */ - int lnFCall, /* Line number that holds z[0] */ - int fmtArg, /* Format string should be this argument */ - int fmtFlags /* Extra processing flags */ -){ - int szFName; - int eToken; - int ln = lnFCall; - int len; - const char *zStart; - char *z; - char *zCopy; - int nArg = 0; - const char **azArg = 0; - int i, k; - int nErr = 0; - char *acType; - - szFName = token_length(zFCall, &eToken, &ln); - zStart = next_non_whitespace(zFCall+szFName, &len, &eToken); - assert( zStart[0]=='(' && len==1 ); - len = distance_to(zStart+1, ')'); - zCopy = safe_malloc( len + 1 ); - memcpy(zCopy, zStart+1, len); - zCopy[len] = 0; - azArg = 0; - nArg = 0; - z = zCopy; - while( z[0] ){ - len = distance_to(z, ','); - azArg = safe_realloc((char*)azArg, (sizeof(azArg[0])+1)*(nArg+1)); - azArg[nArg++] = skip_space(z); - if( z[len]==0 ) break; - z[len] = 0; - for(i=len-1; i>0 && isspace(z[i]); i--){ z[i] = 0; } - z += len + 1; - } - acType = (char*)&azArg[nArg]; - if( fmtArg>nArg ){ - printf("%s:%d: too few arguments to %.*s()\n", - zFilename, lnFCall, szFName, zFCall); - nErr++; - }else{ - const char *zFmt = azArg[fmtArg-1]; - const char *zOverride = strstr(zFmt, "/*works-like:"); - if( zOverride ) zFmt = zOverride + sizeof("/*works-like:")-1; - if( !is_string_lit(zFmt) ){ - printf("%s:%d: %.*s() has non-constant format string\n", - zFilename, lnFCall, szFName, zFCall); - nErr++; - }else if( (k = formatArgCount(zFmt, nArg, acType))>=0 - && nArg!=fmtArg+k ){ - printf("%s:%d: too %s arguments to %.*s() " - "- got %d and expected %d\n", - zFilename, lnFCall, (nArg<fmtArg+k ? "few" : "many"), - szFName, zFCall, nArg, fmtArg+k); - nErr++; - }else if( fmtFlags & FMT_NO_S ){ - for(i=0; i<nArg && i<k; i++){ - if( (acType[i]=='s' || acType[i]=='z' || acType[i]=='b') - && !is_s_safe(azArg[fmtArg+i]) - ){ - printf("%s:%d: Argument %d to %.*s() not safe for SQL\n", - zFilename, lnFCall, i+fmtArg, szFName, zFCall); - nErr++; - } - } - } - } - if( nErr ){ - for(i=0; i<nArg; i++){ - printf(" arg[%d]: %s\n", i, azArg[i]); - } - } - - free((char*)azArg); - free(zCopy); - return nErr; -} - - -/* -** Do a design-rule check of format strings for the file named zName -** with content zContent. Write errors on standard output. Return -** the number of errors. -*/ -static int scan_file(const char *zName, const char *zContent){ - const char *z; - int ln = 0; - int szToken; - int eToken; - const char *zPrev; - int ePrev; - int szPrev; - int lnPrev; - int nCurly = 0; - int x; - unsigned fmtFlags = 0; - int nErr = 0; - - if( zContent==0 ){ - printf("cannot read file: %s\n", zName); - return 1; - } - for(z=zContent; z[0]; z += szToken){ - szToken = token_length(z, &eToken, &ln); - if( eToken==TK_SPACE ) continue; - if( eToken==TK_OTHER ){ - if( z[0]=='{' ){ - nCurly++; - }else if( z[0]=='}' ){ - nCurly--; - }else if( nCurly>0 && z[0]=='(' && ePrev==TK_ID - && (x = isFormatFunc(zPrev,szPrev,&fmtFlags))>0 ){ - nErr += checkFormatFunc(zName, zPrev, lnPrev, x, fmtFlags); - } - } - zPrev = z; - ePrev = eToken; - szPrev = szToken; - lnPrev = ln; - } - return nErr; -} - -/* -** Check for format-string design rule violations on all files listed -** on the command-line. -*/ -int main(int argc, char **argv){ - int i; - int nErr = 0; - for(i=1; i<argc; i++){ - char *zFile = read_file(argv[i]); - nErr += scan_file(argv[i], zFile); - free(zFile); - } - return nErr; -} Index: src/comformat.c ================================================================== --- src/comformat.c +++ src/comformat.c @@ -19,282 +19,38 @@ ** text on a TTY. */ #include "config.h" #include "comformat.h" #include <assert.h> -#ifdef _WIN32 -# include <windows.h> -#else -# include <termios.h> -# if defined(TIOCGWINSZ) -# include <sys/ioctl.h> -# endif -#endif - -#if INTERFACE -#define COMMENT_PRINT_NONE ((u32)0x00000000) /* No flags. */ -#define COMMENT_PRINT_LEGACY ((u32)0x00000001) /* Use legacy algorithm. */ -#define COMMENT_PRINT_TRIM_CRLF ((u32)0x00000002) /* Trim leading CR/LF. */ -#define COMMENT_PRINT_TRIM_SPACE ((u32)0x00000004) /* Trim leading/trailing. */ -#define COMMENT_PRINT_WORD_BREAK ((u32)0x00000008) /* Break lines on words. */ -#define COMMENT_PRINT_ORIG_BREAK ((u32)0x00000010) /* Break before original. */ -#define COMMENT_PRINT_DEFAULT (COMMENT_PRINT_LEGACY) /* Defaults. */ -#endif - -/* -** This is the previous value used by most external callers when they -** needed to specify a default maximum line length to be used with the -** comment_print() function. -*/ -#ifndef COMMENT_LEGACY_LINE_LENGTH -# define COMMENT_LEGACY_LINE_LENGTH (78) -#endif - -/* -** This is the number of spaces to print when a tab character is seen. -*/ -#ifndef COMMENT_TAB_WIDTH -# define COMMENT_TAB_WIDTH (8) -#endif - -/* -** This function sets the maximum number of characters to print per line -** based on the detected terminal line width, if available; otherwise, it -** uses the legacy default terminal line width minus the amount to indent. -** -** Zero is returned to indicate any failure. One is returned to indicate -** the successful detection of the terminal line width. Negative one is -** returned to indicate the terminal line width is using the hard-coded -** legacy default value. -*/ -static int comment_set_maxchars( - int indent, - int *pMaxChars -){ -#if defined(_WIN32) - CONSOLE_SCREEN_BUFFER_INFO csbi; - memset(&csbi, 0, sizeof(CONSOLE_SCREEN_BUFFER_INFO)); - if( GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi) ){ - *pMaxChars = csbi.srWindow.Right - csbi.srWindow.Left - indent; - return 1; - } - return 0; -#elif defined(TIOCGWINSZ) - struct winsize w; - memset(&w, 0, sizeof(struct winsize)); - if( ioctl(0, TIOCGWINSZ, &w)!=-1 ){ - *pMaxChars = w.ws_col - indent; - return 1; - } - return 0; -#else - /* - ** Fallback to using more-or-less the "legacy semantics" of hard-coding - ** the maximum line length to a value reasonable for the vast majority - ** of supported systems. - */ - *pMaxChars = COMMENT_LEGACY_LINE_LENGTH - indent; - return -1; -#endif -} - -/* -** This function checks the current line being printed against the original -** comment text. Upon matching, it emits a new line and updates the provided -** character and line counts, if applicable. -*/ -static int comment_check_orig( - const char *zOrigText, /* [in] Original comment text ONLY, may be NULL. */ - const char *zLine, /* [in] The comment line to print. */ - int *pCharCnt, /* [in/out] Pointer to the line character count. */ - int *pLineCnt /* [in/out] Pointer to the total line count. */ -){ - if( zOrigText && fossil_strcmp(zLine, zOrigText)==0 ){ - fossil_print("\n"); - if( pCharCnt ) *pCharCnt = 0; - if( pLineCnt ) (*pLineCnt)++; - return 1; - } - return 0; -} - -/* -** This function scans the specified comment line starting just after the -** initial index and returns the index of the next spacing character -OR- -** zero if such a character cannot be found. For the purposes of this -** algorithm, the NUL character is treated the same as a spacing character. -*/ -static int comment_next_space( - const char *zLine, /* [in] The comment line being printed. */ - int index /* [in] The current character index being handled. */ -){ - int nextIndex = index + 1; - for(;;){ - char c = zLine[nextIndex]; - if( c==0 || fossil_isspace(c) ){ - return nextIndex; - } - nextIndex++; - } - return 0; /* NOT REACHED */ -} - -/* -** This function is called when printing a logical comment line to perform -** the necessary indenting. -*/ -static void comment_print_indent( - const char *zLine, /* [in] The comment line being printed. */ - int indent, /* [in] Number of spaces to indent, zero for none. */ - int trimCrLf, /* [in] Non-zero to trim leading/trailing CR/LF. */ - int trimSpace, /* [in] Non-zero to trim leading/trailing spaces. */ - int *piIndex /* [in/out] Pointer to first non-space character. */ -){ - if( indent>0 ){ - fossil_print("%*s", indent, ""); - } - if( zLine && piIndex ){ - int index = *piIndex; - if( trimCrLf ){ - while( zLine[index]=='\r' || zLine[index]=='\n' ){ index++; } - } - if( trimSpace ){ - while( fossil_isspace(zLine[index]) ){ index++; } - } - *piIndex = index; - } -} - -/* -** This function prints one logical line of a comment, stopping when it hits -** a new line -OR- runs out of space on the logical line. -*/ -static void comment_print_line( - const char *zOrigText, /* [in] Original comment text ONLY, may be NULL. */ - const char *zLine, /* [in] The comment line to print. */ - int origIndent, /* [in] Number of spaces to indent before the original - ** comment. */ - int indent, /* [in] Number of spaces to indent, before the line - ** to print. */ - int lineChars, /* [in] Maximum number of characters to print. */ - int trimCrLf, /* [in] Non-zero to trim leading/trailing CR/LF. */ - int trimSpace, /* [in] Non-zero to trim leading/trailing spaces. */ - int wordBreak, /* [in] Non-zero to try breaking on word boundaries. */ - int origBreak, /* [in] Non-zero to break before original comment. */ - int *pLineCnt, /* [in/out] Pointer to the total line count. */ - const char **pzLine /* [out] Pointer to the end of the logical line. */ -){ - int index = 0, charCnt = 0, lineCnt = 0, maxChars; - if( !zLine ) return; - if( lineChars<=0 ) return; - comment_print_indent(zLine, indent, trimCrLf, trimSpace, &index); - maxChars = lineChars; - for(;;){ - int useChars = 1; - char c = zLine[index]; - if( c==0 ){ - break; - }else{ - if( origBreak && index>0 ){ - const char *zCurrent = &zLine[index]; - if( comment_check_orig(zOrigText, zCurrent, &charCnt, &lineCnt) ){ - comment_print_indent(zCurrent, origIndent, trimCrLf, trimSpace, - &index); - maxChars = lineChars; - } - } - index++; - } - if( c=='\n' ){ - lineCnt++; - charCnt = 0; - useChars = 0; - }else if( c=='\t' ){ - int nextIndex = comment_next_space(zLine, index); - if( nextIndex<=0 || (nextIndex-index)>maxChars ){ - break; - } - charCnt++; - useChars = COMMENT_TAB_WIDTH; - if( maxChars<useChars ){ - fossil_print(" "); - break; - } - }else if( wordBreak && fossil_isspace(c) ){ - int nextIndex = comment_next_space(zLine, index); - if( nextIndex<=0 || (nextIndex-index)>maxChars ){ - break; - } - charCnt++; - }else{ - charCnt++; - } - assert( c!='\n' || charCnt==0 ); - fossil_print("%c", c); - maxChars -= useChars; - if( maxChars==0 ) break; - assert( maxChars>0 ); - if( c=='\n' ) break; - } - if( charCnt>0 ){ - fossil_print("\n"); - lineCnt++; - } - if( pLineCnt ){ - *pLineCnt += lineCnt; - } - if( pzLine ){ - *pzLine = zLine + index; - } -} - -/* -** This is the legacy comment printing algorithm. It is being retained -** for backward compatibility. -** -** Given a comment string, format that string for printing on a TTY. -** Assume that the output cursors is indent spaces from the left margin -** and that a single line can contain no more than 'width' characters. -** Indent all subsequent lines by 'indent'. -** -** Returns the number of new lines emitted. -*/ -static int comment_print_legacy( - const char *zText, /* The comment text to be printed. */ - int indent, /* Number of spaces to indent each non-initial line. */ - int width /* Maximum number of characters per line. */ -){ - int maxChars = width - indent; - int si, sk, i, k; - int doIndent = 0; - char *zBuf; - char zBuffer[400]; - int lineCnt = 0; - - if( width<0 ){ - comment_set_maxchars(indent, &maxChars); - } - if( zText==0 ) zText = "(NULL)"; - if( maxChars<=0 ){ - maxChars = strlen(zText); - } - if( maxChars >= (sizeof(zBuffer)) ){ - zBuf = fossil_malloc(maxChars+1); - }else{ - zBuf = zBuffer; - } + +/* +** Given a comment string zText, format that string for printing +** on a TTY. Assume that the output cursors is indent spaces from +** the left margin and that a single line can contain no more than +** lineLength characters. Indent all subsequent lines by indent. +** +** lineLength must be less than 400. +** +** Return the number of newlines that are output. +*/ +int comment_print(const char *zText, int indent, int lineLength){ + int tlen = lineLength - indent; + int si, sk, i, k; + int doIndent = 0; + char zBuf[400]; + int lineCnt = 0; + for(;;){ while( fossil_isspace(zText[0]) ){ zText++; } if( zText[0]==0 ){ if( doIndent==0 ){ fossil_print("\n"); lineCnt = 1; } - if( zBuf!=zBuffer) fossil_free(zBuf); return lineCnt; } - for(sk=si=i=k=0; zText[i] && k<maxChars; i++){ + for(sk=si=i=k=0; zText[i] && k<tlen; i++){ char c = zText[i]; if( fossil_isspace(c) ){ si = i; sk = k; if( k==0 || zBuf[k-1]!=' ' ){ @@ -313,207 +69,32 @@ fossil_print("%*s", indent, ""); } doIndent = 1; if( sk>0 && zText[i] ){ zText += si; - zBuf[sk] = 0; - }else{ - zText += i; - zBuf[k] = 0; - } - fossil_print("%s\n", zBuf); - lineCnt++; - } -} - -/* -** This is the comment printing function. The comment printing algorithm -** contained within it attempts to preserve the formatting present within -** the comment string itself while honoring line width limitations. There -** are several flags that modify the default behavior of this function: -** -** COMMENT_PRINT_LEGACY: Forces use of the legacy comment printing -** algorithm. For backward compatibility, -** this is the default. -** -** COMMENT_PRINT_TRIM_CRLF: Trims leading and trailing carriage-returns -** and line-feeds where they do not materially -** impact pre-existing formatting (i.e. at the -** start of the comment string -AND- right -** before line indentation). This flag does -** not apply to the legacy comment printing -** algorithm. This flag may be combined with -** COMMENT_PRINT_TRIM_SPACE. -** -** COMMENT_PRINT_TRIM_SPACE: Trims leading and trailing spaces where they -** do not materially impact the pre-existing -** formatting (i.e. at the start of the comment -** string -AND- right before line indentation). -** This flag does not apply to the legacy -** comment printing algorithm. This flag may -** be combined with COMMENT_PRINT_TRIM_CRLF. -** -** COMMENT_PRINT_WORD_BREAK: Attempts to break lines on word boundaries -** while honoring the logical line length. -** If this flag is not specified, honoring the -** logical line length may result in breaking -** lines in the middle of words. This flag -** does not apply to the legacy comment -** printing algorithm. -** -** COMMENT_PRINT_ORIG_BREAK: Looks for the original comment text within -** the text being printed. Upon matching, a -** new line will be emitted, thus preserving -** more of the pre-existing formatting. -** -** Given a comment string, format that string for printing on a TTY. -** Assume that the output cursors is indent spaces from the left margin -** and that a single line can contain no more than 'width' characters. -** Indent all subsequent lines by 'indent'. -** -** Returns the number of new lines emitted. -*/ -int comment_print( - const char *zText, /* The comment text to be printed. */ - const char *zOrigText, /* Original comment text ONLY, may be NULL. */ - int indent, /* Spaces to indent each non-initial line. */ - int width, /* Maximum number of characters per line. */ - int flags /* Zero or more "COMMENT_PRINT_*" flags. */ -){ - int maxChars = width - indent; - int legacy = flags & COMMENT_PRINT_LEGACY; - int trimCrLf = flags & COMMENT_PRINT_TRIM_CRLF; - int trimSpace = flags & COMMENT_PRINT_TRIM_SPACE; - int wordBreak = flags & COMMENT_PRINT_WORD_BREAK; - int origBreak = flags & COMMENT_PRINT_ORIG_BREAK; - int lineCnt = 0; - const char *zLine; - - if( legacy ){ - return comment_print_legacy(zText, indent, width); - } - if( width<0 ){ - comment_set_maxchars(indent, &maxChars); - } - if( zText==0 ) zText = "(NULL)"; - if( maxChars<=0 ){ - maxChars = strlen(zText); - } - if( trimSpace ){ - while( fossil_isspace(zText[0]) ){ zText++; } - } - if( zText[0]==0 ){ - fossil_print("\n"); - lineCnt++; - return lineCnt; - } - zLine = zText; - for(;;){ - comment_print_line(zOrigText, zLine, indent, zLine>zText ? indent : 0, - maxChars, trimCrLf, trimSpace, wordBreak, origBreak, - &lineCnt, &zLine); - if( !zLine || !zLine[0] ) break; - } - return lineCnt; -} - -/* -** -** 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; - const char *zIndent; - const char *zPrefix; - char *zText; - char *zOrigText; - int indent, width; - int fromFile = find_option("file", 0, 0)!=0; - int decode = find_option("decode", 0, 0)!=0; - int flags = COMMENT_PRINT_NONE; - if( find_option("legacy", 0, 0) ){ - flags |= COMMENT_PRINT_LEGACY; - } - if( find_option("trimcrlf", 0, 0) ){ - flags |= COMMENT_PRINT_TRIM_CRLF; - } - if( find_option("trimspace", 0, 0) ){ - flags |= COMMENT_PRINT_TRIM_SPACE; - } - if( find_option("wordbreak", 0, 0) ){ - flags |= COMMENT_PRINT_WORD_BREAK; - } - if( find_option("origbreak", 0, 0) ){ - flags |= COMMENT_PRINT_ORIG_BREAK; - } - zWidth = find_option("width","W",1); - if( zWidth ){ - width = atoi(zWidth); - }else{ - width = -1; /* automatic */ - } - zIndent = find_option("indent",0,1); - if( zIndent ){ - indent = atoi(zIndent); - }else{ - indent = -1; /* automatic */ - } - if( g.argc!=4 && g.argc!=5 ){ - usage("?OPTIONS? PREFIX TEXT ?ORIGTEXT?"); - } - zPrefix = g.argv[2]; - zText = g.argv[3]; - if( g.argc==5 ){ - zOrigText = g.argv[4]; - }else{ - zOrigText = 0; - } - if( fromFile ){ - Blob fileData; - blob_read_from_file(&fileData, zText); - zText = mprintf("%s", blob_str(&fileData)); - blob_reset(&fileData); - if( zOrigText ){ - blob_read_from_file(&fileData, zOrigText); - zOrigText = mprintf("%s", blob_str(&fileData)); - blob_reset(&fileData); - } - } - if( decode ){ - zText = mprintf(fromFile?"%z":"%s" /*works-like:"%s"*/, zText); - defossilize(zText); - if( zOrigText ){ - zOrigText = mprintf(fromFile?"%z":"%s" /*works-like:"%s"*/, zOrigText); - defossilize(zOrigText); - } - } - if( indent<0 ){ - indent = strlen(zPrefix); - } - if( zPrefix && *zPrefix ){ - fossil_print("%s", zPrefix); - } - fossil_print("(%d lines output)\n", - comment_print(zText, zOrigText, indent, width, flags)); - if( zOrigText && zOrigText!=g.argv[4] ) fossil_free(zOrigText); - if( zText && zText!=g.argv[3] ) fossil_free(zText); + zBuf[sk++] = '\n'; + zBuf[sk] = 0; + fossil_print("%s", zBuf); + }else{ + zText += i; + zBuf[k++] = '\n'; + zBuf[k] = 0; + fossil_print("%s", zBuf); + } + lineCnt++; + } +} + +/* +** Test the comment printing +** +** COMMAND: test-comment-format +*/ +void test_comment_format(void){ + int indent; + if( g.argc!=4 ){ + usage("PREFIX TEXT"); + } + indent = strlen(g.argv[2]) + 1; + fossil_print("%s ", g.argv[2]); + fossil_print("(%d lines output)\n", comment_print(g.argv[3], indent, 79)); } Index: src/config.h ================================================================== --- src/config.h +++ src/config.h @@ -25,20 +25,10 @@ #ifndef _FILE_OFFSET_BITS # define _FILE_OFFSET_BITS 64 #endif #define _LARGEFILE_SOURCE 1 -/* Needed for various definitions... */ -#ifndef _GNU_SOURCE -# define _GNU_SOURCE -#endif - -/* Make sure that in Win32 MinGW builds, _USE_32BIT_TIME_T is always defined. */ -#if defined(_WIN32) && !defined(_WIN64) && !defined(_MSC_VER) && !defined(_USE_32BIT_TIME_T) -# define _USE_32BIT_TIME_T -#endif - #ifdef HAVE_AUTOCONFIG_H #include "autoconfig.h" #endif #ifndef _RC_COMPILE_ @@ -67,99 +57,36 @@ # include <sys/types.h> # include <signal.h> # include <pwd.h> #endif -/* -** Utility macro to wrap an argument with double quotes. -*/ -#if !defined(COMPILER_STRINGIFY) -# define COMPILER_STRINGIFY(x) COMPILER_STRINGIFY1(x) -# define COMPILER_STRINGIFY1(x) #x -#endif - /* ** Define the compiler variant, used to compile the project */ #if !defined(COMPILER_NAME) # if defined(__DMC__) -# if defined(COMPILER_VERSION) && !defined(NO_COMPILER_VERSION) -# define COMPILER_NAME "dmc-" COMPILER_VERSION -# else -# define COMPILER_NAME "dmc" -# endif +# define COMPILER_NAME "dmc" # elif defined(__POCC__) # if defined(_M_X64) -# if defined(COMPILER_VERSION) && !defined(NO_COMPILER_VERSION) -# define COMPILER_NAME "pellesc64-" COMPILER_VERSION -# else -# define COMPILER_NAME "pellesc64" -# endif +# define COMPILER_NAME "pellesc64" # else -# if defined(COMPILER_VERSION) && !defined(NO_COMPILER_VERSION) -# define COMPILER_NAME "pellesc32-" COMPILER_VERSION -# else -# define COMPILER_NAME "pellesc32" -# endif +# define COMPILER_NAME "pellesc32" # endif # elif defined(_MSC_VER) -# if !defined(COMPILER_VERSION) -# define COMPILER_VERSION COMPILER_STRINGIFY(_MSC_VER) -# endif -# if defined(COMPILER_VERSION) && !defined(NO_COMPILER_VERSION) -# define COMPILER_NAME "msc-" COMPILER_VERSION -# else -# define COMPILER_NAME "msc" -# endif +# define COMPILER_NAME "msc" # elif defined(__MINGW32__) -# if !defined(COMPILER_VERSION) -# if defined(__MINGW_VERSION) -# if defined(__GNUC__) -# if defined(__VERSION__) -# define COMPILER_VERSION COMPILER_STRINGIFY(__MINGW_VERSION) "-gcc-" __VERSION__ -# else -# define COMPILER_VERSION COMPILER_STRINGIFY(__MINGW_VERSION) "-gcc" -# endif -# else -# define COMPILER_VERSION COMPILER_STRINGIFY(__MINGW_VERSION) -# endif -# elif defined(__MINGW32_VERSION) -# if defined(__GNUC__) -# if defined(__VERSION__) -# define COMPILER_VERSION COMPILER_STRINGIFY(__MINGW32_VERSION) "-gcc-" __VERSION__ -# else -# define COMPILER_VERSION COMPILER_STRINGIFY(__MINGW32_VERSION) "-gcc" -# endif -# else -# define COMPILER_VERSION COMPILER_STRINGIFY(__MINGW32_VERSION) -# endif -# endif -# endif -# if defined(COMPILER_VERSION) && !defined(NO_COMPILER_VERSION) -# define COMPILER_NAME "mingw32-" COMPILER_VERSION -# else -# define COMPILER_NAME "mingw32" -# endif +# define COMPILER_NAME "mingw32" # elif defined(_WIN32) # define COMPILER_NAME "win32" # elif defined(__GNUC__) -# if !defined(COMPILER_VERSION) -# if defined(__VERSION__) -# define COMPILER_VERSION __VERSION__ -# endif -# endif -# if defined(COMPILER_VERSION) && !defined(NO_COMPILER_VERSION) -# define COMPILER_NAME "gcc-" COMPILER_VERSION -# else -# define COMPILER_NAME "gcc" -# endif +# define COMPILER_NAME "gcc-" __VERSION__ # else # define COMPILER_NAME "unknown" # endif #endif -#if !defined(_RC_COMPILE_) && !defined(SQLITE_AMALGAMATION) +#ifndef _RC_COMPILE_ #include "sqlite3.h" /* ** On Solaris, getpass() will only return up to 8 characters. getpassphrase() returns up to 257. @@ -191,11 +118,11 @@ ** The following macros are used to cast pointers to integers and ** integers to pointers. The way you do this varies from one compiler ** to the next, so we have developed the following set of #if statements ** to generate appropriate macros for a wide range of compilers. ** -** The correct "ANSI" way to do this is to use the intptr_t type. +** The correct "ANSI" way to do this is to use the intptr_t type. ** Unfortunately, that typedef is not available on all compilers, or ** if it is available, it requires an #include of specific headers ** that vary from one machine to the next. */ #if defined(__PTRDIFF_TYPE__) /* This case should work for GCC */ Index: src/configure.c ================================================================== --- src/configure.c +++ src/configure.c @@ -41,17 +41,10 @@ #define CONFIGSET_ALL 0x0000ff /* Everything */ #define CONFIGSET_OVERWRITE 0x100000 /* Causes overwrite instead of merge */ #define CONFIGSET_OLDFORMAT 0x200000 /* Use the legacy format */ -/* -** This mask is used for the common TH1 configuration settings (i.e. those -** that are not specific to one particular subsystem, such as the transfer -** subsystem). -*/ -#define CONFIGSET_TH1 (CONFIGSET_SKIN|CONFIGSET_TKT|CONFIGSET_XFER) - #endif /* INTERFACE */ /* ** Names of the configuration sets */ @@ -86,50 +79,39 @@ int groupMask; /* Which config groups is it part of */ } aConfig[] = { { "css", CONFIGSET_CSS }, { "header", CONFIGSET_SKIN }, { "footer", CONFIGSET_SKIN }, - { "details", CONFIGSET_SKIN }, { "logo-mimetype", CONFIGSET_SKIN }, { "logo-image", CONFIGSET_SKIN }, { "background-mimetype", CONFIGSET_SKIN }, { "background-image", CONFIGSET_SKIN }, + { "index-page", CONFIGSET_SKIN }, { "timeline-block-markup", CONFIGSET_SKIN }, { "timeline-max-comment", CONFIGSET_SKIN }, { "timeline-plaintext", CONFIGSET_SKIN }, { "adunit", CONFIGSET_SKIN }, { "adunit-omit-if-admin", CONFIGSET_SKIN }, { "adunit-omit-if-user", CONFIGSET_SKIN }, - -#ifdef FOSSIL_ENABLE_TH1_DOCS - { "th1-docs", CONFIGSET_TH1 }, -#endif -#ifdef FOSSIL_ENABLE_TH1_HOOKS - { "th1-hooks", CONFIGSET_TH1 }, -#endif - { "th1-setup", CONFIGSET_TH1 }, - { "th1-uri-regexp", CONFIGSET_TH1 }, + { "th1-setup", CONFIGSET_ALL }, #ifdef FOSSIL_ENABLE_TCL - { "tcl", CONFIGSET_TH1 }, - { "tcl-setup", CONFIGSET_TH1 }, + { "tcl", CONFIGSET_SKIN|CONFIGSET_TKT|CONFIGSET_XFER }, + { "tcl-setup", CONFIGSET_SKIN|CONFIGSET_TKT|CONFIGSET_XFER }, #endif { "project-name", CONFIGSET_PROJ }, - { "short-project-name", CONFIGSET_PROJ }, { "project-description", CONFIGSET_PROJ }, - { "index-page", CONFIGSET_PROJ }, { "manifest", CONFIGSET_PROJ }, { "binary-glob", CONFIGSET_PROJ }, { "clean-glob", CONFIGSET_PROJ }, { "ignore-glob", CONFIGSET_PROJ }, { "keep-glob", CONFIGSET_PROJ }, { "crnl-glob", CONFIGSET_PROJ }, { "encoding-glob", CONFIGSET_PROJ }, { "empty-dirs", CONFIGSET_PROJ }, { "allow-symlinks", CONFIGSET_PROJ }, - { "dotfiles", CONFIGSET_PROJ }, { "ticket-table", CONFIGSET_TKT }, { "ticket-common", CONFIGSET_TKT }, { "ticket-change", CONFIGSET_TKT }, { "ticket-newpage", CONFIGSET_TKT }, @@ -148,12 +130,10 @@ { "@shun", CONFIGSET_SHUN }, { "xfer-common-script", CONFIGSET_XFER }, { "xfer-push-script", CONFIGSET_XFER }, - { "xfer-commit-script", CONFIGSET_XFER }, - { "xfer-ticket-script", CONFIGSET_XFER }, }; static int iConfig = 0; /* @@ -197,19 +177,19 @@ Blob x; int i; const char *zSep = ""; blob_zero(&x); - blob_append_sql(&x, "("); + blob_append(&x, "(", 1); for(i=0; i<count(aConfig); i++){ if( (aConfig[i].groupMask & iMask)==0 ) continue; if( aConfig[i].zName[0]=='@' ) continue; - blob_append_sql(&x, "%s'%q'", zSep/*safe-for-%s*/, aConfig[i].zName); + blob_appendf(&x, "%s'%s'", zSep, aConfig[i].zName); zSep = ","; } - blob_append_sql(&x, ")"); - return blob_sql_text(&x); + blob_append(&x, ")", 1); + return blob_str(&x); } /* ** Return the mask for the named configuration parameter if it can be ** safely exported. Return 0 if the parameter is not safe to export. @@ -225,11 +205,11 @@ if( n>2 && zName[0]=='\'' && zName[n-1]=='\'' ){ zName++; n -= 2; } for(i=0; i<count(aConfig); i++){ - if( strncmp(zName, aConfig[i].zName, n)==0 && aConfig[i].zName[n]==0 ){ + if( memcmp(zName, aConfig[i].zName, n)==0 && aConfig[i].zName[n]==0 ){ int m = aConfig[i].groupMask; if( !g.perm.Admin ){ m &= ~CONFIGSET_USER; } if( !g.perm.RdAddr ){ @@ -364,12 +344,11 @@ @ INSERT INTO _xfer_reportfmt @ SELECT rn,owner,title,cols,sqlcode FROM reportfmt; @ INSERT INTO _xfer_user @ SELECT uid,login,pw,cap,cookie,ipaddr,cexpire,info,photo FROM user; ; - assert( strchr(zSQL1,'%')==0 ); - db_multi_exec(zSQL1 /*works-like:""*/); + db_multi_exec(zSQL1); /* When the replace flag is set, add triggers that run the first time ** that new data is seen. The triggers run only once and delete all the ** existing data. */ @@ -394,12 +373,11 @@ sqlite3_create_function(g.db, "config_is_reset", 1, SQLITE_UTF8, 0, config_is_reset_function, 0, 0); sqlite3_create_function(g.db, "config_reset", 1, SQLITE_UTF8, 0, config_reset_function, 0, 0); configHasBeenReset = 0; - assert( strchr(zSQL2,'%')==0 ); - db_multi_exec(zSQL2 /*works-like:""*/); + db_multi_exec(zSQL2); } } /* ** After receiving configuration data, call this routine to transfer @@ -412,27 +390,11 @@ @ DELETE FROM reportfmt; @ INSERT INTO reportfmt SELECT * FROM _xfer_reportfmt; @ DROP TABLE _xfer_user; @ DROP TABLE _xfer_reportfmt; ; - assert( strchr(zSQL,'%')==0 ); - db_multi_exec(zSQL /*works-like:""*/); -} - -/* -** Mask of modified configuration sets -*/ -static int rebuildMask = 0; - -/* -** Rebuild auxiliary tables as required by configuration changes. -*/ -void configure_rebuild(void){ - if( rebuildMask & CONFIGSET_TKT ){ - ticket_rebuild(); - } - rebuildMask = 0; + db_multi_exec(zSQL); } /* ** Return true if z[] is not a "safe" SQL token. A safe token is one of: ** @@ -569,42 +531,37 @@ if( (thisMask & groupMask)==0 ) return; blob_zero(&sql); if( groupMask & CONFIGSET_OVERWRITE ){ if( (thisMask & configHasBeenReset)==0 && aType[ii].zName[0]!='/' ){ - db_multi_exec("DELETE FROM \"%w\"", &aType[ii].zName[1]); + db_multi_exec("DELETE FROM %s", &aType[ii].zName[1]); configHasBeenReset |= thisMask; } - blob_append_sql(&sql, "REPLACE INTO "); - }else{ - blob_append_sql(&sql, "INSERT OR IGNORE INTO "); - } - blob_append_sql(&sql, "\"%w\"(\"%w\", mtime", &zName[1], aType[ii].zPrimKey); - for(jj=2; jj<nToken; jj+=2){ - blob_append_sql(&sql, ",\"%w\"", azToken[jj]); - } - 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_multi_exec("%s)", blob_sql_text(&sql)); + blob_append(&sql, "REPLACE INTO ", -1); + }else{ + blob_append(&sql, "INSERT OR IGNORE INTO ", -1); + } + blob_appendf(&sql, "%s(%s, mtime", &zName[1], aType[ii].zPrimKey); + for(jj=2; jj<nToken; jj+=2){ + blob_appendf(&sql, ",%s", azToken[jj]); + } + blob_appendf(&sql,") VALUES(%s,%s", azToken[1], azToken[0]); + for(jj=2; jj<nToken; jj+=2){ + blob_appendf(&sql, ",%s", azToken[jj+1]); + } + db_multi_exec("%s)", blob_str(&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*/); - } - blob_append_sql(&sql, " WHERE \"%w\"=%s AND mtime<%s", - aType[ii].zPrimKey, azToken[1]/*safe-for-%s*/, - azToken[0]/*safe-for-%s*/); - db_multi_exec("%s", blob_sql_text(&sql)); - } - blob_reset(&sql); - rebuildMask |= thisMask; + blob_appendf(&sql, "UPDATE %s SET mtime=%s", &zName[1], azToken[0]); + for(jj=2; jj<nToken; jj+=2){ + blob_appendf(&sql, ", %s=%s", azToken[jj], azToken[jj+1]); + } + blob_appendf(&sql, " WHERE %s=%s AND mtime<%s", + aType[ii].zPrimKey, azToken[1], azToken[0]); + db_multi_exec("%s", blob_str(&sql)); + } + blob_reset(&sql); }else{ /* Otherwise, the old format */ if( (configure_is_exportable(zName) & groupMask)==0 ) return; if( fossil_strcmp(zName, "logo-image")==0 ){ Stmt ins; @@ -619,11 +576,11 @@ /* Notice that we are evaluating arbitrary SQL received from the ** client. But this can only happen if the client has authenticated ** as an administrator, so presumably we trust the client at this ** point. */ - db_multi_exec("%s", blob_str(pContent) /*safe-for-%s*/); + db_multi_exec("%s", blob_str(pContent)); }else{ db_multi_exec( "REPLACE INTO config(name,value,mtime) VALUES(%Q,%Q,now())", zName, blob_str(pContent) ); @@ -859,11 +816,11 @@ ** ** Push the local configuration into the remote server identified ** by URL. Admin privilege is required on the remote server for ** this to work. When the same record exists both locally and on ** the remote end, the one that was most recently changed wins. -** Use the --legacy flag when talking to older servers. +** Use the --legacy flag when talking to holder servers. ** ** %fossil configuration reset AREA ** ** Restore the configuration to the default. AREA as above. ** @@ -940,11 +897,11 @@ mask = configure_name_to_mask(g.argv[3], 1); if( g.argc==5 ){ zServer = g.argv[4]; } url_parse(zServer, URL_PROMPT_PW); - if( g.url.protocol==0 ) fossil_fatal("no server URL specified"); + if( g.urlProtocol==0 ) fossil_fatal("no server URL specified"); user_select(); url_enable_proxy("via proxy: "); if( legacyFlag ) mask |= CONFIGSET_OLDFORMAT; if( overwriteFlag ) mask |= CONFIGSET_OVERWRITE; if( strncmp(zMethod, "push", n)==0 ){ @@ -976,212 +933,18 @@ db_multi_exec("DELETE FROM concealed"); }else if( fossil_strcmp(zName,"@shun")==0 ){ db_multi_exec("DELETE FROM shun"); }else if( fossil_strcmp(zName,"@reportfmt")==0 ){ db_multi_exec("DELETE FROM reportfmt"); - assert( strchr(zRepositorySchemaDefaultReports,'%')==0 ); - db_multi_exec(zRepositorySchemaDefaultReports /*works-like:""*/); + db_multi_exec(zRepositorySchemaDefaultReports); } } db_end_transaction(0); fossil_print("Configuration reset to factory defaults.\n"); fossil_print("To recover, use: %s %s import %s\n", g.argv[0], g.argv[1], zBackup); - rebuildMask |= mask; }else { fossil_fatal("METHOD should be one of:" " export import merge pull push reset"); } - configure_rebuild(); -} - - -/* -** COMMAND: test-var-list -** -** Usage: %fossil test-var-list ?PATTERN? ?--unset? ?--mtime? -** -** Show the content of the CONFIG table in a repository. If PATTERN is -** specified, then only show the entries that match that glob pattern. -** Last modification time is shown if the --mtime option is present. -** -** If the --unset option is included, then entries are deleted rather than -** being displayed. WARNING! This cannot be undone. Be sure you know what -** you are doing! The --unset option only works if there is a PATTERN. -** Probably you should run the command once without --unset to make sure -** you know exactly what is being deleted. -** -** If not in an open check-out, use the -R REPO option to specify a -** a repository. -*/ -void test_var_list_cmd(void){ - Stmt q; - int i, j; - const char *zPattern = 0; - int doUnset; - int showMtime; - Blob sql; - Blob ans; - unsigned char zTrans[1000]; - - doUnset = find_option("unset",0,0)!=0; - showMtime = find_option("mtime",0,0)!=0; - db_find_and_open_repository(OPEN_ANY_SCHEMA, 0); - verify_all_options(); - if( g.argc>=3 ){ - zPattern = g.argv[2]; - } - blob_init(&sql,0,0); - blob_appendf(&sql, "SELECT name, value, datetime(mtime,'unixepoch')" - " FROM config"); - if( zPattern ){ - blob_appendf(&sql, " WHERE name GLOB %Q", zPattern); - } - if( showMtime ){ - blob_appendf(&sql, " ORDER BY mtime, name"); - }else{ - blob_appendf(&sql, " ORDER BY name"); - } - db_prepare(&q, "%s", blob_str(&sql)/*safe-for-%s*/); - blob_reset(&sql); -#define MX_VAL 40 -#define MX_NM 28 -#define MX_LONGNM 60 - while( db_step(&q)==SQLITE_ROW ){ - const char *zName = db_column_text(&q,0); - int nName = db_column_bytes(&q,0); - const char *zValue = db_column_text(&q,1); - int szValue = db_column_bytes(&q,1); - const char *zMTime = db_column_text(&q,2); - for(i=j=0; j<MX_VAL && zValue[i]; i++){ - unsigned char c = (unsigned char)zValue[i]; - if( c>=' ' && c<='~' ){ - zTrans[j++] = c; - }else{ - zTrans[j++] = '\\'; - if( c=='\n' ){ - zTrans[j++] = 'n'; - }else if( c=='\r' ){ - zTrans[j++] = 'r'; - }else if( c=='\t' ){ - zTrans[j++] = 't'; - }else{ - zTrans[j++] = '0' + ((c>>6)&7); - zTrans[j++] = '0' + ((c>>3)&7); - zTrans[j++] = '0' + (c&7); - } - } - } - zTrans[j] = 0; - if( i<szValue ){ - sqlite3_snprintf(sizeof(zTrans)-j, (char*)zTrans+j, "...+%d", szValue-i); - j += (int)strlen((char*)zTrans+j); - } - if( showMtime ){ - fossil_print("%s:%*s%s\n", zName, 58-nName, "", zMTime); - }else if( nName<MX_NM-2 ){ - fossil_print("%s:%*s%s\n", zName, MX_NM-1-nName, "", zTrans); - }else if( nName<MX_LONGNM-2 && j<10 ){ - fossil_print("%s:%*s%s\n", zName, MX_LONGNM-1-nName, "", zTrans); - }else{ - fossil_print("%s:\n%*s%s\n", zName, MX_NM, "", zTrans); - } - } - db_finalize(&q); - if( zPattern && doUnset ){ - prompt_user("Delete all of the above? (y/N)? ", &ans); - if( blob_str(&ans)[0]=='y' || blob_str(&ans)[0]=='Y' ){ - db_multi_exec("DELETE FROM config WHERE name GLOB %Q", zPattern); - } - blob_reset(&ans); - } -} - -/* -** COMMAND: test-var-get -** -** Usage: %fossil test-var-get VAR ?FILE? -** -** Write the text of the VAR variable into FILE. If FILE is "-" -** or is omitted then output goes to standard output. VAR can be a -** GLOB pattern. -** -** If not in an open check-out, use the -R REPO option to specify a -** a repository. -*/ -void test_var_get_cmd(void){ - const char *zVar; - const char *zFile; - int n; - Blob x; - db_find_and_open_repository(OPEN_ANY_SCHEMA, 0); - verify_all_options(); - if( g.argc<3 ){ - usage("VAR ?FILE?"); - } - zVar = g.argv[2]; - zFile = g.argc>=4 ? g.argv[3] : "-"; - n = db_int(0, "SELECT count(*) FROM config WHERE name GLOB %Q", zVar); - if( n==0 ){ - fossil_fatal("no match for %Q", zVar); - } - if( n>1 ){ - fossil_fatal("multiple matches: %s", - db_text(0, "SELECT group_concat(quote(name),', ') FROM (" - " SELECT name FROM config WHERE name GLOB %Q ORDER BY 1)", - zVar)); - } - blob_init(&x,0,0); - db_blob(&x, "SELECT value FROM config WHERE name GLOB %Q", zVar); - blob_write_to_file(&x, zFile); -} - -/* -** COMMAND: test-var-set -** -** Usage: %fossil test-var-set VAR ?VALUE? ?--file FILE? -** -** Store VALUE or the content of FILE (exactly one of which must be -** supplied) into variable VAR. Use a FILE of "-" to read from -** standard input. -** -** WARNING: changing the value of a variable can interfere with the -** operation of Fossil. Be sure you know what you are doing. -** -** Use "--blob FILE" instead of "--file FILE" to load a binary blob -** such as a GIF. -*/ -void test_var_set_cmd(void){ - const char *zVar; - const char *zFile; - const char *zBlob; - Blob x; - Stmt ins; - zFile = find_option("file",0,1); - zBlob = find_option("blob",0,1); - db_find_and_open_repository(OPEN_ANY_SCHEMA, 0); - verify_all_options(); - if( g.argc<3 || (zFile==0 && zBlob==0 && g.argc<4) ){ - usage("VAR ?VALUE? ?--file FILE?"); - } - zVar = g.argv[2]; - if( zFile ){ - if( zBlob ) fossil_fatal("cannot do both --file or --blob"); - blob_read_from_file(&x, zFile); - }else if( zBlob ){ - blob_read_from_file(&x, zBlob); - }else{ - blob_init(&x,g.argv[3],-1); - } - db_prepare(&ins, - "REPLACE INTO config(name,value,mtime)" - "VALUES(%Q,:val,now())", zVar); - if( zBlob ){ - db_bind_blob(&ins, ":val", &x); - }else{ - db_bind_text(&ins, ":val", blob_str(&x)); - } - db_step(&ins); - db_finalize(&ins); - blob_reset(&x); } Index: src/content.c ================================================================== --- src/content.c +++ src/content.c @@ -114,11 +114,11 @@ contentCache.n = 0; contentCache.szTotal = 0; } /* -** Return the srcid associated with rid. Or return 0 if rid is +** Return the srcid associated with rid. Or return 0 if rid is ** original content and not a delta. */ static int findSrcid(int rid){ static Stmt q; int srcid; @@ -154,11 +154,11 @@ ** a phantom. */ int content_is_available(int rid){ int srcid; int depth = 0; /* Limit to recursion depth */ - while( depth++ < 10000000 ){ + while( depth++ < 10000000 ){ if( bag_find(&contentCache.missing, rid) ){ return 0; } if( bag_find(&contentCache.available, rid) ){ return 1; @@ -388,11 +388,11 @@ int i; /* Parse the object rid itself */ if( linkFlag ){ content_get(rid, &content); - manifest_crosslink(rid, &content, MC_NONE); + manifest_crosslink(rid, &content); assert( blob_is_reset(&content) ); } /* Parse all delta-manifests that depend on baseline-manifest rid */ db_prepare(&q, "SELECT rid FROM orphan WHERE baseline=%d", rid); @@ -405,11 +405,11 @@ aChild[nChildUsed++] = child; } db_finalize(&q); for(i=0; i<nChildUsed; i++){ content_get(aChild[i], &content); - manifest_crosslink(aChild[i], &content, MC_NONE); + manifest_crosslink(aChild[i], &content); assert( blob_is_reset(&content) ); } if( nChildUsed ){ db_multi_exec("DELETE FROM orphan WHERE baseline=%d", rid); } @@ -416,11 +416,11 @@ /* Recursively dephantomize all artifacts that are derived by ** delta from artifact rid and which have not already been ** cross-linked. */ nChildUsed = 0; - db_prepare(&q, + db_prepare(&q, "SELECT rid FROM delta" " WHERE srcid=%d" " AND NOT EXISTS(SELECT 1 FROM mlink WHERE mid=delta.rid)", rid ); @@ -455,11 +455,11 @@ /* ** Write content into the database. Return the record ID. If the ** content is already in the database, just return the record ID. ** ** If srcId is specified, then pBlob is delta content from -** the srcId record. srcId might be a phantom. +** the srcId record. srcId might be a phantom. ** ** pBlob is normally uncompressed text. But if nBlob>0 then the ** pBlob value has already been compressed and nBlob is its uncompressed ** size. If nBlob>0 then zUuid must be valid. ** @@ -486,11 +486,11 @@ Stmt s1; Blob cmpr; Blob hash; int markAsUnclustered = 0; int isDephantomize = 0; - + assert( g.repositoryOpen ); assert( pBlob!=0 ); assert( srcId==0 || zUuid!=0 ); if( zUuid==0 ){ assert( nBlob==0 ); @@ -558,40 +558,40 @@ } }else{ /* We are creating a new entry */ db_prepare(&s1, "INSERT INTO blob(rcvid,size,uuid,content)" - "VALUES(%d,%d,'%q',:data)", - g.rcvid, size, blob_str(&hash) + "VALUES(%d,%d,'%b',:data)", + g.rcvid, size, &hash ); db_bind_blob(&s1, ":data", &cmpr); db_exec(&s1); rid = db_last_insert_rowid(); if( !pBlob ){ db_multi_exec("INSERT OR IGNORE INTO phantom VALUES(%d)", rid); } - } - if( g.markPrivate || isPrivate ){ - db_multi_exec("INSERT INTO private VALUES(%d)", rid); - markAsUnclustered = 0; + if( g.markPrivate || isPrivate ){ + db_multi_exec("INSERT INTO private VALUES(%d)", rid); + markAsUnclustered = 0; + } } if( nBlob==0 ) blob_reset(&cmpr); /* If the srcId is specified, then the data we just added is ** really a delta. Record this fact in the delta table. */ if( srcId ){ db_multi_exec("REPLACE INTO delta(rid,srcid) VALUES(%d,%d)", rid, srcId); } - if( !isDephantomize && bag_find(&contentCache.missing, rid) && + if( !isDephantomize && bag_find(&contentCache.missing, rid) && (srcId==0 || content_is_available(srcId)) ){ content_mark_available(rid); } if( isDephantomize ){ after_dephantomize(rid, 0); } - + /* Add the element to the unclustered table if has never been ** previously seen. */ if( markAsUnclustered ){ db_multi_exec("INSERT OR IGNORE INTO unclustered VALUES(%d)", rid); @@ -628,11 +628,11 @@ ** Create a new phantom with the given UUID and return its artifact ID. */ int content_new(const char *zUuid, int isPrivate){ int rid; static Stmt s1, s2, s3; - + assert( g.repositoryOpen ); db_begin_transaction(); if( uuid_is_shunned(zUuid) ){ db_end_transaction(0); return 0; @@ -727,15 +727,15 @@ "SELECT 1 FROM private WHERE rid=:rid" ); db_bind_int(&s1, ":rid", rid); rc = db_step(&s1); db_reset(&s1); - return rc==SQLITE_ROW; + return rc==SQLITE_ROW; } /* -** Make sure an artifact is public. +** Make sure an artifact is public. */ void content_make_public(int rid){ static Stmt s1; db_static_prepare(&s1, "DELETE FROM private WHERE rid=:rid" @@ -758,11 +758,11 @@ ** ** If srcid is a delta that depends on rid, then srcid is ** converted to undeltaed text. ** ** If either rid or srcid contain less than 50 bytes, or if the -** resulting delta does not achieve a compression of at least 25% +** resulting delta does not achieve a compression of at least 25% ** the rid is left untouched. ** ** Return 1 if a delta is made and 0 if no delta occurs. */ int content_deltify(int rid, int srcid, int force){ @@ -883,11 +883,11 @@ zId, rid, zSrc, srcid ); nErr++; } db_finalize(&q); - + db_prepare(&q, "SELECT rid, uuid, size FROM blob ORDER BY rid"); total = db_int(0, "SELECT max(rid) FROM blob"); while( db_step(&q)==SQLITE_ROW ){ int rid = db_column_int(&q, 0); const char *zUuid = db_column_text(&q, 1); @@ -945,12 +945,12 @@ } db_finalize(&q); fossil_print("%d non-phantom blobs (out of %d total) checked: %d errors\n", n2, n1, nErr); if( bParse ){ - static const char *const azType[] = { 0, "manifest", "cluster", - "control", "wiki", "ticket", "attachment", "event" }; + const char *azType[] = { 0, "manifest", "cluster", "control", "wiki", + "ticket", "attachment", "event" }; int i; fossil_print("%d total control artifacts\n", nCA); for(i=1; i<count(azType); i++){ if( anCA[i] ) fossil_print(" %d %ss\n", anCA[i], azType[i]); } @@ -1019,11 +1019,11 @@ db_reset(&q); if( rc ){ const char *zCFType = "control artifact"; char *zSrc; char *zDate; - const char *zErrType = "MISSING"; + char *zErrType = "MISSING"; if( db_exists("SELECT 1 FROM shun WHERE uuid=%Q", zUuid) ){ if( flags & MISSING_SHUNNED ) return 0; zErrType = "SHUNNED"; } switch( p->type ){ @@ -1050,11 +1050,11 @@ if( zDetail && zDetail[0] ){ fossil_print(" %s\n", zDetail); } fossil_free(zSrc); fossil_free(zDate); - rc = 1; + rc = 1; } return rc; } /* @@ -1097,11 +1097,11 @@ if( p ){ nArtifact++; nErr += check_exists(p->zBaseline, flags, p, "baseline of", 0); nErr += check_exists(p->zAttachSrc, flags, p, "file of", 0); for(i=0; i<p->nFile; i++){ - nErr += check_exists(p->aFile[i].zUuid, flags, p, "file of", + nErr += check_exists(p->aFile[i].zUuid, flags, p, "file of", p->aFile[i].zName); } for(i=0; i<p->nParent; i++){ nErr += check_exists(p->azParent[i], flags, p, "parent of", 0); } @@ -1115,14 +1115,14 @@ nErr += check_exists(p->azCChild[i], flags, p, "in", 0); } for(i=0; i<p->nTag; i++){ nErr += check_exists(p->aTag[i].zUuid, flags, p, "target of", 0); } - manifest_destroy(p); + manifest_destroy(p); } } db_finalize(&q); if( nErr>0 || quietFlag==0 ){ fossil_print("%d missing or shunned references in %d control artifacts\n", nErr, nArtifact); } } Index: src/db.c ================================================================== --- src/db.c +++ src/db.c @@ -44,11 +44,11 @@ ** 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() */ + sqlite3_stmt *pStmt; /* The results of sqlite3_prepare() */ Stmt *pNext, *pPrev; /* List of all unfinalized statements */ int nStep; /* Number of sqlite3_step() calls */ }; /* @@ -65,10 +65,14 @@ */ static void db_err(const char *zFormat, ...){ va_list ap; char *z; int rc = 1; + static const char zRebuildMsg[] = + "If you have recently updated your fossil executable, you might\n" + "need to run \"fossil all rebuild\" to bring the repository\n" + "schemas up to date.\n"; va_start(ap, zFormat); z = vmprintf(zFormat, ap); va_end(ap); #ifdef FOSSIL_ENABLE_JSON if( g.json.isJsonMode ){ @@ -84,14 +88,15 @@ @ error Database\serror:\s%F(z) cgi_reply(); } else if( g.cgiOutput ){ g.cgiOutput = 0; - cgi_printf("<h1>Database Error</h1>\n<p>%h</p>\n", z); + cgi_printf("<h1>Database Error</h1>\n" + "<pre>%h</pre>\n<p>%s</p>\n", z, zRebuildMsg); cgi_reply(); }else{ - fprintf(stderr, "%s: %s\n", g.argv[0], z); + fprintf(stderr, "%s: %s\n\n%s", g.argv[0], z, zRebuildMsg); } free(z); db_force_rollback(); fossil_exit(rc); } @@ -103,11 +108,11 @@ static struct DbLocalData { int nBegin; /* Nesting depth of BEGIN */ int doRollback; /* True to force a rollback */ int nCommitHook; /* Number of commit hooks */ Stmt *pAllStmt; /* List of all unfinalized statements */ - int nPrepare; /* Number of calls to sqlite3_prepare_v2() */ + int nPrepare; /* Number of calls to sqlite3_prepare() */ int nDeleteOnFail; /* Number of entries in azDeleteOnFail[] */ struct sCommitHook { int (*xHook)(void); /* Functions to call at db_end_transaction() */ int sequence; /* Call functions in sequence order */ } aHook[5]; @@ -159,26 +164,24 @@ if( rollbackFlag ) db.doRollback = 1; db.nBegin--; if( db.nBegin==0 ){ int i; if( db.doRollback==0 && db.nPriorChanges<sqlite3_total_changes(g.db) ){ - i = 0; while( db.nBeforeCommit ){ db.nBeforeCommit--; - sqlite3_exec(g.db, db.azBeforeCommit[i], 0, 0, 0); - sqlite3_free(db.azBeforeCommit[i]); - i++; + sqlite3_exec(g.db, db.azBeforeCommit[db.nBeforeCommit], 0, 0, 0); + sqlite3_free(db.azBeforeCommit[db.nBeforeCommit]); } leaf_do_pending_checks(); } for(i=0; db.doRollback==0 && i<db.nCommitHook; i++){ db.doRollback |= db.aHook[i].xHook(); } while( db.pAllStmt ){ db_finalize(db.pAllStmt); } - db_multi_exec("%s", db.doRollback ? "ROLLBACK" : "COMMIT"); + db_multi_exec(db.doRollback ? "ROLLBACK" : "COMMIT"); db.doRollback = 0; } } /* @@ -313,14 +316,10 @@ } int db_bind_text(Stmt *pStmt, const char *zParamName, const char *zValue){ return sqlite3_bind_text(pStmt->pStmt, paramIdx(pStmt, zParamName), zValue, -1, SQLITE_STATIC); } -int db_bind_text16(Stmt *pStmt, const char *zParamName, const char *zValue){ - return sqlite3_bind_text16(pStmt->pStmt, paramIdx(pStmt, zParamName), zValue, - -1, SQLITE_STATIC); -} int db_bind_null(Stmt *pStmt, const char *zParamName){ return sqlite3_bind_null(pStmt->pStmt, paramIdx(pStmt, zParamName)); } int db_bind_blob(Stmt *pStmt, const char *zParamName, Blob *pBlob){ return sqlite3_bind_blob(pStmt->pStmt, paramIdx(pStmt, zParamName), @@ -345,72 +344,10 @@ rc = sqlite3_step(pStmt->pStmt); pStmt->nStep++; return rc; } -/* -** Steps the SQL statement until there are no more rows. Returns the -** total number of rows processed by this function. If the pazValue1 -** parameter is non-zero, captures the iCol1'th column value from each -** row (as text) and stores the resulting final array pointer into it. -** If the pazValue2 parameter is non-zero, captures the iCol2'th column -** value from each row (as text) and stores the resulting final array -** pointer into it. The caller of this function is responsible for -** calling the db_all_column_free() function later, passing it the -** result of this function along with the values for both the pazValue1 -** and pazValue2 paramters. -*/ -int db_all_column_text( - Stmt *pStmt, /* The statement handle. */ - int iCol1, /* The first column number to fetch from the results. */ - char ***pazValue1, /* Array of iCol1'th column values from query. */ - int iCol2, /* The second column number to fetch from the results. */ - char ***pazValue2 /* Array of iCol2'th column values from query. */ -){ - int count = 0; - char **azValue1 = 0; - char **azValue2 = 0; - while( db_step(pStmt)==SQLITE_ROW ){ - count++; - if( pazValue1 ){ - azValue1 = fossil_realloc(azValue1, count * sizeof(char*)); - azValue1[count - 1] = fossil_strdup(db_column_text(pStmt, iCol1)); - } - if( pazValue2 ){ - azValue2 = fossil_realloc(azValue2, count * sizeof(char*)); - azValue2[count - 1] = fossil_strdup(db_column_text(pStmt, iCol2)); - } - } - if( pazValue1 ){ - *pazValue1 = azValue1; - } - if( pazValue2 ){ - *pazValue2 = azValue2; - } - return count; -} - -/* -** This function frees all the storage that was allocated by the -** db_all_column_text() function for a particular column. -*/ -void db_all_column_free( - int count, /* Number of string elements in the arrays. */ - char ***pazValue /* Array of column values from query. */ -){ - if( pazValue ){ - char **azValue = *pazValue; - int i; - for(i=0; i<count; i++){ - fossil_free(azValue[i]); - azValue[i] = 0; - } - fossil_free(azValue); - *pazValue = 0; - } -} - /* ** Print warnings if a query is inefficient. */ static void db_stats(Stmt *pStmt){ #ifdef FOSSIL_DEBUG @@ -483,13 +420,10 @@ /* ** Extract text, integer, or blob values from the N-th column of the ** current row. */ -int db_column_type(Stmt *pStmt, int N){ - return sqlite3_column_type(pStmt->pStmt, N); -} int db_column_bytes(Stmt *pStmt, int N){ return sqlite3_column_bytes(pStmt->pStmt, N); } int db_column_int(Stmt *pStmt, int N){ return sqlite3_column_int(pStmt->pStmt, N); @@ -549,50 +483,10 @@ rc = db_reset(pStmt); db_check_result(rc); return rc; } -/* -** Print the output of one or more SQL queries on standard output. -** This routine is used for debugging purposes only. -*/ -int db_debug(const char *zSql, ...){ - Blob sql; - int rc = SQLITE_OK; - va_list ap; - const char *z, *zEnd; - sqlite3_stmt *pStmt; - blob_init(&sql, 0, 0); - va_start(ap, zSql); - blob_vappendf(&sql, zSql, ap); - va_end(ap); - z = blob_str(&sql); - while( rc==SQLITE_OK && z[0] ){ - pStmt = 0; - rc = sqlite3_prepare_v2(g.db, z, -1, &pStmt, &zEnd); - if( rc!=SQLITE_OK ) break; - if( pStmt ){ - int nRow = 0; - db.nPrepare++; - while( sqlite3_step(pStmt)==SQLITE_ROW ){ - int i, n; - if( nRow++ > 0 ) fossil_print("\n"); - n = sqlite3_column_count(pStmt); - for(i=0; i<n; i++){ - fossil_print("%s = %s\n", sqlite3_column_name(pStmt, i), - sqlite3_column_text(pStmt,i)); - } - } - rc = sqlite3_finalize(pStmt); - if( rc ) db_err("%s: {%.*s}", sqlite3_errmsg(g.db), (int)(zEnd-z), z); - } - z = zEnd; - } - blob_reset(&sql); - return rc; -} - /* ** Execute multiple SQL statements. */ int db_multi_exec(const char *zSql, ...){ Blob sql; @@ -606,13 +500,12 @@ va_end(ap); z = blob_str(&sql); while( rc==SQLITE_OK && z[0] ){ pStmt = 0; rc = sqlite3_prepare_v2(g.db, z, -1, &pStmt, &zEnd); - if( rc ){ - db_err("%s: {%s}", sqlite3_errmsg(g.db), z); - }else if( pStmt ){ + if( rc!=SQLITE_OK ) break; + if( pStmt ){ db.nPrepare++; while( sqlite3_step(pStmt)==SQLITE_ROW ){} rc = sqlite3_finalize(pStmt); if( rc ) db_err("%s: {%.*s}", sqlite3_errmsg(g.db), (int)(zEnd-z), z); } @@ -731,11 +624,11 @@ ** Execute a query. Return the first column of the first row ** of the result set as a string. Space to hold the string is ** obtained from malloc(). If the result set is empty, return ** zDefault instead. */ -char *db_text(const char *zDefault, const char *zSql, ...){ +char *db_text(char const *zDefault, const char *zSql, ...){ va_list ap; Stmt s; char *z; va_start(ap, zSql); db_vprepare(&s, 0, zSql, ap); @@ -767,17 +660,17 @@ db = db_open(zFileName); sqlite3_exec(db, "BEGIN EXCLUSIVE", 0, 0, 0); rc = sqlite3_exec(db, zSchema, 0, 0, 0); if( rc!=SQLITE_OK ){ - db_err("%s", sqlite3_errmsg(db)); + db_err(sqlite3_errmsg(db)); } va_start(ap, zSchema); while( (zSql = va_arg(ap, const char*))!=0 ){ rc = sqlite3_exec(db, zSql, 0, 0, 0); if( rc!=SQLITE_OK ){ - db_err("%s", sqlite3_errmsg(db)); + db_err(sqlite3_errmsg(db)); } } va_end(ap); sqlite3_exec(db, "COMMIT", 0, 0, 0); sqlite3_close(db); @@ -795,18 +688,10 @@ sqlite3_result_int64(context, time(0)); } /* ** Function to return the check-in time for a file. -** -** checkin_mtime(CKINID,RID) -** -** CKINID: The RID for the manifest for a check-in. -** RID: The RID of a file in CKINID for which the check-in time -** is desired. -** -** Returns: The check-in time in seconds since 1970. */ void db_checkin_mtime_function( sqlite3_context *context, int argc, sqlite3_value **argv @@ -817,114 +702,68 @@ if( rc==0 ){ sqlite3_result_int64(context, mtime); } } -/* -** SQL wrapper around the symbolic_name_to_rid() C-language API. -** Examples: -** -** symbolic_name_to_rid('trunk'); -** symbolic_name_to_rid('trunk','w'); -** -*/ -void db_sym2rid_function( - sqlite3_context *context, - int argc, - sqlite3_value **argv -){ - const char *arg; - const char *type; - if(1 != argc && 2 != argc){ - sqlite3_result_error(context, "Expecting one or two arguments", -1); - return; - } - arg = (const char*)sqlite3_value_text(argv[0]); - if(!arg){ - sqlite3_result_error(context, "Expecting a STRING argument", -1); - }else{ - int rid; - type = (2==argc) ? (const char*)sqlite3_value_text(argv[1]) : 0; - if(!type) type = "ci"; - rid = symbolic_name_to_rid( arg, type ); - if(rid<0){ - sqlite3_result_error(context, "Symbolic name is ambiguous.", -1); - }else if(0==rid){ - sqlite3_result_null(context); - }else{ - sqlite3_result_int64(context, rid); - } - } -} - -/* -** Register the SQL functions that are useful both to the internal -** representation and to the "fossil sql" command. -*/ -void db_add_aux_functions(sqlite3 *db){ - sqlite3_create_function(db, "checkin_mtime", 2, SQLITE_UTF8, 0, - db_checkin_mtime_function, 0, 0); - sqlite3_create_function(db, "symbolic_name_to_rid", 1, SQLITE_UTF8, 0, - db_sym2rid_function, 0, 0); - sqlite3_create_function(db, "symbolic_name_to_rid", 2, SQLITE_UTF8, 0, - db_sym2rid_function, 0, 0); - sqlite3_create_function(db, "now", 0, SQLITE_UTF8, 0, - db_now_function, 0, 0); -} - /* ** Open a database file. Return a pointer to the new database ** connection. An error results in process abort. */ LOCAL sqlite3 *db_open(const char *zDbName){ int rc; + const char *zVfs; sqlite3 *db; +#if defined(__CYGWIN__) + zDbName = fossil_utf8_to_filename(zDbName); +#endif if( g.fSqlTrace ) fossil_trace("-- sqlite3_open: [%s]\n", zDbName); + zVfs = fossil_getenv("FOSSIL_VFS"); rc = sqlite3_open_v2( zDbName, &db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, - g.zVfsName + zVfs ); if( rc!=SQLITE_OK ){ db_err("[%s]: %s", zDbName, sqlite3_errmsg(db)); } sqlite3_busy_timeout(db, 5000); sqlite3_wal_autocheckpoint(db, 1); /* Set to checkpoint frequently */ - sqlite3_create_function(db, "user", 0, SQLITE_UTF8, 0, db_sql_user, 0, 0); - sqlite3_create_function(db, "cgi", 1, SQLITE_UTF8, 0, db_sql_cgi, 0, 0); - sqlite3_create_function(db, "cgi", 2, SQLITE_UTF8, 0, db_sql_cgi, 0, 0); + sqlite3_create_function(db, "now", 0, SQLITE_ANY, 0, db_now_function, 0, 0); + sqlite3_create_function(db, "checkin_mtime", 2, SQLITE_ANY, 0, + db_checkin_mtime_function, 0, 0); + sqlite3_create_function(db, "user", 0, SQLITE_ANY, 0, db_sql_user, 0, 0); + sqlite3_create_function(db, "cgi", 1, SQLITE_ANY, 0, db_sql_cgi, 0, 0); + sqlite3_create_function(db, "cgi", 2, SQLITE_ANY, 0, db_sql_cgi, 0, 0); sqlite3_create_function(db, "print", -1, SQLITE_UTF8, 0,db_sql_print,0,0); sqlite3_create_function( db, "is_selected", 1, SQLITE_UTF8, 0, file_is_selected,0,0 ); sqlite3_create_function( db, "if_selected", 3, SQLITE_UTF8, 0, file_is_selected,0,0 ); if( g.fSqlTrace ) sqlite3_trace(db, 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 */ + re_add_sql_func(db); sqlite3_exec(db, "PRAGMA foreign_keys=OFF;", 0, 0, 0); return db; } /* ** Detaches the zLabel database. */ void db_detach(const char *zLabel){ - db_multi_exec("DETACH DATABASE %Q", zLabel); + db_multi_exec("DETACH DATABASE %s", zLabel); } /* ** zDbName is the name of a database file. Attach zDbName using ** the name zLabel. */ void db_attach(const char *zDbName, const char *zLabel){ - db_multi_exec("ATTACH DATABASE %Q AS %Q", zDbName, zLabel); + db_multi_exec("ATTACH DATABASE %Q AS %s", zDbName, zLabel); } /* ** zDbName is the name of a database file. If no other database ** file is open, then open this one. If another database file is @@ -945,33 +784,10 @@ db_attach(zDbName, zLabel); if( pWasAttached ) *pWasAttached = 1; } } -/* -** Close the user database. -*/ -void db_close_config(){ - if( g.useAttach ){ - db_detach("configdb"); - g.useAttach = 0; - g.zConfigDbName = 0; - }else if( g.dbConfig ){ - sqlite3_wal_checkpoint(g.dbConfig, 0); - sqlite3_close(g.dbConfig); - g.dbConfig = 0; - g.zConfigDbType = 0; - g.zConfigDbName = 0; - }else if( g.db && fossil_strcmp(g.zMainDbType, "configdb")==0 ){ - sqlite3_wal_checkpoint(g.db, 0); - sqlite3_close(g.db); - g.db = 0; - g.zMainDbType = 0; - g.zConfigDbName = 0; - } -} - /* ** Open the user database in "~/.fossil". Create the database anew if ** it does not already exist. ** ** If the useAttach flag is 0 (the usual case) then the user database is @@ -983,59 +799,53 @@ ** case, invoke this routine with useAttach as 1. */ void db_open_config(int useAttach){ char *zDbName; char *zHome; - if( g.zConfigDbName ){ - if( useAttach==g.useAttach ) return; - db_close_config(); - } - zHome = fossil_getenv("FOSSIL_HOME"); -#if defined(_WIN32) || defined(__CYGWIN__) - if( zHome==0 ){ - zHome = fossil_getenv("LOCALAPPDATA"); - if( zHome==0 ){ - zHome = fossil_getenv("APPDATA"); - if( zHome==0 ){ - char *zDrive = fossil_getenv("HOMEDRIVE"); - char *zPath = fossil_getenv("HOMEPATH"); - if( zDrive && zPath ) zHome = mprintf("%s%s", zDrive, zPath); - } - } - } - if( zHome==0 ){ - fossil_fatal("cannot locate home directory - please set the " - "FOSSIL_HOME, LOCALAPPDATA, APPDATA, or HOMEPATH " - "environment variables"); - } -#else - if( zHome==0 ){ - zHome = fossil_getenv("HOME"); - } - if( zHome==0 ){ - fossil_fatal("cannot locate home directory - please set the " - "FOSSIL_HOME or HOME environment variables"); + if( g.zConfigDbName ) return; +#if defined(_WIN32) || defined(__CYGWIN__) + zHome = fossil_getenv("LOCALAPPDATA"); + if( zHome==0 ){ + zHome = fossil_getenv("APPDATA"); + if( zHome==0 ){ + char *zDrive = fossil_getenv("HOMEDRIVE"); + zHome = fossil_getenv("HOMEPATH"); + if( zDrive && zHome ) zHome = mprintf("%s%s", zDrive, zHome); + } + } + if( zHome==0 ){ + fossil_fatal("cannot locate home directory - " + "please set the LOCALAPPDATA or APPDATA or HOMEPATH " + "environment variables"); + } +#else + zHome = fossil_getenv("HOME"); + if( zHome==0 ){ + fossil_fatal("cannot locate home directory - " + "please set the HOME environment variable"); } #endif if( file_isdir(zHome)!=1 ){ fossil_fatal("invalid home directory: %s", zHome); } #if defined(_WIN32) || defined(__CYGWIN__) /* . filenames give some window systems problems and many apps problems */ zDbName = mprintf("%//_fossil", zHome); #else + if( file_access(zHome, W_OK) ){ + fossil_fatal("home directory %s must be writeable", zHome); + } zDbName = mprintf("%s/.fossil", zHome); #endif if( file_size(zDbName)<1024*3 ){ - if( file_access(zHome, W_OK) ){ - fossil_fatal("home directory %s must be writeable", zHome); - } db_init_database(zDbName, zConfigSchema, (char*)0); } +#if defined(_WIN32) || defined(__CYGWIN__) if( file_access(zDbName, W_OK) ){ fossil_fatal("configuration file %s must be writeable", zDbName); } +#endif if( useAttach ){ db_open_or_attach(zDbName, "configdb", &g.useAttach); g.dbConfig = 0; g.zConfigDbType = 0; }else{ @@ -1044,47 +854,30 @@ g.zConfigDbType = "configdb"; } g.zConfigDbName = zDbName; } -/* -** Return TRUE if zTable exists. -*/ -int db_table_exists( - const char *zDb, /* One of: NULL, "configdb", "localdb", "repository" */ - const char *zTable /* Name of table */ -){ - return sqlite3_table_column_metadata(g.db, - zDb ? db_name(zDb) : 0, zTable, 0, - 0, 0, 0, 0, 0)==SQLITE_OK; -} - -/* -** Return TRUE if zTable exists and contains column zColumn. -** Return FALSE if zTable does not exist or if zTable exists -** but lacks zColumn. -*/ -int db_table_has_column( - const char *zDb, /* One of: NULL, "config", "localdb", "repository" */ - const char *zTable, /* Name of table */ - const char *zColumn /* Name of column in table */ -){ - return sqlite3_table_column_metadata(g.db, - zDb ? db_name(zDb) : 0, zTable, zColumn, - 0, 0, 0, 0, 0)==SQLITE_OK; -} /* ** Returns TRUE if zTable exists in the local database but lacks column ** zColumn */ static int db_local_table_exists_but_lacks_column( const char *zTable, const char *zColumn ){ - return db_table_exists(db_name("localdb"), zTable) - && !db_table_has_column(db_name("localdb"), zTable, zColumn); + char *zDef = db_text(0, "SELECT sql FROM %s.sqlite_master" + " WHERE name=='%s' /*scan*/", + db_name("localdb"), zTable); + int rc = 0; + if( zDef ){ + char *zPattern = mprintf("* %s *", zColumn); + rc = strglob(zPattern, zDef)==0; + fossil_free(zPattern); + fossil_free(zDef); + } + return rc; } /* ** If zDbName is a valid local database file, open it and return ** true. If it is not a valid local database file, return 0. @@ -1103,19 +896,19 @@ /* 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. */ - if( sqlite3_strglob("* isexe *", zVFileDef)!=0 ){ + if( !strglob("* isexe *", zVFileDef) ){ db_multi_exec("ALTER TABLE vfile ADD COLUMN isexe BOOLEAN DEFAULT 0"); } /* If "islink"/"isLink" columns are missing from tables, then ** add them now. This code added on 2011-01-17 and 2011-08-27. ** After all users have upgraded, this code can be safely deleted. */ - if( sqlite3_strglob("* islink *", zVFileDef)!=0 ){ + if( !strglob("* islink *", zVFileDef) ){ db_multi_exec("ALTER TABLE vfile ADD COLUMN islink BOOLEAN DEFAULT 0"); if( db_local_table_exists_but_lacks_column("stashfile", "isLink") ){ db_multi_exec("ALTER TABLE stashfile ADD COLUMN isLink BOOL DEFAULT 0"); } if( db_local_table_exists_but_lacks_column("undo", "isLink") ){ @@ -1146,23 +939,23 @@ ** is found, it is attached to the open database connection too. */ int db_open_local(const char *zDbName){ int i, n; char zPwd[2000]; - static const char *(aDbName[]) = { "_FOSSIL_", ".fslckout", ".fos" }; + static const char aDbName[][10] = { "_FOSSIL_", ".fslckout", ".fos" }; - if( g.localOpen ) return 1; + if( g.localOpen) return 1; file_getcwd(zPwd, sizeof(zPwd)-20); n = strlen(zPwd); + if( n==1 && zPwd[0]=='/' ) zPwd[0] = '.'; while( n>0 ){ for(i=0; i<count(aDbName); i++){ sqlite3_snprintf(sizeof(zPwd)-n, &zPwd[n], "/%s", aDbName[i]); if( isValidLocalDb(zPwd) ){ /* Found a valid checkout database file */ - g.zLocalDbName = mprintf("%s", zPwd); zPwd[n] = 0; - while( n>0 && zPwd[n-1]=='/' ){ + while( n>1 && zPwd[n-1]=='/' ){ n--; zPwd[n] = 0; } g.zLocalRoot = mprintf("%s/", zPwd); g.localOpen = 1; @@ -1170,12 +963,12 @@ db_open_repository(zDbName); return 1; } } n--; - while( n>1 && zPwd[n]!='/' ){ n--; } - while( n>1 && zPwd[n-1]=='/' ){ n--; } + while( n>0 && zPwd[n]!='/' ){ n--; } + while( n>0 && zPwd[n-1]=='/' ){ n--; } zPwd[n] = 0; } /* A checkout database file could not be found */ return 0; @@ -1212,11 +1005,11 @@ if( zDbName==0 ){ db_err("unable to find the name of a repository database"); } } if( file_access(zDbName, R_OK) || file_size(zDbName)<1024 ){ - if( file_access(zDbName, F_OK) ){ + if( file_access(zDbName, 0) ){ #ifdef FOSSIL_ENABLE_JSON g.json.resultCode = FSL_JSON_E_DB_NOT_FOUND; #endif fossil_panic("repository does not exist or" " is in an unreadable directory: %s", zDbName); @@ -1230,42 +1023,19 @@ g.json.resultCode = FSL_JSON_E_DB_NOT_VALID; #endif fossil_panic("not a valid repository: %s", zDbName); } } +#if defined(__CYGWIN__) + g.zRepositoryName = fossil_utf8_to_filename(zDbName); +#else g.zRepositoryName = mprintf("%s", zDbName); +#endif db_open_or_attach(g.zRepositoryName, "repository", 0); g.repositoryOpen = 1; /* Cache "allow-symlinks" option, because we'll need it on every stat call */ g.allowSymlinks = db_get_boolean("allow-symlinks", 0); - g.zAuxSchema = db_get("aux-schema",""); - - /* Verify that the PLINK table has a new column added by the - ** 2014-11-28 schema change. Create it if necessary. This code - ** can be removed in the future, once all users have upgraded to the - ** 2014-11-28 or later schema. - */ - if( !db_table_has_column("repository","plink","baseid") ){ - db_multi_exec( - "ALTER TABLE %s.plink ADD COLUMN baseid;", db_name("repository") - ); - } - - /* Verify that the MLINK table has the newer columns added by the - ** 2015-01-24 schema change. Create them if necessary. This code - ** can be removed in the future, once all users have upgraded to the - ** 2015-01-24 or later schema. - */ - if( !db_table_has_column("repository","mlink","isaux") ){ - db_begin_transaction(); - db_multi_exec( - "ALTER TABLE %s.mlink ADD COLUMN pmid INTEGER DEFAULT 0;" - "ALTER TABLE %s.mlink ADD COLUMN isaux BOOLEAN DEFAULT 0;", - db_name("repository"), db_name("repository") - ); - db_end_transaction(0); - } } /* ** Flags for the db_find_and_open_repository() function. */ @@ -1280,14 +1050,11 @@ ** use the repository of the open checkout 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)==1 ){ - goto rep_not_found; - } + const char *zRep = find_option("repository", "R", 1); if( zRep==0 && nArgUsed && g.argc==nArgUsed+1 ){ zRep = g.argv[nArgUsed]; } if( zRep==0 ){ if( db_open_local(0)==0 ){ @@ -1329,12 +1096,13 @@ /* ** Return TRUE if the schema is out-of-date */ int db_schema_is_outofdate(void){ - return strcmp(g.zAuxSchema,AUX_SCHEMA_MIN)<0 - || strcmp(g.zAuxSchema,AUX_SCHEMA_MAX)>0; + return db_exists("SELECT 1 FROM config" + " WHERE name='aux-schema'" + " AND value<>'%s'", AUX_SCHEMA); } /* ** Return true if the database is writeable */ @@ -1349,14 +1117,14 @@ void db_verify_schema(void){ if( db_schema_is_outofdate() ){ #ifdef FOSSIL_ENABLE_JSON g.json.resultCode = FSL_JSON_E_DB_NEEDS_REBUILD; #endif - fossil_warning("incorrect repository schema version: " - "current repository schema version is \"%s\" " - "but need versions between \"%s\" and \"%s\".", - g.zAuxSchema, AUX_SCHEMA_MIN, AUX_SCHEMA_MAX); + fossil_warning("incorrect repository schema version"); + fossil_warning("your repository has schema version \"%s\" " + "but this binary expects version \"%s\"", + db_get("aux-schema",0), AUX_SCHEMA); fossil_fatal("run \"fossil rebuild\" to fix this problem"); } } @@ -1375,20 +1143,19 @@ if( g.argc!=3 ){ usage("PATHNAME"); } file_canonical_name(g.argv[2], &repo, 0); zRepo = blob_str(&repo); - if( file_access(zRepo, F_OK) ){ + if( file_access(zRepo, 0) ){ fossil_fatal("no such file: %s", zRepo); } if( db_open_local(zRepo)==0 ){ fossil_fatal("not in a local checkout"); return; } db_open_or_attach(zRepo, "test_repo", 0); db_lset("repository", blob_str(&repo)); - db_record_repository_filename(blob_str(&repo)); db_close(1); } /* @@ -1440,41 +1207,27 @@ while( db.pAllStmt ){ db_finalize(db.pAllStmt); } db_end_transaction(1); pStmt = 0; - db_close_config(); - - /* If the localdb (the check-out database) is open and if it has - ** a lot of unused free space, then VACUUM it as we shut down. - */ - if( g.localOpen && strcmp(db_name("localdb"),"main")==0 ){ - int nFree = db_int(0, "PRAGMA main.freelist_count"); - int nTotal = db_int(0, "PRAGMA main.page_count"); - if( nFree>nTotal/4 ){ - db_multi_exec("VACUUM;"); - } - } - - if( g.db ){ - int rc; - sqlite3_wal_checkpoint(g.db, 0); - rc = sqlite3_close(g.db); - if( rc==SQLITE_BUSY && reportErrors ){ - while( (pStmt = sqlite3_next_stmt(g.db, pStmt))!=0 ){ - fossil_warning("unfinalized SQL statement: [%s]", sqlite3_sql(pStmt)); - } - } - g.db = 0; - g.zMainDbType = 0; + if( reportErrors ){ + while( (pStmt = sqlite3_next_stmt(g.db, pStmt))!=0 ){ + fossil_warning("unfinalized SQL statement: [%s]", sqlite3_sql(pStmt)); + } } g.repositoryOpen = 0; g.localOpen = 0; - assert( g.dbConfig==0 ); - assert( g.useAttach==0 ); - assert( g.zConfigDbName==0 ); - assert( g.zConfigDbType==0 ); + g.zConfigDbName = NULL; + sqlite3_wal_checkpoint(g.db, 0); + sqlite3_close(g.db); + g.db = 0; + g.zMainDbType = 0; + if( g.dbConfig ){ + sqlite3_close(g.dbConfig); + g.dbConfig = 0; + g.zConfigDbType = 0; + } } /* ** Create a new empty repository database with the given name. @@ -1526,13 +1279,13 @@ " WHERE login=%Q", zUser ); if( !setupUserOnly ){ db_multi_exec( "INSERT OR IGNORE INTO user(login,pw,cap,info)" - " VALUES('anonymous',hex(randomblob(8)),'hmnc','Anon');" + " VALUES('anonymous',hex(randomblob(8)),'hmncz','Anon');" "INSERT OR IGNORE INTO user(login,pw,cap,info)" - " VALUES('nobody','','gjorz','Nobody');" + " VALUES('nobody','','gjor','Nobody');" "INSERT OR IGNORE INTO user(login,pw,cap,info)" " VALUES('developer','','dei','Dev');" "INSERT OR IGNORE INTO user(login,pw,cap,info)" " VALUES('reader','','kptw','Reader');" ); @@ -1548,17 +1301,17 @@ Blob x; int i; const char *zSep = ""; blob_zero(&x); - blob_append_sql(&x, "("); - for(i=0; aSetting[i].name; i++){ - blob_append_sql(&x, "%s%Q", zSep/*safe-for-%s*/, aSetting[i].name); + blob_append(&x, "(", 1); + for(i=0; ctrlSettings[i].name; i++){ + blob_appendf(&x, "%s'%s'", zSep, ctrlSettings[i].name); zSep = ","; } - blob_append_sql(&x, ")"); - return blob_sql_text(&x); + blob_append(&x, ")", 1); + return blob_str(&x); } /* ** Fill an empty repository database with the basic information for a ** repository. This function is shared between 'create_repository_cmd' @@ -1578,25 +1331,27 @@ ** not server and project codes are invented for this repository. */ void db_initial_setup( const char *zTemplate, /* Repository from which to copy settings. */ const char *zInitialDate, /* Initial date of repository. (ex: "now") */ - const char *zDefaultUser /* Default user for the repository */ + const char *zDefaultUser, /* Default user for the repository */ + int makeServerCodes /* True to make new server & project codes */ ){ char *zDate; Blob hash; Blob manifest; db_set("content-schema", CONTENT_SCHEMA, 0); - db_set("aux-schema", AUX_SCHEMA_MAX, 0); - db_set("rebuilt", get_version(), 0); - db_multi_exec( + db_set("aux-schema", AUX_SCHEMA, 0); + if( makeServerCodes ){ + db_multi_exec( "INSERT INTO config(name,value,mtime)" " VALUES('server-code', lower(hex(randomblob(20))),now());" "INSERT INTO config(name,value,mtime)" " VALUES('project-code', lower(hex(randomblob(20))),now());" - ); + ); + } if( !db_is_global("autosync") ) db_set_int("autosync", 1, 0); if( !db_is_global("localauth") ) db_set_int("localauth", 0, 0); if( !db_is_global("timeline-plaintext") ){ db_set_int("timeline-plaintext", 1, 0); } @@ -1610,12 +1365,11 @@ */ db_multi_exec( "INSERT OR REPLACE INTO config" " SELECT name,value,mtime FROM settingSrc.config" " WHERE (name IN %s OR name IN %s)" - " AND name NOT GLOB 'project-*'" - " AND name NOT GLOB 'short-project-*';", + " AND name NOT GLOB 'project-*';", configure_inop_rhs(CONFIGSET_ALL), db_setting_inop_rhs() ); db_multi_exec( "REPLACE INTO reportfmt SELECT * FROM settingSrc.reportfmt;" @@ -1658,11 +1412,11 @@ blob_appendf(&manifest, "U %F\n", g.zLogin); md5sum_blob(&manifest, &hash); blob_appendf(&manifest, "Z %b\n", &hash); blob_reset(&hash); rid = content_put(&manifest); - manifest_crosslink(rid, &manifest, MC_NONE); + manifest_crosslink(rid, &manifest); } } /* ** COMMAND: new* @@ -1689,11 +1443,11 @@ ** associated permissions will be copied. ** ** Options: ** --template FILE copy settings from repository file ** --admin-user|-A USERNAME select given USERNAME as admin user -** --date-override DATETIME use DATETIME as time of the initial check-in +** --date-override DATETIME use DATETIME as time of the initial checkin ** ** See also: clone */ void create_repository_cmd(void){ char *zPassword; @@ -1702,28 +1456,20 @@ const char *zDefaultUser; /* Optional name of the default user */ zTemplate = find_option("template",0,1); zDate = find_option("date-override",0,1); zDefaultUser = find_option("admin-user","A",1); - /* We should be done with options.. */ - verify_all_options(); - + if( zDate==0 ) zDate = "now"; if( g.argc!=3 ){ usage("REPOSITORY-NAME"); } - - if( -1 != file_size(g.argv[2]) ){ - fossil_fatal("file already exists: %s", g.argv[2]); - } - db_create_repository(g.argv[2]); db_open_repository(g.argv[2]); db_open_config(0); if( zTemplate ) db_attach(zTemplate, "settingSrc"); db_begin_transaction(); - if( zDate==0 ) zDate = "now"; - db_initial_setup(zTemplate, zDate, zDefaultUser); + db_initial_setup(zTemplate, zDate, zDefaultUser, 1); db_end_transaction(0); if( zTemplate ) db_detach("settingSrc"); 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); @@ -1943,21 +1689,16 @@ g.zConfigDbType = zTempDbType; } } /* -** Try to read a versioned setting string from .fossil-settings/<name>. -** -** Return the text of the string if it is found. Return NULL if not -** found. -** -** If the zNonVersionedSetting parameter is not NULL then it holds the -** non-versioned value for this setting. If both a versioned and ad -** non-versioned value exist and are not equal, then a warning message -** might be generated. +** Logic for reading potentially versioned settings from +** .fossil-settings/<name> , and emits warnings if necessary. +** Returns the non-versioned value without modification if there is no +** versioned value. */ -char *db_get_versioned(const char *zName, char *zNonVersionedSetting){ +char *db_get_do_versionable(const char *zName, char *zNonVersionedSetting){ char *zVersionedSetting = 0; int noWarn = 0; struct _cacheEntry { struct _cacheEntry *next; const char *zName, *zValue; @@ -2028,50 +1769,37 @@ /* ** Get and set values from the CONFIG, GLOBAL_CONFIG and VVAR table in the ** repository and local databases. -** -** If no such variable exists, return zDefault. Or, if zName is the name -** of a setting, then the zDefault is ignored and the default value of the -** setting is returned instead. If zName is a versioned setting, then -** versioned value takes priority. */ char *db_get(const char *zName, char *zDefault){ char *z = 0; - const Setting *pSetting = db_find_setting(zName, 0); + int i; + const struct stControlSettings *ctrlSetting = 0; + /* Is this a setting? */ + for(i=0; ctrlSettings[i].name; i++){ + if( strcmp(ctrlSettings[i].name, zName)==0 ){ + ctrlSetting = &(ctrlSettings[i]); + break; + } + } if( g.repositoryOpen ){ z = db_text(0, "SELECT value FROM config WHERE name=%Q", zName); } if( z==0 && g.zConfigDbName ){ db_swap_connections(); z = db_text(0, "SELECT value FROM global_config WHERE name=%Q", zName); db_swap_connections(); } - if( pSetting!=0 && pSetting->versionable ){ - /* This is a versionable setting, try and get the info from a - ** checked out file */ - z = db_get_versioned(zName, z); - } - if( z==0 ){ - if( zDefault==0 && pSetting && pSetting->def[0] ){ - z = fossil_strdup(pSetting->def); - }else{ - z = zDefault; - } - } - return z; -} -char *db_get_mtime(const char *zName, char *zFormat, char *zDefault){ - char *z = 0; - if( g.repositoryOpen ){ - z = db_text(0, "SELECT mtime FROM config WHERE name=%Q", zName); - } - if( z==0 ){ - z = zDefault; - }else if( zFormat!=0 ){ - z = db_text(0, "SELECT strftime(%Q,%Q,'unixepoch');", zFormat, z); + if( ctrlSetting!=0 && ctrlSetting->versionable ){ + /* This is a versionable setting, try and get the info from a + ** checked out file */ + z = db_get_do_versionable(zName, z); + } + if( z==0 ){ + z = zDefault; } return z; } void db_set(const char *zName, const char *zValue, int globalFlag){ db_begin_transaction(); @@ -2164,10 +1892,31 @@ return db_int(dflt, "SELECT value FROM vvar WHERE name=%Q", zName); } void db_lset_int(const char *zName, int value){ db_multi_exec("REPLACE INTO vvar(name,value) VALUES(%Q,%d)", zName, value); } + +/* +** Returns non-0 if the database (which must be open) table identified +** by zTableName has a column named zColName (case-sensitive), else +** returns 0. +*/ +int db_table_has_column( char const *zTableName, char const *zColName ){ + Stmt q = empty_Stmt; + int rc = 0; + db_prepare( &q, "PRAGMA table_info(%Q)", zTableName ); + while(SQLITE_ROW == db_step(&q)){ + /* Columns: (cid, name, type, notnull, dflt_value, pk) */ + char const * zCol = db_column_text(&q, 1); + if(0==fossil_strcmp(zColName, zCol)){ + rc = 1; + break; + } + } + db_finalize(&q); + return rc; +} /* ** Record the name of a local repository in the global_config() database. ** The repository filename %s is recorded as an entry with a "name" field ** of the following form: @@ -2182,55 +1931,36 @@ ** ckout:%s ** ** Where %s is the checkout 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; zName = db_repository_filename(); } file_canonical_name(zName, &full, 0); - (void)filename_collation(); /* Initialize before connection swap */ db_swap_connections(); - zRepoSetting = mprintf("repo:%q", blob_str(&full)); - db_multi_exec( - "DELETE FROM global_config WHERE name %s = %Q;", - filename_collation(), zRepoSetting - ); db_multi_exec( "INSERT OR IGNORE INTO global_config(name,value)" - "VALUES(%Q,1);", - zRepoSetting + "VALUES('repo:%q',1)", + blob_str(&full) ); - fossil_free(zRepoSetting); if( g.localOpen && g.zLocalRoot && g.zLocalRoot[0] ){ Blob localRoot; file_canonical_name(g.zLocalRoot, &localRoot, 1); - zCkoutSetting = mprintf("ckout:%q", blob_str(&localRoot)); - db_multi_exec( - "DELETE FROM global_config WHERE name %s = %Q;", - filename_collation(), zCkoutSetting - ); db_multi_exec( "REPLACE INTO global_config(name, value)" - "VALUES(%Q,%Q);", - zCkoutSetting, blob_str(&full) + "VALUES('ckout:%q','%q');", + blob_str(&localRoot), blob_str(&full) ); db_swap_connections(); - db_optional_sql("repository", - "DELETE FROM config WHERE name %s = %Q;", - filename_collation(), zCkoutSetting - ); db_optional_sql("repository", "REPLACE INTO config(name,value,mtime)" - "VALUES(%Q,1,now());", - zCkoutSetting + "VALUES('ckout:%q',1,now())", + blob_str(&localRoot) ); - fossil_free(zCkoutSetting); blob_reset(&localRoot); }else{ db_swap_connections(); } blob_reset(&full); @@ -2246,37 +1976,24 @@ ** If VERSION is specified then that version is checked out. Otherwise ** the latest version is checked out. No files other than "manifest" ** and "manifest.uuid" are modified if the --keep option is present. ** ** Options: -** --empty Initialize checkout as being empty, but still connected -** with the local repository. If you commit this checkout, -** it will become a new "initial" commit in the repository. -** --keep Only modify the manifest and manifest.uuid files -** --nested Allow opening a repository inside an opened checkout -** --force-missing Force opening a repository with missing content +** --keep Only modify the manifest and manifest.uuid files +** --nested Allow opening a repository inside an opened checkout ** ** See also: close */ void cmd_open(void){ - int emptyFlag; + int vid; int keepFlag; - int forceMissingFlag; int allowNested; - char **oldArgv; - int oldArgc; - static char *azNewArgv[] = { 0, "checkout", "--prompt", 0, 0, 0, 0 }; + static char *azNewArgv[] = { 0, "checkout", "--prompt", 0, 0, 0 }; url_proxy_options(); - emptyFlag = find_option("empty",0,0)!=0; keepFlag = find_option("keep",0,0)!=0; - forceMissingFlag = find_option("force-missing",0,0)!=0; allowNested = find_option("nested",0,0)!=0; - - /* We should be done with options.. */ - verify_all_options(); - if( g.argc!=3 && g.argc!=4 ){ usage("REPOSITORY-FILENAME ?VERSION?"); } if( !allowNested && db_open_local(0) ){ fossil_fatal("already within an open tree rooted at %s", g.zLocalRoot); @@ -2294,194 +2011,146 @@ (char*)0); db_delete_on_failure(LOCALDB_NAME); db_open_local(0); db_lset("repository", g.argv[2]); db_record_repository_filename(g.argv[2]); - db_lset_int("checkout", 0); - oldArgv = g.argv; - oldArgc = g.argc; - azNewArgv[0] = g.argv[0]; - g.argv = azNewArgv; - if( !emptyFlag ){ + vid = db_int(0, "SELECT pid FROM plink y" + " WHERE NOT EXISTS(SELECT 1 FROM plink x WHERE x.cid=y.pid)"); + if( vid==0 ){ + db_lset_int("checkout", 1); + }else{ + char **oldArgv = g.argv; + int oldArgc = g.argc; + db_lset_int("checkout", vid); + azNewArgv[0] = g.argv[0]; + g.argv = azNewArgv; g.argc = 3; if( oldArgc==4 ){ azNewArgv[g.argc-1] = oldArgv[3]; - }else if( !db_exists("SELECT 1 FROM event WHERE type='ci'") ){ - azNewArgv[g.argc-1] = "--latest"; }else{ azNewArgv[g.argc-1] = db_get("main-branch", "trunk"); } if( keepFlag ){ azNewArgv[g.argc++] = "--keep"; } - if( forceMissingFlag ){ - azNewArgv[g.argc++] = "--force-missing"; - } checkout_cmd(); + g.argc = 2; + info_cmd(); } - g.argc = 2; - info_cmd(); } /* -** Print the current value of a setting identified by the pSetting -** pointer. +** Print the value of a setting named zName */ -static void print_setting(const Setting *pSetting){ +static void print_setting( + const struct stControlSettings *ctrlSetting, + int localOpen +){ Stmt q; 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 + ctrlSetting->name, ctrlSetting->name ); }else{ db_prepare(&q, "SELECT '(global)', value FROM global_config WHERE name=%Q", - pSetting->name + ctrlSetting->name ); } if( db_step(&q)==SQLITE_ROW ){ - fossil_print("%-20s %-8s %s\n", pSetting->name, db_column_text(&q, 0), + fossil_print("%-20s %-8s %s\n", ctrlSetting->name, db_column_text(&q, 0), db_column_text(&q, 1)); }else{ - fossil_print("%-20s\n", pSetting->name); + fossil_print("%-20s\n", ctrlSetting->name); } - if( pSetting->versionable && g.localOpen ){ + if( ctrlSetting->versionable && 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); + g.zLocalRoot, ctrlSetting->name); if( file_size(blob_str(&versionedPathname))>=0 ){ fossil_print(" (overridden by contents of file .fossil-settings/%s)\n", - pSetting->name); + ctrlSetting->name); } } db_finalize(&q); } -#if INTERFACE /* -** Define all settings, which can be controlled via the set/unset -** command. -** -** var is the name of the internal configuration name for db_(un)set. +** define all settings, which can be controlled via the set/unset +** command. var is the name of the internal configuration name for db_(un)set. ** If var is 0, the settings name is used. -** ** width is the length for the edit field on the behavior page, 0 ** is used for on/off checkboxes. -** ** The behaviour page doesn't use a special layout. It lists all ** set-commands and displays the 'set'-help as info. */ -struct Setting { - const char *name; /* Name of the setting */ - const char *var; /* Internal variable name used by db_set() */ - int width; /* Width of display. 0 for boolean values. */ +#if INTERFACE +struct stControlSettings { + char const *name; /* Name of the setting */ + char const *var; /* Internal variable name used by db_set() */ + int width; /* Width of display. 0 for boolean values */ int versionable; /* Is this setting versionable? */ - int forceTextArea; /* Force using a text area for display? */ - const char *def; /* Default value */ + char const *def; /* Default value */ }; #endif /* INTERFACE */ - -const Setting aSetting[] = { - { "access-log", 0, 0, 0, 0, "off" }, - { "admin-log", 0, 0, 0, 0, "off" }, - { "allow-symlinks", 0, 0, 1, 0, "off" }, - { "auto-captcha", "autocaptcha", 0, 0, 0, "on" }, - { "auto-hyperlink", 0, 0, 0, 0, "on", }, - { "auto-shun", 0, 0, 0, 0, "on" }, - { "autosync", 0, 0, 0, 0, "on" }, - { "autosync-tries", 0, 16, 0, 0, "1" }, - { "binary-glob", 0, 40, 1, 0, "" }, -#if defined(_WIN32) || defined(__CYGWIN__) || defined(__DARWIN__) || \ - defined(__APPLE__) - { "case-sensitive", 0, 0, 0, 0, "off" }, +struct stControlSettings const ctrlSettings[] = { + { "access-log", 0, 0, 0, "off" }, + { "allow-symlinks",0, 0, 1, "off" }, + { "auto-captcha", "autocaptcha", 0, 0, "on" }, + { "auto-hyperlink",0, 0, 0, "on", }, + { "auto-shun", 0, 0, 0, "on" }, + { "autosync", 0, 0, 0, "on" }, + { "binary-glob", 0, 40, 1, "" }, + { "clearsign", 0, 0, 0, "off" }, +#if defined(_WIN32) || defined(__CYGWIN__) || defined(__DARWIN__) || defined(__APPLE__) + { "case-sensitive",0, 0, 0, "off" }, #else - { "case-sensitive", 0, 0, 0, 0, "on" }, + { "case-sensitive",0, 0, 0, "on" }, #endif - { "clean-glob", 0, 40, 1, 0, "" }, - { "clearsign", 0, 0, 0, 0, "off" }, - { "crnl-glob", 0, 40, 1, 0, "" }, - { "default-perms", 0, 16, 0, 0, "u" }, - { "diff-binary", 0, 0, 0, 0, "on" }, - { "diff-command", 0, 40, 0, 0, "" }, - { "dont-push", 0, 0, 0, 0, "off" }, - { "dotfiles", 0, 0, 1, 0, "off" }, - { "editor", 0, 32, 0, 0, "" }, - { "empty-dirs", 0, 40, 1, 0, "" }, - { "encoding-glob", 0, 40, 1, 0, "" }, - { "gdiff-command", 0, 40, 0, 0, "gdiff" }, - { "gmerge-command", 0, 40, 0, 0, "" }, - { "hash-digits", 0, 5, 0, 0, "10" }, - { "http-port", 0, 16, 0, 0, "8080" }, - { "https-login", 0, 0, 0, 0, "off" }, - { "ignore-glob", 0, 40, 1, 0, "" }, - { "keep-glob", 0, 40, 1, 0, "" }, - { "localauth", 0, 0, 0, 0, "off" }, - { "main-branch", 0, 40, 0, 0, "trunk" }, - { "manifest", 0, 0, 1, 0, "off" }, - { "max-loadavg", 0, 25, 0, 0, "0.0" }, - { "max-upload", 0, 25, 0, 0, "250000" }, - { "mtime-changes", 0, 0, 0, 0, "on" }, - { "pgp-command", 0, 40, 0, 0, "gpg --clearsign -o " }, - { "proxy", 0, 32, 0, 0, "off" }, - { "relative-paths", 0, 0, 0, 0, "on" }, - { "repo-cksum", 0, 0, 0, 0, "on" }, - { "self-register", 0, 0, 0, 0, "off" }, - { "ssh-command", 0, 40, 0, 0, "" }, - { "ssl-ca-location", 0, 40, 0, 0, "" }, - { "ssl-identity", 0, 40, 0, 0, "" }, + { "clean-glob", 0, 40, 1, "" }, + { "crnl-glob", 0, 40, 1, "" }, + { "default-perms", 0, 16, 0, "u" }, + { "diff-binary", 0, 0, 0, "on" }, + { "diff-command", 0, 40, 0, "" }, + { "dont-push", 0, 0, 0, "off" }, + { "editor", 0, 32, 0, "" }, + { "empty-dirs", 0, 40, 1, "" }, + { "encoding-glob", 0, 40, 1, "" }, + { "gdiff-command", 0, 40, 0, "gdiff" }, + { "gmerge-command",0, 40, 0, "" }, + { "http-port", 0, 16, 0, "8080" }, + { "https-login", 0, 0, 0, "off" }, + { "ignore-glob", 0, 40, 1, "" }, + { "keep-glob", 0, 40, 1, "" }, + { "localauth", 0, 0, 0, "off" }, + { "main-branch", 0, 40, 0, "trunk" }, + { "manifest", 0, 0, 1, "off" }, + { "max-upload", 0, 25, 0, "250000" }, + { "mtime-changes", 0, 0, 0, "on" }, + { "pgp-command", 0, 40, 0, "gpg --clearsign -o " }, + { "proxy", 0, 32, 0, "off" }, + { "relative-paths",0, 0, 0, "on" }, + { "repo-cksum", 0, 0, 0, "on" }, + { "self-register", 0, 0, 0, "off" }, + { "ssh-command", 0, 40, 0, "" }, + { "ssl-ca-location",0, 40, 0, "" }, + { "ssl-identity", 0, 40, 0, "" }, #ifdef FOSSIL_ENABLE_TCL - { "tcl", 0, 0, 0, 0, "off" }, - { "tcl-setup", 0, 40, 1, 1, "" }, -#endif -#ifdef FOSSIL_ENABLE_TH1_DOCS - { "th1-docs", 0, 0, 0, 0, "off" }, -#endif -#ifdef FOSSIL_ENABLE_TH1_HOOKS - { "th1-hooks", 0, 0, 0, 0, "off" }, -#endif - { "th1-setup", 0, 40, 1, 1, "" }, - { "th1-uri-regexp", 0, 40, 1, 0, "" }, - { "web-browser", 0, 32, 0, 0, "" }, - { 0,0,0,0,0,0 } -}; - -/* -** Look up a control setting by its name. Return a pointer to the Setting -** object, or NULL if there is no such setting. -** -** If allowPrefix is true, then the Setting returned is the first one for -** which zName is a prefix of the Setting name. -*/ -const Setting *db_find_setting(const char *zName, int allowPrefix){ - int lwr, mid, upr, c; - int n = (int)strlen(zName) + !allowPrefix; - lwr = 0; - upr = ArraySize(aSetting)-2; - while( upr>=lwr ){ - mid = (upr+lwr)/2; - c = fossil_strncmp(zName, aSetting[mid].name, n); - if( c<0 ){ - upr = mid - 1; - }else if( c>0 ){ - lwr = mid + 1; - }else{ - if( allowPrefix ){ - while( mid>lwr && fossil_strncmp(zName, aSetting[mid-1].name, n)==0 ){ - mid--; - } - } - return &aSetting[mid]; - } - } - return 0; -} + { "tcl", 0, 0, 0, "off" }, + { "tcl-setup", 0, 40, 0, "" }, +#endif + { "th1-setup", 0, 40, 0, "" }, + { "web-browser", 0, 32, 0, "" }, + { "white-foreground", 0, 0, 0, "off" }, + { 0,0,0,0,0 } +}; /* ** COMMAND: settings ** COMMAND: unset* ** @@ -2500,13 +2169,10 @@ ** ** ** access-log If enabled, record successful and failed login attempts ** in the "accesslog" table. Default: off ** -** admin-log If enabled, record configuration changes in the -** "admin_log" table. Default: off -** ** allow-symlinks If enabled, don't follow symlinks, and instead treat ** (versionable) them as symlinks on Unix. Has no effect on Windows ** (existing links in repository created on Unix become ** plain-text files with link destination path inside). ** Default: off @@ -2527,15 +2193,10 @@ ** or update and automatically push after commit or ** tag or branch creation. If the value is "pullonly" ** then only pull operations occur automatically. ** Default: on ** -** autosync-tries If autosync is enabled setting this to a value greater -** than zero will cause autosync to try no more than this -** number of attempts if there is a sync failure. -** Default: 1 -** ** binary-glob The VALUE is a comma or newline-separated list of ** (versionable) GLOB patterns that should be treated as binary files ** for committing and merging purposes. Example: *.jpg ** ** case-sensitive If TRUE, the files whose names differ only in case @@ -2568,13 +2229,10 @@ ** If undefined, the internal text diff will be used. ** ** dont-push Prevent this repository from pushing from client to ** server. Useful when setting up a private branch. ** -** dotfiles Include --dotfiles option for all compatible commands. -** (versionable) -** ** editor Text editor command used for check-in comments. ** ** empty-dirs A comma or newline-separated list of pathnames. On ** (versionable) update and checkout commands, if no file or directory ** exists with that name, an empty directory will be @@ -2593,13 +2251,10 @@ ** on four files. ** Ex: kdiff3 "%baseline" "%original" "%merge" -o "%output" ** Ex: xxdiff "%original" "%baseline" "%merge" -M "%output" ** Ex: meld "%baseline" "%original" "%merge" "%output" ** -** hash-digits The number of hexadecimal digits of the SHA1 hash to -** display. (Default: 10; Minimum: 6) -** ** http-port The TCP/IP port number to use by the "server" ** and "ui" commands. Default: 8080 ** ** https-login Send login credentials using HTTPS instead of HTTP ** even if the login page request came via HTTP. @@ -2622,17 +2277,10 @@ ** ** manifest If enabled, automatically create files "manifest" and ** (versionable) "manifest.uuid" in every checkout. The SQLite and ** Fossil repositories both require this. Default: off. ** -** max-loadavg Some CPU-intensive web pages (ex: /zip, /tarball, /blame) -** are disallowed if the system load average goes above this -** value. "0.0" means no limit. This only works on unix. -** Only local settings of this value make a difference since -** when running as a web-server, Fossil does not open the -** global configuration database. -** ** max-upload A limit on the size of uplink HTTP requests. The ** default is 250000 bytes. ** ** mtime-changes Use file modification times (mtimes) to detect when ** files have been modified. (Default "on".) @@ -2685,34 +2333,16 @@ ** scripts to be evaluated from TH1. Additionally, the Tcl ** interpreter will be able to evaluate arbitrary TH1 ** expressions and scripts. Default: off. ** ** tcl-setup This is the setup script to be evaluated after creating -** (versionable) and initializing the Tcl interpreter. By default, this -** is empty and no extra setup is performed. -** -** th1-docs WARNING: If enabled (and Fossil was compiled with TH1 -** support for embedded documentation files), this allows -** embedded documentation files to contain arbitrary TH1 -** scripts that are evaluated on the server. If native -** Tcl integration is also enabled, this setting has the -** potential to allow anybody with check-in privileges to -** do almost anything that the associated operating system -** user account could do. Extreme caution should be used -** when enabling this setting. Default: off. -** -** th1-hooks If enabled (and Fossil was compiled with support for TH1 -** hooks), special TH1 commands will be called before and -** after any Fossil command or web page. Default: off. -** -** th1-setup This is the setup script to be evaluated after creating -** (versionable) and initializing the TH1 interpreter. By default, this -** is empty and no extra setup is performed. -** -** th1-uri-regexp Specify which URI's are allowed in HTTP requests from -** (versionable) TH1 scripts. If empty, no HTTP requests are allowed -** whatsoever. The default is an empty string. +** and initializing the Tcl interpreter. By default, this +** is empty and no extra setup is performed. +** +** th1-setup This is the setup script to be evaluated after creating +** and initializing the TH1 interpreter. By default, this +** is empty and no extra setup is performed. ** ** web-browser A shell command used to launch your preferred ** web browser when given a URL as an argument. ** Defaults to "start" on windows, "open" on Mac, ** and "firefox" on Unix. @@ -2735,66 +2365,39 @@ globalFlag = 1; } if( unsetFlag && g.argc!=3 ){ usage("PROPERTY ?-global?"); } - - /* Verify that the aSetting[] entries are in sorted order. This is - ** necessary for the binary search in db_find_setting() to work correctly. - */ - for(i=1; aSetting[i].name; i++){ - if( fossil_strcmp(aSetting[i-1].name, aSetting[i].name)>=0 ){ - fossil_panic("Internal Error: aSetting[] entries for \"%s\"" - " and \"%s\" are out of order.", - aSetting[i-1].name, aSetting[i].name); - } - } - if( g.argc==2 ){ - for(i=0; aSetting[i].name; i++){ - print_setting(&aSetting[i]); + int openLocal = db_open_local(0); + for(i=0; ctrlSettings[i].name; i++){ + print_setting(&ctrlSettings[i], openLocal); } }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, 1); - 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!=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); - } - fossil_fatal("ambiguous setting \"%s\" - might be:%s", - zName, blob_str(&x)); - } - if( globalFlag && isManifest ){ - fossil_fatal("cannot set 'manifest' globally"); - } - if( unsetFlag ){ - db_unset(pSetting->name, globalFlag); - }else{ - db_set(pSetting->name, g.argv[3], globalFlag); - } - if( isManifest && g.localOpen ){ - manifest_to_disk(db_lget_int("checkout", 0)); - } - }else{ - while( pSetting->name && fossil_strncmp(pSetting->name,zName,n)==0 ){ - print_setting(pSetting); - pSetting++; - } + int isManifest; + int n = strlen(zName); + for(i=0; ctrlSettings[i].name; i++){ + if( strncmp(ctrlSettings[i].name, zName, n)==0 ) break; + } + if( !ctrlSettings[i].name ){ + fossil_fatal("no such setting: %s", zName); + } + isManifest = fossil_strcmp(ctrlSettings[i].name, "manifest")==0; + if( isManifest && globalFlag ){ + fossil_fatal("cannot set 'manifest' globally"); + } + if( unsetFlag ){ + db_unset(ctrlSettings[i].name, globalFlag); + }else if( g.argc==4 ){ + db_set(ctrlSettings[i].name, g.argv[3], globalFlag); + }else{ + isManifest = 0; + print_setting(&ctrlSettings[i], db_open_local(0)); + } + if( isManifest && g.localOpen ){ + manifest_to_disk(db_lget_int("checkout", 0)); } }else{ usage("?PROPERTY? ?VALUE? ?-global?"); } } @@ -2839,113 +2442,5 @@ rDiff = db_double(0.0, "SELECT julianday('now') - julianday(%Q)", g.argv[2]); fossil_print("Time differences: %s\n", db_timespan_name(rDiff)); sqlite3_close(g.db); g.db = 0; } - -/* -** COMMAND: test-without-rowid -** %fossil test-without-rowid FILENAME... -** -** Change the Fossil repository FILENAME to make use of the WITHOUT ROWID -** optimization. FILENAME can also be the ~/.fossil file 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: -** --dryrun | -n 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++){ - db_open_or_attach(g.argv[i], "main", 0); - blob_init(&allSql, "BEGIN;\n", -1); - db_prepare(&q, - "SELECT name, sql FROM main.sqlite_master " - " WHERE type='table' AND sql NOT LIKE '%%WITHOUT ROWID%%'" - " AND name IN ('global_config','shun','concealed','config'," - " 'plink','tagxref','backlink','vcache');" - ); - while( db_step(&q)==SQLITE_ROW ){ - const char *zTName = db_column_text(&q, 0); - const char *zOrigSql = db_column_text(&q, 1); - Blob newSql; - blob_init(&newSql, 0, 0); - for(j=0; zOrigSql[j]; j++){ - if( fossil_strnicmp(zOrigSql+j,"unique",6)==0 ){ - blob_append(&newSql, zOrigSql, j); - blob_append(&newSql, "PRIMARY KEY", -1); - zOrigSql += j+6; - j = -1; - } - } - blob_append(&newSql, zOrigSql, -1); - blob_append_sql(&allSql, - "ALTER TABLE \"%w\" RENAME TO \"x_%w\";\n" - "%s WITHOUT ROWID;\n" - "INSERT INTO \"%w\" SELECT * FROM \"x_%w\";\n" - "DROP TABLE \"x_%w\";\n", - zTName, zTName, blob_sql_text(&newSql), zTName, zTName, zTName - ); - fossil_print("Converting table %s of %s to WITHOUT ROWID.\n", - zTName, g.argv[i]); - blob_reset(&newSql); - } - blob_append_sql(&allSql, "COMMIT;\n"); - db_finalize(&q); - if( dryRun ){ - fossil_print("SQL that would have been evaluated:\n"); - fossil_print("%.78c\n", '-'); - fossil_print("%s", blob_sql_text(&allSql)); - }else{ - db_multi_exec("%s", blob_sql_text(&allSql)); - } - blob_reset(&allSql); - db_close(1); - } -} - -/* -** 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; - once = 1; - db_multi_exec( - "CREATE TABLE IF NOT EXISTS \"%w\".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" - ")", db_name("repository") - ); -} - -/* -** 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, ...){ - Blob what = empty_blob; - va_list ap; - if( !db_get_boolean("admin-log", 0) ){ - /* Potential leak here (on %z params) but - the alternative is to let blob_vappendf() - do it below. */ - return; - } - create_admin_log_table(); - va_start(ap,zFormat); - blob_vappendf( &what, zFormat, ap ); - va_end(ap); - db_multi_exec("INSERT INTO admin_log(time,page,who,what)" - " VALUES(now(), %Q, %Q, %B)", - g.zPath, g.zLogin, &what); - blob_reset(&what); -} Index: src/delta.c ================================================================== --- src/delta.c +++ src/delta.c @@ -20,11 +20,10 @@ ** Though developed specifically for fossil, the code in this file ** is generally applicable and is thus easily separated from the ** fossil source code base. Nothing in this file depends on anything ** else in fossil. */ -#include "config.h" #include <stdio.h> #include <assert.h> #include <stdlib.h> #include <string.h> #include "delta.h" @@ -65,11 +64,11 @@ ** The "u32" type must be an unsigned 32-bit integer. Adjust this */ typedef unsigned int u32; /* -** Must be a 16-bit value +** Must be a 16-bit value */ typedef short int s16; typedef unsigned short int u16; #endif /* INTERFACE */ @@ -82,11 +81,11 @@ /* ** The current state of the rolling hash. ** ** z[] holds the values that have been hashed. z[] is a circular buffer. -** z[i] is the first entry and z[(i+NHASH-1)%NHASH] is the last entry of +** z[i] is the first entry and z[(i+NHASH-1)%NHASH] is the last entry of ** the window. ** ** Hash.a is the sum of all elements of hash.z[]. Hash.b is a weighted ** sum. Hash.b is z[i]*NHASH + z[i+1]*(NHASH-1) + ... + z[i+NHASH-1]*1. ** (Each index for z[] should be module NHASH, of course. The %NHASH operator @@ -135,11 +134,11 @@ /* ** Write an base-64 integer into the given buffer. */ static void putInt(unsigned int v, char **pz){ - static const char zDigits[] = + static const char zDigits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz~"; /* 123456789 123456789 123456789 123456789 123456789 123456789 123 */ int i, j; char zBuf[20]; if( v==0 ){ @@ -229,11 +228,11 @@ } /* ** Create a new delta. ** -** The delta is written into a preallocated buffer, zDelta, which +** The delta is written into a preallocated buffer, zDelta, which ** should be at least 60 bytes longer than the target file, zOut. ** The delta string will be NUL-terminated, but it might also contain ** embedded NUL characters if either the zSrc or zOut files are ** binary. This function returns the length of the delta string ** in bytes, excluding the final NUL terminator character. @@ -245,11 +244,11 @@ ** delta file z, a program can compute the size of the output file ** simply by reading the first line and decoding the base-64 number ** found there. The delta_output_size() routine does exactly this. ** ** After the initial size number, the delta consists of a series of -** literal text segments and commands to copy from the SOURCE file. +** literal text segments and commands to copy from the SOURCE file. ** A copy command looks like this: ** ** NNN@MMM, ** ** where NNN is the number of bytes to be copied and MMM is the offset @@ -283,11 +282,11 @@ ** search for a matching section in the source file. When a match ** is found, a copy command is added to the delta. An effort is ** made to extend the matching section to regions that come before ** and after the 16-byte hash window. A copy command is only issued ** if the result would use less space that just quoting the text -** literally. Literal text is added to the delta for sections that +** literally. Literal text is added to the delta for sections that ** do not match or which can not be encoded efficiently using copy ** commands. */ int delta_create( const char *zSrc, /* The source or pattern file */ @@ -356,13 +355,13 @@ hv = hash_32bit(&h) % nHash; DEBUG2( printf("LOOKING: %4d [%s]\n", base+i, print16(&zOut[base+i])); ) iBlock = landmark[hv]; while( iBlock>=0 && (limit--)>0 ){ /* - ** The hash window has identified a potential match against + ** The hash window has identified a potential match against ** landmark block iBlock. But we need to investigate further. - ** + ** ** Look for a region in zOut that matches zSrc. Anchor the search ** at zSrc[iSrc] and zOut[base+i]. Do not include anything prior to ** zOut[base] or after zOut[outLen] nor anything after zSrc[srcLen]. ** ** Set cnt equal to the length of the match and set ofst so that @@ -467,17 +466,17 @@ zDelta += lenOut-base; } /* Output the final checksum record. */ putInt(checksum(zOut, lenOut), &zDelta); *(zDelta++) = ';'; - fossil_free(collide); - return zDelta - zOrigDelta; + free(collide); + return zDelta - zOrigDelta; } /* ** Return the size (in bytes) of the output from applying -** a delta. +** a delta. ** ** This routine is provided so that an procedure that is able ** to call delta_apply() can learn how much space is required ** for the output and hence allocate nor more space that is really ** needed. Index: src/deltacmd.c ================================================================== --- src/deltacmd.c +++ src/deltacmd.c @@ -17,11 +17,11 @@ ** ** This module implements the interface to the delta generator. */ #include "config.h" #include "deltacmd.h" - + /* ** Create a delta that describes the change from pOriginal to pTarget ** and put that delta in pDelta. The pDelta blob is assumed to be ** uninitialized. */ Index: src/descendants.c ================================================================== --- src/descendants.c +++ src/descendants.c @@ -30,11 +30,11 @@ ** check-in iBase. ** ** A "leaf" is a check-in that has no children in the same branch. ** There is a separate permanent table LEAF that contains all leaves ** in the tree. This routine is used to compute a subset of that -** table consisting of leaves that are descended from a single check-in. +** table consisting of leaves that are descended from a single checkin. ** ** The closeMode flag determines behavior associated with the "closed" ** tag: ** ** closeMode==0 Show all leaves regardless of the "closed" tag. @@ -130,15 +130,10 @@ db_finalize(&ins); db_finalize(&isBr); db_finalize(&q1); bag_clear(&pending); bag_clear(&seen); - }else{ - db_multi_exec( - "INSERT INTO leaves" - " SELECT leaf.rid FROM leaf" - ); } if( closeMode==1 ){ db_multi_exec( "DELETE FROM leaves WHERE rid IN" " (SELECT leaves.rid FROM leaves, tagxref" @@ -162,25 +157,42 @@ /* ** Load the record ID rid and up to N-1 closest ancestors into ** the "ok" table. */ void compute_ancestors(int rid, int N, int directOnly){ - db_multi_exec( - "WITH RECURSIVE " - " ancestor(rid, mtime) AS (" - " SELECT %d, mtime FROM event WHERE objid=%d " - " UNION " - " SELECT plink.pid, event.mtime" - " FROM ancestor, plink, event" - " WHERE plink.cid=ancestor.rid" - " AND event.objid=plink.pid %s" - " ORDER BY mtime DESC LIMIT %d" - " )" - "INSERT INTO ok" - " SELECT rid FROM ancestor;", - rid, rid, directOnly ? "AND plink.isPrim" : "", N + Bag seen; + PQueue queue; + Stmt ins; + Stmt q; + bag_init(&seen); + pqueuex_init(&queue); + bag_insert(&seen, rid); + pqueuex_insert(&queue, rid, 0.0, 0); + db_prepare(&ins, "INSERT OR IGNORE INTO ok VALUES(:rid)"); + db_prepare(&q, + "SELECT a.pid, b.mtime FROM plink a LEFT JOIN plink b ON b.cid=a.pid" + " WHERE a.cid=:rid %s", + directOnly ? " AND a.isprim" : "" ); + while( (N--)>0 && (rid = pqueuex_extract(&queue, 0))!=0 ){ + db_bind_int(&ins, ":rid", rid); + db_step(&ins); + db_reset(&ins); + db_bind_int(&q, ":rid", rid); + while( db_step(&q)==SQLITE_ROW ){ + int pid = db_column_int(&q, 0); + double mtime = db_column_double(&q, 1); + if( bag_insert(&seen, pid) ){ + pqueuex_insert(&queue, pid, -mtime, 0); + } + } + db_reset(&q); + } + bag_clear(&seen); + pqueuex_clear(&queue); + db_finalize(&ins); + db_finalize(&q); } /* ** Compute up to N direct ancestors (merge ancestors do not count) ** for the check-in rid and put them in a table named "ancestor". @@ -289,42 +301,25 @@ } /* ** COMMAND: descendants* ** -** Usage: %fossil descendants ?CHECKIN? ?OPTIONS? +** Usage: %fossil descendants ?BASELINE-ID? ?OPTIONS? ** -** Find all leaf descendants of the check-in specified or if the argument -** is omitted, of the check-in currently checked out. +** Find all leaf descendants of the baseline specified or if the argument +** is omitted, of the baseline currently checked out. ** ** Options: ** -R|--repository FILE Extract info from repository FILE -** -W|--width <num> Width of lines (default is to auto-detect). -** Must be >20 or 0 (= no limit, resulting in a -** single line per entry). ** ** See also: finfo, info, leaves */ void descendants_cmd(void){ Stmt q; - int base, width; - const char *zWidth; + int base; db_find_and_open_repository(0,0); - zWidth = find_option("width","W",1); - if( zWidth ){ - width = atoi(zWidth); - if( (width!=0) && (width<=20) ){ - fossil_fatal("-W|--width value must be >20 or 0"); - } - }else{ - width = -1; - } - - /* We should be done with options.. */ - verify_all_options(); - if( g.argc==2 ){ base = db_lget_int("checkout", 0); }else{ base = name_to_typed_rid(g.argv[2], "ci"); } @@ -334,11 +329,11 @@ "%s" " AND event.objid IN (SELECT rid FROM leaves)" " ORDER BY event.mtime DESC", timeline_query_for_tty() ); - print_timeline(&q, 0, width, 0); + print_timeline(&q, 20, 0); db_finalize(&q); } /* ** COMMAND: leaves* @@ -351,17 +346,14 @@ ** ** The --recompute flag causes the content of the "leaf" table in the ** repository database to be recomputed. ** ** Options: -** -a|--all show ALL leaves -** -c|--closed show only closed leaves -** --bybranch order output by branch name -** --recompute recompute the "leaf" table in the repository DB -** -W|--width <num> Width of lines (default is to auto-detect). Must be -** >39 or 0 (= no limit, resulting in a single line per -** entry). +** -a|--all show ALL leaves +** -c|--closed show only closed leaves +** --bybranch order output by branch name +** --recompute recompute the "leaf" table in the repository DB ** ** See also: descendants, finfo, info, branch */ void leaves_cmd(void){ Stmt q; @@ -368,43 +360,30 @@ Blob sql; int showAll = find_option("all", "a", 0)!=0; int showClosed = find_option("closed", "c", 0)!=0; int recomputeFlag = find_option("recompute",0,0)!=0; int byBranch = find_option("bybranch",0,0)!=0; - const char *zWidth = find_option("width","W",1); char *zLastBr = 0; - int n, width; + int n; char zLineNo[10]; - if( zWidth ){ - width = atoi(zWidth); - if( (width!=0) && (width<=39) ){ - fossil_fatal("-W|--width value must be >39 or 0"); - } - }else{ - width = -1; - } db_find_and_open_repository(0,0); - - /* We should be done with options.. */ - verify_all_options(); - if( recomputeFlag ) leaf_rebuild(); blob_zero(&sql); blob_append(&sql, timeline_query_for_tty(), -1); - blob_append_sql(&sql, " AND blob.rid IN leaf"); + blob_appendf(&sql, " AND blob.rid IN leaf"); if( showClosed ){ - blob_append_sql(&sql," AND %z", leaf_is_closed_sql("blob.rid")); + blob_appendf(&sql," AND %z", leaf_is_closed_sql("blob.rid")); }else if( !showAll ){ - blob_append_sql(&sql," AND NOT %z", leaf_is_closed_sql("blob.rid")); + blob_appendf(&sql," AND NOT %z", leaf_is_closed_sql("blob.rid")); } if( byBranch ){ db_prepare(&q, "%s ORDER BY nullif(branch,'trunk') COLLATE nocase," " event.mtime DESC", - blob_sql_text(&sql)); + blob_str(&sql)); }else{ - db_prepare(&q, "%s ORDER BY event.mtime DESC", blob_sql_text(&sql)); + db_prepare(&q, "%s ORDER BY event.mtime DESC", blob_str(&sql)); } blob_reset(&sql); n = 0; while( db_step(&q)==SQLITE_ROW ){ const char *zId = db_column_text(&q, 1); @@ -419,12 +398,12 @@ zLastBr = fossil_strdup(zBr); } n++; sqlite3_snprintf(sizeof(zLineNo), zLineNo, "(%d)", n); fossil_print("%6s ", zLineNo); - z = mprintf("%s [%S] %s", zDate, zId, zCom); - comment_print(z, zCom, 7, width, g.comFmtFlags); + z = mprintf("%s [%.10s] %s", zDate, zId, zCom); + comment_print(z, 7, 79); fossil_free(z); } fossil_free(zLastBr); db_finalize(&q); } @@ -439,11 +418,11 @@ Stmt q; int showAll = P("all")!=0; int showClosed = P("closed")!=0; login_check_credentials(); - if( !g.perm.Read ){ login_needed(g.anon.Read); return; } + if( !g.perm.Read ){ login_needed(); return; } if( !showAll ){ style_submenu_element("All", "All", "leaves?all"); } if( !showClosed ){ @@ -452,11 +431,10 @@ if( showClosed || showAll ){ style_submenu_element("Open", "Open", "leaves"); } style_header("Leaves"); login_anonymous_available(); -#if 0 style_sidebox_begin("Nomenclature:", "33%"); @ <ol> @ <li> A <div class="sideboxDescribed">leaf</div> @ is a check-in with no descendants in the same branch.</li> @ <li> An <div class="sideboxDescribed">open leaf</div> @@ -465,11 +443,10 @@ @ <li> A <div class="sideboxDescribed">closed leaf</div> @ has a "closed" tag and is thus assumed to @ be historical and no longer in active use.</li> @ </ol> style_sidebox_end(); -#endif if( showAll ){ @ <h1>All leaves, both open and closed:</h1> }else if( showClosed ){ @ <h1>Closed leaves:</h1> @@ -476,21 +453,27 @@ }else{ @ <h1>Open leaves:</h1> } blob_zero(&sql); blob_append(&sql, timeline_query_for_www(), -1); - blob_append_sql(&sql, " AND blob.rid IN leaf"); + blob_appendf(&sql, " AND blob.rid IN leaf"); if( showClosed ){ - blob_append_sql(&sql," AND %z", leaf_is_closed_sql("blob.rid")); + blob_appendf(&sql," AND %z", leaf_is_closed_sql("blob.rid")); }else if( !showAll ){ - blob_append_sql(&sql," AND NOT %z", leaf_is_closed_sql("blob.rid")); + blob_appendf(&sql," AND NOT %z", leaf_is_closed_sql("blob.rid")); } - db_prepare(&q, "%s ORDER BY event.mtime DESC", blob_sql_text(&sql)); + db_prepare(&q, "%s ORDER BY event.mtime DESC", blob_str(&sql)); blob_reset(&sql); - www_print_timeline(&q, TIMELINE_LEAFONLY, 0, 0, 0, 0); + www_print_timeline(&q, TIMELINE_LEAFONLY, 0, 0, 0); db_finalize(&q); @ <br /> + @ <script type="text/JavaScript"> + @ function xin(id){ + @ } + @ function xout(id){ + @ } + @ </script> style_footer(); } #if INTERFACE /* Flag parameters to compute_uses_file() */ @@ -510,11 +493,11 @@ Stmt q; int rid; bag_init(&seen); bag_init(&pending); - db_prepare(&ins, "INSERT OR IGNORE INTO \"%w\" VALUES(:rid)", zTab); + db_prepare(&ins, "INSERT OR IGNORE INTO \"%s\" VALUES(:rid)", zTab); db_prepare(&q, "SELECT mid FROM mlink WHERE fid=%d", fid); while( db_step(&q)==SQLITE_ROW ){ int mid = db_column_int(&q, 0); bag_insert(&pending, mid); bag_insert(&seen, mid); @@ -533,11 +516,11 @@ db_step(&ins); db_reset(&ins); } } db_finalize(&q); - db_prepare(&q, "SELECT cid FROM plink WHERE pid=:rid AND isprim"); + db_prepare(&q, "SELECT cid FROM plink WHERE pid=:rid"); while( (rid = bag_first(&pending))!=0 ){ bag_remove(&pending, rid); db_bind_int(&q, ":rid", rid); while( db_step(&q)==SQLITE_ROW ){ Index: src/diff.c ================================================================== --- src/diff.c +++ src/diff.c @@ -29,21 +29,21 @@ ** of the diff output. */ #define DIFF_CONTEXT_MASK ((u64)0x0000ffff) /* Lines of context. Default if 0 */ #define DIFF_WIDTH_MASK ((u64)0x00ff0000) /* side-by-side column width */ #define DIFF_IGNORE_EOLWS ((u64)0x01000000) /* Ignore end-of-line whitespace */ -#define DIFF_IGNORE_ALLWS ((u64)0x03000000) /* Ignore all whitespace */ -#define DIFF_SIDEBYSIDE ((u64)0x04000000) /* Generate a side-by-side diff */ -#define DIFF_VERBOSE ((u64)0x08000000) /* Missing shown as empty files */ -#define DIFF_BRIEF ((u64)0x10000000) /* Show filenames only */ -#define DIFF_HTML ((u64)0x20000000) /* Render for HTML */ -#define DIFF_LINENO ((u64)0x40000000) /* Show line numbers */ +#define DIFF_SIDEBYSIDE ((u64)0x02000000) /* Generate a side-by-side diff */ +#define DIFF_VERBOSE ((u64)0x04000000) /* Missing shown as empty files */ +#define DIFF_BRIEF ((u64)0x08000000) /* Show filenames only */ +#define DIFF_INLINE ((u64)0x00000000) /* Inline (not side-by-side) diff */ +#define DIFF_HTML ((u64)0x10000000) /* Render for HTML */ +#define DIFF_LINENO ((u64)0x20000000) /* Show line numbers */ +#define DIFF_WS_WARNING ((u64)0x40000000) /* Warn about whitespace */ #define DIFF_NOOPT (((u64)0x01)<<32) /* Suppress optimizations (debug) */ #define DIFF_INVERT (((u64)0x02)<<32) /* Invert the diff (debug) */ #define DIFF_CONTEXT_EX (((u64)0x04)<<32) /* Use context even if zero */ #define DIFF_NOTTOOBIG (((u64)0x08)<<32) /* Only display if not too big */ -#define DIFF_STRIP_EOLCR (((u64)0x10)<<32) /* Strip trailing CR */ /* ** These error messages are shared in multiple locations. They are defined ** here for consistency. */ @@ -54,13 +54,10 @@ "cannot compute difference between symlink and regular file\n" #define DIFF_TOO_MANY_CHANGES \ "more than 10,000 changes\n" -#define DIFF_WHITESPACE_ONLY \ - "whitespace changes only\n" - /* ** Maximum length of a line in a text file, in bytes. (2**13 = 8192 bytes) */ #define LENGTH_MASK_SZ 13 #define LENGTH_MASK ((1<<LENGTH_MASK_SZ)-1) @@ -76,12 +73,10 @@ */ typedef struct DLine DLine; struct DLine { const char *z; /* The text of the line */ unsigned int h; /* Hash of the line */ - unsigned short indent; /* Indent of the line. Only !=0 with -w/-Z option */ - unsigned short n; /* number of bytes */ unsigned int iNext; /* 1+(Index of next line with same the same hash) */ /* an array of DLine elements serves two purposes. The fields ** above are one per line of input text. But each entry is also ** a bucket in a hash table, as follows: */ @@ -89,11 +84,11 @@ }; /* ** Length of a dline */ -#define LENGTH(X) ((X)->n) +#define LENGTH(X) ((X)->h & LENGTH_MASK) /* ** A context for running a raw diff. ** ** The aEdit[] array describes the raw diff. Each triple of integers in @@ -113,11 +108,10 @@ int nEditAlloc; /* Space allocated for aEdit[] */ DLine *aFrom; /* File on left side of the diff */ int nFrom; /* Number of lines in aFrom[] */ DLine *aTo; /* File on right side of the diff */ int nTo; /* Number of lines in aTo[] */ - int (*same_fn)(const DLine *, const DLine *); /* Function to be used for comparing */ }; /* ** Return an array of DLine objects containing a pointer to the ** start of each line and a hash of that line. The lower @@ -131,12 +125,12 @@ ** too long. ** ** Profiling show that in most cases this routine consumes the bulk of ** the CPU time on a diff. */ -static DLine *break_into_lines(const char *z, int n, int *pnLine, u64 diffFlags){ - int nLine, i, j, k, s, x; +static DLine *break_into_lines(const char *z, int n, int *pnLine, int ignoreWS){ + int nLine, i, j, k, x; unsigned int h, h2; DLine *a; /* Count the number of lines. Allocate space to hold ** the returned array. @@ -164,39 +158,18 @@ return a; } /* Fill in the array */ for(i=0; i<nLine; i++){ - for(j=0; z[j] && z[j]!='\n'; j++){} a[i].z = z; + for(j=0; z[j] && z[j]!='\n'; j++){} k = j; - if( diffFlags & DIFF_STRIP_EOLCR ){ - if( k>0 && z[k-1]=='\r' ){ k--; } - } - a[i].n = k; - s = 0; - if( diffFlags & DIFF_IGNORE_EOLWS ){ - while( k>0 && fossil_isspace(z[k-1]) ){ k--; } - } - if( (diffFlags & DIFF_IGNORE_ALLWS)==DIFF_IGNORE_ALLWS ){ - int numws = 0; - while( s<k && fossil_isspace(z[s]) ){ s++; } - for(h=0, x=s; x<k; x++){ - if( fossil_isspace(z[x]) ){ - ++numws; - }else{ - h = h ^ (h<<2) ^ z[x]; - } - } - k -= numws; - }else{ - for(h=0, x=s; x<k; x++){ - h = h ^ (h<<2) ^ z[x]; - } - } - a[i].indent = s; - a[i].h = h = (h<<LENGTH_MASK_SZ) | (k-s); + while( ignoreWS && k>0 && fossil_isspace(z[k-1]) ){ k--; } + for(h=0, x=0; x<=k; x++){ + h = h ^ (h<<2) ^ z[x]; + } + a[i].h = h = (h<<LENGTH_MASK_SZ) | k;; h2 = h % nLine; a[i].iNext = a[h2].iHash; a[h2].iHash = i+1; z += j+1; } @@ -207,31 +180,12 @@ } /* ** Return true if two DLine elements are identical. */ -static int same_dline(const DLine *pA, const DLine *pB){ - return pA->h==pB->h && memcmp(pA->z,pB->z, pA->h&LENGTH_MASK)==0; -} - -/* -** Return true if two DLine elements are identical, ignoring -** all whitespace. The indent field of pA/pB already points -** to the first non-space character in the string. -*/ - -static int same_dline_ignore_allws(const DLine *pA, const DLine *pB){ - int a = pA->indent, b = pB->indent; - if( pA->h==pB->h ){ - while( a<pA->n || b<pB->n ){ - if( a<pA->n && b<pB->n && pA->z[a++] != pB->z[b++] ) return 0; - while( a<pA->n && fossil_isspace(pA->z[a])) ++a; - while( b<pB->n && fossil_isspace(pB->z[b])) ++b; - } - return pA->n-a == pB->n-b; - } - return 0; +static int same_dline(DLine *pA, DLine *pB){ + return pA->h==pB->h && memcmp(pA->z,pB->z,pA->h & LENGTH_MASK)==0; } /* ** Return true if the regular expression *pRe matches any of the ** N dlines @@ -267,16 +221,16 @@ }else if( cPrefix=='+' ){ blob_append(pOut, "<span class=\"diffadd\">", -1); }else if( cPrefix=='-' ){ blob_append(pOut, "<span class=\"diffrm\">", -1); } - htmlize_to_blob(pOut, pLine->z, pLine->n); + htmlize_to_blob(pOut, pLine->z, (pLine->h & LENGTH_MASK)); if( cPrefix!=' ' ){ blob_append(pOut, "</span>", -1); } }else{ - blob_append(pOut, pLine->z, pLine->n); + blob_append(pOut, pLine->z, pLine->h & LENGTH_MASK); } blob_append(pOut, "\n", 1); } /* @@ -448,11 +402,11 @@ b += m; if( i<nr-1 ){ m = R[r+i*3+3]; for(j=0; j<m; j++){ if( showLn ) appendDiffLineno(pOut, a+j+1, b+j+1, html); - appendDiffLine(pOut, ' ', &A[a+j], html, 0); + appendDiffLine(pOut, ' ', &B[b+j], html, 0); } b += m; a += m; } } @@ -461,11 +415,11 @@ assert( nr==i ); m = R[r+nr*3]; if( m>nContext ) m = nContext; for(j=0; j<m; j++){ if( showLn ) appendDiffLineno(pOut, a+j+1, b+j+1, html); - appendDiffLine(pOut, ' ', &A[a+j], html, 0); + appendDiffLine(pOut, ' ', &B[b+j], html, 0); } } } /* @@ -522,11 +476,11 @@ ** This comment contains multibyte unicode characters (ü, Æ, ð) in order ** to test the ability of the diff code to handle such characters. */ static void sbsWriteText(SbsLine *p, DLine *pLine, int col){ Blob *pCol = p->apCols[col]; - int n = pLine->n; + int n = pLine->h & LENGTH_MASK; int i; /* Number of input characters consumed */ int k; /* Cursor position */ int needEndSpan = 0; const char *zIn = pLine->z; int w = p->width; @@ -594,11 +548,11 @@ "<td><div class=\"diff%scol\">\n" "<pre>\n" "%s" "</pre>\n" "</div></td>\n", - (col % 3) ? (col == SBS_MKR ? "mkr" : "txt") : "ln", + col % 3 ? (col == SBS_MKR ? "mkr" : "txt") : "ln", blob_str(pCol) ); } /* @@ -766,13 +720,13 @@ int aLCS[4]; /* Bounds of common middle segment */ static const char zClassRm[] = "<span class=\"diffrm\">"; static const char zClassAdd[] = "<span class=\"diffadd\">"; static const char zClassChng[] = "<span class=\"diffchng\">"; - nLeft = pLeft->n; + nLeft = pLeft->h & LENGTH_MASK; zLeft = pLeft->z; - nRight = pRight->n; + nRight = pRight->h & LENGTH_MASK; zRight = pRight->z; nShort = nLeft<nRight ? nLeft : nRight; nPrefix = 0; while( nPrefix<nShort && zLeft[nPrefix]==zRight[nPrefix] ){ @@ -849,11 +803,11 @@ p->zStart = zClassChng; } p->iStart2 = nPrefix + aLCS[1]; p->iEnd2 = nLeft - nSuffix; p->zStart2 = aLCS[3]==nRightDiff ? zClassRm : zClassChng; - sbsSimplifyLine(p, zLeft); + sbsSimplifyLine(p, zLeft+nPrefix); sbsWriteText(p, pLeft, SBS_TXTA); sbsWriteMarker(p, " | ", "|"); sbsWriteLineno(p, lnRight, SBS_LNB); p->iStart = nPrefix; p->iEnd = nPrefix + aLCS[2]; @@ -864,11 +818,11 @@ p->zStart = zClassChng; } p->iStart2 = nPrefix + aLCS[3]; p->iEnd2 = nRight - nSuffix; p->zStart2 = aLCS[1]==nLeftDiff ? zClassAdd : zClassChng; - sbsSimplifyLine(p, zRight); + sbsSimplifyLine(p, zRight+nPrefix); sbsWriteText(p, pRight, SBS_TXTB); return; } /* If all else fails, show a single big change between left and right */ @@ -914,12 +868,12 @@ unsigned char aFirst[256]; /* aFirst[X] = index in zB[] of first char X */ unsigned char aNext[252]; /* aNext[i] = index in zB[] of next zB[i] char */ zA = pA->z; zB = pB->z; - nA = pA->n; - nB = pB->n; + nA = pA->h & LENGTH_MASK; + nB = pB->h & LENGTH_MASK; while( nA>0 && fossil_isspace(zA[0]) ){ nA--; zA++; } while( nA>0 && fossil_isspace(zA[nA-1]) ){ nA--; } while( nB>0 && fossil_isspace(zB[0]) ){ nB--; zB++; } while( nB>0 && fossil_isspace(zB[nB-1]) ){ nB--; } if( nA>250 ) nA = 250; @@ -1351,11 +1305,11 @@ sbsWriteMarker(&s, " ", ""); sbsWriteLineno(&s, b+j, SBS_LNB); sbsWriteText(&s, &B[b+j], SBS_TXTB); } } - + if( s.escHtml && blob_size(s.apCols[SBS_LNA])>0 ){ blob_append(pOut, "<table class=\"sbsdiffcols\"><tr>\n", -1); for(i=SBS_LNA; i<=SBS_TXTB; i++){ sbsWriteColumn(pOut, s.apCols[i], i); blob_reset(s.apCols[i]); @@ -1383,16 +1337,16 @@ int iSXb = iS1; /* Best match so far */ int iSYb = iS2; /* Best match so far */ for(i=iS1; i<iE1-mxLength; i++){ for(j=iS2; j<iE2-mxLength; j++){ - if( !p->same_fn(&p->aFrom[i], &p->aTo[j]) ) continue; - if( mxLength && !p->same_fn(&p->aFrom[i+mxLength], &p->aTo[j+mxLength]) ){ + if( !same_dline(&p->aFrom[i], &p->aTo[j]) ) continue; + if( mxLength && !same_dline(&p->aFrom[i+mxLength], &p->aTo[j+mxLength]) ){ continue; } k = 1; - while( i+k<iE1 && j+k<iE2 && p->same_fn(&p->aFrom[i+k],&p->aTo[j+k]) ){ + while( i+k<iE1 && j+k<iE2 && same_dline(&p->aFrom[i+k],&p->aTo[j+k]) ){ k++; } if( k>mxLength ){ iSXb = i; iSYb = j; @@ -1454,11 +1408,11 @@ mid = (iE1 + iS1)/2; for(i=iS1; i<iE1; i++){ int limit = 0; j = p->aTo[p->aFrom[i].h % p->nTo].iHash; while( j>0 - && (j-1<iS2 || j>=iE2 || !p->same_fn(&p->aFrom[i], &p->aTo[j-1])) + && (j-1<iS2 || j>=iE2 || !same_dline(&p->aFrom[i], &p->aTo[j-1])) ){ if( limit++ > 10 ){ j = 0; break; } @@ -1471,19 +1425,19 @@ iSX = i; iSY = j-1; pA = &p->aFrom[iSX-1]; pB = &p->aTo[iSY-1]; n = minInt(iSX-iS1, iSY-iS2); - for(k=0; k<n && p->same_fn(pA,pB); k++, pA--, pB--){} + for(k=0; k<n && same_dline(pA,pB); k++, pA--, pB--){} iSX -= k; iSY -= k; iEX = i+1; iEY = j; pA = &p->aFrom[iEX]; pB = &p->aTo[iEY]; n = minInt(iE1-iEX, iE2-iEY); - for(k=0; k<n && p->same_fn(pA,pB); k++, pA++, pB++){} + for(k=0; k<n && same_dline(pA,pB); k++, pA++, pB++){} iEX += k; iEY += k; skew = (iSX-iS1) - (iSY-iS2); if( skew<0 ) skew = -skew; dist = (iSX+iEX)/2 - mid; @@ -1620,16 +1574,16 @@ int mnE, iS, iE1, iE2; /* Carve off the common header and footer */ iE1 = p->nFrom; iE2 = p->nTo; - while( iE1>0 && iE2>0 && p->same_fn(&p->aFrom[iE1-1], &p->aTo[iE2-1]) ){ + while( iE1>0 && iE2>0 && same_dline(&p->aFrom[iE1-1], &p->aTo[iE2-1]) ){ iE1--; iE2--; } mnE = iE1<iE2 ? iE1 : iE2; - for(iS=0; iS<mnE && p->same_fn(&p->aFrom[iS],&p->aTo[iS]); iS++){} + for(iS=0; iS<mnE && same_dline(&p->aFrom[iS],&p->aTo[iS]); iS++){} /* do the difference */ if( iS>0 ){ appendTriple(p, iS, 0, 0); } @@ -1694,11 +1648,11 @@ /* Shift insertions toward the beginning of the file */ while( cpy>0 && del==0 && ins>0 ){ DLine *pTop = &p->aFrom[lnFrom-1]; /* Line before start of insert */ DLine *pBtm = &p->aTo[lnTo+ins-1]; /* Last line inserted */ - if( p->same_fn(pTop, pBtm)==0 ) break; + if( same_dline(pTop, pBtm)==0 ) break; if( LENGTH(pTop+1)+LENGTH(pBtm)<=LENGTH(pTop)+LENGTH(pBtm-1) ) break; lnFrom--; lnTo--; p->aEdit[r]--; p->aEdit[r+3]++; @@ -1707,11 +1661,11 @@ /* Shift insertions toward the end of the file */ while( r+3<p->nEdit && p->aEdit[r+3]>0 && del==0 && ins>0 ){ DLine *pTop = &p->aTo[lnTo]; /* First line inserted */ DLine *pBtm = &p->aTo[lnTo+ins]; /* First line past end of insert */ - if( p->same_fn(pTop, pBtm)==0 ) break; + if( same_dline(pTop, pBtm)==0 ) break; if( LENGTH(pTop)+LENGTH(pBtm-1)<=LENGTH(pTop+1)+LENGTH(pBtm) ) break; lnFrom++; lnTo++; p->aEdit[r]++; p->aEdit[r+3]--; @@ -1720,11 +1674,11 @@ /* Shift deletions toward the beginning of the file */ while( cpy>0 && del>0 && ins==0 ){ DLine *pTop = &p->aFrom[lnFrom-1]; /* Line before start of delete */ DLine *pBtm = &p->aFrom[lnFrom+del-1]; /* Last line deleted */ - if( p->same_fn(pTop, pBtm)==0 ) break; + if( same_dline(pTop, pBtm)==0 ) break; if( LENGTH(pTop+1)+LENGTH(pBtm)<=LENGTH(pTop)+LENGTH(pBtm-1) ) break; lnFrom--; lnTo--; p->aEdit[r]--; p->aEdit[r+3]++; @@ -1733,11 +1687,11 @@ /* Shift deletions toward the end of the file */ while( r+3<p->nEdit && p->aEdit[r+3]>0 && del>0 && ins==0 ){ DLine *pTop = &p->aFrom[lnFrom]; /* First line deleted */ DLine *pBtm = &p->aFrom[lnFrom+del]; /* First line past end of delete */ - if( p->same_fn(pTop, pBtm)==0 ) break; + if( same_dline(pTop, pBtm)==0 ) break; if( LENGTH(pTop)+LENGTH(pBtm-1)<=LENGTH(pTop)+LENGTH(pBtm) ) break; lnFrom++; lnTo++; p->aEdit[r]++; p->aEdit[r+3]--; @@ -1799,33 +1753,26 @@ Blob *pB_Blob, /* TO file */ Blob *pOut, /* Write diff here if not NULL */ ReCompiled *pRe, /* Only output changes where this Regexp matches */ u64 diffFlags /* DIFF_* flags defined above */ ){ - int ignoreWs; /* Ignore whitespace */ + int ignoreEolWs; /* Ignore whitespace at the end of lines */ DContext c; if( diffFlags & DIFF_INVERT ){ Blob *pTemp = pA_Blob; pA_Blob = pB_Blob; pB_Blob = pTemp; } - ignoreWs = (diffFlags & DIFF_IGNORE_ALLWS)!=0; - blob_to_utf8_no_bom(pA_Blob, 0); - blob_to_utf8_no_bom(pB_Blob, 0); + ignoreEolWs = (diffFlags & DIFF_IGNORE_EOLWS)!=0; /* Prepare the input files */ memset(&c, 0, sizeof(c)); - if( (diffFlags & DIFF_IGNORE_ALLWS)==DIFF_IGNORE_ALLWS ){ - c.same_fn = same_dline_ignore_allws; - }else{ - c.same_fn = same_dline; - } c.aFrom = break_into_lines(blob_str(pA_Blob), blob_size(pA_Blob), - &c.nFrom, diffFlags); + &c.nFrom, ignoreEolWs); c.aTo = break_into_lines(blob_str(pB_Blob), blob_size(pB_Blob), - &c.nTo, diffFlags); + &c.nTo, ignoreEolWs); if( c.aFrom==0 || c.aTo==0 ){ fossil_free(c.aFrom); fossil_free(c.aTo); if( pOut ){ diff_errmsg(pOut, DIFF_CANNOT_COMPUTE_BINARY, diffFlags); @@ -1833,27 +1780,20 @@ return 0; } /* Compute the difference */ diff_all(&c); - if( ignoreWs && c.nEdit==6 && c.aEdit[1]==0 && c.aEdit[2]==0 ){ - fossil_free(c.aFrom); - fossil_free(c.aTo); - fossil_free(c.aEdit); - if( pOut ) diff_errmsg(pOut, DIFF_WHITESPACE_ONLY, diffFlags); - return 0; - } if( (diffFlags & DIFF_NOTTOOBIG)!=0 ){ int i, m, n; int *a = c.aEdit; int mx = c.nEdit; for(i=m=n=0; i<mx; i+=3){ m += a[i]; n += a[i+1]+a[i+2]; } if( n>10000 ){ fossil_free(c.aFrom); fossil_free(c.aTo); fossil_free(c.aEdit); - if( pOut ) diff_errmsg(pOut, DIFF_TOO_MANY_CHANGES, diffFlags); + diff_errmsg(pOut, DIFF_TOO_MANY_CHANGES, diffFlags); return 0; } } if( (diffFlags & DIFF_NOOPT)==0 ){ diff_optimize(&c); @@ -1882,36 +1822,24 @@ /* ** Process diff-related command-line options and return an appropriate ** "diffFlags" integer. ** -** --brief Show filenames only DIFF_BRIEF -** -c|--context N N lines of context. DIFF_CONTEXT_MASK -** --html Format for HTML DIFF_HTML -** --invert Invert the diff DIFF_INVERT -** -n|--linenum Show line numbers DIFF_LINENO -** --noopt Disable optimization DIFF_NOOPT -** --strip-trailing-cr Strip trailing CR DIFF_STRIP_EOLCR -** --unified Unified diff. ~DIFF_SIDEBYSIDE -** -w|--ignore-all-space Ignore all whitespaces DIFF_IGNORE_ALLWS -** -W|--width N N character lines. DIFF_WIDTH_MASK -** -y|--side-by-side Side-by-side diff. DIFF_SIDEBYSIDE -** -Z|--ignore-trailing-space Ignore eol-whitespaces DIFF_IGNORE_EOLWS +** --brief Show filenames only DIFF_BRIEF +** --context|-c N N lines of context. DIFF_CONTEXT_MASK +** --html Format for HTML DIFF_HTML +** --invert Invert the diff DIFF_INVERT +** --linenum|-n Show line numbers DIFF_LINENO +** --noopt Disable optimization DIFF_NOOPT +** --side-by-side|-y Side-by-side diff. DIFF_SIDEBYSIDE +** --unified Unified diff. ~DIFF_SIDEBYSIDE +** --width|-W N N character lines. DIFF_WIDTH_MASK */ u64 diff_options(void){ u64 diffFlags = 0; const char *z; int f; - if( find_option("ignore-trailing-space","Z",0)!=0 ){ - diffFlags = DIFF_IGNORE_EOLWS; - } - if( find_option("ignore-all-space","w",0)!=0 ){ - diffFlags = DIFF_IGNORE_ALLWS; /* stronger than DIFF_IGNORE_EOLWS */ - } - if( find_option("strip-trailing-cr",0,0)!=0 ){ - diffFlags |= DIFF_STRIP_EOLCR; - } if( find_option("side-by-side","y",0)!=0 ) diffFlags |= DIFF_SIDEBYSIDE; if( find_option("unified",0,0)!=0 ) diffFlags &= ~DIFF_SIDEBYSIDE; if( (z = find_option("context","c",1))!=0 && (f = atoi(z))>=0 ){ if( f > DIFF_CONTEXT_MASK ) f = DIFF_CONTEXT_MASK; diffFlags |= f + DIFF_CONTEXT_EX; @@ -2000,11 +1928,11 @@ typedef struct Annotator Annotator; struct Annotator { DContext c; /* The diff-engine context */ struct AnnLine { /* Lines of the original files... */ const char *z; /* The text of the line */ - short int n; /* Number of bytes (omitting trailing \n) */ + short int n; /* Number of bytes (omitting trailing space and \n) */ short int iVers; /* Level at which tag was set */ } *aOrig; int nOrig; /* Number of elements in aOrig[] */ int nVers; /* Number of versions analyzed */ int bLimit; /* True if the iLimit was reached */ @@ -2011,11 +1939,10 @@ struct AnnVers { const char *zFUuid; /* File being analyzed */ const char *zMUuid; /* Check-in containing the file */ const char *zDate; /* Date of the check-in */ const char *zBgColor; /* Suggested background color */ - const char *zUser; /* Name of user who did the check-in */ unsigned cnt; /* Number of lines contributed by this check-in */ } *aVers; /* For each check-in analyzed */ char **azVers; /* Names of versions analyzed */ }; @@ -2022,28 +1949,22 @@ /* ** Initialize the annotation process by specifying the file that is ** to be annotated. The annotator takes control of the input Blob and ** will release it when it is finished with it. */ -static int annotation_start(Annotator *p, Blob *pInput, u64 diffFlags){ +static int annotation_start(Annotator *p, Blob *pInput){ int i; memset(p, 0, sizeof(*p)); - if( (diffFlags & DIFF_IGNORE_ALLWS)==DIFF_IGNORE_ALLWS ){ - p->c.same_fn = same_dline_ignore_allws; - }else{ - p->c.same_fn = same_dline; - } - p->c.aTo = break_into_lines(blob_str(pInput), blob_size(pInput),&p->c.nTo, - diffFlags); + p->c.aTo = break_into_lines(blob_str(pInput), blob_size(pInput),&p->c.nTo,1); if( p->c.aTo==0 ){ return 1; } p->aOrig = fossil_malloc( sizeof(p->aOrig[0])*p->c.nTo ); for(i=0; i<p->c.nTo; i++){ p->aOrig[i].z = p->c.aTo[i].z; - p->aOrig[i].n = p->c.aTo[i].n; + p->aOrig[i].n = p->c.aTo[i].h & LENGTH_MASK; p->aOrig[i].iVers = -1; } p->nOrig = p->c.nTo; return 0; } @@ -2053,17 +1974,17 @@ ** being annotated. Do another step of the annotation. Return true ** if additional annotation is required. zPName is the tag to insert ** on each line of the file being annotated that was contributed by ** pParent. Memory to hold zPName is leaked. */ -static int annotation_step(Annotator *p, Blob *pParent, int iVers, u64 diffFlags){ +static int annotation_step(Annotator *p, Blob *pParent, int iVers){ int i, j; int lnTo; /* Prepare the parent file to be diffed */ p->c.aFrom = break_into_lines(blob_str(pParent), blob_size(pParent), - &p->c.nFrom, diffFlags); + &p->c.nFrom, 1); if( p->c.aFrom==0 ){ return 1; } /* Compute the differences going from pParent to the file being @@ -2096,13 +2017,13 @@ /* Return no errors */ return 0; } -/* Annotation flags (any DIFF flag can be used as Annotation flag as well) */ -#define ANN_FILE_VERS (((u64)0x20)<<32) /* Show file vers rather than commit vers */ -#define ANN_FILE_ANCEST (((u64)0x40)<<32) /* Prefer check-ins in the ANCESTOR table */ +/* Annotation flags */ +#define ANN_FILE_VERS 0x01 /* Show file vers rather than commit vers */ +#define ANN_FILE_ANCEST 0x02 /* Prefer check-ins in the ANCESTOR table */ /* ** Compute a complete annotation on a file. The file is identified ** by its filename number (filename.fnid) and the baseline in which ** it was checked in (mlink.mid). @@ -2110,11 +2031,11 @@ static void annotate_file( Annotator *p, /* The annotator */ int fnid, /* The name of the file to be annotated */ int mid, /* Use the version of the file in this check-in */ int iLimit, /* Limit the number of levels if greater than zero */ - u64 annFlags /* Flags to alter the annotation */ + int annFlags /* Flags to alter the annotation */ ){ Blob toAnnotate; /* Text of the final (mid) version of the file */ Blob step; /* Text of previous revision */ int rid; /* Artifact ID of the file being annotated */ Stmt q; /* Query returning all ancestor versions */ @@ -2128,12 +2049,11 @@ } if( !content_get(rid, &toAnnotate) ){ fossil_fatal("unable to retrieve content of artifact #%d", rid); } if( iLimit<=0 ) iLimit = 1000000000; - blob_to_utf8_no_bom(&toAnnotate, 0); - annotation_start(p, &toAnnotate, annFlags); + annotation_start(p, &toAnnotate); db_begin_transaction(); db_multi_exec( "CREATE TEMP TABLE IF NOT EXISTS vseen(rid INTEGER PRIMARY KEY);" "DELETE FROM vseen;" ); @@ -2141,11 +2061,10 @@ db_prepare(&ins, "INSERT OR IGNORE INTO vseen(rid) VALUES(:rid)"); db_prepare(&q, "SELECT (SELECT uuid FROM blob WHERE rid=mlink.fid)," " (SELECT uuid FROM blob WHERE rid=mlink.mid)," " date(event.mtime)," - " coalesce(event.euser,event.user)," " mlink.pid" " FROM mlink, event" " WHERE mlink.fid=:rid" " AND event.objid=mlink.mid" " AND mlink.pid NOT IN vseen" @@ -2155,20 +2074,18 @@ ); db_bind_int(&q, ":rid", rid); if( iLimit==0 ) iLimit = 1000000000; while( rid && iLimit>cnt && db_step(&q)==SQLITE_ROW ){ - int prevId = db_column_int(&q, 4); + int prevId = db_column_int(&q, 3); p->aVers = fossil_realloc(p->aVers, (p->nVers+1)*sizeof(p->aVers[0])); p->aVers[p->nVers].zFUuid = fossil_strdup(db_column_text(&q, 0)); p->aVers[p->nVers].zMUuid = fossil_strdup(db_column_text(&q, 1)); p->aVers[p->nVers].zDate = fossil_strdup(db_column_text(&q, 2)); - p->aVers[p->nVers].zUser = fossil_strdup(db_column_text(&q, 3)); if( p->nVers ){ content_get(rid, &step); - blob_to_utf8_no_bom(&step, 0); - annotation_step(p, &step, p->nVers-1, annFlags); + annotation_step(p, &step, p->nVers-1); blob_reset(&step); } p->nVers++; db_bind_int(&ins, ":rid", rid); db_step(&ins); @@ -2189,11 +2106,10 @@ */ unsigned gradient_color(unsigned c1, unsigned c2, int n, int i){ unsigned c; /* Result color */ unsigned x1, x2; if( i==0 || n==0 ) return c1; - else if(i>=n) return c2; x1 = (c1>>16)&0xff; x2 = (c2>>16)&0xff; c = (x1*(n-i) + x2*i)/n<<16 & 0xff0000; x1 = (c1>>8)&0xff; x2 = (c2>>8)&0xff; @@ -2204,12 +2120,10 @@ return c; } /* ** WEBPAGE: annotate -** WEBPAGE: blame -** WEBPAGE: praise ** ** Query parameters: ** ** checkin=ID The manifest ID at which to start the annotation ** filename=FILENAME The filename. @@ -2220,35 +2134,30 @@ void annotation_page(void){ int mid; int fnid; int i; int iLimit; /* Depth limit */ - u64 annFlags = (ANN_FILE_ANCEST|DIFF_STRIP_EOLCR); + int annFlags = ANN_FILE_ANCEST; int showLog = 0; /* True to display the log */ - int ignoreWs = 0; /* Ignore whitespace */ const char *zFilename; /* Name of file to annotate */ const char *zCI; /* The check-in containing zFilename */ Annotator ann; HQuery url; struct AnnVers *p; unsigned clr1, clr2, clr; - int bBlame = g.zPath[0]!='a';/* True for BLAME output. False for ANNOTATE. */ /* Gather query parameters */ showLog = atoi(PD("log","1")); login_check_credentials(); - if( !g.perm.Read ){ login_needed(g.anon.Read); return; } + if( !g.perm.Read ){ login_needed(); return; } if( exclude_spiders("annotate") ) return; - load_control(); mid = name_to_typed_rid(PD("checkin","0"),"ci"); zFilename = P("filename"); fnid = db_int(0, "SELECT fnid FROM filename WHERE name=%Q", zFilename); if( mid==0 || fnid==0 ){ fossil_redirect_home(); } iLimit = atoi(PD("limit","20")); if( P("filevers") ) annFlags |= ANN_FILE_VERS; - ignoreWs = P("w")!=0; - if( ignoreWs ) annFlags |= DIFF_IGNORE_ALLWS; if( !db_exists("SELECT 1 FROM mlink WHERE mid=%d AND fnid=%d",mid,fnid) ){ fossil_redirect_home(); } /* compute the annotation */ @@ -2256,68 +2165,56 @@ annotate_file(&ann, fnid, mid, iLimit, annFlags); zCI = ann.aVers[0].zMUuid; /* generate the web page */ style_header("Annotation For %h", zFilename); - if( bBlame ){ - url_initialize(&url, "blame"); - }else{ - url_initialize(&url, "annotate"); - } + url_initialize(&url, "annotate"); url_add_parameter(&url, "checkin", P("checkin")); url_add_parameter(&url, "filename", zFilename); if( iLimit!=20 ){ url_add_parameter(&url, "limit", sqlite3_mprintf("%d", iLimit)); } url_add_parameter(&url, "log", showLog ? "1" : "0"); - if( ignoreWs ){ - url_add_parameter(&url, "w", ""); - style_submenu_element("Show Whitespace Changes", "Show Whitespace Changes", - "%s", url_render(&url, "w", 0, 0, 0)); - }else{ - style_submenu_element("Ignore Whitespace", "Ignore Whitespace", - "%s", url_render(&url, "w", "", 0, 0)); - } if( showLog ){ style_submenu_element("Hide Log", "Hide Log", - "%s", url_render(&url, "log", "0", 0, 0)); + url_render(&url, "log", "0", 0, 0)); }else{ style_submenu_element("Show Log", "Show Log", - "%s", url_render(&url, "log", "1", 0, 0)); + url_render(&url, "log", "1", 0, 0)); } if( ann.bLimit ){ char *z1, *z2; style_submenu_element("All Ancestors", "All Ancestors", - "%s", url_render(&url, "limit", "-1", 0, 0)); + url_render(&url, "limit", "-1", 0, 0)); z1 = sqlite3_mprintf("%d Ancestors", iLimit+20); z2 = sqlite3_mprintf("%d", iLimit+20); - style_submenu_element(z1, z1, "%s", url_render(&url, "limit", z2, 0, 0)); + style_submenu_element(z1, z1, url_render(&url, "limit", z2, 0, 0)); } if( iLimit>20 ){ style_submenu_element("20 Ancestors", "20 Ancestors", - "%s", url_render(&url, "limit", "20", 0, 0)); + url_render(&url, "limit", "20", 0, 0)); } - if( skin_detail_boolean("white-foreground") ){ + if( db_get_boolean("white-foreground", 0) ){ clr1 = 0xa04040; clr2 = 0x4059a0; }else{ clr1 = 0xffb5b5; /* Recent changes: red (hot) */ clr2 = 0xb5e0ff; /* Older changes: blue (cold) */ } for(p=ann.aVers, i=0; i<ann.nVers; i++, p++){ clr = gradient_color(clr1, clr2, ann.nVers-1, i); ann.aVers[i].zBgColor = mprintf("#%06x", clr); - } + } if( showLog ){ - char *zLink = href("%R/finfo?name=%t&ci=%!S",zFilename,zCI); + char *zLink = href("%R/finfo?name=%t&ci=%S",zFilename,zCI); @ <h2>Ancestors of %z(zLink)%h(zFilename)</a> analyzed:</h2> @ <ol> 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> + @ check-in %z(href("%R/info/%S",p->zMUuid))%.10s(p->zMUuid)</a> + @ artifact %z(href("%R/artifact/%S",p->zFUuid))%.10s(p->zFUuid)</a> @ </span> #if 0 if( i>0 ){ char *zLink = xhref("target='infowindow'", "%R/fdiff?v1=%S&v2=%S&sbs=1", @@ -2334,52 +2231,37 @@ } @ </ol> @ <hr> } if( !ann.bLimit ){ - @ <h2>Origin for each line in - @ %z(href("%R/finfo?name=%h&ci=%!S", zFilename, zCI))%h(zFilename)</a> - @ from check-in %z(href("%R/info/%!S",zCI))%S(zCI)</a>:</h2> + @ <h2>Origin for each line in + @ %z(href("%R/finfo?name=%h&ci=%S", zFilename, zCI))%h(zFilename)</a> + @ from check-in %z(href("%R/info/%S",zCI))%S(zCI)</a>:</h2> iLimit = ann.nVers+10; }else{ @ <h2>Lines added by the %d(iLimit) most recent ancestors of - @ %z(href("%R/finfo?name=%h&ci=%!S", zFilename, zCI))%h(zFilename)</a> - @ from check-in %z(href("%R/info/%!S",zCI))%S(zCI)</a>:</h2> + @ %z(href("%R/finfo?name=%h&ci=%S", zFilename, zCI))%h(zFilename)</a> + @ from check-in %z(href("%R/info/%S",zCI))%S(zCI)</a>:</h2> } @ <pre> for(i=0; i<ann.nOrig; i++){ int iVers = ann.aOrig[i].iVers; char *z = (char*)ann.aOrig[i].z; int n = ann.aOrig[i].n; char zPrefix[300]; z[n] = 0; if( iLimit>ann.nVers && iVers<0 ) iVers = ann.nVers-1; - - if( bBlame ){ - if( iVers>=0 ){ - struct AnnVers *p = ann.aVers+iVers; - char *zLink = xhref("target='infowindow'", "%R/info/%!S", p->zMUuid); - sqlite3_snprintf(sizeof(zPrefix), zPrefix, - "<span style='background-color:%s'>" - "%s%.10s</a> %s</span> %13.13s:", - p->zBgColor, zLink, p->zMUuid, p->zDate, p->zUser); - fossil_free(zLink); - }else{ - sqlite3_snprintf(sizeof(zPrefix), zPrefix, "%36s", ""); - } - }else{ - if( iVers>=0 ){ - struct AnnVers *p = ann.aVers+iVers; - char *zLink = xhref("target='infowindow'", "%R/info/%!S", p->zMUuid); - sqlite3_snprintf(sizeof(zPrefix), zPrefix, - "<span style='background-color:%s'>" - "%s%.10s</a> %s</span> %4d:", - p->zBgColor, zLink, p->zMUuid, p->zDate, i+1); - fossil_free(zLink); - }else{ - sqlite3_snprintf(sizeof(zPrefix), zPrefix, "%22s%4d:", "", i+1); - } + if( iVers>=0 ){ + struct AnnVers *p = ann.aVers+iVers; + char *zLink = xhref("target='infowindow'", "%R/info/%S", p->zMUuid); + sqlite3_snprintf(sizeof(zPrefix), zPrefix, + "<span style='background-color:%s'>" + "%s%.10s</a> %s</span> %4d:", + p->zBgColor, zLink, p->zMUuid, p->zDate, i+1); + fossil_free(zLink); + }else{ + sqlite3_snprintf(sizeof(zPrefix), zPrefix, "%22s%4d:", "", i+1); } @ %s(zPrefix) %h(z) } @ </pre> @@ -2386,26 +2268,20 @@ style_footer(); } /* ** COMMAND: annotate -** COMMAND: blame -** COMMAND: praise ** -** %fossil (annotate|blame|praise) ?OPTIONS? FILENAME +** %fossil annotate ?OPTIONS? FILENAME ** ** Output the text of a file with markings to show when each line of -** the file was last modified. The "annotate" command shows line numbers -** and omits the username. The "blame" and "praise" commands show the user -** who made each check-in and omits the line number. +** the file was last modified. ** ** Options: -** --filevers Show file version numbers rather than check-in versions -** -l|--log List all versions analyzed -** -n|--limit N Only look backwards in time by N versions -** -w|--ignore-all-space Ignore white space when comparing lines -** -Z|--ignore-trailing-space Ignore whitespace at line end +** --filevers Show file version numbers rather than check-in versions +** -l|--log List all versions analyzed +** -n|--limit N Only look backwards in time by N versions ** ** See also: info, finfo, timeline */ void annotate_cmd(void){ int fnid; /* Filename ID */ @@ -2418,30 +2294,18 @@ int i; /* Loop counter */ const char *zLimit; /* The value to the -n|--limit option */ int iLimit; /* How far back in time to look */ int showLog; /* True to show the log */ int fileVers; /* Show file version instead of check-in versions */ - u64 annFlags = 0; /* Flags to control annotation properties */ - int bBlame = 0; /* True for BLAME output. False for ANNOTATE. */ + int annFlags = 0; /* Flags to control annotation properties */ - bBlame = g.argv[1][0]!='a'; zLimit = find_option("limit","n",1); if( zLimit==0 || zLimit[0]==0 ) zLimit = "-1"; iLimit = atoi(zLimit); showLog = find_option("log","l",0)!=0; - if( find_option("ignore-trailing-space","Z",0)!=0 ){ - annFlags = DIFF_IGNORE_EOLWS; - } - if( find_option("ignore-all-space","w",0)!=0 ){ - annFlags = DIFF_IGNORE_ALLWS; /* stronger than DIFF_IGNORE_EOLWS */ - } fileVers = find_option("filevers",0,0)!=0; db_must_be_within_tree(); - - /* We should be done with options.. */ - verify_all_options(); - if( g.argc<3 ) { usage("FILENAME"); } file_tree_name(g.argv[2], &treename, 1); zFilename = blob_str(&treename); @@ -2464,40 +2328,32 @@ " ORDER BY ancestor.generation ASC LIMIT 1", fid, fnid); if( mid==0 ){ fossil_fatal("unable to find manifest"); } - annFlags |= (ANN_FILE_ANCEST|DIFF_STRIP_EOLCR); + annFlags |= ANN_FILE_ANCEST; annotate_file(&ann, fnid, mid, iLimit, annFlags); if( showLog ){ struct AnnVers *p; for(p=ann.aVers, i=0; i<ann.nVers; i++, p++){ - fossil_print("version %3d: %s %S file %S\n", + fossil_print("version %3d: %s %.10s file %.10s\n", i+1, p->zDate, p->zMUuid, p->zFUuid); } fossil_print("---------------------------------------------------\n"); } for(i=0; i<ann.nOrig; i++){ int iVers = ann.aOrig[i].iVers; char *z = (char*)ann.aOrig[i].z; int n = ann.aOrig[i].n; - struct AnnVers *p; - if( iLimit>ann.nVers && iVers<0 ) iVers = ann.nVers-1; - p = ann.aVers + iVers; - if( bBlame ){ - if( iVers>=0 ){ - fossil_print("%S %s %13.13s: %.*s\n", - fileVers ? p->zFUuid : p->zMUuid, p->zDate, p->zUser, n, z); - }else{ - fossil_print("%35s %.*s\n", "", n, z); - } - }else{ - if( iVers>=0 ){ - fossil_print("%S %s %5d: %.*s\n", - fileVers ? p->zFUuid : p->zMUuid, p->zDate, i+1, n, z); - }else{ - fossil_print("%21s %5d: %.*s\n", - "", i+1, n, z); - } - } + char zPrefix[200]; + z[n] = 0; + if( iLimit>ann.nVers && iVers<0 ) iVers = ann.nVers-1; + if( iVers>=0 ){ + struct AnnVers *p = ann.aVers+iVers; + sqlite3_snprintf(sizeof(zPrefix), zPrefix, "%.10s %s", + fileVers ? p->zFUuid : p->zMUuid, p->zDate); + }else{ + zPrefix[0] = 0; + } + fossil_print("%21s %4d: %.*s\n", zPrefix, i+1, n, z); } } DELETED src/diff.tcl Index: src/diff.tcl ================================================================== --- src/diff.tcl +++ src/diff.tcl @@ -1,397 +0,0 @@ -# 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 { - 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 - CHNG_BG #d0d0ff - ADD_BG #c0ffc0 - RM_BG #ffc0c0 - HR_FG #888888 - HR_PAD_TOP 4 - HR_PAD_BTM 8 - FN_BG #444444 - FN_FG #ffffff - FN_PAD 5 - 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 {}] - return [string map {& & < < > > ' ' " \"} $x] -} - -proc cols {} { - return [list .lnA .txtA .mkr .lnB .txtB] -} - -proc colType {c} { - regexp {[a-z]+} $c type - return $type -} - -proc getLine {difftxt N iivar} { - upvar $iivar ii - if {$ii>=$N} {return -1} - set x [lindex $difftxt $ii] - incr ii - return $x -} - -proc readDiffs {fossilcmd} { - global difftxt - if {![info exists difftxt]} { - set in [open $fossilcmd r] - fconfigure $in -encoding utf-8 - set difftxt [split [read $in] \n] - close $in - } - set N [llength $difftxt] - set ii 0 - set nDiffs 0 - array set widths {txt 0 ln 0 mkr 0} - while {[set line [getLine $difftxt $N ii]] != -1} { - set fn2 {} - if {![regexp {^=+ (.*?) =+ versus =+ (.*?) =+$} $line all fn fn2] - && ![regexp {^=+ (.*?) =+$} $line all fn] - } { - continue - } - set errMsg "" - set line [getLine $difftxt $N ii] - if {[string compare -length 6 $line "<table"] - && ![regexp {<p[^>]*>(.+)} $line - errMsg]} { - continue - } - incr nDiffs - set idx [expr {$nDiffs > 1 ? [.txtA index end] : "1.0"}] - .wfiles.lb insert end $fn - - foreach c [cols] { - if {$nDiffs > 1} { - $c insert end \n - - } - if {[colType $c] eq "txt"} { - $c insert end $fn\n fn - if {$fn2!=""} {set fn $fn2} - } else { - $c insert end \n fn - } - $c insert end \n - - - if {$errMsg ne ""} continue - while {[getLine $difftxt $N ii] ne "<pre>"} continue - set type [colType $c] - set str {} - while {[set line [getLine $difftxt $N ii]] ne "</pre>"} { - set len [string length [dehtml $line]] - if {$len > $widths($type)} { - set widths($type) $len - } - append str $line\n - } - - set re {<span class="diff([a-z]+)">([^<]*)</span>} - # Use \r as separator since it can't appear in the diff output (it gets - # converted to a space). - set str [regsub -all $re $str "\r\\1\r\\2\r"] - foreach {pre class mid} [split $str \r] { - if {$class ne ""} { - $c insert end [dehtml $pre] - [dehtml $mid] [list $class -] - } else { - $c insert end [dehtml $pre] - - } - } - } - - if {$errMsg ne ""} { - foreach c {.txtA .txtB} {$c insert end [string trim $errMsg] err} - foreach c [cols] {$c insert end \n -} - } - } - - foreach c [cols] { - set type [colType $c] - if {$type ne "txt"} { - $c config -width $widths($type) - } - $c config -state disabled - } - if {$nDiffs <= [.wfiles.lb cget -height]} { - .wfiles.lb config -height $nDiffs - grid remove .wfiles.sb - } - - return $nDiffs -} - -proc viewDiff {idx} { - .txtA yview $idx - .txtA xview moveto 0 -} - -proc cycleDiffs {{reverse 0}} { - if {$reverse} { - set range [.txtA tag prevrange fn @0,0 1.0] - if {$range eq ""} { - viewDiff {fn.last -1c} - } else { - viewDiff [lindex $range 0] - } - } else { - set range [.txtA tag nextrange fn {@0,0 +1c} end] - if {$range eq "" || [lindex [.txtA yview] 1] == 1} { - viewDiff fn.first - } else { - viewDiff [lindex $range 0] - } - } -} - -proc xvis {col} { - set view [$col xview] - return [expr {[lindex $view 1]-[lindex $view 0]}] -} - -proc scroll-x {args} { - set c .txt[expr {[xvis .txtA] < [xvis .txtB] ? "A" : "B"}] - eval $c xview $args -} - -interp alias {} scroll-y {} .txtA yview - -proc noop {args} {} - -proc enableSync {axis} { - update idletasks - interp alias {} sync-$axis {} - rename _sync-$axis sync-$axis -} - -proc disableSync {axis} { - rename sync-$axis _sync-$axis - interp alias {} sync-$axis {} noop -} - -proc sync-x {col first last} { - disableSync x - $col xview moveto [expr {$first*[xvis $col]/($last-$first)}] - foreach side {A B} { - set sb .sbx$side - set xview [.txt$side xview] - if {[lindex $xview 0] > 0 || [lindex $xview 1] < 1} { - grid $sb - eval $sb set $xview - } else { - grid remove $sb - } - } - enableSync x -} - -proc sync-y {first last} { - disableSync y - foreach c [cols] { - $c yview moveto $first - } - if {$first > 0 || $last < 1} { - grid .sby - .sby set $first $last - } else { - grid remove .sby - } - enableSync y -} - -wm withdraw . -wm title . $CFG(TITLE) -wm iconname . $CFG(TITLE) -bind . <q> exit -bind . <Destroy> {after 0 exit} -bind . <Tab> {cycleDiffs; break} -bind . <<PrevWindow>> {cycleDiffs 1; break} -bind . <Return> { - event generate .bb.files <1> - event generate .bb.files <ButtonRelease-1> - break -} -foreach {key axis args} { - Up y {scroll -5 units} - k y {scroll -5 units} - Down y {scroll 5 units} - j y {scroll 5 units} - Left x {scroll -5 units} - h x {scroll -5 units} - Right x {scroll 5 units} - l x {scroll 5 units} - Prior y {scroll -1 page} - b y {scroll -1 page} - Next y {scroll 1 page} - space y {scroll 1 page} - Home y {moveto 0} - g y {moveto 0} - End y {moveto 1} -} { - bind . <$key> "scroll-$axis $args; break" - bind . <Shift-$key> continue -} - -frame .bb -::ttk::menubutton .bb.files -text "Files" -toplevel .wfiles -wm withdraw .wfiles -update idletasks -wm transient .wfiles . -wm overrideredirect .wfiles 1 -listbox .wfiles.lb -width 0 -height $CFG(LB_HEIGHT) -activestyle none \ - -yscroll {.wfiles.sb set} -::ttk::scrollbar .wfiles.sb -command {.wfiles.lb yview} -grid .wfiles.lb .wfiles.sb -sticky ns -bind .bb.files <1> { - set x [winfo rootx %W] - set y [expr {[winfo rooty %W]+[winfo height %W]}] - wm geometry .wfiles +$x+$y - wm deiconify .wfiles - focus .wfiles.lb -} -bind .wfiles <FocusOut> {wm withdraw .wfiles} -bind .wfiles <Escape> {focus .} -foreach evt {1 Return} { - bind .wfiles.lb <$evt> { - catch { - set idx [lindex [.txtA tag ranges fn] [expr {[%W curselection]*2}]] - viewDiff $idx - } - focus . - break - } -} -bind .wfiles.lb <Motion> { - %W selection clear 0 end - %W selection set @%x,%y -} - -foreach {side syncCol} {A .txtB B .txtA} { - set ln .ln$side - text $ln - $ln tag config - -justify right - - set txt .txt$side - text $txt -width $CFG(WIDTH) -height $CFG(HEIGHT) -wrap none \ - -xscroll "sync-x $syncCol" - catch {$txt config -tabstyle wordprocessor} ;# Required for Tk>=8.5 - foreach tag {add rm chng} { - $txt tag config $tag -background $CFG([string toupper $tag]_BG) - $txt tag lower $tag - } - $txt tag config fn -background $CFG(FN_BG) -foreground $CFG(FN_FG) \ - -justify center - $txt tag config err -foreground $CFG(ERR_FG) -} -text .mkr - -foreach c [cols] { - set keyPrefix [string toupper [colType $c]]_COL_ - if {[tk windowingsystem] eq "win32"} {$c config -font {courier 9}} - $c config -bg $CFG(${keyPrefix}BG) -fg $CFG(${keyPrefix}FG) -borderwidth 0 \ - -padx $CFG(PADX) -yscroll sync-y - $c tag config hr -spacing1 $CFG(HR_PAD_TOP) -spacing3 $CFG(HR_PAD_BTM) \ - -foreground $CFG(HR_FG) - $c tag config fn -spacing1 $CFG(FN_PAD) -spacing3 $CFG(FN_PAD) - bindtags $c ". $c Text all" - bind $c <1> {focus %W} -} - -::ttk::scrollbar .sby -command {.txtA yview} -orient vertical -::ttk::scrollbar .sbxA -command {.txtA xview} -orient horizontal -::ttk::scrollbar .sbxB -command {.txtB xview} -orient horizontal -frame .spacer - -if {[readDiffs $fossilcmd] == 0} { - tk_messageBox -type ok -title $CFG(TITLE) -message "No changes" - exit -} -update idletasks - -proc saveDiff {} { - set fn [tk_getSaveFile] - if {$fn==""} return - set out [open $fn wb] - puts $out "#!/usr/bin/tclsh\n#\n# Run this script using 'tclsh' or 'wish'" - puts $out "# to see the graphical diff.\n#" - puts $out "set fossilcmd {}" - puts $out "set prog [list $::prog]" - puts $out "set difftxt \173" - foreach e $::difftxt {puts $out [list $e]} - puts $out "\175" - puts $out "eval \$prog" - close $out -} -proc invertDiff {} { - global CFG - array set x [grid info .txtA] - if {$x(-column)==1} { - grid config .lnB -column 0 - grid config .txtB -column 1 - .txtB tag config add -background $CFG(RM_BG) - grid config .lnA -column 3 - grid config .txtA -column 4 - .txtA tag config rm -background $CFG(ADD_BG) - } else { - grid config .lnA -column 0 - grid config .txtA -column 1 - .txtA tag config rm -background $CFG(RM_BG) - grid config .lnB -column 3 - grid config .txtB -column 4 - .txtB tag config add -background $CFG(ADD_BG) - } - .mkr config -state normal - set clt [.mkr search -all < 1.0 end] - set cgt [.mkr search -all > 1.0 end] - foreach c $clt {.mkr replace $c "$c +1 chars" >} - foreach c $cgt {.mkr replace $c "$c +1 chars" <} - .mkr config -state disabled -} -::ttk::button .bb.quit -text {Quit} -command exit -::ttk::button .bb.invert -text {Invert} -command invertDiff -::ttk::button .bb.save -text {Save As...} -command saveDiff -pack .bb.quit .bb.invert -side left -if {$fossilcmd!=""} {pack .bb.save -side left} -pack .bb.files -side left -grid rowconfigure . 1 -weight 1 -grid columnconfigure . 1 -weight 1 -grid columnconfigure . 4 -weight 1 -grid .bb -row 0 -columnspan 6 -eval grid [cols] -row 1 -sticky nsew -grid .sby -row 1 -column 5 -sticky ns -grid .sbxA -row 2 -columnspan 2 -sticky ew -grid .spacer -row 2 -column 2 -grid .sbxB -row 2 -column 3 -columnspan 2 -sticky ew - -.spacer config -height [winfo height .sbxA] -wm deiconify . -} -eval $prog Index: src/diffcmd.c ================================================================== --- src/diffcmd.c +++ src/diffcmd.c @@ -28,15 +28,10 @@ # define NULL_DEVICE "NUL" #else # define NULL_DEVICE "/dev/null" #endif -/* -** Used when the name for the diff is unknown. -*/ -#define DIFF_NO_NAME "(unknown)" - /* ** Print the "Index:" message that patches wants to see at the top of a diff. */ void diff_print_index(const char *zFile, u64 diffFlags){ if( (diffFlags & (DIFF_SIDEBYSIDE|DIFF_BRIEF))==0 ){ @@ -54,25 +49,15 @@ if( diffFlags & DIFF_BRIEF ){ /* no-op */ }else if( diffFlags & DIFF_SIDEBYSIDE ){ int w = diff_width(diffFlags); int n1 = strlen(zLeft); - int n2 = strlen(zRight); int x; - if( n1==n2 && fossil_strcmp(zLeft,zRight)==0 ){ - if( n1>w*2 ) n1 = w*2; - x = w*2+17 - (n1+2); - z = mprintf("%.*c %.*s %.*c\n", - x/2, '=', n1, zLeft, (x+1)/2, '='); - }else{ - if( w<20 ) w = 20; - if( n1>w-10 ) n1 = w - 10; - if( n2>w-10 ) n2 = w - 10; - z = mprintf("%.*c %.*s %.*c versus %.*c %.*s %.*c\n", - (w-n1+10)/2, '=', n1, zLeft, (w-n1+1)/2, '=', - (w-n2)/2, '=', n2, zRight, (w-n2+1)/2, '='); - } + if( n1>w*2 ) n1 = w*2; + x = w*2+17 - (n1+2); + z = mprintf("%.*c %.*s %.*c\n", + x/2, '=', n1, zLeft, (x+1)/2, '='); }else{ z = mprintf("--- %s\n+++ %s\n", zLeft, zRight); } fossil_print("%s", z); fossil_free(z); @@ -109,11 +94,11 @@ /* Read content of zFile2 into memory */ blob_zero(&file2); if( file_wd_size(zFile2)<0 ){ zName2 = NULL_DEVICE; }else{ - if( file_wd_islink(0) ){ + if( file_wd_islink(zFile2) ){ blob_read_link(&file2, zFile2); }else{ blob_read_from_file(&file2, zFile2); } zName2 = zName; @@ -142,32 +127,32 @@ Blob cmd; /* Text of command to run */ if( !fIncludeBinary ){ Blob file2; if( isBin1 ){ - fossil_print("%s",DIFF_CANNOT_COMPUTE_BINARY); + fossil_print(DIFF_CANNOT_COMPUTE_BINARY); return; } if( zBinGlob ){ Glob *pBinary = glob_create(zBinGlob); if( glob_match(pBinary, zName) ){ - fossil_print("%s",DIFF_CANNOT_COMPUTE_BINARY); + fossil_print(DIFF_CANNOT_COMPUTE_BINARY); glob_free(pBinary); return; } glob_free(pBinary); } blob_zero(&file2); if( file_wd_size(zFile2)>=0 ){ - if( file_wd_islink(0) ){ + if( file_wd_islink(zFile2) ){ blob_read_link(&file2, zFile2); }else{ blob_read_from_file(&file2, zFile2); } } if( looks_like_binary(&file2) ){ - fossil_print("%s",DIFF_CANNOT_COMPUTE_BINARY); + fossil_print(DIFF_CANNOT_COMPUTE_BINARY); blob_reset(&file2); return; } blob_reset(&file2); } @@ -176,11 +161,11 @@ ** zFile2 */ blob_zero(&nameFile1); do{ blob_reset(&nameFile1); blob_appendf(&nameFile1, "%s~%d", zFile2, cnt++); - }while( file_access(blob_str(&nameFile1),F_OK)==0 ); + }while( file_access(blob_str(&nameFile1),0)==0 ); blob_write_to_file(pFile1, blob_str(&nameFile1)); /* Construct the external diff command */ blob_zero(&cmd); blob_appendf(&cmd, "%s ", zDiffCmd); @@ -238,17 +223,17 @@ char zTemp1[300]; char zTemp2[300]; if( !fIncludeBinary ){ if( isBin1 || isBin2 ){ - fossil_print("%s",DIFF_CANNOT_COMPUTE_BINARY); + fossil_print(DIFF_CANNOT_COMPUTE_BINARY); return; } if( zBinGlob ){ Glob *pBinary = glob_create(zBinGlob); if( glob_match(pBinary, zName) ){ - fossil_print("%s",DIFF_CANNOT_COMPUTE_BINARY); + fossil_print(DIFF_CANNOT_COMPUTE_BINARY); glob_free(pBinary); return; } glob_free(pBinary); } @@ -302,11 +287,11 @@ int isBin; file_tree_name(zFileTreeName, &fname, 1); historical_version_of_file(zFrom, blob_str(&fname), &content, &isLink, 0, fIncludeBinary ? 0 : &isBin, 0); if( !isLink != !file_wd_islink(zFrom) ){ - fossil_print("%s",DIFF_CANNOT_COMPUTE_SYMLINK); + fossil_print(DIFF_CANNOT_COMPUTE_SYMLINK); }else{ diff_file(&content, isBin, zFileTreeName, zFileTreeName, zDiffCmd, zBinGlob, fIncludeBinary, diffFlags); } blob_reset(&content); @@ -346,11 +331,11 @@ int rid = name_to_typed_rid(zFrom, "ci"); if( !is_a_version(rid) ){ fossil_fatal("no such check-in: %s", zFrom); } load_vfile_from_rid(rid); - blob_append_sql(&sql, + blob_appendf(&sql, "SELECT v2.pathname, v2.deleted, v2.chnged, v2.rid==0, v1.rid, v1.islink" " FROM vfile v1, vfile v2 " " WHERE v1.pathname=v2.pathname AND v1.vid=%d AND v2.vid=%d" " AND (v2.deleted OR v2.chnged OR v1.mrid!=v2.rid)" "UNION " @@ -363,38 +348,38 @@ "SELECT pathname, 0, 0, 1, 0, islink" " FROM vfile v2" " WHERE v2.vid=%d" " AND NOT EXISTS(SELECT 1 FROM vfile v1" " WHERE v1.vid=%d AND v1.pathname=v2.pathname)" - " ORDER BY 1 /*scan*/", + " ORDER BY 1", rid, vid, rid, vid, vid, rid ); }else{ - blob_append_sql(&sql, + blob_appendf(&sql, "SELECT pathname, deleted, chnged , rid==0, rid, islink" " FROM vfile" " WHERE vid=%d" " AND (deleted OR chnged OR rid==0)" - " ORDER BY pathname /*scan*/", + " ORDER BY pathname", vid ); } - db_prepare(&q, "%s", blob_sql_text(&sql)); + db_prepare(&q, blob_str(&sql)); while( db_step(&q)==SQLITE_ROW ){ 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); int srcid = db_column_int(&q, 4); int isLink = db_column_int(&q, 5); - char *zToFree = mprintf("%s%s", g.zLocalRoot, zPathname); - const char *zFullName = zToFree; + char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname); + char *zToFree = zFullName; int showDiff = 1; if( isDeleted ){ fossil_print("DELETED %s\n", zPathname); if( !asNewFile ){ showDiff = 0; zFullName = NULL_DEVICE; } - }else if( file_access(zFullName, F_OK) ){ + }else if( file_access(zFullName, 0) ){ fossil_print("MISSING %s\n", zPathname); if( !asNewFile ){ showDiff = 0; } }else if( isNew ){ fossil_print("ADDED %s\n", zPathname); srcid = 0; @@ -408,11 +393,11 @@ Blob content; int isBin; if( !isLink != !file_wd_islink(zFullName) ){ diff_print_index(zPathname, diffFlags); diff_print_filenames(zPathname, zPathname, diffFlags); - fossil_print("%s",DIFF_CANNOT_COMPUTE_SYMLINK); + fossil_print(DIFF_CANNOT_COMPUTE_SYMLINK); continue; } if( srcid>0 ){ content_get(srcid, &content); }else{ @@ -462,11 +447,11 @@ fIncludeBinary ? 0 : &isBin1, 0); historical_version_of_file(zTo, zName, &v2, &isLink2, 0, fIncludeBinary ? 0 : &isBin2, 0); if( isLink1 != isLink2 ){ diff_print_filenames(zName, zName, diffFlags); - fossil_print("%s",DIFF_CANNOT_COMPUTE_SYMLINK); + fossil_print(DIFF_CANNOT_COMPUTE_SYMLINK); }else{ diff_file_mem(&v1, &v2, isBin1, isBin2, zName, zDiffCmd, zBinGlob, fIncludeBinary, diffFlags); } blob_reset(&v1); @@ -494,18 +479,11 @@ u64 diffFlags ){ Blob f1, f2; int isBin1, isBin2; int rid; - const char *zName; - if( pFrom ){ - zName = pFrom->zName; - }else if( pTo ){ - zName = pTo->zName; - }else{ - zName = DIFF_NO_NAME; - } + const char *zName = pFrom ? pFrom->zName : pTo->zName; if( diffFlags & DIFF_BRIEF ) return; diff_print_index(zName, diffFlags); if( pFrom ){ rid = uuid_to_rid(pFrom->zUuid, 0); content_get(rid, &f1); @@ -616,74 +594,352 @@ zDefault = 0; zName = "diff-command"; } return db_get(zName, zDefault); } + +/* A Tcl/Tk script used to render diff output. +*/ +static const char zDiffScript[] = +@ package require Tk +@ +@ array set CFG { +@ 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 +@ CHNG_BG #d0d0ff +@ ADD_BG #c0ffc0 +@ RM_BG #ffc0c0 +@ HR_FG #888888 +@ HR_PAD_TOP 4 +@ HR_PAD_BTM 8 +@ FN_BG #444444 +@ FN_FG #ffffff +@ FN_PAD 5 +@ 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 {}] +@ return [string map {& & < < > > ' ' " \"} $x] +@ } +@ +@ proc cols {} { +@ return [list .lnA .txtA .mkr .lnB .txtB] +@ } +@ +@ proc colType {c} { +@ regexp {[a-z]+} $c type +@ return $type +@ } +@ +@ proc readDiffs {fossilcmd} { +@ set in [open $fossilcmd r] +@ fconfigure $in -encoding utf-8 +@ set nDiffs 0 +@ array set widths {txt 0 ln 0 mkr 0} +@ while {[gets $in line] != -1} { +@ if {![regexp {^=+\s+(.*?)\s+=+$} $line all fn]} { +@ continue +@ } +@ if {[string compare -length 6 [gets $in] "<table"]} { +@ continue +@ } +@ incr nDiffs +@ set idx [expr {$nDiffs > 1 ? [.txtA index end] : "1.0"}] +@ .wfiles.lb insert end $fn +@ +@ foreach c [cols] { +@ while {[gets $in] ne "<pre>"} continue +@ +@ if {$nDiffs > 1} { +@ $c insert end \n - +@ } +@ if {[colType $c] eq "txt"} { +@ $c insert end $fn\n fn +@ } else { +@ $c insert end \n fn +@ } +@ $c insert end \n - +@ +@ set type [colType $c] +@ set str {} +@ while {[set line [gets $in]] ne "</pre>"} { +@ set len [string length [dehtml $line]] +@ if {$len > $widths($type)} { +@ set widths($type) $len +@ } +@ append str $line\n +@ } +@ +@ set re {<span class="diff([a-z]+)">([^<]*)</span>} +@ # Use \r as separator since it can't appear in the diff output (it gets +@ # converted to a space). +@ set str [regsub -all $re $str "\r\\1\r\\2\r"] +@ foreach {pre class mid} [split $str \r] { +@ if {$class ne ""} { +@ $c insert end [dehtml $pre] - [dehtml $mid] [list $class -] +@ } else { +@ $c insert end [dehtml $pre] - +@ } +@ } +@ } +@ } +@ close $in +@ +@ foreach c [cols] { +@ set type [colType $c] +@ if {$type ne "txt"} { +@ $c config -width $widths($type) +@ } +@ $c config -state disabled +@ } +@ if {$nDiffs <= [.wfiles.lb cget -height]} { +@ .wfiles.lb config -height $nDiffs +@ grid remove .wfiles.sb +@ } +@ +@ return $nDiffs +@ } +@ +@ proc viewDiff {idx} { +@ .txtA yview $idx +@ .txtA xview moveto 0 +@ } +@ +@ proc cycleDiffs {{reverse 0}} { +@ if {$reverse} { +@ set range [.txtA tag prevrange fn @0,0 1.0] +@ if {$range eq ""} { +@ viewDiff {fn.last -1c} +@ } else { +@ viewDiff [lindex $range 0] +@ } +@ } else { +@ set range [.txtA tag nextrange fn {@0,0 +1c} end] +@ if {$range eq "" || [lindex [.txtA yview] 1] == 1} { +@ viewDiff fn.first +@ } else { +@ viewDiff [lindex $range 0] +@ } +@ } +@ } +@ +@ proc xvis {col} { +@ set view [$col xview] +@ return [expr {[lindex $view 1]-[lindex $view 0]}] +@ } +@ +@ proc scroll-x {args} { +@ set c .txt[expr {[xvis .txtA] < [xvis .txtB] ? "A" : "B"}] +@ eval $c xview $args +@ } +@ +@ interp alias {} scroll-y {} .txtA yview +@ +@ proc noop {args} {} +@ +@ proc enableSync {axis} { +@ update idletasks +@ interp alias {} sync-$axis {} +@ rename _sync-$axis sync-$axis +@ } +@ +@ proc disableSync {axis} { +@ rename sync-$axis _sync-$axis +@ interp alias {} sync-$axis {} noop +@ } +@ +@ proc sync-x {col first last} { +@ disableSync x +@ $col xview moveto [expr {$first*[xvis $col]/($last-$first)}] +@ foreach side {A B} { +@ set sb .sbx$side +@ set xview [.txt$side xview] +@ if {[lindex $xview 0] > 0 || [lindex $xview 1] < 1} { +@ grid $sb +@ eval $sb set $xview +@ } else { +@ grid remove $sb +@ } +@ } +@ enableSync x +@ } +@ +@ proc sync-y {first last} { +@ disableSync y +@ foreach c [cols] { +@ $c yview moveto $first +@ } +@ if {$first > 0 || $last < 1} { +@ grid .sby +@ .sby set $first $last +@ } else { +@ grid remove .sby +@ } +@ enableSync y +@ } +@ +@ wm withdraw . +@ wm title . $CFG(TITLE) +@ wm iconname . $CFG(TITLE) +@ bind . <q> exit +@ bind . <Tab> {cycleDiffs; break} +@ bind . <<PrevWindow>> {cycleDiffs 1; break} +@ bind . <Return> { +@ event generate .files <1> +@ event generate .files <ButtonRelease-1> +@ break +@ } +@ foreach {key axis args} { +@ Up y {scroll -5 units} +@ Down y {scroll 5 units} +@ Left x {scroll -5 units} +@ Right x {scroll 5 units} +@ Prior y {scroll -1 page} +@ Next y {scroll 1 page} +@ Home y {moveto 0} +@ End y {moveto 1} +@ } { +@ bind . <$key> "scroll-$axis $args; break" +@ bind . <Shift-$key> continue +@ } +@ +@ ::ttk::menubutton .files -text "Files" +@ toplevel .wfiles +@ wm withdraw .wfiles +@ update idletasks +@ wm transient .wfiles . +@ wm overrideredirect .wfiles 1 +@ listbox .wfiles.lb -width 0 -height $CFG(LB_HEIGHT) -activestyle none \ +@ -yscroll {.wfiles.sb set} +@ ::ttk::scrollbar .wfiles.sb -command {.wfiles.lb yview} +@ grid .wfiles.lb .wfiles.sb -sticky ns +@ bind .files <1> { +@ set x [winfo rootx %W] +@ set y [expr {[winfo rooty %W]+[winfo height %W]}] +@ wm geometry .wfiles +$x+$y +@ wm deiconify .wfiles +@ focus .wfiles.lb +@ } +@ bind .wfiles <FocusOut> {wm withdraw .wfiles} +@ bind .wfiles <Escape> {focus .} +@ foreach evt {1 Return} { +@ bind .wfiles.lb <$evt> { +@ catch { +@ set idx [lindex [.txtA tag ranges fn] [expr {[%W curselection]*2}]] +@ viewDiff $idx +@ } +@ focus . +@ break +@ } +@ } +@ bind .wfiles.lb <Motion> { +@ %W selection clear 0 end +@ %W selection set @%x,%y +@ } +@ +@ foreach {side syncCol} {A .txtB B .txtA} { +@ set ln .ln$side +@ text $ln +@ $ln tag config - -justify right +@ +@ set txt .txt$side +@ text $txt -width $CFG(WIDTH) -height $CFG(HEIGHT) -wrap none \ +@ -xscroll "sync-x $syncCol" +@ catch {$txt config -tabstyle wordprocessor} ;# Required for Tk>=8.5 +@ foreach tag {add rm chng} { +@ $txt tag config $tag -background $CFG([string toupper $tag]_BG) +@ $txt tag lower $tag +@ } +@ $txt tag config fn -background $CFG(FN_BG) -foreground $CFG(FN_FG) \ +@ -justify center +@ } +@ text .mkr +@ +@ foreach c [cols] { +@ set keyPrefix [string toupper [colType $c]]_COL_ +@ if {[tk windowingsystem] eq "win32"} {$c config -font {courier 9}} +@ $c config -bg $CFG(${keyPrefix}BG) -fg $CFG(${keyPrefix}FG) -borderwidth 0 \ +@ -padx $CFG(PADX) -yscroll sync-y +@ $c tag config hr -spacing1 $CFG(HR_PAD_TOP) -spacing3 $CFG(HR_PAD_BTM) \ +@ -foreground $CFG(HR_FG) +@ $c tag config fn -spacing1 $CFG(FN_PAD) -spacing3 $CFG(FN_PAD) +@ bindtags $c ". $c Text all" +@ bind $c <1> {focus %W} +@ } +@ +@ ::ttk::scrollbar .sby -command {.txtA yview} -orient vertical +@ ::ttk::scrollbar .sbxA -command {.txtA xview} -orient horizontal +@ ::ttk::scrollbar .sbxB -command {.txtB xview} -orient horizontal +@ frame .spacer +@ +@ if {[readDiffs $fossilcmd] == 0} { +@ tk_messageBox -type ok -title $CFG(TITLE) -message "No changes" +@ exit +@ } +@ update idletasks +@ +@ grid rowconfigure . 1 -weight 1 +@ grid columnconfigure . 1 -weight 1 +@ grid columnconfigure . 4 -weight 1 +@ grid .files -row 0 -columnspan 6 +@ eval grid [cols] -row 1 -sticky nsew +@ grid .sby -row 1 -column 5 -sticky ns +@ grid .sbxA -row 2 -columnspan 2 -sticky ew +@ grid .spacer -row 2 -column 2 +@ grid .sbxB -row 2 -column 3 -columnspan 2 -sticky ew +@ +@ .spacer config -height [winfo height .sbxA] +@ wm deiconify . +; /* ** Show diff output in a Tcl/Tk window, in response to the --tk option ** to the diff command. -** -** If fossil has direct access to a Tcl interpreter (either loaded -** dynamically through stubs or linked in statically), we can use it -** directly. Otherwise: +** +** Steps: ** (1) Write the Tcl/Tk script used for rendering into a temp file. -** (2) Invoke "tclsh" on the temp file using fossil_system(). +** (2) Invoke "wish" on the temp file using fossil_system(). ** (3) Delete the temp file. */ void diff_tk(const char *zSubCmd, int firstArg){ int i; Blob script; - const char *zTempFile = 0; + char *zTempFile; char *zCmd; blob_zero(&script); blob_appendf(&script, "set fossilcmd {| \"%/\" %s --html -y -i -v", g.nameOfExe, zSubCmd); - find_option("html",0,0); - find_option("side-by-side","y",0); - find_option("internal","i",0); - find_option("verbose","v",0); - /* The undocumented --script FILENAME option causes the Tk script to - ** be written into the FILENAME instead of being run. This is used - ** for testing and debugging. */ - zTempFile = find_option("script",0,1); for(i=firstArg; i<g.argc; i++){ const char *z = g.argv[i]; - if( sqlite3_strglob("*}*",z) ){ - 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, "}\n%s", builtin_file("diff.tcl", 0)); - if( zTempFile ){ - blob_write_to_file(&script, zTempFile); - fossil_print("To see diff, run: tclsh \"%s\"\n", zTempFile); - }else{ -#if defined(FOSSIL_ENABLE_TCL) - Th_FossilInit(TH_INIT_DEFAULT); - if( evaluateTclWithEvents(g.interp, &g.tcl, blob_str(&script), - blob_size(&script), 1, 0)==TCL_OK ){ - blob_reset(&script); - return; - } - /* - * If evaluation of the Tcl script fails, the reason may be that Tk - * could not be found by the loaded Tcl, or that Tcl cannot be loaded - * dynamically (e.g. x64 Tcl with x86 Fossil). Therefore, fallback - * to using the external "tclsh", if available. - */ -#endif - zTempFile = write_blob_to_temp_file(&script); - zCmd = mprintf("tclsh \"%s\"", zTempFile); - fossil_system(zCmd); - file_delete(zTempFile); - fossil_free(zCmd); - } - blob_reset(&script); + if( z[0]=='-' ){ + if( strglob("*-html",z) ) continue; + if( strglob("*-y",z) ) continue; + if( strglob("*-i",z) ) continue; + } + blob_append(&script, " ", 1); + shell_escape(&script, z); + } + blob_appendf(&script, "}\n%s", zDiffScript); + zTempFile = write_blob_to_temp_file(&script); + zCmd = mprintf("tclsh \"%s\"", zTempFile); + fossil_system(zCmd); + file_delete(zTempFile); + fossil_free(zCmd); } /* ** Returns non-zero if files that may be binary should be used with external ** diff programs. @@ -718,11 +974,11 @@ ** specified (as they exist on disk) and that same file as it was checked ** out. Or if the FILE arguments are omitted, show the unsaved changed ** currently in the working check-out. ** ** If the "--from VERSION" or "-r VERSION" option is used it specifies -** the source check-in for the diff operation. If not specified, the +** 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. ** ** If the "--to VERSION" option appears, it 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 @@ -742,26 +998,23 @@ ** The "--binary" option causes files matching the glob PATTERN to be treated ** as binary when considering if they should be used with external diff program. ** This option overrides the "binary-glob" setting. ** ** 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 -** --context|-c N Use N lines of context -** --diff-binary BOOL Include binary files when using external commands -** --from|-r VERSION select VERSION as source for the diff -** --internal|-i use internal diff logic -** --side-by-side|-y side-by-side diff -** --strip-trailing-cr Strip trailing CR -** --tk Launch a Tcl/Tk GUI for display -** --to VERSION select VERSION as target for the diff -** --unified unified diff -** -v|--verbose output complete text of added or deleted files -** -w|--ignore-all-space Ignore white space when comparing lines -** -W|--width <num> Width of lines in side-by-side diff -** -Z|--ignore-trailing-space Ignore changes to end-of-line whitespace +** --binary PATTERN Treat files that match the glob PATTERN as binary +** --branch BRANCH Show diff of all changes on BRANCH +** --brief Show filenames only +** --context|-c N Use N lines of context +** --diff-binary BOOL Include binary files when using external commands +** --from|-r VERSION select VERSION as source for the diff +** --internal|-i use internal diff logic +** --side-by-side|-y side-by-side diff +** --tk Launch a Tcl/Tk GUI for display +** --to VERSION select VERSION as target for the diff +** --unified unified diff +** -v|--verbose output complete text of added or deleted files +** -W|--width Width of lines in side-by-side diff */ void diff_cmd(void){ int isGDiff; /* True for gdiff. False for normal diff */ int isInternDiff; /* True for internal diff */ int verboseFlag; /* True if -v or --verbose flag is used */ @@ -787,10 +1040,11 @@ verboseFlag = find_option("verbose","v",0)!=0; if( !verboseFlag ){ verboseFlag = find_option("new-file","N",0)!=0; /* deprecated */ } if( verboseFlag ) diffFlags |= DIFF_VERBOSE; + if( zBranch ){ if( zTo || zFrom ){ fossil_fatal("cannot use --from or --to with --branch"); } zTo = zBranch; @@ -841,11 +1095,11 @@ */ void vpatch_page(void){ const char *zFrom = P("from"); const char *zTo = P("to"); login_check_credentials(); - if( !g.perm.Read ){ login_needed(g.anon.Read); return; } + if( !g.perm.Read ){ login_needed(); return; } if( zFrom==0 || zTo==0 ) fossil_redirect_home(); cgi_set_content_type("text/plain"); diff_all_two_versions(zFrom, zTo, 0, 0, 0, DIFF_VERBOSE); } Index: src/doc.c ================================================================== --- src/doc.c +++ src/doc.c @@ -26,11 +26,11 @@ ** Try to guess the mimetype from content. ** ** If the content is pure text, return NULL. ** ** For image types, attempt to return an appropriate mimetype -** name like "image/gif" or "image/jpeg". +** name like "image/gif" or "image/jpeg". ** ** For any other binary type, return "unknown/unknown". */ const char *mimetype_from_content(Blob *pBlob){ int i; @@ -65,252 +65,18 @@ } } if( i>=n ){ return 0; /* Plain text */ } - for(i=0; i<ArraySize(aMime); i++){ + for(i=0; i<sizeof(aMime)/sizeof(aMime[0]); i++){ if( n>=aMime[i].size && memcmp(x, aMime[i].zPrefix, aMime[i].size)==0 ){ return aMime[i].zMimetype; } } return "unknown/unknown"; } -/* A table of mimetypes based on file suffixes. -** Suffixes must be in sorted order so that we can do a binary -** search to find the mime-type -*/ -static const struct { - const char *zSuffix; /* The file suffix */ - int size; /* Length of the suffix */ - const char *zMimetype; /* The corresponding mimetype */ -} aMime[] = { - { "ai", 2, "application/postscript" }, - { "aif", 3, "audio/x-aiff" }, - { "aifc", 4, "audio/x-aiff" }, - { "aiff", 4, "audio/x-aiff" }, - { "arj", 3, "application/x-arj-compressed" }, - { "asc", 3, "text/plain" }, - { "asf", 3, "video/x-ms-asf" }, - { "asx", 3, "video/x-ms-asx" }, - { "au", 2, "audio/ulaw" }, - { "avi", 3, "video/x-msvideo" }, - { "bat", 3, "application/x-msdos-program" }, - { "bcpio", 5, "application/x-bcpio" }, - { "bin", 3, "application/octet-stream" }, - { "c", 1, "text/plain" }, - { "cc", 2, "text/plain" }, - { "ccad", 4, "application/clariscad" }, - { "cdf", 3, "application/x-netcdf" }, - { "class", 5, "application/octet-stream" }, - { "cod", 3, "application/vnd.rim.cod" }, - { "com", 3, "application/x-msdos-program" }, - { "cpio", 4, "application/x-cpio" }, - { "cpt", 3, "application/mac-compactpro" }, - { "csh", 3, "application/x-csh" }, - { "css", 3, "text/css" }, - { "csv", 3, "text/csv" }, - { "dcr", 3, "application/x-director" }, - { "deb", 3, "application/x-debian-package" }, - { "dir", 3, "application/x-director" }, - { "dl", 2, "video/dl" }, - { "dms", 3, "application/octet-stream" }, - { "doc", 3, "application/msword" }, - { "docx", 4, "application/vnd.openxmlformats-" - "officedocument.wordprocessingml.document"}, - { "dot", 3, "application/msword" }, - { "dotx", 4, "application/vnd.openxmlformats-" - "officedocument.wordprocessingml.template"}, - { "drw", 3, "application/drafting" }, - { "dvi", 3, "application/x-dvi" }, - { "dwg", 3, "application/acad" }, - { "dxf", 3, "application/dxf" }, - { "dxr", 3, "application/x-director" }, - { "eps", 3, "application/postscript" }, - { "etx", 3, "text/x-setext" }, - { "exe", 3, "application/octet-stream" }, - { "ez", 2, "application/andrew-inset" }, - { "f", 1, "text/plain" }, - { "f90", 3, "text/plain" }, - { "fli", 3, "video/fli" }, - { "flv", 3, "video/flv" }, - { "gif", 3, "image/gif" }, - { "gl", 2, "video/gl" }, - { "gtar", 4, "application/x-gtar" }, - { "gz", 2, "application/x-gzip" }, - { "h", 1, "text/plain" }, - { "hdf", 3, "application/x-hdf" }, - { "hh", 2, "text/plain" }, - { "hqx", 3, "application/mac-binhex40" }, - { "htm", 3, "text/html" }, - { "html", 4, "text/html" }, - { "ice", 3, "x-conference/x-cooltalk" }, - { "ief", 3, "image/ief" }, - { "iges", 4, "model/iges" }, - { "igs", 3, "model/iges" }, - { "ips", 3, "application/x-ipscript" }, - { "ipx", 3, "application/x-ipix" }, - { "jad", 3, "text/vnd.sun.j2me.app-descriptor" }, - { "jar", 3, "application/java-archive" }, - { "jpe", 3, "image/jpeg" }, - { "jpeg", 4, "image/jpeg" }, - { "jpg", 3, "image/jpeg" }, - { "js", 2, "application/x-javascript" }, - { "kar", 3, "audio/midi" }, - { "latex", 5, "application/x-latex" }, - { "lha", 3, "application/octet-stream" }, - { "lsp", 3, "application/x-lisp" }, - { "lzh", 3, "application/octet-stream" }, - { "m", 1, "text/plain" }, - { "m3u", 3, "audio/x-mpegurl" }, - { "man", 3, "application/x-troff-man" }, - { "markdown", 8, "text/x-markdown" }, - { "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" }, - { "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" }, - { "mpeg", 4, "video/mpeg" }, - { "mpg", 3, "video/mpeg" }, - { "mpga", 4, "audio/mpeg" }, - { "ms", 2, "application/x-troff-ms" }, - { "msh", 3, "model/mesh" }, - { "nc", 2, "application/x-netcdf" }, - { "oda", 3, "application/oda" }, - { "odp", 3, "application/vnd.oasis.opendocument.presentation" }, - { "ods", 3, "application/vnd.oasis.opendocument.spreadsheet" }, - { "odt", 3, "application/vnd.oasis.opendocument.text" }, - { "ogg", 3, "application/ogg" }, - { "ogm", 3, "application/ogg" }, - { "pbm", 3, "image/x-portable-bitmap" }, - { "pdb", 3, "chemical/x-pdb" }, - { "pdf", 3, "application/pdf" }, - { "pgm", 3, "image/x-portable-graymap" }, - { "pgn", 3, "application/x-chess-pgn" }, - { "pgp", 3, "application/pgp" }, - { "pl", 2, "application/x-perl" }, - { "pm", 2, "application/x-perl" }, - { "png", 3, "image/png" }, - { "pnm", 3, "image/x-portable-anymap" }, - { "pot", 3, "application/mspowerpoint" }, - { "potx", 4, "application/vnd.openxmlformats-" - "officedocument.presentationml.template"}, - { "ppm", 3, "image/x-portable-pixmap" }, - { "pps", 3, "application/mspowerpoint" }, - { "ppsx", 4, "application/vnd.openxmlformats-" - "officedocument.presentationml.slideshow"}, - { "ppt", 3, "application/mspowerpoint" }, - { "pptx", 4, "application/vnd.openxmlformats-" - "officedocument.presentationml.presentation"}, - { "ppz", 3, "application/mspowerpoint" }, - { "pre", 3, "application/x-freelance" }, - { "prt", 3, "application/pro_eng" }, - { "ps", 2, "application/postscript" }, - { "qt", 2, "video/quicktime" }, - { "ra", 2, "audio/x-realaudio" }, - { "ram", 3, "audio/x-pn-realaudio" }, - { "rar", 3, "application/x-rar-compressed" }, - { "ras", 3, "image/cmu-raster" }, - { "rgb", 3, "image/x-rgb" }, - { "rm", 2, "audio/x-pn-realaudio" }, - { "roff", 4, "application/x-troff" }, - { "rpm", 3, "audio/x-pn-realaudio-plugin" }, - { "rtf", 3, "text/rtf" }, - { "rtx", 3, "text/richtext" }, - { "scm", 3, "application/x-lotusscreencam" }, - { "set", 3, "application/set" }, - { "sgm", 3, "text/sgml" }, - { "sgml", 4, "text/sgml" }, - { "sh", 2, "application/x-sh" }, - { "shar", 4, "application/x-shar" }, - { "silo", 4, "model/mesh" }, - { "sit", 3, "application/x-stuffit" }, - { "skd", 3, "application/x-koan" }, - { "skm", 3, "application/x-koan" }, - { "skp", 3, "application/x-koan" }, - { "skt", 3, "application/x-koan" }, - { "smi", 3, "application/smil" }, - { "smil", 4, "application/smil" }, - { "snd", 3, "audio/basic" }, - { "sol", 3, "application/solids" }, - { "spl", 3, "application/x-futuresplash" }, - { "src", 3, "application/x-wais-source" }, - { "step", 4, "application/STEP" }, - { "stl", 3, "application/SLA" }, - { "stp", 3, "application/STEP" }, - { "sv4cpio", 7, "application/x-sv4cpio" }, - { "sv4crc", 6, "application/x-sv4crc" }, - { "svg", 3, "image/svg+xml" }, - { "swf", 3, "application/x-shockwave-flash" }, - { "t", 1, "application/x-troff" }, - { "tar", 3, "application/x-tar" }, - { "tcl", 3, "application/x-tcl" }, - { "tex", 3, "application/x-tex" }, - { "texi", 4, "application/x-texinfo" }, - { "texinfo", 7, "application/x-texinfo" }, - { "tgz", 3, "application/x-tar-gz" }, - { "th1", 3, "application/x-th1" }, - { "tif", 3, "image/tiff" }, - { "tiff", 4, "image/tiff" }, - { "tr", 2, "application/x-troff" }, - { "tsi", 3, "audio/TSP-audio" }, - { "tsp", 3, "application/dsptype" }, - { "tsv", 3, "text/tab-separated-values" }, - { "txt", 3, "text/plain" }, - { "unv", 3, "application/i-deas" }, - { "ustar", 5, "application/x-ustar" }, - { "vcd", 3, "application/x-cdlink" }, - { "vda", 3, "application/vda" }, - { "viv", 3, "video/vnd.vivo" }, - { "vivo", 4, "video/vnd.vivo" }, - { "vrml", 4, "model/vrml" }, - { "wav", 3, "audio/x-wav" }, - { "wax", 3, "audio/x-ms-wax" }, - { "wiki", 4, "text/x-fossil-wiki" }, - { "wma", 3, "audio/x-ms-wma" }, - { "wmv", 3, "video/x-ms-wmv" }, - { "wmx", 3, "video/x-ms-wmx" }, - { "wrl", 3, "model/vrml" }, - { "wvx", 3, "video/x-ms-wvx" }, - { "xbm", 3, "image/x-xbitmap" }, - { "xlc", 3, "application/vnd.ms-excel" }, - { "xll", 3, "application/vnd.ms-excel" }, - { "xlm", 3, "application/vnd.ms-excel" }, - { "xls", 3, "application/vnd.ms-excel" }, - { "xlsx", 4, "application/vnd.openxmlformats-" - "officedocument.spreadsheetml.sheet"}, - { "xlw", 3, "application/vnd.ms-excel" }, - { "xml", 3, "text/xml" }, - { "xpm", 3, "image/x-xpixmap" }, - { "xwd", 3, "image/x-xwindowdump" }, - { "xyz", 3, "chemical/x-pdb" }, - { "zip", 3, "application/zip" }, -}; - -/* -** Verify that all entries in the aMime[] table are in sorted order. -** Abort with a fatal error if any is out-of-order. -*/ -static void mimetype_verify(void){ - int i; - for(i=1; i<ArraySize(aMime); i++){ - if( fossil_strcmp(aMime[i-1].zSuffix,aMime[i].zSuffix)>=0 ){ - fossil_fatal("mimetypes out of sequence: %s before %s", - aMime[i-1].zSuffix, aMime[i].zSuffix); - } - } -} - /* ** Guess the mime-type of a document based on its name. */ const char *mimetype_from_name(const char *zName){ const char *z; @@ -317,17 +83,230 @@ int i; int first, last; int len; char zSuffix[20]; + /* A table of mimetypes based on file suffixes. + ** Suffixes must be in sorted order so that we can do a binary + ** search to find the mime-type + */ + static const struct { + const char *zSuffix; /* The file suffix */ + int size; /* Length of the suffix */ + const char *zMimetype; /* The corresponding mimetype */ + } aMime[] = { + { "ai", 2, "application/postscript" }, + { "aif", 3, "audio/x-aiff" }, + { "aifc", 4, "audio/x-aiff" }, + { "aiff", 4, "audio/x-aiff" }, + { "arj", 3, "application/x-arj-compressed" }, + { "asc", 3, "text/plain" }, + { "asf", 3, "video/x-ms-asf" }, + { "asx", 3, "video/x-ms-asx" }, + { "au", 2, "audio/ulaw" }, + { "avi", 3, "video/x-msvideo" }, + { "bat", 3, "application/x-msdos-program" }, + { "bcpio", 5, "application/x-bcpio" }, + { "bin", 3, "application/octet-stream" }, + { "c", 1, "text/plain" }, + { "cc", 2, "text/plain" }, + { "ccad", 4, "application/clariscad" }, + { "cdf", 3, "application/x-netcdf" }, + { "class", 5, "application/octet-stream" }, + { "cod", 3, "application/vnd.rim.cod" }, + { "com", 3, "application/x-msdos-program" }, + { "cpio", 4, "application/x-cpio" }, + { "cpt", 3, "application/mac-compactpro" }, + { "csh", 3, "application/x-csh" }, + { "css", 3, "text/css" }, + { "dcr", 3, "application/x-director" }, + { "deb", 3, "application/x-debian-package" }, + { "dir", 3, "application/x-director" }, + { "dl", 2, "video/dl" }, + { "dms", 3, "application/octet-stream" }, + { "doc", 3, "application/msword" }, + { "docx", 4, "application/vnd.openxmlformats-officedocument.wordprocessingml.document"}, + { "dot", 3, "application/msword" }, + { "dotx", 4, "application/vnd.openxmlformats-officedocument.wordprocessingml.template"}, + { "drw", 3, "application/drafting" }, + { "dvi", 3, "application/x-dvi" }, + { "dwg", 3, "application/acad" }, + { "dxf", 3, "application/dxf" }, + { "dxr", 3, "application/x-director" }, + { "eps", 3, "application/postscript" }, + { "etx", 3, "text/x-setext" }, + { "exe", 3, "application/octet-stream" }, + { "ez", 2, "application/andrew-inset" }, + { "f", 1, "text/plain" }, + { "f90", 3, "text/plain" }, + { "fli", 3, "video/fli" }, + { "flv", 3, "video/flv" }, + { "gif", 3, "image/gif" }, + { "gl", 2, "video/gl" }, + { "gtar", 4, "application/x-gtar" }, + { "gz", 2, "application/x-gzip" }, + { "h", 1, "text/plain" }, + { "hdf", 3, "application/x-hdf" }, + { "hh", 2, "text/plain" }, + { "hqx", 3, "application/mac-binhex40" }, + { "htm", 3, "text/html" }, + { "html", 4, "text/html" }, + { "ice", 3, "x-conference/x-cooltalk" }, + { "ief", 3, "image/ief" }, + { "iges", 4, "model/iges" }, + { "igs", 3, "model/iges" }, + { "ips", 3, "application/x-ipscript" }, + { "ipx", 3, "application/x-ipix" }, + { "jad", 3, "text/vnd.sun.j2me.app-descriptor" }, + { "jar", 3, "application/java-archive" }, + { "jpe", 3, "image/jpeg" }, + { "jpeg", 4, "image/jpeg" }, + { "jpg", 3, "image/jpeg" }, + { "js", 2, "application/x-javascript" }, + { "kar", 3, "audio/midi" }, + { "latex", 5, "application/x-latex" }, + { "lha", 3, "application/octet-stream" }, + { "lsp", 3, "application/x-lisp" }, + { "lzh", 3, "application/octet-stream" }, + { "m", 1, "text/plain" }, + { "m3u", 3, "audio/x-mpegurl" }, + { "man", 3, "application/x-troff-man" }, + { "markdown", 8, "text/x-markdown" }, + { "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" }, + { "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" }, + { "mpeg", 4, "video/mpeg" }, + { "mpg", 3, "video/mpeg" }, + { "mpga", 4, "audio/mpeg" }, + { "ms", 2, "application/x-troff-ms" }, + { "msh", 3, "model/mesh" }, + { "nc", 2, "application/x-netcdf" }, + { "oda", 3, "application/oda" }, + { "ogg", 3, "application/ogg" }, + { "ogm", 3, "application/ogg" }, + { "pbm", 3, "image/x-portable-bitmap" }, + { "pdb", 3, "chemical/x-pdb" }, + { "pdf", 3, "application/pdf" }, + { "pgm", 3, "image/x-portable-graymap" }, + { "pgn", 3, "application/x-chess-pgn" }, + { "pgp", 3, "application/pgp" }, + { "pl", 2, "application/x-perl" }, + { "pm", 2, "application/x-perl" }, + { "png", 3, "image/png" }, + { "pnm", 3, "image/x-portable-anymap" }, + { "pot", 3, "application/mspowerpoint" }, + { "potx", 4, "application/vnd.openxmlformats-officedocument.presentationml.template"}, + { "ppm", 3, "image/x-portable-pixmap" }, + { "pps", 3, "application/mspowerpoint" }, + { "ppsx", 4, "application/vnd.openxmlformats-officedocument.presentationml.slideshow"}, + { "ppt", 3, "application/mspowerpoint" }, + { "pptx", 4, "application/vnd.openxmlformats-officedocument.presentationml.presentation"}, + { "ppz", 3, "application/mspowerpoint" }, + { "pre", 3, "application/x-freelance" }, + { "prt", 3, "application/pro_eng" }, + { "ps", 2, "application/postscript" }, + { "qt", 2, "video/quicktime" }, + { "ra", 2, "audio/x-realaudio" }, + { "ram", 3, "audio/x-pn-realaudio" }, + { "rar", 3, "application/x-rar-compressed" }, + { "ras", 3, "image/cmu-raster" }, + { "rgb", 3, "image/x-rgb" }, + { "rm", 2, "audio/x-pn-realaudio" }, + { "roff", 4, "application/x-troff" }, + { "rpm", 3, "audio/x-pn-realaudio-plugin" }, + { "rtf", 3, "text/rtf" }, + { "rtx", 3, "text/richtext" }, + { "scm", 3, "application/x-lotusscreencam" }, + { "set", 3, "application/set" }, + { "sgm", 3, "text/sgml" }, + { "sgml", 4, "text/sgml" }, + { "sh", 2, "application/x-sh" }, + { "shar", 4, "application/x-shar" }, + { "silo", 4, "model/mesh" }, + { "sit", 3, "application/x-stuffit" }, + { "skd", 3, "application/x-koan" }, + { "skm", 3, "application/x-koan" }, + { "skp", 3, "application/x-koan" }, + { "skt", 3, "application/x-koan" }, + { "smi", 3, "application/smil" }, + { "smil", 4, "application/smil" }, + { "snd", 3, "audio/basic" }, + { "sol", 3, "application/solids" }, + { "spl", 3, "application/x-futuresplash" }, + { "src", 3, "application/x-wais-source" }, + { "step", 4, "application/STEP" }, + { "stl", 3, "application/SLA" }, + { "stp", 3, "application/STEP" }, + { "sv4cpio", 7, "application/x-sv4cpio" }, + { "sv4crc", 6, "application/x-sv4crc" }, + { "svg", 3, "image/svg+xml" }, + { "swf", 3, "application/x-shockwave-flash" }, + { "t", 1, "application/x-troff" }, + { "tar", 3, "application/x-tar" }, + { "tcl", 3, "application/x-tcl" }, + { "tex", 3, "application/x-tex" }, + { "texi", 4, "application/x-texinfo" }, + { "texinfo", 7, "application/x-texinfo" }, + { "tgz", 3, "application/x-tar-gz" }, + { "tif", 3, "image/tiff" }, + { "tiff", 4, "image/tiff" }, + { "tr", 2, "application/x-troff" }, + { "tsi", 3, "audio/TSP-audio" }, + { "tsp", 3, "application/dsptype" }, + { "tsv", 3, "text/tab-separated-values" }, + { "txt", 3, "text/plain" }, + { "unv", 3, "application/i-deas" }, + { "ustar", 5, "application/x-ustar" }, + { "vcd", 3, "application/x-cdlink" }, + { "vda", 3, "application/vda" }, + { "viv", 3, "video/vnd.vivo" }, + { "vivo", 4, "video/vnd.vivo" }, + { "vrml", 4, "model/vrml" }, + { "wav", 3, "audio/x-wav" }, + { "wax", 3, "audio/x-ms-wax" }, + { "wiki", 4, "text/x-fossil-wiki" }, + { "wma", 3, "audio/x-ms-wma" }, + { "wmv", 3, "video/x-ms-wmv" }, + { "wmx", 3, "video/x-ms-wmx" }, + { "wrl", 3, "model/vrml" }, + { "wvx", 3, "video/x-ms-wvx" }, + { "xbm", 3, "image/x-xbitmap" }, + { "xlc", 3, "application/vnd.ms-excel" }, + { "xll", 3, "application/vnd.ms-excel" }, + { "xlm", 3, "application/vnd.ms-excel" }, + { "xls", 3, "application/vnd.ms-excel" }, + { "xlsx", 4, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"}, + { "xlw", 3, "application/vnd.ms-excel" }, + { "xml", 3, "text/xml" }, + { "xpm", 3, "image/x-xpixmap" }, + { "xwd", 3, "image/x-xwindowdump" }, + { "xyz", 3, "chemical/x-pdb" }, + { "zip", 3, "application/zip" }, + }; #ifdef FOSSIL_DEBUG /* This is test code to make sure the table above is in the correct ** order */ if( fossil_strcmp(zName, "mimetype-test")==0 ){ - mimetype_verify(); + for(i=1; i<sizeof(aMime)/sizeof(aMime[0]); i++){ + if( fossil_strcmp(aMime[i-1].zSuffix,aMime[i].zSuffix)>=0 ){ + fossil_fatal("mimetypes out of sequence: %s before %s", + aMime[i-1].zSuffix, aMime[i].zSuffix); + } + } return "ok"; } #endif z = zName; @@ -337,11 +316,11 @@ len = strlen(z); if( len<sizeof(zSuffix)-1 ){ sqlite3_snprintf(sizeof(zSuffix), zSuffix, "%s", z); for(i=0; zSuffix[i]; i++) zSuffix[i] = fossil_tolower(zSuffix[i]); first = 0; - last = ArraySize(aMime) - 1; + last = sizeof(aMime)/sizeof(aMime[0]) - 1; while( first<=last ){ int c; i = (first+last)/2; c = fossil_strcmp(zSuffix, aMime[i].zSuffix); if( c==0 ) return aMime[i].zMimetype; @@ -366,378 +345,269 @@ ** filename is special and verifies the integrity of the mimetype table. ** It should return "ok". */ void mimetype_test_cmd(void){ int i; - mimetype_verify(); for(i=2; i<g.argc; i++){ fossil_print("%-20s -> %s\n", g.argv[i], mimetype_from_name(g.argv[i])); } } /* -** WEBPAGE: mimetype_list -** -** Show the built-in table used to guess embedded document mimetypes -** from file suffixes. -*/ -void mimetype_list_page(void){ - int i; - mimetype_verify(); - style_header("Mimetype List"); - @ <p>The Fossil <a href="%R/help?cmd=/doc">/doc</a> page uses filename - @ suffixes and the following table to guess at the appropriate mimetype - @ for each document.</p> - @ <table id='mimeTable' border=1 cellpadding=0 class='mimetypetable'> - @ <thead> - @ <tr><th>Suffix<th>Mimetype - @ </thead> - @ <tbody> - for(i=0; i<ArraySize(aMime); i++){ - @ <tr><td>%h(aMime[i].zSuffix)<td>%h(aMime[i].zMimetype)</tr> - } - @ </tbody></table> - output_table_sorting_javascript("mimeTable","tt",1); - style_footer(); -} - -/* -** Check to see if the file in the pContent blob is "embedded HTML". Return -** true if it is, and fill pTitle with the document title. -** -** An "embedded HTML" file is HTML that lacks a header and a footer. The -** standard Fossil header is prepended and the standard Fossil footer is -** appended. Otherwise, the file is displayed without change. -** -** Embedded HTML must be contained in a <div class='fossil-doc'> element. -** If that <div> also contains a data-title attribute, then the -** value of that attribute is extracted into pTitle and becomes the title -** of the document. -*/ -int doc_is_embedded_html(Blob *pContent, Blob *pTitle){ - const char *zIn = blob_str(pContent); - const char *zAttr; - const char *zValue; - int nAttr, nValue; - int seenClass = 0; - int seenTitle = 0; - - while( fossil_isspace(zIn[0]) ) zIn++; - if( fossil_strnicmp(zIn,"<div",4)!=0 ) return 0; - zIn += 4; - while( zIn[0] ){ - if( fossil_isspace(zIn[0]) ) zIn++; - if( zIn[0]=='>' ) return 0; - zAttr = zIn; - while( fossil_isalnum(zIn[0]) || zIn[0]=='-' ) zIn++; - nAttr = (int)(zIn - zAttr); - while( fossil_isspace(zIn[0]) ) zIn++; - if( zIn[0]!='=' ) continue; - zIn++; - while( fossil_isspace(zIn[0]) ) zIn++; - if( zIn[0]=='"' || zIn[0]=='\'' ){ - char cDelim = zIn[0]; - zIn++; - zValue = zIn; - while( zIn[0] && zIn[0]!=cDelim ) zIn++; - if( zIn[0]==0 ) return 0; - nValue = (int)(zIn - zValue); - zIn++; - }else{ - zValue = zIn; - while( zIn[0]!=0 && zIn[0]!='>' && zIn[0]!='/' - && !fossil_isspace(zIn[0]) ) zIn++; - if( zIn[0]==0 ) return 0; - nValue = (int)(zIn - zValue); - } - if( nAttr==5 && fossil_strnicmp(zAttr,"class",5)==0 ){ - if( nValue!=10 || fossil_strnicmp(zValue,"fossil-doc",10)!=0 ) return 0; - seenClass = 1; - if( seenTitle ) return 1; - } - if( nAttr==10 && fossil_strnicmp(zAttr,"data-title",10)==0 ){ - blob_append(pTitle, zValue, nValue); - seenTitle = 1; - if( seenClass ) return 1; - } - } - return seenClass; -} - -/* -** 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 rid; /* The RID of the file being loaded */ - if( !db_table_exists("repository","vcache") ){ - db_multi_exec( - "CREATE TABLE IF NOT EXISTS vcache(\n" - " vid INTEGER, -- check-in ID\n" - " fname TEXT, -- filename\n" - " rid INTEGER, -- artifact ID\n" - " PRIMARY KEY(vid,fname)\n" - ") WITHOUT ROWID" - ); - } - if( !db_exists("SELECT 1 FROM vcache WHERE vid=%d", vid) ){ - db_multi_exec( - "DELETE FROM vcache;\n" - "CREATE VIRTUAL TABLE IF NOT EXISTS temp.foci USING files_of_checkin;\n" - "INSERT INTO vcache(vid,fname,rid)" - " SELECT checkinID, filename, blob.rid FROM foci, blob" - " WHERE blob.uuid=foci.uuid" - " AND foci.checkinID=%d;", - vid - ); - } - rid = db_int(0, "SELECT rid FROM vcache" - " WHERE vid=%d AND fname=%Q", vid, zName); - if( rid && content_get(rid, pContent)==0 ){ - rid = 0; - } - return rid; -} - -/* -** WEBPAGE: doc -** URL: /doc?name=CHECKIN/FILE -** URL: /doc/CHECKIN/FILE -** -** CHECKIN can be either tag or SHA1 hash or timestamp identifying a -** particular check, or the name of a branch (meaning the most recent -** check-in on that branch) or one of various magic words: -** -** "tip" means the most recent check-in -** -** "ckout" means the current check-out, if the server is run from -** within a check-out, otherwise it is the same as "tip" -** -** FILE is the name of a file to delivered up as a webpage. FILE is relative -** to the root of the source tree of the repository. The FILE must -** be a part of CHECKIN, except when CHECKIN=="ckout" when FILE is read -** directly from disk and need not be a managed file. -** -** The "ckout" CHECKIN is intended for development - to provide a mechanism -** for looking at what a file will look like using the /doc webpage after -** it gets checked in. -** -** The file extension is used to decide how to render the file. -** -** If FILE ends in "/" then names "FILE/index.html", "FILE/index.wiki", -** and "FILE/index.md" are in that order. If none of those are found, -** then FILE is completely replaced by "404.md" and tried. If that is -** not found, then a default 404 screen is generated. +** WEBPAGE: doc +** URL: /doc?name=BASELINE/PATH +** URL: /doc/BASELINE/PATH +** +** BASELINE can be either a baseline uuid prefix or magic words "tip" +** to mean the most recently checked in baseline or "ckout" to mean the +** content of the local checkout, if any. PATH is the relative pathname +** of some file. This method returns the file content. +** +** If PATH matches the patterns *.wiki or *.txt then formatting content +** is added before returning the file. For all other names, the content +** is returned straight without any interpretation or processing. */ void doc_page(void){ const char *zName; /* Argument to the /doc page */ - const char *zOrigName = "?"; /* Original document name */ const char *zMime; /* Document MIME type */ - char *zCheckin = "tip"; /* The check-in holding the document */ - int vid = 0; /* Artifact of check-in */ + int vid = 0; /* Artifact of baseline */ int rid = 0; /* Artifact of file */ int i; /* Loop counter */ Blob filebody; /* Content of the documentation file */ - Blob title; /* Document title */ - int nMiss = (-1); /* Failed attempts to find the document */ - static const char *const azSuffix[] = { - "index.html", "index.wiki", "index.md" - }; + char zBaseline[UUID_SIZE+1]; /* Baseline UUID */ login_check_credentials(); - if( !g.perm.Read ){ login_needed(g.anon.Read); return; } - blob_init(&title, 0, 0); - db_begin_transaction(); - while( rid==0 && (++nMiss)<=ArraySize(azSuffix) ){ - zName = PD("name", "tip/index.wiki"); - for(i=0; zName[i] && zName[i]!='/'; i++){} - zCheckin = mprintf("%.*s", i, zName); - if( fossil_strcmp(zCheckin,"ckout")==0 && db_open_local(0)==0 ){ - zCheckin = "tip"; - } - if( nMiss==ArraySize(azSuffix) ){ - zName = "404.md"; - }else if( zName[i]==0 ){ - assert( nMiss>=0 && nMiss<ArraySize(azSuffix) ); - zName = azSuffix[nMiss]; - }else{ - zName += i; - } - while( zName[0]=='/' ){ zName++; } - g.zPath = mprintf("%s/%s/%s", g.zPath, zCheckin, zName); - if( nMiss==0 ) zOrigName = zName; - if( !file_is_simple_pathname(zName, 1) ){ - if( sqlite3_strglob("*/", zName)==0 ){ - assert( nMiss>=0 && nMiss<ArraySize(azSuffix) ); - zName = mprintf("%s%s", zName, azSuffix[nMiss]); - if( !file_is_simple_pathname(zName, 1) ){ - goto doc_not_found; - } - }else{ - goto doc_not_found; - } - } - if( fossil_strcmp(zCheckin,"ckout")==0 ){ - /* Read from the local checkout */ - char *zFullpath; - db_must_be_within_tree(); - zFullpath = mprintf("%s/%s", g.zLocalRoot, zName); - if( file_isfile(zFullpath) - && blob_read_from_file(&filebody, zFullpath)>0 ){ - rid = 1; /* Fake RID just to get the loop to end */ - } - fossil_free(zFullpath); - }else{ - vid = name_to_typed_rid(zCheckin, "ci"); - rid = doc_load_content(vid, zName, &filebody); - } - } - if( rid==0 ) goto doc_not_found; - blob_to_utf8_no_bom(&filebody, 0); - - /* The file is now contained in the filebody blob. Deliver the - ** file to the user - */ - zMime = nMiss==0 ? P("mimetype") : 0; + if( !g.perm.Read ){ login_needed(); return; } + zName = PD("name", "tip/index.wiki"); + for(i=0; zName[i] && zName[i]!='/'; i++){} + if( zName[i]==0 || i>UUID_SIZE ){ + zName = "index.html"; + goto doc_not_found; + } + g.zPath = mprintf("%s/%s", g.zPath, zName); + memcpy(zBaseline, zName, i); + zBaseline[i] = 0; + zName += i; + while( zName[0]=='/' ){ zName++; } + if( !file_is_simple_pathname(zName, 1) ){ + int n = strlen(zName); + if( n>0 && zName[n-1]=='/' ){ + zName = mprintf("%sindex.html", zName); + if( !file_is_simple_pathname(zName, 1) ){ + goto doc_not_found; + } + }else{ + goto doc_not_found; + } + } + if( fossil_strcmp(zBaseline,"ckout")==0 && db_open_local(0)==0 ){ + sqlite3_snprintf(sizeof(zBaseline), zBaseline, "tip"); + } + if( fossil_strcmp(zBaseline,"ckout")==0 ){ + /* Read from the local checkout */ + char *zFullpath; + db_must_be_within_tree(); + zFullpath = mprintf("%s/%s", g.zLocalRoot, zName); + if( !file_isfile(zFullpath) ){ + goto doc_not_found; + } + if( blob_read_from_file(&filebody, zFullpath)<0 ){ + goto doc_not_found; + } + }else{ + db_begin_transaction(); + if( fossil_strcmp(zBaseline,"tip")==0 ){ + vid = db_int(0, "SELECT objid FROM event WHERE type='ci'" + " ORDER BY mtime DESC LIMIT 1"); + }else{ + vid = name_to_typed_rid(zBaseline, "ci"); + } + + /* Create the baseline cache if it does not already exist */ + db_multi_exec( + "CREATE TABLE IF NOT EXISTS vcache(\n" + " vid INTEGER, -- baseline ID\n" + " fname TEXT, -- filename\n" + " rid INTEGER, -- artifact ID\n" + " UNIQUE(vid,fname,rid)\n" + ")" + ); + + + + /* Check to see if the documentation file artifact ID is contained + ** in the baseline cache */ + rid = db_int(0, "SELECT rid FROM vcache" + " WHERE vid=%d AND fname=%Q", vid, zName); + if( rid==0 && db_exists("SELECT 1 FROM vcache WHERE vid=%d", vid) ){ + goto doc_not_found; + } + + if( rid==0 ){ + Stmt s; + Manifest *pM; + ManifestFile *pFile; + + /* Add the vid baseline to the cache */ + if( db_int(0, "SELECT count(*) FROM vcache")>10000 ){ + db_multi_exec("DELETE FROM vcache"); + } + pM = manifest_get(vid, CFTYPE_MANIFEST, 0); + if( pM==0 ){ + goto doc_not_found; + } + db_prepare(&s, + "INSERT INTO vcache(vid,fname,rid)" + " SELECT %d, :fname, rid FROM blob" + " WHERE uuid=:uuid", + vid + ); + manifest_file_rewind(pM); + while( (pFile = manifest_file_next(pM,0))!=0 ){ + db_bind_text(&s, ":fname", pFile->zName); + db_bind_text(&s, ":uuid", pFile->zUuid); + db_step(&s); + db_reset(&s); + } + db_finalize(&s); + manifest_destroy(pM); + + /* Try again to find the file */ + rid = db_int(0, "SELECT rid FROM vcache" + " WHERE vid=%d AND fname=%Q", vid, zName); + } + if( rid==0 ){ + goto doc_not_found; + } + + /* Get the file content */ + if( content_get(rid, &filebody)==0 ){ + goto doc_not_found; + } + db_end_transaction(0); + } + + /* The file is now contained in the filebody blob. Deliver the + ** file to the user + */ + zMime = P("mimetype"); if( zMime==0 ){ zMime = mimetype_from_name(zName); } Th_Store("doc_name", zName); 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)); if( fossil_strcmp(zMime, "text/x-fossil-wiki")==0 ){ - Blob tail; - style_adunit_config(ADUNIT_RIGHT_OK); + Blob title, tail; if( wiki_find_title(&filebody, &title, &tail) ){ - style_header("%s", blob_str(&title)); + style_header(blob_str(&title)); wiki_convert(&tail, 0, WIKI_BUTTONS); }else{ style_header("Documentation"); wiki_convert(&filebody, 0, WIKI_BUTTONS); } style_footer(); }else if( fossil_strcmp(zMime, "text/x-markdown")==0 ){ + Blob title = BLOB_INITIALIZER; Blob tail = BLOB_INITIALIZER; markdown_to_html(&filebody, &title, &tail); if( blob_size(&title)>0 ){ - style_header("%s", blob_str(&title)); + style_header(blob_str(&title)); }else{ - style_header("%s", nMiss>=ArraySize(azSuffix)? - "Not Found" : "Documentation"); + style_header("Documentation"); } blob_append(cgi_output_blob(), blob_buffer(&tail), blob_size(&tail)); style_footer(); }else if( fossil_strcmp(zMime, "text/plain")==0 ){ style_header("Documentation"); @ <blockquote><pre> @ %h(blob_str(&filebody)) @ </pre></blockquote> style_footer(); - }else if( fossil_strcmp(zMime, "text/html")==0 - && doc_is_embedded_html(&filebody, &title) ){ - if( blob_size(&title)==0 ) blob_append(&title,zName,-1); - style_header("%s", blob_str(&title)); - blob_append(cgi_output_blob(), blob_buffer(&filebody),blob_size(&filebody)); - style_footer(); -#ifdef FOSSIL_ENABLE_TH1_DOCS - }else if( Th_AreDocsEnabled() && - fossil_strcmp(zMime, "application/x-th1")==0 ){ - style_header("%h", zName); - Th_Render(blob_str(&filebody)); - style_footer(); -#endif }else{ cgi_set_content_type(zMime); cgi_set_content(&filebody); } - if( nMiss>=ArraySize(azSuffix) ) cgi_set_status(404, "Not Found"); - db_end_transaction(0); - return; - - /* Jump here when unable to locate the document */ -doc_not_found: - db_end_transaction(0); - cgi_set_status(404, "Not Found"); - style_header("Not Found"); - @ <p>Document %h(zOrigName) not found - if( fossil_strcmp(zCheckin,"ckout")!=0 ){ - @ in %z(href("%R/tree?ci=%T",zCheckin))%h(zCheckin)</a> - } - style_footer(); - db_end_transaction(0); - return; + return; + +doc_not_found: + /* Jump here when unable to locate the document */ + db_end_transaction(0); + style_header("Document Not Found"); + @ <p>No such document: %h(zName)</p> + style_footer(); + return; } /* ** The default logo. */ static const unsigned char aLogo[] = { - 71, 73, 70, 56, 55, 97, 62, 0, 71, 0, 244, 0, 0, 85, - 129, 149, 95, 136, 155, 99, 139, 157, 106, 144, 162, 113, 150, 166, - 116, 152, 168, 127, 160, 175, 138, 168, 182, 148, 176, 188, 159, 184, - 195, 170, 192, 202, 180, 199, 208, 184, 202, 210, 191, 207, 215, 201, - 215, 221, 212, 223, 228, 223, 231, 235, 226, 227, 226, 226, 234, 237, - 233, 239, 241, 240, 244, 246, 244, 247, 248, 255, 255, 255, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 0, 0, - 0, 0, 62, 0, 71, 0, 0, 5, 255, 96, 100, 141, 100, 105, - 158, 168, 37, 41, 132, 192, 164, 112, 44, 207, 102, 99, 0, 56, - 16, 84, 116, 239, 199, 141, 65, 110, 232, 248, 25, 141, 193, 161, - 82, 113, 108, 202, 32, 55, 229, 210, 73, 61, 41, 164, 88, 102, - 181, 10, 41, 96, 179, 91, 106, 35, 240, 5, 135, 143, 137, 242, - 87, 123, 246, 33, 190, 81, 108, 163, 237, 198, 14, 30, 113, 233, - 131, 78, 115, 72, 11, 115, 87, 101, 19, 124, 51, 66, 74, 8, - 19, 16, 67, 100, 74, 133, 50, 15, 101, 135, 56, 11, 74, 6, - 143, 49, 126, 106, 56, 8, 145, 67, 9, 152, 48, 139, 155, 5, - 22, 13, 74, 115, 161, 41, 147, 101, 13, 130, 57, 132, 170, 40, - 167, 155, 0, 94, 57, 3, 178, 48, 183, 181, 57, 160, 186, 40, - 19, 141, 189, 0, 69, 192, 40, 16, 195, 155, 185, 199, 41, 201, - 189, 191, 205, 193, 188, 131, 210, 49, 175, 88, 209, 214, 38, 19, - 3, 11, 19, 111, 127, 60, 219, 39, 55, 204, 19, 11, 6, 100, - 5, 10, 227, 228, 37, 163, 0, 239, 117, 56, 238, 243, 49, 195, - 177, 247, 48, 158, 56, 251, 50, 216, 254, 197, 56, 128, 107, 158, - 2, 125, 171, 114, 92, 218, 246, 96, 66, 3, 4, 50, 134, 176, - 145, 6, 97, 64, 144, 24, 19, 136, 108, 91, 177, 160, 0, 194, - 19, 253, 0, 216, 107, 214, 224, 192, 129, 5, 16, 83, 255, 244, - 43, 213, 195, 24, 159, 27, 169, 64, 230, 88, 208, 227, 129, 182, - 54, 4, 89, 158, 24, 181, 163, 199, 1, 155, 52, 233, 8, 130, - 176, 83, 24, 128, 137, 50, 18, 32, 48, 48, 114, 11, 173, 137, - 19, 110, 4, 64, 105, 1, 194, 30, 140, 68, 15, 24, 24, 224, - 50, 76, 70, 0, 11, 171, 54, 26, 160, 181, 194, 149, 148, 40, - 174, 148, 122, 64, 180, 208, 161, 17, 207, 112, 164, 1, 128, 96, - 148, 78, 18, 21, 194, 33, 229, 51, 247, 65, 133, 97, 5, 250, - 69, 229, 100, 34, 220, 128, 166, 116, 190, 62, 8, 167, 195, 170, - 47, 163, 0, 130, 90, 152, 11, 160, 173, 170, 27, 154, 26, 91, - 232, 151, 171, 18, 14, 162, 253, 98, 170, 18, 70, 171, 64, 219, - 10, 67, 136, 134, 187, 116, 75, 180, 46, 179, 174, 135, 4, 189, - 229, 231, 78, 40, 10, 62, 226, 164, 172, 64, 240, 167, 170, 10, - 18, 124, 188, 10, 107, 65, 193, 94, 11, 93, 171, 28, 248, 17, - 239, 46, 140, 78, 97, 34, 25, 153, 36, 99, 65, 130, 7, 203, - 183, 168, 51, 34, 136, 25, 140, 10, 6, 16, 28, 255, 145, 241, - 230, 140, 10, 66, 178, 167, 112, 48, 192, 128, 129, 9, 31, 141, - 84, 138, 63, 163, 162, 2, 203, 206, 240, 56, 55, 98, 192, 188, - 15, 185, 50, 160, 6, 0, 125, 62, 33, 214, 195, 33, 5, 24, - 184, 25, 231, 14, 201, 245, 144, 23, 126, 104, 228, 0, 145, 2, - 13, 140, 244, 212, 17, 21, 20, 176, 159, 17, 95, 225, 160, 128, - 16, 1, 32, 224, 142, 32, 227, 125, 87, 64, 0, 16, 54, 129, - 205, 2, 141, 76, 53, 130, 103, 37, 166, 64, 144, 107, 78, 196, - 5, 192, 0, 54, 50, 229, 9, 141, 49, 84, 194, 35, 12, 196, - 153, 48, 192, 137, 57, 84, 24, 7, 87, 159, 249, 240, 215, 143, - 105, 241, 118, 149, 9, 139, 4, 64, 203, 141, 35, 140, 129, 131, - 16, 222, 125, 231, 128, 2, 238, 17, 152, 66, 3, 5, 56, 224, - 159, 103, 16, 76, 25, 75, 5, 11, 164, 215, 96, 9, 14, 16, - 36, 225, 15, 11, 40, 144, 192, 156, 41, 10, 178, 199, 3, 66, - 64, 80, 193, 3, 124, 90, 48, 129, 129, 102, 177, 18, 192, 154, - 49, 84, 240, 208, 92, 22, 149, 96, 39, 9, 31, 74, 17, 94, - 3, 8, 177, 199, 72, 59, 85, 76, 25, 216, 8, 139, 194, 197, - 138, 163, 69, 96, 115, 0, 147, 72, 72, 84, 28, 14, 79, 86, - 233, 230, 23, 113, 26, 160, 128, 3, 10, 58, 129, 103, 14, 159, - 214, 163, 146, 117, 238, 213, 154, 128, 151, 109, 84, 64, 217, 13, - 27, 10, 228, 39, 2, 235, 164, 168, 74, 8, 0, 59, + 71, 73, 70, 56, 55, 97, 62, 0, 71, 0, 244, 0, 0, 85, + 129, 149, 95, 136, 155, 99, 139, 157, 106, 144, 162, 113, 150, 166, + 116, 152, 168, 127, 160, 175, 138, 168, 182, 148, 176, 188, 159, 184, + 195, 170, 192, 202, 180, 199, 208, 184, 202, 210, 191, 207, 215, 201, + 215, 221, 212, 223, 228, 223, 231, 235, 226, 227, 226, 226, 234, 237, + 233, 239, 241, 240, 244, 246, 244, 247, 248, 255, 255, 255, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 0, 0, + 0, 0, 62, 0, 71, 0, 0, 5, 255, 96, 100, 141, 100, 105, + 158, 168, 37, 41, 132, 192, 164, 112, 44, 207, 102, 99, 0, 56, + 16, 84, 116, 239, 199, 141, 65, 110, 232, 248, 25, 141, 193, 161, + 82, 113, 108, 202, 32, 55, 229, 210, 73, 61, 41, 164, 88, 102, + 181, 10, 41, 96, 179, 91, 106, 35, 240, 5, 135, 143, 137, 242, + 87, 123, 246, 33, 190, 81, 108, 163, 237, 198, 14, 30, 113, 233, + 131, 78, 115, 72, 11, 115, 87, 101, 19, 124, 51, 66, 74, 8, + 19, 16, 67, 100, 74, 133, 50, 15, 101, 135, 56, 11, 74, 6, + 143, 49, 126, 106, 56, 8, 145, 67, 9, 152, 48, 139, 155, 5, + 22, 13, 74, 115, 161, 41, 147, 101, 13, 130, 57, 132, 170, 40, + 167, 155, 0, 94, 57, 3, 178, 48, 183, 181, 57, 160, 186, 40, + 19, 141, 189, 0, 69, 192, 40, 16, 195, 155, 185, 199, 41, 201, + 189, 191, 205, 193, 188, 131, 210, 49, 175, 88, 209, 214, 38, 19, + 3, 11, 19, 111, 127, 60, 219, 39, 55, 204, 19, 11, 6, 100, + 5, 10, 227, 228, 37, 163, 0, 239, 117, 56, 238, 243, 49, 195, + 177, 247, 48, 158, 56, 251, 50, 216, 254, 197, 56, 128, 107, 158, + 2, 125, 171, 114, 92, 218, 246, 96, 66, 3, 4, 50, 134, 176, + 145, 6, 97, 64, 144, 24, 19, 136, 108, 91, 177, 160, 0, 194, + 19, 253, 0, 216, 107, 214, 224, 192, 129, 5, 16, 83, 255, 244, + 43, 213, 195, 24, 159, 27, 169, 64, 230, 88, 208, 227, 129, 182, + 54, 4, 89, 158, 24, 181, 163, 199, 1, 155, 52, 233, 8, 130, + 176, 83, 24, 128, 137, 50, 18, 32, 48, 48, 114, 11, 173, 137, + 19, 110, 4, 64, 105, 1, 194, 30, 140, 68, 15, 24, 24, 224, + 50, 76, 70, 0, 11, 171, 54, 26, 160, 181, 194, 149, 148, 40, + 174, 148, 122, 64, 180, 208, 161, 17, 207, 112, 164, 1, 128, 96, + 148, 78, 18, 21, 194, 33, 229, 51, 247, 65, 133, 97, 5, 250, + 69, 229, 100, 34, 220, 128, 166, 116, 190, 62, 8, 167, 195, 170, + 47, 163, 0, 130, 90, 152, 11, 160, 173, 170, 27, 154, 26, 91, + 232, 151, 171, 18, 14, 162, 253, 98, 170, 18, 70, 171, 64, 219, + 10, 67, 136, 134, 187, 116, 75, 180, 46, 179, 174, 135, 4, 189, + 229, 231, 78, 40, 10, 62, 226, 164, 172, 64, 240, 167, 170, 10, + 18, 124, 188, 10, 107, 65, 193, 94, 11, 93, 171, 28, 248, 17, + 239, 46, 140, 78, 97, 34, 25, 153, 36, 99, 65, 130, 7, 203, + 183, 168, 51, 34, 136, 25, 140, 10, 6, 16, 28, 255, 145, 241, + 230, 140, 10, 66, 178, 167, 112, 48, 192, 128, 129, 9, 31, 141, + 84, 138, 63, 163, 162, 2, 203, 206, 240, 56, 55, 98, 192, 188, + 15, 185, 50, 160, 6, 0, 125, 62, 33, 214, 195, 33, 5, 24, + 184, 25, 231, 14, 201, 245, 144, 23, 126, 104, 228, 0, 145, 2, + 13, 140, 244, 212, 17, 21, 20, 176, 159, 17, 95, 225, 160, 128, + 16, 1, 32, 224, 142, 32, 227, 125, 87, 64, 0, 16, 54, 129, + 205, 2, 141, 76, 53, 130, 103, 37, 166, 64, 144, 107, 78, 196, + 5, 192, 0, 54, 50, 229, 9, 141, 49, 84, 194, 35, 12, 196, + 153, 48, 192, 137, 57, 84, 24, 7, 87, 159, 249, 240, 215, 143, + 105, 241, 118, 149, 9, 139, 4, 64, 203, 141, 35, 140, 129, 131, + 16, 222, 125, 231, 128, 2, 238, 17, 152, 66, 3, 5, 56, 224, + 159, 103, 16, 76, 25, 75, 5, 11, 164, 215, 96, 9, 14, 16, + 36, 225, 15, 11, 40, 144, 192, 156, 41, 10, 178, 199, 3, 66, + 64, 80, 193, 3, 124, 90, 48, 129, 129, 102, 177, 18, 192, 154, + 49, 84, 240, 208, 92, 22, 149, 96, 39, 9, 31, 74, 17, 94, + 3, 8, 177, 199, 72, 59, 85, 76, 25, 216, 8, 139, 194, 197, + 138, 163, 69, 96, 115, 0, 147, 72, 72, 84, 28, 14, 79, 86, + 233, 230, 23, 113, 26, 160, 128, 3, 10, 58, 129, 103, 14, 159, + 214, 163, 146, 117, 238, 213, 154, 128, 151, 109, 84, 64, 217, 13, + 27, 10, 228, 39, 2, 235, 164, 168, 74, 8, 0, 59, }; /* ** WEBPAGE: logo ** @@ -790,18 +660,5 @@ } cgi_set_content_type(zMime); cgi_set_content(&bgimg); g.isConst = 1; } - - -/* -** WEBPAGE: /docsrch -** -** Search for documents that match a user-supplied pattern. -*/ -void doc_search_page(void){ - login_check_credentials(); - style_header("Document Search"); - search_screen(SRCH_DOC, 0); - style_footer(); -} Index: src/encode.c ================================================================== --- src/encode.c +++ src/encode.c @@ -47,30 +47,30 @@ } i = 0; zOut = fossil_malloc( count+1 ); while( n-->0 && (c = *zIn)!=0 ){ switch( c ){ - case '<': + case '<': zOut[i++] = '&'; zOut[i++] = 'l'; zOut[i++] = 't'; zOut[i++] = ';'; break; - case '>': + case '>': zOut[i++] = '&'; zOut[i++] = 'g'; zOut[i++] = 't'; zOut[i++] = ';'; break; - case '&': + case '&': zOut[i++] = '&'; zOut[i++] = 'a'; zOut[i++] = 'm'; zOut[i++] = 'p'; zOut[i++] = ';'; break; - case '"': + case '"': zOut[i++] = '&'; zOut[i++] = 'q'; zOut[i++] = 'u'; zOut[i++] = 'o'; zOut[i++] = 't'; @@ -181,11 +181,11 @@ /* ** Convert the input string into a form that is suitable for use as ** a token in the HTTP protocol. Spaces are encoded as '+' and special ** characters are encoded as "%HH" where HH is a two-digit hexidecimal ** representation of the character. The "/" character is not encoded -** by this routine. +** by this routine. */ char *urlize(const char *z, int n){ return EncodeHttp(z, n, 0); } @@ -327,11 +327,11 @@ /* ** The characters used for HTTP base64 encoding. */ -static unsigned char zBase[] = +static unsigned char zBase[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; /* ** Encode a string using a base-64 encoding. ** The encoding can be reversed using the <b>decode64</b> function. @@ -366,11 +366,11 @@ z64[n] = 0; return z64; } /* -** COMMAND: test-encode64 +** COMMAND: test-encode64 ** Usage: %fossil test-encode64 STRING */ void test_encode64_cmd(void){ char *z; int i; @@ -431,11 +431,11 @@ *pnByte = j; return zData; } /* -** COMMAND: test-decode64 +** COMMAND: test-decode64 ** Usage: %fossil test-decode64 STRING */ void test_decode64_cmd(void){ char *z; int i, n; @@ -454,11 +454,11 @@ */ /* ** The array used for encoding */ /* 123456789 12345 */ -static const char zEncode[] = "0123456789abcdef"; +static const char zEncode[] = "0123456789abcdef"; /* ** Encode a N-digit base-256 in base-16. Return zero on success ** and non-zero if there is an error. */ @@ -473,33 +473,33 @@ } /* ** An array for translating single base-16 characters into a value. ** Disallowed input characters have a value of 64. Upper and lower -** case is the same. +** case is the same. */ static const char zDecode[] = { - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 64, 64, 64, 64, 64, 64, 64, 10, 11, 12, 13, 14, 15, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 10, 11, 12, 13, 14, 15, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, }; /* -** Decode a N-character base-16 number into base-256. N must be a +** Decode a N-character base-16 number into base-256. N must be a ** multiple of 2. The output buffer must be at least N/2 characters ** in length */ int decode16(const unsigned char *zIn, unsigned char *pOut, int N){ int i, j; @@ -545,11 +545,11 @@ /* Randomness used for XOR-ing by the obscure() and unobscure() routines */ static const unsigned char aObscurer[16] = { 0xa7, 0x21, 0x31, 0xe3, 0x2a, 0x50, 0x2c, 0x86, 0x4c, 0xa4, 0x52, 0x25, 0xff, 0x49, 0x35, 0x85 }; - + /* ** Obscure plain text so that it is not easily readable. ** ** This is used for storing sensitive information (such as passwords) in a @@ -562,11 +562,11 @@ */ char *obscure(const char *zIn){ int n, i; unsigned char salt; char *zOut; - + if( zIn==0 ) return 0; n = strlen(zIn); zOut = fossil_malloc( n*2+3 ); sqlite3_randomness(1, &salt); zOut[n+1] = (char)salt; @@ -578,17 +578,17 @@ /* ** Undo the obscuring of text performed by obscure(). Or, if the input is ** not hexadecimal (meaning the input is not the output of obscure()) then ** do the equivalent of strdup(). ** -** The result is memory obtained from malloc that should be freed by the caller. +** The result is memory obtained from malloc that should be freed by the caller. */ char *unobscure(const char *zIn){ int n, i; unsigned char salt; char *zOut; - + if( zIn==0 ) return 0; n = strlen(zIn); zOut = fossil_malloc( n + 1 ); if( n<2 || decode16((unsigned char*)zIn, &salt, 2) Index: src/event.c ================================================================== --- src/event.c +++ src/event.c @@ -15,90 +15,78 @@ ** ******************************************************************************* ** ** This file contains code to do formatting of event messages: ** -** Technical Notes ** Milestones ** Blog posts ** New articles ** Process checkpoints ** Announcements -** -** Do not confuse "event" artifacts with the "event" table in the -** repository database. An "event" artifact is a technical-note: a -** wiki- or blog-like essay that appears on the timeline. The "event" -** table records all entries on the timeline, including tech-notes. -** -** (2015-02-14): Changing the name to "tech-note" most everywhere. */ -#include "config.h" #include <assert.h> #include <ctype.h> +#include "config.h" #include "event.h" /* -** Output a hyperlink to an technote given its tagid. +** Output a hyperlink to an event given its tagid. */ void hyperlink_to_event_tagid(int tagid){ - char *zId; - zId = db_text(0, "SELECT substr(tagname, 7) FROM tag WHERE tagid=%d", + char *zEventId; + zEventId = db_text(0, "SELECT substr(tagname, 7) FROM tag WHERE tagid=%d", tagid); - @ [%z(href("%R/technote/%s",zId))%S(zId)</a>] - free(zId); + @ [%z(href("%R/event/%s",zEventId))%S(zEventId)</a>] + free(zEventId); } /* -** WEBPAGE: technote ** WEBPAGE: event -** -** Display a "technical note" or "tech-note" (formerly called an "event"). -** +** URL: /event ** PARAMETERS: ** -** name=ID // Identify the tech-note to display. ID must be complete -** aid=ARTIFACTID // Which specific version of the tech-note. Optional. -** v=BOOLEAN // Show details if TRUE. Default is FALSE. Optional. +** name=EVENTID // Identify the event to display EVENTID must be complete +** aid=ARTIFACTID // Which specific version of the event. Optional. +** v=BOOLEAN // Show details if TRUE. Default is FALSE. Optional. ** ** Display an existing event identified by EVENTID */ void event_page(void){ int rid = 0; /* rid of the event artifact */ char *zUuid; /* UUID corresponding to rid */ - const char *zId; /* Event identifier */ + const char *zEventId; /* Event identifier */ const char *zVerbose; /* Value of verbose option */ - char *zETime; /* Time of the tech-note */ + char *zETime; /* Time of the event */ char *zATime; /* Time the artifact was created */ int specRid; /* rid specified by aid= parameter */ - int prevRid, nextRid; /* Previous or next edits of this tech-note */ - Manifest *pTNote; /* Parsed technote artifact */ - Blob fullbody; /* Complete content of the technote body */ - Blob title; /* Title extracted from the technote body */ + int prevRid, nextRid; /* Previous or next edits of this event */ + Manifest *pEvent; /* Parsed event artifact */ + Blob fullbody; /* Complete content of the event body */ + Blob title; /* Title extracted from the event body */ Blob tail; /* Event body that comes after the title */ - Stmt q1; /* Query to search for the technote */ + Stmt q1; /* Query to search for the event */ int verboseFlag; /* True to show details */ - const char *zMimetype = 0; /* Mimetype of the document */ - /* wiki-read privilege is needed in order to read tech-notes. + /* wiki-read privilege is needed in order to read events. */ login_check_credentials(); if( !g.perm.RdWiki ){ - login_needed(g.anon.RdWiki); + login_needed(); return; } - zId = P("name"); - if( zId==0 ){ fossil_redirect_home(); return; } + zEventId = P("name"); + if( zEventId==0 ){ fossil_redirect_home(); return; } zUuid = (char*)P("aid"); specRid = zUuid ? uuid_to_rid(zUuid, 0) : 0; rid = nextRid = prevRid = 0; db_prepare(&q1, "SELECT rid FROM tagxref" " WHERE tagid=(SELECT tagid FROM tag WHERE tagname GLOB 'event-%q*')" " ORDER BY mtime DESC", - zId + zEventId ); while( db_step(&q1)==SQLITE_ROW ){ nextRid = rid; rid = db_column_int(&q1, 0); if( specRid==0 || specRid==rid ){ @@ -108,12 +96,12 @@ break; } } db_finalize(&q1); if( rid==0 || (specRid!=0 && specRid!=rid) ){ - style_header("No Such Tech-Note"); - @ Cannot locate a technical note called <b>%h(zId)</b>. + style_header("No Such Event"); + @ Cannot locate specified event style_footer(); return; } zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); zVerbose = P("v"); @@ -125,194 +113,161 @@ } 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); - blob_init(&tail, 0, 0); - if( fossil_strcmp(zMimetype, "text/x-fossil-wiki")==0 ){ - if( !wiki_find_title(&fullbody, &title, &tail) ){ - blob_appendf(&title, "Tech-note %S", zId); - tail = fullbody; - } - }else if( fossil_strcmp(zMimetype, "text/x-markdown")==0 ){ - markdown_to_html(&fullbody, &title, &tail); - if( blob_size(&title)==0 ){ - blob_appendf(&title, "Tech-note %S", zId); - } - }else{ - blob_appendf(&title, "Tech-note %S", zId); - tail = fullbody; - } - style_header("%s", blob_str(&title)); - if( g.perm.WrWiki && g.perm.Write && nextRid==0 ){ - style_submenu_element("Edit", 0, "%R/technoteedit?name=%!S", zId); - } - zETime = db_text(0, "SELECT datetime(%.17g)", pTNote->rEventDate); - style_submenu_element("Context", 0, "%R/timeline?c=%.20s", zId); - if( g.perm.Hyperlink ){ - if( verboseFlag ){ - style_submenu_element("Plain", 0, - "%R/technote?name=%!S&aid=%s&mimetype=text/plain", - zId, zUuid); + pEvent = manifest_get(rid, CFTYPE_EVENT, 0); + if( pEvent==0 ){ + fossil_fatal("Object #%d is not an event", rid); + } + blob_init(&fullbody, pEvent->zWiki, -1); + if( wiki_find_title(&fullbody, &title, &tail) ){ + style_header(blob_str(&title)); + }else{ + style_header("Event %S", zEventId); + tail = fullbody; + } + if( g.perm.WrWiki && g.perm.Write && nextRid==0 ){ + style_submenu_element("Edit", "Edit", "%s/eventedit?name=%s", + g.zTop, zEventId); + } + zETime = db_text(0, "SELECT datetime(%.17g)", pEvent->rEventDate); + style_submenu_element("Context", "Context", "%s/timeline?c=%T", + g.zTop, zETime); + if( g.perm.Hyperlink ){ + if( verboseFlag ){ + style_submenu_element("Plain", "Plain", "%s/event?name=%s&aid=%s", + g.zTop, zEventId, zUuid); if( nextRid ){ char *zNext; zNext = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", nextRid); - style_submenu_element("Next", 0,"%R/technote?name=%!S&aid=%s&v", - zId, zNext); + style_submenu_element("Next", "Next", + "%s/event?name=%s&aid=%s&v", + g.zTop, zEventId, zNext); free(zNext); } if( prevRid ){ char *zPrev; zPrev = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", prevRid); - style_submenu_element("Prev", 0, "%R/technote?name=%!S&aid=%s&v", - zId, zPrev); + style_submenu_element("Prev", "Prev", + "%s/event?name=%s&aid=%s&v", + g.zTop, zEventId, zPrev); free(zPrev); } }else{ - style_submenu_element("Detail", 0, "%R/technote?name=%!S&aid=%s&v", - zId, zUuid); + style_submenu_element("Detail", "Detail", + "%s/event?name=%s&aid=%s&v", + g.zTop, zEventId, zUuid); } } if( verboseFlag && g.perm.Hyperlink ){ int i; const char *zClr = 0; Blob comment; - zATime = db_text(0, "SELECT datetime(%.17g)", pTNote->rDate); - @ <p>Tech-note [%z(href("%R/artifact/%!S",zUuid))%S(zUuid)</a>] at + zATime = db_text(0, "SELECT datetime(%.17g)", pEvent->rDate); + @ <p>Event [%z(href("%R/artifact/%s",zUuid))%S(zUuid)</a>] at @ [%z(href("%R/timeline?c=%T",zETime))%s(zETime)</a>] - @ entered by user <b>%h(pTNote->zUser)</b> on + @ entered by user <b>%h(pEvent->zUser)</b> on @ [%z(href("%R/timeline?c=%T",zATime))%s(zATime)</a>]:</p> @ <blockquote> - for(i=0; i<pTNote->nTag; i++){ - if( fossil_strcmp(pTNote->aTag[i].zName,"+bgcolor")==0 ){ - zClr = pTNote->aTag[i].zValue; + for(i=0; i<pEvent->nTag; i++){ + if( fossil_strcmp(pEvent->aTag[i].zName,"+bgcolor")==0 ){ + zClr = pEvent->aTag[i].zValue; } } if( zClr && zClr[0]==0 ) zClr = 0; if( zClr ){ @ <div style="background-color: %h(zClr);"> }else{ @ <div> } - blob_init(&comment, pTNote->zComment, -1); + blob_init(&comment, pEvent->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> - } + } + + wiki_convert(&tail, 0, 0); style_footer(); - manifest_destroy(pTNote); + manifest_destroy(pEvent); } /* -** WEBPAGE: technoteedit -** WEBPAGE: eventedit -** -** Revise or create a technical note (formerly called an 'event'). -** -** Parameters: -** -** name=ID Hex hash ID of the tech-note. If omitted, a new -** tech-note is created. +** WEBPAGE: eventedit +** URL: /eventedit?name=EVENTID +** +** Edit an event. If name is omitted, create a new event. */ void eventedit_page(void){ char *zTag; int rid = 0; Blob event; - const char *zId; + const char *zEventId; + char *zHtmlPageName; int n; const char *z; char *zBody = (char*)P("w"); char *zETime = (char*)P("t"); const char *zComment = P("c"); const char *zTags = P("g"); const char *zClr; - const char *zMimetype = P("mimetype"); - int isNew = 0; if( zBody ){ zBody = mprintf("%s", zBody); } login_check_credentials(); - zId = P("name"); - if( zId==0 ){ - zId = db_text(0, "SELECT lower(hex(randomblob(20)))"); - isNew = 1; + zEventId = P("name"); + if( zEventId==0 ){ + zEventId = db_text(0, "SELECT lower(hex(randomblob(20)))"); }else{ - int nId = strlen(zId); - if( !validate16(zId, nId) ){ + int nEventId = strlen(zEventId); + if( nEventId!=40 || !validate16(zEventId, 40) ){ fossil_redirect_home(); return; } } - zTag = mprintf("event-%s", zId); - rid = db_int(0, + zTag = mprintf("event-%s", zEventId); + rid = db_int(0, "SELECT rid FROM tagxref" - " WHERE tagid=(SELECT tagid FROM tag WHERE tagname GLOB '%q*')" + " WHERE tagid=(SELECT tagid FROM tag WHERE tagname=%Q)" " ORDER BY mtime DESC", zTag ); - if( rid && strlen(zId)<40 ){ - zId = db_text(0, - "SELECT substr(tagname,7) FROM tag WHERE tagname GLOB '%q*'", - zTag - ); - } free(zTag); /* Need both check-in and wiki-write or wiki-create privileges in order ** to edit/create an event. */ if( !g.perm.Write || (rid && !g.perm.WrWiki) || (!rid && !g.perm.NewWiki) ){ - login_needed(g.anon.Write && (rid ? g.anon.WrWiki : g.anon.NewWiki)); + login_needed(); return; } /* Figure out the color */ if( rid ){ - zClr = db_text("", "SELECT bgcolor FROM event WHERE objid=%d", rid); + zClr = db_text("", "SELECT bgcolor FROM event WHERE objid=%d", rid); }else{ zClr = ""; - isNew = 1; } zClr = PD("clr",zClr); if( fossil_strcmp(zClr,"##")==0 ) zClr = PD("cclr",""); /* If editing an existing event, extract the key fields to use as ** a starting point for the edit. */ - if( rid - && (zBody==0 || zETime==0 || zComment==0 || zTags==0 || zMimetype==0) - ){ - Manifest *pTNote; - pTNote = manifest_get(rid, CFTYPE_EVENT, 0); - if( pTNote && pTNote->type==CFTYPE_EVENT ){ - if( zBody==0 ) zBody = pTNote->zWiki; + if( rid && (zBody==0 || zETime==0 || zComment==0 || zTags==0) ){ + Manifest *pEvent; + pEvent = manifest_get(rid, CFTYPE_EVENT, 0); + if( pEvent && pEvent->type==CFTYPE_EVENT ){ + if( zBody==0 ) zBody = pEvent->zWiki; if( zETime==0 ){ - zETime = db_text(0, "SELECT datetime(%.17g)", pTNote->rEventDate); + zETime = db_text(0, "SELECT datetime(%.17g)", pEvent->rEventDate); } - if( zComment==0 ) zComment = pTNote->zComment; - if( zMimetype==0 ) zMimetype = pTNote->zMimetype; + if( zComment==0 ) zComment = pEvent->zComment; } if( zTags==0 ){ zTags = db_text(0, "SELECT group_concat(substr(tagname,5),', ')" " FROM tagxref, tag" @@ -326,11 +281,11 @@ zETime = db_text(0, "SELECT coalesce(datetime(%Q),datetime('now'))", zETime); if( P("submit")!=0 && (zBody!=0 && zComment!=0) ){ char *zDate; Blob cksum; int nrid, n; - blob_init(&event, 0, 0); + blob_zero(&event); db_begin_transaction(); login_verify_csrf_secret(); while( fossil_isspace(zComment[0]) ) zComment++; n = strlen(zComment); while( n>0 && fossil_isspace(zComment[n-1]) ){ n--; } @@ -339,20 +294,17 @@ } zDate = date_in_standard_format("now"); blob_appendf(&event, "D %s\n", zDate); free(zDate); zETime[10] = 'T'; - blob_appendf(&event, "E %s %s\n", zETime, zId); + blob_appendf(&event, "E %s %s\n", zETime, zEventId); zETime[10] = ' '; if( rid ){ char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); blob_appendf(&event, "P %s\n", zUuid); free(zUuid); } - if( zMimetype && zMimetype[0] ){ - blob_appendf(&event, "N %s\n", zMimetype); - } if( zClr && zClr[0] ){ blob_appendf(&event, "T +bgcolor * %F\n", zClr); } if( zTags && zTags[0] ){ Blob tags, one; @@ -360,11 +312,11 @@ Stmt q; char *zBlob; /* Load the tags string into a blob */ blob_zero(&tags); - blob_append(&tags, zTags, -1); + blob_append(&tags, zTags, -1); /* Collapse all sequences of whitespace and "," characters into ** a single space character */ zBlob = blob_str(&tags); for(i=j=0; zBlob[i]; i++, j++){ @@ -389,47 +341,37 @@ db_prepare(&q, "SELECT x FROM newtags ORDER BY x"); while( db_step(&q)==SQLITE_ROW ){ blob_appendf(&event, "T +sym-%F *\n", db_column_text(&q, 0)); } db_finalize(&q); - } - if( !login_is_nobody() ){ - blob_appendf(&event, "U %F\n", login_name()); + } + if( g.zLogin ){ + blob_appendf(&event, "U %F\n", g.zLogin); } 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_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", nrid); - if( manifest_crosslink(nrid, &event, MC_NONE)==0 ){ - db_end_transaction(1); - style_header("Error"); - @ Internal error: Fossil tried to make an invalid artifact for - @ the edited technode. - style_footer(); - return; - } + manifest_crosslink(nrid, &event); assert( blob_is_reset(&event) ); content_deltify(rid, nrid, 0); db_end_transaction(0); - cgi_redirectf("technote?name=%T", zId); + cgi_redirectf("event?name=%T", zEventId); } if( P("cancel")!=0 ){ - cgi_redirectf("technote?name=%T", zId); + cgi_redirectf("event?name=%T", zEventId); return; } if( zBody==0 ){ - zBody = mprintf("Insert new content here..."); - } - if( isNew ){ - style_header("New Tech-note %S", zId); - }else{ - style_header("Edit Tech-note %S", zId); - } - if( P("preview")!=0 ){ - Blob com; + zBody = mprintf("<i>Event Text</i>"); + } + zHtmlPageName = mprintf("Edit Event %S", zEventId); + style_header(zHtmlPageName); + if( P("preview")!=0 ){ + Blob title, tail, com; @ <p><b>Timeline comment preview:</b></p> @ <blockquote> @ <table border="0"> if( zClr && zClr[0] ){ @ <tr><td style="background-color: %h(zClr);"> @@ -441,55 +383,55 @@ wiki_convert(&com, 0, WIKI_INLINE|WIKI_NOBADLINKS); @ </td></tr></table> @ </blockquote> @ <p><b>Page content preview:</b><p> @ <blockquote> - blob_init(&event, 0, 0); + blob_zero(&event); blob_append(&event, zBody, -1); - wiki_render_by_mimetype(&event, zMimetype); + if( wiki_find_title(&event, &title, &tail) ){ + @ <h2 align="center">%h(blob_str(&title))</h2> + wiki_convert(&tail, 0, 0); + }else{ + wiki_convert(&event, 0, 0); + } @ </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> + @ <form method="post" action="%s(g.zTop)/eventedit"><div> login_insert_csrf_secret(); - @ <input type="hidden" name="name" value="%h(zId)" /> + @ <input type="hidden" name="name" value="%h(zEventId)" /> @ <table border="0" cellspacing="10"> - @ <tr><th align="right" valign="top">Timestamp (UTC):</th> + @ <tr><th align="right" valign="top">Event Time (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> + @ <tr><th align="right" valign="top">Timeline Comment:</th> @ <td valign="top"> - @ <textarea name="c" class="technoteedit" cols="80" + @ <textarea name="c" class="eventedit" cols="80" @ rows="3" wrap="virtual">%h(zComment)</textarea> @ </td></tr> - @ <tr><th align="right" valign="top">Timeline Background Color:</th> + @ <tr><th align="right" valign="top">Background Color:</th> @ <td valign="top"> render_color_chooser(0, zClr, 0, "clr", "cclr"); @ </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">Markup Style:</th> - @ <td valign="top"> - mimetype_option_menu(zMimetype); - @ </td></tr> - + @ <tr><th align="right" valign="top">Page Content:</th> @ <td valign="top"> - @ <textarea name="w" class="technoteedit" cols="80" + @ <textarea name="w" class="eventedit" cols="80" @ rows="%d(n)" wrap="virtual">%h(zBody)</textarea> @ </td></tr> @ <tr><td colspan="2"> @ <input type="submit" name="preview" value="Preview Your Changes" /> Index: src/export.c ================================================================== --- src/export.c +++ src/export.c @@ -53,41 +53,25 @@ zName[j] = 0; printf(" %s <%s>", zName, zUser); free(zName); return; } - /* - ** We have contact information. - ** It may or may not contain an email address. - */ zContact = db_column_text(&q, 0); for(i=0; zContact[i] && zContact[i]!='>' && zContact[i]!='<'; i++){} if( zContact[i]==0 ){ - /* No email address found. Take as user info if not empty */ printf(" %s <%s>", zContact[0] ? zContact : zUser, zUser); db_reset(&q); return; } if( zContact[i]=='<' ){ - /* - ** Found beginning of email address. Look for the end and extract - ** the part. - */ zEmail = mprintf("%s", &zContact[i]); - for(j=0; zEmail[j] && zEmail[j]!='>'; j++){} - if( zEmail[j]=='>' ) zEmail[j+1] = 0; + for(i=0; zEmail[i] && zEmail[i]!='>'; i++){} + if( zEmail[i]=='>' ) zEmail[i+1] = 0; }else{ - /* - ** Found an end marker for email, but nothing else. - */ zEmail = mprintf("<%s>", zUser); } - /* - ** Here zContact[i] either '<' or '>'. Extract the string _before_ - ** either as user name. - */ - zName = mprintf("%.*s", i-1, zContact); + zName = mprintf("%.*s", i, zContact); for(i=j=0; zName[i]; i++){ if( zName[i]!='"' ) zName[j++] = zName[i]; } zName[j] = 0; printf(" %s %s", zName, zEmail); @@ -104,18 +88,18 @@ ** ** Usage: %fossil export --git ?OPTIONS? ?REPOSITORY? ** ** 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 +** 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 checkout. 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 +** Only check-ins are exported using --git. Git does not support tickets ** or wiki or events or attachments, so none of those are exported. ** ** If the "--import-marks FILE" option is used, it contains a list of ** rids to skip. ** @@ -124,11 +108,11 @@ ** ** Options: ** --export-marks FILE export rids of exported data to FILE ** --import-marks FILE read rids of data to ignore from FILE ** --repository|-R REPOSITORY export the given REPOSITORY -** +** ** See also: import */ void export_cmd(void){ Stmt q, q2, q3; int i; @@ -179,11 +163,11 @@ db_finalize(&qc); fclose(f); } /* Step 1: Generate "blob" records for every artifact that is part - ** of a check-in + ** of a check-in */ fossil_binary_mode(stdout); db_multi_exec("CREATE TEMP TABLE newblob(rid INTEGER KEY, srcid INTEGER)"); db_multi_exec("CREATE INDEX newblob_src ON newblob(srcid)"); db_multi_exec( @@ -232,12 +216,12 @@ db_finalize(&q3); /* Output the commit records. */ db_prepare(&q, - "SELECT strftime('%%s',mtime), objid, coalesce(ecomment,comment)," - " coalesce(euser,user)," + "SELECT strftime('%%s',mtime), objid, coalesce(comment,ecomment)," + " coalesce(user,euser)," " (SELECT value FROM tagxref WHERE rid=objid AND tagid=%d)" " FROM event" " WHERE type='ci' AND NOT EXISTS (SELECT 1 FROM oldcommit WHERE objid=rid)" " ORDER BY mtime ASC", TAG_BRANCH Index: src/file.c ================================================================== --- src/file.c +++ src/file.c @@ -39,60 +39,46 @@ # include <sys/utime.h> #else # include <sys/time.h> #endif -#if INTERFACE - -#include <dirent.h> -#if defined(_WIN32) -# define DIR _WDIR -# define dirent _wdirent -# define opendir _wopendir -# define readdir _wreaddir -# define closedir _wclosedir -#endif /* _WIN32 */ - +/* +** The file status information from the most recent stat() call. +** +** Use _stati64 rather than stat on windows, in order to handle files +** larger than 2GB. +*/ #if defined(_WIN32) && (defined(__MSVCRT__) || defined(_MSC_VER)) -struct fossilStat { - i64 st_size; - i64 st_mtime; - int st_mode; -}; -#endif - -#endif /* INTERFACE */ - -#if !defined(_WIN32) || !(defined(__MSVCRT__) || defined(_MSC_VER)) -# define fossilStat stat -#endif - +# undef stat +# define stat _stati64 +#endif /* ** On Windows S_ISLNK always returns FALSE. */ #if !defined(S_ISLNK) # define S_ISLNK(x) (0) #endif static int fileStatValid = 0; -static struct fossilStat fileStat; +static struct stat fileStat; /* ** Fill stat buf with information received from stat() or lstat(). ** lstat() is called on Unix if isWd is TRUE and allow-symlinks setting is on. ** */ -static int fossil_stat(const char *zFilename, struct fossilStat *buf, int isWd){ +static int fossil_stat(const char *zFilename, struct stat *buf, int isWd){ int rc; - void *zMbcs = fossil_utf8_to_filename(zFilename); #if !defined(_WIN32) + char *zMbcs = fossil_utf8_to_filename(zFilename); if( isWd && g.allowSymlinks ){ rc = lstat(zMbcs, buf); }else{ rc = stat(zMbcs, buf); } #else - rc = win32_stat(zMbcs, buf, isWd); + wchar_t *zMbcs = fossil_utf8_to_filename(zFilename); + rc = _wstati64(zMbcs, buf); #endif fossil_filename_free(zMbcs); return rc; } @@ -232,24 +218,33 @@ blob_reset(&content); } /* ** Return file permissions (normal, executable, or symlink): -** - PERM_EXE on Unix if file is executable; +** - PERM_EXE if file is executable; ** - PERM_LNK on Unix if file is symlink and allow-symlinks option is on; ** - PERM_REG for all other cases (regular file, directory, fifo, etc). */ int file_wd_perm(const char *zFilename){ -#if !defined(_WIN32) - if( !getStat(zFilename, 1) ){ - if( S_ISREG(fileStat.st_mode) && ((S_IXUSR)&fileStat.st_mode)!=0 ) - return PERM_EXE; - else if( g.allowSymlinks && S_ISLNK(fileStat.st_mode) ) - return PERM_LNK; - } + if( getStat(zFilename, 1) ) return PERM_REG; +#if defined(_WIN32) +# ifndef S_IXUSR +# define S_IXUSR _S_IEXEC +# endif + if( S_ISREG(fileStat.st_mode) && ((S_IXUSR)&fileStat.st_mode)!=0 ) + return PERM_EXE; + else + return PERM_REG; +#else + if( S_ISREG(fileStat.st_mode) && + ((S_IXUSR|S_IXGRP|S_IXOTH)&fileStat.st_mode)!=0 ) + return PERM_EXE; + else if( g.allowSymlinks && S_ISLNK(fileStat.st_mode) ) + return PERM_LNK; + else + return PERM_REG; #endif - return PERM_REG; } /* ** Return TRUE if the named file is an executable. Return false ** for directories, devices, fifos, symlinks, etc. @@ -307,16 +302,16 @@ /* ** Wrapper around the access() system call. */ int file_access(const char *zFilename, int flags){ - int rc; - void *zMbcs = fossil_utf8_to_filename(zFilename); #ifdef _WIN32 - rc = win32_access(zMbcs, flags); + wchar_t *zMbcs = fossil_utf8_to_filename(zFilename); + int rc = _waccess(zMbcs, flags); #else - rc = access(zMbcs, flags); + char *zMbcs = fossil_utf8_to_filename(zFilename); + int rc = access(zMbcs, flags); #endif fossil_filename_free(zMbcs); return rc; } @@ -324,16 +319,16 @@ ** Wrapper around the chdir() system call. ** If bChroot=1, do a chroot to this dir as well ** (UNIX only) */ int file_chdir(const char *zChDir, int bChroot){ - int rc; - void *zPath = fossil_utf8_to_filename(zChDir); #ifdef _WIN32 - rc = win32_chdir(zPath, bChroot); + wchar_t *zPath = fossil_utf8_to_filename(zChDir); + int rc = _wchdir(zPath); #else - rc = chdir(zPath); + char *zPath = fossil_utf8_to_filename(zChDir); + int rc = chdir(zPath); if( !rc && bChroot ){ rc = chroot(zPath); if( !rc ) rc = chdir("/"); } #endif @@ -386,36 +381,19 @@ FILE *in, *out; int got; char zBuf[8192]; in = fossil_fopen(zFrom, "rb"); if( in==0 ) fossil_fatal("cannot open \"%s\" for reading", zFrom); - file_mkfolder(zTo, 0); out = fossil_fopen(zTo, "wb"); if( out==0 ) fossil_fatal("cannot open \"%s\" for writing", zTo); while( (got=fread(zBuf, 1, sizeof(zBuf), in))>0 ){ fwrite(zBuf, 1, got, out); } fclose(in); fclose(out); } -/* -** COMMAND: test-file-copy -** -** Usage: %fossil test-file-copy SOURCE DESTINATION -** -** Make a copy of the file at SOURCE into a new name DESTINATION. Any -** directories in the path leading up to DESTINATION that do not already -** exist are created automatically. -*/ -void test_file_copy(void){ - if( g.argc!=4 ){ - fossil_fatal("Usage: %s test-file-copy SOURCE DESTINATION", g.argv[0]); - } - file_copy(g.argv[2], g.argv[3]); -} - /* ** Set or clear the execute bit on a file. Return true if a change ** occurred and false if this routine is a no-op. */ int file_wd_setexe(const char *zFilename, int onoff){ @@ -423,16 +401,16 @@ #if !defined(_WIN32) struct stat buf; if( fossil_stat(zFilename, &buf, 1)!=0 || S_ISLNK(buf.st_mode) ) return 0; if( onoff ){ int targetMode = (buf.st_mode & 0444)>>2; - if( (buf.st_mode & 0100) == 0 ){ + if( (buf.st_mode & 0111)!=targetMode ){ chmod(zFilename, buf.st_mode | targetMode); rc = 1; } }else{ - if( (buf.st_mode & 0100) != 0 ){ + if( (buf.st_mode & 0111)!=0 ){ chmod(zFilename, buf.st_mode & ~0111); rc = 1; } } #endif /* _WIN32 */ @@ -442,16 +420,15 @@ /* ** Set the mtime for a file. */ void file_set_mtime(const char *zFilename, i64 newMTime){ #if !defined(_WIN32) - char *zMbcs; struct timeval tv[2]; memset(tv, 0, sizeof(tv[0])*2); tv[0].tv_sec = newMTime; tv[1].tv_sec = newMTime; - zMbcs = fossil_utf8_to_filename(zFilename); + char *zMbcs = fossil_utf8_to_filename(zFilename); utimes(zMbcs, tv); #else struct _utimbuf tb; wchar_t *zMbcs = fossil_utf8_to_filename(zFilename); tb.actime = newMTime; @@ -527,45 +504,10 @@ return rc; } return 0; } -/* -** Create the tree of directories in which zFilename belongs, if that sequence -** of directories does not already exist. -*/ -void file_mkfolder(const char *zFilename, int forceFlag){ - int i, nName; - char *zName; - - nName = strlen(zFilename); - zName = mprintf("%s", zFilename); - nName = file_simplify_name(zName, nName, 0); - for(i=1; i<nName; i++){ - if( zName[i]=='/' ){ - zName[i] = 0; -#if defined(_WIN32) || defined(__CYGWIN__) - /* - ** On Windows, local path looks like: C:/develop/project/file.txt - ** The if stops us from trying to create a directory of a drive letter - ** C: in this example. - */ - if( !(i==2 && zName[1]==':') ){ -#endif - if( file_mkdir(zName, forceFlag) && file_isdir(zName)!=1 ){ - fossil_fatal_recursive("unable to create directory %s", zName); - return; - } -#if defined(_WIN32) || defined(__CYGWIN__) - } -#endif - zName[i] = '/'; - } - } - free(zName); -} - /* ** Removes the directory named in the argument, if it exists. The directory ** must be empty and cannot be the current directory or the root directory. ** ** Returns zero upon success. @@ -689,11 +631,10 @@ } /* ** Simplify a filename by ** -** * Remove extended path prefix on windows and cygwin ** * Convert all \ into / on windows and cygwin ** * removing any trailing and duplicate / ** * removing /./ ** * removing /A/../ ** @@ -700,27 +641,17 @@ ** Changes are made in-place. Return the new name length. ** If the slash parameter is non-zero, the trailing slash, if any, ** is retained. */ int file_simplify_name(char *z, int n, int slash){ - int i = 1, j; + int i, j; if( n<0 ) n = strlen(z); - /* On windows and cygwin convert all \ characters to / - * and remove extended path prefix if present */ + /* On windows and cygwin convert all \ characters to / */ #if defined(_WIN32) || defined(__CYGWIN__) - for(j=0; j<n; j++){ - if( z[j]=='\\' ) z[j] = '/'; - } - if( n>3 && !memcmp(z, "//?/", 4) ){ - if( fossil_strnicmp(z+4,"UNC", 3) ){ - i += 4; - z[0] = z[4]; - }else{ - i += 6; - z[0] = '/'; - } + for(i=0; i<n; i++){ + if( z[i]=='\\' ) z[i] = '/'; } #endif /* Removing trailing "/" characters */ if( !slash ){ @@ -727,11 +658,11 @@ while( n>1 && z[n-1]=='/' ){ n--; } } /* Remove duplicate '/' characters. Except, two // at the beginning ** of a pathname is allowed since this is important on windows. */ - for(j=1; i<n; i++){ + for(i=j=1; i<n; i++){ z[j++] = z[i]; while( z[i]=='/' && i<n-1 && z[i+1]=='/' ) i++; } n = j; @@ -759,11 +690,11 @@ } } if( j>=0 ) z[j] = z[i]; j++; } - if( j==0 ) z[j++] = '/'; + if( j==0 ) z[j++] = '.'; z[j] = 0; return j; } /* @@ -792,11 +723,25 @@ ** characters are converted to '/'. No conversions are needed on ** unix. */ void file_getcwd(char *zBuf, int nBuf){ #ifdef _WIN32 - win32_getcwd(zBuf, nBuf); + char *zPwdUtf8; + int nPwd; + int i; + wchar_t zPwd[2000]; + if( _wgetcwd(zPwd, sizeof(zPwd)/sizeof(zPwd[0])-1)==0 ){ + fossil_fatal("cannot find the current working directory."); + } + zPwdUtf8 = fossil_filename_to_utf8(zPwd); + nPwd = strlen(zPwdUtf8); + if( nPwd > nBuf-1 ){ + fossil_fatal("pwd too big: max %d\n", nBuf-1); + } + for(i=0; zPwdUtf8[i]; i++) if( zPwdUtf8[i]=='\\' ) zPwdUtf8[i] = '/'; + memcpy(zBuf, zPwdUtf8, nPwd+1); + fossil_filename_free(zPwdUtf8); #else if( getcwd(zBuf, nBuf-1)==0 ){ if( errno==ERANGE ){ fossil_fatal("pwd too big: max %d\n", nBuf-1); }else{ @@ -814,11 +759,11 @@ int file_is_absolute_path(const char *zPath){ if( zPath[0]=='/' #if defined(_WIN32) || defined(__CYGWIN__) || zPath[0]=='\\' || (fossil_isalpha(zPath[0]) && zPath[1]==':' - && (zPath[2]=='\\' || zPath[2]=='/' || zPath[2]=='\0')) + && (zPath[2]=='\\' || zPath[2]=='/')) #endif ){ return 1; }else{ return 0; @@ -833,40 +778,39 @@ ** Convert /A/../ to just / ** If the slash parameter is non-zero, the trailing slash, if any, ** is retained. */ void file_canonical_name(const char *zOrigName, Blob *pOut, int slash){ - blob_zero(pOut); if( file_is_absolute_path(zOrigName) ){ - blob_appendf(pOut, "%/", zOrigName); - }else{ - char zPwd[2000]; - file_getcwd(zPwd, sizeof(zPwd)-strlen(zOrigName)); - if( zPwd[0]=='/' && strlen(zPwd)==1 ){ - /* when on '/', don't add an extra '/' */ - if( zOrigName[0]=='.' && strlen(zOrigName)==1 ){ - /* '.' when on '/' mean '/' */ - blob_appendf(pOut, "%/", zPwd); - }else{ - blob_appendf(pOut, "%/%/", zPwd, zOrigName); - } - }else{ - blob_appendf(pOut, "%//%/", zPwd, zOrigName); - } - } #if defined(_WIN32) || defined(__CYGWIN__) - { char *zOut; +#endif + blob_set(pOut, zOrigName); + blob_materialize(pOut); +#if defined(_WIN32) || defined(__CYGWIN__) /* ** On Windows/cygwin, normalize the drive letter to upper case. */ zOut = blob_str(pOut); - if( fossil_islower(zOut[0]) && zOut[1]==':' && zOut[2]=='/' ){ + if( fossil_islower(zOut[0]) && zOut[1]==':' ){ zOut[0] = fossil_toupper(zOut[0]); } - } +#endif + }else{ + char zPwd[2000]; + file_getcwd(zPwd, sizeof(zPwd)-strlen(zOrigName)); +#if defined(_WIN32) + /* + ** On Windows, normalize the drive letter to upper case. + */ + if( fossil_islower(zPwd[0]) && zPwd[1]==':' ){ + zPwd[0] = fossil_toupper(zPwd[0]); + } #endif + blob_zero(pOut); + blob_appendf(pOut, "%//%/", zPwd, zOrigName); + } blob_resize(pOut, file_simplify_name(blob_buffer(pOut), blob_size(pOut), slash)); } /* @@ -970,12 +914,10 @@ for(j=i+1; zPwd[j]; j++){ if( zPwd[j]=='/' ){ blob_append(pOut, "/..", 3); } } - while( i>0 && (zPwd[i]!='/')) --i; - blob_append(pOut, zPath+i, j-i); } if( slash && i>0 && zPath[strlen(zPath)-1]=='/'){ blob_append(pOut, "/", 1); } blob_reset(&tmp); @@ -987,16 +929,11 @@ blob_append(pOut, &zPath[i+1], -1); blob_reset(&tmp); return; } while( zPath[i-1]!='/' ){ i--; } - if( zPwd[0]=='/' && strlen(zPwd)==1 ){ - /* If on '/', don't go to higher level */ - blob_zero(&tmp); - }else{ - blob_set(&tmp, "../"); - } + blob_set(&tmp, "../"); for(j=i; zPwd[j]; j++){ if( zPwd[j]=='/' ){ blob_append(&tmp, "../", 3); } } @@ -1039,14 +976,11 @@ int nFull; char *zFull; int (*xCmp)(const char*,const char*,int); blob_zero(pOut); - if( !g.localOpen ){ - blob_appendf(pOut, "%s", zOrigName); - return 1; - } + db_must_be_within_tree(); file_canonical_name(g.zLocalRoot, &localRoot, 1); nLocalRoot = blob_size(&localRoot); zLocalRoot = blob_buffer(&localRoot); assert( nLocalRoot>0 && zLocalRoot[nLocalRoot-1]=='/' ); file_canonical_name(zOrigName, &full, 0); @@ -1057,12 +991,11 @@ }else{ xCmp = fossil_strnicmp; } /* Special case. zOrigName refers to g.zLocalRoot directory. */ - if( (nFull==nLocalRoot-1 && xCmp(zLocalRoot, zFull, nFull)==0) - || (nFull==1 && zFull[0]=='/' && nLocalRoot==1 && zLocalRoot[0]=='/') ){ + if( nFull==nLocalRoot-1 && xCmp(zLocalRoot, zFull, nFull)==0 ){ blob_append(pOut, ".", 1); blob_reset(&localRoot); blob_reset(&full); return 1; } @@ -1091,12 +1024,12 @@ ** a boolean: "yes", "no", "true", "false", etc. */ void cmd_test_tree_name(void){ int i; Blob x; - db_find_and_open_repository(0,0); blob_zero(&x); + capture_case_sensitive_option(); for(i=2; i<g.argc; i++){ if( file_tree_name(g.argv[i], &x, 1) ){ fossil_print("%s\n", blob_buffer(&x)); blob_reset(&x); } @@ -1238,10 +1171,26 @@ rc = blob_compare(&onDisk, pContent); blob_reset(&onDisk); return rc==0; } +/* +** Portable unicode implementation of opendir() +*/ +#if INTERFACE + +#include <dirent.h> +#if defined(_WIN32) +# define DIR _WDIR +# define dirent _wdirent +# define opendir _wopendir +# define readdir _wreaddir +# define closedir _wclosedir +#endif /* _WIN32 */ + +#endif /* INTERFACE */ + /* ** Return the value of an environment variable as UTF8. ** Use fossil_filename_free() to release resources. */ char *fossil_getenv(const char *zName){ @@ -1254,29 +1203,10 @@ #endif if( zValue ) zValue = fossil_filename_to_utf8(zValue); return zValue; } -/* -** Sets the value of an environment variable as UTF8. -*/ -int fossil_setenv(const char *zName, const char *zValue){ - int rc; - char *zString = mprintf("%s=%s", zName, zValue); -#ifdef _WIN32 - wchar_t *uString = fossil_utf8_to_unicode(zString); - rc = _wputenv(uString); - fossil_unicode_free(uString); - fossil_free(zString); -#else - rc = putenv(zString); - /* NOTE: Cannot free the string on POSIX. */ - /* fossil_free(zString); */ -#endif - return rc; -} - /* ** Like fopen() but always takes a UTF8 argument. */ FILE *fossil_fopen(const char *zName, const char *zMode){ #ifdef _WIN32 Index: src/finfo.c ================================================================== --- src/finfo.c +++ src/finfo.c @@ -43,34 +43,28 @@ ** 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. ** -l|--log select log mode (the default) -** -n|--limit N Display the first N changes (default unlimited). -** N<=0 means no limit. +** -n|--limit N display the first N changes ** --offset P skip P changes ** -p|--print select print mode ** -r|--revision R print the given revision (or ckout, if none is given) ** to stdout (only in print mode) ** -s|--status select status mode (print a status indicator for FILE) -** -W|--width <num> Width of lines (default is to auto-detect). Must be -** >22 or 0 (= no limit, resulting in a single line per -** entry). ** ** See also: artifact, cat, descendants, info, leaves */ void finfo_cmd(void){ + capture_case_sensitive_option(); db_must_be_within_tree(); if( find_option("status","s",0) ){ Stmt q; Blob line; Blob fname; int vid; - /* 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 checkout to finfo files in"); } @@ -119,13 +113,10 @@ }else if( find_option("print","p",0) ){ Blob record; Blob fname; const char *zRevision = find_option("revision", "r", 1); - /* We should be done with options.. */ - verify_all_options(); - file_tree_name(g.argv[2], &fname, 1); if( zRevision ){ historical_version_of_file(zRevision, blob_str(&fname), &record, 0,0,0,0); }else{ int rid = db_int(0, "SELECT rid FROM vfile WHERE pathname=%B %s", @@ -143,38 +134,21 @@ Stmt q; Blob fname; int rid; const char *zFilename; const char *zLimit; - const char *zWidth; const char *zOffset; - int iLimit, iOffset, iBrief, iWidth; + int iLimit, iOffset, iBrief; if( find_option("log","l",0) ){ /* this is the default, no-op */ } zLimit = find_option("limit","n",1); - zWidth = find_option("width","W",1); iLimit = zLimit ? atoi(zLimit) : -1; zOffset = find_option("offset",0,1); iOffset = zOffset ? atoi(zOffset) : 0; iBrief = (find_option("brief","b",0) == 0); - if( iLimit==0 ){ - iLimit = -1; - } - if( zWidth ){ - iWidth = atoi(zWidth); - if( (iWidth!=0) && (iWidth<=22) ){ - fossil_fatal("-W|--width value must be >22 or 0"); - } - }else{ - iWidth = -1; - } - - /* We should be done with options.. */ - verify_all_options(); - if( g.argc!=3 ){ usage("?-l|--log? ?-b|--brief? FILENAME"); } file_tree_name(g.argv[2], &fname, 1); rid = db_int(0, "SELECT rid FROM vfile WHERE pathname=%B %s", @@ -182,11 +156,11 @@ if( rid==0 ){ fossil_fatal("no history for file: %b", &fname); } zFilename = blob_str(&fname); db_prepare(&q, - "SELECT b.uuid, ci.uuid, date(event.mtime%s)," + "SELECT b.uuid, ci.uuid, date(event.mtime,'localtime')," " coalesce(event.ecomment, event.comment)," " coalesce(event.euser, event.user)," " (SELECT value FROM tagxref WHERE tagid=%d AND tagtype>0" " AND tagxref.rid=mlink.mid)" /* Tags */ " FROM mlink, blob b, event, blob ci, filename" @@ -194,12 +168,11 @@ " AND mlink.fnid=filename.fnid" " AND b.rid=mlink.fid" " AND event.objid=mlink.mid" " AND event.objid=ci.rid" " ORDER BY event.mtime DESC LIMIT %d OFFSET %d", - timeline_utc(), TAG_BRANCH, zFilename, filename_collation(), - iLimit, iOffset + TAG_BRANCH, zFilename, filename_collation(), iLimit, iOffset ); blob_zero(&line); if( iBrief ){ fossil_print("History of %s\n", blob_str(&fname)); } @@ -212,23 +185,23 @@ const char *zBr = db_column_text(&q, 5); char *zOut; if( zBr==0 ) zBr = "trunk"; if( iBrief ){ fossil_print("%s ", zDate); - zOut = mprintf( - "[%S] %s (user: %s, artifact: [%S], branch: %s)", + zOut = sqlite3_mprintf( + "[%.10s] %s (user: %s, artifact: [%.10s], branch: %s)", zCiUuid, zCom, zUser, zFileUuid, zBr); - comment_print(zOut, zCom, 11, iWidth, g.comFmtFlags); - fossil_free(zOut); + comment_print(zOut, 11, 79); + sqlite3_free(zOut); }else{ blob_reset(&line); - blob_appendf(&line, "%S ", zCiUuid)