Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
| Comment: | merge cleanX |
|---|---|
| Downloads: | Tarball | ZIP archive |
| Timelines: | family | ancestors | descendants | both | cleanX-no-clean-glob |
| Files: | files | file ages | folders |
| SHA1: |
8b97e37e26eeea0e4b930280d4e98a36 |
| User & Date: | jan.nijtmans 2014-02-21 15:02:45.549 |
Context
|
2014-03-23
| ||
| 17:15 | merge cleanX check-in: 1d54c02400 user: jan.nijtmans tags: cleanX-no-clean-glob | |
|
2014-02-21
| ||
| 15:02 | merge cleanX check-in: 8b97e37e26 user: jan.nijtmans tags: cleanX-no-clean-glob | |
| 14:46 | merge trunk check-in: f93b4b4db4 user: jan.nijtmans tags: cleanX | |
|
2013-10-30
| ||
| 10:53 | merge cleanX branch changes (which all come from trunk) check-in: 6934dd3cc0 user: jan.nijtmans tags: cleanX-no-clean-glob | |
Changes
Changes to .fossil-settings/ignore-glob.
| ︙ | ︙ | |||
15 16 17 18 19 20 21 | win/*.exe win/headers win/linkopts autoconfig.h config.log fossil fossil.exe | > | 15 16 17 18 19 20 21 22 | win/*.exe win/headers win/linkopts autoconfig.h config.log fossil fossil.exe win/fossil.exe |
Changes to .fossil-settings/keep-glob.
1 2 3 4 | compat/openssl* compat/tcl* fossil fossil.exe | > | 1 2 3 4 5 | compat/openssl* compat/tcl* fossil fossil.exe win/fossil.exe |
Added Makefile.Cygwin.in.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | #!/usr/bin/make # # This is the top-level makefile for Fossil when the build is occurring # on the Cygwin platform. # #### The toplevel directory of the source tree. Fossil can be built # in a directory that is separate from the source tree. Just change # the following to point from the build directory to the src/ folder. # SRCDIR = @srcdir@/src #### The directory into which object code files should be written. # Having a "./" prefix in the value of this variable breaks our use of the # "makeheaders" tool when running make on the MinGW platform, apparently # due to some command line argument manipulation performed automatically # by the shell. # # OBJDIR = bld #### C Compiler and options for use in building executables that # will run on the platform that is doing the build. This is used # to compile code-generator programs as part of the build process. # See TCC below for the C compiler for building the finished binary. # BCC = @CC_FOR_BUILD@ #### The suffix to add to final executable file. When cross-compiling # to windows, make this ".exe". Otherwise leave it blank. # E = @EXEEXT@ TCC = @CC@ #### 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 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 -DSQLITE_WINNT_MAX_PATH_CHARS=4096 include $(SRCDIR)/main.mk distclean: clean rm -f autoconfig.h config.log Makefile |
Changes to auto.def.
| ︙ | ︙ | |||
26 27 28 29 30 31 32 | define USE_PREAD [cc-check-functions pread] # Find tclsh for the test suite. Can't yet use jimsh for this. cc-check-progs tclsh define EXTRA_CFLAGS "" define EXTRA_LDFLAGS "" | | | | | | | | 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 |
define USE_PREAD [cc-check-functions pread]
# Find tclsh for the test suite. Can't yet use jimsh for this.
cc-check-progs tclsh
define EXTRA_CFLAGS ""
define EXTRA_LDFLAGS ""
define USE_SYSTEM_SQLITE 0
if {![opt-bool internal-sqlite]} {
proc find_internal_sqlite {} {
# On some systems (slackware), libsqlite3 requires -ldl to link. So
# search for the system SQLite once with -ldl, and once without. If
# the library can only be found with $extralibs set to -ldl, then
# the code below will append -ldl to LIBS.
#
foreach extralibs {{} {-ldl}} {
# Locate the system SQLite by searching for sqlite3_open(). Then check
# if sqlite3_strglob() can be found as well. If we can find open() but
# not strglob(), then the system SQLite is too old to link against
# fossil.
#
if {[cc-check-function-in-lib sqlite3_open sqlite3 $extralibs]} {
if {![cc-check-function-in-lib sqlite3_strglob sqlite3 $extralibs]} {
user-error "system sqlite3 too old (require >= 3.7.17)"
}
# Success. Update symbols and return.
#
define USE_SYSTEM_SQLITE 1
define-append LIBS $extralibs
return
|
| ︙ | ︙ | |||
87 88 89 90 91 92 93 |
#}
if {[opt-bool static]} {
# XXX: This will not work on all systems.
define-append EXTRA_LDFLAGS -static
}
| < < < < < < < < < < < | 87 88 89 90 91 92 93 94 95 96 97 98 99 100 |
#}
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} {
set tclconfig(TCL_INCLUDE_SPEC) -Icompat/tcl-8.6/generic
|
| ︙ | ︙ | |||
224 225 226 227 228 229 230 231 232 233 234 235 236 237 |
define-append EXTRA_CFLAGS -Wdeprecated-declarations
}
}
} 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]} {
| > > > > > > > > > > > | 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 |
define-append EXTRA_CFLAGS -Wdeprecated-declarations
}
}
} else {
user-error "OpenSSL not found. Consider --with-openssl=none to disable HTTPS support"
}
}
# 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"
}
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]} {
|
| ︙ | ︙ | |||
255 256 257 258 259 260 261 262 |
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-config-header autoconfig.h -auto {USE_* FOSSIL_*}
| > | 255 256 257 258 259 260 261 262 263 |
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.
| ︙ | ︙ | |||
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 |
** with "." are excluded by default. To include such files, add
** the "--dotfiles" option to the command-line.
**
** The --ignore option is a 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.
**
** 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.
**
** 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 *zIgnoreFlag; /* The --ignore option or ignore-glob setting */
Glob *pIgnore; /* Ignore everything matching the glob patterns */
unsigned scanFlags = 0; /* Flags passed to vfile_scan() */
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( zIgnoreFlag==0 ){
zIgnoreFlag = db_get("ignore-glob", 0);
}
vid = db_lget_int("checkout",0);
db_begin_transaction();
db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY %s)",
filename_collation());
pIgnore = glob_create(zIgnoreFlag);
nRoot = strlen(g.zLocalRoot);
/* Load the names of all files that are to be added into sfile temp table */
for(i=2; i<g.argc; i++){
char *zName;
int isDir;
Blob fullName;
file_canonical_name(g.argv[i], &fullName, 0);
zName = blob_str(&fullName);
isDir = file_wd_isdir(zName);
if( isDir==1 ){
vfile_scan(&fullName, nRoot-1, scanFlags, 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);
}
| > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 |
** with "." are excluded by default. To include such files, add
** the "--dotfiles" option to the command-line.
**
** The --ignore option is a 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 files are attempted to be added explicitly on the command line which
** match "ignore-glob", a confirmation is asked first. This can be prevented
** using the -f|--force option.
**
** The --case-sensitive option determines whether or not filenames should
** be treated case sensitive or not. If the option is not given, the default
** depends on the global setting, or the operating system default, if not set.
**
** Options:
**
** --case-sensitive <BOOL> override case-sensitive setting
** --dotfiles include files beginning with a dot (".")
** -f|--force Add files without prompting
** --ignore <CSG> 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 *zIgnoreFlag; /* The --ignore option or ignore-glob setting */
Glob *pIgnore; /* Ignore everything matching the glob patterns */
unsigned scanFlags = 0; /* Flags passed to vfile_scan() */
int forceFlag;
zIgnoreFlag = find_option("ignore",0,1);
forceFlag = find_option("force","f",0)!=0;
if( find_option("dotfiles",0,0)!=0 ) scanFlags |= SCAN_ALL;
capture_case_sensitive_option();
db_must_be_within_tree();
if( zIgnoreFlag==0 ){
zIgnoreFlag = db_get("ignore-glob", 0);
}
vid = db_lget_int("checkout",0);
db_begin_transaction();
db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY %s)",
filename_collation());
pIgnore = glob_create(zIgnoreFlag);
nRoot = strlen(g.zLocalRoot);
/* Load the names of all files that are to be added into sfile temp table */
for(i=2; i<g.argc; i++){
char *zName;
int isDir;
Blob fullName;
/* file_tree_name() throws a fatal error if g.argv[i] is outside of the
** checkout. */
file_tree_name(g.argv[i], &fullName, 1);
blob_reset(&fullName);
file_canonical_name(g.argv[i], &fullName, 0);
zName = blob_str(&fullName);
isDir = file_wd_isdir(zName);
if( isDir==1 ){
vfile_scan(&fullName, nRoot-1, scanFlags, 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];
if( !forceFlag && glob_match(pIgnore, zTreeName) ){
Blob ans;
char cReply;
char *prompt = mprintf("file \"%s\" matches \"ignore-glob\". "
"Add it (a=all/y/N)? ", zTreeName);
prompt_user(prompt, &ans);
cReply = blob_str(&ans)[0];
blob_reset(&ans);
if( cReply=='a' || cReply=='A' ){
forceFlag = 1;
}else if( cReply!='y' && cReply!='Y' ){
blob_reset(&fullName);
continue;
}
}
db_multi_exec(
"INSERT OR IGNORE INTO sfile(x) VALUES(%Q)",
zTreeName
);
}
blob_reset(&fullName);
}
|
| ︙ | ︙ | |||
304 305 306 307 308 309 310 |
** Options:
** --case-sensitive <BOOL> override case-sensitive setting
**
** See also: addremove, add
*/
void delete_cmd(void){
int i;
| < < < < < | 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 |
** Options:
** --case-sensitive <BOOL> override case-sensitive setting
**
** See also: addremove, add
*/
void delete_cmd(void){
int i;
Stmt loop;
capture_case_sensitive_option();
db_must_be_within_tree();
db_begin_transaction();
db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY %s)",
filename_collation());
for(i=2; i<g.argc; i++){
Blob treeName;
char *zTreeName;
|
| ︙ | ︙ | |||
532 533 534 535 536 537 538 |
/*
** Rename a single file.
**
** The original name of the file is zOrig. The new filename is zNew.
*/
static void mv_one_file(int vid, const char *zOrig, const char *zNew){
int x = db_int(-1, "SELECT deleted FROM vfile WHERE pathname=%Q %s",
| | | 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 |
/*
** Rename a single file.
**
** The original name of the file is zOrig. The new filename is zNew.
*/
static void mv_one_file(int vid, const char *zOrig, const char *zNew){
int x = db_int(-1, "SELECT deleted FROM vfile WHERE pathname=%Q %s",
zNew, filename_collation());
if( x>=0 ){
if( x==0 ){
fossil_fatal("cannot rename '%s' to '%s' since another file named '%s'"
" is currently under management", zOrig, zNew, zNew);
}else{
fossil_fatal("cannot rename '%s' to '%s' since the delete of '%s' has "
"not yet been committed", zOrig, zNew, zNew);
|
| ︙ | ︙ |
Changes to src/allrepo.c.
| ︙ | ︙ | |||
139 140 141 142 143 144 145 |
char *zQFilename;
Blob extra;
int useCheckouts = 0;
int quiet = 0;
int dryRunFlag = 0;
int stopOnError = find_option("dontstop",0,0)==0;
int rc;
| | | 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 |
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 ){
|
| ︙ | ︙ | |||
241 242 243 244 245 246 247 |
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,
| | | | | | < | < | < | < > > > | 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 |
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"
" WHERE substr(name, 1, 6)=='ckout:'"
" ORDER BY 1"
);
}else{
db_prepare(&q,
"SELECT DISTINCT substr(name, 6), name COLLATE nocase"
" FROM global_config"
" WHERE substr(name, 1, 5)=='repo:'"
" ORDER BY 1"
);
}
db_multi_exec("CREATE TEMP TABLE todel(x TEXT)");
while( db_step(&q)==SQLITE_ROW ){
const char *zFilename = db_column_text(&q, 0);
if( file_access(zFilename, 0)
|| !file_is_canonical(zFilename)
|| (useCheckouts && file_isdir(zFilename)!=1)
){
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);
|
| ︙ | ︙ | |||
289 290 291 292 293 294 295 |
}
}
db_finalize(&q);
/* If any repositories whose names appear in the ~/.fossil file could not
** be found, remove those names from the ~/.fossil file.
*/
| | < < < < | < < < < < | | < | 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 |
}
}
db_finalize(&q);
/* If any repositories whose names appear in the ~/.fossil file could not
** be found, remove those names from the ~/.fossil file.
*/
if( nToDel>0 ){
const char *zSql = "DELETE FROM global_config WHERE name IN toDel";
if( dryRunFlag ){
fossil_print("%s\n", zSql);
}else{
db_multi_exec(zSql);
}
}
}
|
Changes to src/attach.c.
| ︙ | ︙ | |||
38 39 40 41 42 43 44 |
const char *zTkt = P("tkt");
Blob sql;
Stmt q;
if( zPage && zTkt ) zTkt = 0;
login_check_credentials();
blob_zero(&sql);
| | | < > | 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
const char *zTkt = P("tkt");
Blob sql;
Stmt q;
if( zPage && zTkt ) zTkt = 0;
login_check_credentials();
blob_zero(&sql);
blob_appendf(&sql,
"SELECT datetime(mtime%s), src, target, filename,"
" comment, user,"
" (SELECT uuid FROM blob WHERE rid=attachid), attachid"
" FROM attachment",
timeline_utc()
);
if( zPage ){
if( g.perm.RdWiki==0 ) login_needed();
style_header("Attachments To %h", zPage);
blob_appendf(&sql, " WHERE target=%Q", zPage);
}else if( zTkt ){
if( g.perm.RdTkt==0 ) login_needed();
|
| ︙ | ︙ | |||
212 213 214 215 216 217 218 |
rid, attachRid
);
}else{
rid = content_put(pAttach);
db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d);", rid);
db_multi_exec("INSERT OR IGNORE INTO unclustered VALUES(%d);", rid);
}
| | | 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 |
rid, attachRid
);
}else{
rid = content_put(pAttach);
db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d);", rid);
db_multi_exec("INSERT OR IGNORE INTO unclustered VALUES(%d);", rid);
}
manifest_crosslink(rid, pAttach, MC_NONE);
}
/*
** WEBPAGE: attachadd
**
** tkt=TICKETUUID
|
| ︙ | ︙ | |||
429 430 431 432 433 434 435 |
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);
| | | 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 |
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>
}
if( P("del")
&& ((zTktUuid && g.perm.WrTkt) || (zWikiName && g.perm.WrWiki))
){
|
| ︙ | ︙ | |||
551 552 553 554 555 556 557 |
void attachment_list(
const char *zTarget, /* Object that things are attached to */
const char *zHeader /* Header to display with attachments */
){
int cnt = 0;
Stmt q;
db_prepare(&q,
| | | | 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 |
void attachment_list(
const char *zTarget, /* Object that things are attached to */
const char *zHeader /* Header to display with attachments */
){
int cnt = 0;
Stmt q;
db_prepare(&q,
"SELECT datetime(mtime%s), filename, user,"
" (SELECT uuid FROM blob WHERE rid=attachid), src"
" FROM attachment"
" WHERE isLatest AND src!='' AND target=%Q"
" ORDER BY mtime DESC",
timeline_utc(), zTarget
);
while( db_step(&q)==SQLITE_ROW ){
const char *zDate = db_column_text(&q, 0);
const char *zFile = db_column_text(&q, 1);
const char *zUser = db_column_text(&q, 2);
const char *zUuid = db_column_text(&q, 3);
const char *zSrc = db_column_text(&q, 4);
|
| ︙ | ︙ |
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.
| ︙ | ︙ | |||
221 222 223 224 225 226 227 228 229 230 231 232 233 234 |
/*
** 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);
| > > > > > > > > > | 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 |
/*
** 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 a nul-terminated string obtained from fossil_malloc().
** The blob will take responsibility for freeing the string.
*/
void blob_set_dynamic(Blob *pBlob, char *zStr){
blob_init(pBlob, zStr, -1);
pBlob->xRealloc = blobReallocMalloc;
}
/*
** Initialize a blob to an empty string.
*/
void blob_zero(Blob *pBlob){
static const char zEmpty[] = "";
assert_blob_is_reset(pBlob);
|
| ︙ | ︙ | |||
1093 1094 1095 1096 1097 1098 1099 |
** 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;
| < < < < | < < | 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 |
** 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);
blob_set_dynamic(pBlob, zUtf8);
#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.
| ︙ | ︙ | |||
49 50 51 52 53 54 55 |
zDateOvrd = find_option("date-override",0,1);
zUserOvrd = find_option("user-override",0,1);
verify_all_options();
if( g.argc<5 ){
usage("new BRANCH-NAME BASIS ?OPTIONS?");
}
db_find_and_open_repository(0, 0);
| | > | 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
zDateOvrd = find_option("date-override",0,1);
zUserOvrd = find_option("user-override",0,1);
verify_all_options();
if( g.argc<5 ){
usage("new BRANCH-NAME BASIS ?OPTIONS?");
}
db_find_and_open_repository(0, 0);
noSign = db_get_boolean("omitsign", 0)|noSign;
if( db_get_boolean("clearsign", 0)==0 ){ noSign = 1; }
/* fossil branch new name */
zBranch = g.argv[3];
if( zBranch==0 || zBranch[0]==0 ){
fossil_fatal("branch name cannot be empty");
}
if( db_exists(
|
| ︙ | ︙ | |||
137 138 139 140 141 142 143 |
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;
| < | | | 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 |
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;
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);
}
}
brid = content_put_ex(&branch, 0, 0, 0, isPrivate);
if( brid==0 ){
fossil_fatal("trouble committing manifest: %s", g.zErrMsg);
}
db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", brid);
if( manifest_crosslink(brid, &branch, MC_PERMIT_HOOKS)==0 ){
fossil_fatal("%s\n", g.zErrMsg);
}
assert( blob_is_reset(&branch) );
content_deltify(rootid, brid, 0);
zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", brid);
fossil_print("New branch: %s\n", zUuid);
if( g.argc==3 ){
fossil_print(
|
| ︙ | ︙ | |||
365 366 367 368 369 370 371 |
@ <li>%z(href("%R/timeline?r=%T",zBr))%h(zBr)</a></li>
}
}
if( cnt ){
@ </ul>
}
db_finalize(&q);
| < < < < < < | 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.
|
| ︙ | ︙ | |||
420 421 422 423 424 425 426 |
"%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);
| < < < < < < | 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();
}
|
Changes to src/browse.c.
| ︙ | ︙ | |||
69 70 71 72 73 74 75 | ** to the "dir" page for the directory. ** ** There is no hyperlink on the file element of the path. ** ** The computed string is appended to the pOut blob. pOut should ** have already been initialized. */ | | > > > > > > | | | | > > > > > > | < | | < < < < > | | > | | | < > | < < < < > > > > | 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 |
** to the "dir" page for the directory.
**
** There is no hyperlink on the file element of the path.
**
** The computed string is appended to the pOut blob. pOut should
** have already been initialized.
*/
void hyperlinked_path(
const char *zPath, /* Path to render */
Blob *pOut, /* Write into this blob */
const char *zCI, /* check-in name, or NULL */
const char *zURI, /* "dir" or "tree" */
const char *zREx /* Extra query parameters */
){
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]);
}
}else{
blob_appendf(pOut, "%s%#h", zSep, j-i, &zPath[i]);
}
zSep = "/";
while( zPath[j]=='/' ){ j++; }
}
}
/*
** WEBPAGE: dir
**
** Query parameters:
**
** name=PATH Directory to display. Optional. Top-level if missing
** ci=LABEL Show only files in this check-in. Optional.
*/
void page_dir(void){
char *zD = fossil_strdup(P("name"));
int nD = zD ? strlen(zD)+1 : 0;
int mxLen;
int nCol, nRow;
int cnt, i;
char *zPrefix;
Stmt q;
const char *zCI = P("ci");
int rid = 0;
char *zUuid = 0;
Blob dirname;
Manifest *pM = 0;
const char *zSubdirLink;
int linkTrunk = 1;
int linkTip = 1;
HQuery sURI;
if( strcmp(PD("type",""),"tree")==0 ){ page_tree(); return; }
login_check_credentials();
if( !g.perm.Read ){ login_needed(); return; }
while( nD>1 && zD[nD-2]=='/' ){ zD[(--nD)-1] = 0; }
style_header("File List");
sqlite3_create_function(g.db, "pathelement", 2, SQLITE_UTF8, 0,
pathelementFunc, 0, 0);
url_initialize(&sURI, "dir");
/* If the name= parameter is an empty string, make it a NULL pointer */
if( zD && strlen(zD)==0 ){ zD = 0; }
/* If a specific check-in is requested, fetch and parse it. If the
** specific check-in does not exist, clear zCI. zCI==0 will cause all
** files from all check-ins to be displayed.
*/
if( zCI ){
pM = manifest_get_by_name(zCI, &rid);
if( pM ){
int trunkRid = symbolic_name_to_rid("tag:trunk", "ci");
linkTrunk = trunkRid && rid != trunkRid;
linkTip = rid != symbolic_name_to_rid("tip", "ci");
zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
url_add_parameter(&sURI, "ci", zCI);
}else{
zCI = 0;
}
}
/* Compute the title of the page */
blob_zero(&dirname);
if( zD ){
url_add_parameter(&sURI, "name", zD);
blob_append(&dirname, "in directory ", -1);
hyperlinked_path(zD, &dirname, zCI, "dir", "");
zPrefix = mprintf("%s/", zD);
style_submenu_element("Top-Level", "Top-Level", "%s",
url_render(&sURI, "name", 0, 0, 0));
}else{
blob_append(&dirname, "in the top-level directory", -1);
zPrefix = "";
}
if( linkTrunk ){
style_submenu_element("Trunk", "Trunk", "%s",
url_render(&sURI, "ci", "trunk", 0, 0));
}
if( linkTip ){
style_submenu_element("Tip", "Tip", "%s",
url_render(&sURI, "ci", "tip", 0, 0));
}
if( 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);
}
style_submenu_element("All", "All", "%s",
url_render(&sURI, "ci", 0, 0, 0));
style_submenu_element("Tree-View", "Tree-View", "%s",
url_render(&sURI, "type", "tree", 0, 0));
/* Compute the temporary table "localfiles" containing the names
** of all files and subdirectories in the zD[] directory.
**
** Subdirectory names begin with "/". This causes them to sort
** first and it also gives us an easy way to distinguish files
** from directories in the loop that follows.
|
| ︙ | ︙ | |||
285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 |
}
}
db_finalize(&q);
manifest_destroy(pM);
@ </ul></td></tr></table>
style_footer();
}
/*
** Return a CSS class name based on the given filename's extension.
** Result must be freed by the caller.
**/
const char *fileext_class(const char *zFilename){
char *zClass;
const char *zExt = strrchr(zFilename, '.');
int isExt = zExt && zExt!=zFilename && zExt[1];
int i;
for( i=1; isExt && zExt[i]; i++ ) isExt &= fossil_isalnum(zExt[i]);
if( isExt ){
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 |
}
}
db_finalize(&q);
manifest_destroy(pM);
@ </ul></td></tr></table>
style_footer();
}
/*
** Objects used by the "tree" webpage.
*/
typedef struct FileTreeNode FileTreeNode;
typedef struct FileTree FileTree;
/*
** A single line of the file hierarchy
*/
struct FileTreeNode {
FileTreeNode *pNext; /* Next line in sequence */
FileTreeNode *pPrev; /* Previous line */
FileTreeNode *pParent; /* Directory containing this line */
char *zName; /* Name of this entry. The "tail" */
char *zFullName; /* Full pathname of this entry */
char *zUuid; /* SHA1 hash of this file. May be NULL. */
unsigned nFullName; /* Length of zFullName */
unsigned iLevel; /* Levels of parent directories */
u8 isDir; /* True if there are children */
u8 isLast; /* True if this is the last child of its parent */
};
/*
** A complete file hierarchy
*/
struct FileTree {
FileTreeNode *pFirst; /* First line of the list */
FileTreeNode *pLast; /* Last line of the list */
};
/*
** Add one or more new FileTreeNodes to the FileTree object so that the
** leaf object zPathname is at the end of the node list
*/
static void tree_add_node(
FileTree *pTree, /* Tree into which nodes are added */
const char *zPath, /* The full pathname of file to add */
const char *zUuid /* UUID of the file. Might be NULL. */
){
int i;
FileTreeNode *pParent;
FileTreeNode *pChild;
pChild = pTree->pLast;
pParent = pChild ? pChild->pParent : 0;
while( pParent!=0 &&
( strncmp(pParent->zFullName, zPath, pParent->nFullName)!=0
|| zPath[pParent->nFullName]!='/' )
){
pChild = pParent;
pParent = pChild->pParent;
}
i = pParent ? pParent->nFullName+1 : 0;
if( pChild ) pChild->isLast = 0;
while( zPath[i] ){
FileTreeNode *pNew;
int iStart = i;
int nByte;
while( zPath[i] && zPath[i]!='/' ){ i++; }
nByte = sizeof(*pNew) + i + 1;
if( zUuid!=0 && zPath[i]==0 ) nByte += UUID_SIZE+1;
pNew = fossil_malloc( nByte );
pNew->zFullName = (char*)&pNew[1];
memcpy(pNew->zFullName, zPath, i);
pNew->zFullName[i] = 0;
pNew->nFullName = i;
if( zUuid!=0 && zPath[i]==0 ){
pNew->zUuid = pNew->zFullName + i + 1;
memcpy(pNew->zUuid, zUuid, UUID_SIZE+1);
}else{
pNew->zUuid = 0;
}
pNew->zName = pNew->zFullName + iStart;
if( pTree->pLast ){
pTree->pLast->pNext = pNew;
}else{
pTree->pFirst = pNew;
}
pNew->pPrev = pTree->pLast;
pNew->pNext = 0;
pNew->pParent = pParent;
pTree->pLast = pNew;
pNew->iLevel = pParent ? pParent->iLevel+1 : 0;
pNew->isDir = zPath[i]=='/';
pNew->isLast = 1;
while( zPath[i]=='/' ){ i++; }
pParent = pNew;
}
}
/*
** WEBPAGE: tree
**
** Query parameters:
**
** name=PATH Directory to display. Optional
** ci=LABEL Show only files in this check-in. Optional.
** re=REGEXP Show only files matching REGEXP. Optional.
** expand Begin with the tree fully expanded.
** nofiles Show directories (folders) only. Omit files.
*/
void page_tree(void){
char *zD = fossil_strdup(P("name"));
int nD = zD ? strlen(zD)+1 : 0;
const char *zCI = P("ci");
int rid = 0;
char *zUuid = 0;
Blob dirname;
Manifest *pM = 0;
int nFile = 0; /* Number of files (or folders with "nofiles") */
int linkTrunk = 1; /* include link to "trunk" */
int linkTip = 1; /* include link to "tip" */
const char *zRE; /* the value for the re=REGEXP query parameter */
const char *zObjType; /* "files" by default or "folders" for "nofiles" */
char *zREx = ""; /* Extra parameters for path hyperlinks */
ReCompiled *pRE = 0; /* Compiled regular expression */
FileTreeNode *p; /* One line of the tree */
FileTree sTree; /* The complete tree of files */
HQuery sURI; /* Hyperlink */
int startExpanded; /* True to start out with the tree expanded */
int showDirOnly; /* Show directories only. Omit files */
int nDir = 0; /* Number of directories. Used for ID attributes */
char *zProjectName = db_get("project-name", 0);
if( strcmp(PD("type",""),"flat")==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; }
sqlite3_create_function(g.db, "pathelement", 2, SQLITE_UTF8, 0,
pathelementFunc, 0, 0);
url_initialize(&sURI, "tree");
if( P("nofiles")!=0 ){
showDirOnly = 1;
url_add_parameter(&sURI, "nofiles", "1");
style_header("Folder Hierarchy");
}else{
showDirOnly = 0;
style_header("File Tree");
}
if( P("expand")!=0 ){
startExpanded = 1;
url_add_parameter(&sURI, "expand", "1");
}else{
startExpanded = 0;
}
/* If a regular expression is specified, compile it */
zRE = P("re");
if( zRE ){
re_compile(&pRE, zRE, 0);
url_add_parameter(&sURI, "re", zRE);
zREx = mprintf("&re=%T", zRE);
}
/* If the name= parameter is an empty string, make it a NULL pointer */
if( zD && strlen(zD)==0 ){ zD = 0; }
/* If a specific check-in is requested, fetch and parse it. If the
** specific check-in does not exist, clear zCI. zCI==0 will cause all
** files from all check-ins to be displayed.
*/
if( zCI ){
pM = manifest_get_by_name(zCI, &rid);
if( pM ){
int trunkRid = symbolic_name_to_rid("tag:trunk", "ci");
linkTrunk = trunkRid && rid != trunkRid;
linkTip = rid != symbolic_name_to_rid("tip", "ci");
zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
url_add_parameter(&sURI, "ci", zCI);
}else{
zCI = 0;
}
}
/* Compute the title of the page */
blob_zero(&dirname);
if( zD ){
url_add_parameter(&sURI, "name", zD);
blob_append(&dirname, "within directory ", -1);
hyperlinked_path(zD, &dirname, zCI, "tree", zREx);
if( zRE ) blob_appendf(&dirname, " matching \"%s\"", zRE);
style_submenu_element("Top-Level", "Top-Level", "%s",
url_render(&sURI, "name", 0, 0, 0));
}else{
if( zRE ){
blob_appendf(&dirname, "matching \"%s\"", zRE);
}
}
if( zCI ){
style_submenu_element("All", "All", "%s",
url_render(&sURI, "ci", 0, 0, 0));
if( nD==0 && !showDirOnly ){
style_submenu_element("File Ages", "File Ages", "%R/fileage?name=%S",
zUuid);
}
}
if( linkTrunk ){
style_submenu_element("Trunk", "Trunk", "%s",
url_render(&sURI, "ci", "trunk", 0, 0));
}
if ( linkTip ){
style_submenu_element("Tip", "Tip", "%s",
url_render(&sURI, "ci", "tip", 0, 0));
}
if( !showDirOnly ){
style_submenu_element("Flat-View", "Flat-View", "%s",
url_render(&sURI, "type", "flat", 0, 0));
}
/* Compute the file hierarchy.
*/
if( zCI ){
Stmt ins, q;
ManifestFile *pFile;
db_multi_exec(
"CREATE TEMP TABLE filelist("
" x TEXT PRIMARY KEY COLLATE nocase,"
" uuid TEXT"
") 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]!='/')
){
continue;
}
if( pRE && re_match(pRE, (const u8*)pFile->zName, -1)==0 ) continue;
db_bind_text(&ins, ":f", pFile->zName);
db_bind_text(&ins, ":u", pFile->zUuid);
db_step(&ins);
db_reset(&ins);
}
db_finalize(&ins);
db_prepare(&q, "SELECT x, uuid FROM filelist ORDER BY x");
while( db_step(&q)==SQLITE_ROW ){
tree_add_node(&sTree, db_column_text(&q,0), db_column_text(&q,1));
nFile++;
}
db_finalize(&q);
}else{
Stmt q;
db_prepare(&q, "SELECT name FROM filename ORDER BY name COLLATE nocase");
while( db_step(&q)==SQLITE_ROW ){
const char *z = db_column_text(&q, 0);
if( nD>0 && (fossil_strncmp(z, zD, nD-1)!=0 || z[nD-1]!='/') ){
continue;
}
if( pRE && re_match(pRE, (const u8*)z, -1)==0 ) continue;
tree_add_node(&sTree, z, 0);
nFile++;
}
db_finalize(&q);
}
if( showDirOnly ){
for(nFile=0, p=sTree.pFirst; p; p=p->pNext){
if( p->isDir && p->nFullName>nD ) nFile++;
}
zObjType = "folders";
style_submenu_element("Files","Files","%s",
url_render(&sURI,"nofiles",0,0,0));
}else{
zObjType = "files";
style_submenu_element("Folders","Folders","%s",
url_render(&sURI,"nofiles","1",0,0));
}
if( zCI ){
@ <h2>%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 last">
}else{
@ <li class="dir subdir last">
}
@ %z(href("%s",url_render(&sURI,"name",0,0,0)))%h(zProjectName)</a>
@ <ul>
for(p=sTree.pFirst, nDir=0; p; p=p->pNext){
const char *zLastClass = p->isLast ? " last" : "";
if( p->isDir ){
const char *zSubdirClass = p->nFullName==nD-1 ? " subdir" : "";
@ <li class="dir%s(zSubdirClass)%s(zLastClass)">
@ %z(href("%s",url_render(&sURI,"name",p->zFullName,0,0)))%h(p->zName)</a>
if( startExpanded || p->nFullName<=nD ){
@ <ul id="dir%d(nDir)">
}else{
@ <ul id="dir%d(nDir)" class="collapsed">
}
nDir++;
}else if( !showDirOnly ){
const char *zFileClass = fileext_class(p->zName);
char *zLink;
if( zCI ){
zLink = href("%R/artifact/%S",p->zUuid);
}else{
zLink = href("%R/finfo?name=%T",p->zFullName);
}
@ <li class="%z(zFileClass)%s(zLastClass)">%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 isExpanded(ul){
@ return ul.className=='';
@ }
@
@ function toggleDir(ul, useInitValue){
@ if( !useInitValue ){
@ expandMap[ul.id] = !isExpanded(ul);
@ history.replaceState(expandMap, '');
@ }
@ ul.className = expandMap[ul.id] ? '' : 'collapsed';
@ }
@
@ function toggleAll(tree, useInitValue){
@ var lists = tree.querySelectorAll('.subdir > ul > li ul');
@ if( !useInitValue ){
@ var expand = true; /* Default action: make all sublists visible */
@ for( var i=0; lists[i]; i++ ){
@ if( isExpanded(lists[i]) ){
@ expand = false; /* Any already visible - make them all hidden */
@ break;
@ }
@ }
@ expandMap = {'*': expand};
@ history.replaceState(expandMap, '');
@ }
@ var className = expandMap['*'] ? '' : 'collapsed';
@ for( var i=0; lists[i]; i++ ){
@ lists[i].className = className;
@ }
@ }
@
@ function checkState(){
@ expandMap = history.state || {};
@ if( '*' in expandMap ) toggleAll(outer_ul, true);
@ for( var id in expandMap ){
@ if( id!=='*' ) toggleDir(gebi(id), true);
@ }
@ }
@
@ function belowSubdir(node){
@ do{
@ node = node.parentNode;
@ if( node==subdir ) return true;
@ } while( node && node!=outer_ul );
@ return false;
@ }
@
@ var history = window.history || {};
@ if( !history.replaceState ) history.replaceState = function(){};
@ var outer_ul = document.querySelector('.filetree > ul');
@ var subdir = outer_ul.querySelector('.subdir');
@ var expandMap = {};
@ checkState();
@ outer_ul.onclick = function(e){
@ e = e || window.event;
@ var a = e.target || e.srcElement;
@ if( a.nodeName!='A' ) return true;
@ if( a.parentNode==subdir ){
@ toggleAll(outer_ul);
@ return false;
@ }
@ if( !belowSubdir(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 */
@ toggleDir(ul);
@ return false;
@ }
@ }())</script>
style_footer();
/* We could free memory used by sTree here if we needed to. But
** the process is about to exit, so doing so would not really accomplish
** anything useful. */
}
/*
** Return a CSS class name based on the given filename's extension.
** Result must be freed by the caller.
**/
const char *fileext_class(const char *zFilename){
char *zClass;
const char *zExt = strrchr(zFilename, '.');
int isExt = zExt && zExt!=zFilename && zExt[1];
int i;
for( i=1; isExt && zExt[i]; i++ ) isExt &= fossil_isalnum(zExt[i]);
if( isExt ){
zClass = mprintf("file file-%s", zExt+1);
for ( i=5; zClass[i]; i++ ) zClass[i] = fossil_tolower(zClass[i]);
}else{
zClass = mprintf("file");
}
return zClass;
}
|
| ︙ | ︙ | |||
402 403 404 405 406 407 408 409 410 411 |
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_header("File Ages", zName);
compute_fileage(rid);
baseTime = db_double(0.0, "SELECT mtime FROM event WHERE objid=%d", rid);
| > | | 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 |
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
@ check-in time for
@ %z(href("%R/info?name=%T",zName))%h(zName)</a></p>
|
| ︙ | ︙ |
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 |
/*
** 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);
}
|
| ︙ | ︙ |
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 279 280 281 282 283 284 285 286 287 288 289 290 291 |
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.
*/
static int is_gzippable(void){
if( strstr(PD("HTTP_ACCEPT_ENCODING", ""), "gzip")==0 ) return 0;
return strncmp(zContentType, "text/", 5)==0
|| strglob("application/*xml", zContentType)
|| strglob("application/*javascript", zContentType);
}
/*
** Do a normal HTTP reply
*/
void cgi_reply(void){
int total_size;
if( iReplyStatus<=0 ){
|
| ︙ | ︙ | |||
346 347 348 349 350 351 352 353 354 355 356 357 358 359 |
fprintf(g.httpOut, "Content-Type: %s; charset=utf-8\r\n", zContentType);
if( fossil_strcmp(zContentType,"application/x-fossil")==0 ){
cgi_combine_header_and_body();
blob_compress(&cgiContent[0], &cgiContent[0]);
}
if( iReplyStatus != 304 ) {
total_size = blob_size(&cgiContent[0]) + blob_size(&cgiContent[1]);
fprintf(g.httpOut, "Content-Length: %d\r\n", total_size);
}else{
total_size = 0;
}
fprintf(g.httpOut, "\r\n");
if( total_size>0 && iReplyStatus != 304 ){
| > > > > > > > > > > > > | 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 |
fprintf(g.httpOut, "Content-Type: %s; charset=utf-8\r\n", zContentType);
if( fossil_strcmp(zContentType,"application/x-fossil")==0 ){
cgi_combine_header_and_body();
blob_compress(&cgiContent[0], &cgiContent[0]);
}
if( iReplyStatus != 304 ) {
if( is_gzippable() ){
int i;
gzip_begin(0);
for( i=0; i<2; i++ ){
int size = blob_size(&cgiContent[i]);
if( size>0 ) gzip_step(blob_buffer(&cgiContent[i]), size);
blob_reset(&cgiContent[i]);
}
gzip_finish(&cgiContent[0]);
fprintf(g.httpOut, "Content-Encoding: gzip\r\n");
fprintf(g.httpOut, "Vary: Accept-Encoding\r\n");
}
total_size = blob_size(&cgiContent[0]) + blob_size(&cgiContent[1]);
fprintf(g.httpOut, "Content-Length: %d\r\n", total_size);
}else{
total_size = 0;
}
fprintf(g.httpOut, "\r\n");
if( total_size>0 && iReplyStatus != 304 ){
|
| ︙ | ︙ | |||
473 474 475 476 477 478 479 |
/*
** 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
|
| ︙ | ︙ | |||
591 592 593 594 595 596 597 |
*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
|
| ︙ | ︙ | |||
698 699 700 701 702 703 704 |
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().
*/
|
| ︙ | ︙ | |||
879 880 881 882 883 884 885 |
}
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, '&');
|
| ︙ | ︙ | |||
925 926 927 928 929 930 931 |
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
|
| ︙ | ︙ | |||
1201 1202 1203 1204 1205 1206 1207 |
** 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
|
| ︙ | ︙ | |||
1273 1274 1275 1276 1277 1278 1279 |
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 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 |
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);
blob_append(&g.httpHeader, zLine, -1);
zFieldName = extract_token(zLine,&zVal);
if( zFieldName==0 || *zFieldName==0 ) break;
while( fossil_isspace(*zVal) ){ zVal++; }
i = strlen(zVal);
while( i>0 && fossil_isspace(zVal[i-1]) ){ i--; }
zVal[i] = 0;
for(i=0; zFieldName[i]; i++){
zFieldName[i] = fossil_tolower(zFieldName[i]);
}
if( fossil_strcmp(zFieldName,"accept-encoding:")==0 ){
cgi_setenv("HTTP_ACCEPT_ENCODING", zVal);
}else if( fossil_strcmp(zFieldName,"content-length:")==0 ){
cgi_setenv("CONTENT_LENGTH", zVal);
}else if( fossil_strcmp(zFieldName,"content-type:")==0 ){
cgi_setenv("CONTENT_TYPE", zVal);
}else if( fossil_strcmp(zFieldName,"cookie:")==0 ){
cgi_setenv("HTTP_COOKIE", zVal);
}else if( fossil_strcmp(zFieldName,"https:")==0 ){
cgi_setenv("HTTPS", zVal);
}else if( fossil_strcmp(zFieldName,"host:")==0 ){
cgi_setenv("HTTP_HOST", zVal);
}else if( fossil_strcmp(zFieldName,"if-none-match:")==0 ){
cgi_setenv("HTTP_IF_NONE_MATCH", zVal);
}else if( fossil_strcmp(zFieldName,"if-modified-since:")==0 ){
cgi_setenv("HTTP_IF_MODIFIED_SINCE", zVal);
}else if( fossil_strcmp(zFieldName,"referer:")==0 ){
cgi_setenv("HTTP_REFERER", zVal);
}else if( fossil_strcmp(zFieldName,"user-agent:")==0 ){
cgi_setenv("HTTP_USER_AGENT", zVal);
}else if( fossil_strcmp(zFieldName,"x-forwarded-for:")==0 ){
const char *zIpAddr = cgi_accept_forwarded_for(zVal);
if( zIpAddr!=0 ){
g.zIpAddr = mprintf("%s", zIpAddr);
cgi_replace_parameter("REMOTE_ADDR", g.zIpAddr);
|
| ︙ | ︙ | |||
1350 1351 1352 1353 1354 1355 1356 |
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 ){
|
| ︙ | ︙ | |||
1416 1417 1418 1419 1420 1421 1422 |
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);
|
| ︙ | ︙ | |||
1597 1598 1599 1600 1601 1602 1603 | 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 */ |
| ︙ | ︙ | |||
1682 1683 1684 1685 1686 1687 1688 |
}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 |
}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);
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 " &" */
|
| ︙ | ︙ | |||
1745 1746 1747 1748 1749 1750 1751 |
}
}
/* Bury dead children */
while( waitpid(0, 0, WNOHANG)>0 ){
nchildren--;
}
}
| | | 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 |
}
}
/* Bury dead children */
while( waitpid(0, 0, WNOHANG)>0 ){
nchildren--;
}
}
/* NOT REACHED */
fossil_exit(1);
#endif
/* NOT REACHED */
return 0;
}
|
| ︙ | ︙ | |||
1833 1834 1835 1836 1837 1838 1839 |
}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++;
| | | 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 |
}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.
| ︙ | ︙ | |||
299 300 301 302 303 304 305 |
filename_collation(), zName, filename_collation(),
zName, filename_collation());
}
vfile_check_signature(vid, 0);
if( showAge ){
db_prepare(&q,
"SELECT pathname, deleted, rid, chnged, coalesce(origname!=pathname,0),"
| | | | 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 |
filename_collation(), zName, filename_collation(),
zName, filename_collation());
}
vfile_check_signature(vid, 0);
if( showAge ){
db_prepare(&q,
"SELECT pathname, deleted, rid, chnged, coalesce(origname!=pathname,0),"
" datetime(checkin_mtime(%d,rid),'unixepoch'%s)"
" FROM vfile %s"
" ORDER BY %s", vid, timeline_utc(), blob_str(&where), zOrderBy
);
}else{
db_prepare(&q,
"SELECT pathname, deleted, rid, chnged, coalesce(origname!=pathname,0)"
" FROM vfile %s"
" ORDER BY %s", blob_str(&where), zOrderBy
);
|
| ︙ | ︙ | |||
621 622 623 624 625 626 627 |
continue;
}
if( !allFileFlag && (!extremeFlag || !glob_match(pIgnore, zName+nRoot)) ){
Blob ans;
char cReply;
char *prompt = mprintf("Remove unmanaged file \"%s\" (a=all/y/N)? ",
zName+nRoot);
| < | 621 622 623 624 625 626 627 628 629 630 631 632 633 634 |
continue;
}
if( !allFileFlag && (!extremeFlag || !glob_match(pIgnore, 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;
|
| ︙ | ︙ | |||
668 669 670 671 672 673 674 |
continue;
}
if( !allDirFlag && (!extremeFlag || !glob_match(pIgnore, zName+nRoot)) ){
Blob ans;
char cReply;
char *prompt = mprintf("Remove empty directory \"%s\" (a=all/y/N)? ",
zName+nRoot);
| < | 667 668 669 670 671 672 673 674 675 676 677 678 679 680 |
continue;
}
if( !allDirFlag && (!extremeFlag || !glob_match(pIgnore, 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;
|
| ︙ | ︙ | |||
842 843 844 845 846 847 848 849 850 851 852 853 854 855 |
status_report(&prompt, "# ", 1, 0);
if( g.markPrivate ){
blob_append(&prompt,
"# PRIVATE BRANCH: This check-in will be private and will not sync to\n"
"# repositories.\n"
"#\n", -1
);
}
prompt_for_user_comment(pComment, &prompt);
blob_reset(&prompt);
}
/*
** Populate the Global.aCommitFile[] based on the command line arguments
| > > > > > > > | 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 |
status_report(&prompt, "# ", 1, 0);
if( g.markPrivate ){
blob_append(&prompt,
"# PRIVATE BRANCH: This check-in will be private and will not sync to\n"
"# repositories.\n"
"#\n", -1
);
}
if( p->integrateFlag ){
blob_append(&prompt,
"#\n"
"# All merged-in branches will be closed due to the --integrate flag\n"
"#\n", -1
);
}
prompt_for_user_comment(pComment, &prompt);
blob_reset(&prompt);
}
/*
** Populate the Global.aCommitFile[] based on the command line arguments
|
| ︙ | ︙ | |||
980 981 982 983 984 985 986 987 988 989 990 991 992 993 |
** check-in manifest.
*/
struct CheckinInfo {
Blob *pComment; /* Check-in comment text */
const char *zMimetype; /* Mimetype of check-in command. May be NULL */
int verifyDate; /* Verify that child is younger */
int closeFlag; /* Close the branch being committed */
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 */
| > | 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 |
** check-in manifest.
*/
struct CheckinInfo {
Blob *pComment; /* Check-in comment text */
const char *zMimetype; /* Mimetype of check-in command. May be NULL */
int verifyDate; /* Verify that child is younger */
int closeFlag; /* Close the branch being committed */
int integrateFlag; /* Close merged-in branches */
Blob *pCksum; /* Repository checksum. May be 0 */
const char *zDateOvrd; /* Date override. If 0 then use 'now' */
const char *zUserOvrd; /* User override. If 0 then use 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 */
|
| ︙ | ︙ | |||
1173 1174 1175 1176 1177 1178 1179 |
/* One-time background color */
blob_appendf(pOut, "T +bgcolor * %F\n", zColor);
}
if( p->closeFlag ){
blob_appendf(pOut, "T +closed *\n");
}
db_prepare(&q, "SELECT uuid,merge FROM vmerge JOIN blob ON merge=rid"
| | > | 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 |
/* One-time background color */
blob_appendf(pOut, "T +bgcolor * %F\n", zColor);
}
if( p->closeFlag ){
blob_appendf(pOut, "T +closed *\n");
}
db_prepare(&q, "SELECT uuid,merge FROM vmerge JOIN blob ON merge=rid"
" WHERE id %s ORDER BY 1",
p->integrateFlag ? "IN(0,-4)" : "=(-4)");
while( db_step(&q)==SQLITE_ROW ){
const char *zIntegrateUuid = db_column_text(&q, 0);
int rid = db_column_int(&q, 1);
if( is_a_leaf(rid) && !db_exists("SELECT 1 FROM tagxref "
" WHERE tagid=%d AND rid=%d AND tagtype>0", TAG_CLOSED, rid)){
blob_appendf(pOut, "T +closed %s\n", zIntegrateUuid);
}
|
| ︙ | ︙ | |||
1301 1302 1303 1304 1305 1306 1307 |
}
zDisable = "\"crnl-glob\" setting";
}else{
if( encodingOk ){
return 0; /* We don't want encoding warnings for this file. */
}
zWarning = "Unicode";
| < < < < | 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 |
}
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];
|
| ︙ | ︙ | |||
1402 1403 1404 1405 1406 1407 1408 | ** interactive user or these warnings should be skipped for some other ** reason, the --no-warnings option may be used. A check-in is not ** allowed against a closed leaf. ** ** The --private option creates a private check-in that is never synced. ** Children of private check-ins are automatically private. ** | | > > > > > > > | 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 |
** interactive user or these warnings should be skipped for some other
** reason, the --no-warnings option may be used. A check-in is not
** allowed against a closed leaf.
**
** The --private option creates a private check-in that is never synced.
** Children of private check-ins are automatically private.
**
** The --tag option applies the symbolic tag name to the check-in.
**
** The --sha1sum option detects edited files by computing each file's
** SHA1 hash rather than just checking for changes to its size or mtime.
**
** Options:
** --allow-conflict allow unresolved merge conflicts
** --allow-empty allow a commit with no changes
** --allow-fork allow the commit to fork
** --allow-older allow a commit older than its ancestor
** --baseline use a baseline manifest in the commit process
** --bgcolor COLOR apply COLOR to this one check-in only
** --branch NEW-BRANCH-NAME check in to this new branch
** --branchcolor COLOR apply given COLOR to the branch
** --close close the branch being committed
** --delta use a delta manifest in the commit process
** --integrate close all merged-in branches
** -m|--comment COMMENT-TEXT use COMMENT-TEXT as commit comment
** -M|--message-file FILE read the commit comment from given file
** --mimetype MIMETYPE mimetype of check-in comment
** -n|--dry-run If given, display instead of run actions
** --no-warnings omit all warnings about file contents
** --nosign do not attempt to sign this commit with gpg
** --private do not sync changes and their descendants
** --sha1sum verify file status using SHA1 hashing rather
** than relying on file mtimes
** --tag TAG-NAME assign given tag TAG-NAME to the 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 */
const char *zComment; /* Check-in comment */
Stmt q; /* Various queries */
char *zUuid; /* UUID of the new check-in */
int useSha1sum = 0; /* True to verify file status using SHA1 hashing */
int noSign = 0; /* True to omit signing the manifest using GPG */
int isAMerge = 0; /* True if checking in a merge */
int noWarningFlag = 0; /* True if skipping all warnings */
int forceFlag = 0; /* Undocumented: Disables all checks */
int forceDelta = 0; /* Force a delta-manifest */
int forceBaseline = 0; /* Force a baseline-manifest */
int allowConflict = 0; /* Allow unresolve merge conflicts */
|
| ︙ | ︙ | |||
1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 |
int nConflict = 0; /* Number of unresolved merge conflicts */
int abortCommit = 0;
Blob ans;
char cReply;
memset(&sCiInfo, 0, sizeof(sCiInfo));
url_proxy_options();
noSign = find_option("nosign",0,0)!=0;
forceDelta = find_option("delta",0,0)!=0;
forceBaseline = find_option("baseline",0,0)!=0;
if( forceDelta && forceBaseline ){
fossil_fatal("cannot use --delta and --baseline together");
}
dryRunFlag = find_option("dry-run","n",0)!=0;
| > | 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 |
int nConflict = 0; /* Number of unresolved merge conflicts */
int abortCommit = 0;
Blob ans;
char cReply;
memset(&sCiInfo, 0, sizeof(sCiInfo));
url_proxy_options();
useSha1sum = find_option("sha1sum", 0, 0)!=0;
noSign = find_option("nosign",0,0)!=0;
forceDelta = find_option("delta",0,0)!=0;
forceBaseline = find_option("baseline",0,0)!=0;
if( forceDelta && forceBaseline ){
fossil_fatal("cannot use --delta and --baseline together");
}
dryRunFlag = find_option("dry-run","n",0)!=0;
|
| ︙ | ︙ | |||
1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 |
allowFork = find_option("allow-fork",0,0)!=0;
allowOlder = find_option("allow-older",0,0)!=0;
noWarningFlag = find_option("no-warnings", 0, 0)!=0;
sCiInfo.zBranch = find_option("branch","b",1);
sCiInfo.zColor = find_option("bgcolor",0,1);
sCiInfo.zBrClr = find_option("branchcolor",0,1);
sCiInfo.closeFlag = find_option("close",0,0)!=0;
sCiInfo.zMimetype = find_option("mimetype",0,1);
while( (zTag = find_option("tag",0,1))!=0 ){
if( zTag[0]==0 ) continue;
sCiInfo.azTag = fossil_realloc((void*)sCiInfo.azTag, sizeof(char*)*(nTag+2));
sCiInfo.azTag[nTag++] = zTag;
sCiInfo.azTag[nTag] = 0;
}
| > | 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 |
allowFork = find_option("allow-fork",0,0)!=0;
allowOlder = find_option("allow-older",0,0)!=0;
noWarningFlag = find_option("no-warnings", 0, 0)!=0;
sCiInfo.zBranch = find_option("branch","b",1);
sCiInfo.zColor = find_option("bgcolor",0,1);
sCiInfo.zBrClr = find_option("branchcolor",0,1);
sCiInfo.closeFlag = find_option("close",0,0)!=0;
sCiInfo.integrateFlag = find_option("integrate",0,0)!=0;
sCiInfo.zMimetype = find_option("mimetype",0,1);
while( (zTag = find_option("tag",0,1))!=0 ){
if( zTag[0]==0 ) continue;
sCiInfo.azTag = fossil_realloc((void*)sCiInfo.azTag, sizeof(char*)*(nTag+2));
sCiInfo.azTag[nTag++] = zTag;
sCiInfo.azTag[nTag] = 0;
}
|
| ︙ | ︙ | |||
1530 1531 1532 1533 1534 1535 1536 |
*/
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);
| > > | < < < | 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 |
*/
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( vid==0 ){
useCksum = 1;
}else 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) ){
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 ){
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() ){
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");
|
| ︙ | ︙ | |||
1611 1612 1613 1614 1615 1616 1617 |
/*
** Check that the user exists.
*/
if( !db_exists("SELECT 1 FROM user WHERE login=%Q", g.zLogin) ){
fossil_fatal("no such user: %s", g.zLogin);
}
| | | 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 |
/*
** Check that the user exists.
*/
if( !db_exists("SELECT 1 FROM user WHERE login=%Q", g.zLogin) ){
fossil_fatal("no such user: %s", g.zLogin);
}
hasChanges = unsaved_changes(useSha1sum ? CKSIG_SHA1 : 0);
db_begin_transaction();
db_record_repository_filename(0);
if( hasChanges==0 && !isAMerge && !allowEmpty && !forceFlag ){
fossil_fatal("nothing has changed; use --allow-empty to override");
}
/* If none of the files that were named on the command line have
|
| ︙ | ︙ | |||
1672 1673 1674 1675 1676 1677 1678 |
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 ){
| < < | 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 |
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];
if( cReply!='y' && cReply!='Y' ) fossil_exit(1);;
}
free(zInit);
}
if( blob_size(&comment)==0 ){
if( !dryRunFlag ){
prompt_user("empty check-in comment. continue (y/N)? ", &ans);
cReply = blob_str(&ans)[0];
if( cReply!='y' && cReply!='Y' ){
fossil_exit(1);
}
}
}else{
|
| ︙ | ︙ | |||
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) ){
| < | 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 |
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);
}
}
|
| ︙ | ︙ | |||
1841 1842 1843 1844 1845 1846 1847 |
}
nvid = content_put(&manifest);
if( nvid==0 ){
fossil_fatal("trouble committing manifest: %s", g.zErrMsg);
}
db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", nvid);
| | > > > | 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 |
}
nvid = content_put(&manifest);
if( nvid==0 ){
fossil_fatal("trouble committing manifest: %s", g.zErrMsg);
}
db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", nvid);
if( manifest_crosslink(nvid, &manifest,
dryRunFlag ? MC_NONE : MC_PERMIT_HOOKS)==0 ){
fossil_fatal("%s\n", g.zErrMsg);
}
assert( blob_is_reset(&manifest) );
content_deltify(vid, nvid, 0);
zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", nvid);
db_prepare(&q, "SELECT uuid,merge FROM vmerge JOIN blob ON merge=rid"
" WHERE id=-4");
while( db_step(&q)==SQLITE_ROW ){
|
| ︙ | ︙ |
Changes to src/checkout.c.
| ︙ | ︙ | |||
26 27 28 29 30 31 32 | ** Check to see if there is an existing checkout that has been ** modified. Return values: ** ** 0: There is an existing checkout but it is unmodified ** 1: There is a modified checkout - there are unsaved changes ** 2: There is no existing checkout */ | | | | 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
** Check to see if there is an existing checkout that has been
** modified. Return values:
**
** 0: There is an existing checkout but it is unmodified
** 1: There is a modified checkout - there are unsaved changes
** 2: There is no existing checkout
*/
int unsaved_changes(unsigned int cksigFlags){
int vid;
db_must_be_within_tree();
vid = db_lget_int("checkout",0);
if( vid==0 ) return 2;
vfile_check_signature(vid, cksigFlags|CKSIG_ENOTFILE);
return db_exists("SELECT 1 FROM vfile WHERE chnged"
" OR coalesce(origname!=pathname,0)");
}
/*
** Undo the current check-out. Unlink all files from the disk.
** Clear the VFILE table.
|
| ︙ | ︙ | |||
198 199 200 201 202 203 204 |
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) ){
usage("VERSION|--latest ?--force? ?--keep?");
}
| | | 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 |
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) ){
usage("VERSION|--latest ?--force? ?--keep?");
}
if( !forceFlag && unsaved_changes(0)==1 ){
fossil_fatal("there are unsaved changes in the current checkout");
}
if( forceFlag ){
db_multi_exec("DELETE FROM vfile");
prior = 0;
}else{
prior = db_lget_int("checkout",0);
|
| ︙ | ︙ | |||
286 287 288 289 290 291 292 |
** --force|-f necessary to close a check out with uncommitted changes
**
** See also: open
*/
void close_cmd(void){
int forceFlag = find_option("force","f",0)!=0;
db_must_be_within_tree();
| | | 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 |
** --force|-f necessary to close a check out with uncommitted changes
**
** See also: open
*/
void close_cmd(void){
int forceFlag = find_option("force","f",0)!=0;
db_must_be_within_tree();
if( !forceFlag && unsaved_changes(0)==1 ){
fossil_fatal("there are unsaved changes in the current checkout");
}
if( !forceFlag
&& db_exists("SELECT 1 FROM %s.sqlite_master WHERE name='stash'",
db_name("localdb"))
&& db_exists("SELECT 1 FROM %s.stash", db_name("localdb"))
){
|
| ︙ | ︙ |
Changes to src/clone.c.
| ︙ | ︙ | |||
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 |
**
** By default, your current login name is used to create the default
** admin user. This can be overridden using the -A|--admin-user
** parameter.
**
** Options:
** --admin-user|-A USERNAME Make USERNAME the administrator
** --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 */
if( find_option("private",0,0)!=0 ) bPrivate = SYNC_PRIVATE;
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]);
}
| > > > > < < | | 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 |
**
** By default, your current login name is used to create the default
** admin user. This can be overridden using the -A|--admin-user
** parameter.
**
** Options:
** --admin-user|-A USERNAME Make USERNAME the administrator
** --once Don't save url.
** --private Also clone private branches
** --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();
|
| ︙ | ︙ | |||
154 155 156 157 158 159 160 161 162 163 164 165 166 167 |
db_open_repository(g.argv[3]);
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);
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);
| > | 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 |
db_open_repository(g.argv[3]);
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);
|
| ︙ | ︙ |
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 |
*/
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{
|
| ︙ | ︙ |
Changes to src/config.h.
| ︙ | ︙ | |||
60 61 62 63 64 65 66 67 68 69 70 71 | # 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__) | > > > > > > > > > > > | > > > > | > > > > | > > > > > > > | > > > > > > > > > > > > > > > > > | > > > > > > > > > | > | 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 | # endif #else # include <sys/types.h> # include <signal.h> # include <pwd.h> #endif /* ** Utility macro to wrap an argument with double quotes. */ #if !defined(COMPILER_STRINGIFY) # define COMPILER_STRINGIFY(x) COMPILER_STRINGIFY1(x) # define COMPILER_STRINGIFY1(x) #x #endif /* ** Define the compiler variant, used to compile the project */ #if !defined(COMPILER_NAME) # if defined(__DMC__) # if defined(COMPILER_VERSION) && !defined(NO_COMPILER_VERSION) # define COMPILER_NAME "dmc-" COMPILER_VERSION # else # define COMPILER_NAME "dmc" # endif # elif defined(__POCC__) # if defined(_M_X64) # if defined(COMPILER_VERSION) && !defined(NO_COMPILER_VERSION) # define COMPILER_NAME "pellesc64-" COMPILER_VERSION # else # define COMPILER_NAME "pellesc64" # endif # else # if defined(COMPILER_VERSION) && !defined(NO_COMPILER_VERSION) # define COMPILER_NAME "pellesc32-" COMPILER_VERSION # else # define COMPILER_NAME "pellesc32" # endif # endif # elif defined(_MSC_VER) # if !defined(COMPILER_VERSION) # define COMPILER_VERSION COMPILER_STRINGIFY(_MSC_VER) # endif # if defined(COMPILER_VERSION) && !defined(NO_COMPILER_VERSION) # define COMPILER_NAME "msc-" COMPILER_VERSION # else # define COMPILER_NAME "msc" # endif # elif defined(__MINGW32__) # if !defined(COMPILER_VERSION) # if defined(__MINGW32_VERSION) # if defined(__GNUC__) # if defined(__VERSION__) # define COMPILER_VERSION COMPILER_STRINGIFY(__MINGW32_VERSION) "-gcc-" __VERSION__ # else # define COMPILER_VERSION COMPILER_STRINGIFY(__MINGW32_VERSION) "-gcc" # endif # else # define COMPILER_VERSION COMPILER_STRINGIFY(__MINGW32_VERSION) # endif # endif # endif # if defined(COMPILER_VERSION) && !defined(NO_COMPILER_VERSION) # define COMPILER_NAME "mingw32-" COMPILER_VERSION # else # define COMPILER_NAME "mingw32" # endif # elif defined(_WIN32) # define COMPILER_NAME "win32" # elif defined(__GNUC__) # if !defined(COMPILER_VERSION) # if defined(__VERSION__) # define COMPILER_VERSION __VERSION__ # endif # endif # if defined(COMPILER_VERSION) && !defined(NO_COMPILER_VERSION) # define COMPILER_NAME "gcc-" COMPILER_VERSION # else # define COMPILER_NAME "gcc" # endif # else # define COMPILER_NAME "unknown" # endif #endif #if !defined(_RC_COMPILE_) && !defined(SQLITE_AMALGAMATION) |
| ︙ | ︙ | |||
121 122 123 124 125 126 127 | /* ** 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. ** | | | 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 | /* ** 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.
| ︙ | ︙ | |||
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 |
{ "timeline-block-markup", CONFIGSET_SKIN },
{ "timeline-max-comment", CONFIGSET_SKIN },
{ "timeline-plaintext", CONFIGSET_SKIN },
{ "adunit", CONFIGSET_SKIN },
{ "adunit-omit-if-admin", CONFIGSET_SKIN },
{ "adunit-omit-if-user", CONFIGSET_SKIN },
{ "th1-setup", CONFIGSET_TH1 },
#ifdef FOSSIL_ENABLE_TCL
{ "tcl", CONFIGSET_TH1 },
{ "tcl-setup", CONFIGSET_TH1 },
#endif
{ "project-name", CONFIGSET_PROJ },
{ "short-project-name", CONFIGSET_PROJ },
{ "project-description", CONFIGSET_PROJ },
{ "manifest", CONFIGSET_PROJ },
{ "binary-glob", CONFIGSET_PROJ },
{ "ignore-glob", CONFIGSET_PROJ },
{ "keep-glob", CONFIGSET_PROJ },
{ "crnl-glob", CONFIGSET_PROJ },
{ "encoding-glob", CONFIGSET_PROJ },
{ "empty-dirs", CONFIGSET_PROJ },
{ "allow-symlinks", CONFIGSET_PROJ },
{ "ticket-table", CONFIGSET_TKT },
{ "ticket-common", CONFIGSET_TKT },
{ "ticket-change", CONFIGSET_TKT },
{ "ticket-newpage", CONFIGSET_TKT },
{ "ticket-viewpage", CONFIGSET_TKT },
| > > | 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 |
{ "timeline-block-markup", CONFIGSET_SKIN },
{ "timeline-max-comment", CONFIGSET_SKIN },
{ "timeline-plaintext", CONFIGSET_SKIN },
{ "adunit", CONFIGSET_SKIN },
{ "adunit-omit-if-admin", CONFIGSET_SKIN },
{ "adunit-omit-if-user", CONFIGSET_SKIN },
{ "th1-setup", CONFIGSET_TH1 },
{ "th1-uri-regexp", CONFIGSET_TH1 },
#ifdef FOSSIL_ENABLE_TCL
{ "tcl", CONFIGSET_TH1 },
{ "tcl-setup", CONFIGSET_TH1 },
#endif
{ "project-name", CONFIGSET_PROJ },
{ "short-project-name", CONFIGSET_PROJ },
{ "project-description", CONFIGSET_PROJ },
{ "manifest", CONFIGSET_PROJ },
{ "binary-glob", CONFIGSET_PROJ },
{ "ignore-glob", CONFIGSET_PROJ },
{ "keep-glob", CONFIGSET_PROJ },
{ "crnl-glob", CONFIGSET_PROJ },
{ "encoding-glob", CONFIGSET_PROJ },
{ "empty-dirs", CONFIGSET_PROJ },
{ "allow-clean-x", CONFIGSET_PROJ },
{ "allow-symlinks", CONFIGSET_PROJ },
{ "ticket-table", CONFIGSET_TKT },
{ "ticket-common", CONFIGSET_TKT },
{ "ticket-change", CONFIGSET_TKT },
{ "ticket-newpage", CONFIGSET_TKT },
{ "ticket-viewpage", CONFIGSET_TKT },
|
| ︙ | ︙ | |||
135 136 137 138 139 140 141 142 143 144 145 146 147 148 |
{ "@concealed", CONFIGSET_ADDR },
{ "@shun", CONFIGSET_SHUN },
{ "xfer-common-script", CONFIGSET_XFER },
{ "xfer-push-script", CONFIGSET_XFER },
};
static int iConfig = 0;
/*
** Return name of first configuration property matching the given mask.
*/
| > > | 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 |
{ "@concealed", CONFIGSET_ADDR },
{ "@shun", CONFIGSET_SHUN },
{ "xfer-common-script", CONFIGSET_XFER },
{ "xfer-push-script", CONFIGSET_XFER },
{ "xfer-commit-script", CONFIGSET_XFER },
{ "xfer-ticket-script", CONFIGSET_XFER },
};
static int iConfig = 0;
/*
** Return name of first configuration property matching the given mask.
*/
|
| ︙ | ︙ | |||
397 398 399 400 401 402 403 404 405 406 407 408 409 410 |
@ DELETE FROM reportfmt;
@ INSERT INTO reportfmt SELECT * FROM _xfer_reportfmt;
@ DROP TABLE _xfer_user;
@ DROP TABLE _xfer_reportfmt;
;
db_multi_exec(zSQL);
}
/*
** Return true if z[] is not a "safe" SQL token. A safe token is one of:
**
** * A string literal
** * A blob literal
** * An integer literal (no floating point)
| > > > > > > > > > > > > > > > | 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 |
@ DELETE FROM reportfmt;
@ INSERT INTO reportfmt SELECT * FROM _xfer_reportfmt;
@ DROP TABLE _xfer_user;
@ DROP TABLE _xfer_reportfmt;
;
db_multi_exec(zSQL);
}
/*
** Mask of modified configuration sets
*/
static int rebuildMask = 0;
/*
** Rebuild auxiliary tables as required by configuration changes.
*/
void configure_rebuild(void){
if( rebuildMask & CONFIGSET_TKT ){
ticket_rebuild();
}
rebuildMask = 0;
}
/*
** Return true if z[] is not a "safe" SQL token. A safe token is one of:
**
** * A string literal
** * A blob literal
** * An integer literal (no floating point)
|
| ︙ | ︙ | |||
563 564 565 566 567 568 569 570 571 572 573 574 575 576 |
blob_appendf(&sql, ", %s=%s", azToken[jj], azToken[jj+1]);
}
blob_appendf(&sql, " WHERE %s=%s AND mtime<%s",
aType[ii].zPrimKey, azToken[1], azToken[0]);
db_multi_exec("%s", blob_str(&sql));
}
blob_reset(&sql);
}else{
/* Otherwise, the old format */
if( (configure_is_exportable(zName) & groupMask)==0 ) return;
if( fossil_strcmp(zName, "logo-image")==0 ){
Stmt ins;
db_prepare(&ins,
"REPLACE INTO config(name, value, mtime) VALUES(:name, :value, now())"
| > | 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 |
blob_appendf(&sql, ", %s=%s", azToken[jj], azToken[jj+1]);
}
blob_appendf(&sql, " WHERE %s=%s AND mtime<%s",
aType[ii].zPrimKey, azToken[1], azToken[0]);
db_multi_exec("%s", blob_str(&sql));
}
blob_reset(&sql);
rebuildMask |= thisMask;
}else{
/* Otherwise, the old format */
if( (configure_is_exportable(zName) & groupMask)==0 ) return;
if( fossil_strcmp(zName, "logo-image")==0 ){
Stmt ins;
db_prepare(&ins,
"REPLACE INTO config(name, value, mtime) VALUES(:name, :value, now())"
|
| ︙ | ︙ | |||
945 946 947 948 949 950 951 952 953 954 955 956 957 |
db_multi_exec(zRepositorySchemaDefaultReports);
}
}
db_end_transaction(0);
fossil_print("Configuration reset to factory defaults.\n");
fossil_print("To recover, use: %s %s import %s\n",
g.argv[0], g.argv[1], zBackup);
}else
{
fossil_fatal("METHOD should be one of:"
" export import merge pull push reset");
}
}
| > > | 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 |
db_multi_exec(zRepositorySchemaDefaultReports);
}
}
db_end_transaction(0);
fossil_print("Configuration reset to factory defaults.\n");
fossil_print("To recover, use: %s %s import %s\n",
g.argv[0], g.argv[1], zBackup);
rebuildMask |= mask;
}else
{
fossil_fatal("METHOD should be one of:"
" export import merge pull push reset");
}
configure_rebuild();
}
|
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 ){
|
| ︙ | ︙ | |||
386 387 388 389 390 391 392 |
while( rid ){
int nChildUsed = 0;
int i;
/* Parse the object rid itself */
if( linkFlag ){
content_get(rid, &content);
| | | | | 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 |
while( rid ){
int nChildUsed = 0;
int i;
/* Parse the object rid itself */
if( linkFlag ){
content_get(rid, &content);
manifest_crosslink(rid, &content, MC_NONE);
assert( blob_is_reset(&content) );
}
/* Parse all delta-manifests that depend on baseline-manifest rid */
db_prepare(&q, "SELECT rid FROM orphan WHERE baseline=%d", rid);
while( db_step(&q)==SQLITE_ROW ){
int child = db_column_int(&q, 0);
if( nChildUsed>=nChildAlloc ){
nChildAlloc = nChildAlloc*2 + 10;
aChild = fossil_realloc(aChild, nChildAlloc*sizeof(aChild));
}
aChild[nChildUsed++] = child;
}
db_finalize(&q);
for(i=0; i<nChildUsed; i++){
content_get(aChild[i], &content);
manifest_crosslink(aChild[i], &content, MC_NONE);
assert( blob_is_reset(&content) );
}
if( nChildUsed ){
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 ){
static const char *const 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_v2() */
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_v2() */
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 */
|
| ︙ | ︙ | |||
313 314 315 316 317 318 319 320 321 322 323 324 325 326 |
}
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);
| > > > > | 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 |
}
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_text16(Stmt *pStmt, const char *zParamName, const char *zValue){
return sqlite3_bind_text16(pStmt->pStmt, paramIdx(pStmt, zParamName), zValue,
-1, SQLITE_STATIC);
}
int db_bind_null(Stmt *pStmt, const char *zParamName){
return sqlite3_bind_null(pStmt->pStmt, paramIdx(pStmt, zParamName));
}
int db_bind_blob(Stmt *pStmt, const char *zParamName, Blob *pBlob){
return sqlite3_bind_blob(pStmt->pStmt, paramIdx(pStmt, zParamName),
blob_buffer(pBlob), blob_size(pBlob), SQLITE_STATIC);
|
| ︙ | ︙ | |||
707 708 709 710 711 712 713 |
/*
** 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;
| < < | | 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 |
/*
** 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
);
if( rc!=SQLITE_OK ){
db_err("[%s]: %s", zDbName, sqlite3_errmsg(db));
}
sqlite3_busy_timeout(db, 5000);
sqlite3_wal_autocheckpoint(db, 1); /* Set to checkpoint frequently */
sqlite3_create_function(db, "now", 0, SQLITE_ANY, 0, db_now_function, 0, 0);
|
| ︙ | ︙ | |||
827 828 829 830 831 832 833 |
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
| < < < > > > < < | 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 |
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 ){
if( file_access(zHome, W_OK) ){
fossil_fatal("home directory %s must be writeable", zHome);
}
db_init_database(zDbName, zConfigSchema, (char*)0);
}
if( file_access(zDbName, W_OK) ){
fossil_fatal("configuration file %s must be writeable", zDbName);
}
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);
|
| ︙ | ︙ | |||
942 943 944 945 946 947 948 |
int i, n;
char zPwd[2000];
static const char aDbName[][10] = { "_FOSSIL_", ".fslckout", ".fos" };
if( g.localOpen) return 1;
file_getcwd(zPwd, sizeof(zPwd)-20);
n = strlen(zPwd);
| < | | | | 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 |
int i, n;
char zPwd[2000];
static const char aDbName[][10] = { "_FOSSIL_", ".fslckout", ".fos" };
if( g.localOpen) return 1;
file_getcwd(zPwd, sizeof(zPwd)-20);
n = strlen(zPwd);
while( n>0 ){
for(i=0; i<count(aDbName); i++){
sqlite3_snprintf(sizeof(zPwd)-n, &zPwd[n], "/%s", aDbName[i]);
if( isValidLocalDb(zPwd) ){
/* Found a valid checkout database file */
zPwd[n] = 0;
while( n>0 && zPwd[n-1]=='/' ){
n--;
zPwd[n] = 0;
}
g.zLocalRoot = mprintf("%s/", zPwd);
g.localOpen = 1;
db_open_config(0);
db_open_repository(zDbName);
return 1;
}
}
n--;
while( n>1 && zPwd[n]!='/' ){ n--; }
while( n>1 && zPwd[n-1]=='/' ){ n--; }
zPwd[n] = 0;
}
/* A checkout database file could not be found */
return 0;
}
|
| ︙ | ︙ | |||
1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 |
){
char *zDate;
Blob hash;
Blob manifest;
db_set("content-schema", CONTENT_SCHEMA, 0);
db_set("aux-schema", AUX_SCHEMA, 0);
if( makeServerCodes ){
db_multi_exec(
"INSERT INTO config(name,value,mtime)"
" VALUES('server-code', lower(hex(randomblob(20))),now());"
"INSERT INTO config(name,value,mtime)"
" VALUES('project-code', lower(hex(randomblob(20))),now());"
);
| > | 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 |
){
char *zDate;
Blob hash;
Blob manifest;
db_set("content-schema", CONTENT_SCHEMA, 0);
db_set("aux-schema", AUX_SCHEMA, 0);
db_set("rebuilt", get_version(), 0);
if( makeServerCodes ){
db_multi_exec(
"INSERT INTO config(name,value,mtime)"
" VALUES('server-code', lower(hex(randomblob(20))),now());"
"INSERT INTO config(name,value,mtime)"
" VALUES('project-code', lower(hex(randomblob(20))),now());"
);
|
| ︙ | ︙ | |||
1363 1364 1365 1366 1367 1368 1369 |
/*
** Copy all settings from the supplied template repository.
*/
db_multi_exec(
"INSERT OR REPLACE INTO config"
" SELECT name,value,mtime FROM settingSrc.config"
" WHERE (name IN %s OR name IN %s)"
| | > | 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 |
/*
** Copy all settings from the supplied template repository.
*/
db_multi_exec(
"INSERT OR REPLACE INTO config"
" SELECT name,value,mtime FROM settingSrc.config"
" WHERE (name IN %s OR name IN %s)"
" AND name NOT GLOB 'project-*'"
" AND name NOT GLOB 'short-project-*';",
configure_inop_rhs(CONFIGSET_ALL),
db_setting_inop_rhs()
);
db_multi_exec(
"REPLACE INTO reportfmt SELECT * FROM settingSrc.reportfmt;"
);
|
| ︙ | ︙ | |||
1410 1411 1412 1413 1414 1415 1416 |
blob_appendf(&manifest, "T *branch * trunk\n");
blob_appendf(&manifest, "T *sym-trunk *\n");
blob_appendf(&manifest, "U %F\n", g.zLogin);
md5sum_blob(&manifest, &hash);
blob_appendf(&manifest, "Z %b\n", &hash);
blob_reset(&hash);
rid = content_put(&manifest);
| | | 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 |
blob_appendf(&manifest, "T *branch * trunk\n");
blob_appendf(&manifest, "T *sym-trunk *\n");
blob_appendf(&manifest, "U %F\n", g.zLogin);
md5sum_blob(&manifest, &hash);
blob_appendf(&manifest, "Z %b\n", &hash);
blob_reset(&hash);
rid = content_put(&manifest);
manifest_crosslink(rid, &manifest, MC_NONE);
}
}
/*
** COMMAND: new*
** COMMAND: init
**
|
| ︙ | ︙ | |||
1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 |
** checked out file */
z = db_get_do_versionable(zName, z);
}
if( z==0 ){
z = zDefault;
}
return z;
}
void db_set(const char *zName, const char *zValue, int globalFlag){
db_begin_transaction();
if( globalFlag ){
db_swap_connections();
db_multi_exec("REPLACE INTO global_config(name,value) VALUES(%Q,%Q)",
zName, zValue);
| > > > > > > > > > > > > | 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 |
** checked out file */
z = db_get_do_versionable(zName, z);
}
if( z==0 ){
z = zDefault;
}
return z;
}
char *db_get_mtime(const char *zName, char *zFormat, char *zDefault){
char *z = 0;
if( g.repositoryOpen ){
z = db_text(0, "SELECT mtime FROM config WHERE name=%Q", zName);
}
if( z==0 ){
z = zDefault;
}else if( zFormat!=0 ){
z = db_text(0, "SELECT strftime(%Q,%Q,'unixepoch');", zFormat, z);
}
return z;
}
void db_set(const char *zName, const char *zValue, int globalFlag){
db_begin_transaction();
if( globalFlag ){
db_swap_connections();
db_multi_exec("REPLACE INTO global_config(name,value) VALUES(%Q,%Q)",
zName, zValue);
|
| ︙ | ︙ | |||
1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 |
** 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){
| > > > | > > > | 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 |
** 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:
** --empty Initialize checkout as being empty, but still connected
** with the local repository. If you commit this checkout,
** it will become a new "initial" commit in the repository.
** --keep Only modify the manifest and manifest.uuid files
** --nested Allow opening a repository inside an opened checkout
**
** See also: close
*/
void cmd_open(void){
int emptyFlag;
int keepFlag;
int allowNested;
char **oldArgv;
int oldArgc;
static char *azNewArgv[] = { 0, "checkout", "--prompt", 0, 0, 0 };
url_proxy_options();
emptyFlag = find_option("empty",0,0)!=0;
keepFlag = find_option("keep",0,0)!=0;
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);
|
| ︙ | ︙ | |||
2009 2010 2011 2012 2013 2014 2015 |
"COMMIT; PRAGMA journal_mode=WAL; BEGIN;",
#endif
(char*)0);
db_delete_on_failure(LOCALDB_NAME);
db_open_local(0);
db_lset("repository", g.argv[2]);
db_record_repository_filename(g.argv[2]);
| < < < | < | | < | | > > > > | | < | 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 |
"COMMIT; PRAGMA journal_mode=WAL; BEGIN;",
#endif
(char*)0);
db_delete_on_failure(LOCALDB_NAME);
db_open_local(0);
db_lset("repository", g.argv[2]);
db_record_repository_filename(g.argv[2]);
db_lset_int("checkout", 0);
oldArgv = g.argv;
oldArgc = g.argc;
azNewArgv[0] = g.argv[0];
g.argv = azNewArgv;
if( !emptyFlag){
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
*/
static void print_setting(
const struct stControlSettings *ctrlSetting,
|
| ︙ | ︙ | |||
2089 2090 2091 2092 2093 2094 2095 |
** The behaviour page doesn't use a special layout. It lists all
** set-commands and displays the 'set'-help as info.
*/
#if INTERFACE
struct stControlSettings {
char const *name; /* Name of the setting */
char const *var; /* Internal variable name used by db_set() */
| | > | | | | | | | | | | > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > | | | 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 |
** The behaviour page doesn't use a special layout. It lists all
** set-commands and displays the 'set'-help as info.
*/
#if INTERFACE
struct stControlSettings {
char const *name; /* Name of the setting */
char const *var; /* Internal variable name used by db_set() */
int width; /* Width of display. 0 for boolean values. */
int versionable; /* Is this setting versionable? */
int forceTextArea; /* Force using a text area for display? */
char const *def; /* Default value */
};
#endif /* INTERFACE */
struct stControlSettings const ctrlSettings[] = {
{ "access-log", 0, 0, 0, 0, "off" },
{ "allow-clean-x", 0, 0, 0, 0, "off" },
{ "allow-symlinks", 0, 0, 1, 0, "off" },
{ "auto-captcha", "autocaptcha", 0, 0, 0, "on" },
{ "auto-hyperlink", 0, 0, 0, 0, "on", },
{ "auto-shun", 0, 0, 0, 0, "on" },
{ "autosync", 0, 0, 0, 0, "on" },
{ "binary-glob", 0, 40, 1, 0, "" },
{ "clearsign", 0, 0, 0, 0, "off" },
#if defined(_WIN32) || defined(__CYGWIN__) || defined(__DARWIN__) || \
defined(__APPLE__)
{ "case-sensitive", 0, 0, 0, 0, "off" },
#else
{ "case-sensitive", 0, 0, 0, 0, "on" },
#endif
{ "crnl-glob", 0, 40, 1, 0, "" },
{ "default-perms", 0, 16, 0, 0, "u" },
{ "diff-binary", 0, 0, 0, 0, "on" },
{ "diff-command", 0, 40, 0, 0, "" },
{ "dont-push", 0, 0, 0, 0, "off" },
{ "editor", 0, 32, 0, 0, "" },
{ "empty-dirs", 0, 40, 1, 0, "" },
{ "encoding-glob", 0, 40, 1, 0, "" },
{ "gdiff-command", 0, 40, 0, 0, "gdiff" },
{ "gmerge-command", 0, 40, 0, 0, "" },
{ "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" },
{ "ssh-command", 0, 40, 0, 0, "" },
{ "ssl-ca-location", 0, 40, 0, 0, "" },
{ "ssl-identity", 0, 40, 0, 0, "" },
#ifdef FOSSIL_ENABLE_TCL
{ "tcl", 0, 0, 0, 0, "off" },
{ "tcl-setup", 0, 40, 0, 1, "" },
#endif
{ "th1-setup", 0, 40, 0, 1, "" },
{ "th1-uri-regexp", 0, 40, 0, 0, "" },
{ "web-browser", 0, 32, 0, 0, "" },
{ "white-foreground", 0, 0, 0, 0, "off" },
{ 0,0,0,0,0,0 }
};
/*
** COMMAND: settings
** COMMAND: unset*
**
** %fossil settings ?PROPERTY? ?VALUE? ?OPTIONS?
|
| ︙ | ︙ | |||
2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 | ** tcl-setup This is the setup script to be evaluated after creating ** and initializing the Tcl interpreter. By default, this ** is empty and no extra setup is performed. ** ** th1-setup This is the setup script to be evaluated after creating ** and initializing the TH1 interpreter. By default, this ** is empty and no extra setup is performed. ** ** web-browser A shell command used to launch your preferred ** web browser when given a URL as an argument. ** Defaults to "start" on windows, "open" on Mac, ** and "firefox" on Unix. ** ** Options: | > > > > | 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 | ** tcl-setup This is the setup script to be evaluated after creating ** and initializing the Tcl interpreter. By default, this ** is empty and no extra setup is performed. ** ** th1-setup This is the setup script to be evaluated after creating ** and initializing the TH1 interpreter. By default, this ** is empty and no extra setup is performed. ** ** th1-uri-regexp Specify which URI's are allowed in HTTP requests from ** TH1 scripts. If empty, no HTTP requests are allowed ** whatsoever. The default is an empty string. ** ** web-browser A shell command used to launch your preferred ** web browser when given a URL as an argument. ** Defaults to "start" on windows, "open" on Mac, ** and "firefox" on Unix. ** ** Options: |
| ︙ | ︙ | |||
2439 2440 2441 2442 2443 2444 2445 |
if( g.argc!=3 ) usage("TIMESTAMP");
sqlite3_open(":memory:", &g.db);
rDiff = db_double(0.0, "SELECT julianday('now') - julianday(%Q)", g.argv[2]);
fossil_print("Time differences: %s\n", db_timespan_name(rDiff));
sqlite3_close(g.db);
g.db = 0;
}
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 |
if( g.argc!=3 ) usage("TIMESTAMP");
sqlite3_open(":memory:", &g.db);
rDiff = db_double(0.0, "SELECT julianday('now') - julianday(%Q)", g.argv[2]);
fossil_print("Time differences: %s\n", db_timespan_name(rDiff));
sqlite3_close(g.db);
g.db = 0;
}
/*
** COMMAND: test-without-rowid
** %fossil test-without-rowid FILENAME...
**
** Change the Fossil repository FILENAME to make use of the WITHOUT ROWID
** optimization. FILENAME can also be the ~/.fossil file or a local
** .fslckout or _FOSSIL_ file.
**
** The purpose of this command is for testing the WITHOUT ROWID capabilities
** of SQLite. There is no big advantage to using WITHOUT ROWID in Fossil.
**
** Options:
** --dryrun | -n No changes. Just print what would happen.
*/
void test_without_rowid(void){
int i, j;
Stmt q;
Blob allSql;
int dryRun = find_option("dry-run", "n", 0)!=0;
for(i=2; i<g.argc; i++){
db_open_or_attach(g.argv[i], "main", 0);
blob_init(&allSql, "BEGIN;\n", -1);
db_prepare(&q,
"SELECT name, sql FROM main.sqlite_master "
" WHERE type='table' AND sql NOT LIKE '%%WITHOUT ROWID%%'"
" AND name IN ('global_config','shun','concealed','config',"
" 'plink','tagxref','backlink','vcache');"
);
while( db_step(&q)==SQLITE_ROW ){
const char *zTName = db_column_text(&q, 0);
const char *zOrigSql = db_column_text(&q, 1);
Blob newSql;
blob_init(&newSql, 0, 0);
for(j=0; zOrigSql[j]; j++){
if( fossil_strnicmp(zOrigSql+j,"unique",6)==0 ){
blob_append(&newSql, zOrigSql, j);
blob_append(&newSql, "PRIMARY KEY", -1);
zOrigSql += j+6;
j = -1;
}
}
blob_append(&newSql, zOrigSql, -1);
blob_appendf(&allSql,
"ALTER TABLE %s RENAME TO x_%s;\n"
"%s WITHOUT ROWID;\n"
"INSERT INTO %s SELECT * FROM x_%s;\n"
"DROP TABLE x_%s;\n",
zTName, zTName, blob_str(&newSql), zTName, zTName, zTName
);
fossil_print("Converting table %s of %s to WITHOUT ROWID.\n", zTName, g.argv[i]);
blob_reset(&newSql);
}
blob_appendf(&allSql, "COMMIT;\n");
db_finalize(&q);
if( dryRun ){
fossil_print("SQL that would have been evaluated:\n");
fossil_print("-------------------------------------------------------------\n");
fossil_print("%s", blob_str(&allSql));
}else{
db_multi_exec("%s", blob_str(&allSql));
}
blob_reset(&allSql);
db_close(1);
}
}
|
Changes to src/descendants.c.
| ︙ | ︙ | |||
155 156 157 158 159 160 161 |
}
/*
** 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){
| | | | > | < | | | > > > | < < | | < < < < < < < < < < < < < < < < < < | 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 |
}
/*
** Load the record ID rid and up to N-1 closest ancestors into
** the "ok" table.
*/
void compute_ancestors(int rid, int N, int directOnly){
db_multi_exec(
"WITH RECURSIVE "
" ancestor(rid, mtime) AS ("
" SELECT %d, mtime FROM event WHERE objid=%d "
" UNION "
" SELECT plink.pid, event.mtime"
" FROM ancestor, plink, event"
" WHERE plink.cid=ancestor.rid"
" AND event.objid=plink.pid %s"
" ORDER BY mtime DESC LIMIT %d"
" )"
"INSERT INTO ok"
" SELECT rid FROM ancestor;",
rid, rid, directOnly ? "AND plink.isPrim" : "", N
);
}
/*
** Compute up to N direct ancestors (merge ancestors do not count)
** for the check-in rid and put them in a table named "ancestor".
** Label each generation with consecutive integers going backwards
** in time such that rid has the smallest generation number and the oldest
|
| ︙ | ︙ | |||
462 463 464 465 466 467 468 |
blob_appendf(&sql," AND NOT %z", leaf_is_closed_sql("blob.rid"));
}
db_prepare(&q, "%s ORDER BY event.mtime DESC", blob_str(&sql));
blob_reset(&sql);
www_print_timeline(&q, TIMELINE_LEAFONLY, 0, 0, 0);
db_finalize(&q);
@ <br />
| < < < < < < | 445 446 447 448 449 450 451 452 453 454 455 456 457 458 |
blob_appendf(&sql," AND NOT %z", leaf_is_closed_sql("blob.rid"));
}
db_prepare(&q, "%s ORDER BY event.mtime DESC", blob_str(&sql));
blob_reset(&sql);
www_print_timeline(&q, TIMELINE_LEAFONLY, 0, 0, 0);
db_finalize(&q);
@ <br />
style_footer();
}
#if INTERFACE
/* Flag parameters to compute_uses_file() */
#define USESFILE_DELETE 0x01 /* Include the check-ins where file deleted */
|
| ︙ | ︙ |
Changes to src/diff.c.
| ︙ | ︙ | |||
801 802 803 804 805 806 807 |
p->zStart = zClassRm;
}else{
p->zStart = zClassChng;
}
p->iStart2 = nPrefix + aLCS[1];
p->iEnd2 = nLeft - nSuffix;
p->zStart2 = aLCS[3]==nRightDiff ? zClassRm : zClassChng;
| | | | 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 |
p->zStart = zClassRm;
}else{
p->zStart = zClassChng;
}
p->iStart2 = nPrefix + aLCS[1];
p->iEnd2 = nLeft - nSuffix;
p->zStart2 = aLCS[3]==nRightDiff ? zClassRm : zClassChng;
sbsSimplifyLine(p, zLeft);
sbsWriteText(p, pLeft, SBS_TXTA);
sbsWriteMarker(p, " | ", "|");
sbsWriteLineno(p, lnRight, SBS_LNB);
p->iStart = nPrefix;
p->iEnd = nPrefix + aLCS[2];
if( aLCS[0]==0 ){
sbsShiftLeft(p, pRight->z);
p->zStart = zClassAdd;
}else{
p->zStart = zClassChng;
}
p->iStart2 = nPrefix + aLCS[3];
p->iEnd2 = nRight - nSuffix;
p->zStart2 = aLCS[1]==nLeftDiff ? zClassAdd : zClassChng;
sbsSimplifyLine(p, zRight);
sbsWriteText(p, pRight, SBS_TXTB);
return;
}
/* If all else fails, show a single big change between left and right */
sbsWriteLineno(p, lnLeft, SBS_LNA);
p->iStart2 = p->iEnd2 = 0;
|
| ︙ | ︙ | |||
1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 |
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);
| > > | 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 |
if( diffFlags & DIFF_INVERT ){
Blob *pTemp = pA_Blob;
pA_Blob = pB_Blob;
pB_Blob = pTemp;
}
ignoreEolWs = (diffFlags & DIFF_IGNORE_EOLWS)!=0;
blob_to_utf8_no_bom(pA_Blob, 0);
blob_to_utf8_no_bom(pB_Blob, 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);
|
| ︙ | ︙ | |||
2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 | x2 = c2&0xff; c |= (x1*(n-i) + x2*i)/n & 0xff; return c; } /* ** WEBPAGE: annotate ** ** 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 | > | 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 | 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 |
| ︙ | ︙ | |||
2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 |
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;
/* 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");
| > | 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 |
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");
|
| ︙ | ︙ | |||
2175 2176 2177 2178 2179 2180 2181 |
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",
| | | | | | | 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 |
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));
}
if( ann.bLimit ){
char *z1, *z2;
style_submenu_element("All Ancestors", "All Ancestors",
"%s", url_render(&url, "limit", "-1", 0, 0));
z1 = sqlite3_mprintf("%d Ancestors", iLimit+20);
z2 = sqlite3_mprintf("%d", iLimit+20);
style_submenu_element(z1, z1, "%s", url_render(&url, "limit", z2, 0, 0));
}
if( iLimit>20 ){
style_submenu_element("20 Ancestors", "20 Ancestors",
"%s", url_render(&url, "limit", "20", 0, 0));
}
if( db_get_boolean("white-foreground", 0) ){
clr1 = 0xa04040;
clr2 = 0x4059a0;
}else{
clr1 = 0xffb5b5; /* Recent changes: red (hot) */
clr2 = 0xb5e0ff; /* Older changes: blue (cold) */
|
| ︙ | ︙ | |||
2249 2250 2251 2252 2253 2254 2255 |
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;
| > > | | | | | > > > > > > > > > > > > | | | | | > | 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 |
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();
}
|
| ︙ | ︙ |
Changes to src/diffcmd.c.
| ︙ | ︙ | |||
597 598 599 600 601 602 603 | return db_get(zName, zDefault); } /* A Tcl/Tk script used to render diff output. */ static const char zDiffScript[] = @ package require Tk | | | 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 |
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
|
| ︙ | ︙ | |||
620 621 622 623 624 625 626 | @ FN_FG #ffffff @ FN_PAD 5 @ PADX 5 @ WIDTH 80 @ HEIGHT 45 @ LB_HEIGHT 25 @ } | | | | | | | | | | | | | | | | | | | | | | | > | | 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 |
@ FN_FG #ffffff
@ FN_PAD 5
@ PADX 5
@ WIDTH 80
@ HEIGHT 45
@ LB_HEIGHT 25
@ }
@
@ if {![namespace exists ttk]} {
@ interp alias {} ::ttk::scrollbar {} ::scrollbar
@ interp alias {} ::ttk::menubutton {} ::menubutton
@ }
@
@ proc dehtml {x} {
@ set x [regsub -all {<[^>]*>} $x {}]
@ return [string map {& & < < > > ' ' " \"} $x]
@ }
@
@ proc cols {} {
@ return [list .lnA .txtA .mkr .lnB .txtB]
@ }
@
@ proc colType {c} {
@ regexp {[a-z]+} $c type
@ return $type
@ }
@
@ proc readDiffs {fossilcmd} {
@ set in [open $fossilcmd r]
@ fconfigure $in -encoding utf-8
@ set nDiffs 0
@ array set widths {txt 0 ln 0 mkr 0}
@ while {[gets $in line] != -1} {
@ if {![regexp {^=+\s+(.*?)\s+=+$} $line all fn]} {
@ continue
@ }
@ if {[string compare -length 6 [gets $in] "<table"]} {
@ continue
@ }
@ incr nDiffs
@ set idx [expr {$nDiffs > 1 ? [.txtA index end] : "1.0"}]
@ .wfiles.lb insert end $fn
@
@ foreach c [cols] {
@ while {[gets $in] ne "<pre>"} continue
@
@ if {$nDiffs > 1} {
@ $c insert end \n -
@ }
@ if {[colType $c] eq "txt"} {
@ $c insert end $fn\n fn
@ } else {
@ $c insert end \n fn
@ }
@ $c insert end \n -
@
@ set type [colType $c]
@ set str {}
@ while {[set line [gets $in]] ne "</pre>"} {
@ set len [string length [dehtml $line]]
@ if {$len > $widths($type)} {
@ set widths($type) $len
@ }
@ append str $line\n
@ }
@
@ set re {<span class="diff([a-z]+)">([^<]*)</span>}
@ # Use \r as separator since it can't appear in the diff output (it gets
@ # converted to a space).
@ set str [regsub -all $re $str "\r\\1\r\\2\r"]
@ foreach {pre class mid} [split $str \r] {
@ if {$class ne ""} {
@ $c insert end [dehtml $pre] - [dehtml $mid] [list $class -]
@ } else {
@ $c insert end [dehtml $pre] -
@ }
@ }
@ }
@ }
@ close $in
@
@ foreach c [cols] {
@ set type [colType $c]
@ if {$type ne "txt"} {
@ $c config -width $widths($type)
@ }
@ $c config -state disabled
@ }
@ if {$nDiffs <= [.wfiles.lb cget -height]} {
@ .wfiles.lb config -height $nDiffs
@ grid remove .wfiles.sb
@ }
@
@ return $nDiffs
@ }
@
@ proc viewDiff {idx} {
@ .txtA yview $idx
@ .txtA xview moveto 0
@ }
@
@ proc cycleDiffs {{reverse 0}} {
@ if {$reverse} {
@ set range [.txtA tag prevrange fn @0,0 1.0]
@ if {$range eq ""} {
@ viewDiff {fn.last -1c}
@ } else {
@ viewDiff [lindex $range 0]
@ }
@ } else {
@ set range [.txtA tag nextrange fn {@0,0 +1c} end]
@ if {$range eq "" || [lindex [.txtA yview] 1] == 1} {
@ viewDiff fn.first
@ } else {
@ viewDiff [lindex $range 0]
@ }
@ }
@ }
@
@ proc xvis {col} {
@ set view [$col xview]
@ return [expr {[lindex $view 1]-[lindex $view 0]}]
@ }
@
@ proc scroll-x {args} {
@ set c .txt[expr {[xvis .txtA] < [xvis .txtB] ? "A" : "B"}]
@ eval $c xview $args
@ }
@
@ interp alias {} scroll-y {} .txtA yview
@
@ proc noop {args} {}
@
@ proc enableSync {axis} {
@ update idletasks
@ interp alias {} sync-$axis {}
@ rename _sync-$axis sync-$axis
@ }
@
@ proc disableSync {axis} {
@ rename sync-$axis _sync-$axis
@ interp alias {} sync-$axis {} noop
@ }
@
@ proc sync-x {col first last} {
@ disableSync x
@ $col xview moveto [expr {$first*[xvis $col]/($last-$first)}]
@ foreach side {A B} {
@ set sb .sbx$side
@ set xview [.txt$side xview]
@ if {[lindex $xview 0] > 0 || [lindex $xview 1] < 1} {
@ grid $sb
@ eval $sb set $xview
@ } else {
@ grid remove $sb
@ }
@ }
@ enableSync x
@ }
@
@ proc sync-y {first last} {
@ disableSync y
@ foreach c [cols] {
@ $c yview moveto $first
@ }
@ if {$first > 0 || $last < 1} {
@ grid .sby
@ .sby set $first $last
@ } else {
@ grid remove .sby
@ }
@ enableSync y
@ }
@
@ wm withdraw .
@ wm title . $CFG(TITLE)
@ wm iconname . $CFG(TITLE)
@ bind . <q> exit
@ bind . <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 \
|
| ︙ | ︙ | |||
845 846 847 848 849 850 851 |
@ 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 920 921 922 923 924 |
@ 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.
*/
void diff_tk(const char *zSubCmd, int firstArg){
int i;
Blob script;
char *zTempFile = 0;
char *zCmd;
|
| ︙ | ︙ | |||
941 942 943 944 945 946 947 948 949 950 951 952 953 954 |
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{
zTempFile = write_blob_to_temp_file(&script);
zCmd = mprintf("tclsh \"%s\"", zTempFile);
fossil_system(zCmd);
file_delete(zTempFile);
fossil_free(zCmd);
}
blob_reset(&script);
| > > > > > > > > > > > > > > | 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 |
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)
Th_FossilInit(TH_INIT_DEFAULT);
if( evaluateTclWithEvents(g.interp, &g.tcl, blob_str(&script),
blob_size(&script), 1)==TCL_OK ){
blob_reset(&script);
return;
}
/*
* If evaluation of the Tcl script fails, the reason may be that Tk
* could not be found by the loaded Tcl, or that Tcl cannot be loaded
* dynamically (e.g. x64 Tcl with x86 Fossil). Therefore, fallback
* to using the external "tclsh", if available.
*/
#endif
zTempFile = write_blob_to_temp_file(&script);
zCmd = mprintf("tclsh \"%s\"", zTempFile);
fossil_system(zCmd);
file_delete(zTempFile);
fossil_free(zCmd);
}
blob_reset(&script);
|
| ︙ | ︙ | |||
986 987 988 989 990 991 992 | ** ** 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. ** |
| ︙ | ︙ | |||
1013 1014 1015 1016 1017 1018 1019 | ** 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 | | | 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 | ** 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 |
| ︙ | ︙ |
Changes to src/doc.c.
| ︙ | ︙ | |||
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);
| > | 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 |
/* Get the file content */
if( content_get(rid, &filebody)==0 ){
goto doc_not_found;
}
db_end_transaction(0);
}
blob_to_utf8_no_bom(&filebody, 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.
| ︙ | ︙ | |||
349 350 351 352 353 354 355 |
}
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);
| | | 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 |
}
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);
manifest_crosslink(nrid, &event, MC_NONE);
assert( blob_is_reset(&event) );
content_deltify(rid, nrid, 0);
db_end_transaction(0);
cgi_redirectf("event?name=%T", zEventId);
}
if( P("cancel")!=0 ){
cgi_redirectf("event?name=%T", zEventId);
|
| ︙ | ︙ |
Changes to src/file.c.
| ︙ | ︙ | |||
37 38 39 40 41 42 43 | # include <direct.h> # include <windows.h> # include <sys/utime.h> #else # include <sys/time.h> #endif | > | < < > | > > > > > | | > > > > > > | > > > | > | | < > > > | < < < | 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 |
# include <direct.h>
# include <windows.h>
# include <sys/utime.h>
#else
# include <sys/time.h>
#endif
#if INTERFACE
#include <dirent.h>
#if defined(_WIN32)
# define DIR _WDIR
# define dirent _wdirent
# define opendir _wopendir
# define readdir _wreaddir
# define closedir _wclosedir
#endif /* _WIN32 */
#if defined(_WIN32) && (defined(__MSVCRT__) || defined(_MSC_VER))
struct fossilStat {
i64 st_size;
i64 st_mtime;
int st_mode;
};
#endif
#endif /* INTERFACE */
#if !defined(_WIN32) || !(defined(__MSVCRT__) || defined(_MSC_VER))
# define fossilStat stat
#endif
/*
** On Windows S_ISLNK always returns FALSE.
*/
#if !defined(S_ISLNK)
# define S_ISLNK(x) (0)
#endif
static int fileStatValid = 0;
static struct fossilStat fileStat;
/*
** Fill stat buf with information received from stat() or lstat().
** lstat() is called on Unix if isWd is TRUE and allow-symlinks setting is on.
**
*/
static int fossil_stat(const char *zFilename, struct fossilStat *buf, int isWd){
#if !defined(_WIN32)
int rc;
char *zMbcs = fossil_utf8_to_filename(zFilename);
if( isWd && g.allowSymlinks ){
rc = lstat(zMbcs, buf);
}else{
rc = stat(zMbcs, buf);
}
fossil_filename_free(zMbcs);
return rc;
#else
return win32_stat(zFilename, buf, isWd);
#endif
}
/*
** Fill in the fileStat variable for the file named zFilename.
** If zFilename==0, then use the previous value of fileStat if
** there is a previous value.
**
|
| ︙ | ︙ | |||
301 302 303 304 305 306 307 |
/*
** Wrapper around the access() system call.
*/
int file_access(const char *zFilename, int flags){
#ifdef _WIN32
| | < < > < | < > | 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 |
/*
** Wrapper around the access() system call.
*/
int file_access(const char *zFilename, int flags){
#ifdef _WIN32
return win32_access(zFilename, flags);
#else
char *zMbcs = fossil_utf8_to_filename(zFilename);
int rc = access(zMbcs, flags);
fossil_filename_free(zMbcs);
return rc;
#endif
}
/*
** Wrapper around the chdir() system call.
** If bChroot=1, do a chroot to this dir as well
** (UNIX only)
*/
int file_chdir(const char *zChDir, int bChroot){
#ifdef _WIN32
return win32_chdir(zChDir, bChroot);
#else
char *zPath = fossil_utf8_to_filename(zChDir);
int rc = chdir(zPath);
if( !rc && bChroot ){
rc = chroot(zPath);
if( !rc ) rc = chdir("/");
}
fossil_filename_free(zPath);
return rc;
#endif
}
/*
** Find an unused filename similar to zBase with zSuffix appended.
**
** Make the name relative to the working directory if relFlag is true.
**
|
| ︙ | ︙ | |||
418 419 420 421 422 423 424 425 426 427 428 |
}
/*
** Set the mtime for a file.
*/
void file_set_mtime(const char *zFilename, i64 newMTime){
#if !defined(_WIN32)
struct timeval tv[2];
memset(tv, 0, sizeof(tv[0])*2);
tv[0].tv_sec = newMTime;
tv[1].tv_sec = newMTime;
| > | | 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 |
}
/*
** Set the mtime for a file.
*/
void file_set_mtime(const char *zFilename, i64 newMTime){
#if !defined(_WIN32)
char *zMbcs;
struct timeval tv[2];
memset(tv, 0, sizeof(tv[0])*2);
tv[0].tv_sec = newMTime;
tv[1].tv_sec = newMTime;
zMbcs = fossil_utf8_to_filename(zFilename);
utimes(zMbcs, tv);
#else
struct _utimbuf tb;
wchar_t *zMbcs = fossil_utf8_to_filename(zFilename);
tb.actime = newMTime;
tb.modtime = newMTime;
_wutime(zMbcs, &tb);
|
| ︙ | ︙ | |||
688 689 690 691 692 693 694 |
i += 2;
continue;
}
}
if( j>=0 ) z[j] = z[i];
j++;
}
| | | 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 |
i += 2;
continue;
}
}
if( j>=0 ) z[j] = z[i];
j++;
}
if( j==0 ) z[j++] = '/';
z[j] = 0;
return j;
}
/*
** COMMAND: test-simplify-name
**
|
| ︙ | ︙ | |||
721 722 723 724 725 726 727 |
**
** On windows, the name is converted from unicode to UTF8 and all '\\'
** characters are converted to '/'. No conversions are needed on
** unix.
*/
void file_getcwd(char *zBuf, int nBuf){
#ifdef _WIN32
| < < < < < < < < < < < < < | < | 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 |
**
** On windows, the name is converted from unicode to UTF8 and all '\\'
** characters are converted to '/'. No conversions are needed on
** unix.
*/
void file_getcwd(char *zBuf, int nBuf){
#ifdef _WIN32
win32_getcwd(zBuf, nBuf);
#else
if( getcwd(zBuf, nBuf-1)==0 ){
if( errno==ERANGE ){
fossil_fatal("pwd too big: max %d\n", nBuf-1);
}else{
fossil_fatal("cannot find current working directory; %s",
strerror(errno));
|
| ︙ | ︙ | |||
776 777 778 779 780 781 782 783 784 785 |
** Remove redundant / characters
** Remove all /./ path elements.
** Convert /A/../ to just /
** If the slash parameter is non-zero, the trailing slash, if any,
** is retained.
*/
void file_canonical_name(const char *zOrigName, Blob *pOut, int slash){
if( file_is_absolute_path(zOrigName) ){
#if defined(_WIN32) || defined(__CYGWIN__)
char *zOut;
| > > > > > > > > > > > > > > > > > > < < < < | < < < < < < < < < < | < < < | 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 |
** Remove redundant / characters
** Remove all /./ path elements.
** Convert /A/../ to just /
** If the slash parameter is non-zero, the trailing slash, if any,
** is retained.
*/
void file_canonical_name(const char *zOrigName, Blob *pOut, int slash){
blob_zero(pOut);
if( file_is_absolute_path(zOrigName) ){
blob_appendf(pOut, "%/", zOrigName);
}else{
char zPwd[2000];
file_getcwd(zPwd, sizeof(zPwd)-strlen(zOrigName));
if( zPwd[0]=='/' && strlen(zPwd)==1 ){
/* when on '/', don't add an extra '/' */
if( zOrigName[0]=='.' && strlen(zOrigName)==1 ){
/* '.' when on '/' mean '/' */
blob_appendf(pOut, "%/", zPwd);
}else{
blob_appendf(pOut, "%/%/", zPwd, zOrigName);
}
}else{
blob_appendf(pOut, "%//%/", zPwd, zOrigName);
}
}
#if defined(_WIN32) || defined(__CYGWIN__)
{
char *zOut;
/*
** On Windows/cygwin, normalize the drive letter to upper case.
*/
zOut = blob_str(pOut);
if( fossil_islower(zOut[0]) && zOut[1]==':' && zOut[2]=='/' ){
zOut[0] = fossil_toupper(zOut[0]);
}
}
#endif
blob_resize(pOut, file_simplify_name(blob_buffer(pOut),
blob_size(pOut), slash));
}
/*
** COMMAND: test-canonical-name
** Usage: %fossil test-canonical-name FILENAME...
|
| ︙ | ︙ | |||
927 928 929 930 931 932 933 |
memcpy(&tmp, pOut, sizeof(tmp));
blob_set(pOut, "./");
blob_append(pOut, &zPath[i+1], -1);
blob_reset(&tmp);
return;
}
while( zPath[i-1]!='/' ){ i--; }
| > > > > | > | 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 |
memcpy(&tmp, pOut, sizeof(tmp));
blob_set(pOut, "./");
blob_append(pOut, &zPath[i+1], -1);
blob_reset(&tmp);
return;
}
while( zPath[i-1]!='/' ){ i--; }
if( zPwd[0]=='/' && strlen(zPwd)==1 ){
/* If on '/', don't go to higher level */
blob_zero(&tmp);
}else{
blob_set(&tmp, "../");
}
for(j=i; zPwd[j]; j++){
if( zPwd[j]=='/' ){
blob_append(&tmp, "../", 3);
}
}
blob_append(&tmp, &zPath[i], -1);
blob_reset(pOut);
|
| ︙ | ︙ | |||
989 990 991 992 993 994 995 |
if( filenames_are_case_sensitive() ){
xCmp = fossil_strncmp;
}else{
xCmp = fossil_strnicmp;
}
/* Special case. zOrigName refers to g.zLocalRoot directory. */
| | > | 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 |
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;
}
if( nFull<=nLocalRoot || xCmp(zLocalRoot, zFull, nLocalRoot) ){
|
| ︙ | ︙ | |||
1169 1170 1171 1172 1173 1174 1175 |
blob_read_from_file(&onDisk, zName);
}
rc = blob_compare(&onDisk, pContent);
blob_reset(&onDisk);
return rc==0;
}
| < < < < < < < < < < < < < < < < | 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 |
blob_read_from_file(&onDisk, zName);
}
rc = blob_compare(&onDisk, pContent);
blob_reset(&onDisk);
return rc==0;
}
/*
** Return the value of an environment variable as UTF8.
** Use fossil_filename_free() to release resources.
*/
char *fossil_getenv(const char *zName){
#ifdef _WIN32
wchar_t *uName = fossil_utf8_to_unicode(zName);
|
| ︙ | ︙ |
Changes to src/finfo.c.
| ︙ | ︙ | |||
47 48 49 50 51 52 53 | ** -l|--log select log mode (the default) ** -n|--limit N display the first N changes. N=0 means no limit. ** --offset P skip P changes ** -p|--print select print mode ** -r|--revision R print the given revision (or ckout, if none is given) ** to stdout (only in print mode) ** -s|--status select status mode (print a status indicator for FILE) | | > | 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
** -l|--log select log mode (the default)
** -n|--limit N display the first N changes. N=0 means no limit.
** --offset P skip P changes
** -p|--print select print mode
** -r|--revision R print the given revision (or ckout, if none is given)
** to stdout (only in print mode)
** -s|--status select status mode (print a status indicator for FILE)
** -W|--width <num> With of lines (default 79). Must be >22 or 0
** (= no limit, resulting in a single line per entry).
**
** See also: artifact, cat, descendants, info, leaves
*/
void finfo_cmd(void){
capture_case_sensitive_option();
db_must_be_within_tree();
if( find_option("status","s",0) ){
|
| ︙ | ︙ | |||
161 162 163 164 165 166 167 |
rid = db_int(0, "SELECT rid FROM vfile WHERE pathname=%B %s",
&fname, filename_collation());
if( rid==0 ){
fossil_fatal("no history for file: %b", &fname);
}
zFilename = blob_str(&fname);
db_prepare(&q,
| | | > | 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 |
rid = db_int(0, "SELECT rid FROM vfile WHERE pathname=%B %s",
&fname, filename_collation());
if( rid==0 ){
fossil_fatal("no history for file: %b", &fname);
}
zFilename = blob_str(&fname);
db_prepare(&q,
"SELECT b.uuid, ci.uuid, date(event.mtime%s),"
" coalesce(event.ecomment, event.comment),"
" coalesce(event.euser, event.user),"
" (SELECT value FROM tagxref WHERE tagid=%d AND tagtype>0"
" AND tagxref.rid=mlink.mid)" /* Tags */
" FROM mlink, blob b, event, blob ci, filename"
" WHERE filename.name=%Q %s"
" AND mlink.fnid=filename.fnid"
" AND b.rid=mlink.fid"
" AND event.objid=mlink.mid"
" AND event.objid=ci.rid"
" ORDER BY event.mtime DESC LIMIT %d OFFSET %d",
timeline_utc(), TAG_BRANCH, zFilename, filename_collation(),
iLimit, iOffset
);
blob_zero(&line);
if( iBrief ){
fossil_print("History of %s\n", blob_str(&fname));
}
while( db_step(&q)==SQLITE_ROW ){
const char *zFileUuid = db_column_text(&q, 0);
|
| ︙ | ︙ | |||
202 203 204 205 206 207 208 |
}else{
blob_reset(&line);
blob_appendf(&line, "%.10s ", zCiUuid);
blob_appendf(&line, "%.10s ", zDate);
blob_appendf(&line, "%8.8s ", zUser);
blob_appendf(&line, "%8.8s ", zBr);
blob_appendf(&line,"%-39.39s", zCom );
| | | 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 |
}else{
blob_reset(&line);
blob_appendf(&line, "%.10s ", zCiUuid);
blob_appendf(&line, "%.10s ", zDate);
blob_appendf(&line, "%8.8s ", zUser);
blob_appendf(&line, "%8.8s ", zBr);
blob_appendf(&line,"%-39.39s", zCom );
comment_print(blob_str(&line), 0, iWidth);
}
}
db_finalize(&q);
blob_reset(&fname);
}
}
|
| ︙ | ︙ | |||
291 292 293 294 295 296 297 |
style_header("File History");
login_anonymous_available();
url_initialize(&url, "finfo");
if( brBg ) url_add_parameter(&url, "brbg", 0);
if( uBg ) url_add_parameter(&url, "ubg", 0);
baseCheckin = name_to_rid_www("ci");
if( baseCheckin ) firstChngOnly = 1;
| | | | | | 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 |
style_header("File History");
login_anonymous_available();
url_initialize(&url, "finfo");
if( brBg ) url_add_parameter(&url, "brbg", 0);
if( uBg ) url_add_parameter(&url, "ubg", 0);
baseCheckin = name_to_rid_www("ci");
if( baseCheckin ) firstChngOnly = 1;
if( !firstChngOnly ) url_add_parameter(&url, "fco", "0");
zPrevDate[0] = 0;
zFilename = PD("name","");
url_add_parameter(&url, "name", zFilename);
blob_zero(&sql);
blob_appendf(&sql,
"SELECT"
" datetime(event.mtime%s)," /* Date of change */
" coalesce(event.ecomment, event.comment)," /* Check-in comment */
" coalesce(event.euser, event.user)," /* User who made chng */
" mlink.pid," /* Parent file rid */
" mlink.fid," /* File rid */
" (SELECT uuid FROM blob WHERE rid=mlink.pid)," /* Parent file uuid */
" (SELECT uuid FROM blob WHERE rid=mlink.fid)," /* Current file uuid */
" (SELECT uuid FROM blob WHERE rid=mlink.mid)," /* Check-in uuid */
" event.bgcolor," /* Background color */
" (SELECT value FROM tagxref WHERE tagid=%d AND tagtype>0"
" AND tagxref.rid=mlink.mid)," /* Tags */
" mlink.mid," /* check-in ID */
" 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
}
|
| ︙ | ︙ | |||
359 360 361 362 363 364 365 |
if( baseCheckin==0 ){
if( firstChngOnly ){
style_submenu_element("Full", "Show all changes","%s",
url_render(&url, "fco", "0", 0, 0));
}else{
style_submenu_element("Simplified",
"Show only first use of a change","%s",
| | | | | 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 |
if( baseCheckin==0 ){
if( firstChngOnly ){
style_submenu_element("Full", "Show all changes","%s",
url_render(&url, "fco", "0", 0, 0));
}else{
style_submenu_element("Simplified",
"Show only first use of a change","%s",
url_render(&url, "fco", 0, 0, 0));
}
}
db_prepare(&q, blob_str(&sql));
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", "");
}
@ <h2>%b(&title)</h2>
blob_reset(&title);
pGraph = graph_init();
@ <div id="canvas" style="position:relative;width:1px;height:1px;"
@ onclick="clickOnGraph(event)"></div>
@ <table id="timelineTable" class="timelineTable">
|
| ︙ | ︙ | |||
460 461 462 463 464 465 466 467 468 469 |
}
hyperlink_to_uuid(zShortCkin);
@ %w(zCom) (user:
hyperlink_to_user(zUser, zDate, "");
@ branch: %h(zBr))
if( g.perm.Hyperlink && zUuid ){
const char *z = zFilename;
if( fpid ){
@ %z(href("%R/fdiff?v1=%S&v2=%S&sbs=1",zPUuid,zUuid))[diff]</a>
}
| > > > > > < < < | 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 |
}
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 ){
@ srcid=%d(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 |
**
** [...] 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){
return sqlite3_strglob(zGlob, 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( sqlite3_strglob(pGlob->azPattern[i], zString)==0 ) return i+1;
}
return 0;
}
/*
** Free all memory associated with the given Glob object
*/
|
| ︙ | ︙ |
Changes to src/gzip.c.
| ︙ | ︙ | |||
53 54 55 56 57 58 59 | char aHdr[10]; assert( gzip.eState==0 ); blob_zero(&gzip.out); aHdr[0] = 0x1f; aHdr[1] = 0x8b; aHdr[2] = 8; aHdr[3] = 0; | | | | 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 |
char aHdr[10];
assert( gzip.eState==0 );
blob_zero(&gzip.out);
aHdr[0] = 0x1f;
aHdr[1] = 0x8b;
aHdr[2] = 8;
aHdr[3] = 0;
if( now==-1 ){
now = db_int64(0, "SELECT (julianday('now') - 2440587.5)*86400.0");
}
put32(&aHdr[4], now&0xffffffff);
aHdr[8] = 2;
aHdr[9] = 255;
blob_append(&gzip.out, aHdr, 10);
gzip.iCRC = 0;
gzip.eState = 1;
}
/*
** 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;
|
| ︙ | ︙ | |||
124 125 126 127 128 129 130 |
** Compress a file using gzip.
*/
void test_gzip_cmd(void){
Blob b;
char *zOut;
if( g.argc!=3 ) usage("FILENAME");
sqlite3_open(":memory:", &g.db);
| | | 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 |
** Compress a file using gzip.
*/
void test_gzip_cmd(void){
Blob b;
char *zOut;
if( g.argc!=3 ) usage("FILENAME");
sqlite3_open(":memory:", &g.db);
gzip_begin(-1);
blob_read_from_file(&b, g.argv[2]);
zOut = mprintf("%s.gz", g.argv[2]);
gzip_step(blob_buffer(&b), blob_size(&b));
blob_reset(&b);
gzip_finish(&b);
blob_write_to_file(&b, zOut);
blob_reset(&b);
fossil_free(zOut);
}
|
Changes to src/http.c.
| ︙ | ︙ | |||
108 109 110 111 112 113 114 |
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);
| | < | 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
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));
|
| ︙ | ︙ | |||
142 143 144 145 146 147 148 | 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 ){
|
| ︙ | ︙ | |||
189 190 191 192 193 194 195 |
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 |
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++;
|
| ︙ | ︙ | |||
253 254 255 256 257 258 259 |
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;
|
| ︙ | ︙ | |||
280 281 282 283 284 285 286 | } /* ** 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]=='<' ){
|
| ︙ | ︙ | |||
309 310 311 312 313 314 315 |
** 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 ){
| | | | | 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 |
** 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.
| ︙ | ︙ | |||
129 130 131 132 133 134 135 | ** 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. */ | | | | | | | > | 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 |
** 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 */
socket_global_init();
if( !addrIsInit ){
addr.sin_family = AF_INET;
addr.sin_port = htons(pUrlData->port);
*(int*)&addr.sin_addr = inet_addr(pUrlData->name);
if( -1 == *(int*)&addr.sin_addr ){
#ifndef FOSSIL_STATIC_LINK
struct hostent *pHost;
pHost = gethostbyname(pUrlData->name);
if( pHost!=0 ){
memcpy(&addr.sin_addr,pHost->h_addr_list[0],pHost->h_length);
}else
#endif
{
socket_set_errmsg("can't resolve host name: %s", pUrlData->name);
return 1;
}
}
addrIsInit = 1;
/* Set the Global.zIpAddr variable to the server we are talking to.
** This is used to populate the ipaddr column of the rcvfrom table,
** if any files are received from the server.
*/
g.zIpAddr = mprintf("%s", inet_ntoa(addr.sin_addr));
}
iSocket = socket(AF_INET,SOCK_STREAM,0);
if( iSocket<0 ){
socket_set_errmsg("cannot create a socket");
return 1;
}
if( connect(iSocket,(struct sockaddr*)&addr,sizeof(addr))<0 ){
socket_set_errmsg("cannot connect to host %s:%d", pUrlData->name,
pUrlData->port);
socket_close();
return 1;
}
#if !defined(_WIN32)
signal(SIGPIPE, SIG_IGN);
#endif
return 0;
|
| ︙ | ︙ | |||
213 214 215 216 217 218 219 | } /* ** 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. */ | | | | 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 |
}
/*
** 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.
| ︙ | ︙ | |||
171 172 173 174 175 176 177 178 179 180 |
*/
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
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | | > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > | < < < < | | | | < | | | | | > > > | | 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 |
*/
void ssl_close(void){
if( iBio!=NULL ){
(void)BIO_reset(iBio);
BIO_free_all(iBio);
}
}
/* See RFC2817 for details */
static int establish_proxy_tunnel(UrlData *pUrlData, BIO *bio){
int rc, httpVerMin;
char *bbuf;
Blob snd, reply;
int done=0,end=0;
blob_zero(&snd);
blob_appendf(&snd, "CONNECT %s:%d HTTP/1.1\r\n", pUrlData->hostname,
pUrlData->proxyOrigPort);
blob_appendf(&snd, "Host: %s:%d\r\n", pUrlData->hostname, pUrlData->proxyOrigPort);
if( pUrlData->proxyAuth ){
blob_appendf(&snd, "Proxy-Authorization: %s\r\n", pUrlData->proxyAuth);
}
blob_append(&snd, "Proxy-Connection: keep-alive\r\n", -1);
blob_appendf(&snd, "User-Agent: %s\r\n", get_user_agent());
blob_append(&snd, "\r\n", 2);
BIO_write(bio, blob_buffer(&snd), blob_size(&snd));
blob_reset(&snd);
/* Wait for end of reply */
blob_zero(&reply);
do{
int len;
char buf[256];
len = BIO_read(bio, buf, sizeof(buf));
blob_append(&reply, buf, len);
bbuf = blob_buffer(&reply);
len = blob_size(&reply);
while(end < len) {
if(bbuf[end] == '\r') {
if(len - end < 4) {
/* need more data */
break;
}
if(memcmp(&bbuf[end], "\r\n\r\n", 4) == 0) {
done = 1;
break;
}
}
end++;
}
}while(!done);
sscanf(bbuf, "HTTP/1.%d %d", &httpVerMin, &rc);
blob_reset(&reply);
return rc;
}
/*
** Open an SSL connection. The identify of the server is determined
** by variables that are set using url_parse():
**
** pUrlData->name Name of the server. Ex: www.fossil-scm.org
** pUrlData->port 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;
unsigned long e;
ssl_global_init();
/* Get certificate for current server from global config and
* (if we have it in config) add it to certificate store.
*/
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;
}
if( pUrlData->useProxy ){
int rc;
BIO *sBio;
char *connStr;
connStr = mprintf("%s:%d", g.urlName, pUrlData->port);
sBio = BIO_new_connect(connStr);
free(connStr);
if( BIO_do_connect(sBio)<=0 ){
ssl_set_errmsg("SSL: cannot connect to proxy %s:%d (%s)",
pUrlData->name, pUrlData->port, ERR_reason_error_string(ERR_get_error()));
ssl_close();
return 1;
}
rc = establish_proxy_tunnel(pUrlData, sBio);
if( rc<200||rc>299 ){
ssl_set_errmsg("SSL: proxy connect failed with HTTP status code %d", rc);
return 1;
}
pUrlData->path = pUrlData->proxyUrlPath;
iBio = BIO_new_ssl(sslCtx, 1);
BIO_push(iBio, sBio);
}else{
iBio = BIO_new_ssl_connect(sslCtx);
}
if( iBio==NULL ) {
ssl_set_errmsg("SSL: cannot open SSL (%s)",
ERR_reason_error_string(ERR_get_error()));
return 1;
}
BIO_get_ssl(iBio, &ssl);
#if (SSLEAY_VERSION_NUMBER >= 0x00908070) && !defined(OPENSSL_NO_TLSEXT)
if( !SSL_set_tlsext_host_name(ssl, (pUrlData->useProxy?pUrlData->hostname: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( !pUrlData->useProxy ){
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->useProxy?pUrlData->hostname:pUrlData->name,
pUrlData->useProxy?pUrlData->proxyOrigPort:pUrlData->port,
ERR_reason_error_string(ERR_get_error()));
ssl_close();
return 1;
}
/* Check if certificate is valid */
cert = SSL_get_peer_certificate(ssl);
if ( cert==NULL ){
|
| ︙ | ︙ | |||
279 280 281 282 283 284 285 |
"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,
| | | | | | | | | | 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 |
"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->useProxy?pUrlData->hostname: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') {
X509_free(cert);
ssl_set_errmsg("SSL certificate declined");
ssl_close();
return 1;
}
if( cReply=='a' || cReply=='A') {
if ( trusted==0 ){
prompt_user("\nSave this certificate as fully trusted (a=always/N)? ",
&ans);
cReply = blob_str(&ans)[0];
trusted = ( cReply=='a' || cReply=='A' );
blob_reset(&ans);
}
ssl_save_certificate(pUrlData, cert, trusted);
}
}
/* Set the Global.zIpAddr variable to the server we are talking to.
** This is used to populate the ipaddr column of the rcvfrom table,
** if any files are received from the server.
*/
{
/* IPv4 only code */
const unsigned char *ip = (const unsigned char *) BIO_get_conn_ip(iBio);
g.zIpAddr = mprintf("%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
}
X509_free(cert);
return 0;
}
/*
** Save certificate to global config.
*/
void ssl_save_certificate(UrlData *pUrlData, X509 *cert, int trusted){
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->useProxy?pUrlData->hostname:pUrlData->name);
db_set(zHost, zCert, 1);
free(zHost);
zHost = mprintf("trusted:%s", pUrlData->useProxy?pUrlData->hostname: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->useProxy?pUrlData->hostname:pUrlData->name);
zCert = db_get(zHost, NULL);
free(zHost);
if ( zCert==NULL )
return NULL;
if ( pTrusted!=0 ){
zHost = mprintf("trusted:%s", pUrlData->useProxy?pUrlData->hostname: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.
| ︙ | ︙ | |||
50 51 52 53 54 55 56 | static int sshIn; /* From ssh subprocess to this process */ static FILE *sshOut; /* From this to ssh subprocess */ /* ** Return the current transport error message. */ | | | | 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
static int sshIn; /* From ssh subprocess to this process */
static FILE *sshOut; /* From this to ssh subprocess */
/*
** Return the current transport error message.
*/
const char *transport_errmsg(UrlData *pUrlData){
#ifdef FOSSIL_ENABLE_SSL
if( pUrlData->isHttps ){
return ssl_errmsg();
}
#endif
return socket_errmsg();
}
/*
|
| ︙ | ︙ | |||
84 85 86 87 88 89 90 | #else static char zDefaultSshCmd[] = "ssh -e none -T"; #endif /* ** SSH initialization of the transport layer */ | | | | | | | | | | | | | 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 |
#else
static char zDefaultSshCmd[] = "ssh -e none -T";
#endif
/*
** SSH initialization of the transport layer
*/
int transport_ssh_open(UrlData *pUrlData){
/* For SSH we need to create and run SSH fossil http
** to talk to the remote machine.
*/
const char *zSsh; /* The base SSH command */
Blob zCmd; /* The SSH command */
char *zHost; /* The host name to contact */
int n; /* Size of prefix string */
socket_ssh_resolve_addr(pUrlData);
zSsh = db_get("ssh-command", zDefaultSshCmd);
blob_init(&zCmd, zSsh, -1);
if( pUrlData->port!=pUrlData->dfltPort && pUrlData->port ){
#ifdef __MINGW32__
blob_appendf(&zCmd, " -P %d", pUrlData->port);
#else
blob_appendf(&zCmd, " -p %d", pUrlData->port);
#endif
}
if( g.fSshTrace ){
fossil_force_newline();
fossil_print("%s", blob_str(&zCmd)); /* Show the base of the SSH command */
}
if( pUrlData->user && pUrlData->user[0] ){
zHost = mprintf("%s@%s", pUrlData->user, pUrlData->name);
}else{
zHost = mprintf("%s", pUrlData->name);
}
n = blob_size(&zCmd);
blob_append(&zCmd, " ", 1);
shell_escape(&zCmd, zHost);
blob_append(&zCmd, " ", 1);
shell_escape(&zCmd, mprintf("%s", pUrlData->fossil));
blob_append(&zCmd, " test-http", 10);
if( pUrlData->path && pUrlData->path[0] ){
blob_append(&zCmd, " ", 1);
shell_escape(&zCmd, mprintf("%s", pUrlData->path));
}
if( g.fSshTrace ){
fossil_print("%s\n", blob_str(&zCmd)+n); /* Show tail of SSH command */
}
free(zHost);
popen2(blob_str(&zCmd), &sshIn, &sshOut, &sshPid);
if( sshPid==0 ){
|
| ︙ | ︙ | |||
144 145 146 147 148 149 150 | ** ** 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. */ | | | | | | | | | | | | | | | | | | | | 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 |
**
** 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 ){
rc = transport_ssh_open(pUrlData);
if( rc==0 ) transport.isOpen = 1;
}else if( pUrlData->isHttps ){
#ifdef FOSSIL_ENABLE_SSL
rc = ssl_open(pUrlData);
if( rc==0 ) transport.isOpen = 1;
#else
socket_set_errmsg("HTTPS: Fossil has been compiled without SSL support");
rc = 1;
#endif
}else if( pUrlData->isFile ){
sqlite3_uint64 iRandId;
sqlite3_randomness(sizeof(iRandId), &iRandId);
transport.zOutFile = mprintf("%s-%llu-out.http",
g.zRepositoryName, iRandId);
transport.zInFile = mprintf("%s-%llu-in.http",
g.zRepositoryName, iRandId);
transport.pFile = fossil_fopen(transport.zOutFile, "wb");
if( transport.pFile==0 ){
fossil_fatal("cannot output temporary file: %s", transport.zOutFile);
}
transport.isOpen = 1;
}else{
rc = socket_open(pUrlData);
if( rc==0 ) transport.isOpen = 1;
}
}
return rc;
}
/*
** Close the current connection
*/
void transport_close(UrlData *pUrlData){
if( transport.isOpen ){
free(transport.pBuf);
transport.pBuf = 0;
transport.nAlloc = 0;
transport.nUsed = 0;
transport.iCursor = 0;
if( transport.pLog ){
fclose(transport.pLog);
transport.pLog = 0;
}
if( pUrlData->isSsh ){
transport_ssh_close();
}else if( pUrlData->isHttps ){
#ifdef FOSSIL_ENABLE_SSL
ssl_close();
#endif
}else if( pUrlData->isFile ){
if( transport.pFile ){
fclose(transport.pFile);
transport.pFile = 0;
}
file_delete(transport.zInFile);
file_delete(transport.zOutFile);
free(transport.zInFile);
free(transport.zOutFile);
}else{
socket_close();
}
transport.isOpen = 0;
}
}
/*
** Send content over the wire.
*/
void transport_send(UrlData *pUrlData, Blob *toSend){
char *z = blob_buffer(toSend);
int n = blob_size(toSend);
transport.nSent += n;
if( pUrlData->isSsh ){
fwrite(z, 1, n, sshOut);
fflush(sshOut);
}else if( pUrlData->isHttps ){
#ifdef FOSSIL_ENABLE_SSL
int sent;
while( n>0 ){
sent = ssl_send(0, z, n);
/* printf("Sent %d of %d bytes\n", sent, n); fflush(stdout); */
if( sent<=0 ) break;
n -= sent;
}
#endif
}else if( pUrlData->isFile ){
fwrite(z, 1, n, transport.pFile);
}else{
int sent;
while( n>0 ){
sent = socket_send(0, z, n);
/* printf("Sent %d of %d bytes\n", sent, n); fflush(stdout); */
if( sent<=0 ) break;
n -= sent;
}
}
}
/*
** This routine is called when the outbound message is complete and
** it is time to being receiving a reply.
*/
void transport_flip(UrlData *pUrlData){
if( pUrlData->isFile ){
char *zCmd;
fclose(transport.pFile);
zCmd = mprintf("\"%s\" http \"%s\" \"%s\" \"%s\" 127.0.0.1 --localauth",
g.nameOfExe, pUrlData->name, transport.zOutFile, transport.zInFile
);
fossil_system(zCmd);
free(zCmd);
transport.pFile = fossil_fopen(transport.zInFile, "rb");
}
}
|
| ︙ | ︙ | |||
280 281 282 283 284 285 286 | transport.pLog = pLog; } /* ** This routine is called when the inbound message has been received ** and it is time to start sending again. */ | | | | | | | | | 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 |
transport.pLog = pLog;
}
/*
** This routine is called when the inbound message has been received
** and it is time to start sending again.
*/
void transport_rewind(UrlData *pUrlData){
if( pUrlData->isFile ){
transport_close(pUrlData);
}
}
/*
** Read N bytes of content directly from the wire and write into
** the buffer.
*/
static int transport_fetch(UrlData *pUrlData, char *zBuf, int N){
int got;
if( sshIn ){
int x;
int wanted = N;
got = 0;
while( wanted>0 ){
x = read(sshIn, &zBuf[got], wanted);
if( x<=0 ) break;
got += x;
wanted -= x;
}
}else if( pUrlData->isHttps ){
#ifdef FOSSIL_ENABLE_SSL
got = ssl_receive(0, zBuf, N);
#else
got = 0;
#endif
}else if( pUrlData->isFile ){
got = fread(zBuf, 1, N, transport.pFile);
}else{
got = socket_receive(0, zBuf, N);
}
/* printf("received %d of %d bytes\n", got, N); fflush(stdout); */
if( transport.pLog ){
fwrite(zBuf, 1, got, transport.pLog);
fflush(transport.pLog);
}
return got;
}
/*
** Read N bytes of content from the wire and store in the supplied buffer.
** Return the number of bytes actually received.
*/
int transport_receive(UrlData *pUrlData, char *zBuf, int N){
int onHand; /* Bytes current held in the transport buffer */
int nByte = 0; /* Bytes of content received */
onHand = transport.nUsed - transport.iCursor;
if( g.fSshTrace){
printf("Reading %d bytes with %d on hand... ", N, onHand);
fflush(stdout);
|
| ︙ | ︙ | |||
349 350 351 352 353 354 355 |
transport.iCursor = 0;
}
N -= toMove;
zBuf += toMove;
nByte += toMove;
}
if( N>0 ){
| | | | 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 |
transport.iCursor = 0;
}
N -= toMove;
zBuf += toMove;
nByte += toMove;
}
if( N>0 ){
int got = transport_fetch(pUrlData, zBuf, N);
if( got>0 ){
nByte += got;
transport.nRcvd += got;
}
}
if( g.fSshTrace ) printf("Got %d bytes\n", nByte);
return nByte;
}
/*
** Load up to N new bytes of content into the transport.pBuf buffer.
** The buffer itself might be moved. And the transport.iCursor value
** might be reset to 0.
*/
static void transport_load_buffer(UrlData *pUrlData, int N){
int i, j;
if( transport.nAlloc==0 ){
transport.nAlloc = N;
transport.pBuf = fossil_malloc( N );
transport.iCursor = 0;
transport.nUsed = 0;
}
|
| ︙ | ︙ | |||
386 387 388 389 390 391 392 |
if( transport.nUsed + N > transport.nAlloc ){
char *pNew;
transport.nAlloc = transport.nUsed + N;
pNew = fossil_realloc(transport.pBuf, transport.nAlloc);
transport.pBuf = pNew;
}
if( N>0 ){
| | | | | 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 |
if( transport.nUsed + N > transport.nAlloc ){
char *pNew;
transport.nAlloc = transport.nUsed + N;
pNew = fossil_realloc(transport.pBuf, transport.nAlloc);
transport.pBuf = pNew;
}
if( N>0 ){
i = transport_fetch(pUrlData, &transport.pBuf[transport.nUsed], N);
if( i>0 ){
transport.nRcvd += i;
transport.nUsed += i;
}
}
}
/*
** Fetch a single line of input where a line is all text up to the next
** \n character or until the end of input. Remove all trailing whitespace
** from the received line and zero-terminate the result. Return a pointer
** to the line.
**
** Each call to this routine potentially overwrites the returned buffer.
*/
char *transport_receive_line(UrlData *pUrlData){
int i;
int iStart;
i = iStart = transport.iCursor;
while(1){
if( i >= transport.nUsed ){
transport_load_buffer(pUrlData, pUrlData->isSsh ? 2 : 1000);
i -= iStart;
iStart = 0;
if( i >= transport.nUsed ){
transport.pBuf[i] = 0;
transport.iCursor = i;
break;
}
|
| ︙ | ︙ | |||
435 436 437 438 439 440 441 |
if( g.fSshTrace ) printf("Got line: [%s]\n", &transport.pBuf[iStart]);
return &transport.pBuf[iStart];
}
/*
** Global transport shutdown
*/
| | | | | 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 |
if( g.fSshTrace ) printf("Got line: [%s]\n", &transport.pBuf[iStart]);
return &transport.pBuf[iStart];
}
/*
** Global transport shutdown
*/
void transport_global_shutdown(UrlData *pUrlData){
if( pUrlData->isSsh ){
transport_ssh_close();
}
if( pUrlData->isHttps ){
#ifdef FOSSIL_ENABLE_SSL
ssl_global_shutdown();
#endif
}else{
socket_global_shutdown();
}
}
|
| ︙ | ︙ |
Changes to src/import.c.
| ︙ | ︙ | |||
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);
| > > > > > > > > > > > > > > > | 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 |
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;
int hastz;
char tzdir;
int tz;
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;
/* We don't use sscanf here because of int64 portability issues. */
for(i=i+2; fossil_isdigit(zLine[i]); i++){
secSince1970 = secSince1970*10 + zLine[i] - '0';
}
/* Read in optional timezone modifier (we don't know if it's strictly
* optional, but better to be sure). */
tzdir = '+';
tz = 0;
hastz = sscanf(&zLine[i], " %c%d", &tzdir, &tz);
if ((hastz == 1) || (hastz > 2)) goto malformed_line;
secSince1970 += ((tzdir == '-') ? -1 : 1) *
((tz/100)*3600 + (tz%100)*60);
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.
| ︙ | ︙ | |||
106 107 108 109 110 111 112 113 114 115 116 117 118 119 |
"SELECT datetime(mtime) || ' UTC' FROM event WHERE objid=%d",
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 ){
| > > > > > > > > > > > > > > > > | 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 |
"SELECT datetime(mtime) || ' UTC' FROM event WHERE objid=%d",
db_column_int(&q, 1)
);
fossil_print("%-13s %s %s\n", zType, zUuid, zDate);
free(zDate);
}
db_finalize(&q);
}
if( zUuid ){
fossil_print("%-13s ", "leaf:");
if(is_a_leaf(rid)){
if(db_int(0, "SELECT 1 FROM tagxref AS tx"
" WHERE tx.rid=%d"
" AND tx.tagid=%d"
" AND tx.tagtype>0",
rid, TAG_CLOSED)){
fossil_print("%s\n", "closed");
}else{
fossil_print("%s\n", "open");
}
}else{
fossil_print("no\n");
}
}
zTags = info_tags_of_checkin(rid, 0);
if( zTags && zTags[0] ){
fossil_print("tags: %s\n", zTags);
}
free(zTags);
if( zComment ){
|
| ︙ | ︙ | |||
228 229 230 231 232 233 234 |
*/
static void showTags(int rid, const char *zNotGlob){
Stmt q;
int cnt = 0;
db_prepare(&q,
"SELECT tag.tagid, tagname, "
" (SELECT uuid FROM blob WHERE rid=tagxref.srcid AND rid!=%d),"
| | | | 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 |
*/
static void showTags(int rid, const char *zNotGlob){
Stmt q;
int cnt = 0;
db_prepare(&q,
"SELECT tag.tagid, tagname, "
" (SELECT uuid FROM blob WHERE rid=tagxref.srcid AND rid!=%d),"
" value, datetime(tagxref.mtime%s), tagtype,"
" (SELECT uuid FROM blob WHERE rid=tagxref.origid AND rid!=%d)"
" FROM tagxref JOIN tag ON tagxref.tagid=tag.tagid"
" WHERE tagxref.rid=%d AND tagname NOT GLOB '%q'"
" ORDER BY tagname /*sort*/", rid, timeline_utc(), rid, rid, zNotGlob
);
while( db_step(&q)==SQLITE_ROW ){
const char *zTagname = db_column_text(&q, 1);
const char *zSrcUuid = db_column_text(&q, 2);
const char *zValue = db_column_text(&q, 3);
const char *zDate = db_column_text(&q, 4);
int tagtype = db_column_int(&q, 5);
|
| ︙ | ︙ | |||
501 502 503 504 505 506 507 |
zParent = db_text(0,
"SELECT uuid FROM plink, blob"
" WHERE plink.cid=%d AND blob.rid=plink.pid AND plink.isprim",
rid
);
isLeaf = is_a_leaf(rid);
db_prepare(&q1,
| | | | | > | 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 |
zParent = db_text(0,
"SELECT uuid FROM plink, blob"
" WHERE plink.cid=%d AND blob.rid=plink.pid AND plink.isprim",
rid
);
isLeaf = is_a_leaf(rid);
db_prepare(&q1,
"SELECT uuid, datetime(mtime%s), user, comment,"
" datetime(omtime%s), mtime"
" FROM blob, event"
" WHERE blob.rid=%d"
" AND event.objid=%d",
timeline_utc(), timeline_utc(), rid, rid
);
sideBySide = !is_false(PD("sbs","1"));
if( db_step(&q1)==SQLITE_ROW ){
const char *zUuid = db_column_text(&q1, 0);
char *zTitle = mprintf("Check-in [%.10s]", zUuid);
char *zEUser, *zEComment;
const char *zUser;
const char *zComment;
const char *zDate;
const char *zOrigDate;
style_header(zTitle);
login_anonymous_available();
free(zTitle);
zEUser = db_text(0,
"SELECT value FROM tagxref"
" WHERE tagid=%d AND rid=%d AND tagtype>0",
TAG_USER, rid);
zEComment = db_text(0,
"SELECT value FROM tagxref WHERE tagid=%d AND rid=%d",
TAG_COMMENT, rid);
zUser = db_column_text(&q1, 2);
zComment = db_column_text(&q1, 3);
zDate = db_column_text(&q1,1);
|
| ︙ | ︙ | |||
591 592 593 594 595 596 597 |
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>
| | | | | | | > | 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 |
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);
@ | %z(href("%R/timeline?r=%T&unhide",zTagName))%h(zTagName)</a>
}
db_finalize(&q2);
/* The Download: line */
if( g.perm.Zip ){
char *zUrl = mprintf("%R/tarball/%t-%S.tar.gz?uuid=%s",
zPJ, zUuid, zUuid);
@ </td></tr>
@ <tr><th>Downloads:</th><td>
@ %z(href("%s",zUrl))Tarball</a>
@ | %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);
|
| ︙ | ︙ | |||
913 914 915 916 917 918 919 | /* ** WEBPAGE: vdiff ** URL: /vdiff ** ** Query parameters: ** | | | | | | > > < < | 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 |
/*
** WEBPAGE: vdiff
** URL: /vdiff
**
** Query parameters:
**
** from=TAG Left side of the comparison
** to=TAG Right side of the comparison
** branch=TAG Show all changes on a particular branch
** v=BOOLEAN Default true. If false, only list files that have changed
** sbs=BOOLEAN Side-by-side diff if true. Unified diff if false
** glob=STRING only diff files matching this glob
**
**
** 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;
const char *zGlob;
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);
}
|
| ︙ | ︙ | |||
961 962 963 964 965 966 967 968 969 970 971 |
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 ){
style_submenu_element("Side-by-side Diff", "sbsdiff",
| > > > > > > > > > > | | > | | > | > > > > > | > > > > > > > > | | > > | | | > < > > | | | | > | 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 |
zVerbose = P("verbose");
}
if( !zVerbose ){
zVerbose = P("detail"); /* deprecated */
}
verboseFlag = (zVerbose!=0) && !is_false(zVerbose);
if( !verboseFlag && sideBySide ) verboseFlag = 1;
zGlob = P("glob");
zFrom = P("from");
zTo = P("to");
if(zGlob && !*zGlob){
zGlob = NULL;
}
if( sideBySide || verboseFlag ){
style_submenu_element("Hide Diff", "hidediff",
"%R/vdiff?from=%T&to=%T&sbs=0%s%T",
zFrom, zTo,
zGlob ? "&glob=" : "", zGlob ? zGlob : "");
}
if( !sideBySide ){
style_submenu_element("Side-by-side Diff", "sbsdiff",
"%R/vdiff?from=%T&to=%T&sbs=1%s%T",
zFrom, zTo,
zGlob ? "&glob=" : "", zGlob ? zGlob : "");
}
if( sideBySide || !verboseFlag ) {
style_submenu_element("Unified Diff", "udiff",
"%R/vdiff?from=%T&to=%T&sbs=0&v%s%T",
zFrom, zTo,
zGlob ? "&glob=" : "", zGlob ? zGlob : "");
}
style_submenu_element("Invert", "invert",
"%R/vdiff?from=%T&to=%T&sbs=%d%s%s%T", zTo, zFrom,
sideBySide, (verboseFlag && !sideBySide)?"&v":"",
zGlob ? "&glob=" : "", zGlob ? zGlob : "");
if( zGlob ){
style_submenu_element("Clear glob", "clearglob",
"%R/vdiff?from=%T&to=%T&sbs=%d%s", zFrom, zTo,
sideBySide, (verboseFlag && !sideBySide)?"&v":"");
}else{
style_submenu_element("Patch", "patch",
"%R/vpatch?from=%T&to=%T", zFrom, zTo);
}
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>
}
if( zGlob ){
@ <p><b>Only files matching the glob "%h(zGlob)" 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 ){
if(!zGlob || strglob(zGlob, pFileFrom->zName)){
append_file_change_line(pFileFrom->zName,
pFileFrom->zUuid, 0, 0, diffFlags, pRe, 0);
}
pFileFrom = manifest_file_next(pFrom, 0);
}else if( cmp>0 ){
if(!zGlob || strglob(zGlob, pFileTo->zName)){
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 ){
pFileFrom = manifest_file_next(pFrom, 0);
pFileTo = manifest_file_next(pTo, 0);
}else{
if(!zGlob || (strglob(zGlob, pFileFrom->zName)
|| strglob(zGlob, pFileTo->zName))){
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);
|
| ︙ | ︙ | |||
1126 1127 1128 1129 1130 1131 1132 1133 1134 |
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/annotate?checkin=%S&filename=%T",zVers,zName))
@ [annotate]</a>
| > | > | 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 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 ){
@ %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);
}
}
if( prevName ){
|
| ︙ | ︙ | |||
1308 1309 1310 1311 1312 1313 1314 |
content_get(v1, &c1);
content_get(v2, &c2);
text_diff(&c1, &c2, pOut, pRe, diffFlags);
blob_reset(&c1);
blob_reset(&c2);
return;
}
| | | 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 |
content_get(v1, &c1);
content_get(v2, &c2);
text_diff(&c1, &c2, pOut, pRe, diffFlags);
blob_reset(&c1);
blob_reset(&c2);
return;
}
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",
|
| ︙ | ︙ | |||
1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 |
** URL: /raw?name=ARTIFACTID&m=TYPE
**
** Return the uninterpreted content of an artifact. Used primarily
** to view artifacts that are images.
*/
void rawartifact_page(void){
int rid;
const char *zMime;
Blob content;
rid = name_to_rid_www("name");
login_check_credentials();
if( !g.perm.Read ){ login_needed(); return; }
if( rid==0 ) fossil_redirect_home();
zMime = P("m");
if( zMime==0 ){
char *zFName = db_text(0, "SELECT filename.name FROM mlink, filename"
" WHERE mlink.fid=%d"
" AND filename.fnid=mlink.fnid", rid);
if( !zFName ){
/* Look also at the attachment table */
| > > > > > > | 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 |
** URL: /raw?name=ARTIFACTID&m=TYPE
**
** Return the uninterpreted content of an artifact. Used primarily
** to view artifacts that are images.
*/
void rawartifact_page(void){
int rid;
char *zUuid;
const char *zMime;
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"
" AND filename.fnid=mlink.fnid", rid);
if( !zFName ){
/* Look also at the attachment table */
|
| ︙ | ︙ | |||
1624 1625 1626 1627 1628 1629 1630 |
}
blob_zero(&downloadName);
objType = object_description(rid, 0, &downloadName);
style_submenu_element("Download", "Download",
"%R/raw/%T?name=%s", blob_str(&downloadName), zUuid);
if( db_exists("SELECT 1 FROM mlink WHERE fid=%d", rid) ){
style_submenu_element("Checkins Using", "Checkins Using",
| | | 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 |
}
blob_zero(&downloadName);
objType = object_description(rid, 0, &downloadName);
style_submenu_element("Download", "Download",
"%R/raw/%T?name=%s", blob_str(&downloadName), zUuid);
if( db_exists("SELECT 1 FROM mlink WHERE fid=%d", rid) ){
style_submenu_element("Checkins Using", "Checkins Using",
"%R/timeline?n=200&uf=%s",zUuid);
}
asText = P("txt")!=0;
zMime = mimetype_from_name(blob_str(&downloadName));
if( zMime ){
if( fossil_strcmp(zMime, "text/html")==0 ){
if( asText ){
style_submenu_element("Html", "Html",
|
| ︙ | ︙ | |||
1658 1659 1660 1661 1662 1663 1664 |
}
@ <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)"
| | | > < | 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 |
}
@ <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);
blob_to_utf8_no_bom(&content, 0);
zMime = mimetype_from_content(&content);
@ <blockquote>
if( zMime==0 ){
const char *zLn = P("ln");
const char *z;
z = blob_str(&content);
if( zLn ){
output_text_with_line_numbers(z, zLn);
}else{
@ <pre>
@ %h(z)
@ </pre>
|
| ︙ | ︙ | |||
1761 1762 1763 1764 1765 1766 1767 |
}
modPending = moderation_pending(rid);
if( modPending ){
@ <span class="modpending">*** Awaiting Moderator Approval ***</span>
}
@ <tr><th>Ticket:</th>
@ <td>%z(href("%R/tktview/%s",zTktName))%s(zTktName)</a>
| | | 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 |
}
modPending = moderation_pending(rid);
if( modPending ){
@ <span class="modpending">*** Awaiting Moderator Approval ***</span>
}
@ <tr><th>Ticket:</th>
@ <td>%z(href("%R/tktview/%s",zTktName))%s(zTktName)</a>
if( zTktTitle ){
@<br>%h(zTktTitle)
}
@</td></tr>
@ <tr><th>Date:</th><td>
hyperlink_to_date(zDate, "</td></tr>");
@ <tr><th>User:</th><td>
hyperlink_to_user(pTktChng->zUser, zDate, "</td></tr>");
|
| ︙ | ︙ | |||
2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 |
const char *zColor;
const char *zNewColor;
const char *zNewTagFlag;
const char *zNewTag;
const char *zNewBrFlag;
const char *zNewBranch;
const char *zCloseFlag;
int fPropagateColor; /* True if color propagates before edit */
int fNewPropagateColor; /* True if color propagates after edit */
const char *zChngTime = 0; /* Value of chngtime= query param, if any */
char *zUuid;
Blob comment;
Stmt q;
login_check_credentials();
if( !g.perm.Write ){ login_needed(); return; }
rid = name_to_typed_rid(P("r"), "ci");
zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
zComment = db_text(0, "SELECT coalesce(ecomment,comment)"
| > > > > | 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 |
const char *zColor;
const char *zNewColor;
const char *zNewTagFlag;
const char *zNewTag;
const char *zNewBrFlag;
const char *zNewBranch;
const char *zCloseFlag;
const char *zHideFlag;
int fPropagateColor; /* True if color propagates before edit */
int fNewPropagateColor; /* True if color propagates after edit */
int fHasHidden = 0; /* True if hidden tag already set */
int fHasClosed = 0; /* True if closed tag already set */
const char *zChngTime = 0; /* Value of chngtime= query param, if any */
char *zUuid;
Blob comment;
char *zBranchName = 0;
Stmt q;
login_check_credentials();
if( !g.perm.Write ){ login_needed(); return; }
rid = name_to_typed_rid(P("r"), "ci");
zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
zComment = db_text(0, "SELECT coalesce(ecomment,comment)"
|
| ︙ | ︙ | |||
2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 |
rid, TAG_BGCOLOR)==2;
fNewPropagateColor = P("clr")!=0 ? P("pclr")!=0 : fPropagateColor;
zNewTagFlag = P("newtag") ? " checked" : "";
zNewTag = PDT("tagname","");
zNewBrFlag = P("newbr") ? " checked" : "";
zNewBranch = PDT("brname","");
zCloseFlag = P("close") ? " checked" : "";
if( P("apply") ){
Blob ctrl;
char *zNow;
int nChng = 0;
login_verify_csrf_secret();
blob_zero(&ctrl);
| > | 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 |
rid, TAG_BGCOLOR)==2;
fNewPropagateColor = P("clr")!=0 ? P("pclr")!=0 : fPropagateColor;
zNewTagFlag = P("newtag") ? " checked" : "";
zNewTag = PDT("tagname","");
zNewBrFlag = P("newbr") ? " checked" : "";
zNewBranch = PDT("brname","");
zCloseFlag = P("close") ? " checked" : "";
zHideFlag = P("hide") ? " checked" : "";
if( P("apply") ){
Blob ctrl;
char *zNow;
int nChng = 0;
login_verify_csrf_secret();
blob_zero(&ctrl);
|
| ︙ | ︙ | |||
2134 2135 2136 2137 2138 2139 2140 2141 |
char zLabel[30];
sqlite3_snprintf(sizeof(zLabel), zLabel, "c%d", tagid);
if( P(zLabel) ){
db_multi_exec("REPLACE INTO newtags VALUES(%Q,'-',NULL)", zTag);
}
}
db_finalize(&q);
if( zCloseFlag[0] ){
| > > > | > | 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 |
char zLabel[30];
sqlite3_snprintf(sizeof(zLabel), zLabel, "c%d", tagid);
if( P(zLabel) ){
db_multi_exec("REPLACE INTO newtags VALUES(%Q,'-',NULL)", zTag);
}
}
db_finalize(&q);
if( zHideFlag[0] ){
db_multi_exec("REPLACE INTO newtags VALUES('hidden','*',NULL)");
}
if( zCloseFlag[0] ){
db_multi_exec("REPLACE INTO newtags VALUES('closed','%s',NULL)",
is_a_leaf(rid)?"+":"*");
}
if( zNewTagFlag[0] && zNewTag[0] ){
db_multi_exec("REPLACE INTO newtags VALUES('sym-%q','+',NULL)", zNewTag);
}
if( zNewBrFlag[0] && zNewBranch[0] ){
db_multi_exec(
"REPLACE INTO newtags "
|
| ︙ | ︙ | |||
2176 2177 2178 2179 2180 2181 2182 |
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);
| | > > > > > > > > > > > > > > > > > > > > > | 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 |
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) );
db_end_transaction(0);
}
cgi_redirectf("ci?name=%s", zUuid);
}
blob_zero(&comment);
blob_append(&comment, zNewComment, -1);
zUuid[10] = 0;
style_header("Edit Check-in [%s]", zUuid);
/*
** chgcbn/chgbn: Handle change of (checkbox for) branch name in
** remaining of form.
*/
@ <script>
@ function chgcbn(checked, branch){
@ val = gebi('brname').value.trim();
@ if( !val || !checked ) val = branch;
@ if( checked ) gebi('brname').select();
@ gebi('hbranch').textContent = val;
@ cidbrid = document.getElementById('cbranch');
@ if( cidbrid ) cidbrid.textContent = val;
@ }
@ function chgbn(val, branch){
@ if( !val ) val = branch;
@ gebi('newbr').checked = (val!=branch);
@ gebi('hbranch').textContent = val;
@ cidbrid = document.getElementById('cbranch');
@ if( cidbrid ) cidbrid.textContent = val;
@ }
@ </script>
if( P("preview") ){
Blob suffix;
int nTag = 0;
@ <b>Preview:</b>
@ <blockquote>
@ <table border=0>
if( zNewColor && zNewColor[0] ){
|
| ︙ | ︙ | |||
2265 2266 2267 2268 2269 2270 2271 2272 |
@ <tr><th align="right" valign="top">Tags:</th>
@ <td valign="top">
@ <label><input type="checkbox" id="newtag" name="newtag"%s(zNewTagFlag) />
@ Add the following new tag name to this check-in:</label>
@ <input type="text" style="width:15;" name="tagname" value="%h(zNewTag)"
@ onkeyup="gebi('newtag').checked=!!this.value" />
db_prepare(&q,
| > > > | > > > > > > > > > > > > | | | > > > > > > | > | > | > > > > > > > | | > | < < < < | | | | | | > > > > > > > > > | > > | 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 |
@ <tr><th align="right" valign="top">Tags:</th>
@ <td valign="top">
@ <label><input type="checkbox" id="newtag" name="newtag"%s(zNewTagFlag) />
@ Add the following new tag name to this check-in:</label>
@ <input type="text" style="width:15;" name="tagname" value="%h(zNewTag)"
@ onkeyup="gebi('newtag').checked=!!this.value" />
zBranchName = db_text(0, "SELECT value FROM tagxref, tag"
" WHERE tagxref.rid=%d AND tagtype>0 AND tagxref.tagid=tag.tagid"
" AND tagxref.tagid=%d", rid, TAG_BRANCH);
db_prepare(&q,
"SELECT tag.tagid, tagname, tagxref.value FROM tagxref, tag"
" WHERE tagxref.rid=%d AND tagtype>0 AND tagxref.tagid=tag.tagid"
" ORDER BY CASE WHEN tagname GLOB 'sym-*' THEN substr(tagname,5)"
" ELSE tagname END /*sort*/",
rid
);
while( db_step(&q)==SQLITE_ROW ){
int tagid = db_column_int(&q, 0);
const char *zTagName = db_column_text(&q, 1);
int isSpecialTag = fossil_strncmp(zTagName, "sym-", 4)!=0;
char zLabel[30];
if( tagid == TAG_CLOSED ){
fHasClosed = 1;
}else if( (tagid == TAG_COMMENT) || (tagid == TAG_BRANCH) ){
continue;
}else if( tagid==TAG_HIDDEN ){
fHasHidden = 1;
}else if( !isSpecialTag && zTagName &&
fossil_strcmp(&zTagName[4], zBranchName)==0){
continue;
}
sqlite3_snprintf(sizeof(zLabel), zLabel, "c%d", tagid);
@ <br /><label>
if( P(zLabel) ){
@ <input type="checkbox" name="c%d(tagid)" checked="checked" />
}else{
@ <input type="checkbox" name="c%d(tagid)" />
}
if( isSpecialTag ){
@ Cancel special tag <b>%h(zTagName)</b></label>
}else{
@ Cancel tag <b>%h(&zTagName[4])</b></label>
}
}
db_finalize(&q);
@ </td></tr>
if( !zBranchName ){
zBranchName = db_get("main-branch", "trunk");
}
if( !zNewBranch || !zNewBranch[0]){
zNewBranch = zBranchName;
}
@ <tr><th align="right" valign="top">Branching:</th>
@ <td valign="top">
@ <label><input id="newbr" type="checkbox" name="newbr"%s(zNewBrFlag)
@ onchange="chgcbn(this.checked,'%h(zBranchName)')" />
@ Make this check-in the start of a new branch named:</label>
@ <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>
@ <td valign="top">
@ <label><input type="checkbox" name="close"%s(zCloseFlag) />
@ Mark this leaf as "closed" so that it no longer appears on the
@ "leaves" page and is no longer labeled as a "<b>Leaf</b>"</label>
@ </td></tr>
}else if( zBranchName ){
@ <tr><th align="right" valign="top">Branch Closure:</th>
@ <td valign="top">
@ <label><input type="checkbox" name="close"%s(zCloseFlag) />
@ Mark branch
@ <span style="font-weight:bold" id="cbranch">%h(zBranchName)</span>
@ as "closed" so that its leafs no longer appear on the "leaves" page
@ and are no longer labeled as a leaf "<b>Leaf</b>"</label>
@ </td></tr>
}
}
if( zBranchName ) fossil_free(zBranchName);
@ <tr><td colspan="2">
@ <input type="submit" name="preview" value="Preview" />
@ <input type="submit" name="apply" value="Apply Changes" />
@ <input type="submit" name="cancel" value="Cancel" />
@ </td></tr>
@ </table>
@ </div></form>
style_footer();
}
|
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 "VERSION.h" #include "config.h" #include "json.h" #include <assert.h> #include <time.h> #if INTERFACE #include "json_detail.h" /* workaround for apparent enum limitation in makeheaders */ #endif |
| ︙ | ︙ | |||
985 986 987 988 989 990 991 |
FILE * inFile = NULL;
char const * jfile = find_option("json-input",NULL,1);
if(!jfile || !*jfile){
break;
}
inFile = (0==strcmp("-",jfile))
? stdin
| | | 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 |
FILE * inFile = NULL;
char const * jfile = find_option("json-input",NULL,1);
if(!jfile || !*jfile){
break;
}
inFile = (0==strcmp("-",jfile))
? stdin
: fossil_fopen(jfile,"rb");
if(!inFile){
g.json.resultCode = FSL_JSON_E_FILE_OPEN_FAILED;
fossil_fatal("Could not open JSON file [%s].",jfile)
/* Does not return. */
;
}
cgi_parse_POST_JSON(inFile, 0);
|
| ︙ | ︙ | |||
1978 1979 1980 1981 1982 1983 1984 | SETBUF(jo, "projectCode"); cson_object_set(jo, "compiler", cson_value_new_string(COMPILER_NAME, strlen(COMPILER_NAME))); jv2 = cson_value_new_object(); jo2 = cson_value_get_object(jv2); cson_object_set(jo, "sqlite", jv2); sqlite3_snprintf(BufLen, zBuf, "%.19s [%.10s] (%s)", | | | 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 |
SETBUF(jo, "projectCode");
cson_object_set(jo, "compiler", cson_value_new_string(COMPILER_NAME, strlen(COMPILER_NAME)));
jv2 = cson_value_new_object();
jo2 = cson_value_get_object(jv2);
cson_object_set(jo, "sqlite", jv2);
sqlite3_snprintf(BufLen, zBuf, "%.19s [%.10s] (%s)",
sqlite3_sourceid(), &sqlite3_sourceid()[20], sqlite3_libversion());
SETBUF(jo2, "version");
zDb = db_name("repository");
cson_object_set(jo2, "pageCount", cson_value_new_integer((cson_int_t)db_int(0, "PRAGMA %s.page_count", zDb)));
cson_object_set(jo2, "pageSize", cson_value_new_integer((cson_int_t)db_int(0, "PRAGMA %s.page_size", zDb)));
cson_object_set(jo2, "freeList", cson_value_new_integer((cson_int_t)db_int(0, "PRAGMA %s.freelist_count", zDb)));
sqlite3_snprintf(BufLen, zBuf, "%s", db_text(0, "PRAGMA %s.encoding", zDb));
SETBUF(jo2, "encoding");
|
| ︙ | ︙ |
Changes to src/json_branch.c.
| ︙ | ︙ | |||
289 290 291 292 293 294 295 |
blob_appendf(&branch, "Z %b\n", &mcksum);
brid = content_put(&branch);
if( brid==0 ){
fossil_fatal("Problem committing manifest: %s", g.zErrMsg);
}
db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", brid);
| | | | 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 |
blob_appendf(&branch, "Z %b\n", &mcksum);
brid = content_put(&branch);
if( brid==0 ){
fossil_fatal("Problem committing manifest: %s", g.zErrMsg);
}
db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", brid);
if( manifest_crosslink(brid, &branch, MC_PERMIT_HOOKS)==0 ){
fossil_fatal("%s\n", g.zErrMsg);
}
assert( blob_is_reset(&branch) );
content_deltify(rootid, brid, 0);
if( zNewRid ){
*zNewRid = brid;
}
|
| ︙ | ︙ |
Changes to src/json_config.c.
| ︙ | ︙ | |||
51 52 53 54 55 56 57 |
** mostly a copy of the config options in configure.c, but that data
** is private and cannot be re-used directly here.
*/
static const struct JsonConfigProperty {
char const * name;
int groupMask;
} JsonConfigProperties[] = {
| | > > > > > > | 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 |
** mostly a copy of the config options in configure.c, but that data
** is private and cannot be re-used directly here.
*/
static const struct JsonConfigProperty {
char const * name;
int groupMask;
} JsonConfigProperties[] = {
{ "css", CONFIGSET_CSS },
{ "header", CONFIGSET_SKIN },
{ "footer", CONFIGSET_SKIN },
{ "logo-mimetype", CONFIGSET_SKIN },
{ "logo-image", CONFIGSET_SKIN },
{ "background-mimetype", CONFIGSET_SKIN },
{ "background-image", CONFIGSET_SKIN },
{ "index-page", CONFIGSET_SKIN },
{ "timeline-block-markup", CONFIGSET_SKIN },
{ "timeline-max-comment", CONFIGSET_SKIN },
{ "timeline-plaintext", CONFIGSET_SKIN },
{ "project-name", CONFIGSET_PROJ },
{ "project-description", CONFIGSET_PROJ },
{ "manifest", CONFIGSET_PROJ },
{ "binary-glob", CONFIGSET_PROJ },
{ "encoding-glob", CONFIGSET_PROJ },
{ "ignore-glob", CONFIGSET_PROJ },
{ "keep-glob", CONFIGSET_PROJ },
{ "crnl-glob", CONFIGSET_PROJ },
{ "empty-dirs", CONFIGSET_PROJ },
{ "allow-clean-x", CONFIGSET_PROJ },
{ "allow-symlinks", CONFIGSET_PROJ },
{ "ticket-table", CONFIGSET_TKT },
{ "ticket-common", CONFIGSET_TKT },
{ "ticket-change", CONFIGSET_TKT },
{ "ticket-newpage", CONFIGSET_TKT },
{ "ticket-viewpage", CONFIGSET_TKT },
|
| ︙ | ︙ | |||
110 111 112 113 114 115 116 |
zName = json_command_arg(i);
for( ; zName; zName = json_command_arg(++i) ){
if(0==(strcmp("all", zName))){
confMask = CONFIGSET_ALL;
}else if(0==(strcmp("project", zName))){
confMask |= CONFIGSET_PROJ;
}else if(0==(strcmp("skin", zName))){
| | | 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
zName = json_command_arg(i);
for( ; zName; zName = json_command_arg(++i) ){
if(0==(strcmp("all", zName))){
confMask = CONFIGSET_ALL;
}else if(0==(strcmp("project", zName))){
confMask |= CONFIGSET_PROJ;
}else if(0==(strcmp("skin", zName))){
confMask |= (CONFIGSET_CSS|CONFIGSET_SKIN);
}else if(0==(strcmp("ticket", zName))){
confMask |= CONFIGSET_TKT;
}else if(0==(strcmp("skin-backup", zName))){
optSkinBackups = 1;
}else{
json_set_err( FSL_JSON_E_INVALID_ARGS,
"Unknown config area: %s", zName);
|
| ︙ | ︙ |
Changes to src/json_finfo.c.
| ︙ | ︙ | |||
72 73 74 75 76 77 78 | /*4*/ " coalesce(event.euser, event.user)," /*5*/ " coalesce(event.ecomment, event.comment)," /*6*/ " (SELECT uuid FROM blob WHERE rid=mlink.pid)," /* Parent file uuid */ /*7*/ " event.bgcolor," /*8*/ " b.size," /*9*/ " (mlink.pid==0) AS isNew," /*10*/ " (mlink.fid==0) AS isDel" | | | 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
/*4*/ " coalesce(event.euser, event.user),"
/*5*/ " coalesce(event.ecomment, event.comment),"
/*6*/ " (SELECT uuid FROM blob WHERE rid=mlink.pid)," /* Parent file uuid */
/*7*/ " event.bgcolor,"
/*8*/ " b.size,"
/*9*/ " (mlink.pid==0) AS isNew,"
/*10*/ " (mlink.fid==0) AS isDel"
" FROM mlink, blob b, event, blob ci, filename"
" WHERE filename.name=%Q"
" AND mlink.fnid=filename.fnid"
" AND b.rid=mlink.fid"
" AND event.objid=mlink.mid"
" AND event.objid=ci.rid",
zFilename
);
|
| ︙ | ︙ |
Changes to src/json_timeline.c.
| ︙ | ︙ | |||
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 |
** both are specified, which one takes precedence is unspecified.
*/
static char json_timeline_add_tag_branch_clause(Blob *pSql,
cson_object * pPayload){
char const * zTag = NULL;
char const * zBranch = NULL;
char const * zMiOnly = NULL;
int tagid = 0;
if(! g.perm.Read ){
return 0;
}
zTag = json_find_option_cstr("tag",NULL,NULL);
if(!zTag || !*zTag){
zBranch = json_find_option_cstr("branch",NULL,NULL);
if(!zBranch || !*zBranch){
return 0;
}
zTag = zBranch;
zMiOnly = json_find_option_cstr("mionly",NULL,NULL);
}
tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname='sym-%q'",
zTag);
if(tagid<=0){
return -1;
}
if(pPayload){
cson_object_set( pPayload, zBranch ? "branch" : "tag", json_new_string(zTag) );
}
blob_appendf(pSql,
" AND ("
" EXISTS(SELECT 1 FROM tagxref"
" WHERE tagid=%d AND tagtype>0 AND rid=blob.rid)",
tagid);
if(zBranch){
/* from "r" flag code in page_timeline().*/
blob_appendf(pSql,
" OR EXISTS(SELECT 1 FROM plink JOIN tagxref ON rid=cid"
" WHERE tagid=%d AND tagtype>0 AND pid=blob.rid)",
tagid);
if( zMiOnly==0 ){
blob_appendf(pSql,
" OR EXISTS(SELECT 1 FROM plink JOIN tagxref ON rid=pid"
" WHERE tagid=%d AND tagtype>0 AND cid=blob.rid)",
tagid);
}
}
blob_append(pSql," ) ",3);
return 1;
}
/*
** Helper for the timeline family of functions. Possibly appends 1
| > > > > > > > > > > > > > > > > > > > > | 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 |
** both are specified, which one takes precedence is unspecified.
*/
static char json_timeline_add_tag_branch_clause(Blob *pSql,
cson_object * pPayload){
char const * zTag = NULL;
char const * zBranch = NULL;
char const * zMiOnly = NULL;
char const * zUnhide = NULL;
int tagid = 0;
if(! g.perm.Read ){
return 0;
}
zTag = json_find_option_cstr("tag",NULL,NULL);
if(!zTag || !*zTag){
zBranch = json_find_option_cstr("branch",NULL,NULL);
if(!zBranch || !*zBranch){
return 0;
}
zTag = zBranch;
zMiOnly = json_find_option_cstr("mionly",NULL,NULL);
}
zUnhide = json_find_option_cstr("unhide",NULL,NULL);
tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname='sym-%q'",
zTag);
if(tagid<=0){
return -1;
}
if(pPayload){
cson_object_set( pPayload, zBranch ? "branch" : "tag", json_new_string(zTag) );
}
blob_appendf(pSql,
" AND ("
" EXISTS(SELECT 1 FROM tagxref"
" WHERE tagid=%d AND tagtype>0 AND rid=blob.rid)",
tagid);
if(!zUnhide){
blob_appendf(pSql,
" AND NOT EXISTS(SELECT 1 FROM plink JOIN tagxref ON rid=blob.rid"
" WHERE tagid=%d AND tagtype>0 AND rid=blob.rid)",
TAG_HIDDEN);
}
if(zBranch){
/* from "r" flag code in page_timeline().*/
blob_appendf(pSql,
" OR EXISTS(SELECT 1 FROM plink JOIN tagxref ON rid=cid"
" WHERE tagid=%d AND tagtype>0 AND pid=blob.rid)",
tagid);
if( !zUnhide ){
blob_appendf(pSql,
" AND NOT EXISTS(SELECT 1 FROM plink JOIN tagxref ON rid=cid"
" WHERE tagid=%d AND tagtype>0 AND pid=blob.rid)",
TAG_HIDDEN);
}
if( zMiOnly==0 ){
blob_appendf(pSql,
" OR EXISTS(SELECT 1 FROM plink JOIN tagxref ON rid=pid"
" WHERE tagid=%d AND tagtype>0 AND cid=blob.rid)",
tagid);
if( !zUnhide ){
blob_appendf(pSql,
" AND NOT EXISTS(SELECT 1 FROM plink JOIN tagxref ON rid=pid"
" WHERE tagid=%d AND tagtype>0 AND cid=blob.rid)",
TAG_HIDDEN);
}
}
}
blob_append(pSql," ) ",3);
return 1;
}
/*
** Helper for the timeline family of functions. Possibly appends 1
|
| ︙ | ︙ |
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);
|
| ︙ | ︙ | |||
396 397 398 399 400 401 402 403 404 405 406 407 408 409 |
if( strncmp("http", zAgent+i,4)==0 ) return 0;
}
if( strncmp(zAgent, "Mozilla/", 8)==0 ){
if( atoi(&zAgent[8])<4 ) return 0; /* Many bots advertise as Mozilla/3 */
if( strglob("*Firefox/[1-9]*", zAgent) ) return 1;
if( strglob("*Chrome/[1-9]*", zAgent) ) return 1;
if( strglob("*(compatible;?MSIE?[1789]*", zAgent) ) return 1;
if( strglob("*AppleWebKit/[1-9]*(KHTML*", zAgent) ) return 1;
return 0;
}
if( strncmp(zAgent, "Opera/", 6)==0 ) return 1;
if( strncmp(zAgent, "Safari/", 7)==0 ) return 1;
if( strncmp(zAgent, "Lynx/", 5)==0 ) return 1;
if( strncmp(zAgent, "NetSurf/", 8)==0 ) return 1;
| > | 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 |
if( strncmp("http", zAgent+i,4)==0 ) return 0;
}
if( strncmp(zAgent, "Mozilla/", 8)==0 ){
if( atoi(&zAgent[8])<4 ) return 0; /* Many bots advertise as Mozilla/3 */
if( strglob("*Firefox/[1-9]*", zAgent) ) return 1;
if( strglob("*Chrome/[1-9]*", zAgent) ) return 1;
if( strglob("*(compatible;?MSIE?[1789]*", zAgent) ) return 1;
if( strglob("*Trident/[1-9]*;?rv:[1-9]*", zAgent) ) return 1; /* IE11+ */
if( strglob("*AppleWebKit/[1-9]*(KHTML*", zAgent) ) return 1;
return 0;
}
if( strncmp(zAgent, "Opera/", 6)==0 ) return 1;
if( strncmp(zAgent, "Safari/", 7)==0 ) return 1;
if( strncmp(zAgent, "Lynx/", 5)==0 ) return 1;
if( strncmp(zAgent, "NetSurf/", 8)==0 ) return 1;
|
| ︙ | ︙ | |||
469 470 471 472 473 474 475 476 477 478 |
const char *zAnonPw = 0;
const char *zGoto = P("g");
int anonFlag;
char *zErrMsg = "";
int uid; /* User id logged in user */
char *zSha1Pw;
const char *zIpAddr; /* IP address of requestor */
login_check_credentials();
sqlite3_create_function(g.db, "constant_time_cmp", 2, SQLITE_UTF8, 0,
| > | | | | | 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 |
const char *zAnonPw = 0;
const char *zGoto = P("g");
int anonFlag;
char *zErrMsg = "";
int uid; /* User id logged in user */
char *zSha1Pw;
const char *zIpAddr; /* IP address of requestor */
const char *zReferer;
login_check_credentials();
sqlite3_create_function(g.db, "constant_time_cmp", 2, SQLITE_UTF8, 0,
constant_time_cmp_function, 0, 0);
zUsername = P("u");
zPasswd = P("p");
anonFlag = P("anon")!=0;
if( P("out")!=0 ){
login_clear_login_data();
redirect_to_g();
}
if( g.perm.Password && zPasswd
&& (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);
|
| ︙ | ︙ | |||
529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 |
}else{
redirect_to_g();
return;
}
}
}
zIpAddr = PD("REMOTE_ADDR","nil"); /* Complete IP address for logging */
uid = login_is_valid_anonymous(zUsername, zPasswd, P("cs"));
if( uid>0 ){
login_set_anon_cookie(zIpAddr, NULL);
record_login_attempt("anonymous", zIpAddr, 1);
redirect_to_g();
}
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);
| > | | 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 |
}else{
redirect_to_g();
return;
}
}
}
zIpAddr = PD("REMOTE_ADDR","nil"); /* Complete IP address for logging */
zReferer = P("HTTP_REFERER");
uid = login_is_valid_anonymous(zUsername, zPasswd, P("cs"));
if( uid>0 ){
login_set_anon_cookie(zIpAddr, NULL);
record_login_attempt("anonymous", zIpAddr, 1);
redirect_to_g();
}
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:
|
| ︙ | ︙ | |||
567 568 569 570 571 572 573 574 575 576 577 578 579 580 |
@ %s(zErrMsg)
if( zGoto && P("anon")==0 ){
@ <p>A login is required for <a href="%h(zGoto)">%h(zGoto)</a>.</p>
}
form_begin(0, "%R/login");
if( zGoto ){
@ <input type="hidden" name="g" value="%h(zGoto)" />
}
@ <table class="login_out">
@ <tr>
@ <td class="login_out_label">User ID:</td>
if( anonFlag ){
@ <td><input type="text" id="u" name="u" value="anonymous" size="30" /></td>
}else{
| > > | 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 |
@ %s(zErrMsg)
if( zGoto && P("anon")==0 ){
@ <p>A login is required for <a href="%h(zGoto)">%h(zGoto)</a>.</p>
}
form_begin(0, "%R/login");
if( zGoto ){
@ <input type="hidden" name="g" value="%h(zGoto)" />
}else if( zReferer && strncmp(g.zBaseURL, zReferer, strlen(g.zBaseURL))==0 ){
@ <input type="hidden" name="g" value="%h(zReferer)" />
}
@ <table class="login_out">
@ <tr>
@ <td class="login_out_label">User ID:</td>
if( anonFlag ){
@ <td><input type="text" id="u" name="u" value="anonymous" size="30" /></td>
}else{
|
| ︙ | ︙ | |||
592 593 594 595 596 597 598 | } @ <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>
@ 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]);
|
| ︙ | ︙ | |||
617 618 619 620 621 622 623 |
@ <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);
|
| ︙ | ︙ | |||
669 670 671 672 673 674 675 |
@ </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 707 708 709 710 711 712 713 714 715 716 717 718 719 720 |
@ </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,
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
g.zVfsName
);
if( rc==SQLITE_OK ){
sqlite3_create_function(pOther,"now",0,SQLITE_ANY,0,db_now_function,0,0);
sqlite3_create_function(pOther, "constant_time_cmp", 2, SQLITE_UTF8, 0,
constant_time_cmp_function, 0, 0);
sqlite3_busy_timeout(pOther, 5000);
zSQL = mprintf(
"SELECT cexpire FROM user"
" WHERE login=%Q"
" AND ipaddr=%Q"
" AND length(cap)>0"
" AND length(pw)>0"
|
| ︙ | ︙ | |||
745 746 747 748 749 750 751 |
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",
|
| ︙ | ︙ | |||
776 777 778 779 780 781 782 783 784 785 786 787 |
void login_check_credentials(void){
int uid = 0; /* User id */
const char *zCookie; /* Text of the login cookie */
const char *zIpAddr; /* Raw IP address of the requestor */
char *zRemoteAddr; /* Abbreviated IP address of the requestor */
const char *zCap = 0; /* Capability string */
const char *zPublicPages = 0; /* GLOB patterns of public pages */
/* Only run this check once. */
if( g.userUid!=0 ) return;
sqlite3_create_function(g.db, "constant_time_cmp", 2, SQLITE_UTF8, 0,
| > | | > > > > | > | 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 |
void login_check_credentials(void){
int uid = 0; /* User id */
const char *zCookie; /* Text of the login cookie */
const char *zIpAddr; /* Raw IP address of the requestor */
char *zRemoteAddr; /* Abbreviated IP address of the requestor */
const char *zCap = 0; /* Capability string */
const char *zPublicPages = 0; /* GLOB patterns of public pages */
const char *zLogin = 0; /* Login user for credentials */
/* Only run this check once. */
if( g.userUid!=0 ) return;
sqlite3_create_function(g.db, "constant_time_cmp", 2, SQLITE_UTF8, 0,
constant_time_cmp_function, 0, 0);
/* 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 ||
g.fSshClient & CGI_SSH_CLIENT )
&& g.useLocalauth
&& db_get_int("localauth",0)==0
&& P("HTTPS")==0
){
if( g.localOpen ) zLogin = db_lget("default-user",0);
if( zLogin!=0 ){
uid = db_int(0, "SELECT uid FROM user WHERE login=%Q", zLogin);
}else{
uid = db_int(0, "SELECT uid FROM user WHERE cap LIKE '%%s%%'");
}
g.zLogin = db_text("?", "SELECT login FROM user WHERE uid=%d", uid);
zCap = "sx";
g.noPswd = 1;
g.isHuman = 1;
sqlite3_snprintf(sizeof(g.zCsrfToken), g.zCsrfToken, "localhost");
}
|
| ︙ | ︙ | |||
834 835 836 837 838 839 840 |
/* 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
);
}
|
| ︙ | ︙ | |||
989 990 991 992 993 994 995 |
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;
|
| ︙ | ︙ | |||
1012 1013 1014 1015 1016 1017 1018 |
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);
}
|
| ︙ | ︙ | |||
1346 1347 1348 1349 1350 1351 1352 |
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 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 |
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 ){
const char *zRepoName = db_column_text(&q, 1);
if( file_size(zRepoName)<0 ){
/* Silently remove non-existent repositories from the login group. */
const char *zLabel = db_column_text(&q, 0);
db_multi_exec(
"DELETE FROM config WHERE name GLOB 'peer-*-%q'",
&zLabel[10]
);
continue;
}
rc = sqlite3_open_v2(
zRepoName, &pPeer,
SQLITE_OPEN_READWRITE,
g.zVfsName
);
if( rc!=SQLITE_OK ){
blob_appendf(&err, "%s%s: %s%s", zPrefix, zRepoName,
sqlite3_errmsg(pPeer), zSuffix);
nErr++;
sqlite3_close(pPeer);
continue;
}
|
| ︙ | ︙ | |||
1424 1425 1426 1427 1428 1429 1430 |
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);
|
| ︙ | ︙ | |||
1451 1452 1453 1454 1455 1456 1457 |
}
/* Make sure the other repository is a valid Fossil database */
if( file_size(zRepo)<0 ){
*pzErrMsg = mprintf("repository file \"%s\" does not exist", zRepo);
return;
}
| | > > > > | 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 |
}
/* Make sure the other repository is a valid Fossil database */
if( file_size(zRepo)<0 ){
*pzErrMsg = mprintf("repository file \"%s\" does not exist", zRepo);
return;
}
rc = sqlite3_open_v2(
zRepo, &pOther,
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
g.zVfsName
);
if( rc!=SQLITE_OK ){
*pzErrMsg = mprintf(sqlite3_errmsg(pOther));
}else{
rc = sqlite3_exec(pOther, "SELECT count(*) FROM user", 0, 0, pzErrMsg);
}
sqlite3_close(pOther);
if( rc ) return;
|
| ︙ | ︙ |
Changes to src/main.c.
| ︙ | ︙ | |||
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> | > | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | ** http://www.hwaci.com/drh/ ** ******************************************************************************* ** ** This module codes the main() procedure that runs first when the ** program is invoked. */ #include "VERSION.h" #include "config.h" #include "main.h" #include <string.h> #include <time.h> #include <fcntl.h> #include <sys/types.h> #include <sys/stat.h> |
| ︙ | ︙ | |||
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
void *pPostContext; /* Optional, provided to xPostEval(). */
};
#endif
/*
** All global variables are in this structure.
*/
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 */
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 */
| > > > | 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
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 */
|
| ︙ | ︙ | |||
165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 | 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 */ 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 */ | > > > > | > > | 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 |
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 */
int useProxy; /* Used to remember that a proxy is in use */
char *proxyUrlPath;
int proxyOrigPort; /* Tunneled port number for https through proxy */
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 */
|
| ︙ | ︙ | |||
367 368 369 370 371 372 373 374 375 376 377 378 379 380 |
cson_value_free(g.json.gc.v);
memset(&g.json, 0, sizeof(g.json));
#endif
free(g.zErrMsg);
if(g.db){
db_close(0);
}
}
/*
** Convert all arguments from mbcs (or unicode) to UTF-8. Then
** search g.argv for arguments "--args FILENAME". If found, then
** (1) remove the two arguments from g.argv
** (2) Read the file FILENAME
| > > > > > > > > > > | 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 |
cson_value_free(g.json.gc.v);
memset(&g.json, 0, sizeof(g.json));
#endif
free(g.zErrMsg);
if(g.db){
db_close(0);
}
/*
** FIXME: The next two lines cannot always be enabled; however, they
** are very useful for tracking down TH1 memory leaks.
*/
if( fossil_getenv("TH1_DELETE_INTERP")!=0 ){
if( g.interp ){
Th_DeleteInterp(g.interp); g.interp = 0;
}
assert( Th_GetOutstandingMalloc()==0 );
}
}
/*
** Convert all arguments from mbcs (or unicode) to UTF-8. Then
** search g.argv for arguments "--args FILENAME". If found, then
** (1) remove the two arguments from g.argv
** (2) Read the file FILENAME
|
| ︙ | ︙ | |||
549 550 551 552 553 554 555 556 557 558 559 560 561 562 |
#endif
int main(int argc, char **argv)
#endif
{
const char *zCmdName = "unknown";
int idx;
int rc;
sqlite3_config(SQLITE_CONFIG_LOG, fossil_sqlite_log, 0);
memset(&g, 0, sizeof(g));
g.now = time(0);
g.httpHeader = empty_blob;
#ifdef FOSSIL_ENABLE_JSON
#if defined(NDEBUG)
g.json.errorDetailParanoia = 2 /* FIXME: make configurable
| > > > > > | 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 |
#endif
int main(int argc, char **argv)
#endif
{
const char *zCmdName = "unknown";
int idx;
int rc;
if( sqlite3_libversion_number()<3008003 ){
fossil_fatal("Unsuitable SQLite version %s, must be at least 3.8.3",
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;
#ifdef FOSSIL_ENABLE_JSON
#if defined(NDEBUG)
g.json.errorDetailParanoia = 2 /* FIXME: make configurable
|
| ︙ | ︙ | |||
573 574 575 576 577 578 579 580 581 582 583 584 585 586 |
expand_args_option(argc, argv);
#ifdef FOSSIL_ENABLE_TCL
memset(&g.tcl, 0, sizeof(TclContext));
g.tcl.argc = g.argc;
g.tcl.argv = copy_args(g.argc, g.argv); /* save full arguments */
#endif
g.mainTimerId = fossil_timer_start();
if( fossil_getenv("GATEWAY_INTERFACE")!=0 && !find_option("nocgi", 0, 0)){
zCmdName = "cgi";
g.isHTTP = 1;
}else if( g.argc<2 ){
fossil_print(
"Usage: %s COMMAND ...\n"
" or: %s help -- for a list of common commands\n"
| > > > > > > > > > > > > > > > > > | 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 |
expand_args_option(argc, argv);
#ifdef FOSSIL_ENABLE_TCL
memset(&g.tcl, 0, sizeof(TclContext));
g.tcl.argc = g.argc;
g.tcl.argv = copy_args(g.argc, g.argv); /* save full arguments */
#endif
g.mainTimerId = fossil_timer_start();
g.zVfsName = find_option("vfs",0,1);
if( g.zVfsName==0 ){
g.zVfsName = fossil_getenv("FOSSIL_VFS");
#if defined(__CYGWIN__)
if( g.zVfsName==0 ){
g.zVfsName = "win32-longpath";
}
#endif
}
if( g.zVfsName ){
sqlite3_vfs *pVfs = sqlite3_vfs_find(g.zVfsName);
if( pVfs ){
sqlite3_vfs_register(pVfs, 1);
}else{
fossil_fatal("no such VFS: \"%s\"", g.zVfsName);
}
}
if( fossil_getenv("GATEWAY_INTERFACE")!=0 && !find_option("nocgi", 0, 0)){
zCmdName = "cgi";
g.isHTTP = 1;
}else if( g.argc<2 ){
fossil_print(
"Usage: %s COMMAND ...\n"
" or: %s help -- for a list of common commands\n"
|
| ︙ | ︙ | |||
802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 |
}
assert(nCmd && "page list is empty?");
multi_column_list(aCmd, nCmd);
}
/*
** COMMAND: version
**
** Usage: %fossil version ?-verbose|-v?
**
** Print the source code version number for the fossil executable.
** If the verbose option is specified, additional details will
** be output about what optional features this binary was compiled
** with
*/
void version_cmd(void){
| > > > > > > > > > > > > > > > > > > | < | | 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 |
}
assert(nCmd && "page list is empty?");
multi_column_list(aCmd, nCmd);
}
/*
** This function returns a human readable version string.
*/
const char *get_version(){
static const char version[] = RELEASE_VERSION " " MANIFEST_VERSION " "
MANIFEST_DATE " UTC";
return version;
}
/*
** This function returns the user-agent string for Fossil, for
** use in HTTP(S) requests.
*/
const char *get_user_agent(){
static const char version[] = "Fossil/" RELEASE_VERSION " (" MANIFEST_DATE
" " MANIFEST_VERSION ")";
return version;
}
/*
** COMMAND: version
**
** Usage: %fossil version ?-verbose|-v?
**
** Print the source code version number for the fossil executable.
** If the verbose option is specified, additional details will
** be output about what optional features this binary was compiled
** with
*/
void version_cmd(void){
fossil_print("This is fossil version %s\n", get_version());
if(!find_option("verbose","v",0)){
return;
}else{
#if defined(FOSSIL_ENABLE_TCL)
int rc;
const char *zRc;
#endif
fossil_print("Compiled on %s %s using %s (%d-bit)\n",
__DATE__, __TIME__, COMPILER_NAME, sizeof(void*)*8);
fossil_print("SQLite %s %.30s\n", sqlite3_libversion(), sqlite3_sourceid());
fossil_print("Schema version %s\n", AUX_SCHEMA);
fossil_print("zlib %s, loaded %s\n", ZLIB_VERSION, zlibVersion());
#if defined(FOSSIL_ENABLE_SSL)
fossil_print("SSL (%s)\n", OPENSSL_VERSION_TEXT);
#endif
#if defined(FOSSIL_ENABLE_TCL)
Th_FossilInit(TH_INIT_DEFAULT | TH_INIT_FORCE_TCL);
|
| ︙ | ︙ | |||
1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 |
@ <td valign="top"><ul>
}
if( aCmdHelp[i].zText && *aCmdHelp[i].zText ){
@ <li><a href="%s(g.zTop)/help?cmd=%s(z)">%s(z+1)</a></li>
}else{
@ <li>%s(z+1)</li>
}
j++;
if( j>=n ){
@ </ul></td>
j = 0;
}
}
if( j>0 ){
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 |
@ <td valign="top"><ul>
}
if( aCmdHelp[i].zText && *aCmdHelp[i].zText ){
@ <li><a href="%s(g.zTop)/help?cmd=%s(z)">%s(z+1)</a></li>
}else{
@ <li>%s(z+1)</li>
}
j++;
if( j>=n ){
@ </ul></td>
j = 0;
}
}
if( j>0 ){
@ </ul></td>
}
@ </tr></table>
@ <h1>Unsupported commands:</h1>
@ <table border="0"><tr>
for(i=j=0; i<count(aCommand); i++){
const char *z = aCommand[i].zName;
if( strncmp(z,"test",4)!=0 ) continue;
j++;
}
n = (j+3)/4;
for(i=j=0; i<count(aCommand); i++){
const char *z = aCommand[i].zName;
if( strncmp(z,"test",4)!=0 ) continue;
if( j==0 ){
@ <td valign="top"><ul>
}
if( aCmdHelp[i].zText && *aCmdHelp[i].zText ){
@ <li><a href="%s(g.zTop)/help?cmd=%s(z)">%s(z)</a></li>
}else{
@ <li>%s(z)</li>
}
j++;
if( j>=n ){
@ </ul></td>
j = 0;
}
}
if( j>0 ){
|
| ︙ | ︙ |
Changes to src/main.mk.
| ︙ | ︙ | |||
112 113 114 115 116 117 118 119 120 121 122 123 124 125 | $(SRCDIR)/user.c \ $(SRCDIR)/utf8.c \ $(SRCDIR)/util.c \ $(SRCDIR)/verify.c \ $(SRCDIR)/vfile.c \ $(SRCDIR)/wiki.c \ $(SRCDIR)/wikiformat.c \ $(SRCDIR)/winhttp.c \ $(SRCDIR)/wysiwyg.c \ $(SRCDIR)/xfer.c \ $(SRCDIR)/xfersetup.c \ $(SRCDIR)/zip.c TRANS_SRC = \ | > | 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 | $(SRCDIR)/user.c \ $(SRCDIR)/utf8.c \ $(SRCDIR)/util.c \ $(SRCDIR)/verify.c \ $(SRCDIR)/vfile.c \ $(SRCDIR)/wiki.c \ $(SRCDIR)/wikiformat.c \ $(SRCDIR)/winfile.c \ $(SRCDIR)/winhttp.c \ $(SRCDIR)/wysiwyg.c \ $(SRCDIR)/xfer.c \ $(SRCDIR)/xfersetup.c \ $(SRCDIR)/zip.c TRANS_SRC = \ |
| ︙ | ︙ | |||
221 222 223 224 225 226 227 228 229 230 231 232 233 234 | $(OBJDIR)/user_.c \ $(OBJDIR)/utf8_.c \ $(OBJDIR)/util_.c \ $(OBJDIR)/verify_.c \ $(OBJDIR)/vfile_.c \ $(OBJDIR)/wiki_.c \ $(OBJDIR)/wikiformat_.c \ $(OBJDIR)/winhttp_.c \ $(OBJDIR)/wysiwyg_.c \ $(OBJDIR)/xfer_.c \ $(OBJDIR)/xfersetup_.c \ $(OBJDIR)/zip_.c OBJ = \ | > | 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 | $(OBJDIR)/user_.c \ $(OBJDIR)/utf8_.c \ $(OBJDIR)/util_.c \ $(OBJDIR)/verify_.c \ $(OBJDIR)/vfile_.c \ $(OBJDIR)/wiki_.c \ $(OBJDIR)/wikiformat_.c \ $(OBJDIR)/winfile_.c \ $(OBJDIR)/winhttp_.c \ $(OBJDIR)/wysiwyg_.c \ $(OBJDIR)/xfer_.c \ $(OBJDIR)/xfersetup_.c \ $(OBJDIR)/zip_.c OBJ = \ |
| ︙ | ︙ | |||
330 331 332 333 334 335 336 337 338 339 340 341 342 343 | $(OBJDIR)/user.o \ $(OBJDIR)/utf8.o \ $(OBJDIR)/util.o \ $(OBJDIR)/verify.o \ $(OBJDIR)/vfile.o \ $(OBJDIR)/wiki.o \ $(OBJDIR)/wikiformat.o \ $(OBJDIR)/winhttp.o \ $(OBJDIR)/wysiwyg.o \ $(OBJDIR)/xfer.o \ $(OBJDIR)/xfersetup.o \ $(OBJDIR)/zip.o APPNAME = fossil$(E) | > | 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 | $(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 APPNAME = fossil$(E) |
| ︙ | ︙ | |||
369 370 371 372 373 374 375 376 377 378 379 380 381 382 | # build is done from, i.e. the checkout belongs to. Do not sync/push # the repository after running the tests. test: $(OBJDIR) $(APPNAME) $(TCLSH) $(SRCDIR)/../test/tester.tcl $(APPNAME) $(OBJDIR)/VERSION.h: $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION $(OBJDIR)/mkversion $(OBJDIR)/mkversion $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION >$(OBJDIR)/VERSION.h # The USE_SYSTEM_SQLITE variable may be undefined, set to 0, or set # 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 | > > > > > > > > > > > > | 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 |
# build is done from, i.e. the checkout belongs to. Do not sync/push
# the repository after running the tests.
test: $(OBJDIR) $(APPNAME)
$(TCLSH) $(SRCDIR)/../test/tester.tcl $(APPNAME)
$(OBJDIR)/VERSION.h: $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION $(OBJDIR)/mkversion
$(OBJDIR)/mkversion $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION >$(OBJDIR)/VERSION.h
# Setup the options used to compile the included SQLite library.
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
# Setup the options used to compile the included SQLite shell.
SHELL_OPTIONS = -Dmain=sqlite3_shell \
-DSQLITE_OMIT_LOAD_EXTENSION=1
# The USE_SYSTEM_SQLITE variable may be undefined, set to 0, or set
# 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
|
| ︙ | ︙ | |||
403 404 405 406 407 408 409 | 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 | | | 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 | 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 |
| ︙ | ︙ | |||
1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 | $(OBJDIR)/wikiformat_.c: $(SRCDIR)/wikiformat.c $(OBJDIR)/translate $(OBJDIR)/translate $(SRCDIR)/wikiformat.c >$(OBJDIR)/wikiformat_.c $(OBJDIR)/wikiformat.o: $(OBJDIR)/wikiformat_.c $(OBJDIR)/wikiformat.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/wikiformat.o -c $(OBJDIR)/wikiformat_.c $(OBJDIR)/wikiformat.h: $(OBJDIR)/headers $(OBJDIR)/winhttp_.c: $(SRCDIR)/winhttp.c $(OBJDIR)/translate $(OBJDIR)/translate $(SRCDIR)/winhttp.c >$(OBJDIR)/winhttp_.c $(OBJDIR)/winhttp.o: $(OBJDIR)/winhttp_.c $(OBJDIR)/winhttp.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/winhttp.o -c $(OBJDIR)/winhttp_.c $(OBJDIR)/winhttp.h: $(OBJDIR)/headers | > > > > > > > | 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 | $(OBJDIR)/wikiformat_.c: $(SRCDIR)/wikiformat.c $(OBJDIR)/translate $(OBJDIR)/translate $(SRCDIR)/wikiformat.c >$(OBJDIR)/wikiformat_.c $(OBJDIR)/wikiformat.o: $(OBJDIR)/wikiformat_.c $(OBJDIR)/wikiformat.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/wikiformat.o -c $(OBJDIR)/wikiformat_.c $(OBJDIR)/wikiformat.h: $(OBJDIR)/headers $(OBJDIR)/winfile_.c: $(SRCDIR)/winfile.c $(OBJDIR)/translate $(OBJDIR)/translate $(SRCDIR)/winfile.c >$(OBJDIR)/winfile_.c $(OBJDIR)/winfile.o: $(OBJDIR)/winfile_.c $(OBJDIR)/winfile.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/winfile.o -c $(OBJDIR)/winfile_.c $(OBJDIR)/winfile.h: $(OBJDIR)/headers $(OBJDIR)/winhttp_.c: $(SRCDIR)/winhttp.c $(OBJDIR)/translate $(OBJDIR)/translate $(SRCDIR)/winhttp.c >$(OBJDIR)/winhttp_.c $(OBJDIR)/winhttp.o: $(OBJDIR)/winhttp_.c $(OBJDIR)/winhttp.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/winhttp.o -c $(OBJDIR)/winhttp_.c $(OBJDIR)/winhttp.h: $(OBJDIR)/headers |
| ︙ | ︙ | |||
1158 1159 1160 1161 1162 1163 1164 | $(OBJDIR)/translate $(SRCDIR)/zip.c >$(OBJDIR)/zip_.c $(OBJDIR)/zip.o: $(OBJDIR)/zip_.c $(OBJDIR)/zip.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/zip.o -c $(OBJDIR)/zip_.c $(OBJDIR)/zip.h: $(OBJDIR)/headers $(OBJDIR)/sqlite3.o: $(SRCDIR)/sqlite3.c | | | | 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 | $(OBJDIR)/translate $(SRCDIR)/zip.c >$(OBJDIR)/zip_.c $(OBJDIR)/zip.o: $(OBJDIR)/zip_.c $(OBJDIR)/zip.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/zip.o -c $(OBJDIR)/zip_.c $(OBJDIR)/zip.h: $(OBJDIR)/headers $(OBJDIR)/sqlite3.o: $(SRCDIR)/sqlite3.c $(XTCC) $(SQLITE_OPTIONS) $(SQLITE_CFLAGS) -c $(SRCDIR)/sqlite3.c -o $(OBJDIR)/sqlite3.o $(OBJDIR)/shell.o: $(SRCDIR)/shell.c $(SRCDIR)/sqlite3.h $(XTCC) $(SHELL_OPTIONS) $(SHELL_CFLAGS) -c $(SRCDIR)/shell.c -o $(OBJDIR)/shell.o $(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 |
| ︙ | ︙ |
Changes to src/makemake.tcl.
| ︙ | ︙ | |||
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 | user utf8 util verify vfile wiki wikiformat winhttp wysiwyg xfer xfersetup zip http_ssl } # Name of the final application # set name fossil # The "writeln" command sends output to the target makefile. # | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 |
user
utf8
util
verify
vfile
wiki
wikiformat
winfile
winhttp
wysiwyg
xfer
xfersetup
zip
http_ssl
}
# Options used to compile the included SQLite library.
#
set 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
}
#lappend SQLITE_OPTIONS -DSQLITE_ENABLE_FTS3=1
#lappend SQLITE_OPTIONS -DSQLITE_ENABLE_STAT4
#lappend SQLITE_OPTIONS -DSQLITE_WIN32_NO_ANSI
#lappend SQLITE_OPTIONS -DSQLITE_WINNT_MAX_PATH_CHARS=4096
# Options used to compile the included SQLite shell.
#
set SHELL_OPTIONS {
-Dmain=sqlite3_shell
-DSQLITE_OMIT_LOAD_EXTENSION=1
}
# Options used to compile the included SQLite shell on Windows.
#
set SHELL_WIN32_OPTIONS $SHELL_OPTIONS
lappend SHELL_WIN32_OPTIONS -Dgetenv=fossil_getenv
lappend SHELL_WIN32_OPTIONS -Dfopen=fossil_fopen
# Name of the final application
#
set name fossil
# The "writeln" command sends output to the target makefile.
#
|
| ︙ | ︙ | |||
184 185 186 187 188 189 190 |
foreach s [lsort $src] {
writeln -nonewline " \\\n \$(OBJDIR)/$s.o"
}
writeln "\n"
writeln "APPNAME = $name\$(E)"
writeln "\n"
| | > > | 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 |
foreach s [lsort $src] {
writeln -nonewline " \\\n \$(OBJDIR)/$s.o"
}
writeln "\n"
writeln "APPNAME = $name\$(E)"
writeln "\n"
writeln [string map [list \
<<<SQLITE_OPTIONS>>> [join $SQLITE_OPTIONS " \\\n "] \
<<<SHELL_OPTIONS>>> [join $SHELL_OPTIONS " \\\n "]] {
all: $(OBJDIR) $(APPNAME)
install: $(APPNAME)
mkdir -p $(INSTALLDIR)
mv $(APPNAME) $(INSTALLDIR)
$(OBJDIR):
|
| ︙ | ︙ | |||
216 217 218 219 220 221 222 223 224 225 226 227 228 229 | test: $(OBJDIR) $(APPNAME) $(TCLSH) $(SRCDIR)/../test/tester.tcl $(APPNAME) $(OBJDIR)/VERSION.h: $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION $(OBJDIR)/mkversion $(OBJDIR)/mkversion $(SRCDIR)/../manifest.uuid \ $(SRCDIR)/../manifest \ $(SRCDIR)/../VERSION >$(OBJDIR)/VERSION.h # The USE_SYSTEM_SQLITE variable may be undefined, set to 0, or set # 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 | > > > > > > | 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 | test: $(OBJDIR) $(APPNAME) $(TCLSH) $(SRCDIR)/../test/tester.tcl $(APPNAME) $(OBJDIR)/VERSION.h: $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION $(OBJDIR)/mkversion $(OBJDIR)/mkversion $(SRCDIR)/../manifest.uuid \ $(SRCDIR)/../manifest \ $(SRCDIR)/../VERSION >$(OBJDIR)/VERSION.h # Setup the options used to compile the included SQLite library. SQLITE_OPTIONS = <<<SQLITE_OPTIONS>>> # Setup the options used to compile the included SQLite shell. SHELL_OPTIONS = <<<SHELL_OPTIONS>>> # The USE_SYSTEM_SQLITE variable may be undefined, set to 0, or set # 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 |
| ︙ | ︙ | |||
252 253 254 255 256 257 258 | # $(SRCDIR)/../manifest: # noop clean: rm -rf $(OBJDIR)/* $(APPNAME) | | | 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 |
#
$(SRCDIR)/../manifest:
# noop
clean:
rm -rf $(OBJDIR)/* $(APPNAME)
}]
set mhargs {}
foreach s [lsort $src] {
append mhargs " \$(OBJDIR)/${s}_.c:\$(OBJDIR)/$s.h"
set extra_h($s) {}
}
append mhargs " \$(SRCDIR)/sqlite3.h"
|
| ︙ | ︙ | |||
281 282 283 284 285 286 287 |
writeln "\$(OBJDIR)/${s}_.c:\t\$(SRCDIR)/$s.c \$(OBJDIR)/translate"
writeln "\t\$(OBJDIR)/translate \$(SRCDIR)/$s.c >\$(OBJDIR)/${s}_.c\n"
writeln "\$(OBJDIR)/$s.o:\t\$(OBJDIR)/${s}_.c \$(OBJDIR)/$s.h $extra_h($s) \$(SRCDIR)/config.h"
writeln "\t\$(XTCC) -o \$(OBJDIR)/$s.o -c \$(OBJDIR)/${s}_.c\n"
writeln "\$(OBJDIR)/$s.h:\t\$(OBJDIR)/headers"
}
| < < < < < < < < < | < < < | < | 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 |
writeln "\$(OBJDIR)/${s}_.c:\t\$(SRCDIR)/$s.c \$(OBJDIR)/translate"
writeln "\t\$(OBJDIR)/translate \$(SRCDIR)/$s.c >\$(OBJDIR)/${s}_.c\n"
writeln "\$(OBJDIR)/$s.o:\t\$(OBJDIR)/${s}_.c \$(OBJDIR)/$s.h $extra_h($s) \$(SRCDIR)/config.h"
writeln "\t\$(XTCC) -o \$(OBJDIR)/$s.o -c \$(OBJDIR)/${s}_.c\n"
writeln "\$(OBJDIR)/$s.h:\t\$(OBJDIR)/headers"
}
writeln "\$(OBJDIR)/sqlite3.o:\t\$(SRCDIR)/sqlite3.c"
writeln "\t\$(XTCC) \$(SQLITE_OPTIONS) \$(SQLITE_CFLAGS) -c \$(SRCDIR)/sqlite3.c -o \$(OBJDIR)/sqlite3.o\n"
writeln "\$(OBJDIR)/shell.o:\t\$(SRCDIR)/shell.c \$(SRCDIR)/sqlite3.h"
writeln "\t\$(XTCC) \$(SHELL_OPTIONS) \$(SHELL_CFLAGS) -c \$(SRCDIR)/shell.c -o \$(OBJDIR)/shell.o\n"
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 "\$(OBJDIR)/th_tcl.o:\t\$(SRCDIR)/th_tcl.c"
writeln "\t\$(XTCC) -c \$(SRCDIR)/th_tcl.c -o \$(OBJDIR)/th_tcl.o\n"
writeln {
$(OBJDIR)/cson_amalgamation.o: $(SRCDIR)/cson_amalgamation.c
$(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.o
#
# The list of all the targets that do not correspond to real files. This stops
# 'make' from getting confused when someone makes an error in a rule.
|
| ︙ | ︙ | |||
421 422 423 424 425 426 427 | ZLIBDIR = $(SRCDIR)/../compat/zlib #### The directories where the OpenSSL include and library files are located. # The recommended usage here is to use the Sysinternals junction tool # to create a hard link between an "openssl-1.x" sub-directory of the # Fossil source code directory and the target OpenSSL source directory. # | | | | 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 | ZLIBDIR = $(SRCDIR)/../compat/zlib #### The directories where the OpenSSL include and library files are located. # The recommended usage here is to use the Sysinternals junction tool # to create a hard link between an "openssl-1.x" sub-directory of the # Fossil source code directory and the target OpenSSL source directory. # OPENSSLINCDIR = $(SRCDIR)/../compat/openssl-1.0.1f/include OPENSSLLIBDIR = $(SRCDIR)/../compat/openssl-1.0.1f #### Either the directory where the Tcl library is installed or the Tcl # source code directory resides (depending on the value of the macro # FOSSIL_TCL_SOURCE). If this points to the Tcl install directory, # this directory must have "include" and "lib" sub-directories. If # this points to the Tcl source code directory, this directory must # have "generic" and "win" sub-directories. The recommended usage |
| ︙ | ︙ | |||
644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 |
writeln {
all: $(OBJDIR) $(APPNAME)
$(OBJDIR)/fossil.o: $(SRCDIR)/../win/fossil.rc $(OBJDIR)/VERSION.h
ifdef USE_WINDOWS
$(CP) $(subst /,\,$(SRCDIR)\..\win\fossil.rc) $(subst /,\,$(OBJDIR))
$(CP) $(subst /,\,$(SRCDIR)\..\win\fossil.ico) $(subst /,\,$(OBJDIR))
else
$(CP) $(SRCDIR)/../win/fossil.rc $(OBJDIR)
$(CP) $(SRCDIR)/../win/fossil.ico $(OBJDIR)
endif
$(RCC) $(OBJDIR)/fossil.rc -o $(OBJDIR)/fossil.o
install: $(OBJDIR) $(APPNAME)
ifdef USE_WINDOWS
$(MKDIR) $(subst /,\,$(INSTALLDIR))
$(MV) $(subst /,\,$(APPNAME)) $(subst /,\,$(INSTALLDIR))
| > > | 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 |
writeln {
all: $(OBJDIR) $(APPNAME)
$(OBJDIR)/fossil.o: $(SRCDIR)/../win/fossil.rc $(OBJDIR)/VERSION.h
ifdef USE_WINDOWS
$(CP) $(subst /,\,$(SRCDIR)\..\win\fossil.rc) $(subst /,\,$(OBJDIR))
$(CP) $(subst /,\,$(SRCDIR)\..\win\fossil.ico) $(subst /,\,$(OBJDIR))
$(CP) $(subst /,\,$(SRCDIR)\..\win\fossil.exe.manifest) $(subst /,\,$(OBJDIR))
else
$(CP) $(SRCDIR)/../win/fossil.rc $(OBJDIR)
$(CP) $(SRCDIR)/../win/fossil.ico $(OBJDIR)
$(CP) $(SRCDIR)/../win/fossil.exe.manifest $(OBJDIR)
endif
$(RCC) $(OBJDIR)/fossil.rc -o $(OBJDIR)/fossil.o
install: $(OBJDIR) $(APPNAME)
ifdef USE_WINDOWS
$(MKDIR) $(subst /,\,$(INSTALLDIR))
$(MV) $(subst /,\,$(APPNAME)) $(subst /,\,$(INSTALLDIR))
|
| ︙ | ︙ | |||
766 767 768 769 770 771 772 773 |
writeln "\$(OBJDIR)/${s}_.c:\t\$(SRCDIR)/$s.c \$(OBJDIR)/translate"
writeln "\t\$(TRANSLATE) \$(SRCDIR)/$s.c >\$(OBJDIR)/${s}_.c\n"
writeln "\$(OBJDIR)/$s.o:\t\$(OBJDIR)/${s}_.c \$(OBJDIR)/$s.h $extra_h($s) \$(SRCDIR)/config.h"
writeln "\t\$(XTCC) -o \$(OBJDIR)/$s.o -c \$(OBJDIR)/${s}_.c\n"
writeln "\$(OBJDIR)/${s}.h:\t\$(OBJDIR)/headers\n"
}
| > > > > > > > > > | < < | < | | < < | | 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 |
writeln "\$(OBJDIR)/${s}_.c:\t\$(SRCDIR)/$s.c \$(OBJDIR)/translate"
writeln "\t\$(TRANSLATE) \$(SRCDIR)/$s.c >\$(OBJDIR)/${s}_.c\n"
writeln "\$(OBJDIR)/$s.o:\t\$(OBJDIR)/${s}_.c \$(OBJDIR)/$s.h $extra_h($s) \$(SRCDIR)/config.h"
writeln "\t\$(XTCC) -o \$(OBJDIR)/$s.o -c \$(OBJDIR)/${s}_.c\n"
writeln "\$(OBJDIR)/${s}.h:\t\$(OBJDIR)/headers\n"
}
set MINGW_SQLITE_OPTIONS $SQLITE_OPTIONS
lappend MINGW_SQLITE_OPTIONS -D_HAVE_SQLITE_CONFIG_H
lappend MINGW_SQLITE_OPTIONS -DSQLITE_USE_MALLOC_H
lappend MINGW_SQLITE_OPTIONS -DSQLITE_USE_MSIZE
set j " \\\n "
writeln "SQLITE_OPTIONS = [join $MINGW_SQLITE_OPTIONS $j]\n"
set j " \\\n "
writeln "SHELL_OPTIONS = [join $SHELL_WIN32_OPTIONS $j]\n"
writeln "\$(OBJDIR)/sqlite3.o:\t\$(SRCDIR)/sqlite3.c \$(SRCDIR)/../win/Makefile.mingw"
writeln "\t\$(XTCC) \$(SQLITE_OPTIONS) \$(SQLITE_CFLAGS) -c \$(SRCDIR)/sqlite3.c -o \$(OBJDIR)/sqlite3.o\n"
writeln "\$(OBJDIR)/cson_amalgamation.o:\t\$(SRCDIR)/cson_amalgamation.c"
writeln "\t\$(XTCC) -c \$(SRCDIR)/cson_amalgamation.c -o \$(OBJDIR)/cson_amalgamation.o\n"
writeln "\$(OBJDIR)/json.o \$(OBJDIR)/json_artifact.o \$(OBJDIR)/json_branch.o \$(OBJDIR)/json_config.o \$(OBJDIR)/json_diff.o \$(OBJDIR)/json_dir.o \$(OBJDIR)/jsos_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\n"
writeln "\$(OBJDIR)/shell.o:\t\$(SRCDIR)/shell.c \$(SRCDIR)/sqlite3.h \$(SRCDIR)/../win/Makefile.mingw"
writeln "\t\$(XTCC) \$(SHELL_OPTIONS) \$(SHELL_CFLAGS) -c \$(SRCDIR)/shell.c -o \$(OBJDIR)/shell.o\n"
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"
|
| ︙ | ︙ | |||
833 834 835 836 837 838 839 | SSL = CFLAGS = -o BCC = $(DMDIR)\bin\dmc $(CFLAGS) TCC = $(DMDIR)\bin\dmc $(CFLAGS) $(DMCDEF) $(SSL) $(INCL) LIBS = $(DMDIR)\extra\lib\ zlib wsock32 advapi32 } | | > | 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 |
SSL =
CFLAGS = -o
BCC = $(DMDIR)\bin\dmc $(CFLAGS)
TCC = $(DMDIR)\bin\dmc $(CFLAGS) $(DMCDEF) $(SSL) $(INCL)
LIBS = $(DMDIR)\extra\lib\ zlib wsock32 advapi32
}
writeln "SQLITE_OPTIONS = [join $SQLITE_OPTIONS { }]\n"
writeln "SHELL_OPTIONS = [join $SHELL_WIN32_OPTIONS { }]\n"
writeln -nonewline "SRC = "
foreach s [lsort $src] {
writeln -nonewline "${s}_.c "
}
writeln "\n"
writeln -nonewline "OBJ = "
foreach s [lsort $src] {
|
| ︙ | ︙ | |||
886 887 888 889 890 891 892 | mkindex$E: $(SRCDIR)\mkindex.c $(BCC) -o$@ $** version$E: $B\src\mkversion.c $(BCC) -o$@ $** $(OBJDIR)\shell$O : $(SRCDIR)\shell.c | | | | 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 | mkindex$E: $(SRCDIR)\mkindex.c $(BCC) -o$@ $** version$E: $B\src\mkversion.c $(BCC) -o$@ $** $(OBJDIR)\shell$O : $(SRCDIR)\shell.c $(TCC) -o$@ -c $(SHELL_OPTIONS) $(SQLITE_OPTIONS) $(SHELL_CFLAGS) $** $(OBJDIR)\sqlite3$O : $(SRCDIR)\sqlite3.c $(TCC) -o$@ -c $(SQLITE_OPTIONS) $(SQLITE_CFLAGS) $** $(OBJDIR)\th$O : $(SRCDIR)\th.c $(TCC) -o$@ -c $** $(OBJDIR)\th_lang$O : $(SRCDIR)\th_lang.c $(TCC) -o$@ -c $** |
| ︙ | ︙ | |||
972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 | # B = .. SRCDIR = $B\src OBJDIR = . OX = . O = .obj E = .exe # Uncomment to enable debug symbols # DEBUG = 1 # Uncomment to enable JSON API # FOSSIL_ENABLE_JSON = 1 # Uncomment to enable SSL support # FOSSIL_ENABLE_SSL = 1 !ifdef FOSSIL_ENABLE_SSL | > > > > | | > > > > > > | | > > > > | | | > > | | | | | | | | | > > > > > > > > > > > | > > > > > | 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 |
#
B = ..
SRCDIR = $B\src
OBJDIR = .
OX = .
O = .obj
E = .exe
P = .pdb
# Uncomment to enable debug symbols
# DEBUG = 1
# Uncomment to enable JSON API
# FOSSIL_ENABLE_JSON = 1
# Uncomment to enable SSL support
# FOSSIL_ENABLE_SSL = 1
# Uncomment to enable Tcl support
# FOSSIL_ENABLE_TCL = 1
!ifdef FOSSIL_ENABLE_SSL
SSLINCDIR = $(B)\compat\openssl-1.0.1f\include
SSLLIBDIR = $(B)\compat\openssl-1.0.1f\out32
SSLLIB = ssleay32.lib libeay32.lib user32.lib gdi32.lib
!endif
!ifdef FOSSIL_ENABLE_TCL
TCLDIR = $(B)\compat\tcl-8.6
TCLSRCDIR = $(TCLDIR)
TCLINCDIR = $(TCLSRCDIR)\generic
!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
!ifdef FOSSIL_ENABLE_TCL
INCL = $(INCL) /I$(TCLINCDIR)
!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
!ifdef FOSSIL_ENABLE_TCL
TCC = $(TCC) /DFOSSIL_ENABLE_TCL=1
RCC = $(RCC) /DFOSSIL_ENABLE_TCL=1
TCC = $(TCC) /DFOSSIL_ENABLE_TCL_STUBS=1
RCC = $(RCC) /DFOSSIL_ENABLE_TCL_STUBS=1
TCC = $(TCC) /DFOSSIL_ENABLE_TCL_PRIVATE_STUBS=1
RCC = $(RCC) /DFOSSIL_ENABLE_TCL_PRIVATE_STUBS=1
TCC = $(TCC) /DUSE_TCL_STUBS=1
RCC = $(RCC) /DUSE_TCL_STUBS=1
!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 " "
}
|
| ︙ | ︙ | |||
1049 1050 1051 1052 1053 1054 1055 |
if {$i > 0} {
writeln " \\"
writeln -nonewline " "
}
writeln -nonewline "\$(OX)\\$s\$O"; incr i
}
writeln " \\"
| | > > > > | > | | | | > | | | | > > > > > | | | > < | | 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 |
if {$i > 0} {
writeln " \\"
writeln -nonewline " "
}
writeln -nonewline "\$(OX)\\$s\$O"; incr i
}
writeln " \\"
writeln -nonewline " \$(OX)\\fossil.res\n\n"
writeln "!ifdef FOSSIL_ENABLE_TCL"
writeln "OBJ = \$(OBJ) \$(OX)\\th_tcl\$O"
writeln "!endif"
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 "!ifdef FOSSIL_ENABLE_TCL"
writeln "\techo \$(OX)\\th_tcl.obj $redir \$@"
set redir {>>}
writeln "!endif"
writeln "\techo \$(LIBS) $redir \$@"
writeln {
$(OX):
@-mkdir $@
translate$E: $(SRCDIR)\translate.c
$(BCC) $**
makeheaders$E: $(SRCDIR)\makeheaders.c
$(BCC) $**
mkindex$E: $(SRCDIR)\mkindex.c
$(BCC) $**
mkversion$E: $B\src\mkversion.c
$(BCC) $**
$(OX)\shell$O : $(SRCDIR)\shell.c $B\win\Makefile.msc
$(TCC) /Fo$@ $(SHELL_OPTIONS) $(SQLITE_OPTIONS) $(SHELL_CFLAGS) -c $(SRCDIR)\shell.c
$(OX)\sqlite3$O : $(SRCDIR)\sqlite3.c $B\win\Makefile.msc
$(TCC) /Fo$@ -c $(SQLITE_OPTIONS) $(SQLITE_CFLAGS) $(SRCDIR)\sqlite3.c
$(OX)\th$O : $(SRCDIR)\th.c
$(TCC) /Fo$@ -c $**
$(OX)\th_lang$O : $(SRCDIR)\th_lang.c
$(TCC) /Fo$@ -c $**
!ifdef FOSSIL_ENABLE_TCL
$(OX)\th_tcl$O : $(SRCDIR)\th_tcl.c
$(TCC) /Fo$@ -c $**
!endif
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
-del *_.c
-del *.h
-del *.map
-del *.res
-del headers
-del linkopts
-del vc*.pdb
realclean: clean
-del $(APPNAME)
-del $(PDBNAME)
-del translate$E
-del mkindex$E
-del makeheaders$E
-del mkversion$E
$(OBJDIR)\json$O : $(SRCDIR)\json_detail.h
$(OBJDIR)\json_artifact$O : $(SRCDIR)\json_detail.h
$(OBJDIR)\json_branch$O : $(SRCDIR)\json_detail.h
$(OBJDIR)\json_config$O : $(SRCDIR)\json_detail.h
$(OBJDIR)\json_diff$O : $(SRCDIR)\json_detail.h
$(OBJDIR)\json_dir$O : $(SRCDIR)\json_detail.h
$(OBJDIR)\json_finfo$O : $(SRCDIR)\json_detail.h
$(OBJDIR)\json_login$O : $(SRCDIR)\json_detail.h
$(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 \$@ \$**\n"
writeln "headers: makeheaders\$E page_index.h VERSION.h"
writeln -nonewline "\tmakeheaders\$E "
set i 0
foreach s [lsort $src] {
if {$i > 0} {
writeln " \\"
|
| ︙ | ︙ | |||
1182 1183 1184 1185 1186 1187 1188 | ############################################################################## # Begin win/Makefile.PellesCGMake output # puts "building ../win/Makefile.PellesCGMake" set output_file [open ../win/Makefile.PellesCGMake w] fconfigure $output_file -translation binary | | > > | 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 |
##############################################################################
# Begin win/Makefile.PellesCGMake output
#
puts "building ../win/Makefile.PellesCGMake"
set output_file [open ../win/Makefile.PellesCGMake w]
fconfigure $output_file -translation binary
writeln [string map [list \
<<<SQLITE_OPTIONS>>> [join $SQLITE_OPTIONS { }] \
<<<SHELL_OPTIONS>>> [join $SHELL_WIN32_OPTIONS { }]] {#
##############################################################################
# WARNING: DO NOT EDIT, AUTOMATICALLY GENERATED FILE (SEE "src/makemake.tcl")
##############################################################################
#
# This file is automatically generated. Instead of editing this
# file, edit "makemake.tcl" then run "tclsh makemake.tcl"
# to regenerate this file.
|
| ︙ | ︙ | |||
1269 1270 1271 1272 1273 1274 1275 | UTILS_OBJ=$(UTILS:.exe=.obj) UTILS_SRC=$(foreach uf,$(UTILS),$(SRCDIR)$(uf:.exe=.c)) # define the sqlite files, which need special flags on compile SQLITESRC=sqlite3.c ORIGSQLITESRC=$(foreach sf,$(SQLITESRC),$(SRCDIR)$(sf)) SQLITEOBJ=$(foreach sf,$(SQLITESRC),$(sf:.c=.obj)) | | | | 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 | UTILS_OBJ=$(UTILS:.exe=.obj) UTILS_SRC=$(foreach uf,$(UTILS),$(SRCDIR)$(uf:.exe=.c)) # define the sqlite files, which need special flags on compile SQLITESRC=sqlite3.c ORIGSQLITESRC=$(foreach sf,$(SQLITESRC),$(SRCDIR)$(sf)) SQLITEOBJ=$(foreach sf,$(SQLITESRC),$(sf:.c=.obj)) SQLITEDEFINES=<<<SQLITE_OPTIONS>>> # define the sqlite shell files, which need special flags on compile SQLITESHELLSRC=shell.c ORIGSQLITESHELLSRC=$(foreach sf,$(SQLITESHELLSRC),$(SRCDIR)$(sf)) SQLITESHELLOBJ=$(foreach sf,$(SQLITESHELLSRC),$(sf:.c=.obj)) SQLITESHELLDEFINES=<<<SHELL_OPTIONS>>> # define the th scripting files, which need special flags on compile THSRC=th.c th_lang.c ORIGTHSRC=$(foreach sf,$(THSRC),$(SRCDIR)$(sf)) THOBJ=$(foreach sf,$(THSRC),$(sf:.c=.obj)) # define the zlib files, needed by this compile |
| ︙ | ︙ | |||
1372 1373 1374 1375 1376 1377 1378 | del /F $(TRANSLATEDSRC) del /F *.h headers del /F $(RESOURCE) .PHONY: clobber clobber: clean del /F *.exe | | | 1448 1449 1450 1451 1452 1453 1454 1455 | del /F $(TRANSLATEDSRC) del /F *.h headers del /F $(RESOURCE) .PHONY: clobber clobber: clean del /F *.exe }] |
Changes to src/manifest.c.
| ︙ | ︙ | |||
40 41 42 43 44 45 46 47 48 49 | /* ** File permissions used by Fossil internally. */ #define PERM_REG 0 /* regular file */ #define PERM_EXE 1 /* executable */ #define PERM_LNK 2 /* symlink */ /* ** A single F-card within a manifest */ | > > > > > > | | 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
/*
** File permissions used by Fossil internally.
*/
#define PERM_REG 0 /* regular file */
#define PERM_EXE 1 /* executable */
#define PERM_LNK 2 /* symlink */
/*
** Flags for use with manifest_crosslink().
*/
#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 */
};
|
| ︙ | ︙ | |||
81 82 83 84 85 86 87 | 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
/*
|
| ︙ | ︙ | |||
243 244 245 246 247 248 249 | /* ** 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);
|
| ︙ | ︙ | |||
427 428 429 430 431 432 433 |
*/
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))
|
| ︙ | ︙ | |||
496 497 498 499 500 501 502 |
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");
|
| ︙ | ︙ | |||
543 544 545 546 547 548 549 |
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;
|
| ︙ | ︙ | |||
735 736 737 738 739 740 741 |
** 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);
|
| ︙ | ︙ | |||
1042 1043 1044 1045 1046 1047 1048 |
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;
}
/*
|
| ︙ | ︙ | |||
1067 1068 1069 1070 1071 1072 1073 | /* ** 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. */
|
| ︙ | ︙ | |||
1211 1212 1213 1214 1215 1216 1217 |
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.
*/
|
| ︙ | ︙ | |||
1255 1256 1257 1258 1259 1260 1261 | } /* ** 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;
|
| ︙ | ︙ | |||
1354 1355 1356 1357 1358 1359 1360 |
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,
|
| ︙ | ︙ | |||
1442 1443 1444 1445 1446 1447 1448 |
}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);
}
|
| ︙ | ︙ | |||
1486 1487 1488 1489 1490 1491 1492 | #define AGE_ADJUST_INCREMENT (25.0/86400000.0) /* 25 milliseconds */ #endif /* LOCAL_INTERFACE */ /* ** Finish up a sequence of manifest_crosslink calls. */ | | > > > > > > > > > > > > | 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 |
#define AGE_ADJUST_INCREMENT (25.0/86400000.0) /* 25 milliseconds */
#endif /* LOCAL_INTERFACE */
/*
** Finish up a sequence of manifest_crosslink calls.
*/
int manifest_crosslink_end(int flags){
Stmt q, u;
int i;
int rc = TH_OK;
int permitHooks = (flags & MC_PERMIT_HOOKS);
const char *zScript = 0;
assert( manifest_crosslink_busy==1 );
if( permitHooks ){
rc = xfer_run_common_script();
if( rc==TH_OK ){
zScript = xfer_ticket_code();
}
}
db_prepare(&q, "SELECT uuid FROM pending_tkt");
while( db_step(&q)==SQLITE_ROW ){
const char *zUuid = db_column_text(&q, 0);
ticket_rebuild_entry(zUuid);
if( permitHooks && rc==TH_OK ){
rc = xfer_run_script(zScript, zUuid);
}
}
db_finalize(&q);
db_multi_exec("DROP TABLE pending_tkt");
/* If multiple check-ins happen close together in time, adjust their
** times by a few milliseconds to make sure they appear in chronological
** order.
|
| ︙ | ︙ | |||
1520 1521 1522 1523 1524 1525 1526 |
db_reset(&q);
if( sqlite3_changes(g.db)==0 ) break;
db_step(&u);
db_reset(&u);
}
db_finalize(&q);
db_finalize(&u);
| > | | | < | > > > | 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 |
db_reset(&q);
if( sqlite3_changes(g.db)==0 ) break;
db_step(&u);
db_reset(&u);
}
db_finalize(&q);
db_finalize(&u);
if( db_exists("SELECT 1 FROM time_fudge") ){
db_multi_exec(
"UPDATE event SET mtime=(SELECT m1 FROM time_fudge WHERE mid=objid)"
" WHERE objid IN (SELECT mid FROM time_fudge);"
);
}
db_multi_exec("DROP TABLE time_fudge;");
db_end_transaction(0);
manifest_crosslink_busy = 0;
return ( rc!=TH_ERROR );
}
/*
** Make an entry in the event table for a ticket change artifact.
*/
void manifest_ticket_event(
int rid, /* Artifact ID of the change ticket artifact */
|
| ︙ | ︙ | |||
1555 1556 1557 1558 1559 1560 1561 |
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 |
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"
|
| ︙ | ︙ | |||
1638 1639 1640 1641 1642 1643 1644 | ** * 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 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 |
** * 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
** file, is a legacy of its original use.
*/
int manifest_crosslink(int rid, Blob *pContent, int flags){
int i, rc = TH_OK;
Manifest *p;
Stmt q;
int parentid = 0;
int permitHooks = (flags & MC_PERMIT_HOOKS);
const char *zScript = 0;
const char *zUuid = 0;
if( (p = manifest_cache_find(rid))!=0 ){
blob_reset(pContent);
}else if( (p = manifest_parse(pContent, rid, 0))==0 ){
assert( blob_is_reset(pContent) || pContent==0 );
fossil_error(1, "syntax error in manifest");
return 0;
}
if( g.xlinkClusterOnly && p->type!=CFTYPE_CLUSTER ){
manifest_destroy(p);
assert( blob_is_reset(pContent) );
fossil_error(1, "no manifest");
return 0;
}
if( p->type==CFTYPE_MANIFEST && fetch_baseline(p, 0) ){
manifest_destroy(p);
assert( blob_is_reset(pContent) );
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 ){
|
| ︙ | ︙ | |||
1711 1712 1713 1714 1715 1716 1717 |
" %.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);
|
| ︙ | ︙ | |||
1766 1767 1768 1769 1770 1771 1772 |
}
if( tid ){
switch( p->aTag[i].zName[0] ){
case '-': type = 0; break; /* Cancel prior occurrences */
case '+': type = 1; break; /* Apply to target only */
case '*': type = 2; break; /* Propagate to descendants */
default:
| | | | 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 |
}
if( tid ){
switch( p->aTag[i].zName[0] ){
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);
}
}
|
| ︙ | ︙ | |||
1810 1811 1812 1813 1814 1815 1816 |
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);
}
|
| ︙ | ︙ | |||
1860 1861 1862 1863 1864 1865 1866 |
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;
|
| ︙ | ︙ | |||
1892 1893 1894 1895 1896 1897 1898 |
"(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 |
"(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{
|
| ︙ | ︙ | |||
1932 1933 1934 1935 1936 1937 1938 |
}
}
if( p->type==CFTYPE_CONTROL ){
Blob comment;
int i;
const char *zName;
const char *zValue;
| | | | | | > > > > > > | | | 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 |
}
}
if( p->type==CFTYPE_CONTROL ){
Blob comment;
int i;
const char *zName;
const char *zValue;
const char *zTagUuid;
int branchMove = 0;
blob_zero(&comment);
if( p->zComment ){
blob_appendf(&comment, " %s.", p->zComment);
}
/* 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( permitHooks && db_exists("SELECT 1 FROM event, blob"
" WHERE event.type='ci' AND event.objid=blob.rid"
" AND blob.uuid='%s'", zTagUuid) ){
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;
}else if( strcmp(zName, "+bgcolor")==0 ){
|
| ︙ | ︙ | |||
2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 |
"REPLACE INTO event(type,mtime,objid,user,comment)"
"VALUES('g',%.17g,%d,%Q,%Q)",
p->rDate, rid, p->zUser, blob_str(&comment)+1
);
blob_reset(&comment);
}
db_end_transaction(0);
if( p->type==CFTYPE_MANIFEST ){
manifest_cache_insert(p);
}else{
manifest_destroy(p);
}
assert( blob_is_reset(pContent) );
| > > > > > > | | | 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 |
"REPLACE INTO event(type,mtime,objid,user,comment)"
"VALUES('g',%.17g,%d,%Q,%Q)",
p->rDate, rid, p->zUser, blob_str(&comment)+1
);
blob_reset(&comment);
}
db_end_transaction(0);
if( permitHooks ){
rc = xfer_run_common_script();
if( rc==TH_OK ){
rc = xfer_run_script(zScript, zUuid);
}
}
if( p->type==CFTYPE_MANIFEST ){
manifest_cache_insert(p);
}else{
manifest_destroy(p);
}
assert( blob_is_reset(pContent) );
return ( rc!=TH_ERROR );
}
/*
** COMMAND: test-crosslink
**
** Usage: %fossil test-crosslink RECORDID
**
** Run the manifest_crosslink() routine on the artifact with the given
** record ID. This is typically done in the debugger.
*/
void test_crosslink_cmd(void){
int rid;
Blob content;
db_find_and_open_repository(0, 0);
if( g.argc!=3 ) usage("RECORDID");
rid = name_to_rid(g.argv[2]);
content_get(rid, &content);
manifest_crosslink(rid, &content, MC_NONE);
}
|
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 {
const char *text;
int size;
};
/********************
* GLOBAL VARIABLES *
********************/
/* block_tags -- recognised block tags, sorted by cmp_html_tag */
static const 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 const struct html_tag *find_block_tag(const 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(const 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(const struct html_tag *tag, const 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;
const 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/md5.c.
| ︙ | ︙ | |||
162 163 164 165 166 167 168 |
}
/*
* Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
* initialization constants.
*/
static void MD5Init(MD5Context *ctx){
| | | 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 |
}
/*
* Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
* initialization constants.
*/
static void MD5Init(MD5Context *ctx){
ctx->isInit = 1;
ctx->buf[0] = 0x67452301;
ctx->buf[1] = 0xefcdab89;
ctx->buf[2] = 0x98badcfe;
ctx->buf[3] = 0x10325476;
ctx->bits[0] = 0;
ctx->bits[1] = 0;
}
|
| ︙ | ︙ |
Changes to src/merge.c.
| ︙ | ︙ | |||
24 25 26 27 28 29 30 |
/*
** Print information about a particular check-in.
*/
void print_checkin_description(int rid, int indent, const char *zLabel){
Stmt q;
db_prepare(&q,
| | | | 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
/*
** Print information about a particular check-in.
*/
void print_checkin_description(int rid, int indent, const char *zLabel){
Stmt q;
db_prepare(&q,
"SELECT datetime(mtime%s),"
" coalesce(euser,user), coalesce(ecomment,comment),"
" (SELECT uuid FROM blob WHERE rid=%d),"
" (SELECT group_concat(substr(tagname,5), ', ') FROM tag, tagxref"
" WHERE tagname GLOB 'sym-*' AND tag.tagid=tagxref.tagid"
" AND tagxref.rid=%d AND tagxref.tagtype>0)"
" FROM event WHERE objid=%d", timeline_utc(), rid, rid, rid);
if( db_step(&q)==SQLITE_ROW ){
const char *zTagList = db_column_text(&q, 4);
char *zCom;
if( zTagList && zTagList[0] ){
zCom = mprintf("%s (%s)", db_column_text(&q, 2), zTagList);
}else{
zCom = mprintf("%s", db_column_text(&q,2));
|
| ︙ | ︙ | |||
193 194 195 196 197 198 199 |
db_text(0, "SELECT value FROM tagxref"
" WHERE tagid=%d AND rid=%d AND tagtype>0",
TAG_BRANCH, vid)
);
}
db_prepare(&q,
"SELECT blob.uuid,"
| | | | 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 |
db_text(0, "SELECT value FROM tagxref"
" WHERE tagid=%d AND rid=%d AND tagtype>0",
TAG_BRANCH, vid)
);
}
db_prepare(&q,
"SELECT blob.uuid,"
" datetime(event.mtime%s),"
" coalesce(ecomment, comment),"
" coalesce(euser, user)"
" FROM event, blob"
" WHERE event.objid=%d AND blob.rid=%d",
timeline_utc(), mid, mid
);
if( db_step(&q)==SQLITE_ROW ){
char *zCom = mprintf("Merging fork [%S] at %s by %s: \"%s\"",
db_column_text(&q, 0), db_column_text(&q, 1),
db_column_text(&q, 3), db_column_text(&q, 2));
comment_print(zCom, 0, 79);
fossil_free(zCom);
|
| ︙ | ︙ | |||
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 |
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 && !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 74 75 |
z[0] = '\0';
break;
}
}
printf("#define RELEASE_RESOURCE_VERSION %s", vx);
while( d<3 ){ printf(",0"); d++; }
printf("\n");
return 0;
}
| > > > > > > > > > > > > > > | 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
z[0] = '\0';
break;
}
}
printf("#define RELEASE_RESOURCE_VERSION %s", vx);
while( d<3 ){ printf(",0"); d++; }
printf("\n");
#if defined(__DMC__) /* e.g. 0x857 */
d = (__DMC__ & 0xF00) >> 8; /* major */
x = (__DMC__ & 0x0F0) >> 4; /* minor */
i = (__DMC__ & 0x00F); /* revision */
printf("#define COMPILER_VERSION \"%d.%d.%d\"\n", d, x, i);
#elif defined(__POCC__) /* e.g. 700 */
d = (__POCC__ / 100); /* major */
x = (__POCC__ % 100); /* minor */
printf("#define COMPILER_VERSION \"%d.%02d\"\n", d, x);
#elif defined(_MSC_VER) /* e.g. 1800 */
d = (_MSC_VER / 100); /* major */
x = (_MSC_VER % 100); /* minor */
printf("#define COMPILER_VERSION \"%d.%02d\"\n", d, x);
#endif
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 *const 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:*" then always resolve the name as
** a date. The forms "utc:*" and "local:" are deprecated.
**
** 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 |
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>
|
| ︙ | ︙ | |||
456 457 458 459 460 461 462 |
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,
| | | | | | | | 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 ){
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/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 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 |
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 *const 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);
fprintf(out, "------------- %04d-%02d-%02d %02d:%02d:%02d UTC ------------\n",
pNow->tm_year+1900, pNow->tm_mon+1, pNow->tm_mday+1,
pNow->tm_hour, pNow->tm_min, pNow->tm_sec);
va_start(ap, zFormat);
vfprintf(out, zFormat, ap);
fprintf(out, "\n");
va_end(ap);
for(i=0; i<sizeof(azEnv)/sizeof(azEnv[0]); i++){
char *p;
if( (p = fossil_getenv(azEnv[i]))!=0 ){
fprintf(out, "%s=%s\n", azEnv[i], p);
fossil_filename_free(p);
}else if( (z = P(azEnv[i]))!=0 ){
fprintf(out, "%s=%s\n", azEnv[i], z);
}
}
fclose(out);
}
/*
|
| ︙ | ︙ |
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 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 |
/* 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 = ©
}
if( zFNameFormat==0 ){
/* We are doing "fossil rebuild" */
manifest_crosslink(rid, pUse, MC_NONE);
}else{
/* We are doing "fossil deconstruct" */
char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
char *zFile = mprintf(zFNameFormat, zUuid, zUuid+prefixLength);
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);
|
| ︙ | ︙ | |||
410 411 412 413 414 415 416 |
}
}else{
db_multi_exec("INSERT OR IGNORE INTO phantom VALUES(%d)", rid);
rebuild_step_done(rid);
}
}
db_finalize(&s);
| | | 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 |
}
}else{
db_multi_exec("INSERT OR IGNORE INTO phantom VALUES(%d)", rid);
rebuild_step_done(rid);
}
}
db_finalize(&s);
manifest_crosslink_end(MC_NONE);
rebuild_tag_trunk();
if( ttyOutput && !g.fQuiet && totalSize>0 ){
processCnt += incrSize;
percent_complete((processCnt*1000)/totalSize);
}
if( doClustering ) create_cluster();
if( ttyOutput && !g.fQuiet && totalSize>0 ){
|
| ︙ | ︙ | |||
579 580 581 582 583 584 585 |
}
db_begin_transaction();
ttyOutput = 1;
errCnt = rebuild_db(randomizeFlag, 1, doClustering);
reconstruct_private_table();
db_multi_exec(
"REPLACE INTO config(name,value,mtime) VALUES('content-schema','%s',now());"
| | > | | 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 |
}
db_begin_transaction();
ttyOutput = 1;
errCnt = rebuild_db(randomizeFlag, 1, doClustering);
reconstruct_private_table();
db_multi_exec(
"REPLACE INTO config(name,value,mtime) VALUES('content-schema','%s',now());"
"REPLACE INTO config(name,value,mtime) VALUES('aux-schema','%s',now());"
"REPLACE INTO config(name,value,mtime) VALUES('rebuilt','%s',now());",
CONTENT_SCHEMA, AUX_SCHEMA, get_version()
);
if( errCnt && !forceFlag ){
fossil_print(
"%d errors. Rolling back changes. Use --force to force a commit.\n",
errCnt
);
db_end_transaction(1);
|
| ︙ | ︙ | |||
605 606 607 608 609 610 611 |
db_open_repository(g.zRepositoryName);
if( newPagesize ){
db_multi_exec("PRAGMA page_size=%d", newPagesize);
runVacuum = 1;
}
if( runDeanalyze ){
db_multi_exec("DROP TABLE IF EXISTS sqlite_stat1;"
| | > | | 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 |
db_open_repository(g.zRepositoryName);
if( newPagesize ){
db_multi_exec("PRAGMA page_size=%d", newPagesize);
runVacuum = 1;
}
if( runDeanalyze ){
db_multi_exec("DROP TABLE IF EXISTS sqlite_stat1;"
"DROP TABLE IF EXISTS sqlite_stat3;"
"DROP TABLE IF EXISTS sqlite_stat4;");
}
if( runAnalyze ){
fossil_print("Analyzing the database... "); fflush(stdout);
db_multi_exec("ANALYZE;");
fossil_print("done\n");
}
if( runVacuum ){
fossil_print("Vacuuming the database... "); fflush(stdout);
db_multi_exec("VACUUM");
fossil_print("done\n");
}
if( activateWal ){
db_multi_exec("PRAGMA journal_mode=WAL;");
}
}
if( showStats ){
static const 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:" },
|
| ︙ | ︙ | |||
683 684 685 686 687 688 689 |
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"
|
| ︙ | ︙ | |||
718 719 720 721 722 723 724 |
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];
|
| ︙ | ︙ | |||
789 790 791 792 793 794 795 |
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;
| < | 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);
}
|
| ︙ | ︙ | |||
857 858 859 860 861 862 863 |
continue;
}
zUtf8Name = fossil_filename_to_utf8(pEntry->d_name);
zSubpath = mprintf("%s/%s", zPath, zUtf8Name);
fossil_filename_free(zUtf8Name);
if( file_isdir(zSubpath)==1 ){
recon_read_dir(zSubpath);
| | | | | | | | | | | < | | > > | 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 |
continue;
}
zUtf8Name = fossil_filename_to_utf8(pEntry->d_name);
zSubpath = mprintf("%s/%s", zPath, zUtf8Name);
fossil_filename_free(zUtf8Name);
if( file_isdir(zSubpath)==1 ){
recon_read_dir(zSubpath);
}else{
blob_init(&path, 0, 0);
blob_appendf(&path, "%s", zSubpath);
if( blob_read_from_file(&aContent, blob_str(&path))==-1 ){
fossil_fatal("some unknown error occurred while reading \"%s\"",
blob_str(&path));
}
content_put(&aContent);
blob_reset(&path);
blob_reset(&aContent);
fossil_print("\r%d", ++nFileRead);
fflush(stdout);
}
free(zSubpath);
}
closedir(d);
}else {
fossil_fatal("encountered error %d while trying to open \"%s\".",
errno, g.argv[3]);
}
fossil_filename_free(zUnicodePath);
|
| ︙ | ︙ | |||
918 919 920 921 922 923 924 | 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(); | | | | 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 |
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 52 53 54 55 |
** 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);
#ifndef SQLITE_RECURSIVE
# define SQLITE_RECURSIVE 33
#endif
/*
** 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);
|
| ︙ | ︙ | |||
64 65 66 67 68 69 70 |
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));
}
| | | | | | 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 |
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();
}
/*
|
| ︙ | ︙ | |||
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 |
"mlink",
"plink",
"event",
"tag",
"tagxref",
};
int i;
for(i=0; i<sizeof(azAllowed)/sizeof(azAllowed[0]); i++){
if( fossil_stricmp(zArg1, azAllowed[i])==0 ) break;
}
if( i>=sizeof(azAllowed)/sizeof(azAllowed[0]) ){
*(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;
}
/*
** Activate the query authorizer
*/
static void report_restrict_sql(char **pzErr){
| > > > > > > > > < | 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 |
"mlink",
"plink",
"event",
"tag",
"tagxref",
};
int i;
if( fossil_strncmp(zArg1, "fx_", 3)==0 ){
break;
}
for(i=0; i<sizeof(azAllowed)/sizeof(azAllowed[0]); i++){
if( fossil_stricmp(zArg1, azAllowed[i])==0 ) break;
}
if( i>=sizeof(azAllowed)/sizeof(azAllowed[0]) ){
*(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;
}
case SQLITE_RECURSIVE: {
*(char**)pError = mprintf("recursive queries are not allowed");
rc = SQLITE_DENY;
break;
}
default: {
*(char**)pError = mprintf("only SELECT statements are allowed");
rc = SQLITE_DENY;
break;
}
}
return rc;
}
/*
** Activate the query authorizer
*/
static void report_restrict_sql(char **pzErr){
sqlite3_set_authorizer(g.db, report_query_authorizer, (void*)pzErr);
}
static void report_unrestrict_sql(void){
sqlite3_set_authorizer(g.db, 0, 0);
}
|
| ︙ | ︙ | |||
249 250 251 252 253 254 255 |
** was found. We don't actually check what's after that.
*/
return mprintf("Semi-colon detected! "
"Only a single SQL statement is allowed");
}
}
}
| | | | 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 |
** 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_v2(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 ){
|
| ︙ | ︙ | |||
370 371 372 373 374 375 376 |
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 ){
| | | 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 |
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)
){
|
| ︙ | ︙ | |||
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 */ | | | | | 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 |
/*
** 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 */
const char **azArg, /* Text of data in all columns */
const char **azName /* Names of the columns */
){
struct GenerateHTML *pState = (struct GenerateHTML*)pUser;
int i;
const char *zTid; /* Ticket UUID. (value of column named '#') */
const 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++){
| | | 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 |
}
/* The first time this routine is called, output a table header
*/
@ <thead><tr>
zTid = 0;
for(i=0; i<nArg; i++){
const 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++){
| | | 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 |
/* 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++){
const 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 */ | | | | 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 |
/*
** 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 */
const char **azArg, /* Text of data in all columns */
const 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;
| | > | | 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 |
}
/*
** Generate HTML that describes a color key.
*/
void output_color_key(const char *zClrKey, int horiz, char *zTabArgs){
int i, j, k;
const char *zSafeKey;
char *zToFree;
while( fossil_isspace(*zClrKey) ) zClrKey++;
if( zClrKey[0]==0 ) return;
@ <table %s(zTabArgs)>
if( horiz ){
@ <tr>
}
zSafeKey = zToFree = 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",
|
| ︙ | ︙ | |||
860 861 862 863 864 865 866 | @ </table> } /* ** Execute a single read-only SQL statement. Invoke xCallback() on each ** row. */ | | > | | | | 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 |
@ </table>
}
/*
** Execute a single read-only SQL statement. Invoke xCallback() on each
** row.
*/
static int db_exec_readonly(
sqlite3 *db, /* The database on which the SQL executes */
const char *zSql, /* The SQL to be executed */
int (*xCallback)(void*,int,const char**, const char**),
/* 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 */
const char **azCols = 0; /* Names of result columns */
int nCol; /* Number of columns of output */
const 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;
|
| ︙ | ︙ | |||
899 900 901 902 903 904 905 |
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++){
| | | | | 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 |
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] = sqlite3_column_name(pStmt, i);
}
}
for(i=0; i<nCol; i++){
azVals[i] = (const char *)sqlite3_column_text(pStmt, i);
}
if( xCallback(pArg, nCol, azVals, azCols) ){
break;
}
}
rc = sqlite3_finalize(pStmt);
fossil_free((void *)azVals);
return rc;
}
/*
** Output Javascript code that will enables sorting of the table with
** the id zTableId by clicking.
**
|
| ︙ | ︙ | |||
1052 1053 1054 1055 1056 1057 1058 |
}
count = 0;
if( !tabs ){
struct GenerateHTML sState;
db_multi_exec("PRAGMA empty_result_callbacks=ON");
| | | | | | | 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 |
}
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);
db_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);
db_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
|
| ︙ | ︙ | |||
1164 1165 1166 1167 1168 1169 1170 |
}
for(j=i; fossil_isspace(z[j]); j++){}
if( j>i ){
fossil_print("%*s", j-i, "");
}
z += j;
}
| | | | | 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 |
}
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 */
const char **azArg, /* Text of data in all columns */
const 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]);
|
| ︙ | ︙ | |||
1199 1200 1201 1202 1203 1204 1205 | } /* ** 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. */ | | | 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 |
}
/*
** 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;
|
| ︙ | ︙ | |||
1238 1239 1240 1241 1242 1243 1244 |
if( zFilter ){
zSql = mprintf("SELECT * FROM (%s) WHERE %s",zSql,zFilter);
}
count = 0;
tktEncode = enc;
zSep = zSepIn;
report_restrict_sql(&zErr1);
| | | 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 |
if( zFilter ){
zSql = mprintf("SELECT * FROM (%s) WHERE %s",zSql,zFilter);
}
count = 0;
tktEncode = enc;
zSep = zSepIn;
report_restrict_sql(&zErr1);
db_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);
|
| ︙ | ︙ | |||
194 195 196 197 198 199 200 201 202 203 204 205 |
free(zDate);
nLine++;
}
db_finalize(&q);
@ </channel>
@ </rss>
if( zFreeProjectName != 0 ){
free( zFreeProjectName );
}
}
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 |
free(zDate);
nLine++;
}
db_finalize(&q);
@ </channel>
@ </rss>
if( zFreeProjectName != 0 ){
free( zFreeProjectName );
}
}
/*
** COMMAND: rss
**
** The CLI variant of the /timeline.rss page, this produces an RSS
** feed of the timeline to stdout. Options:
**
** -type|y FLAG
** may be: all (default), ci (show checkins only), t (show tickets only),
** w (show wiki only). LIMIT is the number of items to show.
**
** -tkt UUID
** Filters for only those events for the specified ticket.
**
** -tag TAG
** filters for a tag
**
** -wiki NAME
** Filters on a specific wiki page.
**
** Only one of -tkt, -tag, or -wiki may be used.
**
** -name FILENAME
** filters for a specific file. This may be combined with one of the other
** filters (useful for looking at a specific branch).
**
** -url STRING
** Sets the RSS feed's root URL to the given string. The default is
** "URL-PLACEHOLDER" (without quotes).
*/
void cmd_timeline_rss(void){
Stmt q;
int nLine=0;
char *zPubDate, *zProjectName, *zProjectDescr, *zFreeProjectName=0;
Blob bSQL;
const char *zType = find_option("type","y",1); /* Type of events. All if NULL */
const char *zTicketUuid = find_option("tkt",NULL,1);
const char *zTag = find_option("tag",NULL,1);
const char *zFilename = find_option("name",NULL,1);
const char *zWiki = find_option("wiki",NULL,1);
const char *zLimit = find_option("limit", "n",1);
const char *zBaseURL = find_option("url", NULL, 1);
int nLimit = atoi( (zLimit && *zLimit) ? zLimit : "20" );
int nTagId;
const char zSQL1[] =
@ SELECT
@ blob.rid,
@ uuid,
@ event.mtime,
@ coalesce(ecomment,comment),
@ coalesce(euser,user),
@ (SELECT count(*) FROM plink WHERE pid=blob.rid AND isprim),
@ (SELECT count(*) FROM plink WHERE cid=blob.rid)
@ FROM event, blob
@ WHERE blob.rid=event.objid
;
if(!zType || !*zType){
zType = "all";
}
if(!zBaseURL || !*zBaseURL){
zBaseURL = "URL-PLACEHOLDER";
}
db_find_and_open_repository(0, 0);
blob_zero(&bSQL);
blob_append( &bSQL, zSQL1, -1 );
if( zType[0]!='a' ){
blob_appendf(&bSQL, " AND event.type=%Q", zType);
}
if( zTicketUuid ){
nTagId = db_int(0, "SELECT tagid FROM tag WHERE tagname GLOB 'tkt-%q*'",
zTicketUuid);
if ( nTagId==0 ){
nTagId = -1;
}
}else if( zTag ){
nTagId = db_int(0, "SELECT tagid FROM tag WHERE tagname GLOB 'sym-%q*'",
zTag);
if ( nTagId==0 ){
nTagId = -1;
}
}else if( zWiki ){
nTagId = db_int(0, "SELECT tagid FROM tag WHERE tagname GLOB 'wiki-%q*'",
zWiki);
if ( nTagId==0 ){
nTagId = -1;
}
}else{
nTagId = 0;
}
if( nTagId==-1 ){
blob_appendf(&bSQL, " AND 0");
}else if( nTagId!=0 ){
blob_appendf(&bSQL, " AND (EXISTS(SELECT 1 FROM tagxref"
" WHERE tagid=%d AND tagtype>0 AND rid=blob.rid))", nTagId);
}
if( zFilename ){
blob_appendf(&bSQL,
" AND (SELECT mlink.fnid FROM mlink WHERE event.objid=mlink.mid) IN (SELECT fnid FROM filename WHERE name=%Q %s)",
zFilename, filename_collation()
);
}
blob_append( &bSQL, " ORDER BY event.mtime DESC", -1 );
zProjectName = db_get("project-name", 0);
if( zProjectName==0 ){
zFreeProjectName = zProjectName = mprintf("Fossil source repository for: %s",
zBaseURL);
}
zProjectDescr = db_get("project-description", 0);
if( zProjectDescr==0 ){
zProjectDescr = zProjectName;
}
zPubDate = cgi_rfc822_datestamp(time(NULL));
fossil_print("<?xml version=\"1.0\"?>");
fossil_print("<rss xmlns:dc=\"http://purl.org/dc/elements/1.1/\" version=\"2.0\">");
fossil_print("<channel>\n");
fossil_print("<title>%h</title>\n", zProjectName);
fossil_print("<link>%s</link>\n", zBaseURL);
fossil_print("<description>%h</description>\n", zProjectDescr);
fossil_print("<pubDate>%s</pubDate>\n", zPubDate);
fossil_print("<generator>Fossil version %s %s</generator>\n",
MANIFEST_VERSION, MANIFEST_DATE);
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);
time_t ts;
ts = (time_t)((db_column_double(&q,2) - 2440587.5)*86400.0);
zDate = cgi_rfc822_datestamp(ts);
if( nParent>1 && nChild>1 ){
zPrefix = "*MERGE/FORK* ";
}else if( nParent>1 ){
zPrefix = "*MERGE* ";
}else if( nChild>1 ){
zPrefix = "*FORK* ";
}
fossil_print("<item>");
fossil_print("<title>%s%h</title>\n", zPrefix, zCom);
fossil_print("<link>%s/info/%s</link>\n", zBaseURL, zId);
fossil_print("<description>%s%h</description>\n", zPrefix, zCom);
fossil_print("<pubDate>%s</pubDate>\n", zDate);
fossil_print("<dc:creator>%h</dc:creator>\n", zAuthor);
fossil_print("<guid>%s/info/%s</guid>\n", g.zBaseURL, zId);
fossil_print("</item>\n");
free(zDate);
nLine++;
}
db_finalize(&q);
fossil_print("</channel>\n");
fossil_print("</rss>\n");
if( zFreeProjectName != 0 ){
free( zFreeProjectName );
}
}
|
Changes to src/schema.c.
| ︙ | ︙ | |||
433 434 435 436 437 438 439 | ** Predefined tagid values */ #if INTERFACE # define TAG_BGCOLOR 1 /* Set the background color for display */ # define TAG_COMMENT 2 /* The check-in comment */ # define TAG_USER 3 /* User who made a checking */ # define TAG_DATE 4 /* The date of a check-in */ | | | | 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 | ** Predefined tagid values */ #if INTERFACE # define TAG_BGCOLOR 1 /* Set the background color for display */ # define TAG_COMMENT 2 /* The check-in comment */ # define TAG_USER 3 /* User who made a checking */ # define TAG_DATE 4 /* The date of a check-in */ # define TAG_HIDDEN 5 /* Do not display in timeline */ # define TAG_PRIVATE 6 /* Do not sync */ # define TAG_CLUSTER 7 /* A cluster */ # define TAG_BRANCH 8 /* Value is name of the current branch */ # define TAG_CLOSED 9 /* Do not display this check-in as a leaf */ # define TAG_PARENT 10 /* Change to parentage on a checkin */ #endif #if EXPORT_INTERFACE # define MAX_INT_TAG 16 /* The largest pre-assigned tag id */ |
| ︙ | ︙ |
Changes to src/search.c.
| ︙ | ︙ | |||
104 105 106 107 108 109 110 111 112 113 114 115 116 117 |
int iPrev = 999;
int score = 10;
int iBonus = 0;
int i, j;
unsigned char seen[8];
memset(seen, 0, sizeof(seen));
for(i=0; zDoc[i]; i++){
char c = zDoc[i];
if( isBoundary[c&0xff] ) continue;
for(j=0; j<p->nTerm; j++){
int n = p->a[j].n;
if( sqlite3_strnicmp(p->a[j].z, &zDoc[i], n)==0 ){
score += 1;
| > | 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
int iPrev = 999;
int score = 10;
int iBonus = 0;
int i, j;
unsigned char seen[8];
memset(seen, 0, sizeof(seen));
if( zDoc==0 ) return score;
for(i=0; zDoc[i]; i++){
char c = zDoc[i];
if( isBoundary[c&0xff] ) continue;
for(j=0; j<p->nTerm; j++){
int n = p->a[j].n;
if( sqlite3_strnicmp(p->a[j].z, &zDoc[i], n)==0 ){
score += 1;
|
| ︙ | ︙ | |||
132 133 134 135 136 137 138 |
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.
*/
|
| ︙ | ︙ | |||
164 165 166 167 168 169 170 |
search_score_sqlfunc, 0, 0);
}
/*
** Testing the search function.
**
** COMMAND: search*
| | | > > | > > > > > > > > > > | | > | | 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 |
search_score_sqlfunc, 0, 0);
}
/*
** Testing the search function.
**
** COMMAND: search*
** %fossil search [-all|-a] [-limit|-n #] [-width|-W #] pattern...
**
** Search for timeline entries matching all words
** provided on the command line. Whole-word matches
** scope more highly than partial matches.
**
** Outputs, by default, some top-N fraction of the
** results. The -all option can be used to output
** all matches, regardless of their search score.
** The -limit option can be used to limit the number
** of entries returned. The -width option can be
** used to set the output width used when printing
** matches.
*/
void search_cmd(void){
Search *p;
Blob pattern;
int i;
Blob sql = empty_blob;
Stmt q;
int iBest;
char fAll = NULL != find_option("all", "a", 0); /* If set, do not lop
off the end of the
results. */
char const * zLimit = find_option("limit","n",1);
const char *zWidth = find_option("width","W",1);
int nLimit = zLimit ? atoi(zLimit) : -1000; /* Max number of matching
lines/entries to list */
int width;
if( zWidth ){
width = atoi(zWidth);
if( (width!=0) && (width<=20) ){
fossil_fatal("--width|-W value must be >20 or 0");
}
}else{
width = 79;
}
db_must_be_within_tree();
if( g.argc<2 ) return;
blob_init(&pattern, g.argv[2], -1);
for(i=3; i<g.argc; i++){
blob_appendf(&pattern, " %s", g.argv[i]);
}
p = search_init(blob_str(&pattern));
blob_reset(&pattern);
search_sql_setup(p);
db_multi_exec(
"CREATE TEMP TABLE srch(rid,uuid,date,comment,x);"
"CREATE INDEX srch_idx1 ON srch(x);"
"INSERT INTO srch(rid,uuid,date,comment,x)"
" SELECT blob.rid, uuid, datetime(event.mtime%s),"
" coalesce(ecomment,comment),"
" score(coalesce(ecomment,comment)) AS y"
" FROM event, blob"
" WHERE blob.rid=event.objid AND y>0;",
timeline_utc()
);
iBest = db_int(0, "SELECT max(x) FROM srch");
blob_append(&sql,
"SELECT rid, uuid, date, comment, 0, 0 FROM srch "
"WHERE 1 ", -1);
if(!fAll){
blob_appendf(&sql,"AND x>%d ", iBest/3);
}
blob_append(&sql, "ORDER BY x DESC, date DESC ", -1);
db_prepare(&q, blob_str(&sql));
blob_reset(&sql);
print_timeline(&q, nLimit, width, 0);
db_finalize(&q);
}
|
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 |
@ <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 ZIP archive or tarball</td></tr>
@ </table>
@ </li>
@
@ <li><p>
@ Every user, logged in or not, inherits the privileges of
@ <span class="usertype">nobody</span>.
@ </p></li>
|
| ︙ | ︙ | |||
598 599 600 601 602 603 604 |
}
@ </table>
@ </div></form>
@ </div>
@ <h2>Privileges And Capabilities:</h2>
@ <ul>
if( higherUser ){
| | | 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 |
}
@ </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
|
| ︙ | ︙ | |||
810 811 812 813 814 815 816 |
const char *zVal = db_get(zVar, zDflt);
const char *zQ = P(zQParm);
if( zQ && fossil_strcmp(zQ,zVal)!=0 ){
login_verify_csrf_secret();
db_set(zVar, zQ, 0);
zVal = zQ;
}
| | | 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 |
const char *zVal = db_get(zVar, zDflt);
const char *zQ = P(zQParm);
if( zQ && fossil_strcmp(zQ,zVal)!=0 ){
login_verify_csrf_secret();
db_set(zVar, zQ, 0);
zVal = zQ;
}
@ <input type="text" id="%s(zQParm)" name="%s(zQParm)" value="%h(zVal)" size="%d(width)"
if( disabled ){
@ disabled="disabled"
}
@ /> <b>%s(zLabel)</b>
}
/*
|
| ︙ | ︙ | |||
857 858 859 860 861 862 863 | */ 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 */ | | | | 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 |
*/
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 *const *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> <b>%h(zLabel)</b>
}
/*
** WEBPAGE: setup_access
*/
void setup_access(void){
|
| ︙ | ︙ | |||
973 974 975 976 977 978 979 |
"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
| | | | 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 |
"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);
|
| ︙ | ︙ | |||
1149 1150 1151 1152 1153 1154 1155 |
/*
** WEBPAGE: setup_timeline
*/
void setup_timeline(void){
double tmDiff;
char zTmDiff[20];
| | | 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 |
/*
** WEBPAGE: setup_timeline
*/
void setup_timeline(void){
double tmDiff;
char zTmDiff[20];
static const char *const 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 ){
|
| ︙ | ︙ | |||
1175 1176 1177 1178 1179 1180 1181 |
@ <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,
| | > < | 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 |
@ <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. (Note: Use CSS to change
@ display formatting features such as fonts and line-wrapping behavior.)</p>
@ <hr />
onoff_attribute("Use Universal Coordinated Time (UTC)",
"timeline-utc", "utc", 1, 0);
@ <p>Show times as UTC (also sometimes called Greenwich Mean Time (GMT) or
@ Zulu) instead of in local time. On this server, local time is currently
tmDiff = db_double(0.0, "SELECT julianday('now')");
tmDiff = db_double(0.0,
"SELECT (julianday(%.17g,'localtime')-julianday(%.17g))*24.0",
tmDiff, tmDiff);
sqlite3_snprintf(sizeof(zTmDiff), zTmDiff, "%.1f", tmDiff);
if( strcmp(zTmDiff, "0.0")==0 ){
@ the same as UTC and so this setting will make no difference in
|
| ︙ | ︙ | |||
1209 1210 1211 1212 1213 1214 1215 |
@ in a separate box (using CSS class "timelineDate") whenever the date changes.
@ With the "YYYY-MM-DD HH:MM" and "YYMMDD ..." formats, the complete date
@ and time is shown on every timeline entry (using the CSS class "timelineTime").</p>
@ <hr />
onoff_attribute("Show version differences by default",
"show-version-diffs", "vdiff", 0, 0);
| | | 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 |
@ in a separate box (using CSS class "timelineDate") whenever the date changes.
@ With the "YYYY-MM-DD HH:MM" and "YYMMDD ..." formats, the complete date
@ and time is shown on every timeline entry (using the CSS class "timelineTime").</p>
@ <hr />
onoff_attribute("Show version differences by default",
"show-version-diffs", "vdiff", 0, 0);
@ <p>The version-information pages linked from the timeline can either
@ show complete diffs of all file changes, or can just list the names of
@ the files that have changed. Users can get to either page by
@ clicking. This setting selects the default.</p>
@ <hr />
entry_attribute("Max timeline comment length", 6,
"timeline-max-comment", "tmc", "0", 0);
|
| ︙ | ︙ | |||
1262 1263 1264 1265 1266 1267 1268 1269 1270 |
if( pSet->versionable ){
@ (v)<br />
} else {
@ <br />
}
}
}
@ </td><td style="width:50px;"></td><td valign="top">
for(pSet=ctrlSettings; pSet->name!=0; pSet++){
| > | > > > > > > > > > > | < < | 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 |
if( pSet->versionable ){
@ (v)<br />
} else {
@ <br />
}
}
}
@ <br /><input type="submit" name="submit" value="Apply Changes" />
@ </td><td style="width:50px;"></td><td valign="top">
for(pSet=ctrlSettings; pSet->name!=0; pSet++){
if( pSet->width!=0 && !pSet->versionable && !pSet->forceTextArea ){
entry_attribute(pSet->name, /*pSet->width*/ 25, pSet->name,
pSet->var!=0 ? pSet->var : pSet->name,
(char*)pSet->def, 0);
@ <br />
}
}
for(pSet=ctrlSettings; pSet->name!=0; pSet++){
if( pSet->width!=0 && !pSet->versionable && pSet->forceTextArea ){
@<b>%s(pSet->name)</b><br />
textarea_attribute("", /*rows*/ 3, /*cols*/ 50, pSet->name,
pSet->var!=0 ? pSet->var : pSet->name,
(char*)pSet->def, 0);
@ <br />
}
}
@ </td><td style="width:50px;"></td><td valign="top">
for(pSet=ctrlSettings; pSet->name!=0; pSet++){
if( pSet->width!=0 && pSet->versionable ){
int hasVersionableValue = db_get_do_versionable(pSet->name, NULL)!=0;
@<b>%s(pSet->name)</b> (v)<br />
textarea_attribute("", /*rows*/ 3, /*cols*/ 20, pSet->name,
pSet->var!=0 ? pSet->var : pSet->name,
(char*)pSet->def, hasVersionableValue);
@<br />
}
}
@ </td></tr></table>
@ </div></form>
@ <p>Settings marked with (v) are 'versionable' and will be overridden
@ by the contents of files named <tt>.fossil-settings/PROPERTY</tt>.
@ If such a file is present, the corresponding field above is not
@ editable.</p><hr /><p>
@ These settings work in the same way, as the <kbd>set</kbd>
@ commandline:<br />
|
| ︙ | ︙ | |||
1470 1471 1472 1473 1474 1475 1476 | @ <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 | | | 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 | @ <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 screens. @ <blockquote><pre> @ %h(zDefaultHeader) @ </pre></blockquote> style_footer(); db_end_transaction(0); } |
| ︙ | ︙ | |||
1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 |
db_end_transaction(0);
}
/*
** WEBPAGE: setup_logo
*/
void setup_logo(void){
const char *zLogoMime = db_get("logo-mimetype","image/gif");
const char *aLogoImg = P("logoim");
int szLogoImg = atoi(PD("logoim:bytes","0"));
const char *zBgMime = db_get("background-mimetype","image/gif");
const char *aBgImg = P("bgim");
int szBgImg = atoi(PD("bgim:bytes","0"));
if( szLogoImg>0 ){
zLogoMime = PD("logoim:mimetype","image/gif");
}
if( szBgImg>0 ){
| > > | 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 |
db_end_transaction(0);
}
/*
** WEBPAGE: setup_logo
*/
void setup_logo(void){
const char *zLogoMtime = db_get_mtime("logo-image", 0, 0);
const char *zLogoMime = db_get("logo-mimetype","image/gif");
const char *aLogoImg = P("logoim");
int szLogoImg = atoi(PD("logoim:bytes","0"));
const char *zBgMtime = db_get_mtime("background-image", 0, 0);
const char *zBgMime = db_get("background-mimetype","image/gif");
const char *aBgImg = P("bgim");
int szBgImg = atoi(PD("bgim:bytes","0"));
if( szLogoImg>0 ){
zLogoMime = PD("logoim:mimetype","image/gif");
}
if( szBgImg>0 ){
|
| ︙ | ︙ | |||
1666 1667 1668 1669 1670 1671 1672 |
);
db_end_transaction(0);
cgi_redirect("setup_logo");
}
style_header("Edit Project Logo And Background");
@ <p>The current project logo has a MIME-Type of <b>%h(zLogoMime)</b>
@ and looks like this:</p>
| | | 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 |
);
db_end_transaction(0);
cgi_redirect("setup_logo");
}
style_header("Edit Project Logo And Background");
@ <p>The current project logo has a MIME-Type of <b>%h(zLogoMime)</b>
@ and looks like this:</p>
@ <blockquote><p><img src="%s(g.zTop)/logo/%z(zLogoMtime)" alt="logo" border="1" />
@ </p></blockquote>
@
@ <form action="%s(g.zTop)/setup_logo" method="post"
@ enctype="multipart/form-data"><div>
@ <p>The logo is accessible to all users at this URL:
@ <a href="%s(g.zBaseURL)/logo">%s(g.zBaseURL)/logo</a>.
@ The logo may or may not appear on each
|
| ︙ | ︙ | |||
1688 1689 1690 1691 1692 1693 1694 | @ <input type="submit" name="setlogo" value="Change Logo" /> @ <input type="submit" name="clrlogo" value="Revert To Default" /></p> @ </div></form> @ <hr /> @ @ <p>The current background image has a MIME-Type of <b>%h(zBgMime)</b> @ and looks like this:</p> | | | 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 | @ <input type="submit" name="setlogo" value="Change Logo" /> @ <input type="submit" name="clrlogo" value="Revert To Default" /></p> @ </div></form> @ <hr /> @ @ <p>The current background image has a MIME-Type of <b>%h(zBgMime)</b> @ and looks like this:</p> @ <blockquote><p><img src="%s(g.zTop)/background/%z(zBgMtime)" alt="background" border=1 /> @ </p></blockquote> @ @ <form action="%s(g.zTop)/setup_logo" method="post" @ enctype="multipart/form-data"><div> @ <p>The background image is accessible to all users at this URL: @ <a href="%s(g.zBaseURL)/background">%s(g.zBaseURL)/background</a>. @ The background image may or may not appear on each |
| ︙ | ︙ |
Changes to src/sha1.c.
| ︙ | ︙ | |||
159 160 161 162 163 164 165 |
const unsigned char *data,
unsigned int len
){
unsigned int i, j;
j = context->count[0];
if ((context->count[0] += len << 3) < j)
| | | | | | | | | | | | | | | 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 |
const unsigned char *data,
unsigned int len
){
unsigned int i, j;
j = context->count[0];
if ((context->count[0] += len << 3) < j)
context->count[1] += (len>>29)+1;
j = (j >> 3) & 63;
if ((j + len) > 63) {
(void)memcpy(&context->buffer[j], data, (i = 64-j));
SHA1Transform(context->state, context->buffer);
for ( ; i + 63 < len; i += 64)
SHA1Transform(context->state, &data[i]);
j = 0;
} else {
i = 0;
}
(void)memcpy(&context->buffer[j], &data[i], len - i);
}
/*
* Add padding and return the message digest.
*/
static void SHA1Final(SHA1Context *context, unsigned char digest[20]){
unsigned int i;
unsigned char finalcount[8];
for (i = 0; i < 8; i++) {
finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)]
>> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */
}
SHA1Update(context, (const unsigned char *)"\200", 1);
while ((context->count[0] & 504) != 448)
SHA1Update(context, (const unsigned char *)"\0", 1);
SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */
if (digest) {
for (i = 0; i < 20; i++)
digest[i] = (unsigned char)
((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
}
}
/*
** Convert a digest into base-16. digest should be declared as
** "unsigned char digest[20]" in the calling function. The SHA1
|
| ︙ | ︙ |
Changes to src/shell.c.
| ︙ | ︙ | |||
41 42 43 44 45 46 47 | # if !defined(__RTP__) && !defined(_WRS_KERNEL) # include <pwd.h> # endif # include <unistd.h> # include <sys/types.h> #endif | < < < | > > > > > > | | 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 | # if !defined(__RTP__) && !defined(_WRS_KERNEL) # include <pwd.h> # endif # include <unistd.h> # include <sys/types.h> #endif #if defined(HAVE_READLINE) && HAVE_READLINE!=0 # include <readline/readline.h> # include <readline/history.h> #else # undef HAVE_READLINE #endif #if defined(HAVE_EDITLINE) && !defined(HAVE_READLINE) # define HAVE_READLINE 1 # include <editline/readline.h> #endif #if !defined(HAVE_READLINE) # define add_history(X) # define read_history(X) # define write_history(X) # define stifle_history(X) #endif #if defined(_WIN32) || defined(WIN32) |
| ︙ | ︙ | |||
82 83 84 85 86 87 88 | /* Windows CE (arm-wince-mingw32ce-gcc) does not provide isatty() * thus we always assume that we have a console. That can be * overridden with the -batch command line option. */ #define isatty(x) 1 #endif | < < < > > > > > > > > > > > > > > > > > > > | > > > | > > | 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 |
/* Windows CE (arm-wince-mingw32ce-gcc) does not provide isatty()
* thus we always assume that we have a console. That can be
* overridden with the -batch command line option.
*/
#define isatty(x) 1
#endif
/* ctype macros that work with signed characters */
#define IsSpace(X) isspace((unsigned char)X)
#define IsDigit(X) isdigit((unsigned char)X)
#define ToLower(X) (char)tolower((unsigned char)X)
/* True if the timer is enabled */
static int enableTimer = 0;
/* Return the current wall-clock time */
static sqlite3_int64 timeOfDay(void){
static sqlite3_vfs *clockVfs = 0;
sqlite3_int64 t;
if( clockVfs==0 ) clockVfs = sqlite3_vfs_find(0);
if( clockVfs->iVersion>=1 && clockVfs->xCurrentTimeInt64!=0 ){
clockVfs->xCurrentTimeInt64(clockVfs, &t);
}else{
double r;
clockVfs->xCurrentTime(clockVfs, &r);
t = (sqlite3_int64)(r*86400000.0);
}
return t;
}
#if !defined(_WIN32) && !defined(WIN32) && !defined(_WRS_KERNEL) \
&& !defined(__minux)
#include <sys/time.h>
#include <sys/resource.h>
/* Saved resource information for the beginning of an operation */
static struct rusage sBegin; /* CPU time at start */
static sqlite3_int64 iBegin; /* Wall-clock time at start */
/*
** Begin timing an operation
*/
static void beginTimer(void){
if( enableTimer ){
getrusage(RUSAGE_SELF, &sBegin);
iBegin = timeOfDay();
}
}
/* Return the difference of two time_structs in seconds */
static double timeDiff(struct timeval *pStart, struct timeval *pEnd){
return (pEnd->tv_usec - pStart->tv_usec)*0.000001 +
(double)(pEnd->tv_sec - pStart->tv_sec);
}
/*
** Print the timing results.
*/
static void endTimer(void){
if( enableTimer ){
struct rusage sEnd;
sqlite3_int64 iEnd = timeOfDay();
getrusage(RUSAGE_SELF, &sEnd);
printf("Run Time: real %.3f user %f sys %f\n",
(iEnd - iBegin)*0.001,
timeDiff(&sBegin.ru_utime, &sEnd.ru_utime),
timeDiff(&sBegin.ru_stime, &sEnd.ru_stime));
}
}
#define BEGIN_TIMER beginTimer()
#define END_TIMER endTimer()
#define HAS_TIMER 1
#elif (defined(_WIN32) || defined(WIN32))
#include <windows.h>
/* Saved resource information for the beginning of an operation */
static HANDLE hProcess;
static FILETIME ftKernelBegin;
static FILETIME ftUserBegin;
static sqlite3_int64 ftWallBegin;
typedef BOOL (WINAPI *GETPROCTIMES)(HANDLE, LPFILETIME, LPFILETIME, LPFILETIME, LPFILETIME);
static GETPROCTIMES getProcessTimesAddr = NULL;
/*
** Check to see if we have timer support. Return 1 if necessary
** support found (or found previously).
*/
|
| ︙ | ︙ | |||
175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 |
/*
** Begin timing an operation
*/
static void beginTimer(void){
if( enableTimer && getProcessTimesAddr ){
FILETIME ftCreation, ftExit;
getProcessTimesAddr(hProcess, &ftCreation, &ftExit, &ftKernelBegin, &ftUserBegin);
}
}
/* Return the difference of two FILETIME structs in seconds */
static double timeDiff(FILETIME *pStart, FILETIME *pEnd){
sqlite_int64 i64Start = *((sqlite_int64 *) pStart);
sqlite_int64 i64End = *((sqlite_int64 *) pEnd);
return (double) ((i64End - i64Start) / 10000000.0);
}
/*
** Print the timing results.
*/
static void endTimer(void){
if( enableTimer && getProcessTimesAddr){
FILETIME ftCreation, ftExit, ftKernelEnd, ftUserEnd;
getProcessTimesAddr(hProcess, &ftCreation, &ftExit, &ftKernelEnd, &ftUserEnd);
| > > | > | 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 |
/*
** Begin timing an operation
*/
static void beginTimer(void){
if( enableTimer && getProcessTimesAddr ){
FILETIME ftCreation, ftExit;
getProcessTimesAddr(hProcess, &ftCreation, &ftExit, &ftKernelBegin, &ftUserBegin);
ftWallBegin = timeOfDay();
}
}
/* Return the difference of two FILETIME structs in seconds */
static double timeDiff(FILETIME *pStart, FILETIME *pEnd){
sqlite_int64 i64Start = *((sqlite_int64 *) pStart);
sqlite_int64 i64End = *((sqlite_int64 *) pEnd);
return (double) ((i64End - i64Start) / 10000000.0);
}
/*
** Print the timing results.
*/
static void endTimer(void){
if( enableTimer && getProcessTimesAddr){
FILETIME ftCreation, ftExit, ftKernelEnd, ftUserEnd;
sqlite3_int64 ftWallEnd = timeOfDay();
getProcessTimesAddr(hProcess, &ftCreation, &ftExit, &ftKernelEnd, &ftUserEnd);
printf("Run Time: real %.3f user %f sys %f\n",
(ftWallEnd - ftWallBegin)*0.001,
timeDiff(&ftUserBegin, &ftUserEnd),
timeDiff(&ftKernelBegin, &ftKernelEnd));
}
}
#define BEGIN_TIMER beginTimer()
#define END_TIMER endTimer()
|
| ︙ | ︙ | |||
385 386 387 388 389 390 391 |
static char *one_input_line(FILE *in, char *zPrior, int isContinuation){
char *zPrompt;
char *zResult;
if( in!=0 ){
zResult = local_getline(zPrior, in);
}else{
zPrompt = isContinuation ? continuePrompt : mainPrompt;
| | | 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 |
static char *one_input_line(FILE *in, char *zPrior, int isContinuation){
char *zPrompt;
char *zResult;
if( in!=0 ){
zResult = local_getline(zPrior, in);
}else{
zPrompt = isContinuation ? continuePrompt : mainPrompt;
#if defined(HAVE_READLINE)
free(zPrior);
zResult = readline(zPrompt);
if( zResult && *zResult ) add_history(zResult);
#else
printf("%s", zPrompt);
fflush(stdout);
zResult = local_getline(zPrior, stdin);
|
| ︙ | ︙ | |||
432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 |
char nullvalue[20]; /* The text to print when a NULL comes back from
** the database */
struct previous_mode_data explainPrev;
/* Holds the mode information just before
** .explain ON */
char outfile[FILENAME_MAX]; /* Filename for *out */
const char *zDbFilename; /* name of the database file */
const char *zVfs; /* Name of VFS to use */
sqlite3_stmt *pStmt; /* Current statement if any. */
FILE *pLog; /* Write log output here */
};
/*
** These are the allowed modes.
*/
#define MODE_Line 0 /* One column per line. Blank line between records */
#define MODE_Column 1 /* One record per line in neat columns */
| > > > > | 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 |
char nullvalue[20]; /* The text to print when a NULL comes back from
** the database */
struct previous_mode_data explainPrev;
/* Holds the mode information just before
** .explain ON */
char outfile[FILENAME_MAX]; /* Filename for *out */
const char *zDbFilename; /* name of the database file */
char *zFreeOnClose; /* Filename to free when closing */
const char *zVfs; /* Name of VFS to use */
sqlite3_stmt *pStmt; /* Current statement if any. */
FILE *pLog; /* Write log output here */
int *aiIndent; /* Array of indents used in MODE_Explain */
int nIndent; /* Size of array aiIndent[] */
int iIndent; /* Index of current op in aiIndent[] */
};
/*
** These are the allowed modes.
*/
#define MODE_Line 0 /* One column per line. Blank line between records */
#define MODE_Column 1 /* One record per line in neat columns */
|
| ︙ | ︙ | |||
565 566 567 568 569 570 571 572 573 574 575 576 577 578 |
/*
** Output the given string with characters that are special to
** HTML escaped.
*/
static void output_html_string(FILE *out, const char *z){
int i;
while( *z ){
for(i=0; z[i]
&& z[i]!='<'
&& z[i]!='&'
&& z[i]!='>'
&& z[i]!='\"'
&& z[i]!='\'';
| > | 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 |
/*
** Output the given string with characters that are special to
** HTML escaped.
*/
static void output_html_string(FILE *out, const char *z){
int i;
if( z==0 ) z = "";
while( *z ){
for(i=0; z[i]
&& z[i]!='<'
&& z[i]!='&'
&& z[i]!='>'
&& z[i]!='\"'
&& z[i]!='\'';
|
| ︙ | ︙ | |||
736 737 738 739 740 741 742 |
for(i=0; i<nArg; i++){
int w;
if( i<ArraySize(p->actualWidth) ){
w = p->actualWidth[i];
}else{
w = 10;
}
| | < > > > > > > | 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 |
for(i=0; i<nArg; i++){
int w;
if( i<ArraySize(p->actualWidth) ){
w = p->actualWidth[i];
}else{
w = 10;
}
if( p->mode==MODE_Explain && azArg[i] && strlen30(azArg[i])>w ){
w = strlen30(azArg[i]);
}
if( i==1 && p->aiIndent && p->pStmt ){
if( p->iIndent<p->nIndent ){
fprintf(p->out, "%*.s", p->aiIndent[p->iIndent], "");
}
p->iIndent++;
}
if( w<0 ){
fprintf(p->out,"%*.*s%s",-w,-w,
azArg[i] ? azArg[i] : p->nullvalue, i==nArg-1 ? "\n": " ");
}else{
fprintf(p->out,"%-*.*s%s",w,w,
azArg[i] ? azArg[i] : p->nullvalue, i==nArg-1 ? "\n": " ");
|
| ︙ | ︙ | |||
967 968 969 970 971 972 973 |
const char *zFirstRow /* Print before first row, if not NULL */
){
sqlite3_stmt *pSelect;
int rc;
int nResult;
int i;
const char *z;
| | | 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 |
const char *zFirstRow /* Print before first row, if not NULL */
){
sqlite3_stmt *pSelect;
int rc;
int nResult;
int i;
const char *z;
rc = sqlite3_prepare_v2(p->db, zSelect, -1, &pSelect, 0);
if( rc!=SQLITE_OK || !pSelect ){
fprintf(p->out, "/**** ERROR: (%d) %s *****/\n", rc, sqlite3_errmsg(p->db));
if( (rc&0xff)!=SQLITE_CORRUPT ) p->nErr++;
return rc;
}
rc = sqlite3_step(pSelect);
nResult = sqlite3_column_count(pSelect);
|
| ︙ | ︙ | |||
1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 |
fprintf(pArg->out, "Autoindex Inserts: %d\n", iCur);
iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_VM_STEP, bReset);
fprintf(pArg->out, "Virtual Machine Steps: %d\n", iCur);
}
return 0;
}
/*
** Execute a statement or set of statements. Print
** any result rows/columns depending on the current mode
** set via the supplied callback.
**
** This is very similar to SQLite's built-in sqlite3_exec()
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 |
fprintf(pArg->out, "Autoindex Inserts: %d\n", iCur);
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
** points to a single nul-terminated string. Return non-zero if zStr
** is equal, according to strcmp(), to any of the strings in the array.
** Otherwise, return zero.
*/
static int str_in_array(const char *zStr, const char **azArray){
int i;
for(i=0; azArray[i]; i++){
if( 0==strcmp(zStr, azArray[i]) ) return 1;
}
return 0;
}
/*
** If compiled statement pSql appears to be an EXPLAIN statement, allocate
** and populate the callback_data.aiIndent[] array with the number of
** spaces each opcode should be indented before it is output.
**
** The indenting rules are:
**
** * For each "Next", "Prev", "VNext" or "VPrev" instruction, indent
** all opcodes that occur between the p2 jump destination and the opcode
** itself by 2 spaces.
**
** * For each "Goto", if the jump destination is earlier in the program
** and ends on one of:
** Yield SeekGt SeekLt RowSetRead Rewind
** then indent all opcodes between the earlier instruction
** and "Goto" by 2 spaces.
*/
static void explain_data_prepare(struct callback_data *p, sqlite3_stmt *pSql){
const char *zSql; /* The text of the SQL statement */
const char *z; /* Used to check if this is an EXPLAIN */
int *abYield = 0; /* True if op is an OP_Yield */
int nAlloc = 0; /* Allocated size of p->aiIndent[], abYield */
int iOp; /* Index of operation in p->aiIndent[] */
const char *azNext[] = { "Next", "Prev", "VPrev", "VNext", "SorterNext", 0 };
const char *azYield[] = { "Yield", "SeekLt", "SeekGt", "RowSetRead", "Rewind", 0 };
const char *azGoto[] = { "Goto", 0 };
/* Try to figure out if this is really an EXPLAIN statement. If this
** cannot be verified, return early. */
zSql = sqlite3_sql(pSql);
if( zSql==0 ) return;
for(z=zSql; *z==' ' || *z=='\t' || *z=='\n' || *z=='\f' || *z=='\r'; z++);
if( sqlite3_strnicmp(z, "explain", 7) ) return;
for(iOp=0; SQLITE_ROW==sqlite3_step(pSql); iOp++){
int i;
int iAddr = sqlite3_column_int(pSql, 0);
const char *zOp = (const char*)sqlite3_column_text(pSql, 1);
/* Set p2 to the P2 field of the current opcode. Then, assuming that
** p2 is an instruction address, set variable p2op to the index of that
** instruction in the aiIndent[] array. p2 and p2op may be different if
** the current instruction is part of a sub-program generated by an
** SQL trigger or foreign key. */
int p2 = sqlite3_column_int(pSql, 3);
int p2op = (p2 + (iOp-iAddr));
/* Grow the p->aiIndent array as required */
if( iOp>=nAlloc ){
nAlloc += 100;
p->aiIndent = (int*)sqlite3_realloc(p->aiIndent, nAlloc*sizeof(int));
abYield = (int*)sqlite3_realloc(abYield, nAlloc*sizeof(int));
}
abYield[iOp] = str_in_array(zOp, azYield);
p->aiIndent[iOp] = 0;
p->nIndent = iOp+1;
if( str_in_array(zOp, azNext) ){
for(i=p2op; i<iOp; i++) p->aiIndent[i] += 2;
}
if( str_in_array(zOp, azGoto) && p2op<p->nIndent && abYield[p2op] ){
for(i=p2op+1; i<iOp; i++) p->aiIndent[i] += 2;
}
}
p->iIndent = 0;
sqlite3_free(abYield);
sqlite3_reset(pSql);
}
/*
** Free the array allocated by explain_data_prepare().
*/
static void explain_data_delete(struct callback_data *p){
sqlite3_free(p->aiIndent);
p->aiIndent = 0;
p->nIndent = 0;
p->iIndent = 0;
}
/*
** Execute a statement or set of statements. Print
** any result rows/columns depending on the current mode
** set via the supplied callback.
**
** This is very similar to SQLite's built-in sqlite3_exec()
|
| ︙ | ︙ | |||
1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 |
if( pArg && pArg->mode==MODE_Explain ){
const char *zExplain = 0;
sqlite3_test_control(SQLITE_TESTCTRL_EXPLAIN_STMT, pStmt, &zExplain);
if( zExplain && zExplain[0] ){
fprintf(pArg->out, "%s", zExplain);
}
}
/* perform the first step. this will tell us if we
** have a result set or not and how wide it is.
*/
rc = sqlite3_step(pStmt);
/* if we have a result set... */
if( SQLITE_ROW == rc ){
| > > > > > > | 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 |
if( pArg && pArg->mode==MODE_Explain ){
const char *zExplain = 0;
sqlite3_test_control(SQLITE_TESTCTRL_EXPLAIN_STMT, pStmt, &zExplain);
if( zExplain && zExplain[0] ){
fprintf(pArg->out, "%s", zExplain);
}
}
/* If the shell is currently in ".explain" mode, gather the extra
** data required to add indents to the output.*/
if( pArg && pArg->mode==MODE_Explain ){
explain_data_prepare(pArg, pStmt);
}
/* perform the first step. this will tell us if we
** have a result set or not and how wide it is.
*/
rc = sqlite3_step(pStmt);
/* if we have a result set... */
if( SQLITE_ROW == rc ){
|
| ︙ | ︙ | |||
1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 |
}
}else{
do{
rc = sqlite3_step(pStmt);
} while( rc == SQLITE_ROW );
}
}
/* print usage stats if stats on */
if( pArg && pArg->statsOn ){
display_stats(db, pArg, 0);
}
/* Finalize the statement just executed. If this fails, save a
| > > | 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 |
}
}else{
do{
rc = sqlite3_step(pStmt);
} while( rc == SQLITE_ROW );
}
}
explain_data_delete(pArg);
/* print usage stats if stats on */
if( pArg && pArg->statsOn ){
display_stats(db, pArg, 0);
}
/* Finalize the statement just executed. If this fails, save a
|
| ︙ | ︙ | |||
1312 1313 1314 1315 1316 1317 1318 |
char *zTmp = 0;
int nRow = 0;
zTableInfo = appendText(zTableInfo, "PRAGMA table_info(", 0);
zTableInfo = appendText(zTableInfo, zTable, '"');
zTableInfo = appendText(zTableInfo, ");", 0);
| | | 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 |
char *zTmp = 0;
int nRow = 0;
zTableInfo = appendText(zTableInfo, "PRAGMA table_info(", 0);
zTableInfo = appendText(zTableInfo, zTable, '"');
zTableInfo = appendText(zTableInfo, ");", 0);
rc = sqlite3_prepare_v2(p->db, zTableInfo, -1, &pTableInfo, 0);
free(zTableInfo);
if( rc!=SQLITE_OK || !pTableInfo ){
return 1;
}
zSelect = appendText(zSelect, "SELECT 'INSERT INTO ' || ", 0);
/* Always quote the table name, even if it appears to be pure ascii,
|
| ︙ | ︙ | |||
1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 | /* ** Text of a help message */ static char zHelp[] = ".backup ?DB? FILE Backup DB (default \"main\") to FILE\n" ".bail ON|OFF Stop after hitting an error. Default OFF\n" ".databases List names and files of attached databases\n" ".dump ?TABLE? ... Dump the database in an SQL text format\n" " If TABLE specified, only dump tables matching\n" " LIKE pattern TABLE.\n" ".echo ON|OFF Turn command echo on or off\n" ".exit Exit this program\n" ".explain ?ON|OFF? Turn output mode suitable for EXPLAIN on or off.\n" | > | 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 | /* ** Text of a help message */ static char zHelp[] = ".backup ?DB? FILE Backup DB (default \"main\") to FILE\n" ".bail ON|OFF Stop after hitting an error. Default OFF\n" ".clone NEWDB Clone data into NEWDB from the existing database\n" ".databases List names and files of attached databases\n" ".dump ?TABLE? ... Dump the database in an SQL text format\n" " If TABLE specified, only dump tables matching\n" " LIKE pattern TABLE.\n" ".echo ON|OFF Turn command echo on or off\n" ".exit Exit this program\n" ".explain ?ON|OFF? Turn output mode suitable for EXPLAIN on or off.\n" |
| ︙ | ︙ | |||
1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 | " html HTML <table> code\n" " insert SQL insert statements for TABLE\n" " line One value per line\n" " list Values delimited by .separator string\n" " tabs Tab-separated values\n" " tcl TCL list elements\n" ".nullvalue STRING Use STRING in place of NULL values\n" ".output FILENAME Send output to FILENAME\n" ".output stdout Send output to the screen\n" ".print STRING... Print literal STRING\n" ".prompt MAIN CONTINUE Replace the standard prompts\n" ".quit Exit this program\n" ".read FILENAME Execute SQL in FILENAME\n" ".restore ?DB? FILE Restore content of DB (default \"main\") from FILE\n" ".schema ?TABLE? Show the CREATE statements\n" " If TABLE specified, only show tables matching\n" " LIKE pattern TABLE.\n" ".separator STRING Change separator used by output mode and .import\n" ".show Show the current values for various settings\n" ".stats ON|OFF Turn stats on or off\n" ".tables ?TABLE? List names of tables\n" | > > | 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 | " html HTML <table> code\n" " insert SQL insert statements for TABLE\n" " line One value per line\n" " list Values delimited by .separator string\n" " tabs Tab-separated values\n" " tcl TCL list elements\n" ".nullvalue STRING Use STRING in place of NULL values\n" ".open ?FILENAME? Close existing database and reopen FILENAME\n" ".output FILENAME Send output to FILENAME\n" ".output stdout Send output to the screen\n" ".print STRING... Print literal STRING\n" ".prompt MAIN CONTINUE Replace the standard prompts\n" ".quit Exit this program\n" ".read FILENAME Execute SQL in FILENAME\n" ".restore ?DB? FILE Restore content of DB (default \"main\") from FILE\n" ".save FILE Write in-memory database into FILE\n" ".schema ?TABLE? Show the CREATE statements\n" " If TABLE specified, only show tables matching\n" " LIKE pattern TABLE.\n" ".separator STRING Change separator used by output mode and .import\n" ".show Show the current values for various settings\n" ".stats ON|OFF Turn stats on or off\n" ".tables ?TABLE? List names of tables\n" |
| ︙ | ︙ | |||
1466 1467 1468 1469 1470 1471 1472 | /* Forward reference */ static int process_input(struct callback_data *p, FILE *in); /* ** Make sure the database is open. If it is not, then open it. If ** the database fails to open, print an error message and exit. */ | | > | 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 |
/* Forward reference */
static int process_input(struct callback_data *p, FILE *in);
/*
** Make sure the database is open. If it is not, then open it. If
** the database fails to open, print an error message and exit.
*/
static void open_db(struct callback_data *p, int keepAlive){
if( p->db==0 ){
sqlite3_initialize();
sqlite3_open(p->zDbFilename, &p->db);
db = p->db;
if( db && sqlite3_errcode(db)==SQLITE_OK ){
sqlite3_create_function(db, "shellstatic", 0, SQLITE_UTF8, 0,
shellstaticFunc, 0, 0);
}
if( db==0 || SQLITE_OK!=sqlite3_errcode(db) ){
fprintf(stderr,"Error: unable to open database \"%s\": %s\n",
p->zDbFilename, sqlite3_errmsg(db));
if( keepAlive ) return;
exit(1);
}
#ifndef SQLITE_OMIT_LOAD_EXTENSION
sqlite3_enable_load_extension(p->db, 1);
#endif
}
}
|
| ︙ | ︙ | |||
1694 1695 1696 1697 1698 1699 1700 |
** + Use p->cSep as the separator. The default is ",".
** + Keep track of the line number in p->nLine.
** + Store the character that terminates the field in p->cTerm. Store
** EOF on end-of-file.
** + Report syntax errors on stderr
*/
static char *csv_read_one_field(CSVReader *p){
| | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 |
** + Use p->cSep as the separator. The default is ",".
** + Keep track of the line number in p->nLine.
** + Store the character that terminates the field in p->cTerm. Store
** EOF on end-of-file.
** + Report syntax errors on stderr
*/
static char *csv_read_one_field(CSVReader *p){
int c, pc, ppc;
int cSep = p->cSeparator;
p->n = 0;
c = fgetc(p->in);
if( c==EOF || seenInterrupt ){
p->cTerm = EOF;
return 0;
}
if( c=='"' ){
int startLine = p->nLine;
int cQuote = c;
pc = ppc = 0;
while( 1 ){
c = fgetc(p->in);
if( c=='\n' ) p->nLine++;
if( c==cQuote ){
if( pc==cQuote ){
pc = 0;
continue;
}
}
if( (c==cSep && pc==cQuote)
|| (c=='\n' && pc==cQuote)
|| (c=='\n' && pc=='\r' && ppc==cQuote)
|| (c==EOF && pc==cQuote)
){
do{ p->n--; }while( p->z[p->n]!=cQuote );
p->cTerm = c;
break;
}
if( pc==cQuote && c!='\r' ){
fprintf(stderr, "%s:%d: unescaped %c character\n",
p->zFile, p->nLine, cQuote);
}
if( c==EOF ){
fprintf(stderr, "%s:%d: unterminated %c-quoted field\n",
p->zFile, startLine, cQuote);
p->cTerm = EOF;
break;
}
csv_append_char(p, c);
ppc = pc;
pc = c;
}
}else{
while( c!=EOF && c!=cSep && c!='\n' ){
csv_append_char(p, c);
c = fgetc(p->in);
}
if( c=='\n' ){
p->nLine++;
if( p->n>1 && p->z[p->n-1]=='\r' ) p->n--;
}
p->cTerm = c;
}
if( p->z ) p->z[p->n] = 0;
return p->z;
}
/*
** Try to transfer data for table zTable. If an error is seen while
** moving forward, try to go backwards. The backwards movement won't
** work for WITHOUT ROWID tables.
*/
static void tryToCloneData(
struct callback_data *p,
sqlite3 *newDb,
const char *zTable
){
sqlite3_stmt *pQuery = 0;
sqlite3_stmt *pInsert = 0;
char *zQuery = 0;
char *zInsert = 0;
int rc;
int i, j, n;
int nTable = (int)strlen(zTable);
int k = 0;
int cnt = 0;
const int spinRate = 10000;
zQuery = sqlite3_mprintf("SELECT * FROM \"%w\"", zTable);
rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
if( rc ){
fprintf(stderr, "Error %d: %s on [%s]\n",
sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db),
zQuery);
goto end_data_xfer;
}
n = sqlite3_column_count(pQuery);
zInsert = sqlite3_malloc(200 + nTable + n*3);
if( zInsert==0 ){
fprintf(stderr, "out of memory\n");
goto end_data_xfer;
}
sqlite3_snprintf(200+nTable,zInsert,
"INSERT OR IGNORE INTO \"%s\" VALUES(?", zTable);
i = (int)strlen(zInsert);
for(j=1; j<n; j++){
memcpy(zInsert+i, ",?", 2);
i += 2;
}
memcpy(zInsert+i, ");", 3);
rc = sqlite3_prepare_v2(newDb, zInsert, -1, &pInsert, 0);
if( rc ){
fprintf(stderr, "Error %d: %s on [%s]\n",
sqlite3_extended_errcode(newDb), sqlite3_errmsg(newDb),
zQuery);
goto end_data_xfer;
}
for(k=0; k<2; k++){
while( (rc = sqlite3_step(pQuery))==SQLITE_ROW ){
for(i=0; i<n; i++){
switch( sqlite3_column_type(pQuery, i) ){
case SQLITE_NULL: {
sqlite3_bind_null(pInsert, i+1);
break;
}
case SQLITE_INTEGER: {
sqlite3_bind_int64(pInsert, i+1, sqlite3_column_int64(pQuery,i));
break;
}
case SQLITE_FLOAT: {
sqlite3_bind_double(pInsert, i+1, sqlite3_column_double(pQuery,i));
break;
}
case SQLITE_TEXT: {
sqlite3_bind_text(pInsert, i+1,
(const char*)sqlite3_column_text(pQuery,i),
-1, SQLITE_STATIC);
break;
}
case SQLITE_BLOB: {
sqlite3_bind_blob(pInsert, i+1, sqlite3_column_blob(pQuery,i),
sqlite3_column_bytes(pQuery,i),
SQLITE_STATIC);
break;
}
}
} /* End for */
rc = sqlite3_step(pInsert);
if( rc!=SQLITE_OK && rc!=SQLITE_ROW && rc!=SQLITE_DONE ){
fprintf(stderr, "Error %d: %s\n", sqlite3_extended_errcode(newDb),
sqlite3_errmsg(newDb));
}
sqlite3_reset(pInsert);
cnt++;
if( (cnt%spinRate)==0 ){
printf("%c\b", "|/-\\"[(cnt/spinRate)%4]);
fflush(stdout);
}
} /* End while */
if( rc==SQLITE_DONE ) break;
sqlite3_finalize(pQuery);
sqlite3_free(zQuery);
zQuery = sqlite3_mprintf("SELECT * FROM \"%w\" ORDER BY rowid DESC;",
zTable);
rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
if( rc ){
fprintf(stderr, "Warning: cannot step \"%s\" backwards", zTable);
break;
}
} /* End for(k=0...) */
end_data_xfer:
sqlite3_finalize(pQuery);
sqlite3_finalize(pInsert);
sqlite3_free(zQuery);
sqlite3_free(zInsert);
}
/*
** Try to transfer all rows of the schema that match zWhere. For
** each row, invoke xForEach() on the object defined by that row.
** If an error is encountered while moving forward through the
** sqlite_master table, try again moving backwards.
*/
static void tryToCloneSchema(
struct callback_data *p,
sqlite3 *newDb,
const char *zWhere,
void (*xForEach)(struct callback_data*,sqlite3*,const char*)
){
sqlite3_stmt *pQuery = 0;
char *zQuery = 0;
int rc;
const unsigned char *zName;
const unsigned char *zSql;
char *zErrMsg = 0;
zQuery = sqlite3_mprintf("SELECT name, sql FROM sqlite_master"
" WHERE %s", zWhere);
rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
if( rc ){
fprintf(stderr, "Error: (%d) %s on [%s]\n",
sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db),
zQuery);
goto end_schema_xfer;
}
while( (rc = sqlite3_step(pQuery))==SQLITE_ROW ){
zName = sqlite3_column_text(pQuery, 0);
zSql = sqlite3_column_text(pQuery, 1);
printf("%s... ", zName); fflush(stdout);
sqlite3_exec(newDb, (const char*)zSql, 0, 0, &zErrMsg);
if( zErrMsg ){
fprintf(stderr, "Error: %s\nSQL: [%s]\n", zErrMsg, zSql);
sqlite3_free(zErrMsg);
zErrMsg = 0;
}
if( xForEach ){
xForEach(p, newDb, (const char*)zName);
}
printf("done\n");
}
if( rc!=SQLITE_DONE ){
sqlite3_finalize(pQuery);
sqlite3_free(zQuery);
zQuery = sqlite3_mprintf("SELECT name, sql FROM sqlite_master"
" WHERE %s ORDER BY rowid DESC", zWhere);
rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
if( rc ){
fprintf(stderr, "Error: (%d) %s on [%s]\n",
sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db),
zQuery);
goto end_schema_xfer;
}
while( (rc = sqlite3_step(pQuery))==SQLITE_ROW ){
zName = sqlite3_column_text(pQuery, 0);
zSql = sqlite3_column_text(pQuery, 1);
printf("%s... ", zName); fflush(stdout);
sqlite3_exec(newDb, (const char*)zSql, 0, 0, &zErrMsg);
if( zErrMsg ){
fprintf(stderr, "Error: %s\nSQL: [%s]\n", zErrMsg, zSql);
sqlite3_free(zErrMsg);
zErrMsg = 0;
}
if( xForEach ){
xForEach(p, newDb, (const char*)zName);
}
printf("done\n");
}
}
end_schema_xfer:
sqlite3_finalize(pQuery);
sqlite3_free(zQuery);
}
/*
** Open a new database file named "zNewDb". Try to recover as much information
** as possible out of the main database (which might be corrupt) and write it
** into zNewDb.
*/
static void tryToClone(struct callback_data *p, const char *zNewDb){
int rc;
sqlite3 *newDb = 0;
if( access(zNewDb,0)==0 ){
fprintf(stderr, "File \"%s\" already exists.\n", zNewDb);
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.
**
** Return 1 on error, 2 to exit, and 0 otherwise.
*/
|
| ︙ | ︙ | |||
1794 1795 1796 1797 1798 1799 1800 | } /* Process the input line. */ if( nArg==0 ) return 0; /* no tokens, no error */ n = strlen30(azArg[0]); c = azArg[0][0]; | | > > | 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 |
}
/* Process the input line.
*/
if( nArg==0 ) return 0; /* no tokens, no error */
n = strlen30(azArg[0]);
c = azArg[0][0];
if( (c=='b' && n>=3 && strncmp(azArg[0], "backup", n)==0)
|| (c=='s' && n>=3 && strncmp(azArg[0], "save", n)==0)
){
const char *zDestFile = 0;
const char *zDb = 0;
sqlite3 *pDest;
sqlite3_backup *pBackup;
int j;
for(j=1; j<nArg; j++){
const char *z = azArg[j];
|
| ︙ | ︙ | |||
1830 1831 1832 1833 1834 1835 1836 |
if( zDb==0 ) zDb = "main";
rc = sqlite3_open(zDestFile, &pDest);
if( rc!=SQLITE_OK ){
fprintf(stderr, "Error: cannot open \"%s\"\n", zDestFile);
sqlite3_close(pDest);
return 1;
}
| | | 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 |
if( zDb==0 ) zDb = "main";
rc = sqlite3_open(zDestFile, &pDest);
if( rc!=SQLITE_OK ){
fprintf(stderr, "Error: cannot open \"%s\"\n", zDestFile);
sqlite3_close(pDest);
return 1;
}
open_db(p, 0);
pBackup = sqlite3_backup_init(pDest, "main", p->db, zDb);
if( pBackup==0 ){
fprintf(stderr, "Error: %s\n", sqlite3_errmsg(pDest));
sqlite3_close(pDest);
return 1;
}
while( (rc = sqlite3_backup_step(pBackup,100))==SQLITE_OK ){}
|
| ︙ | ︙ | |||
1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 |
/* The undocumented ".breakpoint" command causes a call to the no-op
** routine named test_breakpoint().
*/
if( c=='b' && n>=3 && strncmp(azArg[0], "breakpoint", n)==0 ){
test_breakpoint();
}else
if( c=='d' && n>1 && strncmp(azArg[0], "databases", n)==0 && nArg==1 ){
struct callback_data data;
char *zErrMsg = 0;
| > > > > | | | 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 |
/* The undocumented ".breakpoint" command causes a call to the no-op
** routine named test_breakpoint().
*/
if( c=='b' && n>=3 && strncmp(azArg[0], "breakpoint", n)==0 ){
test_breakpoint();
}else
if( c=='c' && strncmp(azArg[0], "clone", n)==0 && nArg>1 && nArg<3 ){
tryToClone(p, azArg[1]);
}else
if( c=='d' && n>1 && strncmp(azArg[0], "databases", n)==0 && nArg==1 ){
struct callback_data data;
char *zErrMsg = 0;
open_db(p, 0);
memcpy(&data, p, sizeof(data));
data.showHeader = 1;
data.mode = MODE_Column;
data.colWidth[0] = 3;
data.colWidth[1] = 15;
data.colWidth[2] = 58;
data.cnt = 0;
sqlite3_exec(p->db, "PRAGMA database_list; ", callback, &data, &zErrMsg);
if( zErrMsg ){
fprintf(stderr,"Error: %s\n", zErrMsg);
sqlite3_free(zErrMsg);
rc = 1;
}
}else
if( c=='d' && strncmp(azArg[0], "dump", n)==0 && nArg<3 ){
open_db(p, 0);
/* When playing back a "dump", the content might appear in an order
** which causes immediate foreign key constraints to be violated.
** So disable foreign-key constraint enforcement to prevent problems. */
fprintf(p->out, "PRAGMA foreign_keys=OFF;\n");
fprintf(p->out, "BEGIN TRANSACTION;\n");
p->writableSchema = 0;
sqlite3_exec(p->db, "SAVEPOINT dump; PRAGMA writable_schema=ON", 0, 0, 0);
|
| ︙ | ︙ | |||
1954 1955 1956 1957 1958 1959 1960 |
** explain mode. However, always executing it allows us an easy
** was to reset to explain mode in case the user previously
** did an .explain followed by a .width, .mode or .header
** command.
*/
p->mode = MODE_Explain;
p->showHeader = 1;
| | | 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 |
** explain mode. However, always executing it allows us an easy
** was to reset to explain mode in case the user previously
** did an .explain followed by a .width, .mode or .header
** command.
*/
p->mode = MODE_Explain;
p->showHeader = 1;
memset(p->colWidth,0,sizeof(p->colWidth));
p->colWidth[0] = 4; /* addr */
p->colWidth[1] = 13; /* opcode */
p->colWidth[2] = 4; /* P1 */
p->colWidth[3] = 4; /* P2 */
p->colWidth[4] = 4; /* P3 */
p->colWidth[5] = 13; /* P4 */
p->colWidth[6] = 2; /* P5 */
|
| ︙ | ︙ | |||
1998 1999 2000 2001 2002 2003 2004 |
int nSep; /* Number of bytes in p->separator[] */
char *zSql; /* An SQL statement */
CSVReader sCsv; /* Reader context */
int (*xCloser)(FILE*); /* Procedure to close th3 connection */
seenInterrupt = 0;
memset(&sCsv, 0, sizeof(sCsv));
| | | 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 |
int nSep; /* Number of bytes in p->separator[] */
char *zSql; /* An SQL statement */
CSVReader sCsv; /* Reader context */
int (*xCloser)(FILE*); /* Procedure to close th3 connection */
seenInterrupt = 0;
memset(&sCsv, 0, sizeof(sCsv));
open_db(p, 0);
nSep = strlen30(p->separator);
if( nSep==0 ){
fprintf(stderr, "Error: non-null separator required for import\n");
return 1;
}
if( nSep>1 ){
fprintf(stderr, "Error: multi-character separators not allowed"
|
| ︙ | ︙ | |||
2031 2032 2033 2034 2035 2036 2037 |
zSql = sqlite3_mprintf("SELECT * FROM %s", zTable);
if( zSql==0 ){
fprintf(stderr, "Error: out of memory\n");
xCloser(sCsv.in);
return 1;
}
nByte = strlen30(zSql);
| | | 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 |
zSql = sqlite3_mprintf("SELECT * FROM %s", zTable);
if( zSql==0 ){
fprintf(stderr, "Error: out of memory\n");
xCloser(sCsv.in);
return 1;
}
nByte = strlen30(zSql);
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
if( rc && sqlite3_strglob("no such table: *", sqlite3_errmsg(db))==0 ){
char *zCreate = sqlite3_mprintf("CREATE TABLE %s", zTable);
char cSep = '(';
while( csv_read_one_field(&sCsv) ){
zCreate = sqlite3_mprintf("%z%c\n \"%s\" TEXT", zCreate, cSep, sCsv.z);
cSep = ',';
if( sCsv.cTerm!=sCsv.cSeparator ) break;
|
| ︙ | ︙ | |||
2057 2058 2059 2060 2061 2062 2063 |
if( rc ){
fprintf(stderr, "CREATE TABLE %s(...) failed: %s\n", zTable,
sqlite3_errmsg(db));
sqlite3_free(sCsv.z);
xCloser(sCsv.in);
return 1;
}
| | | 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 |
if( rc ){
fprintf(stderr, "CREATE TABLE %s(...) failed: %s\n", zTable,
sqlite3_errmsg(db));
sqlite3_free(sCsv.z);
xCloser(sCsv.in);
return 1;
}
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
}
sqlite3_free(zSql);
if( rc ){
if (pStmt) sqlite3_finalize(pStmt);
fprintf(stderr,"Error: %s\n", sqlite3_errmsg(db));
xCloser(sCsv.in);
return 1;
|
| ︙ | ︙ | |||
2084 2085 2086 2087 2088 2089 2090 |
j = strlen30(zSql);
for(i=1; i<nCol; i++){
zSql[j++] = ',';
zSql[j++] = '?';
}
zSql[j++] = ')';
zSql[j] = 0;
| | | 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 |
j = strlen30(zSql);
for(i=1; i<nCol; i++){
zSql[j++] = ',';
zSql[j++] = '?';
}
zSql[j++] = ')';
zSql[j] = 0;
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
sqlite3_free(zSql);
if( rc ){
fprintf(stderr, "Error: %s\n", sqlite3_errmsg(db));
if (pStmt) sqlite3_finalize(pStmt);
xCloser(sCsv.in);
return 1;
}
|
| ︙ | ︙ | |||
2136 2137 2138 2139 2140 2141 2142 |
sqlite3_finalize(pStmt);
if( needCommit ) sqlite3_exec(db, "COMMIT", 0, 0, 0);
}else
if( c=='i' && strncmp(azArg[0], "indices", n)==0 && nArg<3 ){
struct callback_data data;
char *zErrMsg = 0;
| | | 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 |
sqlite3_finalize(pStmt);
if( needCommit ) sqlite3_exec(db, "COMMIT", 0, 0, 0);
}else
if( c=='i' && strncmp(azArg[0], "indices", n)==0 && nArg<3 ){
struct callback_data data;
char *zErrMsg = 0;
open_db(p, 0);
memcpy(&data, p, sizeof(data));
data.showHeader = 0;
data.mode = MODE_List;
if( nArg==1 ){
rc = sqlite3_exec(p->db,
"SELECT name FROM sqlite_master "
"WHERE type='index' AND name NOT LIKE 'sqlite_%' "
|
| ︙ | ︙ | |||
2202 2203 2204 2205 2206 2207 2208 |
#ifndef SQLITE_OMIT_LOAD_EXTENSION
if( c=='l' && strncmp(azArg[0], "load", n)==0 && nArg>=2 ){
const char *zFile, *zProc;
char *zErrMsg = 0;
zFile = azArg[1];
zProc = nArg>=3 ? azArg[2] : 0;
| | | 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 |
#ifndef SQLITE_OMIT_LOAD_EXTENSION
if( c=='l' && strncmp(azArg[0], "load", n)==0 && nArg>=2 ){
const char *zFile, *zProc;
char *zErrMsg = 0;
zFile = azArg[1];
zProc = nArg>=3 ? azArg[2] : 0;
open_db(p, 0);
rc = sqlite3_load_extension(p->db, zFile, zProc, &zErrMsg);
if( rc!=SQLITE_OK ){
fprintf(stderr, "Error: %s\n", zErrMsg);
sqlite3_free(zErrMsg);
rc = 1;
}
}else
|
| ︙ | ︙ | |||
2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 |
}
}else
if( c=='n' && strncmp(azArg[0], "nullvalue", n)==0 && nArg==2 ) {
sqlite3_snprintf(sizeof(p->nullvalue), p->nullvalue,
"%.*s", (int)ArraySize(p->nullvalue)-1, azArg[1]);
}else
if( c=='o' && strncmp(azArg[0], "output", n)==0 && nArg==2 ){
if( p->outfile[0]=='|' ){
pclose(p->out);
}else{
output_file_close(p->out);
}
| > > > > > > > > > > > > > > > > > > > > | 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 |
}
}else
if( c=='n' && strncmp(azArg[0], "nullvalue", n)==0 && nArg==2 ) {
sqlite3_snprintf(sizeof(p->nullvalue), p->nullvalue,
"%.*s", (int)ArraySize(p->nullvalue)-1, azArg[1]);
}else
if( c=='o' && strncmp(azArg[0], "open", n)==0 && n>=2 ){
sqlite3 *savedDb = p->db;
const char *zSavedFilename = p->zDbFilename;
char *zNewFilename = 0;
p->db = 0;
if( nArg>=2 ){
p->zDbFilename = zNewFilename = sqlite3_mprintf("%s", azArg[1]);
}
open_db(p, 1);
if( p->db!=0 ){
sqlite3_close(savedDb);
sqlite3_free(p->zFreeOnClose);
p->zFreeOnClose = zNewFilename;
}else{
sqlite3_free(zNewFilename);
p->db = savedDb;
p->zDbFilename = zSavedFilename;
}
}else
if( c=='o' && strncmp(azArg[0], "output", n)==0 && nArg==2 ){
if( p->outfile[0]=='|' ){
pclose(p->out);
}else{
output_file_close(p->out);
}
|
| ︙ | ︙ | |||
2351 2352 2353 2354 2355 2356 2357 |
}
rc = sqlite3_open(zSrcFile, &pSrc);
if( rc!=SQLITE_OK ){
fprintf(stderr, "Error: cannot open \"%s\"\n", zSrcFile);
sqlite3_close(pSrc);
return 1;
}
| | | 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 |
}
rc = sqlite3_open(zSrcFile, &pSrc);
if( rc!=SQLITE_OK ){
fprintf(stderr, "Error: cannot open \"%s\"\n", zSrcFile);
sqlite3_close(pSrc);
return 1;
}
open_db(p, 0);
pBackup = sqlite3_backup_init(p->db, zDb, pSrc, "main");
if( pBackup==0 ){
fprintf(stderr, "Error: %s\n", sqlite3_errmsg(p->db));
sqlite3_close(pSrc);
return 1;
}
while( (rc = sqlite3_backup_step(pBackup,100))==SQLITE_OK
|
| ︙ | ︙ | |||
2381 2382 2383 2384 2385 2386 2387 |
}
sqlite3_close(pSrc);
}else
if( c=='s' && strncmp(azArg[0], "schema", n)==0 && nArg<3 ){
struct callback_data data;
char *zErrMsg = 0;
| | | 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 |
}
sqlite3_close(pSrc);
}else
if( c=='s' && strncmp(azArg[0], "schema", n)==0 && nArg<3 ){
struct callback_data data;
char *zErrMsg = 0;
open_db(p, 0);
memcpy(&data, p, sizeof(data));
data.showHeader = 0;
data.mode = MODE_Semi;
if( nArg>1 ){
int i;
for(i=0; azArg[1][i]; i++) azArg[1][i] = ToLower(azArg[1][i]);
if( strcmp(azArg[1],"sqlite_master")==0 ){
|
| ︙ | ︙ | |||
2512 2513 2514 2515 2516 2517 2518 |
if( c=='t' && n>1 && strncmp(azArg[0], "tables", n)==0 && nArg<3 ){
sqlite3_stmt *pStmt;
char **azResult;
int nRow, nAlloc;
char *zSql = 0;
int ii;
| | | 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 |
if( c=='t' && n>1 && strncmp(azArg[0], "tables", n)==0 && nArg<3 ){
sqlite3_stmt *pStmt;
char **azResult;
int nRow, nAlloc;
char *zSql = 0;
int ii;
open_db(p, 0);
rc = sqlite3_prepare_v2(p->db, "PRAGMA database_list", -1, &pStmt, 0);
if( rc ) return rc;
zSql = sqlite3_mprintf(
"SELECT name FROM sqlite_master"
" WHERE type IN ('table','view')"
" AND name NOT LIKE 'sqlite_%%'"
" AND name LIKE ?1");
|
| ︙ | ︙ | |||
2612 2613 2614 2615 2616 2617 2618 |
{ "optimizations", SQLITE_TESTCTRL_OPTIMIZATIONS },
{ "iskeyword", SQLITE_TESTCTRL_ISKEYWORD },
{ "scratchmalloc", SQLITE_TESTCTRL_SCRATCHMALLOC },
};
int testctrl = -1;
int rc = 0;
int i, n;
| | | 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 |
{ "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
** of the option name, or a numerical value. */
n = strlen30(azArg[1]);
for(i=0; i<(int)(sizeof(aCtrl)/sizeof(aCtrl[0])); i++){
if( strncmp(azArg[1], aCtrl[i].zCtrlName, n)==0 ){
if( testctrl<0 ){
|
| ︙ | ︙ | |||
2711 2712 2713 2714 2715 2716 2717 |
azArg[1]);
break;
}
}
}else
if( c=='t' && n>4 && strncmp(azArg[0], "timeout", n)==0 && nArg==2 ){
| | | | 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 |
azArg[1]);
break;
}
}
}else
if( c=='t' && n>4 && strncmp(azArg[0], "timeout", n)==0 && nArg==2 ){
open_db(p, 0);
sqlite3_busy_timeout(p->db, (int)integerValue(azArg[1]));
}else
if( HAS_TIMER && c=='t' && n>=5 && strncmp(azArg[0], "timer", n)==0
&& nArg==2
){
enableTimer = booleanValue(azArg[1]);
}else
if( c=='t' && strncmp(azArg[0], "trace", n)==0 && nArg>1 ){
open_db(p, 0);
output_file_close(p->traceOut);
p->traceOut = output_file_open(azArg[1]);
#if !defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_OMIT_FLOATING_POINT)
if( p->traceOut==0 ){
sqlite3_trace(p->db, 0, 0);
}else{
sqlite3_trace(p->db, sql_trace_callback, p->traceOut);
|
| ︙ | ︙ | |||
2875 2876 2877 2878 2879 2880 2881 |
break;
}
if( seenInterrupt ){
if( in!=0 ) break;
seenInterrupt = 0;
}
lineno++;
| | > > > | 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 |
break;
}
if( seenInterrupt ){
if( in!=0 ) break;
seenInterrupt = 0;
}
lineno++;
if( nSql==0 && _all_whitespace(zLine) ){
if( p->echoOn ) printf("%s\n", zLine);
continue;
}
if( zLine && zLine[0]=='.' && nSql==0 ){
if( p->echoOn ) printf("%s\n", zLine);
rc = do_meta_command(zLine, p);
if( rc==2 ){ /* exit requested */
break;
}else if( rc ){
errCnt++;
|
| ︙ | ︙ | |||
2914 2915 2916 2917 2918 2919 2920 |
zSql[nSql++] = '\n';
memcpy(zSql+nSql, zLine, nLine+1);
nSql += nLine;
}
if( nSql && line_contains_semicolon(&zSql[nSqlPrior], nSql-nSqlPrior)
&& sqlite3_complete(zSql) ){
p->cnt = 0;
| | | 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 |
zSql[nSql++] = '\n';
memcpy(zSql+nSql, zLine, nLine+1);
nSql += nLine;
}
if( nSql && line_contains_semicolon(&zSql[nSqlPrior], nSql-nSqlPrior)
&& sqlite3_complete(zSql) ){
p->cnt = 0;
open_db(p, 0);
BEGIN_TIMER;
rc = shell_exec(p->db, zSql, shell_callback, p, &zErrMsg);
END_TIMER;
if( rc || zErrMsg ){
char zPrefix[100];
if( in!=0 || !stdin_is_interactive ){
sqlite3_snprintf(sizeof(zPrefix), zPrefix,
|
| ︙ | ︙ | |||
2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 |
}else{
fprintf(stderr, "%s %s\n", zPrefix, sqlite3_errmsg(p->db));
}
errCnt++;
}
nSql = 0;
}else if( nSql && _all_whitespace(zSql) ){
nSql = 0;
}
}
if( nSql ){
if( !_all_whitespace(zSql) ){
fprintf(stderr, "Error: incomplete SQL: %s\n", zSql);
}
| > | 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 |
}else{
fprintf(stderr, "%s %s\n", zPrefix, sqlite3_errmsg(p->db));
}
errCnt++;
}
nSql = 0;
}else if( nSql && _all_whitespace(zSql) ){
if( p->echoOn ) printf("%s\n", zSql);
nSql = 0;
}
}
if( nSql ){
if( !_all_whitespace(zSql) ){
fprintf(stderr, "Error: incomplete SQL: %s\n", zSql);
}
|
| ︙ | ︙ | |||
3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 |
sqlite3_config(SQLITE_CONFIG_URI, 1);
sqlite3_config(SQLITE_CONFIG_LOG, shellLog, data);
sqlite3_snprintf(sizeof(mainPrompt), mainPrompt,"sqlite> ");
sqlite3_snprintf(sizeof(continuePrompt), continuePrompt," ...> ");
sqlite3_config(SQLITE_CONFIG_SINGLETHREAD);
}
/*
** Get the argument to an --option. Throw an error and die if no argument
** is available.
*/
static char *cmdline_option_value(int argc, char **argv, int i){
if( i==argc ){
fprintf(stderr, "%s: Error: missing argument to %s\n",
argv[0], argv[argc-1]);
exit(1);
}
return argv[i];
}
int main(int argc, char **argv){
char *zErrMsg = 0;
struct callback_data data;
const char *zInitFile = 0;
char *zFirstCmd = 0;
int i;
int rc = 0;
| > > > > > > > > > > > > > > > > > > > > > | | | | 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 |
sqlite3_config(SQLITE_CONFIG_URI, 1);
sqlite3_config(SQLITE_CONFIG_LOG, shellLog, data);
sqlite3_snprintf(sizeof(mainPrompt), mainPrompt,"sqlite> ");
sqlite3_snprintf(sizeof(continuePrompt), continuePrompt," ...> ");
sqlite3_config(SQLITE_CONFIG_SINGLETHREAD);
}
/*
** Output text to the console in a font that attracts extra attention.
*/
#ifdef _WIN32
static void printBold(const char *zText){
HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_SCREEN_BUFFER_INFO defaultScreenInfo;
GetConsoleScreenBufferInfo(out, &defaultScreenInfo);
SetConsoleTextAttribute(out,
FOREGROUND_RED|FOREGROUND_INTENSITY
);
printf("%s", zText);
SetConsoleTextAttribute(out, defaultScreenInfo.wAttributes);
}
#else
static void printBold(const char *zText){
printf("\033[1m%s\033[0m", zText);
}
#endif
/*
** Get the argument to an --option. Throw an error and die if no argument
** is available.
*/
static char *cmdline_option_value(int argc, char **argv, int i){
if( i==argc ){
fprintf(stderr, "%s: Error: missing argument to %s\n",
argv[0], argv[argc-1]);
exit(1);
}
return argv[i];
}
int main(int argc, char **argv){
char *zErrMsg = 0;
struct callback_data data;
const char *zInitFile = 0;
char *zFirstCmd = 0;
int i;
int rc = 0;
int warnInmemoryDb = 0;
if( sqlite3_libversion_number()<3008003 ){
fprintf(stderr, "Unsuitable SQLite version %s, must be at least 3.8.3",
sqlite3_libversion());
exit(1);
}
Argv0 = argv[0];
main_init(&data);
stdin_is_interactive = isatty(0);
/* Make sure we have a valid signal handler early, before anything
|
| ︙ | ︙ | |||
3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 |
exit(1);
}
}
}
if( data.zDbFilename==0 ){
#ifndef SQLITE_OMIT_MEMORYDB
data.zDbFilename = ":memory:";
#else
fprintf(stderr,"%s: Error: no database filename specified\n", Argv0);
return 1;
#endif
/***** Begin Fossil Patch *****/
{
extern void fossil_open(const char **);
fossil_open(&data.zDbFilename);
}
/***** End Fossil Patch *****/
}
data.out = stdout;
/* Go ahead and open the database file if it already exists. If the
** file does not exist, delay opening it. This prevents empty database
** files from being created if a user mistypes the database name argument
** to the sqlite command-line tool.
*/
if( access(data.zDbFilename, 0)==0 ){
| > > | | 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 |
exit(1);
}
}
}
if( data.zDbFilename==0 ){
#ifndef SQLITE_OMIT_MEMORYDB
data.zDbFilename = ":memory:";
warnInmemoryDb = argc==1;
#else
fprintf(stderr,"%s: Error: no database filename specified\n", Argv0);
return 1;
#endif
/***** Begin Fossil Patch *****/
{
extern void fossil_open(const char **);
fossil_open(&data.zDbFilename);
warnInmemoryDb = 0;
}
/***** End Fossil Patch *****/
}
data.out = stdout;
/* Go ahead and open the database file if it already exists. If the
** file does not exist, delay opening it. This prevents empty database
** files from being created if a user mistypes the database name argument
** to the sqlite command-line tool.
*/
if( access(data.zDbFilename, 0)==0 ){
open_db(&data, 0);
}
/* Process the initialization file if there is one. If no -init option
** is given on the command line, look for a file named ~/.sqliterc and
** try to process it.
*/
rc = process_sqliterc(&data,zInitFile);
|
| ︙ | ︙ | |||
3327 3328 3329 3330 3331 3332 3333 |
}else if( strcmp(z,"-cmd")==0 ){
if( i==argc-1 ) break;
z = cmdline_option_value(argc,argv,++i);
if( z[0]=='.' ){
rc = do_meta_command(z, &data);
if( rc && bail_on_error ) return rc==2 ? 0 : rc;
}else{
| | | 3738 3739 3740 3741 3742 3743 3744 3745 3746 3747 3748 3749 3750 3751 3752 |
}else if( strcmp(z,"-cmd")==0 ){
if( i==argc-1 ) break;
z = cmdline_option_value(argc,argv,++i);
if( z[0]=='.' ){
rc = do_meta_command(z, &data);
if( rc && bail_on_error ) return rc==2 ? 0 : rc;
}else{
open_db(&data, 0);
rc = shell_exec(data.db, z, shell_callback, &data, &zErrMsg);
if( zErrMsg!=0 ){
fprintf(stderr,"Error: %s\n", zErrMsg);
if( bail_on_error ) return rc!=0 ? rc : 1;
}else if( rc!=0 ){
fprintf(stderr,"Error: unable to process SQL \"%s\"\n", z);
if( bail_on_error ) return rc;
|
| ︙ | ︙ | |||
3351 3352 3353 3354 3355 3356 3357 |
if( zFirstCmd ){
/* Run just the command that follows the database name
*/
if( zFirstCmd[0]=='.' ){
rc = do_meta_command(zFirstCmd, &data);
if( rc==2 ) rc = 0;
}else{
| | | < > > > > > > | > | 3762 3763 3764 3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 |
if( zFirstCmd ){
/* Run just the command that follows the database name
*/
if( zFirstCmd[0]=='.' ){
rc = do_meta_command(zFirstCmd, &data);
if( rc==2 ) rc = 0;
}else{
open_db(&data, 0);
rc = shell_exec(data.db, zFirstCmd, shell_callback, &data, &zErrMsg);
if( zErrMsg!=0 ){
fprintf(stderr,"Error: %s\n", zErrMsg);
return rc!=0 ? rc : 1;
}else if( rc!=0 ){
fprintf(stderr,"Error: unable to process SQL \"%s\"\n", zFirstCmd);
return rc;
}
}
}else{
/* Run commands received from standard input
*/
if( stdin_is_interactive ){
char *zHome;
char *zHistory = 0;
int nHistory;
printf(
"SQLite version %s %.19s\n" /*extra-version-info*/
"Enter \".help\" for usage hints.\n",
sqlite3_libversion(), sqlite3_sourceid()
);
if( warnInmemoryDb ){
printf("Connected to a ");
printBold("transient in-memory database.");
printf("\nUse \".open FILENAME\" to reopen on a "
"persistent database.\n");
}
zHome = find_home_dir();
if( zHome ){
nHistory = strlen30(zHome) + 20;
if( (zHistory = malloc(nHistory))!=0 ){
sqlite3_snprintf(nHistory, zHistory,"%s/.sqlite_history", zHome);
}
}
#if defined(HAVE_READLINE)
if( zHistory ) read_history(zHistory);
#endif
rc = process_input(&data, 0);
if( zHistory ){
stifle_history(100);
write_history(zHistory);
free(zHistory);
}
}else{
rc = process_input(&data, stdin);
}
}
set_table_name(&data, 0);
if( data.db ){
sqlite3_close(data.db);
}
sqlite3_free(data.zFreeOnClose);
return rc;
}
|
Changes to src/skins.c.
| ︙ | ︙ | |||
115 116 117 118 119 120 121 122 123 124 125 126 127 128 |
@ div.content {
@ padding: 0ex 0ex 0ex 0ex;
@ }
@ /* Hyperlink colors */
@ div.content a { color: #604000; }
@ div.content a:link { color: #604000;}
@ div.content a:visited { color: #600000; }
@
@ /* Some pages have section dividers */
@ div.section {
@ margin-bottom: 0px;
@ margin-top: 1em;
@ padding: 1px 1px 1px 1px;
@ font-size: 1.2em;
| > > > > > > > | 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 |
@ div.content {
@ padding: 0ex 0ex 0ex 0ex;
@ }
@ /* Hyperlink colors */
@ div.content a { color: #604000; }
@ div.content a:link { color: #604000;}
@ div.content a:visited { color: #600000; }
@
@ /* <verbatim> blocks */
@ pre.verbatim {
@ background-color: #ffffff;
@ padding: 0.5em;
@ white-space: pre-wrap;
@ }
@
@ /* Some pages have section dividers */
@ div.section {
@ margin-bottom: 0px;
@ margin-top: 1em;
@ padding: 1px 1px 1px 1px;
@ font-size: 1.2em;
|
| ︙ | ︙ | |||
162 163 164 165 166 167 168 |
@ }');
@ REPLACE INTO config(name,mtime,value) VALUES('header',now(),'<html>
@ <head>
@ <base href="$baseurl/$current_page" />
@ <title>$<project_name>: $<title></title>
@ <link rel="alternate" type="application/rss+xml" title="RSS Feed"
@ href="$home/timeline.rss">
| | | | 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 |
@ }');
@ REPLACE INTO config(name,mtime,value) VALUES('header',now(),'<html>
@ <head>
@ <base href="$baseurl/$current_page" />
@ <title>$<project_name>: $<title></title>
@ <link rel="alternate" type="application/rss+xml" title="RSS Feed"
@ href="$home/timeline.rss">
@ <link rel="stylesheet" href="$stylesheet_url" type="text/css"
@ media="screen">
@ </head>
@ <body>
@ <div class="header">
@ <div class="title"><small>$<project_name></small><br />$<title></div>
@ <div class="status"><th1>
@ if {[info exists login]} {
@ puts "Logged in as $login"
@ } else {
@ puts "Not logged in"
@ }
@ </th1></div>
@ </div>
@ <div class="mainmenu">
@ <th1>
@ html "<a href=''$home$index_page''>Home</a>\n"
@ if {[anycap jor]} {
@ html "<a href=''$home/timeline''>Timeline</a>\n"
@ }
@ if {[hascap oh]} {
@ html "<a href=''$home/tree?ci=tip''>Files</a>\n"
@ }
@ if {[hascap o]} {
@ html "<a href=''$home/brlist''>Branches</a>\n"
@ html "<a href=''$home/taglist''>Tags</a>\n"
@ }
@ if {[hascap r]} {
@ html "<a href=''$home/reportlist''>Tickets</a>\n"
|
| ︙ | ︙ | |||
370 371 372 373 374 375 376 |
@ }');
@ REPLACE INTO config(name,mtime,value) VALUES('header',now(),'<html>
@ <head>
@ <base href="$baseurl/$current_page" />
@ <title>$<project_name>: $<title></title>
@ <link rel="alternate" type="application/rss+xml" title="RSS Feed"
@ href="$home/timeline.rss">
| | | 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 |
@ }');
@ REPLACE INTO config(name,mtime,value) VALUES('header',now(),'<html>
@ <head>
@ <base href="$baseurl/$current_page" />
@ <title>$<project_name>: $<title></title>
@ <link rel="alternate" type="application/rss+xml" title="RSS Feed"
@ href="$home/timeline.rss">
@ <link rel="stylesheet" href="$stylesheet_url" type="text/css"
@ media="screen">
@ </head>
@ <body>
@ <div class="header">
@ <div class="title">$<title></div>
@ <div class="status">
@ <div class="logo">$<project_name></div><br/>
|
| ︙ | ︙ | |||
393 394 395 396 397 398 399 |
@ <div class="mainmenu">
@ <th1>
@ html "<a href=''$home$index_page''>Home</a>\n"
@ if {[anycap jor]} {
@ html "<a href=''$home/timeline''>Timeline</a>\n"
@ }
@ if {[hascap oh]} {
| | | 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 |
@ <div class="mainmenu">
@ <th1>
@ html "<a href=''$home$index_page''>Home</a>\n"
@ if {[anycap jor]} {
@ html "<a href=''$home/timeline''>Timeline</a>\n"
@ }
@ if {[hascap oh]} {
@ html "<a href=''$home/tree?ci=tip''>Files</a>\n"
@ }
@ if {[hascap o]} {
@ html "<a href=''$home/brlist''>Branches</a>\n"
@ html "<a href=''$home/taglist''>Tags</a>\n"
@ }
@ if {[hascap r]} {
@ html "<a href=''$home/reportlist''>Tickets</a>\n"
|
| ︙ | ︙ | |||
611 612 613 614 615 616 617 |
@ }');
@ REPLACE INTO config(name,mtime,value) VALUES('header',now(),'<html>
@ <head>
@ <base href="$baseurl/$current_page" />
@ <title>$<project_name>: $<title></title>
@ <link rel="alternate" type="application/rss+xml" title="RSS Feed"
@ href="$home/timeline.rss">
| | | | | 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 |
@ }');
@ REPLACE INTO config(name,mtime,value) VALUES('header',now(),'<html>
@ <head>
@ <base href="$baseurl/$current_page" />
@ <title>$<project_name>: $<title></title>
@ <link rel="alternate" type="application/rss+xml" title="RSS Feed"
@ href="$home/timeline.rss">
@ <link rel="stylesheet" href="$stylesheet_url" type="text/css"
@ media="screen">
@ </head>
@ <body>
@ <div class="header">
@ <div class="logo">
@ <img src="$logo_image_url" alt="logo">
@ <br />$<project_name>
@ </div>
@ <div class="title">$<title></div>
@ <div class="status"><th1>
@ if {[info exists login]} {
@ puts "Logged in as $login"
@ } else {
@ puts "Not logged in"
@ }
@ </th1></div>
@ </div>
@ <div class="mainmenu">
@ <th1>
@ html "<a href=''$home$index_page''>Home</a>\n"
@ if {[anycap jor]} {
@ html "<a href=''$home/timeline''>Timeline</a>\n"
@ }
@ if {[hascap oh]} {
@ html "<a href=''$home/tree?ci=tip''>Files</a>\n"
@ }
@ if {[hascap o]} {
@ html "<a href=''$home/brlist''>Branches</a>\n"
@ html "<a href=''$home/taglist''>Tags</a>\n"
@ }
@ if {[hascap r]} {
@ html "<a href=''$home/reportlist''>Tickets</a>\n"
|
| ︙ | ︙ | |||
872 873 874 875 876 877 878 |
@ }');
@ REPLACE INTO config(name,mtime,value) VALUES('header',now(),'<html>
@ <head>
@ <base href="$baseurl/$current_page" />
@ <title>$<project_name>: $<title></title>
@ <link rel="alternate" type="application/rss+xml" title="RSS Feed"
@ href="$home/timeline.rss">
| | | | | 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 |
@ }');
@ REPLACE INTO config(name,mtime,value) VALUES('header',now(),'<html>
@ <head>
@ <base href="$baseurl/$current_page" />
@ <title>$<project_name>: $<title></title>
@ <link rel="alternate" type="application/rss+xml" title="RSS Feed"
@ href="$home/timeline.rss">
@ <link rel="stylesheet" href="$stylesheet_url" type="text/css"
@ media="screen">
@ </head>
@ <body>
@ <div class="header">
@ <div class="logo">
@ <img src="$logo_image_url" alt="logo">
@ <br />$<project_name>
@ </div>
@ <div class="title">$<title></div>
@ <div class="status"><th1>
@ if {[info exists login]} {
@ puts "Logged in as $login"
@ } else {
@ puts "Not logged in"
@ }
@ </th1></div>
@ </div>
@ <div class="mainmenu">
@ <th1>
@ html "<a href=''$home$index_page''>Home</a>\n"
@ if {[anycap jor]} {
@ html "<a href=''$home/timeline''>Timeline</a>\n"
@ }
@ if {[hascap oh]} {
@ html "<a href=''$home/tree?ci=tip''>Files</a>\n"
@ }
@ if {[hascap o]} {
@ html "<a href=''$home/brlist''>Branches</a>\n"
@ html "<a href=''$home/taglist''>Tags</a>\n"
@ }
@ if {[hascap r]} {
@ html "<a href=''$home/reportlist''>Tickets</a>\n"
|
| ︙ | ︙ | |||
1100 1101 1102 1103 1104 1105 1106 |
@ }');
@ REPLACE INTO config(name,mtime,value) VALUES('header',now(),'<html>
@ <head>
@ <base href="$baseurl/$current_page" />
@ <title>$<project_name>: $<title></title>
@ <link rel="alternate" type="application/rss+xml" title="RSS Feed"
@ href="$home/timeline.rss" />
| | | 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 |
@ }');
@ REPLACE INTO config(name,mtime,value) VALUES('header',now(),'<html>
@ <head>
@ <base href="$baseurl/$current_page" />
@ <title>$<project_name>: $<title></title>
@ <link rel="alternate" type="application/rss+xml" title="RSS Feed"
@ href="$home/timeline.rss" />
@ <link rel="stylesheet" href="$stylesheet_url" type="text/css"
@ media="screen" />
@ </head>
@ <body>
@ <div class="header">
@ <div class="logo">
@ <th1>
@ ##
|
| ︙ | ︙ | |||
1167 1168 1169 1170 1171 1172 1173 | @ set logourl $baseurl @ } @ return $logourl @ } @ set logourl [getLogoUrl $baseurl] @ </th1> @ <a href="$logourl"> | | | | 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 |
@ set logourl $baseurl
@ }
@ return $logourl
@ }
@ set logourl [getLogoUrl $baseurl]
@ </th1>
@ <a href="$logourl">
@ <img src="$logo_image_url" border="0" alt="$project_name">
@ </a>
@ </div>
@ <div class="title"><small>$<project_name></small><br />$<title></div>
@ <div class="status"><th1>
@ if {[info exists login]} {
@ puts "Logged in as $login"
@ } else {
@ puts "Not logged in"
@ }
@ </th1></div>
@ </div>
@ <div class="mainmenu">
@ <th1>
@ html "<a href=''$home$index_page''>Home</a>\n"
@ if {[anycap jor]} {
@ html "<a href=''$home/timeline''>Timeline</a>\n"
@ }
@ if {[hascap oh]} {
@ html "<a href=''$home/tree?ci=tip''>Files</a>\n"
@ }
@ if {[hascap o]} {
@ html "<a href=''$home/brlist''>Branches</a>\n"
@ html "<a href=''$home/taglist''>Tags</a>\n"
@ }
@ if {[hascap r]} {
@ html "<a href=''$home/reportlist''>Tickets</a>\n"
|
| ︙ | ︙ | |||
1232 1233 1234 1235 1236 1237 1238 |
@ set fossilUrl http://www.fossil-scm.org
@ </th1>
@ This page was generated in about
@ <th1>puts [expr {([utime]+[stime]+1000)/1000*0.001}]</th1>s by
@ <a href="$fossilUrl/">Fossil</a>
@ version $release_version $tclVersion
@ <a href="$fossilUrl/index.html/info/$version">$manifest_version</a>
| | | 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 |
@ set fossilUrl http://www.fossil-scm.org
@ </th1>
@ This page was generated in about
@ <th1>puts [expr {([utime]+[stime]+1000)/1000*0.001}]</th1>s by
@ <a href="$fossilUrl/">Fossil</a>
@ version $release_version $tclVersion
@ <a href="$fossilUrl/index.html/info/$version">$manifest_version</a>
@ <a href="$fossilUrl/index.html/timeline?c=$manifest_date&y=ci">$manifest_date</a>
@ </div>
@ </body></html>
@ ');
;
/*
** An array of available built-in skins.
|
| ︙ | ︙ |
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
|
| ︙ | ︙ | |||
122 123 124 125 126 127 128 |
sqlcmd_decompress, 0, 0);
re_add_sql_func(db);
g.repositoryOpen = 1;
g.db = db;
return SQLITE_OK;
}
| < | | 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 |
sqlcmd_decompress, 0, 0);
re_add_sql_func(db);
g.repositoryOpen = 1;
g.db = db;
return SQLITE_OK;
}
/*
** COMMAND: sqlite3
**
** Usage: %fossil sqlite3 ?DATABASE? ?OPTIONS?
**
** Run the standalone sqlite3 command-line shell on DATABASE with OPTIONS.
** 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 cmd_sqlite3(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.
more than 10,000 changes
Changes to src/sqlite3.h.
| ︙ | ︙ | |||
103 104 105 106 107 108 109 | ** string contains the date and time of the check-in (UTC) and an SHA1 ** hash of the entire source tree. ** ** See also: [sqlite3_libversion()], ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ | | | | | 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 | ** string contains the date and time of the check-in (UTC) and an SHA1 ** hash of the entire source tree. ** ** See also: [sqlite3_libversion()], ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ #define SQLITE_VERSION "3.8.3.1" #define SQLITE_VERSION_NUMBER 3008003 #define SQLITE_SOURCE_ID "2014-02-11 14:52:19 ea3317a4803d71d88183b29f1d3086f46d68a00e" /* ** CAPI3REF: Run-Time Library Version Numbers ** KEYWORDS: sqlite3_version, sqlite3_sourceid ** ** These interfaces provide the same information as the [SQLITE_VERSION], ** [SQLITE_VERSION_NUMBER], and [SQLITE_SOURCE_ID] C preprocessor macros |
| ︙ | ︙ | |||
366 367 368 369 370 371 372 | ** is not changed. ** ** Restrictions: ** ** <ul> ** <li> The application must insure that the 1st parameter to sqlite3_exec() ** is a valid and open [database connection]. | | | 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 | ** is not changed. ** ** Restrictions: ** ** <ul> ** <li> The application must insure that the 1st parameter to sqlite3_exec() ** is a valid and open [database connection]. ** <li> The application must not close the [database connection] specified by ** the 1st parameter to sqlite3_exec() while sqlite3_exec() is running. ** <li> The application must not modify the SQL statement text passed into ** the 2nd parameter of sqlite3_exec() while sqlite3_exec() is running. ** </ul> */ SQLITE_API int sqlite3_exec( sqlite3*, /* An open database */ |
| ︙ | ︙ | |||
443 444 445 446 447 448 449 | ** address this, newer versions of SQLite (version 3.3.8 and later) include ** support for additional result codes that provide more detailed information ** about errors. The extended result codes are enabled or disabled ** on a per database connection basis using the ** [sqlite3_extended_result_codes()] API. ** ** Some of the available extended result codes are listed here. | | | 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 | ** address this, newer versions of SQLite (version 3.3.8 and later) include ** support for additional result codes that provide more detailed information ** about errors. The extended result codes are enabled or disabled ** on a per database connection basis using the ** [sqlite3_extended_result_codes()] API. ** ** Some of the available extended result codes are listed here. ** One may expect the number of extended result codes will increase ** over time. Software that uses extended result codes should expect ** to see new result codes in future releases of SQLite. ** ** The SQLITE_OK result code will never be extended. It will always ** be exactly zero. */ #define SQLITE_IOERR_READ (SQLITE_IOERR | (1<<8)) |
| ︙ | ︙ | |||
487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 | #define SQLITE_CANTOPEN_ISDIR (SQLITE_CANTOPEN | (2<<8)) #define SQLITE_CANTOPEN_FULLPATH (SQLITE_CANTOPEN | (3<<8)) #define SQLITE_CANTOPEN_CONVPATH (SQLITE_CANTOPEN | (4<<8)) #define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1<<8)) #define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1<<8)) #define SQLITE_READONLY_CANTLOCK (SQLITE_READONLY | (2<<8)) #define SQLITE_READONLY_ROLLBACK (SQLITE_READONLY | (3<<8)) #define SQLITE_ABORT_ROLLBACK (SQLITE_ABORT | (2<<8)) #define SQLITE_CONSTRAINT_CHECK (SQLITE_CONSTRAINT | (1<<8)) #define SQLITE_CONSTRAINT_COMMITHOOK (SQLITE_CONSTRAINT | (2<<8)) #define SQLITE_CONSTRAINT_FOREIGNKEY (SQLITE_CONSTRAINT | (3<<8)) #define SQLITE_CONSTRAINT_FUNCTION (SQLITE_CONSTRAINT | (4<<8)) #define SQLITE_CONSTRAINT_NOTNULL (SQLITE_CONSTRAINT | (5<<8)) #define SQLITE_CONSTRAINT_PRIMARYKEY (SQLITE_CONSTRAINT | (6<<8)) #define SQLITE_CONSTRAINT_TRIGGER (SQLITE_CONSTRAINT | (7<<8)) #define SQLITE_CONSTRAINT_UNIQUE (SQLITE_CONSTRAINT | (8<<8)) #define SQLITE_CONSTRAINT_VTAB (SQLITE_CONSTRAINT | (9<<8)) #define SQLITE_NOTICE_RECOVER_WAL (SQLITE_NOTICE | (1<<8)) #define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2<<8)) #define SQLITE_WARNING_AUTOINDEX (SQLITE_WARNING | (1<<8)) /* ** CAPI3REF: Flags For File Open Operations ** | > > | 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 | #define SQLITE_CANTOPEN_ISDIR (SQLITE_CANTOPEN | (2<<8)) #define SQLITE_CANTOPEN_FULLPATH (SQLITE_CANTOPEN | (3<<8)) #define SQLITE_CANTOPEN_CONVPATH (SQLITE_CANTOPEN | (4<<8)) #define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1<<8)) #define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1<<8)) #define SQLITE_READONLY_CANTLOCK (SQLITE_READONLY | (2<<8)) #define SQLITE_READONLY_ROLLBACK (SQLITE_READONLY | (3<<8)) #define SQLITE_READONLY_DBMOVED (SQLITE_READONLY | (4<<8)) #define SQLITE_ABORT_ROLLBACK (SQLITE_ABORT | (2<<8)) #define SQLITE_CONSTRAINT_CHECK (SQLITE_CONSTRAINT | (1<<8)) #define SQLITE_CONSTRAINT_COMMITHOOK (SQLITE_CONSTRAINT | (2<<8)) #define SQLITE_CONSTRAINT_FOREIGNKEY (SQLITE_CONSTRAINT | (3<<8)) #define SQLITE_CONSTRAINT_FUNCTION (SQLITE_CONSTRAINT | (4<<8)) #define SQLITE_CONSTRAINT_NOTNULL (SQLITE_CONSTRAINT | (5<<8)) #define SQLITE_CONSTRAINT_PRIMARYKEY (SQLITE_CONSTRAINT | (6<<8)) #define SQLITE_CONSTRAINT_TRIGGER (SQLITE_CONSTRAINT | (7<<8)) #define SQLITE_CONSTRAINT_UNIQUE (SQLITE_CONSTRAINT | (8<<8)) #define SQLITE_CONSTRAINT_VTAB (SQLITE_CONSTRAINT | (9<<8)) #define SQLITE_CONSTRAINT_ROWID (SQLITE_CONSTRAINT |(10<<8)) #define SQLITE_NOTICE_RECOVER_WAL (SQLITE_NOTICE | (1<<8)) #define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2<<8)) #define SQLITE_WARNING_AUTOINDEX (SQLITE_WARNING | (1<<8)) /* ** CAPI3REF: Flags For File Open Operations ** |
| ︙ | ︙ | |||
553 554 555 556 557 558 559 | ** first then the size of the file is extended, never the other ** way around. The SQLITE_IOCAP_SEQUENTIAL property means that ** information is written to disk in the same order as calls ** to xWrite(). The SQLITE_IOCAP_POWERSAFE_OVERWRITE property means that ** after reboot following a crash or power loss, the only bytes in a ** file that were written at the application level might have changed ** and that adjacent bytes, even bytes within the same sector are | | > | 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 | ** first then the size of the file is extended, never the other ** way around. The SQLITE_IOCAP_SEQUENTIAL property means that ** information is written to disk in the same order as calls ** to xWrite(). The SQLITE_IOCAP_POWERSAFE_OVERWRITE property means that ** after reboot following a crash or power loss, the only bytes in a ** file that were written at the application level might have changed ** and that adjacent bytes, even bytes within the same sector are ** guaranteed to be unchanged. The SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN ** flag indicate that a file cannot be deleted when open. */ #define SQLITE_IOCAP_ATOMIC 0x00000001 #define SQLITE_IOCAP_ATOMIC512 0x00000002 #define SQLITE_IOCAP_ATOMIC1K 0x00000004 #define SQLITE_IOCAP_ATOMIC2K 0x00000008 #define SQLITE_IOCAP_ATOMIC4K 0x00000010 #define SQLITE_IOCAP_ATOMIC8K 0x00000020 |
| ︙ | ︙ | |||
784 785 786 787 788 789 790 | ** <li>[[SQLITE_FCNTL_FILE_POINTER]] ** The [SQLITE_FCNTL_FILE_POINTER] opcode is used to obtain a pointer ** to the [sqlite3_file] object associated with a particular database ** connection. See the [sqlite3_file_control()] documentation for ** additional information. ** ** <li>[[SQLITE_FCNTL_SYNC_OMITTED]] | > > > | | | < > | > > > > | | | > > > > > > > | | 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 | ** <li>[[SQLITE_FCNTL_FILE_POINTER]] ** The [SQLITE_FCNTL_FILE_POINTER] opcode is used to obtain a pointer ** to the [sqlite3_file] object associated with a particular database ** connection. See the [sqlite3_file_control()] documentation for ** additional information. ** ** <li>[[SQLITE_FCNTL_SYNC_OMITTED]] ** No longer in use. ** ** <li>[[SQLITE_FCNTL_SYNC]] ** The [SQLITE_FCNTL_SYNC] opcode is generated internally by SQLite and ** sent to the VFS immediately before the xSync method is invoked on a ** database file descriptor. Or, if the xSync method is not invoked ** because the user has configured SQLite with ** [PRAGMA synchronous | PRAGMA synchronous=OFF] it is invoked in place ** of the xSync method. In most cases, the pointer argument passed with ** this file-control is NULL. However, if the database file is being synced ** as part of a multi-database commit, the argument points to a nul-terminated ** string containing the transactions master-journal file name. VFSes that ** do not need this signal should silently ignore this opcode. Applications ** should not call [sqlite3_file_control()] with this opcode as doing so may ** disrupt the operation of the specialized VFSes that do require it. ** ** <li>[[SQLITE_FCNTL_COMMIT_PHASETWO]] ** The [SQLITE_FCNTL_COMMIT_PHASETWO] opcode is generated internally by SQLite ** and sent to the VFS after a transaction has been committed immediately ** but before the database is unlocked. VFSes that do not need this signal ** should silently ignore this opcode. Applications should not call ** [sqlite3_file_control()] with this opcode as doing so may disrupt the ** operation of the specialized VFSes that do require it. ** ** <li>[[SQLITE_FCNTL_WIN32_AV_RETRY]] ** ^The [SQLITE_FCNTL_WIN32_AV_RETRY] opcode is used to configure automatic ** retry counts and intervals for certain disk I/O operations for the ** windows [VFS] in order to provide robustness in the presence of ** anti-virus programs. By default, the windows VFS will retry file read, ** file write, and file delete operations up to 10 times, with a delay |
| ︙ | ︙ | |||
908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 | ** The argument is a pointer to a value of type sqlite3_int64 that ** is an advisory maximum number of bytes in the file to memory map. The ** pointer is overwritten with the old value. The limit is not changed if ** the value originally pointed to is negative, and so the current limit ** can be queried by passing in a pointer to a negative number. This ** file-control is used internally to implement [PRAGMA mmap_size]. ** ** </ul> */ #define SQLITE_FCNTL_LOCKSTATE 1 #define SQLITE_GET_LOCKPROXYFILE 2 #define SQLITE_SET_LOCKPROXYFILE 3 #define SQLITE_LAST_ERRNO 4 #define SQLITE_FCNTL_SIZE_HINT 5 #define SQLITE_FCNTL_CHUNK_SIZE 6 #define SQLITE_FCNTL_FILE_POINTER 7 #define SQLITE_FCNTL_SYNC_OMITTED 8 #define SQLITE_FCNTL_WIN32_AV_RETRY 9 #define SQLITE_FCNTL_PERSIST_WAL 10 #define SQLITE_FCNTL_OVERWRITE 11 #define SQLITE_FCNTL_VFSNAME 12 #define SQLITE_FCNTL_POWERSAFE_OVERWRITE 13 #define SQLITE_FCNTL_PRAGMA 14 #define SQLITE_FCNTL_BUSYHANDLER 15 #define SQLITE_FCNTL_TEMPFILENAME 16 #define SQLITE_FCNTL_MMAP_SIZE 18 /* ** CAPI3REF: Mutex Handle ** ** The mutex module within SQLite defines [sqlite3_mutex] to be an ** abstract type for a mutex object. The SQLite core never looks ** at the internal representation of an [sqlite3_mutex]. It only | > > > > > > > > > > > > > > > > > > | 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 | ** The argument is a pointer to a value of type sqlite3_int64 that ** is an advisory maximum number of bytes in the file to memory map. The ** pointer is overwritten with the old value. The limit is not changed if ** the value originally pointed to is negative, and so the current limit ** can be queried by passing in a pointer to a negative number. This ** file-control is used internally to implement [PRAGMA mmap_size]. ** ** <li>[[SQLITE_FCNTL_TRACE]] ** The [SQLITE_FCNTL_TRACE] file control provides advisory information ** to the VFS about what the higher layers of the SQLite stack are doing. ** This file control is used by some VFS activity tracing [shims]. ** The argument is a zero-terminated string. Higher layers in the ** SQLite stack may generate instances of this file control if ** the [SQLITE_USE_FCNTL_TRACE] compile-time option is enabled. ** ** <li>[[SQLITE_FCNTL_HAS_MOVED]] ** The [SQLITE_FCNTL_HAS_MOVED] file control interprets its argument as a ** pointer to an integer and it writes a boolean into that integer depending ** on whether or not the file has been renamed, moved, or deleted since it ** was first opened. ** ** </ul> */ #define SQLITE_FCNTL_LOCKSTATE 1 #define SQLITE_GET_LOCKPROXYFILE 2 #define SQLITE_SET_LOCKPROXYFILE 3 #define SQLITE_LAST_ERRNO 4 #define SQLITE_FCNTL_SIZE_HINT 5 #define SQLITE_FCNTL_CHUNK_SIZE 6 #define SQLITE_FCNTL_FILE_POINTER 7 #define SQLITE_FCNTL_SYNC_OMITTED 8 #define SQLITE_FCNTL_WIN32_AV_RETRY 9 #define SQLITE_FCNTL_PERSIST_WAL 10 #define SQLITE_FCNTL_OVERWRITE 11 #define SQLITE_FCNTL_VFSNAME 12 #define SQLITE_FCNTL_POWERSAFE_OVERWRITE 13 #define SQLITE_FCNTL_PRAGMA 14 #define SQLITE_FCNTL_BUSYHANDLER 15 #define SQLITE_FCNTL_TEMPFILENAME 16 #define SQLITE_FCNTL_MMAP_SIZE 18 #define SQLITE_FCNTL_TRACE 19 #define SQLITE_FCNTL_HAS_MOVED 20 #define SQLITE_FCNTL_SYNC 21 #define SQLITE_FCNTL_COMMIT_PHASETWO 22 /* ** CAPI3REF: Mutex Handle ** ** The mutex module within SQLite defines [sqlite3_mutex] to be an ** abstract type for a mutex object. The SQLite core never looks ** at the internal representation of an [sqlite3_mutex]. It only |
| ︙ | ︙ | |||
1371 1372 1373 1374 1375 1376 1377 | ** a memory allocation given a particular requested size. Most memory ** allocators round up memory allocations at least to the next multiple ** of 8. Some allocators round up to a larger multiple or to a power of 2. ** Every memory allocation request coming in through [sqlite3_malloc()] ** or [sqlite3_realloc()] first calls xRoundup. If xRoundup returns 0, ** that causes the corresponding memory allocation to fail. ** | | | 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 | ** a memory allocation given a particular requested size. Most memory ** allocators round up memory allocations at least to the next multiple ** of 8. Some allocators round up to a larger multiple or to a power of 2. ** Every memory allocation request coming in through [sqlite3_malloc()] ** or [sqlite3_realloc()] first calls xRoundup. If xRoundup returns 0, ** that causes the corresponding memory allocation to fail. ** ** The xInit method initializes the memory allocator. For example, ** it might allocate any require mutexes or initialize internal data ** structures. The xShutdown method is invoked (indirectly) by ** [sqlite3_shutdown()] and should deallocate any resources acquired ** by xInit. The pAppData pointer is used as the only parameter to ** xInit and xShutdown. ** ** SQLite holds the [SQLITE_MUTEX_STATIC_MASTER] mutex when it invokes |
| ︙ | ︙ | |||
1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 | ** either the [PRAGMA mmap_size] command, or by using the ** [SQLITE_FCNTL_MMAP_SIZE] file control. ^(The maximum allowed mmap size ** cannot be changed at run-time. Nor may the maximum allowed mmap size ** exceed the compile-time maximum mmap size set by the ** [SQLITE_MAX_MMAP_SIZE] compile-time option.)^ ** ^If either argument to this option is negative, then that argument is ** changed to its compile-time default. ** </dl> */ #define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */ #define SQLITE_CONFIG_MULTITHREAD 2 /* nil */ #define SQLITE_CONFIG_SERIALIZED 3 /* nil */ #define SQLITE_CONFIG_MALLOC 4 /* sqlite3_mem_methods* */ #define SQLITE_CONFIG_GETMALLOC 5 /* sqlite3_mem_methods* */ | > > > > > > > | 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 | ** either the [PRAGMA mmap_size] command, or by using the ** [SQLITE_FCNTL_MMAP_SIZE] file control. ^(The maximum allowed mmap size ** cannot be changed at run-time. Nor may the maximum allowed mmap size ** exceed the compile-time maximum mmap size set by the ** [SQLITE_MAX_MMAP_SIZE] compile-time option.)^ ** ^If either argument to this option is negative, then that argument is ** changed to its compile-time default. ** ** [[SQLITE_CONFIG_WIN32_HEAPSIZE]] ** <dt>SQLITE_CONFIG_WIN32_HEAPSIZE ** <dd>^This option is only available if SQLite is compiled for Windows ** with the [SQLITE_WIN32_MALLOC] pre-processor macro defined. ** SQLITE_CONFIG_WIN32_HEAPSIZE takes a 32-bit unsigned integer value ** that specifies the maximum size of the created heap. ** </dl> */ #define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */ #define SQLITE_CONFIG_MULTITHREAD 2 /* nil */ #define SQLITE_CONFIG_SERIALIZED 3 /* nil */ #define SQLITE_CONFIG_MALLOC 4 /* sqlite3_mem_methods* */ #define SQLITE_CONFIG_GETMALLOC 5 /* sqlite3_mem_methods* */ |
| ︙ | ︙ | |||
1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 | #define SQLITE_CONFIG_LOG 16 /* xFunc, void* */ #define SQLITE_CONFIG_URI 17 /* int */ #define SQLITE_CONFIG_PCACHE2 18 /* sqlite3_pcache_methods2* */ #define SQLITE_CONFIG_GETPCACHE2 19 /* sqlite3_pcache_methods2* */ #define SQLITE_CONFIG_COVERING_INDEX_SCAN 20 /* int */ #define SQLITE_CONFIG_SQLLOG 21 /* xSqllog, void* */ #define SQLITE_CONFIG_MMAP_SIZE 22 /* sqlite3_int64, sqlite3_int64 */ /* ** CAPI3REF: Database Connection Configuration Options ** ** These constants are the available integer configuration options that ** can be passed as the second argument to the [sqlite3_db_config()] interface. ** | > | 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 | #define SQLITE_CONFIG_LOG 16 /* xFunc, void* */ #define SQLITE_CONFIG_URI 17 /* int */ #define SQLITE_CONFIG_PCACHE2 18 /* sqlite3_pcache_methods2* */ #define SQLITE_CONFIG_GETPCACHE2 19 /* sqlite3_pcache_methods2* */ #define SQLITE_CONFIG_COVERING_INDEX_SCAN 20 /* int */ #define SQLITE_CONFIG_SQLLOG 21 /* xSqllog, void* */ #define SQLITE_CONFIG_MMAP_SIZE 22 /* sqlite3_int64, sqlite3_int64 */ #define SQLITE_CONFIG_WIN32_HEAPSIZE 23 /* int nByte */ /* ** CAPI3REF: Database Connection Configuration Options ** ** These constants are the available integer configuration options that ** can be passed as the second argument to the [sqlite3_db_config()] interface. ** |
| ︙ | ︙ | |||
1773 1774 1775 1776 1777 1778 1779 | ** codes are disabled by default for historical compatibility. */ SQLITE_API int sqlite3_extended_result_codes(sqlite3*, int onoff); /* ** CAPI3REF: Last Insert Rowid ** | > | | | | | | | > | 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 | ** codes are disabled by default for historical compatibility. */ SQLITE_API int sqlite3_extended_result_codes(sqlite3*, int onoff); /* ** CAPI3REF: Last Insert Rowid ** ** ^Each entry in most SQLite tables (except for [WITHOUT ROWID] tables) ** has a unique 64-bit signed ** integer key called the [ROWID | "rowid"]. ^The rowid is always available ** as an undeclared column named ROWID, OID, or _ROWID_ as long as those ** names are not also used by explicitly declared columns. ^If ** the table has a column of type [INTEGER PRIMARY KEY] then that column ** is another alias for the rowid. ** ** ^The sqlite3_last_insert_rowid(D) interface returns the [rowid] of the ** most recent successful [INSERT] into a rowid table or [virtual table] ** on database connection D. ** ^Inserts into [WITHOUT ROWID] tables are not recorded. ** ^If no successful [INSERT]s into rowid tables ** have ever occurred on the database connection D, ** then sqlite3_last_insert_rowid(D) returns zero. ** ** ^(If an [INSERT] occurs within a trigger or within a [virtual table] ** method, then this routine will return the [rowid] of the inserted ** row as long as the trigger or virtual table method is running. ** But once the trigger or virtual table method ends, the value returned ** by this routine reverts to what it was before the trigger or virtual ** table method began.)^ |
| ︙ | ︙ | |||
2351 2352 2353 2354 2355 2356 2357 2358 | ** SQLite contains a high-quality pseudo-random number generator (PRNG) used to ** select random [ROWID | ROWIDs] when inserting new records into a table that ** already uses the largest possible [ROWID]. The PRNG is also used for ** the build-in random() and randomblob() SQL functions. This interface allows ** applications to access the same PRNG for other purposes. ** ** ^A call to this routine stores N bytes of randomness into buffer P. ** | > | | | > | | 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 | ** SQLite contains a high-quality pseudo-random number generator (PRNG) used to ** select random [ROWID | ROWIDs] when inserting new records into a table that ** already uses the largest possible [ROWID]. The PRNG is also used for ** the build-in random() and randomblob() SQL functions. This interface allows ** applications to access the same PRNG for other purposes. ** ** ^A call to this routine stores N bytes of randomness into buffer P. ** ^If N is less than one, then P can be a NULL pointer. ** ** ^If this routine has not been previously called or if the previous ** call had N less than one, then the PRNG is seeded using randomness ** obtained from the xRandomness method of the default [sqlite3_vfs] object. ** ^If the previous call to this routine had an N of 1 or more then ** the pseudo-randomness is generated ** internally and without recourse to the [sqlite3_vfs] xRandomness ** method. */ SQLITE_API void sqlite3_randomness(int N, void *P); /* ** CAPI3REF: Compile-Time Authorization Callbacks |
| ︙ | ︙ | |||
2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 | #define SQLITE_REINDEX 27 /* Index Name NULL */ #define SQLITE_ANALYZE 28 /* Table Name NULL */ #define SQLITE_CREATE_VTABLE 29 /* Table Name Module Name */ #define SQLITE_DROP_VTABLE 30 /* Table Name Module Name */ #define SQLITE_FUNCTION 31 /* NULL Function Name */ #define SQLITE_SAVEPOINT 32 /* Operation Savepoint Name */ #define SQLITE_COPY 0 /* No longer used */ /* ** CAPI3REF: Tracing And Profiling Functions ** ** These routines register callback functions that can be used for ** tracing and profiling the execution of SQL statements. ** | > | 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 | #define SQLITE_REINDEX 27 /* Index Name NULL */ #define SQLITE_ANALYZE 28 /* Table Name NULL */ #define SQLITE_CREATE_VTABLE 29 /* Table Name Module Name */ #define SQLITE_DROP_VTABLE 30 /* Table Name Module Name */ #define SQLITE_FUNCTION 31 /* NULL Function Name */ #define SQLITE_SAVEPOINT 32 /* Operation Savepoint Name */ #define SQLITE_COPY 0 /* No longer used */ #define SQLITE_RECURSIVE 33 /* NULL NULL */ /* ** CAPI3REF: Tracing And Profiling Functions ** ** These routines register callback functions that can be used for ** tracing and profiling the execution of SQL statements. ** |
| ︙ | ︙ | |||
3095 3096 3097 3098 3099 3100 3101 | ** then the statement will be automatically recompiled, as if there had been ** a schema change, on the first [sqlite3_step()] call following any change ** to the [sqlite3_bind_text | bindings] of that [parameter]. ** ^The specific value of WHERE-clause [parameter] might influence the ** choice of query plan if the parameter is the left-hand side of a [LIKE] ** or [GLOB] operator or if the parameter is compared to an indexed column ** and the [SQLITE_ENABLE_STAT3] compile-time option is enabled. | < | 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 | ** then the statement will be automatically recompiled, as if there had been ** a schema change, on the first [sqlite3_step()] call following any change ** to the [sqlite3_bind_text | bindings] of that [parameter]. ** ^The specific value of WHERE-clause [parameter] might influence the ** choice of query plan if the parameter is the left-hand side of a [LIKE] ** or [GLOB] operator or if the parameter is compared to an indexed column ** and the [SQLITE_ENABLE_STAT3] compile-time option is enabled. ** </li> ** </ol> */ SQLITE_API int sqlite3_prepare( sqlite3 *db, /* Database handle */ const char *zSql, /* SQL statement, UTF-8 encoded */ int nByte, /* Maximum length of zSql in bytes. */ |
| ︙ | ︙ | |||
3757 3758 3759 3760 3761 3762 3763 | ** ** <blockquote> ** <table border="1"> ** <tr><th> Internal<br>Type <th> Requested<br>Type <th> Conversion ** ** <tr><td> NULL <td> INTEGER <td> Result is 0 ** <tr><td> NULL <td> FLOAT <td> Result is 0.0 | | | | | | | | | | 3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830 | ** ** <blockquote> ** <table border="1"> ** <tr><th> Internal<br>Type <th> Requested<br>Type <th> Conversion ** ** <tr><td> NULL <td> INTEGER <td> Result is 0 ** <tr><td> NULL <td> FLOAT <td> Result is 0.0 ** <tr><td> NULL <td> TEXT <td> Result is a NULL pointer ** <tr><td> NULL <td> BLOB <td> Result is a NULL pointer ** <tr><td> INTEGER <td> FLOAT <td> Convert from integer to float ** <tr><td> INTEGER <td> TEXT <td> ASCII rendering of the integer ** <tr><td> INTEGER <td> BLOB <td> Same as INTEGER->TEXT ** <tr><td> FLOAT <td> INTEGER <td> [CAST] to INTEGER ** <tr><td> FLOAT <td> TEXT <td> ASCII rendering of the float ** <tr><td> FLOAT <td> BLOB <td> [CAST] to BLOB ** <tr><td> TEXT <td> INTEGER <td> [CAST] to INTEGER ** <tr><td> TEXT <td> FLOAT <td> [CAST] to REAL ** <tr><td> TEXT <td> BLOB <td> No change ** <tr><td> BLOB <td> INTEGER <td> [CAST] to INTEGER ** <tr><td> BLOB <td> FLOAT <td> [CAST] to REAL ** <tr><td> BLOB <td> TEXT <td> Add a zero terminator if needed ** </table> ** </blockquote>)^ ** ** The table above makes reference to standard C library functions atoi() ** and atof(). SQLite does not really use these functions. It has its ** own equivalent internal routines. The atoi() and atof() names are |
| ︙ | ︙ | |||
3825 3826 3827 3828 3829 3830 3831 | ** sqlite3_column_bytes16(), and do not mix calls to sqlite3_column_text16() ** with calls to sqlite3_column_bytes(). ** ** ^The pointers returned are valid until a type conversion occurs as ** described above, or until [sqlite3_step()] or [sqlite3_reset()] or ** [sqlite3_finalize()] is called. ^The memory space used to hold strings ** and BLOBs is freed automatically. Do <b>not</b> pass the pointers returned | | | 3872 3873 3874 3875 3876 3877 3878 3879 3880 3881 3882 3883 3884 3885 3886 | ** sqlite3_column_bytes16(), and do not mix calls to sqlite3_column_text16() ** with calls to sqlite3_column_bytes(). ** ** ^The pointers returned are valid until a type conversion occurs as ** described above, or until [sqlite3_step()] or [sqlite3_reset()] or ** [sqlite3_finalize()] is called. ^The memory space used to hold strings ** and BLOBs is freed automatically. Do <b>not</b> pass the pointers returned ** from [sqlite3_column_blob()], [sqlite3_column_text()], etc. into ** [sqlite3_free()]. ** ** ^(If a memory allocation error occurs during the evaluation of any ** of these routines, a default value is returned. The default value ** is either the integer 0, the floating point number 0.0, or a NULL ** pointer. Subsequent calls to [sqlite3_errcode()] will return ** [SQLITE_NOMEM].)^ |
| ︙ | ︙ | |||
3934 3935 3936 3937 3938 3939 3940 | ** aggregate may take any number of arguments between 0 and the limit ** set by [sqlite3_limit]([SQLITE_LIMIT_FUNCTION_ARG]). If the third ** parameter is less than -1 or greater than 127 then the behavior is ** undefined. ** ** ^The fourth parameter, eTextRep, specifies what ** [SQLITE_UTF8 | text encoding] this SQL function prefers for | > | > | < | > | > < > | > > > > > > | 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 | ** aggregate may take any number of arguments between 0 and the limit ** set by [sqlite3_limit]([SQLITE_LIMIT_FUNCTION_ARG]). If the third ** parameter is less than -1 or greater than 127 then the behavior is ** undefined. ** ** ^The fourth parameter, eTextRep, specifies what ** [SQLITE_UTF8 | text encoding] this SQL function prefers for ** its parameters. The application should set this parameter to ** [SQLITE_UTF16LE] if the function implementation invokes ** [sqlite3_value_text16le()] on an input, or [SQLITE_UTF16BE] if the ** implementation invokes [sqlite3_value_text16be()] on an input, or ** [SQLITE_UTF16] if [sqlite3_value_text16()] is used, or [SQLITE_UTF8] ** otherwise. ^The same SQL function may be registered multiple times using ** different preferred text encodings, with different implementations for ** each encoding. ** ^When multiple implementations of the same function are available, SQLite ** will pick the one that involves the least amount of data conversion. ** ** ^The fourth parameter may optionally be ORed with [SQLITE_DETERMINISTIC] ** to signal that the function will always return the same result given ** the same inputs within a single SQL statement. Most SQL functions are ** deterministic. The built-in [random()] SQL function is an example of a ** function that is not deterministic. The SQLite query planner is able to ** perform additional optimizations on deterministic functions, so use ** of the [SQLITE_DETERMINISTIC] flag is recommended where possible. ** ** ^(The fifth parameter is an arbitrary pointer. The implementation of the ** function can gain access to this pointer using [sqlite3_user_data()].)^ ** ** ^The sixth, seventh and eighth parameters, xFunc, xStep and xFinal, are ** pointers to C-language functions that implement the SQL function or ** aggregate. ^A scalar SQL function requires an implementation of the xFunc |
| ︙ | ︙ | |||
4028 4029 4030 4031 4032 4033 4034 | ** These constant define integer codes that represent the various ** text encodings supported by SQLite. */ #define SQLITE_UTF8 1 #define SQLITE_UTF16LE 2 #define SQLITE_UTF16BE 3 #define SQLITE_UTF16 4 /* Use native byte order */ | | > > > > > > > > > > | 4084 4085 4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 | ** These constant define integer codes that represent the various ** text encodings supported by SQLite. */ #define SQLITE_UTF8 1 #define SQLITE_UTF16LE 2 #define SQLITE_UTF16BE 3 #define SQLITE_UTF16 4 /* Use native byte order */ #define SQLITE_ANY 5 /* Deprecated */ #define SQLITE_UTF16_ALIGNED 8 /* sqlite3_create_collation only */ /* ** CAPI3REF: Function Flags ** ** These constants may be ORed together with the ** [SQLITE_UTF8 | preferred text encoding] as the fourth argument ** to [sqlite3_create_function()], [sqlite3_create_function16()], or ** [sqlite3_create_function_v2()]. */ #define SQLITE_DETERMINISTIC 0x800 /* ** CAPI3REF: Deprecated Functions ** DEPRECATED ** ** These functions are [deprecated]. In order to maintain ** backwards compatibility with older code, these functions continue ** to be supported. However, new applications should avoid |
| ︙ | ︙ | |||
4802 4803 4804 4805 4806 4807 4808 | SQLITE_API void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*); /* ** CAPI3REF: Data Change Notification Callbacks ** ** ^The sqlite3_update_hook() interface registers a callback function ** with the [database connection] identified by the first argument | | > | > | 4868 4869 4870 4871 4872 4873 4874 4875 4876 4877 4878 4879 4880 4881 4882 4883 4884 4885 4886 4887 4888 4889 4890 4891 4892 4893 4894 4895 4896 4897 4898 4899 4900 4901 | SQLITE_API void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*); /* ** CAPI3REF: Data Change Notification Callbacks ** ** ^The sqlite3_update_hook() interface registers a callback function ** with the [database connection] identified by the first argument ** to be invoked whenever a row is updated, inserted or deleted in ** a rowid table. ** ^Any callback set by a previous call to this function ** for the same database connection is overridden. ** ** ^The second argument is a pointer to the function to invoke when a ** row is updated, inserted or deleted in a rowid table. ** ^The first argument to the callback is a copy of the third argument ** to sqlite3_update_hook(). ** ^The second callback argument is one of [SQLITE_INSERT], [SQLITE_DELETE], ** or [SQLITE_UPDATE], depending on the operation that caused the callback ** to be invoked. ** ^The third and fourth arguments to the callback contain pointers to the ** database and table name containing the affected row. ** ^The final callback parameter is the [rowid] of the row. ** ^In the case of an update, this is the [rowid] after the update takes place. ** ** ^(The update hook is not invoked when internal system tables are ** modified (i.e. sqlite_master and sqlite_sequence).)^ ** ^The update hook is not invoked when [WITHOUT ROWID] tables are modified. ** ** ^In the current implementation, the update hook ** is not invoked when duplication rows are deleted because of an ** [ON CONFLICT | ON CONFLICT REPLACE] clause. ^Nor is the update hook ** invoked when rows are deleted using the [truncate optimization]. ** The exceptions defined in this paragraph might change in a future ** release of SQLite. |
| ︙ | ︙ | |||
4901 4902 4903 4904 4905 4906 4907 | SQLITE_API int sqlite3_release_memory(int); /* ** CAPI3REF: Free Memory Used By A Database Connection ** ** ^The sqlite3_db_release_memory(D) interface attempts to free as much heap ** memory as possible from database connection D. Unlike the | | | | 4969 4970 4971 4972 4973 4974 4975 4976 4977 4978 4979 4980 4981 4982 4983 4984 | SQLITE_API int sqlite3_release_memory(int); /* ** CAPI3REF: Free Memory Used By A Database Connection ** ** ^The sqlite3_db_release_memory(D) interface attempts to free as much heap ** memory as possible from database connection D. Unlike the ** [sqlite3_release_memory()] interface, this interface is in effect even ** when the [SQLITE_ENABLE_MEMORY_MANAGEMENT] compile-time option is ** omitted. ** ** See also: [sqlite3_release_memory()] */ SQLITE_API int sqlite3_db_release_memory(sqlite3*); /* |
| ︙ | ︙ | |||
5277 5278 5279 5280 5281 5282 5283 | ** ^[sqlite3_free()] is used to free idxPtr if and only if ** needToFreeIdxPtr is true. ** ** ^The orderByConsumed means that output from [xFilter]/[xNext] will occur in ** the correct order to satisfy the ORDER BY clause so that no separate ** sorting step is required. ** | | > | > | | > > > > > > > > > > | 5345 5346 5347 5348 5349 5350 5351 5352 5353 5354 5355 5356 5357 5358 5359 5360 5361 5362 5363 5364 5365 5366 5367 5368 5369 5370 5371 5372 5373 5374 |
** ^[sqlite3_free()] is used to free idxPtr if and only if
** needToFreeIdxPtr is true.
**
** ^The orderByConsumed means that output from [xFilter]/[xNext] will occur in
** the correct order to satisfy the ORDER BY clause so that no separate
** sorting step is required.
**
** ^The estimatedCost value is an estimate of the cost of a particular
** strategy. A cost of N indicates that the cost of the strategy is similar
** to a linear scan of an SQLite table with N rows. A cost of log(N)
** indicates that the expense of the operation is similar to that of a
** binary search on a unique indexed field of an SQLite table with N rows.
**
** ^The estimatedRows value is an estimate of the number of rows that
** will be returned by the strategy.
**
** IMPORTANT: The estimatedRows field was added to the sqlite3_index_info
** structure for SQLite version 3.8.2. If a virtual table extension is
** used with an SQLite version earlier than 3.8.2, the results of attempting
** to read or write the estimatedRows field are undefined (but are likely
** to included crashing the application). The estimatedRows field should
** therefore only be used if [sqlite3_libversion_number()] returns a
** value greater than or equal to 3008002.
*/
struct sqlite3_index_info {
/* Inputs */
int nConstraint; /* Number of entries in aConstraint */
struct sqlite3_index_constraint {
int iColumn; /* Column on left-hand side of constraint */
unsigned char op; /* Constraint operator */
|
| ︙ | ︙ | |||
5305 5306 5307 5308 5309 5310 5311 |
int argvIndex; /* if >0, constraint is part of argv to xFilter */
unsigned char omit; /* Do not code a test for this constraint */
} *aConstraintUsage;
int idxNum; /* Number used to identify the index */
char *idxStr; /* String, possibly obtained from sqlite3_malloc */
int needToFreeIdxStr; /* Free idxStr using sqlite3_free() if true */
int orderByConsumed; /* True if output is already ordered */
| | > > | 5385 5386 5387 5388 5389 5390 5391 5392 5393 5394 5395 5396 5397 5398 5399 5400 5401 |
int argvIndex; /* if >0, constraint is part of argv to xFilter */
unsigned char omit; /* Do not code a test for this constraint */
} *aConstraintUsage;
int idxNum; /* Number used to identify the index */
char *idxStr; /* String, possibly obtained from sqlite3_malloc */
int needToFreeIdxStr; /* Free idxStr using sqlite3_free() if true */
int orderByConsumed; /* True if output is already ordered */
double estimatedCost; /* Estimated cost of using this index */
/* Fields below are only available in SQLite 3.8.2 and later */
sqlite3_int64 estimatedRows; /* Estimated number of rows returned */
};
/*
** CAPI3REF: Virtual Table Constraint Operator Codes
**
** These macros defined the allowed values for the
** [sqlite3_index_info].aConstraint[].op field. Each value represents
|
| ︙ | ︙ | |||
5509 5510 5511 5512 5513 5514 5515 5516 5517 5518 5519 5520 5521 5522 | ** commit if the transaction continues to completion.)^ ** ** ^Use the [sqlite3_blob_bytes()] interface to determine the size of ** the opened blob. ^The size of a blob may not be changed by this ** interface. Use the [UPDATE] SQL command to change the size of a ** blob. ** ** ^The [sqlite3_bind_zeroblob()] and [sqlite3_result_zeroblob()] interfaces ** and the built-in [zeroblob] SQL function can be used, if desired, ** to create an empty, zero-filled blob in which to read or write using ** this interface. ** ** To avoid a resource leak, every open [BLOB handle] should eventually ** be released by a call to [sqlite3_blob_close()]. | > > > | 5591 5592 5593 5594 5595 5596 5597 5598 5599 5600 5601 5602 5603 5604 5605 5606 5607 | ** commit if the transaction continues to completion.)^ ** ** ^Use the [sqlite3_blob_bytes()] interface to determine the size of ** the opened blob. ^The size of a blob may not be changed by this ** interface. Use the [UPDATE] SQL command to change the size of a ** blob. ** ** ^The [sqlite3_blob_open()] interface will fail for a [WITHOUT ROWID] ** table. Incremental BLOB I/O is not possible on [WITHOUT ROWID] tables. ** ** ^The [sqlite3_bind_zeroblob()] and [sqlite3_result_zeroblob()] interfaces ** and the built-in [zeroblob] SQL function can be used, if desired, ** to create an empty, zero-filled blob in which to read or write using ** this interface. ** ** To avoid a resource leak, every open [BLOB handle] should eventually ** be released by a call to [sqlite3_blob_close()]. |
| ︙ | ︙ | |||
6032 6033 6034 6035 6036 6037 6038 | #define SQLITE_TESTCTRL_ALWAYS 13 #define SQLITE_TESTCTRL_RESERVE 14 #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 | > | | 6117 6118 6119 6120 6121 6122 6123 6124 6125 6126 6127 6128 6129 6130 6131 6132 | #define SQLITE_TESTCTRL_ALWAYS 13 #define SQLITE_TESTCTRL_RESERVE 14 #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_LAST 20 /* ** 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);
|
| ︙ | ︙ | |||
309 310 311 312 313 314 315 |
int rid = db_column_int(&q, 0);
int isRemoved = db_column_int(&q, 1);
int isLink = db_column_int(&q, 3);
int isBin1, isBin2;
const char *zOrig = db_column_text(&q, 4);
const char *zNew = db_column_text(&q, 5);
char *zOPath = mprintf("%s%s", g.zLocalRoot, zOrig);
| | | 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 |
int rid = db_column_int(&q, 0);
int isRemoved = db_column_int(&q, 1);
int isLink = db_column_int(&q, 3);
int isBin1, isBin2;
const char *zOrig = db_column_text(&q, 4);
const char *zNew = db_column_text(&q, 5);
char *zOPath = mprintf("%s%s", g.zLocalRoot, zOrig);
Blob a, b;
if( rid==0 ){
db_ephemeral_blob(&q, 6, &a);
fossil_print("ADDED %s\n", zNew);
diff_print_index(zNew, diffFlags);
isBin1 = 0;
isBin2 = fIncludeBinary ? 0 : looks_like_binary(&a);
diff_file_mem(&empty, &a, isBin1, isBin2, zNew, zDiffCmd,
|
| ︙ | ︙ | |||
335 336 337 338 339 340 341 342 343 344 345 346 347 348 |
}
diff_print_index(zNew, diffFlags);
isBin1 = fIncludeBinary ? 0 : looks_like_binary(&a);
isBin2 = 0;
diff_file_mem(&a, &empty, isBin1, isBin2, zOrig, zDiffCmd,
zBinGlob, fIncludeBinary, diffFlags);
}else{
int isOrigLink = file_wd_islink(zOPath);
db_ephemeral_blob(&q, 6, &delta);
if( fBaseline==0 ){
if( isOrigLink ){
blob_read_link(&disk, zOPath);
}else{
blob_read_from_file(&disk, zOPath);
| > | 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 |
}
diff_print_index(zNew, diffFlags);
isBin1 = fIncludeBinary ? 0 : looks_like_binary(&a);
isBin2 = 0;
diff_file_mem(&a, &empty, isBin1, isBin2, zOrig, zDiffCmd,
zBinGlob, fIncludeBinary, diffFlags);
}else{
Blob delta, disk;
int isOrigLink = file_wd_islink(zOPath);
db_ephemeral_blob(&q, 6, &delta);
if( fBaseline==0 ){
if( isOrigLink ){
blob_read_link(&disk, zOPath);
}else{
blob_read_from_file(&disk, zOPath);
|
| ︙ | ︙ | |||
361 362 363 364 365 366 367 |
isBin2 = fIncludeBinary ? 0 : looks_like_binary(&b);
diff_file_mem(fBaseline? &a : &disk, &b, isBin1, isBin2, zNew,
zDiffCmd, zBinGlob, fIncludeBinary, diffFlags);
blob_reset(&a);
blob_reset(&b);
}
if( !fBaseline ) blob_reset(&disk);
| < | > | 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 |
isBin2 = fIncludeBinary ? 0 : looks_like_binary(&b);
diff_file_mem(fBaseline? &a : &disk, &b, isBin1, isBin2, zNew,
zDiffCmd, zBinGlob, fIncludeBinary, diffFlags);
blob_reset(&a);
blob_reset(&b);
}
if( !fBaseline ) blob_reset(&disk);
blob_reset(&delta);
}
}
db_finalize(&q);
}
/*
** Drop the indicated stash
*/
|
| ︙ | ︙ | |||
566 567 568 569 570 571 572 |
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;
| < | 567 568 569 570 571 572 573 574 575 576 577 578 579 580 |
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;
|
| ︙ | ︙ |
Changes to src/stat.c.
| ︙ | ︙ | |||
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. | > | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | ** http://www.hwaci.com/drh/ ** ******************************************************************************* ** ** This file contains code to implement the stat web page ** */ #include "VERSION.h" #include "config.h" #include <string.h> #include "stat.h" /* ** For a sufficiently large integer, provide an alternative ** representation as MB or GB or TB. |
| ︙ | ︙ | |||
53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
login_check_credentials();
if( !g.perm.Read ){ login_needed(); return; }
brief = P("brief")!=0;
style_header("Repository Statistics");
if( g.perm.Admin ){
style_submenu_element("URLs", "URLs and Checkouts", "urllist");
}
@ <table class="label-value">
@ <tr><th>Repository Size:</th><td>
fsize = file_size(g.zRepositoryName);
bigSizeName(sizeof(zBuf), zBuf, fsize);
@ %s(zBuf)
@ </td></tr>
| > | 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
login_check_credentials();
if( !g.perm.Read ){ login_needed(); return; }
brief = P("brief")!=0;
style_header("Repository Statistics");
if( g.perm.Admin ){
style_submenu_element("URLs", "URLs and Checkouts", "urllist");
style_submenu_element("Schema", "Repository Schema", "repo_schema");
}
@ <table class="label-value">
@ <tr><th>Repository Size:</th><td>
fsize = file_size(g.zRepositoryName);
bigSizeName(sizeof(zBuf), zBuf, fsize);
@ %s(zBuf)
@ </td></tr>
|
| ︙ | ︙ | |||
120 121 122 123 124 125 126 |
@ %d(n) days or approximately %.2f(n/365.2425) years.
@ </td></tr>
@ <tr><th>Project ID:</th><td>%h(db_get("project-code",""))</td></tr>
@ <tr><th>Fossil Version:</th><td>
@ %h(MANIFEST_DATE) %h(MANIFEST_VERSION)
@ (%h(RELEASE_VERSION)) [compiled using %h(COMPILER_NAME)]
@ </td></tr>
| | > > > | | 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 |
@ %d(n) days or approximately %.2f(n/365.2425) years.
@ </td></tr>
@ <tr><th>Project ID:</th><td>%h(db_get("project-code",""))</td></tr>
@ <tr><th>Fossil Version:</th><td>
@ %h(MANIFEST_DATE) %h(MANIFEST_VERSION)
@ (%h(RELEASE_VERSION)) [compiled using %h(COMPILER_NAME)]
@ </td></tr>
@ <tr><th>SQLite Version:</th><td>%.19s(sqlite3_sourceid())
@ [%.10s(&sqlite3_sourceid()[20])] (%s(sqlite3_libversion()))</td></tr>
@ <tr><th>Repository Rebuilt:</th><td>
@ %h(db_get_mtime("rebuilt","%Y-%m-%d %H:%M:%S","Never"))
@ By Fossil %h(db_get("rebuilt","Unknown"))</td></tr>
@ <tr><th>Database Stats:</th><td>
zDb = db_name("repository");
@ %d(db_int(0, "PRAGMA %s.page_count", zDb)) pages,
@ %d(db_int(0, "PRAGMA %s.page_size", zDb)) bytes/page,
@ %d(db_int(0, "PRAGMA %s.freelist_count", zDb)) free pages,
@ %s(db_text(0, "PRAGMA %s.encoding", zDb)),
@ %s(db_text(0, "PRAGMA %s.journal_mode", zDb)) mode
|
| ︙ | ︙ | |||
218 219 220 221 222 223 224 |
fossil_print("%*s%s\n", colWidth, "project-id:", db_get("project-code",""));
fossil_print("%*s%s %s [%s] (%s)\n",
colWidth, "fossil-version:",
MANIFEST_DATE, MANIFEST_VERSION, RELEASE_VERSION,
COMPILER_NAME);
fossil_print("%*s%.19s [%.10s] (%s)\n",
colWidth, "sqlite-version:",
| | | < < > | 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 |
fossil_print("%*s%s\n", colWidth, "project-id:", db_get("project-code",""));
fossil_print("%*s%s %s [%s] (%s)\n",
colWidth, "fossil-version:",
MANIFEST_DATE, MANIFEST_VERSION, RELEASE_VERSION,
COMPILER_NAME);
fossil_print("%*s%.19s [%.10s] (%s)\n",
colWidth, "sqlite-version:",
sqlite3_sourceid(), &sqlite3_sourceid()[20],
sqlite3_libversion());
zDb = db_name("repository");
fossil_print("%*s%d pages, %d bytes/pg, %d free pages, "
"%s, %s mode\n",
colWidth, "database-stats:",
db_int(0, "PRAGMA %s.page_count", zDb),
db_int(0, "PRAGMA %s.page_size", zDb),
db_int(0, "PRAGMA %s.freelist_count", zDb),
db_text(0, "PRAGMA %s.encoding", zDb),
db_text(0, "PRAGMA %s.journal_mode", zDb));
}
/*
** WEBPAGE: urllist
**
** Show ways in which this repository has been accessed
*/
void urllist_page(void){
Stmt q;
int cnt;
login_check_credentials();
if( !g.perm.Admin ){ login_needed(); return; }
style_header("URLs and Checkouts");
style_submenu_element("Stat", "Repository Stats", "stat");
style_submenu_element("Schema", "Repository Schema", "repo_schema");
@ <div class="section">URLs</div>
@ <table border="0" width='100%%'>
db_prepare(&q, "SELECT substr(name,9), datetime(mtime,'unixepoch')"
" FROM config WHERE name GLOB 'baseurl:*' ORDER BY 2 DESC");
cnt = 0;
while( db_step(&q)==SQLITE_ROW ){
@ <tr><td width='100%%'>%h(db_column_text(&q,0))</td>
|
| ︙ | ︙ | |||
279 280 281 282 283 284 285 |
db_finalize(&q);
if( cnt==0 ){
@ <tr><td>(none)</td>
}
@ </table>
style_footer();
}
| > > > > > > > > > > > > > > > > > > > > > > > > | 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 |
db_finalize(&q);
if( cnt==0 ){
@ <tr><td>(none)</td>
}
@ </table>
style_footer();
}
/*
** WEBPAGE: repo_schema
**
** Show the repository schema
*/
void repo_schema_page(void){
Stmt q;
login_check_credentials();
if( !g.perm.Admin ){ login_needed(); return; }
style_header("Repository Schema");
style_submenu_element("Stat", "Repository Stats", "stat");
style_submenu_element("URLs", "URLs and Checkouts", "urllist");
db_prepare(&q, "SELECT sql FROM %s.sqlite_master WHERE sql IS NOT NULL",
db_name("repository"));
@ <pre>
while( db_step(&q)==SQLITE_ROW ){
@ %h(db_column_text(&q, 0));
}
@ </pre>
db_finalize(&q);
style_footer();
}
|
Changes to src/style.c.
| ︙ | ︙ | |||
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(). | > | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | ** http://www.hwaci.com/drh/ ** ******************************************************************************* ** ** This file contains code to implement the basic web page look and feel. ** */ #include "VERSION.h" #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(). |
| ︙ | ︙ | |||
161 162 163 164 165 166 167 |
** 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;
| | < | 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>
@ 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 |
@ setTimeout("setAllHrefs();",%d(nDelay));
@ this.onmousemove = null;
@ }
}else{
/* Active hyperlinks right away */
@ setTimeout("setAllHrefs();",%d(nDelay));
}
| < | 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(
|
| ︙ | ︙ | |||
241 242 243 244 245 246 247 248 249 250 251 252 253 254 |
}else{
va_list ap;
va_start(ap, zFormat);
local_zCurrentPage = vmprintf(zFormat, ap);
va_end(ap);
}
}
/*
** Draw the header.
*/
void style_header(const char *zTitleFormat, ...){
va_list ap;
char *zTitle;
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 |
}else{
va_list ap;
va_start(ap, zFormat);
local_zCurrentPage = vmprintf(zFormat, ap);
va_end(ap);
}
}
/*
** Create a TH1 variable containing the URL for the specified config resource.
** The resulting variable name will be of the form $[zVarPrefix]_url.
*/
static void url_var(
const char *zVarPrefix,
const char *zConfigName,
const char *zPageName
){
char *zMtime = db_get_mtime(zConfigName, 0, 0);
char *zUrl = mprintf("%s/%s/%s%.5s", g.zTop, zPageName, zMtime,
MANIFEST_UUID);
char *zVarName = mprintf("%s_url", zVarPrefix);
Th_Store(zVarName, zUrl);
free(zMtime);
free(zUrl);
free(zVarName);
}
/*
** Create a TH1 variable containing the URL for the specified config image.
** The resulting variable name will be of the form $[zImageName]_image_url.
*/
static void image_url_var(const char *zImageName){
char *zVarPrefix = mprintf("%s_image", zImageName);
char *zConfigName = mprintf("%s-image", zImageName);
url_var(zVarPrefix, zConfigName, zImageName);
free(zVarPrefix);
free(zConfigName);
}
/*
** Draw the header.
*/
void style_header(const char *zTitleFormat, ...){
va_list ap;
char *zTitle;
|
| ︙ | ︙ | |||
273 274 275 276 277 278 279 280 281 282 283 284 285 286 |
Th_Store("index_page", db_get("index-page","/home"));
Th_Store("current_page", local_zCurrentPage ? local_zCurrentPage : g.zPath);
Th_Store("csrf_token", g.zCsrfToken);
Th_Store("release_version", RELEASE_VERSION);
Th_Store("manifest_version", MANIFEST_VERSION);
Th_Store("manifest_date", MANIFEST_DATE);
Th_Store("compiler_name", COMPILER_NAME);
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 */
| > > > | 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 |
Th_Store("index_page", db_get("index-page","/home"));
Th_Store("current_page", local_zCurrentPage ? local_zCurrentPage : g.zPath);
Th_Store("csrf_token", g.zCsrfToken);
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 */
|
| ︙ | ︙ | |||
404 405 406 407 408 409 410 | const char zDefaultHeader[] = @ <html> @ <head> @ <base href="$baseurl/$current_page" /> @ <title>$<project_name>: $<title></title> @ <link rel="alternate" type="application/rss+xml" title="RSS Feed" @ href="$home/timeline.rss" /> | | | | | 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 |
const char zDefaultHeader[] =
@ <html>
@ <head>
@ <base href="$baseurl/$current_page" />
@ <title>$<project_name>: $<title></title>
@ <link rel="alternate" type="application/rss+xml" title="RSS Feed"
@ href="$home/timeline.rss" />
@ <link rel="stylesheet" href="$stylesheet_url" type="text/css"
@ media="screen" />
@ </head>
@ <body>
@ <div class="header">
@ <div class="logo">
@ <img src="$logo_image_url" alt="logo" />
@ </div>
@ <div class="title"><small>$<project_name></small><br />$<title></div>
@ <div class="status"><th1>
@ if {[info exists login]} {
@ puts "Logged in as $login"
@ } else {
@ puts "Not logged in"
@ }
@ </th1></div>
@ </div>
@ <div class="mainmenu">
@ <th1>
@ html "<a href='$home$index_page'>Home</a>\n"
@ if {[anycap jor]} {
@ html "<a href='$home/timeline'>Timeline</a>\n"
@ }
@ if {[hascap oh]} {
@ html "<a href='$home/tree?ci=tip'>Files</a>\n"
@ }
@ if {[hascap o]} {
@ html "<a href='$home/brlist'>Branches</a>\n"
@ html "<a href='$home/taglist'>Tags</a>\n"
@ }
@ if {[hascap r]} {
@ html "<a href='$home/reportlist'>Tickets</a>\n"
|
| ︙ | ︙ | |||
735 736 737 738 739 740 741 742 743 744 745 746 747 748 |
},
{ "ul.browser",
"format for the list in the file browser",
@ margin-left: 0.5em;
@ padding-left: 0.5em;
@ white-space: nowrap;
},
{ "table.login_out",
"table format for login/out label/input table",
@ text-align: left;
@ margin-right: 10px;
@ margin-left: 10px;
@ margin-top: 10px;
},
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 |
},
{ "ul.browser",
"format for the list in the file browser",
@ margin-left: 0.5em;
@ padding-left: 0.5em;
@ white-space: nowrap;
},
{ ".filetree",
"tree-view file browser",
@ margin: 1em 0;
@ line-height: 1.5;
},
{ ".filetree ul",
"tree-view lists",
@ margin: 0;
@ padding: 0;
@ list-style: none;
},
{ ".filetree ul.collapsed",
"tree-view collapsed list",
@ display: 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;
@ margin: 0;
@ padding: 0;
},
{ ".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 li > ul:before",
"tree-view directory lines",
@ content: '';
@ position: absolute;
@ top: -1.5em;
@ bottom: 0;
@ left: -35px;
@ border-left: 2px solid #aaa;
},
{ ".filetree li.last > ul:before",
"hide lines for last-child directories",
@ display: none;
},
{ ".filetree a",
"tree-view links",
@ position: relative;
@ z-index: 1;
@ display: inline-block;
@ min-height: 16px;
@ padding-left: 21px;
@ background-image: url(data:image/gif;base64,R0lGODlhEAAQAJEAAP\/\/\/yEhIf\/\/\/wAAACH5BAEHAAIALAAAAAAQABAAAAIvlIKpxqcfmgOUvoaqDSCxrEEfF14GqFXImJZsu73wepJzVMNxrtNTj3NATMKhpwAAOw==);
@ background-position: center left;
@ background-repeat: no-repeat;
},
{ ".filetree .dir > a",
"tree-view directory links",
@ background-image: url(data:image/gif;base64,R0lGODlhEAAQAJEAAP/WVCIiIv\/\/\/wAAACH5BAEHAAIALAAAAAAQABAAAAInlI9pwa3XYniCgQtkrAFfLXkiFo1jaXpo+jUs6b5Z/K4siDu5RPUFADs=);
},
{ "table.login_out",
"table format for login/out label/input table",
@ text-align: left;
@ margin-right: 10px;
@ margin-left: 10px;
@ margin-top: 10px;
},
|
| ︙ | ︙ | |||
1057 1058 1059 1060 1061 1062 1063 |
{ "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",
| | < < < < | 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 |
{ "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 /reports 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-week-number-label",
"for the /stats_report views",
@ text-align: right;
@ font-size: 0.8em;
},
{ ".statistics-report-week-of-year-list",
"for the /stats_report views",
|
| ︙ | ︙ | |||
1112 1113 1114 1115 1116 1117 1118 |
*/
void cgi_append_default_css(void) {
int i;
for (i=0;cssDefaultList[i].elementClass;i++){
if (cssDefaultList[i].elementClass[0]){
cgi_printf("/* %s */\n%s {\n%s\n}\n\n",
| | | | | | | | 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 |
*/
void cgi_append_default_css(void) {
int i;
for (i=0;cssDefaultList[i].elementClass;i++){
if (cssDefaultList[i].elementClass[0]){
cgi_printf("/* %s */\n%s {\n%s\n}\n\n",
cssDefaultList[i].comment,
cssDefaultList[i].elementClass,
cssDefaultList[i].value
);
}else{
cgi_printf("%s",
cssDefaultList[i].value
);
}
}
}
/*
** WEBPAGE: style.css
*/
|
| ︙ | ︙ | |||
1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 |
}
/* Process through TH1 in order to give an opportunity to substitute
** variables such as $baseurl.
*/
Th_Store("baseurl", g.zBaseURL);
Th_Store("home", g.zTop);
Th_Render(blob_str(&css));
/* Tell CGI that the content returned by this page is considered cacheable */
g.isConst = 1;
}
/*
** WEBPAGE: test_env
*/
void page_test_env(void){
char c;
int i;
int showAll;
char zCap[30];
| > > | | 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 |
}
/* Process through TH1 in order to give an opportunity to substitute
** variables such as $baseurl.
*/
Th_Store("baseurl", g.zBaseURL);
Th_Store("home", g.zTop);
image_url_var("logo");
image_url_var("background");
Th_Render(blob_str(&css));
/* Tell CGI that the content returned by this page is considered cacheable */
g.isConst = 1;
}
/*
** WEBPAGE: test_env
*/
void page_test_env(void){
char c;
int i;
int showAll;
char zCap[30];
static const char *const 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",
};
|
| ︙ | ︙ |
Changes to src/sync.c.
| ︙ | ︙ | |||
52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
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();
}
#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
| > | 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
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
|
| ︙ | ︙ | |||
113 114 115 116 117 118 119 120 121 122 123 124 125 126 |
}else if( g.argc==3 ){
zUrl = g.argv[2];
}
if( urlFlags & URL_REMEMBER ){
clone_ssh_db_set_options();
}
url_parse(zUrl, urlFlags);
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) ){
| > | 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 |
}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) ){
|
| ︙ | ︙ | |||
260 261 262 263 264 265 266 |
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;
| | > | 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 |
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.
| ︙ | ︙ | |||
324 325 326 327 328 329 330 |
}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);
| | | 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 |
}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) );
}
/*
** COMMAND: tag
** Usage: %fossil tag SUBCOMMAND ...
**
|
| ︙ | ︙ | |||
593 594 595 596 597 598 599 |
" 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 />
| < < < < < < | 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();
}
|
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 350 |
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
&& strncmp(tball.zPrevDir, zName, i)==0
&& tball.zPrevDir[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)
|
| ︙ | ︙ | |||
425 426 427 428 429 430 431 |
int i;
Blob zip;
Blob file;
if( g.argc<3 ){
usage("ARCHIVE FILE....");
}
sqlite3_open(":memory:", &g.db);
| | | 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 |
int i;
Blob zip;
Blob file;
if( g.argc<3 ){
usage("ARCHIVE FILE....");
}
sqlite3_open(":memory:", &g.db);
tar_begin(-1);
for(i=3; i<g.argc; i++){
blob_zero(&file);
blob_read_from_file(&file, g.argv[i]);
tar_add_file(g.argv[i], &file,
file_wd_perm(g.argv[i]), file_wd_mtime(g.argv[i]));
blob_reset(&file);
}
|
| ︙ | ︙ |
Changes to src/th.c.
1 2 | /* | | | | 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 |
/*
** The implementation of the TH core. This file contains the parser, and
** the implementation of the interface in th.h.
*/
#include "config.h"
#include "th.h"
#include <string.h>
#include <assert.h>
typedef struct Th_Command Th_Command;
typedef struct Th_Frame Th_Frame;
typedef struct Th_Variable Th_Variable;
/*
** Interpreter structure.
*/
struct Th_Interp {
Th_Vtab *pVtab; /* Copy of the argument passed to Th_CreateInterp() */
char *zResult; /* Current interpreter result (Th_Malloc()ed) */
int nResult; /* number of bytes in zResult */
Th_Hash *paCmd; /* Table of registered commands */
Th_Frame *pFrame; /* Current execution frame */
int isListMode; /* True if thSplitList() should operate in "list" mode */
};
/*
|
| ︙ | ︙ | |||
40 41 42 43 44 45 46 | ** Each stack frame (variable scope) is represented by an instance ** of this structure. Variable values set using the Th_SetVar command ** are stored in the Th_Frame.paVar hash table member of the associated ** stack frame object. ** ** When an interpreter is created, a single Th_Frame structure is also ** allocated - the global variable scope. Th_Interp.pFrame (the current | | | | | | | | 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 |
** Each stack frame (variable scope) is represented by an instance
** of this structure. Variable values set using the Th_SetVar command
** are stored in the Th_Frame.paVar hash table member of the associated
** stack frame object.
**
** When an interpreter is created, a single Th_Frame structure is also
** allocated - the global variable scope. Th_Interp.pFrame (the current
** interpreter frame) is initialised to point to this Th_Frame. It is
** not deleted for the lifetime of the interpreter (because the global
** frame never goes out of scope).
**
** New stack frames are created by the Th_InFrame() function. Before
** invoking its callback function, Th_InFrame() allocates a new Th_Frame
** structure with pCaller set to the current frame (Th_Interp.pFrame),
** and sets the current frame to the new frame object. After the callback
** has been invoked, the allocated Th_Frame is deleted and the value
** of the current frame pointer restored.
**
** By default, the Th_SetVar(), Th_UnsetVar() and Th_GetVar() functions
** access variable values in the current frame. If they need to access
** the global frame, they do so by traversing the pCaller pointer list.
** Likewise, the Th_LinkVar() function uses the pCaller pointers to
** link to variables located in the global or other stack frames.
*/
struct Th_Frame {
Th_Hash *paVar; /* Variables defined in this scope */
Th_Frame *pCaller; /* Calling frame */
};
|
| ︙ | ︙ | |||
82 83 84 85 86 87 88 |
** a hash table mapping between array key name (a th1 string) and
** a pointer to the Th_Variable structure holding the scalar
** value.
*/
struct Th_Variable {
int nRef; /* Number of references to this structure */
int nData; /* Number of bytes at Th_Variable.zData */
| | | | | | | | | | | 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 |
** a hash table mapping between array key name (a th1 string) and
** a pointer to the Th_Variable structure holding the scalar
** value.
*/
struct Th_Variable {
int nRef; /* Number of references to this structure */
int nData; /* Number of bytes at Th_Variable.zData */
char *zData; /* Data for scalar variables */
Th_Hash *pHash; /* Data for array variables */
};
/*
** Hash table API:
*/
#define TH_HASHSIZE 257
struct Th_Hash {
Th_HashEntry *a[TH_HASHSIZE];
};
static int thEvalLocal(Th_Interp *, const char *, int);
static int thSplitList(Th_Interp*, const char*, int, char***, int **, int*);
static int thHexdigit(char c);
static int thEndOfLine(const char *, int);
static int thPushFrame(Th_Interp*, Th_Frame*);
static void thPopFrame(Th_Interp*);
static int thFreeVariable(Th_HashEntry*, void*);
static int thFreeCommand(Th_HashEntry*, void*);
/*
** The following are used by both the expression and language parsers.
** Given that the start of the input string (z, n) is a language
** construct of the relevant type (a command enclosed in [], an escape
** sequence etc.), these functions determine the number of bytes
** of the input consumed by the construct. For example:
**
** int nByte;
** thNextCommand(interp, "[expr $a+1] $nIter", 18, &nByte);
**
** results in variable nByte being set to 11. Or,
**
** thNextVarname(interp, "$a+1", 4, &nByte);
**
** 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
** the interpreter result.
*/
static int thSubstCommand(Th_Interp*, const char *z, int n);
static int thSubstEscape (Th_Interp*, const char *z, int n);
static int thSubstVarname(Th_Interp*, const char *z, int n);
/*
** Given that there is a th1 word located at the start of the input
** string (z, n), determine the length in bytes of that word. If the
** isCmd argument is non-zero, then an unescaped ";" byte not
** located inside of a block or quoted string is considered to mark
** the end of the word.
*/
static int thNextWord(Th_Interp*, const char *z, int n, int *pN, int isCmd);
/*
** Perform substitution on the word contained in the input string (z, n).
** Store the resulting string in the interpreter result.
|
| ︙ | ︙ | |||
174 175 176 177 178 179 180 | /* ** Append nAdd bytes of content copied from zAdd to the end of buffer ** pBuffer. If there is not enough space currently allocated, resize ** the allocation to make space. */ static int thBufferWrite( | | | | | 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 |
/*
** Append nAdd bytes of content copied from zAdd to the end of buffer
** pBuffer. If there is not enough space currently allocated, resize
** the allocation to make space.
*/
static int thBufferWrite(
Th_Interp *interp,
Buffer *pBuffer,
const char *zAdd,
int nAdd
){
int nReq;
if( nAdd<0 ){
nAdd = th_strlen(zAdd);
}
|
| ︙ | ︙ | |||
256 257 258 259 260 261 262 263 | /* ** Argument pEntry points to an entry in a stack frame hash table ** (Th_Frame.paVar). Decrement the reference count of the Th_Variable ** structure that the entry points to. Free the Th_Variable if its ** reference count reaches 0. ** ** Argument pContext is a pointer to the interpreter structure. */ | > > | > > > > > | > | 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 |
/*
** Argument pEntry points to an entry in a stack frame hash table
** (Th_Frame.paVar). Decrement the reference count of the Th_Variable
** structure that the entry points to. Free the Th_Variable if its
** reference count reaches 0.
**
** Argument pContext is a pointer to the interpreter structure.
**
** Returns non-zero if the Th_Variable was actually freed.
*/
static int thFreeVariable(Th_HashEntry *pEntry, void *pContext){
Th_Variable *pValue = (Th_Variable *)pEntry->pData;
pValue->nRef--;
assert( pValue->nRef>=0 );
if( pValue->nRef==0 ){
Th_Interp *interp = (Th_Interp *)pContext;
Th_Free(interp, pValue->zData);
if( pValue->pHash ){
Th_HashIterate(interp, pValue->pHash, thFreeVariable, pContext);
Th_HashDelete(interp, pValue->pHash);
}
Th_Free(interp, pValue);
pEntry->pData = 0;
return 1;
}
return 0;
}
/*
** Argument pEntry points to an entry in the command hash table
** (Th_Interp.paCmd). Delete the Th_Command structure that the
** entry points to.
**
** Argument pContext is a pointer to the interpreter structure.
**
** Always returns non-zero.
*/
static int thFreeCommand(Th_HashEntry *pEntry, void *pContext){
Th_Command *pCommand = (Th_Command *)pEntry->pData;
if( pCommand->xDel ){
pCommand->xDel((Th_Interp *)pContext, pCommand->pContext);
}
Th_Free((Th_Interp *)pContext, pEntry->pData);
pEntry->pData = 0;
return 1;
}
/*
** Push a new frame onto the stack.
*/
static int thPushFrame(Th_Interp *interp, Th_Frame *pFrame){
pFrame->paVar = Th_HashNew(interp);
|
| ︙ | ︙ | |||
309 310 311 312 313 314 315 | Th_Frame *pFrame = interp->pFrame; Th_HashIterate(interp, pFrame->paVar, thFreeVariable, (void *)interp); Th_HashDelete(interp, pFrame->paVar); interp->pFrame = pFrame->pCaller; } /* | | | | | 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 |
Th_Frame *pFrame = interp->pFrame;
Th_HashIterate(interp, pFrame->paVar, thFreeVariable, (void *)interp);
Th_HashDelete(interp, pFrame->paVar);
interp->pFrame = pFrame->pCaller;
}
/*
** The first part of the string (zInput,nInput) contains an escape
** sequence. Set *pnEscape to the number of bytes in the escape sequence.
** If there is a parse error, return TH_ERROR and set the interpreter
** result to an error message. Otherwise return TH_OK.
*/
static int thNextEscape(
Th_Interp *interp,
const char *zInput,
int nInput,
int *pnEscape
){
int i = 2;
assert(nInput>0);
assert(zInput[0]=='\\');
|
| ︙ | ︙ | |||
342 343 344 345 346 347 348 | } *pnEscape = i; return TH_OK; } /* ** The first part of the string (zInput,nInput) contains a variable | | | | | | 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 |
}
*pnEscape = i;
return TH_OK;
}
/*
** The first part of the string (zInput,nInput) contains a variable
** reference. Set *pnVarname to the number of bytes in the variable
** reference. If there is a parse error, return TH_ERROR and set the
** interpreter result to an error message. Otherwise return TH_OK.
*/
int thNextVarname(
Th_Interp *interp,
const char *zInput,
int nInput,
int *pnVarname
){
int i;
assert(nInput>0);
assert(zInput[0]=='$');
|
| ︙ | ︙ | |||
399 400 401 402 403 404 405 | *pnVarname = i; return TH_OK; } /* ** The first part of the string (zInput,nInput) contains a command | | | | | | | 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 |
*pnVarname = i;
return TH_OK;
}
/*
** The first part of the string (zInput,nInput) contains a command
** enclosed in a "[]" block. Set *pnCommand to the number of bytes in
** the variable reference. If there is a parse error, return TH_ERROR
** and set the interpreter result to an error message. Otherwise return
** TH_OK.
*/
int thNextCommand(
Th_Interp *interp,
const char *zInput,
int nInput,
int *pnCommand
){
int nBrace = 0;
int nSquare = 0;
int i;
assert(nInput>0);
|
| ︙ | ︙ | |||
436 437 438 439 440 441 442 | *pnCommand = i; return TH_OK; } /* | | | | | | | | | | 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 |
*pnCommand = i;
return TH_OK;
}
/*
** Set *pnSpace to the number of whitespace bytes at the start of
** input string (zInput, nInput). Always return TH_OK.
*/
int thNextSpace(
Th_Interp *interp,
const char *zInput,
int nInput,
int *pnSpace
){
int i;
for(i=0; i<nInput && th_isspace(zInput[i]); i++);
*pnSpace = i;
return TH_OK;
}
/*
** The first byte of the string (zInput,nInput) is not white-space.
** Set *pnWord to the number of bytes in the th1 word that starts
** with this byte. If a complete word cannot be parsed or some other
** error occurs, return TH_ERROR and set the interpreter result to
** an error message. Otherwise return TH_OK.
**
** If the isCmd argument is non-zero, then an unescaped ";" byte not
** located inside of a block or quoted string is considered to mark
** the end of the word.
*/
static int thNextWord(
Th_Interp *interp,
const char *zInput,
int nInput,
int *pnWord,
int isCmd
){
int iEnd = 0;
assert( !th_isspace(zInput[0]) );
|
| ︙ | ︙ | |||
529 530 531 532 533 534 535 | assert(nWord>=2); assert(zWord[0]=='[' && zWord[nWord-1]==']'); return thEvalLocal(interp, &zWord[1], nWord-2); } /* ** The input string (zWord, nWord) contains a th1 variable reference | | | | 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 |
assert(nWord>=2);
assert(zWord[0]=='[' && zWord[nWord-1]==']');
return thEvalLocal(interp, &zWord[1], nWord-2);
}
/*
** The input string (zWord, nWord) contains a th1 variable reference
** (a '$' byte followed by a variable name). Perform substitution on
** the input string and store the resulting string in the interpreter
** result.
*/
static int thSubstVarname(
Th_Interp *interp,
const char *zWord,
int nWord
){
|
| ︙ | ︙ | |||
570 571 572 573 574 575 576 |
}
}
return Th_GetVar(interp, &zWord[1], nWord-1);
}
/*
** The input string (zWord, nWord) contains a th1 escape sequence.
| | | 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 |
}
}
return Th_GetVar(interp, &zWord[1], nWord-1);
}
/*
** The input string (zWord, nWord) contains a th1 escape sequence.
** Perform substitution on the input string and store the resulting
** string in the interpreter result.
*/
static int thSubstEscape(
Th_Interp *interp,
const char *zWord,
int nWord
){
|
| ︙ | ︙ | |||
606 607 608 609 610 611 612 | Th_SetResult(interp, &c, 1); return TH_OK; } /* ** The input string (zWord, nWord) contains a th1 word. Perform | | | 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 |
Th_SetResult(interp, &c, 1);
return TH_OK;
}
/*
** The input string (zWord, nWord) contains a th1 word. Perform
** substitution on the input string and store the resulting
** string in the interpreter result.
*/
static int thSubstWord(
Th_Interp *interp,
const char *zWord,
int nWord
){
|
| ︙ | ︙ | |||
638 639 640 641 642 643 644 |
int nGet;
int (*xGet)(Th_Interp *, const char*, int, int *) = 0;
int (*xSubst)(Th_Interp *, const char*, int) = 0;
switch( zWord[i] ){
case '\\':
| | | | | 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 |
int nGet;
int (*xGet)(Th_Interp *, const char*, int, int *) = 0;
int (*xSubst)(Th_Interp *, const char*, int) = 0;
switch( zWord[i] ){
case '\\':
xGet = thNextEscape; xSubst = thSubstEscape;
break;
case '[':
if( !interp->isListMode ){
xGet = thNextCommand; xSubst = thSubstCommand;
break;
}
case '$':
if( !interp->isListMode ){
xGet = thNextVarname; xSubst = thSubstVarname;
break;
}
default: {
thBufferWrite(interp, &output, &zWord[i], 1);
continue; /* Go to the next iteration of the for(...) loop */
}
}
|
| ︙ | ︙ | |||
683 684 685 686 687 688 689 | /* ** Return true if one of the following is true of the buffer pointed ** to by zInput, length nInput: ** ** + It is empty, or ** + It contains nothing but white-space, or | | | 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 |
/*
** Return true if one of the following is true of the buffer pointed
** to by zInput, length nInput:
**
** + It is empty, or
** + It contains nothing but white-space, or
** + It contains no non-white-space characters before the first
** newline character.
**
** Otherwise return false.
*/
static int thEndOfLine(const char *zInput, int nInput){
int i;
for(i=0; i<nInput && zInput[i]!='\n' && th_isspace(zInput[i]); i++);
|
| ︙ | ︙ | |||
723 724 725 726 727 728 729 | ** Th_SplitList(interp, zList, nList, &argv, &argl, &argc); ** ** // Free all memory allocated by Th_SplitList(). The arrays pointed ** // to by argv and argl are invalidated by this call. ** // ** Th_Free(interp, argv); ** | | | | | 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 |
** Th_SplitList(interp, zList, nList, &argv, &argl, &argc);
**
** // Free all memory allocated by Th_SplitList(). The arrays pointed
** // to by argv and argl are invalidated by this call.
** //
** Th_Free(interp, argv);
**
*/
static int thSplitList(
Th_Interp *interp, /* Interpreter context */
const char *zList, /* Pointer to buffer containing input list */
int nList, /* Size of buffer pointed to by zList */
char ***pazElem, /* OUT: Array of list elements */
int **panElem, /* OUT: Lengths of each list element */
int *pnCount /* OUT: Number of list elements */
){
int rc = TH_OK;
Buffer strbuf;
Buffer lenbuf;
|
| ︙ | ︙ | |||
772 773 774 775 776 777 778 |
}
}
assert((lenbuf.nBuf/sizeof(int))==nCount);
assert((pazElem && panElem) || (!pazElem && !panElem));
if( pazElem && rc==TH_OK ){
int i;
| | | | | 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 |
}
}
assert((lenbuf.nBuf/sizeof(int))==nCount);
assert((pazElem && panElem) || (!pazElem && !panElem));
if( pazElem && rc==TH_OK ){
int i;
char *zElem;
int *anElem;
char **azElem = Th_Malloc(interp,
sizeof(char*) * nCount + /* azElem */
sizeof(int) * nCount + /* anElem */
strbuf.nBuf /* space for list element strings */
);
anElem = (int *)&azElem[nCount];
zElem = (char *)&anElem[nCount];
memcpy(anElem, lenbuf.zBuf, lenbuf.nBuf);
memcpy(zElem, strbuf.zBuf, strbuf.nBuf);
for(i=0; i<nCount;i++){
azElem[i] = zElem;
zElem += (anElem[i] + 1);
}
*pazElem = azElem;
*panElem = anElem;
}
if( pnCount ){
*pnCount = nCount;
}
finish:
thBufferFree(interp, &strbuf);
thBufferFree(interp, &lenbuf);
return rc;
}
/*
|
| ︙ | ︙ | |||
874 875 876 877 878 879 880 |
/* Call the command procedure. */
if( rc==TH_OK ){
Th_Command *p = (Th_Command *)(pEntry->pData);
const char **azArg = (const char **)argv;
rc = p->xProc(interp, p->pContext, argc, azArg, argl);
}
| | | | 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 |
/* Call the command procedure. */
if( rc==TH_OK ){
Th_Command *p = (Th_Command *)(pEntry->pData);
const char **azArg = (const char **)argv;
rc = p->xProc(interp, p->pContext, argc, azArg, argl);
}
/* If an error occurred, add this command to the stack trace report. */
if( rc==TH_ERROR ){
char *zRes;
int nRes;
char *zStack = 0;
int nStack = 0;
zRes = Th_TakeResult(interp, &nRes);
if( TH_OK==Th_GetVar(interp, (char *)"::th_stack_trace", -1) ){
zStack = Th_TakeResult(interp, &nStack);
}
Th_ListAppend(interp, &zStack, &nStack, zFirst, zInput-zFirst);
Th_SetVar(interp, (char *)"::th_stack_trace", -1, zStack, nStack);
Th_SetResult(interp, zRes, nRes);
|
| ︙ | ︙ | |||
910 911 912 913 914 915 916 | ** Th_Frame structure. If unsuccessful (no such frame), return 0 and ** leave an error message in the interpreter result. ** ** Argument iFrame is interpreted as follows: ** ** * If iFrame is 0, this means the current frame. ** | | | | | 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 |
** Th_Frame structure. If unsuccessful (no such frame), return 0 and
** leave an error message in the interpreter result.
**
** Argument iFrame is interpreted as follows:
**
** * If iFrame is 0, this means the current frame.
**
** * If iFrame is negative, then the nth frame up the stack, where
** n is the absolute value of iFrame. A value of -1 means the
** calling procedure.
**
** * If iFrame is +ve, then the nth frame from the bottom of the
** stack. An iFrame value of 1 means the toplevel (global) frame.
*/
static Th_Frame *getFrame(Th_Interp *interp, int iFrame){
Th_Frame *p = interp->pFrame;
int i;
if( iFrame>0 ){
for(i=0; p; i++){
|
| ︙ | ︙ | |||
946 947 948 949 950 951 952 | return p; } /* ** Evaluate th1 script (zProgram, nProgram) in the frame identified by ** argument iFrame. Leave either an error message or a result in the | | | | | 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 |
return p;
}
/*
** Evaluate th1 script (zProgram, nProgram) in the frame identified by
** argument iFrame. Leave either an error message or a result in the
** interpreter result and return a th1 error code (TH_OK, TH_ERROR,
** TH_RETURN, TH_CONTINUE or TH_BREAK).
*/
int Th_Eval(Th_Interp *interp, int iFrame, const char *zProgram, int nProgram){
int rc = TH_OK;
Th_Frame *pSavedFrame = interp->pFrame;
/* Set Th_Interp.pFrame to the frame that this script is to be
** evaluated in. The current frame is saved in pSavedFrame and will
** be restored before this function returns.
*/
interp->pFrame = getFrame(interp, iFrame);
if( !interp->pFrame ){
rc = TH_ERROR;
}else{
int nInput = nProgram;
if( nInput<0 ){
nInput = th_strlen(zProgram);
}
rc = thEvalLocal(interp, zProgram, nInput);
}
interp->pFrame = pSavedFrame;
|
| ︙ | ︙ | |||
993 994 995 996 997 998 999 | ** array variable. If the variable is a scalar, *pzInner is set to 0. ** If it is an array variable, (*pzInner, *pnInner) is set to the ** array key name. */ static int thAnalyseVarname( const char *zVarname, int nVarname, | | | | 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 |
** array variable. If the variable is a scalar, *pzInner is set to 0.
** If it is an array variable, (*pzInner, *pnInner) is set to the
** array key name.
*/
static int thAnalyseVarname(
const char *zVarname,
int nVarname,
const char **pzOuter, /* OUT: Pointer to scalar/array name */
int *pnOuter, /* OUT: Number of bytes at *pzOuter */
const char **pzInner, /* OUT: Pointer to array key (or null) */
int *pnInner, /* OUT: Number of bytes at *pzInner */
int *pisGlobal /* OUT: Set to true if this is a global ref */
){
const char *zOuter = zVarname;
int nOuter;
const char *zInner = 0;
int nInner = 0;
|
| ︙ | ︙ | |||
1040 1041 1042 1043 1044 1045 1046 1047 1048 | *pnOuter = nOuter; *pzInner = zInner; *pnInner = nInner; *pisGlobal = isGlobal; return TH_OK; } /* ** Input string (zVar, nVar) contains a variable name. This function locates | > > > > > > > > > > > > > > > | > | | | | > > > > > > > | > > > > | > > > > > > | > > | > | | | | > | | | | 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 |
*pnOuter = nOuter;
*pzInner = zInner;
*pnInner = nInner;
*pisGlobal = isGlobal;
return TH_OK;
}
/*
** The Find structure is used to return extra information to callers of the
** thFindValue function. The fields within it are populated by thFindValue
** as soon as the necessary information is available. Callers should check
** each field of interest upon return.
*/
struct Find {
Th_HashEntry *pValueEntry; /* Pointer to the scalar or array hash entry */
Th_HashEntry *pElemEntry; /* Pointer to array element hash entry, if any */
const char *zElem; /* Name of array element, if applicable */
int nElem; /* Length of array element name, if applicable */
};
typedef struct Find Find;
/*
** Input string (zVar, nVar) contains a variable name. This function locates
** the Th_Variable structure associated with the named variable. The
** variable name may be a global or local scalar or array variable
**
** If the create argument is non-zero and the named variable does not exist
** it is created. Otherwise, an error is left in the interpreter result
** and NULL returned.
**
** If the arrayok argument is false and the named variable is an array,
** an error is left in the interpreter result and NULL returned. If
** arrayok is true an array name is Ok.
*/
static Th_Variable *thFindValue(
Th_Interp *interp,
const char *zVar, /* Pointer to variable name */
int nVar, /* Number of bytes at nVar */
int create, /* If true, create the variable if not found */
int arrayok, /* If true, an array is Ok. Otherwise array==error */
int noerror, /* If false, set interpreter result to error */
Find *pFind /* If non-zero, place output here */
){
const char *zOuter;
int nOuter;
const char *zInner;
int nInner;
int isGlobal;
Th_HashEntry *pEntry;
Th_Frame *pFrame = interp->pFrame;
Th_Variable *pValue;
thAnalyseVarname(zVar, nVar, &zOuter, &nOuter, &zInner, &nInner, &isGlobal);
if( pFind ){
memset(pFind, 0, sizeof(Find));
pFind->zElem = zInner;
pFind->nElem = nInner;
}
if( isGlobal ){
while( pFrame->pCaller ) pFrame = pFrame->pCaller;
}
pEntry = Th_HashFind(interp, pFrame->paVar, zOuter, nOuter, create);
assert(pEntry || create<=0);
if( pFind ){
pFind->pValueEntry = pEntry;
}
if( !pEntry ){
goto no_such_var;
}
pValue = (Th_Variable *)pEntry->pData;
if( !pValue ){
assert(create);
pValue = Th_Malloc(interp, sizeof(Th_Variable));
pValue->nRef = 1;
pEntry->pData = (void *)pValue;
}
if( zInner ){
if( pValue->zData ){
if( !noerror ){
Th_ErrorMessage(interp, "variable is a scalar:", zOuter, nOuter);
}
return 0;
}
if( !pValue->pHash ){
if( !create ){
goto no_such_var;
}
pValue->pHash = Th_HashNew(interp);
}
pEntry = Th_HashFind(interp, pValue->pHash, zInner, nInner, create);
assert(pEntry || create<=0);
if( pFind ){
pFind->pElemEntry = pEntry;
}
if( !pEntry ){
goto no_such_var;
}
pValue = (Th_Variable *)pEntry->pData;
if( !pValue ){
assert(create);
pValue = Th_Malloc(interp, sizeof(Th_Variable));
pValue->nRef = 1;
pEntry->pData = (void *)pValue;
}
}else{
if( pValue->pHash && !arrayok ){
if( !noerror ){
Th_ErrorMessage(interp, "variable is an array:", zOuter, nOuter);
}
return 0;
}
}
return pValue;
no_such_var:
if( !noerror ){
Th_ErrorMessage(interp, "no such variable:", zVar, nVar);
}
return 0;
}
/*
** String (zVar, nVar) must contain the name of a scalar variable or
** array member. Look up the variable, store its current value in
** the interpreter result and return TH_OK.
**
** If the named variable does not exist, return TH_ERROR and leave
** an error message in the interpreter result.
*/
int Th_GetVar(Th_Interp *interp, const char *zVar, int nVar){
Th_Variable *pValue;
pValue = thFindValue(interp, zVar, nVar, 0, 0, 0, 0);
if( !pValue ){
return TH_ERROR;
}
if( !pValue->zData ){
Th_ErrorMessage(interp, "no such variable:", zVar, nVar);
return TH_ERROR;
}
return Th_SetResult(interp, pValue->zData, pValue->nData);
}
/*
** Return true if variable (zVar, nVar) exists.
*/
int Th_ExistsVar(Th_Interp *interp, const char *zVar, int nVar){
Th_Variable *pValue = thFindValue(interp, zVar, nVar, 0, 1, 1, 0);
return pValue && (pValue->zData || pValue->pHash);
}
/*
** String (zVar, nVar) must contain the name of a scalar variable or
** array member. If the variable does not exist it is created. The
** variable is set to the value supplied in string (zValue, nValue).
**
** If (zVar, nVar) refers to an existing array, TH_ERROR is returned
** and an error message left in the interpreter result.
*/
int Th_SetVar(
Th_Interp *interp,
const char *zVar,
int nVar,
const char *zValue,
int nValue
){
Th_Variable *pValue;
pValue = thFindValue(interp, zVar, nVar, 1, 0, 0, 0);
if( !pValue ){
return TH_ERROR;
}
if( nValue<0 ){
nValue = th_strlen(zValue);
}
|
| ︙ | ︙ | |||
1200 1201 1202 1203 1204 1205 1206 | /* ** Create a variable link so that accessing variable (zLocal, nLocal) is ** the same as accessing variable (zLink, nLink) in stack frame iFrame. */ int Th_LinkVar( Th_Interp *interp, /* Interpreter */ | | | | > > > | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | > | | | | | > > > > > > > > | | 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 |
/*
** Create a variable link so that accessing variable (zLocal, nLocal) is
** the same as accessing variable (zLink, nLink) in stack frame iFrame.
*/
int Th_LinkVar(
Th_Interp *interp, /* Interpreter */
const char *zLocal, int nLocal, /* Local varname */
int iFrame, /* Stack frame of linked var */
const char *zLink, int nLink /* Linked varname */
){
Th_Frame *pSavedFrame = interp->pFrame;
Th_Frame *pFrame;
Th_HashEntry *pEntry;
Th_Variable *pValue;
pFrame = getFrame(interp, iFrame);
if( !pFrame ){
return TH_ERROR;
}
pSavedFrame = interp->pFrame;
interp->pFrame = pFrame;
pValue = thFindValue(interp, zLink, nLink, 1, 1, 0, 0);
interp->pFrame = pSavedFrame;
pEntry = Th_HashFind(interp, interp->pFrame->paVar, zLocal, nLocal, 1);
if( pEntry->pData ){
Th_ErrorMessage(interp, "variable exists:", zLocal, nLocal);
return TH_ERROR;
}
pEntry->pData = (void *)pValue;
pValue->nRef++;
return TH_OK;
}
/*
** Input string (zVar, nVar) must contain the name of a scalar variable,
** an array, or an array member. If the identified variable exists, it
** is deleted and TH_OK returned. Otherwise, an error message is left
** in the interpreter result and TH_ERROR is returned.
*/
int Th_UnsetVar(Th_Interp *interp, const char *zVar, int nVar){
Find find;
Th_Variable *pValue;
Th_HashEntry *pEntry;
int rc = TH_ERROR;
pValue = thFindValue(interp, zVar, nVar, 0, 1, 0, &find);
if( !pValue ){
return rc;
}
if( pValue->zData || pValue->pHash ){
rc = TH_OK;
}else {
Th_ErrorMessage(interp, "no such variable:", zVar, nVar);
}
/*
** The variable may be shared by more than one frame; therefore, make sure
** it is actually freed prior to freeing the parent structure. The values
** for the variable must be freed now so the variable appears undefined in
** all frames. The hash entry in the current frame must also be deleted
** now; otherwise, if the current stack frame is later popped, it will try
** to delete a variable which has already been freed.
*/
if( find.zElem ){
pEntry = find.pElemEntry;
}else{
pEntry = find.pValueEntry;
}
assert( pEntry );
assert( pValue );
if( thFreeVariable(pEntry, (void *)interp) ){
if( find.zElem ){
Th_Variable *pValue2 = find.pValueEntry->pData;
Th_HashFind(interp, pValue2->pHash, find.zElem, find.nElem, -1);
}else if( pEntry->pData ){
Th_Free(interp, pEntry->pData);
pEntry->pData = 0;
}
}else{
if( pValue->zData ){
Th_Free(interp, pValue->zData);
pValue->zData = 0;
}
if( pValue->pHash ){
Th_HashIterate(interp, pValue->pHash, thFreeVariable, (void *)interp);
Th_HashDelete(interp, pValue->pHash);
pValue->pHash = 0;
}
if( find.zElem ){
Th_Variable *pValue2 = find.pValueEntry->pData;
Th_HashFind(interp, pValue2->pHash, find.zElem, find.nElem, -1);
}
}
if( !find.zElem ){
Th_HashFind(interp, interp->pFrame->paVar, zVar, nVar, -1);
}
return rc;
}
/*
** Return an allocated buffer containing a copy of string (z, n). The
** caller is responsible for eventually calling Th_Free() to free
** the returned buffer.
*/
|
| ︙ | ︙ | |||
1289 1290 1291 1292 1293 1294 1295 |
*/
int Th_ErrorMessage(Th_Interp *interp, const char *zPre, const char *z, int n){
if( interp ){
char *zRes = 0;
int nRes = 0;
Th_SetVar(interp, (char *)"::th_stack_trace", -1, 0, 0);
| | | 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 |
*/
int Th_ErrorMessage(Th_Interp *interp, const char *zPre, const char *z, int n){
if( interp ){
char *zRes = 0;
int nRes = 0;
Th_SetVar(interp, (char *)"::th_stack_trace", -1, 0, 0);
Th_StringAppend(interp, &zRes, &nRes, zPre, -1);
if( zRes[nRes-1]=='"' ){
Th_StringAppend(interp, &zRes, &nRes, z, n);
Th_StringAppend(interp, &zRes, &nRes, (const char *)"\"", 1);
}else{
Th_StringAppend(interp, &zRes, &nRes, (const char *)" ", 1);
Th_StringAppend(interp, &zRes, &nRes, z, n);
|
| ︙ | ︙ | |||
1371 1372 1373 1374 1375 1376 1377 |
return zResult;
}else{
return (char *)Th_Malloc(pInterp, 1);
}
}
| | | | | | 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 |
return zResult;
}else{
return (char *)Th_Malloc(pInterp, 1);
}
}
/*
** Wrappers around the supplied malloc() and free()
*/
void *Th_Malloc(Th_Interp *pInterp, int nByte){
void *p = pInterp->pVtab->xMalloc(nByte);
if( p ){
memset(p, 0, nByte);
}
return p;
}
void Th_Free(Th_Interp *pInterp, void *z){
if( z ){
pInterp->pVtab->xFree(z);
}
}
/*
** Install a new th1 command.
**
** If a command of the same name already exists, it is deleted automatically.
*/
int Th_CreateCommand(
Th_Interp *interp,
const char *zName, /* New command name */
Th_CommandProc xProc, /* Command callback proc */
void *pContext, /* Value to pass as second arg to xProc */
void (*xDel)(Th_Interp *, void *) /* Command destructor callback */
){
Th_HashEntry *pEntry;
Th_Command *pCommand;
|
| ︙ | ︙ | |||
1415 1416 1417 1418 1419 1420 1421 |
}else{
pCommand = Th_Malloc(interp, sizeof(Th_Command));
}
pCommand->xProc = xProc;
pCommand->pContext = pContext;
pCommand->xDel = xDel;
pEntry->pData = (void *)pCommand;
| | | | | | | | 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 |
}else{
pCommand = Th_Malloc(interp, sizeof(Th_Command));
}
pCommand->xProc = xProc;
pCommand->pContext = pContext;
pCommand->xDel = xDel;
pEntry->pData = (void *)pCommand;
return TH_OK;
}
/*
** Rename the existing command (zName, nName) to (zNew, nNew). If nNew is 0,
** the command is deleted instead of renamed.
**
** If successful, TH_OK is returned. If command zName does not exist, or
** if command zNew already exists, an error message is left in the
** interpreter result and TH_ERROR is returned.
*/
int Th_RenameCommand(
Th_Interp *interp,
const char *zName, /* Existing command name */
int nName, /* Number of bytes at zName */
const char *zNew, /* New command name */
int nNew /* Number of bytes at zNew */
){
Th_HashEntry *pEntry;
Th_HashEntry *pNewEntry;
pEntry = Th_HashFind(interp, interp->paCmd, zName, nName, 0);
if( !pEntry ){
|
| ︙ | ︙ | |||
1489 1490 1491 1492 1493 1494 1495 | ** Split a th1 list into its component elements. The list to split is ** passed via arguments (zList, nList). If successful, TH_OK is returned. ** If an error occurs (if (zList, nList) is not a valid list) an error ** message is left in the interpreter result and TH_ERROR returned. ** ** If successful, *pnCount is set to the number of elements in the list. ** panElem is set to point at an array of *pnCount integers - the lengths | | | 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 | ** Split a th1 list into its component elements. The list to split is ** passed via arguments (zList, nList). If successful, TH_OK is returned. ** If an error occurs (if (zList, nList) is not a valid list) an error ** message is left in the interpreter result and TH_ERROR returned. ** ** If successful, *pnCount is set to the number of elements in the list. ** panElem is set to point at an array of *pnCount integers - the lengths ** of the element values. *pazElem is set to point at an array of ** pointers to buffers containing the array element's data. ** ** To free the arrays allocated at *pazElem and *panElem, the caller ** should call Th_Free() on *pazElem only. Exactly one such call to ** Th_Free() must be made per call to Th_SplitList(). ** ** Example: |
| ︙ | ︙ | |||
1515 1516 1517 1518 1519 1520 1521 | ** } ** ** Th_Free(interp, azElem); ** */ int Th_SplitList( Th_Interp *interp, | | | | | | | | | 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 |
** }
**
** Th_Free(interp, azElem);
**
*/
int Th_SplitList(
Th_Interp *interp,
const char *zList, /* Pointer to buffer containing list */
int nList, /* Number of bytes at zList */
char ***pazElem, /* OUT: Array of pointers to element data */
int **panElem, /* OUT: Array of element data lengths */
int *pnCount /* OUT: Number of elements in list */
){
int rc;
interp->isListMode = 1;
rc = thSplitList(interp, zList, nList, pazElem, panElem, pnCount);
interp->isListMode = 0;
if( rc ){
Th_ErrorMessage(interp, "Expected list, got: \"", zList, nList);
}
return rc;
}
/*
** Append a new element to an existing th1 list. The element to append
** to the list is (zElem, nElem).
**
** A pointer to the existing list must be stored at *pzList when this
** function is called. The length must be stored in *pnList. The value
** of *pzList must either be NULL (in which case *pnList must be 0), or
** a pointer to memory obtained from Th_Malloc().
**
** This function calls Th_Free() to free the buffer at *pzList and sets
** *pzList to point to a new buffer containing the new list value. *pnList
** is similarly updated before returning. The return value is always TH_OK.
**
** Example:
**
** char *zList = 0;
** int nList = 0;
** for (...) {
** char *zElem = <some expression>;
** Th_ListAppend(interp, &zList, &nList, zElem, -1);
** }
** Th_SetResult(interp, zList, nList);
** Th_Free(interp, zList);
**
*/
int Th_ListAppend(
Th_Interp *interp, /* Interpreter context */
char **pzList, /* IN/OUT: Ptr to ptr to list */
int *pnList, /* IN/OUT: Current length of *pzList */
const char *zElem, /* Data to append */
int nElem /* Length of nElem */
){
Buffer output;
int i;
int hasSpecialChar = 0;
int hasEscapeChar = 0;
|
| ︙ | ︙ | |||
1613 1614 1615 1616 1617 1618 1619 | /* ** Append a new element to an existing th1 string. This function uses ** the same interface as the Th_ListAppend() function. */ int Th_StringAppend( Th_Interp *interp, /* Interpreter context */ | | | | 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 |
/*
** Append a new element to an existing th1 string. This function uses
** the same interface as the Th_ListAppend() function.
*/
int Th_StringAppend(
Th_Interp *interp, /* Interpreter context */
char **pzStr, /* IN/OUT: Ptr to ptr to list */
int *pnStr, /* IN/OUT: Current length of *pzStr */
const char *zElem, /* Data to append */
int nElem /* Length of nElem */
){
char *zNew;
int nNew;
if( nElem<0 ){
nElem = th_strlen(zElem);
|
| ︙ | ︙ | |||
1637 1638 1639 1640 1641 1642 1643 | Th_Free(interp, *pzStr); *pzStr = zNew; *pnStr = nNew; return TH_OK; } | | | | 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 |
Th_Free(interp, *pzStr);
*pzStr = zNew;
*pnStr = nNew;
return TH_OK;
}
/*
** Delete an interpreter.
*/
void Th_DeleteInterp(Th_Interp *interp){
assert(interp->pFrame);
assert(0==interp->pFrame->pCaller);
/* Delete the contents of the global frame. */
thPopFrame(interp);
/* Delete any result currently stored in the interpreter. */
Th_SetResult(interp, 0, 0);
/* Delete all registered commands and the command hash-table itself. */
Th_HashIterate(interp, interp->paCmd, thFreeCommand, (void *)interp);
Th_HashDelete(interp, interp->paCmd);
/* Delete the interpreter structure itself. */
Th_Free(interp, (void *)interp);
}
/*
** Create a new interpreter.
*/
Th_Interp * Th_CreateInterp(Th_Vtab *pVtab){
Th_Interp *p;
/* Allocate and initialise the interpreter and the global frame */
p = pVtab->xMalloc(sizeof(Th_Interp) + sizeof(Th_Frame));
|
| ︙ | ︙ | |||
1692 1693 1694 1695 1696 1697 1698 |
typedef struct Expr Expr;
struct Expr {
Operator *pOp;
Expr *pParent;
Expr *pLeft;
Expr *pRight;
| | | 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 |
typedef struct Expr Expr;
struct Expr {
Operator *pOp;
Expr *pParent;
Expr *pLeft;
Expr *pRight;
char *zValue; /* Pointer to literal value */
int nValue; /* Length of literal value buffer */
};
/* Unary operators */
#define OP_UNARY_MINUS 2
#define OP_UNARY_PLUS 3
#define OP_BITWISE_NOT 4
|
| ︙ | ︙ | |||
1748 1749 1750 1751 1752 1753 1754 |
/* Note: all unary operators have (iPrecedence==1) */
{"-", OP_UNARY_MINUS, 1, ARG_NUMBER},
{"+", OP_UNARY_PLUS, 1, ARG_NUMBER},
{"~", OP_BITWISE_NOT, 1, ARG_INTEGER},
{"!", OP_LOGICAL_NOT, 1, ARG_INTEGER},
/* Binary operators. It is important to the parsing in Th_Expr() that
| | | 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 |
/* Note: all unary operators have (iPrecedence==1) */
{"-", OP_UNARY_MINUS, 1, ARG_NUMBER},
{"+", OP_UNARY_PLUS, 1, ARG_NUMBER},
{"~", OP_BITWISE_NOT, 1, ARG_INTEGER},
{"!", OP_LOGICAL_NOT, 1, ARG_INTEGER},
/* Binary operators. It is important to the parsing in Th_Expr() that
* the two-character symbols ("==") appear before the one-character
* ones ("="). And that the priorities of all binary operators are
* integers between 2 and 12.
*/
{"<<", OP_LEFTSHIFT, 4, ARG_INTEGER},
{">>", OP_RIGHTSHIFT, 4, ARG_INTEGER},
{"<=", OP_LE, 5, ARG_NUMBER},
{">=", OP_GE, 5, ARG_NUMBER},
|
| ︙ | ︙ | |||
1779 1780 1781 1782 1783 1784 1785 |
{"|", OP_BITWISE_OR, 10, ARG_INTEGER},
{0,0,0,0}
};
/*
** The first part of the string (zInput,nInput) contains a number.
| | | | | | 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 |
{"|", 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;
|
| ︙ | ︙ | |||
1854 1855 1856 1857 1858 1859 1860 |
if( rc==TH_OK ){
eArgType = pExpr->pOp->eArgType;
if( eArgType==ARG_NUMBER ){
if( (zLeft==0 || TH_OK==Th_ToInt(0, zLeft, nLeft, &iLeft))
&& (zRight==0 || TH_OK==Th_ToInt(0, zRight, nRight, &iRight))
){
eArgType = ARG_INTEGER;
| | | | | > | | > | 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 |
if( rc==TH_OK ){
eArgType = pExpr->pOp->eArgType;
if( eArgType==ARG_NUMBER ){
if( (zLeft==0 || TH_OK==Th_ToInt(0, zLeft, nLeft, &iLeft))
&& (zRight==0 || TH_OK==Th_ToInt(0, zRight, nRight, &iRight))
){
eArgType = ARG_INTEGER;
}else if(
(zLeft && TH_OK!=Th_ToDouble(interp, zLeft, nLeft, &fLeft)) ||
(zRight && TH_OK!=Th_ToDouble(interp, zRight, nRight, &fRight))
){
/* A type error. */
rc = TH_ERROR;
}
}else if( eArgType==ARG_INTEGER ){
rc = Th_ToInt(interp, zLeft, nLeft, &iLeft);
if( rc==TH_OK && zRight ){
rc = Th_ToInt(interp, zRight, nRight, &iRight);
}
}
}
if( rc==TH_OK && eArgType==ARG_INTEGER ){
int iRes = 0;
switch( pExpr->pOp->eOp ) {
case OP_MULTIPLY: iRes = iLeft*iRight; break;
case OP_DIVIDE:
if( !iRight ){
Th_ErrorMessage(interp, "Divide by 0:", zLeft, nLeft);
rc = TH_ERROR;
goto finish;
}
iRes = iLeft/iRight;
break;
case OP_MODULUS:
if( !iRight ){
Th_ErrorMessage(interp, "Modulo by 0:", zLeft, nLeft);
rc = TH_ERROR;
goto finish;
}
iRes = iLeft%iRight;
break;
case OP_ADD: iRes = iLeft+iRight; break;
case OP_SUBTRACT: iRes = iLeft-iRight; break;
case OP_LEFTSHIFT: iRes = iLeft<<iRight; break;
case OP_RIGHTSHIFT: iRes = iLeft>>iRight; break;
|
| ︙ | ︙ | |||
1910 1911 1912 1913 1914 1915 1916 |
case OP_UNARY_PLUS: 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 ) {
| | > > > > > > | > | | | | | | | | > > > > | 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 |
case OP_UNARY_PLUS: 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;
case OP_UNARY_MINUS: Th_SetResultDouble(interp, -fLeft); break;
case OP_UNARY_PLUS: Th_SetResultDouble(interp, +fLeft); 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;
}
switch( pExpr->pOp->eOp ) {
case OP_SEQ: Th_SetResultInt(interp, iEqual); break;
case OP_SNE: Th_SetResultInt(interp, !iEqual); break;
default: assert(!"Internal error");
}
}
finish:
Th_Free(interp, zLeft);
Th_Free(interp, zRight);
}
return rc;
}
|
| ︙ | ︙ | |||
1957 1958 1959 1960 1961 1962 1963 |
assert(nToken>0);
#define ISTERM(x) (apToken[x] && (!apToken[x]->pOp || apToken[x]->pLeft))
for(jj=0; jj<nToken; jj++){
if( apToken[jj]->pOp && apToken[jj]->pOp->eOp==OP_OPEN_BRACKET ){
int nNest = 1;
| | | 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 |
assert(nToken>0);
#define ISTERM(x) (apToken[x] && (!apToken[x]->pOp || apToken[x]->pLeft))
for(jj=0; jj<nToken; jj++){
if( apToken[jj]->pOp && apToken[jj]->pOp->eOp==OP_OPEN_BRACKET ){
int nNest = 1;
int iLeft = jj;
for(jj++; jj<nToken; jj++){
Operator *pOp = apToken[jj]->pOp;
if( pOp && pOp->eOp==OP_OPEN_BRACKET ) nNest++;
if( pOp && pOp->eOp==OP_CLOSE_BRACKET ) nNest--;
if( nNest==0 ) break;
}
|
| ︙ | ︙ | |||
2031 2032 2033 2034 2035 2036 2037 | } /* ** Parse a string containing a TH expression to a list of tokens. */ static int exprParse( Th_Interp *interp, /* Interpreter to leave error message in */ | | | 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 |
}
/*
** Parse a string containing a TH expression to a list of tokens.
*/
static int exprParse(
Th_Interp *interp, /* Interpreter to leave error message in */
const char *zExpr, /* Pointer to input string */
int nExpr, /* Number of bytes at zExpr */
Expr ***papToken, /* OUT: Array of tokens. */
int *pnToken /* OUT: Size of token array */
){
int i;
int rc = TH_OK;
|
| ︙ | ︙ | |||
2106 2107 2108 2109 2110 2111 2112 |
assert( !pNew->pOp );
pNew->zValue = Th_Malloc(interp, pNew->nValue);
memcpy(pNew->zValue, z, pNew->nValue);
i += pNew->nValue;
}
if( (nToken%16)==0 ){
/* Grow the apToken array. */
| | | 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 |
assert( !pNew->pOp );
pNew->zValue = Th_Malloc(interp, pNew->nValue);
memcpy(pNew->zValue, z, pNew->nValue);
i += pNew->nValue;
}
if( (nToken%16)==0 ){
/* Grow the apToken array. */
Expr **apTokenOld = apToken;
apToken = Th_Malloc(interp, sizeof(Expr *)*(nToken+16));
memcpy(apToken, apTokenOld, sizeof(Expr *)*nToken);
}
/* Put the new token at the end of the apToken array */
apToken[nToken] = pNew;
nToken++;
|
| ︙ | ︙ | |||
2131 2132 2133 2134 2135 2136 2137 | } /* ** Evaluate the string (zExpr, nExpr) as a Th expression. Store ** the result in the interpreter interp and return TH_OK if ** successful. If an error occurs, store an error message in ** the interpreter result and return an error code. | | | | 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 |
}
/*
** Evaluate the string (zExpr, nExpr) as a Th expression. Store
** the result in the interpreter interp and return TH_OK if
** successful. If an error occurs, store an error message in
** the interpreter result and return an error code.
*/
int Th_Expr(Th_Interp *interp, const char *zExpr, int nExpr){
int rc; /* Return Code */
int i; /* Loop counter */
int nToken = 0;
Expr **apToken = 0;
if( nExpr<0 ){
nExpr = th_strlen(zExpr);
}
/* Parse the expression to a list of tokens. */
rc = exprParse(interp, zExpr, nExpr, &apToken, &nToken);
/* If the parsing was successful, create an expression tree from
** the parsed list of tokens. If successful, apToken[0] is set
** to point to the root of the expression tree.
*/
if( rc==TH_OK ){
rc = exprMakeTree(interp, apToken, nToken);
}
if( rc!=TH_OK ){
Th_ErrorMessage(interp, "syntax error in expression: \"", zExpr, nExpr);
|
| ︙ | ︙ | |||
2186 2187 2188 2189 2190 2191 2192 | return p; } /* ** Iterate through all values currently stored in the hash table. Invoke ** the callback function xCallback for each entry. The second argument ** passed to xCallback is a copy of the fourth argument passed to this | | > | | | | > | | | | 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 |
return p;
}
/*
** Iterate through all values currently stored in the hash table. Invoke
** the callback function xCallback for each entry. The second argument
** passed to xCallback is a copy of the fourth argument passed to this
** function. The return value from the callback function xCallback is
** ignored.
*/
void Th_HashIterate(
Th_Interp *interp,
Th_Hash *pHash,
int (*xCallback)(Th_HashEntry *pEntry, void *pContext),
void *pContext
){
int i;
for(i=0; i<TH_HASHSIZE; i++){
Th_HashEntry *pEntry;
Th_HashEntry *pNext;
for(pEntry=pHash->a[i]; pEntry; pEntry=pNext){
pNext = pEntry->pNext;
xCallback(pEntry, pContext);
}
}
}
/*
** Helper function for Th_HashDelete(). Always returns non-zero.
*/
static int xFreeHashEntry(Th_HashEntry *pEntry, void *pContext){
Th_Free((Th_Interp *)pContext, (void *)pEntry);
return 1;
}
/*
** Free a hash-table previously allocated by Th_HashNew().
*/
void Th_HashDelete(Th_Interp *interp, Th_Hash *pHash){
if( pHash ){
Th_HashIterate(interp, pHash, xFreeHashEntry, (void *)interp);
Th_Free(interp, pHash);
}
}
/*
** This function is used to insert or delete hash table items, or to
** query a hash table for an existing item.
**
** If parameter op is less than zero, then the hash-table element
** identified by (zKey, nKey) is removed from the hash-table if it
** exists. NULL is returned.
**
** Otherwise, if the hash-table contains an item with key (zKey, nKey),
** a pointer to the associated Th_HashEntry is returned. If parameter
** op is greater than zero, then a new entry is added if one cannot
** be found. If op is zero, then NULL is returned if the item is
** not already present in the hash-table.
*/
Th_HashEntry *Th_HashFind(
Th_Interp *interp,
Th_Hash *pHash,
const char *zKey,
int nKey,
int op /* -ve = delete, 0 = find, +ve = insert */
){
unsigned int iKey = 0;
int i;
|
| ︙ | ︙ | |||
2305 2306 2307 2308 2309 2310 2311 | ** '\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. | | | 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 |
** '\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
**
|
| ︙ | ︙ | |||
2456 2457 2458 2459 2460 2461 2462 | } *pResult = sign<0 ? -v1 : v1; return z - zBegin; } /* ** Try to convert the string passed as arguments (z, n) to an integer. | | | | | 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 |
}
*pResult = sign<0 ? -v1 : v1;
return z - zBegin;
}
/*
** Try to convert the string passed as arguments (z, n) to an integer.
** If successful, store the result in *piOut and return TH_OK.
**
** 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 ){
|
| ︙ | ︙ | |||
2491 2492 2493 2494 2495 2496 2497 | *piOut = iOut; return TH_OK; } /* ** Try to convert the string passed as arguments (z, n) to a double. | | | | | | | | 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 |
*piOut = iOut;
return TH_OK;
}
/*
** Try to convert the string passed as arguments (z, n) to a double.
** If successful, store the result in *pfOut and return TH_OK.
**
** If the string cannot be converted to a double, return TH_ERROR.
** If the interp argument is not NULL, leave an error message in the
** interpreter result too.
*/
int Th_ToDouble(
Th_Interp *interp,
const char *z,
int n,
double *pfOut
){
if( !sqlite3IsNumber((const char *)z, 0) ){
Th_ErrorMessage(interp, "expected number, got: \"", z, n);
return TH_ERROR;
}
|
| ︙ | ︙ | |||
2526 2527 2528 2529 2530 2531 2532 |
char *z = &zBuf[32];
if( iVal<0 ){
isNegative = 1;
iVal = iVal * -1;
}
*(--z) = '\0';
| | | | | | | | | | | 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 |
char *z = &zBuf[32];
if( iVal<0 ){
isNegative = 1;
iVal = iVal * -1;
}
*(--z) = '\0';
*(--z) = (char)(48+((unsigned)iVal%10));
while( (iVal = ((unsigned)iVal/10))>0 ){
*(--z) = (char)(48+((unsigned)iVal%10));
assert(z>zBuf);
}
if( isNegative ){
*(--z) = '-';
}
return Th_SetResult(interp, z, -1);
}
/*
** Set the result of the interpreter to the th1 representation of
** the double fVal and return TH_OK.
*/
int Th_SetResultDouble(Th_Interp *interp, double fVal){
int i; /* Iterator variable */
double v = fVal; /* Input value */
char zBuf[128]; /* Output buffer */
char *z = zBuf; /* Output cursor */
int iDot = 0; /* Digit after which to place decimal point */
int iExp = 0; /* Exponent (NN in eNN) */
const char *zExp; /* String representation of iExp */
/* Precision: */
#define INSIGNIFICANT 0.000000000001
#define ROUNDER 0.0000000000005
double insignificant = INSIGNIFICANT;
/* If the real value is negative, write a '-' character to the
* output and transform v to the corresponding positive number.
*/
if( v<0.0 ){
*z++ = '-';
v *= -1.0;
}
/* Normalize v to a value between 1.0 and 10.0. Integer
* variable iExp is set to the exponent. i.e the original
* value is (v * 10^iExp) (or the negative thereof).
*/
if( v>0.0 ){
while( (v+ROUNDER)>=10.0 ) { iExp++; v *= 0.1; }
while( (v+ROUNDER)<1.0 ) { iExp--; v *= 10.0; }
}
v += ROUNDER;
/* For a small (<12) positive exponent, move the decimal point
|
| ︙ | ︙ |
Changes to src/th.h.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
/* 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 *);
};
| > < | | | | | | | | | | | | | | | | | | | | | | | 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 |
/* 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.
*/
typedef struct Th_Vtab Th_Vtab;
struct Th_Vtab {
void *(*xMalloc)(unsigned int);
void (*xFree)(void *);
};
/*
** Opaque handle for interpeter.
*/
typedef struct Th_Interp Th_Interp;
/*
** Create and delete interpreters.
*/
Th_Interp * Th_CreateInterp(Th_Vtab *pVtab);
void Th_DeleteInterp(Th_Interp *);
/*
** Evaluate an TH program in the stack frame identified by parameter
** iFrame, according to the following rules:
**
** * If iFrame is 0, this means the current frame.
**
** * If iFrame is negative, then the nth frame up the stack, where n is
** the absolute value of iFrame. A value of -1 means the calling
** procedure.
**
** * If iFrame is +ve, then the nth frame from the bottom of the stack.
** An iFrame value of 1 means the toplevel (global) frame.
*/
int Th_Eval(Th_Interp *interp, int iFrame, const char *zProg, int nProg);
/*
** Evaluate a TH expression. The result is stored in the
** interpreter result.
*/
int Th_Expr(Th_Interp *interp, const char *, int);
/*
** Access TH variables in the current stack frame. If the variable name
** begins with "::", the lookup is in the top level (global) frame.
*/
int Th_ExistsVar(Th_Interp *, const char *, int);
int Th_GetVar(Th_Interp *, const char *, int);
int Th_SetVar(Th_Interp *, const char *, int, const char *, int);
int Th_LinkVar(Th_Interp *, const char *, int, int, const char *, int);
int Th_UnsetVar(Th_Interp *, const char *, int);
typedef int (*Th_CommandProc)(Th_Interp *, void *, int, const char **, int *);
/*
** Register new commands.
*/
int Th_CreateCommand(
Th_Interp *interp,
const char *zName,
/* int (*xProc)(Th_Interp *, void *, int, const char **, int *), */
Th_CommandProc xProc,
void *pContext,
void (*xDel)(Th_Interp *, void *)
);
/*
** Delete or rename commands.
*/
int Th_RenameCommand(Th_Interp *, const char *, int, const char *, int);
/*
** Push a new stack frame (local variable context) onto the interpreter
** stack, call the function supplied as parameter xCall with the two
** context arguments,
**
** xCall(interp, pContext1, pContext2)
**
** , then pop the frame off of the interpreter stack. The value returned
** by the xCall() function is returned as the result of this function.
**
** This is intended for use by the implementation of commands such as
** those created by [proc].
*/
int Th_InFrame(Th_Interp *interp,
int (*xCall)(Th_Interp *, void *pContext1, void *pContext2),
void *pContext1,
void *pContext2
);
/*
** Valid return codes for xProc callbacks.
*/
#define TH_OK 0
#define TH_ERROR 1
#define TH_BREAK 2
#define TH_RETURN 3
#define TH_CONTINUE 4
/*
** Set and get the interpreter result.
*/
int Th_SetResult(Th_Interp *, const char *, int);
const char *Th_GetResult(Th_Interp *, int *);
char *Th_TakeResult(Th_Interp *, int *);
/*
** Set an error message as the interpreter result. This also
** sets the global stack-trace variable $::th_stack_trace.
*/
int Th_ErrorMessage(Th_Interp *, const char *, const char *, int);
/*
** Access the memory management functions associated with the specified
** interpreter.
*/
void *Th_Malloc(Th_Interp *, int);
void Th_Free(Th_Interp *, void *);
/*
** Functions for handling TH lists.
*/
int Th_ListAppend(Th_Interp *, char **, int *, const char *, int);
int Th_SplitList(Th_Interp *, const char *, int, char ***, int **, int *);
int Th_StringAppend(Th_Interp *, char **, int *, const char *, int);
/*
** Functions for handling numbers and pointers.
*/
int Th_ToInt(Th_Interp *, const char *, int, int *);
int Th_ToDouble(Th_Interp *, const char *, int, double *);
int Th_SetResultInt(Th_Interp *, int);
int Th_SetResultDouble(Th_Interp *, double);
|
| ︙ | ︙ | |||
155 156 157 158 159 160 161 | */ int th_register_language(Th_Interp *interp); /* th_lang.c */ int th_register_sqlite(Th_Interp *interp); /* th_sqlite.c */ int th_register_vfs(Th_Interp *interp); /* th_vfs.c */ int th_register_testvfs(Th_Interp *interp); /* th_testvfs.c */ #ifdef FOSSIL_ENABLE_TCL | > > > | | > | | | | 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 |
*/
int th_register_language(Th_Interp *interp); /* th_lang.c */
int th_register_sqlite(Th_Interp *interp); /* th_sqlite.c */
int th_register_vfs(Th_Interp *interp); /* th_vfs.c */
int th_register_testvfs(Th_Interp *interp); /* th_testvfs.c */
#ifdef FOSSIL_ENABLE_TCL
/*
** Interfaces to the full Tcl core library from "th_tcl.c".
*/
int th_register_tcl(Th_Interp *, void *);
int unloadTcl(Th_Interp *, void *);
int evaluateTclWithEvents(Th_Interp *, void *, const char *, int, int);
#endif
/*
** General purpose hash table from th_lang.c.
*/
typedef struct Th_Hash Th_Hash;
typedef struct Th_HashEntry Th_HashEntry;
struct Th_HashEntry {
void *pData;
char *zKey;
int nKey;
Th_HashEntry *pNext; /* Internal use only */
};
Th_Hash *Th_HashNew(Th_Interp *);
void Th_HashDelete(Th_Interp *, Th_Hash *);
void Th_HashIterate(Th_Interp*,Th_Hash*,int (*x)(Th_HashEntry*, void*),void*);
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 {const char *zName; Th_CommandProc xProc;} Th_SubCommand;
int Th_CallSubCommand(Th_Interp*,void*,int,const char**,int*,const Th_SubCommand*);
|
Changes to src/th_lang.c.
1 2 | /* | | | | | | | | | | | | | | | | 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 |
/*
** This file contains the implementation of all of the TH language
** built-in commands.
**
** All built-in commands are implemented using the public interface
** declared in th.h, so this file serves as both a part of the language
** implementation and an example of how to extend the language with
** new commands.
*/
#include "config.h"
#include "th.h"
#include <string.h>
#include <assert.h>
int Th_WrongNumArgs(Th_Interp *interp, const char *zMsg){
Th_ErrorMessage(interp, "wrong # args: should be \"", zMsg, -1);
return TH_ERROR;
}
/*
** Syntax:
**
** catch script ?varname?
*/
static int catch_command(
Th_Interp *interp,
void *ctx,
int argc,
const char **argv,
int *argl
){
int rc;
if( argc!=2 && argc!=3 ){
return Th_WrongNumArgs(interp, "catch script ?varname?");
}
rc = Th_Eval(interp, 0, argv[1], -1);
if( argc==3 ){
int nResult;
const char *zResult = Th_GetResult(interp, &nResult);
Th_SetVar(interp, argv[2], argl[2], zResult, nResult);
}
Th_SetResultInt(interp, rc);
return TH_OK;
}
/*
** TH Syntax:
**
** if expr1 body1 ?elseif expr2 body2? ? ?else? bodyN?
*/
static int if_command(
Th_Interp *interp,
void *ctx,
int argc,
const char **argv,
int *argl
){
int rc = TH_OK;
int iCond; /* Result of evaluating expression */
int i;
|
| ︙ | ︙ | |||
92 93 94 95 96 97 98 | return rc; wrong_args: return Th_WrongNumArgs(interp, "if ..."); } /* | | | | | | | | | | | | | | | | | | | | | | | | | 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 |
return rc;
wrong_args:
return Th_WrongNumArgs(interp, "if ...");
}
/*
** TH Syntax:
**
** expr expr
*/
static int expr_command(
Th_Interp *interp,
void *ctx,
int argc,
const char **argv,
int *argl
){
if( argc!=2 ){
return Th_WrongNumArgs(interp, "expr expression");
}
return Th_Expr(interp, argv[1], argl[1]);
}
/*
** Evaluate the th1 script (zBody, nBody) in the local stack frame.
** Return the result of the evaluation, except if the result
** is TH_CONTINUE, return TH_OK instead.
*/
static int eval_loopbody(Th_Interp *interp, const char *zBody, int nBody){
int rc = Th_Eval(interp, 0, zBody, nBody);
if( rc==TH_CONTINUE ){
rc = TH_OK;
}
return rc;
}
/*
** TH Syntax:
**
** for init condition incr script
*/
static int for_command(
Th_Interp *interp,
void *ctx,
int argc,
const char **argv,
int *argl
){
int rc;
int iCond;
if( argc!=5 ){
return Th_WrongNumArgs(interp, "for init condition incr script");
}
/* Evaluate the 'init' script */
rc = Th_Eval(interp, 0, argv[1], -1);
while( rc==TH_OK
&& TH_OK==(rc = Th_Expr(interp, argv[2], -1))
&& TH_OK==(rc = Th_ToInt(interp, Th_GetResult(interp, 0), -1, &iCond))
&& iCond
&& TH_OK==(rc = eval_loopbody(interp, argv[4], argl[4]))
){
rc = Th_Eval(interp, 0, argv[3], -1);
}
if( rc==TH_BREAK ) rc = TH_OK;
return rc;
}
/*
** TH Syntax:
**
** list ?arg1 ?arg2? ...?
*/
static int list_command(
Th_Interp *interp,
void *ctx,
int argc,
const char **argv,
int *argl
){
char *zList = 0;
int nList = 0;
int i;
for(i=1; i<argc; i++){
Th_ListAppend(interp, &zList, &nList, argv[i], argl[i]);
}
Th_SetResult(interp, zList, nList);
Th_Free(interp, zList);
return TH_OK;
}
/*
** TH Syntax:
**
** lindex list index
*/
static int lindex_command(
Th_Interp *interp,
void *ctx,
int argc,
const char **argv,
int *argl
){
int iElem;
int rc;
char **azElem;
int *anElem;
|
| ︙ | ︙ | |||
225 226 227 228 229 230 231 |
Th_Free(interp, azElem);
}
return rc;
}
/*
| | | | | | | | | | | | | | | | | | | | 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 |
Th_Free(interp, azElem);
}
return rc;
}
/*
** TH Syntax:
**
** llength list
*/
static int llength_command(
Th_Interp *interp,
void *ctx,
int argc,
const char **argv,
int *argl
){
int nElem;
int rc;
if( argc!=2 ){
return Th_WrongNumArgs(interp, "llength list");
}
rc = Th_SplitList(interp, argv[1], argl[1], 0, 0, &nElem);
if( rc==TH_OK ){
Th_SetResultInt(interp, nElem);
}
return rc;
}
/*
** TH Syntax:
**
** set varname ?value?
*/
static int set_command(
Th_Interp *interp,
void *ctx,
int argc,
const char **argv,
int *argl
){
if( argc!=2 && argc!=3 ){
return Th_WrongNumArgs(interp, "set varname ?value?");
}
if( argc==3 ){
Th_SetVar(interp, argv[1], argl[1], argv[2], argl[2]);
}
return Th_GetVar(interp, argv[1], argl[1]);
}
/*
** When a new command is created using the built-in [proc] command, an
** instance of the following structure is allocated and populated. A
** pointer to the structure is passed as the context (second) argument
** to function proc_call1() when the new command is executed.
*/
typedef struct ProcDefn ProcDefn;
struct ProcDefn {
int nParam; /* Number of formal (non "args") parameters */
char **azParam; /* Parameter names */
int *anParam; /* Lengths of parameter names */
char **azDefault; /* Default values */
int *anDefault; /* Lengths of default values */
int hasArgs; /* True if there is an "args" parameter */
char *zProgram; /* Body of proc */
int nProgram; /* Number of bytes at zProgram */
char *zUsage; /* Usage message */
int nUsage; /* Number of bytes at zUsage */
};
/* This structure is used to temporarily store arguments passed to an
** invocation of a command created using [proc]. A pointer to an
** instance is passed as the second argument to the proc_call2() function.
*/
typedef struct ProcArgs ProcArgs;
struct ProcArgs {
int argc;
const char **argv;
int *argl;
|
| ︙ | ︙ | |||
321 322 323 324 325 326 327 | int i; ProcDefn *p = (ProcDefn *)pContext1; ProcArgs *pArgs = (ProcArgs *)pContext2; /* Check if there are the right number of arguments. If there are ** not, generate a usage message for the command. */ | | | 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 |
int i;
ProcDefn *p = (ProcDefn *)pContext1;
ProcArgs *pArgs = (ProcArgs *)pContext2;
/* Check if there are the right number of arguments. If there are
** not, generate a usage message for the command.
*/
if( (pArgs->argc>(p->nParam+1) && !p->hasArgs)
|| (pArgs->argc<=(p->nParam) && !p->azDefault[pArgs->argc-1])
){
char *zUsage = 0;
int nUsage = 0;
Th_StringAppend(interp, &zUsage, &nUsage, pArgs->argv[0], pArgs->argl[0]);
Th_StringAppend(interp, &zUsage, &nUsage, p->zUsage, p->nUsage);
Th_StringAppend(interp, &zUsage, &nUsage, (const char *)"", 1);
|
| ︙ | ︙ | |||
372 373 374 375 376 377 378 | /* ** This function is the command callback registered for all commands ** created using the [proc] command. The second argument, pContext, ** is a pointer to the associated ProcDefn structure. */ static int proc_call1( Th_Interp *interp, | | | | 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 |
/*
** This function is the command callback registered for all commands
** created using the [proc] command. The second argument, pContext,
** is a pointer to the associated ProcDefn structure.
*/
static int proc_call1(
Th_Interp *interp,
void *pContext,
int argc,
const char **argv,
int *argl
){
int rc;
ProcDefn *p = (ProcDefn *)pContext;
ProcArgs procargs;
|
| ︙ | ︙ | |||
398 399 400 401 402 403 404 |
if( rc==TH_RETURN ){
rc = TH_OK;
}
return rc;
}
/*
| | | | | | | | | | | | | | | | 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 |
if( rc==TH_RETURN ){
rc = TH_OK;
}
return rc;
}
/*
** This function is registered as the delete callback for all commands
** created using the built-in [proc] command. It is called automatically
** when a command created using [proc] is deleted.
**
** It frees the ProcDefn structure allocated when the command was created.
*/
static void proc_del(Th_Interp *interp, void *pContext){
ProcDefn *p = (ProcDefn *)pContext;
Th_Free(interp, (void *)p->zUsage);
Th_Free(interp, (void *)p);
}
/*
** TH Syntax:
**
** proc name arglist code
*/
static int proc_command(
Th_Interp *interp,
void *ctx,
int argc,
const char **argv,
int *argl
){
int rc;
const char *zName;
ProcDefn *p;
int nByte;
int i;
char *zSpace;
char **azParam;
int *anParam;
int nParam;
char *zUsage = 0; /* Build up a usage message here */
int nUsage = 0; /* Number of bytes at zUsage */
if( argc!=4 ){
return Th_WrongNumArgs(interp, "proc name arglist code");
}
if( Th_SplitList(interp, argv[2], argl[2], &azParam, &anParam, &nParam) ){
return TH_ERROR;
}
/* Allocate the new ProcDefn structure. */
nByte = sizeof(ProcDefn) + /* ProcDefn structure */
(sizeof(char *) + sizeof(int)) * nParam + /* azParam, anParam */
(sizeof(char *) + sizeof(int)) * nParam + /* azDefault, anDefault */
argl[3] + /* zProgram */
argl[2]; /* Space for copies of parameter names and default values */
p = (ProcDefn *)Th_Malloc(interp, nByte);
/* If the last parameter in the parameter list is "args", then set the
** ProcDefn.hasArgs flag. The "args" parameter does not require an
** entry in the ProcDefn.azParam[] or ProcDefn.azDefault[] arrays.
*/
if( anParam[nParam-1]==4 && 0==memcmp(azParam[nParam-1], "args", 4) ){
p->hasArgs = 1;
nParam--;
}
p->nParam = nParam;
p->azParam = (char **)&p[1];
p->anParam = (int *)&p->azParam[nParam];
p->azDefault = (char **)&p->anParam[nParam];
p->anDefault = (int *)&p->azDefault[nParam];
p->zProgram = (char *)&p->anDefault[nParam];
memcpy(p->zProgram, argv[3], argl[3]);
p->nProgram = argl[3];
zSpace = &p->zProgram[p->nProgram];
for(i=0; i<nParam; i++){
char **az;
int *an;
int n;
if( Th_SplitList(interp, azParam[i], anParam[i], &az, &an, &n) ){
goto error_out;
}
|
| ︙ | ︙ | |||
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 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 |
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 = 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;
error_out:
Th_Free(interp, azParam);
Th_Free(interp, zUsage);
return TH_ERROR;
}
/*
** TH Syntax:
**
** rename oldcmd newcmd
*/
static int rename_command(
Th_Interp *interp,
void *ctx,
int argc,
const char **argv,
int *argl
){
if( argc!=3 ){
return Th_WrongNumArgs(interp, "rename oldcmd newcmd");
}
return Th_RenameCommand(interp, argv[1], argl[1], argv[2], argl[2]);
}
/*
** TH Syntax:
**
** break ?value...?
** continue ?value...?
** ok ?value...?
** error ?value...?
*/
static int simple_command(
Th_Interp *interp,
void *ctx,
int argc,
const char **argv,
int *argl
){
if( argc!=1 && argc!=2 ){
return Th_WrongNumArgs(interp, "return ?value?");
}
if( argc==2 ){
Th_SetResult(interp, argv[1], argl[1]);
}
return FOSSIL_PTR_TO_INT(ctx);
}
/*
** TH Syntax:
**
** return ?-code code? ?value?
*/
static int return_command(
Th_Interp *interp,
void *ctx,
int argc,
const char **argv,
int *argl
){
int iCode = TH_RETURN;
if( argc<1 || argc>4 ){
return Th_WrongNumArgs(interp, "return ?-code code? ?value?");
}
if( argc>2 ){
|
| ︙ | ︙ | |||
636 637 638 639 640 641 642 |
}
if( iRes==0 ){
iRes = nLeft-nRight;
}
if( iRes<0 ) iRes = -1;
if( iRes>0 ) iRes = 1;
| | < < < < | > > > | > | | | | | | | > | 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 |
}
if( iRes==0 ){
iRes = nLeft-nRight;
}
if( iRes<0 ) iRes = -1;
if( iRes>0 ) iRes = 1;
return Th_SetResultInt(interp, iRes);
}
/*
** TH Syntax:
**
** string first NEEDLE HAYSTACK
*/
static int string_first_command(
Th_Interp *interp, void *ctx, int argc, const char **argv, int *argl
){
int nNeedle;
int nHaystack;
int iRes = -1;
if( argc!=4 ){
return Th_WrongNumArgs(interp, "string first needle haystack");
}
nNeedle = argl[2];
nHaystack = argl[3];
if( nNeedle && nHaystack && nNeedle<=nHaystack ){
const char *zNeedle = argv[2];
const char *zHaystack = argv[3];
int i;
for(i=0; i<=(nHaystack-nNeedle); i++){
if( 0==memcmp(zNeedle, &zHaystack[i], nNeedle) ){
iRes = i;
break;
}
}
}
return Th_SetResultInt(interp, iRes);
}
/*
** TH Syntax:
**
** string is CLASS STRING
|
| ︙ | ︙ | |||
709 710 711 712 713 714 715 |
** TH Syntax:
**
** string last NEEDLE HAYSTACK
*/
static int string_last_command(
Th_Interp *interp, void *ctx, int argc, const char **argv, int *argl
){
| < < < | < | > > > | > | | | | | | | > | 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 |
** TH Syntax:
**
** string last NEEDLE HAYSTACK
*/
static int string_last_command(
Th_Interp *interp, void *ctx, int argc, const char **argv, int *argl
){
int nNeedle;
int nHaystack;
int iRes = -1;
if( argc!=4 ){
return Th_WrongNumArgs(interp, "string last needle haystack");
}
nNeedle = argl[2];
nHaystack = argl[3];
if( nNeedle && nHaystack && nNeedle<=nHaystack ){
const char *zNeedle = argv[2];
const char *zHaystack = argv[3];
int i;
for(i=nHaystack-nNeedle; i>=0; i--){
if( 0==memcmp(zNeedle, &zHaystack[i], nNeedle) ){
iRes = i;
break;
}
}
}
return Th_SetResultInt(interp, iRes);
}
/*
** TH Syntax:
**
** string length STRING
|
| ︙ | ︙ | |||
865 866 867 868 869 870 871 | /* ** TH Syntax: ** ** unset VAR */ static int unset_command( | | | | | | 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 |
/*
** TH Syntax:
**
** unset VAR
*/
static int unset_command(
Th_Interp *interp,
void *ctx,
int argc,
const char **argv,
int *argl
){
if( argc!=2 ){
return Th_WrongNumArgs(interp, "unset var");
}
return Th_UnsetVar(interp, argv[1], argl[1]);
}
int Th_CallSubCommand(
Th_Interp *interp,
void *ctx,
int argc,
const char **argv,
int *argl,
const Th_SubCommand *aSub
){
if( argc>1 ){
int i;
for(i=0; aSub[i].zName; i++){
const char *zName = 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]);
|
| ︙ | ︙ | |||
914 915 916 917 918 919 920 | ** string is CLASS STRING ** string last NEEDLE HAYSTACK ?STARTINDEX? ** string length STRING ** string range STRING FIRST LAST ** string repeat STRING COUNT */ static int string_command( | | | | 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 |
** string is CLASS STRING
** string last NEEDLE HAYSTACK ?STARTINDEX?
** string length STRING
** string range STRING FIRST LAST
** string repeat STRING COUNT
*/
static int string_command(
Th_Interp *interp,
void *ctx,
int argc,
const char **argv,
int *argl
){
static const 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 },
|
| ︙ | ︙ | |||
942 943 944 945 946 947 948 | /* ** TH Syntax: ** ** info exists VARNAME */ static int info_command( | | | | | | | | | 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 |
/*
** TH Syntax:
**
** info exists VARNAME
*/
static int info_command(
Th_Interp *interp,
void *ctx,
int argc,
const char **argv,
int *argl
){
static const Th_SubCommand aSub[] = {
{ "exists", info_exists_command },
{ 0, 0 }
};
return Th_CallSubCommand(interp, ctx, argc, argv, argl, aSub);
}
/*
** Convert the script level frame specification (used by the commands
** [uplevel] and [upvar]) in (zFrame, nFrame) to an integer frame as
** used by Th_LinkVar() and Th_Eval(). If successful, write the integer
** frame level to *piFrame and return TH_OK. Otherwise, return TH_ERROR
** and leave an error message in the interpreter result.
*/
static int thToFrame(
Th_Interp *interp,
const char *zFrame,
int nFrame,
int *piFrame
){
int iFrame;
if( th_isdigit(zFrame[0]) ){
int rc = Th_ToInt(interp, zFrame, nFrame, &iFrame);
if( rc!=TH_OK ) return rc;
iFrame = iFrame * -1;
|
| ︙ | ︙ | |||
990 991 992 993 994 995 996 | /* ** TH Syntax: ** ** uplevel ?LEVEL? SCRIPT */ static int uplevel_command( | | | | | | | | | | | | | | 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 |
/*
** TH Syntax:
**
** uplevel ?LEVEL? SCRIPT
*/
static int uplevel_command(
Th_Interp *interp,
void *ctx,
int argc,
const char **argv,
int *argl
){
int iFrame = -1;
if( argc!=2 && argc!=3 ){
return Th_WrongNumArgs(interp, "uplevel ?level? script...");
}
if( argc==3 && TH_OK!=thToFrame(interp, argv[1], argl[1], &iFrame) ){
return TH_ERROR;
}
return Th_Eval(interp, iFrame, argv[argc-1], -1);
}
/*
** TH Syntax:
**
** upvar ?FRAME? OTHERVAR MYVAR ?OTHERVAR MYVAR ...?
*/
static int upvar_command(
Th_Interp *interp,
void *ctx,
int argc,
const char **argv,
int *argl
){
int iVar = 1;
int iFrame = -1;
int rc = TH_OK;
int i;
if( TH_OK==thToFrame(0, argv[1], argl[1], &iFrame) ){
iVar++;
}
if( argc==iVar || (argc-iVar)%2 ){
return Th_WrongNumArgs(interp,
"upvar frame othervar myvar ?othervar myvar...?");
}
for(i=iVar; rc==TH_OK && i<argc; i=i+2){
rc = Th_LinkVar(interp, argv[i+1], argl[i+1], iFrame, argv[i], argl[i]);
}
return rc;
}
/*
** TH Syntax:
**
** breakpoint ARGS
**
** This command does nothing at all. Its purpose in life is to serve
** as a point for setting breakpoints in a debugger.
*/
static int breakpoint_command(
Th_Interp *interp,
void *ctx,
int argc,
const char **argv,
int *argl
){
int cnt = 0;
cnt++;
return TH_OK;
}
|
| ︙ | ︙ | |||
1076 1077 1078 1079 1080 1081 1082 |
{"expr", expr_command, 0},
{"for", for_command, 0},
{"if", if_command, 0},
{"info", info_command, 0},
{"lindex", lindex_command, 0},
{"list", list_command, 0},
{"llength", llength_command, 0},
| | | | | | | 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 |
{"expr", expr_command, 0},
{"for", for_command, 0},
{"if", if_command, 0},
{"info", info_command, 0},
{"lindex", lindex_command, 0},
{"list", list_command, 0},
{"llength", llength_command, 0},
{"proc", proc_command, 0},
{"rename", rename_command, 0},
{"set", set_command, 0},
{"string", string_command, 0},
{"unset", unset_command, 0},
{"uplevel", uplevel_command, 0},
{"upvar", upvar_command, 0},
{"breakpoint", breakpoint_command, 0},
{"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}
};
size_t 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/th_main.c.
| ︙ | ︙ | |||
55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
static void xFree(void *p){
if( p ){
nOutstandingMalloc--;
}
free(p);
}
static Th_Vtab vtab = { xMalloc, xFree };
/*
** Generate a TH1 trace message if debugging is enabled.
*/
void Th_Trace(const char *zFormat, ...){
va_list ap;
va_start(ap, zFormat);
| > > > > > > > | 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
static void xFree(void *p){
if( p ){
nOutstandingMalloc--;
}
free(p);
}
static Th_Vtab vtab = { xMalloc, xFree };
/*
** Returns the number of outstanding TH1 memory allocations.
*/
int Th_GetOutstandingMalloc(){
return nOutstandingMalloc;
}
/*
** Generate a TH1 trace message if debugging is enabled.
*/
void Th_Trace(const char *zFormat, ...){
va_list ap;
va_start(ap, zFormat);
|
| ︙ | ︙ | |||
88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
void Th_PrintTraceLog(){
if( g.thTrace ){
fossil_print("\n------------------ BEGIN TRACE LOG ------------------\n");
fossil_print("%s", blob_str(&g.thLog));
fossil_print("\n------------------- END TRACE LOG -------------------\n");
}
}
/*
** True if output is enabled. False if disabled.
*/
static int enableOutput = 1;
/*
| > > > > > > > > > > > > > > > > > > > > > > > | 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 |
void Th_PrintTraceLog(){
if( g.thTrace ){
fossil_print("\n------------------ BEGIN TRACE LOG ------------------\n");
fossil_print("%s", blob_str(&g.thLog));
fossil_print("\n------------------- END TRACE LOG -------------------\n");
}
}
/*
** TH command: httpize STRING
**
** Escape all characters of STRING which have special meaning in URI
** components. Return a new string result.
*/
static int httpizeCmd(
Th_Interp *interp,
void *p,
int argc,
const char **argv,
int *argl
){
char *zOut;
if( argc!=2 ){
return Th_WrongNumArgs(interp, "httpize STRING");
}
zOut = httpize((char*)argv[1], argl[1]);
Th_SetResult(interp, zOut, -1);
free(zOut);
return TH_OK;
}
/*
** True if output is enabled. False if disabled.
*/
static int enableOutput = 1;
/*
|
| ︙ | ︙ | |||
253 254 255 256 257 258 259 |
void *p,
int argc,
const char **argv,
int *argl
){
char *zOut;
if( argc>=2 && argl[1]==6 && memcmp(argv[1],"-local",6)==0 ){
| | | 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 |
void *p,
int argc,
const char **argv,
int *argl
){
char *zOut;
if( argc>=2 && argl[1]==6 && memcmp(argv[1],"-local",6)==0 ){
zOut = db_text("??", "SELECT datetime('now'%s)", timeline_utc());
}else{
zOut = db_text("??", "SELECT datetime('now')");
}
Th_SetResult(interp, zOut, -1);
free(zOut);
return TH_OK;
}
|
| ︙ | ︙ | |||
825 826 827 828 829 830 831 832 833 834 835 836 837 838 |
}else{
Th_SetResult(interp, zErr, -1);
rc = TH_ERROR;
}
re_free(pRe);
return rc;
}
/*
** Make sure the interpreter has been initialized. Initialize it if
** it has not been already.
**
** The interpreter is stored in the g.interp global variable.
*/
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 |
}else{
Th_SetResult(interp, zErr, -1);
rc = TH_ERROR;
}
re_free(pRe);
return rc;
}
/*
** TH command: http ?-asynchronous? ?--? url ?payload?
**
** Perform an HTTP or HTTPS request for the specified URL. If a
** payload is present, it will be interpreted as text/plain and
** the POST method will be used; otherwise, the GET method will
** be used. Upon success, if the -asynchronous option is used, an
** empty string is returned as the result; otherwise, the response
** from the server is returned as the result. Synchronous requests
** are not currently implemented.
*/
#define HTTP_WRONGNUMARGS "http ?-asynchronous? ?--? url ?payload?"
static int httpCmd(
Th_Interp *interp,
void *p,
int argc,
const char **argv,
int *argl
){
int nArg = 1;
int fAsynchronous = 0;
const char *zType, *zRegexp;
Blob payload;
ReCompiled *pRe = 0;
UrlData urlData;
if( argc<2 || argc>5 ){
return Th_WrongNumArgs(interp, HTTP_WRONGNUMARGS);
}
if( fossil_strnicmp(argv[nArg], "-asynchronous", argl[nArg])==0 ){
fAsynchronous = 1; nArg++;
}
if( fossil_strcmp(argv[nArg], "--")==0 ) nArg++;
if( nArg+1!=argc && nArg+2!=argc ){
return Th_WrongNumArgs(interp, REGEXP_WRONGNUMARGS);
}
memset(&urlData, '\0', sizeof(urlData));
url_parse_local(argv[nArg], 0, &urlData);
if( urlData.isSsh || urlData.isFile ){
Th_ErrorMessage(interp, "url must be http:// or https://", 0, 0);
return TH_ERROR;
}
zRegexp = db_get("th1-uri-regexp", 0);
if( zRegexp && zRegexp[0] ){
const char *zErr = re_compile(&pRe, zRegexp, 0);
if( zErr ){
Th_SetResult(interp, zErr, -1);
return TH_ERROR;
}
}
if( !pRe || !re_match(pRe, (const unsigned char *)urlData.canonical, -1) ){
Th_SetResult(interp, "url not allowed", -1);
re_free(pRe);
return TH_ERROR;
}
re_free(pRe);
blob_zero(&payload);
if( nArg+2==argc ){
blob_append(&payload, argv[nArg+1], argl[nArg+1]);
zType = "POST";
}else{
zType = "GET";
}
if( fAsynchronous ){
const char *zSep, *zParams;
Blob hdr;
zParams = strrchr(argv[nArg], '?');
if( strlen(urlData.path)>0 && zParams!=argv[nArg] ){
zSep = "";
}else{
zSep = "/";
}
blob_zero(&hdr);
blob_appendf(&hdr, "%s %s%s%s HTTP/1.0\r\n",
zType, zSep, urlData.path, zParams ? zParams : "");
if( urlData.proxyAuth ){
blob_appendf(&hdr, "Proxy-Authorization: %s\r\n", urlData.proxyAuth);
}
if( urlData.passwd && urlData.user && urlData.passwd[0]=='#' ){
char *zCredentials = mprintf("%s:%s", urlData.user, &urlData.passwd[1]);
char *zEncoded = encode64(zCredentials, -1);
blob_appendf(&hdr, "Authorization: Basic %s\r\n", zEncoded);
fossil_free(zEncoded);
fossil_free(zCredentials);
}
blob_appendf(&hdr, "Host: %s\r\n"
"User-Agent: %s\r\n", urlData.hostname, get_user_agent());
if( zType[0]=='P' ){
blob_appendf(&hdr, "Content-Type: application/x-www-form-urlencoded\r\n"
"Content-Length: %d\r\n\r\n", blob_size(&payload));
}else{
blob_appendf(&hdr, "\r\n");
}
if( transport_open(&urlData) ){
Th_ErrorMessage(interp, transport_errmsg(&urlData), 0, 0);
blob_reset(&hdr);
blob_reset(&payload);
return TH_ERROR;
}
transport_send(&urlData, &hdr);
transport_send(&urlData, &payload);
blob_reset(&hdr);
blob_reset(&payload);
transport_close(&urlData);
Th_SetResult(interp, 0, 0); /* NOTE: Asynchronous, no results. */
return TH_OK;
}else{
Th_ErrorMessage(interp,
"synchronous requests are not yet implemented", 0, 0);
blob_reset(&payload);
return TH_ERROR;
}
}
/*
** Make sure the interpreter has been initialized. Initialize it if
** it has not been already.
**
** The interpreter is stored in the g.interp global variable.
*/
|
| ︙ | ︙ | |||
849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 |
void *pContext;
} aCommand[] = {
{"anycap", anycapCmd, 0},
{"combobox", comboboxCmd, 0},
{"date", dateCmd, 0},
{"decorate", wikiCmd, (void*)&aFlags[2]},
{"enable_output", enableOutputCmd, 0},
{"hascap", hascapCmd, 0},
{"hasfeature", hasfeatureCmd, 0},
{"html", putsCmd, (void*)&aFlags[0]},
{"htmlize", htmlizeCmd, 0},
{"linecount", linecntCmd, 0},
{"puts", putsCmd, (void*)&aFlags[1]},
{"query", queryCmd, 0},
{"randhex", randhexCmd, 0},
{"regexp", regexpCmd, 0},
{"repository", repositoryCmd, 0},
{"setting", settingCmd, 0},
| > > | 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 |
void *pContext;
} aCommand[] = {
{"anycap", anycapCmd, 0},
{"combobox", comboboxCmd, 0},
{"date", dateCmd, 0},
{"decorate", wikiCmd, (void*)&aFlags[2]},
{"enable_output", enableOutputCmd, 0},
{"httpize", httpizeCmd, 0},
{"hascap", hascapCmd, 0},
{"hasfeature", hasfeatureCmd, 0},
{"html", putsCmd, (void*)&aFlags[0]},
{"htmlize", htmlizeCmd, 0},
{"http", httpCmd, 0},
{"linecount", linecntCmd, 0},
{"puts", putsCmd, (void*)&aFlags[1]},
{"query", queryCmd, 0},
{"randhex", randhexCmd, 0},
{"regexp", regexpCmd, 0},
{"repository", repositoryCmd, 0},
{"setting", settingCmd, 0},
|
| ︙ | ︙ | |||
887 888 889 890 891 892 893 |
g.interp = Th_CreateInterp(&vtab);
created = 1;
}
if( forceReset || created ){
th_register_language(g.interp); /* Basic scripting commands. */
}
#ifdef FOSSIL_ENABLE_TCL
| > | | 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 |
g.interp = Th_CreateInterp(&vtab);
created = 1;
}
if( forceReset || created ){
th_register_language(g.interp); /* Basic scripting commands. */
}
#ifdef FOSSIL_ENABLE_TCL
if( forceTcl || fossil_getenv("TH1_ENABLE_TCL")!=0 ||
db_get_boolean("tcl", 0) ){
if( !g.tcl.setup ){
g.tcl.setup = db_get("tcl-setup", 0); /* Grab Tcl setup script. */
}
th_register_tcl(g.interp, &g.tcl); /* Tcl integration commands. */
}
#endif
for(i=0; i<sizeof(aCommand)/sizeof(aCommand[0]); i++){
|
| ︙ | ︙ |
Changes to src/th_tcl.c.
| ︙ | ︙ | |||
764 765 766 767 768 769 770 771 772 773 774 775 776 777 |
if( !resultObjPtr ){
rc = TCL_ERROR;
}
}
Tcl_DecrRefCount(listPtr);
return rc;
}
/*
** Creates and initializes a Tcl interpreter for use with the specified TH1
** interpreter. Stores the created Tcl interpreter in the Tcl context supplied
** by the caller.
*/
static int createTclInterp(
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 |
if( !resultObjPtr ){
rc = TCL_ERROR;
}
}
Tcl_DecrRefCount(listPtr);
return rc;
}
/*
** Evaluate a Tcl script, creating the Tcl interpreter if necessary. If the
** Tcl script succeeds, start a Tcl event loop until there are no more events
** remaining to process -OR- the script calls [exit]. If the bWait argument
** is zero, only process events that are already in the queue; otherwise,
** process events until the script terminates the Tcl event loop.
*/
int evaluateTclWithEvents(
Th_Interp *interp,
void *pContext,
const char *zScript,
int nScript,
int bWait
){
struct TclContext *tclContext = (struct TclContext *)pContext;
Tcl_Interp *tclInterp;
int rc;
int flags = TCL_ALL_EVENTS;
if( createTclInterp(interp, pContext)!=TH_OK ){
return TH_ERROR;
}
tclInterp = tclContext->interp;
rc = Tcl_EvalEx(tclInterp, zScript, nScript, TCL_EVAL_GLOBAL);
if( rc!=TCL_OK ) return rc;
if( !bWait ) flags |= TCL_DONT_WAIT;
while( Tcl_DoOneEvent(flags) ){
/* do nothing */
}
return rc;
}
/*
** Creates and initializes a Tcl interpreter for use with the specified TH1
** interpreter. Stores the created Tcl interpreter in the Tcl context supplied
** by the caller.
*/
static int createTclInterp(
|
| ︙ | ︙ |
Changes to src/timeline.c.
| ︙ | ︙ | |||
109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
#define TIMELINE_BRIEF 0x0004 /* Combine adjacent elements of same object */
#define TIMELINE_GRAPH 0x0008 /* Compute a graph */
#define TIMELINE_DISJOINT 0x0010 /* Elements are not contiguous */
#define TIMELINE_FCHANGES 0x0020 /* Detail file changes */
#define TIMELINE_BRCOLOR 0x0040 /* Background color by branch name */
#define TIMELINE_UCOLOR 0x0080 /* Background color by user */
#define TIMELINE_FRENAMES 0x0100 /* Detail only file name changes */
#endif
/*
** Hash a string and use the hash to determine a background color.
*/
char *hash_color(const char *z){
int i; /* Loop counter */
| > | 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 |
#define TIMELINE_BRIEF 0x0004 /* Combine adjacent elements of same object */
#define TIMELINE_GRAPH 0x0008 /* Compute a graph */
#define TIMELINE_DISJOINT 0x0010 /* Elements are not contiguous */
#define TIMELINE_FCHANGES 0x0020 /* Detail file changes */
#define TIMELINE_BRCOLOR 0x0040 /* Background color by branch name */
#define TIMELINE_UCOLOR 0x0080 /* Background color by user */
#define TIMELINE_FRENAMES 0x0100 /* Detail only file name changes */
#define TIMELINE_UNHIDE 0x0200 /* Unhide check-ins with "hidden" tag */
#endif
/*
** Hash a string and use the hash to determine a background color.
*/
char *hash_color(const char *z){
int i; /* Loop counter */
|
| ︙ | ︙ | |||
244 245 246 247 248 249 250 | 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 ){
|
| ︙ | ︙ | |||
286 287 288 289 290 291 292 293 294 295 296 297 298 299 |
int tagid = db_column_int(pQuery, 9);
const char *zDispUser = zUser && zUser[0] ? zUser : "anonymous";
const char *zBr = 0; /* Branch */
int commentColumn = 3; /* Column containing comment text */
int modPending; /* Pending moderation */
char zTime[20];
modPending = moderation_pending(rid);
if( tagid ){
if( modPending ) tagid = -tagid;
if( tagid==prevTagid ){
if( tmFlags & TIMELINE_BRIEF ){
suppressCnt++;
continue;
| > | 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 |
int tagid = db_column_int(pQuery, 9);
const char *zDispUser = zUser && zUser[0] ? zUser : "anonymous";
const char *zBr = 0; /* Branch */
int commentColumn = 3; /* Column containing comment text */
int modPending; /* Pending moderation */
char zTime[20];
if( zDate==0 ) zDate = "YYYY-MM-DD HH:MM:SS"; /* Something wrong with the repo */
modPending = moderation_pending(rid);
if( tagid ){
if( modPending ) tagid = -tagid;
if( tagid==prevTagid ){
if( tmFlags & TIMELINE_BRIEF ){
suppressCnt++;
continue;
|
| ︙ | ︙ | |||
317 318 319 320 321 322 323 |
@ <tr><td colspan="3"><hr /></td></tr>
}
prevWasDivider = 1;
continue;
}
prevWasDivider = 0;
if( dateFormat<2 ){
| | | 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 |
@ <tr><td colspan="3"><hr /></td></tr>
}
prevWasDivider = 1;
continue;
}
prevWasDivider = 0;
if( dateFormat<2 ){
if( fossil_strnicmp(zDate, zPrevDate, 10) ){
sqlite3_snprintf(sizeof(zPrevDate), zPrevDate, "%.10s", zDate);
@ <tr><td>
@ <div class="divider timelineDate">%s(zPrevDate)</div>
@ </td><td></td><td></td></tr>
}
memcpy(zTime, &zDate[11], 5+dateFormat*3);
zTime[5+dateFormat*3] = 0;
|
| ︙ | ︙ | |||
587 588 589 590 591 592 593 |
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 |
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>
@ 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
|
| ︙ | ︙ | |||
848 849 850 851 852 853 854 |
@ canvasDiv.removeChild(selBox);
@ selBox = null;
@ selRow = null;
@ }else{
if( fileDiff ){
@ location.href="%R/fdiff?v1="+selRow.h+"&v2="+p.h+"&sbs=1";
}else{
| > > > | > < | 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 |
@ canvasDiv.removeChild(selBox);
@ selBox = null;
@ selRow = null;
@ }else{
if( fileDiff ){
@ location.href="%R/fdiff?v1="+selRow.h+"&v2="+p.h+"&sbs=1";
}else{
if( db_get_boolean("show-version-diffs", 0)==0 ){
@ location.href="%R/vdiff?from="+selRow.h+"&to="+p.h+"&sbs=0";
}else{
@ location.href="%R/vdiff?from="+selRow.h+"&to="+p.h+"&sbs=1";
}
}
@ }
@ }
@ var lastId = "m"+rowinfo[rowinfo.length-1].id;
@ var lastY = 0;
@ function checkHeight(){
@ var h = absoluteY(lastId);
@ if( h!=lastY ){
@ renderGraph();
@ lastY = h;
@ }
@ setTimeout("checkHeight();", 1000);
@ }
@ checkHeight();
@ </script>
}
}
/*
** Create a temporary table suitable for storing timeline data.
*/
|
| ︙ | ︙ | |||
896 897 898 899 900 901 902 |
}
/*
** Return a pointer to a constant string that forms the basis
** for a timeline query for the WWW interface.
*/
const char *timeline_query_for_www(void){
| | | | | 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 |
}
/*
** Return a pointer to a constant string that forms the basis
** for a timeline query for the WWW interface.
*/
const char *timeline_query_for_www(void){
static const char *zBase = 0;
static const char zBaseSql[] =
@ SELECT
@ blob.rid AS blobRid,
@ uuid AS uuid,
@ datetime(event.mtime%s) AS timestamp,
@ coalesce(ecomment, comment) AS comment,
@ coalesce(euser, user) AS user,
@ blob.rid IN leaf AS leaf,
@ bgcolor AS bgColor,
@ event.type AS eventType,
@ (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,
@ event.mtime AS mtime
@ FROM event CROSS JOIN blob
@ WHERE blob.rid=event.objid
;
if( zBase==0 ){
zBase = mprintf(zBaseSql, timeline_utc());
}
return zBase;
}
/*
** Generate a submenu element with a single parameter change.
*/
|
| ︙ | ︙ | |||
1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 |
tagid = 0;
}
if( zType[0]=='a' ){
tmFlags = TIMELINE_BRIEF | TIMELINE_GRAPH;
}else{
tmFlags = TIMELINE_GRAPH;
}
if( P("ng")!=0 || zSearch!=0 ){
tmFlags &= ~TIMELINE_GRAPH;
url_add_parameter(&url, "ng", 0);
}
if( P("brbg")!=0 ){
tmFlags |= TIMELINE_BRCOLOR;
url_add_parameter(&url, "brbg", 0);
}
if( P("ubg")!=0 ){
tmFlags |= TIMELINE_UCOLOR;
url_add_parameter(&url, "ubg", 0);
}
if( zUses!=0 ){
int ufid = db_int(0, "SELECT rid FROM blob WHERE uuid GLOB '%q*'", zUses);
if( ufid ){
| > > > > > | 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 |
tagid = 0;
}
if( zType[0]=='a' ){
tmFlags = TIMELINE_BRIEF | TIMELINE_GRAPH;
}else{
tmFlags = TIMELINE_GRAPH;
}
url_add_parameter(&url, "n", mprintf("%d", nEntry));
if( P("ng")!=0 || zSearch!=0 ){
tmFlags &= ~TIMELINE_GRAPH;
url_add_parameter(&url, "ng", 0);
}
if( P("brbg")!=0 ){
tmFlags |= TIMELINE_BRCOLOR;
url_add_parameter(&url, "brbg", 0);
}
if( P("unhide")!=0 ){
tmFlags |= TIMELINE_UNHIDE;
url_add_parameter(&url, "unhide", 0);
}
if( P("ubg")!=0 ){
tmFlags |= TIMELINE_UCOLOR;
url_add_parameter(&url, "ubg", 0);
}
if( zUses!=0 ){
int ufid = db_int(0, "SELECT rid FROM blob WHERE uuid GLOB '%q*'", zUses);
if( ufid ){
|
| ︙ | ︙ | |||
1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 |
blob_zero(&sql);
blob_zero(&desc);
blob_append(&sql, "INSERT OR IGNORE INTO timeline ", -1);
blob_append(&sql, timeline_query_for_www(), -1);
if( P("fc")!=0 || P("v")!=0 || P("detail")!=0 ){
tmFlags |= TIMELINE_FCHANGES;
url_add_parameter(&url, "v", 0);
}
if( !useDividers ) url_add_parameter(&url, "nd", 0);
if( ((from_rid && to_rid) || (me_rid && you_rid)) && g.perm.Read ){
/* If from= and to= are present, display all nodes on a path connecting
** the two */
PathNode *p = 0;
const char *zFrom = 0;
| > > > > > | 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 |
blob_zero(&sql);
blob_zero(&desc);
blob_append(&sql, "INSERT OR IGNORE INTO timeline ", -1);
blob_append(&sql, timeline_query_for_www(), -1);
if( P("fc")!=0 || P("v")!=0 || P("detail")!=0 ){
tmFlags |= TIMELINE_FCHANGES;
url_add_parameter(&url, "v", 0);
}
if( (tmFlags & TIMELINE_UNHIDE)==0 ){
blob_appendf(&sql, " AND NOT EXISTS(SELECT 1 FROM tagxref"
" WHERE tagid=%d AND tagtype>0 AND rid=blob.rid)",
TAG_HIDDEN);
}
if( !useDividers ) url_add_parameter(&url, "nd", 0);
if( ((from_rid && to_rid) || (me_rid && you_rid)) && g.perm.Read ){
/* If from= and to= are present, display all nodes on a path connecting
** the two */
PathNode *p = 0;
const char *zFrom = 0;
|
| ︙ | ︙ | |||
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 |
blob_appendf(&desc, "%d ancestors", np);
db_multi_exec("%s", blob_str(&sql));
}
if( d_rid==0 && useDividers ) timeline_add_dividers(0, p_rid);
}
blob_appendf(&desc, " of %z[%.10s]</a>",
href("%R/info/%s", zUuid), zUuid);
}else if( f_rid && g.perm.Read ){
/* If f= is present, ignore all other parameters other than n= */
char *zUuid;
db_multi_exec(
"CREATE TEMP TABLE IF NOT EXISTS ok(rid INTEGER PRIMARY KEY);"
"INSERT INTO ok VALUES(%d);"
"INSERT OR IGNORE INTO ok SELECT pid FROM plink WHERE cid=%d;"
"INSERT OR IGNORE INTO ok SELECT cid FROM plink WHERE pid=%d;",
f_rid, f_rid, f_rid
);
blob_appendf(&sql, " AND event.objid IN ok");
db_multi_exec("%s", blob_str(&sql));
if( useDividers ) timeline_add_dividers(0, f_rid);
blob_appendf(&desc, "Parents and children of check-in ");
zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", f_rid);
blob_appendf(&desc, "%z[%.10s]</a>", href("%R/info/%s", zUuid), zUuid);
tmFlags |= TIMELINE_DISJOINT;
}else{
/* Otherwise, a timeline based on a span of time */
int n;
const char *zEType = "timeline item";
char *zDate;
| > > > > > > > > > > > > > > > > > < < | 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 |
blob_appendf(&desc, "%d ancestors", np);
db_multi_exec("%s", blob_str(&sql));
}
if( d_rid==0 && useDividers ) timeline_add_dividers(0, p_rid);
}
blob_appendf(&desc, " of %z[%.10s]</a>",
href("%R/info/%s", zUuid), zUuid);
if( (tmFlags & TIMELINE_UNHIDE)==0 ){
if( p_rid ){
url_add_parameter(&url, "p", zUuid);
}
if( d_rid ){
if( p_rid ){
/* If both p= and d= are set, we don't have the uuid of d yet. */
zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", d_rid);
}
url_add_parameter(&url, "d", zUuid);
}
timeline_submenu(&url, "Unhide", "unhide", "", 0);
}
}else if( f_rid && g.perm.Read ){
/* If f= is present, ignore all other parameters other than n= */
char *zUuid;
db_multi_exec(
"CREATE TEMP TABLE IF NOT EXISTS ok(rid INTEGER PRIMARY KEY);"
"INSERT INTO ok VALUES(%d);"
"INSERT OR IGNORE INTO ok SELECT pid FROM plink WHERE cid=%d;"
"INSERT OR IGNORE INTO ok SELECT cid FROM plink WHERE pid=%d;",
f_rid, f_rid, f_rid
);
blob_appendf(&sql, " AND event.objid IN ok");
db_multi_exec("%s", blob_str(&sql));
if( useDividers ) timeline_add_dividers(0, f_rid);
blob_appendf(&desc, "Parents and children of check-in ");
zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", f_rid);
blob_appendf(&desc, "%z[%.10s]</a>", href("%R/info/%s", zUuid), zUuid);
tmFlags |= TIMELINE_DISJOINT;
if( (tmFlags & TIMELINE_UNHIDE)==0 ){
url_add_parameter(&url, "f", zUuid);
timeline_submenu(&url, "Unhide", "unhide", "", 0);
}
}else{
/* Otherwise, a timeline based on a span of time */
int n;
const char *zEType = "timeline item";
char *zDate;
if( zUses ){
blob_appendf(&sql, " AND event.objid IN usesfile ");
}
if( renameOnly ){
blob_appendf(&sql, " AND event.objid IN rnfile ");
}
if( zYearMonth ){
|
| ︙ | ︙ | |||
1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 |
** branch that is infrequently merged with a much more activate branch.
*/
blob_appendf(&sql,
" OR EXISTS(SELECT 1 FROM plink CROSS JOIN tagxref ON rid=cid"
" WHERE tagid=%d AND tagtype>0 AND pid=blob.rid)",
tagid
);
if( P("mionly")==0 ){
blob_appendf(&sql,
" OR EXISTS(SELECT 1 FROM plink CROSS JOIN tagxref ON rid=pid"
" WHERE tagid=%d AND tagtype>0 AND cid=blob.rid)",
tagid
);
}else{
url_add_parameter(&url, "mionly", "1");
}
}else{
url_add_parameter(&url, "t", zTagName);
}
blob_appendf(&sql, ")");
| > > > > > > > > > > > > | 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 |
** branch that is infrequently merged with a much more activate branch.
*/
blob_appendf(&sql,
" OR EXISTS(SELECT 1 FROM plink CROSS JOIN tagxref ON rid=cid"
" WHERE tagid=%d AND tagtype>0 AND pid=blob.rid)",
tagid
);
if( (tmFlags & TIMELINE_UNHIDE)==0 ){
blob_appendf(&sql,
" AND NOT EXISTS(SELECT 1 FROM plink JOIN tagxref ON rid=cid"
" WHERE tagid=%d AND tagtype>0 AND pid=blob.rid)",
TAG_HIDDEN
);
}
if( P("mionly")==0 ){
blob_appendf(&sql,
" OR EXISTS(SELECT 1 FROM plink CROSS JOIN tagxref ON rid=pid"
" WHERE tagid=%d AND tagtype>0 AND cid=blob.rid)",
tagid
);
if( (tmFlags & TIMELINE_UNHIDE)==0 ){
blob_appendf(&sql, " AND NOT EXISTS(SELECT 1 FROM plink JOIN tagxref ON rid=pid"
" WHERE tagid=%d AND tagtype>0 AND cid=blob.rid)",
TAG_HIDDEN);
}
}else{
url_add_parameter(&url, "mionly", "1");
}
}else{
url_add_parameter(&url, "t", zTagName);
}
blob_appendf(&sql, ")");
|
| ︙ | ︙ | |||
1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 |
}
if( zType[0]=='a' || zType[0]=='c' ){
if( tmFlags & TIMELINE_FCHANGES ){
timeline_submenu(&url, "Hide Files", "v", 0, 0);
}else{
timeline_submenu(&url, "Show Files", "v", "", 0);
}
}
}
}
if( P("showsql") ){
@ <blockquote>%h(blob_str(&sql))</blockquote>
}
blob_zero(&sql);
| > > > | 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 |
}
if( zType[0]=='a' || zType[0]=='c' ){
if( tmFlags & TIMELINE_FCHANGES ){
timeline_submenu(&url, "Hide Files", "v", 0, 0);
}else{
timeline_submenu(&url, "Show Files", "v", "", 0);
}
if( (tmFlags & TIMELINE_UNHIDE)==0 ){
timeline_submenu(&url, "Unhide", "unhide", "", 0);
}
}
}
}
if( P("showsql") ){
@ <blockquote>%h(blob_str(&sql))</blockquote>
}
blob_zero(&sql);
|
| ︙ | ︙ | |||
1516 1517 1518 1519 1520 1521 1522 |
** 7. branch
*/
void print_timeline(Stmt *q, int nLimit, int width, int verboseFlag){
int nAbsLimit = (nLimit >= 0) ? nLimit : -nLimit;
int nLine = 0;
int nEntry = 0;
char zPrevDate[20];
| | | > | | | | | 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 |
** 7. branch
*/
void print_timeline(Stmt *q, int nLimit, int width, int verboseFlag){
int nAbsLimit = (nLimit >= 0) ? nLimit : -nLimit;
int nLine = 0;
int nEntry = 0;
char zPrevDate[20];
const char *zCurrentUuid = 0;
int fchngQueryInit = 0; /* True if fchngQuery is initialized */
Stmt fchngQuery; /* Query for file changes on check-ins */
int rc;
zPrevDate[0] = 0;
if( g.localOpen ){
int rid = db_lget_int("checkout", 0);
zCurrentUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
}
while( (rc=db_step(q))==SQLITE_ROW ){
int rid = db_column_int(q, 0);
const char *zId = db_column_text(q, 1);
const char *zDate = db_column_text(q, 2);
const char *zCom = db_column_text(q, 3);
int nChild = db_column_int(q, 4);
int nParent = db_column_int(q, 5);
char *zFree = 0;
int n = 0;
char zPrefix[80];
char zUuid[UUID_SIZE+1];
if( nAbsLimit!=0 ){
if( nLimit<0 && nLine>=nAbsLimit ){
fossil_print("--- line limit (%d) reached ---\n", nAbsLimit);
break; /* line count limit hit, stop. */
}else if( nEntry>=nAbsLimit ){
fossil_print("--- entry limit (%d) reached ---\n", nAbsLimit);
break; /* entry count limit hit, stop. */
}
}
sqlite3_snprintf(sizeof(zUuid), zUuid, "%.10s", zId);
if( fossil_strnicmp(zDate, zPrevDate, 10) ){
fossil_print("=== %.10s ===\n", zDate);
memcpy(zPrevDate, zDate, 10);
nLine++; /* record another line */
}
if( zCom==0 ) zCom = "";
fossil_print("%.8s ", &zDate[11]);
zPrefix[0] = 0;
|
| ︙ | ︙ | |||
1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 |
fossil_print(" EDITED %s\n", zFilename);
}
nLine++; /* record another line */
}
db_reset(&fchngQuery);
}
nEntry++; /* record another complete entry */
}
if( fchngQueryInit ) db_finalize(&fchngQuery);
}
/*
** Return a pointer to a static string that forms the basis for
** a timeline query for display on a TTY.
*/
const char *timeline_query_for_tty(void){
static const char zBaseSql[] =
@ SELECT
@ blob.rid AS rid,
@ uuid,
| > > > > > > > > > | > > > | | 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 |
fossil_print(" EDITED %s\n", zFilename);
}
nLine++; /* record another line */
}
db_reset(&fchngQuery);
}
nEntry++; /* record another complete entry */
}
if( rc==SQLITE_DONE ){
/* Did the underlying query actually have all entries? */
if( nAbsLimit==0 ){
fossil_print("+++ end of timeline (%d) +++\n", nEntry);
}else{
fossil_print("+++ no more data (%d) +++\n", nEntry);
}
}
if( fchngQueryInit ) db_finalize(&fchngQuery);
}
/*
** Return a pointer to a static string that forms the basis for
** a timeline query for display on a TTY.
*/
const char *timeline_query_for_tty(void){
static const char *zBase = 0;
static const char zBaseSql[] =
@ SELECT
@ blob.rid AS rid,
@ uuid,
@ datetime(event.mtime%s) AS mDateTime,
@ coalesce(ecomment,comment)
@ || ' (user: ' || coalesce(euser,user,'?')
@ || (SELECT case when length(x)>0 then ' tags: ' || x else '' end
@ FROM (SELECT group_concat(substr(tagname,5), ', ') AS x
@ FROM tag, tagxref
@ WHERE tagname GLOB 'sym-*' AND tag.tagid=tagxref.tagid
@ AND tagxref.rid=blob.rid AND tagxref.tagtype>0))
@ || ')' as comment,
@ (SELECT count(*) FROM plink WHERE pid=blob.rid AND isprim)
@ AS primPlinkCount,
@ (SELECT count(*) FROM plink WHERE cid=blob.rid) AS plinkCount,
@ event.mtime AS mtime,
@ tagxref.value AS branch
@ FROM tag CROSS JOIN event CROSS JOIN blob
@ LEFT JOIN tagxref ON tagxref.tagid=tag.tagid
@ AND tagxref.tagtype>0
@ AND tagxref.rid=blob.rid
@ WHERE blob.rid=event.objid
@ AND tag.tagname='branch'
;
if( zBase==0 ){
zBase = mprintf(zBaseSql, timeline_utc());
}
return zBase;
}
/*
** Return true if the input string is a date in the ISO 8601 format:
** YYYY-MM-DD.
*/
static int isIsoDate(const char *z){
|
| ︙ | ︙ | |||
1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 | ** The DATETIME should be in the ISO8601 format. For ** examples: "2007-08-18 07:21:21". You can also say "current" ** for the current version or "now" for the current time. ** ** Options: ** -n|--limit N Output the first N entries (default 20 lines). ** N=0 means no limit. ** -t|--type TYPE Output items from the given types only, such as: ** ci = file commits only ** e = events only ** t = tickets only ** w = wiki commits only ** -v|--verbose Output the list of files changed by each commit ** and the type of each change (edited, deleted, ** etc.) after the checkin comment. | > | > > > > | 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 |
** The DATETIME should be in the ISO8601 format. For
** examples: "2007-08-18 07:21:21". You can also say "current"
** for the current version or "now" for the current time.
**
** Options:
** -n|--limit N Output the first N entries (default 20 lines).
** N=0 means no limit.
** --offset P skip P changes
** -t|--type TYPE Output items from the given types only, such as:
** ci = file commits only
** e = events only
** t = tickets only
** w = wiki commits only
** -v|--verbose Output the list of files changed by each commit
** and the type of each change (edited, deleted,
** etc.) after the checkin comment.
** -W|--width <num> With of lines (default 79). Must be >20 or 0
** (= no limit, resulting in a single line per entry).
*/
void timeline_cmd(void){
Stmt q;
int n, k, width;
const char *zLimit;
const char *zWidth;
const char *zOffset;
const char *zType;
char *zOrigin;
char *zDate;
Blob sql;
int objid = 0;
Blob uuid;
int mode = 0 ; /* 0:none 1: before 2:after 3:children 4:parents */
int verboseFlag = 0 ;
int iOffset;
verboseFlag = find_option("verbose","v", 0)!=0;
if( !verboseFlag){
verboseFlag = find_option("showfiles","f", 0)!=0; /* deprecated */
}
db_find_and_open_repository(0, 0);
zLimit = find_option("limit","n",1);
zWidth = find_option("width","W",1);
|
| ︙ | ︙ | |||
1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 |
width = atoi(zWidth);
if( (width!=0) && (width<=20) ){
fossil_fatal("--width|-W value must be >20 or 0");
}
}else{
width = 79;
}
if( g.argc>=4 ){
k = strlen(g.argv[2]);
if( strncmp(g.argv[2],"before",k)==0 ){
mode = 1;
}else if( strncmp(g.argv[2],"after",k)==0 && k>1 ){
mode = 2;
}else if( strncmp(g.argv[2],"descendants",k)==0 ){
mode = 3;
}else if( strncmp(g.argv[2],"children",k)==0 ){
mode = 3;
}else if( strncmp(g.argv[2],"ancestors",k)==0 && k>1 ){
mode = 4;
}else if( strncmp(g.argv[2],"parents",k)==0 ){
mode = 4;
}else if(!zType && !zLimit){
| > > | > | 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 |
width = atoi(zWidth);
if( (width!=0) && (width<=20) ){
fossil_fatal("--width|-W value must be >20 or 0");
}
}else{
width = 79;
}
zOffset = find_option("offset",0,1);
iOffset = zOffset ? atoi(zOffset) : 0;
if( g.argc>=4 ){
k = strlen(g.argv[2]);
if( strncmp(g.argv[2],"before",k)==0 ){
mode = 1;
}else if( strncmp(g.argv[2],"after",k)==0 && k>1 ){
mode = 2;
}else if( strncmp(g.argv[2],"descendants",k)==0 ){
mode = 3;
}else if( strncmp(g.argv[2],"children",k)==0 ){
mode = 3;
}else if( strncmp(g.argv[2],"ancestors",k)==0 && k>1 ){
mode = 4;
}else if( strncmp(g.argv[2],"parents",k)==0 ){
mode = 4;
}else if(!zType && !zLimit){
usage("?WHEN? ?BASELINE|DATETIME? ?-n|--limit #? ?-t|--type TYPE? "
"?-W|--width WIDTH?");
}
if( '-' != *g.argv[3] ){
zOrigin = g.argv[3];
}else{
zOrigin = "now";
}
}else if( g.argc==3 ){
|
| ︙ | ︙ | |||
1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 |
}
blob_appendf(&sql, " AND blob.rid IN ok");
}
if( zType && (zType[0]!='a') ){
blob_appendf(&sql, " AND event.type=%Q ", zType);
}
blob_appendf(&sql, " ORDER BY event.mtime DESC");
db_prepare(&q, blob_str(&sql));
blob_reset(&sql);
print_timeline(&q, n, width, verboseFlag);
db_finalize(&q);
}
/*
| > > > > > | < < < | < < > > | < | | | 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 |
}
blob_appendf(&sql, " AND blob.rid IN ok");
}
if( zType && (zType[0]!='a') ){
blob_appendf(&sql, " AND event.type=%Q ", zType);
}
blob_appendf(&sql, " ORDER BY event.mtime DESC");
if( iOffset>0 ){
/* Don't handle LIMIT here, otherwise print_timeline()
* will not determine the end-marker correctly! */
blob_appendf(&sql, " LIMIT -1 OFFSET %d", iOffset);
}
db_prepare(&q, blob_str(&sql));
blob_reset(&sql);
print_timeline(&q, n, width, verboseFlag);
db_finalize(&q);
}
/*
** Return one of two things:
**
** ",'localtime'" if the timeline-utc property is set to 0.
**
** "" (empty string) otherwise.
*/
const char *timeline_utc(){
if( g.fTimeFormat==0 ){
if( db_get_int("timeline-utc", 1) ){
g.fTimeFormat = 1;
}else{
g.fTimeFormat = 2;
}
}
if( g.fTimeFormat==1 ){
return "";
}else{
return ",'localtime'";
}
}
/*
** COMMAND: test-timewarp-list
**
|
| ︙ | ︙ | |||
1894 1895 1896 1897 1898 1899 1900 |
" 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>
| | | 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 |
" 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();
}
/*
|
| ︙ | ︙ | |||
2006 2007 2008 2009 2010 2011 2012 |
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
| | | | > > | | > > > > > | > | 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 |
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". Any URL parameters which need to
** be added to the generated URLs should be passed in zParam. The
** caller is expected to have already encoded any zParam in the %T or
** %t encoding. */
static void stats_report_event_types_menu(char const * zCurrentViewName,
char const * zParam){
char * zTop;
if(zParam && !*zParam){
zParam = NULL;
}
zTop = mprintf("%s/reports?view=%s%s%s", g.zTop, zCurrentViewName,
zParam ? "&" : "", zParam);
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);
}
|
| ︙ | ︙ | |||
2102 2103 2104 2105 2106 2107 2108 |
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();
| | | 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 |
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", NULL );
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 ",
|
| ︙ | ︙ | |||
2161 2162 2163 2164 2165 2166 2167 |
(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>
| | | 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 |
(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>
|
| ︙ | ︙ | |||
2199 2200 2201 2202 2203 2204 2205 |
cgi_printf("&u=%t", zUserName);
}
cgi_printf("'>%s</a>", zTimeframe);
}
@ </td><td>%d(nCount)</td>
@ <td>
@ <div class='statistics-report-graph-line'
| | | | 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 |
cgi_printf("&u=%t", zUserName);
}
cgi_printf("'>%s</a>", zTimeframe);
}
@ </td><td>%d(nCount)</td>
@ <td>
@ <div class='statistics-report-graph-line'
@ style='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>
|
| ︙ | ︙ | |||
2225 2226 2227 2228 2229 2230 2231 |
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>
| | | 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 |
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)
|
| ︙ | ︙ | |||
2253 2254 2255 2256 2257 2258 2259 |
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();
| | | 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 |
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", NULL);
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));
|
| ︙ | ︙ | |||
2294 2295 2296 2297 2298 2299 2300 |
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'
| | | | 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 |
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='width:%d(nSize)%%;'> </div>
@ </td>
@</tr>
/*
Potential improvement: calculate the min/max event counts and
use percent-based graph bars.
*/
}
@ </tbody></table>
|
| ︙ | ︙ | |||
2324 2325 2326 2327 2328 2329 2330 |
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();
| > > > | > | > > > | 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 |
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();
if(4==nYear){
Blob urlParams = empty_blob;
blob_appendf(&urlParams, "y=%T", zYear);
stats_report_event_types_menu("byweek", blob_str(&urlParams));
blob_reset(&urlParams);
}else{
stats_report_event_types_menu("byweek", NULL);
}
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);
cgi_printf("Select year: ");
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);
|
| ︙ | ︙ | |||
2416 2417 2418 2419 2420 2421 2422 |
}
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'"
| | | 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 |
}
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='width:%d%%;'> </div>",
nSize);
}
cgi_printf("</td></tr>");
}
db_finalize(&stWeek);
free(zDefaultYear);
cgi_printf("</tbody></table>");
|
| ︙ | ︙ | |||
2458 2459 2460 2461 2462 2463 2464 2465 2466 |
** 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");
| > > > < | 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 |
** 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");
login_check_credentials();
if( !g.perm.Read ){ login_needed(); return; }
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.
| ︙ | ︙ | |||
135 136 137 138 139 140 141 |
*/
static void initializeVariablesFromDb(void){
const char *zName;
Stmt q;
int i, n, size, j;
zName = PD("name","-none-");
| | | > | 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 |
*/
static void initializeVariablesFromDb(void){
const char *zName;
Stmt q;
int i, n, size, j;
zName = PD("name","-none-");
db_prepare(&q, "SELECT datetime(tkt_mtime%s) AS tkt_datetime, *"
" FROM ticket WHERE tkt_uuid GLOB '%q*'",
timeline_utc(), zName);
if( db_step(&q)==SQLITE_ROW ){
n = db_column_count(&q);
for(i=0; i<n; i++){
const char *zVal = db_column_text(&q, i);
const char *zName = db_column_name(&q, i);
char *zRevealed = 0;
if( zVal==0 ){
|
| ︙ | ︙ | |||
511 512 513 514 515 516 517 |
aField[idx].zAppend = mprintf("%.*s", argl[2], argv[2]);
return TH_OK;
}
/*
** Write a ticket into the repository.
*/
| | > | > > > | > > | 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 |
aField[idx].zAppend = mprintf("%.*s", argl[2], argv[2]);
return TH_OK;
}
/*
** Write a ticket into the repository.
*/
static int ticket_put(
Blob *pTicket, /* The text of the ticket change record */
const char *zTktId, /* The ticket to which this change is applied */
int needMod /* True if moderation is needed */
){
int result;
int rid = content_put_ex(pTicket, 0, 0, 0, needMod);
if( rid==0 ){
fossil_fatal("trouble committing ticket: %s", g.zErrMsg);
}
if( needMod ){
moderation_table_create();
db_multi_exec(
"INSERT INTO modreq(objid, tktid) VALUES(%d,'%s')",
rid, zTktId
);
}else{
db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d);", rid);
db_multi_exec("INSERT OR IGNORE INTO unclustered VALUES(%d);", rid);
}
manifest_crosslink_begin();
result = (manifest_crosslink(rid, pTicket, MC_NONE)==0);
assert( blob_is_reset(pTicket) );
if( !result ){
result = manifest_crosslink_end(MC_PERMIT_HOOKS);
}else{
manifest_crosslink_end(MC_NONE);
}
return result;
}
/*
** Subscript command: submit_ticket
**
** 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
|
| ︙ | ︙ | |||
901 902 903 904 905 906 907 |
tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname GLOB 'tkt-%q*'",zUuid);
if( tagid==0 ){
@ No such ticket: %h(zUuid)
style_footer();
return;
}
db_prepare(&q,
| | | | | 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 |
tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname GLOB 'tkt-%q*'",zUuid);
if( tagid==0 ){
@ No such ticket: %h(zUuid)
style_footer();
return;
}
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",
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);
|
| ︙ | ︙ | |||
1210 1211 1212 1213 1214 1215 1216 |
}
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,
| | | | | 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 |
}
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);
|
| ︙ | ︙ | |||
1255 1256 1257 1258 1259 1260 1261 |
for(i=0; i<pTicket->nField; i++){
Blob val;
const char *z;
z = pTicket->aField[i].zName;
blob_set(&val, pTicket->aField[i].zValue);
if( z[0]=='+' ){
fossil_print(" Append to ");
| | | | | | | | 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 |
for(i=0; i<pTicket->nField; i++){
Blob val;
const char *z;
z = pTicket->aField[i].zName;
blob_set(&val, pTicket->aField[i].zValue);
if( z[0]=='+' ){
fossil_print(" Append to ");
z++;
}else{
fossil_print(" Change ");
}
fossil_print("%h: ",z);
if( blob_size(&val)>50 || contains_newline(&val)) {
fossil_print("\n ",blob_str(&val));
comment_print(blob_str(&val),4,79);
}else{
fossil_print("%s\n",blob_str(&val));
}
blob_reset(&val);
}
|
| ︙ | ︙ | |||
1342 1343 1344 1345 1346 1347 1348 |
aField[i].zName, strlen(zValue), zValue);
}
}
blob_appendf(&tktchng, "K %s\n", zTktUuid);
blob_appendf(&tktchng, "U %F\n", zUser);
md5sum_blob(&tktchng, &cksum);
blob_appendf(&tktchng, "Z %b\n", &cksum);
| | > > | > | 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 |
aField[i].zName, strlen(zValue), zValue);
}
}
blob_appendf(&tktchng, "K %s\n", zTktUuid);
blob_appendf(&tktchng, "U %F\n", zUser);
md5sum_blob(&tktchng, &cksum);
blob_appendf(&tktchng, "Z %b\n", &cksum);
if( ticket_put(&tktchng, zTktUuid, 0) ){
fossil_fatal("%s\n", g.zErrMsg);
}else{
fossil_print("ticket %s succeeded for %s\n",
(eCmd==set?"set":"add"),zTktUuid);
}
}
}
}
|
Changes to src/update.c.
| ︙ | ︙ | |||
351 352 353 354 355 356 357 |
" isexe, islinkv, islinkt, deleted FROM fv ORDER BY 1"
);
db_prepare(&mtimeXfer,
"UPDATE vfile SET mtime=(SELECT mtime FROM vfile WHERE id=:idv)"
" WHERE id=:idt"
);
assert( g.zLocalRoot!=0 );
| | | 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 |
" isexe, islinkv, islinkt, deleted FROM fv ORDER BY 1"
);
db_prepare(&mtimeXfer,
"UPDATE vfile SET mtime=(SELECT mtime FROM vfile WHERE id=:idv)"
" WHERE id=:idt"
);
assert( g.zLocalRoot!=0 );
assert( strlen(g.zLocalRoot)>0 );
assert( g.zLocalRoot[strlen(g.zLocalRoot)-1]=='/' );
while( db_step(&q)==SQLITE_ROW ){
const char *zName = db_column_text(&q, 0); /* The filename from root */
int idv = db_column_int(&q, 1); /* VFILE entry for current */
int ridv = db_column_int(&q, 2); /* RecordID for current */
int idt = db_column_int(&q, 3); /* VFILE entry for target */
int ridt = db_column_int(&q, 4); /* RecordID for target */
|
| ︙ | ︙ |
Changes to src/url.c.
| ︙ | ︙ | |||
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 |
**
*******************************************************************************
**
** This file contains code for parsing URLs that appear on the command-line
*/
#include "config.h"
#include "url.h"
#if INTERFACE
/*
** Flags for url_parse()
*/
#define URL_PROMPT_PW 0x001 /* Prompt for password if needed */
#define URL_REMEMBER 0x002 /* Remember the url for later reuse */
#define URL_ASK_REMEMBER_PW 0x004 /* Ask whether to remember prompted pw */
#define URL_REMEMBER_PW 0x008 /* Should remember pw */
#define URL_PROMPTED 0x010 /* Prompted for PW already */
#endif /* INTERFACE */
/*
** Convert a string to lower-case.
*/
static void url_tolower(char *z){
while( *z ){
*z = fossil_tolower(*z);
z++;
}
}
/*
** 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:
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 |
**
*******************************************************************************
**
** This file contains code for parsing URLs that appear on the command-line
*/
#include "config.h"
#include "url.h"
#include <stdio.h>
#ifdef _WIN32
#include <io.h>
#ifndef isatty
#define isatty(d) _isatty(d)
#endif
#ifndef fileno
#define fileno(s) _fileno(s)
#endif
#endif
#if INTERFACE
/*
** Flags for url_parse()
*/
#define URL_PROMPT_PW 0x001 /* Prompt for password if needed */
#define URL_REMEMBER 0x002 /* Remember the url for later reuse */
#define URL_ASK_REMEMBER_PW 0x004 /* Ask whether to remember prompted pw */
#define URL_REMEMBER_PW 0x008 /* Should remember pw */
#define URL_PROMPTED 0x010 /* Prompted for PW already */
/*
** The URL related data used with this subsystem.
*/
struct UrlData {
/*
** NOTE: These members MUST be kept in sync with the related ones in the
** "Global" structure defined in "main.c".
*/
int isFile; /* True if a "file:" url */
int isHttps; /* True if a "https:" url */
int isSsh; /* True if an "ssh:" url */
char *name; /* Hostname for http: or filename for file: */
char *hostname; /* The HOST: parameter on http headers */
char *protocol; /* "http" or "https" */
int port; /* TCP port number for http: or https: */
int dfltPort; /* The default port for the given protocol */
char *path; /* Pathname for http: */
char *user; /* User id for http: */
char *passwd; /* Password for http: */
char *canonical; /* Canonical representation of the URL */
char *proxyAuth; /* Proxy-Authorizer: string */
char *fossil; /* The fossil query parameter on ssh: */
unsigned flags; /* Boolean flags controlling URL processing */
int useProxy; /* Used to remember that a proxy is in use */
char *proxyUrlPath;
int proxyOrigPort; /* Tunneled port number for https through proxy */
};
#endif /* INTERFACE */
/*
** Convert a string to lower-case.
*/
static void url_tolower(char *z){
while( *z ){
*z = fossil_tolower(*z);
z++;
}
}
/*
** Parse the given URL. Populate members of the provided UrlData structure
** as follows:
**
** isFile True if FILE:
** isHttps True if HTTPS:
** isSsh True if SSH:
** protocol "http" or "https" or "file"
** name Hostname for HTTP:, HTTPS:, SSH:. Filename for FILE:
** port TCP port number for HTTP or HTTPS.
** dfltPort Default TCP port number (80 or 443).
** path Path name for HTTP or HTTPS.
** user Userid.
** passwd Password.
** hostname HOST:PORT or just HOST if port is the default.
** canonical The URL in canonical form, omitting the password
**
*/
void url_parse_local(
const char *zUrl,
unsigned int urlFlags,
UrlData *pUrlData
){
int i, j, c;
char *zFile = 0;
if( zUrl==0 ){
zUrl = db_get("last-sync-url", 0);
if( zUrl==0 ) return;
if( pUrlData->passwd==0 ){
pUrlData->passwd = unobscure(db_get("last-sync-pw", 0));
}
}
if( strncmp(zUrl, "http://", 7)==0
|| strncmp(zUrl, "https://", 8)==0
|| strncmp(zUrl, "ssh://", 6)==0
){
int iStart;
char *zLogin;
char *zExe;
char cQuerySep = '?';
pUrlData->isFile = 0;
pUrlData->useProxy = 0;
if( zUrl[4]=='s' ){
pUrlData->isHttps = 1;
pUrlData->protocol = "https";
pUrlData->dfltPort = 443;
iStart = 8;
}else if( zUrl[0]=='s' ){
pUrlData->isSsh = 1;
pUrlData->protocol = "ssh";
pUrlData->dfltPort = 22;
pUrlData->fossil = "fossil";
iStart = 6;
}else{
pUrlData->isHttps = 0;
pUrlData->protocol = "http";
pUrlData->dfltPort = 80;
iStart = 7;
}
for(i=iStart; (c=zUrl[i])!=0 && c!='/' && c!='@'; i++){}
if( c=='@' ){
/* Parse up the user-id and password */
for(j=iStart; j<i && zUrl[j]!=':'; j++){}
pUrlData->user = mprintf("%.*s", j-iStart, &zUrl[iStart]);
dehttpize(pUrlData->user);
if( j<i ){
if( ( urlFlags & URL_REMEMBER ) && pUrlData->isSsh==0 ){
urlFlags |= URL_ASK_REMEMBER_PW;
}
pUrlData->passwd = mprintf("%.*s", i-j-1, &zUrl[j+1]);
dehttpize(pUrlData->passwd);
}
if( pUrlData->isSsh ){
urlFlags &= ~URL_ASK_REMEMBER_PW;
}
zLogin = mprintf("%t@", pUrlData->user);
for(j=i+1; (c=zUrl[j])!=0 && c!='/' && c!=':'; j++){}
pUrlData->name = mprintf("%.*s", j-i-1, &zUrl[i+1]);
i = j;
}else{
for(i=iStart; (c=zUrl[i])!=0 && c!='/' && c!=':'; i++){}
pUrlData->name = mprintf("%.*s", i-iStart, &zUrl[iStart]);
zLogin = mprintf("");
}
url_tolower(pUrlData->name);
if( c==':' ){
pUrlData->port = 0;
i++;
while( (c = zUrl[i])!=0 && fossil_isdigit(c) ){
pUrlData->port = pUrlData->port*10 + c - '0';
i++;
}
pUrlData->hostname = mprintf("%s:%d", pUrlData->name, pUrlData->port);
}else{
pUrlData->port = pUrlData->dfltPort;
pUrlData->hostname = pUrlData->name;
}
dehttpize(pUrlData->name);
pUrlData->path = mprintf("%s", &zUrl[i]);
for(i=0; pUrlData->path[i] && pUrlData->path[i]!='?'; i++){}
if( pUrlData->path[i] ){
pUrlData->path[i] = 0;
i++;
}
zExe = mprintf("");
while( pUrlData->path[i]!=0 ){
char *zName, *zValue;
zName = &pUrlData->path[i];
zValue = zName;
while( pUrlData->path[i] && pUrlData->path[i]!='=' ){ i++; }
if( pUrlData->path[i]=='=' ){
pUrlData->path[i] = 0;
i++;
zValue = &pUrlData->path[i];
while( pUrlData->path[i] && pUrlData->path[i]!='&' ){ i++; }
}
if( pUrlData->path[i] ){
pUrlData->path[i] = 0;
i++;
}
if( fossil_strcmp(zName,"fossil")==0 ){
pUrlData->fossil = zValue;
dehttpize(pUrlData->fossil);
zExe = mprintf("%cfossil=%T", cQuerySep, pUrlData->fossil);
cQuerySep = '&';
}
}
dehttpize(pUrlData->path);
if( pUrlData->dfltPort==pUrlData->port ){
pUrlData->canonical = mprintf(
"%s://%s%T%T%s",
pUrlData->protocol, zLogin, pUrlData->name, pUrlData->path, zExe
);
}else{
pUrlData->canonical = mprintf(
"%s://%s%T:%d%T%s",
pUrlData->protocol, zLogin, pUrlData->name, pUrlData->port,
pUrlData->path, zExe
);
}
if( pUrlData->isSsh && pUrlData->path[1] ) pUrlData->path++;
free(zLogin);
}else if( strncmp(zUrl, "file:", 5)==0 ){
pUrlData->isFile = 1;
if( zUrl[5]=='/' && zUrl[6]=='/' ){
i = 7;
}else{
i = 5;
}
zFile = mprintf("%s", &zUrl[i]);
}else if( file_isfile(zUrl) ){
pUrlData->isFile = 1;
zFile = mprintf("%s", zUrl);
}else if( file_isdir(zUrl)==1 ){
zFile = mprintf("%s/FOSSIL", zUrl);
if( file_isfile(zFile) ){
pUrlData->isFile = 1;
}else{
free(zFile);
fossil_fatal("unknown repository: %s", zUrl);
}
}else{
fossil_fatal("unknown repository: %s", zUrl);
}
if( urlFlags ) pUrlData->flags = urlFlags;
if( pUrlData->isFile ){
Blob cfile;
dehttpize(zFile);
file_canonical_name(zFile, &cfile, 0);
free(zFile);
pUrlData->protocol = "file";
pUrlData->path = "";
pUrlData->name = mprintf("%b", &cfile);
pUrlData->canonical = mprintf("file://%T", pUrlData->name);
blob_reset(&cfile);
}else if( pUrlData->user!=0 && pUrlData->passwd==0 && (urlFlags & URL_PROMPT_PW) ){
url_prompt_for_password_local(pUrlData);
}else if( pUrlData->user!=0 && ( urlFlags & URL_ASK_REMEMBER_PW ) ){
if( isatty(fileno(stdin)) ){
if( save_password_prompt(pUrlData->passwd) ){
pUrlData->flags = urlFlags |= URL_REMEMBER_PW;
}else{
pUrlData->flags = urlFlags &= ~URL_REMEMBER_PW;
}
}
}
}
/*
** 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:
|
| ︙ | ︙ | |||
62 63 64 65 66 67 68 | ** ** HTTP url format as follows (HTTPS is the same with a different scheme): ** ** http://userid:password@host:port/path ** ** SSH url format is: ** | | < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 |
**
** 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?
**
|
| ︙ | ︙ | |||
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 |
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.
| > > > > > > > | 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 |
zProxy = fossil_getenv("http_proxy");
}
}
if( zProxy && zProxy[0] && !is_false(zProxy)
&& !g.urlIsSsh && !g.urlIsFile ){
char *zOriginalUrl = g.urlCanonical;
char *zOriginalHost = g.urlHostname;
int fOriginalIsHttps = g.urlIsHttps;
char *zOriginalUser = g.urlUser;
char *zOriginalPasswd = g.urlPasswd;
char *zOriginalUrlPath = g.urlPath;
int iOriginalPort = g.urlPort;
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.urlIsHttps = fOriginalIsHttps;
g.useProxy = 1;
g.proxyUrlPath = zOriginalUrlPath;
g.proxyOrigPort = iOriginalPort;
g.urlFlags = uOriginalFlags;
}
}
#if INTERFACE
/*
** An instance of this object is used to build a URL with query parameters.
|
| ︙ | ︙ | |||
426 427 428 429 430 431 432 |
blob_appendf(&p->url, "%s%s", zSep, zName2);
if( zValue2[0] ) blob_appendf(&p->url, "=%T", zValue2);
}
return blob_str(&p->url);
}
/*
| | > | | | | | | | | | | | < < | > | > > > > > > > > | > | | | | < > | | 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 |
blob_appendf(&p->url, "%s%s", zSep, zName2);
if( zValue2[0] ) blob_appendf(&p->url, "=%T", zValue2);
}
return blob_str(&p->url);
}
/*
** Prompt the user for the password that corresponds to the "user" member of
** the provided UrlData structure. Store the result into the "passwd" member
** of the provided UrlData structure.
*/
void url_prompt_for_password_local(UrlData *pUrlData){
if( pUrlData->isSsh || pUrlData->isFile ) return;
if( isatty(fileno(stdin))
&& (pUrlData->flags & URL_PROMPT_PW)!=0
&& (pUrlData->flags & URL_PROMPTED)==0
){
pUrlData->flags |= URL_PROMPTED;
pUrlData->passwd = prompt_for_user_password(pUrlData->user);
if( pUrlData->passwd[0]
&& (pUrlData->flags & (URL_REMEMBER|URL_ASK_REMEMBER_PW))!=0
){
if( save_password_prompt(pUrlData->passwd) ){
pUrlData->flags |= URL_REMEMBER_PW;
}else{
pUrlData->flags &= ~URL_REMEMBER_PW;
}
}
}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.
| ︙ | ︙ | |||
130 131 132 133 134 135 136 | } blob_reset(&secondTry); } /* ** Prompt to save Fossil user password */ | | > > > > | 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 |
}
blob_reset(&secondTry);
}
/*
** Prompt to save Fossil user password
*/
int save_password_prompt(const char *passwd){
Blob x;
char c;
const char *old = db_get("last-sync-pw", 0);
if( (old!=0) && fossil_strcmp(unobscure(old), passwd)==0 ){
return 0;
}
prompt_user("remember password (Y/n)? ", &x);
c = blob_str(&x)[0];
blob_reset(&x);
return ( c!='n' && c!='N' );
}
/*
|
| ︙ | ︙ | |||
288 289 290 291 292 293 294 |
db_multi_exec("UPDATE user SET pw=%Q, mtime=now() WHERE uid=%d",
zSecret, uid);
free(zSecret);
}
}else if( n>=2 && strncmp(g.argv[2],"capabilities",2)==0 ){
int uid;
if( g.argc!=4 && g.argc!=5 ){
| | | 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 |
db_multi_exec("UPDATE user SET pw=%Q, mtime=now() WHERE uid=%d",
zSecret, uid);
free(zSecret);
}
}else if( n>=2 && strncmp(g.argv[2],"capabilities",2)==0 ){
int uid;
if( g.argc!=4 && g.argc!=5 ){
usage("capabilities USERNAME ?PERMISSIONS?");
}
uid = db_int(0, "SELECT uid FROM user WHERE login=%Q", g.argv[3]);
if( uid==0 ){
fossil_fatal("no such user: %s", g.argv[3]);
}
if( g.argc==5 ){
db_multi_exec(
|
| ︙ | ︙ | |||
444 445 446 447 448 449 450 |
"(SELECT rowid FROM accesslog ORDER BY rowid DESC"
" LIMIT -1 OFFSET 200)");
cgi_redirectf("%s/access_log?y=%d&n=%d", g.zTop, y, n);
return;
}
style_header("Access Log");
blob_zero(&sql);
| | | | | 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 |
"(SELECT rowid FROM accesslog ORDER BY rowid DESC"
" LIMIT -1 OFFSET 200)");
cgi_redirectf("%s/access_log?y=%d&n=%d", g.zTop, y, n);
return;
}
style_header("Access Log");
blob_zero(&sql);
blob_appendf(&sql,
"SELECT uname, ipaddr, datetime(mtime%s), success"
" FROM accesslog", timeline_utc()
);
if( y==1 ){
blob_append(&sql, " WHERE success", -1);
}else if( y==2 ){
blob_append(&sql, " WHERE NOT success", -1);
}
blob_appendf(&sql," ORDER BY rowid DESC LIMIT %d OFFSET %d", n+1, skip);
|
| ︙ | ︙ |
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 |
** 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 = fossil_malloc( nByte );
WideCharToMultiByte(CP_UTF8, 0, zUnicode, -1, zUtf, nByte, 0, 0);
return zUtf;
#else
static Stmt q;
char *zUtf8;
db_static_prepare(&q, "SELECT :utf8");
db_bind_text16(&q, ":utf8", zUnicode);
db_step(&q);
zUtf8 = fossil_strdup(db_column_text(&q, 0));
db_reset(&q);
return zUtf8;
#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 = fossil_malloc( nByte * 2 );
MultiByteToWideChar(CP_UTF8, 0, zUtf8, -1, zUnicode, nByte);
return zUnicode;
#else
assert( 0 ); /* Never used in unix */
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){
fossil_free(pOld);
}
#if defined(__APPLE__) && !defined(WITHOUT_ICONV)
# include <iconv.h>
#endif
/*
|
| ︙ | ︙ | |||
177 178 179 180 181 182 183 | ** 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 | > | > > > > > > > > > > > | > > | > > > > > > | 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 |
** 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, except in the 'extended path' prefix ('?') and
** as drive specifier (':'). Therefore, translate those to characters
** 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 "//?/" or "\\?\" (extended path), translate
** any slashes to backslashes but leave the '?' intact
*/
if( (zUtf8[0]=='\\' || zUtf8[0]=='/') && (zUtf8[1]=='\\' || zUtf8[1]=='/')
&& zUtf8[2]=='?' && (zUtf8[3]=='\\' || zUtf8[3]=='/')) {
wUnicode[0] = wUnicode[1] = wUnicode[3] = '\\';
zUtf8 += 4;
wUnicode += 4;
}
/*
** If (remainder of) path starts with "<drive>:/" or "<drive>:\",
** leave the ':' intact
*/
if( fossil_isalpha(zUtf8[0]) && zUtf8[1]==':'
&& (zUtf8[2]=='\\' || zUtf8[2]=='/')) {
wUnicode[2] = '\\';
wUnicode += 3;
}
/*
** In the remainder of the path, translate invalid characters to
** characters in the Unicode private use area. This is what makes
** Win32 fossil.exe work well in a Cygwin environment even when a
** filename contains characters which are invalid for Win32.
*/
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().
|
| ︙ | ︙ | |||
646 647 648 649 650 651 652 |
*/
void vfile_aggregate_checksum_disk(int vid, Blob *pOut){
FILE *in;
Stmt q;
char zBuf[4096];
db_must_be_within_tree();
| | | | 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 |
*/
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 ){
|
| ︙ | ︙ | |||
696 697 698 699 700 701 702 |
}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;
| | | 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 |
}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 || vid==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);
|
| ︙ | ︙ | |||
735 736 737 738 739 740 741 |
** 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;
| | | | 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 |
** 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 ){
|
| ︙ | ︙ | |||
801 802 803 804 805 806 807 |
*/
void vfile_aggregate_checksum_repository(int vid, Blob *pOut){
Blob file;
Stmt q;
char zBuf[100];
db_must_be_within_tree();
| | | | | 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 |
*/
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))"
" %s AND vid=%d"
" ORDER BY if_selected(id,pathname,origname) /*scan*/",
(vid ? "AND rid>0" : ""), 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);
|
| ︙ | ︙ | |||
839 840 841 842 843 844 845 | ** ** 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 | | | 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 |
**
** 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.
| ︙ | ︙ | |||
25 26 27 28 29 30 31 | /* ** Return true if the input string is a well-formed wiki page name. ** ** Well-formed wiki page names do not begin or end with whitespace, ** and do not contain tabs or other control characters and do not ** contain more than a single space character in a row. Well-formed | | | | | 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 |
/*
** Return true if the input string is a well-formed wiki page name.
**
** Well-formed wiki page names do not begin or end with whitespace,
** and do not contain tabs or other control characters and do not
** contain more than a single space character in a row. Well-formed
** names must be between 1 and 100 characters in length, inclusive.
*/
int wiki_name_is_wellformed(const unsigned char *z){
int i;
if( z[0]<=0x20 ){
return 0;
}
for(i=1; z[i]; i++){
if( z[i]<0x20 ) return 0;
if( z[i]==0x20 && z[i-1]==0x20 ) return 0;
}
if( z[i-1]==' ' ) return 0;
if( i<1 || i>100 ) return 0;
return 1;
}
/*
** Output rules for well-formed wiki pages
*/
static void well_formed_wiki_name_rules(void){
@ <ul>
@ <li> Must not begin or end with a space.</li>
@ <li> Must not contain any control characters, including tab or
@ newline.</li>
@ <li> Must not have two or more spaces in a row internally.</li>
@ <li> Must be between 1 and 100 characters in length.</li>
@ </ul>
}
/*
** Check a wiki name. If it is not well-formed, then issue an error
** and return true. If it is well-formed, return false.
*/
|
| ︙ | ︙ | |||
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 |
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 ){
|
| ︙ | ︙ | |||
258 259 260 261 262 263 264 |
}
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 ){
| | | 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 |
}
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);
}
|
| ︙ | ︙ | |||
292 293 294 295 296 297 298 |
}else{
nrid = content_put_ex(pWiki, 0, 0, 0, 1);
moderation_table_create();
db_multi_exec("INSERT INTO modreq(objid) VALUES(%d)", nrid);
}
db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", nrid);
db_multi_exec("INSERT OR IGNORE INTO unclustered VALUES(%d);", nrid);
| | | | 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 |
}else{
nrid = content_put_ex(pWiki, 0, 0, 0, 1);
moderation_table_create();
db_multi_exec("INSERT INTO modreq(objid) VALUES(%d)", nrid);
}
db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", nrid);
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 *const 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();
|
| ︙ | ︙ | |||
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 |
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);
|
| ︙ | ︙ | |||
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();
|
| ︙ | ︙ | |||
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 879 880 881 |
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>
}
db_finalize(&q);
@ </ul>
style_footer();
|
| ︙ | ︙ | |||
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
|
| ︙ | ︙ | |||
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.
| ︙ | ︙ | |||
162 163 164 165 166 167 168 | ** 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 228 229 230 231 232 233 | ** 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_HTML5_ARTICLE 3 #define MARKUP_HTML5_ASIDE 4 #define MARKUP_B 5 #define MARKUP_BIG 6 #define MARKUP_BLOCKQUOTE 7 #define MARKUP_BR 8 #define MARKUP_CENTER 9 #define MARKUP_CITE 10 #define MARKUP_CODE 11 #define MARKUP_COL 12 #define MARKUP_COLGROUP 13 #define MARKUP_DD 14 #define MARKUP_DFN 15 #define MARKUP_DIV 16 #define MARKUP_DL 17 #define MARKUP_DT 18 #define MARKUP_EM 19 #define MARKUP_FONT 20 #define MARKUP_HTML5_FOOTER 21 #define MARKUP_H1 22 #define MARKUP_H2 23 #define MARKUP_H3 24 #define MARKUP_H4 25 #define MARKUP_H5 26 #define MARKUP_H6 27 #define MARKUP_HTML5_HEADER 28 #define MARKUP_HR 29 #define MARKUP_I 30 #define MARKUP_IMG 31 #define MARKUP_KBD 32 #define MARKUP_LI 33 #define MARKUP_HTML5_NAV 34 #define MARKUP_NOBR 35 #define MARKUP_NOWIKI 36 #define MARKUP_OL 37 #define MARKUP_P 38 #define MARKUP_PRE 39 #define MARKUP_S 40 #define MARKUP_SAMP 41 #define MARKUP_HTML5_SECTION 42 #define MARKUP_SMALL 43 #define MARKUP_SPAN 44 #define MARKUP_STRIKE 45 #define MARKUP_STRONG 46 #define MARKUP_SUB 47 #define MARKUP_SUP 48 #define MARKUP_TABLE 49 #define MARKUP_TBODY 50 #define MARKUP_TD 51 #define MARKUP_TFOOT 52 #define MARKUP_TH 53 #define MARKUP_THEAD 54 #define MARKUP_TR 55 #define MARKUP_TT 56 #define MARKUP_U 57 #define MARKUP_UL 58 #define MARKUP_VAR 59 #define MARKUP_VERBATIM 60 /* ** 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> */ |
| ︙ | ︙ | |||
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 },
| > > > > > | 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 |
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 },
{ "article", MARKUP_HTML5_ARTICLE, MUTYPE_BLOCK,
AMSK_ID|AMSK_CLASS|AMSK_STYLE },
{ "aside", MARKUP_HTML5_ASIDE, MUTYPE_BLOCK,
AMSK_ID|AMSK_CLASS|AMSK_STYLE },
{ "b", MARKUP_B, MUTYPE_FONT, AMSK_STYLE },
{ "big", MARKUP_BIG, MUTYPE_FONT, AMSK_STYLE },
{ "blockquote", MARKUP_BLOCKQUOTE, MUTYPE_BLOCK, AMSK_STYLE },
{ "br", MARKUP_BR, MUTYPE_SINGLE, AMSK_CLEAR },
{ "center", MARKUP_CENTER, MUTYPE_BLOCK, AMSK_STYLE },
{ "cite", MARKUP_CITE, MUTYPE_FONT, AMSK_STYLE },
{ "code", MARKUP_CODE, MUTYPE_FONT, AMSK_STYLE },
|
| ︙ | ︙ | |||
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 },
| > > > > > > > > > > > | 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 |
AMSK_ID|AMSK_CLASS|AMSK_STYLE },
{ "dl", MARKUP_DL, MUTYPE_LIST,
AMSK_COMPACT|AMSK_STYLE },
{ "dt", MARKUP_DT, MUTYPE_LI, AMSK_STYLE },
{ "em", MARKUP_EM, MUTYPE_FONT, AMSK_STYLE },
{ "font", MARKUP_FONT, MUTYPE_FONT,
AMSK_COLOR|AMSK_FACE|AMSK_SIZE|AMSK_STYLE },
{ "footer", MARKUP_HTML5_FOOTER, MUTYPE_BLOCK,
AMSK_ID|AMSK_CLASS|AMSK_STYLE },
{ "h1", MARKUP_H1, MUTYPE_BLOCK,
AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE },
{ "h2", MARKUP_H2, MUTYPE_BLOCK,
AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE },
{ "h3", MARKUP_H3, MUTYPE_BLOCK,
AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE },
{ "h4", MARKUP_H4, MUTYPE_BLOCK,
AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE },
{ "h5", MARKUP_H5, MUTYPE_BLOCK,
AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE },
{ "h6", MARKUP_H6, MUTYPE_BLOCK,
AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE },
{ "header", MARKUP_HTML5_HEADER, MUTYPE_BLOCK,
AMSK_ID|AMSK_CLASS|AMSK_STYLE },
{ "hr", MARKUP_HR, MUTYPE_SINGLE,
AMSK_ALIGN|AMSK_COLOR|AMSK_SIZE|AMSK_WIDTH|
AMSK_STYLE|AMSK_CLASS },
{ "i", MARKUP_I, MUTYPE_FONT, AMSK_STYLE },
{ "img", MARKUP_IMG, MUTYPE_SINGLE,
AMSK_ALIGN|AMSK_ALT|AMSK_BORDER|AMSK_HEIGHT|
AMSK_HSPACE|AMSK_SRC|AMSK_VSPACE|AMSK_WIDTH|AMSK_STYLE },
{ "kbd", MARKUP_KBD, MUTYPE_FONT, AMSK_STYLE },
{ "li", MARKUP_LI, MUTYPE_LI,
AMSK_TYPE|AMSK_VALUE|AMSK_STYLE },
{ "nav", MARKUP_HTML5_NAV, MUTYPE_BLOCK,
AMSK_ID|AMSK_CLASS|AMSK_STYLE },
{ "nobr", MARKUP_NOBR, MUTYPE_FONT, 0 },
{ "nowiki", MARKUP_NOWIKI, MUTYPE_SPECIAL, 0 },
{ "ol", MARKUP_OL, MUTYPE_LIST,
AMSK_START|AMSK_TYPE|AMSK_COMPACT|AMSK_STYLE },
{ "p", MARKUP_P, MUTYPE_BLOCK,
AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE },
{ "pre", MARKUP_PRE, MUTYPE_BLOCK, AMSK_STYLE },
{ "s", MARKUP_S, MUTYPE_FONT, AMSK_STYLE },
{ "samp", MARKUP_SAMP, MUTYPE_FONT, AMSK_STYLE },
{ "section", MARKUP_HTML5_SECTION, MUTYPE_BLOCK,
AMSK_ID|AMSK_CLASS|AMSK_STYLE },
{ "small", MARKUP_SMALL, MUTYPE_FONT, AMSK_STYLE },
{ "span", MARKUP_SPAN, MUTYPE_BLOCK,
AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE },
{ "strike", MARKUP_STRIKE, MUTYPE_FONT, AMSK_STYLE },
{ "strong", MARKUP_STRONG, MUTYPE_FONT, AMSK_STYLE },
{ "sub", MARKUP_SUB, MUTYPE_FONT, AMSK_STYLE },
{ "sup", MARKUP_SUP, MUTYPE_FONT, AMSK_STYLE },
|
| ︙ | ︙ | |||
337 338 339 340 341 342 343 |
{ "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 */
| < | 359 360 361 362 363 364 365 366 367 368 369 370 371 372 |
{ "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.
|
| ︙ | ︙ | |||
1716 1717 1718 1719 1720 1721 1722 |
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;
| | > > > | > > | > > > | 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 |
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;
for(iStart=i+6; fossil_isspace(z[iStart]); iStart++){}
for(i=iStart; z[i] && (z[i]!='<' || strncmp(&z[i],"</title>",8)!=0); i++){}
if( strncmp(&z[i],"</title>",8)!=0 ){
blob_init(pTitle, 0, 0);
blob_init(pTail, &z[iStart], -1);
return 1;
}
if( i-iStart>0 ){
blob_init(pTitle, &z[iStart], i-iStart);
}else{
blob_init(pTitle, 0, 0);
}
blob_init(pTail, &z[i+8], -1);
return 1;
}
/*
** Parse text looking for wiki hyperlinks in one of the formats:
**
|
| ︙ | ︙ |
Added src/winfile.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 |
/*
** Copyright (c) 2006 D. Richard Hipp
**
** This program is free software; you can redistribute it and/or
** modify it under the terms of the Simplified BSD License (also
** known as the "2-Clause License" or "FreeBSD License".)
** This program is distributed in the hope that it will be useful,
** but without any warranty; without even the implied warranty of
** merchantability or fitness for a particular purpose.
**
** Author contact information:
** drh@hwaci.com
** http://www.hwaci.com/drh/
**
*******************************************************************************
**
** This file implements several non-trivial file handling wrapper functions
** on Windows using the Win32 API.
*/
#include "config.h"
#ifdef _WIN32
/* This code is for win32 only */
#include <sys/stat.h>
#include <windows.h>
#include "winfile.h"
#ifndef LABEL_SECURITY_INFORMATION
# define LABEL_SECURITY_INFORMATION (0x00000010L)
#endif
/*
** Fill stat buf with information received from stat() or lstat().
** lstat() is called on Unix if isWd is TRUE and allow-symlinks setting is on.
**
*/
int win32_stat(const char *zFilename, struct fossilStat *buf, int isWd){
WIN32_FILE_ATTRIBUTE_DATA attr;
wchar_t *zMbcs = fossil_utf8_to_filename(zFilename);
int rc = GetFileAttributesExW(zMbcs, GetFileExInfoStandard, &attr);
fossil_filename_free(zMbcs);
if( rc ){
ULARGE_INTEGER ull;
ull.LowPart = attr.ftLastWriteTime.dwLowDateTime;
ull.HighPart = attr.ftLastWriteTime.dwHighDateTime;
buf->st_mode = (attr.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ?
S_IFDIR : S_IFREG;
buf->st_size = (((i64)attr.nFileSizeHigh)<<32) | attr.nFileSizeLow;
buf->st_mtime = ull.QuadPart / 10000000ULL - 11644473600ULL;
}
return !rc;
}
/*
** Wrapper around the access() system call. This code was copied from Tcl
** 8.6 and then modified.
*/
int win32_access(const char *zFilename, int flags){
int rc = 0;
PSECURITY_DESCRIPTOR pSd = NULL;
unsigned long size;
PSID pSid = NULL;
BOOL sidDefaulted;
BOOL impersonated = FALSE;
SID_IDENTIFIER_AUTHORITY unmapped = {{0, 0, 0, 0, 0, 22}};
GENERIC_MAPPING genMap;
HANDLE hToken = NULL;
DWORD desiredAccess = 0, grantedAccess = 0;
BOOL accessYesNo = FALSE;
PRIVILEGE_SET privSet;
DWORD privSetSize = sizeof(PRIVILEGE_SET);
wchar_t *zMbcs = fossil_utf8_to_filename(zFilename);
DWORD attr = GetFileAttributesW(zMbcs);
if( attr==INVALID_FILE_ATTRIBUTES ){
/*
* File might not exist.
*/
if( GetLastError()!=ERROR_SHARING_VIOLATION ){
rc = -1; goto done;
}
}
if( flags==F_OK ){
/*
* File exists, nothing else to check.
*/
goto done;
}
if( (flags & W_OK)
&& (attr & FILE_ATTRIBUTE_READONLY)
&& !(attr & FILE_ATTRIBUTE_DIRECTORY) ){
/*
* The attributes say the file is not writable. If the file is a
* regular file (i.e., not a directory), then the file is not
* writable, full stop. For directories, the read-only bit is
* (mostly) ignored by Windows, so we can't ascertain anything about
* directory access from the attrib data.
*/
rc = -1; goto done;
}
/*
* It looks as if the permissions are ok, but if we are on NT, 2000 or XP,
* we have a more complex permissions structure so we try to check that.
* The code below is remarkably complex for such a simple thing as finding
* what permissions the OS has set for a file.
*/
/*
* First find out how big the buffer needs to be.
*/
size = 0;
GetFileSecurityW(zMbcs,
OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
DACL_SECURITY_INFORMATION | LABEL_SECURITY_INFORMATION,
0, 0, &size);
/*
* Should have failed with ERROR_INSUFFICIENT_BUFFER
*/
if( GetLastError()!=ERROR_INSUFFICIENT_BUFFER ){
/*
* Most likely case is ERROR_ACCESS_DENIED, which we will convert to
* EACCES - just what we want!
*/
rc = -1; goto done;
}
/*
* Now size contains the size of buffer needed.
*/
pSd = (PSECURITY_DESCRIPTOR)HeapAlloc(GetProcessHeap(), 0, size);
if( pSd==NULL ){
rc = -1; goto done;
}
/*
* Call GetFileSecurity() for real.
*/
if( !GetFileSecurityW(zMbcs,
OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
DACL_SECURITY_INFORMATION | LABEL_SECURITY_INFORMATION,
pSd, size, &size) ){
/*
* Error getting owner SD
*/
rc = -1; goto done;
}
/*
* As of Samba 3.0.23 (10-Jul-2006), unmapped users and groups are
* assigned to SID domains S-1-22-1 and S-1-22-2, where "22" is the
* top-level authority. If the file owner and group is unmapped then
* the ACL access check below will only test against world access,
* which is likely to be more restrictive than the actual access
* restrictions. Since the ACL tests are more likely wrong than
* right, skip them. Moreover, the unix owner access permissions are
* usually mapped to the Windows attributes, so if the user is the
* file owner then the attrib checks above are correct (as far as they
* go).
*/
if( !GetSecurityDescriptorOwner(pSd, &pSid, &sidDefaulted) ||
memcmp(GetSidIdentifierAuthority(pSid), &unmapped,
sizeof(SID_IDENTIFIER_AUTHORITY))==0 ){
goto done; /* Attrib tests say access allowed. */
}
/*
* Perform security impersonation of the user and open the resulting
* thread token.
*/
if( !ImpersonateSelf(SecurityImpersonation) ){
/*
* Unable to perform security impersonation.
*/
rc = -1; goto done;
}
impersonated = TRUE;
if( !OpenThreadToken(GetCurrentThread(),
TOKEN_DUPLICATE | TOKEN_QUERY, FALSE, &hToken) ){
/*
* Unable to get current thread's token.
*/
rc = -1; goto done;
}
/*
* Setup desiredAccess according to the access priveleges we are
* checking.
*/
if( flags & R_OK ){
desiredAccess |= FILE_GENERIC_READ;
}
if( flags & W_OK){
desiredAccess |= FILE_GENERIC_WRITE;
}
memset(&genMap, 0, sizeof(GENERIC_MAPPING));
genMap.GenericRead = FILE_GENERIC_READ;
genMap.GenericWrite = FILE_GENERIC_WRITE;
genMap.GenericExecute = FILE_GENERIC_EXECUTE;
genMap.GenericAll = FILE_ALL_ACCESS;
/*
* Perform access check using the token.
*/
if( !AccessCheck(pSd, hToken, desiredAccess, &genMap, &privSet,
&privSetSize, &grantedAccess, &accessYesNo) ){
/*
* Unable to perform access check.
*/
rc = -1; goto done;
}
if( !accessYesNo ) rc = -1;
done:
if( hToken != NULL ){
CloseHandle(hToken);
}
if( impersonated ){
RevertToSelf();
impersonated = FALSE;
}
if( pSd!=NULL ){
HeapFree(GetProcessHeap(), 0, pSd);
}
fossil_filename_free(zMbcs);
return rc;
}
/*
** Wrapper around the chdir() system call.
** If bChroot=1, do a chroot to this dir as well
** (UNIX only)
*/
int win32_chdir(const char *zChDir, int bChroot){
wchar_t *zPath = fossil_utf8_to_filename(zChDir);
int rc = (int)!SetCurrentDirectoryW(zPath);
fossil_filename_free(zPath);
return rc;
}
/*
** Get the current working directory.
**
** On windows, the name is converted from unicode to UTF8 and all '\\'
** characters are converted to '/'. No conversions are needed on
** unix.
*/
void win32_getcwd(char *zBuf, int nBuf){
int i;
char *zUtf8;
wchar_t *zWide = fossil_malloc( sizeof(wchar_t)*nBuf );
if( GetCurrentDirectoryW(nBuf, zWide)==0 ){
fossil_fatal("cannot find current working directory.");
}
zUtf8 = fossil_filename_to_utf8(zWide);
fossil_free(zWide);
for(i=0; zUtf8[i]; i++) if( zUtf8[i]=='\\' ) zUtf8[i] = '/';
strncpy(zBuf, zUtf8, nBuf);
fossil_filename_free(zUtf8);
}
#endif /* _WIN32 -- This code is for win32 only */
|
Changes to src/winhttp.c.
| ︙ | ︙ | |||
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);
| > > > | 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
*/
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 zCmdFName[MAX_PATH];
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, zCmdFName,
"%s_cmd%d.txt", zTempPrefix, p->id);
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);
|
| ︙ | ︙ | |||
106 107 108 109 110 111 112 |
}else{
break;
}
wanted -= got;
}
fclose(out);
out = 0;
| | | | > > > > > > > > > | 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 |
}else{
break;
}
wanted -= got;
}
fclose(out);
out = 0;
sqlite3_snprintf(sizeof(zCmd), zCmd, "%s%s\n%s\n%s\n%s",
get_utf8_bom(0), g.zRepositoryName, zRequestFName, zReplyFName,
inet_ntoa(p->addr.sin_addr)
);
out = fossil_fopen(zCmdFName, "wb");
if( out==0 ) goto end_request;
fwrite(zCmd, 1, strlen(zCmd), out);
fclose(out);
sqlite3_snprintf(sizeof(zCmd), zCmd, "\"%s\" http -args \"%s\" --nossl%s",
g.nameOfExe, zCmdFName, 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);
file_delete(zCmdFName);
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");
|
| ︙ | ︙ | |||
189 190 191 192 193 194 195 |
rid = content_put_ex(&content, blob_str(&hash), 0, 0, isPriv);
blob_reset(&hash);
if( rid==0 ){
blob_appendf(&pXfer->err, "%s", g.zErrMsg);
blob_reset(&content);
}else{
if( !isPriv ) content_make_public(rid);
| | | | 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 |
rid = content_put_ex(&content, blob_str(&hash), 0, 0, isPriv);
blob_reset(&hash);
if( rid==0 ){
blob_appendf(&pXfer->err, "%s", g.zErrMsg);
blob_reset(&content);
}else{
if( !isPriv ) content_make_public(rid);
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 |
/*
** 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;
|
| ︙ | ︙ | |||
697 698 699 700 701 702 703 |
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);
|
| ︙ | ︙ | |||
736 737 738 739 740 741 742 |
** 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 ){
|
| ︙ | ︙ | |||
770 771 772 773 774 775 776 |
}
/*
** 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));
|
| ︙ | ︙ | |||
818 819 820 821 822 823 824 |
** from a server without authorization.
*/
static void server_private_xfer_not_authorized(void){
@ error not\sauthorized\sto\ssync\sprivate\scontent
}
/*
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | < | > | < < | > > > > | | | < < < | > > > | | > > > > > > > > | | | 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 |
** from a server without authorization.
*/
static void server_private_xfer_not_authorized(void){
@ error not\sauthorized\sto\ssync\sprivate\scontent
}
/*
** Return the common TH1 code to evaluate prior to evaluating any other
** TH1 transfer notification scripts.
*/
const char *xfer_common_code(void){
return db_get("xfer-common-script", 0);
}
/*
** Return the TH1 code to evaluate when a push is processed.
*/
const char *xfer_push_code(void){
return db_get("xfer-push-script", 0);
}
/*
** Return the TH1 code to evaluate when a commit is processed.
*/
const char *xfer_commit_code(void){
return db_get("xfer-commit-script", 0);
}
/*
** Return the TH1 code to evaluate when a ticket change is processed.
*/
const char *xfer_ticket_code(void){
return db_get("xfer-ticket-script", 0);
}
/*
** Run the specified TH1 script, if any, and returns 1 on error.
*/
int xfer_run_script(const char *zScript, const char *zUuid){
int rc;
if( !zScript ) return TH_OK;
Th_FossilInit(TH_INIT_DEFAULT);
if( zUuid ){
rc = Th_SetVar(g.interp, "uuid", -1, zUuid, -1);
if( rc!=TH_OK ){
fossil_error(1, "%s", Th_GetResult(g.interp, 0));
return rc;
}
}
rc = Th_Eval(g.interp, 0, zScript, -1);
if( rc!=TH_OK ){
fossil_error(1, "%s", Th_GetResult(g.interp, 0));
}
return rc;
}
/*
** Runs the pre-transfer TH1 script, if any, and returns its return code.
** This script may be run multiple times. If the script performs actions
** that cannot be redone, it should use an internal [if] guard similar to
** the following:
**
** if {![info exists common_done]} {
** # ... code here
** set common_done 1
** }
*/
int xfer_run_common_script(void){
return xfer_run_script(xfer_common_code(), 0);
}
/*
** If this variable is set, disable login checks. Used for debugging
** only.
*/
static int disableLogin = 0;
|
| ︙ | ︙ | |||
873 874 875 876 877 878 879 880 881 882 883 884 885 886 |
Xfer xfer;
int deltaFlag = 0;
int isClone = 0;
int nGimme = 0;
int size;
int recvConfig = 0;
char *zNow;
if( fossil_strcmp(PD("REQUEST_METHOD","POST"),"POST") ){
fossil_redirect_home();
}
g.zLogin = "anonymous";
login_set_anon_nobody_capabilities();
login_check_credentials();
| > | 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 |
Xfer xfer;
int deltaFlag = 0;
int isClone = 0;
int nGimme = 0;
int size;
int recvConfig = 0;
char *zNow;
int rc;
if( fossil_strcmp(PD("REQUEST_METHOD","POST"),"POST") ){
fossil_redirect_home();
}
g.zLogin = "anonymous";
login_set_anon_nobody_capabilities();
login_check_credentials();
|
| ︙ | ︙ | |||
902 903 904 905 906 907 908 |
g.xferPanic = 1;
db_begin_transaction();
db_multi_exec(
"CREATE TEMP TABLE onremote(rid INTEGER PRIMARY KEY);"
);
manifest_crosslink_begin();
| | > | | 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 |
g.xferPanic = 1;
db_begin_transaction();
db_multi_exec(
"CREATE TEMP TABLE onremote(rid INTEGER PRIMARY KEY);"
);
manifest_crosslink_begin();
rc = xfer_run_common_script();
if( rc==TH_ERROR ){
cgi_reset_content();
@ error common\sscript\sfailed:\s%F(g.zErrMsg)
nErr++;
}
while( blob_line(xfer.pIn, &xfer.line) ){
if( blob_buffer(&xfer.line)[0]=='#' ) continue;
if( blob_size(&xfer.line)==0 ) continue;
xfer.nToken = blob_tokenize(&xfer.line, xfer.aToken, count(xfer.aToken));
|
| ︙ | ︙ | |||
990 991 992 993 994 995 996 |
}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
|
| ︙ | ︙ | |||
1099 1100 1101 1102 1103 1104 1105 |
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
){
|
| ︙ | ︙ | |||
1124 1125 1126 1127 1128 1129 1130 |
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) ){
|
| ︙ | ︙ | |||
1151 1152 1153 1154 1155 1156 1157 |
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
|
| ︙ | ︙ | |||
1229 1230 1231 1232 1233 1234 1235 |
cgi_reset_content();
@ error bad\scommand:\s%F(blob_str(&xfer.line))
}
blobarray_reset(xfer.aToken, xfer.nToken);
blob_reset(&xfer.line);
}
if( isPush ){
| > > | | | | > | 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 |
cgi_reset_content();
@ error bad\scommand:\s%F(blob_str(&xfer.line))
}
blobarray_reset(xfer.aToken, xfer.nToken);
blob_reset(&xfer.line);
}
if( isPush ){
if( rc==TH_OK ){
rc = xfer_run_script(xfer_push_code(), 0);
if( rc==TH_ERROR ){
cgi_reset_content();
@ error push\sscript\sfailed:\s%F(g.zErrMsg)
nErr++;
}
}
request_phantoms(&xfer, 500);
}
if( isClone && nGimme==0 ){
/* The initial "clone" message from client to server contains no
** "gimme" cards. On that initial message, send the client an "igot"
** card for every artifact currently in the repository. This will
|
| ︙ | ︙ | |||
1255 1256 1257 1258 1259 1260 1261 |
send_unclustered(&xfer);
if( xfer.syncPrivate ) send_private(&xfer);
}
if( recvConfig ){
configure_finalize_receive();
}
db_multi_exec("DROP TABLE onremote");
| | > | 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 |
send_unclustered(&xfer);
if( xfer.syncPrivate ) send_private(&xfer);
}
if( recvConfig ){
configure_finalize_receive();
}
db_multi_exec("DROP TABLE onremote");
manifest_crosslink_end(MC_PERMIT_HOOKS);
/* Send the server timestamp last, in case prior processing happened
** to use up a significant fraction of our time window.
*/
zNow = db_text(0, "SELECT strftime('%%Y-%%m-%%dT%%H:%%M:%%S', 'now')");
@ # timestamp %s(zNow)
free(zNow);
db_end_transaction(0);
configure_rebuild();
}
/*
** COMMAND: test-xfer
**
** This command is used for debugging the server. There is a single
** argument which is the uncompressed content of an "xfer" message
|
| ︙ | ︙ | |||
1366 1367 1368 1369 1370 1371 1372 |
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;
|
| ︙ | ︙ | |||
1440 1441 1442 1443 1444 1445 1446 |
/* 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 ){
|
| ︙ | ︙ | |||
1616 1617 1618 1619 1620 1621 1622 |
&& 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
|
| ︙ | ︙ | |||
1669 1670 1671 1672 1673 1674 1675 |
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.
*/
|
| ︙ | ︙ | |||
1691 1692 1693 1694 1695 1696 1697 |
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
|
| ︙ | ︙ | |||
1733 1734 1735 1736 1737 1738 1739 |
/* 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 1839 1840 |
/* 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++;
}
break;
|
| ︙ | ︙ | |||
1845 1846 1847 1848 1849 1850 1851 |
}
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.
| ︙ | ︙ | |||
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
void xfersetup_page(void){
login_check_credentials();
if( !g.perm.Setup ){
login_needed();
}
style_header("Transfer Setup");
@ <table border="0" cellspacing="20">
setup_menu_entry("Common", "xfersetup_com",
"Common TH1 code run before all transfer request processing.");
setup_menu_entry("Push", "xfersetup_push",
"Specific TH1 code to run after \"push\" transfer requests.");
@ </table>
style_footer();
}
/*
** Common implementation for the transfer setup editor pages.
*/
static void xfersetup_generic(
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 |
void xfersetup_page(void){
login_check_credentials();
if( !g.perm.Setup ){
login_needed();
}
style_header("Transfer Setup");
@ <table border="0" cellspacing="20">
setup_menu_entry("Common", "xfersetup_com",
"Common TH1 code run before all transfer request processing.");
setup_menu_entry("Push", "xfersetup_push",
"Specific TH1 code to run after \"push\" transfer requests.");
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);
}
@
@ <blockquote>
@ <form method="post" action="%s(g.zTop)/%s(g.zPath)"><div>
login_insert_csrf_secret();
@ <input type="submit" name="sync" value="%h(zButton)" />
@ </div></form>
@ </blockquote>
@
}
style_footer();
}
/*
** Common implementation for the transfer setup editor pages.
*/
static void xfersetup_generic(
|
| ︙ | ︙ | |||
138 139 140 141 142 143 144 145 146 147 148 |
;
xfersetup_generic(
"Transfer Push Script",
"xfer-push-script",
zDefaultXferPush,
zDesc,
0,
0,
30
);
}
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 |
;
xfersetup_generic(
"Transfer Push Script",
"xfer-push-script",
zDefaultXferPush,
zDesc,
0,
0,
30
);
}
static const char *zDefaultXferCommit = 0;
/*
** WEBPAGE: xfersetup_commit
*/
void xfersetup_commit_page(void){
static const char zDesc[] =
@ Enter TH1 script that runs when a commit is processed.
;
xfersetup_generic(
"Transfer Commit Script",
"xfer-commit-script",
zDefaultXferCommit,
zDesc,
0,
0,
30
);
}
static const char *zDefaultXferTicket = 0;
/*
** WEBPAGE: xfersetup_ticket
*/
void xfersetup_ticket_page(void){
static const char zDesc[] =
@ Enter TH1 script that runs when a ticket change is processed.
;
xfersetup_generic(
"Transfer Ticket Script",
"xfer-ticket-script",
zDefaultXferTicket,
zDesc,
0,
0,
30
);
}
|
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);
fossil_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++){
fossil_free(azDir[i]);
}
fossil_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);
|
| ︙ | ︙ | |||
442 443 444 445 446 447 448 |
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);
| | | | 442 443 444 445 446 447 448 449 450 451 452 453 |
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);
fossil_free( zName );
fossil_free( zRid );
cgi_set_content(&zip);
cgi_set_content_type("application/zip");
}
|
Changes to test/merge2.test.
| ︙ | ︙ | |||
18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
# Tests of the delta mechanism.
#
set filelist [glob $testdir/*]
foreach f $filelist {
if {[file isdir $f]} continue
set base [file root [file tail $f]]
set f1 [read_file $f]
write_file t1 $f1
for {set i 0} {$i<100} {incr i} {
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]]
| > | 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 {[string match "utf16*" $base]} 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 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
}
| > | 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
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 user default drh --user drh
fossil update baseline
checkout-test 10 {
da5c8346496f3421cb58f84b6e59e9531d9d424d one.txt
ed24d19d726d173f18dbf4a9a0f8514daa3e3ca4 three.txt
278a402316510f6ae4a77186796a6bde78c7dbc1 two.txt
}
|
| ︙ | ︙ |
Changes to test/merge_renames.test.
| ︙ | ︙ | |||
42 43 44 45 46 47 48 | 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 file rename -force f1 f2 fossil commit -b rename -m "c5" fossil merge trunk fossil commit -m "trunk merged" fossil update pivot write_file f3 "someline" |
| ︙ | ︙ | |||
72 73 74 75 76 77 78 |
protOut "Error, the merge should not delete any file"
test merge_renames-1 0
} else {
test merge_renames-1 1
}
fossil close -f
| | | | 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 |
protOut "Error, the merge should not delete any file"
test merge_renames-1 0
} else {
test merge_renames-1 1
}
fossil close -f
file delete 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
file rename -force f2 f2new
fossil commit -m "rename"
fossil update pivot
write_file f1 "line3"
fossil commit -b branch -m "change"
fossil merge trunk
|
| ︙ | ︙ | |||
124 125 126 127 128 129 130 |
protOut "Error, the merge should not delete any file"
test merge_renames-2 0
} else {
test merge_renames-2 1
}
fossil close -f
| | | | 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 |
protOut "Error, the merge should not delete any file"
test merge_renames-2 0
} else {
test merge_renames-2 1
}
fossil close -f
file delete 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
file rename -force f2 f2new
fossil commit -m "rename"
fossil update pivot
write_file f1 "line3"
fossil commit -b branch -m "change"
fossil merge trunk
|
| ︙ | ︙ | |||
176 177 178 179 180 181 182 |
protOut "Error, the merge should not delete any file"
test merge_renames-2 0
} else {
test merge_renames-2 1
}
fossil close -f
| | | 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 |
protOut "Error, the merge should not delete any file"
test merge_renames-2 0
} else {
test merge_renames-2 1
}
fossil close -f
file delete rep.fossil
######################################
# Test 4 #
# Reported: Ticket [67176c3aa4] #
######################################
# TO BE WRITTEN.
|
| ︙ | ︙ |
Changes to test/revert.test.
| ︙ | ︙ | |||
89 90 91 92 93 94 95 | # Make changes to be reverted # # Add f0 write_file f0 "f0" fossil add f0 # Remove f1 | | | | 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 |
# Make changes to be reverted
#
# Add f0
write_file f0 "f0"
fossil add f0
# Remove f1
file delete f1
fossil rm f1
# Edit f2
write_file f2 "f2.1"
# Rename f3 to f3n
file rename -force 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
|
| ︙ | ︙ |
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 0 || $RESULT eq 1}
###############################################################################
fossil test-th-eval --th-open-config "setting -strict autosync"
test th1-setting-6 {$RESULT eq 0 || $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"}}
|
| ︙ | ︙ | |||
63 64 65 66 67 68 69 |
fossil test-th-eval --th-open-config "setting -- --"
test th1-setting-9 {$RESULT eq {}}
###############################################################################
fossil test-th-eval --th-open-config "setting -strict -- --"
test th1-setting-10 {$RESULT eq {TH_ERROR: no value for setting "--"}}
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 |
fossil test-th-eval --th-open-config "setting -- --"
test th1-setting-9 {$RESULT eq {}}
###############################################################################
fossil test-th-eval --th-open-config "setting -strict -- --"
test th1-setting-10 {$RESULT eq {TH_ERROR: no value for setting "--"}}
###############################################################################
fossil test-th-eval "expr 42/0"
test th1-divide-by-zero-1 {$RESULT eq {TH_ERROR: Divide by 0: 42}}
###############################################################################
fossil test-th-eval "expr 42/0.0"
test th1-divide-by-zero-2 {$RESULT eq {TH_ERROR: Divide by 0: 42}}
###############################################################################
fossil test-th-eval "expr 42.0/0"
test th1-divide-by-zero-3 {$RESULT eq {TH_ERROR: Divide by 0: 42.0}}
###############################################################################
fossil test-th-eval "expr 42.0/0.0"
test th1-divide-by-zero-4 {$RESULT eq {TH_ERROR: Divide by 0: 42.0}}
###############################################################################
fossil test-th-eval "expr 42%0"
test th1-modulus-by-zero-1 {$RESULT eq {TH_ERROR: Modulo by 0: 42}}
###############################################################################
fossil test-th-eval "expr 42%0.0"
test th1-modulus-by-zero-2 {$RESULT eq {TH_ERROR: expected integer, got: "0.0"}}
###############################################################################
fossil test-th-eval "expr 42.0%0"
test th1-modulus-by-zero-3 {$RESULT eq \
{TH_ERROR: expected integer, got: "42.0"}}
###############################################################################
fossil test-th-eval "expr 42.0%0.0"
test th1-modulus-by-zero-4 {$RESULT eq \
{TH_ERROR: expected integer, got: "42.0"}}
###############################################################################
fossil test-th-eval "set var 1; info exists var"
test th1-info-exists-1 {$RESULT eq {1}}
###############################################################################
fossil test-th-eval "set var 1; unset var; info exists var"
test th1-info-exists-2 {$RESULT eq {0}}
###############################################################################
fossil test-th-eval "set var 1; unset var; set var 2; info exists var"
test th1-info-exists-3 {$RESULT eq {1}}
###############################################################################
fossil test-th-eval "set var 1; expr {\$var+0}"
test th1-info-exists-4 {$RESULT eq {1}}
###############################################################################
fossil test-th-eval "set var 1; unset var; expr {\$var+0}"
test th1-info-exists-5 {$RESULT eq {TH_ERROR: no such variable: var}}
###############################################################################
fossil test-th-eval "catch {bad}; info exists var; set th_stack_trace"
test th1-info-exists-6 {$RESULT eq {bad}}
###############################################################################
fossil test-th-eval "set var(1) 1; info exists var"
test th1-info-exists-7 {$RESULT eq {1}}
###############################################################################
fossil test-th-eval "set var(1) 1; unset var(1); info exists var"
test th1-info-exists-8 {$RESULT eq {1}}
###############################################################################
fossil test-th-eval "set var(1) 1; unset var; info exists var"
test th1-info-exists-9 {$RESULT eq {0}}
###############################################################################
fossil test-th-eval "set var(1) 1; info exists var(1)"
test th1-info-exists-10 {$RESULT eq {1}}
###############################################################################
fossil test-th-eval "set var(1) 1; unset var(1); info exists var(1)"
test th1-info-exists-11 {$RESULT eq {0}}
###############################################################################
fossil test-th-eval "set var(1) 1; unset var; info exists var(1)"
test th1-info-exists-12 {$RESULT eq {0}}
###############################################################################
fossil test-th-eval "set var 1; unset var"
test th1-unset-1 {$RESULT eq {var}}
###############################################################################
fossil test-th-eval "unset var"
test th1-unset-2 {$RESULT eq {TH_ERROR: no such variable: var}}
###############################################################################
fossil test-th-eval "set var 1; unset var; unset var"
test th1-unset-3 {$RESULT eq {TH_ERROR: no such variable: var}}
###############################################################################
fossil test-th-eval "set gv 1; proc p {} {upvar 1 gv lv; unset lv}; p; unset gv"
test th1-unset-4 {$RESULT eq {TH_ERROR: no such variable: gv}}
###############################################################################
fossil test-th-eval "set gv 1; upvar 0 gv gv2; info exists gv2"
test th1-unset-5 {$RESULT eq {1}}
###############################################################################
fossil test-th-eval "set gv 1; upvar 0 gv gv2; unset gv; unset gv2"
test th1-unset-6 {$RESULT eq {TH_ERROR: no such variable: gv2}}
###############################################################################
fossil test-th-eval "set gv 1; upvar 0 gv gv2(1); unset gv; unset gv2(1)"
test th1-unset-7 {$RESULT eq {TH_ERROR: no such variable: gv2(1)}}
###############################################################################
fossil test-th-eval "set gv(1) 1; upvar 0 gv(1) gv2; unset gv(1); unset gv2"
test th1-unset-8 {$RESULT eq {TH_ERROR: no such variable: gv2}}
###############################################################################
fossil test-th-eval "string first {} {}"
test th1-string-first-1 {$RESULT eq {-1}}
###############################################################################
fossil test-th-eval "string first {} {a}"
test th1-string-first-2 {$RESULT eq {-1}}
###############################################################################
fossil test-th-eval "string first {a} {}"
test th1-string-first-3 {$RESULT eq {-1}}
###############################################################################
fossil test-th-eval "string first {a} {a}"
test th1-string-first-4 {$RESULT eq {0}}
###############################################################################
fossil test-th-eval "string first {a} {aa}"
test th1-string-first-5 {$RESULT eq {0}}
###############################################################################
fossil test-th-eval "string first {aa} {a}"
test th1-string-first-6 {$RESULT eq {-1}}
###############################################################################
fossil test-th-eval "string first {ab} {abc}"
test th1-string-first-7 {$RESULT eq {0}}
###############################################################################
fossil test-th-eval "string first {bc} {abc}"
test th1-string-first-8 {$RESULT eq {1}}
###############################################################################
fossil test-th-eval "string first {AB} {abc}"
test th1-string-first-9 {$RESULT eq {-1}}
###############################################################################
fossil test-th-eval "string last {} {}"
test th1-string-last-1 {$RESULT eq {-1}}
###############################################################################
fossil test-th-eval "string last {} {a}"
test th1-string-last-2 {$RESULT eq {-1}}
###############################################################################
fossil test-th-eval "string last {a} {}"
test th1-string-last-3 {$RESULT eq {-1}}
###############################################################################
fossil test-th-eval "string last {a} {a}"
test th1-string-last-4 {$RESULT eq {0}}
###############################################################################
fossil test-th-eval "string last {a} {aa}"
test th1-string-last-5 {$RESULT eq {1}}
###############################################################################
fossil test-th-eval "string last {aa} {a}"
test th1-string-last-6 {$RESULT eq {-1}}
###############################################################################
fossil test-th-eval "string last {ab} {abc}"
test th1-string-last-7 {$RESULT eq {0}}
###############################################################################
fossil test-th-eval "string last {bc} {abc}"
test th1-string-last-8 {$RESULT eq {1}}
###############################################################################
fossil test-th-eval "string last {AB} {abc}"
test th1-string-last-9 {$RESULT eq {-1}}
###############################################################################
fossil test-th-eval "expr -2147483649.0"
test th1-expr-1 {$RESULT eq {-2147483649.0}}
###############################################################################
fossil test-th-eval "expr -2147483649"
test th1-expr-2 {$RESULT eq {2147483647}}
###############################################################################
fossil test-th-eval "expr -2147483648"
test th1-expr-3 {$RESULT eq {-2147483648}}
###############################################################################
fossil test-th-eval "expr -2147483647"
test th1-expr-4 {$RESULT eq {-2147483647}}
###############################################################################
fossil test-th-eval "expr -1"
test th1-expr-5 {$RESULT eq {-1}}
###############################################################################
fossil test-th-eval "expr 0"
test th1-expr-6 {$RESULT eq {0}}
###############################################################################
fossil test-th-eval "expr 0.0"
test th1-expr-7 {$RESULT eq {0.0}}
###############################################################################
fossil test-th-eval "expr 1"
test th1-expr-8 {$RESULT eq {1}}
###############################################################################
fossil test-th-eval "expr 2147483647"
test th1-expr-9 {$RESULT eq {2147483647}}
###############################################################################
fossil test-th-eval "expr 2147483648"
test th1-expr-10 {$RESULT eq {2147483648}}
###############################################################################
fossil test-th-eval "expr 2147483649"
test th1-expr-11 {$RESULT eq {2147483649}}
###############################################################################
fossil test-th-eval "expr +2147483649"
test th1-expr-12 {$RESULT eq {-2147483647}}
###############################################################################
fossil test-th-eval "expr +2147483649.0"
test th1-expr-13 {$RESULT eq {2147483649.0}}
|
Added test/utf16be.txt.
> > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
This file contains utf-16be text.
The purpose for including this file in the Fossil
repository is to provide the ability to test Fossil's
handling of UTF-16 using its own repository.
Browsing to this file in the web interface should display the file as
text on the screen.
When there are changes to this file those changes should show
up in the "diff" output and be properly displayed on the
screen.
Test procedures:
1. Verify that this file is correctly display using the /artifact
webpage.
2. Verify that this file is correctly displayed by the /doc webpage.
3. Verify that changes to are correctly displayed by the /fdiff webpage.
4. Verify that the "fossil diff" command correctly displays changes
in this file. Do the same with the --tk option.
|
Added test/utf16le.txt.
> > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
This file contains utf-16le text.
The purpose for including this file in the Fossil
repository is to provide the ability to test Fossil's
handling of UTF-16 using its own repository.
Browsing to this file in the web interface should display the file as
text on the screen.
When there are changes to this file those changes should show
up in the "diff" output and be properly displayed on the
screen.
Test procedures:
1. Verify that this file is correctly display using the /artifact
webpage.
2. Verify that this file is correctly displayed by the /doc webpage.
3. Verify that changes to are correctly displayed by the /fdiff webpage.
4. Verify that the "fossil diff" command correctly displays changes
in this file. Do the same with the --tk option.
|
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 25 26 |
#
# 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
set msg {}
catch {exec valgrind ./fossil test-http <q.txt 2>@ stderr} msg
return $msg
}
set todo {}
foreach url {
/home
/timeline
/brlist
/taglist
|
| ︙ | ︙ |
Changes to win/Makefile.PellesCGMake.
| ︙ | ︙ | |||
81 82 83 84 85 86 87 | UTILS_OBJ=$(UTILS:.exe=.obj) UTILS_SRC=$(foreach uf,$(UTILS),$(SRCDIR)$(uf:.exe=.c)) # define the sqlite files, which need special flags on compile SQLITESRC=sqlite3.c ORIGSQLITESRC=$(foreach sf,$(SQLITESRC),$(SRCDIR)$(sf)) SQLITEOBJ=$(foreach sf,$(SQLITESRC),$(sf:.c=.obj)) | | | | 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 | UTILS_OBJ=$(UTILS:.exe=.obj) UTILS_SRC=$(foreach uf,$(UTILS),$(SRCDIR)$(uf:.exe=.c)) # define the sqlite files, which need special flags on compile SQLITESRC=sqlite3.c ORIGSQLITESRC=$(foreach sf,$(SQLITESRC),$(SRCDIR)$(sf)) SQLITEOBJ=$(foreach sf,$(SQLITESRC),$(sf:.c=.obj)) SQLITEDEFINES=-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 # define the sqlite shell files, which need special flags on compile SQLITESHELLSRC=shell.c ORIGSQLITESHELLSRC=$(foreach sf,$(SQLITESHELLSRC),$(SRCDIR)$(sf)) SQLITESHELLOBJ=$(foreach sf,$(SQLITESHELLSRC),$(sf:.c=.obj)) SQLITESHELLDEFINES=-Dmain=sqlite3_shell -DSQLITE_OMIT_LOAD_EXTENSION=1 -Dgetenv=fossil_getenv -Dfopen=fossil_fopen # define the th scripting files, which need special flags on compile THSRC=th.c th_lang.c ORIGTHSRC=$(foreach sf,$(THSRC),$(SRCDIR)$(sf)) THOBJ=$(foreach sf,$(THSRC),$(sf:.c=.obj)) # define the zlib files, needed by this compile |
| ︙ | ︙ |
Changes to win/Makefile.dmc.
| ︙ | ︙ | |||
22 23 24 25 26 27 28 | SSL = CFLAGS = -o BCC = $(DMDIR)\bin\dmc $(CFLAGS) TCC = $(DMDIR)\bin\dmc $(CFLAGS) $(DMCDEF) $(SSL) $(INCL) LIBS = $(DMDIR)\extra\lib\ zlib wsock32 advapi32 | > | > | | | | | | 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 | SSL = CFLAGS = -o BCC = $(DMDIR)\bin\dmc $(CFLAGS) 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 -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 $(BCC) -o$@ $** makeheaders$E: $(SRCDIR)\makeheaders.c $(BCC) -o$@ $** mkindex$E: $(SRCDIR)\mkindex.c $(BCC) -o$@ $** version$E: $B\src\mkversion.c $(BCC) -o$@ $** $(OBJDIR)\shell$O : $(SRCDIR)\shell.c $(TCC) -o$@ -c $(SHELL_OPTIONS) $(SQLITE_OPTIONS) $(SHELL_CFLAGS) $** $(OBJDIR)\sqlite3$O : $(SRCDIR)\sqlite3.c $(TCC) -o$@ -c $(SQLITE_OPTIONS) $(SQLITE_CFLAGS) $** $(OBJDIR)\th$O : $(SRCDIR)\th.c $(TCC) -o$@ -c $** $(OBJDIR)\th_lang$O : $(SRCDIR)\th_lang.c $(TCC) -o$@ -c $** |
| ︙ | ︙ | |||
720 721 722 723 724 725 726 727 728 729 730 731 732 733 | +translate$E $** > $@ $(OBJDIR)\wikiformat$O : wikiformat_.c wikiformat.h $(TCC) -o$@ -c wikiformat_.c wikiformat_.c : $(SRCDIR)\wikiformat.c +translate$E $** > $@ $(OBJDIR)\winhttp$O : winhttp_.c winhttp.h $(TCC) -o$@ -c winhttp_.c winhttp_.c : $(SRCDIR)\winhttp.c +translate$E $** > $@ | > > > > > > | 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 | +translate$E $** > $@ $(OBJDIR)\wikiformat$O : wikiformat_.c wikiformat.h $(TCC) -o$@ -c wikiformat_.c wikiformat_.c : $(SRCDIR)\wikiformat.c +translate$E $** > $@ $(OBJDIR)\winfile$O : winfile_.c winfile.h $(TCC) -o$@ -c winfile_.c winfile_.c : $(SRCDIR)\winfile.c +translate$E $** > $@ $(OBJDIR)\winhttp$O : winhttp_.c winhttp.h $(TCC) -o$@ -c winhttp_.c winhttp_.c : $(SRCDIR)\winhttp.c +translate$E $** > $@ |
| ︙ | ︙ | |||
752 753 754 755 756 757 758 | $(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.
| ︙ | ︙ | |||
82 83 84 85 86 87 88 | ZLIBDIR = $(SRCDIR)/../compat/zlib #### The directories where the OpenSSL include and library files are located. # The recommended usage here is to use the Sysinternals junction tool # to create a hard link between an "openssl-1.x" sub-directory of the # Fossil source code directory and the target OpenSSL source directory. # | | | | 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 | ZLIBDIR = $(SRCDIR)/../compat/zlib #### The directories where the OpenSSL include and library files are located. # The recommended usage here is to use the Sysinternals junction tool # to create a hard link between an "openssl-1.x" sub-directory of the # Fossil source code directory and the target OpenSSL source directory. # OPENSSLINCDIR = $(SRCDIR)/../compat/openssl-1.0.1f/include OPENSSLLIBDIR = $(SRCDIR)/../compat/openssl-1.0.1f #### Either the directory where the Tcl library is installed or the Tcl # source code directory resides (depending on the value of the macro # FOSSIL_TCL_SOURCE). If this points to the Tcl install directory, # this directory must have "include" and "lib" sub-directories. If # this points to the Tcl source code directory, this directory must # have "generic" and "win" sub-directories. The recommended usage |
| ︙ | ︙ | |||
355 356 357 358 359 360 361 362 363 364 365 366 367 368 | $(SRCDIR)/user.c \ $(SRCDIR)/utf8.c \ $(SRCDIR)/util.c \ $(SRCDIR)/verify.c \ $(SRCDIR)/vfile.c \ $(SRCDIR)/wiki.c \ $(SRCDIR)/wikiformat.c \ $(SRCDIR)/winhttp.c \ $(SRCDIR)/wysiwyg.c \ $(SRCDIR)/xfer.c \ $(SRCDIR)/xfersetup.c \ $(SRCDIR)/zip.c TRANS_SRC = \ | > | 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 | $(SRCDIR)/user.c \ $(SRCDIR)/utf8.c \ $(SRCDIR)/util.c \ $(SRCDIR)/verify.c \ $(SRCDIR)/vfile.c \ $(SRCDIR)/wiki.c \ $(SRCDIR)/wikiformat.c \ $(SRCDIR)/winfile.c \ $(SRCDIR)/winhttp.c \ $(SRCDIR)/wysiwyg.c \ $(SRCDIR)/xfer.c \ $(SRCDIR)/xfersetup.c \ $(SRCDIR)/zip.c TRANS_SRC = \ |
| ︙ | ︙ | |||
464 465 466 467 468 469 470 471 472 473 474 475 476 477 | $(OBJDIR)/user_.c \ $(OBJDIR)/utf8_.c \ $(OBJDIR)/util_.c \ $(OBJDIR)/verify_.c \ $(OBJDIR)/vfile_.c \ $(OBJDIR)/wiki_.c \ $(OBJDIR)/wikiformat_.c \ $(OBJDIR)/winhttp_.c \ $(OBJDIR)/wysiwyg_.c \ $(OBJDIR)/xfer_.c \ $(OBJDIR)/xfersetup_.c \ $(OBJDIR)/zip_.c OBJ = \ | > | 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 | $(OBJDIR)/user_.c \ $(OBJDIR)/utf8_.c \ $(OBJDIR)/util_.c \ $(OBJDIR)/verify_.c \ $(OBJDIR)/vfile_.c \ $(OBJDIR)/wiki_.c \ $(OBJDIR)/wikiformat_.c \ $(OBJDIR)/winfile_.c \ $(OBJDIR)/winhttp_.c \ $(OBJDIR)/wysiwyg_.c \ $(OBJDIR)/xfer_.c \ $(OBJDIR)/xfersetup_.c \ $(OBJDIR)/zip_.c OBJ = \ |
| ︙ | ︙ | |||
573 574 575 576 577 578 579 580 581 582 583 584 585 586 | $(OBJDIR)/user.o \ $(OBJDIR)/utf8.o \ $(OBJDIR)/util.o \ $(OBJDIR)/verify.o \ $(OBJDIR)/vfile.o \ $(OBJDIR)/wiki.o \ $(OBJDIR)/wikiformat.o \ $(OBJDIR)/winhttp.o \ $(OBJDIR)/wysiwyg.o \ $(OBJDIR)/xfer.o \ $(OBJDIR)/xfersetup.o \ $(OBJDIR)/zip.o APPNAME = fossil.exe | > | 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 | $(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 APPNAME = fossil.exe |
| ︙ | ︙ | |||
616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 | all: $(OBJDIR) $(APPNAME) $(OBJDIR)/fossil.o: $(SRCDIR)/../win/fossil.rc $(OBJDIR)/VERSION.h ifdef USE_WINDOWS $(CP) $(subst /,\,$(SRCDIR)\..\win\fossil.rc) $(subst /,\,$(OBJDIR)) $(CP) $(subst /,\,$(SRCDIR)\..\win\fossil.ico) $(subst /,\,$(OBJDIR)) else $(CP) $(SRCDIR)/../win/fossil.rc $(OBJDIR) $(CP) $(SRCDIR)/../win/fossil.ico $(OBJDIR) endif $(RCC) $(OBJDIR)/fossil.rc -o $(OBJDIR)/fossil.o install: $(OBJDIR) $(APPNAME) ifdef USE_WINDOWS $(MKDIR) $(subst /,\,$(INSTALLDIR)) $(MV) $(subst /,\,$(APPNAME)) $(subst /,\,$(INSTALLDIR)) | > > | 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 | all: $(OBJDIR) $(APPNAME) $(OBJDIR)/fossil.o: $(SRCDIR)/../win/fossil.rc $(OBJDIR)/VERSION.h ifdef USE_WINDOWS $(CP) $(subst /,\,$(SRCDIR)\..\win\fossil.rc) $(subst /,\,$(OBJDIR)) $(CP) $(subst /,\,$(SRCDIR)\..\win\fossil.ico) $(subst /,\,$(OBJDIR)) $(CP) $(subst /,\,$(SRCDIR)\..\win\fossil.exe.manifest) $(subst /,\,$(OBJDIR)) else $(CP) $(SRCDIR)/../win/fossil.rc $(OBJDIR) $(CP) $(SRCDIR)/../win/fossil.ico $(OBJDIR) $(CP) $(SRCDIR)/../win/fossil.exe.manifest $(OBJDIR) endif $(RCC) $(OBJDIR)/fossil.rc -o $(OBJDIR)/fossil.o install: $(OBJDIR) $(APPNAME) ifdef USE_WINDOWS $(MKDIR) $(subst /,\,$(INSTALLDIR)) $(MV) $(subst /,\,$(APPNAME)) $(subst /,\,$(INSTALLDIR)) |
| ︙ | ︙ | |||
812 813 814 815 816 817 818 819 820 821 822 823 824 825 | $(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)/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 \ | > | 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 | $(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 \ |
| ︙ | ︙ | |||
1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 | $(OBJDIR)/wikiformat_.c: $(SRCDIR)/wikiformat.c $(OBJDIR)/translate $(TRANSLATE) $(SRCDIR)/wikiformat.c >$(OBJDIR)/wikiformat_.c $(OBJDIR)/wikiformat.o: $(OBJDIR)/wikiformat_.c $(OBJDIR)/wikiformat.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/wikiformat.o -c $(OBJDIR)/wikiformat_.c $(OBJDIR)/wikiformat.h: $(OBJDIR)/headers $(OBJDIR)/winhttp_.c: $(SRCDIR)/winhttp.c $(OBJDIR)/translate $(TRANSLATE) $(SRCDIR)/winhttp.c >$(OBJDIR)/winhttp_.c $(OBJDIR)/winhttp.o: $(OBJDIR)/winhttp_.c $(OBJDIR)/winhttp.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/winhttp.o -c $(OBJDIR)/winhttp_.c | > > > > > > > > | 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 | $(OBJDIR)/wikiformat_.c: $(SRCDIR)/wikiformat.c $(OBJDIR)/translate $(TRANSLATE) $(SRCDIR)/wikiformat.c >$(OBJDIR)/wikiformat_.c $(OBJDIR)/wikiformat.o: $(OBJDIR)/wikiformat_.c $(OBJDIR)/wikiformat.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/wikiformat.o -c $(OBJDIR)/wikiformat_.c $(OBJDIR)/wikiformat.h: $(OBJDIR)/headers $(OBJDIR)/winfile_.c: $(SRCDIR)/winfile.c $(OBJDIR)/translate $(TRANSLATE) $(SRCDIR)/winfile.c >$(OBJDIR)/winfile_.c $(OBJDIR)/winfile.o: $(OBJDIR)/winfile_.c $(OBJDIR)/winfile.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/winfile.o -c $(OBJDIR)/winfile_.c $(OBJDIR)/winfile.h: $(OBJDIR)/headers $(OBJDIR)/winhttp_.c: $(SRCDIR)/winhttp.c $(OBJDIR)/translate $(TRANSLATE) $(SRCDIR)/winhttp.c >$(OBJDIR)/winhttp_.c $(OBJDIR)/winhttp.o: $(OBJDIR)/winhttp_.c $(OBJDIR)/winhttp.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/winhttp.o -c $(OBJDIR)/winhttp_.c |
| ︙ | ︙ | |||
1682 1683 1684 1685 1686 1687 1688 | $(TRANSLATE) $(SRCDIR)/zip.c >$(OBJDIR)/zip_.c $(OBJDIR)/zip.o: $(OBJDIR)/zip_.c $(OBJDIR)/zip.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/zip.o -c $(OBJDIR)/zip_.c $(OBJDIR)/zip.h: $(OBJDIR)/headers | > > > > > > > > > > > > > > > | | | | | | 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 |
$(TRANSLATE) $(SRCDIR)/zip.c >$(OBJDIR)/zip_.c
$(OBJDIR)/zip.o: $(OBJDIR)/zip_.c $(OBJDIR)/zip.h $(SRCDIR)/config.h
$(XTCC) -o $(OBJDIR)/zip.o -c $(OBJDIR)/zip_.c
$(OBJDIR)/zip.h: $(OBJDIR)/headers
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 \
-D_HAVE_SQLITE_CONFIG_H \
-DSQLITE_USE_MALLOC_H \
-DSQLITE_USE_MSIZE
SHELL_OPTIONS = -Dmain=sqlite3_shell \
-DSQLITE_OMIT_LOAD_EXTENSION=1 \
-Dgetenv=fossil_getenv \
-Dfopen=fossil_fopen
$(OBJDIR)/sqlite3.o: $(SRCDIR)/sqlite3.c $(SRCDIR)/../win/Makefile.mingw
$(XTCC) $(SQLITE_OPTIONS) $(SQLITE_CFLAGS) -c $(SRCDIR)/sqlite3.c -o $(OBJDIR)/sqlite3.o
$(OBJDIR)/cson_amalgamation.o: $(SRCDIR)/cson_amalgamation.c
$(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.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)/jsos_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
$(OBJDIR)/shell.o: $(SRCDIR)/shell.c $(SRCDIR)/sqlite3.h $(SRCDIR)/../win/Makefile.mingw
$(XTCC) $(SHELL_OPTIONS) $(SHELL_CFLAGS) -c $(SRCDIR)/shell.c -o $(OBJDIR)/shell.o
$(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.
| ︙ | ︙ | |||
82 83 84 85 86 87 88 | ZLIBDIR = $(SRCDIR)/../compat/zlib #### The directories where the OpenSSL include and library files are located. # The recommended usage here is to use the Sysinternals junction tool # to create a hard link between an "openssl-1.x" sub-directory of the # Fossil source code directory and the target OpenSSL source directory. # | | | | 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 | ZLIBDIR = $(SRCDIR)/../compat/zlib #### The directories where the OpenSSL include and library files are located. # The recommended usage here is to use the Sysinternals junction tool # to create a hard link between an "openssl-1.x" sub-directory of the # Fossil source code directory and the target OpenSSL source directory. # OPENSSLINCDIR = $(SRCDIR)/../compat/openssl-1.0.1f/include OPENSSLLIBDIR = $(SRCDIR)/../compat/openssl-1.0.1f #### Either the directory where the Tcl library is installed or the Tcl # source code directory resides (depending on the value of the macro # FOSSIL_TCL_SOURCE). If this points to the Tcl install directory, # this directory must have "include" and "lib" sub-directories. If # this points to the Tcl source code directory, this directory must # have "generic" and "win" sub-directories. The recommended usage |
| ︙ | ︙ | |||
355 356 357 358 359 360 361 362 363 364 365 366 367 368 | $(SRCDIR)/user.c \ $(SRCDIR)/utf8.c \ $(SRCDIR)/util.c \ $(SRCDIR)/verify.c \ $(SRCDIR)/vfile.c \ $(SRCDIR)/wiki.c \ $(SRCDIR)/wikiformat.c \ $(SRCDIR)/winhttp.c \ $(SRCDIR)/wysiwyg.c \ $(SRCDIR)/xfer.c \ $(SRCDIR)/xfersetup.c \ $(SRCDIR)/zip.c TRANS_SRC = \ | > | 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 | $(SRCDIR)/user.c \ $(SRCDIR)/utf8.c \ $(SRCDIR)/util.c \ $(SRCDIR)/verify.c \ $(SRCDIR)/vfile.c \ $(SRCDIR)/wiki.c \ $(SRCDIR)/wikiformat.c \ $(SRCDIR)/winfile.c \ $(SRCDIR)/winhttp.c \ $(SRCDIR)/wysiwyg.c \ $(SRCDIR)/xfer.c \ $(SRCDIR)/xfersetup.c \ $(SRCDIR)/zip.c TRANS_SRC = \ |
| ︙ | ︙ | |||
464 465 466 467 468 469 470 471 472 473 474 475 476 477 | $(OBJDIR)/user_.c \ $(OBJDIR)/utf8_.c \ $(OBJDIR)/util_.c \ $(OBJDIR)/verify_.c \ $(OBJDIR)/vfile_.c \ $(OBJDIR)/wiki_.c \ $(OBJDIR)/wikiformat_.c \ $(OBJDIR)/winhttp_.c \ $(OBJDIR)/wysiwyg_.c \ $(OBJDIR)/xfer_.c \ $(OBJDIR)/xfersetup_.c \ $(OBJDIR)/zip_.c OBJ = \ | > | 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 | $(OBJDIR)/user_.c \ $(OBJDIR)/utf8_.c \ $(OBJDIR)/util_.c \ $(OBJDIR)/verify_.c \ $(OBJDIR)/vfile_.c \ $(OBJDIR)/wiki_.c \ $(OBJDIR)/wikiformat_.c \ $(OBJDIR)/winfile_.c \ $(OBJDIR)/winhttp_.c \ $(OBJDIR)/wysiwyg_.c \ $(OBJDIR)/xfer_.c \ $(OBJDIR)/xfersetup_.c \ $(OBJDIR)/zip_.c OBJ = \ |
| ︙ | ︙ | |||
573 574 575 576 577 578 579 580 581 582 583 584 585 586 | $(OBJDIR)/user.o \ $(OBJDIR)/utf8.o \ $(OBJDIR)/util.o \ $(OBJDIR)/verify.o \ $(OBJDIR)/vfile.o \ $(OBJDIR)/wiki.o \ $(OBJDIR)/wikiformat.o \ $(OBJDIR)/winhttp.o \ $(OBJDIR)/wysiwyg.o \ $(OBJDIR)/xfer.o \ $(OBJDIR)/xfersetup.o \ $(OBJDIR)/zip.o APPNAME = fossil.exe | > | 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 | $(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 APPNAME = fossil.exe |
| ︙ | ︙ | |||
616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 | all: $(OBJDIR) $(APPNAME) $(OBJDIR)/fossil.o: $(SRCDIR)/../win/fossil.rc $(OBJDIR)/VERSION.h ifdef USE_WINDOWS $(CP) $(subst /,\,$(SRCDIR)\..\win\fossil.rc) $(subst /,\,$(OBJDIR)) $(CP) $(subst /,\,$(SRCDIR)\..\win\fossil.ico) $(subst /,\,$(OBJDIR)) else $(CP) $(SRCDIR)/../win/fossil.rc $(OBJDIR) $(CP) $(SRCDIR)/../win/fossil.ico $(OBJDIR) endif $(RCC) $(OBJDIR)/fossil.rc -o $(OBJDIR)/fossil.o install: $(OBJDIR) $(APPNAME) ifdef USE_WINDOWS $(MKDIR) $(subst /,\,$(INSTALLDIR)) $(MV) $(subst /,\,$(APPNAME)) $(subst /,\,$(INSTALLDIR)) | > > | 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 | all: $(OBJDIR) $(APPNAME) $(OBJDIR)/fossil.o: $(SRCDIR)/../win/fossil.rc $(OBJDIR)/VERSION.h ifdef USE_WINDOWS $(CP) $(subst /,\,$(SRCDIR)\..\win\fossil.rc) $(subst /,\,$(OBJDIR)) $(CP) $(subst /,\,$(SRCDIR)\..\win\fossil.ico) $(subst /,\,$(OBJDIR)) $(CP) $(subst /,\,$(SRCDIR)\..\win\fossil.exe.manifest) $(subst /,\,$(OBJDIR)) else $(CP) $(SRCDIR)/../win/fossil.rc $(OBJDIR) $(CP) $(SRCDIR)/../win/fossil.ico $(OBJDIR) $(CP) $(SRCDIR)/../win/fossil.exe.manifest $(OBJDIR) endif $(RCC) $(OBJDIR)/fossil.rc -o $(OBJDIR)/fossil.o install: $(OBJDIR) $(APPNAME) ifdef USE_WINDOWS $(MKDIR) $(subst /,\,$(INSTALLDIR)) $(MV) $(subst /,\,$(APPNAME)) $(subst /,\,$(INSTALLDIR)) |
| ︙ | ︙ | |||
812 813 814 815 816 817 818 819 820 821 822 823 824 825 | $(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)/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 \ | > | 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 | $(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 \ |
| ︙ | ︙ | |||
1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 | $(OBJDIR)/wikiformat_.c: $(SRCDIR)/wikiformat.c $(OBJDIR)/translate $(TRANSLATE) $(SRCDIR)/wikiformat.c >$(OBJDIR)/wikiformat_.c $(OBJDIR)/wikiformat.o: $(OBJDIR)/wikiformat_.c $(OBJDIR)/wikiformat.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/wikiformat.o -c $(OBJDIR)/wikiformat_.c $(OBJDIR)/wikiformat.h: $(OBJDIR)/headers $(OBJDIR)/winhttp_.c: $(SRCDIR)/winhttp.c $(OBJDIR)/translate $(TRANSLATE) $(SRCDIR)/winhttp.c >$(OBJDIR)/winhttp_.c $(OBJDIR)/winhttp.o: $(OBJDIR)/winhttp_.c $(OBJDIR)/winhttp.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/winhttp.o -c $(OBJDIR)/winhttp_.c | > > > > > > > > | 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 | $(OBJDIR)/wikiformat_.c: $(SRCDIR)/wikiformat.c $(OBJDIR)/translate $(TRANSLATE) $(SRCDIR)/wikiformat.c >$(OBJDIR)/wikiformat_.c $(OBJDIR)/wikiformat.o: $(OBJDIR)/wikiformat_.c $(OBJDIR)/wikiformat.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/wikiformat.o -c $(OBJDIR)/wikiformat_.c $(OBJDIR)/wikiformat.h: $(OBJDIR)/headers $(OBJDIR)/winfile_.c: $(SRCDIR)/winfile.c $(OBJDIR)/translate $(TRANSLATE) $(SRCDIR)/winfile.c >$(OBJDIR)/winfile_.c $(OBJDIR)/winfile.o: $(OBJDIR)/winfile_.c $(OBJDIR)/winfile.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/winfile.o -c $(OBJDIR)/winfile_.c $(OBJDIR)/winfile.h: $(OBJDIR)/headers $(OBJDIR)/winhttp_.c: $(SRCDIR)/winhttp.c $(OBJDIR)/translate $(TRANSLATE) $(SRCDIR)/winhttp.c >$(OBJDIR)/winhttp_.c $(OBJDIR)/winhttp.o: $(OBJDIR)/winhttp_.c $(OBJDIR)/winhttp.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/winhttp.o -c $(OBJDIR)/winhttp_.c |
| ︙ | ︙ | |||
1682 1683 1684 1685 1686 1687 1688 | $(TRANSLATE) $(SRCDIR)/zip.c >$(OBJDIR)/zip_.c $(OBJDIR)/zip.o: $(OBJDIR)/zip_.c $(OBJDIR)/zip.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/zip.o -c $(OBJDIR)/zip_.c $(OBJDIR)/zip.h: $(OBJDIR)/headers | > > > > > > > > > > > > > > > | | | | | | 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 |
$(TRANSLATE) $(SRCDIR)/zip.c >$(OBJDIR)/zip_.c
$(OBJDIR)/zip.o: $(OBJDIR)/zip_.c $(OBJDIR)/zip.h $(SRCDIR)/config.h
$(XTCC) -o $(OBJDIR)/zip.o -c $(OBJDIR)/zip_.c
$(OBJDIR)/zip.h: $(OBJDIR)/headers
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 \
-D_HAVE_SQLITE_CONFIG_H \
-DSQLITE_USE_MALLOC_H \
-DSQLITE_USE_MSIZE
SHELL_OPTIONS = -Dmain=sqlite3_shell \
-DSQLITE_OMIT_LOAD_EXTENSION=1 \
-Dgetenv=fossil_getenv \
-Dfopen=fossil_fopen
$(OBJDIR)/sqlite3.o: $(SRCDIR)/sqlite3.c $(SRCDIR)/../win/Makefile.mingw.mistachkin
$(XTCC) $(SQLITE_OPTIONS) $(SQLITE_CFLAGS) -c $(SRCDIR)/sqlite3.c -o $(OBJDIR)/sqlite3.o
$(OBJDIR)/cson_amalgamation.o: $(SRCDIR)/cson_amalgamation.c
$(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.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)/jsos_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
$(OBJDIR)/shell.o: $(SRCDIR)/shell.c $(SRCDIR)/sqlite3.h $(SRCDIR)/../win/Makefile.mingw.mistachkin
$(XTCC) $(SHELL_OPTIONS) $(SHELL_CFLAGS) -c $(SRCDIR)/shell.c -o $(OBJDIR)/shell.o
$(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.
| ︙ | ︙ | |||
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | # B = .. SRCDIR = $B\src OBJDIR = . OX = . O = .obj E = .exe # Uncomment to enable debug symbols # DEBUG = 1 # Uncomment to enable JSON API # FOSSIL_ENABLE_JSON = 1 # Uncomment to enable SSL support # FOSSIL_ENABLE_SSL = 1 !ifdef FOSSIL_ENABLE_SSL | > > > > | | > > > > > > | | > > > > | | | > > | | | > > > > > | | | > > | | | > > > > | | > > | | > | > | | 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 |
#
B = ..
SRCDIR = $B\src
OBJDIR = .
OX = .
O = .obj
E = .exe
P = .pdb
# Uncomment to enable debug symbols
# DEBUG = 1
# Uncomment to enable JSON API
# FOSSIL_ENABLE_JSON = 1
# Uncomment to enable SSL support
# FOSSIL_ENABLE_SSL = 1
# Uncomment to enable Tcl support
# FOSSIL_ENABLE_TCL = 1
!ifdef FOSSIL_ENABLE_SSL
SSLINCDIR = $(B)\compat\openssl-1.0.1f\include
SSLLIBDIR = $(B)\compat\openssl-1.0.1f\out32
SSLLIB = ssleay32.lib libeay32.lib user32.lib gdi32.lib
!endif
!ifdef FOSSIL_ENABLE_TCL
TCLDIR = $(B)\compat\tcl-8.6
TCLSRCDIR = $(TCLDIR)
TCLINCDIR = $(TCLSRCDIR)\generic
!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
!ifdef FOSSIL_ENABLE_TCL
INCL = $(INCL) /I$(TCLINCDIR)
!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
!ifdef FOSSIL_ENABLE_TCL
TCC = $(TCC) /DFOSSIL_ENABLE_TCL=1
RCC = $(RCC) /DFOSSIL_ENABLE_TCL=1
TCC = $(TCC) /DFOSSIL_ENABLE_TCL_STUBS=1
RCC = $(RCC) /DFOSSIL_ENABLE_TCL_STUBS=1
TCC = $(TCC) /DFOSSIL_ENABLE_TCL_PRIVATE_STUBS=1
RCC = $(RCC) /DFOSSIL_ENABLE_TCL_PRIVATE_STUBS=1
TCC = $(TCC) /DUSE_TCL_STUBS=1
RCC = $(RCC) /DUSE_TCL_STUBS=1
!endif
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 \
/Dgetenv=fossil_getenv \
/Dfopen=fossil_fopen
SRC = add_.c \
allrepo_.c \
attach_.c \
bag_.c \
bisect_.c \
blob_.c \
|
| ︙ | ︙ | |||
172 173 174 175 176 177 178 179 180 181 182 183 184 185 |
user_.c \
utf8_.c \
util_.c \
verify_.c \
vfile_.c \
wiki_.c \
wikiformat_.c \
winhttp_.c \
wysiwyg_.c \
xfer_.c \
xfersetup_.c \
zip_.c
OBJ = $(OX)\add$O \
| > | 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 |
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 = $(OX)\add$O \
|
| ︙ | ︙ | |||
285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 |
$(OX)\user$O \
$(OX)\utf8$O \
$(OX)\util$O \
$(OX)\verify$O \
$(OX)\vfile$O \
$(OX)\wiki$O \
$(OX)\wikiformat$O \
$(OX)\winhttp$O \
$(OX)\wysiwyg$O \
$(OX)\xfer$O \
$(OX)\xfersetup$O \
$(OX)\zip$O \
$(OX)\fossil.res
APPNAME = $(OX)\fossil$(E)
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)
| > > > > > > | | 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 |
$(OX)\user$O \
$(OX)\utf8$O \
$(OX)\util$O \
$(OX)\verify$O \
$(OX)\vfile$O \
$(OX)\wiki$O \
$(OX)\wikiformat$O \
$(OX)\winfile$O \
$(OX)\winhttp$O \
$(OX)\wysiwyg$O \
$(OX)\xfer$O \
$(OX)\xfersetup$O \
$(OX)\zip$O \
$(OX)\fossil.res
!ifdef FOSSIL_ENABLE_TCL
OBJ = $(OBJ) $(OX)\th_tcl$O
!endif
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 >> $@
|
| ︙ | ︙ | |||
412 413 414 415 416 417 418 419 420 421 422 423 | echo $(OX)\user.obj >> $@ echo $(OX)\utf8.obj >> $@ echo $(OX)\util.obj >> $@ echo $(OX)\verify.obj >> $@ echo $(OX)\vfile.obj >> $@ echo $(OX)\wiki.obj >> $@ echo $(OX)\wikiformat.obj >> $@ echo $(OX)\winhttp.obj >> $@ echo $(OX)\wysiwyg.obj >> $@ echo $(OX)\xfer.obj >> $@ echo $(OX)\xfersetup.obj >> $@ echo $(OX)\zip.obj >> $@ | > | | | | | | | | > > > > > | | | > < | 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 | echo $(OX)\user.obj >> $@ echo $(OX)\utf8.obj >> $@ echo $(OX)\util.obj >> $@ echo $(OX)\verify.obj >> $@ echo $(OX)\vfile.obj >> $@ echo $(OX)\wiki.obj >> $@ echo $(OX)\wikiformat.obj >> $@ echo $(OX)\winfile.obj >> $@ echo $(OX)\winhttp.obj >> $@ echo $(OX)\wysiwyg.obj >> $@ echo $(OX)\xfer.obj >> $@ echo $(OX)\xfersetup.obj >> $@ echo $(OX)\zip.obj >> $@ !ifdef FOSSIL_ENABLE_TCL echo $(OX)\th_tcl.obj >> $@ !endif echo $(LIBS) >> $@ $(OX): @-mkdir $@ translate$E: $(SRCDIR)\translate.c $(BCC) $** makeheaders$E: $(SRCDIR)\makeheaders.c $(BCC) $** mkindex$E: $(SRCDIR)\mkindex.c $(BCC) $** mkversion$E: $B\src\mkversion.c $(BCC) $** $(OX)\shell$O : $(SRCDIR)\shell.c $B\win\Makefile.msc $(TCC) /Fo$@ $(SHELL_OPTIONS) $(SQLITE_OPTIONS) $(SHELL_CFLAGS) -c $(SRCDIR)\shell.c $(OX)\sqlite3$O : $(SRCDIR)\sqlite3.c $B\win\Makefile.msc $(TCC) /Fo$@ -c $(SQLITE_OPTIONS) $(SQLITE_CFLAGS) $(SRCDIR)\sqlite3.c $(OX)\th$O : $(SRCDIR)\th.c $(TCC) /Fo$@ -c $** $(OX)\th_lang$O : $(SRCDIR)\th_lang.c $(TCC) /Fo$@ -c $** !ifdef FOSSIL_ENABLE_TCL $(OX)\th_tcl$O : $(SRCDIR)\th_tcl.c $(TCC) /Fo$@ -c $** !endif 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 -del *_.c -del *.h -del *.map -del *.res -del headers -del linkopts -del vc*.pdb realclean: clean -del $(APPNAME) -del $(PDBNAME) -del translate$E -del mkindex$E -del makeheaders$E -del mkversion$E $(OBJDIR)\json$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_artifact$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_branch$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_config$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_diff$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_dir$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_finfo$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_login$O : $(SRCDIR)\json_detail.h $(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 $** > $@ |
| ︙ | ︙ | |||
1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 | translate$E $** > $@ $(OX)\wikiformat$O : wikiformat_.c wikiformat.h $(TCC) /Fo$@ -c wikiformat_.c wikiformat_.c : $(SRCDIR)\wikiformat.c translate$E $** > $@ $(OX)\winhttp$O : winhttp_.c winhttp.h $(TCC) /Fo$@ -c winhttp_.c winhttp_.c : $(SRCDIR)\winhttp.c translate$E $** > $@ | > > > > > > | 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 | translate$E $** > $@ $(OX)\wikiformat$O : wikiformat_.c wikiformat.h $(TCC) /Fo$@ -c wikiformat_.c wikiformat_.c : $(SRCDIR)\wikiformat.c translate$E $** > $@ $(OX)\winfile$O : winfile_.c winfile.h $(TCC) /Fo$@ -c winfile_.c winfile_.c : $(SRCDIR)\winfile.c translate$E $** > $@ $(OX)\winhttp$O : winhttp_.c winhttp.h $(TCC) /Fo$@ -c winhttp_.c winhttp_.c : $(SRCDIR)\winhttp.c translate$E $** > $@ |
| ︙ | ︙ | |||
1135 1136 1137 1138 1139 1140 1141 | $(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 | | > | 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 | $(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 \ |
| ︙ | ︙ | |||
1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 | 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 \ 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 | > | 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 | 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 |
Added win/buildmsvc.bat.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 |
@ECHO OFF
::
:: buildmsvc.bat --
::
:: This batch file attempts to build Fossil using the latest version
:: Microsoft Visual Studio installed on this machine.
::
::
SETLOCAL
REM SET __ECHO=ECHO
REM SET __ECHO2=ECHO
IF NOT DEFINED _AECHO (SET _AECHO=REM)
IF NOT DEFINED _CECHO (SET _CECHO=REM)
IF NOT DEFINED _VECHO (SET _VECHO=REM)
REM
REM Visual Studio ????
REM
IF DEFINED VSVARS32 IF EXIST "%VSVARS32%" (
%_AECHO% Build environment batch file manually overridden to "%VSVARS32%"...
GOTO skip_detectVisualStudio
)
REM
REM Visual Studio 2013
REM
IF NOT DEFINED VS120COMNTOOLS GOTO skip_detectVisualStudio2013
SET VSVARS32=%VS120COMNTOOLS%\vsvars32.bat
IF EXIST "%VSVARS32%" (
%_AECHO% Using Visual Studio 2013...
GOTO skip_detectVisualStudio
)
:skip_detectVisualStudio2013
REM
REM Visual Studio 2012
REM
IF NOT DEFINED VS110COMNTOOLS GOTO skip_detectVisualStudio2012
SET VSVARS32=%VS110COMNTOOLS%\vsvars32.bat
IF EXIST "%VSVARS32%" (
%_AECHO% Using Visual Studio 2012...
GOTO skip_detectVisualStudio
)
:skip_detectVisualStudio2012
REM
REM Visual Studio 2010
REM
IF NOT DEFINED VS100COMNTOOLS GOTO skip_detectVisualStudio2010
SET VSVARS32=%VS100COMNTOOLS%\vsvars32.bat
IF EXIST "%VSVARS32%" (
%_AECHO% Using Visual Studio 2010...
GOTO skip_detectVisualStudio
)
:skip_detectVisualStudio2010
REM
REM Visual Studio 2008
REM
IF NOT DEFINED VS90COMNTOOLS GOTO skip_detectVisualStudio2008
SET VSVARS32=%VS90COMNTOOLS%\vsvars32.bat
IF EXIST "%VSVARS32%" (
%_AECHO% Using Visual Studio 2008...
GOTO skip_detectVisualStudio
)
:skip_detectVisualStudio2008
REM
REM Visual Studio 2005
REM
IF NOT DEFINED VS80COMNTOOLS GOTO skip_detectVisualStudio2005
SET VSVARS32=%VS80COMNTOOLS%\vsvars32.bat
IF EXIST "%VSVARS32%" (
%_AECHO% Using Visual Studio 2005...
GOTO skip_detectVisualStudio
)
:skip_detectVisualStudio2005
REM
REM Visual Studio 2003
REM
IF NOT DEFINED VS71COMNTOOLS GOTO skip_detectVisualStudio2003
SET VSVARS32=%VS71COMNTOOLS%\vsvars32.bat
IF EXIST "%VSVARS32%" (
%_AECHO% Using Visual Studio 2003...
GOTO skip_detectVisualStudio
)
:skip_detectVisualStudio2003
REM
REM Visual Studio 2002
REM
IF NOT DEFINED VS70COMNTOOLS GOTO skip_detectVisualStudio2002
SET VSVARS32=%VS70COMNTOOLS%\vsvars32.bat
IF EXIST "%VSVARS32%" (
%_AECHO% Using Visual Studio 2002...
GOTO skip_detectVisualStudio
)
:skip_detectVisualStudio2002
REM
REM NOTE: If we get to this point, no Visual Studio build environment batch
REM files were found.
REM
ECHO No Visual Studio build environment batch files were found.
GOTO errors
REM
REM NOTE: At this point, the appropriate Visual Studio version should be
REM selected.
REM
:skip_detectVisualStudio
REM
REM NOTE: Remove any double-backslash sequences that may be present in the
REM selected Visual Studio common tools path. This is not strictly
REM necessary; however, it makes reading the output easier.
REM
SET VSVARS32=%VSVARS32:\\=\%
%_VECHO% VsVars32 = '%VSVARS32%'
REM
REM NOTE: Setup local environment variables that point to the root directory
REM of the Fossil source checkout and to the directory containing this
REM build tool.
REM
SET ROOT=%~dp0\..
SET ROOT=%ROOT:\\=\%
SET TOOLS=%~dp0
SET TOOLS=%TOOLS:~0,-1%
%_VECHO% Root = '%ROOT%'
%_VECHO% Tools = '%TOOLS%'
REM
REM NOTE: After this point, a clean ERRORLEVEL is required; therefore, make
REM sure it is reset now.
REM
CALL :fn_ResetErrorLevel
REM
REM NOTE: Attempt to call the selected batch file to setup the environment
REM variables for building with MSVC.
REM
%__ECHO3% CALL "%VSVARS32%"
IF ERRORLEVEL 1 (
ECHO Visual Studio build environment batch file "%VSVARS32%" failed.
GOTO errors
)
REM
REM NOTE: Attempt to create the build output directory, if necessary.
REM
IF NOT EXIST "%ROOT%\msvcbld" (
%__ECHO% MKDIR "%ROOT%\msvcbld"
IF ERRORLEVEL 1 (
ECHO Could not make directory "%ROOT%\msvcbld".
GOTO errors
)
)
REM
REM NOTE: Attempt to change to the created build output directory so that
REM the generated files will be placed there.
REM
%__ECHO2% PUSHD "%ROOT%\msvcbld"
IF ERRORLEVEL 1 (
ECHO Could not change to directory "%ROOT%\msvcbld".
GOTO errors
)
REM
REM NOTE: Attempt to execute NMAKE for the Fossil MSVC makefile, passing
REM anything extra from our command line along (e.g. extra options).
REM
%__ECHO% nmake /f "%TOOLS%\Makefile.msc" %*
IF ERRORLEVEL 1 (
GOTO errors
)
REM
REM NOTE: Attempt to restore the previously saved directory.
REM
%__ECHO2% POPD
IF ERRORLEVEL 1 (
ECHO Could not restore directory.
GOTO errors
)
GOTO no_errors
:fn_ResetErrorLevel
VERIFY > NUL
GOTO :EOF
:fn_SetErrorLevel
VERIFY MAYBE 2> NUL
GOTO :EOF
:usage
ECHO.
ECHO Usage: %~nx0 [...]
ECHO.
GOTO errors
:errors
CALL :fn_SetErrorLevel
ENDLOCAL
ECHO.
ECHO Build failure, errors were encountered.
GOTO end_of_file
:no_errors
CALL :fn_ResetErrorLevel
ENDLOCAL
ECHO.
ECHO Build success, no errors were encountered.
GOTO end_of_file
:end_of_file
%__ECHO% EXIT /B %ERRORLEVEL%
|
Added win/fossil.exe.manifest.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 |
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"
xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
<assemblyIdentity version="1.0.0.0" processorArchitecture="X86" name="fossil"
type="win32" />
<description>
Simple, high-reliability, distributed software configuration management system.
</description>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
</requestedPrivileges>
</security>
</trustInfo>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- Windows 8.1 -->
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
<!-- Windows 8 -->
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
<!-- Windows 7 -->
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
<!-- Windows Vista -->
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
</application>
</compatibility>
<asmv3:application>
<asmv3:windowsSettings
xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
<dpiAware>true</dpiAware>
</asmv3:windowsSettings>
</asmv3:application>
<dependency>
<dependentAssembly>
<assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls"
version="6.0.0.0" processorArchitecture="X86"
publicKeyToken="6595b64144ccf1df" language="*" />
</dependentAssembly>
</dependency>
</assembly>
|
Changes to win/fossil.rc.
| ︙ | ︙ | |||
128 129 130 131 132 133 134 |
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 0x4b0
END
END
| > > > > > > > > > > > > > > | 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 |
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 0x4b0
END
END
/*
* This embedded manifest is needed for Windows 8.1.
*/
#ifndef RT_MANIFEST
#define RT_MANIFEST 24
#endif
#ifndef CREATEPROCESS_MANIFEST_RESOURCE_ID
#define CREATEPROCESS_MANIFEST_RESOURCE_ID 1
#endif
CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "fossil.exe.manifest"
|
Changes to www/build.wiki.
| ︙ | ︙ | |||
15 16 17 18 19 20 21 | <h2>0.1 Executive Summary</h2> <p>Building and installing is very simple. Three steps:</p> <ol> <li> Download and unpack a source tarball or ZIP. <li> <b>./configure; make</b> | | | | 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | <h2>0.1 Executive Summary</h2> <p>Building and installing is very simple. Three steps:</p> <ol> <li> Download and unpack a source tarball or ZIP. <li> <b>./configure; make</b> <li> Move the resulting "fossil" or "fossil.exe" executable to someplace on your $PATH. </ol> <p><hr> <h2>1.0 Obtaining The Source Code</h2> <p>Fossil is self-hosting, so you can obtain a ZIP archive or tarball |
| ︙ | ︙ | |||
48 49 50 51 52 53 54 55 56 57 58 59 60 61 | link.</p></li> <li><p>Finally, click on one of the "Zip Archive" or "Tarball" links, according to your preference. These link will build a ZIP archive or a gzip-compressed tarball of the complete source code and download it to your browser. </ol> <h2>2.0 Compiling</h2> <ol> <li value="5"> <p>Unpack the ZIP or tarball you downloaded then <b>cd</b> into the directory created.</p></li> | > > > > > > > > > > > > > > > > > > > > | 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 | link.</p></li> <li><p>Finally, click on one of the "Zip Archive" or "Tarball" links, according to your preference. These link will build a ZIP archive or a gzip-compressed tarball of the complete source code and download it to your browser. </ol> <h2>Aside: Is it really safe to use an unreleased development version of the Fossil source code?</h2> Yes! Any check-in on the [/timeline?t=trunk | trunk branch] of the Fossil [http://fossil-scm.org/fossil/timeline | Fossil self-hosting repository] will work fine. (Dodgy code is always on a branch.) In the unlikely event that you pick a version with a serious bug, it still won't clobber your files. Fossil uses several [./selfcheck.wiki | self-checks] prior to committing any repository change that prevent loss-of-work due to bugs. The Fossil [./selfhost.wiki | self-hosting repositories], especially the one at [http://www.fossil-scm.org/fossil], usually run a version of trunk that is less than a week or two old. Look at the bottom right-hand corner of this screen (to the right of "This page was generated in...") to see exactly which version of Fossil is rendering this page. It is always safe to use whatever version of the Fossil code you find running on the main Fossil website. <h2>2.0 Compiling</h2> <ol> <li value="5"> <p>Unpack the ZIP or tarball you downloaded then <b>cd</b> into the directory created.</p></li> |
| ︙ | ︙ | |||
90 91 92 93 94 95 96 | <li><p><i>MinGW/MinGW-w64</i> → Use the mingw makefile: "<b>make -f win/Makefile.mingw</b>". On a Windows box you will need either Cygwin or Msys as build environment. On Cygwin, Linux or Darwin you may want to make minor edits to win/Makefile.mingw to configure the cross-compile environment. | | | > > | 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 |
<li><p><i>MinGW/MinGW-w64</i> → Use the mingw makefile:
"<b>make -f win/Makefile.mingw</b>". On a Windows box you will
need either Cygwin or Msys as build environment. On Cygwin, Linux
or Darwin you may want to make minor edits to win/Makefile.mingw
to configure the cross-compile environment.
<li><p><i>MSVC</i> → Use the msc makefile. First
change to the "win/" subdirectory ("<b>cd win</b>") then run
"<b>nmake /f Makefile.msc</b>". Alternatively, the batch file
"<b>win\buildmsvc.bat</b>" may be used and it will attempt to
detect and use the latest installed version of MSVC.
</ol>
</ol>
<h2>3.0 Installing</h2>
<ol>
<li value="8">
|
| ︙ | ︙ |
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 |
<title>Change Log</title>
<h2>Changes For Version 1.29 (as yet unreleased)</h2>
* Add the ability to display content and diffs for UTF16 text files
in the web interface.
* Honor timezones in imports from git.
* The [/reports] page now requires Read ("o") permissions. The "byweek"
report now properly propagates the selected year through the event type
filter links.
* The [/help/info | info command] now shows leaf status of the checkout.
* Add support for tunneling https through a http proxy (Ticket [e854101c4f]).
* Add option --empty to the "[/help?cmd=open | fossil open]" 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],
[/help?cmd=clean | fossil clean], [/help?cmd=extras | fossil extras],
[/help?cmd=ls | fossil ls] and [/help?cmd=status | fossil status] commands
to restrict operation to files and directories named on the command-line.
* New --integrate option to [/help?cmd=merge | fossil merge], which
|
| ︙ | ︙ | |||
81 82 83 84 85 86 87 |
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].
| | | | | | | 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 |
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
|
| ︙ | ︙ | |||
152 153 154 155 156 157 158 |
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
| | | 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 |
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.
|
| ︙ | ︙ | |||
265 266 267 268 269 270 271 |
* 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
| | | | | | | | | | | 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 |
* 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
|
| ︙ | ︙ | |||
344 345 346 347 348 349 350 |
<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]
| | | | 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 |
<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/makefile.wiki.
| ︙ | ︙ | |||
201 202 203 204 205 206 207 | all at once, or each preprocessed source file can be compiled into a separate object code file and the resulting object code files linked together in a final step. Some files require special C-preprocessor macro definitions. When compiling sqlite.c, the following macros are recommended: | < | | < < < | | > > | 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 | all at once, or each preprocessed source file can be compiled into a separate object code file and the resulting object code files linked together in a final step. Some files require special C-preprocessor macro definitions. When compiling sqlite.c, the following macros are recommended: * -DSQLITE_OMIT_LOAD_EXTENSION=1 * -DSQLITE_ENABLE_LOCKING_STYLE=0 * -DSQLITE_THREADSAFE=0 * -DSQLITE_DEFAULT_FILE_FORMAT=4 * -DSQLITE_ENABLE_EXPLAIN_COMMENTS=1 The first symbol definition above is required; the others are merely recommended. Extension loading is omitted as a security measure. Fossil is single-threaded so mutexing is disabled in SQLite as a performance enhancement. The SQLITE_ENABLE_EXPLAIN_COMMENTS option makes the output of "EXPLAIN" queries in the "[/help?cmd=sqlite3|fossil sql]" command much more readable. When compiling the shell.c source file, these macros are required: * -Dmain=sqlite3_main * -DSQLITE_OMIT_LOAD_EXTENSION=1 The "main()" routine in the shell must be changed into sqlite3_main() |
| ︙ | ︙ |
Changes to www/quotes.wiki.
| ︙ | ︙ | |||
114 115 116 117 118 119 120 121 | the published aspect of the project, so it provides tools for rearranging that history so you can present what you "should" have done rather than what you actually did. <blockquote> <i>Mike Meyer on the Fossil mailing list, 2011-10-04</i> </blockquote> </ol> | > > > > > > | 114 115 116 117 118 119 120 121 122 123 124 125 126 127 | the published aspect of the project, so it provides tools for rearranging that history so you can present what you "should" have done rather than what you actually did. <blockquote> <i>Mike Meyer on the Fossil mailing list, 2011-10-04</i> </blockquote> <li>github is such a pale shadow of what fossil does. <blockquote> <i>dkf on the Tcl chatroom, 2013-12-06</i> </blockquote> </ol> |
Changes to www/sync.wiki.
| ︙ | ︙ | |||
354 355 356 357 358 359 360 361 362 363 364 365 366 367 | <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 | > > > < | 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 | <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> timeline-plaintext <li> ticket-table <li> ticket-common <li> ticket-change <li> ticket-newpage <li> ticket-viewpage <li> ticket-editpage <ul></td><td valign="top"><ul> <li> ticket-reportlist <li> ticket-report-template <li> ticket-key-template <li> ticket-title-expr <li> ticket-closed-expr <li> @reportfmt <li> @user <li> @concealed <li> @shun |
| ︙ | ︙ |