Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Changes In Branch branch-1.28 Excluding Merge-Ins
This is equivalent to a diff from 565ba734 to 4778b1d0
2014-04-22
| ||
10:01 | Make sure SQLITE_TESTCTRL_BYTEORDER is defined. ... (Closed-Leaf check-in: 4778b1d0 user: jan.nijtmans tags: branch-1.28) | |
09:43 | [a138dc97fc]: Fix a potential segfault when the SSH_CONNECTION environment variable is defined. 9d2ae6342c: In the command-line shell, run set writable_schema before running the ".clone" command. ... (check-in: d7889a2e user: jan.nijtmans tags: branch-1.28) | |
2014-04-10
| ||
08:36 | Add test-cases for function file_relative_name(), three of them failing without [565ba734d2] ... (check-in: 1762a72f user: jan.nijtmans tags: trunk) | |
2014-04-09
| ||
21:55 | Cherry-pick [c5b86115de]: Update version of OpenSSL that is referred to in the makefiles. Cherry-pick [565ba734d2]: Fix "fossil extras" when a "extra" entry matches partly with current directory name (reported by j. van den hoff). ... (check-in: c779b689 user: jan.nijtmans tags: branch-1.28) | |
20:35 | Fix "fossil extras" when a "extra" entry matches partly with current directory name (reported by j. van den hoff) ... (check-in: 565ba734 user: jan.nijtmans tags: trunk) | |
2014-04-08
| ||
14:10 | Fix handling of directory link in /dir page, which was broken by [b34fda9692] ... (check-in: 4cb4fd1a user: jan.nijtmans tags: trunk) | |
Changes to BUILD.txt.
︙ | ︙ | |||
20 21 22 23 24 25 26 | If you have VC++ installed on your system, then consider: 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 | | | 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | If you have VC++ installed on your system, then consider: 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 Makefile.classic to an alternative name such as "GNUMakefile", "BSDMakefile", or "makefile" and editing the copy. BUILDING OUTSIDE THE SOURCE TREE An out of source build is pretty easy: |
︙ | ︙ | |||
59 60 61 62 63 64 65 | real makefile in src/main.mk. The src/main.mk makefile is automatically generated by a TCL script found at src/makemake.tcl. 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 | | | 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 | real makefile in src/main.mk. The src/main.mk makefile is automatically generated by a TCL script found at src/makemake.tcl. 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 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. * The src/mkindex.c program generates some C code that implements static lookup tables. See the header comment in the source code for details on what it does. Additional information on the build process is available from http://www.fossil-scm.org/fossil/doc/trunk/www/makefile.wiki |
Changes to COPYRIGHT-BSD2.txt.
1 2 | Copyright 2007 D. Richard Hipp. All rights reserved. | | | | | | | | | | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | 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 following conditions are met: 1. Redistributions of source code must retain the above 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 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 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, 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 as representing official policies, either expressed or implied, of anybody else. |
Changes to Makefile.Cygwin.in.
︙ | ︙ | |||
34 35 36 37 38 39 40 | #### Tcl shell for use in running the fossil testsuite. If you do not # care about testing the end result, this can be blank. # TCLSH = tclsh LIB = @LDFLAGS@ @EXTRA_LDFLAGS@ @LIBS@ | | > > > | 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | #### Tcl shell for use in running the fossil testsuite. If you do not # care about testing the end result, this can be blank. # TCLSH = tclsh LIB = @LDFLAGS@ @EXTRA_LDFLAGS@ @LIBS@ TCC += @EXTRA_CFLAGS@ @CPPFLAGS@ @CFLAGS@ -DHAVE_AUTOCONFIG_H -DFOSSIL_OMIT_LOAD_AVERAGE INSTALLDIR =$(DESTDIR)@prefix@/bin USE_SYSTEM_SQLITE = @USE_SYSTEM_SQLITE@ FOSSIL_ENABLE_TCL = @FOSSIL_ENABLE_TCL@ FOSSIL_ENABLE_TCL_STUBS = @FOSSIL_ENABLE_TCL_STUBS@ FOSSIL_ENABLE_TCL_PRIVATE_STUBS = @FOSSIL_ENABLE_TCL_PRIVATE_STUBS@ SQLITE_CFLAGS += -DSQLITE_WIN32_NO_ANSI SQLITE_CFLAGS += -DSQLITE_WIN32_MAX_PATH_BYTES=4096 SQLITE_CFLAGS += -DSQLITE_MAX_MMAP_SIZE=0x7fff0000 include $(SRCDIR)/main.mk distclean: clean |
︙ | ︙ |
Changes to Makefile.in.
︙ | ︙ | |||
38 39 40 41 42 43 44 45 46 47 48 49 | # TCLSH = tclsh LIB = @LDFLAGS@ @EXTRA_LDFLAGS@ @LIBS@ TCC += @EXTRA_CFLAGS@ @CPPFLAGS@ @CFLAGS@ -DHAVE_AUTOCONFIG_H INSTALLDIR = $(DESTDIR)@prefix@/bin USE_SYSTEM_SQLITE = @USE_SYSTEM_SQLITE@ include $(SRCDIR)/main.mk distclean: clean rm -f autoconfig.h config.log Makefile | > > > | 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | # TCLSH = tclsh LIB = @LDFLAGS@ @EXTRA_LDFLAGS@ @LIBS@ TCC += @EXTRA_CFLAGS@ @CPPFLAGS@ @CFLAGS@ -DHAVE_AUTOCONFIG_H INSTALLDIR = $(DESTDIR)@prefix@/bin USE_SYSTEM_SQLITE = @USE_SYSTEM_SQLITE@ 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 |
Changes to auto.def.
︙ | ︙ | |||
86 87 88 89 90 91 92 93 94 95 96 97 98 99 | # # no-op. Markdown is now enabled by default. #} if {[opt-bool static]} { # XXX: This will not work on all systems. define-append EXTRA_LDFLAGS -static } set tclpath [opt-val with-tcl] if {$tclpath ne ""} { set tclprivatestubs [opt-bool with-tcl-private-stubs] # Note parse-tclconfig-sh is in autosetup/local.tcl if {$tclpath eq "1"} { if {$tclprivatestubs} { | > > > > > > > > > > > | 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 | # # no-op. Markdown is now enabled by default. #} if {[opt-bool static]} { # XXX: This will not work on all systems. define-append EXTRA_LDFLAGS -static } # 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] # Note parse-tclconfig-sh is in autosetup/local.tcl if {$tclpath eq "1"} { if {$tclprivatestubs} { |
︙ | ︙ | |||
214 215 216 217 218 219 220 | } } } else { user-error "OpenSSL not found. Consider --with-openssl=none to disable HTTPS support" } } | < < < < < < < < < < < | 225 226 227 228 229 230 231 232 233 234 235 236 237 238 | } } } else { user-error "OpenSSL not found. Consider --with-openssl=none to disable HTTPS support" } } 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]} { msg-result "Using readline for line editing" } elseif {[cc-check-includes editline/readline.h] && [cc-check-function-in-lib readline edit]} { define-feature editline |
︙ | ︙ | |||
247 248 249 250 251 252 253 | # Last resort, may be Windows if {[string match *mingw* [get-define host]]} { define-append LIBS -lwsock32 } } cc-check-function-in-lib iconv iconv | < < < < < | 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 | # Last resort, may be Windows if {[string match *mingw* [get-define host]]} { define-append LIBS -lwsock32 } } cc-check-function-in-lib iconv iconv # 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 make-template Makefile.in make-template Makefile.Cygwin.in make-config-header autoconfig.h -auto {USE_* FOSSIL_*} |
Changes to src/add.c.
︙ | ︙ | |||
23 24 25 26 27 28 29 | #include <assert.h> #include <dirent.h> #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, | | | 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | #include <assert.h> #include <dirent.h> #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 "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){ /* Possible names of the local per-checkout database file and ** its associated journals |
︙ | ︙ | |||
220 221 222 223 224 225 226 | ** ** The --ignore and --clean options are comma-separate lists of glob patterns ** for files to be excluded. Example: '*.o,*.obj,*.exe' If the --ignore ** option does not appear on the command line then the "ignore-glob" setting ** is used. If the --clean option does not appear on the command line then ** the "clean-glob" setting is used. ** | < < < < < < < | 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 | ** ** The --ignore and --clean options are comma-separate lists of glob patterns ** for files to be excluded. Example: '*.o,*.obj,*.exe' If the --ignore ** option does not appear on the command line then the "ignore-glob" setting ** is used. If the --clean option does not appear on the command line then ** the "clean-glob" setting is used. ** ** 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 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 ** 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 */ 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() */ zCleanFlag = find_option("clean",0,1); zIgnoreFlag = find_option("ignore",0,1); if( find_option("dotfiles",0,0)!=0 ) scanFlags |= SCAN_ALL; capture_case_sensitive_option(); db_must_be_within_tree(); if( zCleanFlag==0 ){ zCleanFlag = db_get("clean-glob", 0); } if( zIgnoreFlag==0 ){ |
︙ | ︙ | |||
292 293 294 295 296 297 298 | vfile_scan(&fullName, nRoot-1, scanFlags, pClean, pIgnore); }else if( isDir==0 ){ fossil_warning("not found: %s", zName); }else if( file_access(zName, R_OK) ){ fossil_fatal("cannot open %s", zName); }else{ char *zTreeName = &zName[nRoot]; | < < < < < < < < < < < < < < < | 285 286 287 288 289 290 291 292 293 294 295 296 297 298 | vfile_scan(&fullName, nRoot-1, scanFlags, pClean, pIgnore); }else if( isDir==0 ){ fossil_warning("not found: %s", zName); }else if( file_access(zName, R_OK) ){ fossil_fatal("cannot open %s", zName); }else{ char *zTreeName = &zName[nRoot]; db_multi_exec( "INSERT OR IGNORE INTO sfile(x) VALUES(%Q)", zTreeName ); } blob_reset(&fullName); } |
︙ | ︙ | |||
459 460 461 462 463 464 465 | ** ** Usage: %fossil addremove ?OPTIONS? ** ** 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, | | | 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 | ** ** Usage: %fossil addremove ?OPTIONS? ** ** 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 "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. ** ** The command does not "commit". You must run the "commit" separately |
︙ | ︙ | |||
690 691 692 693 694 695 696 | const char *zFrom = db_column_text(&q, 0); const char *zTo = db_column_text(&q, 1); mv_one_file(vid, zFrom, zTo); } db_finalize(&q); db_end_transaction(0); } | < < < < < < < < | 668 669 670 671 672 673 674 | const char *zFrom = db_column_text(&q, 0); const char *zTo = db_column_text(&q, 1); mv_one_file(vid, zFrom, zTo); } db_finalize(&q); db_end_transaction(0); } |
Changes to src/allrepo.c.
︙ | ︙ | |||
63 64 65 66 67 68 69 | if( zValue[0] ){ blob_appendf(pExtra, " --%s %s", zArg, zValue); }else{ blob_appendf(pExtra, " --%s \"\"", zArg); } } } | < < < < < < | | 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 | if( zValue[0] ){ blob_appendf(pExtra, " --%s %s", zArg, zValue); }else{ blob_appendf(pExtra, " --%s \"\"", zArg); } } } /* ** COMMAND: all ** ** Usage: %fossil all (changes|clean|extra|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. ** ** On Win32 systems, the file is named "_fossil" and is located in ** %LOCALAPPDATA%, %APPDATA% or %HOMEPATH%. |
︙ | ︙ | |||
97 98 99 100 101 102 103 | ** 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. ** | | | < < < < < < < | | | < | < < < | 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 | ** 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. ** ** extra 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. ** ** ignore Arguments are repositories that should be ignored by ** subsequent clean, extra, 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. ** ** 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. ** ** 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: ** --dontstop Continue with other repositories even after an error. ** --dry-run If given, display instead of run actions. */ void all_cmd(void){ int n; Stmt q; const char *zCmd; char *zSyscmd; char *zFossil; char *zQFilename; Blob extra; int useCheckouts = 0; int quiet = 0; int dryRunFlag = 0; int stopOnError = find_option("dontstop",0,0)==0; int rc; int nToDel = 0; dryRunFlag = find_option("dry-run","n",0)!=0; if( !dryRunFlag ){ dryRunFlag = find_option("test",0,0)!=0; /* deprecated */ } if( g.argc<3 ){ usage("changes|clean|extra|ignore|list|ls|pull|push|rebuild|sync"); } n = strlen(g.argv[2]); db_open_config(1); blob_zero(&extra); zCmd = g.argv[2]; 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, "extra", n)==0 ){ zCmd = "extra --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; |
︙ | ︙ | |||
216 217 218 219 220 221 222 | collect_argument(&extra, "noverify",0); collect_argument_value(&extra, "pagesize"); 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); | < < < < < < | 199 200 201 202 203 204 205 206 207 208 209 210 211 212 | collect_argument(&extra, "noverify",0); collect_argument_value(&extra, "pagesize"); 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); }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); zCmd = "test-integrity"; }else if( strncmp(zCmd, "test-orphans", n)==0 ){ |
︙ | ︙ | |||
258 259 260 261 262 263 264 | } fossil_free(zSql); } db_end_transaction(0); return; }else{ fossil_fatal("\"all\" subcommand should be one of: " | | | 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 | } fossil_free(zSql); } db_end_transaction(0); return; }else{ fossil_fatal("\"all\" subcommand should be one of: " "changes clean extra ignore list ls push pull rebuild sync"); } verify_all_options(); zFossil = quoteFilename(g.nameOfExe); if( useCheckouts ){ db_prepare(&q, "SELECT DISTINCT substr(name, 7), name COLLATE nocase" " FROM global_config" |
︙ | ︙ | |||
291 292 293 294 295 296 297 | db_multi_exec("INSERT INTO todel VALUES(%Q)", db_column_text(&q, 1)); nToDel++; continue; } if( zCmd[0]=='l' ){ fossil_print("%s\n", zFilename); continue; | < < < | 268 269 270 271 272 273 274 275 276 277 278 279 280 281 | db_multi_exec("INSERT INTO todel VALUES(%Q)", db_column_text(&q, 1)); nToDel++; 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( !quiet || dryRunFlag ){ fossil_print("%s\n", zSyscmd); fflush(stdout); |
︙ | ︙ |
Changes to src/attach.c.
︙ | ︙ | |||
256 257 258 259 260 261 262 | 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" " WHERE tagname GLOB 'tkt-%q*'", zTkt); if( zTkt==0 ) fossil_redirect_home(); } zTarget = zTkt; | | | 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 | 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" " WHERE tagname GLOB 'tkt-%q*'", zTkt); if( zTkt==0 ) fossil_redirect_home(); } zTarget = 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); } if( P("ok") && szContent>0 && (goodCaptcha = captcha_is_correct()) ){ |
︙ | ︙ | |||
307 308 309 310 311 312 313 | n = strlen(zComment); while( n>0 && fossil_isspace(zComment[n-1]) ){ n--; } if( n>0 ){ blob_appendf(&manifest, "C %#F\n", n, zComment); } zDate = date_in_standard_format("now"); blob_appendf(&manifest, "D %s\n", zDate); | | | 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 | n = strlen(zComment); while( n>0 && fossil_isspace(zComment[n-1]) ){ n--; } 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", 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); cgi_redirect(zFrom); } |
︙ | ︙ | |||
425 426 427 428 429 430 431 | if( zFile[i]=='/' || zFile[i]=='\\' ) n = i; } 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); | | | 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 | if( zFile[i]=='/' || zFile[i]=='\\' ) n = i; } 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", 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); db_end_transaction(0); @ <p>The attachment below has been deleted.</p> } |
︙ | ︙ | |||
461 462 463 464 465 466 467 | return; } if( strcmp(zModAction,"approve")==0 ){ moderation_approve(rid); } } style_header("Attachment Details"); | | | 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 | return; } if( strcmp(zModAction,"approve")==0 ){ moderation_approve(rid); } } style_header("Attachment Details"); 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> if( g.perm.Setup ){ @ (%d(rid)) |
︙ | ︙ | |||
529 530 531 532 533 534 535 | output_text_with_line_numbers(z, zLn); }else{ @ <pre> @ %h(z) @ </pre> } }else if( strncmp(zMime, "image/", 6)==0 ){ | | | | 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 | output_text_with_line_numbers(z, zLn); }else{ @ <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); }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> manifest_destroy(pAttach); blob_reset(&attach); |
︙ | ︙ |
Changes to src/bag.c.
︙ | ︙ | |||
73 74 75 76 77 78 79 | #define bag_hash(i) (i*101) /* ** Change the size of the hash table on a bag so that ** it contains N slots ** ** Completely reconstruct the hash table from scratch. Deleted | | | 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 | #define bag_hash(i) (i*101) /* ** 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 ** should be the case that p->cnt==p->used. */ static void bag_resize(Bag *p, int newSize){ int i; Bag old; int nDel = 0; /* Number of deleted entries */ int nLive = 0; /* Number of live entries */ |
︙ | ︙ |
Changes to src/bisect.c.
︙ | ︙ | |||
368 369 370 371 372 373 374 | }else{ g.argv[1] = "update"; g.argv[2] = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", pMid->rid); g.argc = 3; g.fNoSync = 1; update_cmd(); } | | | 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 | }else{ g.argv[1] = "update"; 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 ){ bisect_list(1); } |
︙ | ︙ |
Changes to src/blob.c.
︙ | ︙ | |||
222 223 224 225 226 227 228 | ** Initialize a blob to a nul-terminated string. ** Any prior data in the blob is discarded. */ void blob_set(Blob *pBlob, const char *zStr){ blob_init(pBlob, zStr, -1); } | < < < < < < < < < | 222 223 224 225 226 227 228 229 230 231 232 233 234 235 | ** Initialize a blob to a nul-terminated string. ** Any prior data in the blob is discarded. */ void blob_set(Blob *pBlob, const char *zStr){ blob_init(pBlob, zStr, -1); } /* ** Initialize a blob to an empty string. */ void blob_zero(Blob *pBlob){ static const char zEmpty[] = ""; assert_blob_is_reset(pBlob); pBlob->nUsed = 0; |
︙ | ︙ | |||
784 785 786 787 788 789 790 | #if defined(_WIN32) if( fossil_utf8_to_console(blob_buffer(pBlob), nWrote, 0) >= 0 ){ return nWrote; } #endif fwrite(blob_buffer(pBlob), 1, nWrote, stdout); }else{ | > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | < > | 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 | #if defined(_WIN32) if( fossil_utf8_to_console(blob_buffer(pBlob), nWrote, 0) >= 0 ){ return nWrote; } #endif fwrite(blob_buffer(pBlob), 1, nWrote, stdout); }else{ 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", 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, blob_size(pBlob), zFilename); } |
︙ | ︙ | |||
1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 | ** is either no BOM at all or an (le/be) UTF-16 BOM, a conversion to UTF-8 is ** done. If useMbcs is false and there is no BOM, the input string is assumed ** 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; int bomReverse = 0; 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); }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); while( i>0 ){ /* swap bytes of unicode representation */ char zTemp = zUtf8[--i]; zUtf8[i] = zUtf8[i-1]; zUtf8[--i] = zTemp; } } /* Make sure the blob contains two terminating 0-bytes */ blob_append(pBlob, "", 1); zUtf8 = blob_str(pBlob) + bomSize; zUtf8 = fossil_unicode_to_utf8(zUtf8); | > > > > | > > | 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 | ** is either no BOM at all or an (le/be) UTF-16 BOM, a conversion to UTF-8 is ** done. If useMbcs is false and there is no BOM, the input string is assumed ** 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); while( i>0 ){ /* swap bytes of unicode representation */ char zTemp = zUtf8[--i]; zUtf8[i] = zUtf8[i-1]; zUtf8[--i] = zTemp; } } /* 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_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); #endif /* _WIN32 */ } } |
Changes to src/branch.c.
︙ | ︙ | |||
132 133 134 135 136 137 138 | rootid); while( db_step(&q)==SQLITE_ROW ){ const char *zTag = db_column_text(&q, 0); blob_appendf(&branch, "T -%F *\n", zTag); } db_finalize(&q); | | > | 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 | rootid); while( db_step(&q)==SQLITE_ROW ){ 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 : 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); } } |
︙ | ︙ | |||
365 366 367 368 369 370 371 372 373 374 375 376 377 378 | @ <li>%z(href("%R/timeline?r=%T",zBr))%h(zBr)</a></li> } } if( cnt ){ @ </ul> } db_finalize(&q); style_footer(); } /* ** This routine is called while for each check-in that is rendered by ** the timeline of a "brlist" page. Add some additional hyperlinks ** to the end of the line. | > > > > > > | 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 | @ <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 ** the timeline of a "brlist" page. Add some additional hyperlinks ** to the end of the line. |
︙ | ︙ | |||
414 415 416 417 418 419 420 421 422 | "%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, brtimeline_extra); db_finalize(&q); style_footer(); } | > > > > > > | 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 | "%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, brtimeline_extra); db_finalize(&q); @ <script type="text/JavaScript"> @ function xin(id){ @ } @ function xout(id){ @ } @ </script> style_footer(); } |
Changes to src/browse.c.
︙ | ︙ | |||
83 84 85 86 87 88 89 | 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 ){ | | | 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 | 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?ci=%S&name=%#T%s", zURI, zCI, j, zPath,zREx); 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); blob_appendf(pOut, "%s%z%#h</a>", zSep, zLink, j-i, &zPath[i]); } |
︙ | ︙ | |||
177 178 179 180 181 182 183 | url_render(&sURI, "ci", "trunk", 0, 0)); } if( linkTip ){ style_submenu_element("Tip", "Tip", "%s", url_render(&sURI, "ci", "tip", 0, 0)); } if( zCI ){ | > > > | | | | 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 | url_render(&sURI, "ci", "trunk", 0, 0)); } if( linkTip ){ style_submenu_element("Tip", "Tip", "%s", url_render(&sURI, "ci", "tip", 0, 0)); } if( zCI ){ 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", zUuid); } }else{ @ <h2>The union of all files from all check-ins @ %s(blob_str(&dirname))</h2> zSubdirLink = mprintf("%R/dir?name=%T", zPrefix); } |
︙ | ︙ | |||
413 414 415 416 417 418 419 | 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 */ | < | 416 417 418 419 420 421 422 423 424 425 426 427 428 429 | 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 */ char *zProjectName = db_get("project-name", 0); if( strcmp(PD("type",""),"flat")==0 ){ page_dir(); return; } memset(&sTree, 0, sizeof(sTree)); login_check_credentials(); if( !g.perm.Read ){ login_needed(); return; } while( nD>1 && zD[nD-2]=='/' ){ zD[(--nD)-1] = 0; } |
︙ | ︙ | |||
485 486 487 488 489 490 491 | blob_appendf(&dirname, "matching \"%s\"", zRE); } } if( zCI ){ style_submenu_element("All", "All", "%s", url_render(&sURI, "ci", 0, 0, 0)); if( nD==0 && !showDirOnly ){ | | | 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 | blob_appendf(&dirname, "matching \"%s\"", zRE); } } 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)); } |
︙ | ︙ | |||
512 513 514 515 516 517 518 | Stmt ins, q; ManifestFile *pFile; db_multi_exec( "CREATE TEMP TABLE filelist(" " x TEXT PRIMARY KEY COLLATE nocase," " uuid TEXT" | > > | | 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 | Stmt ins, q; ManifestFile *pFile; db_multi_exec( "CREATE TEMP TABLE filelist(" " x TEXT PRIMARY KEY COLLATE nocase," " uuid TEXT" ")%s;", /* Can be removed as soon as SQLite 3.8.2 is sufficiently wide-spread */ sqlite3_libversion_number()>=3008002 ? " WITHOUT ROWID" : "" ); db_prepare(&ins, "INSERT OR IGNORE INTO filelist VALUES(:f,:u)"); manifest_file_rewind(pM); while( (pFile = manifest_file_next(pM,0))!=0 ){ if( nD>0 && (fossil_strncmp(pFile->zName, zD, nD-1)!=0 || pFile->zName[nD-1]!='/') |
︙ | ︙ | |||
569 570 571 572 573 574 575 | } if( zCI ){ @ <h2>%d(nFile) %s(zObjType) of check-in if( sqlite3_strnicmp(zCI, zUuid, (int)strlen(zCI))!=0 ){ @ "%h(zCI)" } | | | | | < | > > | > | | < < | | | | < < < < < < < < | < | | | | < | < < < < < < < < < < < | | | < < < < < < < < < < < < | < | | | | 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 | } if( zCI ){ @ <h2>%d(nFile) %s(zObjType) of check-in if( sqlite3_strnicmp(zCI, zUuid, (int)strlen(zCI))!=0 ){ @ "%h(zCI)" } @ [%z(href("vinfo?name=%T",zUuid))%S(zUuid)</a>] %s(blob_str(&dirname))</h2> }else{ int n = db_int(0, "SELECT count(*) FROM plink"); @ <h2>%d(nFile) %s(zObjType) from all %d(n) check-ins @ %s(blob_str(&dirname))</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"> }else{ @ <li class="dir subdir"> } @ %z(href("%s",url_render(&sURI,"name",0,0,0)))%h(zProjectName)</a> @ <ul> for(p=sTree.pFirst; p; p=p->pNext){ if( p->isDir ){ if( p->nFullName==nD-1 ){ @ <li class="dir subdir"> }else{ @ <li class="dir"> } @ %z(href("%s",url_render(&sURI,"name",p->zFullName,0,0)))%h(p->zName)</a> if( startExpanded || p->nFullName<=nD ){ @ <ul> }else{ @ <ul style='display:none;'> } }else if( !showDirOnly ){ char *zLink; if( zCI ){ zLink = href("%R/artifact/%S",p->zUuid); }else{ zLink = href("%R/finfo?name=%T",p->zFullName); } @ <li class="%z(fileext_class(p->zName))">%z(zLink)%h(p->zName)</a> } if( p->isLast ){ int nClose = p->iLevel - (p->pNext ? p->pNext->iLevel : 0); while( nClose-- > 0 ){ @ </ul> } } } @ </ul> @ </ul></div> @ <script>(function(){ @ function style(elem, prop){ @ return window.getComputedStyle(elem).getPropertyValue(prop); @ } @ @ function toggleAll(tree){ @ var lists = tree.querySelectorAll('.subdir > ul > li ul'); @ var display = 'block'; /* Default action: make all sublists visible */ @ for( var i=0; lists[i]; i++ ){ @ if( style(lists[i], 'display')!='none'){ @ display = 'none'; /* Any already visible - make them all hidden */ @ break; @ } @ } @ for( var i=0; lists[i]; i++ ){ @ lists[i].style.display = display; @ } @ } @ @ var outer_ul = document.querySelector('.filetree > ul'); @ var subdir = outer_ul.querySelector('.subdir'); @ outer_ul.onclick = function( e ){ @ var a = e.target; @ if( a.nodeName!='A' ) return true; @ if( a.parentNode==subdir ){ @ toggleAll(outer_ul); @ return false; @ } @ if( !subdir.contains(a) ) return true; @ var ul = a.nextSibling; @ while( ul && ul.nodeName!='UL' ) ul = ul.nextSibling; @ if( !ul ) return true; /* This is a file link, not a directory */ @ ul.style.display = style(ul, 'display')=='none' ? 'block' : 'none'; @ 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 |
︙ | ︙ | |||
727 728 729 730 731 732 733 | return zClass; } /* ** 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 | | < | < < | 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 | return zClass; } /* ** 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 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); |
︙ | ︙ | |||
805 806 807 808 809 810 811 | return 0; } /* ** WEBPAGE: fileage ** ** Parameters: | | < < < > < | | 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 | return 0; } /* ** WEBPAGE: fileage ** ** Parameters: ** name=VERSION */ void fileage_page(void){ int rid; const char *zName; char *zBaseTime; Stmt q; double baseTime; int lastMid = -1; login_check_credentials(); 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); } style_submenu_element("Tree-View", "Tree-View", "%R/tree?ci=%T", zName); 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%s)", baseTime, timeline_utc()); @ <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 |
︙ | ︙ | |||
870 871 872 873 874 875 876 | } }else{ zAge[0] = 0; } @ <tr> @ <td>%s(zAge) @ <td width="25"> | | | 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 | } }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(); } |
Changes to src/captcha.c.
︙ | ︙ | |||
90 91 92 93 94 95 96 | } z[k++] = ' '; z[k++] = ' '; } z[k++] = '\n'; } z[k] = 0; | | | 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 | } z[k++] = ' '; z[k++] = ' '; } z[k++] = '\n'; } z[k] = 0; return z; } #endif /* CAPTCHA==1 */ #if CAPTCHA==2 static const char *const azFont2[] = { /* 0 */ |
︙ | ︙ | |||
146 147 148 149 150 151 152 | /* 7 */ " ____ ", "|__ |", " / / ", " /_/ ", /* 8 */ | | | 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 | /* 7 */ " ____ ", "|__ |", " / / ", " /_/ ", /* 8 */ " ___ ", "( _ )", "/ _ \\", "\\___/", /* 9 */ " ___ ", "/ _ \\", |
︙ | ︙ | |||
216 217 218 219 220 221 222 | for(m=0; zChar[m]; m++){ z[k++] = zChar[m]; } } z[k++] = '\n'; } z[k] = 0; | | | | | | | | | | | | | | | | | | 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 | for(m=0; zChar[m]; m++){ z[k++] = zChar[m]; } } z[k++] = '\n'; } z[k] = 0; return z; } #endif /* CAPTCHA==2 */ #if CAPTCHA==3 static const char *const azFont3[] = { /* 0 */ " ___ ", " / _ \\ ", "| | | |", "| | | |", "| |_| |", " \\___/ ", /* 1 */ " __ ", "/_ |", " | |", " | |", " | |", " |_|", /* 2 */ " ___ ", "|__ \\ ", " ) |", " / / ", " / /_ ", "|____|", /* 3 */ " ____ ", "|___ \\ ", " __) |", " |__ < ", " ___) |", "|____/ ", /* 4 */ " _ _ ", "| || | ", "| || |_ ", "|__ _|", " | | ", " |_| ", /* 5 */ " _____ ", "| ____|", "| |__ ", "|___ \\ ", " ___) |", "|____/ ", /* 6 */ " __ ", " / / ", " / /_ ", "| '_ \\ ", "| (_) |", " \\___/ ", /* 7 */ " ______ ", "|____ |", " / / ", " / / ", " / / ", " /_/ ", /* 8 */ " ___ ", " / _ \\ ", "| (_) |", " > _ < ", "| (_) |", " \\___/ ", /* 9 */ " ___ ", " / _ \\ ", "| (_) |", " \\__, |", " / / ", " /_/ ", /* A */ " ", " /\\ ", " / \\ ", " / /\\ \\ ", " / ____ \\ ", "/_/ \\_\\", /* B */ " ____ ", "| _ \\ ", "| |_) |", "| _ < ", "| |_) |", "|____/ ", /* C */ " _____ ", " / ____|", "| | ", "| | ", "| |____ ", " \\_____|", /* D */ " _____ ", "| __ \\ ", "| | | |", "| | | |", "| |__| |", "|_____/ ", /* E */ " ______ ", "| ____|", "| |__ ", "| __| ", "| |____ ", "|______|", /* F */ " ______ ", "| ____|", "| |__ ", "| __| ", "| | ", "|_| ", |
︙ | ︙ | |||
406 407 408 409 410 411 412 | for(m=0; zChar[m]; m++){ z[k++] = zChar[m]; } } z[k++] = '\n'; } z[k] = 0; | | | 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 | for(m=0; zChar[m]; m++){ z[k++] = zChar[m]; } } z[k++] = '\n'; } z[k] = 0; return z; } #endif /* CAPTCHA==3 */ /* ** COMMAND: test-captcha */ void test_captcha(void){ |
︙ | ︙ | |||
476 477 478 479 480 481 482 | /* ** 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 | | > | | 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 | /* ** 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 ** defaults to true. */ int captcha_needed(void){ 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). ** ** If no captcha is required or if the correct captcha is supplied, return |
︙ | ︙ |
Changes to src/cgi.c.
︙ | ︙ | |||
264 265 266 267 268 269 270 | for( zTok = strtok_r(zBuf, ",\"",&zPos); zTok && fossil_stricmp(zTok,zETag); zTok = strtok_r(0, ",\"",&zPos)){} fossil_free(zBuf); if(zTok) return 1; } } | | | 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 | for( zTok = strtok_r(zBuf, ",\"",&zPos); zTok && fossil_stricmp(zTok,zETag); 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. */ |
︙ | ︙ | |||
495 496 497 498 499 500 501 | /* ** 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); } | | | 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 | /* ** 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 ** VALUE may be url-encoded ("+" for space, "%HH" for other special ** characters). But this routine assumes that NAME contains no |
︙ | ︙ | |||
613 614 615 616 617 618 619 | *pnContent = i; i += nBoundry; break; } } *pz = &z[i]; get_line_from_string(pz, pLen); | | | 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 | *pnContent = i; i += nBoundry; break; } } *pz = &z[i]; get_line_from_string(pz, pLen); return z; } /* ** Tokenize a line of text into as many as nArg tokens. Make ** azArg[] point to the start of each token. ** ** Tokens consist of space or semi-colon delimited words or |
︙ | ︙ | |||
720 721 722 723 724 725 726 | char *z = azArg[++i]; if( zName && z && fossil_islower(zName[0]) ){ cgi_set_parameter_nocopy(mprintf("%s:mimetype",zName), z, 1); } } } } | | | 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 | char *z = azArg[++i]; if( zName && z && fossil_islower(zName[0]) ){ cgi_set_parameter_nocopy(mprintf("%s:mimetype",zName), z, 1); } } } } } } #ifdef FOSSIL_ENABLE_JSON /* ** Internal helper for cson_data_source_FILE_n(). */ |
︙ | ︙ | |||
901 902 903 904 905 906 907 | } z = (char*)P("HTTP_COOKIE"); if( z ){ z = mprintf("%s",z); add_param_list(z, ';'); } | | | | 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 | } 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, '&'); } z = (char*)P("REMOTE_ADDR"); if( z ){ g.zIpAddr = mprintf("%s", z); } 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 || 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); if( zType[0]=='a' ){ add_param_list(z, '&'); |
︙ | ︙ | |||
947 948 949 950 951 952 953 | g.json.isJsonMode = 1; cgi_parse_POST_JSON(g.httpIn, (unsigned int)len); /* 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. | | | 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 | g.json.isJsonMode = 1; cgi_parse_POST_JSON(g.httpIn, (unsigned int)len); /* 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 GET/POST arguments. i prefer for GET entries to take precedence over like-named POST entries, but in order for that to happen we |
︙ | ︙ | |||
1223 1224 1225 1226 1227 1228 1229 | ** Return a pointer to a string containing the real IP address, or a ** NULL pointer to stick with the IP address previously computed and ** 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; | | | 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 | ** Return a pointer to a string containing the real IP address, or a ** NULL pointer to stick with the IP address previously computed and ** 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]; } /* ** Remove the first space-delimited token from a string and return |
︙ | ︙ | |||
1295 1296 1297 1298 1299 1300 1301 | cgi_setenv("REQUEST_URI", zToken); cgi_setenv("SCRIPT_NAME", ""); 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 && | | | | | 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 | cgi_setenv("REQUEST_URI", zToken); cgi_setenv("SCRIPT_NAME", ""); 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, &size)>=0 ){ zIpAddr = inet_ntoa(remoteName.sin_addr); } 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; cgi_trace(zLine); |
︙ | ︙ | |||
1372 1373 1374 1375 1376 1377 1378 | 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 ){ | | | 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 | 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 ){ |
︙ | ︙ | |||
1438 1439 1440 1441 1442 1443 1444 | 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)); } | | | 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 | 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); |
︙ | ︙ | |||
1619 1620 1621 1622 1623 1624 1625 | fossil_free(zToFree); fgetc(g.httpIn); /* Read past the "," separating header from content */ cgi_init(); } #if INTERFACE | | | 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 | fossil_free(zToFree); fgetc(g.httpIn); /* Read past the "," separating header from content */ 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 */ #endif /* INTERFACE */ |
︙ | ︙ | |||
1704 1705 1706 1707 1708 1709 1710 | }else{ fossil_fatal("unable to open listening socket on any" " port in the range %d..%d", mnPort, mxPort); } } if( iPort>mxPort ) return 1; listen(listener,10); | > | | | > | 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 | }else{ fossil_fatal("unable to open listening socket on any" " port in the range %d..%d", mnPort, mxPort); } } if( iPort>mxPort ) return 1; listen(listener,10); 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 ){ zBrowser = mprintf(zBrowser, iPort); #if defined(__CYGWIN__) /* On Cygwin, we can do better than "echo" */ if( memcmp(zBrowser, "echo ", 5)==0 ){ wchar_t *wUrl = fossil_utf8_to_unicode(zBrowser+5); wUrl[wcslen(wUrl)-2] = 0; /* Strip terminating " &" */ |
︙ | ︙ | |||
1765 1766 1767 1768 1769 1770 1771 | } } /* Bury dead children */ while( waitpid(0, 0, WNOHANG)>0 ){ nchildren--; } } | | | 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 | } } /* Bury dead children */ while( waitpid(0, 0, WNOHANG)>0 ){ nchildren--; } } /* NOT REACHED */ fossil_exit(1); #endif /* NOT REACHED */ return 0; } |
︙ | ︙ | |||
1853 1854 1855 1856 1857 1858 1859 | }else if( p->tm_mon>11 ){ p->tm_year += p->tm_mon/12; 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++; | | | 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 | }else if( p->tm_mon>11 ){ p->tm_year += p->tm_mon/12; 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 + (p->tm_year+300)/400 + p->tm_yday; t = ((nDay*24 + p->tm_hour)*60 + p->tm_min)*60 + p->tm_sec; return t; } /* ** Check the objectTime against the If-Modified-Since request header. If the |
︙ | ︙ |
Changes to src/checkin.c.
︙ | ︙ | |||
177 178 179 180 181 182 183 | ** --rel-paths Display pathnames relative to the current working ** directory. ** --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 ** | | | 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 | ** --rel-paths Display pathnames relative to the current working ** directory. ** --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: 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; |
︙ | ︙ | |||
221 222 223 224 225 226 227 | ** ** --abs-paths Display absolute pathnames. ** --rel-paths Display pathnames relative to the current working ** directory. ** --sha1sum Verify file status using SHA1 hashing rather ** than relying on file mtimes. ** | | | 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 | ** ** --abs-paths Display absolute pathnames. ** --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, extra, ls */ void status_cmd(void){ int vid; db_must_be_within_tree(); /* 012345678901234 */ fossil_print("repository: %s\n", db_repository_filename()); fossil_print("local-root: %s\n", g.zLocalRoot); |
︙ | ︙ | |||
253 254 255 256 257 258 259 | ** extra information about each file. If FILENAMES are included, only ** the files listed (or their children if they are directories) are shown. ** ** Options: ** --age Show when each file was committed ** -v|--verbose Provide extra information about each file. ** | | | 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 | ** extra information about each file. If FILENAMES are included, only ** the files listed (or their children if they are directories) are shown. ** ** Options: ** --age Show when each file was committed ** -v|--verbose Provide extra information about each file. ** ** See also: changes, extra, status */ void ls_cmd(void){ int vid; Stmt q; int verboseFlag; int showAge; char *zOrderBy = "pathname"; |
︙ | ︙ | |||
431 432 433 434 435 436 437 | ** Pathnames are displayed according to the "relative-paths" setting, ** unless overridden by the --abs-paths or --rel-paths options. ** ** Options: ** --abs-paths Display absolute pathnames. ** --case-sensitive <BOOL> override case-sensitive setting ** --dotfiles include files beginning with a dot (".") | < | < | 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 | ** Pathnames are displayed according to the "relative-paths" setting, ** unless overridden by the --abs-paths or --rel-paths options. ** ** Options: ** --abs-paths Display absolute pathnames. ** --case-sensitive <BOOL> override case-sensitive setting ** --dotfiles include files beginning with a dot (".") ** --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 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 cwdRelative = 0; Glob *pIgnore; Blob rewrittenPathname; const char *zPathname, *zDisplayName; if( find_option("temp",0,0)!=0 ) scanFlags |= SCAN_TEMP; capture_case_sensitive_option(); |
︙ | ︙ | |||
477 478 479 480 481 482 483 | file_relative_name(zFullName, &rewrittenPathname, 0); free(zFullName); zDisplayName = blob_str(&rewrittenPathname); if( zDisplayName[0]=='.' && zDisplayName[1]=='/' ){ zDisplayName += 2; /* no unnecessary ./ prefix */ } } | < < < < < | 475 476 477 478 479 480 481 482 483 484 485 486 487 488 | file_relative_name(zFullName, &rewrittenPathname, 0); free(zFullName); zDisplayName = blob_str(&rewrittenPathname); if( zDisplayName[0]=='.' && zDisplayName[1]=='/' ){ zDisplayName += 2; /* no unnecessary ./ prefix */ } } fossil_print("%s\n", zDisplayName); } blob_reset(&rewrittenPathname); db_finalize(&q); } /* |
︙ | ︙ | |||
541 542 543 544 545 546 547 | ** comma separated list of glob patterns. ** --keep <CSG> Keep files matching this comma separated ** 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. ** | | | 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 | ** comma separated list of glob patterns. ** --keep <CSG> Keep files matching this comma separated ** 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, extra, status */ void clean_cmd(void){ int allFileFlag, allDirFlag, dryRunFlag, verboseFlag; int emptyDirsFlag, dirsOnlyFlag; unsigned scanFlags = 0; const char *zIgnoreFlag, *zKeepFlag, *zCleanFlag; Glob *pIgnore, *pKeep, *pClean; |
︙ | ︙ | |||
605 606 607 608 609 610 611 612 613 614 615 616 617 618 | while( db_step(&q)==SQLITE_ROW ){ const char *zName = db_column_text(&q, 0); 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); prompt_user(prompt, &ans); cReply = blob_str(&ans)[0]; if( cReply=='a' || cReply=='A' ){ allFileFlag = 1; }else if( cReply!='y' && cReply!='Y' ){ blob_reset(&ans); continue; | > | 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 | while( db_step(&q)==SQLITE_ROW ){ const char *zName = db_column_text(&q, 0); 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' ){ blob_reset(&ans); continue; |
︙ | ︙ | |||
646 647 648 649 650 651 652 653 654 655 656 657 658 659 | while( db_step(&q)==SQLITE_ROW ){ const char *zName = db_column_text(&q, 0); 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); prompt_user(prompt, &ans); cReply = blob_str(&ans)[0]; if( cReply=='a' || cReply=='A' ){ allDirFlag = 1; }else if( cReply!='y' && cReply!='Y' ){ blob_reset(&ans); continue; | > | 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 | while( db_step(&q)==SQLITE_ROW ){ const char *zName = db_column_text(&q, 0); 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' ){ blob_reset(&ans); continue; |
︙ | ︙ | |||
806 807 808 809 810 811 812 | blob_init(&prompt, zInit, -1); #endif blob_append(&prompt, "\n" "# Enter commit message for this check-in. Lines beginning with # are ignored.\n" "#\n", -1 ); | | | 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 | blob_init(&prompt, zInit, -1); #endif blob_append(&prompt, "\n" "# Enter commit message for this check-in. Lines beginning with # are ignored.\n" "#\n", -1 ); 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 ) blob_appendf(&prompt, "# tags: %z\n#\n", zTags); } status_report(&prompt, "# ", 1, 0); |
︙ | ︙ | |||
968 969 970 971 972 973 974 | 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' */ | | | 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 | 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 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 */ }; #endif /* INTERFACE */ |
︙ | ︙ | |||
1194 1195 1196 1197 1198 1199 1200 | vid, p->zBranch); while( db_step(&q)==SQLITE_ROW ){ const char *zBrTag = db_column_text(&q, 0); blob_appendf(pOut, "T -%F *\n", zBrTag); } db_finalize(&q); } | | | 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 | vid, p->zBranch); while( db_step(&q)==SQLITE_ROW ){ 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 : g.zLogin); md5sum_blob(pOut, &mcksum); blob_appendf(pOut, "Z %b\n", &mcksum); if( pnFBcard ) *pnFBcard = nFBcard; } /* ** Issue a warning and give the user an opportunity to abandon out |
︙ | ︙ | |||
1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 | } zDisable = "\"crnl-glob\" setting"; }else{ if( encodingOk ){ return 0; /* We don't want encoding warnings for this file. */ } zWarning = "Unicode"; zDisable = "\"encoding-glob\" setting"; } file_relative_name(zFilename, &fname, 0); 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); fossil_free(zMsg); cReply = blob_str(&ans)[0]; if( cReply=='a' || cReply=='A' ){ allOk = 1; }else if( *zConvert && (cReply=='c' || cReply=='C') ){ char *zOrig = file_newname(zFilename, "original", 1); FILE *f; blob_write_to_file(p, zOrig); fossil_free(zOrig); f = fossil_fopen(zFilename, "wb"); | > > > > < < < | | | | | | | | | | | < | 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 | } zDisable = "\"crnl-glob\" setting"; }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); fossil_free(zMsg); cReply = blob_str(&ans)[0]; if( cReply=='a' || cReply=='A' ){ allOk = 1; }else if( *zConvert && (cReply=='c' || cReply=='C') ){ char *zOrig = file_newname(zFilename, "original", 1); FILE *f; blob_write_to_file(p, zOrig); fossil_free(zOrig); f = fossil_fopen(zFilename, "wb"); 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)); } blob_reset(&ans); blob_reset(&fname); |
︙ | ︙ | |||
1417 1418 1419 1420 1421 1422 1423 | ** --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 checkin ** | | | 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 | ** --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 checkin ** ** 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 */ int nvid; /* Blob-id of the new check-in */ Blob comment; /* Check-in comment */ |
︙ | ︙ | |||
1526 1527 1528 1529 1530 1531 1532 | */ if( !forceDelta && !db_get_boolean("seen-delta-manifest",0) ){ forceBaseline = 1; } /* Get the ID of the parent manifest artifact */ vid = db_lget_int("checkout", 0); | < < | > > > | | 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 | */ if( !forceDelta && !db_get_boolean("seen-delta-manifest",0) ){ forceBaseline = 1; } /* Get the ID of the parent manifest artifact */ vid = db_lget_int("checkout", 0); 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(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); } } } /* 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); } } /* There are two ways this command may be executed. If there are ** no arguments following the word "commit", then all modified files ** in the checked out directory are committed. If one or more arguments ** follows "commit", then only those files are committed. ** ** After the following function call has returned, the Global.aCommitFile[] ** array is allocated to contain the "id" field from the vfile table ** for each file to be committed. Or, if aCommitFile is NULL, all files ** should be committed. */ 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);; } 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"); } /* Doing "fossil mv fileA fileB; fossil add fileA; fossil commit fileA" |
︙ | ︙ | |||
1667 1668 1669 1670 1671 1672 1673 1674 1675 | blob_to_utf8_no_bom(&comment, 1); }else if(dryRunFlag){ 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 ){ prompt_user("unchanged check-in comment. continue (y/N)? ", &ans); cReply = blob_str(&ans)[0]; | > | > | 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 | blob_to_utf8_no_bom(&comment, 1); }else if(dryRunFlag){ 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);; } 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); } } }else{ |
︙ | ︙ | |||
1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 | blob_reset(&delta); } }else if( forceDelta ){ fossil_fatal("unable to find a baseline-manifest for the delta"); } } if( !noSign && !g.markPrivate && clearsign(&manifest, &manifest) ){ prompt_user("unable to sign manifest. continue (y/N)? ", &ans); cReply = blob_str(&ans)[0]; if( cReply!='y' && cReply!='Y' ){ fossil_exit(1); } } | > | 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 | blob_reset(&delta); } }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); } } |
︙ | ︙ |
Changes to src/checkout.c.
︙ | ︙ | |||
155 156 157 158 159 160 161 | } if( !db_exists("SELECT 1 FROM vfile WHERE pathname='manifest.uuid'") ){ zManFile = mprintf("%smanifest.uuid", g.zLocalRoot); file_delete(zManFile); free(zManFile); } } | | | | | 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 | } if( !db_exists("SELECT 1 FROM vfile WHERE pathname='manifest.uuid'") ){ zManFile = mprintf("%smanifest.uuid", g.zLocalRoot); file_delete(zManFile); free(zManFile); } } } /* ** COMMAND: checkout* ** COMMAND: co* ** ** Usage: %fossil checkout ?VERSION | --latest? ?OPTIONS? ** or: %fossil co ?VERSION | --latest? ?OPTIONS? ** ** Check out a version specified on the command-line. This command ** will abort if there are edited files in the current checkout unless ** the --force option appears on the command-line. The --keep option ** leaves files on disk unchanged, except the manifest and manifest.uuid ** files. ** ** The --latest flag can be used in place of VERSION to 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 ** ** See also: update */ void checkout_cmd(void){ int forceFlag; /* Force checkout even if edits exist */ 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; keepFlag = find_option("keep",0,0)!=0; latestFlag = find_option("latest",0,0)!=0; promptFlag = find_option("prompt",0,0)!=0 || forceFlag==0; if( (latestFlag!=0 && g.argc!=2) || (latestFlag==0 && g.argc!=3) ){ |
︙ | ︙ |
Changes to src/clone.c.
︙ | ︙ | |||
107 108 109 110 111 112 113 | ** ** Options: ** --admin-user|-A USERNAME Make USERNAME the administrator ** --once Don't save url. ** --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 | < < < | | | | 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 | ** ** Options: ** --admin-user|-A USERNAME Make USERNAME the administrator ** --once Don't save url. ** --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 ** ** See also: init */ void clone_cmd(void){ char *zPassword; const char *zDefaultUser; /* Optional name of the default user */ int nErr = 0; int bPrivate = 0; /* Also clone private branches */ int urlFlags = URL_PROMPT_PW | URL_REMEMBER; if( find_option("private",0,0)!=0 ) bPrivate = SYNC_PRIVATE; if( find_option("once",0,0)!=0) urlFlags &= ~URL_REMEMBER; zDefaultUser = find_option("admin-user","A",1); clone_ssh_find_options(); url_proxy_options(); if( g.argc < 4 ){ usage("?OPTIONS? FILE-OR-URL NEW-REPOSITORY"); } db_open_config(0); 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.urlUser!=0 ) zDefaultUser = g.urlUser; 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( !bPrivate ) delete_private_content(); shun_artifacts(); db_create_default_users(1, zDefaultUser); |
︙ | ︙ | |||
160 161 162 163 164 165 166 | db_begin_transaction(); db_record_repository_filename(g.argv[3]); db_initial_setup(0, 0, zDefaultUser, 0); user_select(); db_set("content-schema", CONTENT_SCHEMA, 0); db_set("aux-schema", AUX_SCHEMA, 0); db_set("rebuilt", get_version(), 0); | < | 157 158 159 160 161 162 163 164 165 166 167 168 169 170 | db_begin_transaction(); db_record_repository_filename(g.argv[3]); db_initial_setup(0, 0, zDefaultUser, 0); user_select(); db_set("content-schema", CONTENT_SCHEMA, 0); db_set("aux-schema", AUX_SCHEMA, 0); db_set("rebuilt", get_version(), 0); url_remember(); if( g.zSSLIdentity!=0 ){ /* If the --ssl-identity option was specified, store it as a setting */ Blob fn; blob_zero(&fn); file_canonical_name(g.zSSLIdentity, &fn, 0); db_set("ssl-identity", blob_str(&fn), 0); |
︙ | ︙ | |||
198 199 200 201 202 203 204 | rebuild_db(0, 1, 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); db_end_transaction(0); } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 194 195 196 197 198 199 200 201 202 203 204 205 206 207 | rebuild_db(0, 1, 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); db_end_transaction(0); } /* ** 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); |
︙ | ︙ |
Changes to src/comformat.c.
︙ | ︙ | |||
32 33 34 35 36 37 38 | */ int comment_print(const char *zText, int indent, int lineLength){ int tlen = lineLength - indent; int si, sk, i, k; int doIndent = 0; char *zBuf; char zBuffer[400]; | | < | 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | */ int comment_print(const char *zText, int indent, int lineLength){ int tlen = lineLength - indent; int si, sk, i, k; int doIndent = 0; char *zBuf; char zBuffer[400]; int lineCnt = 0; if( tlen<=0 ){ tlen = strlen(zText); } if( tlen >= (sizeof(zBuffer)) ){ zBuf = fossil_malloc(tlen+1); }else{ zBuf = zBuffer; |
︙ | ︙ |
Changes to src/config.h.
︙ | ︙ | |||
60 61 62 63 64 65 66 | # endif #else # include <sys/types.h> # include <signal.h> # include <pwd.h> #endif | < < < < < < < < < < < | < < < < | < < < < | < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < | < | 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | # endif #else # include <sys/types.h> # include <signal.h> # include <pwd.h> #endif /* ** Define the compiler variant, used to compile the project */ #if !defined(COMPILER_NAME) # if defined(__DMC__) # define COMPILER_NAME "dmc" # elif defined(__POCC__) # if defined(_M_X64) # define COMPILER_NAME "pellesc64" # else # define COMPILER_NAME "pellesc32" # endif # elif defined(_MSC_VER) # define COMPILER_NAME "msc" # elif defined(__MINGW32__) # define COMPILER_NAME "mingw32" # elif defined(_WIN32) # define COMPILER_NAME "win32" # elif defined(__GNUC__) # define COMPILER_NAME "gcc-" __VERSION__ # else # define COMPILER_NAME "unknown" # endif #endif #if !defined(_RC_COMPILE_) && !defined(SQLITE_AMALGAMATION) |
︙ | ︙ | |||
184 185 186 187 188 189 190 | /* ** 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. ** | | | 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 | /* ** 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. ** 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 */ # define FOSSIL_INT_TO_PTR(X) ((void*)(__PTRDIFF_TYPE__)(X)) # define FOSSIL_PTR_TO_INT(X) ((int)(__PTRDIFF_TYPE__)(X)) |
︙ | ︙ |
Changes to src/configure.c.
︙ | ︙ | |||
922 923 924 925 926 927 928 | usage(mprintf("%s AREA ?URL?", zMethod)); } mask = configure_name_to_mask(g.argv[3], 1); if( g.argc==5 ){ zServer = g.argv[4]; } url_parse(zServer, URL_PROMPT_PW); | | | 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 | usage(mprintf("%s AREA ?URL?", zMethod)); } 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.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 ){ client_sync(0,0,(unsigned)mask); }else if( strncmp(zMethod, "pull", n)==0 ){ |
︙ | ︙ |
Changes to src/content.c.
︙ | ︙ | |||
112 113 114 115 116 117 118 | bag_clear(&contentCache.available); bag_clear(&contentCache.inCache); contentCache.n = 0; contentCache.szTotal = 0; } /* | | | 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 | bag_clear(&contentCache.available); bag_clear(&contentCache.inCache); contentCache.n = 0; contentCache.szTotal = 0; } /* ** 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; db_static_prepare(&q, "SELECT srcid FROM delta WHERE rid=:rid"); db_bind_int(&q, ":rid", rid); |
︙ | ︙ | |||
152 153 154 155 156 157 158 | ** Check to see if content is available for artifact "rid". Return ** true if it is. Return false if rid is a phantom or depends on ** a phantom. */ int content_is_available(int rid){ int srcid; int depth = 0; /* Limit to recursion depth */ | | | 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 | ** Check to see if content is available for artifact "rid". Return ** true if it is. Return false if rid is a phantom or depends on ** a phantom. */ int content_is_available(int rid){ int srcid; int depth = 0; /* Limit to recursion depth */ while( depth++ < 10000000 ){ if( bag_find(&contentCache.missing, rid) ){ return 0; } if( bag_find(&contentCache.available, rid) ){ return 1; } if( content_size(rid, -1)<0 ){ |
︙ | ︙ | |||
414 415 416 417 418 419 420 | db_multi_exec("DELETE FROM orphan WHERE baseline=%d", rid); } /* Recursively dephantomize all artifacts that are derived by ** delta from artifact rid and which have not already been ** cross-linked. */ nChildUsed = 0; | | | 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 | db_multi_exec("DELETE FROM orphan WHERE baseline=%d", rid); } /* 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, "SELECT rid FROM delta" " WHERE srcid=%d" " AND NOT EXISTS(SELECT 1 FROM mlink WHERE mid=delta.rid)", rid ); while( db_step(&q)==SQLITE_ROW ){ int child = db_column_int(&q, 0); |
︙ | ︙ | |||
453 454 455 456 457 458 459 | } /* ** 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 | | | 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 | } /* ** 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. ** ** 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. ** ** zUuid is the UUID of the artifact, if it is specified. When srcId is ** specified then zUuid must always be specified. If srcId is zero, |
︙ | ︙ | |||
484 485 486 487 488 489 490 | int size; int rid; Stmt s1; Blob cmpr; Blob hash; int markAsUnclustered = 0; int isDephantomize = 0; | | | 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 | int size; int rid; 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 ); sha1sum_blob(pBlob, &hash); }else{ |
︙ | ︙ | |||
578 579 580 581 582 583 584 | /* 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); } | | | | 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 | /* 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) && (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); } |
︙ | ︙ | |||
626 627 628 629 630 631 632 | /* ** 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; | | | 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 | /* ** 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; } db_static_prepare(&s1, |
︙ | ︙ | |||
725 726 727 728 729 730 731 | int rc; db_static_prepare(&s1, "SELECT 1 FROM private WHERE rid=:rid" ); db_bind_int(&s1, ":rid", rid); rc = db_step(&s1); db_reset(&s1); | | | | 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 | int rc; db_static_prepare(&s1, "SELECT 1 FROM private WHERE rid=:rid" ); db_bind_int(&s1, ":rid", rid); rc = db_step(&s1); db_reset(&s1); return rc==SQLITE_ROW; } /* ** 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" ); db_bind_int(&s1, ":rid", rid); |
︙ | ︙ | |||
756 757 758 759 760 761 762 | ** the source of the delta. It is OK to delta private->private and ** public->private and public->public. Just no private->public delta. ** ** 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 | | | 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 | ** the source of the delta. It is OK to delta private->private and ** public->private and public->public. Just no private->public delta. ** ** 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% ** 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){ int s; Blob data, src, delta; |
︙ | ︙ | |||
881 882 883 884 885 886 887 | fossil_print( "public artifact %S (%d) is a delta from private artifact %S (%d)\n", zId, rid, zSrc, srcid ); nErr++; } db_finalize(&q); | | | 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 | fossil_print( "public artifact %S (%d) is a delta from private artifact %S (%d)\n", 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); int size = db_column_int(&q, 2); n1++; |
︙ | ︙ | |||
943 944 945 946 947 948 949 | blob_reset(&cksum); n2++; } db_finalize(&q); fossil_print("%d non-phantom blobs (out of %d total) checked: %d errors\n", n2, n1, nErr); if( bParse ){ | | | | 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 | blob_reset(&cksum); n2++; } db_finalize(&q); fossil_print("%d non-phantom blobs (out of %d total) checked: %d errors\n", n2, n1, nErr); if( bParse ){ 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]); } } } |
︙ | ︙ | |||
1048 1049 1050 1051 1052 1053 1054 | fossil_print("%s: %s\n %s %s %S (%d) %s\n", zErrType, zUuid, zRole, zCFType, zSrc, p->rid, zDate); if( zDetail && zDetail[0] ){ fossil_print(" %s\n", zDetail); } fossil_free(zSrc); fossil_free(zDate); | | | 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 | fossil_print("%s: %s\n %s %s %S (%d) %s\n", zErrType, zUuid, zRole, zCFType, zSrc, p->rid, zDate); if( zDetail && zDetail[0] ){ fossil_print(" %s\n", zDetail); } fossil_free(zSrc); fossil_free(zDate); rc = 1; } return rc; } /* ** COMMAND: test-missing ** |
︙ | ︙ | |||
1095 1096 1097 1098 1099 1100 1101 | content_get(rid, &content); p = manifest_parse(&content, rid, 0); 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++){ | | | | 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 | content_get(rid, &content); p = manifest_parse(&content, rid, 0); 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", p->aFile[i].zName); } for(i=0; i<p->nParent; i++){ nErr += check_exists(p->azParent[i], flags, p, "parent of", 0); } for(i=0; i<p->nCherrypick; i++){ nErr += check_exists(p->aCherrypick[i].zCPTarget+1, flags, p, "cherry-pick target of", 0); nErr += check_exists(p->aCherrypick[i].zCPBase, flags, p, "cherry-pick baseline of", 0); } for(i=0; i<p->nCChild; i++){ 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); } } db_finalize(&q); if( nErr>0 || quietFlag==0 ){ fossil_print("%d missing or shunned references in %d control artifacts\n", nErr, nArtifact); } } |
Changes to src/db.c.
︙ | ︙ | |||
42 43 44 45 46 47 48 | #if INTERFACE /* ** An single SQL statement is represented as an instance of the following ** structure. */ struct Stmt { Blob sql; /* The SQL for this statement */ | | | 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | #if INTERFACE /* ** 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() */ Stmt *pNext, *pPrev; /* List of all unfinalized statements */ int nStep; /* Number of sqlite3_step() calls */ }; /* ** Copy this to initialize a Stmt object to a clean/empty state. This ** is useful to help avoid assertions when performing cleanup in some |
︙ | ︙ | |||
106 107 108 109 110 111 112 | ** the following structure. */ 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 */ | | | 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 | ** the following structure. */ 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() */ 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]; char *azDeleteOnFail[3]; /* Files to delete on a failure */ char *azBeforeCommit[5]; /* Commands to run prior to COMMIT */ |
︙ | ︙ | |||
314 315 316 317 318 319 320 | int db_bind_double(Stmt *pStmt, const char *zParamName, double rValue){ return sqlite3_bind_double(pStmt->pStmt, paramIdx(pStmt, zParamName), rValue); } 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); } | < < < < | 314 315 316 317 318 319 320 321 322 323 324 325 326 327 | int db_bind_double(Stmt *pStmt, const char *zParamName, double rValue){ return sqlite3_bind_double(pStmt->pStmt, paramIdx(pStmt, zParamName), rValue); } 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_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), blob_buffer(pBlob), blob_size(pBlob), SQLITE_STATIC); } |
︙ | ︙ | |||
713 714 715 716 717 718 719 | ** 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; sqlite3 *db; | | | 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 | ** 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; sqlite3 *db; #if defined(__CYGWIN__) zDbName = fossil_utf8_to_filename(zDbName); #endif if( g.fSqlTrace ) fossil_trace("-- sqlite3_open: [%s]\n", zDbName); rc = sqlite3_open_v2( zDbName, &db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, g.zVfsName |
︙ | ︙ | |||
829 830 831 832 833 834 835 836 837 838 | 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 zDbName = mprintf("%s/.fossil", zHome); #endif if( file_size(zDbName)<1024*3 ){ | > > > < < < > > | 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 | 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 ){ 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{ g.useAttach = 0; g.dbConfig = db_open(zDbName); |
︙ | ︙ | |||
1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 | }else{ #ifdef FOSSIL_ENABLE_JSON g.json.resultCode = FSL_JSON_E_DB_NOT_VALID; #endif fossil_panic("not a valid repository: %s", zDbName); } } g.zRepositoryName = mprintf("%s", zDbName); 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); } /* | > > > > | 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 | }else{ #ifdef FOSSIL_ENABLE_JSON 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); } /* |
︙ | ︙ | |||
1983 1984 1985 1986 1987 1988 1989 | ** Open a connection to the local repository in FILENAME. A checkout ** for the repository is created with its root at the working directory. ** 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: | < < < < < | 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 | ** Open a connection to the local repository in FILENAME. A checkout ** for the repository is created with its root at the working directory. ** 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: ** --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 keepFlag; int allowNested; char **oldArgv; int oldArgc; static char *azNewArgv[] = { 0, "checkout", "--prompt", 0, 0, 0 }; url_proxy_options(); keepFlag = find_option("keep",0,0)!=0; allowNested = find_option("nested",0,0)!=0; 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); |
︙ | ︙ | |||
2029 2030 2031 2032 2033 2034 2035 | 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; | < | | | | | | | | | | | | < | 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 | 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; 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"; } checkout_cmd(); g.argc = 2; info_cmd(); } /* ** Print the value of a setting named zName */ |
︙ | ︙ | |||
2141 2142 2143 2144 2145 2146 2147 | { "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" }, | < | 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 | { "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-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" }, |
︙ | ︙ | |||
2292 2293 2294 2295 2296 2297 2298 | ** ** main-branch The primary branch for the project. Default: trunk ** ** manifest If enabled, automatically create files "manifest" and ** (versionable) "manifest.uuid" in every checkout. The SQLite and ** Fossil repositories both require this. Default: off. ** | < < < < < < < | 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 | ** ** main-branch The primary branch for the project. Default: trunk ** ** 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-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".) ** ** pgp-command Command used to clear-sign manifests at check-in. |
︙ | ︙ |
Changes to src/delta.c.
︙ | ︙ | |||
465 466 467 468 469 470 471 | *(zDelta++) = ':'; memcpy(zDelta, &zOut[base], lenOut-base); zDelta += lenOut-base; } /* Output the final checksum record. */ putInt(checksum(zOut, lenOut), &zDelta); *(zDelta++) = ';'; | | | 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 | *(zDelta++) = ':'; memcpy(zDelta, &zOut[base], lenOut-base); zDelta += lenOut-base; } /* Output the final checksum record. */ putInt(checksum(zOut, lenOut), &zDelta); *(zDelta++) = ';'; free(collide); return zDelta - zOrigDelta; } /* ** Return the size (in bytes) of the output from applying ** a delta. ** |
︙ | ︙ |
Changes to src/descendants.c.
︙ | ︙ | |||
155 156 157 158 159 160 161 162 163 164 165 166 167 168 | } /* ** 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" | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 | } /* ** 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){ #if USE_SYSTEM_SQLITE+0==1 if( sqlite3_libversion_number()<3008003 ){ 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); } else #endif 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" |
︙ | ︙ |
Changes to src/diff.c.
︙ | ︙ | |||
27 28 29 30 31 32 33 | /* ** Flag parameters to the text_diff() routine used to control the formatting ** 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 */ | < | | | > | | > < < < < < < | | 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 | /* ** Flag parameters to the text_diff() routine used to control the formatting ** 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_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 */ /* ** These error messages are shared in multiple locations. They are defined ** here for consistency. */ #define DIFF_CANNOT_COMPUTE_BINARY \ "cannot compute difference between binary files\n" #define DIFF_CANNOT_COMPUTE_SYMLINK \ "cannot compute difference between symlink and regular file\n" #define DIFF_TOO_MANY_CHANGES \ "more than 10,000 changes\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) #endif /* INTERFACE */ /* ** Information about each line of a file being diffed. ** ** The lower LENGTH_MASK_SZ bits of the hash (DLine.h) are the length ** of the line. If any line is longer than LENGTH_MASK characters, ** the file is considered binary. */ typedef struct DLine DLine; struct DLine { const char *z; /* The text of the line */ unsigned int h; /* Hash of the line */ 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: */ unsigned int iHash; /* 1+(first entry in the hash chain) */ }; /* ** Length of a dline */ #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 ** aEdit[] means: ** |
︙ | ︙ | |||
111 112 113 114 115 116 117 | int *aEdit; /* Array of copy/delete/insert triples */ int nEdit; /* Number of integers (3x num of triples) in aEdit[] */ 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[] */ | < | | | 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 | int *aEdit; /* Array of copy/delete/insert triples */ int nEdit; /* Number of integers (3x num of triples) in aEdit[] */ 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[] */ }; /* ** Return an array of DLine objects containing a pointer to the ** start of each line and a hash of that line. The lower ** bits of the hash store the length of each line. ** ** Trailing whitespace is removed from each line. 2010-08-20: Not any ** more. If trailing whitespace is ignored, the "patch" command gets ** confused by the diff output. Ticket [a9f7b23c2e376af5b0e5b] ** ** Return 0 if the file is binary or contains a line that is ** 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, 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. */ for(i=j=0, nLine=1; i<n; i++, j++){ |
︙ | ︙ | |||
162 163 164 165 166 167 168 | if( n==0 ){ *pnLine = 0; return a; } /* Fill in the array */ for(i=0; i<nLine; i++){ | < > < < < < < < | < < < < | < < < | | < < < < < < < < | | | < < < < < < < < < < < < < < < < < < < | 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 | if( n==0 ){ *pnLine = 0; return a; } /* Fill in the array */ for(i=0; i<nLine; i++){ a[i].z = z; for(j=0; z[j] && z[j]!='\n'; j++){} k = j; 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; } /* Return results */ *pnLine = nLine; return a; } /* ** Return true if two DLine elements are identical. */ 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 */ static int re_dline_match( |
︙ | ︙ | |||
265 266 267 268 269 270 271 | if( pRe && re_dline_match(pRe, pLine, 1)==0 ){ cPrefix = ' '; }else if( cPrefix=='+' ){ blob_append(pOut, "<span class=\"diffadd\">", -1); }else if( cPrefix=='-' ){ blob_append(pOut, "<span class=\"diffrm\">", -1); } | | | | 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 | if( pRe && re_dline_match(pRe, pLine, 1)==0 ){ cPrefix = ' '; }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->h & LENGTH_MASK)); if( cPrefix!=' ' ){ blob_append(pOut, "</span>", -1); } }else{ blob_append(pOut, pLine->z, pLine->h & LENGTH_MASK); } blob_append(pOut, "\n", 1); } /* ** Add two line numbers to the beginning of an output line for a context ** diff. One or the other of the two numbers might be zero, which means |
︙ | ︙ | |||
446 447 448 449 450 451 452 | appendDiffLine(pOut, '+', &B[b+j], html, pRe); } 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); | | | | 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 | appendDiffLine(pOut, '+', &B[b+j], html, pRe); } 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, ' ', &B[b+j], html, 0); } b += m; a += m; } } /* Show the final common area */ assert( nr==i ); m = R[r+nr*3]; if( m>nContext ) m = nContext; for(j=0; j<m; j++){ if( showLn ) appendDiffLineno(pOut, a+j+1, b+j+1, html); appendDiffLine(pOut, ' ', &B[b+j], html, 0); } } } /* ** Status of a single output line */ |
︙ | ︙ | |||
520 521 522 523 524 525 526 | ** rendering to width bytes if col is SBS_TXTA and escHtml is false. ** ** 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]; | | | 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 | ** rendering to width bytes if col is SBS_TXTA and escHtml is false. ** ** 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->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; int colorize = p->escHtml; if( colorize && p->pRe && re_dline_match(p->pRe, pLine, 1)==0 ){ |
︙ | ︙ | |||
764 765 766 767 768 769 770 | int nLeftDiff; /* nLeft - nPrefix - nSuffix */ int nRightDiff; /* nRight - nPrefix - nSuffix */ 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\">"; | | | | 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 | int nLeftDiff; /* nLeft - nPrefix - nSuffix */ int nRightDiff; /* nRight - nPrefix - nSuffix */ 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->h & LENGTH_MASK; zLeft = pLeft->z; nRight = pRight->h & LENGTH_MASK; zRight = pRight->z; nShort = nLeft<nRight ? nLeft : nRight; nPrefix = 0; while( nPrefix<nShort && zLeft[nPrefix]==zRight[nPrefix] ){ nPrefix++; } |
︙ | ︙ | |||
912 913 914 915 916 917 918 | int score; /* Final score. 0..100 */ unsigned char c; /* Character being examined */ 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; | | | | 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 | int score; /* Final score. 0..100 */ unsigned char c; /* Character being examined */ 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->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; if( nB>250 ) nB = 250; avg = (nA+nB)/2; |
︙ | ︙ | |||
1349 1350 1351 1352 1353 1354 1355 | s.iStart = s.iEnd = -1; sbsWriteText(&s, &A[a+j], SBS_TXTA); sbsWriteMarker(&s, " ", ""); sbsWriteLineno(&s, b+j, SBS_LNB); sbsWriteText(&s, &B[b+j], SBS_TXTB); } } | | | 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 | s.iStart = s.iEnd = -1; sbsWriteText(&s, &A[a+j], SBS_TXTA); 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]); } blob_append(pOut, "</tr></table>\n", -1); |
︙ | ︙ | |||
1381 1382 1383 1384 1385 1386 1387 | int i, j; /* Loop counters */ int k; /* Length of a candidate subsequence */ 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++){ | | | | | 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 | int i, j; /* Loop counters */ int k; /* Length of a candidate subsequence */ 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( !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 && same_dline(&p->aFrom[i+k],&p->aTo[j+k]) ){ k++; } if( k>mxLength ){ iSXb = i; iSYb = j; mxLength = k; } |
︙ | ︙ | |||
1452 1453 1454 1455 1456 1457 1458 | iSYb = iSYp = iS2; iEYb = iEYp = iS2; 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 | | | | | 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 | iSYb = iSYp = iS2; iEYb = iEYp = iS2; 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 || !same_dline(&p->aFrom[i], &p->aTo[j-1])) ){ if( limit++ > 10 ){ j = 0; break; } j = p->aTo[j-1].iNext; } if( j==0 ) continue; assert( i>=iSXb && i>=iSXp ); if( i<iEXb && j>=iSYb && j<iEYb ) continue; if( i<iEXp && j>=iSYp && j<iEYp ) continue; 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 && 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 && 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; if( dist<0 ) dist = -dist; score = (iEX - iSX)*(sqlite3_int64)span - (skew + dist); |
︙ | ︙ | |||
1618 1619 1620 1621 1622 1623 1624 | */ static void diff_all(DContext *p){ int mnE, iS, iE1, iE2; /* Carve off the common header and footer */ iE1 = p->nFrom; iE2 = p->nTo; | | | | 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 | */ static void diff_all(DContext *p){ int mnE, iS, iE1, iE2; /* Carve off the common header and footer */ iE1 = p->nFrom; iE2 = p->nTo; 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 && same_dline(&p->aFrom[iS],&p->aTo[iS]); iS++){} /* do the difference */ if( iS>0 ){ appendTriple(p, iS, 0, 0); } diff_step(p, iS, iE1, iS, iE2); if( iE1<p->nFrom ){ |
︙ | ︙ | |||
1692 1693 1694 1695 1696 1697 1698 | lnFrom += cpy; lnTo += cpy; /* 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 */ | | | | | | 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 | lnFrom += cpy; lnTo += cpy; /* 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( 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]++; cpy--; } /* 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( 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]--; cpy++; } /* 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( 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]++; cpy--; } /* 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( 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]--; cpy++; } |
︙ | ︙ | |||
1797 1798 1799 1800 1801 1802 1803 | int *text_diff( Blob *pA_Blob, /* FROM file */ 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 */ ){ | | | < < < < < < < | | < < < < < < < | | 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 | int *text_diff( Blob *pA_Blob, /* FROM file */ 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 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; } ignoreEolWs = (diffFlags & DIFF_IGNORE_EOLWS)!=0; /* Prepare the input files */ memset(&c, 0, sizeof(c)); c.aFrom = break_into_lines(blob_str(pA_Blob), blob_size(pA_Blob), &c.nFrom, ignoreEolWs); c.aTo = break_into_lines(blob_str(pB_Blob), blob_size(pB_Blob), &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); } return 0; } /* Compute the difference */ diff_all(&c); 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); diff_errmsg(pOut, DIFF_TOO_MANY_CHANGES, diffFlags); return 0; } } if( (diffFlags & DIFF_NOOPT)==0 ){ diff_optimize(&c); } |
︙ | ︙ | |||
1880 1881 1882 1883 1884 1885 1886 | } } /* ** Process diff-related command-line options and return an appropriate ** "diffFlags" integer. ** | | | | | | | | | < | < < < < < < < < < < < | 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 | } } /* ** Process diff-related command-line options and return an appropriate ** "diffFlags" integer. ** ** --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("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; } if( (z = find_option("width","W",1))!=0 && (f = atoi(z))>0 ){ |
︙ | ︙ | |||
1998 1999 2000 2001 2002 2003 2004 | ** of the following structure. */ 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 */ | | | 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 | ** of the following structure. */ 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 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 */ struct AnnVers { const char *zFUuid; /* File being analyzed */ |
︙ | ︙ | |||
2020 2021 2022 2023 2024 2025 2026 | }; /* ** 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. */ | | < < < < < | < | | | | 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 | }; /* ** 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){ int i; memset(p, 0, sizeof(*p)); 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].h & LENGTH_MASK; p->aOrig[i].iVers = -1; } p->nOrig = p->c.nTo; return 0; } /* ** The input pParent is the next most recent ancestor of the file ** 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){ 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, 1); if( p->c.aFrom==0 ){ return 1; } /* Compute the differences going from pParent to the file being ** annotated. */ diff_all(&p->c); |
︙ | ︙ | |||
2094 2095 2096 2097 2098 2099 2100 | free(p->c.aFrom); /* Return no errors */ return 0; } | | | | | < | | 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 | free(p->c.aFrom); /* Return no errors */ return 0; } /* 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). */ 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 */ 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 */ Stmt ins; /* Inserts into the temporary VSEEN table */ int cnt = 0; /* Number of versions examined */ /* Initialize the annotation */ rid = db_int(0, "SELECT fid FROM mlink WHERE mid=%d AND fnid=%d",mid,fnid); if( rid==0 ){ fossil_fatal("file #%d is unchanged in manifest #%d", fnid, mid); } if( !content_get(rid, &toAnnotate) ){ fossil_fatal("unable to retrieve content of artifact #%d", rid); } if( iLimit<=0 ) iLimit = 1000000000; annotation_start(p, &toAnnotate); db_begin_transaction(); db_multi_exec( "CREATE TEMP TABLE IF NOT EXISTS vseen(rid INTEGER PRIMARY KEY);" "DELETE FROM vseen;" ); db_prepare(&ins, "INSERT OR IGNORE INTO vseen(rid) VALUES(:rid)"); |
︙ | ︙ | |||
2161 2162 2163 2164 2165 2166 2167 | 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); | < | | 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 | 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); annotation_step(p, &step, p->nVers-1); blob_reset(&step); } p->nVers++; db_bind_int(&ins, ":rid", rid); db_step(&ins); db_reset(&ins); db_reset(&q); |
︙ | ︙ | |||
2187 2188 2189 2190 2191 2192 2193 | /* ** Return a color from a gradient. */ 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; | < < | < | < < < < < < | < < < < < < < < < | 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 | /* ** Return a color from a gradient. */ 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; 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; c |= (x1*(n-i) + x2*i)/n<<8 & 0xff00; x1 = c1&0xff; x2 = c2&0xff; c |= (x1*(n-i) + x2*i)/n & 0xff; return c; } /* ** WEBPAGE: annotate ** WEBPAGE: blame ** ** Query parameters: ** ** checkin=ID The manifest ID at which to start the annotation ** filename=FILENAME The filename. ** filevers Show file versions rather than check-in versions ** log=BOOLEAN Show a log of versions analyzed ** limit=N Limit the search depth to N ancestors */ void annotation_page(void){ int mid; int fnid; int i; int iLimit; /* Depth limit */ int annFlags = ANN_FILE_ANCEST; int showLog = 0; /* True to display the log */ 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]=='b';/* True for BLAME output. False for ANNOTATE. */ /* Gather query parameters */ showLog = atoi(PD("log","1")); login_check_credentials(); if( !g.perm.Read ){ login_needed(); return; } if( exclude_spiders("annotate") ) return; 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; if( !db_exists("SELECT 1 FROM mlink WHERE mid=%d AND fnid=%d",mid,fnid) ){ fossil_redirect_home(); } /* compute the annotation */ compute_direct_ancestors(mid, 10000000); annotate_file(&ann, fnid, mid, iLimit, annFlags); zCI = ann.aVers[0].zMUuid; /* generate the web page */ style_header("Annotation For %h", zFilename); 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( showLog ){ style_submenu_element("Hide Log", "Hide Log", "%s", url_render(&url, "log", "0", 0, 0)); }else{ style_submenu_element("Show Log", "Show Log", "%s", url_render(&url, "log", "1", 0, 0)); } |
︙ | ︙ | |||
2302 2303 2304 2305 2306 2307 2308 | }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); | | | | | | | | | | | | < | | | | | | < < | | < < < < < < | 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 | }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); @ <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))%.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", p->zFUuid,ann.aVers[0].zFUuid); @ %z(zLink)[diff-to-top]</a> if( i>1 ){ zLink = xhref("target='infowindow'", "%R/fdiff?v1=%S&v2=%S&sbs=1", p->zFUuid,p[-1].zFUuid); @ %z(zLink)[diff-to-previous]</a> } } #endif } @ </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> 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> } @ <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); } } @ %s(zPrefix) %h(z) } @ </pre> style_footer(); } /* ** COMMAND: annotate ** COMMAND: blame ** ** %fossil (annotate|blame) ?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" command shows the user who made each ** checkin and omits the line number. ** ** 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 ** ** See also: info, finfo, timeline */ void annotate_cmd(void){ int fnid; /* Filename ID */ int fid; /* File instance ID */ int mid; /* Manifest where file was checked in */ int cid; /* Checkout ID */ Blob treename; /* FILENAME translated to canonical form */ char *zFilename; /* Canonical filename */ Annotator ann; /* The annotation of the file */ 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 */ int annFlags = 0; /* Flags to control annotation properties */ int bBlame = 0; /* True for BLAME output. False for ANNOTATE. */ bBlame = g.argv[1][0]=='b'; zLimit = find_option("limit","n",1); if( zLimit==0 || zLimit[0]==0 ) zLimit = "-1"; iLimit = atoi(zLimit); showLog = find_option("log","l",0)!=0; fileVers = find_option("filevers",0,0)!=0; db_must_be_within_tree(); if( g.argc<3 ) { usage("FILENAME"); } file_tree_name(g.argv[2], &treename, 1); zFilename = blob_str(&treename); |
︙ | ︙ | |||
2458 2459 2460 2461 2462 2463 2464 | mid = db_int(0, "SELECT mlink.mid FROM mlink, ancestor " " WHERE mlink.fid=%d AND mlink.fnid=%d AND mlink.mid=ancestor.rid" " ORDER BY ancestor.generation ASC LIMIT 1", fid, fnid); if( mid==0 ){ fossil_fatal("unable to find manifest"); } | | | 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 | mid = db_int(0, "SELECT mlink.mid FROM mlink, ancestor " " WHERE mlink.fid=%d AND mlink.fnid=%d AND mlink.mid=ancestor.rid" " ORDER BY ancestor.generation ASC LIMIT 1", fid, fnid); if( mid==0 ){ fossil_fatal("unable to find manifest"); } 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 %.10s file %.10s\n", i+1, p->zDate, p->zMUuid, p->zFUuid); } |
︙ | ︙ |
Changes to src/diffcmd.c.
︙ | ︙ | |||
47 48 49 50 51 52 53 | void diff_print_filenames(const char *zLeft, const char *zRight, u64 diffFlags){ char *z = 0; if( diffFlags & DIFF_BRIEF ){ /* no-op */ }else if( diffFlags & DIFF_SIDEBYSIDE ){ int w = diff_width(diffFlags); int n1 = strlen(zLeft); | < < | | | | < < < < < < < < | 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | void diff_print_filenames(const char *zLeft, const char *zRight, u64 diffFlags){ char *z = 0; if( diffFlags & DIFF_BRIEF ){ /* no-op */ }else if( diffFlags & DIFF_SIDEBYSIDE ){ int w = diff_width(diffFlags); int n1 = strlen(zLeft); int x; 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); } |
︙ | ︙ | |||
606 607 608 609 610 611 612 | } return db_get(zName, zDefault); } /* A Tcl/Tk script used to render diff output. */ static const char zDiffScript[] = | < | < | | | | | < < < < < < < < < < | | < < < < < | < | < < < < | < | > > < | < < | | < < < < | | | | | | | | | | | | | | 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 | } 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} { |
︙ | ︙ | |||
824 825 826 827 828 829 830 | @ grid .sby @ .sby set $first $last @ } else { @ grid remove .sby @ } @ enableSync y @ } | | | | | < | | | 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 | @ 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 .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} |
︙ | ︙ | |||
885 886 887 888 889 890 891 | @ break @ } @ } @ bind .wfiles.lb <Motion> { @ %W selection clear 0 end @ %W selection set @%x,%y @ } | | | < | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < | | 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 | @ 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: ** (1) Write the Tcl/Tk script used for rendering into a temp file. ** (2) Invoke "tclsh" on the temp file using fossil_system(). ** (3) Delete the temp file. */ |
︙ | ︙ | |||
1022 1023 1024 1025 1026 1027 1028 | ** for testing and debugging. */ if( strglob("*-script",z) && i<g.argc-1 ){ i++; zTempFile = g.argv[i]; continue; } } | < < < < | | < | 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 | ** for testing and debugging. */ if( strglob("*-script",z) && i<g.argc-1 ){ i++; zTempFile = g.argv[i]; continue; } } blob_append(&script, " ", 1); shell_escape(&script, z); } blob_appendf(&script, "}\n%s", zDiffScript); if( zTempFile ){ blob_write_to_file(&script, zTempFile); fossil_print("To see diff, run: tclsh \"%s\"\n", zTempFile); }else{ #if defined(FOSSIL_ENABLE_TCL) |
︙ | ︙ | |||
1094 1095 1096 1097 1098 1099 1100 | ** ** Show the difference between the current version of each of the FILEs ** specified (as they exist on disk) and that same file as it was checked ** out. Or if the FILE arguments are omitted, show the unsaved changed ** currently in the working check-out. ** ** If the "--from VERSION" or "-r VERSION" option is used it specifies | | | 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 | ** ** Show the difference between the current version of each of the FILEs ** specified (as they exist on disk) and that same file as it was checked ** out. Or if the FILE arguments are omitted, show 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 ** 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 ** are used. ** |
︙ | ︙ | |||
1118 1119 1120 1121 1122 1123 1124 | ** when using an external diff program. ** ** The "--binary" option causes files matching the glob PATTERN to be treated ** as binary when considering if they should be used with external diff program. ** This option overrides the "binary-glob" setting. ** ** Options: | | | | | | | | | < | | | | < | < | 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 | ** when using an external diff program. ** ** The "--binary" option causes files matching the glob PATTERN to be treated ** as binary when considering if they should be used with 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 ** --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 */ const char *zFrom; /* Source version number */ const char *zTo; /* Target version number */ |
︙ | ︙ | |||
1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 | zBranch = find_option("branch", 0, 1); diffFlags = diff_options(); 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; zFrom = mprintf("root:%s", zBranch); } | > | 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 | zBranch = find_option("branch", 0, 1); diffFlags = diff_options(); 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; zFrom = mprintf("root:%s", zBranch); } |
︙ | ︙ |
Changes to src/doc.c.
︙ | ︙ | |||
481 482 483 484 485 486 487 | /* Get the file content */ if( content_get(rid, &filebody)==0 ){ goto doc_not_found; } db_end_transaction(0); } | < | 481 482 483 484 485 486 487 488 489 490 491 492 493 494 | /* 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); |
︙ | ︙ |
Changes to src/event.c.
︙ | ︙ | |||
183 184 185 186 187 188 189 | @ <div> } blob_init(&comment, pEvent->zComment, -1); wiki_convert(&comment, 0, WIKI_INLINE); blob_reset(&comment); @ </div> @ </blockquote><hr /> | | | 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 | @ <div> } blob_init(&comment, pEvent->zComment, -1); wiki_convert(&comment, 0, WIKI_INLINE); blob_reset(&comment); @ </div> @ </blockquote><hr /> } wiki_convert(&tail, 0, 0); style_footer(); manifest_destroy(pEvent); } /* |
︙ | ︙ | |||
225 226 227 228 229 230 231 | int nEventId = strlen(zEventId); if( nEventId!=40 || !validate16(zEventId, 40) ){ fossil_redirect_home(); return; } } zTag = mprintf("event-%s", zEventId); | | | 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 | int nEventId = strlen(zEventId); if( nEventId!=40 || !validate16(zEventId, 40) ){ fossil_redirect_home(); return; } } zTag = mprintf("event-%s", zEventId); rid = db_int(0, "SELECT rid FROM tagxref" " WHERE tagid=(SELECT tagid FROM tag WHERE tagname=%Q)" " ORDER BY mtime DESC", zTag ); free(zTag); /* Need both check-in and wiki-write or wiki-create privileges in order |
︙ | ︙ | |||
310 311 312 313 314 315 316 | Blob tags, one; int i, j; Stmt q; char *zBlob; /* Load the tags string into a blob */ blob_zero(&tags); | | | 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 | Blob tags, one; int i, j; Stmt q; char *zBlob; /* Load the tags string into a blob */ blob_zero(&tags); 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++){ if( fossil_isspace(zBlob[i]) || zBlob[i]==',' ){ while( fossil_isspace(zBlob[i+1]) ){ i++; } |
︙ | ︙ | |||
339 340 341 342 343 344 345 | /* Extract the tags in sorted order and make an entry in the ** artifact for each. */ 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); | | | | | 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 | /* Extract the tags in sorted order and make an entry in the ** artifact for each. */ 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( 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); |
︙ | ︙ | |||
409 410 411 412 413 414 415 | @ <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> @ <td valign="top"> | | | | | | 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 | @ <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> @ <td valign="top"> @ <textarea name="c" class="eventedit" cols="80" @ rows="3" wrap="virtual">%h(zComment)</textarea> @ </td></tr> @ <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">Page Content:</th> @ <td valign="top"> @ <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" /> @ <input type="submit" name="submit" value="Apply These Changes" /> @ <input type="submit" name="cancel" value="Cancel" /> @ </td></tr></table> @ </div></form> style_footer(); } |
Changes to src/file.c.
︙ | ︙ | |||
391 392 393 394 395 396 397 | */ void file_copy(const char *zFrom, const char *zTo){ FILE *in, *out; int got; char zBuf[8192]; in = fossil_fopen(zFrom, "rb"); if( in==0 ) fossil_fatal("cannot open \"%s\" for reading", zFrom); | < < < < < < < < < < < < < < < < < | 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 | */ void file_copy(const char *zFrom, const char *zTo){ FILE *in, *out; int got; char zBuf[8192]; in = fossil_fopen(zFrom, "rb"); if( in==0 ) fossil_fatal("cannot open \"%s\" for reading", zFrom); 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); } /* ** 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){ int rc = 0; #if !defined(_WIN32) |
︙ | ︙ | |||
532 533 534 535 536 537 538 | #endif fossil_filename_free(zMbcs); return rc; } return 0; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 515 516 517 518 519 520 521 522 523 524 525 526 527 528 | #endif fossil_filename_free(zMbcs); return rc; } return 0; } /* ** 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. */ int file_rmdir(const char *zName){ |
︙ | ︙ | |||
694 695 696 697 698 699 700 | *pJ = i-1; return 1; } /* ** Simplify a filename by ** | < | | < | | < < < < < < < < < | | 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 | *pJ = i-1; return 1; } /* ** Simplify a filename by ** ** * Convert all \ into / on windows and cygwin ** * removing any trailing and duplicate / ** * removing /./ ** * removing /A/../ ** ** 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, j; if( n<0 ) n = strlen(z); /* On windows and cygwin convert all \ characters to / */ #if defined(_WIN32) || defined(__CYGWIN__) for(i=0; i<n; i++){ if( z[i]=='\\' ) z[i] = '/'; } #endif /* Removing trailing "/" characters */ if( !slash ){ 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(i=j=1; i<n; i++){ z[j++] = z[i]; while( z[i]=='/' && i<n-1 && z[i+1]=='/' ) i++; } n = j; /* Skip over zero or more initial "./" sequences */ for(i=0; i<n-1 && z[i]=='.' && z[i+1]=='/'; i+=2){} |
︙ | ︙ | |||
1044 1045 1046 1047 1048 1049 1050 | char *zLocalRoot; Blob full; int nFull; char *zFull; int (*xCmp)(const char*,const char*,int); blob_zero(pOut); | < < | < | | 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 | char *zLocalRoot; Blob full; int nFull; char *zFull; int (*xCmp)(const char*,const char*,int); blob_zero(pOut); 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); nFull = blob_size(&full); zFull = blob_buffer(&full); if( filenames_are_case_sensitive() ){ xCmp = fossil_strncmp; }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]=='/') ){ blob_append(pOut, ".", 1); blob_reset(&localRoot); blob_reset(&full); return 1; } |
︙ | ︙ | |||
1096 1097 1098 1099 1100 1101 1102 | ** Options: ** --case-sensitive B Enable or disable case-sensitive filenames. B is ** a boolean: "yes", "no", "true", "false", etc. */ void cmd_test_tree_name(void){ int i; Blob x; | < | 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 | ** Options: ** --case-sensitive B Enable or disable case-sensitive filenames. B is ** a boolean: "yes", "no", "true", "false", etc. */ void cmd_test_tree_name(void){ int i; Blob x; 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); } |
︙ | ︙ |
Changes to src/finfo.c.
︙ | ︙ | |||
320 321 322 323 324 325 326 | " mlink.pfnid", /* Previous filename */ timeline_utc(), TAG_BRANCH ); if( firstChngOnly ){ #if 0 blob_appendf(&sql, ", min(event.mtime)"); #else | | | 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 | " mlink.pfnid", /* Previous filename */ timeline_utc(), TAG_BRANCH ); if( firstChngOnly ){ #if 0 blob_appendf(&sql, ", min(event.mtime)"); #else blob_appendf(&sql, ", min(CASE (SELECT value FROM tagxref" " WHERE tagtype>0 AND tagid=%d" " AND tagxref.rid=mlink.mid)" " WHEN 'trunk' THEN event.mtime-10000 ELSE event.mtime END)", TAG_BRANCH); #endif } |
︙ | ︙ | |||
372 373 374 375 376 377 378 | if( P("showsql")!=0 ){ @ <p>SQL: %h(blob_str(&sql))</p> } blob_reset(&sql); blob_zero(&title); if( baseCheckin ){ char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", baseCheckin); | | | 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 | if( P("showsql")!=0 ){ @ <p>SQL: %h(blob_str(&sql))</p> } blob_reset(&sql); blob_zero(&title); if( baseCheckin ){ char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", baseCheckin); char *zLink = href("%R/info/%S", zUuid); blob_appendf(&title, "Ancestors of file "); hyperlinked_path(zFilename, &title, zUuid, "tree", ""); blob_appendf(&title, " from check-in %z%.10s</a>", zLink, zUuid); fossil_free(zUuid); }else{ blob_appendf(&title, "History of files named "); hyperlinked_path(zFilename, &title, 0, "tree", ""); |
︙ | ︙ | |||
402 403 404 405 406 407 408 409 410 411 412 413 414 415 | const char *zCkin = db_column_text(&q,7); const char *zBgClr = db_column_text(&q, 8); const char *zBr = db_column_text(&q, 9); int fmid = db_column_int(&q, 10); int pfnid = db_column_int(&q, 11); int gidx; char zTime[10]; if( zBr==0 ) zBr = "trunk"; if( uBg ){ zBgClr = hash_color(zUser); }else if( brBg || zBgClr==0 || zBgClr[0]==0 ){ zBgClr = strcmp(zBr,"trunk")==0 ? "" : hash_color(zBr); } gidx = graph_add_row(pGraph, frid, fpid>0 ? 1 : 0, &fpid, zBr, zBgClr, | > > | 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 | const char *zCkin = db_column_text(&q,7); const char *zBgClr = db_column_text(&q, 8); const char *zBr = db_column_text(&q, 9); int fmid = db_column_int(&q, 10); int pfnid = db_column_int(&q, 11); int gidx; char zTime[10]; char zShort[20]; char zShortCkin[20]; if( zBr==0 ) zBr = "trunk"; if( uBg ){ zBgClr = hash_color(zUser); }else if( brBg || zBgClr==0 || zBgClr[0]==0 ){ zBgClr = strcmp(zBr,"trunk")==0 ? "" : hash_color(zBr); } gidx = graph_add_row(pGraph, frid, fpid>0 ? 1 : 0, &fpid, zBr, zBgClr, |
︙ | ︙ | |||
426 427 428 429 430 431 432 433 434 435 436 437 438 439 | @ %z(href("%R/timeline?c=%t",zDate))%s(zTime)</a></td> @ <td class="timelineGraph"><div id="m%d(gidx)"></div></td> if( zBgClr && zBgClr[0] ){ @ <td class="timelineTableCell" style="background-color: %h(zBgClr);"> }else{ @ <td class="timelineTableCell"> } if( zUuid ){ if( fpid==0 ){ @ <b>Added</b> }else if( pfnid ){ char *zPrevName = db_text(0, "SELECT name FROM filename WHERE fnid=%d", pfnid); @ <b>Renamed</b> from | > > | 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 | @ %z(href("%R/timeline?c=%t",zDate))%s(zTime)</a></td> @ <td class="timelineGraph"><div id="m%d(gidx)"></div></td> if( zBgClr && zBgClr[0] ){ @ <td class="timelineTableCell" style="background-color: %h(zBgClr);"> }else{ @ <td class="timelineTableCell"> } sqlite3_snprintf(sizeof(zShort), zShort, "%.10s", zUuid); sqlite3_snprintf(sizeof(zShortCkin), zShortCkin, "%.10s", zCkin); if( zUuid ){ if( fpid==0 ){ @ <b>Added</b> }else if( pfnid ){ char *zPrevName = db_text(0, "SELECT name FROM filename WHERE fnid=%d", pfnid); @ <b>Renamed</b> from |
︙ | ︙ | |||
452 453 454 455 456 457 458 | @ <b>Renamed</b> to @ %z(href("%R/finfo?name=%t",zNewName))%h(zNewName)</a> by check-in fossil_free(zNewName); }else{ @ <b>Deleted</b> by check-in } } | | | | | | | 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 | @ <b>Renamed</b> to @ %z(href("%R/finfo?name=%t",zNewName))%h(zNewName)</a> by check-in fossil_free(zNewName); }else{ @ <b>Deleted</b> by check-in } } hyperlink_to_uuid(zShortCkin); @ %w(zCom) (user: hyperlink_to_user(zUser, zDate, ""); @ branch: %h(zBr)) if( g.perm.Hyperlink && zUuid ){ const char *z = zFilename; @ %z(href("%R/annotate?checkin=%S&filename=%h",zCkin,z)) @ [annotate]</a> @ %z(href("%R/blame?checkin=%S&filename=%h",zCkin,z)) @ [blame]</a> @ %z(href("%R/timeline?n=200&uf=%S",zUuid))[checkins using]</a> if( fpid ){ @ %z(href("%R/fdiff?v1=%S&v2=%S&sbs=1",zPUuid,zUuid))[diff]</a> } } if( fDebug & FINFO_DEBUG_MLINK ){ int srcid = db_int(0, "SELECT srcid FROM delta WHERE rid=%d", frid); int sz = db_int(0, "SELECT length(content) FROM blob WHERE rid=%d", frid); @ <br>fid=%d(frid) pid=%d(fpid) mid=%d(fmid) sz=%d(sz) if( srcid ){ |
︙ | ︙ |
Changes to src/glob.c.
︙ | ︙ | |||
152 153 154 155 156 157 158 | ** ** [...] Matches one character from the enclosed list of ** characters. ** ** [^...] Matches one character not in the enclosed list. */ int strglob(const char *zGlob, const char *z){ | > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 | ** ** [...] Matches one character from the enclosed list of ** characters. ** ** [^...] Matches one character not in the enclosed list. */ int strglob(const char *zGlob, const char *z){ int c, c2; int invert; int seen; while( (c = (*(zGlob++)))!=0 ){ if( c=='*' ){ while( (c=(*(zGlob++))) == '*' || c=='?' ){ if( c=='?' && (*(z++))==0 ) return 0; } if( c==0 ){ return 1; }else if( c=='[' ){ while( *z && strglob(zGlob-1,z)==0 ){ z++; } return (*z)!=0; } while( (c2 = (*(z++)))!=0 ){ while( c2!=c ){ c2 = *(z++); if( c2==0 ) return 0; } if( strglob(zGlob,z) ) return 1; } return 0; }else if( c=='?' ){ if( (*(z++))==0 ) return 0; }else if( c=='[' ){ int prior_c = 0; seen = 0; invert = 0; c = *(z++); if( c==0 ) return 0; c2 = *(zGlob++); if( c2=='^' ){ invert = 1; c2 = *(zGlob++); } if( c2==']' ){ if( c==']' ) seen = 1; c2 = *(zGlob++); } while( c2 && c2!=']' ){ if( c2=='-' && zGlob[0]!=']' && zGlob[0]!=0 && prior_c>0 ){ c2 = *(zGlob++); if( c>=prior_c && c<=c2 ) seen = 1; prior_c = 0; }else{ if( c==c2 ){ seen = 1; } prior_c = c2; } c2 = *(zGlob++); } if( c2==0 || (seen ^ invert)==0 ) return 0; }else{ if( c!=(*(z++)) ) return 0; } } return *z==0; } /* ** Return true (non-zero) if zString matches any of the patterns in ** the Glob. The value returned is actually a 1-based index of the pattern ** that matched. Return 0 if none of the patterns match zString. ** ** A NULL glob matches nothing. */ int glob_match(Glob *pGlob, const char *zString){ int i; if( pGlob==0 ) return 0; for(i=0; i<pGlob->nPattern; i++){ if( strglob(pGlob->azPattern[i], zString) ) return i+1; } return 0; } /* ** Free all memory associated with the given Glob object */ |
︙ | ︙ |
Changes to src/gzip.c.
︙ | ︙ | |||
71 72 73 74 75 76 77 | /* ** Add nIn bytes of content from pIn to the gzip file. */ #define GZIP_BUFSZ 100000 void gzip_step(const char *pIn, int nIn){ char *zOutBuf; int nOut; | | | 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | /* ** Add nIn bytes of content from pIn to the gzip file. */ #define GZIP_BUFSZ 100000 void gzip_step(const char *pIn, int nIn){ char *zOutBuf; int nOut; nOut = nIn + nIn/10 + 100; if( nOut<100000 ) nOut = 100000; zOutBuf = fossil_malloc(nOut); gzip.stream.avail_in = nIn; gzip.stream.next_in = (unsigned char*)pIn; gzip.stream.avail_out = nOut; gzip.stream.next_out = (unsigned char*)zOutBuf; |
︙ | ︙ |
Changes to src/http.c.
︙ | ︙ | |||
17 18 19 20 21 22 23 | ** ** This file contains code that implements the client-side HTTP protocol */ #include "config.h" #include "http.h" #include <assert.h> | < < < < < < < < < < < < < < < < | | | | | | > > > > > > | 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 | ** ** This file contains code that implements the client-side HTTP protocol */ #include "config.h" #include "http.h" #include <assert.h> /* ** Construct the "login" card with the client credentials. ** ** login LOGIN NONCE SIGNATURE ** ** The LOGIN is the user id of the client. NONCE is the sha1 checksum ** of all payload that follows the login card. SIGNATURE is the sha1 ** checksum of the nonce followed by the user password. ** ** Write the constructed login card into pLogin. pLogin is initialized ** by this routine. */ static void http_build_login_card(Blob *pPayload, Blob *pLogin){ Blob nonce; /* The nonce */ const char *zLogin; /* The user login name */ const char *zPw; /* The user password */ Blob pw; /* The nonce with user password appended */ Blob sig; /* The signature field */ blob_zero(pLogin); if( g.urlUser==0 || fossil_strcmp(g.urlUser, "anonymous")==0 ){ return; /* If no login card for users "nobody" and "anonymous" */ } if( g.urlIsSsh ){ return; /* If no login card for SSH: */ } blob_zero(&nonce); blob_zero(&pw); sha1sum_blob(pPayload, &nonce); blob_copy(&pw, &nonce); zLogin = g.urlUser; if( g.urlPasswd ){ zPw = g.urlPasswd; }else if( g.cgiOutput ){ /* Password failure while doing a sync from the web interface */ cgi_printf("*** incorrect or missing password for user %h\n", zLogin); zPw = 0; }else{ /* Password failure while doing a sync from the command-line interface */ url_prompt_for_password(); zPw = g.urlPasswd; } /* If the first character of the password is "#", then that character is ** not really part of the password - it is an indicator that we should ** use Basic Authentication. So skip that character. */ if( zPw && zPw[0]=='#' ) zPw++; /* The login card wants the SHA1 hash of the password, so convert the ** password to its SHA1 hash it it isn't already a SHA1 hash. */ /* fossil_print("\nzPw=[%s]\n", zPw); // TESTING ONLY */ if( zPw && zPw[0] ) zPw = sha1_shared_secret(zPw, zLogin, 0); |
︙ | ︙ | |||
100 101 102 103 104 105 106 | ** the complete payload (including the login card) already compressed. */ static void http_build_header(Blob *pPayload, Blob *pHdr){ int i; const char *zSep; blob_zero(pHdr); | | | | | | | | > | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 | ** the complete payload (including the login card) already compressed. */ static void http_build_header(Blob *pPayload, Blob *pHdr){ int i; const char *zSep; blob_zero(pHdr); i = strlen(g.urlPath); if( i>0 && g.urlPath[i-1]=='/' ){ zSep = ""; }else{ zSep = "/"; } blob_appendf(pHdr, "POST %s%sxfer/xfer HTTP/1.0\r\n", g.urlPath, zSep); if( g.urlProxyAuth ){ blob_appendf(pHdr, "Proxy-Authorization: %s\r\n", g.urlProxyAuth); } if( g.urlPasswd && g.urlUser && g.urlPasswd[0]=='#' ){ char *zCredentials = mprintf("%s:%s", g.urlUser, &g.urlPasswd[1]); char *zEncoded = encode64(zCredentials, -1); blob_appendf(pHdr, "Authorization: Basic %s\r\n", zEncoded); fossil_free(zEncoded); fossil_free(zCredentials); } blob_appendf(pHdr, "Host: %s\r\n", g.urlHostname); blob_appendf(pHdr, "User-Agent: %s\r\n", get_user_agent()); if( g.urlIsSsh ) blob_appendf(pHdr, "X-Fossil-Transport: SSH\r\n"); if( g.fHttpTrace ){ blob_appendf(pHdr, "Content-Type: application/x-fossil-debug\r\n"); }else{ blob_appendf(pHdr, "Content-Type: application/x-fossil\r\n"); } blob_appendf(pHdr, "Content-Length: %d\r\n\r\n", blob_size(pPayload)); } /* ** Sign the content in pSend, compress it, and send it to the server ** via HTTP or HTTPS. Get a reply, uncompress the reply, and store the reply ** in pRecv. pRecv is assumed to be uninitialized when ** this routine is called - this routine will initialize it. ** ** The server address is contain in the "g" global structure. The |
︙ | ︙ | |||
211 212 213 214 215 216 217 | int rc = 0; /* Result code */ int iHttpVersion; /* Which version of HTTP protocol server uses */ char *zLine; /* A single line of the reply header */ int i; /* Loop counter */ int isError = 0; /* True if the reply is an error message */ int isCompressed = 1; /* True if the reply is compressed */ | | | | 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 | int rc = 0; /* Result code */ int iHttpVersion; /* Which version of HTTP protocol server uses */ char *zLine; /* A single line of the reply header */ int i; /* Loop counter */ int isError = 0; /* True if the reply is an error message */ int isCompressed = 1; /* True if the reply is compressed */ if( transport_open(GLOBAL_URL()) ){ fossil_warning(transport_errmsg(GLOBAL_URL())); return 1; } /* Construct the login card and prepare the complete payload */ blob_zero(&login); if( useLogin ) http_build_login_card(pSend, &login); if( g.fHttpTrace ){ |
︙ | ︙ | |||
258 259 260 261 262 263 264 | transport_log(out); free(zOutFile); } /* ** Send the request to the server. */ | | | | | < < < < < < < < < < | | 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 | transport_log(out); free(zOutFile); } /* ** Send the request to the server. */ transport_send(GLOBAL_URL(), &hdr); transport_send(GLOBAL_URL(), &payload); blob_reset(&hdr); blob_reset(&payload); transport_flip(GLOBAL_URL()); /* ** Read and interpret the server reply */ closeConnection = 1; iLength = -1; while( (zLine = transport_receive_line(GLOBAL_URL()))!=0 && zLine[0]!=0 ){ /* printf("[%s]\n", zLine); fflush(stdout); */ if( fossil_strnicmp(zLine, "http/1.", 7)==0 ){ if( sscanf(zLine, "HTTP/1.%d %d", &iHttpVersion, &rc)!=2 ) goto write_err; if( rc!=200 && rc!=302 ){ int ii; for(ii=7; zLine[ii] && zLine[ii]!=' '; ii++){} while( zLine[ii]==' ' ) ii++; fossil_warning("server says: %s", &zLine[ii]); goto write_err; } if( iHttpVersion==0 ){ closeConnection = 1; }else{ closeConnection = 0; } }else if( g.urlIsSsh && fossil_strnicmp(zLine, "status:", 7)==0 ){ if( sscanf(zLine, "Status: %d", &rc)!=1 ) goto write_err; if( rc!=200 && rc!=302 ){ int ii; for(ii=7; zLine[ii] && zLine[ii]!=' '; ii++){} while( zLine[ii]==' ' ) ii++; fossil_warning("server says: %s", &zLine[ii]); goto write_err; |
︙ | ︙ | |||
332 333 334 335 336 337 338 | j = strlen(zLine) - 1; while( j>4 && fossil_strcmp(&zLine[j-4],"/xfer")==0 ){ j -= 4; zLine[j] = 0; } fossil_print("redirect to %s\n", &zLine[i]); url_parse(&zLine[i], 0); | < < < | | 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 | j = strlen(zLine) - 1; while( j>4 && fossil_strcmp(&zLine[j-4],"/xfer")==0 ){ j -= 4; zLine[j] = 0; } fossil_print("redirect to %s\n", &zLine[i]); url_parse(&zLine[i], 0); transport_close(GLOBAL_URL()); return http_exchange(pSend, pReply, useLogin, maxRedirect); }else if( fossil_strnicmp(zLine, "content-type: ", 14)==0 ){ if( fossil_strnicmp(&zLine[14], "application/x-fossil-debug", -1)==0 ){ isCompressed = 0; }else if( fossil_strnicmp(&zLine[14], "application/x-fossil-uncompressed", -1)==0 ){ isCompressed = 0; |
︙ | ︙ | |||
362 363 364 365 366 367 368 | } /* ** Extract the reply payload that follows the header */ blob_zero(pReply); blob_resize(pReply, iLength); | | | 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 | } /* ** Extract the reply payload that follows the header */ blob_zero(pReply); blob_resize(pReply, iLength); iLength = transport_receive(GLOBAL_URL(), blob_buffer(pReply), iLength); blob_resize(pReply, iLength); if( isError ){ char *z; int i, j; z = blob_str(pReply); for(i=j=0; z[i]; i++, j++){ if( z[i]=='<' ){ |
︙ | ︙ | |||
389 390 391 392 393 394 395 | ** ** FIXME: There is some bug in the lower layers that prevents the ** connection from remaining open. The easiest fix for now is to ** simply close and restart the connection for each round-trip. ** ** For SSH we will leave the connection open. */ | | | | | | 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 | ** ** FIXME: There is some bug in the lower layers that prevents the ** connection from remaining open. The easiest fix for now is to ** simply close and restart the connection for each round-trip. ** ** For SSH we will leave the connection open. */ if( ! g.urlIsSsh ) closeConnection = 1; /* FIX ME */ if( closeConnection ){ transport_close(GLOBAL_URL()); }else{ transport_rewind(GLOBAL_URL()); } return 0; /* ** Jump to here if an error is seen. */ write_err: transport_close(GLOBAL_URL()); return 1; } |
Changes to src/http_socket.c.
︙ | ︙ | |||
122 123 124 125 126 127 128 | #endif iSocket = -1; } } /* ** Open a socket connection. The identify of the server is determined | | | | | 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 | #endif iSocket = -1; } } /* ** Open a socket connection. The identify of the server is determined ** by global variables that are set using url_parse(): ** ** g.urlName Name of the server. Ex: www.fossil-scm.org ** g.urlPort TCP/IP port to use. Ex: 80 ** ** Return the number of errors. */ int socket_open(UrlData *pUrlData){ static struct sockaddr_in addr; /* The server address */ static int addrIsInit = 0; /* True once addr is initialized */ |
︙ | ︙ | |||
210 211 212 213 214 215 216 | N -= (size_t)got; pContent = (void*)&((char*)pContent)[got]; } return total; } /* | | | | < | 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 | N -= (size_t)got; pContent = (void*)&((char*)pContent)[got]; } return total; } /* ** Attempt to resolve g.urlName to IP and setup g.zIpAddr so rcvfrom gets ** populated. For hostnames with more than one IP (or if overridden in ** ~/.ssh/config) the rcvfrom may not match the host to which we connect. */ void socket_ssh_resolve_addr(UrlData *pUrlData){ struct hostent *pHost; /* Used to make best effort for rcvfrom */ struct sockaddr_in addr; memset(&addr, 0, sizeof(addr)); pHost = gethostbyname(pUrlData->name); if( pHost!=0 ){ memcpy(&addr.sin_addr,pHost->h_addr_list[0],pHost->h_length); g.zIpAddr = mprintf("%s", inet_ntoa(addr.sin_addr)); } } |
Changes to src/http_ssl.c.
︙ | ︙ | |||
172 173 174 175 176 177 178 | void ssl_close(void){ if( iBio!=NULL ){ (void)BIO_reset(iBio); BIO_free_all(iBio); } } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < > | | | 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 | void ssl_close(void){ if( iBio!=NULL ){ (void)BIO_reset(iBio); BIO_free_all(iBio); } } /* ** Open an SSL connection. The identify of the server is determined ** by global variables that are set using url_parse(): ** ** g.urlName Name of the server. Ex: www.fossil-scm.org ** g.urlPort TCP/IP port to use. Ex: 80 ** ** Return the number of errors. */ int ssl_open(UrlData *pUrlData){ X509 *cert; int hasSavedCertificate = 0; int trusted = 0; |
︙ | ︙ | |||
247 248 249 250 251 252 253 | cert = ssl_get_certificate(pUrlData, &trusted); if ( cert!=NULL ){ X509_STORE_add_cert(SSL_CTX_get_cert_store(sslCtx), cert); X509_free(cert); hasSavedCertificate = 1; } | < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < | > > > > | | | | > | | | > | | < | < | 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 | cert = ssl_get_certificate(pUrlData, &trusted); if ( cert!=NULL ){ X509_STORE_add_cert(SSL_CTX_get_cert_store(sslCtx), cert); X509_free(cert); hasSavedCertificate = 1; } iBio = BIO_new_ssl_connect(sslCtx); BIO_get_ssl(iBio, &ssl); #if (SSLEAY_VERSION_NUMBER >= 0x00908070) && !defined(OPENSSL_NO_TLSEXT) if( !SSL_set_tlsext_host_name(ssl, pUrlData->name) ){ fossil_warning("WARNING: failed to set server name indication (SNI), " "continuing without it.\n"); } #endif SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY); if( iBio==NULL ) { ssl_set_errmsg("SSL: cannot open SSL (%s)", ERR_reason_error_string(ERR_get_error())); return 1; } BIO_set_conn_hostname(iBio, pUrlData->name); BIO_set_conn_int_port(iBio, &pUrlData->port); if( BIO_do_connect(iBio)<=0 ){ ssl_set_errmsg("SSL: cannot connect to host %s:%d (%s)", pUrlData->name, pUrlData->port, ERR_reason_error_string(ERR_get_error())); ssl_close(); return 1; } if( BIO_do_handshake(iBio)<=0 ) { ssl_set_errmsg("Error establishing SSL connection %s:%d (%s)", pUrlData->name, pUrlData->port, ERR_reason_error_string(ERR_get_error())); ssl_close(); return 1; } /* Check if certificate is valid */ cert = SSL_get_peer_certificate(ssl); |
︙ | ︙ | |||
355 356 357 358 359 360 361 | "SHA1 fingerprint above\n" " * use the global ssl-ca-location setting to specify your CA root\n" " certificates list\n\n" "If you are not expecting this message, answer no and " "contact your server\nadministrator.\n\n" "Accept certificate for host %s (a=always/y/N)? ", X509_verify_cert_error_string(e), desc, warning, | | | 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 | "SHA1 fingerprint above\n" " * use the global ssl-ca-location setting to specify your CA root\n" " certificates list\n\n" "If you are not expecting this message, answer no and " "contact your server\nadministrator.\n\n" "Accept certificate for host %s (a=always/y/N)? ", X509_verify_cert_error_string(e), desc, warning, pUrlData->name); BIO_free(mem); prompt_user(prompt, &ans); free(prompt); cReply = blob_str(&ans)[0]; blob_reset(&ans); if( cReply!='y' && cReply!='Y' && cReply!='a' && cReply!='A') { |
︙ | ︙ | |||
405 406 407 408 409 410 411 | BIO *mem; char *zCert, *zHost; mem = BIO_new(BIO_s_mem()); PEM_write_bio_X509(mem, cert); BIO_write(mem, "", 1); /* nul-terminate mem buffer */ BIO_get_mem_data(mem, &zCert); | | | | | < | < | 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 | BIO *mem; char *zCert, *zHost; mem = BIO_new(BIO_s_mem()); PEM_write_bio_X509(mem, cert); BIO_write(mem, "", 1); /* nul-terminate mem buffer */ BIO_get_mem_data(mem, &zCert); zHost = mprintf("cert:%s", pUrlData->name); db_set(zHost, zCert, 1); free(zHost); zHost = mprintf("trusted:%s", pUrlData->name); db_set_int(zHost, trusted, 1); free(zHost); BIO_free(mem); } /* ** Get certificate for g.urlName from global config. ** Return NULL if no certificate found. */ X509 *ssl_get_certificate(UrlData *pUrlData, int *pTrusted){ char *zHost, *zCert; BIO *mem; X509 *cert; zHost = mprintf("cert:%s", pUrlData->name); zCert = db_get(zHost, NULL); free(zHost); if ( zCert==NULL ) return NULL; if ( pTrusted!=0 ){ zHost = mprintf("trusted:%s", pUrlData->name); *pTrusted = db_get_int(zHost, 0); free(zHost); } mem = BIO_new(BIO_s_mem()); BIO_puts(mem, zCert); cert = PEM_read_bio_X509(mem, NULL, 0, NULL); |
︙ | ︙ |
Changes to src/http_transport.c.
︙ | ︙ | |||
136 137 138 139 140 141 142 | } blob_reset(&zCmd); return sshPid==0; } /* ** Open a connection to the server. The server is defined by the following | | | | | | 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 | } blob_reset(&zCmd); return sshPid==0; } /* ** Open a connection to the server. The server is defined by the following ** global variables: ** ** g.urlName Name of the server. Ex: www.fossil-scm.org ** g.urlPort TCP/IP port. Ex: 80 ** g.urlIsHttps Use TLS for the connection ** ** Return the number of errors. */ int transport_open(UrlData *pUrlData){ int rc = 0; if( transport.isOpen==0 ){ if( pUrlData->isSsh ){ |
︙ | ︙ |
Changes to src/import.c.
︙ | ︙ | |||
573 574 575 576 577 578 579 | if( memcmp(zLine, "mark ", 5)==0 ){ trim_newline(&zLine[5]); fossil_free(gg.zMark); gg.zMark = fossil_strdup(&zLine[5]); }else if( memcmp(zLine, "tagger ", 7)==0 || memcmp(zLine, "committer ",10)==0 ){ sqlite3_int64 secSince1970; | < < < < < < < < < < < < < < < | 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 | if( memcmp(zLine, "mark ", 5)==0 ){ trim_newline(&zLine[5]); fossil_free(gg.zMark); gg.zMark = fossil_strdup(&zLine[5]); }else if( memcmp(zLine, "tagger ", 7)==0 || memcmp(zLine, "committer ",10)==0 ){ sqlite3_int64 secSince1970; for(i=0; zLine[i] && zLine[i]!='<'; i++){} if( zLine[i]==0 ) goto malformed_line; z = &zLine[i+1]; for(i=i+1; zLine[i] && zLine[i]!='>'; i++){} if( zLine[i]==0 ) goto malformed_line; zLine[i] = 0; fossil_free(gg.zUser); gg.zUser = fossil_strdup(z); secSince1970 = 0; for(i=i+2; fossil_isdigit(zLine[i]); i++){ secSince1970 = secSince1970*10 + zLine[i] - '0'; } fossil_free(gg.zDate); gg.zDate = db_text(0, "SELECT datetime(%lld, 'unixepoch')", secSince1970); gg.zDate[10] = 'T'; }else if( memcmp(zLine, "from ", 5)==0 ){ trim_newline(&zLine[5]); fossil_free(gg.zFromMark); |
︙ | ︙ |
Changes to src/info.c.
︙ | ︙ | |||
107 108 109 110 111 112 113 | db_column_int(&q, 1) ); fossil_print("%-13s %s %s\n", zType, zUuid, zDate); free(zDate); } db_finalize(&q); } | < < < < < < < < < < < < < < < < | 107 108 109 110 111 112 113 114 115 116 117 118 119 120 | db_column_int(&q, 1) ); fossil_print("%-13s %s %s\n", zType, zUuid, zDate); free(zDate); } db_finalize(&q); } zTags = info_tags_of_checkin(rid, 0); if( zTags && zTags[0] ){ fossil_print("tags: %s\n", zTags); } free(zTags); if( zComment ){ fossil_print("comment: "); |
︙ | ︙ | |||
397 398 399 400 401 402 403 | @ <p>Added %z(href("%R/finfo?name=%T",zName))%h(zName)</a> @ version %z(href("%R/artifact/%s",zNew))[%S(zNew)]</a> } if( diffFlags ){ append_diff(zOld, zNew, diffFlags, pRe); }else if( zOld && zNew && fossil_strcmp(zOld,zNew)!=0 ){ @ | | | 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 | @ <p>Added %z(href("%R/finfo?name=%T",zName))%h(zName)</a> @ version %z(href("%R/artifact/%s",zNew))[%S(zNew)]</a> } if( diffFlags ){ append_diff(zOld, zNew, diffFlags, pRe); }else if( zOld && zNew && fossil_strcmp(zOld,zNew)!=0 ){ @ @ %z(href("%R/fdiff?v1=%S&v2=%S&sbs=1",zOld,zNew))[diff]</a> } } } /* ** Generate javascript to enhance HTML diffs. */ |
︙ | ︙ | |||
441 442 443 444 445 446 447 | } /* ** Construct an appropriate diffFlag for text_diff() based on query ** parameters and the to boolean arguments. */ u64 construct_diff_flags(int verboseFlag, int sideBySide){ | | | > > | | > | < < | < > | 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 | } /* ** Construct an appropriate diffFlag for text_diff() based on query ** parameters and the to boolean arguments. */ u64 construct_diff_flags(int verboseFlag, int sideBySide){ u64 diffFlags; if( verboseFlag==0 ){ diffFlags = 0; /* Zero means do not show any diff */ }else{ int x; if( sideBySide ){ diffFlags = DIFF_SIDEBYSIDE | DIFF_IGNORE_EOLWS; /* "dw" query parameter determines width of each column */ x = atoi(PD("dw","80"))*(DIFF_CONTEXT_MASK+1); if( x<0 || x>DIFF_WIDTH_MASK ) x = DIFF_WIDTH_MASK; diffFlags += x; }else{ diffFlags = DIFF_INLINE | DIFF_IGNORE_EOLWS; } /* "dc" query parameter determines lines of context */ x = atoi(PD("dc","7")); if( x<0 || x>DIFF_CONTEXT_MASK ) x = DIFF_CONTEXT_MASK; diffFlags += x; /* The "noopt" parameter disables diff optimization */ if( PD("noopt",0)!=0 ) diffFlags |= DIFF_NOOPT; } return diffFlags; } /* ** WEBPAGE: vinfo ** WEBPAGE: ci ** URL: /ci?name=RID|ARTIFACTID ** ** Display information about a particular check-in. |
︙ | ︙ | |||
495 496 497 498 499 500 501 | int sideBySide; /* True for side-by-side diffs */ u64 diffFlags; /* Flag parameter for text_diff() */ const char *zName; /* Name of the checkin to be displayed */ const char *zUuid; /* UUID of zName */ const char *zParent; /* UUID of the parent checkin (if any) */ const char *zRe; /* regex parameter */ ReCompiled *pRe = 0; /* regex */ | < < < | 480 481 482 483 484 485 486 487 488 489 490 491 492 493 | int sideBySide; /* True for side-by-side diffs */ u64 diffFlags; /* Flag parameter for text_diff() */ const char *zName; /* Name of the checkin to be displayed */ const char *zUuid; /* UUID of zName */ const char *zParent; /* UUID of the parent checkin (if any) */ const char *zRe; /* regex parameter */ ReCompiled *pRe = 0; /* regex */ login_check_credentials(); if( !g.perm.Read ){ login_needed(); return; } zName = P("name"); rid = name_to_rid_www("name"); if( rid==0 ){ style_header("Check-in Information Error"); |
︙ | ︙ | |||
610 611 612 613 614 615 616 | zPJ = blob_str(&projName); for(jj=0; zPJ[jj]; jj++){ if( (zPJ[jj]>0 && zPJ[jj]<' ') || strchr("\"*/:<>?\\|", zPJ[jj]) ){ zPJ[jj] = '_'; } } @ <tr><th>Timelines:</th><td> | | | | | | 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 | zPJ = blob_str(&projName); for(jj=0; zPJ[jj]; jj++){ if( (zPJ[jj]>0 && zPJ[jj]<' ') || strchr("\"*/:<>?\\|", zPJ[jj]) ){ zPJ[jj] = '_'; } } @ <tr><th>Timelines:</th><td> @ %z(href("%R/timeline?f=%S&unhide",zUuid))family</a> if( zParent ){ @ | %z(href("%R/timeline?p=%S&unhide",zUuid))ancestors</a> } if( !isLeaf ){ @ | %z(href("%R/timeline?d=%S&unhide",zUuid))descendants</a> } if( zParent && !isLeaf ){ @ | %z(href("%R/timeline?dp=%S&unhide",zUuid))both</a> } db_prepare(&q2,"SELECT substr(tag.tagname,5) FROM tagxref, tag " " WHERE rid=%d AND tagtype>0 " " AND tag.tagid=tagxref.tagid " " AND +tag.tagname GLOB 'sym-*'", rid); while( db_step(&q2)==SQLITE_ROW ){ const char *zTagName = db_column_text(&q2, 0); |
︙ | ︙ | |||
645 646 647 648 649 650 651 | @ | %z(href("%R/zip/%t-%S.zip?uuid=%s",zPJ,zUuid,zUuid)) @ ZIP archive</a> fossil_free(zUrl); } @ </td></tr> @ <tr><th>Other Links:</th> @ <td> | | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < > > > > > > | | > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > | | | | | | | | | | | | | | | | | | > | | | | | | | | | > | 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 | @ | %z(href("%R/zip/%t-%S.zip?uuid=%s",zPJ,zUuid,zUuid)) @ ZIP archive</a> fossil_free(zUrl); } @ </td></tr> @ <tr><th>Other Links:</th> @ <td> @ %z(href("%R/tree?ci=%S",zUuid))files</a> @ | %z(href("%R/fileage?name=%S",zUuid))file ages</a> @ | %z(href("%R/tree?ci=%S&nofiles",zUuid))folders</a> @ | %z(href("%R/artifact/%S",zUuid))manifest</a> if( g.perm.Write ){ @ | %z(href("%R/ci_edit?r=%S",zUuid))edit</a> } @ </td> @ </tr> blob_reset(&projName); } @ </table> }else{ style_header("Check-in Information"); login_anonymous_available(); } db_finalize(&q1); showTags(rid, ""); if( zParent ){ @ <div class="section">Changes</div> @ <div class="sectionmenu"> verboseFlag = g.zPath[0]!='c'; if( db_get_boolean("show-version-diffs", 0)==0 ){ verboseFlag = !verboseFlag; if( verboseFlag ){ @ %z(xhref("class='button'","%R/vinfo/%T",zName)) @ hide diffs</a> if( sideBySide ){ @ %z(xhref("class='button'","%R/ci/%T?sbs=0",zName)) @ unified diffs</a> }else{ @ %z(xhref("class='button'","%R/ci/%T?sbs=1",zName)) @ side-by-side diffs</a> } }else{ @ %z(xhref("class='button'","%R/ci/%T?sbs=0",zName)) @ show unified diffs</a> @ %z(xhref("class='button'","%R/ci/%T?sbs=1",zName)) @ show side-by-side diffs</a> } }else{ if( verboseFlag ){ @ %z(xhref("class='button'","%R/ci/%T",zName))hide diffs</a> if( sideBySide ){ @ %z(xhref("class='button'","%R/info/%T?sbs=0",zName)) @ unified diffs</a> }else{ @ %z(xhref("class='button'","%R/info/%T?sbs=1",zName)) @ side-by-side diffs</a> } }else{ @ %z(xhref("class='button'","%R/vinfo/%T?sbs=0",zName)) @ show unified diffs</a> @ %z(xhref("class='button'","%R/vinfo/%T?sbs=1",zName)) @ show side-by-side diffs</a> } } @ %z(xhref("class='button'","%R/vpatch?from=%S&to=%S",zParent,zUuid)) @ patch</a></div> if( pRe ){ @ <p><b>Only differences that match regular expression "%h(zRe)" @ are shown.</b></p> } db_prepare(&q3, "SELECT name," " mperm," " (SELECT uuid FROM blob WHERE rid=mlink.pid)," " (SELECT uuid FROM blob WHERE rid=mlink.fid)," " (SELECT name FROM filename WHERE filename.fnid=mlink.pfnid)" " FROM mlink JOIN filename ON filename.fnid=mlink.fnid" " WHERE mlink.mid=%d" " AND (mlink.fid>0" " OR mlink.fnid NOT IN (SELECT pfnid FROM mlink WHERE mid=%d))" " ORDER BY name /*sort*/", rid, rid ); diffFlags = construct_diff_flags(verboseFlag, sideBySide); while( db_step(&q3)==SQLITE_ROW ){ const char *zName = db_column_text(&q3,0); int mperm = db_column_int(&q3, 1); const char *zOld = db_column_text(&q3,2); const char *zNew = db_column_text(&q3,3); const char *zOldName = db_column_text(&q3, 4); append_file_change_line(zName, zOld, zNew, zOldName, diffFlags,pRe,mperm); } db_finalize(&q3); } append_diff_javascript(sideBySide); style_footer(); } /* ** WEBPAGE: winfo ** URL: /winfo?name=UUID |
︙ | ︙ | |||
768 769 770 771 772 773 774 | if( strcmp(zModAction,"approve")==0 ){ moderation_approve(rid); } } style_header("Update of \"%h\"", pWiki->zWikiTitle); zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); zDate = db_text(0, "SELECT datetime(%.17g)", pWiki->rDate); | | | 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 | if( strcmp(zModAction,"approve")==0 ){ moderation_approve(rid); } } style_header("Update of \"%h\"", pWiki->zWikiTitle); zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); zDate = db_text(0, "SELECT datetime(%.17g)", pWiki->rDate); style_submenu_element("Raw", "Raw", "artifact/%S", zUuid); style_submenu_element("History", "History", "whistory?name=%t", pWiki->zWikiTitle); style_submenu_element("Page", "Page", "wiki?name=%t", pWiki->zWikiTitle); login_anonymous_available(); @ <div class="section">Overview</div> @ <p><table class="label-value"> |
︙ | ︙ | |||
796 797 798 799 800 801 802 | @ <tr><th>Original User:</th><td> hyperlink_to_user(pWiki->zUser, zDate, "</td></tr>"); if( pWiki->nParent>0 ){ int i; @ <tr><th>Parent%s(pWiki->nParent==1?"":"s"):</th><td> for(i=0; i<pWiki->nParent; i++){ char *zParent = pWiki->azParent[i]; | | | 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 | @ <tr><th>Original User:</th><td> hyperlink_to_user(pWiki->zUser, zDate, "</td></tr>"); if( pWiki->nParent>0 ){ int i; @ <tr><th>Parent%s(pWiki->nParent==1?"":"s"):</th><td> for(i=0; i<pWiki->nParent; i++){ char *zParent = pWiki->azParent[i]; @ %z(href("info/%S",zParent))%s(zParent)</a> } @ </td></tr> } @ </table> if( g.perm.ModWiki && modPending ){ @ <div class="section">Moderation</div> |
︙ | ︙ | |||
928 929 930 931 932 933 934 | /* ** WEBPAGE: vdiff ** URL: /vdiff ** ** Query parameters: ** | | | | | | < < < > > | 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 | /* ** WEBPAGE: vdiff ** URL: /vdiff ** ** Query parameters: ** ** from=TAG ** to=TAG ** branch=TAG ** v=BOOLEAN ** sbs=BOOLEAN ** ** ** Show all differences between two checkins. */ void vdiff_page(void){ int ridFrom, ridTo; int verboseFlag = 0; int sideBySide = 0; u64 diffFlags = 0; Manifest *pFrom, *pTo; ManifestFile *pFileFrom, *pFileTo; const char *zBranch; const char *zFrom; const char *zTo; const char *zRe; const char *zVerbose; ReCompiled *pRe = 0; login_check_credentials(); if( !g.perm.Read ){ login_needed(); return; } login_anonymous_available(); zRe = P("regex"); if( zRe ) re_compile(&pRe, zRe, 0); zBranch = P("branch"); if( zBranch && zBranch[0] ){ cgi_replace_parameter("from", mprintf("root:%s", zBranch)); cgi_replace_parameter("to", zBranch); } |
︙ | ︙ | |||
977 978 979 980 981 982 983 | zVerbose = P("verbose"); } if( !zVerbose ){ zVerbose = P("detail"); /* deprecated */ } verboseFlag = (zVerbose!=0) && !is_false(zVerbose); if( !verboseFlag && sideBySide ) verboseFlag = 1; | < < < < < < | | < | | | < | | < | | < < < < < < < < < < < < < < < < < < < < < < < < < > < | | < < | | | < > < < | | | | < | 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 | zVerbose = P("verbose"); } if( !zVerbose ){ zVerbose = P("detail"); /* deprecated */ } verboseFlag = (zVerbose!=0) && !is_false(zVerbose); if( !verboseFlag && sideBySide ) verboseFlag = 1; zFrom = P("from"); zTo = P("to"); if( sideBySide || verboseFlag ){ style_submenu_element("Hide Diff", "hidediff", "%R/vdiff?from=%T&to=%T&sbs=0", zFrom, zTo); } if( !sideBySide ){ style_submenu_element("Side-by-side Diff", "sbsdiff", "%R/vdiff?from=%T&to=%T&sbs=1", zFrom, zTo); } if( sideBySide || !verboseFlag ) { style_submenu_element("Unified Diff", "udiff", "%R/vdiff?from=%T&to=%T&sbs=0&v", zFrom, zTo); } style_submenu_element("Invert", "invert", "%R/vdiff?from=%T&to=%T&sbs=%d%s", zTo, zFrom, sideBySide, (verboseFlag && !sideBySide)?"&v":""); style_header("Check-in Differences"); @ <h2>Difference From:</h2><blockquote> checkin_description(ridFrom); @ </blockquote><h2>To:</h2><blockquote> checkin_description(ridTo); @ </blockquote> if( pRe ){ @ <p><b>Only differences that match regular expression "%h(zRe)" @ are shown.</b></p> } @<hr /><p> manifest_file_rewind(pFrom); pFileFrom = manifest_file_next(pFrom, 0); manifest_file_rewind(pTo); pFileTo = manifest_file_next(pTo, 0); diffFlags = construct_diff_flags(verboseFlag, sideBySide); while( pFileFrom || pFileTo ){ int cmp; if( pFileFrom==0 ){ cmp = +1; }else if( pFileTo==0 ){ cmp = -1; }else{ cmp = fossil_strcmp(pFileFrom->zName, pFileTo->zName); } if( cmp<0 ){ append_file_change_line(pFileFrom->zName, pFileFrom->zUuid, 0, 0, diffFlags, pRe, 0); pFileFrom = manifest_file_next(pFrom, 0); }else if( cmp>0 ){ append_file_change_line(pFileTo->zName, 0, pFileTo->zUuid, 0, diffFlags, pRe, manifest_file_mperm(pFileTo)); pFileTo = manifest_file_next(pTo, 0); }else if( fossil_strcmp(pFileFrom->zUuid, pFileTo->zUuid)==0 ){ /* No changes */ pFileFrom = manifest_file_next(pFrom, 0); pFileTo = manifest_file_next(pTo, 0); }else{ append_file_change_line(pFileFrom->zName, pFileFrom->zUuid, pFileTo->zUuid, 0, diffFlags, pRe, manifest_file_mperm(pFileTo)); pFileFrom = manifest_file_next(pFrom, 0); pFileTo = manifest_file_next(pTo, 0); } } manifest_destroy(pFrom); manifest_destroy(pTo); append_diff_javascript(sideBySide); |
︙ | ︙ | |||
1186 1187 1188 1189 1190 1191 1192 | hyperlink_to_uuid(zVers); if( zBr && zBr[0] ){ @ on branch %z(href("%R/timeline?r=%T",zBr))%h(zBr)</a> } @ - %!w(zCom) (user: hyperlink_to_user(zUser,zDate,")"); if( g.perm.Hyperlink ){ | | | | | 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 | hyperlink_to_uuid(zVers); if( zBr && zBr[0] ){ @ on branch %z(href("%R/timeline?r=%T",zBr))%h(zBr)</a> } @ - %!w(zCom) (user: hyperlink_to_user(zUser,zDate,")"); if( g.perm.Hyperlink ){ @ %z(href("%R/finfo?name=%T&ci=%S",zName,zVers))[ancestry]</a> @ %z(href("%R/annotate?checkin=%S&filename=%T",zVers,zName)) @ [annotate]</a> @ %z(href("%R/blame?checkin=%S&filename=%T",zVers,zName)) @ [blame]</a> } cnt++; if( pDownloadName && blob_size(pDownloadName)==0 ){ blob_append(pDownloadName, zName, -1); } } |
︙ | ︙ | |||
1300 1301 1302 1303 1304 1305 1306 | @ Also attachment "%h(zFilename)" to }else{ @ Attachment "%h(zFilename)" to } objType |= OBJTYPE_ATTACHMENT; if( strlen(zTarget)==UUID_SIZE && validate16(zTarget,UUID_SIZE) ){ if( g.perm.Hyperlink && g.perm.RdTkt ){ | | | 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 | @ Also attachment "%h(zFilename)" to }else{ @ Attachment "%h(zFilename)" to } objType |= OBJTYPE_ATTACHMENT; if( strlen(zTarget)==UUID_SIZE && validate16(zTarget,UUID_SIZE) ){ if( g.perm.Hyperlink && g.perm.RdTkt ){ @ ticket [%z(href("%R/tktview?name=%S",zTarget))%S(zTarget)</a>] }else{ @ ticket [%S(zTarget)] } }else{ if( g.perm.Hyperlink && g.perm.RdWiki ){ @ wiki page [%z(href("%R/wiki?name=%t",zTarget))%h(zTarget)</a>] }else{ |
︙ | ︙ | |||
1326 1327 1328 1329 1330 1331 1332 | db_finalize(&q); if( cnt==0 ){ @ Control artifact. if( pDownloadName && blob_size(pDownloadName)==0 ){ blob_appendf(pDownloadName, "%.10s.txt", zUuid); } }else if( linkToView && g.perm.Hyperlink ){ | | < | 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 | db_finalize(&q); if( cnt==0 ){ @ Control artifact. if( pDownloadName && blob_size(pDownloadName)==0 ){ blob_appendf(pDownloadName, "%.10s.txt", zUuid); } }else if( linkToView && g.perm.Hyperlink ){ @ %z(href("%R/artifact/%S",zUuid))[view]</a> } return objType; } /* ** WEBPAGE: fdiff ** URL: fdiff?v1=UUID&v2=UUID&patch&sbs=BOOLEAN®ex=REGEX ** ** Two arguments, v1 and v2, identify the files to be diffed. Show the ** difference between the two artifacts. Show diff side by side unless sbs ** is 0. Generate plaintext if "patch" is present. */ void diff_page(void){ int v1, v2; int isPatch; int sideBySide; char *zV1; char *zV2; const char *zRe; ReCompiled *pRe = 0; u64 diffFlags; login_check_credentials(); if( !g.perm.Read ){ login_needed(); return; } v1 = name_to_rid_www("v1"); v2 = name_to_rid_www("v2"); |
︙ | ︙ | |||
1378 1379 1380 1381 1382 1383 1384 | sideBySide = !is_false(PD("sbs","1")); zV1 = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", v1); zV2 = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", v2); diffFlags = construct_diff_flags(1, sideBySide) | DIFF_HTML; style_header("Diff"); | < < < < < < < < < < | | | | | | | | | | 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 | sideBySide = !is_false(PD("sbs","1")); zV1 = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", v1); zV2 = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", v2); diffFlags = construct_diff_flags(1, sideBySide) | DIFF_HTML; style_header("Diff"); style_submenu_element("Patch", "Patch", "%s/fdiff?v1=%T&v2=%T&patch", g.zTop, P("v1"), P("v2")); if( !sideBySide ){ style_submenu_element("Side-by-side Diff", "sbsdiff", "%s/fdiff?v1=%T&v2=%T&sbs=1", g.zTop, P("v1"), P("v2")); }else{ style_submenu_element("Unified Diff", "udiff", "%s/fdiff?v1=%T&v2=%T&sbs=0", g.zTop, P("v1"), P("v2")); } if( P("smhdr")!=0 ){ @ <h2>Differences From Artifact @ %z(href("%R/artifact/%S",zV1))[%S(zV1)]</a> To @ %z(href("%R/artifact/%S",zV2))[%S(zV2)]</a>.</h2> }else{ @ <h2>Differences From @ Artifact %z(href("%R/artifact/%S",zV1))[%S(zV1)]</a>:</h2> object_description(v1, 0, 0); @ <h2>To Artifact %z(href("%R/artifact/%S",zV2))[%S(zV2)]</a>:</h2> object_description(v2, 0, 0); } if( pRe ){ @ <b>Only differences that match regular expression "%h(zRe)" @ are shown.</b> } @ <hr /> |
︙ | ︙ | |||
1439 1440 1441 1442 1443 1444 1445 | Blob content; rid = name_to_rid_www("name"); login_check_credentials(); if( !g.perm.Read ){ login_needed(); return; } if( rid==0 ) fossil_redirect_home(); zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); | | | 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 | Blob content; rid = name_to_rid_www("name"); login_check_credentials(); if( !g.perm.Read ){ login_needed(); return; } if( rid==0 ) fossil_redirect_home(); zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); if( fossil_strcmp(P("name"), zUuid)==0 ){ g.isConst = 1; } free(zUuid); zMime = P("m"); if( zMime==0 ){ char *zFName = db_text(0, "SELECT filename.name FROM mlink, filename" " WHERE mlink.fid=%d" |
︙ | ︙ | |||
1717 1718 1719 1720 1721 1722 1723 | style_submenu_element("Html", "Html", "%s/artifact/%s", g.zTop, zUuid); }else{ renderAsHtml = 1; style_submenu_element("Text", "Text", "%s/artifact/%s?txt=1", g.zTop, zUuid); } | | < | < > | | | 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 | style_submenu_element("Html", "Html", "%s/artifact/%s", g.zTop, zUuid); }else{ renderAsHtml = 1; style_submenu_element("Text", "Text", "%s/artifact/%s?txt=1", g.zTop, zUuid); } }else if( fossil_strcmp(zMime, "text/x-fossil-wiki")==0 ){ if( asText ){ style_submenu_element("Wiki", "Wiki", "%s/artifact/%s", g.zTop, zUuid); }else{ renderAsWiki = 1; style_submenu_element("Text", "Text", "%s/artifact/%s?txt=1", g.zTop, zUuid); } } } if( (objType & (OBJTYPE_WIKI|OBJTYPE_TICKET))!=0 ){ style_submenu_element("Parsed", "Parsed", "%R/info/%s", zUuid); } @ <hr /> content_get(rid, &content); if( renderAsWiki ){ wiki_convert(&content, 0, 0); }else if( renderAsHtml ){ @ <iframe src="%R/raw/%T(blob_str(&downloadName))?name=%s(zUuid)" @ width="100%%" frameborder="0" marginwidth="0" marginheight="0" @ sandbox="allow-same-origin" @ onload="this.height = this.contentDocument.documentElement.scrollHeight;"> @ </iframe> }else{ style_submenu_element("Hex","Hex", "%s/hexdump?name=%s", g.zTop, zUuid); zMime = mimetype_from_content(&content); @ <blockquote> if( zMime==0 ){ const char *zLn = P("ln"); const char *z; blob_to_utf8_no_bom(&content, 0); z = blob_str(&content); if( zLn ){ output_text_with_line_numbers(z, zLn); }else{ @ <pre> @ %h(z) @ </pre> } }else if( strncmp(zMime, "image/", 6)==0 ){ @ <img src="%R/raw/%S(zUuid)?m=%s(zMime)" /> style_submenu_element("Image", "Image", "%R/raw/%S?m=%s", zUuid, zMime); }else{ @ <i>(file is %d(blob_size(&content)) bytes of binary data)</i> } @ </blockquote> } style_footer(); } |
︙ | ︙ | |||
1817 1818 1819 1820 1821 1822 1823 | moderation_approve(rid); } } zTktTitle = db_table_has_column( "ticket", "title" ) ? db_text("(No title)", "SELECT title FROM ticket WHERE tkt_uuid=%Q", zTktName) : 0; style_header("Ticket Change Details"); | | | | | 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 | moderation_approve(rid); } } zTktTitle = db_table_has_column( "ticket", "title" ) ? db_text("(No title)", "SELECT title FROM ticket WHERE tkt_uuid=%Q", zTktName) : 0; style_header("Ticket Change Details"); style_submenu_element("Raw", "Raw", "%R/artifact/%S", zUuid); style_submenu_element("History", "History", "%R/tkthistory/%s", zTktName); style_submenu_element("Page", "Page", "%R/tktview/%t", zTktName); style_submenu_element("Timeline", "Timeline", "%R/tkttimeline/%t", zTktName); if( P("plaintext") ){ style_submenu_element("Formatted", "Formatted", "%R/info/%S", zUuid); }else{ style_submenu_element("Plaintext", "Plaintext", "%R/info/%S?plaintext", zUuid); } @ <div class="section">Overview</div> @ <p><table class="label-value"> @ <tr><th>Artifact ID:</th> @ <td>%z(href("%R/artifact/%s",zUuid))%s(zUuid)</a> if( g.perm.Setup ){ |
︙ | ︙ | |||
2259 2260 2261 2262 2263 2264 2265 | blob_appendf(&ctrl, "T %s%F %s\n", zPrefix, zTag, zUuid); } } db_finalize(&q); if( nChng>0 ){ int nrid; Blob cksum; | | | 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 | blob_appendf(&ctrl, "T %s%F %s\n", zPrefix, zTag, zUuid); } } db_finalize(&q); if( nChng>0 ){ int nrid; Blob cksum; blob_appendf(&ctrl, "U %F\n", g.zLogin); md5sum_blob(&ctrl, &cksum); blob_appendf(&ctrl, "Z %b\n", &cksum); db_begin_transaction(); g.markPrivate = content_is_private(rid); nrid = content_put(&ctrl); manifest_crosslink(nrid, &ctrl, MC_PERMIT_HOOKS); assert( blob_is_reset(&ctrl) ); |
︙ | ︙ | |||
2339 2340 2341 2342 2343 2344 2345 | @ <hr /> blob_reset(&suffix); } @ <p>Make changes to attributes of check-in @ [%z(href("%R/ci/%s",zUuid))%s(zUuid)</a>]:</p> form_begin(0, "%R/ci_edit"); login_insert_csrf_secret(); | | | 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 | @ <hr /> blob_reset(&suffix); } @ <p>Make changes to attributes of check-in @ [%z(href("%R/ci/%s",zUuid))%s(zUuid)</a>]:</p> form_begin(0, "%R/ci_edit"); login_insert_csrf_secret(); @ <div><input type="hidden" name="r" value="%S(zUuid)" /> @ <table border="0" cellspacing="10"> @ <tr><th align="right" valign="top">User:</th> @ <td valign="top"> @ <input type="text" name="u" size="20" value="%h(zNewUser)" /> @ </td></tr> |
︙ | ︙ | |||
2435 2436 2437 2438 2439 2440 2441 | @ <input id="brname" type="text" style="width:15;" name="brname" @ value="%h(zNewBranch)" @ onkeyup="chgbn(this.value.trim(),'%h(zBranchName)')" /></td></tr> if( !fHasHidden ){ @ <tr><th align="right" valign="top">Branch Hiding:</th> @ <td valign="top"> @ <label><input type="checkbox" id="hidebr" name="hide"%s(zHideFlag) /> | | | 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 | @ <input id="brname" type="text" style="width:15;" name="brname" @ value="%h(zNewBranch)" @ onkeyup="chgbn(this.value.trim(),'%h(zBranchName)')" /></td></tr> if( !fHasHidden ){ @ <tr><th align="right" valign="top">Branch Hiding:</th> @ <td valign="top"> @ <label><input type="checkbox" id="hidebr" name="hide"%s(zHideFlag) /> @ Hide branch @ <span style="font-weight:bold" id="hbranch">%h(zBranchName)</span> @ from the timeline starting from this check-in</label> @ </td></tr> } if( !fHasClosed ){ if( is_a_leaf(rid) ){ @ <tr><th align="right" valign="top">Leaf Closure:</th> |
︙ | ︙ |
Changes to src/json.c.
︙ | ︙ | |||
28 29 30 31 32 33 34 | ** Here's how command/page dispatching works: json_page_top() (in HTTP mode) or ** json_cmd_top() (in CLI mode) catch the "json" path/command. Those functions then ** dispatch to a JSON-mode-specific command/page handler with the type fossil_json_f(). ** See the API docs for that typedef (below) for the semantics of the callbacks. ** ** */ | | | | 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | ** Here's how command/page dispatching works: json_page_top() (in HTTP mode) or ** json_cmd_top() (in CLI mode) catch the "json" path/command. Those functions then ** dispatch to a JSON-mode-specific command/page handler with the type fossil_json_f(). ** See the API docs for that typedef (below) for the semantics of the callbacks. ** ** */ #include "config.h" #include "VERSION.h" #include "json.h" #include <assert.h> #include <time.h> #if INTERFACE #include "json_detail.h" /* workaround for apparent enum limitation in makeheaders */ #endif |
︙ | ︙ | |||
1273 1274 1275 1276 1277 1278 1279 | INT(g, xferPanic); INT(g, fullHttpReply); INT(g, xlinkClusterOnly); INT(g, fTimeFormat); INT(g, markPrivate); INT(g, clockSkewSeen); INT(g, isHTTP); | | | | | | | | | | | | | | | | 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 | INT(g, xferPanic); INT(g, fullHttpReply); INT(g, xlinkClusterOnly); INT(g, fTimeFormat); INT(g, markPrivate); INT(g, clockSkewSeen); INT(g, isHTTP); INT(g, urlIsFile); INT(g, urlIsHttps); INT(g, urlIsSsh); INT(g, urlPort); INT(g, urlDfltPort); INT(g, useLocalauth); INT(g, noPswd); INT(g, userUid); INT(g, rcvid); INT(g, okCsrf); INT(g, thTrace); INT(g, isHome); INT(g, nAux); INT(g, allowSymlinks); CSTR(g, zMainDbType); CSTR(g, zConfigDbType); CSTR(g, zLocalRoot); CSTR(g, zPath); CSTR(g, zExtra); CSTR(g, zBaseURL); CSTR(g, zTop); CSTR(g, zContentType); CSTR(g, zErrMsg); CSTR(g, urlName); CSTR(g, urlHostname); CSTR(g, urlProtocol); CSTR(g, urlPath); CSTR(g, urlUser); CSTR(g, urlPasswd); CSTR(g, urlCanonical); CSTR(g, urlProxyAuth); CSTR(g, urlFossil); CSTR(g, zLogin); CSTR(g, zSSLIdentity); CSTR(g, zIpAddr); CSTR(g, zNonce); CSTR(g, zCsrfToken); o = cson_new_object(); |
︙ | ︙ |
Changes to src/json_timeline.c.
︙ | ︙ | |||
64 65 66 67 68 69 70 | } /* ** Create a temporary table suitable for storing timeline data. */ static void json_timeline_temp_table(void){ /* Field order MUST match that from json_timeline_query()!!! */ | | | 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 | } /* ** Create a temporary table suitable for storing timeline data. */ static void json_timeline_temp_table(void){ /* Field order MUST match that from json_timeline_query()!!! */ static const char zSql[] = @ CREATE TEMP TABLE IF NOT EXISTS json_timeline( @ sortId INTEGER PRIMARY KEY, @ rid INTEGER, @ uuid TEXT, @ mtime INTEGER, @ timestampString TEXT, @ comment TEXT, |
︙ | ︙ | |||
107 108 109 110 111 112 113 | @ bgcolor, @ event.type, @ (SELECT group_concat(substr(tagname,5), ',') FROM tag, tagxref @ WHERE tagname GLOB 'sym-*' AND tag.tagid=tagxref.tagid @ AND tagxref.rid=blob.rid AND tagxref.tagtype>0) as tags, @ tagid as tagId, @ brief as brief | | | 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 | @ bgcolor, @ event.type, @ (SELECT group_concat(substr(tagname,5), ',') FROM tag, tagxref @ WHERE tagname GLOB 'sym-*' AND tag.tagid=tagxref.tagid @ AND tagxref.rid=blob.rid AND tagxref.tagtype>0) as tags, @ tagid as tagId, @ brief as brief @ FROM event JOIN blob @ WHERE blob.rid=event.objid ; return zBaseSql; } /* ** Internal helper to append query information if the |
︙ | ︙ | |||
314 315 316 317 318 319 320 | ** flags may optionally be a bitmask of json_get_changed_files flags, ** or 0 for defaults. */ cson_value * json_get_changed_files(int rid, int flags){ cson_value * rowsV = NULL; cson_array * rows = NULL; Stmt q = empty_Stmt; | | | 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 | ** flags may optionally be a bitmask of json_get_changed_files flags, ** or 0 for defaults. */ cson_value * json_get_changed_files(int rid, int flags){ cson_value * rowsV = NULL; cson_array * rows = NULL; Stmt q = empty_Stmt; db_prepare(&q, "SELECT (pid==0) AS isnew," " (fid==0) AS isdel," " (SELECT name FROM filename WHERE fnid=mlink.fnid) AS name," " blob.uuid as uuid," " (SELECT uuid FROM blob WHERE rid=pid) as parent," " blob.size as size" " FROM mlink, blob" |
︙ | ︙ |
Changes to src/json_wiki.c.
︙ | ︙ | |||
540 541 542 543 544 545 546 | goto manifest; } blob_init(&w1, pW1->zWiki, -1); blob_zero(&w2); blob_init(&w2, pW2->zWiki, -1); blob_zero(&d); | | | 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 | goto manifest; } blob_init(&w1, pW1->zWiki, -1); blob_zero(&w2); blob_init(&w2, pW2->zWiki, -1); blob_zero(&d); diffFlags = DIFF_IGNORE_EOLWS | DIFF_INLINE; text_diff(&w2, &w1, &d, 0, diffFlags); blob_reset(&w1); blob_reset(&w2); pay = cson_new_object(); zUuid = json_wiki_get_uuid_for_rid( pW1->rid ); |
︙ | ︙ |
Deleted src/loadctrl.c.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to src/login.c.
︙ | ︙ | |||
39 40 41 42 43 44 45 | ** not really the point. The anonymous login keeps search-engine ** crawlers and site download tools like wget from walking change ** logs and downloading diffs of very version of the archive that ** has ever existed, and things like that. */ #include "config.h" #include "login.h" | | | 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | ** not really the point. The anonymous login keeps search-engine ** crawlers and site download tools like wget from walking change ** logs and downloading diffs of very version of the archive that ** has ever existed, and things like that. */ #include "config.h" #include "login.h" #if defined(_WIN32) # include <windows.h> /* for Sleep */ # if defined(__MINGW32__) || defined(_MSC_VER) # define sleep Sleep /* windows does not have sleep, but Sleep */ # endif #endif #include <time.h> |
︙ | ︙ | |||
110 111 112 113 114 115 116 | }else{ fossil_redirect_home(); } } /* ** The IP address of the client is stored as part of login cookies. | | | | | 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 | }else{ fossil_redirect_home(); } } /* ** The IP address of the client is stored as part of login cookies. ** But some clients are behind firewalls that shift the IP address ** with each HTTP request. To allow such (broken) clients to log in, ** extract just a prefix of the IP address. */ static char *ipPrefix(const char *zIP){ int i, j; static int ip_prefix_terms = -1; if( ip_prefix_terms<0 ){ ip_prefix_terms = db_get_int("ip-prefix-terms",2); } |
︙ | ︙ | |||
342 343 344 345 346 347 348 | ** ** This is a no-op if g.userUid is 0. */ void login_clear_login_data(){ if(!g.userUid){ return; }else{ | | | 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 | ** ** This is a no-op if g.userUid is 0. */ void login_clear_login_data(){ if(!g.userUid){ return; }else{ char const * cookie = login_cookie_name(); /* To logout, change the cookie value to an empty string */ cgi_set_cookie(cookie, "", login_cookie_path(), -86400); db_multi_exec("UPDATE user SET cookie=NULL, ipaddr=NULL, " " cexpire=0 WHERE uid=%d" " AND login NOT IN ('anonymous','nobody'," " 'developer','reader')", g.userUid); |
︙ | ︙ | |||
490 491 492 493 494 495 496 | && (zNew1 = P("n1"))!=0 && (zNew2 = P("n2"))!=0 ){ /* The user requests a password change */ zSha1Pw = sha1_shared_secret(zPasswd, g.zLogin, 0); if( db_int(1, "SELECT 0 FROM user" " WHERE uid=%d" " AND (constant_time_cmp(pw,%Q)=0" | | | | | 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 | && (zNew1 = P("n1"))!=0 && (zNew2 = P("n2"))!=0 ){ /* The user requests a password change */ zSha1Pw = sha1_shared_secret(zPasswd, g.zLogin, 0); if( db_int(1, "SELECT 0 FROM user" " WHERE uid=%d" " AND (constant_time_cmp(pw,%Q)=0" " OR constant_time_cmp(pw,%Q)=0)", g.userUid, zSha1Pw, zPasswd) ){ sleep(1); zErrMsg = @ <p><span class="loginError"> @ You entered an incorrect old password while attempting to change @ your password. Your password is unchanged. @ </span></p> ; }else if( fossil_strcmp(zNew1,zNew2)!=0 ){ zErrMsg = @ <p><span class="loginError"> @ The two copies of your new passwords do not match. @ Your password is unchanged. @ </span></p> ; }else{ char *zNewPw = sha1_shared_secret(zNew1, g.zLogin, 0); |
︙ | ︙ | |||
544 545 546 547 548 549 550 | } if( zUsername!=0 && zPasswd!=0 && zPasswd[0]!=0 ){ /* Attempting to log in as a user other than anonymous. */ uid = login_search_uid(zUsername, zPasswd); if( uid<=0 ){ sleep(1); | | | 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 | } if( zUsername!=0 && zPasswd!=0 && zPasswd[0]!=0 ){ /* Attempting to log in as a user other than anonymous. */ uid = login_search_uid(zUsername, zPasswd); if( uid<=0 ){ sleep(1); zErrMsg = @ <p><span class="loginError"> @ You entered an unknown user or an incorrect password. @ </span></p> ; record_login_attempt(zUsername, zIpAddr, 0); }else{ /* Non-anonymous login is successful. Set a cookie of the form: |
︙ | ︙ | |||
597 598 599 600 601 602 603 | } @ <tr> @ <td></td> @ <td><input type="submit" name="in" value="Login" @ onClick="chngAction(this.form)" /></td> @ </tr> @ </table> | | | 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 | } @ <tr> @ <td></td> @ <td><input type="submit" name="in" value="Login" @ onClick="chngAction(this.form)" /></td> @ </tr> @ </table> @ <script type="text/JavaScript"> @ gebi('u').focus() @ function chngAction(form){ if( g.sslNotAvailable==0 && strncmp(g.zBaseURL,"https:",6)!=0 && db_get_boolean("https-login",0) ){ char *zSSL = mprintf("https:%s", &g.zBaseURL[5]); |
︙ | ︙ | |||
622 623 624 625 626 627 628 | @ <p>To change your login to a different user, enter } @ your user-id and password at the left and press the @ "Login" button. Your user name will be stored in a browser cookie. @ You must configure your web browser to accept cookies in order for @ the login to take.</p> if( db_get_boolean("self-register", 0) ){ | | | 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 | @ <p>To change your login to a different user, enter } @ your user-id and password at the left and press the @ "Login" button. Your user name will be stored in a browser cookie. @ You must configure your web browser to accept cookies in order for @ the login to take.</p> if( db_get_boolean("self-register", 0) ){ @ <p>If you do not have an account, you can @ <a href="%s(g.zTop)/register?g=%T(P("G"))">create one</a>. } if( zAnonPw ){ unsigned int uSeed = captcha_seed(); char const *zDecoded = captcha_decode(uSeed); int bAutoCaptcha = db_get_boolean("auto-captcha", 0); char *zCaptcha = captcha_render(zDecoded); |
︙ | ︙ | |||
674 675 676 677 678 679 680 | @ </form> } style_footer(); } /* ** Attempt to find login credentials for user zLogin on a peer repository | | | | 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 | @ </form> } style_footer(); } /* ** Attempt to find login credentials for user zLogin on a peer repository ** with project code zCode. Transfer those credentials to the local ** repository. ** ** Return true if a transfer was made and false if not. */ static int login_transfer_credentials( const char *zLogin, /* Login we are looking for */ const char *zCode, /* Project code of peer repository */ const char *zHash, /* HASH from login cookie HASH/CODE/LOGIN */ const char *zRemoteAddr /* Request comes from here */ ){ sqlite3 *pOther = 0; /* The other repository */ sqlite3_stmt *pStmt; /* Query against the other repository */ char *zSQL; /* SQL of the query against other repo */ char *zOtherRepo; /* Filename of the other repository */ int rc; /* Result code from SQLite library functions */ int nXfer = 0; /* Number of credentials transferred */ zOtherRepo = db_text(0, "SELECT value FROM config WHERE name='peer-repo-%q'", zCode ); if( zOtherRepo==0 ) return 0; /* No such peer repository */ rc = sqlite3_open_v2( zOtherRepo, &pOther, |
︙ | ︙ | |||
754 755 756 757 758 759 760 | const char *zRemoteAddr /* Abbreviated IP address for valid login */ ){ int uid; if( fossil_strcmp(zLogin, "anonymous")==0 ) return 0; if( fossil_strcmp(zLogin, "nobody")==0 ) return 0; if( fossil_strcmp(zLogin, "developer")==0 ) return 0; if( fossil_strcmp(zLogin, "reader")==0 ) return 0; | | | 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 | const char *zRemoteAddr /* Abbreviated IP address for valid login */ ){ int uid; if( fossil_strcmp(zLogin, "anonymous")==0 ) return 0; if( fossil_strcmp(zLogin, "nobody")==0 ) return 0; if( fossil_strcmp(zLogin, "developer")==0 ) return 0; if( fossil_strcmp(zLogin, "reader")==0 ) return 0; uid = db_int(0, "SELECT uid FROM user" " WHERE login=%Q" " AND ipaddr=%Q" " AND cexpire>julianday('now')" " AND length(cap)>0" " AND length(pw)>0" " AND constant_time_cmp(cookie,%Q)=0", |
︙ | ︙ | |||
794 795 796 797 798 799 800 | /* Only run this check once. */ if( g.userUid!=0 ) return; sqlite3_create_function(g.db, "constant_time_cmp", 2, SQLITE_UTF8, 0, constant_time_cmp_function, 0, 0); /* If the HTTP connection is coming over 127.0.0.1 and if | | | 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 | /* Only run this check once. */ if( g.userUid!=0 ) return; sqlite3_create_function(g.db, "constant_time_cmp", 2, SQLITE_UTF8, 0, constant_time_cmp_function, 0, 0); /* If the HTTP connection is coming over 127.0.0.1 and if ** local login is disabled and if we are using HTTP and not HTTPS, ** then there is no need to check user credentials. ** ** This feature allows the "fossil ui" command to give the user ** full access rights without having to log in. */ zRemoteAddr = ipPrefix(zIpAddr = PD("REMOTE_ADDR","nil")); if( ( fossil_strcmp(zIpAddr, "127.0.0.1")==0 || |
︙ | ︙ | |||
849 850 851 852 853 854 855 | /* Cookies of the form "HASH/TIME/anonymous". The TIME must not be ** too old and the sha1 hash of TIME/IPADDR/SECRET must match HASH. ** SECRET is the "captcha-secret" value in the repository. */ double rTime = atof(zArg); Blob b; blob_zero(&b); | | | | 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 | /* Cookies of the form "HASH/TIME/anonymous". The TIME must not be ** too old and the sha1 hash of TIME/IPADDR/SECRET must match HASH. ** SECRET is the "captcha-secret" value in the repository. */ double rTime = atof(zArg); Blob b; blob_zero(&b); blob_appendf(&b, "%s/%s/%s", zArg, zRemoteAddr, db_get("captcha-secret","")); sha1sum_blob(&b, &b); if( fossil_strcmp(zHash, blob_str(&b))==0 ){ uid = db_int(0, "SELECT uid FROM user WHERE login='anonymous'" " AND length(cap)>0" " AND length(pw)>0" " AND %.17g+0.25>julianday('now')", rTime ); } |
︙ | ︙ | |||
1004 1005 1006 1007 1008 1009 1010 | return; } for(i=0; zCap[i]; i++){ switch( zCap[i] ){ case 's': g.perm.Setup = 1; /* Fall thru into Admin */ case 'a': g.perm.Admin = g.perm.RdTkt = g.perm.WrTkt = g.perm.Zip = g.perm.RdWiki = g.perm.WrWiki = g.perm.NewWiki = | | | 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 | return; } for(i=0; zCap[i]; i++){ switch( zCap[i] ){ case 's': g.perm.Setup = 1; /* Fall thru into Admin */ case 'a': g.perm.Admin = g.perm.RdTkt = g.perm.WrTkt = g.perm.Zip = g.perm.RdWiki = g.perm.WrWiki = g.perm.NewWiki = g.perm.ApndWiki = g.perm.Hyperlink = g.perm.Clone = g.perm.NewTkt = g.perm.Password = g.perm.RdAddr = g.perm.TktFmt = g.perm.Attach = g.perm.ApndTkt = g.perm.ModWiki = g.perm.ModTkt = 1; /* Fall thru into Read/Write */ case 'i': g.perm.Read = g.perm.Write = 1; break; case 'o': g.perm.Read = 1; break; case 'z': g.perm.Zip = 1; break; |
︙ | ︙ | |||
1027 1028 1029 1030 1031 1032 1033 | case 'm': g.perm.ApndWiki = 1; break; case 'f': g.perm.NewWiki = 1; break; case 'l': g.perm.ModWiki = 1; break; case 'e': g.perm.RdAddr = 1; break; case 'r': g.perm.RdTkt = 1; break; case 'n': g.perm.NewTkt = 1; break; | | | | | 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 | case 'm': g.perm.ApndWiki = 1; break; case 'f': g.perm.NewWiki = 1; break; case 'l': g.perm.ModWiki = 1; break; case 'e': g.perm.RdAddr = 1; break; case 'r': g.perm.RdTkt = 1; break; case 'n': g.perm.NewTkt = 1; break; case 'w': g.perm.WrTkt = g.perm.RdTkt = g.perm.NewTkt = g.perm.ApndTkt = 1; break; case 'c': g.perm.ApndTkt = 1; break; case 'q': g.perm.ModTkt = 1; break; case 't': g.perm.TktFmt = 1; break; case 'b': g.perm.Attach = 1; break; case 'x': g.perm.Private = 1; break; /* The "u" privileges is a little different. It recursively ** inherits all privileges of the user named "reader" */ case 'u': { if( (flags & LOGIN_IGNORE_UV)==0 ){ const char *zUser; zUser = db_text("", "SELECT cap FROM user WHERE login='reader'"); login_set_capabilities(zUser, flags | LOGIN_IGNORE_UV); } break; } /* The "v" privileges is a little different. It recursively ** inherits all privileges of the user named "developer" */ case 'v': { if( (flags & LOGIN_IGNORE_UV)==0 ){ const char *zDev; zDev = db_text("", "SELECT cap FROM user WHERE login='developer'"); login_set_capabilities(zDev, flags | LOGIN_IGNORE_UV); } |
︙ | ︙ | |||
1141 1142 1143 1144 1145 1146 1147 | /* Set the capabilities */ login_set_capabilities(zCap, 0); login_anon_once = 1; login_set_anon_nobody_capabilities(); } | < < < < < < < < < < < < < < | 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 | /* Set the capabilities */ login_set_capabilities(zCap, 0); login_anon_once = 1; login_set_anon_nobody_capabilities(); } /* ** Call this routine when the credential check fails. It causes ** a redirect to the "login" page. */ void login_needed(void){ #ifdef FOSSIL_ENABLE_JSON if(g.json.isJsonMode){ |
︙ | ︙ | |||
1375 1376 1377 1378 1379 1380 1381 | Stmt q; /* Query of all peer-* entries in CONFIG */ if( zPrefix==0 ) zPrefix = ""; if( zSuffix==0 ) zSuffix = ""; if( pzErrorMsg ) *pzErrorMsg = 0; zSelfCode = abbreviated_project_code(db_get("project-code", "x")); blob_zero(&err); | | | 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 | Stmt q; /* Query of all peer-* entries in CONFIG */ if( zPrefix==0 ) zPrefix = ""; if( zSuffix==0 ) zSuffix = ""; if( pzErrorMsg ) *pzErrorMsg = 0; zSelfCode = abbreviated_project_code(db_get("project-code", "x")); blob_zero(&err); db_prepare(&q, "SELECT name, value FROM config" " WHERE name GLOB 'peer-repo-*'" " AND name <> 'peer-repo-%q'" " ORDER BY +value", zSelfCode ); while( db_step(&q)==SQLITE_ROW ){ |
︙ | ︙ | |||
1457 1458 1459 1460 1461 1462 1463 | char *zSelfProjCode; /* Our project-code */ char *zSql; /* SQL to run on all peers */ const char *zSelf; /* The ATTACH name of our repository */ *pzErrMsg = 0; /* Default to no errors */ zSelf = db_name("repository"); | | | 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 | char *zSelfProjCode; /* Our project-code */ char *zSql; /* SQL to run on all peers */ const char *zSelf; /* The ATTACH name of our repository */ *pzErrMsg = 0; /* Default to no errors */ zSelf = db_name("repository"); /* Get the full pathname of the other repository */ file_canonical_name(zRepo, &fullName, 0); zRepo = mprintf(blob_str(&fullName)); blob_reset(&fullName); /* Get the full pathname for our repository. Also the project code ** and project name for ourself. */ file_canonical_name(g.zRepositoryName, &fullName, 0); |
︙ | ︙ |
Changes to src/main.c.
︙ | ︙ | |||
14 15 16 17 18 19 20 | ** http://www.hwaci.com/drh/ ** ******************************************************************************* ** ** This module codes the main() procedure that runs first when the ** program is invoked. */ | < | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | ** http://www.hwaci.com/drh/ ** ******************************************************************************* ** ** This module codes the main() procedure that runs first when the ** program is invoked. */ #include "config.h" #include "main.h" #include <string.h> #include <time.h> #include <fcntl.h> #include <sys/types.h> #include <sys/stat.h> |
︙ | ︙ | |||
110 111 112 113 114 115 116 117 118 119 120 | void *xPreEval; /* Optional, called before Tcl_Eval*(). */ void *pPreContext; /* Optional, provided to xPreEval(). */ void *xPostEval; /* Optional, called after Tcl_Eval*(). */ void *pPostContext; /* Optional, provided to xPostEval(). */ }; #endif struct Global { int argc; char **argv; /* Command-line arguments to the program */ char *nameOfExe; /* Full path of executable. */ const char *zErrlog; /* Log errors to this file, if not NULL */ | > > > > > | < | 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 | void *xPreEval; /* Optional, called before Tcl_Eval*(). */ void *pPreContext; /* Optional, provided to xPreEval(). */ void *xPostEval; /* Optional, called after Tcl_Eval*(). */ void *pPostContext; /* Optional, provided to xPostEval(). */ }; #endif /* ** All global variables are in this structure. */ #define GLOBAL_URL() ((UrlData *)(&g.urlIsFile)) struct Global { int argc; char **argv; /* Command-line arguments to the program */ char *nameOfExe; /* Full path of executable. */ const char *zErrlog; /* Log errors to this file, if not NULL */ int isConst; /* True if the output is unchanging */ const char *zVfsName; /* The VFS to use for database connections */ sqlite3 *db; /* The connection to the databases */ sqlite3 *dbConfig; /* Separate connection for global_config table */ int useAttach; /* True if global_config is attached to repository */ const char *zConfigDbName;/* Path of the config database. NULL if not open */ sqlite3_int64 now; /* Seconds since 1970 */ int repositoryOpen; /* True if the main repository database is open */ char *zRepositoryName; /* Name of the repository database */ const char *zMainDbType;/* "configdb", "localdb", or "repository" */ const char *zConfigDbType; /* "configdb", "localdb", or "repository" */ int localOpen; /* True if the local database is open */ char *zLocalRoot; /* The directory holding the local database */ int minPrefix; /* Number of digits needed for a distinct UUID */ int fSqlTrace; /* True if --sqltrace flag is present */ int fSqlStats; /* True if --sqltrace or --sqlstats are present */ int fSqlPrint; /* True if -sqlprint flag is present */ int fQuiet; /* True if -quiet flag is present */ int fHttpTrace; /* Trace outbound HTTP requests */ int fSystemTrace; /* Trace calls to fossil_system(), --systemtrace */ int fSshTrace; /* Trace the SSH setup traffic */ int fSshClient; /* HTTP client flags for SSH client */ char *zSshCmd; /* SSH command string */ int fNoSync; /* Do not do an autosync ever. --nosync */ char *zPath; /* Name of webpage being served */ char *zExtra; /* Extra path information past the webpage name */ |
︙ | ︙ | |||
164 165 166 167 168 169 170 | int *aCommitFile; /* Array of files to be committed */ int markPrivate; /* All new artifacts are private if true */ int clockSkewSeen; /* True if clocks on client and server out of sync */ int wikiFlags; /* Wiki conversion flags applied to %w and %W */ char isHTTP; /* True if server/CGI modes, else assume CLI. */ char javascriptHyperlink; /* If true, set href= using script, not HTML */ Blob httpHeader; /* Complete text of the HTTP request header */ | | < < < < < | | 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 | int *aCommitFile; /* Array of files to be committed */ int markPrivate; /* All new artifacts are private if true */ int clockSkewSeen; /* True if clocks on client and server out of sync */ int wikiFlags; /* Wiki conversion flags applied to %w and %W */ char isHTTP; /* True if server/CGI modes, else assume CLI. */ char javascriptHyperlink; /* If true, set href= using script, not HTML */ Blob httpHeader; /* Complete text of the HTTP request header */ /* ** NOTE: These members MUST be kept in sync with those in the "UrlData" ** structure defined in "url.c". */ int urlIsFile; /* True if a "file:" url */ int urlIsHttps; /* True if a "https:" url */ int urlIsSsh; /* True if an "ssh:" url */ char *urlName; /* Hostname for http: or filename for file: */ char *urlHostname; /* The HOST: parameter on http headers */ char *urlProtocol; /* "http" or "https" */ int urlPort; /* TCP port number for http: or https: */ int urlDfltPort; /* The default port for the given protocol */ char *urlPath; /* Pathname for http: */ char *urlUser; /* User id for http: */ char *urlPasswd; /* Password for http: */ char *urlCanonical; /* Canonical representation of the URL */ char *urlProxyAuth; /* Proxy-Authorizer: string */ char *urlFossil; /* The fossil query parameter on ssh: */ unsigned urlFlags; /* Boolean flags controlling URL processing */ const char *zLogin; /* Login name. "" if not logged in. */ const char *zSSLIdentity; /* Value of --ssl-identity option, filename of ** SSL client identity */ int useLocalauth; /* No login required if from 127.0.0.1 */ int noPswd; /* Logged in without password (on 127.0.0.1) */ int userUid; /* Integer user id */ int isHuman; /* True if access by a human, not a spider or bot */ |
︙ | ︙ | |||
568 569 570 571 572 573 574 | #endif int main(int argc, char **argv) #endif { const char *zCmdName = "unknown"; int idx; int rc; | | | | 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 | #endif int main(int argc, char **argv) #endif { const char *zCmdName = "unknown"; int idx; int rc; if( sqlite3_libversion_number()<3007017 ){ fossil_fatal("Unsuitable SQLite version %s, must be at least 3.7.17", sqlite3_libversion()); } sqlite3_config(SQLITE_CONFIG_SINGLETHREAD); sqlite3_config(SQLITE_CONFIG_LOG, fossil_sqlite_log, 0); memset(&g, 0, sizeof(g)); g.now = time(0); g.httpHeader = empty_blob; |
︙ | ︙ | |||
643 644 645 646 647 648 649 | g.fSystemTrace = find_option("systemtrace", 0, 0)!=0; g.fSshTrace = find_option("sshtrace", 0, 0)!=0; g.fSshClient = 0; g.zSshCmd = 0; if( g.fSqlTrace ) g.fSqlStats = 1; g.fSqlPrint = find_option("sqlprint", 0, 0)!=0; g.fHttpTrace = find_option("httptrace", 0, 0)!=0; | < | 641 642 643 644 645 646 647 648 649 650 651 652 653 654 | g.fSystemTrace = find_option("systemtrace", 0, 0)!=0; g.fSshTrace = find_option("sshtrace", 0, 0)!=0; g.fSshClient = 0; g.zSshCmd = 0; if( g.fSqlTrace ) g.fSqlStats = 1; g.fSqlPrint = find_option("sqlprint", 0, 0)!=0; g.fHttpTrace = find_option("httptrace", 0, 0)!=0; g.zLogin = find_option("user", "U", 1); g.zSSLIdentity = find_option("ssl-identity", 0, 1); g.zErrlog = find_option("errorlog", 0, 1); if( find_option("utc",0,0) ) g.fTimeFormat = 1; if( find_option("localtime",0,0) ) g.fTimeFormat = 2; if( zChdir && file_chdir(zChdir, 0) ){ fossil_fatal("unable to change directories to %s", zChdir); |
︙ | ︙ | |||
1061 1062 1063 1064 1065 1066 1067 | } } if( j>0 ){ @ </ul></td> } @ </tr></table> | | | 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 | } } if( j>0 ){ @ </ul></td> } @ </tr></table> @ <h1>Available pages:</h1> @ (Only pages with help text are linked.) @ <table border="0"><tr> for(i=j=0; i<count(aCommand); i++){ const char *z = aCommand[i].zName; if( '/'!=*z ) continue; j++; } |
︙ | ︙ | |||
1450 1451 1452 1453 1454 1455 1456 | for(jj=0; zAltRepo[jj] && zAltRepo[jj]!=':'; jj++){} if( zAltRepo[jj]==':' ){ zAltRepo[jj] = 0; zAltRepo += jj+1; }else{ zUser = "nobody"; } | | | 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 | for(jj=0; zAltRepo[jj] && zAltRepo[jj]!=':'; jj++){} if( zAltRepo[jj]==':' ){ zAltRepo[jj] = 0; zAltRepo += jj+1; }else{ zUser = "nobody"; } if( g.zLogin==0 ) zUser = "nobody"; if( zAltRepo[0]!='/' ){ zAltRepo = mprintf("%s/../%s", g.zRepositoryName, zAltRepo); file_simplify_name(zAltRepo, -1, 0); } db_close(1); db_open_repository(zAltRepo); login_as_user(zUser); |
︙ | ︙ | |||
1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 | process_one_web_page(zNotFound, glob_create(zFileGlob)); } /* ** Process all requests in a single SSH connection if possible. */ void ssh_request_loop(const char *zIpAddr, Glob *FileGlob){ do{ cgi_handle_ssh_http_request(zIpAddr); process_one_web_page(0, FileGlob); blob_reset(&g.cgiIn); } while ( g.fSshClient & CGI_SSH_FOSSIL || g.fSshClient & CGI_SSH_COMPAT ); } | > | 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 | process_one_web_page(zNotFound, glob_create(zFileGlob)); } /* ** Process all requests in a single SSH connection if possible. */ void ssh_request_loop(const char *zIpAddr, Glob *FileGlob){ blob_zero(&g.cgiIn); do{ cgi_handle_ssh_http_request(zIpAddr); process_one_web_page(0, FileGlob); blob_reset(&g.cgiIn); } while ( g.fSshClient & CGI_SSH_FOSSIL || g.fSshClient & CGI_SSH_COMPAT ); } |
︙ | ︙ |
Changes to src/main.mk.
︙ | ︙ | |||
64 65 66 67 68 69 70 | $(SRCDIR)/json_report.c \ $(SRCDIR)/json_status.c \ $(SRCDIR)/json_tag.c \ $(SRCDIR)/json_timeline.c \ $(SRCDIR)/json_user.c \ $(SRCDIR)/json_wiki.c \ $(SRCDIR)/leaf.c \ | < | 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | $(SRCDIR)/json_report.c \ $(SRCDIR)/json_status.c \ $(SRCDIR)/json_tag.c \ $(SRCDIR)/json_timeline.c \ $(SRCDIR)/json_user.c \ $(SRCDIR)/json_wiki.c \ $(SRCDIR)/leaf.c \ $(SRCDIR)/login.c \ $(SRCDIR)/lookslike.c \ $(SRCDIR)/main.c \ $(SRCDIR)/manifest.c \ $(SRCDIR)/markdown.c \ $(SRCDIR)/markdown_html.c \ $(SRCDIR)/md5.c \ |
︙ | ︙ | |||
175 176 177 178 179 180 181 | $(OBJDIR)/json_report_.c \ $(OBJDIR)/json_status_.c \ $(OBJDIR)/json_tag_.c \ $(OBJDIR)/json_timeline_.c \ $(OBJDIR)/json_user_.c \ $(OBJDIR)/json_wiki_.c \ $(OBJDIR)/leaf_.c \ | < | 174 175 176 177 178 179 180 181 182 183 184 185 186 187 | $(OBJDIR)/json_report_.c \ $(OBJDIR)/json_status_.c \ $(OBJDIR)/json_tag_.c \ $(OBJDIR)/json_timeline_.c \ $(OBJDIR)/json_user_.c \ $(OBJDIR)/json_wiki_.c \ $(OBJDIR)/leaf_.c \ $(OBJDIR)/login_.c \ $(OBJDIR)/lookslike_.c \ $(OBJDIR)/main_.c \ $(OBJDIR)/manifest_.c \ $(OBJDIR)/markdown_.c \ $(OBJDIR)/markdown_html_.c \ $(OBJDIR)/md5_.c \ |
︙ | ︙ | |||
286 287 288 289 290 291 292 | $(OBJDIR)/json_report.o \ $(OBJDIR)/json_status.o \ $(OBJDIR)/json_tag.o \ $(OBJDIR)/json_timeline.o \ $(OBJDIR)/json_user.o \ $(OBJDIR)/json_wiki.o \ $(OBJDIR)/leaf.o \ | < | 284 285 286 287 288 289 290 291 292 293 294 295 296 297 | $(OBJDIR)/json_report.o \ $(OBJDIR)/json_status.o \ $(OBJDIR)/json_tag.o \ $(OBJDIR)/json_timeline.o \ $(OBJDIR)/json_user.o \ $(OBJDIR)/json_wiki.o \ $(OBJDIR)/leaf.o \ $(OBJDIR)/login.o \ $(OBJDIR)/lookslike.o \ $(OBJDIR)/main.o \ $(OBJDIR)/manifest.o \ $(OBJDIR)/markdown.o \ $(OBJDIR)/markdown_html.o \ $(OBJDIR)/md5.o \ |
︙ | ︙ | |||
398 399 400 401 402 403 404 | # to 1. If it is set to 1, then there is no need to build or link # the sqlite3.o object. Instead, the system sqlite will be linked # using -lsqlite3. SQLITE3_OBJ.1 = SQLITE3_OBJ.0 = $(OBJDIR)/sqlite3.o SQLITE3_OBJ. = $(SQLITE3_OBJ.0) | > > > > > > > | | | 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 | # to 1. If it is set to 1, then there is no need to build or link # the sqlite3.o object. Instead, the system sqlite will be linked # using -lsqlite3. SQLITE3_OBJ.1 = SQLITE3_OBJ.0 = $(OBJDIR)/sqlite3.o SQLITE3_OBJ. = $(SQLITE3_OBJ.0) # The FOSSIL_ENABLE_TCL variable may be undefined, set to 0, or set to 1. # If it is set to 1, then we need to build the Tcl integration code and # link to the Tcl library. TCL_OBJ.0 = TCL_OBJ.1 = $(OBJDIR)/th_tcl.o TCL_OBJ. = $(TCL_OBJ.0) EXTRAOBJ = $(SQLITE3_OBJ.$(USE_SYSTEM_SQLITE)) $(OBJDIR)/shell.o $(OBJDIR)/th.o $(OBJDIR)/th_lang.o $(TCL_OBJ.$(FOSSIL_ENABLE_TCL)) $(OBJDIR)/cson_amalgamation.o $(APPNAME): $(OBJDIR)/headers $(OBJ) $(EXTRAOBJ) $(TCC) -o $(APPNAME) $(OBJ) $(EXTRAOBJ) $(LIB) # This rule prevents make from using its default rules to try build # an executable named "manifest" out of the file named "manifest.c" # $(SRCDIR)/../manifest: # noop clean: rm -rf $(OBJDIR)/* $(APPNAME) $(OBJDIR)/page_index.h: $(TRANS_SRC) $(OBJDIR)/mkindex $(OBJDIR)/mkindex $(TRANS_SRC) >$@ $(OBJDIR)/headers: $(OBJDIR)/page_index.h $(OBJDIR)/makeheaders $(OBJDIR)/VERSION.h $(OBJDIR)/makeheaders $(OBJDIR)/add_.c:$(OBJDIR)/add.h $(OBJDIR)/allrepo_.c:$(OBJDIR)/allrepo.h $(OBJDIR)/attach_.c:$(OBJDIR)/attach.h $(OBJDIR)/bag_.c:$(OBJDIR)/bag.h $(OBJDIR)/bisect_.c:$(OBJDIR)/bisect.h $(OBJDIR)/blob_.c:$(OBJDIR)/blob.h $(OBJDIR)/branch_.c:$(OBJDIR)/branch.h $(OBJDIR)/browse_.c:$(OBJDIR)/browse.h $(OBJDIR)/captcha_.c:$(OBJDIR)/captcha.h $(OBJDIR)/cgi_.c:$(OBJDIR)/cgi.h $(OBJDIR)/checkin_.c:$(OBJDIR)/checkin.h $(OBJDIR)/checkout_.c:$(OBJDIR)/checkout.h $(OBJDIR)/clearsign_.c:$(OBJDIR)/clearsign.h $(OBJDIR)/clone_.c:$(OBJDIR)/clone.h $(OBJDIR)/comformat_.c:$(OBJDIR)/comformat.h $(OBJDIR)/configure_.c:$(OBJDIR)/configure.h $(OBJDIR)/content_.c:$(OBJDIR)/content.h $(OBJDIR)/db_.c:$(OBJDIR)/db.h $(OBJDIR)/delta_.c:$(OBJDIR)/delta.h $(OBJDIR)/deltacmd_.c:$(OBJDIR)/deltacmd.h $(OBJDIR)/descendants_.c:$(OBJDIR)/descendants.h $(OBJDIR)/diff_.c:$(OBJDIR)/diff.h $(OBJDIR)/diffcmd_.c:$(OBJDIR)/diffcmd.h $(OBJDIR)/doc_.c:$(OBJDIR)/doc.h $(OBJDIR)/encode_.c:$(OBJDIR)/encode.h $(OBJDIR)/event_.c:$(OBJDIR)/event.h $(OBJDIR)/export_.c:$(OBJDIR)/export.h $(OBJDIR)/file_.c:$(OBJDIR)/file.h $(OBJDIR)/finfo_.c:$(OBJDIR)/finfo.h $(OBJDIR)/glob_.c:$(OBJDIR)/glob.h $(OBJDIR)/graph_.c:$(OBJDIR)/graph.h $(OBJDIR)/gzip_.c:$(OBJDIR)/gzip.h $(OBJDIR)/http_.c:$(OBJDIR)/http.h $(OBJDIR)/http_socket_.c:$(OBJDIR)/http_socket.h $(OBJDIR)/http_ssl_.c:$(OBJDIR)/http_ssl.h $(OBJDIR)/http_transport_.c:$(OBJDIR)/http_transport.h $(OBJDIR)/import_.c:$(OBJDIR)/import.h $(OBJDIR)/info_.c:$(OBJDIR)/info.h $(OBJDIR)/json_.c:$(OBJDIR)/json.h $(OBJDIR)/json_artifact_.c:$(OBJDIR)/json_artifact.h $(OBJDIR)/json_branch_.c:$(OBJDIR)/json_branch.h $(OBJDIR)/json_config_.c:$(OBJDIR)/json_config.h $(OBJDIR)/json_diff_.c:$(OBJDIR)/json_diff.h $(OBJDIR)/json_dir_.c:$(OBJDIR)/json_dir.h $(OBJDIR)/json_finfo_.c:$(OBJDIR)/json_finfo.h $(OBJDIR)/json_login_.c:$(OBJDIR)/json_login.h $(OBJDIR)/json_query_.c:$(OBJDIR)/json_query.h $(OBJDIR)/json_report_.c:$(OBJDIR)/json_report.h $(OBJDIR)/json_status_.c:$(OBJDIR)/json_status.h $(OBJDIR)/json_tag_.c:$(OBJDIR)/json_tag.h $(OBJDIR)/json_timeline_.c:$(OBJDIR)/json_timeline.h $(OBJDIR)/json_user_.c:$(OBJDIR)/json_user.h $(OBJDIR)/json_wiki_.c:$(OBJDIR)/json_wiki.h $(OBJDIR)/leaf_.c:$(OBJDIR)/leaf.h $(OBJDIR)/login_.c:$(OBJDIR)/login.h $(OBJDIR)/lookslike_.c:$(OBJDIR)/lookslike.h $(OBJDIR)/main_.c:$(OBJDIR)/main.h $(OBJDIR)/manifest_.c:$(OBJDIR)/manifest.h $(OBJDIR)/markdown_.c:$(OBJDIR)/markdown.h $(OBJDIR)/markdown_html_.c:$(OBJDIR)/markdown_html.h $(OBJDIR)/md5_.c:$(OBJDIR)/md5.h $(OBJDIR)/merge_.c:$(OBJDIR)/merge.h $(OBJDIR)/merge3_.c:$(OBJDIR)/merge3.h $(OBJDIR)/moderate_.c:$(OBJDIR)/moderate.h $(OBJDIR)/name_.c:$(OBJDIR)/name.h $(OBJDIR)/path_.c:$(OBJDIR)/path.h $(OBJDIR)/pivot_.c:$(OBJDIR)/pivot.h $(OBJDIR)/popen_.c:$(OBJDIR)/popen.h $(OBJDIR)/pqueue_.c:$(OBJDIR)/pqueue.h $(OBJDIR)/printf_.c:$(OBJDIR)/printf.h $(OBJDIR)/rebuild_.c:$(OBJDIR)/rebuild.h $(OBJDIR)/regexp_.c:$(OBJDIR)/regexp.h $(OBJDIR)/report_.c:$(OBJDIR)/report.h $(OBJDIR)/rss_.c:$(OBJDIR)/rss.h $(OBJDIR)/schema_.c:$(OBJDIR)/schema.h $(OBJDIR)/search_.c:$(OBJDIR)/search.h $(OBJDIR)/setup_.c:$(OBJDIR)/setup.h $(OBJDIR)/sha1_.c:$(OBJDIR)/sha1.h $(OBJDIR)/shun_.c:$(OBJDIR)/shun.h $(OBJDIR)/skins_.c:$(OBJDIR)/skins.h $(OBJDIR)/sqlcmd_.c:$(OBJDIR)/sqlcmd.h $(OBJDIR)/stash_.c:$(OBJDIR)/stash.h $(OBJDIR)/stat_.c:$(OBJDIR)/stat.h $(OBJDIR)/style_.c:$(OBJDIR)/style.h $(OBJDIR)/sync_.c:$(OBJDIR)/sync.h $(OBJDIR)/tag_.c:$(OBJDIR)/tag.h $(OBJDIR)/tar_.c:$(OBJDIR)/tar.h $(OBJDIR)/th_main_.c:$(OBJDIR)/th_main.h $(OBJDIR)/timeline_.c:$(OBJDIR)/timeline.h $(OBJDIR)/tkt_.c:$(OBJDIR)/tkt.h $(OBJDIR)/tktsetup_.c:$(OBJDIR)/tktsetup.h $(OBJDIR)/undo_.c:$(OBJDIR)/undo.h $(OBJDIR)/unicode_.c:$(OBJDIR)/unicode.h $(OBJDIR)/update_.c:$(OBJDIR)/update.h $(OBJDIR)/url_.c:$(OBJDIR)/url.h $(OBJDIR)/user_.c:$(OBJDIR)/user.h $(OBJDIR)/utf8_.c:$(OBJDIR)/utf8.h $(OBJDIR)/util_.c:$(OBJDIR)/util.h $(OBJDIR)/verify_.c:$(OBJDIR)/verify.h $(OBJDIR)/vfile_.c:$(OBJDIR)/vfile.h $(OBJDIR)/wiki_.c:$(OBJDIR)/wiki.h $(OBJDIR)/wikiformat_.c:$(OBJDIR)/wikiformat.h $(OBJDIR)/winfile_.c:$(OBJDIR)/winfile.h $(OBJDIR)/winhttp_.c:$(OBJDIR)/winhttp.h $(OBJDIR)/wysiwyg_.c:$(OBJDIR)/wysiwyg.h $(OBJDIR)/xfer_.c:$(OBJDIR)/xfer.h $(OBJDIR)/xfersetup_.c:$(OBJDIR)/xfersetup.h $(OBJDIR)/zip_.c:$(OBJDIR)/zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h $(OBJDIR)/VERSION.h touch $(OBJDIR)/headers $(OBJDIR)/headers: Makefile $(OBJDIR)/json.o $(OBJDIR)/json_artifact.o $(OBJDIR)/json_branch.o $(OBJDIR)/json_config.o $(OBJDIR)/json_diff.o $(OBJDIR)/json_dir.o $(OBJDIR)/json_finfo.o $(OBJDIR)/json_login.o $(OBJDIR)/json_query.o $(OBJDIR)/json_report.o $(OBJDIR)/json_status.o $(OBJDIR)/json_tag.o $(OBJDIR)/json_timeline.o $(OBJDIR)/json_user.o $(OBJDIR)/json_wiki.o : $(SRCDIR)/json_detail.h Makefile: $(OBJDIR)/add_.c: $(SRCDIR)/add.c $(OBJDIR)/translate $(OBJDIR)/translate $(SRCDIR)/add.c >$(OBJDIR)/add_.c |
︙ | ︙ | |||
799 800 801 802 803 804 805 | $(OBJDIR)/leaf_.c: $(SRCDIR)/leaf.c $(OBJDIR)/translate $(OBJDIR)/translate $(SRCDIR)/leaf.c >$(OBJDIR)/leaf_.c $(OBJDIR)/leaf.o: $(OBJDIR)/leaf_.c $(OBJDIR)/leaf.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/leaf.o -c $(OBJDIR)/leaf_.c $(OBJDIR)/leaf.h: $(OBJDIR)/headers | < < < < < < < | 803 804 805 806 807 808 809 810 811 812 813 814 815 816 | $(OBJDIR)/leaf_.c: $(SRCDIR)/leaf.c $(OBJDIR)/translate $(OBJDIR)/translate $(SRCDIR)/leaf.c >$(OBJDIR)/leaf_.c $(OBJDIR)/leaf.o: $(OBJDIR)/leaf_.c $(OBJDIR)/leaf.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/leaf.o -c $(OBJDIR)/leaf_.c $(OBJDIR)/leaf.h: $(OBJDIR)/headers $(OBJDIR)/login_.c: $(SRCDIR)/login.c $(OBJDIR)/translate $(OBJDIR)/translate $(SRCDIR)/login.c >$(OBJDIR)/login_.c $(OBJDIR)/login.o: $(OBJDIR)/login_.c $(OBJDIR)/login.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/login.o -c $(OBJDIR)/login_.c $(OBJDIR)/login.h: $(OBJDIR)/headers |
︙ | ︙ |
Changes to src/makemake.tcl.
︙ | ︙ | |||
67 68 69 70 71 72 73 | json_report json_status json_tag json_timeline json_user json_wiki leaf | < | 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | json_report json_status json_tag json_timeline json_user json_wiki leaf login lookslike main manifest markdown markdown_html md5 |
︙ | ︙ | |||
266 267 268 269 270 271 272 273 274 275 276 277 | # to 1. If it is set to 1, then there is no need to build or link # the sqlite3.o object. Instead, the system sqlite will be linked # using -lsqlite3. SQLITE3_OBJ.1 = SQLITE3_OBJ.0 = $(OBJDIR)/sqlite3.o SQLITE3_OBJ. = $(SQLITE3_OBJ.0) EXTRAOBJ = \ $(SQLITE3_OBJ.$(USE_SYSTEM_SQLITE)) \ $(OBJDIR)/shell.o \ $(OBJDIR)/th.o \ $(OBJDIR)/th_lang.o \ | > > > > > > > | | 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 | # to 1. If it is set to 1, then there is no need to build or link # the sqlite3.o object. Instead, the system sqlite will be linked # using -lsqlite3. SQLITE3_OBJ.1 = SQLITE3_OBJ.0 = $(OBJDIR)/sqlite3.o SQLITE3_OBJ. = $(SQLITE3_OBJ.0) # The FOSSIL_ENABLE_TCL variable may be undefined, set to 0, or set to 1. # If it is set to 1, then we need to build the Tcl integration code and # link to the Tcl library. TCL_OBJ.0 = TCL_OBJ.1 = $(OBJDIR)/th_tcl.o TCL_OBJ. = $(TCL_OBJ.0) EXTRAOBJ = \ $(SQLITE3_OBJ.$(USE_SYSTEM_SQLITE)) \ $(OBJDIR)/shell.o \ $(OBJDIR)/th.o \ $(OBJDIR)/th_lang.o \ $(TCL_OBJ.$(FOSSIL_ENABLE_TCL)) \ $(OBJDIR)/cson_amalgamation.o $(APPNAME): $(OBJDIR)/headers $(OBJ) $(EXTRAOBJ) $(TCC) -o $(APPNAME) $(OBJ) $(EXTRAOBJ) $(LIB) # This rule prevents make from using its default rules to try build # an executable named "manifest" out of the file named "manifest.c" |
︙ | ︙ | |||
715 716 717 718 719 720 721 | $(VERSION) $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION >$(OBJDIR)/VERSION.h EXTRAOBJ = \ $(OBJDIR)/sqlite3.o \ $(OBJDIR)/shell.o \ $(OBJDIR)/th.o \ $(OBJDIR)/th_lang.o \ | < > > > > | 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 | $(VERSION) $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION >$(OBJDIR)/VERSION.h EXTRAOBJ = \ $(OBJDIR)/sqlite3.o \ $(OBJDIR)/shell.o \ $(OBJDIR)/th.o \ $(OBJDIR)/th_lang.o \ $(OBJDIR)/cson_amalgamation.o ifdef FOSSIL_ENABLE_TCL EXTRAOBJ += $(OBJDIR)/th_tcl.o endif zlib: $(MAKE) -C $(ZLIBDIR) PREFIX=$(PREFIX) -f win32/Makefile.gcc libz.a clean-zlib: $(MAKE) -C $(ZLIBDIR) PREFIX=$(PREFIX) -f win32/Makefile.gcc clean |
︙ | ︙ | |||
812 813 814 815 816 817 818 | writeln "\$(OBJDIR)/th.o:\t\$(SRCDIR)/th.c" writeln "\t\$(XTCC) -c \$(SRCDIR)/th.c -o \$(OBJDIR)/th.o\n" writeln "\$(OBJDIR)/th_lang.o:\t\$(SRCDIR)/th_lang.c" writeln "\t\$(XTCC) -c \$(SRCDIR)/th_lang.c -o \$(OBJDIR)/th_lang.o\n" | > | | > | 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 | writeln "\$(OBJDIR)/th.o:\t\$(SRCDIR)/th.c" writeln "\t\$(XTCC) -c \$(SRCDIR)/th.c -o \$(OBJDIR)/th.o\n" writeln "\$(OBJDIR)/th_lang.o:\t\$(SRCDIR)/th_lang.c" writeln "\t\$(XTCC) -c \$(SRCDIR)/th_lang.c -o \$(OBJDIR)/th_lang.o\n" writeln {ifdef FOSSIL_ENABLE_TCL $(OBJDIR)/th_tcl.o: $(SRCDIR)/th_tcl.c $(XTCC) -c $(SRCDIR)/th_tcl.c -o $(OBJDIR)/th_tcl.o endif} close $output_file # # End of the win/Makefile.mingw output ############################################################################## ############################################################################## ############################################################################## |
︙ | ︙ | |||
1006 1007 1008 1009 1010 1011 1012 | # Uncomment to enable JSON API # FOSSIL_ENABLE_JSON = 1 # Uncomment to enable SSL support # FOSSIL_ENABLE_SSL = 1 | < < < < < < < < < | | < < < < | | | | | | | | | | | < < < < < < < < < < < | | | < | > > | 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 | # Uncomment to enable JSON API # FOSSIL_ENABLE_JSON = 1 # Uncomment to enable SSL support # FOSSIL_ENABLE_SSL = 1 !ifdef FOSSIL_ENABLE_SSL SSLINCDIR = $(B)\compat\openssl-1.0.1g\include SSLLIBDIR = $(B)\compat\openssl-1.0.1g\out32 SSLLIB = ssleay32.lib libeay32.lib user32.lib gdi32.lib !endif # zlib options ZINCDIR = $(B)\compat\zlib ZLIBDIR = $(B)\compat\zlib ZLIB = zlib.lib INCL = -I. -I$(SRCDIR) -I$B\win\include -I$(ZINCDIR) !ifdef FOSSIL_ENABLE_SSL INCL = $(INCL) -I$(SSLINCDIR) !endif CFLAGS = -nologo LDFLAGS = /NODEFAULTLIB:msvcrt /MANIFEST:NO !ifdef DEBUG CFLAGS = $(CFLAGS) -Zi -MTd -Od LDFLAGS = $(LDFLAGS) /DEBUG !else CFLAGS = $(CFLAGS) -MT -O2 !endif BCC = $(CC) $(CFLAGS) TCC = $(CC) -c $(CFLAGS) $(MSCDEF) $(INCL) RCC = rc -D_WIN32 -D_MSC_VER $(MSCDEF) $(INCL) LIBS = $(ZLIB) ws2_32.lib advapi32.lib LIBDIR = -LIBPATH:$(ZLIBDIR) !ifdef FOSSIL_ENABLE_JSON TCC = $(TCC) -DFOSSIL_ENABLE_JSON=1 RCC = $(RCC) -DFOSSIL_ENABLE_JSON=1 !endif !ifdef FOSSIL_ENABLE_SSL TCC = $(TCC) -DFOSSIL_ENABLE_SSL=1 RCC = $(RCC) -DFOSSIL_ENABLE_SSL=1 LIBS = $(LIBS) $(SSLLIB) LIBDIR = $(LIBDIR) -LIBPATH:$(SSLLIBDIR) !endif } regsub -all {[-]D} [join $SQLITE_OPTIONS { }] {/D} MSC_SQLITE_OPTIONS set j " \\\n " writeln "SQLITE_OPTIONS = [join $MSC_SQLITE_OPTIONS $j]\n" regsub -all {[-]D} [join $SHELL_WIN32_OPTIONS { }] {/D} MSC_SHELL_OPTIONS set j " \\\n " writeln "SHELL_OPTIONS = [join $MSC_SHELL_OPTIONS $j]\n" writeln -nonewline "SRC = " set i 0 foreach s [lsort $src] { if {$i > 0} { writeln " \\" writeln -nonewline " " } writeln -nonewline "${s}_.c"; incr i } writeln "\n" set AdditionalObj [list shell sqlite3 th th_lang cson_amalgamation] writeln -nonewline "OBJ = " set i 0 foreach s [lsort [concat $src $AdditionalObj]] { if {$i > 0} { writeln " \\" writeln -nonewline " " } writeln -nonewline "\$(OX)\\$s\$O"; incr i } writeln " \\" writeln -nonewline " \$(OX)\\fossil.res\n" writeln { APPNAME = $(OX)\fossil$(E) PDBNAME = $(OX)\fossil$(P) all: $(OX) $(APPNAME) zlib: @echo Building zlib from "$(ZLIBDIR)"... @pushd "$(ZLIBDIR)" && nmake /f win32\Makefile.msc $(ZLIB) && popd $(APPNAME) : translate$E mkindex$E headers $(OBJ) $(OX)\linkopts zlib cd $(OX) link $(LDFLAGS) -OUT:$@ $(LIBDIR) Wsetargv.obj fossil.res @linkopts $(OX)\linkopts: $B\win\Makefile.msc} set redir {>} foreach s [lsort [concat $src $AdditionalObj]] { writeln "\techo \$(OX)\\$s.obj $redir \$@" set redir {>>} } writeln "\techo \$(LIBS) >> \$@\n\n" writeln { $(OX): @-mkdir $@ translate$E: $(SRCDIR)\translate.c $(BCC) $** makeheaders$E: $(SRCDIR)\makeheaders.c |
︙ | ︙ | |||
1155 1156 1157 1158 1159 1160 1161 | $(OX)\th$O : $(SRCDIR)\th.c $(TCC) /Fo$@ -c $** $(OX)\th_lang$O : $(SRCDIR)\th_lang.c $(TCC) /Fo$@ -c $** | < < < | | 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 | $(OX)\th$O : $(SRCDIR)\th.c $(TCC) /Fo$@ -c $** $(OX)\th_lang$O : $(SRCDIR)\th_lang.c $(TCC) /Fo$@ -c $** VERSION.h : mkversion$E $B\manifest.uuid $B\manifest $B\VERSION $** > $@ $(OX)\cson_amalgamation$O : $(SRCDIR)\cson_amalgamation.c $(TCC) /Fo$@ -c $** page_index.h: mkindex$E $(SRC) $** > $@ clean: -del $(OX)\*.obj -del *.obj |
︙ | ︙ | |||
1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 | $(OBJDIR)\json_query$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_report$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_status$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_tag$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_timeline$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_user$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_wiki$O : $(SRCDIR)\json_detail.h } foreach s [lsort $src] { writeln "\$(OX)\\$s\$O : ${s}_.c ${s}.h" writeln "\t\$(TCC) /Fo\$@ -c ${s}_.c\n" writeln "${s}_.c : \$(SRCDIR)\\$s.c" writeln "\ttranslate\$E \$** > \$@\n" } writeln "fossil.res : \$B\\win\\fossil.rc" | > | | 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 | $(OBJDIR)\json_query$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_report$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_status$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_tag$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_timeline$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_user$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_wiki$O : $(SRCDIR)\json_detail.h } foreach s [lsort $src] { writeln "\$(OX)\\$s\$O : ${s}_.c ${s}.h" writeln "\t\$(TCC) /Fo\$@ -c ${s}_.c\n" writeln "${s}_.c : \$(SRCDIR)\\$s.c" writeln "\ttranslate\$E \$** > \$@\n" } writeln "fossil.res : \$B\\win\\fossil.rc" writeln "\t\$(RCC) -fo \$@ \$**" writeln "headers: makeheaders\$E page_index.h VERSION.h" writeln -nonewline "\tmakeheaders\$E " set i 0 foreach s [lsort $src] { if {$i > 0} { writeln " \\" |
︙ | ︙ |
Changes to src/manifest.c.
︙ | ︙ | |||
49 50 51 52 53 54 55 | */ #define MC_NONE 0 /* default handling */ #define MC_PERMIT_HOOKS 1 /* permit hooks to execute */ /* ** A single F-card within a manifest */ | | | 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | */ #define MC_NONE 0 /* default handling */ #define MC_PERMIT_HOOKS 1 /* permit hooks to execute */ /* ** A single F-card within a manifest */ struct ManifestFile { char *zName; /* Name of a file */ char *zUuid; /* UUID of the file */ char *zPerm; /* File permissions */ char *zPrior; /* Prior name if the name was changed */ }; |
︙ | ︙ | |||
87 88 89 90 91 92 93 | int nFileAlloc; /* Slots allocated in aFile[] */ int iFile; /* Index of current file in iterator */ ManifestFile *aFile; /* One entry for each F-card */ int nParent; /* Number of parents. */ int nParentAlloc; /* Slots allocated in azParent[] */ char **azParent; /* UUIDs of parents. One for each P card argument */ int nCherrypick; /* Number of entries in aCherrypick[] */ | | | | 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 | int nFileAlloc; /* Slots allocated in aFile[] */ int iFile; /* Index of current file in iterator */ ManifestFile *aFile; /* One entry for each F-card */ int nParent; /* Number of parents. */ int nParentAlloc; /* Slots allocated in azParent[] */ char **azParent; /* UUIDs of parents. One for each P card argument */ int nCherrypick; /* Number of entries in aCherrypick[] */ struct { char *zCPTarget; /* UUID of cherry-picked version w/ +|- prefix */ char *zCPBase; /* UUID of cherry-pick baseline. NULL for singletons */ } *aCherrypick; int nCChild; /* Number of cluster children */ int nCChildAlloc; /* Number of closts allocated in azCChild[] */ char **azCChild; /* UUIDs of referenced objects in a cluster. M cards */ int nTag; /* Number of T Cards */ int nTagAlloc; /* Slots allocated in aTag[] */ struct TagType { char *zName; /* Name of the tag */ char *zUuid; /* UUID that the tag is applied to */ char *zValue; /* Value if the tag is really a property */ } *aTag; /* One for each T card */ int nField; /* Number of J cards */ int nFieldAlloc; /* Slots allocated in aField[] */ struct { char *zName; /* Key or field name */ char *zValue; /* Value of the field */ } *aField; /* One for each J card */ }; #endif /* |
︙ | ︙ | |||
249 250 251 252 253 254 255 | /* ** Verify the Z-card checksum on the artifact, if there is such a ** checksum. Return 0 if there is no Z-card. Return 1 if the Z-card ** exists and is correct. Return 2 if the Z-card exists and has the wrong ** value. ** | | | 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 | /* ** Verify the Z-card checksum on the artifact, if there is such a ** checksum. Return 0 if there is no Z-card. Return 1 if the Z-card ** exists and is correct. Return 2 if the Z-card exists and has the wrong ** value. ** ** 0123456789 123456789 123456789 123456789 ** Z aea84f4f863865a8d59d0384e4d2a41c */ static int verify_z_card(const char *z, int n){ if( n<35 ) return 0; if( z[n-35]!='Z' || z[n-34]!=' ' ) return 0; md5sum_init(); md5sum_step_text(z, n-35); |
︙ | ︙ | |||
433 434 435 436 437 438 439 | */ case 'A': { char *zName, *zTarget, *zSrc; int nTarget = 0, nSrc = 0; zName = next_token(&x, 0); zTarget = next_token(&x, &nTarget); zSrc = next_token(&x, &nSrc); | | | 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 | */ case 'A': { char *zName, *zTarget, *zSrc; int nTarget = 0, nSrc = 0; zName = next_token(&x, 0); zTarget = next_token(&x, &nTarget); zSrc = next_token(&x, &nSrc); if( zName==0 || zTarget==0 ) goto manifest_syntax_error; if( p->zAttachName!=0 ) goto manifest_syntax_error; defossilize(zName); if( !file_is_simple_pathname(zName, 0) ){ SYNTAX("invalid filename on A-card"); } defossilize(zTarget); if( (nTarget!=UUID_SIZE || !validate16(zTarget, UUID_SIZE)) |
︙ | ︙ | |||
502 503 504 505 506 507 508 | if( p->rDate<=0.0 ) SYNTAX("cannot parse date on D-card"); break; } /* ** E <timestamp> <uuid> ** | | | 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 | if( p->rDate<=0.0 ) SYNTAX("cannot parse date on D-card"); break; } /* ** E <timestamp> <uuid> ** ** An "event" card that contains the timestamp of the event in the ** format YYYY-MM-DDtHH:MM:SS and a unique identifier for the event. ** The event timestamp is distinct from the D timestamp. The D ** timestamp is when the artifact was created whereas the E timestamp ** is when the specific event is said to occur. */ case 'E': { if( p->rEventDate>0.0 ) SYNTAX("more than one E-card"); |
︙ | ︙ | |||
549 550 551 552 553 554 555 | defossilize(zPriorName); if( !file_is_simple_pathname(zPriorName, 0) ){ SYNTAX("F-card old filename is not a simple path"); } } if( p->nFile>=p->nFileAlloc ){ p->nFileAlloc = p->nFileAlloc*2 + 10; | | | 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 | defossilize(zPriorName); if( !file_is_simple_pathname(zPriorName, 0) ){ SYNTAX("F-card old filename is not a simple path"); } } if( p->nFile>=p->nFileAlloc ){ p->nFileAlloc = p->nFileAlloc*2 + 10; p->aFile = fossil_realloc(p->aFile, p->nFileAlloc*sizeof(p->aFile[0]) ); } i = p->nFile++; p->aFile[i].zName = zName; p->aFile[i].zUuid = zUuid; p->aFile[i].zPerm = zPerm; p->aFile[i].zPrior = zPriorName; |
︙ | ︙ | |||
741 742 743 744 745 746 747 | ** Create or cancel a tag or property. The tagname is fossil-encoded. ** The first character of the name must be either "+" to create a ** singleton tag, "*" to create a propagating tag, or "-" to create ** anti-tag that undoes a prior "+" or blocks propagation of of ** a "*". ** ** The tag is applied to <uuid>. If <uuid> is "*" then the tag is | | | 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 | ** Create or cancel a tag or property. The tagname is fossil-encoded. ** The first character of the name must be either "+" to create a ** singleton tag, "*" to create a propagating tag, or "-" to create ** anti-tag that undoes a prior "+" or blocks propagation of of ** a "*". ** ** The tag is applied to <uuid>. If <uuid> is "*" then the tag is ** applied to the current manifest. If <value> is provided then ** the tag is really a property with the given value. ** ** Tags are not allowed in clusters. Multiple T lines are allowed. */ case 'T': { char *zName, *zValue; zName = next_token(&x, 0); |
︙ | ︙ | |||
1048 1049 1050 1051 1052 1053 1054 | if( p->pBaseline==0 ){ if( !throwError ){ db_multi_exec( "INSERT OR IGNORE INTO orphan(rid, baseline) VALUES(%d,%d)", p->rid, rid ); return 1; | | | 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 | if( p->pBaseline==0 ){ if( !throwError ){ db_multi_exec( "INSERT OR IGNORE INTO orphan(rid, baseline) VALUES(%d,%d)", p->rid, rid ); return 1; } fossil_fatal("cannot access baseline manifest %S", p->zBaseline); } } return 0; } /* |
︙ | ︙ | |||
1073 1074 1075 1076 1077 1078 1079 | /* ** Advance to the next manifest-file. ** ** Return NULL for end-of-records or if there is an error. If an error ** occurs and pErr!=0 then store 1 in *pErr. */ ManifestFile *manifest_file_next( | | | 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 | /* ** Advance to the next manifest-file. ** ** Return NULL for end-of-records or if there is an error. If an error ** occurs and pErr!=0 then store 1 in *pErr. */ ManifestFile *manifest_file_next( Manifest *p, int *pErr ){ ManifestFile *pOut = 0; if( pErr ) *pErr = 0; if( p->pBaseline==0 ){ /* Manifest p is a baseline-manifest. Just scan down the list ** of files. */ |
︙ | ︙ | |||
1217 1218 1219 1220 1221 1222 1223 | db_exec(&s1); if( pid && fid ){ content_deltify(pid, fid, 0); } } /* | | | 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 | db_exec(&s1); if( pid && fid ){ content_deltify(pid, fid, 0); } } /* ** Do a binary search to find a file in the p->aFile[] array. ** ** As an optimization, guess that the file we seek is at index p->iFile. ** That will usually be the case. If it is not found there, then do the ** actual binary search. ** ** Update p->iFile to be the index of the file that is found. */ |
︙ | ︙ | |||
1261 1262 1263 1264 1265 1266 1267 | } /* ** Locate a file named zName in the aFile[] array of the given manifest. ** Return a pointer to the appropriate ManifestFile object. Return NULL ** if not found. ** | | | | 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 | } /* ** Locate a file named zName in the aFile[] array of the given manifest. ** Return a pointer to the appropriate ManifestFile object. Return NULL ** if not found. ** ** This routine works even if p is a delta-manifest. The pointer ** returned might be to the baseline. ** ** We assume that filenames are in sorted order and use a binary search. */ ManifestFile *manifest_file_seek(Manifest *p, const char *zName){ ManifestFile *pFile; pFile = manifest_file_seek_base(p, zName); if( pFile && pFile->zUuid==0 ) return 0; if( pFile==0 && p->zBaseline ){ fetch_baseline(p, 1); pFile = manifest_file_seek_base(p->pBaseline, zName); } return pFile; |
︙ | ︙ | |||
1360 1361 1362 1363 1364 1365 1366 | if( fetch_baseline(pParent, 0) || fetch_baseline(pChild, 0) ){ manifest_destroy(*ppOther); return; } isPublic = !content_is_private(cid); /* Try to make the parent manifest a delta from the child, if that | | | | | 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 | if( fetch_baseline(pParent, 0) || fetch_baseline(pChild, 0) ){ manifest_destroy(*ppOther); return; } isPublic = !content_is_private(cid); /* Try to make the parent manifest a delta from the child, if that ** is an appropriate thing to do. For a new baseline, make the ** previous baseline a delta from the current baseline. */ if( (pParent->zBaseline==0)==(pChild->zBaseline==0) ){ content_deltify(pid, cid, 0); }else if( pChild->zBaseline==0 && pParent->zBaseline!=0 ){ content_deltify(pParent->pBaseline->rid, cid, 0); } /* Remember all children less than a few seconds younger than their parent, ** as we might want to fudge the times for those children. */ if( pChild->rDate<pParent->rDate+AGE_FUDGE_WINDOW && manifest_crosslink_busy ){ db_multi_exec( "INSERT OR REPLACE INTO time_fudge VALUES(%d, %.17g, %d, %.17g);", pParent->rid, pParent->rDate, pChild->rid, pChild->rDate ); } /* First look at all files in pChild, ignoring its baseline. This ** is where most of the changes will be found. */ for(i=0, pChildFile=pChild->aFile; i<pChild->nFile; i++, pChildFile++){ int mperm = manifest_file_mperm(pChildFile); if( pChildFile->zPrior ){ pParentFile = manifest_file_seek(pParent, pChildFile->zPrior); if( pParentFile ){ /* File with name change */ add_one_mlink(cid, pParentFile->zUuid, pChildFile->zUuid, |
︙ | ︙ | |||
1448 1449 1450 1451 1452 1453 1454 | }else if( pChild->zBaseline==0 ){ /* pChild is a baseline. Look for files that are present in pParent ** but are missing from pChild and mark them as having been deleted. */ manifest_file_rewind(pParent); while( (pParentFile = manifest_file_next(pParent,0))!=0 ){ pChildFile = manifest_file_seek(pChild, pParentFile->zName); if( pChildFile==0 && pParentFile->zUuid!=0 ){ | | | 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 | }else if( pChild->zBaseline==0 ){ /* pChild is a baseline. Look for files that are present in pParent ** but are missing from pChild and mark them as having been deleted. */ manifest_file_rewind(pParent); while( (pParentFile = manifest_file_next(pParent,0))!=0 ){ pChildFile = manifest_file_seek(pChild, pParentFile->zName); if( pChildFile==0 && pParentFile->zUuid!=0 ){ add_one_mlink(cid, pParentFile->zUuid, 0, pParentFile->zName, 0, isPublic, 0); } } } manifest_cache_insert(*ppOther); } |
︙ | ︙ | |||
1576 1577 1578 1579 1580 1581 1582 | blob_zero(&comment); blob_zero(&brief); if( once ){ once = 0; zTitleExpr = db_get("ticket-title-expr", "title"); zStatusColumn = db_get("ticket-status-column", "status"); } | | | | | | | | | | | | | | | < | 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 | blob_zero(&comment); blob_zero(&brief); if( once ){ once = 0; zTitleExpr = db_get("ticket-title-expr", "title"); zStatusColumn = db_get("ticket-status-column", "status"); } zTitle = db_text("unknown", "SELECT %s FROM ticket WHERE tkt_uuid='%s'", zTitleExpr, pManifest->zTicketUuid ); if( !isNew ){ for(i=0; i<pManifest->nField; i++){ if( fossil_strcmp(pManifest->aField[i].zName, zStatusColumn)==0 ){ zNewStatus = pManifest->aField[i].zValue; } } if( zNewStatus ){ blob_appendf(&comment, "%h ticket [%.10s]: <i>%h</i>", zNewStatus, pManifest->zTicketUuid, zTitle ); if( pManifest->nField>1 ){ blob_appendf(&comment, " plus %d other change%s", pManifest->nField-1, pManifest->nField==2 ? "" : "s"); } blob_appendf(&brief, "%h ticket [%.10s].", zNewStatus, pManifest->zTicketUuid); }else{ zNewStatus = db_text("unknown", "SELECT %s FROM ticket WHERE tkt_uuid='%s'", zStatusColumn, pManifest->zTicketUuid ); blob_appendf(&comment, "Ticket [%.10s] <i>%h</i> status still %h with " "%d other change%s", pManifest->zTicketUuid, zTitle, zNewStatus, pManifest->nField, pManifest->nField==1 ? "" : "s" ); free(zNewStatus); blob_appendf(&brief, "Ticket [%.10s]: %d change%s", pManifest->zTicketUuid, pManifest->nField, pManifest->nField==1 ? "" : "s" ); } }else{ blob_appendf(&comment, "New ticket [%.10s] <i>%h</i>.", pManifest->zTicketUuid, zTitle ); blob_appendf(&brief, "New ticket [%.10s].", pManifest->zTicketUuid); } free(zTitle); db_multi_exec( "REPLACE INTO event(type,tagid,mtime,objid,user,comment,brief)" "VALUES('t',%d,%.17g,%d,%Q,%Q,%Q)", tktTagId, pManifest->rDate, rid, pManifest->zUser, blob_str(&comment), blob_str(&brief) |
︙ | ︙ | |||
1660 1661 1662 1663 1664 1665 1666 | ** * Attachment ** * Event ** ** If the input is a control artifact, then make appropriate entries ** in the auxiliary tables of the database in order to crosslink the ** artifact. ** | | | 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 | ** * Attachment ** * Event ** ** If the input is a control artifact, then make appropriate entries ** in the auxiliary tables of the database in order to crosslink the ** artifact. ** ** If global variable g.xlinkClusterOnly is true, then ignore all ** control artifacts other than clusters. ** ** This routine always resets the pContent blob before returning. ** ** Historical note: This routine original processed manifests only. ** Processing for other control artifacts was added later. The name ** of the routine, "manifest_crosslink", and the name of this source |
︙ | ︙ | |||
1702 1703 1704 1705 1706 1707 1708 | fossil_error(1, "cannot fetch baseline manifest"); return 0; } db_begin_transaction(); if( p->type==CFTYPE_MANIFEST ){ if( permitHooks ){ zScript = xfer_commit_code(); | < > | 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 | fossil_error(1, "cannot fetch baseline manifest"); return 0; } db_begin_transaction(); if( p->type==CFTYPE_MANIFEST ){ if( permitHooks ){ zScript = xfer_commit_code(); } zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); if( !db_exists("SELECT 1 FROM mlink WHERE mid=%d", rid) ){ char *zCom; for(i=0; i<p->nParent; i++){ int pid = uuid_to_rid(p->azParent[i], 1); db_multi_exec("INSERT OR IGNORE INTO plink(pid, cid, isprim, mtime)" "VALUES(%d, %d, %d, %.17g)", pid, rid, i==0, p->rDate); if( i==0 ){ |
︙ | ︙ | |||
1743 1744 1745 1746 1747 1748 1749 | " %.17g" " )," " %d,%Q,%Q," " (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d AND tagtype>0)," " (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d)," " (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d),%.17g);", TAG_DATE, rid, p->rDate, | | | 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 | " %.17g" " )," " %d,%Q,%Q," " (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d AND tagtype>0)," " (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d)," " (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d),%.17g);", TAG_DATE, rid, p->rDate, rid, p->zUser, p->zComment, TAG_BGCOLOR, rid, TAG_USER, rid, TAG_COMMENT, rid, p->rDate ); zCom = db_text(0, "SELECT coalesce(ecomment, comment) FROM event" " WHERE rowid=last_insert_rowid()"); wiki_extract_links(zCom, rid, 0, p->rDate, 1, WIKI_INLINE); |
︙ | ︙ | |||
1801 1802 1803 1804 1805 1806 1807 | case '-': type = 0; break; /* Cancel prior occurrences */ case '+': type = 1; break; /* Apply to target only */ case '*': type = 2; break; /* Propagate to descendants */ default: fossil_error(1, "unknown tag type in manifest: %s", p->aTag); return 0; } | | | 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 | case '-': type = 0; break; /* Cancel prior occurrences */ case '+': type = 1; break; /* Apply to target only */ case '*': type = 2; break; /* Propagate to descendants */ default: fossil_error(1, "unknown tag type in manifest: %s", p->aTag); return 0; } tag_insert(&p->aTag[i].zName[1], type, p->aTag[i].zValue, rid, p->rDate, tid); } } if( parentid ){ tag_propagate_all(parentid); } } |
︙ | ︙ | |||
1842 1843 1844 1845 1846 1847 1848 | db_multi_exec( "REPLACE INTO event(type,mtime,objid,user,comment," " bgcolor,euser,ecomment)" "VALUES('w',%.17g,%d,%Q,%Q," " (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d AND tagtype>1)," " (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d)," " (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d));", | | | 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 | db_multi_exec( "REPLACE INTO event(type,mtime,objid,user,comment," " bgcolor,euser,ecomment)" "VALUES('w',%.17g,%d,%Q,%Q," " (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d AND tagtype>1)," " (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d)," " (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d));", p->rDate, rid, p->zUser, zComment, TAG_BGCOLOR, rid, TAG_BGCOLOR, rid, TAG_USER, rid, TAG_COMMENT, rid ); free(zComment); } |
︙ | ︙ | |||
1892 1893 1894 1895 1896 1897 1898 | if( subsequent ){ content_deltify(rid, subsequent, 0); }else{ db_multi_exec( "REPLACE INTO event(type,mtime,objid,tagid,user,comment,bgcolor)" "VALUES('e',%.17g,%d,%d,%Q,%Q," " (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d));", | | | 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 | if( subsequent ){ content_deltify(rid, subsequent, 0); }else{ db_multi_exec( "REPLACE INTO event(type,mtime,objid,tagid,user,comment,bgcolor)" "VALUES('e',%.17g,%d,%d,%Q,%Q," " (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d));", p->rEventDate, rid, tagid, p->zUser, p->zComment, TAG_BGCOLOR, rid ); } } if( p->type==CFTYPE_TICKET ){ char *zTag; |
︙ | ︙ | |||
1924 1925 1926 1927 1928 1929 1930 | "(SELECT max(mtime) FROM attachment" " WHERE target=%Q AND filename=%Q))" " WHERE target=%Q AND filename=%Q", p->zAttachTarget, p->zAttachName, p->zAttachTarget, p->zAttachName ); if( strlen(p->zAttachTarget)!=UUID_SIZE | | | | | | | | 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 | "(SELECT max(mtime) FROM attachment" " WHERE target=%Q AND filename=%Q))" " WHERE target=%Q AND filename=%Q", p->zAttachTarget, p->zAttachName, p->zAttachTarget, p->zAttachName ); if( strlen(p->zAttachTarget)!=UUID_SIZE || !validate16(p->zAttachTarget, UUID_SIZE) ){ char *zComment; if( p->zAttachSrc && p->zAttachSrc[0] ){ zComment = mprintf( "Add attachment [/artifact/%S|%h] to wiki page [%h]", p->zAttachSrc, p->zAttachName, p->zAttachTarget); }else{ zComment = mprintf("Delete attachment \"%h\" from wiki page [%h]", p->zAttachName, p->zAttachTarget); } db_multi_exec( "REPLACE INTO event(type,mtime,objid,user,comment)" "VALUES('w',%.17g,%d,%Q,%Q)", p->rDate, rid, p->zUser, zComment ); free(zComment); }else{ char *zComment; if( p->zAttachSrc && p->zAttachSrc[0] ){ zComment = mprintf( "Add attachment [/artifact/%S|%h] to ticket [%S]", p->zAttachSrc, p->zAttachName, p->zAttachTarget); }else{ zComment = mprintf("Delete attachment \"%h\" from ticket [%.10s]", p->zAttachName, p->zAttachTarget); } db_multi_exec( "REPLACE INTO event(type,mtime,objid,user,comment)" "VALUES('t',%.17g,%d,%Q,%Q)", p->rDate, rid, p->zUser, zComment ); free(zComment); |
︙ | ︙ | |||
1977 1978 1979 1980 1981 1982 1983 | /* Next loop expects tags to be sorted on UUID, so sort it. */ qsort(p->aTag, p->nTag, sizeof(p->aTag[0]), tag_compare); for(i=0; i<p->nTag; i++){ zTagUuid = p->aTag[i].zUuid; if( !zTagUuid ) continue; if( i==0 || fossil_strcmp(zTagUuid, p->aTag[i-1].zUuid)!=0 ){ blob_appendf(&comment, | | | | > | > | | 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 | /* Next loop expects tags to be sorted on UUID, so sort it. */ qsort(p->aTag, p->nTag, sizeof(p->aTag[0]), tag_compare); for(i=0; i<p->nTag; i++){ zTagUuid = p->aTag[i].zUuid; if( !zTagUuid ) continue; if( i==0 || fossil_strcmp(zTagUuid, p->aTag[i-1].zUuid)!=0 ){ blob_appendf(&comment, " Edit [%S]:", zTagUuid); branchMove = 0; if( db_exists("SELECT 1 FROM event, blob" " WHERE event.type='ci' AND event.objid=blob.rid" " AND blob.uuid='%s'", zTagUuid) ){ if( permitHooks ){ zScript = xfer_commit_code(); } zUuid = zTagUuid; } } zName = p->aTag[i].zName; zValue = p->aTag[i].zValue; if( strcmp(zName, "*branch")==0 ){ blob_appendf(&comment, " Move to branch [/timeline?r=%h&nd&dp=%S&unhide | %h].", zValue, zTagUuid, zValue); branchMove = 1; continue; }else if( strcmp(zName, "*bgcolor")==0 ){ blob_appendf(&comment, " Change branch background color to \"%h\".", zValue); continue; |
︙ | ︙ |
Changes to src/markdown.c.
︙ | ︙ | |||
159 160 161 162 163 164 165 | int work_active; struct Blob *work; }; /* html_tag -- structure for quick HTML tag search (inspired from discount) */ struct html_tag { | | | | 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 | int work_active; struct Blob *work; }; /* html_tag -- structure for quick HTML tag search (inspired from discount) */ struct html_tag { char *text; int size; }; /******************** * GLOBAL VARIABLES * ********************/ /* block_tags -- recognised block tags, sorted by cmp_html_tag */ static struct html_tag block_tags[] = { { "p", 1 }, { "dl", 2 }, { "h1", 2 }, { "h2", 2 }, { "h3", 2 }, { "h4", 2 }, { "h5", 2 }, |
︙ | ︙ | |||
274 275 276 277 278 279 280 | const struct html_tag *htb = b; if( hta->size!=htb->size ) return hta->size-htb->size; return fossil_strnicmp(hta->text, htb->text, hta->size); } /* find_block_tag -- returns the current block tag */ | | | 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 | const struct html_tag *htb = b; if( hta->size!=htb->size ) return hta->size-htb->size; return fossil_strnicmp(hta->text, htb->text, hta->size); } /* find_block_tag -- returns the current block tag */ static struct html_tag *find_block_tag(char *data, size_t size){ size_t i = 0; struct html_tag key; /* looking for the word end */ while( i<size && ((data[i]>='0' && data[i]<='9') || (data[i]>='A' && data[i]<='Z') |
︙ | ︙ | |||
1068 1069 1070 1071 1072 1073 1074 | /********************************* * BLOCK-LEVEL PARSING FUNCTIONS * *********************************/ /* is_empty -- returns the line length when it is empty, 0 otherwise */ | | | 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 | /********************************* * BLOCK-LEVEL PARSING FUNCTIONS * *********************************/ /* is_empty -- returns the line length when it is empty, 0 otherwise */ static size_t is_empty(char *data, size_t size){ size_t i; for(i=0; i<size && data[i]!='\n'; i++){ if( data[i]!=' ' && data[i]!='\t' ) return 0; } return i+1; } |
︙ | ︙ | |||
1629 1630 1631 1632 1633 1634 1635 | } return skip; } /* htmlblock_end -- checking end of HTML block : </tag>[ \t]*\n[ \t*]\n */ /* returns the length on match, 0 otherwise */ | | | 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 | } return skip; } /* htmlblock_end -- checking end of HTML block : </tag>[ \t]*\n[ \t*]\n */ /* returns the length on match, 0 otherwise */ static size_t htmlblock_end(struct html_tag *tag, char *data, size_t size){ size_t i, w; /* assuming data[0]=='<' && data[1]=='/' already tested */ /* checking tag is a match */ if( (tag->size+3)>=size || fossil_strnicmp(data+2, tag->text, tag->size) |
︙ | ︙ | |||
1666 1667 1668 1669 1670 1671 1672 | static size_t parse_htmlblock( struct Blob *ob, struct render *rndr, char *data, size_t size ){ size_t i, j = 0; | | | 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 | static size_t parse_htmlblock( struct Blob *ob, struct render *rndr, char *data, size_t size ){ size_t i, j = 0; struct html_tag *curtag; int found; size_t work_size = 0; struct Blob work = BLOB_INITIALIZER; /* identification of the opening tag */ if( size<2 || data[0]!='<' ) return 0; curtag = find_block_tag(data+1, size-1); |
︙ | ︙ |
Changes to src/merge.c.
︙ | ︙ | |||
256 257 258 259 260 261 262 | fossil_fatal("not a version: record #%d", pid); } if( !forceFlag && mid==pid ){ fossil_print("Merge skipped because it is a no-op. " " Use --force to override.\n"); return; } | | > > > > > > > | | > | 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 | fossil_fatal("not a version: record #%d", pid); } if( !forceFlag && mid==pid ){ fossil_print("Merge skipped because it is a no-op. " " Use --force to override.\n"); return; } if( integrateFlag ){ if( db_exists("SELECT 1 FROM vmerge WHERE id=-4")) { /* Fossil earlier than [55cacfcace] cannot handle this, * therefore disallow it. */ fossil_fatal("Integration of another branch already in progress." " Commit or Undo needed first", g.argv[2]); } if( !is_a_leaf(mid) ){ fossil_warning("ignoring --integrate: %s is not a leaf", g.argv[2]); integrateFlag = 0; } } if( verboseFlag ){ print_checkin_description(mid, 12, integrateFlag?"integrate:":"merge-from:"); print_checkin_description(pid, 12, "baseline:"); } vfile_check_signature(vid, CKSIG_ENOTFILE); db_begin_transaction(); |
︙ | ︙ |
Changes to src/merge3.c.
︙ | ︙ | |||
362 363 364 365 366 367 368 | ** that the "Xbase.c" is an exact copy of the last imported "Xup.c". ** Then to import the latest "Xup.c" while preserving all the local changes: ** ** fossil 3-way-merge Xbase.c Xlocal.c Xup.c Xlocal.c ** cp Xup.c Xbase.c ** # Verify that everything still works ** fossil commit | | | 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 | ** that the "Xbase.c" is an exact copy of the last imported "Xup.c". ** Then to import the latest "Xup.c" while preserving all the local changes: ** ** fossil 3-way-merge Xbase.c Xlocal.c Xup.c Xlocal.c ** cp Xup.c Xbase.c ** # Verify that everything still works ** fossil commit ** */ void delta_3waymerge_cmd(void){ Blob pivot, v1, v2, merged; if( g.argc!=6 ){ usage("PIVOT V1 V2 MERGED"); } if( blob_read_from_file(&pivot, g.argv[2])<0 ){ |
︙ | ︙ |
Changes to src/mkversion.c.
︙ | ︙ | |||
67 68 69 70 71 72 73 | z[0] = '\0'; break; } } printf("#define RELEASE_RESOURCE_VERSION %s", vx); while( d<3 ){ printf(",0"); d++; } printf("\n"); | < < < < < < < < < < < < < < | 67 68 69 70 71 72 73 74 75 | z[0] = '\0'; break; } } printf("#define RELEASE_RESOURCE_VERSION %s", vx); while( d<3 ){ printf(",0"); d++; } printf("\n"); return 0; } |
Changes to src/moderate.c.
︙ | ︙ | |||
62 63 64 65 66 67 68 | return rc; } /* ** Check to see if the object identified by RID is used for anything. */ static int object_used(int rid){ | | | 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | return rc; } /* ** Check to see if the object identified by RID is used for anything. */ static int object_used(int rid){ static const char *aTabField[] = { "modreq", "attachRid", "mlink", "mid", "mlink", "fid", "tagxref", "srcid", "tagxref", "rid", }; int i; |
︙ | ︙ |
Changes to src/name.c.
︙ | ︙ | |||
15 16 17 18 19 20 21 | ** ******************************************************************************* ** ** This file contains code used to convert user-supplied object names into ** canonical UUIDs. ** ** A user-supplied object name is any unique prefix of a valid UUID but | | | 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | ** ******************************************************************************* ** ** This file contains code used to convert user-supplied object names into ** canonical UUIDs. ** ** A user-supplied object name is any unique prefix of a valid UUID but ** not necessarily in canonical form. */ #include "config.h" #include "name.h" #include <assert.h> /* ** Return TRUE if the string begins with something that looks roughly |
︙ | ︙ | |||
48 49 50 51 52 53 54 | /* ** Convert a symbolic name into a RID. Acceptable forms: ** ** * SHA1 hash ** * SHA1 hash prefix of at least 4 characters ** * Symbolic Name ** * "tag:" + symbolic name | | | | 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | /* ** Convert a symbolic name into a RID. Acceptable forms: ** ** * SHA1 hash ** * SHA1 hash prefix of at least 4 characters ** * Symbolic Name ** * "tag:" + symbolic name ** * Date or date-time ** * "date:" + Date or date-time ** * symbolic-name ":" date-time ** * "tip" ** ** The following additional forms are available in local checkouts: ** ** * "current" ** * "prev" or "previous" ** * "next" ** ** Return the RID of the matching artifact. Or return 0 if the name does not ** match any known object. Or return -1 if the name is ambiguous. ** ** The zType parameter specifies the type of artifact: ci, t, w, e, g. ** If zType is NULL or "" or "*" then any type of artifact will serve. ** zType is "ci" in most use cases since we are usually searching for ** a check-in. */ int symbolic_name_to_rid(const char *zTag, const char *zType){ int vid; int rid = 0; |
︙ | ︙ | |||
91 92 93 94 95 96 97 | if( rid ) return rid; } /* special keywords: "prev", "previous", "current", and "next" */ if( g.localOpen && (vid=db_lget_int("checkout",0))!=0 ){ if( fossil_strcmp(zTag, "current")==0 ){ rid = vid; | | | | | | | | 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 | if( rid ) return rid; } /* special keywords: "prev", "previous", "current", and "next" */ if( g.localOpen && (vid=db_lget_int("checkout",0))!=0 ){ if( fossil_strcmp(zTag, "current")==0 ){ rid = vid; }else if( fossil_strcmp(zTag, "prev")==0 || fossil_strcmp(zTag, "previous")==0 ){ rid = db_int(0, "SELECT pid FROM plink WHERE cid=%d AND isprim", vid); }else if( fossil_strcmp(zTag, "next")==0 ){ rid = db_int(0, "SELECT cid FROM plink WHERE pid=%d" " ORDER BY isprim DESC, mtime DESC", vid); } if( rid ) return rid; } /* Date and times */ if( memcmp(zTag, "date:", 5)==0 ){ rid = db_int(0, "SELECT objid FROM event" " WHERE mtime<=julianday(%Q,'utc') AND type GLOB '%q'" " ORDER BY mtime DESC LIMIT 1", &zTag[5], zType); return rid; } if( fossil_isdate(zTag) ){ rid = db_int(0, "SELECT objid FROM event" " WHERE mtime<=julianday(%Q,'utc') AND type GLOB '%q'" " ORDER BY mtime DESC LIMIT 1", zTag, zType); if( rid) return rid; } /* Deprecated date & time formats: "local:" + date-time and ** "utc:" + date-time */ if( memcmp(zTag, "local:", 6)==0 ){ rid = db_int(0, "SELECT objid FROM event" " WHERE mtime<=julianday(%Q) AND type GLOB '%q'" " ORDER BY mtime DESC LIMIT 1", &zTag[6], zType); return rid; } if( memcmp(zTag, "utc:", 4)==0 ){ rid = db_int(0, "SELECT objid FROM event" " WHERE mtime<=julianday('%qz') AND type GLOB '%q'" " ORDER BY mtime DESC LIMIT 1", &zTag[4], zType); return rid; } /* "tag:" + symbolic-name */ if( memcmp(zTag, "tag:", 4)==0 ){ rid = db_int(0, "SELECT event.objid, max(event.mtime)" " FROM tag, tagxref, event" " WHERE tag.tagname='sym-%q' " " AND tagxref.tagid=tag.tagid AND tagxref.tagtype>0 " " AND event.objid=tagxref.rid " " AND event.type GLOB '%q'", &zTag[4], zType ); return rid; } /* root:TAG -> The origin of the branch */ if( memcmp(zTag, "root:", 5)==0 ){ Stmt q; int rc; char *zBr; rid = symbolic_name_to_rid(zTag+5, zType); zBr = db_text("trunk","SELECT value FROM tagxref" |
︙ | ︙ | |||
253 254 255 256 257 258 259 | if( memcmp(zTag, "rid:", 4)==0 ){ zTag += 4; for(i=0; fossil_isdigit(zTag[i]); i++){} if( zTag[i]==0 ){ if( strcmp(zType,"*")==0 ){ rid = atoi(zTag); }else{ | | | 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 | if( memcmp(zTag, "rid:", 4)==0 ){ zTag += 4; for(i=0; fossil_isdigit(zTag[i]); i++){} if( zTag[i]==0 ){ if( strcmp(zType,"*")==0 ){ rid = atoi(zTag); }else{ rid = db_int(0, "SELECT event.objid" " FROM event" " WHERE event.objid=%s" " AND event.type GLOB '%q'", zTag, zType); } } } |
︙ | ︙ | |||
276 277 278 279 280 281 282 | ** ** If the input is not a UUID or a UUID prefix, then try to resolve ** the name as a tag. If multiple tags match, pick the latest. ** If the input name matches "tag:*" then always resolve as a tag. ** ** If the input is not a tag, then try to match it as an ISO-8601 date ** string YYYY-MM-DD HH:MM:SS and pick the nearest check-in to that date. | | | | 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 | ** ** If the input is not a UUID or a UUID prefix, then try to resolve ** the name as a tag. If multiple tags match, pick the latest. ** If the input name matches "tag:*" then always resolve as a tag. ** ** If the input is not a tag, then try to match it as an ISO-8601 date ** string YYYY-MM-DD HH:MM:SS and pick the nearest check-in to that date. ** If the input is of the form "date:*" or "localtime:*" or "utc:*" then ** always resolve the name as a date. ** ** Return 0 on success. Return 1 if the name cannot be resolved. ** Return 2 name is ambiguous. */ int name_to_uuid(Blob *pName, int iErrPriority, const char *zType){ char *zName = blob_str(pName); int rid = symbolic_name_to_rid(zName, zType); |
︙ | ︙ | |||
377 378 379 380 381 382 383 | int name_to_rid(const char *zName){ return name_to_typed_rid(zName, "*"); } /* ** WEBPAGE: ambiguous ** URL: /ambiguous?name=UUID&src=WEBPAGE | | | | | | < | 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 | int name_to_rid(const char *zName){ return name_to_typed_rid(zName, "*"); } /* ** WEBPAGE: ambiguous ** URL: /ambiguous?name=UUID&src=WEBPAGE ** ** The UUID given by the name parameter is ambiguous. Display a page ** that shows all possible choices and let the user select between them. */ void ambiguous_page(void){ Stmt q; const char *zName = P("name"); const char *zSrc = P("src"); char *z; if( zName==0 || zName[0]==0 || zSrc==0 || zSrc[0]==0 ){ fossil_redirect_home(); } style_header("Ambiguous Artifact ID"); @ <p>The artifact id <b>%h(zName)</b> is ambiguous and might @ mean any of the following: @ <ol> z = mprintf("%s", zName); canonical16(z, strlen(z)); db_prepare(&q, "SELECT uuid, rid FROM blob WHERE uuid GLOB '%q*'", z); while( db_step(&q)==SQLITE_ROW ){ const char *zUuid = db_column_text(&q, 0); int rid = db_column_int(&q, 1); @ <li><p><a href="%s(g.zTop)/%T(zSrc)/%S(zUuid)"> @ %S(zUuid)</a> - object_description(rid, 0, 0); @ </p></li> } @ </ol> style_footer(); } /* ** Convert the name in CGI parameter zParamName into a rid and return that ** rid. If the CGI parameter is missing or is not a valid artifact tag, ** return 0. If the CGI parameter is ambiguous, redirect to a page that |
︙ | ︙ | |||
433 434 435 436 437 438 439 | if( rid<0 ){ cgi_redirectf("%s/ambiguous/%T?src=%t", g.zTop, zName, g.zPath); rid = 0; } return rid; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < > > > > > > > > > > > > | > > > > > > > > | > > | > > > > > > > > > > > > > > > | < < | < < < < | | > > | | > > > > > > > > > | > > > > > | | | | > | 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 | if( rid<0 ){ cgi_redirectf("%s/ambiguous/%T?src=%t", g.zTop, zName, g.zPath); rid = 0; } return rid; } /* ** COMMAND: whatis* ** Usage: %fossil whatis NAME ** ** Resolve the symbol NAME into its canonical 40-character SHA1-hash ** artifact name and provide a description of what role that artifact ** plays. */ void whatis_cmd(void){ int rid; const char *zName; int verboseFlag; db_find_and_open_repository(0,0); verboseFlag = find_option("verbose","v",0)!=0; if( g.argc!=3 ) usage("whatis NAME"); zName = g.argv[2]; rid = symbolic_name_to_rid(zName, 0); if( rid<0 ){ fossil_print("Ambiguous artifact name prefix: %s\n", zName); }else if( rid==0 ){ fossil_print("Unknown artifact: %s\n", zName); }else{ Stmt q; db_prepare(&q, "SELECT uuid, size, datetime(mtime%s), ipaddr," " (SELECT group_concat(substr(tagname,5), ', ') FROM tag, tagxref" " WHERE tagname GLOB 'sym-*' AND tag.tagid=tagxref.tagid" " AND tagxref.rid=blob.rid AND tagxref.tagtype>0)" " FROM blob, rcvfrom" " WHERE rid=%d" " AND rcvfrom.rcvid=blob.rcvid", timeline_utc(), rid); if( db_step(&q)==SQLITE_ROW ){ const char *zTagList = db_column_text(&q, 4); if( verboseFlag ){ fossil_print("artifact: %s (%d)\n", db_column_text(&q,0), rid); fossil_print("size: %d bytes\n", db_column_int(&q,1)); fossil_print("received: %s from %s\n", db_column_text(&q, 2), db_column_text(&q, 3)); }else{ fossil_print("artifact: %s\n", db_column_text(&q,0)); fossil_print("size: %d bytes\n", db_column_int(&q,1)); } if( zTagList && zTagList[0] ){ fossil_print("tags: %s\n", zTagList); } } db_finalize(&q); db_prepare(&q, "SELECT type, datetime(mtime%s)," " coalesce(euser,user), coalesce(ecomment,comment)" " FROM event WHERE objid=%d", timeline_utc(), rid); if( db_step(&q)==SQLITE_ROW ){ const char *zType; switch( db_column_text(&q,0)[0] ){ case 'c': zType = "Check-in"; break; case 'w': zType = "Wiki-edit"; break; case 'e': zType = "Event"; break; case 't': zType = "Ticket-change"; break; case 'g': zType = "Tag-change"; break; default: zType = "Unknown"; break; } fossil_print("type: %s by %s on %s\n", zType, db_column_text(&q,2), db_column_text(&q, 1)); fossil_print("comment: "); comment_print(db_column_text(&q,3), 10, 78); } db_finalize(&q); db_prepare(&q, "SELECT filename.name, blob.uuid, datetime(event.mtime%s)," " coalesce(euser,user), coalesce(ecomment,comment)" " FROM mlink, filename, blob, event" " WHERE mlink.fid=%d" " AND filename.fnid=mlink.fnid" " AND event.objid=mlink.mid" " AND blob.rid=mlink.mid" " ORDER BY event.mtime DESC /*sort*/", timeline_utc(), rid); while( db_step(&q)==SQLITE_ROW ){ fossil_print("file: %s\n", db_column_text(&q,0)); fossil_print(" part of [%.10s] by %s on %s\n", db_column_text(&q, 1), db_column_text(&q, 3), db_column_text(&q, 2)); fossil_print(" "); comment_print(db_column_text(&q,4), 10, 78); } db_finalize(&q); } } |
Changes to src/popen.c.
︙ | ︙ | |||
202 203 204 205 206 207 208 | return 0; } #endif } /* ** Close the connection to a child process previously created using | | > | 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 | return 0; } #endif } /* ** Close the connection to a child process previously created using ** popen2(). Kill off the child process, then close the pipes. */ void pclose2(int fdIn, FILE *pOut, int childPid){ #ifdef _WIN32 /* Not implemented, yet */ close(fdIn); fclose(pOut); #else close(fdIn); fclose(pOut); kill(childPid, SIGINT); while( waitpid(0, 0, WNOHANG)>0 ) {} #endif } |
Changes to src/printf.c.
︙ | ︙ | |||
857 858 859 860 861 862 863 | #endif assert( toStdErr==0 || toStdErr==1 ); fwrite(z, 1, n, toStdErr ? stderr : stdout); fflush(toStdErr ? stderr : stdout); } /* | | | 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 | #endif assert( toStdErr==0 || toStdErr==1 ); fwrite(z, 1, n, toStdErr ? stderr : stdout); fflush(toStdErr ? stderr : stdout); } /* ** Force the standard output cursor to move to the beginning ** of a line, if it is not there already. */ void fossil_force_newline(void){ if( g.cgiOutput==0 && stdoutAtBOL==0 ) fossil_puts("\n", 0); } /* |
︙ | ︙ | |||
916 917 918 919 920 921 922 | static void fossil_errorlog(const char *zFormat, ...){ struct tm *pNow; time_t now; FILE *out; const char *z; int i; va_list ap; | | | 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 | static void fossil_errorlog(const char *zFormat, ...){ struct tm *pNow; time_t now; FILE *out; const char *z; int i; va_list ap; static const char *azEnv[] = { "HTTP_HOST", "HTTP_USER_AGENT", "PATH_INFO", "QUERY_STRING", "REMOTE_ADDR", "REQUEST_METHOD", "REQUEST_URI", "SCRIPT_NAME" }; if( g.zErrlog==0 ) return; out = fossil_fopen(g.zErrlog, "a"); if( out==0 ) return; now = time(0); pNow = gmtime(&now); |
︙ | ︙ |
Changes to src/rebuild.c.
︙ | ︙ | |||
45 46 47 48 49 50 51 | @ CREATE TABLE IF NOT EXISTS shun( @ uuid UNIQUE, -- UUID of artifact to be shunned. Canonical form @ mtime INTEGER, -- When added. Seconds since 1970 @ scom TEXT -- Optional text explaining why the shun occurred @ ); @ @ -- Artifacts that should not be pushed are stored in the "private" | | | | 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | @ CREATE TABLE IF NOT EXISTS shun( @ uuid UNIQUE, -- UUID of artifact to be shunned. Canonical form @ mtime INTEGER, -- When added. Seconds since 1970 @ scom TEXT -- Optional text explaining why the shun occurred @ ); @ @ -- Artifacts that should not be pushed are stored in the "private" @ -- table. @ -- @ CREATE TABLE IF NOT EXISTS private(rid INTEGER PRIMARY KEY); @ @ -- Some ticket content (such as the originators email address or contact @ -- information) needs to be obscured to protect privacy. This is achieved @ -- by storing an SHA1 hash of the content. For display, the hash is @ -- mapped back into the original text using this table. @ -- @ -- This table contains sensitive information and should not be shared @ -- with unauthorized users. @ -- @ CREATE TABLE IF NOT EXISTS concealed( @ hash TEXT PRIMARY KEY, -- The SHA1 hash of content @ mtime INTEGER, -- Time created. Seconds since 1970 |
︙ | ︙ | |||
151 152 153 154 155 156 157 | " WHERE name='concealed' AND sql GLOB '* mtime *'"); if( rc==0 ){ db_multi_exec( "ALTER TABLE concealed ADD COLUMN mtime INTEGER;" "UPDATE concealed SET mtime=now();" ); } | | | 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 | " WHERE name='concealed' AND sql GLOB '* mtime *'"); if( rc==0 ){ db_multi_exec( "ALTER TABLE concealed ADD COLUMN mtime INTEGER;" "UPDATE concealed SET mtime=now();" ); } } /* ** Variables used to store state information about an on-going "rebuild" ** or "deconstruct". */ static int totalSize; /* Total number of artifacts to process */ static int processCnt; /* Number processed so far */ |
︙ | ︙ | |||
225 226 227 228 229 230 231 | /* Fix up the "blob.size" field if needed. */ if( size!=blob_size(pBase) ){ db_multi_exec( "UPDATE blob SET size=%d WHERE rid=%d", blob_size(pBase), rid ); } | | | | 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 | /* Fix up the "blob.size" field if needed. */ if( size!=blob_size(pBase) ){ db_multi_exec( "UPDATE blob SET size=%d WHERE rid=%d", blob_size(pBase), rid ); } /* Find all children of artifact rid */ db_static_prepare(&q1, "SELECT rid FROM delta WHERE srcid=:rid"); db_bind_int(&q1, ":rid", rid); bag_init(&children); while( db_step(&q1)==SQLITE_ROW ){ int cid = db_column_int(&q1, 0); if( !bag_find(&bagDone, cid) ){ bag_insert(&children, cid); } } nChild = bag_count(&children); db_reset(&q1); /* Crosslink the artifact */ if( nChild==0 ){ pUse = pBase; }else{ blob_copy(©, pBase); pUse = © } |
︙ | ︙ | |||
260 261 262 263 264 265 266 | blob_write_to_file(pUse,zFile); free(zFile); free(zUuid); blob_reset(pUse); } assert( blob_is_reset(pUse) ); rebuild_step_done(rid); | | | 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 | blob_write_to_file(pUse,zFile); free(zFile); free(zUuid); blob_reset(pUse); } assert( blob_is_reset(pUse) ); rebuild_step_done(rid); /* Call all children recursively */ rid = 0; for(cid=bag_first(&children), i=1; cid; cid=bag_next(&children, cid), i++){ static Stmt q2; int sz; db_static_prepare(&q2, "SELECT content, size FROM blob WHERE rid=:rid"); db_bind_int(&q2, ":rid", cid); |
︙ | ︙ | |||
624 625 626 627 628 629 630 | fossil_print("done\n"); } if( activateWal ){ db_multi_exec("PRAGMA journal_mode=WAL;"); } } if( showStats ){ | | | 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 | fossil_print("done\n"); } if( activateWal ){ db_multi_exec("PRAGMA journal_mode=WAL;"); } } if( showStats ){ static struct { int idx; const char *zLabel; } aStat[] = { { CFTYPE_ANY, "Artifacts:" }, { CFTYPE_MANIFEST, "Manifests:" }, { CFTYPE_CLUSTER, "Clusters:" }, { CFTYPE_CONTROL, "Tags:" }, { CFTYPE_WIKI, "Wikis:" }, { CFTYPE_TICKET, "Tickets:" }, { CFTYPE_ATTACHMENT,"Attachments:" }, |
︙ | ︙ | |||
685 686 687 688 689 690 691 | usage("?REPOSITORY-FILENAME?"); } db_close(1); db_open_repository(g.zRepositoryName); } db_begin_transaction(); create_cluster(); | | | | 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 | usage("?REPOSITORY-FILENAME?"); } db_close(1); db_open_repository(g.zRepositoryName); } db_begin_transaction(); create_cluster(); db_end_transaction(0); } /* ** COMMAND: test-clusters ** ** Verify that all non-private and non-shunned artifacts are accessible ** through the cluster chain. */ void test_clusters_cmd(void){ Bag pending; Stmt q; int n; db_find_and_open_repository(0, 2); bag_init(&pending); db_multi_exec( "CREATE TEMP TABLE xdone(x INTEGER PRIMARY KEY);" "INSERT INTO xdone SELECT rid FROM unclustered;" "INSERT OR IGNORE INTO xdone SELECT rid FROM private;" "INSERT OR IGNORE INTO xdone" |
︙ | ︙ | |||
720 721 722 723 724 725 726 | bag_insert(&pending, db_column_int(&q, 0)); } db_finalize(&q); while( bag_count(&pending)>0 ){ Manifest *p; int rid = bag_first(&pending); int i; | | | 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 | bag_insert(&pending, db_column_int(&q, 0)); } db_finalize(&q); while( bag_count(&pending)>0 ){ Manifest *p; int rid = bag_first(&pending); int i; bag_remove(&pending, rid); p = manifest_get(rid, CFTYPE_CLUSTER, 0); if( p==0 ){ fossil_fatal("bad cluster: rid=%d", rid); } for(i=0; i<p->nCChild; i++){ const char *zUuid = p->azCChild[i]; |
︙ | ︙ | |||
791 792 793 794 795 796 797 798 799 800 801 802 803 804 | int bNeedRebuild = 0; db_find_and_open_repository(OPEN_ANY_SCHEMA, 2); db_close(1); db_open_repository(g.zRepositoryName); if( !bForce ){ Blob ans; char cReply; prompt_user( "Scrubbing the repository will permanently delete information.\n" "Changes cannot be undone. Continue (y/N)? ", &ans); cReply = blob_str(&ans)[0]; if( cReply!='y' && cReply!='Y' ){ fossil_exit(1); } | > | 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 | int bNeedRebuild = 0; db_find_and_open_repository(OPEN_ANY_SCHEMA, 2); db_close(1); db_open_repository(g.zRepositoryName); if( !bForce ){ Blob ans; char cReply; blob_zero(&ans); prompt_user( "Scrubbing the repository will permanently delete information.\n" "Changes cannot be undone. Continue (y/N)? ", &ans); cReply = blob_str(&ans)[0]; if( cReply!='y' && cReply!='Y' ){ fossil_exit(1); } |
︙ | ︙ | |||
926 927 928 929 930 931 932 | reconstruct_private_table(); /* Skip the verify_before_commit() step on a reconstruct. Most artifacts ** will have been changed and verification therefore takes a really, really ** long time. */ verify_cancel(); | | | | 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 | reconstruct_private_table(); /* Skip the verify_before_commit() step on a reconstruct. Most artifacts ** will have been changed and verification therefore takes a really, really ** long time. */ verify_cancel(); db_end_transaction(0); fossil_print("project-id: %s\n", db_get("project-code", 0)); fossil_print("server-id: %s\n", db_get("server-code", 0)); zPassword = db_text(0, "SELECT pw FROM user WHERE login=%Q", g.zLogin); fossil_print("admin-user: %s (initial password is \"%s\")\n", g.zLogin, zPassword); } /* ** COMMAND: deconstruct* ** ** Usage %fossil deconstruct ?OPTIONS? DESTINATION ** ** ** This command exports all artifacts of a given repository and ** writes all artifacts to the file system. The DESTINATION directory ** will be populated with subdirectories AA and files AA/BBBBBBBBB.., where ** AABBBBBBBBB.. is the 40 character artifact ID, AA the first 2 characters. ** If -L|--prefixlength is given, the length (default 2) of the directory ** prefix can be set to 0,1,..,9 characters. ** ** Options: ** -R|--repository REPOSITORY deconstruct given REPOSITORY ** -L|--prefixlength N set the length of the names of the DESTINATION ** subdirectories to N ** --private Include private artifacts. ** ** See also: rebuild, reconstruct |
︙ | ︙ |
Changes to src/report.c.
︙ | ︙ | |||
10 11 12 13 14 15 16 | ** merchantability or fitness for a particular purpose. ** ** Author contact information: ** drh@hwaci.com ** http://www.hwaci.com/drh/ ** ******************************************************************************* | | < < < < | | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | ** merchantability or fitness for a particular purpose. ** ** Author contact information: ** drh@hwaci.com ** http://www.hwaci.com/drh/ ** ******************************************************************************* ** ** Code to generate the ticket listings */ #include "config.h" #include <time.h> #include "report.h" #include <assert.h> /* Forward references to static routines */ static void report_format_hints(void); /* ** WEBPAGE: /reportlist */ void view_list(void){ const char *zScript; Blob ril; /* Report Item List */ Stmt q; int rn = 0; int cnt = 0; login_check_credentials(); if( !g.perm.RdTkt && !g.perm.NewTkt ){ login_needed(); return; } style_header("Ticket Main Menu"); if( g.thTrace ) Th_Trace("BEGIN_REPORTLIST<br />\n", -1); zScript = ticket_reportlist_code(); if( g.thTrace ) Th_Trace("BEGIN_REPORTLIST_SCRIPT<br />\n", -1); blob_zero(&ril); ticket_init(); db_prepare(&q, "SELECT rn, title, owner FROM reportfmt ORDER BY title"); while( db_step(&q)==SQLITE_ROW ){ const char *zTitle = db_column_text(&q, 1); const char *zOwner = db_column_text(&q, 2); |
︙ | ︙ | |||
68 69 70 71 72 73 74 | if( g.perm.Write && zOwner && zOwner[0] ){ blob_appendf(&ril, "(by <i>%h</i>) ", zOwner); } if( g.perm.TktFmt ){ blob_appendf(&ril, "[%zcopy</a>] ", href("%R/rptedit?rn=%d©=1", rn)); } | | | | | | 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 | if( g.perm.Write && zOwner && zOwner[0] ){ blob_appendf(&ril, "(by <i>%h</i>) ", zOwner); } if( g.perm.TktFmt ){ blob_appendf(&ril, "[%zcopy</a>] ", href("%R/rptedit?rn=%d©=1", rn)); } if( g.perm.Admin || (g.perm.WrTkt && zOwner && fossil_strcmp(g.zLogin,zOwner)==0) ){ blob_appendf(&ril, "[%zedit</a>]", href("%R/rptedit?rn=%d", rn)); } if( g.perm.TktFmt ){ blob_appendf(&ril, "[%zsql</a>]", href("%R/rptsql?rn=%d", rn)); } blob_appendf(&ril, "</li>\n"); } db_finalize(&q); Th_Store("report_items", blob_str(&ril)); Th_Render(zScript); blob_reset(&ril); if( g.thTrace ) Th_Trace("END_REPORTLIST<br />\n", -1); style_footer(); } /* |
︙ | ︙ | |||
199 200 201 202 203 204 205 | *(char**)pError = mprintf("access to table \"%s\" is restricted",zArg1); rc = SQLITE_DENY; }else if( !g.perm.RdAddr && strncmp(zArg2, "private_", 8)==0 ){ rc = SQLITE_IGNORE; } break; } | < < < < < | 195 196 197 198 199 200 201 202 203 204 205 206 207 208 | *(char**)pError = mprintf("access to table \"%s\" is restricted",zArg1); rc = SQLITE_DENY; }else if( !g.perm.RdAddr && strncmp(zArg2, "private_", 8)==0 ){ rc = SQLITE_IGNORE; } break; } default: { *(char**)pError = mprintf("only SELECT statements are allowed"); rc = SQLITE_DENY; break; } } return rc; |
︙ | ︙ | |||
260 261 262 263 264 265 266 | ** was found. We don't actually check what's after that. */ return mprintf("Semi-colon detected! " "Only a single SQL statement is allowed"); } } } | | | | 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 | ** was found. We don't actually check what's after that. */ return mprintf("Semi-colon detected! " "Only a single SQL statement is allowed"); } } } /* Compile the statement and check for illegal accesses or syntax errors. */ report_restrict_sql(&zErr); rc = sqlite3_prepare(g.db, zSql, -1, &pStmt, &zTail); if( rc!=SQLITE_OK ){ zErr = mprintf("Syntax error: %s", sqlite3_errmsg(g.db)); } if( !sqlite3_stmt_readonly(pStmt) ){ zErr = mprintf("SQL must not modify the database"); } if( pStmt ){ |
︙ | ︙ | |||
300 301 302 303 304 305 306 | rn = atoi(PD("rn","0")); db_prepare(&q, "SELECT title, sqlcode, owner, cols " "FROM reportfmt WHERE rn=%d",rn); style_header("SQL For Report Format Number %d", rn); if( db_step(&q)!=SQLITE_ROW ){ @ <p>Unknown report number: %d(rn)</p> style_footer(); | < | 291 292 293 294 295 296 297 298 299 300 301 302 303 304 | rn = atoi(PD("rn","0")); db_prepare(&q, "SELECT title, sqlcode, owner, cols " "FROM reportfmt WHERE rn=%d",rn); style_header("SQL For Report Format Number %d", rn); if( db_step(&q)!=SQLITE_ROW ){ @ <p>Unknown report number: %d(rn)</p> style_footer(); return; } zTitle = db_column_text(&q, 0); zSQL = db_column_text(&q, 1); zOwner = db_column_text(&q, 2); zClrKey = db_column_text(&q, 3); @ <table cellpadding=0 cellspacing=0 border=0> |
︙ | ︙ | |||
322 323 324 325 326 327 328 | @ </pre></td> @ <td width=15></td><td valign="top"> output_color_key(zClrKey, 0, "border=0 cellspacing=0 cellpadding=3"); @ </td> @ </tr></table> report_format_hints(); style_footer(); | < | 312 313 314 315 316 317 318 319 320 321 322 323 324 325 | @ </pre></td> @ <td width=15></td><td valign="top"> output_color_key(zClrKey, 0, "border=0 cellspacing=0 cellpadding=3"); @ </td> @ </tr></table> report_format_hints(); style_footer(); } /* ** WEBPAGE: /rptnew ** WEBPAGE: /rptedit */ void view_edit(void){ |
︙ | ︙ | |||
383 384 385 386 387 388 389 | cgi_redirect("reportlist"); return; } if( zTitle && zSQL ){ if( zSQL[0]==0 ){ zErr = "Please supply an SQL query statement"; }else if( (zTitle = trim_string(zTitle))[0]==0 ){ | | | 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 | cgi_redirect("reportlist"); return; } if( zTitle && zSQL ){ if( zSQL[0]==0 ){ zErr = "Please supply an SQL query statement"; }else if( (zTitle = trim_string(zTitle))[0]==0 ){ zErr = "Please supply a title"; }else{ zErr = verify_sql_statement(zSQL); } if( zErr==0 && db_exists("SELECT 1 FROM reportfmt WHERE title=%Q and rn<>%d", zTitle, rn) ){ |
︙ | ︙ | |||
614 615 616 617 618 619 620 621 622 623 624 625 626 627 | @ priority AS 'Pri', @ title AS 'Title', @ description AS '_Description', -- When the column name begins with '_' @ remarks AS '_Remarks' -- content is rendered as wiki @ FROM ticket @ </pre></blockquote> @ } /* ** The state of the report generation. */ struct GenerateHTML { int rn; /* Report number */ | > > > > > > > > > > > > > | 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 | @ priority AS 'Pri', @ title AS 'Title', @ description AS '_Description', -- When the column name begins with '_' @ remarks AS '_Remarks' -- content is rendered as wiki @ FROM ticket @ </pre></blockquote> @ @ <p>Or, to see part of the description on the same row, use the @ <b>wiki()</b> function with some string manipulation. Using the @ <b>tkt()</b> function on the ticket number will also generate a linked @ field, but without the extra <i>edit</i> column: @ </p> @ <blockquote><pre> @ SELECT @ tkt(tn) AS '', @ title AS 'Title', @ wiki(substr(description,0,80)) AS 'Description' @ FROM ticket @ </pre></blockquote> @ } /* ** The state of the report generation. */ struct GenerateHTML { int rn; /* Report number */ |
︙ | ︙ | |||
637 638 639 640 641 642 643 | /* ** The callback function for db_query */ static int generate_html( void *pUser, /* Pointer to output state */ int nArg, /* Number of columns in this result row */ | | | | | 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 | /* ** The callback function for db_query */ static int generate_html( void *pUser, /* Pointer to output state */ int nArg, /* Number of columns in this result row */ char **azArg, /* Text of data in all columns */ char **azName /* Names of the columns */ ){ struct GenerateHTML *pState = (struct GenerateHTML*)pUser; int i; const char *zTid; /* Ticket UUID. (value of column named '#') */ char *zBg = 0; /* Use this background color */ /* Do initialization */ if( pState->nCount==0 ){ /* Turn off the authorizer. It is no longer doing anything since the ** query has already been prepared. */ |
︙ | ︙ | |||
697 698 699 700 701 702 703 | } /* The first time this routine is called, output a table header */ @ <thead><tr> zTid = 0; for(i=0; i<nArg; i++){ | | | 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 | } /* The first time this routine is called, output a table header */ @ <thead><tr> zTid = 0; for(i=0; i<nArg; i++){ char *zName = azName[i]; if( i==pState->iBg ) continue; if( pState->iNewRow>=0 && i>=pState->iNewRow ){ if( g.perm.Write && zTid ){ @ <th> </th> zTid = 0; } if( zName[0]=='_' ) zName++; |
︙ | ︙ | |||
740 741 742 743 744 745 746 | /* Output the data for this entry from the database */ zBg = pState->iBg>=0 ? azArg[pState->iBg] : 0; if( zBg==0 ) zBg = "white"; @ <tr style="background-color:%h(zBg)"> zTid = 0; for(i=0; i<nArg; i++){ | | | 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 | /* Output the data for this entry from the database */ zBg = pState->iBg>=0 ? azArg[pState->iBg] : 0; if( zBg==0 ) zBg = "white"; @ <tr style="background-color:%h(zBg)"> zTid = 0; for(i=0; i<nArg; i++){ char *zData; if( i==pState->iBg ) continue; zData = azArg[i]; if( zData==0 ) zData = ""; if( pState->iNewRow>=0 && i>=pState->iNewRow ){ if( zTid && g.perm.Write ){ @ <td valign="top">%z(href("%R/tktedit/%h",zTid))edit</a></td> zTid = 0; |
︙ | ︙ | |||
802 803 804 805 806 807 808 | /* ** Output a row as a tab-separated line of text. */ static int output_tab_separated( void *pUser, /* Pointer to row-count integer */ int nArg, /* Number of columns in this result row */ | | | | 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 | /* ** Output a row as a tab-separated line of text. */ static int output_tab_separated( void *pUser, /* Pointer to row-count integer */ int nArg, /* Number of columns in this result row */ char **azArg, /* Text of data in all columns */ char **azName /* Names of the columns */ ){ int *pCount = (int*)pUser; int i; if( *pCount==0 ){ for(i=0; i<nArg; i++){ output_no_tabs(azName[i]); |
︙ | ︙ | |||
827 828 829 830 831 832 833 | } /* ** Generate HTML that describes a color key. */ void output_color_key(const char *zClrKey, int horiz, char *zTabArgs){ int i, j, k; | | < | | 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 | } /* ** Generate HTML that describes a color key. */ void output_color_key(const char *zClrKey, int horiz, char *zTabArgs){ int i, j, k; char *zSafeKey, *zToFree; while( fossil_isspace(*zClrKey) ) zClrKey++; if( zClrKey[0]==0 ) return; @ <table %s(zTabArgs)> if( horiz ){ @ <tr> } zToFree = zSafeKey = mprintf("%h", zClrKey); while( zSafeKey[0] ){ while( fossil_isspace(*zSafeKey) ) zSafeKey++; for(i=0; zSafeKey[i] && !fossil_isspace(zSafeKey[i]); i++){} for(j=i; fossil_isspace(zSafeKey[j]); j++){} for(k=j; zSafeKey[k] && zSafeKey[k]!='\n' && zSafeKey[k]!='\r'; k++){} if( !horiz ){ cgi_printf("<tr style=\"background-color: %.*s;\"><td>%.*s</td></tr>\n", |
︙ | ︙ | |||
861 862 863 864 865 866 867 | @ </table> } /* ** Execute a single read-only SQL statement. Invoke xCallback() on each ** row. */ | | < | | | | 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 | @ </table> } /* ** Execute a single read-only SQL statement. Invoke xCallback() on each ** row. */ int sqlite3_exec_readonly( sqlite3 *db, /* The database on which the SQL executes */ const char *zSql, /* The SQL to be executed */ sqlite3_callback xCallback, /* Invoke this callback routine */ void *pArg, /* First argument to xCallback() */ char **pzErrMsg /* Write error messages here */ ){ int rc = SQLITE_OK; /* Return code */ const char *zLeftover; /* Tail of unprocessed SQL */ sqlite3_stmt *pStmt = 0; /* The current SQL statement */ char **azCols = 0; /* Names of result columns */ int nCol; /* Number of columns of output */ char **azVals = 0; /* Text of all output columns */ int i; /* Loop counter */ pStmt = 0; rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zLeftover); assert( rc==SQLITE_OK || pStmt==0 ); if( rc!=SQLITE_OK ){ return rc; |
︙ | ︙ | |||
901 902 903 904 905 906 907 | nCol = sqlite3_column_count(pStmt); azVals = fossil_malloc(2*nCol*sizeof(const char*) + 1); while( (rc = sqlite3_step(pStmt))==SQLITE_ROW ){ if( azCols==0 ){ azCols = &azVals[nCol]; for(i=0; i<nCol; i++){ | | | | | 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 | nCol = sqlite3_column_count(pStmt); azVals = fossil_malloc(2*nCol*sizeof(const char*) + 1); while( (rc = sqlite3_step(pStmt))==SQLITE_ROW ){ if( azCols==0 ){ azCols = &azVals[nCol]; for(i=0; i<nCol; i++){ azCols[i] = (char *)sqlite3_column_name(pStmt, i); } } for(i=0; i<nCol; i++){ azVals[i] = (char *)sqlite3_column_text(pStmt, i); } if( xCallback(pArg, nCol, azVals, azCols) ){ break; } } rc = sqlite3_finalize(pStmt); fossil_free(azVals); return rc; } /* ** Output Javascript code that will enables sorting of the table with ** the id zTableId by clicking. ** |
︙ | ︙ | |||
1026 1027 1028 1029 1030 1031 1032 | } tabs = P("tablist")!=0; /* view_add_functions(tabs); */ db_prepare(&q, "SELECT title, sqlcode, owner, cols FROM reportfmt WHERE rn=%d", rn); if( db_step(&q)!=SQLITE_ROW ){ cgi_redirect("reportlist"); | < | 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 | } tabs = P("tablist")!=0; /* view_add_functions(tabs); */ db_prepare(&q, "SELECT title, sqlcode, owner, cols FROM reportfmt WHERE rn=%d", rn); if( db_step(&q)!=SQLITE_ROW ){ cgi_redirect("reportlist"); return; } zTitle = db_column_malloc(&q, 0); zSql = db_column_malloc(&q, 1); zOwner = db_column_malloc(&q, 2); zClrKey = db_column_malloc(&q, 3); db_finalize(&q); |
︙ | ︙ | |||
1055 1056 1057 1058 1059 1060 1061 | } count = 0; if( !tabs ){ struct GenerateHTML sState; db_multi_exec("PRAGMA empty_result_callbacks=ON"); | | | | | | | 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 | } count = 0; if( !tabs ){ struct GenerateHTML sState; db_multi_exec("PRAGMA empty_result_callbacks=ON"); style_submenu_element("Raw", "Raw", "rptview?tablist=1&%h", PD("QUERY_STRING","")); if( g.perm.Admin || (g.perm.TktFmt && g.zLogin && fossil_strcmp(g.zLogin,zOwner)==0) ){ style_submenu_element("Edit", "Edit", "rptedit?rn=%d", rn); } if( g.perm.TktFmt ){ style_submenu_element("SQL", "SQL", "rptsql?rn=%d",rn); } if( g.perm.NewTkt ){ style_submenu_element("New Ticket", "Create a new ticket", "%s/tktnew", g.zTop); } style_header(zTitle); output_color_key(zClrKey, 1, "border=\"0\" cellpadding=\"3\" cellspacing=\"0\" class=\"report\""); @ <table border="1" cellpadding="2" cellspacing="0" class="report" @ id="reportTable"> sState.rn = rn; sState.nCount = 0; report_restrict_sql(&zErr1); sqlite3_exec_readonly(g.db, zSql, generate_html, &sState, &zErr2); report_unrestrict_sql(); @ </tbody></table> if( zErr1 ){ @ <p class="reportError">Error: %h(zErr1)</p> }else if( zErr2 ){ @ <p class="reportError">Error: %h(zErr2)</p> } output_table_sorting_javascript("reportTable",""); style_footer(); }else{ report_restrict_sql(&zErr1); sqlite3_exec_readonly(g.db, zSql, output_tab_separated, &count, &zErr2); report_unrestrict_sql(); cgi_set_content_type("text/plain"); } } /* ** report number for full table ticket export |
︙ | ︙ | |||
1167 1168 1169 1170 1171 1172 1173 | } for(j=i; fossil_isspace(z[j]); j++){} if( j>i ){ fossil_print("%*s", j-i, ""); } z += j; } | | | | | 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 | } for(j=i; fossil_isspace(z[j]); j++){} if( j>i ){ fossil_print("%*s", j-i, ""); } z += j; } break; } } /* ** Output a row as a tab-separated line of text. */ int output_separated_file( void *pUser, /* Pointer to row-count integer */ int nArg, /* Number of columns in this result row */ char **azArg, /* Text of data in all columns */ char **azName /* Names of the columns */ ){ int *pCount = (int*)pUser; int i; if( *pCount==0 ){ for(i=0; i<nArg; i++){ output_no_tabs_file(azName[i]); |
︙ | ︙ | |||
1202 1203 1204 1205 1206 1207 1208 | } /* ** Generate a report. The rn query parameter is the report number. ** The output is written to stdout as flat file. The zFilter parameter ** is a full WHERE-condition. */ | | | 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 | } /* ** Generate a report. The rn query parameter is the report number. ** The output is written to stdout as flat file. The zFilter parameter ** is a full WHERE-condition. */ void rptshow( const char *zRep, const char *zSepIn, const char *zFilter, tTktShowEncoding enc ){ Stmt q; char *zSql; |
︙ | ︙ | |||
1241 1242 1243 1244 1245 1246 1247 | if( zFilter ){ zSql = mprintf("SELECT * FROM (%s) WHERE %s",zSql,zFilter); } count = 0; tktEncode = enc; zSep = zSepIn; report_restrict_sql(&zErr1); | | | 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 | if( zFilter ){ zSql = mprintf("SELECT * FROM (%s) WHERE %s",zSql,zFilter); } count = 0; tktEncode = enc; zSep = zSepIn; report_restrict_sql(&zErr1); sqlite3_exec_readonly(g.db, zSql, output_separated_file, &count, &zErr2); report_unrestrict_sql(); if( zFilter ){ free(zSql); } } |
Changes to src/rss.c.
︙ | ︙ | |||
158 159 160 161 162 163 164 | @ <link>%s(g.zBaseURL)</link> @ <description>%h(zProjectDescr)</description> @ <pubDate>%s(zPubDate)</pubDate> @ <generator>Fossil version %s(MANIFEST_VERSION) %s(MANIFEST_DATE)</generator> free(zPubDate); db_prepare(&q, blob_str(&bSQL)); blob_reset( &bSQL ); | | | 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 | @ <link>%s(g.zBaseURL)</link> @ <description>%h(zProjectDescr)</description> @ <pubDate>%s(zPubDate)</pubDate> @ <generator>Fossil version %s(MANIFEST_VERSION) %s(MANIFEST_DATE)</generator> free(zPubDate); db_prepare(&q, blob_str(&bSQL)); blob_reset( &bSQL ); while( db_step(&q)==SQLITE_ROW && nLine<=nLimit ){ const char *zId = db_column_text(&q, 1); const char *zCom = db_column_text(&q, 3); const char *zAuthor = db_column_text(&q, 4); char *zPrefix = ""; char *zDate; int nChild = db_column_int(&q, 5); int nParent = db_column_int(&q, 6); |
︙ | ︙ | |||
195 196 197 198 199 200 201 202 203 204 205 | nLine++; } db_finalize(&q); @ </channel> @ </rss> if( zFreeProjectName != 0 ){ free( zFreeProjectName ); } } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 195 196 197 198 199 200 201 202 203 204 205 | nLine++; } db_finalize(&q); @ </channel> @ </rss> if( zFreeProjectName != 0 ){ free( zFreeProjectName ); } } |
Changes to src/schema.c.
︙ | ︙ | |||
19 20 21 22 23 24 25 | */ #include "config.h" #include "schema.h" /* ** The database schema for the ~/.fossil configuration database. */ | | | 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | */ #include "config.h" #include "schema.h" /* ** The database schema for the ~/.fossil configuration database. */ const char zConfigSchema[] = @ -- This file contains the schema for the database that is kept in the @ -- ~/.fossil file and that stores information about the users setup. @ -- @ CREATE TABLE global_config( @ name TEXT PRIMARY KEY, @ value TEXT @ ); |
︙ | ︙ | |||
48 49 50 51 52 53 54 | #define CONTENT_SCHEMA "2" #define AUX_SCHEMA "2011-04-25 19:50" #endif /* INTERFACE */ /* | | | | | | 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 | #define CONTENT_SCHEMA "2" #define AUX_SCHEMA "2011-04-25 19:50" #endif /* INTERFACE */ /* ** The schema for a repository database. ** ** Schema1[] contains parts of the schema that are fixed and unchanging ** across versions. Schema2[] contains parts of the schema that can ** change from one version to the next. The information in Schema2[] ** is reconstructed from the information in Schema1[] by the "rebuild" ** operation. */ const char zRepositorySchema1[] = @ -- The BLOB and DELTA tables contain all records held in the repository. @ -- @ -- The BLOB.CONTENT column is always compressed using zlib. This @ -- column might hold the full text of the record or it might hold @ -- a delta that is able to reconstruct the record from some other @ -- record. If BLOB.CONTENT holds a delta, then a DELTA table entry @ -- will exist for the record and that entry will point to another @ -- entry that holds the source of the delta. Deltas can be chained. @ -- @ -- The blob and delta tables collectively hold the "global state" of @ -- a Fossil repository. @ -- @ CREATE TABLE blob( @ rid INTEGER PRIMARY KEY, -- Record ID @ rcvid INTEGER, -- Origin of this record @ size INTEGER, -- Size of content. -1 for a phantom. @ uuid TEXT UNIQUE NOT NULL, -- SHA1 hash of the content @ content BLOB, -- Compressed content of this record @ CHECK( length(uuid)==40 AND rid>0 ) @ ); @ CREATE TABLE delta( @ rid INTEGER PRIMARY KEY, -- Record ID @ srcid INTEGER NOT NULL REFERENCES blob -- Record holding source document @ ); @ CREATE INDEX delta_i1 ON delta(srcid); @ @ ------------------------------------------------------------------------- @ -- The BLOB and DELTA tables above hold the "global state" of a Fossil @ -- project; the stuff that is normally exchanged during "sync". The @ -- "local state" of a repository is contained in the remaining tables of @ -- the zRepositorySchema1 string. @ ------------------------------------------------------------------------- @ @ -- Whenever new blobs are received into the repository, an entry @ -- in this table records the source of the blob. @ -- @ CREATE TABLE rcvfrom( @ rcvid INTEGER PRIMARY KEY, -- Received-From ID |
︙ | ︙ | |||
170 171 172 173 174 175 176 | @ cols TEXT, -- A color-key specification @ sqlcode TEXT -- An SQL SELECT statement for this report @ ); @ @ -- Some ticket content (such as the originators email address or contact @ -- information) needs to be obscured to protect privacy. This is achieved @ -- by storing an SHA1 hash of the content. For display, the hash is | | | | 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 | @ cols TEXT, -- A color-key specification @ sqlcode TEXT -- An SQL SELECT statement for this report @ ); @ @ -- Some ticket content (such as the originators email address or contact @ -- information) needs to be obscured to protect privacy. This is achieved @ -- by storing an SHA1 hash of the content. For display, the hash is @ -- mapped back into the original text using this table. @ -- @ -- This table contains sensitive information and should not be shared @ -- with unauthorized users. @ -- @ CREATE TABLE concealed( @ hash TEXT PRIMARY KEY, -- The SHA1 hash of content @ mtime DATE, -- Time created. Seconds since 1970 @ content TEXT -- Content intended to be concealed @ ); @ @ -- The application ID helps the unix "file" command to identify the @ -- database as a fossil repository. @ PRAGMA application_id=252006673; ; /* ** The default reportfmt entry for the schema. This is in an extra ** script so that (configure reset) can install the default report. */ const char zRepositorySchemaDefaultReports[] = @ INSERT INTO reportfmt(title,mtime,cols,sqlcode) @ VALUES('All Tickets',julianday('1970-01-01'),'#ffffff Key: @ #f2dcdc Active @ #e8e8e8 Review @ #cfe8bd Fixed @ #bde5d6 Tested @ #cacae5 Deferred @ #c8c8c8 Closed','SELECT |
︙ | ︙ | |||
319 320 321 322 323 324 325 | @ -- @ CREATE TABLE unsent( @ rid INTEGER PRIMARY KEY -- Record ID of the phantom @ ); @ @ -- Each baseline or manifest can have one or more tags. A tag @ -- is defined by a row in the next table. | | | | 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 | @ -- @ CREATE TABLE unsent( @ rid INTEGER PRIMARY KEY -- Record ID of the phantom @ ); @ @ -- Each baseline or manifest can have one or more tags. A tag @ -- is defined by a row in the next table. @ -- @ -- Wiki pages are tagged with "wiki-NAME" where NAME is the name of @ -- the wiki page. Tickets changes are tagged with "ticket-UUID" where @ -- UUID is the indentifier of the ticket. Tags used to assign symbolic @ -- names to baselines are branches are of the form "sym-NAME" where @ -- NAME is the symbolic name. @ -- @ CREATE TABLE tag( @ tagid INTEGER PRIMARY KEY, -- Numeric tag ID @ tagname TEXT UNIQUE -- Tag name. |
︙ | ︙ |
Changes to src/search.c.
︙ | ︙ | |||
133 134 135 136 137 138 139 | while( !isBoundary[zDoc[i]&0xff] ){ i++; } } /* Every term must be seen or else the score is zero */ for(j=0; j<p->nTerm; j++){ if( !seen[j] ) return 0; } | | | 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 | while( !isBoundary[zDoc[i]&0xff] ){ i++; } } /* Every term must be seen or else the score is zero */ for(j=0; j<p->nTerm; j++){ if( !seen[j] ) return 0; } return score; } /* ** This is an SQLite function that scores its input using ** a pre-computed pattern. */ |
︙ | ︙ |
Changes to src/setup.c.
︙ | ︙ | |||
247 248 249 250 251 252 253 | @ <td><i>Developer:</i> Inherit privileges of @ user <tt>developer</tt></td></tr> @ <tr><th valign="top">w</th> @ <td><i>Write-Tkt:</i> Edit tickets</td></tr> @ <tr><th valign="top">x</th> @ <td><i>Private:</i> Push and/or pull private branches</td></tr> @ <tr><th valign="top">z</th> | | > > > | 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 | @ <td><i>Developer:</i> Inherit privileges of @ user <tt>developer</tt></td></tr> @ <tr><th valign="top">w</th> @ <td><i>Write-Tkt:</i> Edit tickets</td></tr> @ <tr><th valign="top">x</th> @ <td><i>Private:</i> Push and/or pull private branches</td></tr> @ <tr><th valign="top">z</th> @ <td><i>Zip download:</i> Download a baseline via the @ <tt>/zip</tt> URL even without @ check<span class="capability">o</span>ut @ and <span class="capability">h</span>istory permissions</td></tr> @ </table> @ </li> @ @ <li><p> @ Every user, logged in or not, inherits the privileges of @ <span class="usertype">nobody</span>. @ </p></li> |
︙ | ︙ | |||
275 276 277 278 279 280 281 | @ <span class="usertype">anonymous</span>, and @ <span class="usertype">nobody</span>. @ </p></li> @ @ </ol> @ </td></tr></table> style_footer(); | < | 278 279 280 281 282 283 284 285 286 287 288 289 290 291 | @ <span class="usertype">anonymous</span>, and @ <span class="usertype">nobody</span>. @ </p></li> @ @ </ol> @ </td></tr></table> style_footer(); } /* ** Return true if zPw is a valid password string. A valid ** password string is: ** ** (1) A zero-length string, or |
︙ | ︙ | |||
596 597 598 599 600 601 602 | } @ </table> @ </div></form> @ </div> @ <h2>Privileges And Capabilities:</h2> @ <ul> if( higherUser ){ | | | 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 | } @ </table> @ </div></form> @ </div> @ <h2>Privileges And Capabilities:</h2> @ <ul> if( higherUser ){ @ <li><p class=missingPriv"> @ User %h(zLogin) has Setup privileges and you only have Admin privileges @ so you are not permitted to make changes to %h(zLogin). @ </p></li> @ } @ <li><p> @ The <span class="capability">Setup</span> user can make arbitrary |
︙ | ︙ | |||
855 856 857 858 859 860 861 | */ static void multiple_choice_attribute( const char *zLabel, /* The text label on the menu */ const char *zVar, /* The corresponding row in the VAR table */ const char *zQP, /* The query parameter */ const char *zDflt, /* Default value if VAR table entry does not exist */ int nChoice, /* Number of choices */ | | | | 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 | */ static void multiple_choice_attribute( const char *zLabel, /* The text label on the menu */ const char *zVar, /* The corresponding row in the VAR table */ const char *zQP, /* The query parameter */ const char *zDflt, /* Default value if VAR table entry does not exist */ int nChoice, /* Number of choices */ const char **azChoice /* Choices. 2 per choice: (VAR value, Display) */ ){ const char *z = db_get(zVar, (char*)zDflt); const char *zQ = P(zQP); int i; if( zQ && fossil_strcmp(zQ,z)!=0){ login_verify_csrf_secret(); db_set(zVar, zQ, 0); z = zQ; } @ <select size="1" name="%s(zQP)" id="id%s(zQP)"> for(i=0; i<nChoice*2; i+=2){ const char *zSel = fossil_strcmp(azChoice[i],z)==0 ? " selected" : ""; @ <option value="%h(azChoice[i])"%s(zSel)>%h(azChoice[i+1])</option> } @ </select> } /* ** WEBPAGE: setup_access */ void setup_access(void){ |
︙ | ︙ | |||
961 962 963 964 965 966 967 | "30", 0); @ <p>Fossil tries to spend less than this many seconds gathering @ the out-bound data of sync, clone, and pull packets. @ If the client request takes longer, a partial reply is given similar @ to the download packet limit. 30s is a reasonable default.</p> | < < < < < < < < < < < | | < | | 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 | "30", 0); @ <p>Fossil tries to spend less than this many seconds gathering @ the out-bound data of sync, clone, and pull packets. @ If the client request takes longer, a partial reply is given similar @ to the download packet limit. 30s is a reasonable default.</p> @ <hr /> onoff_attribute( "Enable hyperlinks for \"nobody\" based on User-Agent and Javascript", "auto-hyperlink", "autohyperlink", 1, 0); @ <p>Enable hyperlinks (the equivalent of the "h" permission) for all users @ including user "nobody", as long as (1) the User-Agent string in the @ HTTP header indicates that the request is coming from an actual human @ being and not a a robot or spider and (2) the user agent is able to @ run Javascript in order to set the href= attribute of hyperlinks. Bots @ and spiders can forge a User-Agent string that makes them seem to be a @ normal browser and they can run javascript just like browsers. But most @ bots do not go to that much trouble so this is normally an effective defense.</p> @ @ <p>You do not normally want a bot to walk your entire repository because @ if it does, your server will end up computing diffs and annotations for @ every historical version of every file and creating ZIPs and tarballs of @ every historical check-in, which can use a lot of CPU and bandwidth @ even for relatively small projects.</p> @ @ <p>Additional parameters that control this behavior:</p> @ <blockquote> onoff_attribute("Require mouse movement before enabling hyperlinks", "auto-hyperlink-mouseover", "ahmo", 0, 0); @ <br> entry_attribute("Delay before enabling hyperlinks (milliseconds)", 5, "auto-hyperlink-delay", "ah-delay", "10", 0); |
︙ | ︙ | |||
1159 1160 1161 1162 1163 1164 1165 | /* ** WEBPAGE: setup_timeline */ void setup_timeline(void){ double tmDiff; char zTmDiff[20]; | | | 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 | /* ** WEBPAGE: setup_timeline */ void setup_timeline(void){ double tmDiff; char zTmDiff[20]; static const char *azTimeFormats[] = { "0", "HH:MM", "1", "HH:MM:SS", "2", "YYYY-MM-DD HH:MM", "3", "YYMMDD HH:MM" }; login_check_credentials(); if( !g.perm.Setup ){ |
︙ | ︙ | |||
1185 1186 1187 1188 1189 1190 1191 | @ <p>In timeline displays, check-in comments can be displayed with or @ without block markup (paragraphs, tables, etc.)</p> @ <hr /> onoff_attribute("Plaintext comments on timelines", "timeline-plaintext", "tpt", 0, 0); @ <p>In timeline displays, check-in comments are displayed literally, | | < | 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 | @ <p>In timeline displays, check-in comments can be displayed with or @ without block markup (paragraphs, tables, etc.)</p> @ <hr /> onoff_attribute("Plaintext comments on timelines", "timeline-plaintext", "tpt", 0, 0); @ <p>In timeline displays, check-in comments are displayed literally, @ without any wiki or HTML interpretation.</p> @ <hr /> onoff_attribute("Use Universal Coordinated Time (UTC)", "timeline-utc", "utc", 1, 0); @ <p>Show times as UTC (also sometimes called Greenwich Mean Time (GMT) or @ Zulu) instead of in local time. On this server, local time is currently tmDiff = db_double(0.0, "SELECT julianday('now')"); |
︙ | ︙ | |||
1489 1490 1491 1492 1493 1494 1495 | @ <input type="submit" name="submit" value="Apply Changes" /> @ <input type="submit" name="clear" value="Revert To Default" /> @ </div></form> @ <hr /> @ The default header is shown below for reference. Other examples @ of headers can be seen on the <a href="setup_skin">skins page</a>. @ See also the <a href="setup_editcss">CSS</a> and | | | 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 | @ <input type="submit" name="submit" value="Apply Changes" /> @ <input type="submit" name="clear" value="Revert To Default" /> @ </div></form> @ <hr /> @ The default header is shown below for reference. Other examples @ of headers can be seen on the <a href="setup_skin">skins page</a>. @ See also the <a href="setup_editcss">CSS</a> and @ <a href="setup_footer">footer</a> editing screeens. @ <blockquote><pre> @ %h(zDefaultHeader) @ </pre></blockquote> style_footer(); db_end_transaction(0); } |
︙ | ︙ |
Changes to src/shell.c.
︙ | ︙ | |||
1145 1146 1147 1148 1149 1150 1151 | if( pArg && pArg->out && db && pArg->pStmt ){ iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_FULLSCAN_STEP, bReset); fprintf(pArg->out, "Fullscan Steps: %d\n", iCur); iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_SORT, bReset); fprintf(pArg->out, "Sort Operations: %d\n", iCur); iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_AUTOINDEX, bReset); fprintf(pArg->out, "Autoindex Inserts: %d\n", iCur); | > | | > | 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 | if( pArg && pArg->out && db && pArg->pStmt ){ iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_FULLSCAN_STEP, bReset); fprintf(pArg->out, "Fullscan Steps: %d\n", iCur); iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_SORT, bReset); fprintf(pArg->out, "Sort Operations: %d\n", iCur); iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_AUTOINDEX, bReset); fprintf(pArg->out, "Autoindex Inserts: %d\n", iCur); if( sqlite3_libversion_number()>=3008000 ){ iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_VM_STEP, bReset); fprintf(pArg->out, "Virtual Machine Steps: %d\n", iCur); } } return 0; } /* ** Parameter azArray points to a zero-terminated array of strings. zStr |
︙ | ︙ | |||
2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 | return; } rc = sqlite3_open(zNewDb, &newDb); if( rc ){ fprintf(stderr, "Cannot create output database: %s\n", sqlite3_errmsg(newDb)); }else{ sqlite3_exec(newDb, "BEGIN EXCLUSIVE;", 0, 0, 0); tryToCloneSchema(p, newDb, "type='table'", tryToCloneData); tryToCloneSchema(p, newDb, "type!='table'", 0); sqlite3_exec(newDb, "COMMIT;", 0, 0, 0); } sqlite3_close(newDb); } /* ** If an input line begins with "." then invoke this routine to ** process that line. | > > | 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 | return; } rc = sqlite3_open(zNewDb, &newDb); if( rc ){ fprintf(stderr, "Cannot create output database: %s\n", sqlite3_errmsg(newDb)); }else{ sqlite3_exec(p->db, "PRAGMA writable_schema=ON;", 0, 0, 0); sqlite3_exec(newDb, "BEGIN EXCLUSIVE;", 0, 0, 0); tryToCloneSchema(p, newDb, "type='table'", tryToCloneData); tryToCloneSchema(p, newDb, "type!='table'", 0); sqlite3_exec(newDb, "COMMIT;", 0, 0, 0); sqlite3_exec(p->db, "PRAGMA writable_schema=OFF;", 0, 0, 0); } sqlite3_close(newDb); } /* ** If an input line begins with "." then invoke this routine to ** process that line. |
︙ | ︙ | |||
3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 | { "pending_byte", SQLITE_TESTCTRL_PENDING_BYTE }, { "assert", SQLITE_TESTCTRL_ASSERT }, { "always", SQLITE_TESTCTRL_ALWAYS }, { "reserve", SQLITE_TESTCTRL_RESERVE }, { "optimizations", SQLITE_TESTCTRL_OPTIMIZATIONS }, { "iskeyword", SQLITE_TESTCTRL_ISKEYWORD }, { "scratchmalloc", SQLITE_TESTCTRL_SCRATCHMALLOC }, }; int testctrl = -1; int rc = 0; int i, n; open_db(p, 0); /* convert testctrl text option to value. allow any unique prefix | > | 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 | { "pending_byte", SQLITE_TESTCTRL_PENDING_BYTE }, { "assert", SQLITE_TESTCTRL_ASSERT }, { "always", SQLITE_TESTCTRL_ALWAYS }, { "reserve", SQLITE_TESTCTRL_RESERVE }, { "optimizations", SQLITE_TESTCTRL_OPTIMIZATIONS }, { "iskeyword", SQLITE_TESTCTRL_ISKEYWORD }, { "scratchmalloc", SQLITE_TESTCTRL_SCRATCHMALLOC }, { "byteorder", SQLITE_TESTCTRL_BYTEORDER }, }; int testctrl = -1; int rc = 0; int i, n; open_db(p, 0); /* convert testctrl text option to value. allow any unique prefix |
︙ | ︙ | |||
3061 3062 3063 3064 3065 3066 3067 | } else { fprintf(stderr,"Error: testctrl %s takes a single int option\n", azArg[1]); } break; /* sqlite3_test_control(int) */ | | | > | 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 | } else { fprintf(stderr,"Error: testctrl %s takes a single int option\n", azArg[1]); } break; /* sqlite3_test_control(int) */ case SQLITE_TESTCTRL_PRNG_SAVE: case SQLITE_TESTCTRL_PRNG_RESTORE: case SQLITE_TESTCTRL_PRNG_RESET: case SQLITE_TESTCTRL_BYTEORDER: if( nArg==2 ){ rc = sqlite3_test_control(testctrl); fprintf(p->out, "%d (0x%08x)\n", rc, rc); } else { fprintf(stderr,"Error: testctrl %s takes no options\n", azArg[1]); } break; |
︙ | ︙ |
Changes to src/shun.c.
︙ | ︙ | |||
67 68 69 70 71 72 73 | } } style_header("Shunned Artifacts"); if( zUuid && P("sub") ){ login_verify_csrf_secret(); db_multi_exec("DELETE FROM shun WHERE uuid='%s'", zUuid); if( db_exists("SELECT 1 FROM blob WHERE uuid='%s'", zUuid) ){ | | | 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 | } } style_header("Shunned Artifacts"); if( zUuid && P("sub") ){ login_verify_csrf_secret(); db_multi_exec("DELETE FROM shun WHERE uuid='%s'", zUuid); if( db_exists("SELECT 1 FROM blob WHERE uuid='%s'", zUuid) ){ @ <p class="noMoreShun">Artifact @ <a href="%s(g.zTop)/artifact/%s(zUuid)">%s(zUuid)</a> is no @ longer being shunned.</p> }else{ @ <p class="noMoreShun">Artifact %s(zUuid) will no longer @ be shunned. But it does not exist in the repository. It @ may be necessary to rebuild the repository using the @ <b>fossil rebuild</b> command-line before the artifact content |
︙ | ︙ | |||
105 106 107 108 109 110 111 | db_multi_exec("DELETE FROM tagxref WHERE tagid=%d", tagid); } } @ <p>A shunned artifact will not be pushed nor accepted in a pull and the @ artifact content will be purged from the repository the next time the @ repository is rebuilt. A list of shunned artifacts can be seen at the @ bottom of this page.</p> | | | | 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 | db_multi_exec("DELETE FROM tagxref WHERE tagid=%d", tagid); } } @ <p>A shunned artifact will not be pushed nor accepted in a pull and the @ artifact content will be purged from the repository the next time the @ repository is rebuilt. A list of shunned artifacts can be seen at the @ bottom of this page.</p> @ @ <a name="addshun"></a> @ <p>To shun an artifact, enter its artifact ID (the 40-character SHA1 @ hash of the artifact) in the @ following box and press the "Shun" button. This will cause the artifact @ to be removed from the repository and will prevent the artifact from being @ readded to the repository by subsequent sync operation.</p> @ @ <p>Note that you must enter the full 40-character artifact ID, not @ an abbreviation or a symbolic tag.</p> @ @ <p>Warning: Shunning should only be used to remove inappropriate content @ from the repository. Inappropriate content includes such things as @ spam added to Wiki, files that violate copyright or patent agreements, @ or artifacts that by design or accident interfere with the processing @ of the repository. Do not shun artifacts merely to remove them from @ sight - set the "hidden" tag on such artifacts instead.</p> @ @ <blockquote> @ <form method="post" action="%s(g.zTop)/%s(g.zPath)"><div> login_insert_csrf_secret(); @ <input type="text" name="uuid" value="%h(PD("shun",""))" size="50" /> @ <input type="submit" name="add" value="Shun" /> @ </div></form> @ </blockquote> |
︙ | ︙ | |||
157 158 159 160 161 162 163 | @ @ <blockquote> @ <form method="post" action="%s(g.zTop)/%s(g.zPath)"><div> login_insert_csrf_secret(); @ <input type="submit" name="rebuild" value="Rebuild" /> @ </div></form> @ </blockquote> | | | | 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 | @ @ <blockquote> @ <form method="post" action="%s(g.zTop)/%s(g.zPath)"><div> login_insert_csrf_secret(); @ <input type="submit" name="rebuild" value="Rebuild" /> @ </div></form> @ </blockquote> @ @ <hr /><p>Shunned Artifacts:</p> @ <blockquote><p> db_prepare(&q, "SELECT uuid, EXISTS(SELECT 1 FROM blob WHERE blob.uuid=shun.uuid)" " FROM shun ORDER BY uuid"); while( db_step(&q)==SQLITE_ROW ){ const char *zUuid = db_column_text(&q, 0); int stillExists = db_column_int(&q, 1); cnt++; if( stillExists ){ |
︙ | ︙ | |||
226 227 228 229 230 231 232 | login_needed(); } style_header("Content Sources"); if( ofst>0 ){ style_submenu_element("Newer", "Newer", "rcvfromlist?ofst=%d", ofst>30 ? ofst-30 : 0); } | | | 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 | login_needed(); } style_header("Content Sources"); if( ofst>0 ){ style_submenu_element("Newer", "Newer", "rcvfromlist?ofst=%d", ofst>30 ? ofst-30 : 0); } db_prepare(&q, "SELECT rcvid, login, datetime(rcvfrom.mtime), rcvfrom.ipaddr" " FROM rcvfrom LEFT JOIN user USING(uid)" " ORDER BY rcvid DESC LIMIT 31 OFFSET %d", ofst ); @ <p>Whenever new artifacts are added to the repository, either by @ push or using the web interface, an entry is made in the RCVFROM table |
︙ | ︙ | |||
285 286 287 288 289 290 291 | Stmt q; login_check_credentials(); if( !g.perm.Admin ){ login_needed(); } style_header("Content Source %d", rcvid); | | | 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 | Stmt q; login_check_credentials(); if( !g.perm.Admin ){ login_needed(); } style_header("Content Source %d", rcvid); db_prepare(&q, "SELECT login, datetime(rcvfrom.mtime), rcvfrom.ipaddr" " FROM rcvfrom LEFT JOIN user USING(uid)" " WHERE rcvid=%d", rcvid ); @ <table cellspacing="15" cellpadding="0" border="0"> @ <tr><th valign="top" align="right">rcvid:</th> |
︙ | ︙ |
Changes to src/sqlcmd.c.
︙ | ︙ | |||
40 41 42 43 44 45 46 | zName = (const char*)sqlite3_value_text(argv[0]); if( zName==0 ) return; g.db = sqlite3_context_db_handle(context); g.repositoryOpen = 1; rid = name_to_rid(zName); if( rid==0 ) return; if( content_get(rid, &cx) ){ | | | 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | zName = (const char*)sqlite3_value_text(argv[0]); if( zName==0 ) return; g.db = sqlite3_context_db_handle(context); g.repositoryOpen = 1; rid = name_to_rid(zName); if( rid==0 ) return; if( content_get(rid, &cx) ){ sqlite3_result_blob(context, blob_buffer(&cx), blob_size(&cx), SQLITE_TRANSIENT); blob_reset(&cx); } } /* ** Implementation of the "compress(X)" SQL function. The input X is |
︙ | ︙ | |||
135 136 137 138 139 140 141 | ** If DATABASE is omitted, then the repository that serves the working ** directory is opened. ** ** WARNING: Careless use of this command can corrupt a Fossil repository ** in ways that are unrecoverable. Be sure you know what you are doing before ** running any SQL commands that modifies the repository database. */ | | | 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 | ** If DATABASE is omitted, then the repository that serves the working ** directory is opened. ** ** WARNING: Careless use of this command can corrupt a Fossil repository ** in ways that are unrecoverable. Be sure you know what you are doing before ** running any SQL commands that modifies the repository database. */ void sqlite3_cmd(void){ extern int sqlite3_shell(int, char**); db_find_and_open_repository(OPEN_ANY_SCHEMA, 0); db_close(1); sqlite3_shutdown(); sqlite3_shell(g.argc-1, g.argv+1); g.db = 0; } |
︙ | ︙ |
Changes to src/sqlite3.c.
︙ | ︙ | |||
6234 6235 6236 6237 6238 6239 6240 | #define SQLITE_TESTCTRL_OPTIMIZATIONS 15 #define SQLITE_TESTCTRL_ISKEYWORD 16 #define SQLITE_TESTCTRL_SCRATCHMALLOC 17 #define SQLITE_TESTCTRL_LOCALTIME_FAULT 18 #define SQLITE_TESTCTRL_EXPLAIN_STMT 19 #define SQLITE_TESTCTRL_NEVER_CORRUPT 20 #define SQLITE_TESTCTRL_VDBE_COVERAGE 21 | > | | 6234 6235 6236 6237 6238 6239 6240 6241 6242 6243 6244 6245 6246 6247 6248 6249 | #define SQLITE_TESTCTRL_OPTIMIZATIONS 15 #define SQLITE_TESTCTRL_ISKEYWORD 16 #define SQLITE_TESTCTRL_SCRATCHMALLOC 17 #define SQLITE_TESTCTRL_LOCALTIME_FAULT 18 #define SQLITE_TESTCTRL_EXPLAIN_STMT 19 #define SQLITE_TESTCTRL_NEVER_CORRUPT 20 #define SQLITE_TESTCTRL_VDBE_COVERAGE 21 #define SQLITE_TESTCTRL_BYTEORDER 22 #define SQLITE_TESTCTRL_LAST 22 /* ** CAPI3REF: SQLite Runtime Status ** ** ^This interface is used to retrieve runtime status information ** about the performance of SQLite, and optionally to reset various ** highwater marks. ^The first argument is an integer code for |
︙ | ︙ |
Changes to src/sqlite3.h.
︙ | ︙ | |||
6119 6120 6121 6122 6123 6124 6125 | #define SQLITE_TESTCTRL_OPTIMIZATIONS 15 #define SQLITE_TESTCTRL_ISKEYWORD 16 #define SQLITE_TESTCTRL_SCRATCHMALLOC 17 #define SQLITE_TESTCTRL_LOCALTIME_FAULT 18 #define SQLITE_TESTCTRL_EXPLAIN_STMT 19 #define SQLITE_TESTCTRL_NEVER_CORRUPT 20 #define SQLITE_TESTCTRL_VDBE_COVERAGE 21 | > | | 6119 6120 6121 6122 6123 6124 6125 6126 6127 6128 6129 6130 6131 6132 6133 6134 | #define SQLITE_TESTCTRL_OPTIMIZATIONS 15 #define SQLITE_TESTCTRL_ISKEYWORD 16 #define SQLITE_TESTCTRL_SCRATCHMALLOC 17 #define SQLITE_TESTCTRL_LOCALTIME_FAULT 18 #define SQLITE_TESTCTRL_EXPLAIN_STMT 19 #define SQLITE_TESTCTRL_NEVER_CORRUPT 20 #define SQLITE_TESTCTRL_VDBE_COVERAGE 21 #define SQLITE_TESTCTRL_BYTEORDER 22 #define SQLITE_TESTCTRL_LAST 22 /* ** CAPI3REF: SQLite Runtime Status ** ** ^This interface is used to retrieve runtime status information ** about the performance of SQLite, and optionally to reset various ** highwater marks. ^The first argument is an integer code for |
︙ | ︙ |
Changes to src/stash.c.
︙ | ︙ | |||
166 167 168 169 170 171 172 | blob_init(&prompt, (const char *) bom, bomSize); #else blob_zero(&prompt); #endif blob_append(&prompt, "\n" "# Enter a description of what is being stashed. Lines beginning\n" | | | 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 | blob_init(&prompt, (const char *) bom, bomSize); #else blob_zero(&prompt); #endif blob_append(&prompt, "\n" "# Enter a description of what is being stashed. Lines beginning\n" "# with \"#\" are ignored. Stash comments are plain text except.\n" "# newlines are not preserved.\n", -1); prompt_for_user_comment(&comment, &prompt); blob_reset(&prompt); zComment = blob_str(&comment); } stashid = db_lget_int("stash-next", 1); |
︙ | ︙ | |||
197 198 199 200 201 202 203 | return stashid; } /* ** Apply a stash to the current check-out. */ static void stash_apply(int stashid, int nConflict){ | < < < < < > | 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 | return stashid; } /* ** Apply a stash to the current check-out. */ static void stash_apply(int stashid, int nConflict){ Stmt q; db_prepare(&q, "SELECT rid, isRemoved, isExec, isLink, origname, newname, delta" " FROM stashfile WHERE stashid=%d", stashid ); while( db_step(&q)==SQLITE_ROW ){ int rid = db_column_int(&q, 0); int isRemoved = db_column_int(&q, 1); int isExec = db_column_int(&q, 2); int isLink = db_column_int(&q, 3); const char *zOrig = db_column_text(&q, 4); const char *zNew = db_column_text(&q, 5); char *zOPath = mprintf("%s%s", g.zLocalRoot, zOrig); char *zNPath = mprintf("%s%s", g.zLocalRoot, zNew); Blob delta; undo_save(zNew); blob_zero(&delta); if( rid==0 ){ db_ephemeral_blob(&q, 6, &delta); blob_write_to_file(&delta, zNPath); file_wd_setexe(zNPath, isExec); fossil_print("ADD %s\n", zNew); }else if( isRemoved ){ fossil_print("DELETE %s\n", zOrig); file_delete(zOPath); }else{ Blob a, b, out, disk; int isNewLink = file_wd_islink(zOPath); db_ephemeral_blob(&q, 6, &delta); |
︙ | ︙ | |||
278 279 280 281 282 283 284 | } blob_reset(&delta); if( fossil_strcmp(zOrig,zNew)!=0 ){ undo_save(zOrig); file_delete(zOPath); } } | < | 274 275 276 277 278 279 280 281 282 283 284 285 286 287 | } blob_reset(&delta); if( fossil_strcmp(zOrig,zNew)!=0 ){ undo_save(zOrig); file_delete(zOPath); } } db_finalize(&q); if( nConflict ){ fossil_print( "WARNING: %d merge conflicts - see messages above for details.\n", nConflict); } } |
︙ | ︙ | |||
572 573 574 575 576 577 578 579 580 581 582 583 584 585 | if( n==0 ) fossil_print("empty stash\n"); }else if( memcmp(zCmd, "drop", nCmd)==0 || memcmp(zCmd, "rm", nCmd)==0 ){ int allFlag = find_option("all", "a", 0)!=0; if( allFlag ){ Blob ans; char cReply; prompt_user("This action is not undoable. Continue (y/N)? ", &ans); cReply = blob_str(&ans)[0]; if( cReply=='y' || cReply=='Y' ){ db_multi_exec("DELETE FROM stash; DELETE FROM stashfile;"); } }else if( g.argc>=4 ){ int i; | > | 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 | if( n==0 ) fossil_print("empty stash\n"); }else if( memcmp(zCmd, "drop", nCmd)==0 || memcmp(zCmd, "rm", nCmd)==0 ){ int allFlag = find_option("all", "a", 0)!=0; if( allFlag ){ Blob ans; char cReply; blob_zero(&ans); prompt_user("This action is not undoable. Continue (y/N)? ", &ans); cReply = blob_str(&ans)[0]; if( cReply=='y' || cReply=='Y' ){ db_multi_exec("DELETE FROM stash; DELETE FROM stashfile;"); } }else if( g.argc>=4 ){ int i; |
︙ | ︙ |
Changes to src/stat.c.
︙ | ︙ | |||
14 15 16 17 18 19 20 | ** http://www.hwaci.com/drh/ ** ******************************************************************************* ** ** This file contains code to implement the stat web page ** */ | < | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | ** http://www.hwaci.com/drh/ ** ******************************************************************************* ** ** This file contains code to implement the stat web page ** */ #include "config.h" #include <string.h> #include "stat.h" /* ** For a sufficiently large integer, provide an alternative ** representation as MB or GB or TB. |
︙ | ︙ |
Changes to src/style.c.
︙ | ︙ | |||
14 15 16 17 18 19 20 | ** http://www.hwaci.com/drh/ ** ******************************************************************************* ** ** This file contains code to implement the basic web page look and feel. ** */ | < | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | ** http://www.hwaci.com/drh/ ** ******************************************************************************* ** ** This file contains code to implement the basic web page look and feel. ** */ #include "config.h" #include "style.h" /* ** Elements of the submenu are collected into the following ** structure and displayed below the main menu by style_header(). |
︙ | ︙ | |||
162 163 164 165 166 167 168 | ** Generate javascript that will set the href= attribute on all anchors. */ void style_resolve_href(void){ int i; int nDelay = db_get_int("auto-hyperlink-delay",10); if( !g.perm.Hyperlink ) return; if( nHref==0 && nFormAction==0 ) return; | | > | 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 | ** Generate javascript that will set the href= attribute on all anchors. */ void style_resolve_href(void){ int i; int nDelay = db_get_int("auto-hyperlink-delay",10); if( !g.perm.Hyperlink ) return; if( nHref==0 && nFormAction==0 ) return; @ <script type="text/JavaScript"> @ /* <![CDATA[ */ @ function setAllHrefs(){ if( g.javascriptHyperlink ){ for(i=0; i<nHref; i++){ @ gebi("a%d(i+1)").href="%s(aHref[i])"; } } for(i=0; i<nFormAction; i++){ |
︙ | ︙ | |||
190 191 192 193 194 195 196 197 198 199 200 201 202 203 | @ setTimeout("setAllHrefs();",%d(nDelay)); @ this.onmousemove = null; @ } }else{ /* Active hyperlinks right away */ @ setTimeout("setAllHrefs();",%d(nDelay)); } @ </script> } /* ** Add a new element to the submenu */ void style_submenu_element( | > | 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 | @ setTimeout("setAllHrefs();",%d(nDelay)); @ this.onmousemove = null; @ } }else{ /* Active hyperlinks right away */ @ setTimeout("setAllHrefs();",%d(nDelay)); } @ /* ]]> */ @ </script> } /* ** Add a new element to the submenu */ void style_submenu_element( |
︙ | ︙ | |||
306 307 308 309 310 311 312 | Th_Store("release_version", RELEASE_VERSION); Th_Store("manifest_version", MANIFEST_VERSION); Th_Store("manifest_date", MANIFEST_DATE); Th_Store("compiler_name", COMPILER_NAME); url_var("stylesheet", "css", "style.css"); image_url_var("logo"); image_url_var("background"); | | | 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 | Th_Store("release_version", RELEASE_VERSION); Th_Store("manifest_version", MANIFEST_VERSION); Th_Store("manifest_date", MANIFEST_DATE); Th_Store("compiler_name", COMPILER_NAME); url_var("stylesheet", "css", "style.css"); image_url_var("logo"); image_url_var("background"); if( g.zLogin ){ Th_Store("login", g.zLogin); } if( g.thTrace ) Th_Trace("BEGIN_HEADER_SCRIPT<br />\n", -1); Th_Render(zHeader); if( g.thTrace ) Th_Trace("END_HEADER<br />\n", -1); Th_Unstore("title"); /* Avoid collisions with ticket field names */ cgi_destination(CGI_BODY); |
︙ | ︙ | |||
344 345 346 347 348 349 350 | ** Append ad unit text if appropriate. */ static void style_ad_unit(void){ const char *zAd; if( g.perm.Admin && db_get_boolean("adunit-omit-if-admin",0) ){ return; } | < | | < | 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 | ** Append ad unit text if appropriate. */ static void style_ad_unit(void){ const char *zAd; if( g.perm.Admin && db_get_boolean("adunit-omit-if-admin",0) ){ return; } if( g.zLogin && strcmp(g.zLogin,"anonymous")!=0 && db_get_boolean("adunit-omit-if-user",0) ){ return; } zAd = db_get("adunit", 0); if( zAd ) cgi_append_content(zAd, -1); } /* |
︙ | ︙ | |||
781 782 783 784 785 786 787 | }, { ".filetree ul", "tree-view lists", @ margin: 0; @ padding: 0; @ list-style: none; }, | < < < < < < | | | 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 | }, { ".filetree ul", "tree-view lists", @ margin: 0; @ padding: 0; @ list-style: none; }, { ".filetree ul ul", "tree-view lists below the root", @ position: relative; @ margin: 0 0 0 21px; }, { ".filetree li", "tree-view lists items", @ position: relative; }, { ".filetree li li:before", "tree-view node lines", @ content: ''; @ position: absolute; @ top: -.8em; @ left: -14px; @ width: 14px; @ height: 1.5em; @ border-left: 2px solid #aaa; @ border-bottom: 2px solid #aaa; }, { ".filetree ul ul:before", "tree-view directory lines", @ content: ''; @ position: absolute; @ top: -1.5em; @ bottom: 0; @ left: -35px; @ border-left: 2px solid #aaa; }, { ".filetree li:last-child > ul:before", "hide lines for last-child directories", @ display: none; }, { ".filetree a", "tree-view links", @ position: relative; @ z-index: 1; |
︙ | ︙ | |||
1157 1158 1159 1160 1161 1162 1163 | { "table.tale-value th", "The label/value pairs on (for example) the ci page", @ vertical-align: top; @ text-align: right; @ padding: 0.2ex 2ex; }, { ".statistics-report-graph-line", | | > > > > | 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 | { "table.tale-value th", "The label/value pairs on (for example) the ci page", @ vertical-align: top; @ text-align: right; @ padding: 0.2ex 2ex; }, { ".statistics-report-graph-line", "for the /stats_report views", @ background-color: #446979; }, { ".statistics-report-table-events th", "", @ padding: 0 1em 0 1em; }, { ".statistics-report-table-events td", "", @ padding: 0.1em 1em 0.1em 1em; }, { ".statistics-report-row-year", "", @ text-align: left; }, { ".statistics-report-graph-line", "for the /stats_report views", @ background-color: #446979; }, { ".statistics-report-week-number-label", "for the /stats_report views", @ text-align: right; @ font-size: 0.8em; }, { ".statistics-report-week-of-year-list", |
︙ | ︙ | |||
1261 1262 1263 1264 1265 1266 1267 | ** WEBPAGE: test_env */ void page_test_env(void){ char c; int i; int showAll; char zCap[30]; | | | 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 | ** WEBPAGE: test_env */ void page_test_env(void){ char c; int i; int showAll; char zCap[30]; static const char *azCgiVars[] = { "COMSPEC", "DOCUMENT_ROOT", "GATEWAY_INTERFACE", "HTTP_ACCEPT", "HTTP_ACCEPT_CHARSET", "HTTP_ACCEPT_ENCODING", "HTTP_ACCEPT_LANGUAGE", "HTTP_CONNECTION", "HTTP_HOST", "HTTP_USER_AGENT", "HTTP_REFERER", "PATH_INFO", "PATH_TRANSLATED", "QUERY_STRING", "REMOTE_ADDR", "REMOTE_PORT", "REQUEST_METHOD", "REQUEST_URI", "SCRIPT_FILENAME", "SCRIPT_NAME", "SERVER_PROTOCOL", }; |
︙ | ︙ | |||
1298 1299 1300 1301 1302 1303 1304 | if( login_has_capability(&c, 1) ) zCap[i++] = c; } zCap[i] = 0; @ g.userUid = %d(g.userUid)<br /> @ g.zLogin = %h(g.zLogin)<br /> @ g.isHuman = %d(g.isHuman)<br /> @ capabilities = %s(zCap)<br /> | < < | 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 | if( login_has_capability(&c, 1) ) zCap[i++] = c; } zCap[i] = 0; @ g.userUid = %d(g.userUid)<br /> @ g.zLogin = %h(g.zLogin)<br /> @ g.isHuman = %d(g.isHuman)<br /> @ capabilities = %s(zCap)<br /> @ <hr> P("HTTP_USER_AGENT"); cgi_print_all(showAll); if( showAll && blob_size(&g.httpHeader)>0 ){ @ <hr> @ <pre> @ %h(blob_str(&g.httpHeader)) |
︙ | ︙ |
Changes to src/sync.c.
︙ | ︙ | |||
46 47 48 49 50 51 52 | if( is_false(zAutosync) ){ return 0; /* Autosync is completely off */ } }else{ /* Autosync defaults on. To make it default off, "return" here. */ } url_parse(0, URL_REMEMBER); | | | | | < | < < | 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 | if( is_false(zAutosync) ){ return 0; /* Autosync is completely off */ } }else{ /* Autosync defaults on. To make it default off, "return" here. */ } url_parse(0, URL_REMEMBER); if( g.urlProtocol==0 ) return 0; if( g.urlUser!=0 && g.urlPasswd==0 ){ g.urlPasswd = unobscure(db_get("last-sync-pw", 0)); g.urlFlags |= URL_PROMPT_PW; url_prompt_for_password(); } url_remember(); #if 0 /* Disabled for now */ if( (flags & AUTOSYNC_PULL)!=0 && db_get_boolean("auto-shun",1) ){ /* When doing an automatic pull, also automatically pull shuns from ** the server if pull_shuns is enabled. ** ** TODO: What happens if the shun list gets really big? ** Maybe the shunning list should only be pulled on every 10th ** autosync, or something? */ configSync = CONFIGSET_SHUN; } #endif if( find_option("verbose","v",0)!=0 ) flags |= SYNC_VERBOSE; fossil_print("Autosync: %s\n", g.urlCanonical); url_enable_proxy("via proxy: "); rc = client_sync(flags, configSync, 0); if( rc ) fossil_warning("Autosync failed"); return rc; } /* ** This routine processes the command-line argument for push, pull, ** and sync. If a command-line argument is given, that is the URL ** of a server to sync against. If no argument is given, use the ** most recently synced URL. Remember the current URL for next time. */ static void process_sync_args(unsigned *pConfigFlags, unsigned *pSyncFlags){ const char *zUrl = 0; unsigned configSync = 0; unsigned urlFlags = URL_REMEMBER | URL_PROMPT_PW; int urlOptional = 0; if( find_option("autourl",0,0)!=0 ){ urlOptional = 1; urlFlags = 0; } if( find_option("once",0,0)!=0 ) urlFlags &= ~URL_REMEMBER; if( find_option("private",0,0)!=0 ){ *pSyncFlags |= SYNC_PRIVATE; } if( find_option("verbose","v",0)!=0 ){ *pSyncFlags |= SYNC_VERBOSE; } |
︙ | ︙ | |||
117 118 119 120 121 122 123 | }else if( g.argc==3 ){ zUrl = g.argv[2]; } if( urlFlags & URL_REMEMBER ){ clone_ssh_db_set_options(); } url_parse(zUrl, urlFlags); | < | | | | | 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 | }else if( g.argc==3 ){ zUrl = g.argv[2]; } if( urlFlags & URL_REMEMBER ){ clone_ssh_db_set_options(); } url_parse(zUrl, urlFlags); url_remember(); if( g.urlProtocol==0 ){ if( urlOptional ) fossil_exit(0); usage("URL"); } user_select(); if( g.argc==2 ){ if( ((*pSyncFlags) & (SYNC_PUSH|SYNC_PULL))==(SYNC_PUSH|SYNC_PULL) ){ fossil_print("Sync with %s\n", g.urlCanonical); }else if( (*pSyncFlags) & SYNC_PUSH ){ fossil_print("Push to %s\n", g.urlCanonical); }else if( (*pSyncFlags) & SYNC_PULL ){ fossil_print("Pull from %s\n", g.urlCanonical); } } url_enable_proxy("via proxy: "); *pConfigFlags |= configSync; } /* |
︙ | ︙ | |||
265 266 267 268 269 270 271 | db_find_and_open_repository(0, 0); if( g.argc!=2 && g.argc!=3 ){ usage("remote-url ?URL|off?"); } if( g.argc==3 ){ db_unset("last-sync-url", 0); db_unset("last-sync-pw", 0); | < | | 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 | db_find_and_open_repository(0, 0); if( g.argc!=2 && g.argc!=3 ){ usage("remote-url ?URL|off?"); } if( g.argc==3 ){ db_unset("last-sync-url", 0); db_unset("last-sync-pw", 0); if( is_false(g.argv[2]) ) return; url_parse(g.argv[2], URL_REMEMBER|URL_PROMPT_PW|URL_ASK_REMEMBER_PW); } url_remember(); zUrl = db_get("last-sync-url", 0); if( zUrl==0 ){ fossil_print("off\n"); return; }else{ url_parse(zUrl, 0); fossil_print("%s\n", g.urlCanonical); } } |
Changes to src/tag.c.
︙ | ︙ | |||
320 321 322 323 324 325 326 | blob_appendf(&ctrl, "T %c%s%F %b", zTagtype[tagtype], zPrefix, zTagname, &uuid); if( tagtype>0 && zValue && zValue[0] ){ blob_appendf(&ctrl, " %F\n", zValue); }else{ blob_appendf(&ctrl, "\n"); } | | | 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 | blob_appendf(&ctrl, "T %c%s%F %b", zTagtype[tagtype], zPrefix, zTagname, &uuid); if( tagtype>0 && zValue && zValue[0] ){ blob_appendf(&ctrl, " %F\n", zValue); }else{ blob_appendf(&ctrl, "\n"); } blob_appendf(&ctrl, "U %F\n", zUserOvrd ? zUserOvrd : g.zLogin); md5sum_blob(&ctrl, &cksum); blob_appendf(&ctrl, "Z %b\n", &cksum); nrid = content_put(&ctrl); manifest_crosslink(nrid, &ctrl, MC_PERMIT_HOOKS); assert( blob_is_reset(&ctrl) ); } |
︙ | ︙ | |||
593 594 595 596 597 598 599 600 601 | " WHERE tagname GLOB 'sym-*'))" " ORDER BY event.mtime DESC", timeline_query_for_www() ); www_print_timeline(&q, 0, 0, 0, 0); db_finalize(&q); @ <br /> style_footer(); } | > > > > > > | 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 | " WHERE tagname GLOB 'sym-*'))" " ORDER BY event.mtime DESC", timeline_query_for_www() ); www_print_timeline(&q, 0, 0, 0, 0); db_finalize(&q); @ <br /> @ <script type="text/JavaScript"> @ function xin(id){ @ } @ function xout(id){ @ } @ </script> style_footer(); } |
Changes to src/tar.c.
︙ | ︙ | |||
334 335 336 337 338 339 340 | const char *zName, /* Name of directory including final "/" */ int nName, /* Characters in zName */ unsigned int mTime /* Modification time */ ){ int i; for(i=nName-1; i>0 && zName[i]!='/'; i--){} if( i<=0 ) return; | | | < | 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 | const char *zName, /* Name of directory including final "/" */ int nName, /* Characters in zName */ unsigned int mTime /* Modification time */ ){ int i; for(i=nName-1; i>0 && zName[i]!='/'; i--){} if( i<=0 ) return; if( i < tball.nPrevDirAlloc && tball.zPrevDir[i]==0 && memcmp(tball.zPrevDir, zName, i)==0 ) return; db_multi_exec("INSERT OR IGNORE INTO dir VALUES('%#q')", i, zName); if( sqlite3_changes(g.db)==0 ) return; tar_add_directory_of(zName, i-1, mTime); tar_add_header(zName, i, 0755, mTime, 0, '5'); if( i >= tball.nPrevDirAlloc ){ int nsize = tball.nPrevDirAlloc * 2; if(i+1 > nsize) |
︙ | ︙ | |||
569 570 571 572 573 574 575 | /* ** WEBPAGE: tarball ** URL: /tarball/RID.tar.gz ** ** Generate a compressed tarball for a checkin. ** Return that tarball as the HTTP reply content. | < < < < < < < < < < | 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 | /* ** WEBPAGE: tarball ** URL: /tarball/RID.tar.gz ** ** Generate a compressed tarball for a checkin. ** Return that tarball as the HTTP reply content. */ void tarball_page(void){ int rid; char *zName, *zRid; int nName, nRid; Blob tarball; login_check_credentials(); if( !g.perm.Zip ){ login_needed(); return; } zName = mprintf("%s", PD("name","")); nName = strlen(zName); zRid = mprintf("%s", PD("uuid","trunk")); nRid = strlen(zRid); if( nName>7 && fossil_strcmp(&zName[nName-7], ".tar.gz")==0 ){ /* Special case: Remove the ".tar.gz" suffix. */ nName -= 7; |
︙ | ︙ |
Changes to src/th.c.
︙ | ︙ | |||
126 127 128 129 130 131 132 | ** ** results in nByte being set to 2. */ static int thNextCommand(Th_Interp*, const char *z, int n, int *pN); static int thNextEscape (Th_Interp*, const char *z, int n, int *pN); static int thNextVarname(Th_Interp*, const char *z, int n, int *pN); static int thNextNumber (Th_Interp*, const char *z, int n, int *pN); | < | 126 127 128 129 130 131 132 133 134 135 136 137 138 139 | ** ** results in nByte being set to 2. */ static int thNextCommand(Th_Interp*, const char *z, int n, int *pN); static int thNextEscape (Th_Interp*, const char *z, int n, int *pN); static int thNextVarname(Th_Interp*, const char *z, int n, int *pN); static int thNextNumber (Th_Interp*, const char *z, int n, int *pN); static int thNextSpace (Th_Interp*, const char *z, int n, int *pN); /* ** Given that the input string (z, n) contains a language construct of ** the relevant type (a command enclosed in [], an escape sequence ** like "\xFF" or a variable reference like "${varname}", perform ** substitution on the string and store the resulting string in |
︙ | ︙ | |||
1866 1867 1868 1869 1870 1871 1872 | {"&", OP_BITWISE_AND, 8, ARG_INTEGER}, {"^", OP_BITWISE_XOR, 9, ARG_INTEGER}, {"|", OP_BITWISE_OR, 10, ARG_INTEGER}, {0,0,0,0} }; | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 | {"&", OP_BITWISE_AND, 8, ARG_INTEGER}, {"^", OP_BITWISE_XOR, 9, ARG_INTEGER}, {"|", OP_BITWISE_OR, 10, ARG_INTEGER}, {0,0,0,0} }; /* ** The first part of the string (zInput,nInput) contains a number. ** Set *pnVarname to the number of bytes in the numeric string. */ static int thNextNumber( Th_Interp *interp, const char *zInput, int nInput, int *pnLiteral ){ int i; int seenDot = 0; for(i=0; i<nInput; i++){ char c = zInput[i]; if( (seenDot || c!='.') && !th_isdigit(c) ) break; if( c=='.' ) seenDot = 1; } *pnLiteral = i; return TH_OK; } |
︙ | ︙ | |||
2035 2036 2037 2038 2039 2040 2041 | case OP_BITWISE_NOT: iRes = ~iLeft; break; case OP_LOGICAL_NOT: iRes = !iLeft; break; default: assert(!"Internal error"); } Th_SetResultInt(interp, iRes); }else if( rc==TH_OK && eArgType==ARG_NUMBER ){ switch( pExpr->pOp->eOp ) { | | | | | | | | | | < < | 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 | case OP_BITWISE_NOT: iRes = ~iLeft; break; case OP_LOGICAL_NOT: iRes = !iLeft; break; default: assert(!"Internal error"); } Th_SetResultInt(interp, iRes); }else if( rc==TH_OK && eArgType==ARG_NUMBER ){ switch( pExpr->pOp->eOp ) { case OP_MULTIPLY: Th_SetResultDouble(interp, fLeft*fRight); break; case OP_DIVIDE: if( fRight==0.0 ){ Th_ErrorMessage(interp, "Divide by 0:", zLeft, nLeft); rc = TH_ERROR; goto finish; } Th_SetResultDouble(interp, fLeft/fRight); break; case OP_ADD: Th_SetResultDouble(interp, fLeft+fRight); break; case OP_SUBTRACT: Th_SetResultDouble(interp, fLeft-fRight); break; case OP_LT: Th_SetResultInt(interp, fLeft<fRight); break; case OP_GT: Th_SetResultInt(interp, fLeft>fRight); break; case OP_LE: Th_SetResultInt(interp, fLeft<=fRight); break; case OP_GE: Th_SetResultInt(interp, fLeft>=fRight); break; case OP_EQ: Th_SetResultInt(interp, fLeft==fRight); break; case OP_NE: Th_SetResultInt(interp, fLeft!=fRight); break; default: assert(!"Internal error"); } }else if( rc==TH_OK ){ int iEqual = 0; assert( eArgType==ARG_STRING ); if( nRight==nLeft && 0==memcmp(zRight, zLeft, nRight) ){ iEqual = 1; |
︙ | ︙ | |||
2187 2188 2189 2190 2191 2192 2193 | if( th_isspace(c) ){ /* White-space */ i++; }else{ Expr *pNew = (Expr *)Th_Malloc(interp, sizeof(Expr)); const char *z = &zExpr[i]; switch (c) { | < < < < < | | | 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 | if( th_isspace(c) ){ /* White-space */ i++; }else{ Expr *pNew = (Expr *)Th_Malloc(interp, sizeof(Expr)); const char *z = &zExpr[i]; switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': thNextNumber(interp, z, nExpr-i, &pNew->nValue); break; case '$': thNextVarname(interp, z, nExpr-i, &pNew->nValue); break; |
︙ | ︙ | |||
2448 2449 2450 2451 2452 2453 2454 | ** '\n' 0x0A ** '\v' 0x0B ** '\f' 0x0C ** '\r' 0x0D ** ** Whitespace characters have the 0x01 flag set. Decimal digits have the ** 0x2 flag set. Single byte printable characters have the 0x4 flag set. | | < | | | | 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 | ** '\n' 0x0A ** '\v' 0x0B ** '\f' 0x0C ** '\r' 0x0D ** ** Whitespace characters have the 0x01 flag set. Decimal digits have the ** 0x2 flag set. Single byte printable characters have the 0x4 flag set. ** Alphabet characters have the 0x8 bit set. ** ** The special list characters have the 0x10 flag set ** ** { } [ ] \ ; ' " ** ** " 0x22 ** */ static unsigned char aCharProp[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, /* 0x0. */ 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x1. */ 5, 4, 20, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, /* 0x2. */ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 4, 20, 4, 4, 4, 4, /* 0x3. */ 4, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, /* 0x4. */ 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 20, 20, 20, 4, 4, /* 0x5. */ 4, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, /* 0x6. */ 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 20, 4, 20, 4, 4, /* 0x7. */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x8. */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x9. */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xA. */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xB. */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xC. */ |
︙ | ︙ | |||
2493 2494 2495 2496 2497 2498 2499 | } int th_isspecial(char c){ return (aCharProp[(unsigned char)c] & 0x11); } int th_isalnum(char c){ return (aCharProp[(unsigned char)c] & 0x0A); } | < < < < < < < < < < < < | 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 | } int th_isspecial(char c){ return (aCharProp[(unsigned char)c] & 0x11); } int th_isalnum(char c){ return (aCharProp[(unsigned char)c] & 0x0A); } #ifndef LONGDOUBLE_TYPE # define LONGDOUBLE_TYPE long double #endif /* |
︙ | ︙ | |||
2621 2622 2623 2624 2625 2626 2627 | ** If the string cannot be converted to an integer, return TH_ERROR. ** If the interp argument is not NULL, leave an error message in the ** interpreter result too. */ int Th_ToInt(Th_Interp *interp, const char *z, int n, int *piOut){ int i = 0; int iOut = 0; | < < < < < < < < < < < < < < < < < < < < | < < < < < < < | | 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 | ** If the string cannot be converted to an integer, return TH_ERROR. ** If the interp argument is not NULL, leave an error message in the ** interpreter result too. */ int Th_ToInt(Th_Interp *interp, const char *z, int n, int *piOut){ int i = 0; int iOut = 0; if( n<0 ){ n = th_strlen(z); } if( n>0 && (z[0]=='-' || z[0]=='+') ){ i = 1; } for(; i<n; i++){ if( !th_isdigit(z[i]) ){ Th_ErrorMessage(interp, "expected integer, got: \"", z, n); return TH_ERROR; } iOut = iOut * 10 + (z[i] - 48); } if( n>0 && z[0]=='-' ){ iOut *= -1; } *piOut = iOut; |
︙ | ︙ | |||
2709 2710 2711 2712 2713 2714 2715 | char *z = &zBuf[32]; if( iVal<0 ){ isNegative = 1; iVal = iVal * -1; } *(--z) = '\0'; | | | | | 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 | char *z = &zBuf[32]; if( iVal<0 ){ isNegative = 1; iVal = iVal * -1; } *(--z) = '\0'; *(--z) = (char)(48+(iVal%10)); while( (iVal = (iVal/10))>0 ){ *(--z) = (char)(48+(iVal%10)); assert(z>zBuf); } if( isNegative ){ *(--z) = '-'; } return Th_SetResult(interp, z, -1); |
︙ | ︙ |
Changes to src/th.h.
1 2 3 4 5 6 7 8 9 10 11 | /* This header file defines the external interface to the custom Scripting ** Language (TH) interpreter. TH is very similar to TCL but is not an ** exact clone. */ /* ** Before creating an interpreter, the application must allocate and ** populate an instance of the following structure. It must remain valid ** for the lifetime of the interpreter. */ | < > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | /* This header file defines the external interface to the custom Scripting ** Language (TH) interpreter. TH is very similar to TCL but is not an ** exact clone. */ /* ** Before creating an interpreter, the application must allocate and ** populate an instance of the following structure. It must remain valid ** for the lifetime of the interpreter. */ struct Th_Vtab { void *(*xMalloc)(unsigned int); void (*xFree)(void *); }; typedef struct Th_Vtab Th_Vtab; /* ** Opaque handle for interpeter. */ typedef struct Th_Interp Th_Interp; /* |
︙ | ︙ | |||
143 144 145 146 147 148 149 | /* ** Drop in replacements for the corresponding standard library functions. */ int th_strlen(const char *); int th_isdigit(char); int th_isspace(char); int th_isalnum(char); | < < < < | 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 | /* ** Drop in replacements for the corresponding standard library functions. */ int th_strlen(const char *); int th_isdigit(char); int th_isspace(char); int th_isalnum(char); int th_isspecial(char); char *th_strdup(Th_Interp *interp, const char *z, int n); /* ** Interfaces to register the language extensions. */ int th_register_language(Th_Interp *interp); /* th_lang.c */ int th_register_sqlite(Th_Interp *interp); /* th_sqlite.c */ |
︙ | ︙ | |||
188 189 190 191 192 193 194 | Th_HashEntry *Th_HashFind(Th_Interp*, Th_Hash*, const char*, int, int); /* ** Useful functions from th_lang.c. */ int Th_WrongNumArgs(Th_Interp *interp, const char *zMsg); | | | | 184 185 186 187 188 189 190 191 192 | Th_HashEntry *Th_HashFind(Th_Interp*, Th_Hash*, const char*, int, int); /* ** Useful functions from th_lang.c. */ int Th_WrongNumArgs(Th_Interp *interp, const char *zMsg); typedef struct Th_SubCommand {char *zName; Th_CommandProc xProc;} Th_SubCommand; int Th_CallSubCommand(Th_Interp*,void*,int,const char**,int*,Th_SubCommand*); |
Changes to src/th_lang.c.
︙ | ︙ | |||
423 424 425 426 427 428 429 | Th_Interp *interp, void *ctx, int argc, const char **argv, int *argl ){ int rc; | | | 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 | Th_Interp *interp, void *ctx, int argc, const char **argv, int *argl ){ int rc; char *zName; ProcDefn *p; int nByte; int i; char *zSpace; char **azParam; |
︙ | ︙ | |||
519 520 521 522 523 524 525 | if( p->hasArgs ){ Th_StringAppend(interp, &zUsage, &nUsage, (const char *)" ?args...?", -1); } p->zUsage = zUsage; p->nUsage = nUsage; /* Register the new command with the th1 interpreter. */ | | | 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 | if( p->hasArgs ){ Th_StringAppend(interp, &zUsage, &nUsage, (const char *)" ?args...?", -1); } p->zUsage = zUsage; p->nUsage = nUsage; /* Register the new command with the th1 interpreter. */ zName = (char *)argv[1]; rc = Th_CreateCommand(interp, zName, proc_call1, (void *)p, proc_del); if( rc==TH_OK ){ Th_SetResult(interp, 0, 0); } Th_Free(interp, azParam); return TH_OK; |
︙ | ︙ | |||
885 886 887 888 889 890 891 | int Th_CallSubCommand( Th_Interp *interp, void *ctx, int argc, const char **argv, int *argl, | | | | 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 | int Th_CallSubCommand( Th_Interp *interp, void *ctx, int argc, const char **argv, int *argl, Th_SubCommand *aSub ){ if( argc>1 ){ int i; for(i=0; aSub[i].zName; i++){ char *zName = (char *)aSub[i].zName; if( th_strlen(zName)==argl[1] && 0==memcmp(zName, argv[1], argl[1]) ){ return aSub[i].xProc(interp, ctx, argc, argv, argl); } } } if(argc<2){ Th_ErrorMessage(interp, "Expected sub-command for", argv[0], argl[0]); |
︙ | ︙ | |||
922 923 924 925 926 927 928 | static int string_command( Th_Interp *interp, void *ctx, int argc, const char **argv, int *argl ){ | | | 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 | static int string_command( Th_Interp *interp, void *ctx, int argc, const char **argv, int *argl ){ Th_SubCommand aSub[] = { { "compare", string_compare_command }, { "first", string_first_command }, { "is", string_is_command }, { "last", string_last_command }, { "length", string_length_command }, { "range", string_range_command }, { "repeat", string_repeat_command }, |
︙ | ︙ | |||
950 951 952 953 954 955 956 | static int info_command( Th_Interp *interp, void *ctx, int argc, const char **argv, int *argl ){ | | | 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 | static int info_command( Th_Interp *interp, void *ctx, int argc, const char **argv, int *argl ){ Th_SubCommand aSub[] = { { "exists", info_exists_command }, { 0, 0 } }; return Th_CallSubCommand(interp, ctx, argc, argv, argl, aSub); } /* |
︙ | ︙ | |||
1095 1096 1097 1098 1099 1100 1101 | {"return", return_command, 0}, {"break", simple_command, (void *)TH_BREAK}, {"continue", simple_command, (void *)TH_CONTINUE}, {"error", simple_command, (void *)TH_ERROR}, {0, 0, 0} }; | | | 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 | {"return", return_command, 0}, {"break", simple_command, (void *)TH_BREAK}, {"continue", simple_command, (void *)TH_CONTINUE}, {"error", simple_command, (void *)TH_ERROR}, {0, 0, 0} }; int i; /* Add the language commands. */ for(i=0; i<(sizeof(aCommand)/sizeof(aCommand[0])); i++){ void *ctx; if ( !aCommand[i].zName || !aCommand[i].xProc ) continue; ctx = aCommand[i].pContext; Th_CreateCommand(interp, aCommand[i].zName, aCommand[i].xProc, ctx, 0); } return TH_OK; } |
Changes to src/timeline.c.
︙ | ︙ | |||
46 47 48 49 50 51 52 | /* ** Generate a hyperlink to a version. */ void hyperlink_to_uuid(const char *zUuid){ char z[UUID_SIZE+1]; shorten_uuid(z, zUuid); if( g.perm.Hyperlink ){ | | > > > > > > > > > > > > > | 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | /* ** Generate a hyperlink to a version. */ void hyperlink_to_uuid(const char *zUuid){ char z[UUID_SIZE+1]; shorten_uuid(z, zUuid); if( g.perm.Hyperlink ){ @ %z(xhref("class='timelineHistLink'","%R/info/%s",z))[%s(z)]</a> }else{ @ <span class="timelineHistDsp">[%s(z)]</span> } } /* ** Generate a hyperlink to a diff between two versions. */ void hyperlink_to_diff(const char *zV1, const char *zV2){ if( g.perm.Hyperlink ){ if( zV2==0 ){ @ %z(href("%R/diff?v2=%s",zV1))[diff]</a> }else{ @ %z(href("%R/diff?v1=%s&v2=%s",zV1,zV2))[diff]</a> } } } /* ** Generate a hyperlink to a date & time. */ void hyperlink_to_date(const char *zDate, const char *zSuffix){ if( zSuffix==0 ) zSuffix = ""; if( g.perm.Hyperlink ){ |
︙ | ︙ | |||
232 233 234 235 236 237 238 | GraphContext *pGraph = 0; int prevWasDivider = 0; /* True if previous output row was <hr> */ int fchngQueryInit = 0; /* True if fchngQuery is initialized */ Stmt fchngQuery; /* Query for file changes on check-ins */ static Stmt qbranch; int pendingEndTr = 0; /* True if a </td></tr> is needed */ int vid = 0; /* Current checkout version */ | | | | 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 | GraphContext *pGraph = 0; int prevWasDivider = 0; /* True if previous output row was <hr> */ int fchngQueryInit = 0; /* True if fchngQuery is initialized */ Stmt fchngQuery; /* Query for file changes on check-ins */ static Stmt qbranch; int pendingEndTr = 0; /* True if a </td></tr> is needed */ int vid = 0; /* Current checkout version */ int dateFormat = 0; /* 0: HH:MM 1: HH:MM:SS 2: YYYY-MM-DD HH:MM 3: YYMMDD HH:MM */ if( fossil_strcmp(g.zIpAddr, "127.0.0.1")==0 && db_open_local(0) ){ vid = db_lget_int("checkout", 0); } zPrevDate[0] = 0; mxWikiLen = db_get_int("timeline-max-comment", 0); dateFormat = db_get_int("timeline-date-format", 0); if( tmFlags & TIMELINE_GRAPH ){ |
︙ | ︙ | |||
433 434 435 436 437 438 439 | @ (user: %z(href("%z",zLink))%h(zDispUser)</a>%s(zTagList?",":"\051") }else{ @ (user: %h(zDispUser)%s(zTagList?",":"\051") } /* Generate a "detail" link for tags. */ if( (zType[0]=='g' || zType[0]=='w' || zType[0]=='t') && g.perm.Hyperlink ){ | | | 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 | @ (user: %z(href("%z",zLink))%h(zDispUser)</a>%s(zTagList?",":"\051") }else{ @ (user: %h(zDispUser)%s(zTagList?",":"\051") } /* Generate a "detail" link for tags. */ if( (zType[0]=='g' || zType[0]=='w' || zType[0]=='t') && g.perm.Hyperlink ){ @ [%z(href("%R/info/%S",zUuid))details</a>] } /* Generate the "tags: TAGLIST" at the end of the comment, together ** with hyperlinks to the tag list. */ if( zTagList ){ if( g.perm.Hyperlink ){ |
︙ | ︙ | |||
512 513 514 515 516 517 518 | if( !isNew && !isDel && zOldName!=0 ){ @ <li> %h(zOldName) → %h(zFilename) } continue; } if( isNew ){ @ <li> %h(zFilename) (new file) | | | | | 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 | if( !isNew && !isDel && zOldName!=0 ){ @ <li> %h(zOldName) → %h(zFilename) } continue; } if( isNew ){ @ <li> %h(zFilename) (new file) @ %z(href("%R/artifact/%S",zNew))[view]</a></li> }else if( isDel ){ @ <li> %h(zFilename) (deleted)</li> }else if( fossil_strcmp(zOld,zNew)==0 && zOldName!=0 ){ @ <li> %h(zOldName) → %h(zFilename) @ %z(href("%R/artifact/%S",zNew))[view]</a></li> }else{ if( zOldName!=0 ){ @ <li> %h(zOldName) → %h(zFilename) }else{ @ <li> %h(zFilename) } @ %z(href("%R/fdiff?v1=%S&v2=%S&sbs=1",zOld,zNew))[diff]</a></li> } } db_reset(&fchngQuery); if( inUl ){ @ </ul> } } |
︙ | ︙ | |||
576 577 578 579 580 581 582 | int omitDescenders, /* True to omit descenders */ int fileDiff /* True for file diff. False for check-in diff */ ){ if( pGraph && pGraph->nErr==0 && pGraph->nRow>0 ){ GraphRow *pRow; int i; char cSep; | | | > | 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 | int omitDescenders, /* True to omit descenders */ int fileDiff /* True for file diff. False for check-in diff */ ){ if( pGraph && pGraph->nErr==0 && pGraph->nRow>0 ){ GraphRow *pRow; int i; char cSep; @ <script type="text/JavaScript"> @ /* <![CDATA[ */ @ var railPitch=%d(pGraph->iRailPitch); /* the rowinfo[] array contains all the information needed to generate ** the graph. Each entry contains information for a single row: ** ** id: The id of the <div> element for the row. This is an integer. ** to get an actual id, prepend "m" to the integer. The top node |
︙ | ︙ | |||
856 857 858 859 860 861 862 863 864 865 866 867 868 869 | @ if( h!=lastY ){ @ renderGraph(); @ lastY = h; @ } @ setTimeout("checkHeight();", 1000); @ } @ checkHeight(); @ </script> } } /* ** Create a temporary table suitable for storing timeline data. */ | > | 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 | @ if( h!=lastY ){ @ renderGraph(); @ lastY = h; @ } @ setTimeout("checkHeight();", 1000); @ } @ checkHeight(); @ /* ]]> */ @ </script> } } /* ** Create a temporary table suitable for storing timeline data. */ |
︙ | ︙ | |||
1427 1428 1429 1430 1431 1432 1433 | blob_appendf(&desc, "%d most recent %ss", n, zEType); }else{ blob_appendf(&desc, "%d %ss", n, zEType); } if( zUses ){ char *zFilenames = names_of_file(zUses); blob_appendf(&desc, " using file %s version %z%S</a>", zFilenames, | | | 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 | blob_appendf(&desc, "%d most recent %ss", n, zEType); }else{ blob_appendf(&desc, "%d %ss", n, zEType); } if( zUses ){ char *zFilenames = names_of_file(zUses); blob_appendf(&desc, " using file %s version %z%S</a>", zFilenames, href("%R/artifact/%S",zUses), zUses); tmFlags |= TIMELINE_DISJOINT; } if( renameOnly ){ blob_appendf(&desc, " that contain filename changes"); tmFlags |= TIMELINE_DISJOINT|TIMELINE_FRENAMES; } if( zUser ){ |
︙ | ︙ | |||
1948 1949 1950 1951 1952 1953 1954 | " FROM plink p, plink c, blob" " WHERE p.cid=c.pid AND p.mtime>c.mtime" " AND blob.rid=c.cid" ); while( db_step(&q)==SQLITE_ROW ){ const char *zUuid = db_column_text(&q, 0); @ <li> | | | 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 | " FROM plink p, plink c, blob" " WHERE p.cid=c.pid AND p.mtime>c.mtime" " AND blob.rid=c.cid" ); while( db_step(&q)==SQLITE_ROW ){ const char *zUuid = db_column_text(&q, 0); @ <li> @ <a href="%s(g.zTop)/timeline?p=%S(zUuid)&d=%S(zUuid)&unhide">%S(zUuid)</a> } db_finalize(&q); style_footer(); } /* |
︙ | ︙ | |||
2060 2061 2062 2063 2064 2065 2066 | return "all types"; } } /* ** A helper for the /reports family of pages which prints out a menu ** of links for the various type=XXX flags. zCurrentViewName must be | | | | < < | | < < < < < | < | 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 | return "all types"; } } /* ** A helper for the /reports family of pages which prints out a menu ** of links for the various type=XXX flags. zCurrentViewName must be ** the name/value of the 'view' parameter which is in effect at ** the time this is called. e.g. if called from the 'byuser' view ** then zCurrentViewName must be "byuser". */ static void stats_report_event_types_menu(char const * zCurrentViewName){ char * zTop = mprintf("%s/reports?view=%s", g.zTop, zCurrentViewName); cgi_printf("<div>"); cgi_printf("<span>Event types:</span> "); if('*' == statsReportType){ cgi_printf(" <strong>all</strong>", zTop); }else{ cgi_printf(" <a href='%s'>all</a>", zTop); } |
︙ | ︙ | |||
2164 2165 2166 2167 2168 2169 2170 | the per-year event totals */ Blob header = empty_blob; /* Page header text */ int nMaxEvents = 1; /* for calculating length of graph bars. */ int iterations = 0; /* number of weeks/months we iterate over */ stats_report_init_view(); | | | 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 | the per-year event totals */ Blob header = empty_blob; /* Page header text */ int nMaxEvents = 1; /* for calculating length of graph bars. */ int iterations = 0; /* number of weeks/months we iterate over */ stats_report_init_view(); stats_report_event_types_menu( includeMonth ? "bymonth" : "byyear" ); blob_appendf(&header, "Timeline Events (%s) by year%s", stats_report_label_for_type(), (includeMonth ? "/month" : "")); blob_appendf(&sql, "SELECT substr(date(mtime),1,%d) AS timeframe, " "count(*) AS eventCount " "FROM v_reports ", |
︙ | ︙ | |||
2223 2224 2225 2226 2227 2228 2229 | (0!=fossil_strncmp(zPrevYear,zTimeframe,4))){ showYearTotal = *zPrevYear; if(showYearTotal){ rowClass = ++nRowNumber % 2; @ <tr class='row%d(rowClass)'> @ <td></td> @ <td colspan='2'>Yearly total: %d(nEventsPerYear)</td> | | | 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 | (0!=fossil_strncmp(zPrevYear,zTimeframe,4))){ showYearTotal = *zPrevYear; if(showYearTotal){ rowClass = ++nRowNumber % 2; @ <tr class='row%d(rowClass)'> @ <td></td> @ <td colspan='2'>Yearly total: %d(nEventsPerYear)</td> @</tr> } nEventsPerYear = 0; memcpy(zPrevYear,zTimeframe,4); rowClass = ++nRowNumber % 2; @ <tr class='row%d(rowClass)'> @ <th colspan='3' class='statistics-report-row-year'>%s(zPrevYear)</th> @ </tr> |
︙ | ︙ | |||
2261 2262 2263 2264 2265 2266 2267 | cgi_printf("&u=%t", zUserName); } cgi_printf("'>%s</a>", zTimeframe); } @ </td><td>%d(nCount)</td> @ <td> @ <div class='statistics-report-graph-line' | | | | 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 | cgi_printf("&u=%t", zUserName); } cgi_printf("'>%s</a>", zTimeframe); } @ </td><td>%d(nCount)</td> @ <td> @ <div class='statistics-report-graph-line' @ style='height:16px;width:%d(nSize)%%;'> @ </div></td> @</tr> if(includeWeeks){ /* This part works fine for months but it terribly slow (4.5s on my PC), so it's only shown for by-year for now. Suggestions/patches for a better/faster layout are welcomed. */ @ <tr class='row%d(rowClass)'> @ <td colspan='2' class='statistics-report-week-number-label'>Week #:</td> |
︙ | ︙ | |||
2287 2288 2289 2290 2291 2292 2293 | db_finalize(&query); if(includeMonth && !showYearTotal && *zPrevYear){ /* Add final year total separator. */ rowClass = ++nRowNumber % 2; @ <tr class='row%d(rowClass)'> @ <td></td> @ <td colspan='2'>Yearly total: %d(nEventsPerYear)</td> | | | 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 | db_finalize(&query); if(includeMonth && !showYearTotal && *zPrevYear){ /* Add final year total separator. */ rowClass = ++nRowNumber % 2; @ <tr class='row%d(rowClass)'> @ <td></td> @ <td colspan='2'>Yearly total: %d(nEventsPerYear)</td> @</tr> } @ </tbody></table> if(nEventTotal){ char const * zAvgLabel = includeMonth ? "month" : "year"; int nAvg = iterations ? (nEventTotal/iterations) : 0; @ <br><div>Total events: %d(nEventTotal) @ <br>Average per active %s(zAvgLabel): %d(nAvg) |
︙ | ︙ | |||
2315 2316 2317 2318 2319 2320 2321 | int nEventTotal = 0; /* Total event count */ int rowClass = 0; /* counter for alternating row colors */ Blob sql = empty_blob; /* SQL */ int nMaxEvents = 1; /* max number of events for all rows. */ stats_report_init_view(); | | | 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 | int nEventTotal = 0; /* Total event count */ int rowClass = 0; /* counter for alternating row colors */ Blob sql = empty_blob; /* SQL */ int nMaxEvents = 1; /* max number of events for all rows. */ stats_report_init_view(); stats_report_event_types_menu("byuser"); blob_append(&sql, "SELECT user, " "COUNT(*) AS eventCount " "FROM v_reports " "GROUP BY user ORDER BY eventCount DESC", -1); db_prepare(&query, blob_str(&sql)); |
︙ | ︙ | |||
2356 2357 2358 2359 2360 2361 2362 | nEventTotal += nCount; @<tr class='row%d(rowClass)'> @ <td> @ <a href="?view=bymonth&user=%h(zUser)&type=%c((char)statsReportType)">%h(zUser)</a> @ </td><td>%d(nCount)</td> @ <td> @ <div class='statistics-report-graph-line' | | | | 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 | nEventTotal += nCount; @<tr class='row%d(rowClass)'> @ <td> @ <a href="?view=bymonth&user=%h(zUser)&type=%c((char)statsReportType)">%h(zUser)</a> @ </td><td>%d(nCount)</td> @ <td> @ <div class='statistics-report-graph-line' @ style='height:16px;width:%d(nSize)%%;'> @ </div></td> @</tr> /* Potential improvement: calculate the min/max event counts and use percent-based graph bars. */ } @ </tbody></table> |
︙ | ︙ | |||
2386 2387 2388 2389 2390 2391 2392 | Stmt qYears = empty_Stmt; char * zDefaultYear = NULL; Blob sql = empty_blob; int nMaxEvents = 1; /* max number of events for all rows. */ int iterations = 0; /* # of active time periods. */ stats_report_init_view(); | < < < | < | < < < | 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 | Stmt qYears = empty_Stmt; char * zDefaultYear = NULL; Blob sql = empty_blob; int nMaxEvents = 1; /* max number of events for all rows. */ int iterations = 0; /* # of active time periods. */ stats_report_init_view(); stats_report_event_types_menu("byweek"); cgi_printf("Select year: "); blob_append(&sql, "SELECT DISTINCT substr(date(mtime),1,4) AS y " "FROM v_reports WHERE 1 ", -1); if(zUserName&&*zUserName){ blob_appendf(&sql,"AND user=%Q ", zUserName); } blob_append(&sql,"GROUP BY y ORDER BY y", -1); db_prepare(&qYears, blob_str(&sql)); blob_reset(&sql); while( SQLITE_ROW == db_step(&qYears) ){ const char * zT = db_column_text(&qYears, 0); if( i++ ){ cgi_printf(" "); } cgi_printf("<a href='?view=byweek&y=%s&type=%c", zT, (char)statsReportType); |
︙ | ︙ | |||
2485 2486 2487 2488 2489 2490 2491 | } cgi_printf("'>%s</a></td>",zWeek); cgi_printf("<td>%d</td>",nCount); cgi_printf("<td>"); if(nCount){ cgi_printf("<div class='statistics-report-graph-line'" | | | 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 | } cgi_printf("'>%s</a></td>",zWeek); cgi_printf("<td>%d</td>",nCount); cgi_printf("<td>"); if(nCount){ cgi_printf("<div class='statistics-report-graph-line'" "style='height:16px;width:%d%%;'></div>", nSize); } cgi_printf("</td></tr>"); } db_finalize(&stWeek); free(zDefaultYear); cgi_printf("</tbody></table>"); |
︙ | ︙ | |||
2527 2528 2529 2530 2531 2532 2533 | ** y=YYYY The year to report (default is the server's ** current year). */ void stats_report_page(){ HQuery url; /* URL for various branch links */ const char * zView = P("view"); /* Which view/report to show. */ const char *zUserName = P("user"); | < < < > | 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 | ** y=YYYY The year to report (default is the server's ** current year). */ void stats_report_page(){ HQuery url; /* URL for various branch links */ const char * zView = P("view"); /* Which view/report to show. */ const char *zUserName = P("user"); if(!zUserName) zUserName = P("u"); url_initialize(&url, "reports"); if(zUserName && *zUserName){ url_add_parameter(&url,"user", zUserName); timeline_submenu(&url, "(Remove User Flag)", "view", zView, "user"); } timeline_submenu(&url, "By Year", "view", "byyear", 0); timeline_submenu(&url, "By Month", "view", "bymonth", 0); timeline_submenu(&url, "By Week", "view", "byweek", 0); |
︙ | ︙ |
Changes to src/tkt.c.
︙ | ︙ | |||
59 60 61 62 63 64 65 | for(i=0; i<nField; i++){ if( fossil_strcmp(aField[i].zName, zFieldName)==0 ) return i; } return -1; } /* | | | 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | for(i=0; i<nField; i++){ if( fossil_strcmp(aField[i].zName, zFieldName)==0 ) return i; } return -1; } /* ** Obtain a list of all fields of the TICKET and TICKETCHNG tables. Put them ** in sorted order in aField[]. ** ** The haveTicket and haveTicketChng variables are set to 1 if the TICKET and ** TICKETCHANGE tables exist, respectively. */ static void getAllTicketFields(void){ Stmt q; |
︙ | ︙ | |||
427 428 429 430 431 432 433 | login_check_credentials(); if( !g.perm.RdTkt ){ login_needed(); return; } if( g.perm.WrTkt || g.perm.ApndTkt ){ style_submenu_element("Edit", "Edit The Ticket", "%s/tktedit?name=%T", g.zTop, PD("name","")); } if( g.perm.Hyperlink ){ | | | | | | | | | | | | | 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 | login_check_credentials(); if( !g.perm.RdTkt ){ login_needed(); return; } if( g.perm.WrTkt || g.perm.ApndTkt ){ style_submenu_element("Edit", "Edit The Ticket", "%s/tktedit?name=%T", g.zTop, PD("name","")); } if( g.perm.Hyperlink ){ style_submenu_element("History", "History Of This Ticket", "%s/tkthistory/%T", g.zTop, zUuid); style_submenu_element("Timeline", "Timeline Of This Ticket", "%s/tkttimeline/%T", g.zTop, zUuid); style_submenu_element("Check-ins", "Check-ins Of This Ticket", "%s/tkttimeline/%T?y=ci", g.zTop, zUuid); } if( g.perm.NewTkt ){ style_submenu_element("New Ticket", "Create a new ticket", "%s/tktnew", g.zTop); } if( g.perm.ApndTkt && g.perm.Attach ){ style_submenu_element("Attach", "Add An Attachment", "%s/attachadd?tkt=%T&from=%s/tktview/%t", g.zTop, zUuid, g.zTop, zUuid); } if( P("plaintext") ){ style_submenu_element("Formatted", "Formatted", "%R/tktview/%S", zUuid); }else{ style_submenu_element("Plaintext", "Plaintext", "%R/tktview/%S?plaintext", zUuid); } style_header("View Ticket"); if( g.thTrace ) Th_Trace("BEGIN_TKTVIEW<br />\n", -1); ticket_init(); initializeVariablesFromCGI(); getAllTicketFields(); initializeVariablesFromDb(); zScript = ticket_viewpage_code(); if( P("showfields")!=0 ) showAllFields(); if( g.thTrace ) Th_Trace("BEGIN_TKTVIEW_SCRIPT<br />\n", -1); Th_Render(zScript); if( g.thTrace ) Th_Trace("END_TKTVIEW<br />\n", -1); zFullName = db_text(0, "SELECT tkt_uuid FROM ticket" " WHERE tkt_uuid GLOB '%q*'", zUuid); if( zFullName ){ attachment_list(zFullName, "<hr /><h2>Attachments:</h2><ul>"); } style_footer(); } /* ** TH command: append_field FIELD STRING ** ** FIELD is the name of a database column to which we might want ** to append text. STRING is the text to be appended to that ** column. The append does not actually occur until the ** submit_ticket command is run. */ static int appendRemarkCmd( Th_Interp *interp, void *p, int argc, const char **argv, int *argl ){ int idx; if( argc!=3 ){ return Th_WrongNumArgs(interp, "append_field FIELD STRING"); } |
︙ | ︙ | |||
553 554 555 556 557 558 559 | ** Construct and submit a new ticket artifact. The fields of the artifact ** are the names of the columns in the TICKET table. The content is ** taken from TH variables. If the content is unchanged, the field is ** omitted from the artifact. Fields whose names begin with "private_" ** are concealed using the db_conceal() function. */ static int submitTicketCmd( | | | | | | 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 | ** Construct and submit a new ticket artifact. The fields of the artifact ** are the names of the columns in the TICKET table. The content is ** taken from TH variables. If the content is unchanged, the field is ** omitted from the artifact. Fields whose names begin with "private_" ** are concealed using the db_conceal() function. */ static int submitTicketCmd( Th_Interp *interp, void *pUuid, int argc, const char **argv, int *argl ){ char *zDate; const char *zUuid; int i; int nJ = 0; Blob tktchng, cksum; |
︙ | ︙ | |||
604 605 606 607 608 609 610 | blob_appendf(&tktchng, "J %s %#F\n", aField[i].zName, nValue, zValue); } nJ++; } } } if( *(char**)pUuid ){ | | | | 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 | blob_appendf(&tktchng, "J %s %#F\n", aField[i].zName, nValue, zValue); } nJ++; } } } if( *(char**)pUuid ){ zUuid = db_text(0, "SELECT tkt_uuid FROM ticket WHERE tkt_uuid GLOB '%q*'", P("name") ); }else{ zUuid = db_text(0, "SELECT lower(hex(randomblob(20)))"); } *(const char**)pUuid = zUuid; blob_appendf(&tktchng, "K %s\n", zUuid); blob_appendf(&tktchng, "U %F\n", g.zLogin ? g.zLogin : ""); md5sum_blob(&tktchng, &cksum); blob_appendf(&tktchng, "Z %b\n", &cksum); if( nJ==0 ){ blob_reset(&tktchng); return TH_OK; } if( g.zPath[0]=='d' ){ |
︙ | ︙ | |||
673 674 675 676 677 678 679 | if( g.zPath[0]=='d' ) showAllFields(); form_begin(0, "%R/%s", g.zPath); login_insert_csrf_secret(); if( P("date_override") && g.perm.Setup ){ @ <input type="hidden" name="date_override" value="%h(P("date_override"))"> } zScript = ticket_newpage_code(); | | | 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 | if( g.zPath[0]=='d' ) showAllFields(); form_begin(0, "%R/%s", g.zPath); login_insert_csrf_secret(); if( P("date_override") && g.perm.Setup ){ @ <input type="hidden" name="date_override" value="%h(P("date_override"))"> } zScript = ticket_newpage_code(); Th_Store("login", g.zLogin ? g.zLogin : "nobody"); Th_Store("date", db_text(0, "SELECT datetime('now')")); Th_CreateCommand(g.interp, "submit_ticket", submitTicketCmd, (void*)&zNewUuid, 0); if( g.thTrace ) Th_Trace("BEGIN_TKTNEW_SCRIPT<br />\n", -1); if( Th_Render(zScript)==TH_RETURN && !g.thTrace && zNewUuid ){ cgi_redirect(mprintf("%s/tktview/%s", g.zTop, zNewUuid)); return; |
︙ | ︙ | |||
741 742 743 744 745 746 747 | initializeVariablesFromCGI(); initializeVariablesFromDb(); if( g.zPath[0]=='d' ) showAllFields(); form_begin(0, "%R/%s", g.zPath); @ <input type="hidden" name="name" value="%s(zName)" /> login_insert_csrf_secret(); zScript = ticket_editpage_code(); | | | 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 | initializeVariablesFromCGI(); initializeVariablesFromDb(); if( g.zPath[0]=='d' ) showAllFields(); form_begin(0, "%R/%s", g.zPath); @ <input type="hidden" name="name" value="%s(zName)" /> login_insert_csrf_secret(); zScript = ticket_editpage_code(); Th_Store("login", g.zLogin ? g.zLogin : "nobody"); Th_Store("date", db_text(0, "SELECT datetime('now')")); Th_CreateCommand(g.interp, "append_field", appendRemarkCmd, 0, 0); Th_CreateCommand(g.interp, "submit_ticket", submitTicketCmd, (void*)&zName,0); if( g.thTrace ) Th_Trace("BEGIN_TKTEDIT_SCRIPT<br />\n", -1); if( Th_Render(zScript)==TH_RETURN && !g.thTrace && zName ){ cgi_redirect(mprintf("%s/tktview/%s", g.zTop, zName)); return; |
︙ | ︙ | |||
893 894 895 896 897 898 899 | "%s/info/%s", g.zTop, zUuid); style_submenu_element("Check-ins", "Check-ins", "%s/tkttimeline?name=%s&y=ci", g.zTop, zUuid); style_submenu_element("Timeline", "Timeline", "%s/tkttimeline?name=%s", g.zTop, zUuid); if( P("plaintext")!=0 ){ style_submenu_element("Formatted", "Formatted", | | | | 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 | "%s/info/%s", g.zTop, zUuid); style_submenu_element("Check-ins", "Check-ins", "%s/tkttimeline?name=%s&y=ci", g.zTop, zUuid); style_submenu_element("Timeline", "Timeline", "%s/tkttimeline?name=%s", g.zTop, zUuid); if( P("plaintext")!=0 ){ style_submenu_element("Formatted", "Formatted", "%R/tkthistory/%S", zUuid); }else{ style_submenu_element("Plaintext", "Plaintext", "%R/tkthistory/%S?plaintext", zUuid); } style_header(zTitle); free(zTitle); tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname GLOB 'tkt-%q*'",zUuid); if( tagid==0 ){ @ No such ticket: %h(zUuid) |
︙ | ︙ | |||
922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 | " WHERE target=(SELECT substr(tagname,5) FROM tag WHERE tagid=%d)" " AND blob.rid=attachid" " ORDER BY 1", timeline_utc(), tagid, timeline_utc(), tagid ); while( db_step(&q)==SQLITE_ROW ){ Manifest *pTicket; const char *zDate = db_column_text(&q, 0); int rid = db_column_int(&q, 1); const char *zChngUuid = db_column_text(&q, 2); const char *zFile = db_column_text(&q, 4); if( nChng==0 ){ @ <ol> } nChng++; if( zFile!=0 ){ const char *zSrc = db_column_text(&q, 3); const char *zUser = db_column_text(&q, 5); if( zSrc==0 || zSrc[0]==0 ){ | > > > | | | | | | 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 | " WHERE target=(SELECT substr(tagname,5) FROM tag WHERE tagid=%d)" " AND blob.rid=attachid" " ORDER BY 1", timeline_utc(), tagid, timeline_utc(), tagid ); while( db_step(&q)==SQLITE_ROW ){ Manifest *pTicket; char zShort[12]; const char *zDate = db_column_text(&q, 0); int rid = db_column_int(&q, 1); const char *zChngUuid = db_column_text(&q, 2); const char *zFile = db_column_text(&q, 4); memcpy(zShort, zChngUuid, 10); zShort[10] = 0; if( nChng==0 ){ @ <ol> } nChng++; if( zFile!=0 ){ const char *zSrc = db_column_text(&q, 3); const char *zUser = db_column_text(&q, 5); if( zSrc==0 || zSrc[0]==0 ){ @ @ <li><p>Delete attachment "%h(zFile)" }else{ @ @ <li><p>Add attachment @ "%z(href("%R/artifact/%S",zSrc))%s(zFile)</a>" } @ [%z(href("%R/artifact/%T",zChngUuid))%s(zShort)</a>] @ (rid %d(rid)) by hyperlink_to_user(zUser,zDate," on"); hyperlink_to_date(zDate, ".</p>"); }else{ pTicket = manifest_get(rid, CFTYPE_TICKET, 0); if( pTicket ){ @ @ <li><p>Ticket change @ [%z(href("%R/artifact/%T",zChngUuid))%s(zShort)</a>] @ (rid %d(rid)) by hyperlink_to_user(pTicket->zUser,zDate," on"); hyperlink_to_date(zDate, ":"); @ </p> ticket_output_change_artifact(pTicket, "a"); } manifest_destroy(pTicket); |
︙ | ︙ | |||
1097 1098 1099 1100 1101 1102 1103 | const char *zTktUuid; /* do some ints, we want to be inside a checkout */ db_find_and_open_repository(0, 0); user_select(); zUser = find_option("user-override",0,1); | | | 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 | const char *zTktUuid; /* do some ints, we want to be inside a checkout */ db_find_and_open_repository(0, 0); user_select(); zUser = find_option("user-override",0,1); if( zUser==0 ) zUser = g.zLogin; zDate = find_option("date-override",0,1); if( zDate==0 ) zDate = "now"; zDate = date_in_standard_format(zDate); zTktUuid = find_option("uuid-override",0,1); if( zTktUuid && (strlen(zTktUuid)!=40 || !validate16(zTktUuid,40)) ){ fossil_fatal("invalid --uuid-override: must be 40 characters of hex"); } |
︙ | ︙ | |||
1146 1147 1148 1149 1150 1151 1152 | } } }else{ /* add a new ticket or set fields on existing tickets */ tTktShowEncoding tktEncoding; tktEncoding = find_option("quote","q",0) ? tktFossilize : tktNoTab; | | | 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 | } } }else{ /* add a new ticket or set fields on existing tickets */ tTktShowEncoding tktEncoding; tktEncoding = find_option("quote","q",0) ? tktFossilize : tktNoTab; if( strncmp(g.argv[2],"show",n)==0 ){ if( g.argc==3 ){ usage("show REPORTNR"); }else{ const char *zRep = 0; const char *zSep = 0; const char *zFilterUuid = 0; |
︙ | ︙ | |||
1181 1182 1183 1184 1185 1186 1187 | eCmd = history; }else{ eCmd = set; } if( g.argc==3 ){ usage("set|change|history TICKETUUID"); } | | | 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 | eCmd = history; }else{ eCmd = set; } if( g.argc==3 ){ usage("set|change|history TICKETUUID"); } zTktUuid = db_text(0, "SELECT tkt_uuid FROM ticket WHERE tkt_uuid GLOB '%s*'", g.argv[3] ); if( !zTktUuid ){ fossil_fatal("unknown ticket: '%s'!",g.argv[3]); } i=4; }else if( strncmp(g.argv[2],"add",n)==0 ){ |
︙ | ︙ | |||
1212 1213 1214 1215 1216 1217 1218 | if ( i != g.argc ){ fossil_fatal("no other parameters expected to %s!",g.argv[2]); } tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname GLOB 'tkt-%q*'", zTktUuid); if( tagid==0 ){ fossil_fatal("no such ticket %h", zTktUuid); | | | | | > > | > > | | 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 | if ( i != g.argc ){ fossil_fatal("no other parameters expected to %s!",g.argv[2]); } tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname GLOB 'tkt-%q*'", zTktUuid); if( tagid==0 ){ fossil_fatal("no such ticket %h", zTktUuid); } db_prepare(&q, "SELECT datetime(mtime%s), objid, uuid, NULL, NULL, NULL" " FROM event, blob" " WHERE objid IN (SELECT rid FROM tagxref WHERE tagid=%d)" " AND blob.rid=event.objid" " UNION " "SELECT datetime(mtime%s), attachid, uuid, src, " " filename, user" " FROM attachment, blob" " WHERE target=(SELECT substr(tagname,5) FROM tag WHERE tagid=%d)" " AND blob.rid=attachid" " ORDER BY 1 DESC", timeline_utc(), tagid, timeline_utc(), tagid ); while( db_step(&q)==SQLITE_ROW ){ Manifest *pTicket; char zShort[12]; const char *zDate = db_column_text(&q, 0); int rid = db_column_int(&q, 1); const char *zChngUuid = db_column_text(&q, 2); const char *zFile = db_column_text(&q, 4); memcpy(zShort, zChngUuid, 10); zShort[10] = 0; if( zFile!=0 ){ const char *zSrc = db_column_text(&q, 3); const char *zUser = db_column_text(&q, 5); if( zSrc==0 || zSrc[0]==0 ){ fossil_print("Delete attachment %s\n", zFile); }else{ fossil_print("Add attachment %s\n", zFile); } fossil_print(" by %s on %s\n", zUser, zDate); }else{ |
︙ | ︙ |
Changes to src/tktsetup.c.
︙ | ︙ | |||
113 114 115 116 117 118 119 | const char *zDesc, /* Description of this field */ char *(*xText)(const char*), /* Validity test or NULL */ void (*xRebuild)(void), /* Run after successful update */ int height /* Height of the edit box */ ){ const char *z; int isSubmit; | | | 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 | const char *zDesc, /* Description of this field */ char *(*xText)(const char*), /* Validity test or NULL */ void (*xRebuild)(void), /* Run after successful update */ int height /* Height of the edit box */ ){ const char *z; int isSubmit; login_check_credentials(); if( !g.perm.Setup ){ login_needed(); } if( P("setup") ){ cgi_redirect("tktsetup"); } |
︙ | ︙ | |||
312 313 314 315 316 317 318 | @ <table cellpadding="5"> @ <tr> @ <td colspan="3"> @ Enter a one-line summary of the ticket:<br /> @ <input type="text" name="title" size="60" value="$<title>" /> @ </td> @ </tr> | | | | | | | | | | | | 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 | @ <table cellpadding="5"> @ <tr> @ <td colspan="3"> @ Enter a one-line summary of the ticket:<br /> @ <input type="text" name="title" size="60" value="$<title>" /> @ </td> @ </tr> @ @ <tr> @ <td align="right">Type:</td> @ <td align="left"><th1>combobox type $type_choices 1</th1></td> @ <td align="left">What type of ticket is this?</td> @ </tr> @ @ <tr> @ <td align="right">Version:</td> @ <td align="left"> @ <input type="text" name="foundin" size="20" value="$<foundin>" /> @ </td> @ <td align="left">In what version or build number do you observe @ the problem?</td> @ </tr> @ @ <tr> @ <td align="right">Severity:</td> @ <td align="left"><th1>combobox severity $severity_choices 1</th1></td> @ <td align="left">How debilitating is the problem? How badly does the problem @ affect the operation of the product?</td> @ </tr> @ @ <tr> @ <td align="right">EMail:</td> @ <td align="left"> @ <input type="text" name="private_contact" value="$<private_contact>" @ size="30" /> @ </td> @ <td align="left"><u>Not publicly visible</u> @ Used by developers to contact you with questions.</td> @ </tr> @ @ <tr> @ <td colspan="3"> @ Enter a detailed description of the problem. @ For code defects, be sure to provide details on exactly how @ the problem can be reproduced. Provide as much detail as @ possible. Format: @ <th1>combobox mutype {Wiki HTML {Plain Text} {[links only]}} 1</th1> @ <br /> @ <th1>set nline [linecount $comment 50 10]</th1> @ <textarea name="icomment" cols="80" rows="$nline" @ wrap="virtual" class="wikiedit">$<icomment></textarea><br /> @ </tr> @ @ <th1>enable_output [info exists preview]</th1> @ <tr><td colspan="3"> @ Description Preview:<br /><hr /> @ <th1> @ if {$mutype eq "Wiki"} { @ wiki $icomment @ } elseif {$mutype eq "Plain Text"} { @ set r [randhex] @ wiki "<verbatim-$r>[string trimright $icomment]\n</verbatim-$r>" @ } elseif {$mutype eq {[links only]}} { @ set r [randhex] @ wiki "<verbatim-$r links>[string trimright $icomment]\n</verbatim-$r>" @ } else { @ wiki "<nowiki>$icomment\n</nowiki>" @ } @ </th1> @ <hr /></td></tr> @ <th1>enable_output 1</th1> @ @ <tr> @ <td><td align="left"> @ <input type="submit" name="preview" value="Preview" /> @ </td> @ <td align="left">See how the description will appear after formatting.</td> @ </tr> @ @ <th1>enable_output [info exists preview]</th1> @ <tr> @ <td><td align="left"> @ <input type="submit" name="submit" value="Submit" /> @ </td> @ <td align="left">After filling in the information above, press this @ button to create the new ticket</td> @ </tr> @ <th1>enable_output 1</th1> @ @ <tr> @ <td><td align="left"> @ <input type="submit" name="cancel" value="Cancel" /> @ </td> @ <td>Abandon and forget this ticket</td> @ </tr> @ </table> |
︙ | ︙ | |||
475 476 477 478 479 480 481 | @ </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> | | | 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 | @ </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] && [string length $comment]>10} { @ html { @ <tr><td class="tktDspLabel">Description:</td></tr> @ <tr><td colspan="5" class="tktDspValue"> @ } @ if {[info exists plaintext]} { |
︙ | ︙ | |||
575 576 577 578 579 580 581 | @ set preview 1 @ } @ </th1> @ <table cellpadding="5"> @ <tr><td class="tktDspLabel">Title:</td><td> @ <input type="text" name="title" value="$<title>" size="60" /> @ </td></tr> | | | | | | | | | | | | | | | | 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 | @ set preview 1 @ } @ </th1> @ <table cellpadding="5"> @ <tr><td class="tktDspLabel">Title:</td><td> @ <input type="text" name="title" value="$<title>" size="60" /> @ </td></tr> @ @ <tr><td class="tktDspLabel">Status:</td><td> @ <th1>combobox status $status_choices 1</th1> @ </td></tr> @ @ <tr><td class="tktDspLabel">Type:</td><td> @ <th1>combobox type $type_choices 1</th1> @ </td></tr> @ @ <tr><td class="tktDspLabel">Severity:</td><td> @ <th1>combobox severity $severity_choices 1</th1> @ </td></tr> @ @ <tr><td class="tktDspLabel">Priority:</td><td> @ <th1>combobox priority $priority_choices 1</th1> @ </td></tr> @ @ <tr><td class="tktDspLabel">Resolution:</td><td> @ <th1>combobox resolution $resolution_choices 1</th1> @ </td></tr> @ @ <tr><td class="tktDspLabel">Subsystem:</td><td> @ <th1>combobox subsystem $subsystem_choices 1</th1> @ </td></tr> @ @ <th1>enable_output [hascap e]</th1> @ <tr><td class="tktDspLabel">Contact:</td><td> @ <input type="text" name="private_contact" size="40" @ value="$<private_contact>" /> @ </td></tr> @ <th1>enable_output 1</th1> @ @ <tr><td class="tktDspLabel">Version Found In:</td><td> @ <input type="text" name="foundin" size="50" value="$<foundin>" /> @ </td></tr> @ @ <tr><td colspan="2"> @ Append Remark with format @ <th1>combobox mutype {Wiki HTML {Plain Text} {[links only]}} 1</th1> @ from @ <input type="text" name="username" value="$<username>" size="30" />:<br /> @ <textarea name="icomment" cols="80" rows="15" @ wrap="virtual" class="wikiedit">$<icomment></textarea> @ </td></tr> @ @ <th1>enable_output [info exists preview]</th1> @ <tr><td colspan="2"> @ Description Preview:<br><hr> @ <th1> @ if {$mutype eq "Wiki"} { @ wiki $icomment @ } elseif {$mutype eq "Plain Text"} { @ set r [randhex] @ wiki "<verbatim-$r>\n[string trimright $icomment]\n</verbatim-$r>" @ } elseif {$mutype eq {[links only]}} { @ set r [randhex] @ wiki "<verbatim-$r links>\n[string trimright $icomment]</verbatim-$r>" @ } else { @ wiki "<nowiki>\n[string trimright $icomment]\n</nowiki>" @ } @ </th1> @ <hr> @ </td></tr> @ <th1>enable_output 1</th1> @ @ <tr> @ <td align="right"> @ <input type="submit" name="preview" value="Preview" /> @ </td> @ <td align="left">See how the description will appear after formatting.</td> @ </tr> @ @ <th1>enable_output [info exists preview]</th1> @ <tr> @ <td align="right"> @ <input type="submit" name="submit" value="Submit" /> @ </td> @ <td align="left">Apply the changes shown above</td> @ </tr> @ <th1>enable_output 1</th1> @ @ <tr> @ <td align="right"> @ <input type="submit" name="cancel" value="Cancel" /> @ </td> @ <td>Abandon this edit</td> @ </tr> @ @ </table> ; /* ** Return the code used to generate the edit ticket page */ const char *ticket_editpage_code(void){ |
︙ | ︙ | |||
701 702 703 704 705 706 707 | static const char zDefaultReportList[] = @ <th1> @ if {[hascap n]} { @ html "<p>Enter a new ticket:</p>" @ html "<ul><li><a href='tktnew'>New ticket</a></li></ul>" @ } @ </th1> | | | | 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 | static const char zDefaultReportList[] = @ <th1> @ if {[hascap n]} { @ html "<p>Enter a new ticket:</p>" @ html "<ul><li><a href='tktnew'>New ticket</a></li></ul>" @ } @ </th1> @ @ <p>Choose a report format from the following list:</p> @ <ol> @ <th1>html $report_items</th1> @ </ol> @ @ <th1> @ if {[hascap t q]} { @ html "<p>Other options:</p>\n<ul>\n" @ if {[hascap t]} { @ html "<li><a href='rptnew'>New report format</a></li>\n" @ } @ if {[hascap q]} { |
︙ | ︙ | |||
748 749 750 751 752 753 754 | 40 ); } /* ** The default template ticket report format: */ | | | 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 | 40 ); } /* ** The default template ticket report format: */ static char zDefaultReport[] = @ SELECT @ CASE WHEN status IN ('Open','Verified') THEN '#f2dcdc' @ WHEN status='Review' THEN '#e8e8e8' @ WHEN status='Fixed' THEN '#cfe8bd' @ WHEN status='Tested' THEN '#bde5d6' @ WHEN status='Deferred' THEN '#cacae5' @ ELSE '#c8c8c8' END AS 'bgcolor', |
︙ | ︙ | |||
797 798 799 800 801 802 803 | 20 ); } /* ** The default template ticket key: */ | | | 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 | 20 ); } /* ** The default template ticket key: */ static const char zDefaultKey[] = @ #ffffff Key: @ #f2dcdc Active @ #e8e8e8 Review @ #cfe8bd Fixed @ #bde5d6 Tested @ #cacae5 Deferred @ #c8c8c8 Closed |
︙ | ︙ | |||
878 879 880 881 882 883 884 | @ <p> @ <input type="submit" name="submit" value="Apply Changes" /> @ <input type="submit" name="setup" value="Cancel" /> @ </p> @ </div></form> db_end_transaction(0); style_footer(); | | | 878 879 880 881 882 883 884 885 886 | @ <p> @ <input type="submit" name="submit" value="Apply Changes" /> @ <input type="submit" name="setup" value="Cancel" /> @ </p> @ </div></form> db_end_transaction(0); style_footer(); } |
Changes to src/update.c.
︙ | ︙ | |||
623 624 625 626 627 628 629 | ){ Manifest *pManifest; ManifestFile *pFile; int rid=0; if( revision ){ rid = name_to_typed_rid(revision,"ci"); | < < | 623 624 625 626 627 628 629 630 631 632 633 634 635 636 | ){ Manifest *pManifest; ManifestFile *pFile; int rid=0; if( revision ){ rid = name_to_typed_rid(revision,"ci"); }else{ rid = db_lget_int("checkout", 0); } if( !is_a_version(rid) ){ if( errCode>0 ) return errCode; fossil_fatal("no such checkin: %s", revision); } |
︙ | ︙ | |||
717 718 719 720 721 722 723 | zFile = mprintf("%/", g.argv[i]); file_tree_name(zFile, &fname, 1); db_multi_exec( "REPLACE INTO torevert VALUES(%B);" "INSERT OR IGNORE INTO torevert" " SELECT pathname" " FROM vfile" | | > > > > | | < < < < > | | | | > | 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 | zFile = mprintf("%/", g.argv[i]); file_tree_name(zFile, &fname, 1); db_multi_exec( "REPLACE INTO torevert VALUES(%B);" "INSERT OR IGNORE INTO torevert" " SELECT pathname" " FROM vfile" " WHERE origname IN(%B)" " UNION ALL" " SELECT origname" " FROM vfile" " WHERE pathname IN(%B) AND origname IS NOT NULL;", &fname, &fname, &fname ); blob_reset(&fname); } }else{ int vid; vid = db_lget_int("checkout", 0); vfile_check_signature(vid, 0); db_multi_exec( "DELETE FROM vmerge;" "INSERT OR IGNORE INTO torevert " " SELECT pathname" " FROM vfile " " WHERE chnged OR deleted OR rid=0 OR pathname!=origname " " UNION ALL " " SELECT origname" " FROM vfile" " WHERE origname!=pathname;" ); } blob_zero(&record); db_prepare(&q, "SELECT name FROM torevert"); if( zRevision==0 ){ int vid = db_lget_int("checkout", 0); zRevision = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", vid); } while( db_step(&q)==SQLITE_ROW ){ |
︙ | ︙ | |||
764 765 766 767 768 769 770 | fossil_print("UNMANAGE: %s\n", zFile); }else{ undo_save(zFile); file_delete(zFull); fossil_print("DELETE: %s\n", zFile); } db_multi_exec( | | | | 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 | fossil_print("UNMANAGE: %s\n", zFile); }else{ undo_save(zFile); file_delete(zFull); fossil_print("DELETE: %s\n", zFile); } db_multi_exec( "UPDATE vfile" " SET pathname=origname, origname=NULL" " WHERE pathname=%Q AND origname!=pathname AND origname IS NOT NULL;" "DELETE FROM vfile WHERE pathname=%Q", zFile, zFile ); }else{ sqlite3_int64 mtime; undo_save(zFile); if( file_wd_size(zFull)>=0 && (isLink || file_wd_islink(zFull)) ){ |
︙ | ︙ |
Changes to src/url.c.
︙ | ︙ | |||
60 61 62 63 64 65 66 | char *path; /* Pathname for http: */ char *user; /* User id for http: */ char *passwd; /* Password for http: */ char *canonical; /* Canonical representation of the URL */ char *proxyAuth; /* Proxy-Authorizer: string */ char *fossil; /* The fossil query parameter on ssh: */ unsigned flags; /* Boolean flags controlling URL processing */ | < < < | 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | char *path; /* Pathname for http: */ char *user; /* User id for http: */ char *passwd; /* Password for http: */ char *canonical; /* Canonical representation of the URL */ char *proxyAuth; /* Proxy-Authorizer: string */ char *fossil; /* The fossil query parameter on ssh: */ unsigned flags; /* Boolean flags controlling URL processing */ }; #endif /* INTERFACE */ /* ** Convert a string to lower-case. */ |
︙ | ︙ | |||
121 122 123 124 125 126 127 | ){ int iStart; char *zLogin; char *zExe; char cQuerySep = '?'; pUrlData->isFile = 0; | < | 118 119 120 121 122 123 124 125 126 127 128 129 130 131 | ){ int iStart; char *zLogin; char *zExe; char cQuerySep = '?'; pUrlData->isFile = 0; if( zUrl[4]=='s' ){ pUrlData->isHttps = 1; pUrlData->protocol = "https"; pUrlData->dfltPort = 443; iStart = 8; }else if( zUrl[0]=='s' ){ pUrlData->isSsh = 1; |
︙ | ︙ | |||
273 274 275 276 277 278 279 | } } /* ** Parse the given URL, which describes a sync server. Populate variables ** in the global "g" structure as follows: ** | | | | | | | | | | | | | | | 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 | } } /* ** Parse the given URL, which describes a sync server. Populate variables ** in the global "g" structure as follows: ** ** g.urlIsFile True if FILE: ** g.urlIsHttps True if HTTPS: ** g.urlIsSsh True if SSH: ** g.urlProtocol "http" or "https" or "file" ** g.urlName Hostname for HTTP:, HTTPS:, SSH:. Filename for FILE: ** g.urlPort TCP port number for HTTP or HTTPS. ** g.urlDfltPort Default TCP port number (80 or 443). ** g.urlPath Path name for HTTP or HTTPS. ** g.urlUser Userid. ** g.urlPasswd Password. ** g.urlHostname HOST:PORT or just HOST if port is the default. ** g.urlCanonical The URL in canonical form, omitting the password ** ** HTTP url format as follows (HTTPS is the same with a different scheme): ** ** http://userid:password@host:port/path ** ** SSH url format is: ** ** ssh://userid@host:port/path?fossil=path/to/fossil.exe ** */ void url_parse(const char *zUrl, unsigned int urlFlags){ url_parse_local(zUrl, urlFlags, GLOBAL_URL()); } /* ** COMMAND: test-urlparser ** ** Usage: %fossil test-urlparser URL ?options? ** |
︙ | ︙ | |||
321 322 323 324 325 326 327 | } if( find_option("prompt-pw",0,0) ) fg |= URL_PROMPT_PW; if( g.argc!=3 && g.argc!=4 ){ usage("URL"); } url_parse(g.argv[2], fg); for(i=0; i<2; i++){ | | | | | | | | | | | | | | | | | 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 | } if( find_option("prompt-pw",0,0) ) fg |= URL_PROMPT_PW; if( g.argc!=3 && g.argc!=4 ){ usage("URL"); } url_parse(g.argv[2], fg); for(i=0; i<2; i++){ fossil_print("g.urlIsFile = %d\n", g.urlIsFile); fossil_print("g.urlIsHttps = %d\n", g.urlIsHttps); fossil_print("g.urlIsSsh = %d\n", g.urlIsSsh); fossil_print("g.urlProtocol = %s\n", g.urlProtocol); fossil_print("g.urlName = %s\n", g.urlName); fossil_print("g.urlPort = %d\n", g.urlPort); fossil_print("g.urlDfltPort = %d\n", g.urlDfltPort); fossil_print("g.urlHostname = %s\n", g.urlHostname); fossil_print("g.urlPath = %s\n", g.urlPath); fossil_print("g.urlUser = %s\n", g.urlUser); fossil_print("g.urlPasswd = %s\n", g.urlPasswd); fossil_print("g.urlCanonical = %s\n", g.urlCanonical); fossil_print("g.urlFossil = %s\n", g.urlFossil); fossil_print("g.urlFlags = 0x%02x\n", g.urlFlags); if( g.urlIsFile || g.urlIsSsh ) break; if( i==0 ){ fossil_print("********\n"); url_enable_proxy("Using proxy: "); } } } |
︙ | ︙ | |||
383 384 385 386 387 388 389 | if( zProxy==0 ){ zProxy = db_get("proxy", 0); if( zProxy==0 || zProxy[0]==0 || is_truth(zProxy) ){ zProxy = fossil_getenv("http_proxy"); } } if( zProxy && zProxy[0] && !is_false(zProxy) | | | | < | | < < | | | | | | | | | | | < < < < | | 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 | if( zProxy==0 ){ zProxy = db_get("proxy", 0); if( zProxy==0 || zProxy[0]==0 || is_truth(zProxy) ){ zProxy = fossil_getenv("http_proxy"); } } if( zProxy && zProxy[0] && !is_false(zProxy) && !g.urlIsSsh && !g.urlIsFile ){ char *zOriginalUrl = g.urlCanonical; char *zOriginalHost = g.urlHostname; char *zOriginalUser = g.urlUser; char *zOriginalPasswd = g.urlPasswd; unsigned uOriginalFlags = g.urlFlags; g.urlUser = 0; g.urlPasswd = ""; url_parse(zProxy, 0); if( zMsg ) fossil_print("%s%s\n", zMsg, g.urlCanonical); g.urlPath = zOriginalUrl; g.urlHostname = zOriginalHost; if( g.urlUser ){ char *zCredentials1 = mprintf("%s:%s", g.urlUser, g.urlPasswd); char *zCredentials2 = encode64(zCredentials1, -1); g.urlProxyAuth = mprintf("Basic %z", zCredentials2); free(zCredentials1); } g.urlUser = zOriginalUser; g.urlPasswd = zOriginalPasswd; g.urlFlags = uOriginalFlags; } } #if INTERFACE /* ** An instance of this object is used to build a URL with query parameters. */ |
︙ | ︙ | |||
527 528 529 530 531 532 533 | }else{ fossil_fatal("missing or incorrect password for user \"%s\"", pUrlData->user); } } /* | | | | | | | | | | | 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 | }else{ fossil_fatal("missing or incorrect password for user \"%s\"", pUrlData->user); } } /* ** Prompt the user for the password for g.urlUser. Store the result ** in g.urlPasswd. */ void url_prompt_for_password(void){ url_prompt_for_password_local(GLOBAL_URL()); } /* ** Remember the URL and password if requested. */ void url_remember(void){ if( g.urlFlags & URL_REMEMBER ){ db_set("last-sync-url", g.urlCanonical, 0); if( g.urlUser!=0 && g.urlPasswd!=0 && ( g.urlFlags & URL_REMEMBER_PW ) ){ db_set("last-sync-pw", obscure(g.urlPasswd), 0); } } } /* Preemptively prompt for a password if a username is given in the ** URL but no password. */ void url_get_password_if_needed(void){ if( (g.urlUser && g.urlUser[0]) && (g.urlPasswd==0 || g.urlPasswd[0]==0) && isatty(fileno(stdin)) ){ url_prompt_for_password(); } } |
Changes to src/user.c.
︙ | ︙ | |||
373 374 375 376 377 378 379 | if( attempt_user(fossil_getenv("USER")) ) return; if( attempt_user(fossil_getenv("LOGNAME")) ) return; if( attempt_user(fossil_getenv("USERNAME")) ) return; url_parse(0, 0); | | | 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 | if( attempt_user(fossil_getenv("USER")) ) return; if( attempt_user(fossil_getenv("LOGNAME")) ) return; if( attempt_user(fossil_getenv("USERNAME")) ) return; url_parse(0, 0); if( g.urlUser && attempt_user(g.urlUser) ) return; fossil_print( "Cannot figure out who you are! Consider using the --user\n" "command line option, setting your USER environment variable,\n" "or setting a default user with \"fossil user default USER\".\n" ); fossil_fatal("cannot determine user"); |
︙ | ︙ |
Changes to src/utf8.c.
︙ | ︙ | |||
52 53 54 55 56 57 58 | ** Return a pointer to the translated text. ** Call fossil_unicode_free() to deallocate any memory used to store the ** returned pointer when done. */ char *fossil_unicode_to_utf8(const void *zUnicode){ #if defined(_WIN32) || defined(__CYGWIN__) int nByte = WideCharToMultiByte(CP_UTF8, 0, zUnicode, -1, 0, 0, 0, 0); | | > > > < < < < < | < < | > > > < > > > > | 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 | ** Return a pointer to the translated text. ** Call fossil_unicode_free() to deallocate any memory used to store the ** returned pointer when done. */ char *fossil_unicode_to_utf8(const void *zUnicode){ #if defined(_WIN32) || defined(__CYGWIN__) int nByte = WideCharToMultiByte(CP_UTF8, 0, zUnicode, -1, 0, 0, 0, 0); char *zUtf = sqlite3_malloc( nByte ); if( zUtf==0 ){ return 0; } WideCharToMultiByte(CP_UTF8, 0, zUnicode, -1, zUtf, nByte, 0, 0); return zUtf; #else return fossil_strdup(zUnicode); /* TODO: implement for unix */ #endif } /* ** Translate UTF-8 to unicode for use in system calls. Return a pointer to the ** translated text.. Call fossil_unicode_free() to deallocate any memory ** used to store the returned pointer when done. */ void *fossil_utf8_to_unicode(const char *zUtf8){ #if defined(_WIN32) || defined(__CYGWIN__) int nByte = MultiByteToWideChar(CP_UTF8, 0, zUtf8, -1, 0, 0); wchar_t *zUnicode = sqlite3_malloc( nByte * 2 ); if( zUnicode==0 ){ return 0; } MultiByteToWideChar(CP_UTF8, 0, zUtf8, -1, zUnicode, nByte); return zUnicode; #else return fossil_strdup(zUtf8); /* TODO: implement for unix */ #endif } /* ** Deallocate any memory that was previously allocated by ** fossil_unicode_to_utf8(). */ void fossil_unicode_free(void *pOld){ #if defined(_WIN32) || defined(__CYGWIN__) sqlite3_free(pOld); #else fossil_free(pOld); #endif } #if defined(__APPLE__) && !defined(WITHOUT_ICONV) # include <iconv.h> #endif /* |
︙ | ︙ | |||
175 176 177 178 179 180 181 | ** Translate text from UTF-8 to the filename character set. ** Return a pointer to the translated text. ** Call fossil_filename_free() to deallocate any memory used to store the ** returned pointer when done. ** ** On Windows, characters in the range U+0001 to U+0031 and the ** characters '"', '*', ':', '<', '>', '?' and '|' are invalid | < | < | < | < < < < < < < < < < < < < < < | < < < < < < < < < | < < < < < < < < < < < < | 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 | ** Translate text from UTF-8 to the filename character set. ** Return a pointer to the translated text. ** Call fossil_filename_free() to deallocate any memory used to store the ** returned pointer when done. ** ** On Windows, characters in the range U+0001 to U+0031 and the ** characters '"', '*', ':', '<', '>', '?' and '|' are invalid ** to be used. Therefore, translate those to characters in the ** in the range U+F001 - U+F07F (private use area), so those ** characters never arrive in any Windows API. The filenames might ** look strange in Windows explorer, but in the cygwin shell ** everything looks as expected. ** ** See: <http://cygwin.com/cygwin-ug-net/using-specialnames.html> ** */ void *fossil_utf8_to_filename(const char *zUtf8){ #ifdef _WIN32 int nChar = MultiByteToWideChar(CP_UTF8, 0, zUtf8, -1, 0, 0); wchar_t *zUnicode = sqlite3_malloc( nChar * 2 ); wchar_t *wUnicode = zUnicode; if( zUnicode==0 ){ return 0; } MultiByteToWideChar(CP_UTF8, 0, zUtf8, -1, zUnicode, nChar); /* If path starts with "<drive>:/" or "<drive>:\", don't translate the ':' */ if( fossil_isalpha(zUtf8[0]) && zUtf8[1]==':' && (zUtf8[2]=='\\' || zUtf8[2]=='/')) { zUnicode[2] = '\\'; wUnicode += 3; } while( *wUnicode != '\0' ){ if ( (*wUnicode < ' ') || wcschr(L"\"*:<>?|", *wUnicode) ){ *wUnicode |= 0xF000; }else if( *wUnicode == '/' ){ *wUnicode = '\\'; } ++wUnicode; |
︙ | ︙ |
Changes to src/vfile.c.
︙ | ︙ | |||
43 44 45 46 47 48 49 | /* ** Given a UUID, return the corresponding record ID. If the UUID ** does not exist, then return 0. ** ** For this routine, the UUID must be exact. For a match against ** user input with mixed case, use resolve_uuid(). ** | | | | 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | /* ** Given a UUID, return the corresponding record ID. If the UUID ** does not exist, then return 0. ** ** For this routine, the UUID must be exact. For a match against ** user input with mixed case, use resolve_uuid(). ** ** If the UUID is not found and phantomize is 1 or 2, then attempt to ** create a phantom record. A private phantom is created for 2 and ** a public phantom is created for 1. */ int uuid_to_rid(const char *zUuid, int phantomize){ int rid, sz; char z[UUID_SIZE+1]; sz = strlen(zUuid); if( sz!=UUID_SIZE || !validate16(zUuid, sz) ){ return 0; } memcpy(z, zUuid, UUID_SIZE+1); canonical16(z, sz); rid = fast_uuid_to_rid(z); |
︙ | ︙ | |||
138 139 140 141 142 143 144 | ** VFILE.CHNGED field according to whether or not ** the file has changed. 0 means no change. 1 means edited. 2 means ** the file has changed due to a merge. 3 means the file was added ** by a merge. ** ** If VFILE.DELETED is true or if VFILE.RID is zero, then the file was either ** removed from configuration management via "fossil rm" or added via | | | 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 | ** VFILE.CHNGED field according to whether or not ** the file has changed. 0 means no change. 1 means edited. 2 means ** the file has changed due to a merge. 3 means the file was added ** by a merge. ** ** If VFILE.DELETED is true or if VFILE.RID is zero, then the file was either ** removed from configuration management via "fossil rm" or added via ** "fossil add", respectively, and in both cases we always know that ** the file has changed without having the check the size, mtime, ** or on-disk content. ** ** If the size of the file has changed, then we always know that the file ** changed without having to look at the mtime or on-disk content. ** ** The mtime of the file is only a factor if the mtime-changes setting |
︙ | ︙ | |||
313 314 315 316 317 318 319 | continue; } } if( verbose ) fossil_print("%s\n", &zName[nRepos]); if( file_wd_isdir(zName) == 1 ){ /*TODO(dchest): remove directories? */ fossil_fatal("%s is directory, cannot overwrite\n", zName); | | | 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 | continue; } } if( verbose ) fossil_print("%s\n", &zName[nRepos]); if( file_wd_isdir(zName) == 1 ){ /*TODO(dchest): remove directories? */ fossil_fatal("%s is directory, cannot overwrite\n", zName); } if( file_wd_size(zName)>=0 && (isLink || file_wd_islink(zName)) ){ file_delete(zName); } if( isLink ){ symlink_create(blob_str(&content), zName); }else{ blob_write_to_file(&content, zName); |
︙ | ︙ | |||
390 391 392 393 394 395 396 | static const char *const azTemp[] = { "baseline", "merge", "original", "output", }; int i, j, n; | | | | 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 | static const char *const azTemp[] = { "baseline", "merge", "original", "output", }; int i, j, n; if( strglob("ci-comment-????????????.txt", zName) ) return 1; for(; zName[0]!=0; zName++){ if( zName[0]=='/' && strglob("/ci-comment-????????????.txt", zName) ){ return 1; } if( zName[0]!='-' ) continue; for(i=0; i<sizeof(azTemp)/sizeof(azTemp[0]); i++){ n = (int)strlen(azTemp[i]); if( memcmp(azTemp[i], zName+1, n) ) continue; if( zName[n+1]==0 ) return 1; if( zName[n+1]=='-' ){ for(j=n+2; zName[j] && fossil_isdigit(zName[j]); j++){} if( zName[j]==0 ) return 1; } } } return 0; } #if INTERFACE /* ** Values for the scanFlags parameter to vfile_scan(). |
︙ | ︙ | |||
672 673 674 675 676 677 678 | */ void vfile_aggregate_checksum_disk(int vid, Blob *pOut){ FILE *in; Stmt q; char zBuf[4096]; db_must_be_within_tree(); | | | | 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 | */ void vfile_aggregate_checksum_disk(int vid, Blob *pOut){ FILE *in; Stmt q; char zBuf[4096]; db_must_be_within_tree(); db_prepare(&q, "SELECT %Q || pathname, pathname, origname, is_selected(id), rid" " FROM vfile" " WHERE (NOT deleted OR NOT is_selected(id)) AND vid=%d" " ORDER BY if_selected(id, pathname, origname) /*scan*/", g.zLocalRoot, vid ); md5sum_init(); while( db_step(&q)==SQLITE_ROW ){ const char *zFullpath = db_column_text(&q, 0); const char *zName = db_column_text(&q, 1); int isSelected = db_column_int(&q, 3); if( isSelected ){ md5sum_step_text(zName, -1); if( file_wd_islink(zFullpath) ){ /* Instead of file content, use link destination path */ Blob pathBuf; sqlite3_snprintf(sizeof(zBuf), zBuf, " %ld\n", blob_read_link(&pathBuf, zFullpath)); md5sum_step_text(zBuf, -1); md5sum_step_text(blob_str(&pathBuf), -1); blob_reset(&pathBuf); }else{ in = fossil_fopen(zFullpath,"rb"); if( in==0 ){ |
︙ | ︙ | |||
722 723 724 725 726 727 728 | }else{ int rid = db_column_int(&q, 4); const char *zOrigName = db_column_text(&q, 2); char zBuf[100]; Blob file; if( zOrigName ) zName = zOrigName; | | | 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 | }else{ int rid = db_column_int(&q, 4); const char *zOrigName = db_column_text(&q, 2); char zBuf[100]; Blob file; if( zOrigName ) zName = zOrigName; if( rid>0 ){ md5sum_step_text(zName, -1); blob_zero(&file); content_get(rid, &file); sqlite3_snprintf(sizeof(zBuf), zBuf, " %d\n", blob_size(&file)); md5sum_step_text(zBuf, -1); md5sum_step_blob(&file); blob_reset(&file); |
︙ | ︙ | |||
761 762 763 764 765 766 767 | ** the working check-out on disk. Report any errors. */ void vfile_compare_repository_to_disk(int vid){ int rc; Stmt q; Blob disk, repo; char *zOut; | | | | 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 | ** the working check-out on disk. Report any errors. */ void vfile_compare_repository_to_disk(int vid){ int rc; Stmt q; Blob disk, repo; char *zOut; db_must_be_within_tree(); db_prepare(&q, "SELECT %Q || pathname, pathname, rid FROM vfile" " WHERE NOT deleted AND vid=%d AND is_selected(id)" " ORDER BY if_selected(id, pathname, origname) /*scan*/", g.zLocalRoot, vid ); md5sum_init(); while( db_step(&q)==SQLITE_ROW ){ |
︙ | ︙ | |||
827 828 829 830 831 832 833 | */ void vfile_aggregate_checksum_repository(int vid, Blob *pOut){ Blob file; Stmt q; char zBuf[100]; db_must_be_within_tree(); | | | | | 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 | */ void vfile_aggregate_checksum_repository(int vid, Blob *pOut){ Blob file; Stmt q; char zBuf[100]; db_must_be_within_tree(); db_prepare(&q, "SELECT pathname, origname, rid, is_selected(id)" " FROM vfile" " WHERE (NOT deleted OR NOT is_selected(id))" " AND rid>0 AND vid=%d" " ORDER BY if_selected(id,pathname,origname) /*scan*/", vid); blob_zero(&file); md5sum_init(); while( db_step(&q)==SQLITE_ROW ){ const char *zName = db_column_text(&q, 0); const char *zOrigName = db_column_text(&q, 1); int rid = db_column_int(&q, 2); int isSelected = db_column_int(&q, 3); |
︙ | ︙ | |||
865 866 867 868 869 870 871 | ** ** Return the resulting checksum in blob pOut. ** ** If pManOut is not NULL then fill it with the checksum found in the ** "R" card near the end of the manifest. ** ** In a well-formed manifest, the two checksums computed here, pOut and | | | 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 | ** ** Return the resulting checksum in blob pOut. ** ** If pManOut is not NULL then fill it with the checksum found in the ** "R" card near the end of the manifest. ** ** In a well-formed manifest, the two checksums computed here, pOut and ** pManOut, should be identical. */ void vfile_aggregate_checksum_manifest(int vid, Blob *pOut, Blob *pManOut){ int fid; Blob file; Blob err; Manifest *pManifest; ManifestFile *pFile; |
︙ | ︙ |
Changes to src/wiki.c.
︙ | ︙ | |||
220 221 222 223 224 225 226 | isSandbox = is_sandbox(zPageName); if( isSandbox ){ zBody = db_get("sandbox",zBody); zMimetype = db_get("sandbox-mimetype","text/x-fossil-wiki"); rid = 0; }else{ zTag = mprintf("wiki-%s", zPageName); | | | | | 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 | isSandbox = is_sandbox(zPageName); if( isSandbox ){ zBody = db_get("sandbox",zBody); zMimetype = db_get("sandbox-mimetype","text/x-fossil-wiki"); rid = 0; }else{ zTag = mprintf("wiki-%s", zPageName); rid = db_int(0, "SELECT rid FROM tagxref" " WHERE tagid=(SELECT tagid FROM tag WHERE tagname=%Q)" " ORDER BY mtime DESC", zTag ); free(zTag); pWiki = manifest_get(rid, CFTYPE_WIKI, 0); if( pWiki ){ zBody = pWiki->zWiki; zMimetype = pWiki->zMimetype; } } zMimetype = wiki_filter_mimetypes(zMimetype); if( !g.isHome ){ if( rid ){ style_submenu_element("Diff", "Last change", "%R/wdiff?name=%T&a=%d", zPageName, rid); zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); style_submenu_element("Details", "Details", "%R/info/%S", zUuid); } if( (rid && g.perm.WrWiki) || (!rid && g.perm.NewWiki) ){ if( db_get_boolean("wysiwyg-wiki", 0) ){ style_submenu_element("Edit", "Edit Wiki Page", "%s/wikiedit?name=%T&wysiwyg=1", g.zTop, zPageName); }else{ style_submenu_element("Edit", "Edit Wiki Page", "%s/wikiedit?name=%T", g.zTop, zPageName); } } if( rid && g.perm.ApndWiki && g.perm.Attach ){ style_submenu_element("Attach", "Add An Attachment", "%s/attachadd?page=%T&from=%s/wiki%%3fname=%T", g.zTop, zPageName, g.zTop, zPageName); } if( rid && g.perm.ApndWiki ){ style_submenu_element("Append", "Add A Comment", "%s/wikiappend?name=%T&mimetype=%s", g.zTop, zPageName, zMimetype); } if( g.perm.Hyperlink ){ style_submenu_element("History", "History", "%s/whistory?name=%T", g.zTop, zPageName); } |
︙ | ︙ | |||
298 299 300 301 302 303 304 | db_multi_exec("INSERT OR IGNORE INTO unclustered VALUES(%d);", nrid); manifest_crosslink(nrid, pWiki, MC_NONE); } /* ** Formal names and common names for the various wiki styles. */ | | | 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 | db_multi_exec("INSERT OR IGNORE INTO unclustered VALUES(%d);", nrid); manifest_crosslink(nrid, pWiki, MC_NONE); } /* ** Formal names and common names for the various wiki styles. */ static const char *azStyles[] = { "text/x-fossil-wiki", "Fossil Wiki", "text/x-markdown", "Markdown", "text/plain", "Plain Text" }; /* ** Output a selection box from which the user can select the |
︙ | ︙ | |||
379 380 381 382 383 384 385 | } if( zBody==0 ){ zBody = db_get("sandbox",""); zMimetype = db_get("sandbox-mimetype","text/x-fossil-wiki"); } }else{ zTag = mprintf("wiki-%s", zPageName); | | | 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 | } if( zBody==0 ){ zBody = db_get("sandbox",""); zMimetype = db_get("sandbox-mimetype","text/x-fossil-wiki"); } }else{ zTag = mprintf("wiki-%s", zPageName); rid = db_int(0, "SELECT rid FROM tagxref" " WHERE tagid=(SELECT tagid FROM tag WHERE tagname=%Q)" " ORDER BY mtime DESC", zTag ); free(zTag); if( (rid && !g.perm.WrWiki) || (!rid && !g.perm.NewWiki) ){ login_needed(); |
︙ | ︙ | |||
418 419 420 421 422 423 424 | blob_appendf(&wiki, "N %s\n", zMimetype); } if( rid ){ char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); blob_appendf(&wiki, "P %s\n", zUuid); free(zUuid); } | | | | 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 | blob_appendf(&wiki, "N %s\n", zMimetype); } if( rid ){ char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); blob_appendf(&wiki, "P %s\n", zUuid); free(zUuid); } if( g.zLogin ){ blob_appendf(&wiki, "U %F\n", g.zLogin); } blob_appendf(&wiki, "W %d\n%s\n", strlen(zBody), zBody); md5sum_blob(&wiki, &cksum); blob_appendf(&wiki, "Z %b\n", &cksum); blob_reset(&cksum); wiki_put(&wiki, 0); } |
︙ | ︙ | |||
460 461 462 463 464 465 466 | if( n<20 ) n = 20; if( n>30 ) n = 30; if( !isWysiwyg ){ /* Traditional markup-only editing */ form_begin(0, "%R/wikiedit"); @ <div> mimetype_option_menu(zMimetype); | | | 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 | if( n<20 ) n = 20; if( n>30 ) n = 30; if( !isWysiwyg ){ /* Traditional markup-only editing */ form_begin(0, "%R/wikiedit"); @ <div> mimetype_option_menu(zMimetype); @ <br /><textarea name="w" class="wikiedit" cols="80" @ rows="%d(n)" wrap="virtual">%h(zBody)</textarea> @ <br /> if( db_get_boolean("wysiwyg-wiki", 0) ){ @ <input type="submit" name="edit-wysiwyg" value="Wysiwyg Editor" @ onclick='return confirm("Switching to WYSIWYG-mode\nwill erase your markup\nedits. Continue?")' /> } @ <input type="submit" name="preview" value="Preview Your Changes" /> |
︙ | ︙ | |||
512 513 514 515 516 517 518 | void wikinew_page(void){ const char *zName; const char *zMimetype; login_check_credentials(); if( !g.perm.NewWiki ){ login_needed(); return; | | | 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 | void wikinew_page(void){ const char *zName; const char *zMimetype; login_check_credentials(); if( !g.perm.NewWiki ){ login_needed(); return; } zName = PD("name",""); zMimetype = wiki_filter_mimetypes(P("mimetype")); if( zName[0] && wiki_name_is_wellformed((const unsigned char *)zName) ){ if( fossil_strcmp(zMimetype,"text/x-fossil-wiki")==0 && db_get_boolean("wysiwyg-wiki", 0) ){ cgi_redirectf("wikiedit?name=%T&wysiwyg=1", zName); |
︙ | ︙ | |||
555 556 557 558 559 560 561 | char *zId; zDate = db_text(0, "SELECT datetime('now')"); zRemark = PD("r",""); zUser = PD("u",g.zLogin); if( fossil_strcmp(zMimetype, "text/x-fossil-wiki")==0 ){ zId = db_text(0, "SELECT lower(hex(randomblob(8)))"); | | | | | | | | | 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 | char *zId; zDate = db_text(0, "SELECT datetime('now')"); zRemark = PD("r",""); zUser = PD("u",g.zLogin); if( fossil_strcmp(zMimetype, "text/x-fossil-wiki")==0 ){ zId = db_text(0, "SELECT lower(hex(randomblob(8)))"); blob_appendf(p, "\n\n<hr><div id=\"%s\"><i>On %s UTC %h", zId, zDate, g.zLogin); if( zUser[0] && fossil_strcmp(zUser,g.zLogin) ){ blob_appendf(p, " (claiming to be %h)", zUser); } blob_appendf(p, " added:</i><br />\n%s</div id=\"%s\">", zRemark, zId); }else if( fossil_strcmp(zMimetype, "text/x-markdown")==0 ){ blob_appendf(p, "\n\n------\n*On %s UTC %h", zDate, g.zLogin); if( zUser[0] && fossil_strcmp(zUser,g.zLogin) ){ blob_appendf(p, " (claiming to be %h)", zUser); } blob_appendf(p, " added:*\n\n%s\n", zRemark); }else{ blob_appendf(p, "\n\n------------------------------------------------\n" "On %s UTC %s", zDate, g.zLogin); if( zUser[0] && fossil_strcmp(zUser,g.zLogin) ){ blob_appendf(p, " (claiming to be %s)", zUser); } blob_appendf(p, " added:\n\n%s\n", zRemark); } fossil_free(zDate); } |
︙ | ︙ | |||
599 600 601 602 603 604 605 | login_check_credentials(); zPageName = PD("name",""); zMimetype = wiki_filter_mimetypes(P("mimetype")); if( check_name(zPageName) ) return; isSandbox = is_sandbox(zPageName); if( !isSandbox ){ zTag = mprintf("wiki-%s", zPageName); | | | 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 | login_check_credentials(); zPageName = PD("name",""); zMimetype = wiki_filter_mimetypes(P("mimetype")); if( check_name(zPageName) ) return; isSandbox = is_sandbox(zPageName); if( !isSandbox ){ zTag = mprintf("wiki-%s", zPageName); rid = db_int(0, "SELECT rid FROM tagxref" " WHERE tagid=(SELECT tagid FROM tag WHERE tagname=%Q)" " ORDER BY mtime DESC", zTag ); free(zTag); if( !rid ){ fossil_redirect_home(); |
︙ | ︙ | |||
648 649 650 651 652 653 654 | blob_appendf(&wiki, "N %s\n", zMimetype); } if( rid ){ char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); blob_appendf(&wiki, "P %s\n", zUuid); free(zUuid); } | | | | 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 | blob_appendf(&wiki, "N %s\n", zMimetype); } if( rid ){ char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); blob_appendf(&wiki, "P %s\n", zUuid); free(zUuid); } if( g.zLogin ){ blob_appendf(&wiki, "U %F\n", g.zLogin); } appendRemark(&body, zMimetype); blob_appendf(&wiki, "W %d\n%s\n", blob_size(&body), blob_str(&body)); md5sum_blob(&wiki, &cksum); blob_appendf(&wiki, "Z %b\n", &cksum); blob_reset(&cksum); wiki_put(&wiki, rid); |
︙ | ︙ | |||
688 689 690 691 692 693 694 | login_insert_csrf_secret(); @ <input type="hidden" name="name" value="%h(zPageName)" /> @ <input type="hidden" name="mimetype" value="%h(zMimetype)" /> @ Your Name: @ <input type="text" name="u" size="20" value="%h(zUser)" /><br /> zFormat = mimetype_common_name(zMimetype); @ Comment to append (formatted as %s(zFormat)):<br /> | | | 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 | login_insert_csrf_secret(); @ <input type="hidden" name="name" value="%h(zPageName)" /> @ <input type="hidden" name="mimetype" value="%h(zMimetype)" /> @ Your Name: @ <input type="text" name="u" size="20" value="%h(zUser)" /><br /> zFormat = mimetype_common_name(zMimetype); @ Comment to append (formatted as %s(zFormat)):<br /> @ <textarea name="r" class="wikiedit" cols="80" @ rows="10" wrap="virtual">%h(PD("r",""))</textarea> @ <br /> @ <input type="submit" name="preview" value="Preview Your Comment" /> @ <input type="submit" name="submit" value="Append Your Changes" /> @ <input type="submit" name="cancel" value="Cancel" /> captcha_generate(0); @ </form> |
︙ | ︙ | |||
807 808 809 810 811 812 813 | ** ** - wiki page name ** - tagxref (whatever that really is!) ** ** Used by wcontent_page() and the JSON wiki code. */ void wiki_prepare_page_list( Stmt * pStmt ){ | | | 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 | ** ** - wiki page name ** - tagxref (whatever that really is!) ** ** Used by wcontent_page() and the JSON wiki code. */ void wiki_prepare_page_list( Stmt * pStmt ){ db_prepare(pStmt, "SELECT" " substr(tagname, 6) as name," " (SELECT value FROM tagxref WHERE tagid=tag.tagid ORDER BY mtime DESC) as tagXref" " FROM tag WHERE tagname GLOB 'wiki-*'" " ORDER BY lower(tagname) /*sort*/" ); } |
︙ | ︙ | |||
864 865 866 867 868 869 870 | Stmt q; const char * zTitle; login_check_credentials(); if( !g.perm.RdWiki ){ login_needed(); return; } zTitle = PD("title","*"); style_header("Wiki Pages Found"); @ <ul> | | | 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 | Stmt q; const char * zTitle; login_check_credentials(); if( !g.perm.RdWiki ){ login_needed(); return; } zTitle = PD("title","*"); style_header("Wiki Pages Found"); @ <ul> db_prepare(&q, "SELECT substr(tagname, 6, 1000) FROM tag WHERE tagname like 'wiki-%%%q%%'" " ORDER BY lower(tagname) /*sort*/" , zTitle); while( db_step(&q)==SQLITE_ROW ){ const char *zName = db_column_text(&q, 0); @ <li>%z(href("%R/wiki?name=%T",zName))%h(zName)</a></li> } |
︙ | ︙ | |||
915 916 917 918 919 920 921 | @ <li> <p><span class="wikiruleHead">Enumeration Lists</span>. @ An enumeration list item is a line that begins with a single "#" character @ surrounded on both sides by two or more spaces or by a tab. Only a single @ level of enumeration list is supported by wiki. For nested lists or for @ enumerations that count using letters or roman numerials, use HTML.</p></li> @ <li> <p><span class="wikiruleHead">Indented Paragraphs</span>. @ Any paragraph that begins with two or more spaces or a tab and | | | 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 | @ <li> <p><span class="wikiruleHead">Enumeration Lists</span>. @ An enumeration list item is a line that begins with a single "#" character @ surrounded on both sides by two or more spaces or by a tab. Only a single @ level of enumeration list is supported by wiki. For nested lists or for @ enumerations that count using letters or roman numerials, use HTML.</p></li> @ <li> <p><span class="wikiruleHead">Indented Paragraphs</span>. @ Any paragraph that begins with two or more spaces or a tab and @ which is not a bullet or enumeration list item is rendered @ indented. Only a single level of indentation is supported by wiki; use @ HTML for deeper indentation.</p></li> @ <li> <p><span class="wikiruleHead">Hyperlinks</span>. @ Text within square brackets ("[...]") becomes a hyperlink. The @ target can be a wiki page name, the artifact ID of a check-in or ticket, @ the name of an image, or a URL. By default, the target is displayed @ as the text of the hyperlink. But you can specify alternative text |
︙ | ︙ | |||
991 992 993 994 995 996 997 | blob_appendf(&wiki, "L %F\n", zPageName ); if( rid ){ zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); blob_appendf(&wiki, "P %s\n", zUuid); free(zUuid); } user_select(); | | | | 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 | blob_appendf(&wiki, "L %F\n", zPageName ); if( rid ){ zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); blob_appendf(&wiki, "P %s\n", zUuid); free(zUuid); } user_select(); if( g.zLogin ){ blob_appendf(&wiki, "U %F\n", g.zLogin); } blob_appendf( &wiki, "W %d\n%s\n", blob_size(pContent), blob_str(pContent) ); md5sum_blob(&wiki, &cksum); blob_appendf(&wiki, "Z %b\n", &cksum); blob_reset(&cksum); db_begin_transaction(); |
︙ | ︙ | |||
1060 1061 1062 1063 1064 1065 1066 | if( (g.argc!=4) && (g.argc!=5) ){ usage("export PAGENAME ?FILE?"); } zPageName = g.argv[3]; rid = db_int(0, "SELECT x.rid FROM tag t, tagxref x" " WHERE x.tagid=t.tagid AND t.tagname='wiki-%q'" " ORDER BY x.mtime DESC LIMIT 1", | | | 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 | if( (g.argc!=4) && (g.argc!=5) ){ usage("export PAGENAME ?FILE?"); } zPageName = g.argv[3]; rid = db_int(0, "SELECT x.rid FROM tag t, tagxref x" " WHERE x.tagid=t.tagid AND t.tagname='wiki-%q'" " ORDER BY x.mtime DESC LIMIT 1", zPageName ); if( (pWiki = manifest_get(rid, CFTYPE_WIKI, 0))!=0 ){ zBody = pWiki->zWiki; } if( zBody==0 ){ fossil_fatal("wiki page [%s] not found",zPageName); } |
︙ | ︙ | |||
1108 1109 1110 1111 1112 1113 1114 | if( g.argc!=5 ){ usage("delete PAGENAME"); } fossil_fatal("delete not yet implemented."); }else if( strncmp(g.argv[2],"list",n)==0 ){ Stmt q; | | | 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 | if( g.argc!=5 ){ usage("delete PAGENAME"); } fossil_fatal("delete not yet implemented."); }else if( strncmp(g.argv[2],"list",n)==0 ){ Stmt q; db_prepare(&q, "SELECT substr(tagname, 6) FROM tag WHERE tagname GLOB 'wiki-*'" " ORDER BY lower(tagname) /*sort*/" ); while( db_step(&q)==SQLITE_ROW ){ const char *zName = db_column_text(&q, 0); fossil_print( "%s\n",zName); } |
︙ | ︙ |
Changes to src/wikiformat.c.
︙ | ︙ | |||
33 34 35 36 37 38 39 | #define WIKI_LINKSONLY 0x020 /* No markup. Only decorate links */ #endif /* ** These are the only markup attributes allowed. */ | < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | < < < | | | | | | | | | | | < | | | | | | | | | | | | | | | | | | < < < < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 | #define WIKI_LINKSONLY 0x020 /* No markup. Only decorate links */ #endif /* ** These are the only markup attributes allowed. */ #define ATTR_ALIGN 1 #define ATTR_ALT 2 #define ATTR_BGCOLOR 3 #define ATTR_BORDER 4 #define ATTR_CELLPADDING 5 #define ATTR_CELLSPACING 6 #define ATTR_CLASS 7 #define ATTR_CLEAR 8 #define ATTR_COLOR 9 #define ATTR_COLSPAN 10 #define ATTR_COMPACT 11 #define ATTR_FACE 12 #define ATTR_HEIGHT 13 #define ATTR_HREF 14 #define ATTR_HSPACE 15 #define ATTR_ID 16 #define ATTR_LINKS 17 #define ATTR_NAME 18 #define ATTR_ROWSPAN 19 #define ATTR_SIZE 20 #define ATTR_SRC 21 #define ATTR_START 22 #define ATTR_STYLE 23 #define ATTR_TARGET 24 #define ATTR_TYPE 25 #define ATTR_VALIGN 26 #define ATTR_VALUE 27 #define ATTR_VSPACE 28 #define ATTR_WIDTH 29 #define AMSK_ALIGN 0x00000001 #define AMSK_ALT 0x00000002 #define AMSK_BGCOLOR 0x00000004 #define AMSK_BORDER 0x00000008 #define AMSK_CELLPADDING 0x00000010 #define AMSK_CELLSPACING 0x00000020 #define AMSK_CLASS 0x00000040 #define AMSK_CLEAR 0x00000080 #define AMSK_COLOR 0x00000100 #define AMSK_COLSPAN 0x00000200 #define AMSK_COMPACT 0x00000400 #define AMSK_FACE 0x00000800 #define AMSK_HEIGHT 0x00001000 #define AMSK_HREF 0x00002000 #define AMSK_HSPACE 0x00004000 #define AMSK_ID 0x00008000 #define AMSK_LINKS 0x00010000 #define AMSK_NAME 0x00020000 #define AMSK_ROWSPAN 0x00040000 #define AMSK_SIZE 0x00080000 #define AMSK_SRC 0x00100000 #define AMSK_START 0x00200000 #define AMSK_STYLE 0x00400000 #define AMSK_TARGET 0x00800000 #define AMSK_TYPE 0x01000000 #define AMSK_VALIGN 0x02000000 #define AMSK_VALUE 0x04000000 #define AMSK_VSPACE 0x08000000 #define AMSK_WIDTH 0x10000000 static const struct AllowedAttribute { const char *zName; unsigned int iMask; } aAttribute[] = { { 0, 0 }, { "align", AMSK_ALIGN, }, { "alt", AMSK_ALT, }, { "bgcolor", AMSK_BGCOLOR, }, { "border", AMSK_BORDER, }, { "cellpadding", AMSK_CELLPADDING, }, { "cellspacing", AMSK_CELLSPACING, }, { "class", AMSK_CLASS, }, { "clear", AMSK_CLEAR, }, { "color", AMSK_COLOR, }, { "colspan", AMSK_COLSPAN, }, { "compact", AMSK_COMPACT, }, { "face", AMSK_FACE, }, { "height", AMSK_HEIGHT, }, { "href", AMSK_HREF, }, { "hspace", AMSK_HSPACE, }, { "id", AMSK_ID, }, { "links", AMSK_LINKS, }, { "name", AMSK_NAME, }, { "rowspan", AMSK_ROWSPAN, }, { "size", AMSK_SIZE, }, { "src", AMSK_SRC, }, { "start", AMSK_START, }, { "style", AMSK_STYLE, }, { "target", AMSK_TARGET, }, { "type", AMSK_TYPE, }, { "valign", AMSK_VALIGN, }, { "value", AMSK_VALUE, }, { "vspace", AMSK_VSPACE, }, { "width", AMSK_WIDTH, }, }; /* ** Use binary search to locate a tag in the aAttribute[] table. */ static int findAttr(const char *z){ int i, c, first, last; |
︙ | ︙ | |||
171 172 173 174 175 176 177 | ** and in numerical sequence. The first markup type must be zero. ** The value for MARKUP_XYZ must correspond to the <xyz> entry ** in aAllowedMarkup[]. */ #define MARKUP_INVALID 0 #define MARKUP_A 1 #define MARKUP_ADDRESS 2 | < < | | | | | | | | | | | | | | | | < | | | | | | < | | | | | < | | | | | | | < | | | | | | | | | | | | < | | | | | | | 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 | ** and in numerical sequence. The first markup type must be zero. ** The value for MARKUP_XYZ must correspond to the <xyz> entry ** in aAllowedMarkup[]. */ #define MARKUP_INVALID 0 #define MARKUP_A 1 #define MARKUP_ADDRESS 2 #define MARKUP_B 3 #define MARKUP_BIG 4 #define MARKUP_BLOCKQUOTE 5 #define MARKUP_BR 6 #define MARKUP_CENTER 7 #define MARKUP_CITE 8 #define MARKUP_CODE 9 #define MARKUP_COL 10 #define MARKUP_COLGROUP 11 #define MARKUP_DD 12 #define MARKUP_DFN 13 #define MARKUP_DIV 14 #define MARKUP_DL 15 #define MARKUP_DT 16 #define MARKUP_EM 17 #define MARKUP_FONT 18 #define MARKUP_H1 19 #define MARKUP_H2 20 #define MARKUP_H3 21 #define MARKUP_H4 22 #define MARKUP_H5 23 #define MARKUP_H6 24 #define MARKUP_HR 25 #define MARKUP_I 26 #define MARKUP_IMG 27 #define MARKUP_KBD 28 #define MARKUP_LI 29 #define MARKUP_NOBR 30 #define MARKUP_NOWIKI 31 #define MARKUP_OL 32 #define MARKUP_P 33 #define MARKUP_PRE 34 #define MARKUP_S 35 #define MARKUP_SAMP 36 #define MARKUP_SMALL 37 #define MARKUP_SPAN 38 #define MARKUP_STRIKE 39 #define MARKUP_STRONG 40 #define MARKUP_SUB 41 #define MARKUP_SUP 42 #define MARKUP_TABLE 43 #define MARKUP_TBODY 44 #define MARKUP_TD 45 #define MARKUP_TFOOT 46 #define MARKUP_TH 47 #define MARKUP_THEAD 48 #define MARKUP_TR 49 #define MARKUP_TT 50 #define MARKUP_U 51 #define MARKUP_UL 52 #define MARKUP_VAR 53 #define MARKUP_VERBATIM 54 /* ** The various markup is divided into the following types: */ #define MUTYPE_SINGLE 0x0001 /* <img>, <br>, or <hr> */ #define MUTYPE_BLOCK 0x0002 /* Forms a new paragraph. ex: <p>, <h2> */ #define MUTYPE_FONT 0x0004 /* Font changes. ex: <b>, <font>, <sub> */ |
︙ | ︙ | |||
265 266 267 268 269 270 271 | short int iType; /* The MUTYPE_* code */ int allowedAttr; /* Allowed attributes on this markup */ } aMarkup[] = { { 0, MARKUP_INVALID, 0, 0 }, { "a", MARKUP_A, MUTYPE_HYPERLINK, AMSK_HREF|AMSK_NAME|AMSK_CLASS|AMSK_TARGET|AMSK_STYLE }, { "address", MARKUP_ADDRESS, MUTYPE_BLOCK, AMSK_STYLE }, | < < < < < | 249 250 251 252 253 254 255 256 257 258 259 260 261 262 | short int iType; /* The MUTYPE_* code */ int allowedAttr; /* Allowed attributes on this markup */ } aMarkup[] = { { 0, MARKUP_INVALID, 0, 0 }, { "a", MARKUP_A, MUTYPE_HYPERLINK, AMSK_HREF|AMSK_NAME|AMSK_CLASS|AMSK_TARGET|AMSK_STYLE }, { "address", MARKUP_ADDRESS, MUTYPE_BLOCK, AMSK_STYLE }, { "b", MARKUP_B, MUTYPE_FONT, AMSK_STYLE }, { "big", MARKUP_BIG, MUTYPE_FONT, AMSK_STYLE }, { "blockquote", MARKUP_BLOCKQUOTE, MUTYPE_BLOCK, AMSK_STYLE }, { "br", MARKUP_BR, MUTYPE_SINGLE, AMSK_CLEAR }, { "center", MARKUP_CENTER, MUTYPE_BLOCK, AMSK_STYLE }, { "cite", MARKUP_CITE, MUTYPE_FONT, AMSK_STYLE }, { "code", MARKUP_CODE, MUTYPE_FONT, AMSK_STYLE }, |
︙ | ︙ | |||
291 292 293 294 295 296 297 | AMSK_ID|AMSK_CLASS|AMSK_STYLE }, { "dl", MARKUP_DL, MUTYPE_LIST, AMSK_COMPACT|AMSK_STYLE }, { "dt", MARKUP_DT, MUTYPE_LI, AMSK_STYLE }, { "em", MARKUP_EM, MUTYPE_FONT, AMSK_STYLE }, { "font", MARKUP_FONT, MUTYPE_FONT, AMSK_COLOR|AMSK_FACE|AMSK_SIZE|AMSK_STYLE }, | < < < < < < < < < < < | 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 | AMSK_ID|AMSK_CLASS|AMSK_STYLE }, { "dl", MARKUP_DL, MUTYPE_LIST, AMSK_COMPACT|AMSK_STYLE }, { "dt", MARKUP_DT, MUTYPE_LI, AMSK_STYLE }, { "em", MARKUP_EM, MUTYPE_FONT, AMSK_STYLE }, { "font", MARKUP_FONT, MUTYPE_FONT, AMSK_COLOR|AMSK_FACE|AMSK_SIZE|AMSK_STYLE }, { "h1", MARKUP_H1, MUTYPE_BLOCK, AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE }, { "h2", MARKUP_H2, MUTYPE_BLOCK, AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE }, { "h3", MARKUP_H3, MUTYPE_BLOCK, AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE }, { "h4", MARKUP_H4, MUTYPE_BLOCK, AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE }, { "h5", MARKUP_H5, MUTYPE_BLOCK, AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE }, { "h6", MARKUP_H6, MUTYPE_BLOCK, AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE }, { "hr", MARKUP_HR, MUTYPE_SINGLE, AMSK_ALIGN|AMSK_COLOR|AMSK_SIZE|AMSK_WIDTH| AMSK_STYLE|AMSK_CLASS }, { "i", MARKUP_I, MUTYPE_FONT, AMSK_STYLE }, { "img", MARKUP_IMG, MUTYPE_SINGLE, AMSK_ALIGN|AMSK_ALT|AMSK_BORDER|AMSK_HEIGHT| AMSK_HSPACE|AMSK_SRC|AMSK_VSPACE|AMSK_WIDTH|AMSK_STYLE }, { "kbd", MARKUP_KBD, MUTYPE_FONT, AMSK_STYLE }, { "li", MARKUP_LI, MUTYPE_LI, AMSK_TYPE|AMSK_VALUE|AMSK_STYLE }, { "nobr", MARKUP_NOBR, MUTYPE_FONT, 0 }, { "nowiki", MARKUP_NOWIKI, MUTYPE_SPECIAL, 0 }, { "ol", MARKUP_OL, MUTYPE_LIST, AMSK_START|AMSK_TYPE|AMSK_COMPACT|AMSK_STYLE }, { "p", MARKUP_P, MUTYPE_BLOCK, AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE }, { "pre", MARKUP_PRE, MUTYPE_BLOCK, AMSK_STYLE }, { "s", MARKUP_S, MUTYPE_FONT, AMSK_STYLE }, { "samp", MARKUP_SAMP, MUTYPE_FONT, AMSK_STYLE }, { "small", MARKUP_SMALL, MUTYPE_FONT, AMSK_STYLE }, { "span", MARKUP_SPAN, MUTYPE_BLOCK, AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE }, { "strike", MARKUP_STRIKE, MUTYPE_FONT, AMSK_STYLE }, { "strong", MARKUP_STRONG, MUTYPE_FONT, AMSK_STYLE }, { "sub", MARKUP_SUB, MUTYPE_FONT, AMSK_STYLE }, { "sup", MARKUP_SUP, MUTYPE_FONT, AMSK_STYLE }, |
︙ | ︙ | |||
356 357 358 359 360 361 362 | { "tfoot", MARKUP_TFOOT, MUTYPE_BLOCK, AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE }, { "th", MARKUP_TH, MUTYPE_TD, AMSK_ALIGN|AMSK_BGCOLOR|AMSK_COLSPAN| AMSK_ROWSPAN|AMSK_VALIGN|AMSK_CLASS|AMSK_STYLE }, { "thead", MARKUP_THEAD, MUTYPE_BLOCK, AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE }, | < > | 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 | { "tfoot", MARKUP_TFOOT, MUTYPE_BLOCK, AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE }, { "th", MARKUP_TH, MUTYPE_TD, AMSK_ALIGN|AMSK_BGCOLOR|AMSK_COLSPAN| AMSK_ROWSPAN|AMSK_VALIGN|AMSK_CLASS|AMSK_STYLE }, { "thead", MARKUP_THEAD, MUTYPE_BLOCK, AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE }, { "tr", MARKUP_TR, MUTYPE_TR, AMSK_ALIGN|AMSK_BGCOLOR|AMSK_VALIGN|AMSK_CLASS|AMSK_STYLE }, { "tt", MARKUP_TT, MUTYPE_FONT, AMSK_STYLE }, { "u", MARKUP_U, MUTYPE_FONT, AMSK_STYLE }, { "ul", MARKUP_UL, MUTYPE_LIST, AMSK_TYPE|AMSK_COMPACT|AMSK_STYLE }, { "var", MARKUP_VAR, MUTYPE_FONT, AMSK_STYLE }, { "verbatim", MARKUP_VERBATIM, MUTYPE_SPECIAL, AMSK_ID|AMSK_TYPE }, }; void show_allowed_wiki_markup( void ){ int i; /* loop over allowedAttr */ for( i=1 ; i<=sizeof(aMarkup)/sizeof(aMarkup[0]) - 1 ; i++ ){ @ <%s(aMarkup[i].zName)> } } /* ** Use binary search to locate a tag in the aMarkup[] table. |
︙ | ︙ | |||
796 797 798 799 800 801 802 | p->aAttr[0].cTerm = c = z[i]; z[i++] = 0; p->nAttr = 1; if( c=='>' ) return; } while( fossil_isspace(z[i]) ){ i++; } while( c!='>' && p->nAttr<8 && fossil_isalpha(z[i]) ){ | | | 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 | p->aAttr[0].cTerm = c = z[i]; z[i++] = 0; p->nAttr = 1; if( c=='>' ) return; } while( fossil_isspace(z[i]) ){ i++; } while( c!='>' && p->nAttr<8 && fossil_isalpha(z[i]) ){ int attrOk; /* True to preserver attribute. False to ignore it */ j = 0; while( fossil_isalnum(z[i]) ){ if( j<sizeof(zTag)-1 ) zTag[j++] = fossil_tolower(z[i]); i++; } zTag[j] = 0; p->aAttr[p->nAttr].iACode = iACode = findAttr(zTag); |
︙ | ︙ | |||
878 879 880 881 882 883 884 | ** original content. */ static void unparseMarkup(ParsedMarkup *p){ int i, n; for(i=0; i<p->nAttr; i++){ char *z = p->aAttr[i].zValue; if( z==0 ) continue; | < | | < | 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 | ** original content. */ static void unparseMarkup(ParsedMarkup *p){ int i, n; for(i=0; i<p->nAttr; i++){ char *z = p->aAttr[i].zValue; if( z==0 ) continue; n = strlen(z); z[n] = p->aAttr[i].cTerm; } } /* ** Return the value of attribute attrId. Return NULL if there is no ** ID attribute. */ |
︙ | ︙ | |||
1480 1481 1482 1483 1484 1485 1486 | break; } case TOKEN_MARKUP: { const char *zId; int iDiv; parseMarkup(&markup, z); | < < < < < < < < < | 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 | break; } case TOKEN_MARKUP: { const char *zId; int iDiv; parseMarkup(&markup, z); /* Markup of the form </div id=ID> where there is a matching ** ID somewhere on the stack. Exit any contained verbatim. ** Pop the stack up to the matching <div>. Discard the </div> */ if( markup.iCode==MARKUP_DIV && markup.endTag && (zId = markupId(&markup))!=0 && (iDiv = findTagWithId(p, MARKUP_DIV, zId))>=0 |
︙ | ︙ | |||
1759 1760 1761 1762 1763 1764 1765 | int iStart; blob_to_utf8_no_bom(pIn, 0); z = blob_str(pIn); for(i=0; fossil_isspace(z[i]); i++){} if( z[i]!='<' ) return 0; i++; if( strncmp(&z[i],"title>", 6)!=0 ) return 0; | | < < < | < < | < < < | 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 | int iStart; blob_to_utf8_no_bom(pIn, 0); z = blob_str(pIn); for(i=0; fossil_isspace(z[i]); i++){} if( z[i]!='<' ) return 0; i++; if( strncmp(&z[i],"title>", 6)!=0 ) return 0; iStart = i+6; for(i=iStart; z[i] && (z[i]!='<' || strncmp(&z[i],"</title>",8)!=0); i++){} if( z[i]!='<' ) return 0; blob_init(pTitle, &z[iStart], i-iStart); blob_init(pTail, &z[i+8], -1); return 1; } /* ** Parse text looking for wiki hyperlinks in one of the formats: ** |
︙ | ︙ |
Changes to src/winhttp.c.
︙ | ︙ | |||
65 66 67 68 69 70 71 | */ static void win32_http_request(void *pAppData){ HttpRequest *p = (HttpRequest*)pAppData; FILE *in = 0, *out = 0; int amt, got; int wanted = 0; char *z; | < < < | 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | */ static void win32_http_request(void *pAppData){ HttpRequest *p = (HttpRequest*)pAppData; FILE *in = 0, *out = 0; int amt, got; int wanted = 0; char *z; char zRequestFName[MAX_PATH]; char zReplyFName[MAX_PATH]; char zCmd[2000]; /* Command-line to process the request */ char zHdr[2000]; /* The HTTP request header */ sqlite3_snprintf(MAX_PATH, zRequestFName, "%s_in%d.txt", zTempPrefix, p->id); sqlite3_snprintf(MAX_PATH, zReplyFName, "%s_out%d.txt", zTempPrefix, p->id); amt = 0; while( amt<sizeof(zHdr) ){ got = recv(p->s, &zHdr[amt], sizeof(zHdr)-1-amt, 0); |
︙ | ︙ | |||
109 110 111 112 113 114 115 | }else{ break; } wanted -= got; } fclose(out); out = 0; | | | | < < < < < < < < < | 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 | }else{ break; } wanted -= got; } fclose(out); out = 0; sqlite3_snprintf(sizeof(zCmd), zCmd, "\"%s\" http \"%s\" %s %s %s --nossl%s", g.nameOfExe, g.zRepositoryName, zRequestFName, zReplyFName, inet_ntoa(p->addr.sin_addr), p->zOptions ); fossil_system(zCmd); in = fossil_fopen(zReplyFName, "rb"); if( in ){ while( (got = fread(zHdr, 1, sizeof(zHdr), in))>0 ){ send(p->s, zHdr, got, 0); } } end_request: if( out ) fclose(out); if( in ) fclose(in); closesocket(p->s); file_delete(zRequestFName); file_delete(zReplyFName); free(p); } /* ** Process a single incoming SCGI request. */ static void win32_scgi_request(void *pAppData){ |
︙ | ︙ |
Changes to src/wysiwyg.c.
︙ | ︙ | |||
226 227 228 229 230 231 232 | @ </div> @ <div id="wysiwygBox" @ style="resize:both; overflow:auto; width: %d(w)em; height: %d(h)em;" @ contenteditable="true">%s(zContent)</div> @ <script> @ var oDoc; | | | | | | | | | 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 | @ </div> @ <div id="wysiwygBox" @ style="resize:both; overflow:auto; width: %d(w)em; height: %d(h)em;" @ contenteditable="true">%s(zContent)</div> @ <script> @ var oDoc; @ @ /* Initialize the document editor */ @ function initDoc() { @ oDoc = document.getElementById("wysiwygBox"); @ if (!isWysiwyg()) { setDocMode(true); } @ } @ @ /* Return true if the document editor is in WYSIWYG mode. Return @ ** false if it is in Markup mode */ @ function isWysiwyg() { @ return document.getElementById("editMode").selectedIndex==0; @ } @ @ /* Invoke this routine prior to submitting the HTML content back @ ** to the server */ @ function wysiwygSubmit() { @ if(oDoc.style.whiteSpace=="pre-wrap"){setDocMode(0);} @ document.getElementById("wysiwygValue").value=oDoc.innerHTML; @ } @ @ /* Run the editing command if in WYSIWYG mode */ @ function formatDoc(sCmd, sValue) { @ if (isWysiwyg()){ @ document.execCommand("styleWithCSS", false, false); @ document.execCommand(sCmd, false, sValue); @ oDoc.focus(); @ } @ } @ @ /* Change the editing mode. Convert to markup if the argument @ ** is true and wysiwyg if the argument is false. */ @ function setDocMode(bToMarkup) { @ var oContent; @ if (bToMarkup) { @ /* WYSIWYG -> Markup */ @ var linebreak = new RegExp("</p><p>","ig"); @ oContent = document.createTextNode( @ oDoc.innerHTML.replace(linebreak,"</p>\n\n<p>")); |
︙ | ︙ |
Changes to src/xfer.c.
︙ | ︙ | |||
92 93 94 95 96 97 98 | db_bind_int(&q, ":r", rid); db_step(&q); db_reset(&q); } } /* | | | 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 | db_bind_int(&q, ":r", rid); db_step(&q); db_reset(&q); } } /* ** The aToken[0..nToken-1] blob array is a parse of a "file" line ** message. This routine finishes parsing that message and does ** a record insert of the file. ** ** The file line is in one of the following two forms: ** ** file UUID SIZE \n CONTENT ** file UUID DELTASRC SIZE \n CONTENT |
︙ | ︙ | |||
117 118 119 120 121 122 123 | */ static void xfer_accept_file(Xfer *pXfer, int cloneFlag){ int n; int rid; int srcid = 0; Blob content, hash; int isPriv; | | | | 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | */ static void xfer_accept_file(Xfer *pXfer, int cloneFlag){ int n; int rid; int srcid = 0; Blob content, hash; int isPriv; isPriv = pXfer->nextIsPrivate; pXfer->nextIsPrivate = 0; if( pXfer->nToken<3 || pXfer->nToken>4 || !blob_is_uuid(&pXfer->aToken[1]) || !blob_is_int(&pXfer->aToken[pXfer->nToken-1], &n) || n<0 || (pXfer->nToken==4 && !blob_is_uuid(&pXfer->aToken[2])) ){ blob_appendf(&pXfer->err, "malformed file line"); |
︙ | ︙ | |||
196 197 198 199 200 201 202 | manifest_crosslink(rid, &content, MC_NONE); } assert( blob_is_reset(&content) ); remote_has(rid); } /* | | | 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 | manifest_crosslink(rid, &content, MC_NONE); } assert( blob_is_reset(&content) ); remote_has(rid); } /* ** The aToken[0..nToken-1] blob array is a parse of a "cfile" line ** message. This routine finishes parsing that message and does ** a record insert of the file. The difference between "file" and ** "cfile" is that with "cfile" the content is already compressed. ** ** The file line is in one of the following two forms: ** ** cfile UUID USIZE CSIZE \n CONTENT |
︙ | ︙ | |||
225 226 227 228 229 230 231 | static void xfer_accept_compressed_file(Xfer *pXfer){ int szC; /* CSIZE */ int szU; /* USIZE */ int rid; int srcid = 0; Blob content; int isPriv; | | | | 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 | static void xfer_accept_compressed_file(Xfer *pXfer){ int szC; /* CSIZE */ int szU; /* USIZE */ int rid; int srcid = 0; Blob content; int isPriv; isPriv = pXfer->nextIsPrivate; pXfer->nextIsPrivate = 0; if( pXfer->nToken<4 || pXfer->nToken>5 || !blob_is_uuid(&pXfer->aToken[1]) || !blob_is_int(&pXfer->aToken[pXfer->nToken-2], &szU) || !blob_is_int(&pXfer->aToken[pXfer->nToken-1], &szC) || szC<0 || szU<0 || (pXfer->nToken==5 && !blob_is_uuid(&pXfer->aToken[2])) ){ |
︙ | ︙ | |||
282 283 284 285 286 287 288 | Blob *pContent, /* The content of the file to send */ Blob *pUuid /* The UUID of the file to send */ ){ static const char *const azQuery[] = { "SELECT pid FROM plink x" " WHERE cid=%d" " AND NOT EXISTS(SELECT 1 FROM phantom WHERE rid=pid)", | | | 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 | Blob *pContent, /* The content of the file to send */ Blob *pUuid /* The UUID of the file to send */ ){ static const char *const azQuery[] = { "SELECT pid FROM plink x" " WHERE cid=%d" " AND NOT EXISTS(SELECT 1 FROM phantom WHERE rid=pid)", "SELECT pid, min(mtime) FROM mlink, event ON mlink.mid=event.objid" " WHERE fid=%d" " AND NOT EXISTS(SELECT 1 FROM phantom WHERE rid=pid)" }; int i; Blob src, delta; int size = 0; |
︙ | ︙ | |||
319 320 321 322 323 324 325 | free(zUuid); blob_reset(&src); } return size; } /* | | | 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 | free(zUuid); blob_reset(&src); } return size; } /* ** Try to send a file as a native delta. ** If successful, return the number of bytes in the delta. ** If we cannot generate an appropriate delta, then send ** nothing and return zero. ** ** Never send a delta against a private artifact. */ static int send_delta_native( |
︙ | ︙ | |||
401 402 403 404 405 406 407 | }else{ pUuid = &uuid; } if( uuid_is_shunned(blob_str(pUuid)) ){ blob_reset(&uuid); return; } | | | 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 | }else{ pUuid = &uuid; } if( uuid_is_shunned(blob_str(pUuid)) ){ blob_reset(&uuid); return; } if( (pXfer->maxTime != -1 && time(NULL) >= pXfer->maxTime) || pXfer->mxSend<=blob_size(pXfer->pOut) ){ const char *zFormat = isPriv ? "igot %b 1\n" : "igot %b\n"; blob_appendf(pXfer->pOut, zFormat, pUuid); pXfer->nIGotSent++; blob_reset(&uuid); return; } |
︙ | ︙ | |||
443 444 445 446 447 448 449 | blob_appendf(pXfer->pOut, "\n", 1); } #endif } /* ** Send the file identified by rid as a compressed artifact. Basically, | | | 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 | blob_appendf(pXfer->pOut, "\n", 1); } #endif } /* ** Send the file identified by rid as a compressed artifact. Basically, ** send the content exactly as it appears in the BLOB table using ** a "cfile" card. */ static void send_compressed_file(Xfer *pXfer, int rid){ const char *zContent; const char *zUuid; const char *zDelta; int szU; |
︙ | ︙ | |||
513 514 515 516 517 518 519 | ** Send a gimme message for every phantom. ** ** Except: do not request shunned artifacts. And do not request ** private artifacts if we are not doing a private transfer. */ static void request_phantoms(Xfer *pXfer, int maxReq){ Stmt q; | | | 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 | ** Send a gimme message for every phantom. ** ** Except: do not request shunned artifacts. And do not request ** private artifacts if we are not doing a private transfer. */ static void request_phantoms(Xfer *pXfer, int maxReq){ Stmt q; db_prepare(&q, "SELECT uuid FROM phantom JOIN blob USING(rid)" " WHERE NOT EXISTS(SELECT 1 FROM shun WHERE uuid=blob.uuid) %s", (pXfer->syncPrivate ? "" : " AND NOT EXISTS(SELECT 1 FROM private WHERE rid=blob.rid)") ); while( db_step(&q)==SQLITE_ROW && maxReq-- > 0 ){ const char *zUuid = db_column_text(&q, 0); |
︙ | ︙ | |||
549 550 551 552 553 554 555 | /* ** Check the signature on an application/x-fossil payload received by ** the HTTP server. The signature is a line of the following form: ** ** login LOGIN NONCE SIGNATURE ** | | | | | < | 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 | /* ** Check the signature on an application/x-fossil payload received by ** the HTTP server. The signature is a line of the following form: ** ** login LOGIN NONCE SIGNATURE ** ** The NONCE is the SHA1 hash of the remainder of the input. ** SIGNATURE is the SHA1 checksum of the NONCE concatenated ** with the users password. ** ** The parameters to this routine are ephemeral blobs holding the ** LOGIN, NONCE and SIGNATURE. ** ** This routine attempts to locate the user and verify the signature. ** If everything checks out, the USER.CAP column for the USER table ** is consulted to set privileges in the global g variable. ** ** If anything fails to check out, no changes are made to privileges. ** ** Signature generation on the client side is handled by the ** http_exchange() routine. ** ** Return non-zero for a login failure and zero for success. */ int check_login(Blob *pLogin, Blob *pNonce, Blob *pSig){ Stmt q; int rc = -1; char *zLogin = blob_terminate(pLogin); defossilize(zLogin); if( fossil_strcmp(zLogin, "nobody")==0 || fossil_strcmp(zLogin,"anonymous")==0 ){ return 0; /* Anybody is allowed to sync as "nobody" or "anonymous" */ } if( fossil_strcmp(P("REMOTE_USER"), zLogin)==0 ){ return 0; /* Accept Basic Authorization */ } db_prepare(&q, "SELECT pw, cap, uid FROM user" " WHERE login=%Q" " AND login NOT IN ('anonymous','nobody','developer','reader')" " AND length(pw)>0", |
︙ | ︙ | |||
698 699 700 701 702 703 704 | nUncl -= nRow; nRow = 0; blob_appendf(&deleteWhere, ",%d", rid); } } db_finalize(&q); db_multi_exec( | | | 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 | nUncl -= nRow; nRow = 0; blob_appendf(&deleteWhere, ",%d", rid); } } db_finalize(&q); db_multi_exec( "DELETE FROM unclustered WHERE rid NOT IN (0 %s)", blob_str(&deleteWhere) ); blob_reset(&deleteWhere); if( nRow>0 ){ md5sum_blob(&cluster, &cksum); blob_appendf(&cluster, "Z %b\n", &cksum); blob_reset(&cksum); |
︙ | ︙ | |||
737 738 739 740 741 742 743 | ** Send an igot message for every entry in unclustered table. ** Return the number of cards sent. */ static int send_unclustered(Xfer *pXfer){ Stmt q; int cnt = 0; if( pXfer->resync ){ | | | | 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 | ** Send an igot message for every entry in unclustered table. ** Return the number of cards sent. */ static int send_unclustered(Xfer *pXfer){ Stmt q; int cnt = 0; if( pXfer->resync ){ db_prepare(&q, "SELECT uuid, rid FROM blob" " WHERE NOT EXISTS(SELECT 1 FROM shun WHERE uuid=blob.uuid)" " AND NOT EXISTS(SELECT 1 FROM phantom WHERE rid=blob.rid)" " AND NOT EXISTS(SELECT 1 FROM private WHERE rid=blob.rid)" " AND blob.rid<=%d" " ORDER BY blob.rid DESC", pXfer->resync ); }else{ db_prepare(&q, "SELECT uuid FROM unclustered JOIN blob USING(rid)" " WHERE NOT EXISTS(SELECT 1 FROM shun WHERE uuid=blob.uuid)" " AND NOT EXISTS(SELECT 1 FROM phantom WHERE rid=blob.rid)" " AND NOT EXISTS(SELECT 1 FROM private WHERE rid=blob.rid)" ); } while( db_step(&q)==SQLITE_ROW ){ |
︙ | ︙ | |||
771 772 773 774 775 776 777 | } /* ** Send an igot message for every artifact. */ static void send_all(Xfer *pXfer){ Stmt q; | | | 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 | } /* ** Send an igot message for every artifact. */ static void send_all(Xfer *pXfer){ Stmt q; db_prepare(&q, "SELECT uuid FROM blob " " WHERE NOT EXISTS(SELECT 1 FROM shun WHERE uuid=blob.uuid)" " AND NOT EXISTS(SELECT 1 FROM private WHERE rid=blob.rid)" " AND NOT EXISTS(SELECT 1 FROM phantom WHERE rid=blob.rid)" ); while( db_step(&q)==SQLITE_ROW ){ blob_appendf(pXfer->pOut, "igot %s\n", db_column_text(&q, 0)); |
︙ | ︙ | |||
1032 1033 1034 1035 1036 1037 1038 | }else if( g.perm.Private ){ rid_from_uuid(&xfer.aToken[1], 1, 1); }else{ server_private_xfer_not_authorized(); } } }else | | | | 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 | }else if( g.perm.Private ){ rid_from_uuid(&xfer.aToken[1], 1, 1); }else{ server_private_xfer_not_authorized(); } } }else /* pull SERVERCODE PROJECTCODE ** push SERVERCODE PROJECTCODE ** ** The client wants either send or receive. The server should ** verify that the project code matches. */ if( xfer.nToken==3 |
︙ | ︙ | |||
1141 1142 1143 1144 1145 1146 1147 | if( check_tail_hash(&xfer.aToken[2], xfer.pIn) || check_login(&xfer.aToken[1], &xfer.aToken[2], &xfer.aToken[3]) ){ cgi_reset_content(); @ error login\sfailed nErr++; break; | | | | 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 | if( check_tail_hash(&xfer.aToken[2], xfer.pIn) || check_login(&xfer.aToken[1], &xfer.aToken[2], &xfer.aToken[3]) ){ cgi_reset_content(); @ error login\sfailed nErr++; break; } } }else /* reqconfig NAME ** ** Request a configuration value */ if( blob_eq(&xfer.aToken[0], "reqconfig") && xfer.nToken==2 ){ |
︙ | ︙ | |||
1166 1167 1168 1169 1170 1171 1172 | configure_send_group(xfer.pOut, groupMask, 0); }else if( configure_is_exportable(zName) ){ /* Old style configuration transfer */ send_legacy_config_card(&xfer, zName); } } }else | | | 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 | configure_send_group(xfer.pOut, groupMask, 0); }else if( configure_is_exportable(zName) ){ /* Old style configuration transfer */ send_legacy_config_card(&xfer, zName); } } }else /* config NAME SIZE \n CONTENT ** ** Receive a configuration value from the client. This is only ** permitted for high-privilege users. */ if( blob_eq(&xfer.aToken[0],"config") && xfer.nToken==3 && blob_is_int(&xfer.aToken[2], &size) ){ |
︙ | ︙ | |||
1193 1194 1195 1196 1197 1198 1199 | recvConfig = 1; } configure_receive(zName, &content, CONFIGSET_ALL); blob_reset(&content); blob_seek(xfer.pIn, 1, BLOB_SEEK_CUR); }else | | | 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 | recvConfig = 1; } configure_receive(zName, &content, CONFIGSET_ALL); blob_reset(&content); blob_seek(xfer.pIn, 1, BLOB_SEEK_CUR); }else /* cookie TEXT ** ** A cookie contains a arbitrary-length argument that is server-defined. ** The argument must be encoded so as not to contain any whitespace. ** The server can optionally send a cookie to the client. The client ** might then return the same cookie back to the server on its next |
︙ | ︙ | |||
1373 1374 1375 1376 1377 1378 1379 | ** Floating-point absolute value */ static double fossil_fabs(double x){ return x>0.0 ? x : -x; } /* | | | 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 | ** Floating-point absolute value */ static double fossil_fabs(double x){ return x>0.0 ? x : -x; } /* ** Sync to the host identified in g.urlName and g.urlPath. This ** routine is called by the client. ** ** Records are pushed to the server if pushFlag is true. Records ** are pulled if pullFlag is true. A full sync occurs if both are ** true. */ int client_sync( |
︙ | ︙ | |||
1412 1413 1414 1415 1416 1417 1418 | int nRoundtrip= 0; /* Number of HTTP requests */ int nArtifactSent = 0; /* Total artifacts sent */ int nArtifactRcvd = 0; /* Total artifacts received */ const char *zOpType = 0;/* Push, Pull, Sync, Clone */ double rSkew = 0.0; /* Maximum time skew */ if( db_get_boolean("dont-push", 0) ) syncFlags &= ~SYNC_PUSH; | | | 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 | int nRoundtrip= 0; /* Number of HTTP requests */ int nArtifactSent = 0; /* Total artifacts sent */ int nArtifactRcvd = 0; /* Total artifacts received */ const char *zOpType = 0;/* Push, Pull, Sync, Clone */ double rSkew = 0.0; /* Maximum time skew */ if( db_get_boolean("dont-push", 0) ) syncFlags &= ~SYNC_PUSH; if( (syncFlags & (SYNC_PUSH|SYNC_PULL|SYNC_CLONE))==0 && configRcvMask==0 && configSendMask==0 ) return 0; transport_stats(0, 0, 1); socket_global_init(); memset(&xfer, 0, sizeof(xfer)); xfer.pIn = &recv; xfer.pOut = &send; |
︙ | ︙ | |||
1486 1487 1488 1489 1490 1491 1492 | /* Send make the most recently received cookie. Let the server ** figure out if this is a cookie that it cares about. */ zCookie = db_get("cookie", 0); if( zCookie ){ blob_appendf(&send, "cookie %s\n", zCookie); } | | | | 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 | /* Send make the most recently received cookie. Let the server ** figure out if this is a cookie that it cares about. */ zCookie = db_get("cookie", 0); if( zCookie ){ blob_appendf(&send, "cookie %s\n", zCookie); } /* Generate gimme cards for phantoms and leaf cards ** for all leaves. */ if( (syncFlags & SYNC_PULL)!=0 || ((syncFlags & SYNC_CLONE)!=0 && cloneSeqno==1) ){ request_phantoms(&xfer, mxPhantomReq); } if( syncFlags & SYNC_PUSH ){ send_unsent(&xfer); nCardSent += send_unclustered(&xfer); if( syncFlags & SYNC_PRIVATE ) send_private(&xfer); } /* Send configuration parameter requests. On a clone, delay sending ** this until the second cycle since the login card might fail on ** the first cycle. */ if( configRcvMask && ((syncFlags & SYNC_CLONE)==0 || nCycle>0) ){ const char *zName; if( zOpType==0 ) zOpType = "Pull"; zName = configure_first_name(configRcvMask); while( zName ){ |
︙ | ︙ | |||
1662 1663 1664 1665 1666 1667 1668 | && blob_is_uuid(&xfer.aToken[1]) ){ if( syncFlags & SYNC_PUSH ){ int rid = rid_from_uuid(&xfer.aToken[1], 0, 0); if( rid ) send_file(&xfer, rid, &xfer.aToken[1], 0); } }else | | | | | | 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 | && blob_is_uuid(&xfer.aToken[1]) ){ if( syncFlags & SYNC_PUSH ){ int rid = rid_from_uuid(&xfer.aToken[1], 0, 0); if( rid ) send_file(&xfer, rid, &xfer.aToken[1], 0); } }else /* igot UUID ?PRIVATEFLAG? ** ** Server announces that it has a particular file. If this is ** not a file that we have and we are pulling, then create a ** phantom to cause this file to be requested on the next cycle. ** Always remember that the server has this file so that we do ** not transmit it by accident. ** ** If the PRIVATE argument exists and is 1, then the file is ** private. Pretend it does not exists if we are not pulling ** private files. */ if( xfer.nToken>=2 && blob_eq(&xfer.aToken[0], "igot") && blob_is_uuid(&xfer.aToken[1]) ){ int rid; int isPriv = xfer.nToken>=3 && blob_eq(&xfer.aToken[2],"1"); rid = rid_from_uuid(&xfer.aToken[1], 0, 0); if( rid>0 ){ if( !isPriv ) content_make_public(rid); }else if( isPriv && !g.perm.Private ){ /* ignore private files */ }else if( (syncFlags & (SYNC_PULL|SYNC_CLONE))!=0 ){ rid = content_new(blob_str(&xfer.aToken[1]), isPriv); if( rid ) newPhantom = 1; } remote_has(rid); }else /* push SERVERCODE PRODUCTCODE ** ** Should only happen in response to a clone. This message tells ** the client what product to use for the new database. */ if( blob_eq(&xfer.aToken[0],"push") && xfer.nToken==3 |
︙ | ︙ | |||
1715 1716 1717 1718 1719 1720 1721 | if( zPCode==0 ){ zPCode = mprintf("%b", &xfer.aToken[2]); db_set("project-code", zPCode, 0); } if( cloneSeqno>0 ) blob_appendf(&send, "clone 3 %d\n", cloneSeqno); nCardSent++; }else | | | 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 | if( zPCode==0 ){ zPCode = mprintf("%b", &xfer.aToken[2]); db_set("project-code", zPCode, 0); } if( cloneSeqno>0 ) blob_appendf(&send, "clone 3 %d\n", cloneSeqno); nCardSent++; }else /* config NAME SIZE \n CONTENT ** ** Receive a configuration value from the server. ** ** The received configuration setting is silently ignored if it was ** not requested by a prior "reqconfig" sent from client to server. */ |
︙ | ︙ | |||
1737 1738 1739 1740 1741 1742 1743 | configure_receive(zName, &content, origConfigRcvMask); nCardRcvd++; nArtifactRcvd++; blob_reset(&content); blob_seek(xfer.pIn, 1, BLOB_SEEK_CUR); }else | | | 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 | configure_receive(zName, &content, origConfigRcvMask); nCardRcvd++; nArtifactRcvd++; blob_reset(&content); blob_seek(xfer.pIn, 1, BLOB_SEEK_CUR); }else /* cookie TEXT ** ** The server might include a cookie in its reply. The client ** should remember this cookie and send it back to the server ** in its next query. ** ** Each cookie received overwrites the prior cookie from the |
︙ | ︙ | |||
1779 1780 1781 1782 1783 1784 1785 | /* message MESSAGE ** ** Print a message. Similar to "error" but does not stop processing. ** ** If the "login failed" message is seen, clear the sync password prior ** to the next cycle. | | | | | | | | | 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 | /* message MESSAGE ** ** Print a message. Similar to "error" but does not stop processing. ** ** If the "login failed" message is seen, clear the sync password prior ** to the next cycle. */ if( blob_eq(&xfer.aToken[0],"message") && xfer.nToken==2 ){ char *zMsg = blob_terminate(&xfer.aToken[1]); defossilize(zMsg); if( (syncFlags & SYNC_PUSH) && zMsg && strglob("pull only *", zMsg) ){ syncFlags &= ~SYNC_PUSH; zMsg = 0; } if( zMsg && zMsg[0] ){ fossil_force_newline(); fossil_print("Server says: %s\n", zMsg); } }else /* pragma NAME VALUE... ** ** The server can send pragmas to try to convey meta-information to ** the client. These are informational only. Unknown pragmas are ** silently ignored. */ if( blob_eq(&xfer.aToken[0], "pragma") && xfer.nToken>=2 ){ }else /* error MESSAGE ** ** Report an error and abandon the sync session. ** ** Except, when cloning we will sometimes get an error on the ** first message exchange because the project-code is unknown ** and so the login card on the request was invalid. The project-code ** is returned in the reply before the error card, so second and ** subsequent messages should be OK. Nevertheless, we need to ignore ** the error card on the first message of a clone. */ if( blob_eq(&xfer.aToken[0],"error") && xfer.nToken==2 ){ if( (syncFlags & SYNC_CLONE)==0 || nCycle>0 ){ char *zMsg = blob_terminate(&xfer.aToken[1]); defossilize(zMsg); fossil_force_newline(); fossil_print("Error: %s\n", zMsg); if( fossil_strcmp(zMsg, "login failed")==0 ){ if( nCycle<2 ){ g.urlPasswd = 0; go = 1; if( g.cgiOutput==0 ){ g.urlFlags |= URL_PROMPT_PW; g.urlFlags &= ~URL_PROMPTED; url_prompt_for_password(); url_remember(); } } }else{ blob_appendf(&xfer.err, "server says: %s\n", zMsg); nErr++; |
︙ | ︙ | |||
1893 1894 1895 1896 1897 1898 1899 | } nCardRcvd = 0; xfer.nFileRcvd = 0; xfer.nDeltaRcvd = 0; xfer.nDanglingFile = 0; /* If we have one or more files queued to send, then go | | | | | | 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 | } nCardRcvd = 0; xfer.nFileRcvd = 0; xfer.nDeltaRcvd = 0; xfer.nDanglingFile = 0; /* If we have one or more files queued to send, then go ** another round */ if( xfer.nFileSent+xfer.nDeltaSent>0 ){ go = 1; } /* If this is a clone, the go at least two rounds */ if( (syncFlags & SYNC_CLONE)!=0 && nCycle==1 ) go = 1; /* Stop the cycle if the server sends a "clone_seqno 0" card and ** we have gone at least two rounds. Always go at least two rounds ** on a clone in order to be sure to retrieve the configuration ** information which is only sent on the second round. */ if( cloneSeqno<=0 && nCycle>1 ) go = 0; }; transport_stats(&nSent, &nRcvd, 1); if( (rSkew*24.0*3600.0) > 10.0 ){ fossil_warning("*** time skew *** server is fast by %s", db_timespan_name(rSkew)); g.clockSkewSeen = 1; }else if( rSkew*24.0*3600.0 < -10.0 ){ fossil_warning("*** time skew *** server is slow by %s", db_timespan_name(-rSkew)); g.clockSkewSeen = 1; } fossil_force_newline(); fossil_print( "%s finished with %lld bytes sent, %lld bytes received\n", zOpType, nSent, nRcvd); transport_close(GLOBAL_URL()); transport_global_shutdown(GLOBAL_URL()); db_multi_exec("DROP TABLE onremote"); manifest_crosslink_end(MC_PERMIT_HOOKS); content_enable_dephantomize(1); db_end_transaction(0); return nErr; } |
Changes to src/xfersetup.c.
︙ | ︙ | |||
42 43 44 45 46 47 48 | setup_menu_entry("Commit", "xfersetup_commit", "Specific TH1 code to run after processing a commit."); setup_menu_entry("Ticket", "xfersetup_ticket", "Specific TH1 code to run after processing a ticket change."); @ </table> url_parse(0, 0); | | | | | 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | setup_menu_entry("Commit", "xfersetup_commit", "Specific TH1 code to run after processing a commit."); setup_menu_entry("Ticket", "xfersetup_ticket", "Specific TH1 code to run after processing a ticket change."); @ </table> url_parse(0, 0); if( g.urlProtocol ){ unsigned syncFlags; const char *zButton; char *zWarning; if( db_get_boolean("dont-push", 0) ){ syncFlags = SYNC_PULL; zButton = "Pull"; zWarning = 0; }else{ syncFlags = SYNC_PUSH | SYNC_PULL; zButton = "Synchronize"; zWarning = mprintf("WARNING: Pushing to \"%s\" is enabled.", g.urlCanonical); } if( P("sync") ){ user_select(); url_enable_proxy(0); client_sync(syncFlags, 0, 0); } @ <p>Press the %h(zButton) button below to synchronize with the @ "%h(g.urlCanonical)" repository now. This may be useful when @ testing the various transfer scripts.</p> @ <p>You can use the "http -async" command in your scripts, but @ make sure the "th1-uri-regexp" setting is set first.</p> if( zWarning ){ @ @ <big><b>%h(zWarning)</b></big> free(zWarning); |
︙ | ︙ |
Changes to src/zip.c.
︙ | ︙ | |||
79 80 81 82 83 84 85 | /* ** Set the date and time from a julian day number. */ void zip_set_timedate(double rDate){ char *zDate = db_text(0, "SELECT datetime(%.17g)", rDate); zip_set_timedate_from_str(zDate); | | | 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | /* ** Set the date and time from a julian day number. */ void zip_set_timedate(double rDate){ char *zDate = db_text(0, "SELECT datetime(%.17g)", rDate); zip_set_timedate_from_str(zDate); free(zDate); unixTime = (rDate - 2440587.5)*86400.0; } /* ** If the given filename includes one or more directory entries, make ** sure the directories are already in the archive. If they are not ** in the archive, add them. |
︙ | ︙ | |||
156 157 158 159 160 161 162 | put16(&zHdr[4], 0x000a); put16(&zHdr[6], 0x0800); put16(&zHdr[8], iMethod); put16(&zHdr[10], dosTime); put16(&zHdr[12], dosDate); put16(&zHdr[26], nameLen); put16(&zHdr[28], 13); | | | | 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 | put16(&zHdr[4], 0x000a); put16(&zHdr[6], 0x0800); put16(&zHdr[8], iMethod); put16(&zHdr[10], dosTime); put16(&zHdr[12], dosDate); put16(&zHdr[26], nameLen); put16(&zHdr[28], 13); put16(&zExTime[0], 0x5455); put16(&zExTime[2], 9); zExTime[4] = 3; put32(&zExTime[5], unixTime); put32(&zExTime[9], unixTime); /* Write the header and filename. */ iStart = blob_size(&body); blob_append(&body, zHdr, 30); blob_append(&body, zName, nameLen); blob_append(&body, zExTime, 13); |
︙ | ︙ | |||
200 201 202 203 204 205 206 | deflate(&stream, Z_FINISH); toOut = sizeof(zOutBuf) - stream.avail_out; blob_append(&body, zOutBuf, toOut); }while( stream.avail_out==0 ); nByte = stream.total_in; nByteCompr = stream.total_out; deflateEnd(&stream); | | | | 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 | deflate(&stream, Z_FINISH); toOut = sizeof(zOutBuf) - stream.avail_out; blob_append(&body, zOutBuf, toOut); }while( stream.avail_out==0 ); nByte = stream.total_in; nByteCompr = stream.total_out; deflateEnd(&stream); /* Go back and write the header, now that we know the compressed file size. */ z = &blob_buffer(&body)[iStart]; put32(&z[14], iCRC); put32(&z[18], nByteCompr); put32(&z[22], nByte); } /* Make an entry in the tables of contents */ memset(zBuf, 0, sizeof(zBuf)); put32(&zBuf[0], 0x02014b50); put16(&zBuf[4], 0x0317); put16(&zBuf[6], 0x000a); put16(&zBuf[8], 0x0800); |
︙ | ︙ | |||
265 266 267 268 269 270 271 | put16(&zBuf[20], 0); blob_append(&body, zBuf, 22); blob_reset(&toc); *pZip = body; blob_zero(&body); nEntry = 0; for(i=0; i<nDir; i++){ | | | | 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 | put16(&zBuf[20], 0); blob_append(&body, zBuf, 22); blob_reset(&toc); *pZip = body; blob_zero(&body); nEntry = 0; for(i=0; i<nDir; i++){ free(azDir[i]); } free(azDir); nDir = 0; azDir = 0; } /* ** COMMAND: test-filezip ** |
︙ | ︙ | |||
320 321 322 323 324 325 326 | */ void zip_of_baseline(int rid, Blob *pZip, const char *zDir){ Blob mfile, hash, file; Manifest *pManifest; ManifestFile *pFile; Blob filename; int nPrefix; | | | 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 | */ void zip_of_baseline(int rid, Blob *pZip, const char *zDir){ Blob mfile, hash, file; Manifest *pManifest; ManifestFile *pFile; Blob filename; int nPrefix; content_get(rid, &mfile); if( blob_size(&mfile)==0 ){ blob_zero(pZip); return; } blob_zero(&hash); blob_zero(&filename); |
︙ | ︙ | |||
416 417 418 419 420 421 422 | /* ** WEBPAGE: zip ** URL: /zip/RID.zip ** ** Generate a ZIP archive for the baseline. ** Return that ZIP archive as the HTTP reply content. | < < < < < < < < < < | | | 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 | /* ** WEBPAGE: zip ** URL: /zip/RID.zip ** ** Generate a ZIP archive for the baseline. ** Return that ZIP archive as the HTTP reply content. */ void baseline_zip_page(void){ int rid; char *zName, *zRid; int nName, nRid; Blob zip; login_check_credentials(); if( !g.perm.Zip ){ login_needed(); return; } zName = mprintf("%s", PD("name","")); nName = strlen(zName); zRid = mprintf("%s", PD("uuid","trunk")); nRid = strlen(zRid); for(nName=strlen(zName)-1; nName>5; nName--){ if( zName[nName]=='.' ){ zName[nName] = 0; break; } } rid = name_to_typed_rid(nRid?zRid:zName,"ci"); if( rid==0 ){ @ Not found return; } if( nRid==0 && nName>10 ) zName[10] = 0; zip_of_baseline(rid, &zip, zName); free( zName ); free( zRid ); cgi_set_content(&zip); cgi_set_content_type("application/zip"); } |
Changes to test/file1.test.
︙ | ︙ | |||
31 32 33 34 35 36 37 | simplify-name 101 {} {} / / ///////// / ././././ . simplify-name 102 x x /x /x ///x //x simplify-name 103 a/b a/b /a/b /a/b a///b a/b ///a///b///// //a/b simplify-name 104 a/b/../c/ a/c /a/b/../c /a/c /a/b//../c /a/c /a/b/..///c /a/c simplify-name 105 a/b/../../x/y x/y /a/b/../../x/y /x/y simplify-name 106 a/b/../../../x/y ../x/y /a/b/../../../x/y /../x/y simplify-name 107 a/./b/.././../x/y x/y a//.//b//..//.//..//x//y/// x/y | < < < < < | 31 32 33 34 35 36 37 | simplify-name 101 {} {} / / ///////// / ././././ . simplify-name 102 x x /x /x ///x //x simplify-name 103 a/b a/b /a/b /a/b a///b a/b ///a///b///// //a/b simplify-name 104 a/b/../c/ a/c /a/b/../c /a/c /a/b//../c /a/c /a/b/..///c /a/c simplify-name 105 a/b/../../x/y x/y /a/b/../../x/y /x/y simplify-name 106 a/b/../../../x/y ../x/y /a/b/../../../x/y /../x/y simplify-name 107 a/./b/.././../x/y x/y a//.//b//..//.//..//x//y/// x/y |
Changes to test/merge2.test.
︙ | ︙ | |||
18 19 20 21 22 23 24 | # Tests of the delta mechanism. # set filelist [glob $testdir/*] foreach f $filelist { if {[file isdir $f]} continue set base [file root [file tail $f]] | | | 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | # Tests of the delta mechanism. # set filelist [glob $testdir/*] foreach f $filelist { if {[file isdir $f]} continue set base [file root [file tail $f]] if {$base eq "utf"} continue set f1 [read_file $f] write_file t1 $f1 for {set i 0} {$i<100} {incr i} { expr {srand($i*2)} write_file t2 [set f2 [random_changes $f1 2 4 0 0.1]] expr {srand($i*2+1)} write_file t3 [set f3 [random_changes $f1 2 4 2 0.1]] |
︙ | ︙ |
Changes to test/merge5.test.
︙ | ︙ | |||
50 51 52 53 54 55 56 | set env(HOME) [pwd] # Construct a test repository # exec sqlite3 m5.fossil <$testdir/${testfile}_repo.sql fossil rebuild m5.fossil fossil open m5.fossil | < | 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | set env(HOME) [pwd] # Construct a test repository # exec sqlite3 m5.fossil <$testdir/${testfile}_repo.sql fossil rebuild m5.fossil fossil open m5.fossil fossil update baseline checkout-test 10 { da5c8346496f3421cb58f84b6e59e9531d9d424d one.txt ed24d19d726d173f18dbf4a9a0f8514daa3e3ca4 three.txt 278a402316510f6ae4a77186796a6bde78c7dbc1 two.txt } |
︙ | ︙ |
Changes to test/merge_renames.test.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | # # Tests for merging with renames # # catch {exec $::fossilexe info} res puts res=$res if {![regexp {use --repository} $res]} { puts stderr "Cannot run this test within an open checkout" return } ###################################### # Test 1 # # Reported: Ticket [554f44ee74e3d] # ###################################### | > > > > > > | > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | # # Tests for merging with renames # # catch {exec $::fossilexe info} res puts res=$res if {![regexp {use --repository} $res]} { puts stderr "Cannot run this test within an open checkout" return } # Fossil will write data on $HOME, running 'fossil new' here. # We need not to clutter the $HOME of the test caller. set env(HOME) [pwd] ###################################### # Test 1 # # Reported: Ticket [554f44ee74e3d] # ###################################### fossil new rep.fossil fossil open rep.fossil write_file f1 "line" fossil add f1 fossil commit -m "c1" fossil tag add pivot current write_file f1 "line2" |
︙ | ︙ | |||
35 36 37 38 39 40 41 | fossil commit -m "c4" write_file f1 "line6" fossil commit -m "c4" fossil update pivot fossil mv f1 f2 | | | 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | fossil commit -m "c4" write_file f1 "line6" fossil commit -m "c4" fossil update pivot fossil mv f1 f2 exec mv f1 f2 fossil commit -b rename -m "c5" fossil merge trunk fossil commit -m "trunk merged" fossil update pivot write_file f3 "someline" |
︙ | ︙ | |||
64 65 66 67 68 69 70 71 72 73 74 75 | # failed protOut "Error, the merge should not delete any file" test merge_renames-1 0 } else { test merge_renames-1 1 } ###################################### # Test 2 # # Reported: Ticket [74413366fe5067] # ###################################### | > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 | # failed protOut "Error, the merge should not delete any file" test merge_renames-1 0 } else { test merge_renames-1 1 } fossil close -f exec rm rep.fossil ###################################### # Test 2 # # Reported: Ticket [74413366fe5067] # ###################################### fossil new rep.fossil fossil open rep.fossil write_file f1 "line" fossil add f1 fossil commit -m "base file" fossil tag add pivot current write_file f2 "line2" fossil add f2 fossil commit -m "newfile" fossil mv f2 f2new exec mv f2 f2new fossil commit -m "rename" fossil update pivot write_file f1 "line3" fossil commit -b branch -m "change" fossil merge trunk fossil commit -m "trunk merged" fossil update trunk fossil merge branch puts $RESULT # Not a nice way to check, but I don't know more tcl now set deletes 0 foreach {status filename} $RESULT { if {$status=="DELETE"} { set deletes [expr $deletes + 1] } } if {$deletes!=0} { # failed protOut "Error, the merge should not delete any file" test merge_renames-2 0 } else { test merge_renames-2 1 } fossil close -f exec rm rep.fossil ###################################### # Test 3 # # Reported: Ticket [30b28cf351] # ###################################### fossil new rep.fossil fossil open rep.fossil write_file f1 "line" fossil add f1 fossil commit -m "base file" fossil tag add pivot current write_file f2 "line2" fossil add f2 fossil commit -m "newfile" fossil mv f2 f2new exec mv f2 f2new fossil commit -m "rename" fossil update pivot write_file f1 "line3" fossil commit -b branch -m "change" fossil merge trunk |
︙ | ︙ | |||
112 113 114 115 116 117 118 | # failed protOut "Error, the merge should not delete any file" test merge_renames-2 0 } else { test merge_renames-2 1 } | < < < < < < < < | < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 | # failed protOut "Error, the merge should not delete any file" test merge_renames-2 0 } else { test merge_renames-2 1 } fossil close -f exec rm rep.fossil ###################################### # Test 4 # # Reported: Ticket [67176c3aa4] # ###################################### # TO BE WRITTEN. |
︙ | ︙ |
Changes to test/revert.test.
1 2 3 4 5 6 | # # Tests for 'fossil revert' # # # Test 'fossil revert' against expected results from 'fossil changes' and | > > > > > > > > > > > > > > > > > > > > > > > > > > | | > > > > > > | < | | | | > > > > < > < | < < < < | | > | | | < < < < < < | < < | < < | < < | < < < | < < < < < < < < | < < < < < < < < < < < < < < < < < < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 | # # Tests for 'fossil revert' # # catch {exec $::fossilexe info} res puts res=$res if {![regexp {use --repository} $res]} { puts stderr "Cannot run this test within an open checkout" return } # Fossil will write data on $HOME, running 'fossil new' here. # We need not to clutter the $HOME of the test caller. # set env(HOME) [pwd] # Normalize file status lists (like those returned by 'fossil changes') # so they can be compared using simple string comparison # proc normalize-status-list {list} { set normalized [list] set matches [regexp -all -inline -line {^\s*([A-Z]+)\s+(.*)$} $list] foreach {_ status file} $matches { lappend normalized [list $status [string trim $file]] } set normalized [lsort -index 1 $normalized] return $normalized } # Test 'fossil revert' against expected results from 'fossil changes' and # 'fossil addremove --test', as well as by verifying the existence of files # on the file system. 'fossil undo' is called after each test # proc revert-test {testid args} { global RESULT set passed 1 if {[llength $args] % 2} { set revertArgs [lindex $args 0] set args [lrange $args 1 end] } else { set revertArgs {} } set args [dict merge { -changes {} -addremove {} -exists {} -notexists {} } $args] fossil revert {*}$revertArgs set statusListTests [list -changes changes -addremove {addremove --test}] foreach {key fossilArgs} $statusListTests { set expected [normalize-status-list [dict get $args $key]] set result [normalize-status-list [fossil {*}$fossilArgs]] if {$result ne $expected} { set passed 0 protOut " Expected:\n [join $expected "\n "]" protOut " Got:\n [join $result "\n "]" } } set fileExistsTests [list -exists 1 does -notexists 0 should] foreach {key expected verb} $fileExistsTests { foreach path [dict get $args $key] { if {[file exists $path] != $expected} { set passed 0 protOut " Failure: File $verb not exist: $path" } } } fossil undo test revert-$testid $passed } # Create the repo # fossil new rep.fossil fossil open rep.fossil # Prepare first commit # write_file f1 "f1" write_file f2 "f2" write_file f3 "f3" fossil add f1 f2 f3 fossil commit -m "c1" # Make changes to be reverted # # Add f0 write_file f0 "f0" fossil add f0 # Remove f1 exec rm f1 fossil rm f1 # Edit f2 write_file f2 "f2.1" # Rename f3 to f3n exec mv f3 f3n fossil mv f3 f3n # Test 'fossil revert' with no arguments # revert-test 1 -addremove { ADDED f0 } -exists {f0 f1 f2 f3} -notexists f3n # Test with a single filename argument # revert-test 2 f0 -changes { DELETED f1 EDITED f2 RENAMED f3n } -addremove { ADDED f0 } -exists {f0 f2 f3n} -notexists f3 revert-test 3 f1 -changes { ADDED f0 EDITED f2 RENAMED f3n } -exists {f0 f1 f2 f3n} -notexists f3 revert-test 4 f2 -changes { ADDED f0 DELETED f1 RENAMED f3n } -exists {f0 f2 f3n} -notexists {f1 f3} # Both files involved in a rename are reverted regardless of which filename # is used as an argument to 'fossil revert' # revert-test 5 f3 -changes { ADDED f0 DELETED f1 EDITED f2 } -exists {f0 f2 f3} -notexists {f1 f3n} revert-test 6 f3n -changes { ADDED f0 DELETED f1 EDITED f2 } -exists {f0 f2 f3} -notexists {f1 f3n} # Test with multiple filename arguments # revert-test 7 {f0 f2 f3n} -changes { DELETED f1 } -addremove { ADDED f0 } -exists {f0 f2 f3} -notexists {f1 f3n} |
Changes to test/tester.tcl.
︙ | ︙ | |||
119 120 121 122 123 124 125 | set x [read_file $a] regsub -all { +\n} $x \n x set y [read_file $b] regsub -all { +\n} $y \n y return [expr {$x==$y}] } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 119 120 121 122 123 124 125 126 127 128 129 130 131 132 | set x [read_file $a] regsub -all { +\n} $x \n x set y [read_file $b] regsub -all { +\n} $y \n y return [expr {$x==$y}] } # Perform a test # set test_count 0 proc test {name expr} { global bad_test test_count incr test_count set r [uplevel 1 [list expr $expr]] |
︙ | ︙ |
Changes to test/th1.test.
︙ | ︙ | |||
35 36 37 38 39 40 41 | fossil test-th-eval --th-open-config "setting -strict -- abc" test th1-setting-4 {$RESULT eq {TH_ERROR: no value for setting "abc"}} ############################################################################### fossil test-th-eval --th-open-config "setting autosync" | | | | 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | fossil test-th-eval --th-open-config "setting -strict -- abc" test th1-setting-4 {$RESULT eq {TH_ERROR: no value for setting "abc"}} ############################################################################### fossil test-th-eval --th-open-config "setting autosync" test th1-setting-5 {$RESULT eq 1} ############################################################################### fossil test-th-eval --th-open-config "setting -strict autosync" test th1-setting-6 {$RESULT eq 1} ############################################################################### fossil test-th-eval --th-open-config "setting --" test th1-setting-7 {$RESULT eq \ {TH_ERROR: wrong # args: should be "setting ?-strict? ?--? name"}} |
︙ | ︙ | |||
298 299 300 301 302 303 304 | ############################################################################### fossil test-th-eval "string last {AB} {abc}" test th1-string-last-9 {$RESULT eq {-1}} ############################################################################### | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 298 299 300 301 302 303 304 305 306 307 308 309 310 311 | ############################################################################### fossil test-th-eval "string last {AB} {abc}" test th1-string-last-9 {$RESULT eq {-1}} ############################################################################### fossil test-th-eval "expr ~(-1)" test th1-expr-14 {$RESULT eq {0}} ############################################################################### fossil test-th-eval "expr ~-1" test th1-expr-15 {$RESULT eq {0}} |
︙ | ︙ | |||
410 411 412 413 414 415 416 | fossil test-th-eval "expr ~+1" test th1-expr-22 {$RESULT eq {-2}} ############################################################################### fossil test-th-eval "expr ~(+1)" test th1-expr-23 {$RESULT eq {-2}} | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 345 346 347 348 349 350 351 | fossil test-th-eval "expr ~+1" test th1-expr-22 {$RESULT eq {-2}} ############################################################################### fossil test-th-eval "expr ~(+1)" test th1-expr-23 {$RESULT eq {-2}} |
Deleted test/utf16be.txt.
|
| < < < < < < < < < < < < < < < < < < < < < < < |
Deleted test/utf16le.txt.
|
| < < < < < < < < < < < < < < < < < < < < < < < |
Changes to test/valgrind-www.tcl.
︙ | ︙ | |||
10 11 12 13 14 15 16 | # # Then examine the valgrind-out.txt file for issues. # proc run_query {url} { set fd [open q.txt w] puts $fd "GET $url HTTP/1.0\r\n\r" close $fd | < | < | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | # # Then examine the valgrind-out.txt file for issues. # proc run_query {url} { set fd [open q.txt w] puts $fd "GET $url HTTP/1.0\r\n\r" close $fd return [exec valgrind ./fossil test-http <q.txt 2>@ stderr] } set todo {} foreach url { /home /timeline /brlist /taglist |
︙ | ︙ |
Changes to win/Makefile.dmc.
︙ | ︙ | |||
26 27 28 29 30 31 32 | TCC = $(DMDIR)\bin\dmc $(CFLAGS) $(DMCDEF) $(SSL) $(INCL) LIBS = $(DMDIR)\extra\lib\ zlib wsock32 advapi32 SQLITE_OPTIONS = -DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_ENABLE_LOCKING_STYLE=0 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_OMIT_DEPRECATED -DSQLITE_ENABLE_EXPLAIN_COMMENTS SHELL_OPTIONS = -Dmain=sqlite3_shell -DSQLITE_OMIT_LOAD_EXTENSION=1 -DUSE_SYSTEM_SQLITE=$(USE_SYSTEM_SQLITE) -DSQLITE_SHELL_DBNAME_PROC=fossil_open -Daccess=win32_access -Dgetenv=fossil_getenv -Dfopen=fossil_fopen | | | | | 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | TCC = $(DMDIR)\bin\dmc $(CFLAGS) $(DMCDEF) $(SSL) $(INCL) LIBS = $(DMDIR)\extra\lib\ zlib wsock32 advapi32 SQLITE_OPTIONS = -DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_ENABLE_LOCKING_STYLE=0 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_OMIT_DEPRECATED -DSQLITE_ENABLE_EXPLAIN_COMMENTS SHELL_OPTIONS = -Dmain=sqlite3_shell -DSQLITE_OMIT_LOAD_EXTENSION=1 -DUSE_SYSTEM_SQLITE=$(USE_SYSTEM_SQLITE) -DSQLITE_SHELL_DBNAME_PROC=fossil_open -Daccess=win32_access -Dgetenv=fossil_getenv -Dfopen=fossil_fopen SRC = add_.c allrepo_.c attach_.c bag_.c bisect_.c blob_.c branch_.c browse_.c captcha_.c cgi_.c checkin_.c checkout_.c clearsign_.c clone_.c comformat_.c configure_.c content_.c db_.c delta_.c deltacmd_.c descendants_.c diff_.c diffcmd_.c doc_.c encode_.c event_.c export_.c file_.c finfo_.c glob_.c graph_.c gzip_.c http_.c http_socket_.c http_ssl_.c http_transport_.c import_.c info_.c json_.c json_artifact_.c json_branch_.c json_config_.c json_diff_.c json_dir_.c json_finfo_.c json_login_.c json_query_.c json_report_.c json_status_.c json_tag_.c json_timeline_.c json_user_.c json_wiki_.c leaf_.c login_.c lookslike_.c main_.c manifest_.c markdown_.c markdown_html_.c md5_.c merge_.c merge3_.c moderate_.c name_.c path_.c pivot_.c popen_.c pqueue_.c printf_.c rebuild_.c regexp_.c report_.c rss_.c schema_.c search_.c setup_.c sha1_.c shun_.c skins_.c sqlcmd_.c stash_.c stat_.c style_.c sync_.c tag_.c tar_.c th_main_.c timeline_.c tkt_.c tktsetup_.c undo_.c unicode_.c update_.c url_.c user_.c utf8_.c util_.c verify_.c vfile_.c wiki_.c wikiformat_.c winfile_.c winhttp_.c wysiwyg_.c xfer_.c xfersetup_.c zip_.c OBJ = $(OBJDIR)\add$O $(OBJDIR)\allrepo$O $(OBJDIR)\attach$O $(OBJDIR)\bag$O $(OBJDIR)\bisect$O $(OBJDIR)\blob$O $(OBJDIR)\branch$O $(OBJDIR)\browse$O $(OBJDIR)\captcha$O $(OBJDIR)\cgi$O $(OBJDIR)\checkin$O $(OBJDIR)\checkout$O $(OBJDIR)\clearsign$O $(OBJDIR)\clone$O $(OBJDIR)\comformat$O $(OBJDIR)\configure$O $(OBJDIR)\content$O $(OBJDIR)\db$O $(OBJDIR)\delta$O $(OBJDIR)\deltacmd$O $(OBJDIR)\descendants$O $(OBJDIR)\diff$O $(OBJDIR)\diffcmd$O $(OBJDIR)\doc$O $(OBJDIR)\encode$O $(OBJDIR)\event$O $(OBJDIR)\export$O $(OBJDIR)\file$O $(OBJDIR)\finfo$O $(OBJDIR)\glob$O $(OBJDIR)\graph$O $(OBJDIR)\gzip$O $(OBJDIR)\http$O $(OBJDIR)\http_socket$O $(OBJDIR)\http_ssl$O $(OBJDIR)\http_transport$O $(OBJDIR)\import$O $(OBJDIR)\info$O $(OBJDIR)\json$O $(OBJDIR)\json_artifact$O $(OBJDIR)\json_branch$O $(OBJDIR)\json_config$O $(OBJDIR)\json_diff$O $(OBJDIR)\json_dir$O $(OBJDIR)\json_finfo$O $(OBJDIR)\json_login$O $(OBJDIR)\json_query$O $(OBJDIR)\json_report$O $(OBJDIR)\json_status$O $(OBJDIR)\json_tag$O $(OBJDIR)\json_timeline$O $(OBJDIR)\json_user$O $(OBJDIR)\json_wiki$O $(OBJDIR)\leaf$O $(OBJDIR)\login$O $(OBJDIR)\lookslike$O $(OBJDIR)\main$O $(OBJDIR)\manifest$O $(OBJDIR)\markdown$O $(OBJDIR)\markdown_html$O $(OBJDIR)\md5$O $(OBJDIR)\merge$O $(OBJDIR)\merge3$O $(OBJDIR)\moderate$O $(OBJDIR)\name$O $(OBJDIR)\path$O $(OBJDIR)\pivot$O $(OBJDIR)\popen$O $(OBJDIR)\pqueue$O $(OBJDIR)\printf$O $(OBJDIR)\rebuild$O $(OBJDIR)\regexp$O $(OBJDIR)\report$O $(OBJDIR)\rss$O $(OBJDIR)\schema$O $(OBJDIR)\search$O $(OBJDIR)\setup$O $(OBJDIR)\sha1$O $(OBJDIR)\shun$O $(OBJDIR)\skins$O $(OBJDIR)\sqlcmd$O $(OBJDIR)\stash$O $(OBJDIR)\stat$O $(OBJDIR)\style$O $(OBJDIR)\sync$O $(OBJDIR)\tag$O $(OBJDIR)\tar$O $(OBJDIR)\th_main$O $(OBJDIR)\timeline$O $(OBJDIR)\tkt$O $(OBJDIR)\tktsetup$O $(OBJDIR)\undo$O $(OBJDIR)\unicode$O $(OBJDIR)\update$O $(OBJDIR)\url$O $(OBJDIR)\user$O $(OBJDIR)\utf8$O $(OBJDIR)\util$O $(OBJDIR)\verify$O $(OBJDIR)\vfile$O $(OBJDIR)\wiki$O $(OBJDIR)\wikiformat$O $(OBJDIR)\winfile$O $(OBJDIR)\winhttp$O $(OBJDIR)\wysiwyg$O $(OBJDIR)\xfer$O $(OBJDIR)\xfersetup$O $(OBJDIR)\zip$O $(OBJDIR)\shell$O $(OBJDIR)\sqlite3$O $(OBJDIR)\th$O $(OBJDIR)\th_lang$O RC=$(DMDIR)\bin\rcc RCFLAGS=-32 -w1 -I$(SRCDIR) /D__DMC__ APPNAME = $(OBJDIR)\fossil$(E) all: $(APPNAME) $(APPNAME) : translate$E mkindex$E headers $(OBJ) $(OBJDIR)\link cd $(OBJDIR) $(DMDIR)\bin\link @link $(OBJDIR)\fossil.res: $B\win\fossil.rc $(RC) $(RCFLAGS) -o$@ $** $(OBJDIR)\link: $B\win\Makefile.dmc $(OBJDIR)\fossil.res +echo add allrepo attach bag bisect blob branch browse captcha cgi checkin checkout clearsign clone comformat configure content db delta deltacmd descendants diff diffcmd doc encode event export file finfo glob graph gzip http http_socket http_ssl http_transport import info json json_artifact json_branch json_config json_diff json_dir json_finfo json_login json_query json_report json_status json_tag json_timeline json_user json_wiki leaf login lookslike main manifest markdown markdown_html md5 merge merge3 moderate name path pivot popen pqueue printf rebuild regexp report rss schema search setup sha1 shun skins sqlcmd stash stat style sync tag tar th_main timeline tkt tktsetup undo unicode update url user utf8 util verify vfile wiki wikiformat winfile winhttp wysiwyg xfer xfersetup zip shell sqlite3 th th_lang > $@ +echo fossil >> $@ +echo fossil >> $@ +echo $(LIBS) >> $@ +echo. >> $@ +echo fossil >> $@ translate$E: $(SRCDIR)\translate.c |
︙ | ︙ | |||
435 436 437 438 439 440 441 | $(OBJDIR)\leaf$O : leaf_.c leaf.h $(TCC) -o$@ -c leaf_.c leaf_.c : $(SRCDIR)\leaf.c +translate$E $** > $@ | < < < < < < | 435 436 437 438 439 440 441 442 443 444 445 446 447 448 | $(OBJDIR)\leaf$O : leaf_.c leaf.h $(TCC) -o$@ -c leaf_.c leaf_.c : $(SRCDIR)\leaf.c +translate$E $** > $@ $(OBJDIR)\login$O : login_.c login.h $(TCC) -o$@ -c login_.c login_.c : $(SRCDIR)\login.c +translate$E $** > $@ $(OBJDIR)\lookslike$O : lookslike_.c lookslike.h |
︙ | ︙ | |||
766 767 768 769 770 771 772 | $(OBJDIR)\zip$O : zip_.c zip.h $(TCC) -o$@ -c zip_.c zip_.c : $(SRCDIR)\zip.c +translate$E $** > $@ headers: makeheaders$E page_index.h VERSION.h | | | 760 761 762 763 764 765 766 767 768 | $(OBJDIR)\zip$O : zip_.c zip.h $(TCC) -o$@ -c zip_.c zip_.c : $(SRCDIR)\zip.c +translate$E $** > $@ headers: makeheaders$E page_index.h VERSION.h +makeheaders$E add_.c:add.h allrepo_.c:allrepo.h attach_.c:attach.h bag_.c:bag.h bisect_.c:bisect.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h captcha_.c:captcha.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h configure_.c:configure.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendants_.c:descendants.h diff_.c:diff.h diffcmd_.c:diffcmd.h doc_.c:doc.h encode_.c:encode.h event_.c:event.h export_.c:export.h file_.c:file.h finfo_.c:finfo.h glob_.c:glob.h graph_.c:graph.h gzip_.c:gzip.h http_.c:http.h http_socket_.c:http_socket.h http_ssl_.c:http_ssl.h http_transport_.c:http_transport.h import_.c:import.h info_.c:info.h json_.c:json.h json_artifact_.c:json_artifact.h json_branch_.c:json_branch.h json_config_.c:json_config.h json_diff_.c:json_diff.h json_dir_.c:json_dir.h json_finfo_.c:json_finfo.h json_login_.c:json_login.h json_query_.c:json_query.h json_report_.c:json_report.h json_status_.c:json_status.h json_tag_.c:json_tag.h json_timeline_.c:json_timeline.h json_user_.c:json_user.h json_wiki_.c:json_wiki.h leaf_.c:leaf.h login_.c:login.h lookslike_.c:lookslike.h main_.c:main.h manifest_.c:manifest.h markdown_.c:markdown.h markdown_html_.c:markdown_html.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h moderate_.c:moderate.h name_.c:name.h path_.c:path.h pivot_.c:pivot.h popen_.c:popen.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h regexp_.c:regexp.h report_.c:report.h rss_.c:rss.h schema_.c:schema.h search_.c:search.h setup_.c:setup.h sha1_.c:sha1.h shun_.c:shun.h skins_.c:skins.h sqlcmd_.c:sqlcmd.h stash_.c:stash.h stat_.c:stat.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tar_.c:tar.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktsetup_.c:tktsetup.h undo_.c:undo.h unicode_.c:unicode.h update_.c:update.h url_.c:url.h user_.c:user.h utf8_.c:utf8.h util_.c:util.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h winfile_.c:winfile.h winhttp_.c:winhttp.h wysiwyg_.c:wysiwyg.h xfer_.c:xfer.h xfersetup_.c:xfersetup.h zip_.c:zip.h $(SRCDIR)\sqlite3.h $(SRCDIR)\th.h VERSION.h $(SRCDIR)\cson_amalgamation.h @copy /Y nul: headers |
Changes to win/Makefile.mingw.
︙ | ︙ | |||
307 308 309 310 311 312 313 | $(SRCDIR)/json_report.c \ $(SRCDIR)/json_status.c \ $(SRCDIR)/json_tag.c \ $(SRCDIR)/json_timeline.c \ $(SRCDIR)/json_user.c \ $(SRCDIR)/json_wiki.c \ $(SRCDIR)/leaf.c \ | < | 307 308 309 310 311 312 313 314 315 316 317 318 319 320 | $(SRCDIR)/json_report.c \ $(SRCDIR)/json_status.c \ $(SRCDIR)/json_tag.c \ $(SRCDIR)/json_timeline.c \ $(SRCDIR)/json_user.c \ $(SRCDIR)/json_wiki.c \ $(SRCDIR)/leaf.c \ $(SRCDIR)/login.c \ $(SRCDIR)/lookslike.c \ $(SRCDIR)/main.c \ $(SRCDIR)/manifest.c \ $(SRCDIR)/markdown.c \ $(SRCDIR)/markdown_html.c \ $(SRCDIR)/md5.c \ |
︙ | ︙ | |||
418 419 420 421 422 423 424 | $(OBJDIR)/json_report_.c \ $(OBJDIR)/json_status_.c \ $(OBJDIR)/json_tag_.c \ $(OBJDIR)/json_timeline_.c \ $(OBJDIR)/json_user_.c \ $(OBJDIR)/json_wiki_.c \ $(OBJDIR)/leaf_.c \ | < | 417 418 419 420 421 422 423 424 425 426 427 428 429 430 | $(OBJDIR)/json_report_.c \ $(OBJDIR)/json_status_.c \ $(OBJDIR)/json_tag_.c \ $(OBJDIR)/json_timeline_.c \ $(OBJDIR)/json_user_.c \ $(OBJDIR)/json_wiki_.c \ $(OBJDIR)/leaf_.c \ $(OBJDIR)/login_.c \ $(OBJDIR)/lookslike_.c \ $(OBJDIR)/main_.c \ $(OBJDIR)/manifest_.c \ $(OBJDIR)/markdown_.c \ $(OBJDIR)/markdown_html_.c \ $(OBJDIR)/md5_.c \ |
︙ | ︙ | |||
529 530 531 532 533 534 535 | $(OBJDIR)/json_report.o \ $(OBJDIR)/json_status.o \ $(OBJDIR)/json_tag.o \ $(OBJDIR)/json_timeline.o \ $(OBJDIR)/json_user.o \ $(OBJDIR)/json_wiki.o \ $(OBJDIR)/leaf.o \ | < | 527 528 529 530 531 532 533 534 535 536 537 538 539 540 | $(OBJDIR)/json_report.o \ $(OBJDIR)/json_status.o \ $(OBJDIR)/json_tag.o \ $(OBJDIR)/json_timeline.o \ $(OBJDIR)/json_user.o \ $(OBJDIR)/json_wiki.o \ $(OBJDIR)/leaf.o \ $(OBJDIR)/login.o \ $(OBJDIR)/lookslike.o \ $(OBJDIR)/main.o \ $(OBJDIR)/manifest.o \ $(OBJDIR)/markdown.o \ $(OBJDIR)/markdown_html.o \ $(OBJDIR)/md5.o \ |
︙ | ︙ | |||
667 668 669 670 671 672 673 | # the repository after running the tests. test: $(OBJDIR) $(APPNAME) $(TCLSH) $(SRCDIR)/../test/tester.tcl $(APPNAME) $(OBJDIR)/VERSION.h: $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(VERSION) $(VERSION) $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION >$(OBJDIR)/VERSION.h | | > > > > | 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 | # the repository after running the tests. test: $(OBJDIR) $(APPNAME) $(TCLSH) $(SRCDIR)/../test/tester.tcl $(APPNAME) $(OBJDIR)/VERSION.h: $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(VERSION) $(VERSION) $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION >$(OBJDIR)/VERSION.h EXTRAOBJ = $(OBJDIR)/sqlite3.o $(OBJDIR)/shell.o $(OBJDIR)/th.o $(OBJDIR)/th_lang.o $(OBJDIR)/cson_amalgamation.o ifdef FOSSIL_ENABLE_TCL EXTRAOBJ += $(OBJDIR)/th_tcl.o endif zlib: $(MAKE) -C $(ZLIBDIR) PREFIX=$(PREFIX) -f win32/Makefile.gcc libz.a clean-zlib: $(MAKE) -C $(ZLIBDIR) PREFIX=$(PREFIX) -f win32/Makefile.gcc clean |
︙ | ︙ | |||
768 769 770 771 772 773 774 | $(OBJDIR)/json_report_.c:$(OBJDIR)/json_report.h \ $(OBJDIR)/json_status_.c:$(OBJDIR)/json_status.h \ $(OBJDIR)/json_tag_.c:$(OBJDIR)/json_tag.h \ $(OBJDIR)/json_timeline_.c:$(OBJDIR)/json_timeline.h \ $(OBJDIR)/json_user_.c:$(OBJDIR)/json_user.h \ $(OBJDIR)/json_wiki_.c:$(OBJDIR)/json_wiki.h \ $(OBJDIR)/leaf_.c:$(OBJDIR)/leaf.h \ | < | 769 770 771 772 773 774 775 776 777 778 779 780 781 782 | $(OBJDIR)/json_report_.c:$(OBJDIR)/json_report.h \ $(OBJDIR)/json_status_.c:$(OBJDIR)/json_status.h \ $(OBJDIR)/json_tag_.c:$(OBJDIR)/json_tag.h \ $(OBJDIR)/json_timeline_.c:$(OBJDIR)/json_timeline.h \ $(OBJDIR)/json_user_.c:$(OBJDIR)/json_user.h \ $(OBJDIR)/json_wiki_.c:$(OBJDIR)/json_wiki.h \ $(OBJDIR)/leaf_.c:$(OBJDIR)/leaf.h \ $(OBJDIR)/login_.c:$(OBJDIR)/login.h \ $(OBJDIR)/lookslike_.c:$(OBJDIR)/lookslike.h \ $(OBJDIR)/main_.c:$(OBJDIR)/main.h \ $(OBJDIR)/manifest_.c:$(OBJDIR)/manifest.h \ $(OBJDIR)/markdown_.c:$(OBJDIR)/markdown.h \ $(OBJDIR)/markdown_html_.c:$(OBJDIR)/markdown_html.h \ $(OBJDIR)/md5_.c:$(OBJDIR)/md5.h \ |
︙ | ︙ | |||
1264 1265 1266 1267 1268 1269 1270 | $(TRANSLATE) $(SRCDIR)/leaf.c >$(OBJDIR)/leaf_.c $(OBJDIR)/leaf.o: $(OBJDIR)/leaf_.c $(OBJDIR)/leaf.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/leaf.o -c $(OBJDIR)/leaf_.c $(OBJDIR)/leaf.h: $(OBJDIR)/headers | < < < < < < < < | 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 | $(TRANSLATE) $(SRCDIR)/leaf.c >$(OBJDIR)/leaf_.c $(OBJDIR)/leaf.o: $(OBJDIR)/leaf_.c $(OBJDIR)/leaf.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/leaf.o -c $(OBJDIR)/leaf_.c $(OBJDIR)/leaf.h: $(OBJDIR)/headers $(OBJDIR)/login_.c: $(SRCDIR)/login.c $(OBJDIR)/translate $(TRANSLATE) $(SRCDIR)/login.c >$(OBJDIR)/login_.c $(OBJDIR)/login.o: $(OBJDIR)/login_.c $(OBJDIR)/login.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/login.o -c $(OBJDIR)/login_.c $(OBJDIR)/login.h: $(OBJDIR)/headers |
︙ | ︙ | |||
1739 1740 1741 1742 1743 1744 1745 1746 1747 | $(OBJDIR)/th.o: $(SRCDIR)/th.c $(XTCC) -c $(SRCDIR)/th.c -o $(OBJDIR)/th.o $(OBJDIR)/th_lang.o: $(SRCDIR)/th_lang.c $(XTCC) -c $(SRCDIR)/th_lang.c -o $(OBJDIR)/th_lang.o $(OBJDIR)/th_tcl.o: $(SRCDIR)/th_tcl.c $(XTCC) -c $(SRCDIR)/th_tcl.c -o $(OBJDIR)/th_tcl.o | > | | 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 | $(OBJDIR)/th.o: $(SRCDIR)/th.c $(XTCC) -c $(SRCDIR)/th.c -o $(OBJDIR)/th.o $(OBJDIR)/th_lang.o: $(SRCDIR)/th_lang.c $(XTCC) -c $(SRCDIR)/th_lang.c -o $(OBJDIR)/th_lang.o ifdef FOSSIL_ENABLE_TCL $(OBJDIR)/th_tcl.o: $(SRCDIR)/th_tcl.c $(XTCC) -c $(SRCDIR)/th_tcl.c -o $(OBJDIR)/th_tcl.o endif |
Changes to win/Makefile.mingw.mistachkin.
︙ | ︙ | |||
307 308 309 310 311 312 313 | $(SRCDIR)/json_report.c \ $(SRCDIR)/json_status.c \ $(SRCDIR)/json_tag.c \ $(SRCDIR)/json_timeline.c \ $(SRCDIR)/json_user.c \ $(SRCDIR)/json_wiki.c \ $(SRCDIR)/leaf.c \ | < | 307 308 309 310 311 312 313 314 315 316 317 318 319 320 | $(SRCDIR)/json_report.c \ $(SRCDIR)/json_status.c \ $(SRCDIR)/json_tag.c \ $(SRCDIR)/json_timeline.c \ $(SRCDIR)/json_user.c \ $(SRCDIR)/json_wiki.c \ $(SRCDIR)/leaf.c \ $(SRCDIR)/login.c \ $(SRCDIR)/lookslike.c \ $(SRCDIR)/main.c \ $(SRCDIR)/manifest.c \ $(SRCDIR)/markdown.c \ $(SRCDIR)/markdown_html.c \ $(SRCDIR)/md5.c \ |
︙ | ︙ | |||
418 419 420 421 422 423 424 | $(OBJDIR)/json_report_.c \ $(OBJDIR)/json_status_.c \ $(OBJDIR)/json_tag_.c \ $(OBJDIR)/json_timeline_.c \ $(OBJDIR)/json_user_.c \ $(OBJDIR)/json_wiki_.c \ $(OBJDIR)/leaf_.c \ | < | 417 418 419 420 421 422 423 424 425 426 427 428 429 430 | $(OBJDIR)/json_report_.c \ $(OBJDIR)/json_status_.c \ $(OBJDIR)/json_tag_.c \ $(OBJDIR)/json_timeline_.c \ $(OBJDIR)/json_user_.c \ $(OBJDIR)/json_wiki_.c \ $(OBJDIR)/leaf_.c \ $(OBJDIR)/login_.c \ $(OBJDIR)/lookslike_.c \ $(OBJDIR)/main_.c \ $(OBJDIR)/manifest_.c \ $(OBJDIR)/markdown_.c \ $(OBJDIR)/markdown_html_.c \ $(OBJDIR)/md5_.c \ |
︙ | ︙ | |||
529 530 531 532 533 534 535 | $(OBJDIR)/json_report.o \ $(OBJDIR)/json_status.o \ $(OBJDIR)/json_tag.o \ $(OBJDIR)/json_timeline.o \ $(OBJDIR)/json_user.o \ $(OBJDIR)/json_wiki.o \ $(OBJDIR)/leaf.o \ | < | 527 528 529 530 531 532 533 534 535 536 537 538 539 540 | $(OBJDIR)/json_report.o \ $(OBJDIR)/json_status.o \ $(OBJDIR)/json_tag.o \ $(OBJDIR)/json_timeline.o \ $(OBJDIR)/json_user.o \ $(OBJDIR)/json_wiki.o \ $(OBJDIR)/leaf.o \ $(OBJDIR)/login.o \ $(OBJDIR)/lookslike.o \ $(OBJDIR)/main.o \ $(OBJDIR)/manifest.o \ $(OBJDIR)/markdown.o \ $(OBJDIR)/markdown_html.o \ $(OBJDIR)/md5.o \ |
︙ | ︙ | |||
667 668 669 670 671 672 673 | # the repository after running the tests. test: $(OBJDIR) $(APPNAME) $(TCLSH) $(SRCDIR)/../test/tester.tcl $(APPNAME) $(OBJDIR)/VERSION.h: $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(VERSION) $(VERSION) $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION >$(OBJDIR)/VERSION.h | | > > > > | 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 | # the repository after running the tests. test: $(OBJDIR) $(APPNAME) $(TCLSH) $(SRCDIR)/../test/tester.tcl $(APPNAME) $(OBJDIR)/VERSION.h: $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(VERSION) $(VERSION) $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION >$(OBJDIR)/VERSION.h EXTRAOBJ = $(OBJDIR)/sqlite3.o $(OBJDIR)/shell.o $(OBJDIR)/th.o $(OBJDIR)/th_lang.o $(OBJDIR)/cson_amalgamation.o ifdef FOSSIL_ENABLE_TCL EXTRAOBJ += $(OBJDIR)/th_tcl.o endif zlib: $(MAKE) -C $(ZLIBDIR) PREFIX=$(PREFIX) -f win32/Makefile.gcc libz.a clean-zlib: $(MAKE) -C $(ZLIBDIR) PREFIX=$(PREFIX) -f win32/Makefile.gcc clean |
︙ | ︙ | |||
768 769 770 771 772 773 774 | $(OBJDIR)/json_report_.c:$(OBJDIR)/json_report.h \ $(OBJDIR)/json_status_.c:$(OBJDIR)/json_status.h \ $(OBJDIR)/json_tag_.c:$(OBJDIR)/json_tag.h \ $(OBJDIR)/json_timeline_.c:$(OBJDIR)/json_timeline.h \ $(OBJDIR)/json_user_.c:$(OBJDIR)/json_user.h \ $(OBJDIR)/json_wiki_.c:$(OBJDIR)/json_wiki.h \ $(OBJDIR)/leaf_.c:$(OBJDIR)/leaf.h \ | < | 769 770 771 772 773 774 775 776 777 778 779 780 781 782 | $(OBJDIR)/json_report_.c:$(OBJDIR)/json_report.h \ $(OBJDIR)/json_status_.c:$(OBJDIR)/json_status.h \ $(OBJDIR)/json_tag_.c:$(OBJDIR)/json_tag.h \ $(OBJDIR)/json_timeline_.c:$(OBJDIR)/json_timeline.h \ $(OBJDIR)/json_user_.c:$(OBJDIR)/json_user.h \ $(OBJDIR)/json_wiki_.c:$(OBJDIR)/json_wiki.h \ $(OBJDIR)/leaf_.c:$(OBJDIR)/leaf.h \ $(OBJDIR)/login_.c:$(OBJDIR)/login.h \ $(OBJDIR)/lookslike_.c:$(OBJDIR)/lookslike.h \ $(OBJDIR)/main_.c:$(OBJDIR)/main.h \ $(OBJDIR)/manifest_.c:$(OBJDIR)/manifest.h \ $(OBJDIR)/markdown_.c:$(OBJDIR)/markdown.h \ $(OBJDIR)/markdown_html_.c:$(OBJDIR)/markdown_html.h \ $(OBJDIR)/md5_.c:$(OBJDIR)/md5.h \ |
︙ | ︙ | |||
1264 1265 1266 1267 1268 1269 1270 | $(TRANSLATE) $(SRCDIR)/leaf.c >$(OBJDIR)/leaf_.c $(OBJDIR)/leaf.o: $(OBJDIR)/leaf_.c $(OBJDIR)/leaf.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/leaf.o -c $(OBJDIR)/leaf_.c $(OBJDIR)/leaf.h: $(OBJDIR)/headers | < < < < < < < < | 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 | $(TRANSLATE) $(SRCDIR)/leaf.c >$(OBJDIR)/leaf_.c $(OBJDIR)/leaf.o: $(OBJDIR)/leaf_.c $(OBJDIR)/leaf.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/leaf.o -c $(OBJDIR)/leaf_.c $(OBJDIR)/leaf.h: $(OBJDIR)/headers $(OBJDIR)/login_.c: $(SRCDIR)/login.c $(OBJDIR)/translate $(TRANSLATE) $(SRCDIR)/login.c >$(OBJDIR)/login_.c $(OBJDIR)/login.o: $(OBJDIR)/login_.c $(OBJDIR)/login.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/login.o -c $(OBJDIR)/login_.c $(OBJDIR)/login.h: $(OBJDIR)/headers |
︙ | ︙ | |||
1739 1740 1741 1742 1743 1744 1745 1746 1747 | $(OBJDIR)/th.o: $(SRCDIR)/th.c $(XTCC) -c $(SRCDIR)/th.c -o $(OBJDIR)/th.o $(OBJDIR)/th_lang.o: $(SRCDIR)/th_lang.c $(XTCC) -c $(SRCDIR)/th_lang.c -o $(OBJDIR)/th_lang.o $(OBJDIR)/th_tcl.o: $(SRCDIR)/th_tcl.c $(XTCC) -c $(SRCDIR)/th_tcl.c -o $(OBJDIR)/th_tcl.o | > > | 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 | $(OBJDIR)/th.o: $(SRCDIR)/th.c $(XTCC) -c $(SRCDIR)/th.c -o $(OBJDIR)/th.o $(OBJDIR)/th_lang.o: $(SRCDIR)/th_lang.c $(XTCC) -c $(SRCDIR)/th_lang.c -o $(OBJDIR)/th_lang.o ifdef FOSSIL_ENABLE_TCL $(OBJDIR)/th_tcl.o: $(SRCDIR)/th_tcl.c $(XTCC) -c $(SRCDIR)/th_tcl.c -o $(OBJDIR)/th_tcl.o endif |
Changes to win/Makefile.msc.
︙ | ︙ | |||
20 21 22 23 24 25 26 | # Uncomment to enable JSON API # FOSSIL_ENABLE_JSON = 1 # Uncomment to enable SSL support # FOSSIL_ENABLE_SSL = 1 | < < < < < < < < < | | < < < < | | | | | | | | | | | < < < < < < < < < < < | 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | # Uncomment to enable JSON API # FOSSIL_ENABLE_JSON = 1 # Uncomment to enable SSL support # FOSSIL_ENABLE_SSL = 1 !ifdef FOSSIL_ENABLE_SSL SSLINCDIR = $(B)\compat\openssl-1.0.1g\include SSLLIBDIR = $(B)\compat\openssl-1.0.1g\out32 SSLLIB = ssleay32.lib libeay32.lib user32.lib gdi32.lib !endif # zlib options ZINCDIR = $(B)\compat\zlib ZLIBDIR = $(B)\compat\zlib ZLIB = zlib.lib INCL = -I. -I$(SRCDIR) -I$B\win\include -I$(ZINCDIR) !ifdef FOSSIL_ENABLE_SSL INCL = $(INCL) -I$(SSLINCDIR) !endif CFLAGS = -nologo LDFLAGS = /NODEFAULTLIB:msvcrt /MANIFEST:NO !ifdef DEBUG CFLAGS = $(CFLAGS) -Zi -MTd -Od LDFLAGS = $(LDFLAGS) /DEBUG !else CFLAGS = $(CFLAGS) -MT -O2 !endif BCC = $(CC) $(CFLAGS) TCC = $(CC) -c $(CFLAGS) $(MSCDEF) $(INCL) RCC = rc -D_WIN32 -D_MSC_VER $(MSCDEF) $(INCL) LIBS = $(ZLIB) ws2_32.lib advapi32.lib LIBDIR = -LIBPATH:$(ZLIBDIR) !ifdef FOSSIL_ENABLE_JSON TCC = $(TCC) -DFOSSIL_ENABLE_JSON=1 RCC = $(RCC) -DFOSSIL_ENABLE_JSON=1 !endif !ifdef FOSSIL_ENABLE_SSL TCC = $(TCC) -DFOSSIL_ENABLE_SSL=1 RCC = $(RCC) -DFOSSIL_ENABLE_SSL=1 LIBS = $(LIBS) $(SSLLIB) LIBDIR = $(LIBDIR) -LIBPATH:$(SSLLIBDIR) !endif SQLITE_OPTIONS = /DSQLITE_OMIT_LOAD_EXTENSION=1 \ /DSQLITE_ENABLE_LOCKING_STYLE=0 \ /DSQLITE_THREADSAFE=0 \ /DSQLITE_DEFAULT_FILE_FORMAT=4 \ /DSQLITE_OMIT_DEPRECATED \ |
︙ | ︙ | |||
158 159 160 161 162 163 164 | json_report_.c \ json_status_.c \ json_tag_.c \ json_timeline_.c \ json_user_.c \ json_wiki_.c \ leaf_.c \ | < | 134 135 136 137 138 139 140 141 142 143 144 145 146 147 | json_report_.c \ json_status_.c \ json_tag_.c \ json_timeline_.c \ json_user_.c \ json_wiki_.c \ leaf_.c \ login_.c \ lookslike_.c \ main_.c \ manifest_.c \ markdown_.c \ markdown_html_.c \ md5_.c \ |
︙ | ︙ | |||
269 270 271 272 273 274 275 | $(OX)\json_report$O \ $(OX)\json_status$O \ $(OX)\json_tag$O \ $(OX)\json_timeline$O \ $(OX)\json_user$O \ $(OX)\json_wiki$O \ $(OX)\leaf$O \ | < | 244 245 246 247 248 249 250 251 252 253 254 255 256 257 | $(OX)\json_report$O \ $(OX)\json_status$O \ $(OX)\json_tag$O \ $(OX)\json_timeline$O \ $(OX)\json_user$O \ $(OX)\json_wiki$O \ $(OX)\leaf$O \ $(OX)\login$O \ $(OX)\lookslike$O \ $(OX)\main$O \ $(OX)\manifest$O \ $(OX)\markdown$O \ $(OX)\markdown_html$O \ $(OX)\md5$O \ |
︙ | ︙ | |||
308 309 310 311 312 313 314 | $(OX)\style$O \ $(OX)\sync$O \ $(OX)\tag$O \ $(OX)\tar$O \ $(OX)\th$O \ $(OX)\th_lang$O \ $(OX)\th_main$O \ | < | 282 283 284 285 286 287 288 289 290 291 292 293 294 295 | $(OX)\style$O \ $(OX)\sync$O \ $(OX)\tag$O \ $(OX)\tar$O \ $(OX)\th$O \ $(OX)\th_lang$O \ $(OX)\th_main$O \ $(OX)\timeline$O \ $(OX)\tkt$O \ $(OX)\tktsetup$O \ $(OX)\undo$O \ $(OX)\unicode$O \ $(OX)\update$O \ $(OX)\url$O \ |
︙ | ︙ | |||
331 332 333 334 335 336 337 | $(OX)\winhttp$O \ $(OX)\wysiwyg$O \ $(OX)\xfer$O \ $(OX)\xfersetup$O \ $(OX)\zip$O \ $(OX)\fossil.res | < | | 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 | $(OX)\winhttp$O \ $(OX)\wysiwyg$O \ $(OX)\xfer$O \ $(OX)\xfersetup$O \ $(OX)\zip$O \ $(OX)\fossil.res APPNAME = $(OX)\fossil$(E) PDBNAME = $(OX)\fossil$(P) all: $(OX) $(APPNAME) zlib: @echo Building zlib from "$(ZLIBDIR)"... @pushd "$(ZLIBDIR)" && nmake /f win32\Makefile.msc $(ZLIB) && popd $(APPNAME) : translate$E mkindex$E headers $(OBJ) $(OX)\linkopts zlib cd $(OX) link $(LDFLAGS) -OUT:$@ $(LIBDIR) Wsetargv.obj fossil.res @linkopts $(OX)\linkopts: $B\win\Makefile.msc echo $(OX)\add.obj > $@ echo $(OX)\allrepo.obj >> $@ echo $(OX)\attach.obj >> $@ echo $(OX)\bag.obj >> $@ echo $(OX)\bisect.obj >> $@ |
︙ | ︙ | |||
401 402 403 404 405 406 407 | echo $(OX)\json_report.obj >> $@ echo $(OX)\json_status.obj >> $@ echo $(OX)\json_tag.obj >> $@ echo $(OX)\json_timeline.obj >> $@ echo $(OX)\json_user.obj >> $@ echo $(OX)\json_wiki.obj >> $@ echo $(OX)\leaf.obj >> $@ | < | 373 374 375 376 377 378 379 380 381 382 383 384 385 386 | echo $(OX)\json_report.obj >> $@ echo $(OX)\json_status.obj >> $@ echo $(OX)\json_tag.obj >> $@ echo $(OX)\json_timeline.obj >> $@ echo $(OX)\json_user.obj >> $@ echo $(OX)\json_wiki.obj >> $@ echo $(OX)\leaf.obj >> $@ echo $(OX)\login.obj >> $@ echo $(OX)\lookslike.obj >> $@ echo $(OX)\main.obj >> $@ echo $(OX)\manifest.obj >> $@ echo $(OX)\markdown.obj >> $@ echo $(OX)\markdown_html.obj >> $@ echo $(OX)\md5.obj >> $@ |
︙ | ︙ | |||
440 441 442 443 444 445 446 | echo $(OX)\style.obj >> $@ echo $(OX)\sync.obj >> $@ echo $(OX)\tag.obj >> $@ echo $(OX)\tar.obj >> $@ echo $(OX)\th.obj >> $@ echo $(OX)\th_lang.obj >> $@ echo $(OX)\th_main.obj >> $@ | < | 411 412 413 414 415 416 417 418 419 420 421 422 423 424 | echo $(OX)\style.obj >> $@ echo $(OX)\sync.obj >> $@ echo $(OX)\tag.obj >> $@ echo $(OX)\tar.obj >> $@ echo $(OX)\th.obj >> $@ echo $(OX)\th_lang.obj >> $@ echo $(OX)\th_main.obj >> $@ echo $(OX)\timeline.obj >> $@ echo $(OX)\tkt.obj >> $@ echo $(OX)\tktsetup.obj >> $@ echo $(OX)\undo.obj >> $@ echo $(OX)\unicode.obj >> $@ echo $(OX)\update.obj >> $@ echo $(OX)\url.obj >> $@ |
︙ | ︙ | |||
462 463 464 465 466 467 468 469 470 471 472 473 474 475 | echo $(OX)\winfile.obj >> $@ echo $(OX)\winhttp.obj >> $@ echo $(OX)\wysiwyg.obj >> $@ echo $(OX)\xfer.obj >> $@ echo $(OX)\xfersetup.obj >> $@ echo $(OX)\zip.obj >> $@ echo $(LIBS) >> $@ $(OX): @-mkdir $@ translate$E: $(SRCDIR)\translate.c $(BCC) $** | > > > | 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 | echo $(OX)\winfile.obj >> $@ echo $(OX)\winhttp.obj >> $@ echo $(OX)\wysiwyg.obj >> $@ echo $(OX)\xfer.obj >> $@ echo $(OX)\xfersetup.obj >> $@ echo $(OX)\zip.obj >> $@ echo $(LIBS) >> $@ $(OX): @-mkdir $@ translate$E: $(SRCDIR)\translate.c $(BCC) $** |
︙ | ︙ | |||
490 491 492 493 494 495 496 | $(OX)\th$O : $(SRCDIR)\th.c $(TCC) /Fo$@ -c $** $(OX)\th_lang$O : $(SRCDIR)\th_lang.c $(TCC) /Fo$@ -c $** | < < < | | 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 | $(OX)\th$O : $(SRCDIR)\th.c $(TCC) /Fo$@ -c $** $(OX)\th_lang$O : $(SRCDIR)\th_lang.c $(TCC) /Fo$@ -c $** VERSION.h : mkversion$E $B\manifest.uuid $B\manifest $B\VERSION $** > $@ $(OX)\cson_amalgamation$O : $(SRCDIR)\cson_amalgamation.c $(TCC) /Fo$@ -c $** page_index.h: mkindex$E $(SRC) $** > $@ clean: -del $(OX)\*.obj -del *.obj |
︙ | ︙ | |||
535 536 537 538 539 540 541 542 543 544 545 546 547 548 | $(OBJDIR)\json_query$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_report$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_status$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_tag$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_timeline$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_user$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_wiki$O : $(SRCDIR)\json_detail.h $(OX)\add$O : add_.c add.h $(TCC) /Fo$@ -c add_.c add_.c : $(SRCDIR)\add.c translate$E $** > $@ | > | 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 | $(OBJDIR)\json_query$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_report$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_status$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_tag$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_timeline$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_user$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_wiki$O : $(SRCDIR)\json_detail.h $(OX)\add$O : add_.c add.h $(TCC) /Fo$@ -c add_.c add_.c : $(SRCDIR)\add.c translate$E $** > $@ |
︙ | ︙ | |||
860 861 862 863 864 865 866 | $(OX)\leaf$O : leaf_.c leaf.h $(TCC) /Fo$@ -c leaf_.c leaf_.c : $(SRCDIR)\leaf.c translate$E $** > $@ | < < < < < < | 831 832 833 834 835 836 837 838 839 840 841 842 843 844 | $(OX)\leaf$O : leaf_.c leaf.h $(TCC) /Fo$@ -c leaf_.c leaf_.c : $(SRCDIR)\leaf.c translate$E $** > $@ $(OX)\login$O : login_.c login.h $(TCC) /Fo$@ -c login_.c login_.c : $(SRCDIR)\login.c translate$E $** > $@ $(OX)\lookslike$O : lookslike_.c lookslike.h |
︙ | ︙ | |||
1191 1192 1193 1194 1195 1196 1197 | $(OX)\zip$O : zip_.c zip.h $(TCC) /Fo$@ -c zip_.c zip_.c : $(SRCDIR)\zip.c translate$E $** > $@ fossil.res : $B\win\fossil.rc | | < | 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 | $(OX)\zip$O : zip_.c zip.h $(TCC) /Fo$@ -c zip_.c zip_.c : $(SRCDIR)\zip.c translate$E $** > $@ fossil.res : $B\win\fossil.rc $(RCC) -fo $@ $** headers: makeheaders$E page_index.h VERSION.h makeheaders$E add_.c:add.h \ allrepo_.c:allrepo.h \ attach_.c:attach.h \ bag_.c:bag.h \ bisect_.c:bisect.h \ blob_.c:blob.h \ |
︙ | ︙ | |||
1248 1249 1250 1251 1252 1253 1254 | json_report_.c:json_report.h \ json_status_.c:json_status.h \ json_tag_.c:json_tag.h \ json_timeline_.c:json_timeline.h \ json_user_.c:json_user.h \ json_wiki_.c:json_wiki.h \ leaf_.c:leaf.h \ | < | 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 | json_report_.c:json_report.h \ json_status_.c:json_status.h \ json_tag_.c:json_tag.h \ json_timeline_.c:json_timeline.h \ json_user_.c:json_user.h \ json_wiki_.c:json_wiki.h \ leaf_.c:leaf.h \ login_.c:login.h \ lookslike_.c:lookslike.h \ main_.c:main.h \ manifest_.c:manifest.h \ markdown_.c:markdown.h \ markdown_html_.c:markdown_html.h \ md5_.c:md5.h \ |
︙ | ︙ |
Changes to www/changes.wiki.
1 2 | <title>Change Log</title> | | | | | | | < < | > > | | | | | | | | > > | < > > > > > > > > | > > > | | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 | <title>Change Log</title> <h2>Changes For Version 1.28.1 (most likely never being released, those are candidate cherry-picks just in case)</h2> * Upgraded internal SQLite to version 3.8.4.3, which adds support for CTE and the WITH clause, and fixes various (minor) SQLite bugs. * Relax minimum SQLite version check to 3.7.17, as Fossil 1.28 actually works fine with this version and higher, when configured with --disable-internal-sqlite. See: [https://www.mail-archive.com/fossil-users@lists.fossil-scm.org/msg14520.html] * [252aff3e62]: Make "fossil diff --tk" work out-of-the-box on Windows when Activestate Tcl is installed. * [d5d7e640d0]: After successful "login" return to web-page immediately before logging in. * [cec85224c1]: Make 'th1-setup' a textarea in settings UI. * [d752140c7a]: RECONSTRUCT failure. * [d8a588ba76]: Fix checking for "clearsign" option in "fossil branch" command. * [1c39f113d1]: Crash on STASH DIFF command. * [b4dffdac5e]: Avoid unnecessary no-op write transactions on the server during a pull. * [3fbdaa243d]: Speedup "fossil extras" and other commands which traverse the local filesystem. * [684eb478e7]: Fix the SCGI processing so that it works with Nginx. * [ee1aa460a4]: Fix using the unary bitwise NOT operator in TH1 * [f2ebd7e52d]: Make use of a recursive query capability (if available) to replace the compute_ancestors() function with a single query. * [a138dc97fc]: Fix a potential segfault when the SSH_CONNECTION environment variable is defined. * [bfdabaecc8]: Fix the EXPLAIN indenter in the command-line shell to correctly handle NextIfOpen and PrevIfOpen opcodes. * [http://www.sqlite.org/src/info/9d2ae6342c|9d2ae6342c]: In the command-line shell, run set writable_schema before running the ".clone" command. * [fc6bb93689]: Add the "httpize" TH1 command. <h2>Changes For Version 1.28 (2014-01-27)</h2> * Enhance [/help?cmd=/reports | /reports] to support event type filtering. * When cloning a repository, the user name passed via the URL (if any) is now used as the default local admin user's name. * Enhance the SSH transport mechanism so that it runs a single instance of the "fossil" executable on the remote side, obviating the need for a shell on the remote side. Some users may need to add the "?fossil=/path/to/fossil" query parameter to "ssh:" URIs if their fossil binary is not in a standard place. * Add the "[/help?cmd=blame | fossil blame]" command that works just like "fossil annotate" but uses a different output format that includes the user who made each changes and omits line numbers. * Add the "Tarball and ZIP-archive Prefix" configuration parameter under Admin/Configuration. * Fix CGI processing so that it works on web servers that do not supply REQUEST_URI. * Add options --dirsonly, --emptydirs, and --allckouts to the "[/help?cmd=clean | fossil clean]" command. * Ten-fold performance improvement in large "fossil blame" or "fossil annotate" commands. * Add option -W|--width and --offset to "[/help?cmd=timeline | fossil timeline]" and "[/help?cmd=finfo | fossil finfo]" commands. * Option -n|--limit of "[/help?cmd=timeline | fossil timeline]" now specifies the number of entries, just like all other commands which have the -n|--limit option. The various timeline-related functions now output "--- ?? limit (??) reached ---" at the end whenever appropriate. Use "-n 0" if no limit is desired. * Fix handling of password embedded in Fossil URL. * New <tt>--once</tt> option to [/help?cmd=clone | fossil clone] command which does not store the URL or password when cloning. * Modify [/help?cmd=ui | fossil ui] to respect "default user" in an open repository. * Fossil now hides check-ins that have the "hidden" tag in timeline webpages. * Enhance <tt>/ci_edit</tt> page to add the "hidden" tag to check-ins. * Advanced possibilities for commit and ticket change notifications over http using TH1 scripting. * Add --sha1sum and --integrate options to the "[/help?cmd=commit | fossil commit]" command. * Add the "clean" and "extra" subcommands to the "[/help?cmd=all | fossil all]" command * Add the --whatif option to "[/help?cmd=clean|fossil clean]" that works the same as "--dry-run", so that the name does not collide with the --dry-run option of "fossil all". * Provide a configuration option to show dates on the web timeline as "YYMMMDD HH:MM" * Add an option to the "stats" webpage that allows an administrator to see the current repository schema. * Enhancements to the "[/help?cmd=/vdiff|/vdiff]" webpage for more difference display options. * Added the "[/tree?ci=trunk&expand | /tree]" webpage as an alternative to "/dir" and make it the default way of showing file lists. * Send gzipped HTTP responses to clients that support it. <h2>Changes For Version 1.27 (2013-09-11)</h2> * Enhance the [/help?cmd=changes | fossil changes], |
︙ | ︙ | |||
127 128 129 130 131 132 133 | letter everywhere. The default value of the "case-sensitive" setting is now FALSE, except when case-sensitivity is enabled in the Windows kernel. See [http://cygwin.com/cygwin-ug-net/using-specialnames.html#pathnames-casesensitive] * Enhancements to /timeline.rss, adding more flags for filtering results, including the ability to subscribe to changes made to individual tickets. For example: [/timeline.rss?y=t&tkt=12fceeec82]. | | | | | | | 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 | letter everywhere. The default value of the "case-sensitive" setting is now FALSE, except when case-sensitivity is enabled in the Windows kernel. See [http://cygwin.com/cygwin-ug-net/using-specialnames.html#pathnames-casesensitive] * Enhancements to /timeline.rss, adding more flags for filtering results, including the ability to subscribe to changes made to individual tickets. For example: [/timeline.rss?y=t&tkt=12fceeec82]. * Improved handling of the differences between case-sensitive and case-insensitive filesystems. * JSON API: added the 'status' command to report local checkout status. * Fixes to the <tt>--args</tt> support and documented this feature in the help. * Added [/stats_report] page. * Added <tt>ym=YYYY-MM</tt> filter to the [/timeline?ym=2013-06]. * Fixed: <tt>config reset</tt> now re-installs default ticket report format. * <tt>ssh://</tt> and <tt>file://</tt> protocols now ignore proxy settings. * Added [/hash-color-test] web page. * Cherry-pick merges are recorded internally (though no yet displayed on the timeline graph.) * Bring in the latest versions of SQLite, zlib, and autosetup from upstream. <h2>Changes For Version 1.25 (2013-02-16)</h2> * Enhancements to ticket processing. There are now two tables: TICKET and TICKETCHNG. There is one row in TICKETCHNG for each ticket artifact. Fields from ticket artifacts go into either or both of TICKET and TICKETCHNG, whichever contain matching column names. Default ticket edit and viewing scripts are updated to use TICKETCHNG. The TH1 scripting language is enhanced to support this, including the new "query" command for doing SQL queries against the repository database. All changes should be backwards compatible. * Add the ability to moderate ticket and wiki changes. Unmoderated changes do not sync and may be deleted by the moderator if found to contain spam or other objectionable content. * Add javascript so that clicking on a node of the timeline graph selects that node. Then clicking on a second node shows a diff between the two nodes. Clicking on the selected node unselects it. * Warn of unresolved merge conflicts in "fossil status" and disallow commits of unresolved conflicts unless the --allow-conflict option is used. * Add javascript so that clicking on column headers in a ticket report sorts by the indicated column. * Add the "fossil cat" command which is basically an alias for "fossil finfo -p". * Hyperlinks with the class "button" are rendered as submenu buttons on embedded documentation. * The check-in comment editor on windows now defaults to NotePad.exe. * Correctly deal with BOMs in check-in comments. Also attempt to convert check-in comments to UTF8 from other encodings. * Allow the deletion of multiple stash entries using multiple arguments to the "fossil stash rm" command. * Enhance the "fossil server DIRECTORY" command to serve static content files contained in DIRECTORY. For security, only files with a recognized suffix (such as *.html, *.jpg, *.txt, etc) will be delivered as static content, and *.fossil files are not on the list of recognized suffixes. There are additional restrictions on the names of the files. * Allow the "fossil ui" command to specify a directory as long as the the --notfound option is used. * Add a configuration option that causes timeline messages to be rendered as text/x-fossil-plain (which is the same as text/plain except that |
︙ | ︙ | |||
198 199 200 201 202 203 204 | dry-run merge. Display an improved merge-summary message at the end of the merge. * Add options to "fossil commit" to override the various sanity checks. Options added: --allow-empty, --allow-fork, --allow-older, and --allow-conflict. * Optionally require a CAPTCHA (controlled by a setting on the Admin/Access webpage) when a user who is not logged in tries to | | | 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 | dry-run merge. Display an improved merge-summary message at the end of the merge. * Add options to "fossil commit" to override the various sanity checks. Options added: --allow-empty, --allow-fork, --allow-older, and --allow-conflict. * Optionally require a CAPTCHA (controlled by a setting on the Admin/Access webpage) when a user who is not logged in tries to edit wiki, or a ticket, or an attachment. * Improvements to the "ssh://" sync protocol, to help it move past noisey motd comments. * Add the uf=FILE-SHA1-HASH query parameter to the timeline, causing the timeline to show only check-ins that contain the specific file identified by FILE-SHA1-HASH. ("uf" stands for "uses file".) * Enhance the file change annotator so that it follows the file across name changes. |
︙ | ︙ | |||
311 312 313 314 315 316 317 | * Added the "fossil all changes" command * Added the --ckout option to the "fossil all list" command * Added the "public-pages" glob pattern that can be configured to allow anonymous users to see embedded documentation on sites where source code should not be accessible to anonymous users. * Allow multiple --tag options on the same "fossil commit" command. * Change the meaning of the --bgcolor option for "fossil commit" to only | | | | | | | | | | | 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 | * Added the "fossil all changes" command * Added the --ckout option to the "fossil all list" command * Added the "public-pages" glob pattern that can be configured to allow anonymous users to see embedded documentation on sites where source code should not be accessible to anonymous users. * Allow multiple --tag options on the same "fossil commit" command. * Change the meaning of the --bgcolor option for "fossil commit" to only change the color for that one commit. The new --branchcolor option is available to set a persistent background color. * Add the branch= query parameter to the vdiff page and the --branch option to the "fossil diff" command. * Check-in names of the form "root:BRANCH" now refer to the origin of the branch. Hence to see all changes in a branch, use "fossil diff --from root:BRANCH --to BRANCH". The --branch option on the diff command is an alias for the same. * Add the ability to configure ad-units to be displayed between the menu bar and the content. * Add the ability to set a background image as part of server configuration. * Allow partial commits of cherrypick merges. * Updates against an uncommitted merge are now a warning, not a fatal error. * Prompt the user to continue if a check-in comment is unedited. * Fixes to case sensitivity settings with the /dir webpage. * Repositories now try to remember the locations of all checkouts and web-access URLs and display this information with the "fossil info $REPO" command. * Improved defense against spiders: The src= attribute of <a> elements is set using javascript after the page loads. * Enhanced formatting of the user list page. * If a file named in "fossil add" is missing, that is now a warning instead of a fatal error. * Fix side-by-side diff so that it displays correctly with multi-byte UTF8 characters. * Performance improvements in the diff logic. * Other performance tweaks and documentation updates. <h2>Changes For Version 1.22 (2012-03-17)</h2> * Greatly improved "diff" processing including the new --brief option, partial line matching, colorized in-line diffs, and better performance. * Promote "allow-symlinks" to a versionable setting * Harden the CGI processing logic against DOS attacks * Add the ability to run TH1 scripts after sync requests * Store the repository name in _FOSSIL_ as it is type in the "open" command, possibly as a relative pathname. * Make ".fslckout" the alternative name for the "_FOSSIL_" file. * Change the "ssh:" transfer method to allow all access regardless of user permission. * Improvements to the timeline messages associated with tag changes. (Requires a "[/help/rebuild | fossil rebuild]" to take effect.) * Various additions and fixes for the JSON API. * Improved merge-with-rename handling. * --cherrypick merges use their origin's commit message by default. * Added support for multiple concurrent logins per user. * Update to use SQLite version 3.7.11. * Various minor bug fixes. <h2>Changes For Version 1.21 (2011-12-13)</h2> * Added side-by-side diffs in the command-line interface * Automatically enable hyperlinks if the UserAgent string in the HTTP header suggests that the requestor is a human and not a bot. * Show only commonly used commands with "fossil help". Use "fossil help --all" to see the complete list now. * Improvements to the "stash" command: (1) Stash all files, not just those below the working directory. (2) Add the --detail option to "list". (3) Confirm before "drop --all". (4) Add the "help" subcommand. * Add an Admin/Access setting to change the number of octets of the IP address that are saved in login cookies - allowing this setting to be changed to zero * Promote the "test-md5sum" command to "md5sum". * Added the "whatis" command. * Stop showing the server-code in status outputs - it is no longer used |
︙ | ︙ | |||
390 391 392 393 394 395 396 | <h2>Changes For Version 1.20 (2011-10-21)</h2> * Added side-by-side diffs in HTML interface. [0bde74ea1e] * Added support for symlinks. (Controlled by "allow-symlinks" setting, off by default). [e4f1c1fe95] * Fixed CLI annotate to show the proper file version in case there are multiple equal versions in history. [e161670939] | | | | 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 | <h2>Changes For Version 1.20 (2011-10-21)</h2> * Added side-by-side diffs in HTML interface. [0bde74ea1e] * Added support for symlinks. (Controlled by "allow-symlinks" setting, off by default). [e4f1c1fe95] * Fixed CLI annotate to show the proper file version in case there are multiple equal versions in history. [e161670939] * Timeline now shows tag changes (requires rebuild).[87540ed6e6] * Fixed annotate to show "more relevant" versions of lines in some cases. [e161670939] * New command: ticket history. [98a855c508] * Disabled SSLv2 in HTTPS client.[ea1d369d23] * Fixed constant prompting regarding previously-saved SSL certificates. [636804745b] * Other SSL improvements. * Added -R REPOFILE support to several more CLI commands. [e080560378] * Generated tarballs now have constant timestamps, so they are always identical for any given checkin. [e080560378] * A number of minor HTML-related tweaks and fixes. * Added --args FILENAME global CLI argument to import arbitrary CLI arguments from a file (e.g. long file lists). [e080560378] * Fixed significant memory leak in annotation of files with long histories.[9929bab702] * Added warnings when a merge operation overwrites local copies (UNDO is available, but previously this condition normally went silently unnoticed). [39f979b08c] * Improved performance when adding many files. [a369dc7721] * Improve merges which contain many file renames. [0b93b0f958] * Added protection against timing attacks. [d4a341b49d] * Firefox now remembers filled fields when returning to forms. [3fac77d7b0] |
︙ | ︙ |
Changes to www/fileformat.wiki.
︙ | ︙ | |||
136 137 138 139 140 141 142 | <blockquote> <i>YYYY</i><b>-</b><i>MM</i><b>-</b><i>DD</i><b>T</b><i>HH</i><b>:</b><i>MM</i><b>:</b><i>SS</i><br> <i>YYYY</i><b>-</b><i>MM</i><b>-</b><i>DD</i><b>T</b><i>HH</i><b>:</b><i>MM</i><b>:</b><i>SS</i><b>.</b><i>SSS</i> </blockquote> A manifest has zero or more F-cards. Each F-card identifies a file | | > | | | | | | | | | | < | | | < | | > | | | | 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 | <blockquote> <i>YYYY</i><b>-</b><i>MM</i><b>-</b><i>DD</i><b>T</b><i>HH</i><b>:</b><i>MM</i><b>:</b><i>SS</i><br> <i>YYYY</i><b>-</b><i>MM</i><b>-</b><i>DD</i><b>T</b><i>HH</i><b>:</b><i>MM</i><b>:</b><i>SS</i><b>.</b><i>SSS</i> </blockquote> A manifest has zero or more F-cards. Each F-card identifies a file that is part of the check-in. There are one, two, three, or four arguments. The first argument is the pathname of the file in the check-in relative to the root of the project file hierarchy. No ".." or "." directories are allowed within the filename. Space characters are escaped as in C-card comment text. Backslash characters and newlines are not allowed within filenames. The directory separator character is a forward slash (ASCII 0x2F). The second argument to the F-card is the full 40-character lower-case hexadecimal SHA1 hash of the content artifact. The second argument is required for baseline manifests but is optional for delta manifests. When the second argument to the F-card is omitted, it means that the file has been deleted relative to the baseline. The optional 3rd argument defines any special access permissions associated with the file. The only special code currently defined is "x" which means that the file is executable. All files are always readable and writable. This can be expressed by "w" permission if desired but is optional. The file format might be extended with new permission letters in the future. The optional 4th argument is the name of the same file as it existed in the parent check-in. If the name of the file is unchanged from its parent, then the 4th argument is omitted. A manifest has zero or one N-cards. The N-card specifies the mimetype for the text in the comment of the C-card. If the N-card is omitted, a default mimetype is used. A manifest has zero or one P-cards. Most manifests have one P-card. The P-card has a varying number of arguments that |
︙ | ︙ |
Changes to www/index.wiki.
︙ | ︙ | |||
21 22 23 24 25 26 27 | <li> [./build.wiki | Install] <li> [../COPYRIGHT-BSD2.txt | License] <li> [/timeline | Recent changes] <li> [./faq.wiki | FAQ] <li> [./hacker-howto.wiki | Hacker How-To] <li> [./changes.wiki | Change Log] <li> [./hints.wiki | Tip & Hints] | | | 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | <li> [./build.wiki | Install] <li> [../COPYRIGHT-BSD2.txt | License] <li> [/timeline | Recent changes] <li> [./faq.wiki | FAQ] <li> [./hacker-howto.wiki | Hacker How-To] <li> [./changes.wiki | Change Log] <li> [./hints.wiki | Tip & Hints] <li> [./permutedindex.wiki#pindex | Documentation Index] <li> [http://www.fossil-scm.org/schimpf-book/home | Jim Schimpf's book] <li> Mailing list <ul> <li> [http://lists.fossil-scm.org:8080/cgi-bin/mailman/listinfo/fossil-users | sign-up] <li> [http://www.mail-archive.com/fossil-users@lists.fossil-scm.org | archives] <ul> </ul> |
︙ | ︙ |
Changes to www/quickstart.wiki.
︙ | ︙ | |||
118 119 120 121 122 123 124 | </blockquote> <p>Note that Fossil allows you to make multiple check-outs in separate directories from the same repository. This enables you, for example, to do builds from multiple branches or versions at the same time without having to generate extra clones.</p> | < < < < < < < < < < < < < < | 118 119 120 121 122 123 124 125 126 127 128 129 130 131 | </blockquote> <p>Note that Fossil allows you to make multiple check-outs in separate directories from the same repository. This enables you, for example, to do builds from multiple branches or versions at the same time without having to generate extra clones.</p> <h2>Configuring Your Local Repository</h2> <p>When you create a new repository, either by cloning an existing project or create a new project of your own, you usually want to do some local configuration. This is easily accomplished using the web-server that is built into fossil. Start the fossil webserver like this: ([/help/ui | more info])</p> |
︙ | ︙ | |||
239 240 241 242 243 244 245 | <p>The default behavior is for [./concepts.wiki#workflow|autosync] to be turned on. That means that a [/help/pull|pull] automatically occurs when you run [/help/update|update] and a [/help/push|push] happens automatically after you [/help/commit|commit]. So in normal practice, the push, pull, and sync commands are rarely used. But it is important to know about them, all the same.</p> | < < < < < < < < < | 225 226 227 228 229 230 231 232 233 234 235 236 237 238 | <p>The default behavior is for [./concepts.wiki#workflow|autosync] to be turned on. That means that a [/help/pull|pull] automatically occurs when you run [/help/update|update] and a [/help/push|push] happens automatically after you [/help/commit|commit]. So in normal practice, the push, pull, and sync commands are rarely used. But it is important to know about them, all the same.</p> <h2>Branching And Merging</h2> <p>Use the --branch option to the [/help/commit | commit] command to start a new branch. Note that in Fossil, branches are normally created when you commit, not before you start editing. You can use the [/help/branch | branch new] command to create a new branch before you start editing, if you want, but most people just wait |
︙ | ︙ |
Changes to www/server.wiki.
︙ | ︙ | |||
239 240 241 242 243 244 245 | support SSL. </p> <p> For more information, see <a href="./ssl.wiki">Using SSL with Fossil</a>. </p> </blockquote> | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 239 240 241 242 243 244 245 246 | support SSL. </p> <p> For more information, see <a href="./ssl.wiki">Using SSL with Fossil</a>. </p> </blockquote> </blockquote> |
Changes to www/sync.wiki.
︙ | ︙ | |||
354 355 356 357 358 359 360 | <li> project-name <li> project-description <li> manifest <li> index-page <ul></td><td valign="top"><ul> <li> timeline-block-markup <li> timeline-max-comment | < < < > | 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 | <li> project-name <li> project-description <li> manifest <li> index-page <ul></td><td valign="top"><ul> <li> timeline-block-markup <li> timeline-max-comment <li> ticket-table <li> ticket-common <li> ticket-newpage <li> ticket-viewpage <li> ticket-editpage <li> ticket-reportlist <li> ticket-report-template <ul></td><td valign="top"><ul> <li> ticket-key-template <li> ticket-title-expr <li> ticket-closed-expr <li> @reportfmt <li> @user <li> @concealed <li> @shun |
︙ | ︙ |