Fossil SCM

Sync with trunk to get sqlite changes et al.

amb 2013-07-27 21:09 ssh-shared-account merge
Commit 021e41014d69a67b767f494a12bbff76c0261eaa
+2
--- src/blob.c
+++ src/blob.c
@@ -1096,11 +1096,13 @@
10961096
** to be UTF-8 already, so no conversion is done.
10971097
*/
10981098
void blob_to_utf8_no_bom(Blob *pBlob, int useMbcs){
10991099
char *zUtf8;
11001100
int bomSize = 0;
1101
+#if defined(_WIN32) || defined(__CYGWIN__)
11011102
int bomReverse = 0;
1103
+#endif
11021104
if( starts_with_utf8_bom(pBlob, &bomSize) ){
11031105
struct Blob temp;
11041106
zUtf8 = blob_str(pBlob) + bomSize;
11051107
blob_zero(&temp);
11061108
blob_append(&temp, zUtf8, -1);
11071109
--- src/blob.c
+++ src/blob.c
@@ -1096,11 +1096,13 @@
1096 ** to be UTF-8 already, so no conversion is done.
1097 */
1098 void blob_to_utf8_no_bom(Blob *pBlob, int useMbcs){
1099 char *zUtf8;
1100 int bomSize = 0;
 
1101 int bomReverse = 0;
 
1102 if( starts_with_utf8_bom(pBlob, &bomSize) ){
1103 struct Blob temp;
1104 zUtf8 = blob_str(pBlob) + bomSize;
1105 blob_zero(&temp);
1106 blob_append(&temp, zUtf8, -1);
1107
--- src/blob.c
+++ src/blob.c
@@ -1096,11 +1096,13 @@
1096 ** to be UTF-8 already, so no conversion is done.
1097 */
1098 void blob_to_utf8_no_bom(Blob *pBlob, int useMbcs){
1099 char *zUtf8;
1100 int bomSize = 0;
1101 #if defined(_WIN32) || defined(__CYGWIN__)
1102 int bomReverse = 0;
1103 #endif
1104 if( starts_with_utf8_bom(pBlob, &bomSize) ){
1105 struct Blob temp;
1106 zUtf8 = blob_str(pBlob) + bomSize;
1107 blob_zero(&temp);
1108 blob_append(&temp, zUtf8, -1);
1109
+17 -9
--- src/checkin.c
+++ src/checkin.c
@@ -103,16 +103,16 @@
103103
}
104104
}else if( isNew ){
105105
blob_appendf(report, "ADDED %s\n", zDisplayName);
106106
}else if( isDeleted ){
107107
blob_appendf(report, "DELETED %s\n", zDisplayName);
108
- }else if( isChnged==2 ){
109
- blob_appendf(report, "UPDATED_BY_MERGE %s\n", zDisplayName);
110
- }else if( isChnged==3 ){
111
- blob_appendf(report, "ADDED_BY_MERGE %s\n", zDisplayName);
112
- }else if( isChnged==1 ){
113
- if( file_contains_merge_marker(zFullName) ){
108
+ }else if( isChnged ){
109
+ if( isChnged==2 ){
110
+ blob_appendf(report, "UPDATED_BY_MERGE %s\n", zDisplayName);
111
+ }else if( isChnged==3 ){
112
+ blob_appendf(report, "ADDED_BY_MERGE %s\n", zDisplayName);
113
+ }else if( file_contains_merge_marker(zFullName) ){
114114
blob_appendf(report, "CONFLICT %s\n", zDisplayName);
115115
}else{
116116
blob_appendf(report, "EDITED %s\n", zDisplayName);
117117
}
118118
}else if( isRenamed ){
@@ -127,12 +127,12 @@
127127
db_prepare(&q, "SELECT uuid, id FROM vmerge JOIN blob ON merge=rid"
128128
" WHERE id<=0");
129129
while( db_step(&q)==SQLITE_ROW ){
130130
const char *zLabel = "MERGED_WITH";
131131
switch( db_column_int(&q, 1) ){
132
- case -1: zLabel = "CHERRYPICK"; break;
133
- case -2: zLabel = "BACKOUT "; break;
132
+ case -1: zLabel = "CHERRYPICK "; break;
133
+ case -2: zLabel = "BACKOUT "; break;
134134
}
135135
blob_append(report, zPrefix, nPrefix);
136136
blob_appendf(report, "%s %s\n", zLabel, db_column_text(&q, 0));
137137
}
138138
db_finalize(&q);
@@ -328,11 +328,19 @@
328328
type = "NOT_A_FILE ";
329329
}else{
330330
type = "MISSING ";
331331
}
332332
}else if( chnged ){
333
- type = "EDITED ";
333
+ if( chnged==2 ){
334
+ type = "UPDATED_BY_MERGE ";
335
+ }else if( chnged==3 ){
336
+ type = "ADDED_BY_MERGE ";
337
+ }else if( file_contains_merge_marker(zFullName) ){
338
+ type = "CONFLICT ";
339
+ }else{
340
+ type = "EDITED ";
341
+ }
334342
}else if( renamed ){
335343
type = "RENAMED ";
336344
}else{
337345
type = "UNCHANGED ";
338346
}
339347
--- src/checkin.c
+++ src/checkin.c
@@ -103,16 +103,16 @@
103 }
104 }else if( isNew ){
105 blob_appendf(report, "ADDED %s\n", zDisplayName);
106 }else if( isDeleted ){
107 blob_appendf(report, "DELETED %s\n", zDisplayName);
108 }else if( isChnged==2 ){
109 blob_appendf(report, "UPDATED_BY_MERGE %s\n", zDisplayName);
110 }else if( isChnged==3 ){
111 blob_appendf(report, "ADDED_BY_MERGE %s\n", zDisplayName);
112 }else if( isChnged==1 ){
113 if( file_contains_merge_marker(zFullName) ){
114 blob_appendf(report, "CONFLICT %s\n", zDisplayName);
115 }else{
116 blob_appendf(report, "EDITED %s\n", zDisplayName);
117 }
118 }else if( isRenamed ){
@@ -127,12 +127,12 @@
127 db_prepare(&q, "SELECT uuid, id FROM vmerge JOIN blob ON merge=rid"
128 " WHERE id<=0");
129 while( db_step(&q)==SQLITE_ROW ){
130 const char *zLabel = "MERGED_WITH";
131 switch( db_column_int(&q, 1) ){
132 case -1: zLabel = "CHERRYPICK"; break;
133 case -2: zLabel = "BACKOUT "; break;
134 }
135 blob_append(report, zPrefix, nPrefix);
136 blob_appendf(report, "%s %s\n", zLabel, db_column_text(&q, 0));
137 }
138 db_finalize(&q);
@@ -328,11 +328,19 @@
328 type = "NOT_A_FILE ";
329 }else{
330 type = "MISSING ";
331 }
332 }else if( chnged ){
333 type = "EDITED ";
 
 
 
 
 
 
 
 
334 }else if( renamed ){
335 type = "RENAMED ";
336 }else{
337 type = "UNCHANGED ";
338 }
339
--- src/checkin.c
+++ src/checkin.c
@@ -103,16 +103,16 @@
103 }
104 }else if( isNew ){
105 blob_appendf(report, "ADDED %s\n", zDisplayName);
106 }else if( isDeleted ){
107 blob_appendf(report, "DELETED %s\n", zDisplayName);
108 }else if( isChnged ){
109 if( isChnged==2 ){
110 blob_appendf(report, "UPDATED_BY_MERGE %s\n", zDisplayName);
111 }else if( isChnged==3 ){
112 blob_appendf(report, "ADDED_BY_MERGE %s\n", zDisplayName);
113 }else if( file_contains_merge_marker(zFullName) ){
114 blob_appendf(report, "CONFLICT %s\n", zDisplayName);
115 }else{
116 blob_appendf(report, "EDITED %s\n", zDisplayName);
117 }
118 }else if( isRenamed ){
@@ -127,12 +127,12 @@
127 db_prepare(&q, "SELECT uuid, id FROM vmerge JOIN blob ON merge=rid"
128 " WHERE id<=0");
129 while( db_step(&q)==SQLITE_ROW ){
130 const char *zLabel = "MERGED_WITH";
131 switch( db_column_int(&q, 1) ){
132 case -1: zLabel = "CHERRYPICK "; break;
133 case -2: zLabel = "BACKOUT "; break;
134 }
135 blob_append(report, zPrefix, nPrefix);
136 blob_appendf(report, "%s %s\n", zLabel, db_column_text(&q, 0));
137 }
138 db_finalize(&q);
@@ -328,11 +328,19 @@
328 type = "NOT_A_FILE ";
329 }else{
330 type = "MISSING ";
331 }
332 }else if( chnged ){
333 if( chnged==2 ){
334 type = "UPDATED_BY_MERGE ";
335 }else if( chnged==3 ){
336 type = "ADDED_BY_MERGE ";
337 }else if( file_contains_merge_marker(zFullName) ){
338 type = "CONFLICT ";
339 }else{
340 type = "EDITED ";
341 }
342 }else if( renamed ){
343 type = "RENAMED ";
344 }else{
345 type = "UNCHANGED ";
346 }
347
+9 -2
--- src/db.c
+++ src/db.c
@@ -712,10 +712,13 @@
712712
LOCAL sqlite3 *db_open(const char *zDbName){
713713
int rc;
714714
const char *zVfs;
715715
sqlite3 *db;
716716
717
+#if defined(__CYGWIN__)
718
+ zDbName = fossil_utf8_to_filename(zDbName);
719
+#endif
717720
if( g.fSqlTrace ) fossil_trace("-- sqlite3_open: [%s]\n", zDbName);
718721
zVfs = fossil_getenv("FOSSIL_VFS");
719722
rc = sqlite3_open_v2(
720723
zDbName, &db,
721724
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
@@ -1020,13 +1023,17 @@
10201023
g.json.resultCode = FSL_JSON_E_DB_NOT_VALID;
10211024
#endif
10221025
fossil_panic("not a valid repository: %s", zDbName);
10231026
}
10241027
}
1025
- db_open_or_attach(zDbName, "repository", 0);
1026
- g.repositoryOpen = 1;
1028
+#if defined(__CYGWIN__)
1029
+ g.zRepositoryName = fossil_utf8_to_filename(zDbName);
1030
+#else
10271031
g.zRepositoryName = mprintf("%s", zDbName);
1032
+#endif
1033
+ db_open_or_attach(g.zRepositoryName, "repository", 0);
1034
+ g.repositoryOpen = 1;
10281035
/* Cache "allow-symlinks" option, because we'll need it on every stat call */
10291036
g.allowSymlinks = db_get_boolean("allow-symlinks", 0);
10301037
}
10311038
10321039
/*
10331040
--- src/db.c
+++ src/db.c
@@ -712,10 +712,13 @@
712 LOCAL sqlite3 *db_open(const char *zDbName){
713 int rc;
714 const char *zVfs;
715 sqlite3 *db;
716
 
 
 
717 if( g.fSqlTrace ) fossil_trace("-- sqlite3_open: [%s]\n", zDbName);
718 zVfs = fossil_getenv("FOSSIL_VFS");
719 rc = sqlite3_open_v2(
720 zDbName, &db,
721 SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
@@ -1020,13 +1023,17 @@
1020 g.json.resultCode = FSL_JSON_E_DB_NOT_VALID;
1021 #endif
1022 fossil_panic("not a valid repository: %s", zDbName);
1023 }
1024 }
1025 db_open_or_attach(zDbName, "repository", 0);
1026 g.repositoryOpen = 1;
 
1027 g.zRepositoryName = mprintf("%s", zDbName);
 
 
 
1028 /* Cache "allow-symlinks" option, because we'll need it on every stat call */
1029 g.allowSymlinks = db_get_boolean("allow-symlinks", 0);
1030 }
1031
1032 /*
1033
--- src/db.c
+++ src/db.c
@@ -712,10 +712,13 @@
712 LOCAL sqlite3 *db_open(const char *zDbName){
713 int rc;
714 const char *zVfs;
715 sqlite3 *db;
716
717 #if defined(__CYGWIN__)
718 zDbName = fossil_utf8_to_filename(zDbName);
719 #endif
720 if( g.fSqlTrace ) fossil_trace("-- sqlite3_open: [%s]\n", zDbName);
721 zVfs = fossil_getenv("FOSSIL_VFS");
722 rc = sqlite3_open_v2(
723 zDbName, &db,
724 SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
@@ -1020,13 +1023,17 @@
1023 g.json.resultCode = FSL_JSON_E_DB_NOT_VALID;
1024 #endif
1025 fossil_panic("not a valid repository: %s", zDbName);
1026 }
1027 }
1028 #if defined(__CYGWIN__)
1029 g.zRepositoryName = fossil_utf8_to_filename(zDbName);
1030 #else
1031 g.zRepositoryName = mprintf("%s", zDbName);
1032 #endif
1033 db_open_or_attach(g.zRepositoryName, "repository", 0);
1034 g.repositoryOpen = 1;
1035 /* Cache "allow-symlinks" option, because we'll need it on every stat call */
1036 g.allowSymlinks = db_get_boolean("allow-symlinks", 0);
1037 }
1038
1039 /*
1040
+9 -2
--- src/db.c
+++ src/db.c
@@ -712,10 +712,13 @@
712712
LOCAL sqlite3 *db_open(const char *zDbName){
713713
int rc;
714714
const char *zVfs;
715715
sqlite3 *db;
716716
717
+#if defined(__CYGWIN__)
718
+ zDbName = fossil_utf8_to_filename(zDbName);
719
+#endif
717720
if( g.fSqlTrace ) fossil_trace("-- sqlite3_open: [%s]\n", zDbName);
718721
zVfs = fossil_getenv("FOSSIL_VFS");
719722
rc = sqlite3_open_v2(
720723
zDbName, &db,
721724
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
@@ -1020,13 +1023,17 @@
10201023
g.json.resultCode = FSL_JSON_E_DB_NOT_VALID;
10211024
#endif
10221025
fossil_panic("not a valid repository: %s", zDbName);
10231026
}
10241027
}
1025
- db_open_or_attach(zDbName, "repository", 0);
1026
- g.repositoryOpen = 1;
1028
+#if defined(__CYGWIN__)
1029
+ g.zRepositoryName = fossil_utf8_to_filename(zDbName);
1030
+#else
10271031
g.zRepositoryName = mprintf("%s", zDbName);
1032
+#endif
1033
+ db_open_or_attach(g.zRepositoryName, "repository", 0);
1034
+ g.repositoryOpen = 1;
10281035
/* Cache "allow-symlinks" option, because we'll need it on every stat call */
10291036
g.allowSymlinks = db_get_boolean("allow-symlinks", 0);
10301037
}
10311038
10321039
/*
10331040
--- src/db.c
+++ src/db.c
@@ -712,10 +712,13 @@
712 LOCAL sqlite3 *db_open(const char *zDbName){
713 int rc;
714 const char *zVfs;
715 sqlite3 *db;
716
 
 
 
717 if( g.fSqlTrace ) fossil_trace("-- sqlite3_open: [%s]\n", zDbName);
718 zVfs = fossil_getenv("FOSSIL_VFS");
719 rc = sqlite3_open_v2(
720 zDbName, &db,
721 SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
@@ -1020,13 +1023,17 @@
1020 g.json.resultCode = FSL_JSON_E_DB_NOT_VALID;
1021 #endif
1022 fossil_panic("not a valid repository: %s", zDbName);
1023 }
1024 }
1025 db_open_or_attach(zDbName, "repository", 0);
1026 g.repositoryOpen = 1;
 
1027 g.zRepositoryName = mprintf("%s", zDbName);
 
 
 
1028 /* Cache "allow-symlinks" option, because we'll need it on every stat call */
1029 g.allowSymlinks = db_get_boolean("allow-symlinks", 0);
1030 }
1031
1032 /*
1033
--- src/db.c
+++ src/db.c
@@ -712,10 +712,13 @@
712 LOCAL sqlite3 *db_open(const char *zDbName){
713 int rc;
714 const char *zVfs;
715 sqlite3 *db;
716
717 #if defined(__CYGWIN__)
718 zDbName = fossil_utf8_to_filename(zDbName);
719 #endif
720 if( g.fSqlTrace ) fossil_trace("-- sqlite3_open: [%s]\n", zDbName);
721 zVfs = fossil_getenv("FOSSIL_VFS");
722 rc = sqlite3_open_v2(
723 zDbName, &db,
724 SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
@@ -1020,13 +1023,17 @@
1023 g.json.resultCode = FSL_JSON_E_DB_NOT_VALID;
1024 #endif
1025 fossil_panic("not a valid repository: %s", zDbName);
1026 }
1027 }
1028 #if defined(__CYGWIN__)
1029 g.zRepositoryName = fossil_utf8_to_filename(zDbName);
1030 #else
1031 g.zRepositoryName = mprintf("%s", zDbName);
1032 #endif
1033 db_open_or_attach(g.zRepositoryName, "repository", 0);
1034 g.repositoryOpen = 1;
1035 /* Cache "allow-symlinks" option, because we'll need it on every stat call */
1036 g.allowSymlinks = db_get_boolean("allow-symlinks", 0);
1037 }
1038
1039 /*
1040
+202 -516
--- src/diff.c
+++ src/diff.c
@@ -51,47 +51,20 @@
5151
"cannot compute difference between binary files\n"
5252
5353
#define DIFF_CANNOT_COMPUTE_SYMLINK \
5454
"cannot compute difference between symlink and regular file\n"
5555
56
-#define DIFF_TOO_MANY_CHANGES_TXT \
56
+#define DIFF_TOO_MANY_CHANGES \
5757
"more than 10,000 changes\n"
5858
59
-#define DIFF_TOO_MANY_CHANGES_HTML \
60
- "<p class='generalError'>More than 10,000 changes</p>\n"
61
-
62
-/*
63
-** This macro is designed to return non-zero if the specified blob contains
64
-** data that MAY be binary in nature; otherwise, zero will be returned.
65
-*/
66
-#define looks_like_binary(blob) \
67
- ((looks_like_utf8((blob), LOOK_BINARY) & LOOK_BINARY) != LOOK_NONE)
68
-
69
-/*
70
-** Output flags for the looks_like_utf8() and looks_like_utf16() routines used
71
-** to convey status information about the blob content.
72
-*/
73
-#define LOOK_NONE ((int)0x00000000) /* Nothing special was found. */
74
-#define LOOK_NUL ((int)0x00000001) /* One or more NUL chars were found. */
75
-#define LOOK_CR ((int)0x00000002) /* One or more CR chars were found. */
76
-#define LOOK_LONE_CR ((int)0x00000004) /* An unpaired CR char was found. */
77
-#define LOOK_LF ((int)0x00000008) /* One or more LF chars were found. */
78
-#define LOOK_LONE_LF ((int)0x00000010) /* An unpaired LF char was found. */
79
-#define LOOK_CRLF ((int)0x00000020) /* One or more CR/LF pairs were found. */
80
-#define LOOK_LONG ((int)0x00000040) /* An over length line was found. */
81
-#define LOOK_ODD ((int)0x00000080) /* An odd number of bytes was found. */
82
-#define LOOK_SHORT ((int)0x00000100) /* Unable to perform full check. */
83
-#define LOOK_INVALID ((int)0x00000200) /* Invalid sequence was found. */
84
-#define LOOK_BINARY (LOOK_NUL | LOOK_LONG | LOOK_SHORT) /* May be binary. */
85
-#define LOOK_EOL (LOOK_LONE_CR | LOOK_LONE_LF | LOOK_CRLF) /* Line seps. */
86
-#endif /* INTERFACE */
87
-
8859
/*
8960
** Maximum length of a line in a text file, in bytes. (2**13 = 8192 bytes)
9061
*/
9162
#define LENGTH_MASK_SZ 13
9263
#define LENGTH_MASK ((1<<LENGTH_MASK_SZ)-1)
64
+
65
+#endif /* INTERFACE */
9366
9467
/*
9568
** Information about each line of a file being diffed.
9669
**
9770
** The lower LENGTH_MASK_SZ bits of the hash (DLine.h) are the length
@@ -204,282 +177,10 @@
204177
/* Return results */
205178
*pnLine = nLine;
206179
return a;
207180
}
208181
209
-/*
210
-** This function attempts to scan each logical line within the blob to
211
-** determine the type of content it appears to contain. The return value
212
-** is a combination of one or more of the LOOK_XXX flags (see above):
213
-**
214
-** !LOOK_BINARY -- The content appears to consist entirely of text; however,
215
-** the encoding may not be UTF-8.
216
-**
217
-** LOOK_BINARY -- The content appears to be binary because it contains one
218
-** or more embedded NUL characters or an extremely long line.
219
-** Since this function does not understand UTF-16, it may
220
-** falsely consider UTF-16 text to be binary.
221
-**
222
-** Additional flags (i.e. those other than the ones included in LOOK_BINARY)
223
-** may be present in the result as well; however, they should not impact the
224
-** determination of text versus binary content.
225
-**
226
-************************************ WARNING **********************************
227
-**
228
-** This function does not validate that the blob content is properly formed
229
-** UTF-8. It assumes that all code points are the same size. It does not
230
-** validate any code points. It makes no attempt to detect if any [invalid]
231
-** switches between UTF-8 and other encodings occur.
232
-**
233
-** The only code points that this function cares about are the NUL character,
234
-** carriage-return, and line-feed.
235
-**
236
-** This function examines the contents of the blob until one of the flags
237
-** specified in "stopFlags" is set.
238
-**
239
-************************************ WARNING **********************************
240
-*/
241
-int looks_like_utf8(const Blob *pContent, int stopFlags){
242
- const char *z = blob_buffer(pContent);
243
- unsigned int n = blob_size(pContent);
244
- int j, c, flags = LOOK_NONE; /* Assume UTF-8 text, prove otherwise */
245
-
246
- if( n==0 ) return flags; /* Empty file -> text */
247
- c = *z;
248
- if( c==0 ){
249
- flags |= LOOK_NUL; /* NUL character in a file -> binary */
250
- }else if( c=='\r' ){
251
- flags |= LOOK_CR;
252
- if( n<=1 || z[1]!='\n' ){
253
- flags |= LOOK_LONE_CR; /* More chars, next char is not LF */
254
- }
255
- }
256
- j = (c!='\n');
257
- if( !j ) flags |= (LOOK_LF | LOOK_LONE_LF); /* Found LF as first char */
258
- while( !(flags&stopFlags) && --n>0 ){
259
- int c2 = c;
260
- c = *++z; ++j;
261
- if( c==0 ){
262
- flags |= LOOK_NUL; /* NUL character in a file -> binary */
263
- }else if( c=='\n' ){
264
- flags |= LOOK_LF;
265
- if( c2=='\r' ){
266
- flags |= (LOOK_CR | LOOK_CRLF); /* Found LF preceded by CR */
267
- }else{
268
- flags |= LOOK_LONE_LF;
269
- }
270
- if( j>LENGTH_MASK ){
271
- flags |= LOOK_LONG; /* Very long line -> binary */
272
- }
273
- j = 0;
274
- }else if( c=='\r' ){
275
- flags |= LOOK_CR;
276
- if( n<=1 || z[1]!='\n' ){
277
- flags |= LOOK_LONE_CR; /* More chars, next char is not LF */
278
- }
279
- }
280
- }
281
- if( n ){
282
- flags |= LOOK_SHORT; /* The whole blob was not examined */
283
- }
284
- if( j>LENGTH_MASK ){
285
- flags |= LOOK_LONG; /* Very long line -> binary */
286
- }
287
- return flags;
288
-}
289
-
290
-/*
291
-** Define the type needed to represent a Unicode (UTF-16) character.
292
-*/
293
-#ifndef WCHAR_T
294
-# ifdef _WIN32
295
-# define WCHAR_T wchar_t
296
-# else
297
-# define WCHAR_T unsigned short
298
-# endif
299
-#endif
300
-
301
-/*
302
-** Maximum length of a line in a text file, in UTF-16 characters. (4096)
303
-** The number of bytes represented by this value cannot exceed LENGTH_MASK
304
-** bytes, because that is the line buffer size used by the diff engine.
305
-*/
306
-#define UTF16_LENGTH_MASK_SZ (LENGTH_MASK_SZ-(sizeof(WCHAR_T)-sizeof(char)))
307
-#define UTF16_LENGTH_MASK ((1<<UTF16_LENGTH_MASK_SZ)-1)
308
-
309
-/*
310
-** This macro is used to swap the byte order of a UTF-16 character in the
311
-** looks_like_utf16() function.
312
-*/
313
-#define UTF16_SWAP(ch) ((((ch) << 8) & 0xFF00) | (((ch) >> 8) & 0xFF))
314
-#define UTF16_SWAP_IF(expr,ch) ((expr) ? UTF16_SWAP((ch)) : (ch))
315
-
316
-/*
317
-** This function attempts to scan each logical line within the blob to
318
-** determine the type of content it appears to contain. The return value
319
-** is a combination of one or more of the LOOK_XXX flags (see above):
320
-**
321
-** !LOOK_BINARY -- The content appears to consist entirely of text; however,
322
-** the encoding may not be UTF-16.
323
-**
324
-** LOOK_BINARY -- The content appears to be binary because it contains one
325
-** or more embedded NUL characters or an extremely long line.
326
-** Since this function does not understand UTF-8, it may
327
-** falsely consider UTF-8 text to be binary.
328
-**
329
-** Additional flags (i.e. those other than the ones included in LOOK_BINARY)
330
-** may be present in the result as well; however, they should not impact the
331
-** determination of text versus binary content.
332
-**
333
-************************************ WARNING **********************************
334
-**
335
-** This function does not validate that the blob content is properly formed
336
-** UTF-16. It assumes that all code points are the same size. It does not
337
-** validate any code points. It makes no attempt to detect if any [invalid]
338
-** switches between the UTF-16be and UTF-16le encodings occur.
339
-**
340
-** The only code points that this function cares about are the NUL character,
341
-** carriage-return, and line-feed.
342
-**
343
-** This function examines the contents of the blob until one of the flags
344
-** specified in "stopFlags" is set.
345
-**
346
-************************************ WARNING **********************************
347
-*/
348
-int looks_like_utf16(const Blob *pContent, int bReverse, int stopFlags){
349
- const WCHAR_T *z = (WCHAR_T *)blob_buffer(pContent);
350
- unsigned int n = blob_size(pContent);
351
- int j, c, flags = LOOK_NONE; /* Assume UTF-16 text, prove otherwise */
352
-
353
- if( n==0 ) return flags; /* Empty file -> text */
354
- if( n%sizeof(WCHAR_T) ){
355
- flags |= LOOK_ODD; /* Odd number of bytes -> binary (UTF-8?) */
356
- if( n<sizeof(WCHAR_T) ) return flags; /* One byte -> binary (UTF-8?) */
357
- }
358
- c = *z;
359
- if( bReverse ){
360
- c = UTF16_SWAP(c);
361
- }
362
- if( c==0 ){
363
- flags |= LOOK_NUL; /* NUL character in a file -> binary */
364
- }else if( c=='\r' ){
365
- flags |= LOOK_CR;
366
- if( n<(2*sizeof(WCHAR_T)) || UTF16_SWAP_IF(bReverse, z[1])!='\n' ){
367
- flags |= LOOK_LONE_CR; /* More chars, next char is not LF */
368
- }
369
- }
370
- j = (c!='\n');
371
- if( !j ) flags |= (LOOK_LF | LOOK_LONE_LF); /* Found LF as first char */
372
- while( 1 ){
373
- int c2 = c;
374
- if( flags&stopFlags ) break;
375
- n -= sizeof(WCHAR_T);
376
- if( n<sizeof(WCHAR_T) ) break;
377
- c = *++z;
378
- if( bReverse ){
379
- c = UTF16_SWAP(c);
380
- }
381
- ++j;
382
- if( c==0 ){
383
- flags |= LOOK_NUL; /* NUL character in a file -> binary */
384
- }else if( c=='\n' ){
385
- flags |= LOOK_LF;
386
- if( c2=='\r' ){
387
- flags |= (LOOK_CR | LOOK_CRLF); /* Found LF preceded by CR */
388
- }else{
389
- flags |= LOOK_LONE_LF;
390
- }
391
- if( j>UTF16_LENGTH_MASK ){
392
- flags |= LOOK_LONG; /* Very long line -> binary */
393
- }
394
- j = 0;
395
- }else if( c=='\r' ){
396
- flags |= LOOK_CR;
397
- if( n<(2*sizeof(WCHAR_T)) || UTF16_SWAP_IF(bReverse, z[1])!='\n' ){
398
- flags |= LOOK_LONE_CR; /* More chars, next char is not LF */
399
- }
400
- }
401
- }
402
- if( n ){
403
- flags |= LOOK_SHORT; /* The whole blob was not examined */
404
- }
405
- if( j>UTF16_LENGTH_MASK ){
406
- flags |= LOOK_LONG; /* Very long line -> binary */
407
- }
408
- return flags;
409
-}
410
-
411
-/*
412
-** This function returns an array of bytes representing the byte-order-mark
413
-** for UTF-8.
414
-*/
415
-const unsigned char *get_utf8_bom(int *pnByte){
416
- static const unsigned char bom[] = {
417
- 0xEF, 0xBB, 0xBF, 0x00, 0x00, 0x00
418
- };
419
- if( pnByte ) *pnByte = 3;
420
- return bom;
421
-}
422
-
423
-/*
424
-** This function returns non-zero if the blob starts with a UTF-8
425
-** byte-order-mark (BOM).
426
-*/
427
-int starts_with_utf8_bom(const Blob *pContent, int *pnByte){
428
- const char *z = blob_buffer(pContent);
429
- int bomSize = 0;
430
- const unsigned char *bom = get_utf8_bom(&bomSize);
431
-
432
- if( pnByte ) *pnByte = bomSize;
433
- if( blob_size(pContent)<bomSize ) return 0;
434
- return memcmp(z, bom, bomSize)==0;
435
-}
436
-
437
-/*
438
-** This function returns non-zero if the blob starts with a UTF-16
439
-** byte-order-mark (BOM), either in the endianness of the machine
440
-** or in reversed byte order. The UTF-32 BOM is ruled out by checking
441
-** if the UTF-16 BOM is not immediately followed by (utf16) 0.
442
-** pnByte is only set when the function returns 1.
443
-**
444
-** pbReverse is always set, even when no BOM is found. Without a BOM,
445
-** it is set to 1 on little-endian and 0 on big-endian platforms. See
446
-** clause D98 of conformance (section 3.10) of the Unicode standard.
447
-*/
448
-int starts_with_utf16_bom(
449
- const Blob *pContent, /* IN: Blob content to perform BOM detection on. */
450
- int *pnByte, /* OUT: The number of bytes used for the BOM. */
451
- int *pbReverse /* OUT: Non-zero for BOM in reverse byte-order. */
452
-){
453
- const unsigned short *z = (unsigned short *)blob_buffer(pContent);
454
- int bomSize = sizeof(unsigned short);
455
- int size = blob_size(pContent);
456
-
457
- if( size<bomSize ) goto noBom; /* No: cannot read BOM. */
458
- if( size>=(2*bomSize) && z[1]==0 ) goto noBom; /* No: possible UTF-32. */
459
- if( z[0]==0xfeff ){
460
- if( pbReverse ) *pbReverse = 0;
461
- }else if( z[0]==0xfffe ){
462
- if( pbReverse ) *pbReverse = 1;
463
- }else{
464
- static const int one = 1;
465
- noBom:
466
- if( pbReverse ) *pbReverse = *(char *) &one;
467
- return 0; /* No: UTF-16 byte-order-mark not found. */
468
- }
469
- if( pnByte ) *pnByte = bomSize;
470
- return 1; /* Yes. */
471
-}
472
-
473
-/*
474
-** Returns non-zero if the specified content could be valid UTF-16.
475
-*/
476
-int could_be_utf16(const Blob *pContent, int *pbReverse){
477
- return (blob_size(pContent) % sizeof(WCHAR_T) == 0) ?
478
- starts_with_utf16_bom(pContent, 0, pbReverse) : 0;
479
-}
480
-
481182
/*
482183
** Return true if two DLine elements are identical.
483184
*/
484185
static int same_dline(DLine *pA, DLine *pB){
485186
return pA->h==pB->h && memcmp(pA->z,pB->z,pA->h & LENGTH_MASK)==0;
@@ -576,11 +277,11 @@
576277
int mxr; /* Maximum value for r */
577278
int na, nb; /* Number of lines shown from A and B */
578279
int i, j; /* Loop counters */
579280
int m; /* Number of lines to output */
580281
int skip; /* Number of lines to skip */
581
- int nChunk = 0; /* Number of diff chunks seen so far */
282
+ static int nChunk = 0; /* Number of diff chunks seen so far */
582283
int nContext; /* Number of lines of context */
583284
int showLn; /* Show line numbers */
584285
int html; /* Render as HTML */
585286
int showDivider = 0; /* True to show the divider between diff blocks */
586287
@@ -657,14 +358,14 @@
657358
if( !showDivider ){
658359
/* Do not show a top divider */
659360
showDivider = 1;
660361
}else if( html ){
661362
blob_appendf(pOut, "<span class=\"diffhr\">%.80c</span>\n", '.');
662
- blob_appendf(pOut, "<a name=\"chunk%d\"></a>\n", nChunk);
663363
}else{
664364
blob_appendf(pOut, "%.80c\n", '.');
665365
}
366
+ if( html ) blob_appendf(pOut, "<span id=\"chunk%d\"></span>", nChunk);
666367
}else{
667368
if( html ) blob_appendf(pOut, "<span class=\"diffln\">");
668369
/*
669370
* If the patch changes an empty file or results in an empty file,
670371
* the block header must use 0,0 as position indicator and not 1,0.
@@ -727,12 +428,11 @@
727428
/*
728429
** Status of a single output line
729430
*/
730431
typedef struct SbsLine SbsLine;
731432
struct SbsLine {
732
- char *zLine; /* The output line under construction */
733
- int n; /* Index of next unused slot in the zLine[] */
433
+ Blob *apCols[5]; /* Array of pointers to output columns */
734434
int width; /* Maximum width of a column in the output */
735435
unsigned char escHtml; /* True to escape html characters */
736436
int iStart; /* Write zStart prior to character iStart */
737437
const char *zStart; /* A <span> tag */
738438
int iEnd; /* Write </span> prior to character iEnd */
@@ -741,125 +441,155 @@
741441
int iEnd2; /* Write </span> prior to character iEnd2 */
742442
ReCompiled *pRe; /* Only colorize matching lines, if not NULL */
743443
};
744444
745445
/*
746
-** Flags for sbsWriteText()
446
+** Column indices for SbsLine.apCols[]
447
+*/
448
+#define SBS_LNA 0 /* Left line number */
449
+#define SBS_TXTA 1 /* Left text */
450
+#define SBS_MKR 2 /* Middle separator column */
451
+#define SBS_LNB 3 /* Right line number */
452
+#define SBS_TXTB 4 /* Right text */
453
+
454
+/*
455
+** Append newlines to all columns.
456
+*/
457
+static void sbsWriteNewlines(SbsLine *p){
458
+ int i;
459
+ for( i=p->escHtml ? SBS_LNA : SBS_TXTB; i<=SBS_TXTB; i++ ){
460
+ blob_append(p->apCols[i], "\n", 1);
461
+ }
462
+}
463
+
464
+/*
465
+** Append n spaces to the column.
747466
*/
748
-#define SBS_NEWLINE 0x0001 /* End with \n\000 */
749
-#define SBS_PAD 0x0002 /* Pad output to width spaces */
467
+static void sbsWriteSpace(SbsLine *p, int n, int col){
468
+ blob_appendf(p->apCols[col], "%*s", n, "");
469
+}
750470
751471
/*
752
-** Write up to width characters of pLine into p->zLine[]. Translate tabs into
753
-** spaces. Add a newline if SBS_NEWLINE is set. Translate HTML characters
754
-** if SBS_HTML is set. Pad the rendering out width bytes if SBS_PAD is set.
472
+** Write the text of pLine into column iCol of p.
473
+**
474
+** If outputting HTML, write the full line. Otherwise, only write the
475
+** width characters. Translate tabs into spaces. Add newlines if col
476
+** is SBS_TXTB. Translate HTML characters if escHtml is true. Pad the
477
+** rendering to width bytes if col is SBS_TXTA and escHtml is false.
755478
**
756479
** This comment contains multibyte unicode characters (ü, Æ, ð) in order
757480
** to test the ability of the diff code to handle such characters.
758481
*/
759
-static void sbsWriteText(SbsLine *p, DLine *pLine, unsigned flags){
482
+static void sbsWriteText(SbsLine *p, DLine *pLine, int col){
483
+ Blob *pCol = p->apCols[col];
760484
int n = pLine->h & LENGTH_MASK;
761485
int i; /* Number of input characters consumed */
762
- int j; /* Number of output characters generated */
763486
int k; /* Cursor position */
764487
int needEndSpan = 0;
765488
const char *zIn = pLine->z;
766
- char *z = &p->zLine[p->n];
767489
int w = p->width;
768490
int colorize = p->escHtml;
769491
if( colorize && p->pRe && re_dline_match(p->pRe, pLine, 1)==0 ){
770492
colorize = 0;
771493
}
772
- for(i=j=k=0; k<w && i<n; i++, k++){
494
+ for(i=k=0; (p->escHtml || k<w) && i<n; i++, k++){
773495
char c = zIn[i];
774496
if( colorize ){
775497
if( i==p->iStart ){
776498
int x = strlen(p->zStart);
777
- memcpy(z+j, p->zStart, x);
778
- j += x;
499
+ blob_append(pCol, p->zStart, x);
779500
needEndSpan = 1;
780501
if( p->iStart2 ){
781502
p->iStart = p->iStart2;
782503
p->zStart = p->zStart2;
783504
p->iStart2 = 0;
784505
}
785506
}else if( i==p->iEnd ){
786
- memcpy(z+j, "</span>", 7);
787
- j += 7;
507
+ blob_append(pCol, "</span>", 7);
788508
needEndSpan = 0;
789509
if( p->iEnd2 ){
790510
p->iEnd = p->iEnd2;
791511
p->iEnd2 = 0;
792512
}
793513
}
794514
}
795
- if( c=='\t' ){
796
- z[j++] = ' ';
797
- while( (k&7)!=7 && k<w ){ z[j++] = ' '; k++; }
515
+ if( c=='\t' && !p->escHtml ){
516
+ blob_append(pCol, " ", 1);
517
+ while( (k&7)!=7 && (p->escHtml || k<w) ){
518
+ blob_append(pCol, " ", 1);
519
+ k++;
520
+ }
798521
}else if( c=='\r' || c=='\f' ){
799
- z[j++] = ' ';
522
+ blob_append(pCol, " ", 1);
800523
}else if( c=='<' && p->escHtml ){
801
- memcpy(&z[j], "&lt;", 4);
802
- j += 4;
524
+ blob_append(pCol, "&lt;", 4);
803525
}else if( c=='&' && p->escHtml ){
804
- memcpy(&z[j], "&amp;", 5);
805
- j += 5;
526
+ blob_append(pCol, "&amp;", 5);
806527
}else if( c=='>' && p->escHtml ){
807
- memcpy(&z[j], "&gt;", 4);
808
- j += 4;
528
+ blob_append(pCol, "&gt;", 4);
809529
}else if( c=='"' && p->escHtml ){
810
- memcpy(&z[j], "&quot;", 6);
811
- j += 6;
530
+ blob_append(pCol, "&quot;", 6);
812531
}else{
813
- z[j++] = c;
532
+ blob_append(pCol, &zIn[i], 1);
814533
if( (c&0xc0)==0x80 ) k--;
815534
}
816535
}
817536
if( needEndSpan ){
818
- memcpy(&z[j], "</span>", 7);
819
- j += 7;
820
- }
821
- if( (flags & SBS_PAD)!=0 ){
822
- while( k<w ){ k++; z[j++] = ' '; }
823
- }
824
- if( flags & SBS_NEWLINE ){
825
- z[j++] = '\n';
826
- }
827
- p->n += j;
828
-}
829
-
830
-/*
831
-** Append a string to an SbSLine without coding, interpretation, or padding.
832
-*/
833
-static void sbsWrite(SbsLine *p, const char *zIn, int nIn){
834
- memcpy(p->zLine+p->n, zIn, nIn);
835
- p->n += nIn;
836
-}
837
-
838
-/*
839
-** Append n spaces to the string.
840
-*/
841
-static void sbsWriteSpace(SbsLine *p, int n){
842
- while( n-- ) p->zLine[p->n++] = ' ';
843
-}
844
-
845
-/*
846
-** Append a string to the output only if we are rendering HTML.
847
-*/
848
-static void sbsWriteHtml(SbsLine *p, const char *zIn){
849
- if( p->escHtml ) sbsWrite(p, zIn, strlen(zIn));
850
-}
851
-
852
-/*
853
-** Write a 6-digit line number followed by a single space onto the line.
854
-*/
855
-static void sbsWriteLineno(SbsLine *p, int ln){
856
- sbsWriteHtml(p, "<span class=\"diffln\">");
857
- sqlite3_snprintf(7, &p->zLine[p->n], "%5d ", ln+1);
858
- p->n += 6;
859
- sbsWriteHtml(p, "</span>");
860
- p->zLine[p->n++] = ' ';
537
+ blob_append(pCol, "</span>", 7);
538
+ }
539
+ if( col==SBS_TXTB ){
540
+ sbsWriteNewlines(p);
541
+ }else if( !p->escHtml ){
542
+ sbsWriteSpace(p, w-k, SBS_TXTA);
543
+ }
544
+}
545
+
546
+/*
547
+** Append a column to the final output blob.
548
+*/
549
+static void sbsWriteColumn(Blob *pOut, Blob *pCol, int col){
550
+ blob_appendf(pOut,
551
+ "<td><div class=\"diff%scol\">\n"
552
+ "<pre>\n"
553
+ "%s"
554
+ "</pre>\n"
555
+ "</div></td>\n",
556
+ col % 3 ? (col == SBS_MKR ? "mkr" : "txt") : "ln",
557
+ blob_str(pCol)
558
+ );
559
+}
560
+
561
+/*
562
+** Append a separator line to column iCol
563
+*/
564
+static void sbsWriteSep(SbsLine *p, int len, int col){
565
+ char ch = '.';
566
+ if( len<1 ){
567
+ len = 1;
568
+ ch = ' ';
569
+ }
570
+ blob_appendf(p->apCols[col], "<span class=\"diffhr\">%.*c</span>\n", len, ch);
571
+}
572
+
573
+/*
574
+** Append the appropriate marker into the center column of the diff.
575
+*/
576
+static void sbsWriteMarker(SbsLine *p, const char *zTxt, const char *zHtml){
577
+ blob_append(p->apCols[SBS_MKR], p->escHtml ? zHtml : zTxt, -1);
578
+}
579
+
580
+/*
581
+** Append a line number to the column.
582
+*/
583
+static void sbsWriteLineno(SbsLine *p, int ln, int col){
584
+ if( p->escHtml ){
585
+ blob_appendf(p->apCols[col], "%d", ln+1);
586
+ }else{
587
+ char zLn[7];
588
+ sqlite3_snprintf(7, zLn, "%5d ", ln+1);
589
+ blob_appendf(p->apCols[col], "%s ", zLn);
590
+ }
861591
}
862592
863593
/*
864594
** The two text segments zLeft and zRight are known to be different on
865595
** both ends, but they might have a common segment in the middle. If
@@ -1018,43 +748,42 @@
1018748
}
1019749
if( nSuffix==nLeft || nSuffix==nRight ) nPrefix = 0;
1020750
}
1021751
if( nPrefix+nSuffix > nShort ) nPrefix = nShort - nSuffix;
1022752
1023
-
1024753
/* A single chunk of text inserted on the right */
1025754
if( nPrefix+nSuffix==nLeft ){
1026
- sbsWriteLineno(p, lnLeft);
755
+ sbsWriteLineno(p, lnLeft, SBS_LNA);
1027756
p->iStart2 = p->iEnd2 = 0;
1028757
p->iStart = p->iEnd = -1;
1029
- sbsWriteText(p, pLeft, SBS_PAD);
758
+ sbsWriteText(p, pLeft, SBS_TXTA);
1030759
if( nLeft==nRight && zLeft[nLeft]==zRight[nRight] ){
1031
- sbsWrite(p, " ", 3);
760
+ sbsWriteMarker(p, " ", "");
1032761
}else{
1033
- sbsWrite(p, " | ", 3);
762
+ sbsWriteMarker(p, " | ", "|");
1034763
}
1035
- sbsWriteLineno(p, lnRight);
764
+ sbsWriteLineno(p, lnRight, SBS_LNB);
1036765
p->iStart = nPrefix;
1037766
p->iEnd = nRight - nSuffix;
1038767
p->zStart = zClassAdd;
1039
- sbsWriteText(p, pRight, SBS_NEWLINE);
768
+ sbsWriteText(p, pRight, SBS_TXTB);
1040769
return;
1041770
}
1042771
1043772
/* A single chunk of text deleted from the left */
1044773
if( nPrefix+nSuffix==nRight ){
1045774
/* Text deleted from the left */
1046
- sbsWriteLineno(p, lnLeft);
775
+ sbsWriteLineno(p, lnLeft, SBS_LNA);
1047776
p->iStart2 = p->iEnd2 = 0;
1048777
p->iStart = nPrefix;
1049778
p->iEnd = nLeft - nSuffix;
1050779
p->zStart = zClassRm;
1051
- sbsWriteText(p, pLeft, SBS_PAD);
1052
- sbsWrite(p, " | ", 3);
1053
- sbsWriteLineno(p, lnRight);
780
+ sbsWriteText(p, pLeft, SBS_TXTA);
781
+ sbsWriteMarker(p, " | ", "|");
782
+ sbsWriteLineno(p, lnRight, SBS_LNB);
1054783
p->iStart = p->iEnd = -1;
1055
- sbsWriteText(p, pRight, SBS_NEWLINE);
784
+ sbsWriteText(p, pRight, SBS_TXTB);
1056785
return;
1057786
}
1058787
1059788
/* At this point we know that there is a chunk of text that has
1060789
** changed between the left and the right. Check to see if there
@@ -1065,11 +794,11 @@
1065794
if( p->escHtml
1066795
&& nLeftDiff >= 6
1067796
&& nRightDiff >= 6
1068797
&& textLCS(&zLeft[nPrefix], nLeftDiff, &zRight[nPrefix], nRightDiff, aLCS)
1069798
){
1070
- sbsWriteLineno(p, lnLeft);
799
+ sbsWriteLineno(p, lnLeft, SBS_LNA);
1071800
p->iStart = nPrefix;
1072801
p->iEnd = nPrefix + aLCS[0];
1073802
if( aLCS[2]==0 ){
1074803
sbsShiftLeft(p, pLeft->z);
1075804
p->zStart = zClassRm;
@@ -1078,13 +807,13 @@
1078807
}
1079808
p->iStart2 = nPrefix + aLCS[1];
1080809
p->iEnd2 = nLeft - nSuffix;
1081810
p->zStart2 = aLCS[3]==nRightDiff ? zClassRm : zClassChng;
1082811
sbsSimplifyLine(p, zLeft+nPrefix);
1083
- sbsWriteText(p, pLeft, SBS_PAD);
1084
- sbsWrite(p, " | ", 3);
1085
- sbsWriteLineno(p, lnRight);
812
+ sbsWriteText(p, pLeft, SBS_TXTA);
813
+ sbsWriteMarker(p, " | ", "|");
814
+ sbsWriteLineno(p, lnRight, SBS_LNB);
1086815
p->iStart = nPrefix;
1087816
p->iEnd = nPrefix + aLCS[2];
1088817
if( aLCS[0]==0 ){
1089818
sbsShiftLeft(p, pRight->z);
1090819
p->zStart = zClassAdd;
@@ -1093,25 +822,25 @@
1093822
}
1094823
p->iStart2 = nPrefix + aLCS[3];
1095824
p->iEnd2 = nRight - nSuffix;
1096825
p->zStart2 = aLCS[1]==nLeftDiff ? zClassAdd : zClassChng;
1097826
sbsSimplifyLine(p, zRight+nPrefix);
1098
- sbsWriteText(p, pRight, SBS_NEWLINE);
827
+ sbsWriteText(p, pRight, SBS_TXTB);
1099828
return;
1100829
}
1101830
1102831
/* If all else fails, show a single big change between left and right */
1103
- sbsWriteLineno(p, lnLeft);
832
+ sbsWriteLineno(p, lnLeft, SBS_LNA);
1104833
p->iStart2 = p->iEnd2 = 0;
1105834
p->iStart = nPrefix;
1106835
p->iEnd = nLeft - nSuffix;
1107836
p->zStart = zClassChng;
1108
- sbsWriteText(p, pLeft, SBS_PAD);
1109
- sbsWrite(p, " | ", 3);
1110
- sbsWriteLineno(p, lnRight);
837
+ sbsWriteText(p, pLeft, SBS_TXTA);
838
+ sbsWriteMarker(p, " | ", "|");
839
+ sbsWriteLineno(p, lnRight, SBS_LNB);
1111840
p->iEnd = nRight - nSuffix;
1112
- sbsWriteText(p, pRight, SBS_NEWLINE);
841
+ sbsWriteText(p, pRight, SBS_TXTB);
1113842
}
1114843
1115844
/*
1116845
** Minimum of two values
1117846
*/
@@ -1357,30 +1086,40 @@
13571086
int mxr; /* Maximum value for r */
13581087
int na, nb; /* Number of lines shown from A and B */
13591088
int i, j; /* Loop counters */
13601089
int m, ma, mb;/* Number of lines to output */
13611090
int skip; /* Number of lines to skip */
1362
- int nChunk = 0; /* Number of chunks of diff output seen so far */
1091
+ static int nChunk = 0; /* Number of chunks of diff output seen so far */
13631092
SbsLine s; /* Output line buffer */
13641093
int nContext; /* Lines of context above and below each change */
13651094
int showDivider = 0; /* True to show the divider */
1095
+ Blob aCols[5]; /* Array of column blobs */
13661096
13671097
memset(&s, 0, sizeof(s));
13681098
s.width = diff_width(diffFlags);
1369
- s.zLine = fossil_malloc( 15*s.width + 200 );
1370
- if( s.zLine==0 ) return;
13711099
nContext = diff_context_lines(diffFlags);
13721100
s.escHtml = (diffFlags & DIFF_HTML)!=0;
1101
+ if( s.escHtml ){
1102
+ for(i=SBS_LNA; i<=SBS_TXTB; i++){
1103
+ blob_zero(&aCols[i]);
1104
+ s.apCols[i] = &aCols[i];
1105
+ }
1106
+ }else{
1107
+ for(i=SBS_LNA; i<=SBS_TXTB; i++){
1108
+ s.apCols[i] = pOut;
1109
+ }
1110
+ }
13731111
s.pRe = pRe;
13741112
s.iStart = -1;
13751113
s.iStart2 = 0;
13761114
s.iEnd = -1;
13771115
A = p->aFrom;
13781116
B = p->aTo;
13791117
R = p->aEdit;
13801118
mxr = p->nEdit;
13811119
while( mxr>2 && R[mxr-1]==0 && R[mxr-2]==0 ){ mxr -= 3; }
1120
+
13821121
for(r=0; r<mxr; r += 3*nr){
13831122
/* Figure out how many triples to show in a single block */
13841123
for(nr=1; R[r+nr*3]>0 && R[r+nr*3]<nContext*2; nr++){}
13851124
/* printf("r=%d nr=%d\n", r, nr); */
13861125
@@ -1436,35 +1175,39 @@
14361175
}
14371176
14381177
/* Draw the separator between blocks */
14391178
if( showDivider ){
14401179
if( s.escHtml ){
1441
- blob_appendf(pOut, "<span class=\"diffhr\">%.*c</span>\n",
1442
- s.width*2+16, '.');
1180
+ char zLn[10];
1181
+ sqlite3_snprintf(sizeof(zLn), zLn, "%d", a+skip+1);
1182
+ sbsWriteSep(&s, strlen(zLn), SBS_LNA);
1183
+ sbsWriteSep(&s, s.width, SBS_TXTA);
1184
+ sbsWriteSep(&s, 0, SBS_MKR);
1185
+ sqlite3_snprintf(sizeof(zLn), zLn, "%d", b+skip+1);
1186
+ sbsWriteSep(&s, strlen(zLn), SBS_LNB);
1187
+ sbsWriteSep(&s, s.width, SBS_TXTB);
14431188
}else{
14441189
blob_appendf(pOut, "%.*c\n", s.width*2+16, '.');
14451190
}
14461191
}
14471192
showDivider = 1;
14481193
nChunk++;
14491194
if( s.escHtml ){
1450
- blob_appendf(pOut, "<a name=\"chunk%d\"></a>\n", nChunk);
1195
+ blob_appendf(s.apCols[SBS_LNA], "<span id=\"chunk%d\"></span>", nChunk);
14511196
}
14521197
14531198
/* Show the initial common area */
14541199
a += skip;
14551200
b += skip;
14561201
m = R[r] - skip;
14571202
for(j=0; j<m; j++){
1458
- s.n = 0;
1459
- sbsWriteLineno(&s, a+j);
1203
+ sbsWriteLineno(&s, a+j, SBS_LNA);
14601204
s.iStart = s.iEnd = -1;
1461
- sbsWriteText(&s, &A[a+j], SBS_PAD);
1462
- sbsWrite(&s, " ", 3);
1463
- sbsWriteLineno(&s, b+j);
1464
- sbsWriteText(&s, &B[b+j], SBS_NEWLINE);
1465
- blob_append(pOut, s.zLine, s.n);
1205
+ sbsWriteText(&s, &A[a+j], SBS_TXTA);
1206
+ sbsWriteMarker(&s, " ", "");
1207
+ sbsWriteLineno(&s, b+j, SBS_LNB);
1208
+ sbsWriteText(&s, &B[b+j], SBS_TXTB);
14661209
}
14671210
a += m;
14681211
b += m;
14691212
14701213
/* Show the differences */
@@ -1485,87 +1228,71 @@
14851228
14861229
alignment = sbsAlignment(&A[a], ma, &B[b], mb);
14871230
for(j=0; ma+mb>0; j++){
14881231
if( alignment[j]==1 ){
14891232
/* Delete one line from the left */
1490
- s.n = 0;
1491
- sbsWriteLineno(&s, a);
1233
+ sbsWriteLineno(&s, a, SBS_LNA);
14921234
s.iStart = 0;
14931235
s.zStart = "<span class=\"diffrm\">";
14941236
s.iEnd = LENGTH(&A[a]);
1495
- sbsWriteText(&s, &A[a], SBS_PAD);
1496
- if( s.escHtml ){
1497
- sbsWrite(&s, " &lt;\n", 6);
1498
- }else{
1499
- sbsWrite(&s, " <\n", 3);
1500
- }
1501
- blob_append(pOut, s.zLine, s.n);
1237
+ sbsWriteText(&s, &A[a], SBS_TXTA);
1238
+ sbsWriteMarker(&s, " <", "&lt;");
1239
+ sbsWriteNewlines(&s);
15021240
assert( ma>0 );
15031241
ma--;
15041242
a++;
15051243
}else if( alignment[j]==3 ){
15061244
/* The left line is changed into the right line */
1507
- s.n = 0;
15081245
sbsWriteLineChange(&s, &A[a], a, &B[b], b);
1509
- blob_append(pOut, s.zLine, s.n);
15101246
assert( ma>0 && mb>0 );
15111247
ma--;
15121248
mb--;
15131249
a++;
15141250
b++;
15151251
}else if( alignment[j]==2 ){
15161252
/* Insert one line on the right */
1517
- s.n = 0;
1518
- sbsWriteSpace(&s, s.width + 7);
1519
- if( s.escHtml ){
1520
- sbsWrite(&s, " &gt; ", 6);
1521
- }else{
1522
- sbsWrite(&s, " > ", 3);
1523
- }
1524
- sbsWriteLineno(&s, b);
1253
+ if( !s.escHtml ){
1254
+ sbsWriteSpace(&s, s.width + 7, SBS_TXTA);
1255
+ }
1256
+ sbsWriteMarker(&s, " > ", "&gt;");
1257
+ sbsWriteLineno(&s, b, SBS_LNB);
15251258
s.iStart = 0;
15261259
s.zStart = "<span class=\"diffadd\">";
15271260
s.iEnd = LENGTH(&B[b]);
1528
- sbsWriteText(&s, &B[b], SBS_NEWLINE);
1529
- blob_append(pOut, s.zLine, s.n);
1261
+ sbsWriteText(&s, &B[b], SBS_TXTB);
15301262
assert( mb>0 );
15311263
mb--;
15321264
b++;
15331265
}else{
15341266
/* Delete from the left and insert on the right */
1535
- s.n = 0;
1536
- sbsWriteLineno(&s, a);
1267
+ sbsWriteLineno(&s, a, SBS_LNA);
15371268
s.iStart = 0;
15381269
s.zStart = "<span class=\"diffrm\">";
15391270
s.iEnd = LENGTH(&A[a]);
1540
- sbsWriteText(&s, &A[a], SBS_PAD);
1541
- sbsWrite(&s, " | ", 3);
1542
- sbsWriteLineno(&s, b);
1271
+ sbsWriteText(&s, &A[a], SBS_TXTA);
1272
+ sbsWriteMarker(&s, " | ", "|");
1273
+ sbsWriteLineno(&s, b, SBS_LNB);
15431274
s.iStart = 0;
15441275
s.zStart = "<span class=\"diffadd\">";
15451276
s.iEnd = LENGTH(&B[b]);
1546
- sbsWriteText(&s, &B[b], SBS_NEWLINE);
1547
- blob_append(pOut, s.zLine, s.n);
1277
+ sbsWriteText(&s, &B[b], SBS_TXTB);
15481278
ma--;
15491279
mb--;
15501280
a++;
15511281
b++;
15521282
}
1553
-
15541283
}
15551284
fossil_free(alignment);
15561285
if( i<nr-1 ){
15571286
m = R[r+i*3+3];
15581287
for(j=0; j<m; j++){
1559
- s.n = 0;
1560
- sbsWriteLineno(&s, a+j);
1288
+ sbsWriteLineno(&s, a+j, SBS_LNA);
15611289
s.iStart = s.iEnd = -1;
1562
- sbsWriteText(&s, &A[a+j], SBS_PAD);
1563
- sbsWrite(&s, " ", 3);
1564
- sbsWriteLineno(&s, b+j);
1565
- sbsWriteText(&s, &B[b+j], SBS_NEWLINE);
1566
- blob_append(pOut, s.zLine, s.n);
1290
+ sbsWriteText(&s, &A[a+j], SBS_TXTA);
1291
+ sbsWriteMarker(&s, " ", "");
1292
+ sbsWriteLineno(&s, b+j, SBS_LNB);
1293
+ sbsWriteText(&s, &B[b+j], SBS_TXTB);
15671294
}
15681295
b += m;
15691296
a += m;
15701297
}
15711298
}
@@ -1573,21 +1300,27 @@
15731300
/* Show the final common area */
15741301
assert( nr==i );
15751302
m = R[r+nr*3];
15761303
if( m>nContext ) m = nContext;
15771304
for(j=0; j<m; j++){
1578
- s.n = 0;
1579
- sbsWriteLineno(&s, a+j);
1305
+ sbsWriteLineno(&s, a+j, SBS_LNA);
15801306
s.iStart = s.iEnd = -1;
1581
- sbsWriteText(&s, &A[a+j], SBS_PAD);
1582
- sbsWrite(&s, " ", 3);
1583
- sbsWriteLineno(&s, b+j);
1584
- sbsWriteText(&s, &B[b+j], SBS_NEWLINE);
1585
- blob_append(pOut, s.zLine, s.n);
1307
+ sbsWriteText(&s, &A[a+j], SBS_TXTA);
1308
+ sbsWriteMarker(&s, " ", "");
1309
+ sbsWriteLineno(&s, b+j, SBS_LNB);
1310
+ sbsWriteText(&s, &B[b+j], SBS_TXTB);
15861311
}
15871312
}
1588
- free(s.zLine);
1313
+
1314
+ if( s.escHtml && blob_size(s.apCols[SBS_LNA])>0 ){
1315
+ blob_append(pOut, "<table class=\"sbsdiffcols\" width=\"90%\"><tr>\n", -1);
1316
+ for(i=SBS_LNA; i<=SBS_TXTB; i++){
1317
+ sbsWriteColumn(pOut, s.apCols[i], i);
1318
+ blob_reset(s.apCols[i]);
1319
+ }
1320
+ blob_append(pOut, "</tr></table>\n", -1);
1321
+ }
15891322
}
15901323
15911324
/*
15921325
** Compute the optimal longest common subsequence (LCS) using an
15931326
** exhaustive search. This version of the LCS is only used for
@@ -1990,10 +1723,21 @@
19901723
int diff_width(u64 diffFlags){
19911724
int w = (diffFlags & DIFF_WIDTH_MASK)/(DIFF_CONTEXT_MASK+1);
19921725
if( w==0 ) w = 80;
19931726
return w;
19941727
}
1728
+
1729
+/*
1730
+** Append the error message to pOut.
1731
+*/
1732
+void diff_errmsg(Blob *pOut, const char *msg, int diffFlags){
1733
+ if( diffFlags & DIFF_HTML ){
1734
+ blob_appendf(pOut, "<p class=\"generalError\">%s</p>", msg);
1735
+ }else{
1736
+ blob_append(pOut, msg, -1);
1737
+ }
1738
+}
19951739
19961740
/*
19971741
** Generate a report of the differences between files pA and pB.
19981742
** If pOut is not NULL then a unified diff is appended there. It
19991743
** is assumed that pOut has already been initialized. If pOut is
@@ -2032,11 +1776,11 @@
20321776
&c.nTo, ignoreEolWs);
20331777
if( c.aFrom==0 || c.aTo==0 ){
20341778
fossil_free(c.aFrom);
20351779
fossil_free(c.aTo);
20361780
if( pOut ){
2037
- blob_appendf(pOut, DIFF_CANNOT_COMPUTE_BINARY);
1781
+ diff_errmsg(pOut, DIFF_CANNOT_COMPUTE_BINARY, diffFlags);
20381782
}
20391783
return 0;
20401784
}
20411785
20421786
/* Compute the difference */
@@ -2048,15 +1792,11 @@
20481792
for(i=m=n=0; i<mx; i+=3){ m += a[i]; n += a[i+1]+a[i+2]; }
20491793
if( n>10000 ){
20501794
fossil_free(c.aFrom);
20511795
fossil_free(c.aTo);
20521796
fossil_free(c.aEdit);
2053
- if( diffFlags & DIFF_HTML ){
2054
- blob_append(pOut, DIFF_TOO_MANY_CHANGES_HTML, -1);
2055
- }else{
2056
- blob_append(pOut, DIFF_TOO_MANY_CHANGES_TXT, -1);
2057
- }
1797
+ diff_errmsg(pOut, DIFF_TOO_MANY_CHANGES, diffFlags);
20581798
return 0;
20591799
}
20601800
}
20611801
if( (diffFlags & DIFF_NOOPT)==0 ){
20621802
diff_optimize(&c);
@@ -2159,10 +1899,11 @@
21591899
if( find_option("tk",0,0)!=0 ){
21601900
diff_tk("test-diff", 2);
21611901
return;
21621902
}
21631903
find_option("i",0,0);
1904
+ find_option("v",0,0);
21641905
zRe = find_option("regexp","e",1);
21651906
if( zRe ){
21661907
const char *zErr = re_compile(&pRe, zRe, 0);
21671908
if( zErr ) fossil_fatal("regex error: %s", zErr);
21681909
}
@@ -2616,60 +2357,5 @@
26162357
zPrefix[0] = 0;
26172358
}
26182359
fossil_print("%21s %4d: %.*s\n", zPrefix, i+1, n, z);
26192360
}
26202361
}
2621
-
2622
-/*
2623
-** COMMAND: test-looks-like-utf
2624
-**
2625
-** Usage: %fossil test-looks-like-utf FILENAME
2626
-**
2627
-** Options:
2628
-** --utf8 Ignoring BOM and file size, force UTF-8 checking
2629
-** --utf16 Ignoring BOM and file size, force UTF-16 checking
2630
-**
2631
-** FILENAME is the name of a file to check for textual content in the UTF-8
2632
-** and/or UTF-16 encodings.
2633
-*/
2634
-void looks_like_utf_test_cmd(void){
2635
- Blob blob; /* the contents of the specified file */
2636
- int fUtf8; /* return value of starts_with_utf8_bom() */
2637
- int fUtf16; /* return value of starts_with_utf16_bom() */
2638
- int fUnicode; /* return value of could_be_utf16() */
2639
- int lookFlags; /* output flags from looks_like_utf8/utf16() */
2640
- int bRevUtf16 = 0; /* non-zero -> UTF-16 byte order reversed */
2641
- int bRevUnicode = 0; /* non-zero -> UTF-16 byte order reversed */
2642
- int fForceUtf8 = find_option("utf8",0,0)!=0;
2643
- int fForceUtf16 = find_option("utf16",0,0)!=0;
2644
- if( g.argc!=3 ) usage("FILENAME");
2645
- blob_read_from_file(&blob, g.argv[2]);
2646
- fUtf8 = starts_with_utf8_bom(&blob, 0);
2647
- fUtf16 = starts_with_utf16_bom(&blob, 0, &bRevUtf16);
2648
- if( fForceUtf8 ){
2649
- fUnicode = 0;
2650
- }else{
2651
- fUnicode = could_be_utf16(&blob, &bRevUnicode) || fForceUtf16;
2652
- }
2653
- lookFlags = fUnicode ? looks_like_utf16(&blob, bRevUnicode, 0) :
2654
- looks_like_utf8(&blob, 0);
2655
- fossil_print("File \"%s\" has %d bytes.\n",g.argv[2],blob_size(&blob));
2656
- fossil_print("Starts with UTF-8 BOM: %s\n",fUtf8?"yes":"no");
2657
- fossil_print("Starts with UTF-16 BOM: %s\n",
2658
- fUtf16?(bRevUtf16?"reversed":"yes"):"no");
2659
- fossil_print("Looks like UTF-%s: %s\n",fUnicode?"16":"8",
2660
- (lookFlags&LOOK_BINARY)?"no":"yes");
2661
- fossil_print("Has flag LOOK_NUL: %s\n",(lookFlags&LOOK_NUL)?"yes":"no");
2662
- fossil_print("Has flag LOOK_CR: %s\n",(lookFlags&LOOK_CR)?"yes":"no");
2663
- fossil_print("Has flag LOOK_LONE_CR: %s\n",
2664
- (lookFlags&LOOK_LONE_CR)?"yes":"no");
2665
- fossil_print("Has flag LOOK_LF: %s\n",(lookFlags&LOOK_LF)?"yes":"no");
2666
- fossil_print("Has flag LOOK_LONE_LF: %s\n",
2667
- (lookFlags&LOOK_LONE_LF)?"yes":"no");
2668
- fossil_print("Has flag LOOK_CRLF: %s\n",(lookFlags&LOOK_CRLF)?"yes":"no");
2669
- fossil_print("Has flag LOOK_LONG: %s\n",(lookFlags&LOOK_LONG)?"yes":"no");
2670
- fossil_print("Has flag LOOK_INVALID: %s\n",
2671
- (lookFlags&LOOK_INVALID)?"yes":"no");
2672
- fossil_print("Has flag LOOK_ODD: %s\n",(lookFlags&LOOK_ODD)?"yes":"no");
2673
- fossil_print("Has flag LOOK_SHORT: %s\n",(lookFlags&LOOK_SHORT)?"yes":"no");
2674
- blob_reset(&blob);
2675
-}
26762362
--- src/diff.c
+++ src/diff.c
@@ -51,47 +51,20 @@
51 "cannot compute difference between binary files\n"
52
53 #define DIFF_CANNOT_COMPUTE_SYMLINK \
54 "cannot compute difference between symlink and regular file\n"
55
56 #define DIFF_TOO_MANY_CHANGES_TXT \
57 "more than 10,000 changes\n"
58
59 #define DIFF_TOO_MANY_CHANGES_HTML \
60 "<p class='generalError'>More than 10,000 changes</p>\n"
61
62 /*
63 ** This macro is designed to return non-zero if the specified blob contains
64 ** data that MAY be binary in nature; otherwise, zero will be returned.
65 */
66 #define looks_like_binary(blob) \
67 ((looks_like_utf8((blob), LOOK_BINARY) & LOOK_BINARY) != LOOK_NONE)
68
69 /*
70 ** Output flags for the looks_like_utf8() and looks_like_utf16() routines used
71 ** to convey status information about the blob content.
72 */
73 #define LOOK_NONE ((int)0x00000000) /* Nothing special was found. */
74 #define LOOK_NUL ((int)0x00000001) /* One or more NUL chars were found. */
75 #define LOOK_CR ((int)0x00000002) /* One or more CR chars were found. */
76 #define LOOK_LONE_CR ((int)0x00000004) /* An unpaired CR char was found. */
77 #define LOOK_LF ((int)0x00000008) /* One or more LF chars were found. */
78 #define LOOK_LONE_LF ((int)0x00000010) /* An unpaired LF char was found. */
79 #define LOOK_CRLF ((int)0x00000020) /* One or more CR/LF pairs were found. */
80 #define LOOK_LONG ((int)0x00000040) /* An over length line was found. */
81 #define LOOK_ODD ((int)0x00000080) /* An odd number of bytes was found. */
82 #define LOOK_SHORT ((int)0x00000100) /* Unable to perform full check. */
83 #define LOOK_INVALID ((int)0x00000200) /* Invalid sequence was found. */
84 #define LOOK_BINARY (LOOK_NUL | LOOK_LONG | LOOK_SHORT) /* May be binary. */
85 #define LOOK_EOL (LOOK_LONE_CR | LOOK_LONE_LF | LOOK_CRLF) /* Line seps. */
86 #endif /* INTERFACE */
87
88 /*
89 ** Maximum length of a line in a text file, in bytes. (2**13 = 8192 bytes)
90 */
91 #define LENGTH_MASK_SZ 13
92 #define LENGTH_MASK ((1<<LENGTH_MASK_SZ)-1)
 
 
93
94 /*
95 ** Information about each line of a file being diffed.
96 **
97 ** The lower LENGTH_MASK_SZ bits of the hash (DLine.h) are the length
@@ -204,282 +177,10 @@
204 /* Return results */
205 *pnLine = nLine;
206 return a;
207 }
208
209 /*
210 ** This function attempts to scan each logical line within the blob to
211 ** determine the type of content it appears to contain. The return value
212 ** is a combination of one or more of the LOOK_XXX flags (see above):
213 **
214 ** !LOOK_BINARY -- The content appears to consist entirely of text; however,
215 ** the encoding may not be UTF-8.
216 **
217 ** LOOK_BINARY -- The content appears to be binary because it contains one
218 ** or more embedded NUL characters or an extremely long line.
219 ** Since this function does not understand UTF-16, it may
220 ** falsely consider UTF-16 text to be binary.
221 **
222 ** Additional flags (i.e. those other than the ones included in LOOK_BINARY)
223 ** may be present in the result as well; however, they should not impact the
224 ** determination of text versus binary content.
225 **
226 ************************************ WARNING **********************************
227 **
228 ** This function does not validate that the blob content is properly formed
229 ** UTF-8. It assumes that all code points are the same size. It does not
230 ** validate any code points. It makes no attempt to detect if any [invalid]
231 ** switches between UTF-8 and other encodings occur.
232 **
233 ** The only code points that this function cares about are the NUL character,
234 ** carriage-return, and line-feed.
235 **
236 ** This function examines the contents of the blob until one of the flags
237 ** specified in "stopFlags" is set.
238 **
239 ************************************ WARNING **********************************
240 */
241 int looks_like_utf8(const Blob *pContent, int stopFlags){
242 const char *z = blob_buffer(pContent);
243 unsigned int n = blob_size(pContent);
244 int j, c, flags = LOOK_NONE; /* Assume UTF-8 text, prove otherwise */
245
246 if( n==0 ) return flags; /* Empty file -> text */
247 c = *z;
248 if( c==0 ){
249 flags |= LOOK_NUL; /* NUL character in a file -> binary */
250 }else if( c=='\r' ){
251 flags |= LOOK_CR;
252 if( n<=1 || z[1]!='\n' ){
253 flags |= LOOK_LONE_CR; /* More chars, next char is not LF */
254 }
255 }
256 j = (c!='\n');
257 if( !j ) flags |= (LOOK_LF | LOOK_LONE_LF); /* Found LF as first char */
258 while( !(flags&stopFlags) && --n>0 ){
259 int c2 = c;
260 c = *++z; ++j;
261 if( c==0 ){
262 flags |= LOOK_NUL; /* NUL character in a file -> binary */
263 }else if( c=='\n' ){
264 flags |= LOOK_LF;
265 if( c2=='\r' ){
266 flags |= (LOOK_CR | LOOK_CRLF); /* Found LF preceded by CR */
267 }else{
268 flags |= LOOK_LONE_LF;
269 }
270 if( j>LENGTH_MASK ){
271 flags |= LOOK_LONG; /* Very long line -> binary */
272 }
273 j = 0;
274 }else if( c=='\r' ){
275 flags |= LOOK_CR;
276 if( n<=1 || z[1]!='\n' ){
277 flags |= LOOK_LONE_CR; /* More chars, next char is not LF */
278 }
279 }
280 }
281 if( n ){
282 flags |= LOOK_SHORT; /* The whole blob was not examined */
283 }
284 if( j>LENGTH_MASK ){
285 flags |= LOOK_LONG; /* Very long line -> binary */
286 }
287 return flags;
288 }
289
290 /*
291 ** Define the type needed to represent a Unicode (UTF-16) character.
292 */
293 #ifndef WCHAR_T
294 # ifdef _WIN32
295 # define WCHAR_T wchar_t
296 # else
297 # define WCHAR_T unsigned short
298 # endif
299 #endif
300
301 /*
302 ** Maximum length of a line in a text file, in UTF-16 characters. (4096)
303 ** The number of bytes represented by this value cannot exceed LENGTH_MASK
304 ** bytes, because that is the line buffer size used by the diff engine.
305 */
306 #define UTF16_LENGTH_MASK_SZ (LENGTH_MASK_SZ-(sizeof(WCHAR_T)-sizeof(char)))
307 #define UTF16_LENGTH_MASK ((1<<UTF16_LENGTH_MASK_SZ)-1)
308
309 /*
310 ** This macro is used to swap the byte order of a UTF-16 character in the
311 ** looks_like_utf16() function.
312 */
313 #define UTF16_SWAP(ch) ((((ch) << 8) & 0xFF00) | (((ch) >> 8) & 0xFF))
314 #define UTF16_SWAP_IF(expr,ch) ((expr) ? UTF16_SWAP((ch)) : (ch))
315
316 /*
317 ** This function attempts to scan each logical line within the blob to
318 ** determine the type of content it appears to contain. The return value
319 ** is a combination of one or more of the LOOK_XXX flags (see above):
320 **
321 ** !LOOK_BINARY -- The content appears to consist entirely of text; however,
322 ** the encoding may not be UTF-16.
323 **
324 ** LOOK_BINARY -- The content appears to be binary because it contains one
325 ** or more embedded NUL characters or an extremely long line.
326 ** Since this function does not understand UTF-8, it may
327 ** falsely consider UTF-8 text to be binary.
328 **
329 ** Additional flags (i.e. those other than the ones included in LOOK_BINARY)
330 ** may be present in the result as well; however, they should not impact the
331 ** determination of text versus binary content.
332 **
333 ************************************ WARNING **********************************
334 **
335 ** This function does not validate that the blob content is properly formed
336 ** UTF-16. It assumes that all code points are the same size. It does not
337 ** validate any code points. It makes no attempt to detect if any [invalid]
338 ** switches between the UTF-16be and UTF-16le encodings occur.
339 **
340 ** The only code points that this function cares about are the NUL character,
341 ** carriage-return, and line-feed.
342 **
343 ** This function examines the contents of the blob until one of the flags
344 ** specified in "stopFlags" is set.
345 **
346 ************************************ WARNING **********************************
347 */
348 int looks_like_utf16(const Blob *pContent, int bReverse, int stopFlags){
349 const WCHAR_T *z = (WCHAR_T *)blob_buffer(pContent);
350 unsigned int n = blob_size(pContent);
351 int j, c, flags = LOOK_NONE; /* Assume UTF-16 text, prove otherwise */
352
353 if( n==0 ) return flags; /* Empty file -> text */
354 if( n%sizeof(WCHAR_T) ){
355 flags |= LOOK_ODD; /* Odd number of bytes -> binary (UTF-8?) */
356 if( n<sizeof(WCHAR_T) ) return flags; /* One byte -> binary (UTF-8?) */
357 }
358 c = *z;
359 if( bReverse ){
360 c = UTF16_SWAP(c);
361 }
362 if( c==0 ){
363 flags |= LOOK_NUL; /* NUL character in a file -> binary */
364 }else if( c=='\r' ){
365 flags |= LOOK_CR;
366 if( n<(2*sizeof(WCHAR_T)) || UTF16_SWAP_IF(bReverse, z[1])!='\n' ){
367 flags |= LOOK_LONE_CR; /* More chars, next char is not LF */
368 }
369 }
370 j = (c!='\n');
371 if( !j ) flags |= (LOOK_LF | LOOK_LONE_LF); /* Found LF as first char */
372 while( 1 ){
373 int c2 = c;
374 if( flags&stopFlags ) break;
375 n -= sizeof(WCHAR_T);
376 if( n<sizeof(WCHAR_T) ) break;
377 c = *++z;
378 if( bReverse ){
379 c = UTF16_SWAP(c);
380 }
381 ++j;
382 if( c==0 ){
383 flags |= LOOK_NUL; /* NUL character in a file -> binary */
384 }else if( c=='\n' ){
385 flags |= LOOK_LF;
386 if( c2=='\r' ){
387 flags |= (LOOK_CR | LOOK_CRLF); /* Found LF preceded by CR */
388 }else{
389 flags |= LOOK_LONE_LF;
390 }
391 if( j>UTF16_LENGTH_MASK ){
392 flags |= LOOK_LONG; /* Very long line -> binary */
393 }
394 j = 0;
395 }else if( c=='\r' ){
396 flags |= LOOK_CR;
397 if( n<(2*sizeof(WCHAR_T)) || UTF16_SWAP_IF(bReverse, z[1])!='\n' ){
398 flags |= LOOK_LONE_CR; /* More chars, next char is not LF */
399 }
400 }
401 }
402 if( n ){
403 flags |= LOOK_SHORT; /* The whole blob was not examined */
404 }
405 if( j>UTF16_LENGTH_MASK ){
406 flags |= LOOK_LONG; /* Very long line -> binary */
407 }
408 return flags;
409 }
410
411 /*
412 ** This function returns an array of bytes representing the byte-order-mark
413 ** for UTF-8.
414 */
415 const unsigned char *get_utf8_bom(int *pnByte){
416 static const unsigned char bom[] = {
417 0xEF, 0xBB, 0xBF, 0x00, 0x00, 0x00
418 };
419 if( pnByte ) *pnByte = 3;
420 return bom;
421 }
422
423 /*
424 ** This function returns non-zero if the blob starts with a UTF-8
425 ** byte-order-mark (BOM).
426 */
427 int starts_with_utf8_bom(const Blob *pContent, int *pnByte){
428 const char *z = blob_buffer(pContent);
429 int bomSize = 0;
430 const unsigned char *bom = get_utf8_bom(&bomSize);
431
432 if( pnByte ) *pnByte = bomSize;
433 if( blob_size(pContent)<bomSize ) return 0;
434 return memcmp(z, bom, bomSize)==0;
435 }
436
437 /*
438 ** This function returns non-zero if the blob starts with a UTF-16
439 ** byte-order-mark (BOM), either in the endianness of the machine
440 ** or in reversed byte order. The UTF-32 BOM is ruled out by checking
441 ** if the UTF-16 BOM is not immediately followed by (utf16) 0.
442 ** pnByte is only set when the function returns 1.
443 **
444 ** pbReverse is always set, even when no BOM is found. Without a BOM,
445 ** it is set to 1 on little-endian and 0 on big-endian platforms. See
446 ** clause D98 of conformance (section 3.10) of the Unicode standard.
447 */
448 int starts_with_utf16_bom(
449 const Blob *pContent, /* IN: Blob content to perform BOM detection on. */
450 int *pnByte, /* OUT: The number of bytes used for the BOM. */
451 int *pbReverse /* OUT: Non-zero for BOM in reverse byte-order. */
452 ){
453 const unsigned short *z = (unsigned short *)blob_buffer(pContent);
454 int bomSize = sizeof(unsigned short);
455 int size = blob_size(pContent);
456
457 if( size<bomSize ) goto noBom; /* No: cannot read BOM. */
458 if( size>=(2*bomSize) && z[1]==0 ) goto noBom; /* No: possible UTF-32. */
459 if( z[0]==0xfeff ){
460 if( pbReverse ) *pbReverse = 0;
461 }else if( z[0]==0xfffe ){
462 if( pbReverse ) *pbReverse = 1;
463 }else{
464 static const int one = 1;
465 noBom:
466 if( pbReverse ) *pbReverse = *(char *) &one;
467 return 0; /* No: UTF-16 byte-order-mark not found. */
468 }
469 if( pnByte ) *pnByte = bomSize;
470 return 1; /* Yes. */
471 }
472
473 /*
474 ** Returns non-zero if the specified content could be valid UTF-16.
475 */
476 int could_be_utf16(const Blob *pContent, int *pbReverse){
477 return (blob_size(pContent) % sizeof(WCHAR_T) == 0) ?
478 starts_with_utf16_bom(pContent, 0, pbReverse) : 0;
479 }
480
481 /*
482 ** Return true if two DLine elements are identical.
483 */
484 static int same_dline(DLine *pA, DLine *pB){
485 return pA->h==pB->h && memcmp(pA->z,pB->z,pA->h & LENGTH_MASK)==0;
@@ -576,11 +277,11 @@
576 int mxr; /* Maximum value for r */
577 int na, nb; /* Number of lines shown from A and B */
578 int i, j; /* Loop counters */
579 int m; /* Number of lines to output */
580 int skip; /* Number of lines to skip */
581 int nChunk = 0; /* Number of diff chunks seen so far */
582 int nContext; /* Number of lines of context */
583 int showLn; /* Show line numbers */
584 int html; /* Render as HTML */
585 int showDivider = 0; /* True to show the divider between diff blocks */
586
@@ -657,14 +358,14 @@
657 if( !showDivider ){
658 /* Do not show a top divider */
659 showDivider = 1;
660 }else if( html ){
661 blob_appendf(pOut, "<span class=\"diffhr\">%.80c</span>\n", '.');
662 blob_appendf(pOut, "<a name=\"chunk%d\"></a>\n", nChunk);
663 }else{
664 blob_appendf(pOut, "%.80c\n", '.');
665 }
 
666 }else{
667 if( html ) blob_appendf(pOut, "<span class=\"diffln\">");
668 /*
669 * If the patch changes an empty file or results in an empty file,
670 * the block header must use 0,0 as position indicator and not 1,0.
@@ -727,12 +428,11 @@
727 /*
728 ** Status of a single output line
729 */
730 typedef struct SbsLine SbsLine;
731 struct SbsLine {
732 char *zLine; /* The output line under construction */
733 int n; /* Index of next unused slot in the zLine[] */
734 int width; /* Maximum width of a column in the output */
735 unsigned char escHtml; /* True to escape html characters */
736 int iStart; /* Write zStart prior to character iStart */
737 const char *zStart; /* A <span> tag */
738 int iEnd; /* Write </span> prior to character iEnd */
@@ -741,125 +441,155 @@
741 int iEnd2; /* Write </span> prior to character iEnd2 */
742 ReCompiled *pRe; /* Only colorize matching lines, if not NULL */
743 };
744
745 /*
746 ** Flags for sbsWriteText()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
747 */
748 #define SBS_NEWLINE 0x0001 /* End with \n\000 */
749 #define SBS_PAD 0x0002 /* Pad output to width spaces */
 
750
751 /*
752 ** Write up to width characters of pLine into p->zLine[]. Translate tabs into
753 ** spaces. Add a newline if SBS_NEWLINE is set. Translate HTML characters
754 ** if SBS_HTML is set. Pad the rendering out width bytes if SBS_PAD is set.
 
 
 
755 **
756 ** This comment contains multibyte unicode characters (ü, Æ, ð) in order
757 ** to test the ability of the diff code to handle such characters.
758 */
759 static void sbsWriteText(SbsLine *p, DLine *pLine, unsigned flags){
 
760 int n = pLine->h & LENGTH_MASK;
761 int i; /* Number of input characters consumed */
762 int j; /* Number of output characters generated */
763 int k; /* Cursor position */
764 int needEndSpan = 0;
765 const char *zIn = pLine->z;
766 char *z = &p->zLine[p->n];
767 int w = p->width;
768 int colorize = p->escHtml;
769 if( colorize && p->pRe && re_dline_match(p->pRe, pLine, 1)==0 ){
770 colorize = 0;
771 }
772 for(i=j=k=0; k<w && i<n; i++, k++){
773 char c = zIn[i];
774 if( colorize ){
775 if( i==p->iStart ){
776 int x = strlen(p->zStart);
777 memcpy(z+j, p->zStart, x);
778 j += x;
779 needEndSpan = 1;
780 if( p->iStart2 ){
781 p->iStart = p->iStart2;
782 p->zStart = p->zStart2;
783 p->iStart2 = 0;
784 }
785 }else if( i==p->iEnd ){
786 memcpy(z+j, "</span>", 7);
787 j += 7;
788 needEndSpan = 0;
789 if( p->iEnd2 ){
790 p->iEnd = p->iEnd2;
791 p->iEnd2 = 0;
792 }
793 }
794 }
795 if( c=='\t' ){
796 z[j++] = ' ';
797 while( (k&7)!=7 && k<w ){ z[j++] = ' '; k++; }
 
 
 
798 }else if( c=='\r' || c=='\f' ){
799 z[j++] = ' ';
800 }else if( c=='<' && p->escHtml ){
801 memcpy(&z[j], "&lt;", 4);
802 j += 4;
803 }else if( c=='&' && p->escHtml ){
804 memcpy(&z[j], "&amp;", 5);
805 j += 5;
806 }else if( c=='>' && p->escHtml ){
807 memcpy(&z[j], "&gt;", 4);
808 j += 4;
809 }else if( c=='"' && p->escHtml ){
810 memcpy(&z[j], "&quot;", 6);
811 j += 6;
812 }else{
813 z[j++] = c;
814 if( (c&0xc0)==0x80 ) k--;
815 }
816 }
817 if( needEndSpan ){
818 memcpy(&z[j], "</span>", 7);
819 j += 7;
820 }
821 if( (flags & SBS_PAD)!=0 ){
822 while( k<w ){ k++; z[j++] = ' '; }
823 }
824 if( flags & SBS_NEWLINE ){
825 z[j++] = '\n';
826 }
827 p->n += j;
828 }
829
830 /*
831 ** Append a string to an SbSLine without coding, interpretation, or padding.
832 */
833 static void sbsWrite(SbsLine *p, const char *zIn, int nIn){
834 memcpy(p->zLine+p->n, zIn, nIn);
835 p->n += nIn;
836 }
837
838 /*
839 ** Append n spaces to the string.
840 */
841 static void sbsWriteSpace(SbsLine *p, int n){
842 while( n-- ) p->zLine[p->n++] = ' ';
843 }
844
845 /*
846 ** Append a string to the output only if we are rendering HTML.
847 */
848 static void sbsWriteHtml(SbsLine *p, const char *zIn){
849 if( p->escHtml ) sbsWrite(p, zIn, strlen(zIn));
850 }
851
852 /*
853 ** Write a 6-digit line number followed by a single space onto the line.
854 */
855 static void sbsWriteLineno(SbsLine *p, int ln){
856 sbsWriteHtml(p, "<span class=\"diffln\">");
857 sqlite3_snprintf(7, &p->zLine[p->n], "%5d ", ln+1);
858 p->n += 6;
859 sbsWriteHtml(p, "</span>");
860 p->zLine[p->n++] = ' ';
 
 
 
 
 
 
 
 
 
 
 
861 }
862
863 /*
864 ** The two text segments zLeft and zRight are known to be different on
865 ** both ends, but they might have a common segment in the middle. If
@@ -1018,43 +748,42 @@
1018 }
1019 if( nSuffix==nLeft || nSuffix==nRight ) nPrefix = 0;
1020 }
1021 if( nPrefix+nSuffix > nShort ) nPrefix = nShort - nSuffix;
1022
1023
1024 /* A single chunk of text inserted on the right */
1025 if( nPrefix+nSuffix==nLeft ){
1026 sbsWriteLineno(p, lnLeft);
1027 p->iStart2 = p->iEnd2 = 0;
1028 p->iStart = p->iEnd = -1;
1029 sbsWriteText(p, pLeft, SBS_PAD);
1030 if( nLeft==nRight && zLeft[nLeft]==zRight[nRight] ){
1031 sbsWrite(p, " ", 3);
1032 }else{
1033 sbsWrite(p, " | ", 3);
1034 }
1035 sbsWriteLineno(p, lnRight);
1036 p->iStart = nPrefix;
1037 p->iEnd = nRight - nSuffix;
1038 p->zStart = zClassAdd;
1039 sbsWriteText(p, pRight, SBS_NEWLINE);
1040 return;
1041 }
1042
1043 /* A single chunk of text deleted from the left */
1044 if( nPrefix+nSuffix==nRight ){
1045 /* Text deleted from the left */
1046 sbsWriteLineno(p, lnLeft);
1047 p->iStart2 = p->iEnd2 = 0;
1048 p->iStart = nPrefix;
1049 p->iEnd = nLeft - nSuffix;
1050 p->zStart = zClassRm;
1051 sbsWriteText(p, pLeft, SBS_PAD);
1052 sbsWrite(p, " | ", 3);
1053 sbsWriteLineno(p, lnRight);
1054 p->iStart = p->iEnd = -1;
1055 sbsWriteText(p, pRight, SBS_NEWLINE);
1056 return;
1057 }
1058
1059 /* At this point we know that there is a chunk of text that has
1060 ** changed between the left and the right. Check to see if there
@@ -1065,11 +794,11 @@
1065 if( p->escHtml
1066 && nLeftDiff >= 6
1067 && nRightDiff >= 6
1068 && textLCS(&zLeft[nPrefix], nLeftDiff, &zRight[nPrefix], nRightDiff, aLCS)
1069 ){
1070 sbsWriteLineno(p, lnLeft);
1071 p->iStart = nPrefix;
1072 p->iEnd = nPrefix + aLCS[0];
1073 if( aLCS[2]==0 ){
1074 sbsShiftLeft(p, pLeft->z);
1075 p->zStart = zClassRm;
@@ -1078,13 +807,13 @@
1078 }
1079 p->iStart2 = nPrefix + aLCS[1];
1080 p->iEnd2 = nLeft - nSuffix;
1081 p->zStart2 = aLCS[3]==nRightDiff ? zClassRm : zClassChng;
1082 sbsSimplifyLine(p, zLeft+nPrefix);
1083 sbsWriteText(p, pLeft, SBS_PAD);
1084 sbsWrite(p, " | ", 3);
1085 sbsWriteLineno(p, lnRight);
1086 p->iStart = nPrefix;
1087 p->iEnd = nPrefix + aLCS[2];
1088 if( aLCS[0]==0 ){
1089 sbsShiftLeft(p, pRight->z);
1090 p->zStart = zClassAdd;
@@ -1093,25 +822,25 @@
1093 }
1094 p->iStart2 = nPrefix + aLCS[3];
1095 p->iEnd2 = nRight - nSuffix;
1096 p->zStart2 = aLCS[1]==nLeftDiff ? zClassAdd : zClassChng;
1097 sbsSimplifyLine(p, zRight+nPrefix);
1098 sbsWriteText(p, pRight, SBS_NEWLINE);
1099 return;
1100 }
1101
1102 /* If all else fails, show a single big change between left and right */
1103 sbsWriteLineno(p, lnLeft);
1104 p->iStart2 = p->iEnd2 = 0;
1105 p->iStart = nPrefix;
1106 p->iEnd = nLeft - nSuffix;
1107 p->zStart = zClassChng;
1108 sbsWriteText(p, pLeft, SBS_PAD);
1109 sbsWrite(p, " | ", 3);
1110 sbsWriteLineno(p, lnRight);
1111 p->iEnd = nRight - nSuffix;
1112 sbsWriteText(p, pRight, SBS_NEWLINE);
1113 }
1114
1115 /*
1116 ** Minimum of two values
1117 */
@@ -1357,30 +1086,40 @@
1357 int mxr; /* Maximum value for r */
1358 int na, nb; /* Number of lines shown from A and B */
1359 int i, j; /* Loop counters */
1360 int m, ma, mb;/* Number of lines to output */
1361 int skip; /* Number of lines to skip */
1362 int nChunk = 0; /* Number of chunks of diff output seen so far */
1363 SbsLine s; /* Output line buffer */
1364 int nContext; /* Lines of context above and below each change */
1365 int showDivider = 0; /* True to show the divider */
 
1366
1367 memset(&s, 0, sizeof(s));
1368 s.width = diff_width(diffFlags);
1369 s.zLine = fossil_malloc( 15*s.width + 200 );
1370 if( s.zLine==0 ) return;
1371 nContext = diff_context_lines(diffFlags);
1372 s.escHtml = (diffFlags & DIFF_HTML)!=0;
 
 
 
 
 
 
 
 
 
 
1373 s.pRe = pRe;
1374 s.iStart = -1;
1375 s.iStart2 = 0;
1376 s.iEnd = -1;
1377 A = p->aFrom;
1378 B = p->aTo;
1379 R = p->aEdit;
1380 mxr = p->nEdit;
1381 while( mxr>2 && R[mxr-1]==0 && R[mxr-2]==0 ){ mxr -= 3; }
 
1382 for(r=0; r<mxr; r += 3*nr){
1383 /* Figure out how many triples to show in a single block */
1384 for(nr=1; R[r+nr*3]>0 && R[r+nr*3]<nContext*2; nr++){}
1385 /* printf("r=%d nr=%d\n", r, nr); */
1386
@@ -1436,35 +1175,39 @@
1436 }
1437
1438 /* Draw the separator between blocks */
1439 if( showDivider ){
1440 if( s.escHtml ){
1441 blob_appendf(pOut, "<span class=\"diffhr\">%.*c</span>\n",
1442 s.width*2+16, '.');
 
 
 
 
 
 
1443 }else{
1444 blob_appendf(pOut, "%.*c\n", s.width*2+16, '.');
1445 }
1446 }
1447 showDivider = 1;
1448 nChunk++;
1449 if( s.escHtml ){
1450 blob_appendf(pOut, "<a name=\"chunk%d\"></a>\n", nChunk);
1451 }
1452
1453 /* Show the initial common area */
1454 a += skip;
1455 b += skip;
1456 m = R[r] - skip;
1457 for(j=0; j<m; j++){
1458 s.n = 0;
1459 sbsWriteLineno(&s, a+j);
1460 s.iStart = s.iEnd = -1;
1461 sbsWriteText(&s, &A[a+j], SBS_PAD);
1462 sbsWrite(&s, " ", 3);
1463 sbsWriteLineno(&s, b+j);
1464 sbsWriteText(&s, &B[b+j], SBS_NEWLINE);
1465 blob_append(pOut, s.zLine, s.n);
1466 }
1467 a += m;
1468 b += m;
1469
1470 /* Show the differences */
@@ -1485,87 +1228,71 @@
1485
1486 alignment = sbsAlignment(&A[a], ma, &B[b], mb);
1487 for(j=0; ma+mb>0; j++){
1488 if( alignment[j]==1 ){
1489 /* Delete one line from the left */
1490 s.n = 0;
1491 sbsWriteLineno(&s, a);
1492 s.iStart = 0;
1493 s.zStart = "<span class=\"diffrm\">";
1494 s.iEnd = LENGTH(&A[a]);
1495 sbsWriteText(&s, &A[a], SBS_PAD);
1496 if( s.escHtml ){
1497 sbsWrite(&s, " &lt;\n", 6);
1498 }else{
1499 sbsWrite(&s, " <\n", 3);
1500 }
1501 blob_append(pOut, s.zLine, s.n);
1502 assert( ma>0 );
1503 ma--;
1504 a++;
1505 }else if( alignment[j]==3 ){
1506 /* The left line is changed into the right line */
1507 s.n = 0;
1508 sbsWriteLineChange(&s, &A[a], a, &B[b], b);
1509 blob_append(pOut, s.zLine, s.n);
1510 assert( ma>0 && mb>0 );
1511 ma--;
1512 mb--;
1513 a++;
1514 b++;
1515 }else if( alignment[j]==2 ){
1516 /* Insert one line on the right */
1517 s.n = 0;
1518 sbsWriteSpace(&s, s.width + 7);
1519 if( s.escHtml ){
1520 sbsWrite(&s, " &gt; ", 6);
1521 }else{
1522 sbsWrite(&s, " > ", 3);
1523 }
1524 sbsWriteLineno(&s, b);
1525 s.iStart = 0;
1526 s.zStart = "<span class=\"diffadd\">";
1527 s.iEnd = LENGTH(&B[b]);
1528 sbsWriteText(&s, &B[b], SBS_NEWLINE);
1529 blob_append(pOut, s.zLine, s.n);
1530 assert( mb>0 );
1531 mb--;
1532 b++;
1533 }else{
1534 /* Delete from the left and insert on the right */
1535 s.n = 0;
1536 sbsWriteLineno(&s, a);
1537 s.iStart = 0;
1538 s.zStart = "<span class=\"diffrm\">";
1539 s.iEnd = LENGTH(&A[a]);
1540 sbsWriteText(&s, &A[a], SBS_PAD);
1541 sbsWrite(&s, " | ", 3);
1542 sbsWriteLineno(&s, b);
1543 s.iStart = 0;
1544 s.zStart = "<span class=\"diffadd\">";
1545 s.iEnd = LENGTH(&B[b]);
1546 sbsWriteText(&s, &B[b], SBS_NEWLINE);
1547 blob_append(pOut, s.zLine, s.n);
1548 ma--;
1549 mb--;
1550 a++;
1551 b++;
1552 }
1553
1554 }
1555 fossil_free(alignment);
1556 if( i<nr-1 ){
1557 m = R[r+i*3+3];
1558 for(j=0; j<m; j++){
1559 s.n = 0;
1560 sbsWriteLineno(&s, a+j);
1561 s.iStart = s.iEnd = -1;
1562 sbsWriteText(&s, &A[a+j], SBS_PAD);
1563 sbsWrite(&s, " ", 3);
1564 sbsWriteLineno(&s, b+j);
1565 sbsWriteText(&s, &B[b+j], SBS_NEWLINE);
1566 blob_append(pOut, s.zLine, s.n);
1567 }
1568 b += m;
1569 a += m;
1570 }
1571 }
@@ -1573,21 +1300,27 @@
1573 /* Show the final common area */
1574 assert( nr==i );
1575 m = R[r+nr*3];
1576 if( m>nContext ) m = nContext;
1577 for(j=0; j<m; j++){
1578 s.n = 0;
1579 sbsWriteLineno(&s, a+j);
1580 s.iStart = s.iEnd = -1;
1581 sbsWriteText(&s, &A[a+j], SBS_PAD);
1582 sbsWrite(&s, " ", 3);
1583 sbsWriteLineno(&s, b+j);
1584 sbsWriteText(&s, &B[b+j], SBS_NEWLINE);
1585 blob_append(pOut, s.zLine, s.n);
1586 }
1587 }
1588 free(s.zLine);
 
 
 
 
 
 
 
 
1589 }
1590
1591 /*
1592 ** Compute the optimal longest common subsequence (LCS) using an
1593 ** exhaustive search. This version of the LCS is only used for
@@ -1990,10 +1723,21 @@
1990 int diff_width(u64 diffFlags){
1991 int w = (diffFlags & DIFF_WIDTH_MASK)/(DIFF_CONTEXT_MASK+1);
1992 if( w==0 ) w = 80;
1993 return w;
1994 }
 
 
 
 
 
 
 
 
 
 
 
1995
1996 /*
1997 ** Generate a report of the differences between files pA and pB.
1998 ** If pOut is not NULL then a unified diff is appended there. It
1999 ** is assumed that pOut has already been initialized. If pOut is
@@ -2032,11 +1776,11 @@
2032 &c.nTo, ignoreEolWs);
2033 if( c.aFrom==0 || c.aTo==0 ){
2034 fossil_free(c.aFrom);
2035 fossil_free(c.aTo);
2036 if( pOut ){
2037 blob_appendf(pOut, DIFF_CANNOT_COMPUTE_BINARY);
2038 }
2039 return 0;
2040 }
2041
2042 /* Compute the difference */
@@ -2048,15 +1792,11 @@
2048 for(i=m=n=0; i<mx; i+=3){ m += a[i]; n += a[i+1]+a[i+2]; }
2049 if( n>10000 ){
2050 fossil_free(c.aFrom);
2051 fossil_free(c.aTo);
2052 fossil_free(c.aEdit);
2053 if( diffFlags & DIFF_HTML ){
2054 blob_append(pOut, DIFF_TOO_MANY_CHANGES_HTML, -1);
2055 }else{
2056 blob_append(pOut, DIFF_TOO_MANY_CHANGES_TXT, -1);
2057 }
2058 return 0;
2059 }
2060 }
2061 if( (diffFlags & DIFF_NOOPT)==0 ){
2062 diff_optimize(&c);
@@ -2159,10 +1899,11 @@
2159 if( find_option("tk",0,0)!=0 ){
2160 diff_tk("test-diff", 2);
2161 return;
2162 }
2163 find_option("i",0,0);
 
2164 zRe = find_option("regexp","e",1);
2165 if( zRe ){
2166 const char *zErr = re_compile(&pRe, zRe, 0);
2167 if( zErr ) fossil_fatal("regex error: %s", zErr);
2168 }
@@ -2616,60 +2357,5 @@
2616 zPrefix[0] = 0;
2617 }
2618 fossil_print("%21s %4d: %.*s\n", zPrefix, i+1, n, z);
2619 }
2620 }
2621
2622 /*
2623 ** COMMAND: test-looks-like-utf
2624 **
2625 ** Usage: %fossil test-looks-like-utf FILENAME
2626 **
2627 ** Options:
2628 ** --utf8 Ignoring BOM and file size, force UTF-8 checking
2629 ** --utf16 Ignoring BOM and file size, force UTF-16 checking
2630 **
2631 ** FILENAME is the name of a file to check for textual content in the UTF-8
2632 ** and/or UTF-16 encodings.
2633 */
2634 void looks_like_utf_test_cmd(void){
2635 Blob blob; /* the contents of the specified file */
2636 int fUtf8; /* return value of starts_with_utf8_bom() */
2637 int fUtf16; /* return value of starts_with_utf16_bom() */
2638 int fUnicode; /* return value of could_be_utf16() */
2639 int lookFlags; /* output flags from looks_like_utf8/utf16() */
2640 int bRevUtf16 = 0; /* non-zero -> UTF-16 byte order reversed */
2641 int bRevUnicode = 0; /* non-zero -> UTF-16 byte order reversed */
2642 int fForceUtf8 = find_option("utf8",0,0)!=0;
2643 int fForceUtf16 = find_option("utf16",0,0)!=0;
2644 if( g.argc!=3 ) usage("FILENAME");
2645 blob_read_from_file(&blob, g.argv[2]);
2646 fUtf8 = starts_with_utf8_bom(&blob, 0);
2647 fUtf16 = starts_with_utf16_bom(&blob, 0, &bRevUtf16);
2648 if( fForceUtf8 ){
2649 fUnicode = 0;
2650 }else{
2651 fUnicode = could_be_utf16(&blob, &bRevUnicode) || fForceUtf16;
2652 }
2653 lookFlags = fUnicode ? looks_like_utf16(&blob, bRevUnicode, 0) :
2654 looks_like_utf8(&blob, 0);
2655 fossil_print("File \"%s\" has %d bytes.\n",g.argv[2],blob_size(&blob));
2656 fossil_print("Starts with UTF-8 BOM: %s\n",fUtf8?"yes":"no");
2657 fossil_print("Starts with UTF-16 BOM: %s\n",
2658 fUtf16?(bRevUtf16?"reversed":"yes"):"no");
2659 fossil_print("Looks like UTF-%s: %s\n",fUnicode?"16":"8",
2660 (lookFlags&LOOK_BINARY)?"no":"yes");
2661 fossil_print("Has flag LOOK_NUL: %s\n",(lookFlags&LOOK_NUL)?"yes":"no");
2662 fossil_print("Has flag LOOK_CR: %s\n",(lookFlags&LOOK_CR)?"yes":"no");
2663 fossil_print("Has flag LOOK_LONE_CR: %s\n",
2664 (lookFlags&LOOK_LONE_CR)?"yes":"no");
2665 fossil_print("Has flag LOOK_LF: %s\n",(lookFlags&LOOK_LF)?"yes":"no");
2666 fossil_print("Has flag LOOK_LONE_LF: %s\n",
2667 (lookFlags&LOOK_LONE_LF)?"yes":"no");
2668 fossil_print("Has flag LOOK_CRLF: %s\n",(lookFlags&LOOK_CRLF)?"yes":"no");
2669 fossil_print("Has flag LOOK_LONG: %s\n",(lookFlags&LOOK_LONG)?"yes":"no");
2670 fossil_print("Has flag LOOK_INVALID: %s\n",
2671 (lookFlags&LOOK_INVALID)?"yes":"no");
2672 fossil_print("Has flag LOOK_ODD: %s\n",(lookFlags&LOOK_ODD)?"yes":"no");
2673 fossil_print("Has flag LOOK_SHORT: %s\n",(lookFlags&LOOK_SHORT)?"yes":"no");
2674 blob_reset(&blob);
2675 }
2676
--- src/diff.c
+++ src/diff.c
@@ -51,47 +51,20 @@
51 "cannot compute difference between binary files\n"
52
53 #define DIFF_CANNOT_COMPUTE_SYMLINK \
54 "cannot compute difference between symlink and regular file\n"
55
56 #define DIFF_TOO_MANY_CHANGES \
57 "more than 10,000 changes\n"
58
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
59 /*
60 ** Maximum length of a line in a text file, in bytes. (2**13 = 8192 bytes)
61 */
62 #define LENGTH_MASK_SZ 13
63 #define LENGTH_MASK ((1<<LENGTH_MASK_SZ)-1)
64
65 #endif /* INTERFACE */
66
67 /*
68 ** Information about each line of a file being diffed.
69 **
70 ** The lower LENGTH_MASK_SZ bits of the hash (DLine.h) are the length
@@ -204,282 +177,10 @@
177 /* Return results */
178 *pnLine = nLine;
179 return a;
180 }
181
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
182 /*
183 ** Return true if two DLine elements are identical.
184 */
185 static int same_dline(DLine *pA, DLine *pB){
186 return pA->h==pB->h && memcmp(pA->z,pB->z,pA->h & LENGTH_MASK)==0;
@@ -576,11 +277,11 @@
277 int mxr; /* Maximum value for r */
278 int na, nb; /* Number of lines shown from A and B */
279 int i, j; /* Loop counters */
280 int m; /* Number of lines to output */
281 int skip; /* Number of lines to skip */
282 static int nChunk = 0; /* Number of diff chunks seen so far */
283 int nContext; /* Number of lines of context */
284 int showLn; /* Show line numbers */
285 int html; /* Render as HTML */
286 int showDivider = 0; /* True to show the divider between diff blocks */
287
@@ -657,14 +358,14 @@
358 if( !showDivider ){
359 /* Do not show a top divider */
360 showDivider = 1;
361 }else if( html ){
362 blob_appendf(pOut, "<span class=\"diffhr\">%.80c</span>\n", '.');
 
363 }else{
364 blob_appendf(pOut, "%.80c\n", '.');
365 }
366 if( html ) blob_appendf(pOut, "<span id=\"chunk%d\"></span>", nChunk);
367 }else{
368 if( html ) blob_appendf(pOut, "<span class=\"diffln\">");
369 /*
370 * If the patch changes an empty file or results in an empty file,
371 * the block header must use 0,0 as position indicator and not 1,0.
@@ -727,12 +428,11 @@
428 /*
429 ** Status of a single output line
430 */
431 typedef struct SbsLine SbsLine;
432 struct SbsLine {
433 Blob *apCols[5]; /* Array of pointers to output columns */
 
434 int width; /* Maximum width of a column in the output */
435 unsigned char escHtml; /* True to escape html characters */
436 int iStart; /* Write zStart prior to character iStart */
437 const char *zStart; /* A <span> tag */
438 int iEnd; /* Write </span> prior to character iEnd */
@@ -741,125 +441,155 @@
441 int iEnd2; /* Write </span> prior to character iEnd2 */
442 ReCompiled *pRe; /* Only colorize matching lines, if not NULL */
443 };
444
445 /*
446 ** Column indices for SbsLine.apCols[]
447 */
448 #define SBS_LNA 0 /* Left line number */
449 #define SBS_TXTA 1 /* Left text */
450 #define SBS_MKR 2 /* Middle separator column */
451 #define SBS_LNB 3 /* Right line number */
452 #define SBS_TXTB 4 /* Right text */
453
454 /*
455 ** Append newlines to all columns.
456 */
457 static void sbsWriteNewlines(SbsLine *p){
458 int i;
459 for( i=p->escHtml ? SBS_LNA : SBS_TXTB; i<=SBS_TXTB; i++ ){
460 blob_append(p->apCols[i], "\n", 1);
461 }
462 }
463
464 /*
465 ** Append n spaces to the column.
466 */
467 static void sbsWriteSpace(SbsLine *p, int n, int col){
468 blob_appendf(p->apCols[col], "%*s", n, "");
469 }
470
471 /*
472 ** Write the text of pLine into column iCol of p.
473 **
474 ** If outputting HTML, write the full line. Otherwise, only write the
475 ** width characters. Translate tabs into spaces. Add newlines if col
476 ** is SBS_TXTB. Translate HTML characters if escHtml is true. Pad the
477 ** rendering to width bytes if col is SBS_TXTA and escHtml is false.
478 **
479 ** This comment contains multibyte unicode characters (ü, Æ, ð) in order
480 ** to test the ability of the diff code to handle such characters.
481 */
482 static void sbsWriteText(SbsLine *p, DLine *pLine, int col){
483 Blob *pCol = p->apCols[col];
484 int n = pLine->h & LENGTH_MASK;
485 int i; /* Number of input characters consumed */
 
486 int k; /* Cursor position */
487 int needEndSpan = 0;
488 const char *zIn = pLine->z;
 
489 int w = p->width;
490 int colorize = p->escHtml;
491 if( colorize && p->pRe && re_dline_match(p->pRe, pLine, 1)==0 ){
492 colorize = 0;
493 }
494 for(i=k=0; (p->escHtml || k<w) && i<n; i++, k++){
495 char c = zIn[i];
496 if( colorize ){
497 if( i==p->iStart ){
498 int x = strlen(p->zStart);
499 blob_append(pCol, p->zStart, x);
 
500 needEndSpan = 1;
501 if( p->iStart2 ){
502 p->iStart = p->iStart2;
503 p->zStart = p->zStart2;
504 p->iStart2 = 0;
505 }
506 }else if( i==p->iEnd ){
507 blob_append(pCol, "</span>", 7);
 
508 needEndSpan = 0;
509 if( p->iEnd2 ){
510 p->iEnd = p->iEnd2;
511 p->iEnd2 = 0;
512 }
513 }
514 }
515 if( c=='\t' && !p->escHtml ){
516 blob_append(pCol, " ", 1);
517 while( (k&7)!=7 && (p->escHtml || k<w) ){
518 blob_append(pCol, " ", 1);
519 k++;
520 }
521 }else if( c=='\r' || c=='\f' ){
522 blob_append(pCol, " ", 1);
523 }else if( c=='<' && p->escHtml ){
524 blob_append(pCol, "&lt;", 4);
 
525 }else if( c=='&' && p->escHtml ){
526 blob_append(pCol, "&amp;", 5);
 
527 }else if( c=='>' && p->escHtml ){
528 blob_append(pCol, "&gt;", 4);
 
529 }else if( c=='"' && p->escHtml ){
530 blob_append(pCol, "&quot;", 6);
 
531 }else{
532 blob_append(pCol, &zIn[i], 1);
533 if( (c&0xc0)==0x80 ) k--;
534 }
535 }
536 if( needEndSpan ){
537 blob_append(pCol, "</span>", 7);
538 }
539 if( col==SBS_TXTB ){
540 sbsWriteNewlines(p);
541 }else if( !p->escHtml ){
542 sbsWriteSpace(p, w-k, SBS_TXTA);
543 }
544 }
545
546 /*
547 ** Append a column to the final output blob.
548 */
549 static void sbsWriteColumn(Blob *pOut, Blob *pCol, int col){
550 blob_appendf(pOut,
551 "<td><div class=\"diff%scol\">\n"
552 "<pre>\n"
553 "%s"
554 "</pre>\n"
555 "</div></td>\n",
556 col % 3 ? (col == SBS_MKR ? "mkr" : "txt") : "ln",
557 blob_str(pCol)
558 );
559 }
560
561 /*
562 ** Append a separator line to column iCol
563 */
564 static void sbsWriteSep(SbsLine *p, int len, int col){
565 char ch = '.';
566 if( len<1 ){
567 len = 1;
568 ch = ' ';
569 }
570 blob_appendf(p->apCols[col], "<span class=\"diffhr\">%.*c</span>\n", len, ch);
571 }
572
573 /*
574 ** Append the appropriate marker into the center column of the diff.
575 */
576 static void sbsWriteMarker(SbsLine *p, const char *zTxt, const char *zHtml){
577 blob_append(p->apCols[SBS_MKR], p->escHtml ? zHtml : zTxt, -1);
578 }
579
580 /*
581 ** Append a line number to the column.
582 */
583 static void sbsWriteLineno(SbsLine *p, int ln, int col){
584 if( p->escHtml ){
585 blob_appendf(p->apCols[col], "%d", ln+1);
586 }else{
587 char zLn[7];
588 sqlite3_snprintf(7, zLn, "%5d ", ln+1);
589 blob_appendf(p->apCols[col], "%s ", zLn);
590 }
591 }
592
593 /*
594 ** The two text segments zLeft and zRight are known to be different on
595 ** both ends, but they might have a common segment in the middle. If
@@ -1018,43 +748,42 @@
748 }
749 if( nSuffix==nLeft || nSuffix==nRight ) nPrefix = 0;
750 }
751 if( nPrefix+nSuffix > nShort ) nPrefix = nShort - nSuffix;
752
 
753 /* A single chunk of text inserted on the right */
754 if( nPrefix+nSuffix==nLeft ){
755 sbsWriteLineno(p, lnLeft, SBS_LNA);
756 p->iStart2 = p->iEnd2 = 0;
757 p->iStart = p->iEnd = -1;
758 sbsWriteText(p, pLeft, SBS_TXTA);
759 if( nLeft==nRight && zLeft[nLeft]==zRight[nRight] ){
760 sbsWriteMarker(p, " ", "");
761 }else{
762 sbsWriteMarker(p, " | ", "|");
763 }
764 sbsWriteLineno(p, lnRight, SBS_LNB);
765 p->iStart = nPrefix;
766 p->iEnd = nRight - nSuffix;
767 p->zStart = zClassAdd;
768 sbsWriteText(p, pRight, SBS_TXTB);
769 return;
770 }
771
772 /* A single chunk of text deleted from the left */
773 if( nPrefix+nSuffix==nRight ){
774 /* Text deleted from the left */
775 sbsWriteLineno(p, lnLeft, SBS_LNA);
776 p->iStart2 = p->iEnd2 = 0;
777 p->iStart = nPrefix;
778 p->iEnd = nLeft - nSuffix;
779 p->zStart = zClassRm;
780 sbsWriteText(p, pLeft, SBS_TXTA);
781 sbsWriteMarker(p, " | ", "|");
782 sbsWriteLineno(p, lnRight, SBS_LNB);
783 p->iStart = p->iEnd = -1;
784 sbsWriteText(p, pRight, SBS_TXTB);
785 return;
786 }
787
788 /* At this point we know that there is a chunk of text that has
789 ** changed between the left and the right. Check to see if there
@@ -1065,11 +794,11 @@
794 if( p->escHtml
795 && nLeftDiff >= 6
796 && nRightDiff >= 6
797 && textLCS(&zLeft[nPrefix], nLeftDiff, &zRight[nPrefix], nRightDiff, aLCS)
798 ){
799 sbsWriteLineno(p, lnLeft, SBS_LNA);
800 p->iStart = nPrefix;
801 p->iEnd = nPrefix + aLCS[0];
802 if( aLCS[2]==0 ){
803 sbsShiftLeft(p, pLeft->z);
804 p->zStart = zClassRm;
@@ -1078,13 +807,13 @@
807 }
808 p->iStart2 = nPrefix + aLCS[1];
809 p->iEnd2 = nLeft - nSuffix;
810 p->zStart2 = aLCS[3]==nRightDiff ? zClassRm : zClassChng;
811 sbsSimplifyLine(p, zLeft+nPrefix);
812 sbsWriteText(p, pLeft, SBS_TXTA);
813 sbsWriteMarker(p, " | ", "|");
814 sbsWriteLineno(p, lnRight, SBS_LNB);
815 p->iStart = nPrefix;
816 p->iEnd = nPrefix + aLCS[2];
817 if( aLCS[0]==0 ){
818 sbsShiftLeft(p, pRight->z);
819 p->zStart = zClassAdd;
@@ -1093,25 +822,25 @@
822 }
823 p->iStart2 = nPrefix + aLCS[3];
824 p->iEnd2 = nRight - nSuffix;
825 p->zStart2 = aLCS[1]==nLeftDiff ? zClassAdd : zClassChng;
826 sbsSimplifyLine(p, zRight+nPrefix);
827 sbsWriteText(p, pRight, SBS_TXTB);
828 return;
829 }
830
831 /* If all else fails, show a single big change between left and right */
832 sbsWriteLineno(p, lnLeft, SBS_LNA);
833 p->iStart2 = p->iEnd2 = 0;
834 p->iStart = nPrefix;
835 p->iEnd = nLeft - nSuffix;
836 p->zStart = zClassChng;
837 sbsWriteText(p, pLeft, SBS_TXTA);
838 sbsWriteMarker(p, " | ", "|");
839 sbsWriteLineno(p, lnRight, SBS_LNB);
840 p->iEnd = nRight - nSuffix;
841 sbsWriteText(p, pRight, SBS_TXTB);
842 }
843
844 /*
845 ** Minimum of two values
846 */
@@ -1357,30 +1086,40 @@
1086 int mxr; /* Maximum value for r */
1087 int na, nb; /* Number of lines shown from A and B */
1088 int i, j; /* Loop counters */
1089 int m, ma, mb;/* Number of lines to output */
1090 int skip; /* Number of lines to skip */
1091 static int nChunk = 0; /* Number of chunks of diff output seen so far */
1092 SbsLine s; /* Output line buffer */
1093 int nContext; /* Lines of context above and below each change */
1094 int showDivider = 0; /* True to show the divider */
1095 Blob aCols[5]; /* Array of column blobs */
1096
1097 memset(&s, 0, sizeof(s));
1098 s.width = diff_width(diffFlags);
 
 
1099 nContext = diff_context_lines(diffFlags);
1100 s.escHtml = (diffFlags & DIFF_HTML)!=0;
1101 if( s.escHtml ){
1102 for(i=SBS_LNA; i<=SBS_TXTB; i++){
1103 blob_zero(&aCols[i]);
1104 s.apCols[i] = &aCols[i];
1105 }
1106 }else{
1107 for(i=SBS_LNA; i<=SBS_TXTB; i++){
1108 s.apCols[i] = pOut;
1109 }
1110 }
1111 s.pRe = pRe;
1112 s.iStart = -1;
1113 s.iStart2 = 0;
1114 s.iEnd = -1;
1115 A = p->aFrom;
1116 B = p->aTo;
1117 R = p->aEdit;
1118 mxr = p->nEdit;
1119 while( mxr>2 && R[mxr-1]==0 && R[mxr-2]==0 ){ mxr -= 3; }
1120
1121 for(r=0; r<mxr; r += 3*nr){
1122 /* Figure out how many triples to show in a single block */
1123 for(nr=1; R[r+nr*3]>0 && R[r+nr*3]<nContext*2; nr++){}
1124 /* printf("r=%d nr=%d\n", r, nr); */
1125
@@ -1436,35 +1175,39 @@
1175 }
1176
1177 /* Draw the separator between blocks */
1178 if( showDivider ){
1179 if( s.escHtml ){
1180 char zLn[10];
1181 sqlite3_snprintf(sizeof(zLn), zLn, "%d", a+skip+1);
1182 sbsWriteSep(&s, strlen(zLn), SBS_LNA);
1183 sbsWriteSep(&s, s.width, SBS_TXTA);
1184 sbsWriteSep(&s, 0, SBS_MKR);
1185 sqlite3_snprintf(sizeof(zLn), zLn, "%d", b+skip+1);
1186 sbsWriteSep(&s, strlen(zLn), SBS_LNB);
1187 sbsWriteSep(&s, s.width, SBS_TXTB);
1188 }else{
1189 blob_appendf(pOut, "%.*c\n", s.width*2+16, '.');
1190 }
1191 }
1192 showDivider = 1;
1193 nChunk++;
1194 if( s.escHtml ){
1195 blob_appendf(s.apCols[SBS_LNA], "<span id=\"chunk%d\"></span>", nChunk);
1196 }
1197
1198 /* Show the initial common area */
1199 a += skip;
1200 b += skip;
1201 m = R[r] - skip;
1202 for(j=0; j<m; j++){
1203 sbsWriteLineno(&s, a+j, SBS_LNA);
 
1204 s.iStart = s.iEnd = -1;
1205 sbsWriteText(&s, &A[a+j], SBS_TXTA);
1206 sbsWriteMarker(&s, " ", "");
1207 sbsWriteLineno(&s, b+j, SBS_LNB);
1208 sbsWriteText(&s, &B[b+j], SBS_TXTB);
 
1209 }
1210 a += m;
1211 b += m;
1212
1213 /* Show the differences */
@@ -1485,87 +1228,71 @@
1228
1229 alignment = sbsAlignment(&A[a], ma, &B[b], mb);
1230 for(j=0; ma+mb>0; j++){
1231 if( alignment[j]==1 ){
1232 /* Delete one line from the left */
1233 sbsWriteLineno(&s, a, SBS_LNA);
 
1234 s.iStart = 0;
1235 s.zStart = "<span class=\"diffrm\">";
1236 s.iEnd = LENGTH(&A[a]);
1237 sbsWriteText(&s, &A[a], SBS_TXTA);
1238 sbsWriteMarker(&s, " <", "&lt;");
1239 sbsWriteNewlines(&s);
 
 
 
 
1240 assert( ma>0 );
1241 ma--;
1242 a++;
1243 }else if( alignment[j]==3 ){
1244 /* The left line is changed into the right line */
 
1245 sbsWriteLineChange(&s, &A[a], a, &B[b], b);
 
1246 assert( ma>0 && mb>0 );
1247 ma--;
1248 mb--;
1249 a++;
1250 b++;
1251 }else if( alignment[j]==2 ){
1252 /* Insert one line on the right */
1253 if( !s.escHtml ){
1254 sbsWriteSpace(&s, s.width + 7, SBS_TXTA);
1255 }
1256 sbsWriteMarker(&s, " > ", "&gt;");
1257 sbsWriteLineno(&s, b, SBS_LNB);
 
 
 
1258 s.iStart = 0;
1259 s.zStart = "<span class=\"diffadd\">";
1260 s.iEnd = LENGTH(&B[b]);
1261 sbsWriteText(&s, &B[b], SBS_TXTB);
 
1262 assert( mb>0 );
1263 mb--;
1264 b++;
1265 }else{
1266 /* Delete from the left and insert on the right */
1267 sbsWriteLineno(&s, a, SBS_LNA);
 
1268 s.iStart = 0;
1269 s.zStart = "<span class=\"diffrm\">";
1270 s.iEnd = LENGTH(&A[a]);
1271 sbsWriteText(&s, &A[a], SBS_TXTA);
1272 sbsWriteMarker(&s, " | ", "|");
1273 sbsWriteLineno(&s, b, SBS_LNB);
1274 s.iStart = 0;
1275 s.zStart = "<span class=\"diffadd\">";
1276 s.iEnd = LENGTH(&B[b]);
1277 sbsWriteText(&s, &B[b], SBS_TXTB);
 
1278 ma--;
1279 mb--;
1280 a++;
1281 b++;
1282 }
 
1283 }
1284 fossil_free(alignment);
1285 if( i<nr-1 ){
1286 m = R[r+i*3+3];
1287 for(j=0; j<m; j++){
1288 sbsWriteLineno(&s, a+j, SBS_LNA);
 
1289 s.iStart = s.iEnd = -1;
1290 sbsWriteText(&s, &A[a+j], SBS_TXTA);
1291 sbsWriteMarker(&s, " ", "");
1292 sbsWriteLineno(&s, b+j, SBS_LNB);
1293 sbsWriteText(&s, &B[b+j], SBS_TXTB);
 
1294 }
1295 b += m;
1296 a += m;
1297 }
1298 }
@@ -1573,21 +1300,27 @@
1300 /* Show the final common area */
1301 assert( nr==i );
1302 m = R[r+nr*3];
1303 if( m>nContext ) m = nContext;
1304 for(j=0; j<m; j++){
1305 sbsWriteLineno(&s, a+j, SBS_LNA);
 
1306 s.iStart = s.iEnd = -1;
1307 sbsWriteText(&s, &A[a+j], SBS_TXTA);
1308 sbsWriteMarker(&s, " ", "");
1309 sbsWriteLineno(&s, b+j, SBS_LNB);
1310 sbsWriteText(&s, &B[b+j], SBS_TXTB);
 
1311 }
1312 }
1313
1314 if( s.escHtml && blob_size(s.apCols[SBS_LNA])>0 ){
1315 blob_append(pOut, "<table class=\"sbsdiffcols\" width=\"90%\"><tr>\n", -1);
1316 for(i=SBS_LNA; i<=SBS_TXTB; i++){
1317 sbsWriteColumn(pOut, s.apCols[i], i);
1318 blob_reset(s.apCols[i]);
1319 }
1320 blob_append(pOut, "</tr></table>\n", -1);
1321 }
1322 }
1323
1324 /*
1325 ** Compute the optimal longest common subsequence (LCS) using an
1326 ** exhaustive search. This version of the LCS is only used for
@@ -1990,10 +1723,21 @@
1723 int diff_width(u64 diffFlags){
1724 int w = (diffFlags & DIFF_WIDTH_MASK)/(DIFF_CONTEXT_MASK+1);
1725 if( w==0 ) w = 80;
1726 return w;
1727 }
1728
1729 /*
1730 ** Append the error message to pOut.
1731 */
1732 void diff_errmsg(Blob *pOut, const char *msg, int diffFlags){
1733 if( diffFlags & DIFF_HTML ){
1734 blob_appendf(pOut, "<p class=\"generalError\">%s</p>", msg);
1735 }else{
1736 blob_append(pOut, msg, -1);
1737 }
1738 }
1739
1740 /*
1741 ** Generate a report of the differences between files pA and pB.
1742 ** If pOut is not NULL then a unified diff is appended there. It
1743 ** is assumed that pOut has already been initialized. If pOut is
@@ -2032,11 +1776,11 @@
1776 &c.nTo, ignoreEolWs);
1777 if( c.aFrom==0 || c.aTo==0 ){
1778 fossil_free(c.aFrom);
1779 fossil_free(c.aTo);
1780 if( pOut ){
1781 diff_errmsg(pOut, DIFF_CANNOT_COMPUTE_BINARY, diffFlags);
1782 }
1783 return 0;
1784 }
1785
1786 /* Compute the difference */
@@ -2048,15 +1792,11 @@
1792 for(i=m=n=0; i<mx; i+=3){ m += a[i]; n += a[i+1]+a[i+2]; }
1793 if( n>10000 ){
1794 fossil_free(c.aFrom);
1795 fossil_free(c.aTo);
1796 fossil_free(c.aEdit);
1797 diff_errmsg(pOut, DIFF_TOO_MANY_CHANGES, diffFlags);
 
 
 
 
1798 return 0;
1799 }
1800 }
1801 if( (diffFlags & DIFF_NOOPT)==0 ){
1802 diff_optimize(&c);
@@ -2159,10 +1899,11 @@
1899 if( find_option("tk",0,0)!=0 ){
1900 diff_tk("test-diff", 2);
1901 return;
1902 }
1903 find_option("i",0,0);
1904 find_option("v",0,0);
1905 zRe = find_option("regexp","e",1);
1906 if( zRe ){
1907 const char *zErr = re_compile(&pRe, zRe, 0);
1908 if( zErr ) fossil_fatal("regex error: %s", zErr);
1909 }
@@ -2616,60 +2357,5 @@
2357 zPrefix[0] = 0;
2358 }
2359 fossil_print("%21s %4d: %.*s\n", zPrefix, i+1, n, z);
2360 }
2361 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2362
+307 -38
--- src/diffcmd.c
+++ src/diffcmd.c
@@ -597,52 +597,321 @@
597597
return db_get(zName, zDefault);
598598
}
599599
600600
/* A Tcl/Tk script used to render diff output.
601601
*/
602
-static const char zDiffScript[] =
602
+static const char zDiffScript[] =
603603
@ package require Tk
604
-@ wm withdraw .
605
-@ wm title . {Fossil Diff}
606
-@ wm iconname . {Fossil Diff}
607
-@ bind . <q> exit
608
-@ set body {}
609
-@ set mx 80 ;# Length of the longest line of text
610
-@ set nLine 0 ;# Number of lines of text
611
-@ text .t -width 180 -yscroll {.sb set}
612
-@ if {$tcl_platform(platform)=="windows"} {.t config -font {courier 9}}
613
-@ .t tag config ln -foreground gray
614
-@ .t tag config chng -background {#d0d0ff}
615
-@ .t tag config add -background {#c0ffc0}
616
-@ .t tag config rm -background {#ffc0c0}
604
+@
605
+@ array set CFG {
606
+@ TITLE {Fossil Diff}
607
+@ LN_COL_BG #dddddd
608
+@ LN_COL_FG #444444
609
+@ TXT_COL_BG #ffffff
610
+@ TXT_COL_FG #000000
611
+@ MKR_COL_BG #444444
612
+@ MKR_COL_FG #dddddd
613
+@ CHNG_BG #d0d0ff
614
+@ ADD_BG #c0ffc0
615
+@ RM_BG #ffc0c0
616
+@ HR_FG #888888
617
+@ HR_PAD_TOP 4
618
+@ HR_PAD_BTM 8
619
+@ FN_BG #444444
620
+@ FN_FG #ffffff
621
+@ FN_PAD 5
622
+@ FONTS {{DejaVu Sans Mono} Consolas Monaco}
623
+@ FONT_SIZE 9
624
+@ PADX 5
625
+@ WIDTH 80
626
+@ HEIGHT 45
627
+@ LB_HEIGHT 25
628
+@ }
629
+@
630
+@ if {![namespace exists ttk]} {
631
+@ interp alias {} ::ttk::scrollbar {} ::scrollbar
632
+@ interp alias {} ::ttk::menubutton {} ::menubutton
633
+@ }
634
+@
617635
@ proc dehtml {x} {
636
+@ set x [regsub -all {<[^>]*>} $x {}]
618637
@ return [string map {&amp; & &lt; < &gt; > &#39; ' &quot; \"} $x]
619638
@ }
620
-@ # puts $cmd
621
-@ set in [open $cmd r]
622
-@ while {![eof $in]} {
623
-@ set line [gets $in]
624
-@ if {[regexp {^<a name="chunk.*"></a>} $line]} continue
625
-@ if {[regexp {^===} $line]} {
626
-@ set n [string length $line]
627
-@ if {$n>$mx} {set mx $n}
628
-@ }
629
-@ incr nLine
630
-@ while {[regexp {^(.*?)<span class="diff([a-z]+)">(.*?)</span>(.*)$} $line \
631
-@ all pre class mid tail]} {
632
-@ .t insert end [dehtml $pre] {} [dehtml $mid] $class
633
-@ set line $tail
634
-@ }
635
-@ .t insert end [dehtml $line]\n {}
639
+@
640
+@ proc cols {} {
641
+@ return [list .lnA .txtA .mkr .lnB .txtB]
642
+@ }
643
+@
644
+@ proc colType {c} {
645
+@ regexp {[a-z]+} $c type
646
+@ return $type
647
+@ }
648
+@
649
+@ proc readDiffs {cmd} {
650
+@ set in [open $cmd r]
651
+@ fconfigure $in -encoding utf-8
652
+@ set nDiffs 0
653
+@ array set widths {txt 0 ln 0 mkr 0}
654
+@ while {[gets $in line] != -1} {
655
+@ if {![regexp {^=+\s+(.*?)\s+=+$} $line all fn]} {
656
+@ continue
657
+@ }
658
+@ if {[string compare -length 6 [gets $in] "<table"]} {
659
+@ continue
660
+@ }
661
+@ incr nDiffs
662
+@ set idx [expr {$nDiffs > 1 ? [.txtA index end] : "1.0"}]
663
+@ .wfiles.lb insert end $fn
664
+@
665
+@ foreach c [cols] {
666
+@ while {[gets $in] ne "<pre>"} continue
667
+@
668
+@ if {$nDiffs > 1} {
669
+@ $c insert end \n -
670
+@ }
671
+@ if {[colType $c] eq "txt"} {
672
+@ $c insert end $fn\n fn
673
+@ } else {
674
+@ $c insert end \n fn
675
+@ }
676
+@ $c insert end \n -
677
+@
678
+@ set type [colType $c]
679
+@ set str {}
680
+@ while {[set line [gets $in]] ne "</pre>"} {
681
+@ set len [string length [dehtml $line]]
682
+@ if {$len > $widths($type)} {
683
+@ set widths($type) $len
684
+@ }
685
+@ append str $line\n
686
+@ }
687
+@
688
+@ set re {<span class="diff([a-z]+)">([^<]*)</span>}
689
+@ # Use \r as separator since it can't appear in the diff output (it gets
690
+@ # converted to a space).
691
+@ set str [regsub -all $re $str "\r\\1\r\\2\r"]
692
+@ foreach {pre class mid} [split $str \r] {
693
+@ if {$class ne ""} {
694
+@ $c insert end [dehtml $pre] - [dehtml $mid] [list $class -]
695
+@ } else {
696
+@ $c insert end [dehtml $pre] -
697
+@ }
698
+@ }
699
+@ }
700
+@ }
701
+@ close $in
702
+@
703
+@ foreach c [cols] {
704
+@ set type [colType $c]
705
+@ if {$type ne "txt"} {
706
+@ $c config -width $widths($type)
707
+@ }
708
+@ $c config -state disabled
709
+@ }
710
+@ if {$nDiffs <= [.wfiles.lb cget -height]} {
711
+@ .wfiles.lb config -height $nDiffs
712
+@ grid remove .wfiles.sb
713
+@ }
714
+@
715
+@ return $nDiffs
716
+@ }
717
+@
718
+@ proc viewDiff {idx} {
719
+@ .txtA yview $idx
720
+@ .txtA xview moveto 0
721
+@ }
722
+@
723
+@ proc cycleDiffs {{reverse 0}} {
724
+@ if {$reverse} {
725
+@ set range [.txtA tag prevrange fn @0,0 1.0]
726
+@ if {$range eq ""} {
727
+@ viewDiff {fn.last -1c}
728
+@ } else {
729
+@ viewDiff [lindex $range 0]
730
+@ }
731
+@ } else {
732
+@ set range [.txtA tag nextrange fn {@0,0 +1c} end]
733
+@ if {$range eq "" || [lindex [.txtA yview] 1] == 1} {
734
+@ viewDiff fn.first
735
+@ } else {
736
+@ viewDiff [lindex $range 0]
737
+@ }
738
+@ }
739
+@ }
740
+@
741
+@ proc xvis {col} {
742
+@ set view [$col xview]
743
+@ return [expr {[lindex $view 1]-[lindex $view 0]}]
744
+@ }
745
+@
746
+@ proc scroll-x {args} {
747
+@ set c .txt[expr {[xvis .txtA] < [xvis .txtB] ? "A" : "B"}]
748
+@ eval $c xview $args
749
+@ }
750
+@
751
+@ interp alias {} scroll-y {} .txtA yview
752
+@
753
+@ proc noop {args} {}
754
+@
755
+@ proc enableSync {axis} {
756
+@ update idletasks
757
+@ interp alias {} sync-$axis {}
758
+@ rename _sync-$axis sync-$axis
759
+@ }
760
+@
761
+@ proc disableSync {axis} {
762
+@ rename sync-$axis _sync-$axis
763
+@ interp alias {} sync-$axis {} noop
764
+@ }
765
+@
766
+@ proc sync-x {col first last} {
767
+@ disableSync x
768
+@ $col xview moveto [expr {$first*[xvis $col]/($last-$first)}]
769
+@ foreach side {A B} {
770
+@ set sb .sbx$side
771
+@ set xview [.txt$side xview]
772
+@ if {[lindex $xview 0] > 0 || [lindex $xview 1] < 1} {
773
+@ grid $sb
774
+@ eval $sb set $xview
775
+@ } else {
776
+@ grid remove $sb
777
+@ }
778
+@ }
779
+@ enableSync x
780
+@ }
781
+@
782
+@ proc sync-y {first last} {
783
+@ disableSync y
784
+@ foreach c [cols] {
785
+@ $c yview moveto $first
786
+@ }
787
+@ if {$first > 0 || $last < 1} {
788
+@ grid .sby
789
+@ .sby set $first $last
790
+@ } else {
791
+@ grid remove .sby
792
+@ }
793
+@ enableSync y
794
+@ }
795
+@
796
+@ wm withdraw .
797
+@ wm title . $CFG(TITLE)
798
+@ wm iconname . $CFG(TITLE)
799
+@ bind . <q> exit
800
+@ bind . <Tab> {cycleDiffs; break}
801
+@ bind . <<PrevWindow>> {cycleDiffs 1; break}
802
+@ bind . <Return> {
803
+@ event generate .files <1>
804
+@ event generate .files <ButtonRelease-1>
805
+@ break
806
+@ }
807
+@ foreach {key axis args} {
808
+@ Up y {scroll -5 units}
809
+@ Down y {scroll 5 units}
810
+@ Left x {scroll -5 units}
811
+@ Right x {scroll 5 units}
812
+@ Prior y {scroll -1 page}
813
+@ Next y {scroll 1 page}
814
+@ Home y {moveto 0}
815
+@ End y {moveto 1}
816
+@ } {
817
+@ bind . <$key> "scroll-$axis $args; break"
818
+@ bind . <Shift-$key> continue
819
+@ }
820
+@
821
+@ ::ttk::menubutton .files -text "Files"
822
+@ toplevel .wfiles
823
+@ wm withdraw .wfiles
824
+@ update idletasks
825
+@ wm transient .wfiles .
826
+@ wm overrideredirect .wfiles 1
827
+@ listbox .wfiles.lb -width 0 -height $CFG(LB_HEIGHT) -activestyle none \
828
+@ -yscroll {.wfiles.sb set}
829
+@ ::ttk::scrollbar .wfiles.sb -command {.wfiles.lb yview}
830
+@ grid .wfiles.lb .wfiles.sb -sticky ns
831
+@ bind .files <1> {
832
+@ set x [winfo rootx %W]
833
+@ set y [expr {[winfo rooty %W]+[winfo height %W]}]
834
+@ wm geometry .wfiles +$x+$y
835
+@ wm deiconify .wfiles
836
+@ focus .wfiles.lb
837
+@ }
838
+@ bind .wfiles <FocusOut> {wm withdraw .wfiles}
839
+@ bind .wfiles <Escape> {focus .}
840
+@ foreach evt {1 Return} {
841
+@ bind .wfiles.lb <$evt> {
842
+@ catch {
843
+@ set idx [lindex [.txtA tag ranges fn] [expr {[%W curselection]*2}]]
844
+@ viewDiff $idx
845
+@ }
846
+@ focus .
847
+@ break
848
+@ }
849
+@ }
850
+@ bind .wfiles.lb <Motion> {
851
+@ %W selection clear 0 end
852
+@ %W selection set @%x,%y
853
+@ }
854
+@
855
+@ foreach {side syncCol} {A .txtB B .txtA} {
856
+@ set ln .ln$side
857
+@ text $ln
858
+@ $ln tag config - -justify right
859
+@
860
+@ set txt .txt$side
861
+@ text $txt -width $CFG(WIDTH) -height $CFG(HEIGHT) -wrap none \
862
+@ -xscroll "sync-x $syncCol"
863
+@ catch {$txt config -tabstyle wordprocessor} ;# Required for Tk>=8.5
864
+@ foreach tag {add rm chng} {
865
+@ $txt tag config $tag -background $CFG([string toupper $tag]_BG)
866
+@ $txt tag lower $tag
867
+@ }
868
+@ $txt tag config fn -background $CFG(FN_BG) -foreground $CFG(FN_FG) \
869
+@ -justify center
870
+@ }
871
+@ text .mkr
872
+@
873
+@ font create mono -family courier -size $CFG(FONT_SIZE)
874
+@ foreach font $CFG(FONTS) {
875
+@ if {[lsearch -exact [font families] $font] != -1} {
876
+@ font config mono -family $font
877
+@ break
878
+@ }
879
+@ }
880
+@ foreach c [cols] {
881
+@ set keyPrefix [string toupper [colType $c]]_COL_
882
+@ $c config -bg $CFG(${keyPrefix}BG) -fg $CFG(${keyPrefix}FG) -borderwidth 0 \
883
+@ -font mono -padx $CFG(PADX) -yscroll sync-y
884
+@ $c tag config hr -spacing1 $CFG(HR_PAD_TOP) -spacing3 $CFG(HR_PAD_BTM) \
885
+@ -foreground $CFG(HR_FG)
886
+@ $c tag config fn -spacing1 $CFG(FN_PAD) -spacing3 $CFG(FN_PAD)
887
+@ bindtags $c ". $c Text all"
888
+@ bind $c <1> {focus %W}
889
+@ }
890
+@
891
+@ ::ttk::scrollbar .sby -command {.txtA yview} -orient vertical
892
+@ ::ttk::scrollbar .sbxA -command {.txtA xview} -orient horizontal
893
+@ ::ttk::scrollbar .sbxB -command {.txtB xview} -orient horizontal
894
+@ frame .spacer
895
+@
896
+@ if {[readDiffs $cmd] == 0} {
897
+@ tk_messageBox -type ok -title $CFG(TITLE) -message "No changes"
898
+@ exit
636899
@ }
637
-@ close $in
638
-@ if {$mx>250} {set mx 250} ;# Limit window width to 200 characters
639
-@ if {$nLine>55} {set nLine 55} ;# Limit window height to 55 lines
640
-@ .t config -height $nLine -width $mx
641
-@ pack .t -side left -fill both -expand 1
642
-@ scrollbar .sb -command {.t yview} -orient vertical
643
-@ pack .sb -side left -fill y
900
+@ update idletasks
901
+@
902
+@ grid rowconfigure . 1 -weight 1
903
+@ grid columnconfigure . 1 -weight 1
904
+@ grid columnconfigure . 4 -weight 1
905
+@ grid .files -row 0 -columnspan 6
906
+@ eval grid [cols] -row 1 -sticky nsew
907
+@ grid .sby -row 1 -column 5 -sticky ns
908
+@ grid .sbxA -row 2 -columnspan 2 -sticky ew
909
+@ grid .spacer -row 2 -column 2
910
+@ grid .sbxB -row 2 -column 3 -columnspan 2 -sticky ew
911
+@
912
+@ .spacer config -height [winfo height .sbxA]
644913
@ wm deiconify .
645914
;
646915
647916
/*
648917
** Show diff output in a Tcl/Tk window, in response to the --tk option
@@ -657,11 +926,11 @@
657926
int i;
658927
Blob script;
659928
char *zTempFile;
660929
char *zCmd;
661930
blob_zero(&script);
662
- blob_appendf(&script, "set cmd {| \"%/\" %s --html -y -i",
931
+ blob_appendf(&script, "set cmd {| \"%/\" %s --html -y -i -v",
663932
g.nameOfExe, zSubCmd);
664933
for(i=firstArg; i<g.argc; i++){
665934
const char *z = g.argv[i];
666935
if( z[0]=='-' ){
667936
if( strglob("*-html",z) ) continue;
668937
--- src/diffcmd.c
+++ src/diffcmd.c
@@ -597,52 +597,321 @@
597 return db_get(zName, zDefault);
598 }
599
600 /* A Tcl/Tk script used to render diff output.
601 */
602 static const char zDiffScript[] =
603 @ package require Tk
604 @ wm withdraw .
605 @ wm title . {Fossil Diff}
606 @ wm iconname . {Fossil Diff}
607 @ bind . <q> exit
608 @ set body {}
609 @ set mx 80 ;# Length of the longest line of text
610 @ set nLine 0 ;# Number of lines of text
611 @ text .t -width 180 -yscroll {.sb set}
612 @ if {$tcl_platform(platform)=="windows"} {.t config -font {courier 9}}
613 @ .t tag config ln -foreground gray
614 @ .t tag config chng -background {#d0d0ff}
615 @ .t tag config add -background {#c0ffc0}
616 @ .t tag config rm -background {#ffc0c0}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
617 @ proc dehtml {x} {
 
618 @ return [string map {&amp; & &lt; < &gt; > &#39; ' &quot; \"} $x]
619 @ }
620 @ # puts $cmd
621 @ set in [open $cmd r]
622 @ while {![eof $in]} {
623 @ set line [gets $in]
624 @ if {[regexp {^<a name="chunk.*"></a>} $line]} continue
625 @ if {[regexp {^===} $line]} {
626 @ set n [string length $line]
627 @ if {$n>$mx} {set mx $n}
628 @ }
629 @ incr nLine
630 @ while {[regexp {^(.*?)<span class="diff([a-z]+)">(.*?)</span>(.*)$} $line \
631 @ all pre class mid tail]} {
632 @ .t insert end [dehtml $pre] {} [dehtml $mid] $class
633 @ set line $tail
634 @ }
635 @ .t insert end [dehtml $line]\n {}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
636 @ }
637 @ close $in
638 @ if {$mx>250} {set mx 250} ;# Limit window width to 200 characters
639 @ if {$nLine>55} {set nLine 55} ;# Limit window height to 55 lines
640 @ .t config -height $nLine -width $mx
641 @ pack .t -side left -fill both -expand 1
642 @ scrollbar .sb -command {.t yview} -orient vertical
643 @ pack .sb -side left -fill y
 
 
 
 
 
 
644 @ wm deiconify .
645 ;
646
647 /*
648 ** Show diff output in a Tcl/Tk window, in response to the --tk option
@@ -657,11 +926,11 @@
657 int i;
658 Blob script;
659 char *zTempFile;
660 char *zCmd;
661 blob_zero(&script);
662 blob_appendf(&script, "set cmd {| \"%/\" %s --html -y -i",
663 g.nameOfExe, zSubCmd);
664 for(i=firstArg; i<g.argc; i++){
665 const char *z = g.argv[i];
666 if( z[0]=='-' ){
667 if( strglob("*-html",z) ) continue;
668
--- src/diffcmd.c
+++ src/diffcmd.c
@@ -597,52 +597,321 @@
597 return db_get(zName, zDefault);
598 }
599
600 /* A Tcl/Tk script used to render diff output.
601 */
602 static const char zDiffScript[] =
603 @ package require Tk
604 @
605 @ array set CFG {
606 @ TITLE {Fossil Diff}
607 @ LN_COL_BG #dddddd
608 @ LN_COL_FG #444444
609 @ TXT_COL_BG #ffffff
610 @ TXT_COL_FG #000000
611 @ MKR_COL_BG #444444
612 @ MKR_COL_FG #dddddd
613 @ CHNG_BG #d0d0ff
614 @ ADD_BG #c0ffc0
615 @ RM_BG #ffc0c0
616 @ HR_FG #888888
617 @ HR_PAD_TOP 4
618 @ HR_PAD_BTM 8
619 @ FN_BG #444444
620 @ FN_FG #ffffff
621 @ FN_PAD 5
622 @ FONTS {{DejaVu Sans Mono} Consolas Monaco}
623 @ FONT_SIZE 9
624 @ PADX 5
625 @ WIDTH 80
626 @ HEIGHT 45
627 @ LB_HEIGHT 25
628 @ }
629 @
630 @ if {![namespace exists ttk]} {
631 @ interp alias {} ::ttk::scrollbar {} ::scrollbar
632 @ interp alias {} ::ttk::menubutton {} ::menubutton
633 @ }
634 @
635 @ proc dehtml {x} {
636 @ set x [regsub -all {<[^>]*>} $x {}]
637 @ return [string map {&amp; & &lt; < &gt; > &#39; ' &quot; \"} $x]
638 @ }
639 @
640 @ proc cols {} {
641 @ return [list .lnA .txtA .mkr .lnB .txtB]
642 @ }
643 @
644 @ proc colType {c} {
645 @ regexp {[a-z]+} $c type
646 @ return $type
647 @ }
648 @
649 @ proc readDiffs {cmd} {
650 @ set in [open $cmd r]
651 @ fconfigure $in -encoding utf-8
652 @ set nDiffs 0
653 @ array set widths {txt 0 ln 0 mkr 0}
654 @ while {[gets $in line] != -1} {
655 @ if {![regexp {^=+\s+(.*?)\s+=+$} $line all fn]} {
656 @ continue
657 @ }
658 @ if {[string compare -length 6 [gets $in] "<table"]} {
659 @ continue
660 @ }
661 @ incr nDiffs
662 @ set idx [expr {$nDiffs > 1 ? [.txtA index end] : "1.0"}]
663 @ .wfiles.lb insert end $fn
664 @
665 @ foreach c [cols] {
666 @ while {[gets $in] ne "<pre>"} continue
667 @
668 @ if {$nDiffs > 1} {
669 @ $c insert end \n -
670 @ }
671 @ if {[colType $c] eq "txt"} {
672 @ $c insert end $fn\n fn
673 @ } else {
674 @ $c insert end \n fn
675 @ }
676 @ $c insert end \n -
677 @
678 @ set type [colType $c]
679 @ set str {}
680 @ while {[set line [gets $in]] ne "</pre>"} {
681 @ set len [string length [dehtml $line]]
682 @ if {$len > $widths($type)} {
683 @ set widths($type) $len
684 @ }
685 @ append str $line\n
686 @ }
687 @
688 @ set re {<span class="diff([a-z]+)">([^<]*)</span>}
689 @ # Use \r as separator since it can't appear in the diff output (it gets
690 @ # converted to a space).
691 @ set str [regsub -all $re $str "\r\\1\r\\2\r"]
692 @ foreach {pre class mid} [split $str \r] {
693 @ if {$class ne ""} {
694 @ $c insert end [dehtml $pre] - [dehtml $mid] [list $class -]
695 @ } else {
696 @ $c insert end [dehtml $pre] -
697 @ }
698 @ }
699 @ }
700 @ }
701 @ close $in
702 @
703 @ foreach c [cols] {
704 @ set type [colType $c]
705 @ if {$type ne "txt"} {
706 @ $c config -width $widths($type)
707 @ }
708 @ $c config -state disabled
709 @ }
710 @ if {$nDiffs <= [.wfiles.lb cget -height]} {
711 @ .wfiles.lb config -height $nDiffs
712 @ grid remove .wfiles.sb
713 @ }
714 @
715 @ return $nDiffs
716 @ }
717 @
718 @ proc viewDiff {idx} {
719 @ .txtA yview $idx
720 @ .txtA xview moveto 0
721 @ }
722 @
723 @ proc cycleDiffs {{reverse 0}} {
724 @ if {$reverse} {
725 @ set range [.txtA tag prevrange fn @0,0 1.0]
726 @ if {$range eq ""} {
727 @ viewDiff {fn.last -1c}
728 @ } else {
729 @ viewDiff [lindex $range 0]
730 @ }
731 @ } else {
732 @ set range [.txtA tag nextrange fn {@0,0 +1c} end]
733 @ if {$range eq "" || [lindex [.txtA yview] 1] == 1} {
734 @ viewDiff fn.first
735 @ } else {
736 @ viewDiff [lindex $range 0]
737 @ }
738 @ }
739 @ }
740 @
741 @ proc xvis {col} {
742 @ set view [$col xview]
743 @ return [expr {[lindex $view 1]-[lindex $view 0]}]
744 @ }
745 @
746 @ proc scroll-x {args} {
747 @ set c .txt[expr {[xvis .txtA] < [xvis .txtB] ? "A" : "B"}]
748 @ eval $c xview $args
749 @ }
750 @
751 @ interp alias {} scroll-y {} .txtA yview
752 @
753 @ proc noop {args} {}
754 @
755 @ proc enableSync {axis} {
756 @ update idletasks
757 @ interp alias {} sync-$axis {}
758 @ rename _sync-$axis sync-$axis
759 @ }
760 @
761 @ proc disableSync {axis} {
762 @ rename sync-$axis _sync-$axis
763 @ interp alias {} sync-$axis {} noop
764 @ }
765 @
766 @ proc sync-x {col first last} {
767 @ disableSync x
768 @ $col xview moveto [expr {$first*[xvis $col]/($last-$first)}]
769 @ foreach side {A B} {
770 @ set sb .sbx$side
771 @ set xview [.txt$side xview]
772 @ if {[lindex $xview 0] > 0 || [lindex $xview 1] < 1} {
773 @ grid $sb
774 @ eval $sb set $xview
775 @ } else {
776 @ grid remove $sb
777 @ }
778 @ }
779 @ enableSync x
780 @ }
781 @
782 @ proc sync-y {first last} {
783 @ disableSync y
784 @ foreach c [cols] {
785 @ $c yview moveto $first
786 @ }
787 @ if {$first > 0 || $last < 1} {
788 @ grid .sby
789 @ .sby set $first $last
790 @ } else {
791 @ grid remove .sby
792 @ }
793 @ enableSync y
794 @ }
795 @
796 @ wm withdraw .
797 @ wm title . $CFG(TITLE)
798 @ wm iconname . $CFG(TITLE)
799 @ bind . <q> exit
800 @ bind . <Tab> {cycleDiffs; break}
801 @ bind . <<PrevWindow>> {cycleDiffs 1; break}
802 @ bind . <Return> {
803 @ event generate .files <1>
804 @ event generate .files <ButtonRelease-1>
805 @ break
806 @ }
807 @ foreach {key axis args} {
808 @ Up y {scroll -5 units}
809 @ Down y {scroll 5 units}
810 @ Left x {scroll -5 units}
811 @ Right x {scroll 5 units}
812 @ Prior y {scroll -1 page}
813 @ Next y {scroll 1 page}
814 @ Home y {moveto 0}
815 @ End y {moveto 1}
816 @ } {
817 @ bind . <$key> "scroll-$axis $args; break"
818 @ bind . <Shift-$key> continue
819 @ }
820 @
821 @ ::ttk::menubutton .files -text "Files"
822 @ toplevel .wfiles
823 @ wm withdraw .wfiles
824 @ update idletasks
825 @ wm transient .wfiles .
826 @ wm overrideredirect .wfiles 1
827 @ listbox .wfiles.lb -width 0 -height $CFG(LB_HEIGHT) -activestyle none \
828 @ -yscroll {.wfiles.sb set}
829 @ ::ttk::scrollbar .wfiles.sb -command {.wfiles.lb yview}
830 @ grid .wfiles.lb .wfiles.sb -sticky ns
831 @ bind .files <1> {
832 @ set x [winfo rootx %W]
833 @ set y [expr {[winfo rooty %W]+[winfo height %W]}]
834 @ wm geometry .wfiles +$x+$y
835 @ wm deiconify .wfiles
836 @ focus .wfiles.lb
837 @ }
838 @ bind .wfiles <FocusOut> {wm withdraw .wfiles}
839 @ bind .wfiles <Escape> {focus .}
840 @ foreach evt {1 Return} {
841 @ bind .wfiles.lb <$evt> {
842 @ catch {
843 @ set idx [lindex [.txtA tag ranges fn] [expr {[%W curselection]*2}]]
844 @ viewDiff $idx
845 @ }
846 @ focus .
847 @ break
848 @ }
849 @ }
850 @ bind .wfiles.lb <Motion> {
851 @ %W selection clear 0 end
852 @ %W selection set @%x,%y
853 @ }
854 @
855 @ foreach {side syncCol} {A .txtB B .txtA} {
856 @ set ln .ln$side
857 @ text $ln
858 @ $ln tag config - -justify right
859 @
860 @ set txt .txt$side
861 @ text $txt -width $CFG(WIDTH) -height $CFG(HEIGHT) -wrap none \
862 @ -xscroll "sync-x $syncCol"
863 @ catch {$txt config -tabstyle wordprocessor} ;# Required for Tk>=8.5
864 @ foreach tag {add rm chng} {
865 @ $txt tag config $tag -background $CFG([string toupper $tag]_BG)
866 @ $txt tag lower $tag
867 @ }
868 @ $txt tag config fn -background $CFG(FN_BG) -foreground $CFG(FN_FG) \
869 @ -justify center
870 @ }
871 @ text .mkr
872 @
873 @ font create mono -family courier -size $CFG(FONT_SIZE)
874 @ foreach font $CFG(FONTS) {
875 @ if {[lsearch -exact [font families] $font] != -1} {
876 @ font config mono -family $font
877 @ break
878 @ }
879 @ }
880 @ foreach c [cols] {
881 @ set keyPrefix [string toupper [colType $c]]_COL_
882 @ $c config -bg $CFG(${keyPrefix}BG) -fg $CFG(${keyPrefix}FG) -borderwidth 0 \
883 @ -font mono -padx $CFG(PADX) -yscroll sync-y
884 @ $c tag config hr -spacing1 $CFG(HR_PAD_TOP) -spacing3 $CFG(HR_PAD_BTM) \
885 @ -foreground $CFG(HR_FG)
886 @ $c tag config fn -spacing1 $CFG(FN_PAD) -spacing3 $CFG(FN_PAD)
887 @ bindtags $c ". $c Text all"
888 @ bind $c <1> {focus %W}
889 @ }
890 @
891 @ ::ttk::scrollbar .sby -command {.txtA yview} -orient vertical
892 @ ::ttk::scrollbar .sbxA -command {.txtA xview} -orient horizontal
893 @ ::ttk::scrollbar .sbxB -command {.txtB xview} -orient horizontal
894 @ frame .spacer
895 @
896 @ if {[readDiffs $cmd] == 0} {
897 @ tk_messageBox -type ok -title $CFG(TITLE) -message "No changes"
898 @ exit
899 @ }
900 @ update idletasks
901 @
902 @ grid rowconfigure . 1 -weight 1
903 @ grid columnconfigure . 1 -weight 1
904 @ grid columnconfigure . 4 -weight 1
905 @ grid .files -row 0 -columnspan 6
906 @ eval grid [cols] -row 1 -sticky nsew
907 @ grid .sby -row 1 -column 5 -sticky ns
908 @ grid .sbxA -row 2 -columnspan 2 -sticky ew
909 @ grid .spacer -row 2 -column 2
910 @ grid .sbxB -row 2 -column 3 -columnspan 2 -sticky ew
911 @
912 @ .spacer config -height [winfo height .sbxA]
913 @ wm deiconify .
914 ;
915
916 /*
917 ** Show diff output in a Tcl/Tk window, in response to the --tk option
@@ -657,11 +926,11 @@
926 int i;
927 Blob script;
928 char *zTempFile;
929 char *zCmd;
930 blob_zero(&script);
931 blob_appendf(&script, "set cmd {| \"%/\" %s --html -y -i -v",
932 g.nameOfExe, zSubCmd);
933 for(i=firstArg; i<g.argc; i++){
934 const char *z = g.argv[i];
935 if( z[0]=='-' ){
936 if( strglob("*-html",z) ) continue;
937
+5 -5
--- src/event.c
+++ src/event.c
@@ -399,32 +399,32 @@
399399
@ <form method="post" action="%s(g.zTop)/eventedit"><div>
400400
login_insert_csrf_secret();
401401
@ <input type="hidden" name="name" value="%h(zEventId)" />
402402
@ <table border="0" cellspacing="10">
403403
404
- @ <tr><td align="right" valign="top"><b>Event&nbsp;Time:</b></td>
404
+ @ <tr><th align="right" valign="top">Event&nbsp;Time:</th>
405405
@ <td valign="top">
406406
@ <input type="text" name="t" size="25" value="%h(zETime)" />
407407
@ </td></tr>
408408
409
- @ <tr><td align="right" valign="top"><b>Timeline&nbsp;Comment:</b></td>
409
+ @ <tr><th align="right" valign="top">Timeline&nbsp;Comment:</th>
410410
@ <td valign="top">
411411
@ <textarea name="c" class="eventedit" cols="80"
412412
@ rows="3" wrap="virtual">%h(zComment)</textarea>
413413
@ </td></tr>
414414
415
- @ <tr><td align="right" valign="top"><b>Background&nbsp;Color:</b></td>
415
+ @ <tr><th align="right" valign="top">Background&nbsp;Color:</th>
416416
@ <td valign="top">
417417
render_color_chooser(0, zClr, 0, "clr", "cclr");
418418
@ </td></tr>
419419
420
- @ <tr><td align="right" valign="top"><b>Tags:</b></td>
420
+ @ <tr><th align="right" valign="top">Tags:</th>
421421
@ <td valign="top">
422422
@ <input type="text" name="g" size="40" value="%h(zTags)" />
423423
@ </td></tr>
424424
425
- @ <tr><td align="right" valign="top"><b>Page&nbsp;Content:</b></td>
425
+ @ <tr><th align="right" valign="top">Page&nbsp;Content:</th>
426426
@ <td valign="top">
427427
@ <textarea name="w" class="eventedit" cols="80"
428428
@ rows="%d(n)" wrap="virtual">%h(zBody)</textarea>
429429
@ </td></tr>
430430
431431
--- src/event.c
+++ src/event.c
@@ -399,32 +399,32 @@
399 @ <form method="post" action="%s(g.zTop)/eventedit"><div>
400 login_insert_csrf_secret();
401 @ <input type="hidden" name="name" value="%h(zEventId)" />
402 @ <table border="0" cellspacing="10">
403
404 @ <tr><td align="right" valign="top"><b>Event&nbsp;Time:</b></td>
405 @ <td valign="top">
406 @ <input type="text" name="t" size="25" value="%h(zETime)" />
407 @ </td></tr>
408
409 @ <tr><td align="right" valign="top"><b>Timeline&nbsp;Comment:</b></td>
410 @ <td valign="top">
411 @ <textarea name="c" class="eventedit" cols="80"
412 @ rows="3" wrap="virtual">%h(zComment)</textarea>
413 @ </td></tr>
414
415 @ <tr><td align="right" valign="top"><b>Background&nbsp;Color:</b></td>
416 @ <td valign="top">
417 render_color_chooser(0, zClr, 0, "clr", "cclr");
418 @ </td></tr>
419
420 @ <tr><td align="right" valign="top"><b>Tags:</b></td>
421 @ <td valign="top">
422 @ <input type="text" name="g" size="40" value="%h(zTags)" />
423 @ </td></tr>
424
425 @ <tr><td align="right" valign="top"><b>Page&nbsp;Content:</b></td>
426 @ <td valign="top">
427 @ <textarea name="w" class="eventedit" cols="80"
428 @ rows="%d(n)" wrap="virtual">%h(zBody)</textarea>
429 @ </td></tr>
430
431
--- src/event.c
+++ src/event.c
@@ -399,32 +399,32 @@
399 @ <form method="post" action="%s(g.zTop)/eventedit"><div>
400 login_insert_csrf_secret();
401 @ <input type="hidden" name="name" value="%h(zEventId)" />
402 @ <table border="0" cellspacing="10">
403
404 @ <tr><th align="right" valign="top">Event&nbsp;Time:</th>
405 @ <td valign="top">
406 @ <input type="text" name="t" size="25" value="%h(zETime)" />
407 @ </td></tr>
408
409 @ <tr><th align="right" valign="top">Timeline&nbsp;Comment:</th>
410 @ <td valign="top">
411 @ <textarea name="c" class="eventedit" cols="80"
412 @ rows="3" wrap="virtual">%h(zComment)</textarea>
413 @ </td></tr>
414
415 @ <tr><th align="right" valign="top">Background&nbsp;Color:</th>
416 @ <td valign="top">
417 render_color_chooser(0, zClr, 0, "clr", "cclr");
418 @ </td></tr>
419
420 @ <tr><th align="right" valign="top">Tags:</th>
421 @ <td valign="top">
422 @ <input type="text" name="g" size="40" value="%h(zTags)" />
423 @ </td></tr>
424
425 @ <tr><th align="right" valign="top">Page&nbsp;Content:</th>
426 @ <td valign="top">
427 @ <textarea name="w" class="eventedit" cols="80"
428 @ rows="%d(n)" wrap="virtual">%h(zBody)</textarea>
429 @ </td></tr>
430
431
+94 -78
--- src/info.c
+++ src/info.c
@@ -316,25 +316,22 @@
316316
blob_zero(&to);
317317
}
318318
blob_zero(&out);
319319
if( diffFlags & DIFF_SIDEBYSIDE ){
320320
text_diff(&from, &to, &out, pRe, diffFlags | DIFF_HTML | DIFF_NOTTOOBIG);
321
- @ <div class="sbsdiff">
322321
@ %s(blob_str(&out))
323
- @ </div>
324322
}else{
325323
text_diff(&from, &to, &out, pRe,
326324
diffFlags | DIFF_LINENO | DIFF_HTML | DIFF_NOTTOOBIG);
327
- @ <div class="udiff">
325
+ @ <pre class="udiff">
328326
@ %s(blob_str(&out))
329
- @ </div>
327
+ @ </pre>
330328
}
331329
blob_reset(&from);
332330
blob_reset(&to);
333331
blob_reset(&out);
334332
}
335
-
336333
337334
/*
338335
** Write a line of web-page output that shows changes that have occurred
339336
** to a file between two check-ins.
340337
*/
@@ -359,13 +356,11 @@
359356
@ for %h(zName)</p>
360357
}else{
361358
@ <p>Changes to %h(zName)</p>
362359
}
363360
if( diffFlags ){
364
- @ <pre style="white-space:pre;">
365361
append_diff(zOld, zNew, diffFlags, pRe);
366
- @ </pre>
367362
}
368363
}else{
369364
if( zOld && zNew ){
370365
if( fossil_strcmp(zOld, zNew)!=0 ){
371366
@ <p>Modified %z(href("%R/finfo?name=%T",zName))%h(zName)</a>
@@ -385,20 +380,51 @@
385380
}else{
386381
@ <p>Added %z(href("%R/finfo?name=%T",zName))%h(zName)</a>
387382
@ version %z(href("%R/artifact/%s",zNew))[%S(zNew)]</a>
388383
}
389384
if( diffFlags ){
390
- @ <pre style="white-space:pre;">
391385
append_diff(zOld, zNew, diffFlags, pRe);
392
- @ </pre>
393386
}else if( zOld && zNew && fossil_strcmp(zOld,zNew)!=0 ){
394387
@ &nbsp;&nbsp;
395388
@ %z(href("%R/fdiff?v1=%S&v2=%S&sbs=1",zOld,zNew))[diff]</a>
396389
}
397
- @ </p>
398390
}
399391
}
392
+
393
+/*
394
+** Generate javascript to enhance HTML diffs.
395
+*/
396
+void append_diff_javascript(int sideBySide){
397
+ if( !sideBySide ) return;
398
+ @ <script>(function(){
399
+ @ var SCROLL_LEN = 25;
400
+ @ function initSbsDiff(diff){
401
+ @ var txtCols = diff.querySelectorAll('.difftxtcol');
402
+ @ var txtPres = diff.querySelectorAll('.difftxtcol pre');
403
+ @ var width = Math.max(txtPres[0].scrollWidth, txtPres[1].scrollWidth);
404
+ @ for(var i=0; i<2; i++){
405
+ @ txtPres[i].style.width = width + 'px';
406
+ @ txtCols[i].onscroll = function(e){
407
+ @ txtCols[0].scrollLeft = txtCols[1].scrollLeft = this.scrollLeft;
408
+ @ };
409
+ @ }
410
+ @ diff.tabIndex = 0;
411
+ @ diff.onkeydown = function(e){
412
+ @ e = e || event;
413
+ @ var len = {37: -SCROLL_LEN, 39: SCROLL_LEN}[e.keyCode];
414
+ @ if( !len ) return;
415
+ @ txtCols[0].scrollLeft += len;
416
+ @ return false;
417
+ @ };
418
+ @ }
419
+ @
420
+ @ var diffs = document.querySelectorAll('.sbsdiffcols');
421
+ @ for(var i=0; i<diffs.length; i++){
422
+ @ initSbsDiff(diffs[i]);
423
+ @ }
424
+ @ }())</script>
425
+}
400426
401427
/*
402428
** Construct an appropriate diffFlag for text_diff() based on query
403429
** parameters and the to boolean arguments.
404430
*/
@@ -675,10 +701,11 @@
675701
const char *zOldName = db_column_text(&q, 4);
676702
append_file_change_line(zName, zOld, zNew, zOldName, diffFlags,pRe,mperm);
677703
}
678704
db_finalize(&q);
679705
}
706
+ append_diff_javascript(sideBySide);
680707
style_footer();
681708
}
682709
683710
/*
684711
** WEBPAGE: winfo
@@ -988,11 +1015,11 @@
9881015
pFileTo = manifest_file_next(pTo, 0);
9891016
}
9901017
}
9911018
manifest_destroy(pFrom);
9921019
manifest_destroy(pTo);
993
-
1020
+ append_diff_javascript(sideBySide);
9941021
style_footer();
9951022
}
9961023
9971024
#if INTERFACE
9981025
/*
@@ -1244,85 +1271,74 @@
12441271
*/
12451272
void diff_page(void){
12461273
int v1, v2;
12471274
int isPatch;
12481275
int sideBySide;
1249
- Blob c1, c2, diff, *pOut;
12501276
char *zV1;
12511277
char *zV2;
12521278
const char *zRe;
12531279
ReCompiled *pRe = 0;
12541280
u64 diffFlags;
1255
- const char *zStyle = "sbsdiff";
12561281
12571282
login_check_credentials();
12581283
if( !g.perm.Read ){ login_needed(); return; }
12591284
v1 = name_to_rid_www("v1");
12601285
v2 = name_to_rid_www("v2");
12611286
if( v1==0 || v2==0 ) fossil_redirect_home();
1262
- sideBySide = !is_false(PD("sbs","1"));
1263
- zV1 = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", v1);
1264
- zV2 = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", v2);
1287
+ zRe = P("regex");
1288
+ if( zRe ) re_compile(&pRe, zRe, 0);
12651289
isPatch = P("patch")!=0;
12661290
if( isPatch ){
1291
+ Blob c1, c2, *pOut;
12671292
pOut = cgi_output_blob();
12681293
cgi_set_content_type("text/plain");
12691294
diffFlags = 4;
1270
- }else{
1271
- blob_zero(&diff);
1272
- pOut = &diff;
1273
- diffFlags = construct_diff_flags(1, sideBySide) | DIFF_HTML;
1274
- if( sideBySide ){
1275
- zStyle = "sbsdiff";
1276
- }else{
1277
- diffFlags |= DIFF_LINENO;
1278
- zStyle = "udiff";
1279
- }
1280
- }
1281
- zRe = P("regex");
1282
- if( zRe ) re_compile(&pRe, zRe, 0);
1283
- content_get(v1, &c1);
1284
- content_get(v2, &c2);
1285
- text_diff(&c1, &c2, pOut, pRe, diffFlags);
1286
- blob_reset(&c1);
1287
- blob_reset(&c2);
1288
- if( !isPatch ){
1289
- style_header("Diff");
1290
- style_submenu_element("Patch", "Patch", "%s/fdiff?v1=%T&v2=%T&patch",
1291
- g.zTop, P("v1"), P("v2"));
1292
- if( !sideBySide ){
1293
- style_submenu_element("Side-by-side Diff", "sbsdiff",
1294
- "%s/fdiff?v1=%T&v2=%T&sbs=1",
1295
- g.zTop, P("v1"), P("v2"));
1296
- }else{
1297
- style_submenu_element("Unified Diff", "udiff",
1298
- "%s/fdiff?v1=%T&v2=%T&sbs=0",
1299
- g.zTop, P("v1"), P("v2"));
1300
- }
1301
-
1302
- if( P("smhdr")!=0 ){
1303
- @ <h2>Differences From Artifact
1304
- @ %z(href("%R/artifact/%S",zV1))[%S(zV1)]</a> To
1305
- @ %z(href("%R/artifact/%S",zV2))[%S(zV2)]</a>.</h2>
1306
- }else{
1307
- @ <h2>Differences From
1308
- @ Artifact %z(href("%R/artifact/%S",zV1))[%S(zV1)]</a>:</h2>
1309
- object_description(v1, 0, 0);
1310
- @ <h2>To Artifact %z(href("%R/artifact/%S",zV2))[%S(zV2)]</a>:</h2>
1311
- object_description(v2, 0, 0);
1312
- }
1313
- if( pRe ){
1314
- @ <b>Only differences that match regular expression "%h(zRe)"
1315
- @ are shown.</b>
1316
- }
1317
- @ <hr />
1318
- @ <div class="%s(zStyle)">
1319
- @ %s(blob_str(&diff))
1320
- @ </div>
1321
- blob_reset(&diff);
1322
- style_footer();
1323
- }
1295
+ content_get(v1, &c1);
1296
+ content_get(v2, &c2);
1297
+ text_diff(&c1, &c2, pOut, pRe, diffFlags);
1298
+ blob_reset(&c1);
1299
+ blob_reset(&c2);
1300
+ return;
1301
+ }
1302
+
1303
+ sideBySide = !is_false(PD("sbs","1"));
1304
+ zV1 = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", v1);
1305
+ zV2 = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", v2);
1306
+ diffFlags = construct_diff_flags(1, sideBySide) | DIFF_HTML;
1307
+
1308
+ style_header("Diff");
1309
+ style_submenu_element("Patch", "Patch", "%s/fdiff?v1=%T&v2=%T&patch",
1310
+ g.zTop, P("v1"), P("v2"));
1311
+ if( !sideBySide ){
1312
+ style_submenu_element("Side-by-side Diff", "sbsdiff",
1313
+ "%s/fdiff?v1=%T&v2=%T&sbs=1",
1314
+ g.zTop, P("v1"), P("v2"));
1315
+ }else{
1316
+ style_submenu_element("Unified Diff", "udiff",
1317
+ "%s/fdiff?v1=%T&v2=%T&sbs=0",
1318
+ g.zTop, P("v1"), P("v2"));
1319
+ }
1320
+
1321
+ if( P("smhdr")!=0 ){
1322
+ @ <h2>Differences From Artifact
1323
+ @ %z(href("%R/artifact/%S",zV1))[%S(zV1)]</a> To
1324
+ @ %z(href("%R/artifact/%S",zV2))[%S(zV2)]</a>.</h2>
1325
+ }else{
1326
+ @ <h2>Differences From
1327
+ @ Artifact %z(href("%R/artifact/%S",zV1))[%S(zV1)]</a>:</h2>
1328
+ object_description(v1, 0, 0);
1329
+ @ <h2>To Artifact %z(href("%R/artifact/%S",zV2))[%S(zV2)]</a>:</h2>
1330
+ object_description(v2, 0, 0);
1331
+ }
1332
+ if( pRe ){
1333
+ @ <b>Only differences that match regular expression "%h(zRe)"
1334
+ @ are shown.</b>
1335
+ }
1336
+ @ <hr />
1337
+ append_diff(zV1, zV2, diffFlags, pRe);
1338
+ append_diff_javascript(sideBySide);
1339
+ style_footer();
13241340
}
13251341
13261342
/*
13271343
** WEBPAGE: raw
13281344
** URL: /raw?name=ARTIFACTID&m=TYPE
@@ -2205,38 +2221,38 @@
22052221
form_begin(0, "%R/ci_edit");
22062222
login_insert_csrf_secret();
22072223
@ <div><input type="hidden" name="r" value="%S(zUuid)" />
22082224
@ <table border="0" cellspacing="10">
22092225
2210
- @ <tr><td align="right" valign="top"><b>User:</b></td>
2226
+ @ <tr><th align="right" valign="top">User:</th>
22112227
@ <td valign="top">
22122228
@ <input type="text" name="u" size="20" value="%h(zNewUser)" />
22132229
@ </td></tr>
22142230
2215
- @ <tr><td align="right" valign="top"><b>Comment:</b></td>
2231
+ @ <tr><th align="right" valign="top">Comment:</th>
22162232
@ <td valign="top">
22172233
@ <textarea name="c" rows="10" cols="80">%h(zNewComment)</textarea>
22182234
@ </td></tr>
22192235
2220
- @ <tr><td align="right" valign="top"><b>Check-in Time:</b></td>
2236
+ @ <tr><th align="right" valign="top">Check-in Time:</th>
22212237
@ <td valign="top">
22222238
@ <input type="text" name="dt" size="20" value="%h(zNewDate)" />
22232239
@ </td></tr>
22242240
22252241
if( zChngTime ){
2226
- @ <tr><td align="right" valign="top"><b>Timestamp of this change:</b></td>
2242
+ @ <tr><th align="right" valign="top">Timestamp of this change:</th>
22272243
@ <td valign="top">
22282244
@ <input type="text" name="chngtime" size="20" value="%h(zChngTime)" />
22292245
@ </td></tr>
22302246
}
22312247
2232
- @ <tr><td align="right" valign="top"><b>Background Color:</b></td>
2248
+ @ <tr><th align="right" valign="top">Background Color:</th>
22332249
@ <td valign="top">
22342250
render_color_chooser(fNewPropagateColor, zNewColor, "pclr", "clr", "clrcust");
22352251
@ </td></tr>
22362252
2237
- @ <tr><td align="right" valign="top"><b>Tags:</b></td>
2253
+ @ <tr><th align="right" valign="top">Tags:</th>
22382254
@ <td valign="top">
22392255
@ <label><input type="checkbox" id="newtag" name="newtag"%s(zNewTagFlag) />
22402256
@ Add the following new tag name to this check-in:</label>
22412257
@ <input type="text" style="width:15;" name="tagname" value="%h(zNewTag)"
22422258
@ onkeyup="gebi('newtag').checked=!!this.value" />
@@ -2265,11 +2281,11 @@
22652281
}
22662282
}
22672283
db_finalize(&q);
22682284
@ </td></tr>
22692285
2270
- @ <tr><td align="right" valign="top"><b>Branching:</b></td>
2286
+ @ <tr><th align="right" valign="top">Branching:</th>
22712287
@ <td valign="top">
22722288
@ <label><input id="newbr" type="checkbox" name="newbr"%s(zNewBrFlag) />
22732289
@ Make this check-in the start of a new branch named:</label>
22742290
@ <input type="text" style="width:15;" name="brname" value="%h(zNewBranch)"
22752291
@ onkeyup="gebi('newbr').checked=!!this.value" />
@@ -2278,11 +2294,11 @@
22782294
if( is_a_leaf(rid)
22792295
&& !db_exists("SELECT 1 FROM tagxref "
22802296
" WHERE tagid=%d AND rid=%d AND tagtype>0",
22812297
TAG_CLOSED, rid)
22822298
){
2283
- @ <tr><td align="right" valign="top"><b>Leaf Closure:</b></td>
2299
+ @ <tr><th align="right" valign="top">Leaf Closure:</th>
22842300
@ <td valign="top">
22852301
@ <label><input type="checkbox" name="close"%s(zCloseFlag) />
22862302
@ Mark this leaf as "closed" so that it no longer appears on the
22872303
@ "leaves" page and is no longer labeled as a "<b>Leaf</b>".</label>
22882304
@ </td></tr>
22892305
22902306
ADDED src/lookslike.c
--- src/info.c
+++ src/info.c
@@ -316,25 +316,22 @@
316 blob_zero(&to);
317 }
318 blob_zero(&out);
319 if( diffFlags & DIFF_SIDEBYSIDE ){
320 text_diff(&from, &to, &out, pRe, diffFlags | DIFF_HTML | DIFF_NOTTOOBIG);
321 @ <div class="sbsdiff">
322 @ %s(blob_str(&out))
323 @ </div>
324 }else{
325 text_diff(&from, &to, &out, pRe,
326 diffFlags | DIFF_LINENO | DIFF_HTML | DIFF_NOTTOOBIG);
327 @ <div class="udiff">
328 @ %s(blob_str(&out))
329 @ </div>
330 }
331 blob_reset(&from);
332 blob_reset(&to);
333 blob_reset(&out);
334 }
335
336
337 /*
338 ** Write a line of web-page output that shows changes that have occurred
339 ** to a file between two check-ins.
340 */
@@ -359,13 +356,11 @@
359 @ for %h(zName)</p>
360 }else{
361 @ <p>Changes to %h(zName)</p>
362 }
363 if( diffFlags ){
364 @ <pre style="white-space:pre;">
365 append_diff(zOld, zNew, diffFlags, pRe);
366 @ </pre>
367 }
368 }else{
369 if( zOld && zNew ){
370 if( fossil_strcmp(zOld, zNew)!=0 ){
371 @ <p>Modified %z(href("%R/finfo?name=%T",zName))%h(zName)</a>
@@ -385,20 +380,51 @@
385 }else{
386 @ <p>Added %z(href("%R/finfo?name=%T",zName))%h(zName)</a>
387 @ version %z(href("%R/artifact/%s",zNew))[%S(zNew)]</a>
388 }
389 if( diffFlags ){
390 @ <pre style="white-space:pre;">
391 append_diff(zOld, zNew, diffFlags, pRe);
392 @ </pre>
393 }else if( zOld && zNew && fossil_strcmp(zOld,zNew)!=0 ){
394 @ &nbsp;&nbsp;
395 @ %z(href("%R/fdiff?v1=%S&v2=%S&sbs=1",zOld,zNew))[diff]</a>
396 }
397 @ </p>
398 }
399 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
400
401 /*
402 ** Construct an appropriate diffFlag for text_diff() based on query
403 ** parameters and the to boolean arguments.
404 */
@@ -675,10 +701,11 @@
675 const char *zOldName = db_column_text(&q, 4);
676 append_file_change_line(zName, zOld, zNew, zOldName, diffFlags,pRe,mperm);
677 }
678 db_finalize(&q);
679 }
 
680 style_footer();
681 }
682
683 /*
684 ** WEBPAGE: winfo
@@ -988,11 +1015,11 @@
988 pFileTo = manifest_file_next(pTo, 0);
989 }
990 }
991 manifest_destroy(pFrom);
992 manifest_destroy(pTo);
993
994 style_footer();
995 }
996
997 #if INTERFACE
998 /*
@@ -1244,85 +1271,74 @@
1244 */
1245 void diff_page(void){
1246 int v1, v2;
1247 int isPatch;
1248 int sideBySide;
1249 Blob c1, c2, diff, *pOut;
1250 char *zV1;
1251 char *zV2;
1252 const char *zRe;
1253 ReCompiled *pRe = 0;
1254 u64 diffFlags;
1255 const char *zStyle = "sbsdiff";
1256
1257 login_check_credentials();
1258 if( !g.perm.Read ){ login_needed(); return; }
1259 v1 = name_to_rid_www("v1");
1260 v2 = name_to_rid_www("v2");
1261 if( v1==0 || v2==0 ) fossil_redirect_home();
1262 sideBySide = !is_false(PD("sbs","1"));
1263 zV1 = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", v1);
1264 zV2 = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", v2);
1265 isPatch = P("patch")!=0;
1266 if( isPatch ){
 
1267 pOut = cgi_output_blob();
1268 cgi_set_content_type("text/plain");
1269 diffFlags = 4;
1270 }else{
1271 blob_zero(&diff);
1272 pOut = &diff;
1273 diffFlags = construct_diff_flags(1, sideBySide) | DIFF_HTML;
1274 if( sideBySide ){
1275 zStyle = "sbsdiff";
1276 }else{
1277 diffFlags |= DIFF_LINENO;
1278 zStyle = "udiff";
1279 }
1280 }
1281 zRe = P("regex");
1282 if( zRe ) re_compile(&pRe, zRe, 0);
1283 content_get(v1, &c1);
1284 content_get(v2, &c2);
1285 text_diff(&c1, &c2, pOut, pRe, diffFlags);
1286 blob_reset(&c1);
1287 blob_reset(&c2);
1288 if( !isPatch ){
1289 style_header("Diff");
1290 style_submenu_element("Patch", "Patch", "%s/fdiff?v1=%T&v2=%T&patch",
1291 g.zTop, P("v1"), P("v2"));
1292 if( !sideBySide ){
1293 style_submenu_element("Side-by-side Diff", "sbsdiff",
1294 "%s/fdiff?v1=%T&v2=%T&sbs=1",
1295 g.zTop, P("v1"), P("v2"));
1296 }else{
1297 style_submenu_element("Unified Diff", "udiff",
1298 "%s/fdiff?v1=%T&v2=%T&sbs=0",
1299 g.zTop, P("v1"), P("v2"));
1300 }
1301
1302 if( P("smhdr")!=0 ){
1303 @ <h2>Differences From Artifact
1304 @ %z(href("%R/artifact/%S",zV1))[%S(zV1)]</a> To
1305 @ %z(href("%R/artifact/%S",zV2))[%S(zV2)]</a>.</h2>
1306 }else{
1307 @ <h2>Differences From
1308 @ Artifact %z(href("%R/artifact/%S",zV1))[%S(zV1)]</a>:</h2>
1309 object_description(v1, 0, 0);
1310 @ <h2>To Artifact %z(href("%R/artifact/%S",zV2))[%S(zV2)]</a>:</h2>
1311 object_description(v2, 0, 0);
1312 }
1313 if( pRe ){
1314 @ <b>Only differences that match regular expression "%h(zRe)"
1315 @ are shown.</b>
1316 }
1317 @ <hr />
1318 @ <div class="%s(zStyle)">
1319 @ %s(blob_str(&diff))
1320 @ </div>
1321 blob_reset(&diff);
1322 style_footer();
1323 }
1324 }
1325
1326 /*
1327 ** WEBPAGE: raw
1328 ** URL: /raw?name=ARTIFACTID&m=TYPE
@@ -2205,38 +2221,38 @@
2205 form_begin(0, "%R/ci_edit");
2206 login_insert_csrf_secret();
2207 @ <div><input type="hidden" name="r" value="%S(zUuid)" />
2208 @ <table border="0" cellspacing="10">
2209
2210 @ <tr><td align="right" valign="top"><b>User:</b></td>
2211 @ <td valign="top">
2212 @ <input type="text" name="u" size="20" value="%h(zNewUser)" />
2213 @ </td></tr>
2214
2215 @ <tr><td align="right" valign="top"><b>Comment:</b></td>
2216 @ <td valign="top">
2217 @ <textarea name="c" rows="10" cols="80">%h(zNewComment)</textarea>
2218 @ </td></tr>
2219
2220 @ <tr><td align="right" valign="top"><b>Check-in Time:</b></td>
2221 @ <td valign="top">
2222 @ <input type="text" name="dt" size="20" value="%h(zNewDate)" />
2223 @ </td></tr>
2224
2225 if( zChngTime ){
2226 @ <tr><td align="right" valign="top"><b>Timestamp of this change:</b></td>
2227 @ <td valign="top">
2228 @ <input type="text" name="chngtime" size="20" value="%h(zChngTime)" />
2229 @ </td></tr>
2230 }
2231
2232 @ <tr><td align="right" valign="top"><b>Background Color:</b></td>
2233 @ <td valign="top">
2234 render_color_chooser(fNewPropagateColor, zNewColor, "pclr", "clr", "clrcust");
2235 @ </td></tr>
2236
2237 @ <tr><td align="right" valign="top"><b>Tags:</b></td>
2238 @ <td valign="top">
2239 @ <label><input type="checkbox" id="newtag" name="newtag"%s(zNewTagFlag) />
2240 @ Add the following new tag name to this check-in:</label>
2241 @ <input type="text" style="width:15;" name="tagname" value="%h(zNewTag)"
2242 @ onkeyup="gebi('newtag').checked=!!this.value" />
@@ -2265,11 +2281,11 @@
2265 }
2266 }
2267 db_finalize(&q);
2268 @ </td></tr>
2269
2270 @ <tr><td align="right" valign="top"><b>Branching:</b></td>
2271 @ <td valign="top">
2272 @ <label><input id="newbr" type="checkbox" name="newbr"%s(zNewBrFlag) />
2273 @ Make this check-in the start of a new branch named:</label>
2274 @ <input type="text" style="width:15;" name="brname" value="%h(zNewBranch)"
2275 @ onkeyup="gebi('newbr').checked=!!this.value" />
@@ -2278,11 +2294,11 @@
2278 if( is_a_leaf(rid)
2279 && !db_exists("SELECT 1 FROM tagxref "
2280 " WHERE tagid=%d AND rid=%d AND tagtype>0",
2281 TAG_CLOSED, rid)
2282 ){
2283 @ <tr><td align="right" valign="top"><b>Leaf Closure:</b></td>
2284 @ <td valign="top">
2285 @ <label><input type="checkbox" name="close"%s(zCloseFlag) />
2286 @ Mark this leaf as "closed" so that it no longer appears on the
2287 @ "leaves" page and is no longer labeled as a "<b>Leaf</b>".</label>
2288 @ </td></tr>
2289
2290 DDED src/lookslike.c
--- src/info.c
+++ src/info.c
@@ -316,25 +316,22 @@
316 blob_zero(&to);
317 }
318 blob_zero(&out);
319 if( diffFlags & DIFF_SIDEBYSIDE ){
320 text_diff(&from, &to, &out, pRe, diffFlags | DIFF_HTML | DIFF_NOTTOOBIG);
 
321 @ %s(blob_str(&out))
 
322 }else{
323 text_diff(&from, &to, &out, pRe,
324 diffFlags | DIFF_LINENO | DIFF_HTML | DIFF_NOTTOOBIG);
325 @ <pre class="udiff">
326 @ %s(blob_str(&out))
327 @ </pre>
328 }
329 blob_reset(&from);
330 blob_reset(&to);
331 blob_reset(&out);
332 }
 
333
334 /*
335 ** Write a line of web-page output that shows changes that have occurred
336 ** to a file between two check-ins.
337 */
@@ -359,13 +356,11 @@
356 @ for %h(zName)</p>
357 }else{
358 @ <p>Changes to %h(zName)</p>
359 }
360 if( diffFlags ){
 
361 append_diff(zOld, zNew, diffFlags, pRe);
 
362 }
363 }else{
364 if( zOld && zNew ){
365 if( fossil_strcmp(zOld, zNew)!=0 ){
366 @ <p>Modified %z(href("%R/finfo?name=%T",zName))%h(zName)</a>
@@ -385,20 +380,51 @@
380 }else{
381 @ <p>Added %z(href("%R/finfo?name=%T",zName))%h(zName)</a>
382 @ version %z(href("%R/artifact/%s",zNew))[%S(zNew)]</a>
383 }
384 if( diffFlags ){
 
385 append_diff(zOld, zNew, diffFlags, pRe);
 
386 }else if( zOld && zNew && fossil_strcmp(zOld,zNew)!=0 ){
387 @ &nbsp;&nbsp;
388 @ %z(href("%R/fdiff?v1=%S&v2=%S&sbs=1",zOld,zNew))[diff]</a>
389 }
 
390 }
391 }
392
393 /*
394 ** Generate javascript to enhance HTML diffs.
395 */
396 void append_diff_javascript(int sideBySide){
397 if( !sideBySide ) return;
398 @ <script>(function(){
399 @ var SCROLL_LEN = 25;
400 @ function initSbsDiff(diff){
401 @ var txtCols = diff.querySelectorAll('.difftxtcol');
402 @ var txtPres = diff.querySelectorAll('.difftxtcol pre');
403 @ var width = Math.max(txtPres[0].scrollWidth, txtPres[1].scrollWidth);
404 @ for(var i=0; i<2; i++){
405 @ txtPres[i].style.width = width + 'px';
406 @ txtCols[i].onscroll = function(e){
407 @ txtCols[0].scrollLeft = txtCols[1].scrollLeft = this.scrollLeft;
408 @ };
409 @ }
410 @ diff.tabIndex = 0;
411 @ diff.onkeydown = function(e){
412 @ e = e || event;
413 @ var len = {37: -SCROLL_LEN, 39: SCROLL_LEN}[e.keyCode];
414 @ if( !len ) return;
415 @ txtCols[0].scrollLeft += len;
416 @ return false;
417 @ };
418 @ }
419 @
420 @ var diffs = document.querySelectorAll('.sbsdiffcols');
421 @ for(var i=0; i<diffs.length; i++){
422 @ initSbsDiff(diffs[i]);
423 @ }
424 @ }())</script>
425 }
426
427 /*
428 ** Construct an appropriate diffFlag for text_diff() based on query
429 ** parameters and the to boolean arguments.
430 */
@@ -675,10 +701,11 @@
701 const char *zOldName = db_column_text(&q, 4);
702 append_file_change_line(zName, zOld, zNew, zOldName, diffFlags,pRe,mperm);
703 }
704 db_finalize(&q);
705 }
706 append_diff_javascript(sideBySide);
707 style_footer();
708 }
709
710 /*
711 ** WEBPAGE: winfo
@@ -988,11 +1015,11 @@
1015 pFileTo = manifest_file_next(pTo, 0);
1016 }
1017 }
1018 manifest_destroy(pFrom);
1019 manifest_destroy(pTo);
1020 append_diff_javascript(sideBySide);
1021 style_footer();
1022 }
1023
1024 #if INTERFACE
1025 /*
@@ -1244,85 +1271,74 @@
1271 */
1272 void diff_page(void){
1273 int v1, v2;
1274 int isPatch;
1275 int sideBySide;
 
1276 char *zV1;
1277 char *zV2;
1278 const char *zRe;
1279 ReCompiled *pRe = 0;
1280 u64 diffFlags;
 
1281
1282 login_check_credentials();
1283 if( !g.perm.Read ){ login_needed(); return; }
1284 v1 = name_to_rid_www("v1");
1285 v2 = name_to_rid_www("v2");
1286 if( v1==0 || v2==0 ) fossil_redirect_home();
1287 zRe = P("regex");
1288 if( zRe ) re_compile(&pRe, zRe, 0);
 
1289 isPatch = P("patch")!=0;
1290 if( isPatch ){
1291 Blob c1, c2, *pOut;
1292 pOut = cgi_output_blob();
1293 cgi_set_content_type("text/plain");
1294 diffFlags = 4;
1295 content_get(v1, &c1);
1296 content_get(v2, &c2);
1297 text_diff(&c1, &c2, pOut, pRe, diffFlags);
1298 blob_reset(&c1);
1299 blob_reset(&c2);
1300 return;
1301 }
1302
1303 sideBySide = !is_false(PD("sbs","1"));
1304 zV1 = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", v1);
1305 zV2 = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", v2);
1306 diffFlags = construct_diff_flags(1, sideBySide) | DIFF_HTML;
1307
1308 style_header("Diff");
1309 style_submenu_element("Patch", "Patch", "%s/fdiff?v1=%T&v2=%T&patch",
1310 g.zTop, P("v1"), P("v2"));
1311 if( !sideBySide ){
1312 style_submenu_element("Side-by-side Diff", "sbsdiff",
1313 "%s/fdiff?v1=%T&v2=%T&sbs=1",
1314 g.zTop, P("v1"), P("v2"));
1315 }else{
1316 style_submenu_element("Unified Diff", "udiff",
1317 "%s/fdiff?v1=%T&v2=%T&sbs=0",
1318 g.zTop, P("v1"), P("v2"));
1319 }
1320
1321 if( P("smhdr")!=0 ){
1322 @ <h2>Differences From Artifact
1323 @ %z(href("%R/artifact/%S",zV1))[%S(zV1)]</a> To
1324 @ %z(href("%R/artifact/%S",zV2))[%S(zV2)]</a>.</h2>
1325 }else{
1326 @ <h2>Differences From
1327 @ Artifact %z(href("%R/artifact/%S",zV1))[%S(zV1)]</a>:</h2>
1328 object_description(v1, 0, 0);
1329 @ <h2>To Artifact %z(href("%R/artifact/%S",zV2))[%S(zV2)]</a>:</h2>
1330 object_description(v2, 0, 0);
1331 }
1332 if( pRe ){
1333 @ <b>Only differences that match regular expression "%h(zRe)"
1334 @ are shown.</b>
1335 }
1336 @ <hr />
1337 append_diff(zV1, zV2, diffFlags, pRe);
1338 append_diff_javascript(sideBySide);
1339 style_footer();
 
 
 
 
 
 
 
 
 
1340 }
1341
1342 /*
1343 ** WEBPAGE: raw
1344 ** URL: /raw?name=ARTIFACTID&m=TYPE
@@ -2205,38 +2221,38 @@
2221 form_begin(0, "%R/ci_edit");
2222 login_insert_csrf_secret();
2223 @ <div><input type="hidden" name="r" value="%S(zUuid)" />
2224 @ <table border="0" cellspacing="10">
2225
2226 @ <tr><th align="right" valign="top">User:</th>
2227 @ <td valign="top">
2228 @ <input type="text" name="u" size="20" value="%h(zNewUser)" />
2229 @ </td></tr>
2230
2231 @ <tr><th align="right" valign="top">Comment:</th>
2232 @ <td valign="top">
2233 @ <textarea name="c" rows="10" cols="80">%h(zNewComment)</textarea>
2234 @ </td></tr>
2235
2236 @ <tr><th align="right" valign="top">Check-in Time:</th>
2237 @ <td valign="top">
2238 @ <input type="text" name="dt" size="20" value="%h(zNewDate)" />
2239 @ </td></tr>
2240
2241 if( zChngTime ){
2242 @ <tr><th align="right" valign="top">Timestamp of this change:</th>
2243 @ <td valign="top">
2244 @ <input type="text" name="chngtime" size="20" value="%h(zChngTime)" />
2245 @ </td></tr>
2246 }
2247
2248 @ <tr><th align="right" valign="top">Background Color:</th>
2249 @ <td valign="top">
2250 render_color_chooser(fNewPropagateColor, zNewColor, "pclr", "clr", "clrcust");
2251 @ </td></tr>
2252
2253 @ <tr><th align="right" valign="top">Tags:</th>
2254 @ <td valign="top">
2255 @ <label><input type="checkbox" id="newtag" name="newtag"%s(zNewTagFlag) />
2256 @ Add the following new tag name to this check-in:</label>
2257 @ <input type="text" style="width:15;" name="tagname" value="%h(zNewTag)"
2258 @ onkeyup="gebi('newtag').checked=!!this.value" />
@@ -2265,11 +2281,11 @@
2281 }
2282 }
2283 db_finalize(&q);
2284 @ </td></tr>
2285
2286 @ <tr><th align="right" valign="top">Branching:</th>
2287 @ <td valign="top">
2288 @ <label><input id="newbr" type="checkbox" name="newbr"%s(zNewBrFlag) />
2289 @ Make this check-in the start of a new branch named:</label>
2290 @ <input type="text" style="width:15;" name="brname" value="%h(zNewBranch)"
2291 @ onkeyup="gebi('newbr').checked=!!this.value" />
@@ -2278,11 +2294,11 @@
2294 if( is_a_leaf(rid)
2295 && !db_exists("SELECT 1 FROM tagxref "
2296 " WHERE tagid=%d AND rid=%d AND tagtype>0",
2297 TAG_CLOSED, rid)
2298 ){
2299 @ <tr><th align="right" valign="top">Leaf Closure:</th>
2300 @ <td valign="top">
2301 @ <label><input type="checkbox" name="close"%s(zCloseFlag) />
2302 @ Mark this leaf as "closed" so that it no longer appears on the
2303 @ "leaves" page and is no longer labeled as a "<b>Leaf</b>".</label>
2304 @ </td></tr>
2305
2306 DDED src/lookslike.c
--- a/src/lookslike.c
+++ b/src/lookslike.c
@@ -0,0 +1,119 @@
1
+utf8((blob), LOOK_BINARY, 0) & LOOK_BINARY) != LOOK_NONE)
2
+
3
+/*
4
+** Output flags for the looks_like_utf8() and looks_like_utf16() routines used
5
+** to convey status information about the blob content.
6
+*/
7
+#define LOOK_NONE ((int)0x00000000) /* Nothing special was found. */
8
+#define LOOK_NUL ((int)0x00000001) /* One or more Nfossil_isalnumne LOOK_NUL ((int)0x00000001) /* One or more Nutf8((blob), Lz[i+n]!=0&&SQL. This is only a
9
+** high-level check, not intended to be used for any application-level
10
+** logic other than in defense against spiders in limited context((blob), LOOK_BINARY, 0) & LOOK_BINARY) != LOOK_NONE)
11
+
12
+/*
13
+** Output flags for the looks_like_utf8() and looks_like_utf16() routines used
14
+** to convey status information about the blob content.
15
+*/
16
+#define LOOK_NONE ((int)0x00000000) /* Nothing special was found. */
17
+#define LOOK_NUL ((int)0x00000001) /* One or more Nfossil_isalnumne LOOK_NUL ((int)0x00000001) /* One or more Nutf8((blob), LRY, 0) & LOOK_BINARY) != LOOK_NONE)
18
+
19
+/*
20
+** Output flags for the looks_like_utf8() and looks_like_utf16() routines used
21
+** to convey status information about the blob content.
22
+*/
23
+#define LOOK_NONE ((int)0x00000000) /* Nothing special was found. */
24
+#define LOOK_NUL ((int)0x00000001) /* One or more Nfossil_isalnumne LOOK_NUL ((int)0x00000001) /* One or more Nutf8((blob), Lmight_be_sql(cCR tatus i10ormation a02LOOK_BINARY, 0) & LOOK_BI were LOOK_NUL ((int)0x00LONE_CR 20d ") || L(" or ")
25
+ /* ^^^^^ F tatus i10ormation a08/* One or more Nfossil_is were LOOK_NUL ((int)0x00LONE_LF ((int)0x00000010 ")
26
+ /* ^^^^^ no=08ere LOOK_NUL ((/LF paiLF ((int)0x00000010") || L20F ((int)0x00000010") || L("updaten 0;
27
+#define L(GLOB1" andf8() an88((blob), LOO4f8() and looks_like_utf16() routines used
28
+** to 2onvey status i10ormation a8efine LOOK_NONE ((in04#define LOOK_NONE ((int)0x0000000020/* Nothing sp10ial was found. */
29
+#08fine LOOK_NUL ((int)0x00000001) /* One or more N20ssil_isalnumne LOOK_NUL ((int)0x00000001) /* One or more Nutf8((blob), Lz[i+n]!=0&&SQL. This is only aited context((blob), LOOK_BINARY, 0)define LOOK_CR [i+n]!=0&&SQL. This is onlCRLFere LOOK_ne or more Nfossil_isalnumne LOOK_NUL ((int)0x00000001) /* One or more Nutf8((blob), Lz[i+n]!=0&&SQL. This is only aited context((blob), LOOK_BINARY, 0) & LOOK_BINARY) != LOOK_NONE)
30
+
31
+/*
32
+** Output flags for the looks_like_utf8() and looks_like_utf16() routines used
33
+** to convey status information about the blob content.
34
+*/
35
+#define LOOK_NONE ((int)0x00000000) /* Nothing special was found. */
36
+#define LOOK_NUL ((int)0x00000001) /* One or more Nfossil_isalnumne LOOK_NUL ((int)0x00000001) /* One or more Nutf8((blob), LRY, 0) & LOOK_BINARY) != LOOK_NONE)
37
+
38
+/*
39
+** Output flags for the looks_like_utf8() and looks_like_utf16() routines used
40
+** to convey status information about the blob content.
41
+*/
42
+#define LOOK_NONE ((int)0x00000000) /* Nothing special was found. */
43
+#define LOOK_NUL ((int)0x00000001) /* One or more Nfossil_isalnumne LOOK_NUL ((int)0x00000001) /* One or more Nutf8((blob), Lmight_be_sql(const char *zTxt){
44
+ if( zTxt==0 || zTxt[0]==0 ) return 0;
45
+#define L(GLOB) 0==sqlite3_strlike("%" GLOB "%",zTxt, '%')
46
+ return L(";") || L("'")
47
+ || L("select") || L("order") || L("drop")
48
+ || L(" and ") || L(" or ")
49
+ /* ^^^^^ noting that \n and \t should also be checked */
50
+ || L("null") || L("delete") || L("update")
51
+ |;<num> Repeatest_looks_like_utflooks_like_utf_testshort *z = (unsigned short1]==0possible UTF-32. */
52
+ if( z[0]z[0]==0xfffeutf8((blob), LOOK_BINARY, 0) & LOOK_BINARY) != LOOK_NONE)
53
+
54
+/*
55
+** Output flflags |= LOOK_CR;
56
+F | flags |= LOOK_LF; | flags |= LOOK_CR;flags |= LOOK_CR;
57
+F | flags |= LOOK_LF; | flags |= LOOK_CR;f8() and looks_like_utf16() roututf8((blob), LOOKf8() and looks_like_utf16() routines used
58
+** to convey status information about the blob content.
59
+*/
60
+#define LOOK_NONE ((int)0x00000000) /* Nothing special was found. */
61
+#define LOOK_NUL ((int)0x00000001) /* One or more Nfossil_isalnumne LOOK_NUL ((int)0x00000001) /* One or more Nutf8((blobflags |= LOOK_CR;(blob), Lz[i+n]!=0&&SQL. This is only a
62
+** high-level check, not intended to be used for any application-level
63
+** logic other tMore chars, next char is--n>0() and flags |= LOOK_LF; | * to convey status informatiBF LOOK_BINARY) != nformationBF LOOK_BINARY) != LOO((int)0x00000000) /* NothingBF LOOK_BINARY) != int)0x0000BF LOOK_BINARY) != LOOK ((int)0x00000001) /* One BF LOOK_BINARY) != ),flags |= LOOK_CR;
64
+ K_CR CRLFurn 0;
65
+#define L(GLOB) 0=LF (rop")
66
+ || L(" andf8() an88((blob), LOOKf8() and looks_like_utf16() routines used
67
+** to convey status i10ormation about the blob content.
68
+*/
69
+#define LOOK_NONE ((int)0x0000000020More chars, next char is0/* Nothing special was found. */
70
+#define LOOK_NUL , c2;
71
+ if( c2>=0xC0 ){
72
+ *def = &lb_tab[(2*c2)-0x180];
73
+ if( c2>=0xe80 ){
74
+ if( ((c2<0xc2) || (c2>=0xf4) || ((c&0xc0)!=0x80)) &&
75
+ (((c2!=0xf4) || (c>=0x90)) &c = (c2 >= 0xe0) ? (c2<<1)+1 : ' '|flags |= LOOK_CR;
76
+ intended to be used for any application-level
77
+** logic other than in defense against spiders F | flags |= LOOK_LF; | * to convey status informat** to convey status information about the blob content.
78
+*/
79
+#define LOOK_NONE ((int)0x00000000) /* Nothing special was found. */
80
+#define LOOK_NUL ((int)0x00000001) /* One or more Nfossil_isalnumne LOOK_NUL ((int)0x00000001) /* One or more Nutf8((blob), Lz[i+n]!=0&&SQL. This is only a
81
+** high-level check, not intended to be used for any application-level
82
+** logic other than in defense against spiders in limited context((blob), LOOK_BINARY, 0) & LOOK_BINARY) != LOOK_NONE)
83
+
84
+/*
85
+** Output flags for the looks_like_utf8() and looks_like_utf16() routines used
86
+** to convey status information about the blob content.
87
+*/
88
+#define LOOK_NONE ((int)0((blob), LOOK_BINARY, 0) & LO{
89
+ *def || (c> ){
90
+ return 1 }c>=0x8tf8((blob), LOOK_BINARY, 0) & LOOK_BINARY) != LOOK_NONE)
91
+
92
+/*
93
+** Output flags for the looks_like_utf8() and looks_like_utf16() routines used
94
+** to convey status information about the blob content.
95
+*/
96
+#define LOOK_NONE ((int)0x00000000) /* Nothing special was found. */
97
+#define LOOK_NUL ((int)0x00000001) /* One or more Nfossil_isalnumne LOOK_NUL ((int)0x00000001) /* One or more Nutf8((blob), Lz[i+n]!=0&&SQL. This is only a
98
+** high-level check, not intended to be used for any application-level
99
+** logic other than in defense against spiders in limited context((blob), LOOK_BINARY, 0) & LOOK_BINARY) != LOOK_NONE)
100
+
101
+/*
102
+** Output flags for the looks_like_utf8() and looks_like_utf16() routines used
103
+** to convey status information about the blob content.
104
+*/
105
+#define LOOK_NONE ((int)0x00000000) /* Nothing special was found. */
106
+#define LOOK_NUL ((int)0x00000001) /* One or more Nfossil_isalnumne LOOKY, 0) & LOOK_BINARY) }utf8((blob), LOOKK_BINARY, 0) & LOOK_BINARY) != LOOK_NONE)
107
+
108
+/*
109
+** Output flags for the looks_like_utf8() and looks_like_utf16() routines used
110
+** to convey status information about the blob content.
111
+*/
112
+#define LOOK_NONE ((int)0x00000000) /* Nothing special was found. */
113
+#define LOOK_NUL ((int)0x00000001) /* One or more Nfossil_isalnumne LOOK_NUL ((int)0x00000001) /* One or more Nutf8((blob), Lz[i+n]!=0&&SQL. This is o1if( flags&stopFlags ) break;
114
+ n -= sizeof(WCHAR_T);
115
+ if( n< break/*bRevUnicodefUtf16((int)0x00000000) utf8((blob), LOOK_BINARY, 0) & LfUnicode = 0;
116
+ }else{
117
+&bRevUnicode) || fForceUtEF, 0xBB, 0xBFlookFlags = fUnicode ? :
118
+und. */
119
+#define
--- a/src/lookslike.c
+++ b/src/lookslike.c
@@ -0,0 +1,119 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
--- a/src/lookslike.c
+++ b/src/lookslike.c
@@ -0,0 +1,119 @@
1 utf8((blob), LOOK_BINARY, 0) & LOOK_BINARY) != LOOK_NONE)
2
3 /*
4 ** Output flags for the looks_like_utf8() and looks_like_utf16() routines used
5 ** to convey status information about the blob content.
6 */
7 #define LOOK_NONE ((int)0x00000000) /* Nothing special was found. */
8 #define LOOK_NUL ((int)0x00000001) /* One or more Nfossil_isalnumne LOOK_NUL ((int)0x00000001) /* One or more Nutf8((blob), Lz[i+n]!=0&&SQL. This is only a
9 ** high-level check, not intended to be used for any application-level
10 ** logic other than in defense against spiders in limited context((blob), LOOK_BINARY, 0) & LOOK_BINARY) != LOOK_NONE)
11
12 /*
13 ** Output flags for the looks_like_utf8() and looks_like_utf16() routines used
14 ** to convey status information about the blob content.
15 */
16 #define LOOK_NONE ((int)0x00000000) /* Nothing special was found. */
17 #define LOOK_NUL ((int)0x00000001) /* One or more Nfossil_isalnumne LOOK_NUL ((int)0x00000001) /* One or more Nutf8((blob), LRY, 0) & LOOK_BINARY) != LOOK_NONE)
18
19 /*
20 ** Output flags for the looks_like_utf8() and looks_like_utf16() routines used
21 ** to convey status information about the blob content.
22 */
23 #define LOOK_NONE ((int)0x00000000) /* Nothing special was found. */
24 #define LOOK_NUL ((int)0x00000001) /* One or more Nfossil_isalnumne LOOK_NUL ((int)0x00000001) /* One or more Nutf8((blob), Lmight_be_sql(cCR tatus i10ormation a02LOOK_BINARY, 0) & LOOK_BI were LOOK_NUL ((int)0x00LONE_CR 20d ") || L(" or ")
25 /* ^^^^^ F tatus i10ormation a08/* One or more Nfossil_is were LOOK_NUL ((int)0x00LONE_LF ((int)0x00000010 ")
26 /* ^^^^^ no=08ere LOOK_NUL ((/LF paiLF ((int)0x00000010") || L20F ((int)0x00000010") || L("updaten 0;
27 #define L(GLOB1" andf8() an88((blob), LOO4f8() and looks_like_utf16() routines used
28 ** to 2onvey status i10ormation a8efine LOOK_NONE ((in04#define LOOK_NONE ((int)0x0000000020/* Nothing sp10ial was found. */
29 #08fine LOOK_NUL ((int)0x00000001) /* One or more N20ssil_isalnumne LOOK_NUL ((int)0x00000001) /* One or more Nutf8((blob), Lz[i+n]!=0&&SQL. This is only aited context((blob), LOOK_BINARY, 0)define LOOK_CR [i+n]!=0&&SQL. This is onlCRLFere LOOK_ne or more Nfossil_isalnumne LOOK_NUL ((int)0x00000001) /* One or more Nutf8((blob), Lz[i+n]!=0&&SQL. This is only aited context((blob), LOOK_BINARY, 0) & LOOK_BINARY) != LOOK_NONE)
30
31 /*
32 ** Output flags for the looks_like_utf8() and looks_like_utf16() routines used
33 ** to convey status information about the blob content.
34 */
35 #define LOOK_NONE ((int)0x00000000) /* Nothing special was found. */
36 #define LOOK_NUL ((int)0x00000001) /* One or more Nfossil_isalnumne LOOK_NUL ((int)0x00000001) /* One or more Nutf8((blob), LRY, 0) & LOOK_BINARY) != LOOK_NONE)
37
38 /*
39 ** Output flags for the looks_like_utf8() and looks_like_utf16() routines used
40 ** to convey status information about the blob content.
41 */
42 #define LOOK_NONE ((int)0x00000000) /* Nothing special was found. */
43 #define LOOK_NUL ((int)0x00000001) /* One or more Nfossil_isalnumne LOOK_NUL ((int)0x00000001) /* One or more Nutf8((blob), Lmight_be_sql(const char *zTxt){
44 if( zTxt==0 || zTxt[0]==0 ) return 0;
45 #define L(GLOB) 0==sqlite3_strlike("%" GLOB "%",zTxt, '%')
46 return L(";") || L("'")
47 || L("select") || L("order") || L("drop")
48 || L(" and ") || L(" or ")
49 /* ^^^^^ noting that \n and \t should also be checked */
50 || L("null") || L("delete") || L("update")
51 |;<num> Repeatest_looks_like_utflooks_like_utf_testshort *z = (unsigned short1]==0possible UTF-32. */
52 if( z[0]z[0]==0xfffeutf8((blob), LOOK_BINARY, 0) & LOOK_BINARY) != LOOK_NONE)
53
54 /*
55 ** Output flflags |= LOOK_CR;
56 F | flags |= LOOK_LF; | flags |= LOOK_CR;flags |= LOOK_CR;
57 F | flags |= LOOK_LF; | flags |= LOOK_CR;f8() and looks_like_utf16() roututf8((blob), LOOKf8() and looks_like_utf16() routines used
58 ** to convey status information about the blob content.
59 */
60 #define LOOK_NONE ((int)0x00000000) /* Nothing special was found. */
61 #define LOOK_NUL ((int)0x00000001) /* One or more Nfossil_isalnumne LOOK_NUL ((int)0x00000001) /* One or more Nutf8((blobflags |= LOOK_CR;(blob), Lz[i+n]!=0&&SQL. This is only a
62 ** high-level check, not intended to be used for any application-level
63 ** logic other tMore chars, next char is--n>0() and flags |= LOOK_LF; | * to convey status informatiBF LOOK_BINARY) != nformationBF LOOK_BINARY) != LOO((int)0x00000000) /* NothingBF LOOK_BINARY) != int)0x0000BF LOOK_BINARY) != LOOK ((int)0x00000001) /* One BF LOOK_BINARY) != ),flags |= LOOK_CR;
64 K_CR CRLFurn 0;
65 #define L(GLOB) 0=LF (rop")
66 || L(" andf8() an88((blob), LOOKf8() and looks_like_utf16() routines used
67 ** to convey status i10ormation about the blob content.
68 */
69 #define LOOK_NONE ((int)0x0000000020More chars, next char is0/* Nothing special was found. */
70 #define LOOK_NUL , c2;
71 if( c2>=0xC0 ){
72 *def = &lb_tab[(2*c2)-0x180];
73 if( c2>=0xe80 ){
74 if( ((c2<0xc2) || (c2>=0xf4) || ((c&0xc0)!=0x80)) &&
75 (((c2!=0xf4) || (c>=0x90)) &c = (c2 >= 0xe0) ? (c2<<1)+1 : ' '|flags |= LOOK_CR;
76 intended to be used for any application-level
77 ** logic other than in defense against spiders F | flags |= LOOK_LF; | * to convey status informat** to convey status information about the blob content.
78 */
79 #define LOOK_NONE ((int)0x00000000) /* Nothing special was found. */
80 #define LOOK_NUL ((int)0x00000001) /* One or more Nfossil_isalnumne LOOK_NUL ((int)0x00000001) /* One or more Nutf8((blob), Lz[i+n]!=0&&SQL. This is only a
81 ** high-level check, not intended to be used for any application-level
82 ** logic other than in defense against spiders in limited context((blob), LOOK_BINARY, 0) & LOOK_BINARY) != LOOK_NONE)
83
84 /*
85 ** Output flags for the looks_like_utf8() and looks_like_utf16() routines used
86 ** to convey status information about the blob content.
87 */
88 #define LOOK_NONE ((int)0((blob), LOOK_BINARY, 0) & LO{
89 *def || (c> ){
90 return 1 }c>=0x8tf8((blob), LOOK_BINARY, 0) & LOOK_BINARY) != LOOK_NONE)
91
92 /*
93 ** Output flags for the looks_like_utf8() and looks_like_utf16() routines used
94 ** to convey status information about the blob content.
95 */
96 #define LOOK_NONE ((int)0x00000000) /* Nothing special was found. */
97 #define LOOK_NUL ((int)0x00000001) /* One or more Nfossil_isalnumne LOOK_NUL ((int)0x00000001) /* One or more Nutf8((blob), Lz[i+n]!=0&&SQL. This is only a
98 ** high-level check, not intended to be used for any application-level
99 ** logic other than in defense against spiders in limited context((blob), LOOK_BINARY, 0) & LOOK_BINARY) != LOOK_NONE)
100
101 /*
102 ** Output flags for the looks_like_utf8() and looks_like_utf16() routines used
103 ** to convey status information about the blob content.
104 */
105 #define LOOK_NONE ((int)0x00000000) /* Nothing special was found. */
106 #define LOOK_NUL ((int)0x00000001) /* One or more Nfossil_isalnumne LOOKY, 0) & LOOK_BINARY) }utf8((blob), LOOKK_BINARY, 0) & LOOK_BINARY) != LOOK_NONE)
107
108 /*
109 ** Output flags for the looks_like_utf8() and looks_like_utf16() routines used
110 ** to convey status information about the blob content.
111 */
112 #define LOOK_NONE ((int)0x00000000) /* Nothing special was found. */
113 #define LOOK_NUL ((int)0x00000001) /* One or more Nfossil_isalnumne LOOK_NUL ((int)0x00000001) /* One or more Nutf8((blob), Lz[i+n]!=0&&SQL. This is o1if( flags&stopFlags ) break;
114 n -= sizeof(WCHAR_T);
115 if( n< break/*bRevUnicodefUtf16((int)0x00000000) utf8((blob), LOOK_BINARY, 0) & LfUnicode = 0;
116 }else{
117 &bRevUnicode) || fForceUtEF, 0xBB, 0xBFlookFlags = fUnicode ? :
118 und. */
119 #define
+12 -2
--- src/main.mk
+++ src/main.mk
@@ -67,10 +67,11 @@
6767
$(SRCDIR)/json_timeline.c \
6868
$(SRCDIR)/json_user.c \
6969
$(SRCDIR)/json_wiki.c \
7070
$(SRCDIR)/leaf.c \
7171
$(SRCDIR)/login.c \
72
+ $(SRCDIR)/lookslike.c \
7273
$(SRCDIR)/main.c \
7374
$(SRCDIR)/manifest.c \
7475
$(SRCDIR)/markdown.c \
7576
$(SRCDIR)/markdown_html.c \
7677
$(SRCDIR)/md5.c \
@@ -175,10 +176,11 @@
175176
$(OBJDIR)/json_timeline_.c \
176177
$(OBJDIR)/json_user_.c \
177178
$(OBJDIR)/json_wiki_.c \
178179
$(OBJDIR)/leaf_.c \
179180
$(OBJDIR)/login_.c \
181
+ $(OBJDIR)/lookslike_.c \
180182
$(OBJDIR)/main_.c \
181183
$(OBJDIR)/manifest_.c \
182184
$(OBJDIR)/markdown_.c \
183185
$(OBJDIR)/markdown_html_.c \
184186
$(OBJDIR)/md5_.c \
@@ -283,10 +285,11 @@
283285
$(OBJDIR)/json_timeline.o \
284286
$(OBJDIR)/json_user.o \
285287
$(OBJDIR)/json_wiki.o \
286288
$(OBJDIR)/leaf.o \
287289
$(OBJDIR)/login.o \
290
+ $(OBJDIR)/lookslike.o \
288291
$(OBJDIR)/main.o \
289292
$(OBJDIR)/manifest.o \
290293
$(OBJDIR)/markdown.o \
291294
$(OBJDIR)/markdown_html.o \
292295
$(OBJDIR)/md5.o \
@@ -402,11 +405,11 @@
402405
403406
404407
$(OBJDIR)/page_index.h: $(TRANS_SRC) $(OBJDIR)/mkindex
405408
$(OBJDIR)/mkindex $(TRANS_SRC) >$@
406409
$(OBJDIR)/headers: $(OBJDIR)/page_index.h $(OBJDIR)/makeheaders $(OBJDIR)/VERSION.h
407
- $(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)/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)/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
410
+ $(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)/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
408411
touch $(OBJDIR)/headers
409412
$(OBJDIR)/headers: Makefile
410413
$(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
411414
Makefile:
412415
$(OBJDIR)/add_.c: $(SRCDIR)/add.c $(OBJDIR)/translate
@@ -792,10 +795,17 @@
792795
793796
$(OBJDIR)/login.o: $(OBJDIR)/login_.c $(OBJDIR)/login.h $(SRCDIR)/config.h
794797
$(XTCC) -o $(OBJDIR)/login.o -c $(OBJDIR)/login_.c
795798
796799
$(OBJDIR)/login.h: $(OBJDIR)/headers
800
+$(OBJDIR)/lookslike_.c: $(SRCDIR)/lookslike.c $(OBJDIR)/translate
801
+ $(OBJDIR)/translate $(SRCDIR)/lookslike.c >$(OBJDIR)/lookslike_.c
802
+
803
+$(OBJDIR)/lookslike.o: $(OBJDIR)/lookslike_.c $(OBJDIR)/lookslike.h $(SRCDIR)/config.h
804
+ $(XTCC) -o $(OBJDIR)/lookslike.o -c $(OBJDIR)/lookslike_.c
805
+
806
+$(OBJDIR)/lookslike.h: $(OBJDIR)/headers
797807
$(OBJDIR)/main_.c: $(SRCDIR)/main.c $(OBJDIR)/translate
798808
$(OBJDIR)/translate $(SRCDIR)/main.c >$(OBJDIR)/main_.c
799809
800810
$(OBJDIR)/main.o: $(OBJDIR)/main_.c $(OBJDIR)/main.h $(OBJDIR)/page_index.h $(SRCDIR)/config.h
801811
$(XTCC) -o $(OBJDIR)/main.o -c $(OBJDIR)/main_.c
@@ -1153,11 +1163,11 @@
11531163
$(OBJDIR)/zip.h: $(OBJDIR)/headers
11541164
$(OBJDIR)/sqlite3.o: $(SRCDIR)/sqlite3.c
11551165
$(XTCC) -DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_STAT3 -Dlocaltime=fossil_localtime -DSQLITE_ENABLE_LOCKING_STYLE=0 -c $(SRCDIR)/sqlite3.c -o $(OBJDIR)/sqlite3.o
11561166
11571167
$(OBJDIR)/shell.o: $(SRCDIR)/shell.c $(SRCDIR)/sqlite3.h
1158
- $(XTCC) -Dmain=sqlite3_shell -DSQLITE_OMIT_LOAD_EXTENSION=1 -c $(SRCDIR)/shell.c -o $(OBJDIR)/shell.o
1168
+ $(XTCC) -Dmain=sqlite3_shell -DSQLITE_OMIT_LOAD_EXTENSION=1 -Dsqlite3_strglob=strglob -c $(SRCDIR)/shell.c -o $(OBJDIR)/shell.o
11591169
11601170
$(OBJDIR)/th.o: $(SRCDIR)/th.c
11611171
$(XTCC) -c $(SRCDIR)/th.c -o $(OBJDIR)/th.o
11621172
11631173
$(OBJDIR)/th_lang.o: $(SRCDIR)/th_lang.c
11641174
--- src/main.mk
+++ src/main.mk
@@ -67,10 +67,11 @@
67 $(SRCDIR)/json_timeline.c \
68 $(SRCDIR)/json_user.c \
69 $(SRCDIR)/json_wiki.c \
70 $(SRCDIR)/leaf.c \
71 $(SRCDIR)/login.c \
 
72 $(SRCDIR)/main.c \
73 $(SRCDIR)/manifest.c \
74 $(SRCDIR)/markdown.c \
75 $(SRCDIR)/markdown_html.c \
76 $(SRCDIR)/md5.c \
@@ -175,10 +176,11 @@
175 $(OBJDIR)/json_timeline_.c \
176 $(OBJDIR)/json_user_.c \
177 $(OBJDIR)/json_wiki_.c \
178 $(OBJDIR)/leaf_.c \
179 $(OBJDIR)/login_.c \
 
180 $(OBJDIR)/main_.c \
181 $(OBJDIR)/manifest_.c \
182 $(OBJDIR)/markdown_.c \
183 $(OBJDIR)/markdown_html_.c \
184 $(OBJDIR)/md5_.c \
@@ -283,10 +285,11 @@
283 $(OBJDIR)/json_timeline.o \
284 $(OBJDIR)/json_user.o \
285 $(OBJDIR)/json_wiki.o \
286 $(OBJDIR)/leaf.o \
287 $(OBJDIR)/login.o \
 
288 $(OBJDIR)/main.o \
289 $(OBJDIR)/manifest.o \
290 $(OBJDIR)/markdown.o \
291 $(OBJDIR)/markdown_html.o \
292 $(OBJDIR)/md5.o \
@@ -402,11 +405,11 @@
402
403
404 $(OBJDIR)/page_index.h: $(TRANS_SRC) $(OBJDIR)/mkindex
405 $(OBJDIR)/mkindex $(TRANS_SRC) >$@
406 $(OBJDIR)/headers: $(OBJDIR)/page_index.h $(OBJDIR)/makeheaders $(OBJDIR)/VERSION.h
407 $(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)/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)/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
408 touch $(OBJDIR)/headers
409 $(OBJDIR)/headers: Makefile
410 $(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
411 Makefile:
412 $(OBJDIR)/add_.c: $(SRCDIR)/add.c $(OBJDIR)/translate
@@ -792,10 +795,17 @@
792
793 $(OBJDIR)/login.o: $(OBJDIR)/login_.c $(OBJDIR)/login.h $(SRCDIR)/config.h
794 $(XTCC) -o $(OBJDIR)/login.o -c $(OBJDIR)/login_.c
795
796 $(OBJDIR)/login.h: $(OBJDIR)/headers
 
 
 
 
 
 
 
797 $(OBJDIR)/main_.c: $(SRCDIR)/main.c $(OBJDIR)/translate
798 $(OBJDIR)/translate $(SRCDIR)/main.c >$(OBJDIR)/main_.c
799
800 $(OBJDIR)/main.o: $(OBJDIR)/main_.c $(OBJDIR)/main.h $(OBJDIR)/page_index.h $(SRCDIR)/config.h
801 $(XTCC) -o $(OBJDIR)/main.o -c $(OBJDIR)/main_.c
@@ -1153,11 +1163,11 @@
1153 $(OBJDIR)/zip.h: $(OBJDIR)/headers
1154 $(OBJDIR)/sqlite3.o: $(SRCDIR)/sqlite3.c
1155 $(XTCC) -DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_STAT3 -Dlocaltime=fossil_localtime -DSQLITE_ENABLE_LOCKING_STYLE=0 -c $(SRCDIR)/sqlite3.c -o $(OBJDIR)/sqlite3.o
1156
1157 $(OBJDIR)/shell.o: $(SRCDIR)/shell.c $(SRCDIR)/sqlite3.h
1158 $(XTCC) -Dmain=sqlite3_shell -DSQLITE_OMIT_LOAD_EXTENSION=1 -c $(SRCDIR)/shell.c -o $(OBJDIR)/shell.o
1159
1160 $(OBJDIR)/th.o: $(SRCDIR)/th.c
1161 $(XTCC) -c $(SRCDIR)/th.c -o $(OBJDIR)/th.o
1162
1163 $(OBJDIR)/th_lang.o: $(SRCDIR)/th_lang.c
1164
--- src/main.mk
+++ src/main.mk
@@ -67,10 +67,11 @@
67 $(SRCDIR)/json_timeline.c \
68 $(SRCDIR)/json_user.c \
69 $(SRCDIR)/json_wiki.c \
70 $(SRCDIR)/leaf.c \
71 $(SRCDIR)/login.c \
72 $(SRCDIR)/lookslike.c \
73 $(SRCDIR)/main.c \
74 $(SRCDIR)/manifest.c \
75 $(SRCDIR)/markdown.c \
76 $(SRCDIR)/markdown_html.c \
77 $(SRCDIR)/md5.c \
@@ -175,10 +176,11 @@
176 $(OBJDIR)/json_timeline_.c \
177 $(OBJDIR)/json_user_.c \
178 $(OBJDIR)/json_wiki_.c \
179 $(OBJDIR)/leaf_.c \
180 $(OBJDIR)/login_.c \
181 $(OBJDIR)/lookslike_.c \
182 $(OBJDIR)/main_.c \
183 $(OBJDIR)/manifest_.c \
184 $(OBJDIR)/markdown_.c \
185 $(OBJDIR)/markdown_html_.c \
186 $(OBJDIR)/md5_.c \
@@ -283,10 +285,11 @@
285 $(OBJDIR)/json_timeline.o \
286 $(OBJDIR)/json_user.o \
287 $(OBJDIR)/json_wiki.o \
288 $(OBJDIR)/leaf.o \
289 $(OBJDIR)/login.o \
290 $(OBJDIR)/lookslike.o \
291 $(OBJDIR)/main.o \
292 $(OBJDIR)/manifest.o \
293 $(OBJDIR)/markdown.o \
294 $(OBJDIR)/markdown_html.o \
295 $(OBJDIR)/md5.o \
@@ -402,11 +405,11 @@
405
406
407 $(OBJDIR)/page_index.h: $(TRANS_SRC) $(OBJDIR)/mkindex
408 $(OBJDIR)/mkindex $(TRANS_SRC) >$@
409 $(OBJDIR)/headers: $(OBJDIR)/page_index.h $(OBJDIR)/makeheaders $(OBJDIR)/VERSION.h
410 $(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)/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
411 touch $(OBJDIR)/headers
412 $(OBJDIR)/headers: Makefile
413 $(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
414 Makefile:
415 $(OBJDIR)/add_.c: $(SRCDIR)/add.c $(OBJDIR)/translate
@@ -792,10 +795,17 @@
795
796 $(OBJDIR)/login.o: $(OBJDIR)/login_.c $(OBJDIR)/login.h $(SRCDIR)/config.h
797 $(XTCC) -o $(OBJDIR)/login.o -c $(OBJDIR)/login_.c
798
799 $(OBJDIR)/login.h: $(OBJDIR)/headers
800 $(OBJDIR)/lookslike_.c: $(SRCDIR)/lookslike.c $(OBJDIR)/translate
801 $(OBJDIR)/translate $(SRCDIR)/lookslike.c >$(OBJDIR)/lookslike_.c
802
803 $(OBJDIR)/lookslike.o: $(OBJDIR)/lookslike_.c $(OBJDIR)/lookslike.h $(SRCDIR)/config.h
804 $(XTCC) -o $(OBJDIR)/lookslike.o -c $(OBJDIR)/lookslike_.c
805
806 $(OBJDIR)/lookslike.h: $(OBJDIR)/headers
807 $(OBJDIR)/main_.c: $(SRCDIR)/main.c $(OBJDIR)/translate
808 $(OBJDIR)/translate $(SRCDIR)/main.c >$(OBJDIR)/main_.c
809
810 $(OBJDIR)/main.o: $(OBJDIR)/main_.c $(OBJDIR)/main.h $(OBJDIR)/page_index.h $(SRCDIR)/config.h
811 $(XTCC) -o $(OBJDIR)/main.o -c $(OBJDIR)/main_.c
@@ -1153,11 +1163,11 @@
1163 $(OBJDIR)/zip.h: $(OBJDIR)/headers
1164 $(OBJDIR)/sqlite3.o: $(SRCDIR)/sqlite3.c
1165 $(XTCC) -DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_STAT3 -Dlocaltime=fossil_localtime -DSQLITE_ENABLE_LOCKING_STYLE=0 -c $(SRCDIR)/sqlite3.c -o $(OBJDIR)/sqlite3.o
1166
1167 $(OBJDIR)/shell.o: $(SRCDIR)/shell.c $(SRCDIR)/sqlite3.h
1168 $(XTCC) -Dmain=sqlite3_shell -DSQLITE_OMIT_LOAD_EXTENSION=1 -Dsqlite3_strglob=strglob -c $(SRCDIR)/shell.c -o $(OBJDIR)/shell.o
1169
1170 $(OBJDIR)/th.o: $(SRCDIR)/th.c
1171 $(XTCC) -c $(SRCDIR)/th.c -o $(OBJDIR)/th.o
1172
1173 $(OBJDIR)/th_lang.o: $(SRCDIR)/th_lang.c
1174
--- src/makemake.tcl
+++ src/makemake.tcl
@@ -70,10 +70,11 @@
7070
json_timeline
7171
json_user
7272
json_wiki
7373
leaf
7474
login
75
+ lookslike
7576
main
7677
manifest
7778
markdown
7879
markdown_html
7980
md5
@@ -296,10 +297,11 @@
296297
writeln "\t\$(XTCC) $opt -c \$(SRCDIR)/sqlite3.c -o \$(OBJDIR)/sqlite3.o\n"
297298
298299
writeln "\$(OBJDIR)/shell.o:\t\$(SRCDIR)/shell.c \$(SRCDIR)/sqlite3.h"
299300
set opt {-Dmain=sqlite3_shell}
300301
append opt " -DSQLITE_OMIT_LOAD_EXTENSION=1"
302
+append opt " -Dsqlite3_strglob=strglob"
301303
writeln "\t\$(XTCC) $opt -c \$(SRCDIR)/shell.c -o \$(OBJDIR)/shell.o\n"
302304
303305
writeln "\$(OBJDIR)/th.o:\t\$(SRCDIR)/th.c"
304306
writeln "\t\$(XTCC) -c \$(SRCDIR)/th.c -o \$(OBJDIR)/th.o\n"
305307
306308
--- src/makemake.tcl
+++ src/makemake.tcl
@@ -70,10 +70,11 @@
70 json_timeline
71 json_user
72 json_wiki
73 leaf
74 login
 
75 main
76 manifest
77 markdown
78 markdown_html
79 md5
@@ -296,10 +297,11 @@
296 writeln "\t\$(XTCC) $opt -c \$(SRCDIR)/sqlite3.c -o \$(OBJDIR)/sqlite3.o\n"
297
298 writeln "\$(OBJDIR)/shell.o:\t\$(SRCDIR)/shell.c \$(SRCDIR)/sqlite3.h"
299 set opt {-Dmain=sqlite3_shell}
300 append opt " -DSQLITE_OMIT_LOAD_EXTENSION=1"
 
301 writeln "\t\$(XTCC) $opt -c \$(SRCDIR)/shell.c -o \$(OBJDIR)/shell.o\n"
302
303 writeln "\$(OBJDIR)/th.o:\t\$(SRCDIR)/th.c"
304 writeln "\t\$(XTCC) -c \$(SRCDIR)/th.c -o \$(OBJDIR)/th.o\n"
305
306
--- src/makemake.tcl
+++ src/makemake.tcl
@@ -70,10 +70,11 @@
70 json_timeline
71 json_user
72 json_wiki
73 leaf
74 login
75 lookslike
76 main
77 manifest
78 markdown
79 markdown_html
80 md5
@@ -296,10 +297,11 @@
297 writeln "\t\$(XTCC) $opt -c \$(SRCDIR)/sqlite3.c -o \$(OBJDIR)/sqlite3.o\n"
298
299 writeln "\$(OBJDIR)/shell.o:\t\$(SRCDIR)/shell.c \$(SRCDIR)/sqlite3.h"
300 set opt {-Dmain=sqlite3_shell}
301 append opt " -DSQLITE_OMIT_LOAD_EXTENSION=1"
302 append opt " -Dsqlite3_strglob=strglob"
303 writeln "\t\$(XTCC) $opt -c \$(SRCDIR)/shell.c -o \$(OBJDIR)/shell.o\n"
304
305 writeln "\$(OBJDIR)/th.o:\t\$(SRCDIR)/th.c"
306 writeln "\t\$(XTCC) -c \$(SRCDIR)/th.c -o \$(OBJDIR)/th.o\n"
307
308
+23 -4
--- src/merge3.c
+++ src/merge3.c
@@ -340,16 +340,35 @@
340340
blob_reset(&file);
341341
return rc;
342342
}
343343
344344
/*
345
-** COMMAND: test-3-way-merge
345
+** COMMAND: 3-way-merge*
346
+**
347
+** Usage: %fossil 3-way-merge BASELINE V1 V2 MERGED
348
+**
349
+** Inputs are files BASELINE, V1, and V2. The file MERGED is generated
350
+** as output.
351
+**
352
+** BASELINE is a common ancestor of two files V1 and V2 that have diverging
353
+** edits. The generated output file MERGED is the combination of all
354
+** changes in both V1 and V2.
355
+**
356
+** This command has no effect on the Fossil repository. It is a utility
357
+** command made available for the convenience of users. This command can
358
+** be used, for example, to help import changes from an upstream project.
346359
**
347
-** Usage: %fossil test-3-way-merge PIVOT V1 V2 MERGED
360
+** Suppose an upstream project has a file named "Xup.c" which is imported
361
+** with modifications to the local project as "Xlocal.c". Suppose further
362
+** that the "Xbase.c" is an exact copy of the last imported "Xup.c".
363
+** Then to import the latest "Xup.c" while preserving all the local changes:
348364
**
349
-** Combine change in going from PIVOT->VERSION1 with the change going
350
-** from PIVOT->VERSION2 and write the combined changes into MERGED.
365
+** fossil 3-way-merge Xbase.c Xlocal.c Xup.c Xlocal.c
366
+** cp Xup.c Xbase.c
367
+** # Verify that everything still works
368
+** fossil commit
369
+**
351370
*/
352371
void delta_3waymerge_cmd(void){
353372
Blob pivot, v1, v2, merged;
354373
if( g.argc!=6 ){
355374
usage("PIVOT V1 V2 MERGED");
356375
--- src/merge3.c
+++ src/merge3.c
@@ -340,16 +340,35 @@
340 blob_reset(&file);
341 return rc;
342 }
343
344 /*
345 ** COMMAND: test-3-way-merge
 
 
 
 
 
 
 
 
 
 
 
 
 
346 **
347 ** Usage: %fossil test-3-way-merge PIVOT V1 V2 MERGED
 
 
 
348 **
349 ** Combine change in going from PIVOT->VERSION1 with the change going
350 ** from PIVOT->VERSION2 and write the combined changes into MERGED.
 
 
 
351 */
352 void delta_3waymerge_cmd(void){
353 Blob pivot, v1, v2, merged;
354 if( g.argc!=6 ){
355 usage("PIVOT V1 V2 MERGED");
356
--- src/merge3.c
+++ src/merge3.c
@@ -340,16 +340,35 @@
340 blob_reset(&file);
341 return rc;
342 }
343
344 /*
345 ** COMMAND: 3-way-merge*
346 **
347 ** Usage: %fossil 3-way-merge BASELINE V1 V2 MERGED
348 **
349 ** Inputs are files BASELINE, V1, and V2. The file MERGED is generated
350 ** as output.
351 **
352 ** BASELINE is a common ancestor of two files V1 and V2 that have diverging
353 ** edits. The generated output file MERGED is the combination of all
354 ** changes in both V1 and V2.
355 **
356 ** This command has no effect on the Fossil repository. It is a utility
357 ** command made available for the convenience of users. This command can
358 ** be used, for example, to help import changes from an upstream project.
359 **
360 ** Suppose an upstream project has a file named "Xup.c" which is imported
361 ** with modifications to the local project as "Xlocal.c". Suppose further
362 ** that the "Xbase.c" is an exact copy of the last imported "Xup.c".
363 ** Then to import the latest "Xup.c" while preserving all the local changes:
364 **
365 ** fossil 3-way-merge Xbase.c Xlocal.c Xup.c Xlocal.c
366 ** cp Xup.c Xbase.c
367 ** # Verify that everything still works
368 ** fossil commit
369 **
370 */
371 void delta_3waymerge_cmd(void){
372 Blob pivot, v1, v2, merged;
373 if( g.argc!=6 ){
374 usage("PIVOT V1 V2 MERGED");
375
+29 -7
--- src/search.c
+++ src/search.c
@@ -166,20 +166,35 @@
166166
167167
/*
168168
** Testing the search function.
169169
**
170170
** COMMAND: search*
171
-** %fossil search pattern...
171
+** %fossil search [-all|-a] [-limit|-n #] pattern...
172
+**
173
+** Search for timeline entries matching all words
174
+** provided on the command line. Whole-word matches
175
+** scope more highly than partial matches.
172176
**
173
-** Search for timeline entries matching the pattern.
177
+** Outputs, by default, some top-N fraction of the
178
+** results. The -all option can be used to output
179
+** all matches, regardless of their search score.
180
+** -limit can be used to limit the number of entries
181
+** returned.
174182
*/
175183
void search_cmd(void){
176184
Search *p;
177185
Blob pattern;
178186
int i;
187
+ Blob sql = empty_blob;
179188
Stmt q;
180189
int iBest;
190
+ char fAll = NULL != find_option("all", "a", 0); /* If set, do not lop
191
+ off the end of the
192
+ results. */
193
+ char const * zLimit = find_option("limit","n",1);
194
+ int const nLimit = zLimit ? atoi(zLimit) : -1; /* Max number of entries
195
+ to list */
181196
182197
db_must_be_within_tree();
183198
if( g.argc<2 ) return;
184199
blob_init(&pattern, g.argv[2], -1);
185200
for(i=3; i<g.argc; i++){
@@ -198,13 +213,20 @@
198213
" score(coalesce(ecomment,comment)) AS y"
199214
" FROM event, blob"
200215
" WHERE blob.rid=event.objid AND y>0;"
201216
);
202217
iBest = db_int(0, "SELECT max(x) FROM srch");
203
- db_prepare(&q,
204
- "SELECT rid, uuid, date, comment, 0, 0 FROM srch"
205
- " WHERE x>%d ORDER BY x DESC, date DESC",
206
- iBest/3
207
- );
218
+ blob_append(&sql,
219
+ "SELECT rid, uuid, date, comment, 0, 0 FROM srch "
220
+ "WHERE 1 ", -1);
221
+ if(!fAll){
222
+ blob_appendf(&sql,"AND x>%d ", iBest/3);
223
+ }
224
+ blob_append(&sql, "ORDER BY x DESC, date DESC ", -1);
225
+ if(nLimit>0){
226
+ blob_appendf(&sql, "LIMIT %d", nLimit);
227
+ }
228
+ db_prepare(&q, blob_str(&sql));
229
+ blob_reset(&sql);
208230
print_timeline(&q, 1000, 0);
209231
db_finalize(&q);
210232
}
211233
--- src/search.c
+++ src/search.c
@@ -166,20 +166,35 @@
166
167 /*
168 ** Testing the search function.
169 **
170 ** COMMAND: search*
171 ** %fossil search pattern...
 
 
 
 
172 **
173 ** Search for timeline entries matching the pattern.
 
 
 
 
174 */
175 void search_cmd(void){
176 Search *p;
177 Blob pattern;
178 int i;
 
179 Stmt q;
180 int iBest;
 
 
 
 
 
 
181
182 db_must_be_within_tree();
183 if( g.argc<2 ) return;
184 blob_init(&pattern, g.argv[2], -1);
185 for(i=3; i<g.argc; i++){
@@ -198,13 +213,20 @@
198 " score(coalesce(ecomment,comment)) AS y"
199 " FROM event, blob"
200 " WHERE blob.rid=event.objid AND y>0;"
201 );
202 iBest = db_int(0, "SELECT max(x) FROM srch");
203 db_prepare(&q,
204 "SELECT rid, uuid, date, comment, 0, 0 FROM srch"
205 " WHERE x>%d ORDER BY x DESC, date DESC",
206 iBest/3
207 );
 
 
 
 
 
 
 
208 print_timeline(&q, 1000, 0);
209 db_finalize(&q);
210 }
211
--- src/search.c
+++ src/search.c
@@ -166,20 +166,35 @@
166
167 /*
168 ** Testing the search function.
169 **
170 ** COMMAND: search*
171 ** %fossil search [-all|-a] [-limit|-n #] pattern...
172 **
173 ** Search for timeline entries matching all words
174 ** provided on the command line. Whole-word matches
175 ** scope more highly than partial matches.
176 **
177 ** Outputs, by default, some top-N fraction of the
178 ** results. The -all option can be used to output
179 ** all matches, regardless of their search score.
180 ** -limit can be used to limit the number of entries
181 ** returned.
182 */
183 void search_cmd(void){
184 Search *p;
185 Blob pattern;
186 int i;
187 Blob sql = empty_blob;
188 Stmt q;
189 int iBest;
190 char fAll = NULL != find_option("all", "a", 0); /* If set, do not lop
191 off the end of the
192 results. */
193 char const * zLimit = find_option("limit","n",1);
194 int const nLimit = zLimit ? atoi(zLimit) : -1; /* Max number of entries
195 to list */
196
197 db_must_be_within_tree();
198 if( g.argc<2 ) return;
199 blob_init(&pattern, g.argv[2], -1);
200 for(i=3; i<g.argc; i++){
@@ -198,13 +213,20 @@
213 " score(coalesce(ecomment,comment)) AS y"
214 " FROM event, blob"
215 " WHERE blob.rid=event.objid AND y>0;"
216 );
217 iBest = db_int(0, "SELECT max(x) FROM srch");
218 blob_append(&sql,
219 "SELECT rid, uuid, date, comment, 0, 0 FROM srch "
220 "WHERE 1 ", -1);
221 if(!fAll){
222 blob_appendf(&sql,"AND x>%d ", iBest/3);
223 }
224 blob_append(&sql, "ORDER BY x DESC, date DESC ", -1);
225 if(nLimit>0){
226 blob_appendf(&sql, "LIMIT %d", nLimit);
227 }
228 db_prepare(&q, blob_str(&sql));
229 blob_reset(&sql);
230 print_timeline(&q, 1000, 0);
231 db_finalize(&q);
232 }
233
+29 -29
--- src/setup.c
+++ src/setup.c
@@ -197,62 +197,62 @@
197197
@ </td><td class="usetupColumnLayout">
198198
@ <span class="note">Notes:</span>
199199
@ <ol>
200200
@ <li><p>The permission flags are as follows:</p>
201201
@ <table>
202
- @ <tr><td valign="top"><b>a</b></td>
202
+ @ <tr><th valign="top">a</th>
203203
@ <td><i>Admin:</i> Create and delete users</td></tr>
204
- @ <tr><td valign="top"><b>b</b></td>
204
+ @ <tr><th valign="top">b</th>
205205
@ <td><i>Attach:</i> Add attachments to wiki or tickets</td></tr>
206
- @ <tr><td valign="top"><b>c</b></td>
206
+ @ <tr><th valign="top">c</th>
207207
@ <td><i>Append-Tkt:</i> Append to tickets</td></tr>
208
- @ <tr><td valign="top"><b>d</b></td>
208
+ @ <tr><th valign="top">d</th>
209209
@ <td><i>Delete:</i> Delete wiki and tickets</td></tr>
210
- @ <tr><td valign="top"><b>e</b></td>
210
+ @ <tr><th valign="top">e</th>
211211
@ <td><i>Email:</i> View sensitive data such as EMail addresses</td></tr>
212
- @ <tr><td valign="top"><b>f</b></td>
212
+ @ <tr><th valign="top">f</th>
213213
@ <td><i>New-Wiki:</i> Create new wiki pages</td></tr>
214
- @ <tr><td valign="top"><b>g</b></td>
214
+ @ <tr><th valign="top">g</th>
215215
@ <td><i>Clone:</i> Clone the repository</td></tr>
216
- @ <tr><td valign="top"><b>h</b></td>
216
+ @ <tr><th valign="top">h</th>
217217
@ <td><i>Hyperlinks:</i> Show hyperlinks to detailed
218218
@ repository history</td></tr>
219
- @ <tr><td valign="top"><b>i</b></td>
219
+ @ <tr><th valign="top">i</th>
220220
@ <td><i>Check-In:</i> Commit new versions in the repository</td></tr>
221
- @ <tr><td valign="top"><b>j</b></td>
221
+ @ <tr><th valign="top">j</th>
222222
@ <td><i>Read-Wiki:</i> View wiki pages</td></tr>
223
- @ <tr><td valign="top"><b>k</b></td>
223
+ @ <tr><th valign="top">k</th>
224224
@ <td><i>Write-Wiki:</i> Edit wiki pages</td></tr>
225
- @ <tr><td valign="top"><b>l</b></td>
225
+ @ <tr><th valign="top">l</th>
226226
@ <td><i>Mod-Wiki:</i> Moderator for wiki pages</td></tr>
227
- @ <tr><td valign="top"><b>m</b></td>
227
+ @ <tr><th valign="top">m</th>
228228
@ <td><i>Append-Wiki:</i> Append to wiki pages</td></tr>
229
- @ <tr><td valign="top"><b>n</b></td>
229
+ @ <tr><th valign="top">n</th>
230230
@ <td><i>New-Tkt:</i> Create new tickets</td></tr>
231
- @ <tr><td valign="top"><b>o</b></td>
231
+ @ <tr><th valign="top">o</th>
232232
@ <td><i>Check-Out:</i> Check out versions</td></tr>
233
- @ <tr><td valign="top"><b>p</b></td>
233
+ @ <tr><th valign="top">p</th>
234234
@ <td><i>Password:</i> Change your own password</td></tr>
235
- @ <tr><td valign="top"><b>q</b></td>
235
+ @ <tr><th valign="top">q</th>
236236
@ <td><i>Mod-Tkt:</i> Moderator for tickets</td></tr>
237
- @ <tr><td valign="top"><b>r</b></td>
237
+ @ <tr><th valign="top">r</th>
238238
@ <td><i>Read-Tkt:</i> View tickets</td></tr>
239
- @ <tr><td valign="top"><b>s</b></td>
239
+ @ <tr><th valign="top">s</th>
240240
@ <td><i>Setup/Super-user:</i> Setup and configure this website</td></tr>
241
- @ <tr><td valign="top"><b>t</b></td>
241
+ @ <tr><th valign="top">t</th>
242242
@ <td><i>Tkt-Report:</i> Create new bug summary reports</td></tr>
243
- @ <tr><td valign="top"><b>u</b></td>
243
+ @ <tr><th valign="top">u</th>
244244
@ <td><i>Reader:</i> Inherit privileges of
245245
@ user <tt>reader</tt></td></tr>
246
- @ <tr><td valign="top"><b>v</b></td>
246
+ @ <tr><th valign="top">v</th>
247247
@ <td><i>Developer:</i> Inherit privileges of
248248
@ user <tt>developer</tt></td></tr>
249
- @ <tr><td valign="top"><b>w</b></td>
249
+ @ <tr><th valign="top">w</th>
250250
@ <td><i>Write-Tkt:</i> Edit tickets</td></tr>
251
- @ <tr><td valign="top"><b>x</b></td>
251
+ @ <tr><th valign="top">x</th>
252252
@ <td><i>Private:</i> Push and/or pull private branches</td></tr>
253
- @ <tr><td valign="top"><b>z</b></td>
253
+ @ <tr><th valign="top">z</th>
254254
@ <td><i>Zip download:</i> Download a baseline via the
255255
@ <tt>/zip</tt> URL even without
256256
@ check<span class="capability">o</span>ut
257257
@ and <span class="capability">h</span>istory permissions</td></tr>
258258
@ </table>
@@ -1062,23 +1062,23 @@
10621062
@
10631063
@ <form action="%s(g.zTop)/setup_login_group" method="post"><div>
10641064
login_insert_csrf_secret();
10651065
@ <blockquote><table border="0">
10661066
@
1067
- @ <tr><td align="right"><b>Repository filename in group to join:</b></td>
1067
+ @ <tr><th align="right">Repository filename in group to join:</th>
10681068
@ <td width="5"></td><td>
10691069
@ <input type="text" size="50" value="%h(zRepo)" name="repo"></td></tr>
10701070
@
1071
- @ <tr><td align="right"><b>Login on the above repo:</b></td>
1071
+ @ <tr><th align="right">Login on the above repo:</th>
10721072
@ <td width="5"></td><td>
10731073
@ <input type="text" size="20" value="%h(zLogin)" name="login"></td></tr>
10741074
@
1075
- @ <tr><td align="right"><b>Password:</b></td>
1075
+ @ <tr><th align="right">Password:</th>
10761076
@ <td width="5"></td><td>
10771077
@ <input type="password" size="20" name="pw"></td></tr>
10781078
@
1079
- @ <tr><td align="right"><b>Name of login-group:</b></td>
1079
+ @ <tr><th align="right">Name of login-group:</th>
10801080
@ <td width="5"></td><td>
10811081
@ <input type="text" size="30" value="%h(zNewName)" name="newname">
10821082
@ (only used if creating a new login-group).</td></tr>
10831083
@
10841084
@ <tr><td colspan="3" align="center">
10851085
--- src/setup.c
+++ src/setup.c
@@ -197,62 +197,62 @@
197 @ </td><td class="usetupColumnLayout">
198 @ <span class="note">Notes:</span>
199 @ <ol>
200 @ <li><p>The permission flags are as follows:</p>
201 @ <table>
202 @ <tr><td valign="top"><b>a</b></td>
203 @ <td><i>Admin:</i> Create and delete users</td></tr>
204 @ <tr><td valign="top"><b>b</b></td>
205 @ <td><i>Attach:</i> Add attachments to wiki or tickets</td></tr>
206 @ <tr><td valign="top"><b>c</b></td>
207 @ <td><i>Append-Tkt:</i> Append to tickets</td></tr>
208 @ <tr><td valign="top"><b>d</b></td>
209 @ <td><i>Delete:</i> Delete wiki and tickets</td></tr>
210 @ <tr><td valign="top"><b>e</b></td>
211 @ <td><i>Email:</i> View sensitive data such as EMail addresses</td></tr>
212 @ <tr><td valign="top"><b>f</b></td>
213 @ <td><i>New-Wiki:</i> Create new wiki pages</td></tr>
214 @ <tr><td valign="top"><b>g</b></td>
215 @ <td><i>Clone:</i> Clone the repository</td></tr>
216 @ <tr><td valign="top"><b>h</b></td>
217 @ <td><i>Hyperlinks:</i> Show hyperlinks to detailed
218 @ repository history</td></tr>
219 @ <tr><td valign="top"><b>i</b></td>
220 @ <td><i>Check-In:</i> Commit new versions in the repository</td></tr>
221 @ <tr><td valign="top"><b>j</b></td>
222 @ <td><i>Read-Wiki:</i> View wiki pages</td></tr>
223 @ <tr><td valign="top"><b>k</b></td>
224 @ <td><i>Write-Wiki:</i> Edit wiki pages</td></tr>
225 @ <tr><td valign="top"><b>l</b></td>
226 @ <td><i>Mod-Wiki:</i> Moderator for wiki pages</td></tr>
227 @ <tr><td valign="top"><b>m</b></td>
228 @ <td><i>Append-Wiki:</i> Append to wiki pages</td></tr>
229 @ <tr><td valign="top"><b>n</b></td>
230 @ <td><i>New-Tkt:</i> Create new tickets</td></tr>
231 @ <tr><td valign="top"><b>o</b></td>
232 @ <td><i>Check-Out:</i> Check out versions</td></tr>
233 @ <tr><td valign="top"><b>p</b></td>
234 @ <td><i>Password:</i> Change your own password</td></tr>
235 @ <tr><td valign="top"><b>q</b></td>
236 @ <td><i>Mod-Tkt:</i> Moderator for tickets</td></tr>
237 @ <tr><td valign="top"><b>r</b></td>
238 @ <td><i>Read-Tkt:</i> View tickets</td></tr>
239 @ <tr><td valign="top"><b>s</b></td>
240 @ <td><i>Setup/Super-user:</i> Setup and configure this website</td></tr>
241 @ <tr><td valign="top"><b>t</b></td>
242 @ <td><i>Tkt-Report:</i> Create new bug summary reports</td></tr>
243 @ <tr><td valign="top"><b>u</b></td>
244 @ <td><i>Reader:</i> Inherit privileges of
245 @ user <tt>reader</tt></td></tr>
246 @ <tr><td valign="top"><b>v</b></td>
247 @ <td><i>Developer:</i> Inherit privileges of
248 @ user <tt>developer</tt></td></tr>
249 @ <tr><td valign="top"><b>w</b></td>
250 @ <td><i>Write-Tkt:</i> Edit tickets</td></tr>
251 @ <tr><td valign="top"><b>x</b></td>
252 @ <td><i>Private:</i> Push and/or pull private branches</td></tr>
253 @ <tr><td valign="top"><b>z</b></td>
254 @ <td><i>Zip download:</i> Download a baseline via the
255 @ <tt>/zip</tt> URL even without
256 @ check<span class="capability">o</span>ut
257 @ and <span class="capability">h</span>istory permissions</td></tr>
258 @ </table>
@@ -1062,23 +1062,23 @@
1062 @
1063 @ <form action="%s(g.zTop)/setup_login_group" method="post"><div>
1064 login_insert_csrf_secret();
1065 @ <blockquote><table border="0">
1066 @
1067 @ <tr><td align="right"><b>Repository filename in group to join:</b></td>
1068 @ <td width="5"></td><td>
1069 @ <input type="text" size="50" value="%h(zRepo)" name="repo"></td></tr>
1070 @
1071 @ <tr><td align="right"><b>Login on the above repo:</b></td>
1072 @ <td width="5"></td><td>
1073 @ <input type="text" size="20" value="%h(zLogin)" name="login"></td></tr>
1074 @
1075 @ <tr><td align="right"><b>Password:</b></td>
1076 @ <td width="5"></td><td>
1077 @ <input type="password" size="20" name="pw"></td></tr>
1078 @
1079 @ <tr><td align="right"><b>Name of login-group:</b></td>
1080 @ <td width="5"></td><td>
1081 @ <input type="text" size="30" value="%h(zNewName)" name="newname">
1082 @ (only used if creating a new login-group).</td></tr>
1083 @
1084 @ <tr><td colspan="3" align="center">
1085
--- src/setup.c
+++ src/setup.c
@@ -197,62 +197,62 @@
197 @ </td><td class="usetupColumnLayout">
198 @ <span class="note">Notes:</span>
199 @ <ol>
200 @ <li><p>The permission flags are as follows:</p>
201 @ <table>
202 @ <tr><th valign="top">a</th>
203 @ <td><i>Admin:</i> Create and delete users</td></tr>
204 @ <tr><th valign="top">b</th>
205 @ <td><i>Attach:</i> Add attachments to wiki or tickets</td></tr>
206 @ <tr><th valign="top">c</th>
207 @ <td><i>Append-Tkt:</i> Append to tickets</td></tr>
208 @ <tr><th valign="top">d</th>
209 @ <td><i>Delete:</i> Delete wiki and tickets</td></tr>
210 @ <tr><th valign="top">e</th>
211 @ <td><i>Email:</i> View sensitive data such as EMail addresses</td></tr>
212 @ <tr><th valign="top">f</th>
213 @ <td><i>New-Wiki:</i> Create new wiki pages</td></tr>
214 @ <tr><th valign="top">g</th>
215 @ <td><i>Clone:</i> Clone the repository</td></tr>
216 @ <tr><th valign="top">h</th>
217 @ <td><i>Hyperlinks:</i> Show hyperlinks to detailed
218 @ repository history</td></tr>
219 @ <tr><th valign="top">i</th>
220 @ <td><i>Check-In:</i> Commit new versions in the repository</td></tr>
221 @ <tr><th valign="top">j</th>
222 @ <td><i>Read-Wiki:</i> View wiki pages</td></tr>
223 @ <tr><th valign="top">k</th>
224 @ <td><i>Write-Wiki:</i> Edit wiki pages</td></tr>
225 @ <tr><th valign="top">l</th>
226 @ <td><i>Mod-Wiki:</i> Moderator for wiki pages</td></tr>
227 @ <tr><th valign="top">m</th>
228 @ <td><i>Append-Wiki:</i> Append to wiki pages</td></tr>
229 @ <tr><th valign="top">n</th>
230 @ <td><i>New-Tkt:</i> Create new tickets</td></tr>
231 @ <tr><th valign="top">o</th>
232 @ <td><i>Check-Out:</i> Check out versions</td></tr>
233 @ <tr><th valign="top">p</th>
234 @ <td><i>Password:</i> Change your own password</td></tr>
235 @ <tr><th valign="top">q</th>
236 @ <td><i>Mod-Tkt:</i> Moderator for tickets</td></tr>
237 @ <tr><th valign="top">r</th>
238 @ <td><i>Read-Tkt:</i> View tickets</td></tr>
239 @ <tr><th valign="top">s</th>
240 @ <td><i>Setup/Super-user:</i> Setup and configure this website</td></tr>
241 @ <tr><th valign="top">t</th>
242 @ <td><i>Tkt-Report:</i> Create new bug summary reports</td></tr>
243 @ <tr><th valign="top">u</th>
244 @ <td><i>Reader:</i> Inherit privileges of
245 @ user <tt>reader</tt></td></tr>
246 @ <tr><th valign="top">v</th>
247 @ <td><i>Developer:</i> Inherit privileges of
248 @ user <tt>developer</tt></td></tr>
249 @ <tr><th valign="top">w</th>
250 @ <td><i>Write-Tkt:</i> Edit tickets</td></tr>
251 @ <tr><th valign="top">x</th>
252 @ <td><i>Private:</i> Push and/or pull private branches</td></tr>
253 @ <tr><th valign="top">z</th>
254 @ <td><i>Zip download:</i> Download a baseline via the
255 @ <tt>/zip</tt> URL even without
256 @ check<span class="capability">o</span>ut
257 @ and <span class="capability">h</span>istory permissions</td></tr>
258 @ </table>
@@ -1062,23 +1062,23 @@
1062 @
1063 @ <form action="%s(g.zTop)/setup_login_group" method="post"><div>
1064 login_insert_csrf_secret();
1065 @ <blockquote><table border="0">
1066 @
1067 @ <tr><th align="right">Repository filename in group to join:</th>
1068 @ <td width="5"></td><td>
1069 @ <input type="text" size="50" value="%h(zRepo)" name="repo"></td></tr>
1070 @
1071 @ <tr><th align="right">Login on the above repo:</th>
1072 @ <td width="5"></td><td>
1073 @ <input type="text" size="20" value="%h(zLogin)" name="login"></td></tr>
1074 @
1075 @ <tr><th align="right">Password:</th>
1076 @ <td width="5"></td><td>
1077 @ <input type="password" size="20" name="pw"></td></tr>
1078 @
1079 @ <tr><th align="right">Name of login-group:</th>
1080 @ <td width="5"></td><td>
1081 @ <input type="text" size="30" value="%h(zNewName)" name="newname">
1082 @ (only used if creating a new login-group).</td></tr>
1083 @
1084 @ <tr><td colspan="3" align="center">
1085
+1 -3
--- src/shell.c
+++ src/shell.c
@@ -1719,11 +1719,10 @@
17191719
|| (c=='\n' && pc==cQuote)
17201720
|| (c=='\n' && pc=='\r' && p->n>2 && p->z[p->n-2]==cQuote)
17211721
|| (c==EOF && pc==cQuote)
17221722
){
17231723
do{ p->n--; }while( p->z[p->n]!=cQuote );
1724
- p->z[p->n] = 0;
17251724
p->cTerm = c;
17261725
break;
17271726
}
17281727
if( pc==cQuote && c!='\r' ){
17291728
fprintf(stderr, "%s:%d: unescaped %c character\n",
@@ -1730,11 +1729,10 @@
17301729
p->zFile, p->nLine, cQuote);
17311730
}
17321731
if( c==EOF ){
17331732
fprintf(stderr, "%s:%d: unterminated %c-quoted field\n",
17341733
p->zFile, startLine, cQuote);
1735
- p->z[p->n] = 0;
17361734
p->cTerm = EOF;
17371735
break;
17381736
}
17391737
csv_append_char(p, c);
17401738
pc = c;
@@ -1746,13 +1744,13 @@
17461744
}
17471745
if( c=='\n' ){
17481746
p->nLine++;
17491747
if( p->n>1 && p->z[p->n-1]=='\r' ) p->n--;
17501748
}
1751
- p->z[p->n] = 0;
17521749
p->cTerm = c;
17531750
}
1751
+ if( p->z ) p->z[p->n] = 0;
17541752
return p->z;
17551753
}
17561754
17571755
/*
17581756
** If an input line begins with "." then invoke this routine to
17591757
--- src/shell.c
+++ src/shell.c
@@ -1719,11 +1719,10 @@
1719 || (c=='\n' && pc==cQuote)
1720 || (c=='\n' && pc=='\r' && p->n>2 && p->z[p->n-2]==cQuote)
1721 || (c==EOF && pc==cQuote)
1722 ){
1723 do{ p->n--; }while( p->z[p->n]!=cQuote );
1724 p->z[p->n] = 0;
1725 p->cTerm = c;
1726 break;
1727 }
1728 if( pc==cQuote && c!='\r' ){
1729 fprintf(stderr, "%s:%d: unescaped %c character\n",
@@ -1730,11 +1729,10 @@
1730 p->zFile, p->nLine, cQuote);
1731 }
1732 if( c==EOF ){
1733 fprintf(stderr, "%s:%d: unterminated %c-quoted field\n",
1734 p->zFile, startLine, cQuote);
1735 p->z[p->n] = 0;
1736 p->cTerm = EOF;
1737 break;
1738 }
1739 csv_append_char(p, c);
1740 pc = c;
@@ -1746,13 +1744,13 @@
1746 }
1747 if( c=='\n' ){
1748 p->nLine++;
1749 if( p->n>1 && p->z[p->n-1]=='\r' ) p->n--;
1750 }
1751 p->z[p->n] = 0;
1752 p->cTerm = c;
1753 }
 
1754 return p->z;
1755 }
1756
1757 /*
1758 ** If an input line begins with "." then invoke this routine to
1759
--- src/shell.c
+++ src/shell.c
@@ -1719,11 +1719,10 @@
1719 || (c=='\n' && pc==cQuote)
1720 || (c=='\n' && pc=='\r' && p->n>2 && p->z[p->n-2]==cQuote)
1721 || (c==EOF && pc==cQuote)
1722 ){
1723 do{ p->n--; }while( p->z[p->n]!=cQuote );
 
1724 p->cTerm = c;
1725 break;
1726 }
1727 if( pc==cQuote && c!='\r' ){
1728 fprintf(stderr, "%s:%d: unescaped %c character\n",
@@ -1730,11 +1729,10 @@
1729 p->zFile, p->nLine, cQuote);
1730 }
1731 if( c==EOF ){
1732 fprintf(stderr, "%s:%d: unterminated %c-quoted field\n",
1733 p->zFile, startLine, cQuote);
 
1734 p->cTerm = EOF;
1735 break;
1736 }
1737 csv_append_char(p, c);
1738 pc = c;
@@ -1746,13 +1744,13 @@
1744 }
1745 if( c=='\n' ){
1746 p->nLine++;
1747 if( p->n>1 && p->z[p->n-1]=='\r' ) p->n--;
1748 }
 
1749 p->cTerm = c;
1750 }
1751 if( p->z ) p->z[p->n] = 0;
1752 return p->z;
1753 }
1754
1755 /*
1756 ** If an input line begins with "." then invoke this routine to
1757
+5 -5
--- src/shun.c
+++ src/shun.c
@@ -293,28 +293,28 @@
293293
" FROM rcvfrom LEFT JOIN user USING(uid)"
294294
" WHERE rcvid=%d",
295295
rcvid
296296
);
297297
@ <table cellspacing="15" cellpadding="0" border="0">
298
- @ <tr><td valign="top" align="right"><b>rcvid:</b></td>
298
+ @ <tr><th valign="top" align="right">rcvid:</th>
299299
@ <td valign="top">%d(rcvid)</td></tr>
300300
if( db_step(&q)==SQLITE_ROW ){
301301
const char *zUser = db_column_text(&q, 0);
302302
const char *zDate = db_column_text(&q, 1);
303303
const char *zIpAddr = db_column_text(&q, 2);
304
- @ <tr><td valign="top" align="right"><b>User:</b></td>
304
+ @ <tr><th valign="top" align="right">User:</th>
305305
@ <td valign="top">%s(zUser)</td></tr>
306
- @ <tr><td valign="top" align="right"><b>Date:</b></td>
306
+ @ <tr><th valign="top" align="right">Date:</th>
307307
@ <td valign="top">%s(zDate)</td></tr>
308
- @ <tr><td valign="top" align="right"><b>IP&nbsp;Address:</b></td>
308
+ @ <tr><th valign="top" align="right">IP&nbsp;Address:</th>
309309
@ <td valign="top">%s(zIpAddr)</td></tr>
310310
}
311311
db_finalize(&q);
312312
db_prepare(&q,
313313
"SELECT rid, uuid, size FROM blob WHERE rcvid=%d", rcvid
314314
);
315
- @ <tr><td valign="top" align="right"><b>Artifacts:</b></td>
315
+ @ <tr><th valign="top" align="right">Artifacts:</th>
316316
@ <td valign="top">
317317
while( db_step(&q)==SQLITE_ROW ){
318318
int rid = db_column_int(&q, 0);
319319
const char *zUuid = db_column_text(&q, 1);
320320
int size = db_column_int(&q, 2);
321321
--- src/shun.c
+++ src/shun.c
@@ -293,28 +293,28 @@
293 " FROM rcvfrom LEFT JOIN user USING(uid)"
294 " WHERE rcvid=%d",
295 rcvid
296 );
297 @ <table cellspacing="15" cellpadding="0" border="0">
298 @ <tr><td valign="top" align="right"><b>rcvid:</b></td>
299 @ <td valign="top">%d(rcvid)</td></tr>
300 if( db_step(&q)==SQLITE_ROW ){
301 const char *zUser = db_column_text(&q, 0);
302 const char *zDate = db_column_text(&q, 1);
303 const char *zIpAddr = db_column_text(&q, 2);
304 @ <tr><td valign="top" align="right"><b>User:</b></td>
305 @ <td valign="top">%s(zUser)</td></tr>
306 @ <tr><td valign="top" align="right"><b>Date:</b></td>
307 @ <td valign="top">%s(zDate)</td></tr>
308 @ <tr><td valign="top" align="right"><b>IP&nbsp;Address:</b></td>
309 @ <td valign="top">%s(zIpAddr)</td></tr>
310 }
311 db_finalize(&q);
312 db_prepare(&q,
313 "SELECT rid, uuid, size FROM blob WHERE rcvid=%d", rcvid
314 );
315 @ <tr><td valign="top" align="right"><b>Artifacts:</b></td>
316 @ <td valign="top">
317 while( db_step(&q)==SQLITE_ROW ){
318 int rid = db_column_int(&q, 0);
319 const char *zUuid = db_column_text(&q, 1);
320 int size = db_column_int(&q, 2);
321
--- src/shun.c
+++ src/shun.c
@@ -293,28 +293,28 @@
293 " FROM rcvfrom LEFT JOIN user USING(uid)"
294 " WHERE rcvid=%d",
295 rcvid
296 );
297 @ <table cellspacing="15" cellpadding="0" border="0">
298 @ <tr><th valign="top" align="right">rcvid:</th>
299 @ <td valign="top">%d(rcvid)</td></tr>
300 if( db_step(&q)==SQLITE_ROW ){
301 const char *zUser = db_column_text(&q, 0);
302 const char *zDate = db_column_text(&q, 1);
303 const char *zIpAddr = db_column_text(&q, 2);
304 @ <tr><th valign="top" align="right">User:</th>
305 @ <td valign="top">%s(zUser)</td></tr>
306 @ <tr><th valign="top" align="right">Date:</th>
307 @ <td valign="top">%s(zDate)</td></tr>
308 @ <tr><th valign="top" align="right">IP&nbsp;Address:</th>
309 @ <td valign="top">%s(zIpAddr)</td></tr>
310 }
311 db_finalize(&q);
312 db_prepare(&q,
313 "SELECT rid, uuid, size FROM blob WHERE rcvid=%d", rcvid
314 );
315 @ <tr><th valign="top" align="right">Artifacts:</th>
316 @ <td valign="top">
317 while( db_step(&q)==SQLITE_ROW ){
318 int rid = db_column_int(&q, 0);
319 const char *zUuid = db_column_text(&q, 1);
320 int size = db_column_int(&q, 2);
321
+320 -126
--- src/sqlite3.c
+++ src/sqlite3.c
@@ -670,11 +670,11 @@
670670
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
671671
** [sqlite_version()] and [sqlite_source_id()].
672672
*/
673673
#define SQLITE_VERSION "3.8.0"
674674
#define SQLITE_VERSION_NUMBER 3008000
675
-#define SQLITE_SOURCE_ID "2013-07-09 03:04:32 52a49cbc1621094b2fe2b021209b768d29e0426b"
675
+#define SQLITE_SOURCE_ID "2013-07-18 14:50:56 5dcffa671f592ae9355628afa439ae9a2d26f0cd"
676676
677677
/*
678678
** CAPI3REF: Run-Time Library Version Numbers
679679
** KEYWORDS: sqlite3_version, sqlite3_sourceid
680680
**
@@ -3120,11 +3120,11 @@
31203120
** [sqlite3_exec()], [sqlite3_step()] and [sqlite3_get_table()] for
31213121
** database connection D. An example use for this
31223122
** interface is to keep a GUI updated during a large query.
31233123
**
31243124
** ^The parameter P is passed through as the only parameter to the
3125
-** callback function X. ^The parameter N is the number of
3125
+** callback function X. ^The parameter N is the approximate number of
31263126
** [virtual machine instructions] that are evaluated between successive
31273127
** invocations of the callback X.
31283128
**
31293129
** ^Only a single progress handler may be defined at one time per
31303130
** [database connection]; setting a new progress handler cancels the
@@ -4745,12 +4745,12 @@
47454745
** CAPI3REF: Function Auxiliary Data
47464746
**
47474747
** The following two functions may be used by scalar SQL functions to
47484748
** associate metadata with argument values. If the same value is passed to
47494749
** multiple invocations of the same SQL function during query execution, under
4750
-** some circumstances the associated metadata may be preserved. This may
4751
-** be used, for example, to add a regular-expression matching scalar
4750
+** some circumstances the associated metadata may be preserved. This might
4751
+** be used, for example, in a regular-expression matching
47524752
** function. The compiled version of the regular expression is stored as
47534753
** metadata associated with the SQL value passed as the regular expression
47544754
** pattern. The compiled regular expression can be reused on multiple
47554755
** invocations of the same function so that the original pattern string
47564756
** does not need to be recompiled on each invocation.
@@ -4760,27 +4760,36 @@
47604760
** value to the application-defined function. ^If no metadata has been ever
47614761
** been set for the Nth argument of the function, or if the corresponding
47624762
** function parameter has changed since the meta-data was set,
47634763
** then sqlite3_get_auxdata() returns a NULL pointer.
47644764
**
4765
-** ^The sqlite3_set_auxdata() interface saves the metadata
4766
-** pointed to by its 3rd parameter as the metadata for the N-th
4767
-** argument of the application-defined function. Subsequent
4768
-** calls to sqlite3_get_auxdata() might return this data, if it has
4769
-** not been destroyed.
4770
-** ^If it is not NULL, SQLite will invoke the destructor
4771
-** function given by the 4th parameter to sqlite3_set_auxdata() on
4772
-** the metadata when the corresponding function parameter changes
4773
-** or when the SQL statement completes, whichever comes first.
4765
+** ^The sqlite3_set_auxdata(C,N,P,X) interface saves P as metadata for the N-th
4766
+** argument of the application-defined function. ^Subsequent
4767
+** calls to sqlite3_get_auxdata(C,N) return P from the most recent
4768
+** sqlite3_set_auxdata(C,N,P,X) call if the data has not been dropped, or
4769
+** NULL if the data has been dropped.
4770
+** ^(If it is not NULL, SQLite will invoke the destructor
4771
+** function X passed to sqlite3_set_auxdata(C,N,P,X) when <ul>
4772
+** <li> the corresponding function parameter changes,
4773
+** <li> [sqlite3_reset()] or [sqlite3_finalize()] is called for the
4774
+** SQL statement,
4775
+** <li> sqlite3_set_auxdata() is invoked again on the same parameter, or
4776
+** <li> a memory allocation error occurs. </ul>)^
47744777
**
47754778
** SQLite is free to call the destructor and drop metadata on any
47764779
** parameter of any function at any time. ^The only guarantee is that
4777
-** the destructor will be called before the metadata is dropped.
4780
+** the destructor will be called when the [prepared statement] is destroyed.
4781
+** Note in particular that the destructor X in the call to
4782
+** sqlite3_set_auxdata(C,N,P,X) might be called immediately, before
4783
+** the sqlite3_set_auxdata() call even returns. Hence sqlite3_set_auxdata()
4784
+** should be called near the end of the function implementation and the
4785
+** implementation should not make any use of P after sqlite3_set_auxdata()
4786
+** has been called.
47784787
**
47794788
** ^(In practice, metadata is preserved between function calls for
4780
-** expressions that are constant at compile time. This includes literal
4781
-** values and [parameters].)^
4789
+** function parameters that are compile-time constants, including literal
4790
+** values and [parameters] and expressions composed from the same.)^
47824791
**
47834792
** These routines must be called from the same thread in which
47844793
** the SQL function is running.
47854794
*/
47864795
SQLITE_API void *sqlite3_get_auxdata(sqlite3_context*, int N);
@@ -5689,14 +5698,27 @@
56895698
**
56905699
** ^Calling sqlite3_auto_extension(X) with an entry point X that is already
56915700
** on the list of automatic extensions is a harmless no-op. ^No entry point
56925701
** will be called more than once for each database connection that is opened.
56935702
**
5694
-** See also: [sqlite3_reset_auto_extension()].
5703
+** See also: [sqlite3_reset_auto_extension()]
5704
+** and [sqlite3_cancel_auto_extension()]
56955705
*/
56965706
SQLITE_API int sqlite3_auto_extension(void (*xEntryPoint)(void));
56975707
5708
+/*
5709
+** CAPI3REF: Cancel Automatic Extension Loading
5710
+**
5711
+** ^The [sqlite3_cancel_auto_extension(X)] interface unregisters the
5712
+** initialization routine X that was registered using a prior call to
5713
+** [sqlite3_auto_extension(X)]. ^The [sqlite3_cancel_auto_extension(X)]
5714
+** routine returns 1 if initialization routine X was successfully
5715
+** unregistered and it returns 0 if X was not on the list of initialization
5716
+** routines.
5717
+*/
5718
+SQLITE_API int sqlite3_cancel_auto_extension(void (*xEntryPoint)(void));
5719
+
56985720
/*
56995721
** CAPI3REF: Reset Automatic Extension Loading
57005722
**
57015723
** ^This interface disables all automatic extensions previously
57025724
** registered using [sqlite3_auto_extension()].
@@ -6805,10 +6827,16 @@
68056827
** transaction rollback or database recovery operations are not included.
68066828
** If an IO or other error occurs while writing a page to disk, the effect
68076829
** on subsequent SQLITE_DBSTATUS_CACHE_WRITE requests is undefined.)^ ^The
68086830
** highwater mark associated with SQLITE_DBSTATUS_CACHE_WRITE is always 0.
68096831
** </dd>
6832
+**
6833
+** [[SQLITE_DBSTATUS_DEFERRED_FKS]] ^(<dt>SQLITE_DBSTATUS_DEFERRED_FKS</dt>
6834
+** <dd>This parameter returns the zero for the current value if and only if
6835
+** there all foreign key constraints (deferred or immediate) have been
6836
+** resolved. The highwater mark is always 0.
6837
+** </dd>
68106838
** </dl>
68116839
*/
68126840
#define SQLITE_DBSTATUS_LOOKASIDE_USED 0
68136841
#define SQLITE_DBSTATUS_CACHE_USED 1
68146842
#define SQLITE_DBSTATUS_SCHEMA_USED 2
@@ -6817,11 +6845,12 @@
68176845
#define SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE 5
68186846
#define SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL 6
68196847
#define SQLITE_DBSTATUS_CACHE_HIT 7
68206848
#define SQLITE_DBSTATUS_CACHE_MISS 8
68216849
#define SQLITE_DBSTATUS_CACHE_WRITE 9
6822
-#define SQLITE_DBSTATUS_MAX 9 /* Largest defined DBSTATUS */
6850
+#define SQLITE_DBSTATUS_DEFERRED_FKS 10
6851
+#define SQLITE_DBSTATUS_MAX 10 /* Largest defined DBSTATUS */
68236852
68246853
68256854
/*
68266855
** CAPI3REF: Prepared Statement Status
68276856
**
@@ -10117,11 +10146,11 @@
1011710146
void *pAuthArg; /* 1st argument to the access auth function */
1011810147
#endif
1011910148
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
1012010149
int (*xProgress)(void *); /* The progress callback */
1012110150
void *pProgressArg; /* Argument to the progress callback */
10122
- int nProgressOps; /* Number of opcodes for progress callback */
10151
+ unsigned nProgressOps; /* Number of opcodes for progress callback */
1012310152
#endif
1012410153
#ifndef SQLITE_OMIT_VIRTUALTABLE
1012510154
int nVTrans; /* Allocated size of aVTrans */
1012610155
Hash aModule; /* populated by sqlite3_create_module() */
1012710156
VtabCtx *pVtabCtx; /* Context for active vtab connect/create */
@@ -10135,10 +10164,11 @@
1013510164
Savepoint *pSavepoint; /* List of active savepoints */
1013610165
int busyTimeout; /* Busy handler timeout, in msec */
1013710166
int nSavepoint; /* Number of non-transaction savepoints */
1013810167
int nStatement; /* Number of nested statement-transactions */
1013910168
i64 nDeferredCons; /* Net deferred constraints this transaction. */
10169
+ i64 nDeferredImmCons; /* Net deferred immediate constraints */
1014010170
int *pnBytesFreed; /* If not NULL, increment this in DbFree() */
1014110171
1014210172
#ifdef SQLITE_ENABLE_UNLOCK_NOTIFY
1014310173
/* The following variables are all protected by the STATIC_MASTER
1014410174
** mutex, not by sqlite3.mutex. They are used by code in notify.c.
@@ -10190,10 +10220,13 @@
1019010220
#define SQLITE_ForeignKeys 0x00040000 /* Enforce foreign key constraints */
1019110221
#define SQLITE_AutoIndex 0x00080000 /* Enable automatic indexes */
1019210222
#define SQLITE_PreferBuiltin 0x00100000 /* Preference to built-in funcs */
1019310223
#define SQLITE_LoadExtension 0x00200000 /* Enable load_extension */
1019410224
#define SQLITE_EnableTrigger 0x00400000 /* True to enable triggers */
10225
+#define SQLITE_DeferFKs 0x00800000 /* Defer all FK constraints */
10226
+#define SQLITE_QueryOnly 0x01000000 /* Disable database changes */
10227
+
1019510228
1019610229
/*
1019710230
** Bits of the sqlite3.dbOptFlags field that are used by the
1019810231
** sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS,...) interface to
1019910232
** selectively disable various optimizations.
@@ -10336,10 +10369,11 @@
1033610369
** OP_Savepoint instruction.
1033710370
*/
1033810371
struct Savepoint {
1033910372
char *zName; /* Savepoint name (nul-terminated) */
1034010373
i64 nDeferredCons; /* Number of deferred fk violations */
10374
+ i64 nDeferredImmCons; /* Number of deferred imm fk. */
1034110375
Savepoint *pNext; /* Parent savepoint (if any) */
1034210376
};
1034310377
1034410378
/*
1034510379
** The following are used as the second parameter to sqlite3Savepoint(),
@@ -13530,10 +13564,11 @@
1353013564
#ifndef SQLITE_OMIT_TRACE
1353113565
i64 startTime; /* Time when query started - used for profiling */
1353213566
#endif
1353313567
i64 nFkConstraint; /* Number of imm. FK constraints this VM */
1353413568
i64 nStmtDefCons; /* Number of def. constraints when stmt started */
13569
+ i64 nStmtDefImmCons; /* Number of def. imm constraints when stmt started */
1353513570
char *zSql; /* Text of the SQL statement that generated this */
1353613571
void *pFree; /* Free this when deleting the vdbe */
1353713572
#ifdef SQLITE_DEBUG
1353813573
FILE *trace; /* Write an execution trace here, if not NULL */
1353913574
#endif
@@ -13889,10 +13924,20 @@
1388913924
}
1389013925
*pHighwater = 0;
1389113926
*pCurrent = nRet;
1389213927
break;
1389313928
}
13929
+
13930
+ /* Set *pCurrent to non-zero if there are unresolved deferred foreign
13931
+ ** key constraints. Set *pCurrent to zero if all foreign key constraints
13932
+ ** have been satisfied. The *pHighwater is always set to zero.
13933
+ */
13934
+ case SQLITE_DBSTATUS_DEFERRED_FKS: {
13935
+ *pHighwater = 0;
13936
+ *pCurrent = db->nDeferredImmCons>0 || db->nDeferredCons>0;
13937
+ break;
13938
+ }
1389413939
1389513940
default: {
1389613941
rc = SQLITE_ERROR;
1389713942
}
1389813943
}
@@ -61946,10 +61991,11 @@
6194661991
/* If the statement transaction is being rolled back, also restore the
6194761992
** database handles deferred constraint counter to the value it had when
6194861993
** the statement transaction was opened. */
6194961994
if( eOp==SAVEPOINT_ROLLBACK ){
6195061995
db->nDeferredCons = p->nStmtDefCons;
61996
+ db->nDeferredImmCons = p->nStmtDefImmCons;
6195161997
}
6195261998
}
6195361999
return rc;
6195462000
}
6195562001
@@ -61964,11 +62010,13 @@
6196462010
** and write an error message to it. Then return SQLITE_ERROR.
6196562011
*/
6196662012
#ifndef SQLITE_OMIT_FOREIGN_KEY
6196762013
SQLITE_PRIVATE int sqlite3VdbeCheckFk(Vdbe *p, int deferred){
6196862014
sqlite3 *db = p->db;
61969
- if( (deferred && db->nDeferredCons>0) || (!deferred && p->nFkConstraint>0) ){
62015
+ if( (deferred && (db->nDeferredCons+db->nDeferredImmCons)>0)
62016
+ || (!deferred && p->nFkConstraint>0)
62017
+ ){
6197062018
p->rc = SQLITE_CONSTRAINT_FOREIGNKEY;
6197162019
p->errorAction = OE_Abort;
6197262020
sqlite3SetString(&p->zErrMsg, db, "foreign key constraint failed");
6197362021
return SQLITE_ERROR;
6197462022
}
@@ -62097,10 +62145,12 @@
6209762145
}else if( rc!=SQLITE_OK ){
6209862146
p->rc = rc;
6209962147
sqlite3RollbackAll(db, SQLITE_OK);
6210062148
}else{
6210162149
db->nDeferredCons = 0;
62150
+ db->nDeferredImmCons = 0;
62151
+ db->flags &= ~SQLITE_DeferFKs;
6210262152
sqlite3CommitInternalChanges(db);
6210362153
}
6210462154
}else{
6210562155
sqlite3RollbackAll(db, SQLITE_OK);
6210662156
}
@@ -63536,11 +63586,13 @@
6353663586
*/
6353763587
if( db->nVdbeActive==0 ){
6353863588
db->u1.isInterrupted = 0;
6353963589
}
6354063590
63541
- assert( db->nVdbeWrite>0 || db->autoCommit==0 || db->nDeferredCons==0 );
63591
+ assert( db->nVdbeWrite>0 || db->autoCommit==0
63592
+ || (db->nDeferredCons==0 && db->nDeferredImmCons==0)
63593
+ );
6354263594
6354363595
#ifndef SQLITE_OMIT_TRACE
6354463596
if( db->xProfile && !db->init.busy ){
6354563597
sqlite3OsCurrentTimeInt64(db->pVfs, &p->startTime);
6354663598
}
@@ -65384,16 +65436,15 @@
6538465436
Op *pOp; /* Current operation */
6538565437
int rc = SQLITE_OK; /* Value to return */
6538665438
sqlite3 *db = p->db; /* The database */
6538765439
u8 resetSchemaOnFault = 0; /* Reset schema after an error if positive */
6538865440
u8 encoding = ENC(db); /* The database encoding */
65389
-#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
65390
- int checkProgress; /* True if progress callbacks are enabled */
65391
- int nProgressOps = 0; /* Opcodes executed since progress callback. */
65392
-#endif
6539365441
int iCompare = 0; /* Result of last OP_Compare operation */
6539465442
unsigned nVmStep = 0; /* Number of virtual machine steps */
65443
+#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
65444
+ unsigned nProgressOps = 0; /* nVmStep at last progress callback. */
65445
+#endif
6539565446
Mem *aMem = p->aMem; /* Copy of p->aMem */
6539665447
Mem *pIn1 = 0; /* 1st input operand */
6539765448
Mem *pIn2 = 0; /* 2nd input operand */
6539865449
Mem *pIn3 = 0; /* 3rd input operand */
6539965450
Mem *pOut = 0; /* Output operand */
@@ -65847,13 +65898,10 @@
6584765898
assert( p->explain==0 );
6584865899
p->pResultSet = 0;
6584965900
db->busyHandler.nBusy = 0;
6585065901
CHECK_FOR_INTERRUPT;
6585165902
sqlite3VdbeIOTraceSql(p);
65852
-#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
65853
- checkProgress = db->xProgress!=0;
65854
-#endif
6585565903
#ifdef SQLITE_DEBUG
6585665904
sqlite3BeginBenignMalloc();
6585765905
if( p->pc==0 && (p->db->flags & SQLITE_VdbeListing)!=0 ){
6585865906
int i;
6585965907
printf("VDBE Program Listing:\n");
@@ -65895,31 +65943,10 @@
6589565943
sqlite3_interrupt_count--;
6589665944
if( sqlite3_interrupt_count==0 ){
6589765945
sqlite3_interrupt(db);
6589865946
}
6589965947
}
65900
-#endif
65901
-
65902
-#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
65903
- /* Call the progress callback if it is configured and the required number
65904
- ** of VDBE ops have been executed (either since this invocation of
65905
- ** sqlite3VdbeExec() or since last time the progress callback was called).
65906
- ** If the progress callback returns non-zero, exit the virtual machine with
65907
- ** a return code SQLITE_ABORT.
65908
- */
65909
- if( checkProgress ){
65910
- if( db->nProgressOps==nProgressOps ){
65911
- int prc;
65912
- prc = db->xProgress(db->pProgressArg);
65913
- if( prc!=0 ){
65914
- rc = SQLITE_INTERRUPT;
65915
- goto vdbe_error_halt;
65916
- }
65917
- nProgressOps = 0;
65918
- }
65919
- nProgressOps++;
65920
- }
6592165948
#endif
6592265949
6592365950
/* On any opcode with the "out2-prerelease" tag, free any
6592465951
** external allocations out of mem[p2] and set mem[p2] to be
6592565952
** an undefined integer. Opcodes will either fill in the integer
@@ -66010,12 +66037,42 @@
6601066037
** The next instruction executed will be
6601166038
** the one at index P2 from the beginning of
6601266039
** the program.
6601366040
*/
6601466041
case OP_Goto: { /* jump */
66015
- CHECK_FOR_INTERRUPT;
6601666042
pc = pOp->p2 - 1;
66043
+
66044
+ /* Opcodes that are used as the bottom of a loop (OP_Next, OP_Prev,
66045
+ ** OP_VNext, OP_RowSetNext, or OP_SorterNext) all jump here upon
66046
+ ** completion. Check to see if sqlite3_interrupt() has been called
66047
+ ** or if the progress callback needs to be invoked.
66048
+ **
66049
+ ** This code uses unstructured "goto" statements and does not look clean.
66050
+ ** But that is not due to sloppy coding habits. The code is written this
66051
+ ** way for performance, to avoid having to run the interrupt and progress
66052
+ ** checks on every opcode. This helps sqlite3_step() to run about 1.5%
66053
+ ** faster according to "valgrind --tool=cachegrind" */
66054
+check_for_interrupt:
66055
+ CHECK_FOR_INTERRUPT;
66056
+#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
66057
+ /* Call the progress callback if it is configured and the required number
66058
+ ** of VDBE ops have been executed (either since this invocation of
66059
+ ** sqlite3VdbeExec() or since last time the progress callback was called).
66060
+ ** If the progress callback returns non-zero, exit the virtual machine with
66061
+ ** a return code SQLITE_ABORT.
66062
+ */
66063
+ if( db->xProgress!=0 && (nVmStep - nProgressOps)>=db->nProgressOps ){
66064
+ int prc;
66065
+ prc = db->xProgress(db->pProgressArg);
66066
+ if( prc!=0 ){
66067
+ rc = SQLITE_INTERRUPT;
66068
+ goto vdbe_error_halt;
66069
+ }
66070
+ nProgressOps = nVmStep;
66071
+ }
66072
+#endif
66073
+
6601766074
break;
6601866075
}
6601966076
6602066077
/* Opcode: Gosub P1 P2 * * *
6602166078
**
@@ -66132,11 +66189,11 @@
6613266189
assert( rc==SQLITE_BUSY || rc==SQLITE_OK || rc==SQLITE_ERROR );
6613366190
if( rc==SQLITE_BUSY ){
6613466191
p->rc = rc = SQLITE_BUSY;
6613566192
}else{
6613666193
assert( rc==SQLITE_OK || (p->rc&0xff)==SQLITE_CONSTRAINT );
66137
- assert( rc==SQLITE_OK || db->nDeferredCons>0 );
66194
+ assert( rc==SQLITE_OK || db->nDeferredCons>0 || db->nDeferredImmCons>0 );
6613866195
rc = p->rc ? SQLITE_ERROR : SQLITE_DONE;
6613966196
}
6614066197
goto vdbe_return;
6614166198
}
6614266199
@@ -68028,10 +68085,11 @@
6802868085
6802968086
/* Link the new savepoint into the database handle's list. */
6803068087
u.as.pNew->pNext = db->pSavepoint;
6803168088
db->pSavepoint = u.as.pNew;
6803268089
u.as.pNew->nDeferredCons = db->nDeferredCons;
68090
+ u.as.pNew->nDeferredImmCons = db->nDeferredImmCons;
6803368091
}
6803468092
}
6803568093
}else{
6803668094
u.as.iSavepoint = 0;
6803768095
@@ -68115,10 +68173,11 @@
6811568173
if( !isTransaction ){
6811668174
db->nSavepoint--;
6811768175
}
6811868176
}else{
6811968177
db->nDeferredCons = u.as.pSavepoint->nDeferredCons;
68178
+ db->nDeferredImmCons = u.as.pSavepoint->nDeferredImmCons;
6812068179
}
6812168180
6812268181
if( !isTransaction ){
6812368182
rc = sqlite3VtabSavepoint(db, u.as.p1, u.as.iSavepoint);
6812468183
if( rc!=SQLITE_OK ) goto abort_due_to_error;
@@ -68244,10 +68303,14 @@
6824468303
6824568304
assert( p->bIsReader );
6824668305
assert( p->readOnly==0 || pOp->p2==0 );
6824768306
assert( pOp->p1>=0 && pOp->p1<db->nDb );
6824868307
assert( (p->btreeMask & (((yDbMask)1)<<pOp->p1))!=0 );
68308
+ if( pOp->p2 && (db->flags & SQLITE_QueryOnly)!=0 ){
68309
+ rc = SQLITE_READONLY;
68310
+ goto abort_due_to_error;
68311
+ }
6824968312
u.au.pBt = db->aDb[pOp->p1].pBt;
6825068313
6825168314
if( u.au.pBt ){
6825268315
rc = sqlite3BtreeBeginTrans(u.au.pBt, pOp->p2);
6825368316
if( rc==SQLITE_BUSY ){
@@ -68276,10 +68339,11 @@
6827668339
6827768340
/* Store the current value of the database handles deferred constraint
6827868341
** counter. If the statement transaction needs to be rolled back,
6827968342
** the value of this counter needs to be restored too. */
6828068343
p->nStmtDefCons = db->nDeferredCons;
68344
+ p->nStmtDefImmCons = db->nDeferredImmCons;
6828168345
}
6828268346
}
6828368347
break;
6828468348
}
6828568349
@@ -69851,11 +69915,10 @@
6985169915
#if 0 /* local variables moved into u.br */
6985269916
VdbeCursor *pC;
6985369917
int res;
6985469918
#endif /* local variables moved into u.br */
6985569919
69856
- CHECK_FOR_INTERRUPT;
6985769920
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
6985869921
assert( pOp->p5<=ArraySize(p->aCounter) );
6985969922
u.br.pC = p->apCsr[pOp->p1];
6986069923
if( u.br.pC==0 ){
6986169924
break; /* See ticket #2273 */
@@ -69880,11 +69943,11 @@
6988069943
#ifdef SQLITE_TEST
6988169944
sqlite3_search_count++;
6988269945
#endif
6988369946
}
6988469947
u.br.pC->rowidIsValid = 0;
69885
- break;
69948
+ goto check_for_interrupt;
6988669949
}
6988769950
6988869951
/* Opcode: IdxInsert P1 P2 P3 * P5
6988969952
**
6989069953
** Register P2 holds an SQL index key made using the
@@ -70426,11 +70489,11 @@
7042670489
*/
7042770490
case OP_RowSetRead: { /* jump, in1, out3 */
7042870491
#if 0 /* local variables moved into u.cb */
7042970492
i64 val;
7043070493
#endif /* local variables moved into u.cb */
70431
- CHECK_FOR_INTERRUPT;
70494
+
7043270495
pIn1 = &aMem[pOp->p1];
7043370496
if( (pIn1->flags & MEM_RowSet)==0
7043470497
|| sqlite3RowSetNext(pIn1->u.pRowSet, &u.cb.val)==0
7043570498
){
7043670499
/* The boolean index is empty */
@@ -70438,11 +70501,11 @@
7043870501
pc = pOp->p2 - 1;
7043970502
}else{
7044070503
/* A value was pulled from the index */
7044170504
sqlite3VdbeMemSetInt64(&aMem[pOp->p3], u.cb.val);
7044270505
}
70443
- break;
70506
+ goto check_for_interrupt;
7044470507
}
7044570508
7044670509
/* Opcode: RowSetTest P1 P2 P3 P4
7044770510
**
7044870511
** Register P3 is assumed to hold a 64-bit integer value. If register P1
@@ -70658,11 +70721,13 @@
7065870721
** If P1 is non-zero, the database constraint counter is incremented
7065970722
** (deferred foreign key constraints). Otherwise, if P1 is zero, the
7066070723
** statement counter is incremented (immediate foreign key constraints).
7066170724
*/
7066270725
case OP_FkCounter: {
70663
- if( pOp->p1 ){
70726
+ if( db->flags & SQLITE_DeferFKs ){
70727
+ db->nDeferredImmCons += pOp->p2;
70728
+ }else if( pOp->p1 ){
7066470729
db->nDeferredCons += pOp->p2;
7066570730
}else{
7066670731
p->nFkConstraint += pOp->p2;
7066770732
}
7066870733
break;
@@ -70679,13 +70744,13 @@
7067970744
** zero, the jump is taken if the statement constraint-counter is zero
7068070745
** (immediate foreign key constraint violations).
7068170746
*/
7068270747
case OP_FkIfZero: { /* jump */
7068370748
if( pOp->p1 ){
70684
- if( db->nDeferredCons==0 ) pc = pOp->p2-1;
70749
+ if( db->nDeferredCons==0 && db->nDeferredImmCons==0 ) pc = pOp->p2-1;
7068570750
}else{
70686
- if( p->nFkConstraint==0 ) pc = pOp->p2-1;
70751
+ if( p->nFkConstraint==0 && db->nDeferredImmCons==0 ) pc = pOp->p2-1;
7068770752
}
7068870753
break;
7068970754
}
7069070755
#endif /* #ifndef SQLITE_OMIT_FOREIGN_KEY */
7069170756
@@ -71367,11 +71432,11 @@
7136771432
7136871433
if( !u.cp.res ){
7136971434
/* If there is data, jump to P2 */
7137071435
pc = pOp->p2 - 1;
7137171436
}
71372
- break;
71437
+ goto check_for_interrupt;
7137371438
}
7137471439
#endif /* SQLITE_OMIT_VIRTUALTABLE */
7137571440
7137671441
#ifndef SQLITE_OMIT_VIRTUALTABLE
7137771442
/* Opcode: VRename P1 * * P4 *
@@ -89262,11 +89327,14 @@
8926289327
sqlite3ReleaseTempReg(pParse, regRec);
8926389328
sqlite3ReleaseTempRange(pParse, regTemp, nCol);
8926489329
}
8926589330
}
8926689331
89267
- if( !pFKey->isDeferred && !pParse->pToplevel && !pParse->isMultiWrite ){
89332
+ if( !pFKey->isDeferred && !(pParse->db->flags & SQLITE_DeferFKs)
89333
+ && !pParse->pToplevel
89334
+ && !pParse->isMultiWrite
89335
+ ){
8926889336
/* Special case: If this is an INSERT statement that will insert exactly
8926989337
** one row into the table, raise a constraint immediately instead of
8927089338
** incrementing a counter. This is necessary as the VM code is being
8927189339
** generated for will not open a statement transaction. */
8927289340
assert( nIncr==1 );
@@ -89653,11 +89721,13 @@
8965389721
for(pFKey = sqlite3FkReferences(pTab); pFKey; pFKey=pFKey->pNextTo){
8965489722
Index *pIdx = 0; /* Foreign key index for pFKey */
8965589723
SrcList *pSrc;
8965689724
int *aiCol = 0;
8965789725
89658
- if( !pFKey->isDeferred && !pParse->pToplevel && !pParse->isMultiWrite ){
89726
+ if( !pFKey->isDeferred && !(db->flags & SQLITE_DeferFKs)
89727
+ && !pParse->pToplevel && !pParse->isMultiWrite
89728
+ ){
8965989729
assert( regOld==0 && regNew!=0 );
8966089730
/* Inserting a single row into a parent table cannot cause an immediate
8966189731
** foreign key violation. So do nothing in this case. */
8966289732
continue;
8966389733
}
@@ -92615,15 +92685,18 @@
9261592685
#ifndef SQLITE_CORE
9261692686
/* This case when the file really is being compiled as a loadable
9261792687
** extension */
9261892688
# define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api=0;
9261992689
# define SQLITE_EXTENSION_INIT2(v) sqlite3_api=v;
92690
+# define SQLITE_EXTENSION_INIT3 \
92691
+ extern const sqlite3_api_routines *sqlite3_api;
9262092692
#else
9262192693
/* This case when the file is being statically linked into the
9262292694
** application */
9262392695
# define SQLITE_EXTENSION_INIT1 /*no-op*/
9262492696
# define SQLITE_EXTENSION_INIT2(v) (void)v; /* unused parameter */
92697
+# define SQLITE_EXTENSION_INIT3 /*no-op*/
9262592698
#endif
9262692699
9262792700
#endif /* _SQLITE3EXT_H_ */
9262892701
9262992702
/************** End of sqlite3ext.h ******************************************/
@@ -93275,10 +93348,39 @@
9327593348
sqlite3_mutex_leave(mutex);
9327693349
assert( (rc&0xff)==rc );
9327793350
return rc;
9327893351
}
9327993352
}
93353
+
93354
+/*
93355
+** Cancel a prior call to sqlite3_auto_extension. Remove xInit from the
93356
+** set of routines that is invoked for each new database connection, if it
93357
+** is currently on the list. If xInit is not on the list, then this
93358
+** routine is a no-op.
93359
+**
93360
+** Return 1 if xInit was found on the list and removed. Return 0 if xInit
93361
+** was not on the list.
93362
+*/
93363
+SQLITE_API int sqlite3_cancel_auto_extension(void (*xInit)(void)){
93364
+#if SQLITE_THREADSAFE
93365
+ sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
93366
+#endif
93367
+ int i;
93368
+ int n = 0;
93369
+ wsdAutoextInit;
93370
+ sqlite3_mutex_enter(mutex);
93371
+ for(i=wsdAutoext.nExt-1; i>=0; i--){
93372
+ if( wsdAutoext.aExt[i]==xInit ){
93373
+ wsdAutoext.nExt--;
93374
+ wsdAutoext.aExt[i] = wsdAutoext.aExt[wsdAutoext.nExt];
93375
+ n++;
93376
+ break;
93377
+ }
93378
+ }
93379
+ sqlite3_mutex_leave(mutex);
93380
+ return n;
93381
+}
9328093382
9328193383
/*
9328293384
** Reset the automatic extension loading mechanism.
9328393385
*/
9328493386
SQLITE_API void sqlite3_reset_auto_extension(void){
@@ -93516,10 +93618,11 @@
9351693618
{ "empty_result_callbacks", SQLITE_NullCallback },
9351793619
{ "legacy_file_format", SQLITE_LegacyFileFmt },
9351893620
{ "fullfsync", SQLITE_FullFSync },
9351993621
{ "checkpoint_fullfsync", SQLITE_CkptFullFSync },
9352093622
{ "reverse_unordered_selects", SQLITE_ReverseOrder },
93623
+ { "query_only", SQLITE_QueryOnly },
9352193624
#ifndef SQLITE_OMIT_AUTOMATIC_INDEX
9352293625
{ "automatic_index", SQLITE_AutoIndex },
9352393626
#endif
9352493627
#ifdef SQLITE_DEBUG
9352593628
{ "sql_trace", SQLITE_SqlTrace },
@@ -93536,16 +93639,17 @@
9353693639
{ "writable_schema", SQLITE_WriteSchema|SQLITE_RecoveryMode },
9353793640
9353893641
/* TODO: Maybe it shouldn't be possible to change the ReadUncommitted
9353993642
** flag if there are any active statements. */
9354093643
{ "read_uncommitted", SQLITE_ReadUncommitted },
93541
- { "recursive_triggers", SQLITE_RecTriggers },
93644
+ { "recursive_triggers", SQLITE_RecTriggers },
9354293645
9354393646
/* This flag may only be set if both foreign-key and trigger support
9354493647
** are present in the build. */
9354593648
#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
93546
- { "foreign_keys", SQLITE_ForeignKeys },
93649
+ { "foreign_keys", SQLITE_ForeignKeys },
93650
+ { "defer_foreign_keys", SQLITE_DeferFKs },
9354793651
#endif
9354893652
};
9354993653
int i;
9355093654
const struct sPragmaType *p;
9355193655
for(i=0, p=aPragma; i<ArraySize(aPragma); i++, p++){
@@ -93567,10 +93671,11 @@
9356793671
9356893672
if( sqlite3GetBoolean(zRight, 0) ){
9356993673
db->flags |= mask;
9357093674
}else{
9357193675
db->flags &= ~mask;
93676
+ if( mask==SQLITE_DeferFKs ) db->nDeferredImmCons = 0;
9357293677
}
9357393678
9357493679
/* Many of the flag-pragmas modify the code generated by the SQL
9357593680
** compiler (eg. count_changes). So add an opcode to expire all
9357693681
** compiled SQL statements after modifying a pragma value.
@@ -95979,10 +96084,16 @@
9597996084
9598096085
assert( ppStmt );
9598196086
*ppStmt = 0;
9598296087
if( !sqlite3SafetyCheckOk(db) ){
9598396088
return SQLITE_MISUSE_BKPT;
96089
+ }
96090
+ if( nBytes>=0 ){
96091
+ int sz;
96092
+ const char *z = (const char*)zSql;
96093
+ for(sz=0; sz<nBytes && (z[sz]!=0 || z[sz+1]!=0); sz += 2){}
96094
+ nBytes = sz;
9598496095
}
9598596096
sqlite3_mutex_enter(db->mutex);
9598696097
zSql8 = sqlite3Utf16to8(db, zSql, nBytes, SQLITE_UTF16NATIVE);
9598796098
if( zSql8 ){
9598896099
rc = sqlite3LockAndPrepare(db, zSql8, -1, saveSqlFlag, 0, ppStmt, &zTail8);
@@ -104070,12 +104181,12 @@
104070104181
int (*x)(sqlite3_vtab *);
104071104182
sqlite3_vtab *pVtab = aVTrans[i]->pVtab;
104072104183
if( pVtab && (x = pVtab->pModule->xSync)!=0 ){
104073104184
rc = x(pVtab);
104074104185
sqlite3DbFree(db, *pzErrmsg);
104075
- *pzErrmsg = sqlite3DbStrDup(db, pVtab->zErrMsg);
104076
- sqlite3_free(pVtab->zErrMsg);
104186
+ *pzErrmsg = pVtab->zErrMsg;
104187
+ pVtab->zErrMsg = 0;
104077104188
}
104078104189
}
104079104190
db->aVTrans = aVTrans;
104080104191
return rc;
104081104192
}
@@ -104391,10 +104502,12 @@
104391104502
typedef struct WhereLoop WhereLoop;
104392104503
typedef struct WherePath WherePath;
104393104504
typedef struct WhereTerm WhereTerm;
104394104505
typedef struct WhereLoopBuilder WhereLoopBuilder;
104395104506
typedef struct WhereScan WhereScan;
104507
+typedef struct WhereOrCost WhereOrCost;
104508
+typedef struct WhereOrSet WhereOrSet;
104396104509
104397104510
/*
104398104511
** Cost X is tracked as 10*log2(X) stored in a 16-bit integer. The
104399104512
** maximum cost for ordinary tables is 64*(2**63) which becomes 6900.
104400104513
** (Virtual tables can return a larger cost, but let's assume they do not.)
@@ -104497,10 +104610,31 @@
104497104610
u16 nLSlot; /* Number of slots allocated for aLTerm[] */
104498104611
WhereTerm **aLTerm; /* WhereTerms used */
104499104612
WhereLoop *pNextLoop; /* Next WhereLoop object in the WhereClause */
104500104613
WhereTerm *aLTermSpace[4]; /* Initial aLTerm[] space */
104501104614
};
104615
+
104616
+/* This object holds the prerequisites and the cost of running a
104617
+** subquery on one operand of an OR operator in the WHERE clause.
104618
+** See WhereOrSet for additional information
104619
+*/
104620
+struct WhereOrCost {
104621
+ Bitmask prereq; /* Prerequisites */
104622
+ WhereCost rRun; /* Cost of running this subquery */
104623
+ WhereCost nOut; /* Number of outputs for this subquery */
104624
+};
104625
+
104626
+/* The WhereOrSet object holds a set of possible WhereOrCosts that
104627
+** correspond to the subquery(s) of OR-clause processing. At most
104628
+** favorable N_OR_COST elements are retained.
104629
+*/
104630
+#define N_OR_COST 3
104631
+struct WhereOrSet {
104632
+ u16 n; /* Number of valid a[] entries */
104633
+ WhereOrCost a[N_OR_COST]; /* Set of best costs */
104634
+};
104635
+
104502104636
104503104637
/* Forward declaration of methods */
104504104638
static int whereLoopResize(sqlite3*, WhereLoop*, int);
104505104639
104506104640
/*
@@ -104712,11 +104846,11 @@
104712104846
struct WhereLoopBuilder {
104713104847
WhereInfo *pWInfo; /* Information about this WHERE */
104714104848
WhereClause *pWC; /* WHERE clause terms */
104715104849
ExprList *pOrderBy; /* ORDER BY clause */
104716104850
WhereLoop *pNew; /* Template WhereLoop */
104717
- WhereLoop *pBest; /* If non-NULL, store single best loop here */
104851
+ WhereOrSet *pOrSet; /* Record best loops here, if not NULL */
104718104852
};
104719104853
104720104854
/*
104721104855
** The WHERE clause processing routine has two halves. The
104722104856
** first part does the start of the WHERE loop and the second
@@ -104854,10 +104988,58 @@
104854104988
** UPDATE or DELETE might change subsequent WHERE clause results.
104855104989
*/
104856104990
SQLITE_PRIVATE int sqlite3WhereOkOnePass(WhereInfo *pWInfo){
104857104991
return pWInfo->okOnePass;
104858104992
}
104993
+
104994
+/*
104995
+** Move the content of pSrc into pDest
104996
+*/
104997
+static void whereOrMove(WhereOrSet *pDest, WhereOrSet *pSrc){
104998
+ pDest->n = pSrc->n;
104999
+ memcpy(pDest->a, pSrc->a, pDest->n*sizeof(pDest->a[0]));
105000
+}
105001
+
105002
+/*
105003
+** Try to insert a new prerequisite/cost entry into the WhereOrSet pSet.
105004
+**
105005
+** The new entry might overwrite an existing entry, or it might be
105006
+** appended, or it might be discarded. Do whatever is the right thing
105007
+** so that pSet keeps the N_OR_COST best entries seen so far.
105008
+*/
105009
+static int whereOrInsert(
105010
+ WhereOrSet *pSet, /* The WhereOrSet to be updated */
105011
+ Bitmask prereq, /* Prerequisites of the new entry */
105012
+ WhereCost rRun, /* Run-cost of the new entry */
105013
+ WhereCost nOut /* Number of outputs for the new entry */
105014
+){
105015
+ u16 i;
105016
+ WhereOrCost *p;
105017
+ for(i=pSet->n, p=pSet->a; i>0; i--, p++){
105018
+ if( rRun<=p->rRun && (prereq & p->prereq)==prereq ){
105019
+ goto whereOrInsert_done;
105020
+ }
105021
+ if( p->rRun<=rRun && (p->prereq & prereq)==p->prereq ){
105022
+ return 0;
105023
+ }
105024
+ }
105025
+ if( pSet->n<N_OR_COST ){
105026
+ p = &pSet->a[pSet->n++];
105027
+ p->nOut = nOut;
105028
+ }else{
105029
+ p = pSet->a;
105030
+ for(i=1; i<pSet->n; i++){
105031
+ if( p->rRun>pSet->a[i].rRun ) p = pSet->a + i;
105032
+ }
105033
+ if( p->rRun<=rRun ) return 0;
105034
+ }
105035
+whereOrInsert_done:
105036
+ p->prereq = prereq;
105037
+ p->rRun = rRun;
105038
+ if( p->nOut>nOut ) p->nOut = nOut;
105039
+ return 1;
105040
+}
104859105041
104860105042
/*
104861105043
** Initialize a preallocated WhereClause structure.
104862105044
*/
104863105045
static void whereClauseInit(
@@ -108089,12 +108271,13 @@
108089108271
*/
108090108272
if( pWC->nTerm>1 ){
108091108273
int iTerm;
108092108274
for(iTerm=0; iTerm<pWC->nTerm; iTerm++){
108093108275
Expr *pExpr = pWC->a[iTerm].pExpr;
108276
+ if( &pWC->a[iTerm] == pTerm ) continue;
108094108277
if( ExprHasProperty(pExpr, EP_FromJoin) ) continue;
108095
- if( pWC->a[iTerm].wtFlags & (TERM_VIRTUAL|TERM_ORINFO) ) continue;
108278
+ if( pWC->a[iTerm].wtFlags & (TERM_ORINFO) ) continue;
108096108279
if( (pWC->a[iTerm].eOperator & WO_ALL)==0 ) continue;
108097108280
pExpr = sqlite3ExprDup(pParse->db, pExpr, 0);
108098108281
pAndExpr = sqlite3ExprAnd(pParse->db, pAndExpr, pExpr);
108099108282
}
108100108283
if( pAndExpr ){
@@ -108418,16 +108601,16 @@
108418108601
** is better and has fewer dependencies. Or the template will be ignored
108419108602
** and no insert will occur if an existing WhereLoop is faster and has
108420108603
** fewer dependencies than the template. Otherwise a new WhereLoop is
108421108604
** added based on the template.
108422108605
**
108423
-** If pBuilder->pBest is not NULL then we only care about the very
108424
-** best template and that template should be stored in pBuilder->pBest.
108425
-** If pBuilder->pBest is NULL then a list of the best templates are stored
108426
-** in pBuilder->pWInfo->pLoops.
108606
+** If pBuilder->pOrSet is not NULL then we only care about only the
108607
+** prerequisites and rRun and nOut costs of the N best loops. That
108608
+** information is gathered in the pBuilder->pOrSet object. This special
108609
+** processing mode is used only for OR clause processing.
108427108610
**
108428
-** When accumulating multiple loops (when pBuilder->pBest is NULL) we
108611
+** When accumulating multiple loops (when pBuilder->pOrSet is NULL) we
108429108612
** still might overwrite similar loops with the new template if the
108430108613
** template is better. Loops may be overwritten if the following
108431108614
** conditions are met:
108432108615
**
108433108616
** (1) They have the same iTab.
@@ -108440,34 +108623,26 @@
108440108623
static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){
108441108624
WhereLoop **ppPrev, *p, *pNext = 0;
108442108625
WhereInfo *pWInfo = pBuilder->pWInfo;
108443108626
sqlite3 *db = pWInfo->pParse->db;
108444108627
108445
- /* If pBuilder->pBest is defined, then only keep track of the single
108446
- ** best WhereLoop. pBuilder->pBest->maskSelf==0 indicates that no
108447
- ** prior WhereLoops have been evaluated and that the current pTemplate
108448
- ** is therefore the first and hence the best and should be retained.
108628
+ /* If pBuilder->pOrSet is defined, then only keep track of the costs
108629
+ ** and prereqs.
108449108630
*/
108450
- if( (p = pBuilder->pBest)!=0 ){
108451
- if( p->maskSelf!=0 ){
108452
- WhereCost rCost = whereCostAdd(p->rRun,p->rSetup);
108453
- WhereCost rTemplate = whereCostAdd(pTemplate->rRun,pTemplate->rSetup);
108454
- if( rCost < rTemplate ){
108455
- testcase( rCost==rTemplate-1 );
108456
- goto whereLoopInsert_noop;
108457
- }
108458
- if( rCost==rTemplate && (p->prereq & pTemplate->prereq)==p->prereq ){
108459
- goto whereLoopInsert_noop;
108460
- }
108461
- }
108631
+ if( pBuilder->pOrSet!=0 ){
108632
+#if WHERETRACE_ENABLED
108633
+ u16 n = pBuilder->pOrSet->n;
108634
+ int x =
108635
+#endif
108636
+ whereOrInsert(pBuilder->pOrSet, pTemplate->prereq, pTemplate->rRun,
108637
+ pTemplate->nOut);
108462108638
#if WHERETRACE_ENABLED
108463108639
if( sqlite3WhereTrace & 0x8 ){
108464
- sqlite3DebugPrintf(p->maskSelf==0 ? "ins-init: " : "ins-best: ");
108640
+ sqlite3DebugPrintf(x?" or-%d: ":" or-X: ", n);
108465108641
whereLoopPrint(pTemplate, pWInfo->pTabList);
108466108642
}
108467108643
#endif
108468
- whereLoopXfer(db, p, pTemplate);
108469108644
return SQLITE_OK;
108470108645
}
108471108646
108472108647
/* Search for an existing WhereLoop to overwrite, or which takes
108473108648
** priority over pTemplate.
@@ -108557,11 +108732,11 @@
108557108732
108558108733
/* Jump here if the insert is a no-op */
108559108734
whereLoopInsert_noop:
108560108735
#if WHERETRACE_ENABLED
108561108736
if( sqlite3WhereTrace & 0x8 ){
108562
- sqlite3DebugPrintf(pBuilder->pBest ? "ins-skip: " : "ins-noop: ");
108737
+ sqlite3DebugPrintf("ins-noop: ");
108563108738
whereLoopPrint(pTemplate, pWInfo->pTabList);
108564108739
}
108565108740
#endif
108566108741
return SQLITE_OK;
108567108742
}
@@ -108839,11 +109014,11 @@
108839109014
}
108840109015
rSize = whereCost(pSrc->pTab->nRowEst);
108841109016
rLogSize = estLog(rSize);
108842109017
108843109018
/* Automatic indexes */
108844
- if( !pBuilder->pBest
109019
+ if( !pBuilder->pOrSet
108845109020
&& (pWInfo->pParse->db->flags & SQLITE_AutoIndex)!=0
108846109021
&& pSrc->pIndex==0
108847109022
&& !pSrc->viaCoroutine
108848109023
&& !pSrc->notIndexed
108849109024
&& !pSrc->isCorrelated
@@ -109125,11 +109300,11 @@
109125109300
WhereTerm *pTerm, *pWCEnd;
109126109301
int rc = SQLITE_OK;
109127109302
int iCur;
109128109303
WhereClause tempWC;
109129109304
WhereLoopBuilder sSubBuild;
109130
- WhereLoop sBest;
109305
+ WhereOrSet sSum, sCur, sPrev;
109131109306
struct SrcList_item *pItem;
109132109307
109133109308
pWC = pBuilder->pWC;
109134109309
if( pWInfo->wctrlFlags & WHERE_AND_ONLY ) return SQLITE_OK;
109135109310
pWCEnd = pWC->a + pWC->nTerm;
@@ -109140,20 +109315,18 @@
109140109315
&& (pTerm->u.pOrInfo->indexable & pNew->maskSelf)!=0
109141109316
){
109142109317
WhereClause * const pOrWC = &pTerm->u.pOrInfo->wc;
109143109318
WhereTerm * const pOrWCEnd = &pOrWC->a[pOrWC->nTerm];
109144109319
WhereTerm *pOrTerm;
109145
- WhereCost rTotal = 0;
109146
- WhereCost nRow = 0;
109147
- Bitmask prereq = mExtra;
109320
+ int once = 1;
109321
+ int i, j;
109148109322
109149
- whereLoopInit(&sBest);
109150109323
pItem = pWInfo->pTabList->a + pNew->iTab;
109151109324
iCur = pItem->iCursor;
109152109325
sSubBuild = *pBuilder;
109153109326
sSubBuild.pOrderBy = 0;
109154
- sSubBuild.pBest = &sBest;
109327
+ sSubBuild.pOrSet = &sCur;
109155109328
109156109329
for(pOrTerm=pOrWC->a; pOrTerm<pOrWCEnd; pOrTerm++){
109157109330
if( (pOrTerm->eOperator & WO_AND)!=0 ){
109158109331
sSubBuild.pWC = &pOrTerm->u.pAndInfo->wc;
109159109332
}else if( pOrTerm->leftCursor==iCur ){
@@ -109164,43 +109337,52 @@
109164109337
tempWC.a = pOrTerm;
109165109338
sSubBuild.pWC = &tempWC;
109166109339
}else{
109167109340
continue;
109168109341
}
109169
- sBest.maskSelf = 0;
109170
- sBest.rSetup = 0;
109171
- sBest.rRun = 0;
109342
+ sCur.n = 0;
109172109343
#ifndef SQLITE_OMIT_VIRTUALTABLE
109173109344
if( IsVirtual(pItem->pTab) ){
109174109345
rc = whereLoopAddVirtual(&sSubBuild);
109346
+ for(i=0; i<sCur.n; i++) sCur.a[i].prereq |= mExtra;
109175109347
}else
109176109348
#endif
109177109349
{
109178109350
rc = whereLoopAddBtree(&sSubBuild, mExtra);
109179109351
}
109180
- /* sBest.maskSelf is always zero if an error occurs */
109181
- assert( rc==SQLITE_OK || sBest.maskSelf==0 );
109182
- if( sBest.maskSelf==0 ) break;
109183
- assert( sBest.rSetup==0 );
109184
- rTotal = whereCostAdd(rTotal, sBest.rRun);
109185
- nRow = whereCostAdd(nRow, sBest.nOut);
109186
- prereq |= sBest.prereq;
109187
- }
109188
- assert( pNew->nLSlot>=1 );
109189
- if( sBest.maskSelf ){
109190
- pNew->nLTerm = 1;
109191
- pNew->aLTerm[0] = pTerm;
109192
- pNew->wsFlags = WHERE_MULTI_OR;
109193
- pNew->rSetup = 0;
109352
+ assert( rc==SQLITE_OK || sCur.n==0 );
109353
+ if( sCur.n==0 ){
109354
+ sSum.n = 0;
109355
+ break;
109356
+ }else if( once ){
109357
+ whereOrMove(&sSum, &sCur);
109358
+ once = 0;
109359
+ }else{
109360
+ whereOrMove(&sPrev, &sSum);
109361
+ sSum.n = 0;
109362
+ for(i=0; i<sPrev.n; i++){
109363
+ for(j=0; j<sCur.n; j++){
109364
+ whereOrInsert(&sSum, sPrev.a[i].prereq | sCur.a[j].prereq,
109365
+ whereCostAdd(sPrev.a[i].rRun, sCur.a[j].rRun),
109366
+ whereCostAdd(sPrev.a[i].nOut, sCur.a[j].nOut));
109367
+ }
109368
+ }
109369
+ }
109370
+ }
109371
+ pNew->nLTerm = 1;
109372
+ pNew->aLTerm[0] = pTerm;
109373
+ pNew->wsFlags = WHERE_MULTI_OR;
109374
+ pNew->rSetup = 0;
109375
+ pNew->iSortIdx = 0;
109376
+ memset(&pNew->u, 0, sizeof(pNew->u));
109377
+ for(i=0; rc==SQLITE_OK && i<sSum.n; i++){
109194109378
/* TUNING: Multiple by 3.5 for the secondary table lookup */
109195
- pNew->rRun = rTotal + 18; assert( 18==whereCost(7)-whereCost(2) );
109196
- pNew->nOut = nRow;
109197
- pNew->prereq = prereq;
109198
- memset(&pNew->u, 0, sizeof(pNew->u));
109379
+ pNew->rRun = sSum.a[i].rRun + 18;
109380
+ pNew->nOut = sSum.a[i].nOut;
109381
+ pNew->prereq = sSum.a[i].prereq;
109199109382
rc = whereLoopInsert(pBuilder, pNew);
109200109383
}
109201
- whereLoopClear(pWInfo->pParse->db, &sBest);
109202109384
}
109203109385
}
109204109386
return rc;
109205109387
}
109206109388
@@ -110003,11 +110185,12 @@
110003110185
pWInfo->wctrlFlags = wctrlFlags;
110004110186
pWInfo->savedNQueryLoop = pParse->nQueryLoop;
110005110187
pMaskSet = &pWInfo->sMaskSet;
110006110188
sWLB.pWInfo = pWInfo;
110007110189
sWLB.pWC = &pWInfo->sWC;
110008
- sWLB.pNew = (WhereLoop*)&pWInfo->a[nTabList];
110190
+ sWLB.pNew = (WhereLoop*)(((char*)pWInfo)+nByteWInfo);
110191
+ assert( EIGHT_BYTE_ALIGNMENT(sWLB.pNew) );
110009110192
whereLoopInit(sWLB.pNew);
110010110193
#ifdef SQLITE_DEBUG
110011110194
sWLB.pNew->cId = '*';
110012110195
#endif
110013110196
@@ -116127,10 +116310,12 @@
116127116310
}
116128116311
sqlite3BtreeLeaveAll(db);
116129116312
116130116313
/* Any deferred constraint violations have now been resolved. */
116131116314
db->nDeferredCons = 0;
116315
+ db->nDeferredImmCons = 0;
116316
+ db->flags &= ~SQLITE_DeferFKs;
116132116317
116133116318
/* If one has been configured, invoke the rollback-hook callback */
116134116319
if( db->xRollbackCallback && (inTrans || !db->autoCommit) ){
116135116320
db->xRollbackCallback(db->pRollbackArg);
116136116321
}
@@ -116388,11 +116573,11 @@
116388116573
void *pArg
116389116574
){
116390116575
sqlite3_mutex_enter(db->mutex);
116391116576
if( nOps>0 ){
116392116577
db->xProgress = xProgress;
116393
- db->nProgressOps = nOps;
116578
+ db->nProgressOps = (unsigned)nOps;
116394116579
db->pProgressArg = pArg;
116395116580
}else{
116396116581
db->xProgress = 0;
116397116582
db->nProgressOps = 0;
116398116583
db->pProgressArg = 0;
@@ -119087,11 +119272,11 @@
119087119272
119088119273
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3)
119089119274
119090119275
/* If not building as part of the core, include sqlite3ext.h. */
119091119276
#ifndef SQLITE_CORE
119092
-SQLITE_API extern const sqlite3_api_routines *sqlite3_api;
119277
+SQLITE_EXTENSION_INIT3
119093119278
#endif
119094119279
119095119280
/************** Include fts3_tokenizer.h in the middle of fts3Int.h **********/
119096119281
/************** Begin file fts3_tokenizer.h **********************************/
119097119282
/*
@@ -124995,11 +125180,14 @@
124995125180
124996125181
#if !SQLITE_CORE
124997125182
/*
124998125183
** Initialize API pointer table, if required.
124999125184
*/
125000
-SQLITE_API int sqlite3_extension_init(
125185
+#ifdef _WIN32
125186
+__declspec(dllexport)
125187
+#endif
125188
+SQLITE_API int sqlite3_fts3_init(
125001125189
sqlite3 *db,
125002125190
char **pzErrMsg,
125003125191
const sqlite3_api_routines *pApi
125004125192
){
125005125193
SQLITE_EXTENSION_INIT2(pApi)
@@ -140042,11 +140230,14 @@
140042140230
(void *)pGeomCtx, geomCallback, 0, 0, doSqlite3Free
140043140231
);
140044140232
}
140045140233
140046140234
#if !SQLITE_CORE
140047
-SQLITE_API int sqlite3_extension_init(
140235
+#ifdef _WIN32
140236
+__declspec(dllexport)
140237
+#endif
140238
+SQLITE_API int sqlite3_rtree_init(
140048140239
sqlite3 *db,
140049140240
char **pzErrMsg,
140050140241
const sqlite3_api_routines *pApi
140051140242
){
140052140243
SQLITE_EXTENSION_INIT2(pApi)
@@ -140544,11 +140735,14 @@
140544140735
140545140736
return rc;
140546140737
}
140547140738
140548140739
#if !SQLITE_CORE
140549
-SQLITE_API int sqlite3_extension_init(
140740
+#ifdef _WIN32
140741
+__declspec(dllexport)
140742
+#endif
140743
+SQLITE_API int sqlite3_icu_init(
140550140744
sqlite3 *db,
140551140745
char **pzErrMsg,
140552140746
const sqlite3_api_routines *pApi
140553140747
){
140554140748
SQLITE_EXTENSION_INIT2(pApi)
140555140749
--- src/sqlite3.c
+++ src/sqlite3.c
@@ -670,11 +670,11 @@
670 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
671 ** [sqlite_version()] and [sqlite_source_id()].
672 */
673 #define SQLITE_VERSION "3.8.0"
674 #define SQLITE_VERSION_NUMBER 3008000
675 #define SQLITE_SOURCE_ID "2013-07-09 03:04:32 52a49cbc1621094b2fe2b021209b768d29e0426b"
676
677 /*
678 ** CAPI3REF: Run-Time Library Version Numbers
679 ** KEYWORDS: sqlite3_version, sqlite3_sourceid
680 **
@@ -3120,11 +3120,11 @@
3120 ** [sqlite3_exec()], [sqlite3_step()] and [sqlite3_get_table()] for
3121 ** database connection D. An example use for this
3122 ** interface is to keep a GUI updated during a large query.
3123 **
3124 ** ^The parameter P is passed through as the only parameter to the
3125 ** callback function X. ^The parameter N is the number of
3126 ** [virtual machine instructions] that are evaluated between successive
3127 ** invocations of the callback X.
3128 **
3129 ** ^Only a single progress handler may be defined at one time per
3130 ** [database connection]; setting a new progress handler cancels the
@@ -4745,12 +4745,12 @@
4745 ** CAPI3REF: Function Auxiliary Data
4746 **
4747 ** The following two functions may be used by scalar SQL functions to
4748 ** associate metadata with argument values. If the same value is passed to
4749 ** multiple invocations of the same SQL function during query execution, under
4750 ** some circumstances the associated metadata may be preserved. This may
4751 ** be used, for example, to add a regular-expression matching scalar
4752 ** function. The compiled version of the regular expression is stored as
4753 ** metadata associated with the SQL value passed as the regular expression
4754 ** pattern. The compiled regular expression can be reused on multiple
4755 ** invocations of the same function so that the original pattern string
4756 ** does not need to be recompiled on each invocation.
@@ -4760,27 +4760,36 @@
4760 ** value to the application-defined function. ^If no metadata has been ever
4761 ** been set for the Nth argument of the function, or if the corresponding
4762 ** function parameter has changed since the meta-data was set,
4763 ** then sqlite3_get_auxdata() returns a NULL pointer.
4764 **
4765 ** ^The sqlite3_set_auxdata() interface saves the metadata
4766 ** pointed to by its 3rd parameter as the metadata for the N-th
4767 ** argument of the application-defined function. Subsequent
4768 ** calls to sqlite3_get_auxdata() might return this data, if it has
4769 ** not been destroyed.
4770 ** ^If it is not NULL, SQLite will invoke the destructor
4771 ** function given by the 4th parameter to sqlite3_set_auxdata() on
4772 ** the metadata when the corresponding function parameter changes
4773 ** or when the SQL statement completes, whichever comes first.
 
 
 
4774 **
4775 ** SQLite is free to call the destructor and drop metadata on any
4776 ** parameter of any function at any time. ^The only guarantee is that
4777 ** the destructor will be called before the metadata is dropped.
 
 
 
 
 
 
4778 **
4779 ** ^(In practice, metadata is preserved between function calls for
4780 ** expressions that are constant at compile time. This includes literal
4781 ** values and [parameters].)^
4782 **
4783 ** These routines must be called from the same thread in which
4784 ** the SQL function is running.
4785 */
4786 SQLITE_API void *sqlite3_get_auxdata(sqlite3_context*, int N);
@@ -5689,14 +5698,27 @@
5689 **
5690 ** ^Calling sqlite3_auto_extension(X) with an entry point X that is already
5691 ** on the list of automatic extensions is a harmless no-op. ^No entry point
5692 ** will be called more than once for each database connection that is opened.
5693 **
5694 ** See also: [sqlite3_reset_auto_extension()].
 
5695 */
5696 SQLITE_API int sqlite3_auto_extension(void (*xEntryPoint)(void));
5697
 
 
 
 
 
 
 
 
 
 
 
 
5698 /*
5699 ** CAPI3REF: Reset Automatic Extension Loading
5700 **
5701 ** ^This interface disables all automatic extensions previously
5702 ** registered using [sqlite3_auto_extension()].
@@ -6805,10 +6827,16 @@
6805 ** transaction rollback or database recovery operations are not included.
6806 ** If an IO or other error occurs while writing a page to disk, the effect
6807 ** on subsequent SQLITE_DBSTATUS_CACHE_WRITE requests is undefined.)^ ^The
6808 ** highwater mark associated with SQLITE_DBSTATUS_CACHE_WRITE is always 0.
6809 ** </dd>
 
 
 
 
 
 
6810 ** </dl>
6811 */
6812 #define SQLITE_DBSTATUS_LOOKASIDE_USED 0
6813 #define SQLITE_DBSTATUS_CACHE_USED 1
6814 #define SQLITE_DBSTATUS_SCHEMA_USED 2
@@ -6817,11 +6845,12 @@
6817 #define SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE 5
6818 #define SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL 6
6819 #define SQLITE_DBSTATUS_CACHE_HIT 7
6820 #define SQLITE_DBSTATUS_CACHE_MISS 8
6821 #define SQLITE_DBSTATUS_CACHE_WRITE 9
6822 #define SQLITE_DBSTATUS_MAX 9 /* Largest defined DBSTATUS */
 
6823
6824
6825 /*
6826 ** CAPI3REF: Prepared Statement Status
6827 **
@@ -10117,11 +10146,11 @@
10117 void *pAuthArg; /* 1st argument to the access auth function */
10118 #endif
10119 #ifndef SQLITE_OMIT_PROGRESS_CALLBACK
10120 int (*xProgress)(void *); /* The progress callback */
10121 void *pProgressArg; /* Argument to the progress callback */
10122 int nProgressOps; /* Number of opcodes for progress callback */
10123 #endif
10124 #ifndef SQLITE_OMIT_VIRTUALTABLE
10125 int nVTrans; /* Allocated size of aVTrans */
10126 Hash aModule; /* populated by sqlite3_create_module() */
10127 VtabCtx *pVtabCtx; /* Context for active vtab connect/create */
@@ -10135,10 +10164,11 @@
10135 Savepoint *pSavepoint; /* List of active savepoints */
10136 int busyTimeout; /* Busy handler timeout, in msec */
10137 int nSavepoint; /* Number of non-transaction savepoints */
10138 int nStatement; /* Number of nested statement-transactions */
10139 i64 nDeferredCons; /* Net deferred constraints this transaction. */
 
10140 int *pnBytesFreed; /* If not NULL, increment this in DbFree() */
10141
10142 #ifdef SQLITE_ENABLE_UNLOCK_NOTIFY
10143 /* The following variables are all protected by the STATIC_MASTER
10144 ** mutex, not by sqlite3.mutex. They are used by code in notify.c.
@@ -10190,10 +10220,13 @@
10190 #define SQLITE_ForeignKeys 0x00040000 /* Enforce foreign key constraints */
10191 #define SQLITE_AutoIndex 0x00080000 /* Enable automatic indexes */
10192 #define SQLITE_PreferBuiltin 0x00100000 /* Preference to built-in funcs */
10193 #define SQLITE_LoadExtension 0x00200000 /* Enable load_extension */
10194 #define SQLITE_EnableTrigger 0x00400000 /* True to enable triggers */
 
 
 
10195
10196 /*
10197 ** Bits of the sqlite3.dbOptFlags field that are used by the
10198 ** sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS,...) interface to
10199 ** selectively disable various optimizations.
@@ -10336,10 +10369,11 @@
10336 ** OP_Savepoint instruction.
10337 */
10338 struct Savepoint {
10339 char *zName; /* Savepoint name (nul-terminated) */
10340 i64 nDeferredCons; /* Number of deferred fk violations */
 
10341 Savepoint *pNext; /* Parent savepoint (if any) */
10342 };
10343
10344 /*
10345 ** The following are used as the second parameter to sqlite3Savepoint(),
@@ -13530,10 +13564,11 @@
13530 #ifndef SQLITE_OMIT_TRACE
13531 i64 startTime; /* Time when query started - used for profiling */
13532 #endif
13533 i64 nFkConstraint; /* Number of imm. FK constraints this VM */
13534 i64 nStmtDefCons; /* Number of def. constraints when stmt started */
 
13535 char *zSql; /* Text of the SQL statement that generated this */
13536 void *pFree; /* Free this when deleting the vdbe */
13537 #ifdef SQLITE_DEBUG
13538 FILE *trace; /* Write an execution trace here, if not NULL */
13539 #endif
@@ -13889,10 +13924,20 @@
13889 }
13890 *pHighwater = 0;
13891 *pCurrent = nRet;
13892 break;
13893 }
 
 
 
 
 
 
 
 
 
 
13894
13895 default: {
13896 rc = SQLITE_ERROR;
13897 }
13898 }
@@ -61946,10 +61991,11 @@
61946 /* If the statement transaction is being rolled back, also restore the
61947 ** database handles deferred constraint counter to the value it had when
61948 ** the statement transaction was opened. */
61949 if( eOp==SAVEPOINT_ROLLBACK ){
61950 db->nDeferredCons = p->nStmtDefCons;
 
61951 }
61952 }
61953 return rc;
61954 }
61955
@@ -61964,11 +62010,13 @@
61964 ** and write an error message to it. Then return SQLITE_ERROR.
61965 */
61966 #ifndef SQLITE_OMIT_FOREIGN_KEY
61967 SQLITE_PRIVATE int sqlite3VdbeCheckFk(Vdbe *p, int deferred){
61968 sqlite3 *db = p->db;
61969 if( (deferred && db->nDeferredCons>0) || (!deferred && p->nFkConstraint>0) ){
 
 
61970 p->rc = SQLITE_CONSTRAINT_FOREIGNKEY;
61971 p->errorAction = OE_Abort;
61972 sqlite3SetString(&p->zErrMsg, db, "foreign key constraint failed");
61973 return SQLITE_ERROR;
61974 }
@@ -62097,10 +62145,12 @@
62097 }else if( rc!=SQLITE_OK ){
62098 p->rc = rc;
62099 sqlite3RollbackAll(db, SQLITE_OK);
62100 }else{
62101 db->nDeferredCons = 0;
 
 
62102 sqlite3CommitInternalChanges(db);
62103 }
62104 }else{
62105 sqlite3RollbackAll(db, SQLITE_OK);
62106 }
@@ -63536,11 +63586,13 @@
63536 */
63537 if( db->nVdbeActive==0 ){
63538 db->u1.isInterrupted = 0;
63539 }
63540
63541 assert( db->nVdbeWrite>0 || db->autoCommit==0 || db->nDeferredCons==0 );
 
 
63542
63543 #ifndef SQLITE_OMIT_TRACE
63544 if( db->xProfile && !db->init.busy ){
63545 sqlite3OsCurrentTimeInt64(db->pVfs, &p->startTime);
63546 }
@@ -65384,16 +65436,15 @@
65384 Op *pOp; /* Current operation */
65385 int rc = SQLITE_OK; /* Value to return */
65386 sqlite3 *db = p->db; /* The database */
65387 u8 resetSchemaOnFault = 0; /* Reset schema after an error if positive */
65388 u8 encoding = ENC(db); /* The database encoding */
65389 #ifndef SQLITE_OMIT_PROGRESS_CALLBACK
65390 int checkProgress; /* True if progress callbacks are enabled */
65391 int nProgressOps = 0; /* Opcodes executed since progress callback. */
65392 #endif
65393 int iCompare = 0; /* Result of last OP_Compare operation */
65394 unsigned nVmStep = 0; /* Number of virtual machine steps */
 
 
 
65395 Mem *aMem = p->aMem; /* Copy of p->aMem */
65396 Mem *pIn1 = 0; /* 1st input operand */
65397 Mem *pIn2 = 0; /* 2nd input operand */
65398 Mem *pIn3 = 0; /* 3rd input operand */
65399 Mem *pOut = 0; /* Output operand */
@@ -65847,13 +65898,10 @@
65847 assert( p->explain==0 );
65848 p->pResultSet = 0;
65849 db->busyHandler.nBusy = 0;
65850 CHECK_FOR_INTERRUPT;
65851 sqlite3VdbeIOTraceSql(p);
65852 #ifndef SQLITE_OMIT_PROGRESS_CALLBACK
65853 checkProgress = db->xProgress!=0;
65854 #endif
65855 #ifdef SQLITE_DEBUG
65856 sqlite3BeginBenignMalloc();
65857 if( p->pc==0 && (p->db->flags & SQLITE_VdbeListing)!=0 ){
65858 int i;
65859 printf("VDBE Program Listing:\n");
@@ -65895,31 +65943,10 @@
65895 sqlite3_interrupt_count--;
65896 if( sqlite3_interrupt_count==0 ){
65897 sqlite3_interrupt(db);
65898 }
65899 }
65900 #endif
65901
65902 #ifndef SQLITE_OMIT_PROGRESS_CALLBACK
65903 /* Call the progress callback if it is configured and the required number
65904 ** of VDBE ops have been executed (either since this invocation of
65905 ** sqlite3VdbeExec() or since last time the progress callback was called).
65906 ** If the progress callback returns non-zero, exit the virtual machine with
65907 ** a return code SQLITE_ABORT.
65908 */
65909 if( checkProgress ){
65910 if( db->nProgressOps==nProgressOps ){
65911 int prc;
65912 prc = db->xProgress(db->pProgressArg);
65913 if( prc!=0 ){
65914 rc = SQLITE_INTERRUPT;
65915 goto vdbe_error_halt;
65916 }
65917 nProgressOps = 0;
65918 }
65919 nProgressOps++;
65920 }
65921 #endif
65922
65923 /* On any opcode with the "out2-prerelease" tag, free any
65924 ** external allocations out of mem[p2] and set mem[p2] to be
65925 ** an undefined integer. Opcodes will either fill in the integer
@@ -66010,12 +66037,42 @@
66010 ** The next instruction executed will be
66011 ** the one at index P2 from the beginning of
66012 ** the program.
66013 */
66014 case OP_Goto: { /* jump */
66015 CHECK_FOR_INTERRUPT;
66016 pc = pOp->p2 - 1;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
66017 break;
66018 }
66019
66020 /* Opcode: Gosub P1 P2 * * *
66021 **
@@ -66132,11 +66189,11 @@
66132 assert( rc==SQLITE_BUSY || rc==SQLITE_OK || rc==SQLITE_ERROR );
66133 if( rc==SQLITE_BUSY ){
66134 p->rc = rc = SQLITE_BUSY;
66135 }else{
66136 assert( rc==SQLITE_OK || (p->rc&0xff)==SQLITE_CONSTRAINT );
66137 assert( rc==SQLITE_OK || db->nDeferredCons>0 );
66138 rc = p->rc ? SQLITE_ERROR : SQLITE_DONE;
66139 }
66140 goto vdbe_return;
66141 }
66142
@@ -68028,10 +68085,11 @@
68028
68029 /* Link the new savepoint into the database handle's list. */
68030 u.as.pNew->pNext = db->pSavepoint;
68031 db->pSavepoint = u.as.pNew;
68032 u.as.pNew->nDeferredCons = db->nDeferredCons;
 
68033 }
68034 }
68035 }else{
68036 u.as.iSavepoint = 0;
68037
@@ -68115,10 +68173,11 @@
68115 if( !isTransaction ){
68116 db->nSavepoint--;
68117 }
68118 }else{
68119 db->nDeferredCons = u.as.pSavepoint->nDeferredCons;
 
68120 }
68121
68122 if( !isTransaction ){
68123 rc = sqlite3VtabSavepoint(db, u.as.p1, u.as.iSavepoint);
68124 if( rc!=SQLITE_OK ) goto abort_due_to_error;
@@ -68244,10 +68303,14 @@
68244
68245 assert( p->bIsReader );
68246 assert( p->readOnly==0 || pOp->p2==0 );
68247 assert( pOp->p1>=0 && pOp->p1<db->nDb );
68248 assert( (p->btreeMask & (((yDbMask)1)<<pOp->p1))!=0 );
 
 
 
 
68249 u.au.pBt = db->aDb[pOp->p1].pBt;
68250
68251 if( u.au.pBt ){
68252 rc = sqlite3BtreeBeginTrans(u.au.pBt, pOp->p2);
68253 if( rc==SQLITE_BUSY ){
@@ -68276,10 +68339,11 @@
68276
68277 /* Store the current value of the database handles deferred constraint
68278 ** counter. If the statement transaction needs to be rolled back,
68279 ** the value of this counter needs to be restored too. */
68280 p->nStmtDefCons = db->nDeferredCons;
 
68281 }
68282 }
68283 break;
68284 }
68285
@@ -69851,11 +69915,10 @@
69851 #if 0 /* local variables moved into u.br */
69852 VdbeCursor *pC;
69853 int res;
69854 #endif /* local variables moved into u.br */
69855
69856 CHECK_FOR_INTERRUPT;
69857 assert( pOp->p1>=0 && pOp->p1<p->nCursor );
69858 assert( pOp->p5<=ArraySize(p->aCounter) );
69859 u.br.pC = p->apCsr[pOp->p1];
69860 if( u.br.pC==0 ){
69861 break; /* See ticket #2273 */
@@ -69880,11 +69943,11 @@
69880 #ifdef SQLITE_TEST
69881 sqlite3_search_count++;
69882 #endif
69883 }
69884 u.br.pC->rowidIsValid = 0;
69885 break;
69886 }
69887
69888 /* Opcode: IdxInsert P1 P2 P3 * P5
69889 **
69890 ** Register P2 holds an SQL index key made using the
@@ -70426,11 +70489,11 @@
70426 */
70427 case OP_RowSetRead: { /* jump, in1, out3 */
70428 #if 0 /* local variables moved into u.cb */
70429 i64 val;
70430 #endif /* local variables moved into u.cb */
70431 CHECK_FOR_INTERRUPT;
70432 pIn1 = &aMem[pOp->p1];
70433 if( (pIn1->flags & MEM_RowSet)==0
70434 || sqlite3RowSetNext(pIn1->u.pRowSet, &u.cb.val)==0
70435 ){
70436 /* The boolean index is empty */
@@ -70438,11 +70501,11 @@
70438 pc = pOp->p2 - 1;
70439 }else{
70440 /* A value was pulled from the index */
70441 sqlite3VdbeMemSetInt64(&aMem[pOp->p3], u.cb.val);
70442 }
70443 break;
70444 }
70445
70446 /* Opcode: RowSetTest P1 P2 P3 P4
70447 **
70448 ** Register P3 is assumed to hold a 64-bit integer value. If register P1
@@ -70658,11 +70721,13 @@
70658 ** If P1 is non-zero, the database constraint counter is incremented
70659 ** (deferred foreign key constraints). Otherwise, if P1 is zero, the
70660 ** statement counter is incremented (immediate foreign key constraints).
70661 */
70662 case OP_FkCounter: {
70663 if( pOp->p1 ){
 
 
70664 db->nDeferredCons += pOp->p2;
70665 }else{
70666 p->nFkConstraint += pOp->p2;
70667 }
70668 break;
@@ -70679,13 +70744,13 @@
70679 ** zero, the jump is taken if the statement constraint-counter is zero
70680 ** (immediate foreign key constraint violations).
70681 */
70682 case OP_FkIfZero: { /* jump */
70683 if( pOp->p1 ){
70684 if( db->nDeferredCons==0 ) pc = pOp->p2-1;
70685 }else{
70686 if( p->nFkConstraint==0 ) pc = pOp->p2-1;
70687 }
70688 break;
70689 }
70690 #endif /* #ifndef SQLITE_OMIT_FOREIGN_KEY */
70691
@@ -71367,11 +71432,11 @@
71367
71368 if( !u.cp.res ){
71369 /* If there is data, jump to P2 */
71370 pc = pOp->p2 - 1;
71371 }
71372 break;
71373 }
71374 #endif /* SQLITE_OMIT_VIRTUALTABLE */
71375
71376 #ifndef SQLITE_OMIT_VIRTUALTABLE
71377 /* Opcode: VRename P1 * * P4 *
@@ -89262,11 +89327,14 @@
89262 sqlite3ReleaseTempReg(pParse, regRec);
89263 sqlite3ReleaseTempRange(pParse, regTemp, nCol);
89264 }
89265 }
89266
89267 if( !pFKey->isDeferred && !pParse->pToplevel && !pParse->isMultiWrite ){
 
 
 
89268 /* Special case: If this is an INSERT statement that will insert exactly
89269 ** one row into the table, raise a constraint immediately instead of
89270 ** incrementing a counter. This is necessary as the VM code is being
89271 ** generated for will not open a statement transaction. */
89272 assert( nIncr==1 );
@@ -89653,11 +89721,13 @@
89653 for(pFKey = sqlite3FkReferences(pTab); pFKey; pFKey=pFKey->pNextTo){
89654 Index *pIdx = 0; /* Foreign key index for pFKey */
89655 SrcList *pSrc;
89656 int *aiCol = 0;
89657
89658 if( !pFKey->isDeferred && !pParse->pToplevel && !pParse->isMultiWrite ){
 
 
89659 assert( regOld==0 && regNew!=0 );
89660 /* Inserting a single row into a parent table cannot cause an immediate
89661 ** foreign key violation. So do nothing in this case. */
89662 continue;
89663 }
@@ -92615,15 +92685,18 @@
92615 #ifndef SQLITE_CORE
92616 /* This case when the file really is being compiled as a loadable
92617 ** extension */
92618 # define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api=0;
92619 # define SQLITE_EXTENSION_INIT2(v) sqlite3_api=v;
 
 
92620 #else
92621 /* This case when the file is being statically linked into the
92622 ** application */
92623 # define SQLITE_EXTENSION_INIT1 /*no-op*/
92624 # define SQLITE_EXTENSION_INIT2(v) (void)v; /* unused parameter */
 
92625 #endif
92626
92627 #endif /* _SQLITE3EXT_H_ */
92628
92629 /************** End of sqlite3ext.h ******************************************/
@@ -93275,10 +93348,39 @@
93275 sqlite3_mutex_leave(mutex);
93276 assert( (rc&0xff)==rc );
93277 return rc;
93278 }
93279 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
93280
93281 /*
93282 ** Reset the automatic extension loading mechanism.
93283 */
93284 SQLITE_API void sqlite3_reset_auto_extension(void){
@@ -93516,10 +93618,11 @@
93516 { "empty_result_callbacks", SQLITE_NullCallback },
93517 { "legacy_file_format", SQLITE_LegacyFileFmt },
93518 { "fullfsync", SQLITE_FullFSync },
93519 { "checkpoint_fullfsync", SQLITE_CkptFullFSync },
93520 { "reverse_unordered_selects", SQLITE_ReverseOrder },
 
93521 #ifndef SQLITE_OMIT_AUTOMATIC_INDEX
93522 { "automatic_index", SQLITE_AutoIndex },
93523 #endif
93524 #ifdef SQLITE_DEBUG
93525 { "sql_trace", SQLITE_SqlTrace },
@@ -93536,16 +93639,17 @@
93536 { "writable_schema", SQLITE_WriteSchema|SQLITE_RecoveryMode },
93537
93538 /* TODO: Maybe it shouldn't be possible to change the ReadUncommitted
93539 ** flag if there are any active statements. */
93540 { "read_uncommitted", SQLITE_ReadUncommitted },
93541 { "recursive_triggers", SQLITE_RecTriggers },
93542
93543 /* This flag may only be set if both foreign-key and trigger support
93544 ** are present in the build. */
93545 #if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
93546 { "foreign_keys", SQLITE_ForeignKeys },
 
93547 #endif
93548 };
93549 int i;
93550 const struct sPragmaType *p;
93551 for(i=0, p=aPragma; i<ArraySize(aPragma); i++, p++){
@@ -93567,10 +93671,11 @@
93567
93568 if( sqlite3GetBoolean(zRight, 0) ){
93569 db->flags |= mask;
93570 }else{
93571 db->flags &= ~mask;
 
93572 }
93573
93574 /* Many of the flag-pragmas modify the code generated by the SQL
93575 ** compiler (eg. count_changes). So add an opcode to expire all
93576 ** compiled SQL statements after modifying a pragma value.
@@ -95979,10 +96084,16 @@
95979
95980 assert( ppStmt );
95981 *ppStmt = 0;
95982 if( !sqlite3SafetyCheckOk(db) ){
95983 return SQLITE_MISUSE_BKPT;
 
 
 
 
 
 
95984 }
95985 sqlite3_mutex_enter(db->mutex);
95986 zSql8 = sqlite3Utf16to8(db, zSql, nBytes, SQLITE_UTF16NATIVE);
95987 if( zSql8 ){
95988 rc = sqlite3LockAndPrepare(db, zSql8, -1, saveSqlFlag, 0, ppStmt, &zTail8);
@@ -104070,12 +104181,12 @@
104070 int (*x)(sqlite3_vtab *);
104071 sqlite3_vtab *pVtab = aVTrans[i]->pVtab;
104072 if( pVtab && (x = pVtab->pModule->xSync)!=0 ){
104073 rc = x(pVtab);
104074 sqlite3DbFree(db, *pzErrmsg);
104075 *pzErrmsg = sqlite3DbStrDup(db, pVtab->zErrMsg);
104076 sqlite3_free(pVtab->zErrMsg);
104077 }
104078 }
104079 db->aVTrans = aVTrans;
104080 return rc;
104081 }
@@ -104391,10 +104502,12 @@
104391 typedef struct WhereLoop WhereLoop;
104392 typedef struct WherePath WherePath;
104393 typedef struct WhereTerm WhereTerm;
104394 typedef struct WhereLoopBuilder WhereLoopBuilder;
104395 typedef struct WhereScan WhereScan;
 
 
104396
104397 /*
104398 ** Cost X is tracked as 10*log2(X) stored in a 16-bit integer. The
104399 ** maximum cost for ordinary tables is 64*(2**63) which becomes 6900.
104400 ** (Virtual tables can return a larger cost, but let's assume they do not.)
@@ -104497,10 +104610,31 @@
104497 u16 nLSlot; /* Number of slots allocated for aLTerm[] */
104498 WhereTerm **aLTerm; /* WhereTerms used */
104499 WhereLoop *pNextLoop; /* Next WhereLoop object in the WhereClause */
104500 WhereTerm *aLTermSpace[4]; /* Initial aLTerm[] space */
104501 };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
104502
104503 /* Forward declaration of methods */
104504 static int whereLoopResize(sqlite3*, WhereLoop*, int);
104505
104506 /*
@@ -104712,11 +104846,11 @@
104712 struct WhereLoopBuilder {
104713 WhereInfo *pWInfo; /* Information about this WHERE */
104714 WhereClause *pWC; /* WHERE clause terms */
104715 ExprList *pOrderBy; /* ORDER BY clause */
104716 WhereLoop *pNew; /* Template WhereLoop */
104717 WhereLoop *pBest; /* If non-NULL, store single best loop here */
104718 };
104719
104720 /*
104721 ** The WHERE clause processing routine has two halves. The
104722 ** first part does the start of the WHERE loop and the second
@@ -104854,10 +104988,58 @@
104854 ** UPDATE or DELETE might change subsequent WHERE clause results.
104855 */
104856 SQLITE_PRIVATE int sqlite3WhereOkOnePass(WhereInfo *pWInfo){
104857 return pWInfo->okOnePass;
104858 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
104859
104860 /*
104861 ** Initialize a preallocated WhereClause structure.
104862 */
104863 static void whereClauseInit(
@@ -108089,12 +108271,13 @@
108089 */
108090 if( pWC->nTerm>1 ){
108091 int iTerm;
108092 for(iTerm=0; iTerm<pWC->nTerm; iTerm++){
108093 Expr *pExpr = pWC->a[iTerm].pExpr;
 
108094 if( ExprHasProperty(pExpr, EP_FromJoin) ) continue;
108095 if( pWC->a[iTerm].wtFlags & (TERM_VIRTUAL|TERM_ORINFO) ) continue;
108096 if( (pWC->a[iTerm].eOperator & WO_ALL)==0 ) continue;
108097 pExpr = sqlite3ExprDup(pParse->db, pExpr, 0);
108098 pAndExpr = sqlite3ExprAnd(pParse->db, pAndExpr, pExpr);
108099 }
108100 if( pAndExpr ){
@@ -108418,16 +108601,16 @@
108418 ** is better and has fewer dependencies. Or the template will be ignored
108419 ** and no insert will occur if an existing WhereLoop is faster and has
108420 ** fewer dependencies than the template. Otherwise a new WhereLoop is
108421 ** added based on the template.
108422 **
108423 ** If pBuilder->pBest is not NULL then we only care about the very
108424 ** best template and that template should be stored in pBuilder->pBest.
108425 ** If pBuilder->pBest is NULL then a list of the best templates are stored
108426 ** in pBuilder->pWInfo->pLoops.
108427 **
108428 ** When accumulating multiple loops (when pBuilder->pBest is NULL) we
108429 ** still might overwrite similar loops with the new template if the
108430 ** template is better. Loops may be overwritten if the following
108431 ** conditions are met:
108432 **
108433 ** (1) They have the same iTab.
@@ -108440,34 +108623,26 @@
108440 static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){
108441 WhereLoop **ppPrev, *p, *pNext = 0;
108442 WhereInfo *pWInfo = pBuilder->pWInfo;
108443 sqlite3 *db = pWInfo->pParse->db;
108444
108445 /* If pBuilder->pBest is defined, then only keep track of the single
108446 ** best WhereLoop. pBuilder->pBest->maskSelf==0 indicates that no
108447 ** prior WhereLoops have been evaluated and that the current pTemplate
108448 ** is therefore the first and hence the best and should be retained.
108449 */
108450 if( (p = pBuilder->pBest)!=0 ){
108451 if( p->maskSelf!=0 ){
108452 WhereCost rCost = whereCostAdd(p->rRun,p->rSetup);
108453 WhereCost rTemplate = whereCostAdd(pTemplate->rRun,pTemplate->rSetup);
108454 if( rCost < rTemplate ){
108455 testcase( rCost==rTemplate-1 );
108456 goto whereLoopInsert_noop;
108457 }
108458 if( rCost==rTemplate && (p->prereq & pTemplate->prereq)==p->prereq ){
108459 goto whereLoopInsert_noop;
108460 }
108461 }
108462 #if WHERETRACE_ENABLED
108463 if( sqlite3WhereTrace & 0x8 ){
108464 sqlite3DebugPrintf(p->maskSelf==0 ? "ins-init: " : "ins-best: ");
108465 whereLoopPrint(pTemplate, pWInfo->pTabList);
108466 }
108467 #endif
108468 whereLoopXfer(db, p, pTemplate);
108469 return SQLITE_OK;
108470 }
108471
108472 /* Search for an existing WhereLoop to overwrite, or which takes
108473 ** priority over pTemplate.
@@ -108557,11 +108732,11 @@
108557
108558 /* Jump here if the insert is a no-op */
108559 whereLoopInsert_noop:
108560 #if WHERETRACE_ENABLED
108561 if( sqlite3WhereTrace & 0x8 ){
108562 sqlite3DebugPrintf(pBuilder->pBest ? "ins-skip: " : "ins-noop: ");
108563 whereLoopPrint(pTemplate, pWInfo->pTabList);
108564 }
108565 #endif
108566 return SQLITE_OK;
108567 }
@@ -108839,11 +109014,11 @@
108839 }
108840 rSize = whereCost(pSrc->pTab->nRowEst);
108841 rLogSize = estLog(rSize);
108842
108843 /* Automatic indexes */
108844 if( !pBuilder->pBest
108845 && (pWInfo->pParse->db->flags & SQLITE_AutoIndex)!=0
108846 && pSrc->pIndex==0
108847 && !pSrc->viaCoroutine
108848 && !pSrc->notIndexed
108849 && !pSrc->isCorrelated
@@ -109125,11 +109300,11 @@
109125 WhereTerm *pTerm, *pWCEnd;
109126 int rc = SQLITE_OK;
109127 int iCur;
109128 WhereClause tempWC;
109129 WhereLoopBuilder sSubBuild;
109130 WhereLoop sBest;
109131 struct SrcList_item *pItem;
109132
109133 pWC = pBuilder->pWC;
109134 if( pWInfo->wctrlFlags & WHERE_AND_ONLY ) return SQLITE_OK;
109135 pWCEnd = pWC->a + pWC->nTerm;
@@ -109140,20 +109315,18 @@
109140 && (pTerm->u.pOrInfo->indexable & pNew->maskSelf)!=0
109141 ){
109142 WhereClause * const pOrWC = &pTerm->u.pOrInfo->wc;
109143 WhereTerm * const pOrWCEnd = &pOrWC->a[pOrWC->nTerm];
109144 WhereTerm *pOrTerm;
109145 WhereCost rTotal = 0;
109146 WhereCost nRow = 0;
109147 Bitmask prereq = mExtra;
109148
109149 whereLoopInit(&sBest);
109150 pItem = pWInfo->pTabList->a + pNew->iTab;
109151 iCur = pItem->iCursor;
109152 sSubBuild = *pBuilder;
109153 sSubBuild.pOrderBy = 0;
109154 sSubBuild.pBest = &sBest;
109155
109156 for(pOrTerm=pOrWC->a; pOrTerm<pOrWCEnd; pOrTerm++){
109157 if( (pOrTerm->eOperator & WO_AND)!=0 ){
109158 sSubBuild.pWC = &pOrTerm->u.pAndInfo->wc;
109159 }else if( pOrTerm->leftCursor==iCur ){
@@ -109164,43 +109337,52 @@
109164 tempWC.a = pOrTerm;
109165 sSubBuild.pWC = &tempWC;
109166 }else{
109167 continue;
109168 }
109169 sBest.maskSelf = 0;
109170 sBest.rSetup = 0;
109171 sBest.rRun = 0;
109172 #ifndef SQLITE_OMIT_VIRTUALTABLE
109173 if( IsVirtual(pItem->pTab) ){
109174 rc = whereLoopAddVirtual(&sSubBuild);
 
109175 }else
109176 #endif
109177 {
109178 rc = whereLoopAddBtree(&sSubBuild, mExtra);
109179 }
109180 /* sBest.maskSelf is always zero if an error occurs */
109181 assert( rc==SQLITE_OK || sBest.maskSelf==0 );
109182 if( sBest.maskSelf==0 ) break;
109183 assert( sBest.rSetup==0 );
109184 rTotal = whereCostAdd(rTotal, sBest.rRun);
109185 nRow = whereCostAdd(nRow, sBest.nOut);
109186 prereq |= sBest.prereq;
109187 }
109188 assert( pNew->nLSlot>=1 );
109189 if( sBest.maskSelf ){
109190 pNew->nLTerm = 1;
109191 pNew->aLTerm[0] = pTerm;
109192 pNew->wsFlags = WHERE_MULTI_OR;
109193 pNew->rSetup = 0;
 
 
 
 
 
 
 
 
 
 
 
 
109194 /* TUNING: Multiple by 3.5 for the secondary table lookup */
109195 pNew->rRun = rTotal + 18; assert( 18==whereCost(7)-whereCost(2) );
109196 pNew->nOut = nRow;
109197 pNew->prereq = prereq;
109198 memset(&pNew->u, 0, sizeof(pNew->u));
109199 rc = whereLoopInsert(pBuilder, pNew);
109200 }
109201 whereLoopClear(pWInfo->pParse->db, &sBest);
109202 }
109203 }
109204 return rc;
109205 }
109206
@@ -110003,11 +110185,12 @@
110003 pWInfo->wctrlFlags = wctrlFlags;
110004 pWInfo->savedNQueryLoop = pParse->nQueryLoop;
110005 pMaskSet = &pWInfo->sMaskSet;
110006 sWLB.pWInfo = pWInfo;
110007 sWLB.pWC = &pWInfo->sWC;
110008 sWLB.pNew = (WhereLoop*)&pWInfo->a[nTabList];
 
110009 whereLoopInit(sWLB.pNew);
110010 #ifdef SQLITE_DEBUG
110011 sWLB.pNew->cId = '*';
110012 #endif
110013
@@ -116127,10 +116310,12 @@
116127 }
116128 sqlite3BtreeLeaveAll(db);
116129
116130 /* Any deferred constraint violations have now been resolved. */
116131 db->nDeferredCons = 0;
 
 
116132
116133 /* If one has been configured, invoke the rollback-hook callback */
116134 if( db->xRollbackCallback && (inTrans || !db->autoCommit) ){
116135 db->xRollbackCallback(db->pRollbackArg);
116136 }
@@ -116388,11 +116573,11 @@
116388 void *pArg
116389 ){
116390 sqlite3_mutex_enter(db->mutex);
116391 if( nOps>0 ){
116392 db->xProgress = xProgress;
116393 db->nProgressOps = nOps;
116394 db->pProgressArg = pArg;
116395 }else{
116396 db->xProgress = 0;
116397 db->nProgressOps = 0;
116398 db->pProgressArg = 0;
@@ -119087,11 +119272,11 @@
119087
119088 #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3)
119089
119090 /* If not building as part of the core, include sqlite3ext.h. */
119091 #ifndef SQLITE_CORE
119092 SQLITE_API extern const sqlite3_api_routines *sqlite3_api;
119093 #endif
119094
119095 /************** Include fts3_tokenizer.h in the middle of fts3Int.h **********/
119096 /************** Begin file fts3_tokenizer.h **********************************/
119097 /*
@@ -124995,11 +125180,14 @@
124995
124996 #if !SQLITE_CORE
124997 /*
124998 ** Initialize API pointer table, if required.
124999 */
125000 SQLITE_API int sqlite3_extension_init(
 
 
 
125001 sqlite3 *db,
125002 char **pzErrMsg,
125003 const sqlite3_api_routines *pApi
125004 ){
125005 SQLITE_EXTENSION_INIT2(pApi)
@@ -140042,11 +140230,14 @@
140042 (void *)pGeomCtx, geomCallback, 0, 0, doSqlite3Free
140043 );
140044 }
140045
140046 #if !SQLITE_CORE
140047 SQLITE_API int sqlite3_extension_init(
 
 
 
140048 sqlite3 *db,
140049 char **pzErrMsg,
140050 const sqlite3_api_routines *pApi
140051 ){
140052 SQLITE_EXTENSION_INIT2(pApi)
@@ -140544,11 +140735,14 @@
140544
140545 return rc;
140546 }
140547
140548 #if !SQLITE_CORE
140549 SQLITE_API int sqlite3_extension_init(
 
 
 
140550 sqlite3 *db,
140551 char **pzErrMsg,
140552 const sqlite3_api_routines *pApi
140553 ){
140554 SQLITE_EXTENSION_INIT2(pApi)
140555
--- src/sqlite3.c
+++ src/sqlite3.c
@@ -670,11 +670,11 @@
670 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
671 ** [sqlite_version()] and [sqlite_source_id()].
672 */
673 #define SQLITE_VERSION "3.8.0"
674 #define SQLITE_VERSION_NUMBER 3008000
675 #define SQLITE_SOURCE_ID "2013-07-18 14:50:56 5dcffa671f592ae9355628afa439ae9a2d26f0cd"
676
677 /*
678 ** CAPI3REF: Run-Time Library Version Numbers
679 ** KEYWORDS: sqlite3_version, sqlite3_sourceid
680 **
@@ -3120,11 +3120,11 @@
3120 ** [sqlite3_exec()], [sqlite3_step()] and [sqlite3_get_table()] for
3121 ** database connection D. An example use for this
3122 ** interface is to keep a GUI updated during a large query.
3123 **
3124 ** ^The parameter P is passed through as the only parameter to the
3125 ** callback function X. ^The parameter N is the approximate number of
3126 ** [virtual machine instructions] that are evaluated between successive
3127 ** invocations of the callback X.
3128 **
3129 ** ^Only a single progress handler may be defined at one time per
3130 ** [database connection]; setting a new progress handler cancels the
@@ -4745,12 +4745,12 @@
4745 ** CAPI3REF: Function Auxiliary Data
4746 **
4747 ** The following two functions may be used by scalar SQL functions to
4748 ** associate metadata with argument values. If the same value is passed to
4749 ** multiple invocations of the same SQL function during query execution, under
4750 ** some circumstances the associated metadata may be preserved. This might
4751 ** be used, for example, in a regular-expression matching
4752 ** function. The compiled version of the regular expression is stored as
4753 ** metadata associated with the SQL value passed as the regular expression
4754 ** pattern. The compiled regular expression can be reused on multiple
4755 ** invocations of the same function so that the original pattern string
4756 ** does not need to be recompiled on each invocation.
@@ -4760,27 +4760,36 @@
4760 ** value to the application-defined function. ^If no metadata has been ever
4761 ** been set for the Nth argument of the function, or if the corresponding
4762 ** function parameter has changed since the meta-data was set,
4763 ** then sqlite3_get_auxdata() returns a NULL pointer.
4764 **
4765 ** ^The sqlite3_set_auxdata(C,N,P,X) interface saves P as metadata for the N-th
4766 ** argument of the application-defined function. ^Subsequent
4767 ** calls to sqlite3_get_auxdata(C,N) return P from the most recent
4768 ** sqlite3_set_auxdata(C,N,P,X) call if the data has not been dropped, or
4769 ** NULL if the data has been dropped.
4770 ** ^(If it is not NULL, SQLite will invoke the destructor
4771 ** function X passed to sqlite3_set_auxdata(C,N,P,X) when <ul>
4772 ** <li> the corresponding function parameter changes,
4773 ** <li> [sqlite3_reset()] or [sqlite3_finalize()] is called for the
4774 ** SQL statement,
4775 ** <li> sqlite3_set_auxdata() is invoked again on the same parameter, or
4776 ** <li> a memory allocation error occurs. </ul>)^
4777 **
4778 ** SQLite is free to call the destructor and drop metadata on any
4779 ** parameter of any function at any time. ^The only guarantee is that
4780 ** the destructor will be called when the [prepared statement] is destroyed.
4781 ** Note in particular that the destructor X in the call to
4782 ** sqlite3_set_auxdata(C,N,P,X) might be called immediately, before
4783 ** the sqlite3_set_auxdata() call even returns. Hence sqlite3_set_auxdata()
4784 ** should be called near the end of the function implementation and the
4785 ** implementation should not make any use of P after sqlite3_set_auxdata()
4786 ** has been called.
4787 **
4788 ** ^(In practice, metadata is preserved between function calls for
4789 ** function parameters that are compile-time constants, including literal
4790 ** values and [parameters] and expressions composed from the same.)^
4791 **
4792 ** These routines must be called from the same thread in which
4793 ** the SQL function is running.
4794 */
4795 SQLITE_API void *sqlite3_get_auxdata(sqlite3_context*, int N);
@@ -5689,14 +5698,27 @@
5698 **
5699 ** ^Calling sqlite3_auto_extension(X) with an entry point X that is already
5700 ** on the list of automatic extensions is a harmless no-op. ^No entry point
5701 ** will be called more than once for each database connection that is opened.
5702 **
5703 ** See also: [sqlite3_reset_auto_extension()]
5704 ** and [sqlite3_cancel_auto_extension()]
5705 */
5706 SQLITE_API int sqlite3_auto_extension(void (*xEntryPoint)(void));
5707
5708 /*
5709 ** CAPI3REF: Cancel Automatic Extension Loading
5710 **
5711 ** ^The [sqlite3_cancel_auto_extension(X)] interface unregisters the
5712 ** initialization routine X that was registered using a prior call to
5713 ** [sqlite3_auto_extension(X)]. ^The [sqlite3_cancel_auto_extension(X)]
5714 ** routine returns 1 if initialization routine X was successfully
5715 ** unregistered and it returns 0 if X was not on the list of initialization
5716 ** routines.
5717 */
5718 SQLITE_API int sqlite3_cancel_auto_extension(void (*xEntryPoint)(void));
5719
5720 /*
5721 ** CAPI3REF: Reset Automatic Extension Loading
5722 **
5723 ** ^This interface disables all automatic extensions previously
5724 ** registered using [sqlite3_auto_extension()].
@@ -6805,10 +6827,16 @@
6827 ** transaction rollback or database recovery operations are not included.
6828 ** If an IO or other error occurs while writing a page to disk, the effect
6829 ** on subsequent SQLITE_DBSTATUS_CACHE_WRITE requests is undefined.)^ ^The
6830 ** highwater mark associated with SQLITE_DBSTATUS_CACHE_WRITE is always 0.
6831 ** </dd>
6832 **
6833 ** [[SQLITE_DBSTATUS_DEFERRED_FKS]] ^(<dt>SQLITE_DBSTATUS_DEFERRED_FKS</dt>
6834 ** <dd>This parameter returns the zero for the current value if and only if
6835 ** there all foreign key constraints (deferred or immediate) have been
6836 ** resolved. The highwater mark is always 0.
6837 ** </dd>
6838 ** </dl>
6839 */
6840 #define SQLITE_DBSTATUS_LOOKASIDE_USED 0
6841 #define SQLITE_DBSTATUS_CACHE_USED 1
6842 #define SQLITE_DBSTATUS_SCHEMA_USED 2
@@ -6817,11 +6845,12 @@
6845 #define SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE 5
6846 #define SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL 6
6847 #define SQLITE_DBSTATUS_CACHE_HIT 7
6848 #define SQLITE_DBSTATUS_CACHE_MISS 8
6849 #define SQLITE_DBSTATUS_CACHE_WRITE 9
6850 #define SQLITE_DBSTATUS_DEFERRED_FKS 10
6851 #define SQLITE_DBSTATUS_MAX 10 /* Largest defined DBSTATUS */
6852
6853
6854 /*
6855 ** CAPI3REF: Prepared Statement Status
6856 **
@@ -10117,11 +10146,11 @@
10146 void *pAuthArg; /* 1st argument to the access auth function */
10147 #endif
10148 #ifndef SQLITE_OMIT_PROGRESS_CALLBACK
10149 int (*xProgress)(void *); /* The progress callback */
10150 void *pProgressArg; /* Argument to the progress callback */
10151 unsigned nProgressOps; /* Number of opcodes for progress callback */
10152 #endif
10153 #ifndef SQLITE_OMIT_VIRTUALTABLE
10154 int nVTrans; /* Allocated size of aVTrans */
10155 Hash aModule; /* populated by sqlite3_create_module() */
10156 VtabCtx *pVtabCtx; /* Context for active vtab connect/create */
@@ -10135,10 +10164,11 @@
10164 Savepoint *pSavepoint; /* List of active savepoints */
10165 int busyTimeout; /* Busy handler timeout, in msec */
10166 int nSavepoint; /* Number of non-transaction savepoints */
10167 int nStatement; /* Number of nested statement-transactions */
10168 i64 nDeferredCons; /* Net deferred constraints this transaction. */
10169 i64 nDeferredImmCons; /* Net deferred immediate constraints */
10170 int *pnBytesFreed; /* If not NULL, increment this in DbFree() */
10171
10172 #ifdef SQLITE_ENABLE_UNLOCK_NOTIFY
10173 /* The following variables are all protected by the STATIC_MASTER
10174 ** mutex, not by sqlite3.mutex. They are used by code in notify.c.
@@ -10190,10 +10220,13 @@
10220 #define SQLITE_ForeignKeys 0x00040000 /* Enforce foreign key constraints */
10221 #define SQLITE_AutoIndex 0x00080000 /* Enable automatic indexes */
10222 #define SQLITE_PreferBuiltin 0x00100000 /* Preference to built-in funcs */
10223 #define SQLITE_LoadExtension 0x00200000 /* Enable load_extension */
10224 #define SQLITE_EnableTrigger 0x00400000 /* True to enable triggers */
10225 #define SQLITE_DeferFKs 0x00800000 /* Defer all FK constraints */
10226 #define SQLITE_QueryOnly 0x01000000 /* Disable database changes */
10227
10228
10229 /*
10230 ** Bits of the sqlite3.dbOptFlags field that are used by the
10231 ** sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS,...) interface to
10232 ** selectively disable various optimizations.
@@ -10336,10 +10369,11 @@
10369 ** OP_Savepoint instruction.
10370 */
10371 struct Savepoint {
10372 char *zName; /* Savepoint name (nul-terminated) */
10373 i64 nDeferredCons; /* Number of deferred fk violations */
10374 i64 nDeferredImmCons; /* Number of deferred imm fk. */
10375 Savepoint *pNext; /* Parent savepoint (if any) */
10376 };
10377
10378 /*
10379 ** The following are used as the second parameter to sqlite3Savepoint(),
@@ -13530,10 +13564,11 @@
13564 #ifndef SQLITE_OMIT_TRACE
13565 i64 startTime; /* Time when query started - used for profiling */
13566 #endif
13567 i64 nFkConstraint; /* Number of imm. FK constraints this VM */
13568 i64 nStmtDefCons; /* Number of def. constraints when stmt started */
13569 i64 nStmtDefImmCons; /* Number of def. imm constraints when stmt started */
13570 char *zSql; /* Text of the SQL statement that generated this */
13571 void *pFree; /* Free this when deleting the vdbe */
13572 #ifdef SQLITE_DEBUG
13573 FILE *trace; /* Write an execution trace here, if not NULL */
13574 #endif
@@ -13889,10 +13924,20 @@
13924 }
13925 *pHighwater = 0;
13926 *pCurrent = nRet;
13927 break;
13928 }
13929
13930 /* Set *pCurrent to non-zero if there are unresolved deferred foreign
13931 ** key constraints. Set *pCurrent to zero if all foreign key constraints
13932 ** have been satisfied. The *pHighwater is always set to zero.
13933 */
13934 case SQLITE_DBSTATUS_DEFERRED_FKS: {
13935 *pHighwater = 0;
13936 *pCurrent = db->nDeferredImmCons>0 || db->nDeferredCons>0;
13937 break;
13938 }
13939
13940 default: {
13941 rc = SQLITE_ERROR;
13942 }
13943 }
@@ -61946,10 +61991,11 @@
61991 /* If the statement transaction is being rolled back, also restore the
61992 ** database handles deferred constraint counter to the value it had when
61993 ** the statement transaction was opened. */
61994 if( eOp==SAVEPOINT_ROLLBACK ){
61995 db->nDeferredCons = p->nStmtDefCons;
61996 db->nDeferredImmCons = p->nStmtDefImmCons;
61997 }
61998 }
61999 return rc;
62000 }
62001
@@ -61964,11 +62010,13 @@
62010 ** and write an error message to it. Then return SQLITE_ERROR.
62011 */
62012 #ifndef SQLITE_OMIT_FOREIGN_KEY
62013 SQLITE_PRIVATE int sqlite3VdbeCheckFk(Vdbe *p, int deferred){
62014 sqlite3 *db = p->db;
62015 if( (deferred && (db->nDeferredCons+db->nDeferredImmCons)>0)
62016 || (!deferred && p->nFkConstraint>0)
62017 ){
62018 p->rc = SQLITE_CONSTRAINT_FOREIGNKEY;
62019 p->errorAction = OE_Abort;
62020 sqlite3SetString(&p->zErrMsg, db, "foreign key constraint failed");
62021 return SQLITE_ERROR;
62022 }
@@ -62097,10 +62145,12 @@
62145 }else if( rc!=SQLITE_OK ){
62146 p->rc = rc;
62147 sqlite3RollbackAll(db, SQLITE_OK);
62148 }else{
62149 db->nDeferredCons = 0;
62150 db->nDeferredImmCons = 0;
62151 db->flags &= ~SQLITE_DeferFKs;
62152 sqlite3CommitInternalChanges(db);
62153 }
62154 }else{
62155 sqlite3RollbackAll(db, SQLITE_OK);
62156 }
@@ -63536,11 +63586,13 @@
63586 */
63587 if( db->nVdbeActive==0 ){
63588 db->u1.isInterrupted = 0;
63589 }
63590
63591 assert( db->nVdbeWrite>0 || db->autoCommit==0
63592 || (db->nDeferredCons==0 && db->nDeferredImmCons==0)
63593 );
63594
63595 #ifndef SQLITE_OMIT_TRACE
63596 if( db->xProfile && !db->init.busy ){
63597 sqlite3OsCurrentTimeInt64(db->pVfs, &p->startTime);
63598 }
@@ -65384,16 +65436,15 @@
65436 Op *pOp; /* Current operation */
65437 int rc = SQLITE_OK; /* Value to return */
65438 sqlite3 *db = p->db; /* The database */
65439 u8 resetSchemaOnFault = 0; /* Reset schema after an error if positive */
65440 u8 encoding = ENC(db); /* The database encoding */
 
 
 
 
65441 int iCompare = 0; /* Result of last OP_Compare operation */
65442 unsigned nVmStep = 0; /* Number of virtual machine steps */
65443 #ifndef SQLITE_OMIT_PROGRESS_CALLBACK
65444 unsigned nProgressOps = 0; /* nVmStep at last progress callback. */
65445 #endif
65446 Mem *aMem = p->aMem; /* Copy of p->aMem */
65447 Mem *pIn1 = 0; /* 1st input operand */
65448 Mem *pIn2 = 0; /* 2nd input operand */
65449 Mem *pIn3 = 0; /* 3rd input operand */
65450 Mem *pOut = 0; /* Output operand */
@@ -65847,13 +65898,10 @@
65898 assert( p->explain==0 );
65899 p->pResultSet = 0;
65900 db->busyHandler.nBusy = 0;
65901 CHECK_FOR_INTERRUPT;
65902 sqlite3VdbeIOTraceSql(p);
 
 
 
65903 #ifdef SQLITE_DEBUG
65904 sqlite3BeginBenignMalloc();
65905 if( p->pc==0 && (p->db->flags & SQLITE_VdbeListing)!=0 ){
65906 int i;
65907 printf("VDBE Program Listing:\n");
@@ -65895,31 +65943,10 @@
65943 sqlite3_interrupt_count--;
65944 if( sqlite3_interrupt_count==0 ){
65945 sqlite3_interrupt(db);
65946 }
65947 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
65948 #endif
65949
65950 /* On any opcode with the "out2-prerelease" tag, free any
65951 ** external allocations out of mem[p2] and set mem[p2] to be
65952 ** an undefined integer. Opcodes will either fill in the integer
@@ -66010,12 +66037,42 @@
66037 ** The next instruction executed will be
66038 ** the one at index P2 from the beginning of
66039 ** the program.
66040 */
66041 case OP_Goto: { /* jump */
 
66042 pc = pOp->p2 - 1;
66043
66044 /* Opcodes that are used as the bottom of a loop (OP_Next, OP_Prev,
66045 ** OP_VNext, OP_RowSetNext, or OP_SorterNext) all jump here upon
66046 ** completion. Check to see if sqlite3_interrupt() has been called
66047 ** or if the progress callback needs to be invoked.
66048 **
66049 ** This code uses unstructured "goto" statements and does not look clean.
66050 ** But that is not due to sloppy coding habits. The code is written this
66051 ** way for performance, to avoid having to run the interrupt and progress
66052 ** checks on every opcode. This helps sqlite3_step() to run about 1.5%
66053 ** faster according to "valgrind --tool=cachegrind" */
66054 check_for_interrupt:
66055 CHECK_FOR_INTERRUPT;
66056 #ifndef SQLITE_OMIT_PROGRESS_CALLBACK
66057 /* Call the progress callback if it is configured and the required number
66058 ** of VDBE ops have been executed (either since this invocation of
66059 ** sqlite3VdbeExec() or since last time the progress callback was called).
66060 ** If the progress callback returns non-zero, exit the virtual machine with
66061 ** a return code SQLITE_ABORT.
66062 */
66063 if( db->xProgress!=0 && (nVmStep - nProgressOps)>=db->nProgressOps ){
66064 int prc;
66065 prc = db->xProgress(db->pProgressArg);
66066 if( prc!=0 ){
66067 rc = SQLITE_INTERRUPT;
66068 goto vdbe_error_halt;
66069 }
66070 nProgressOps = nVmStep;
66071 }
66072 #endif
66073
66074 break;
66075 }
66076
66077 /* Opcode: Gosub P1 P2 * * *
66078 **
@@ -66132,11 +66189,11 @@
66189 assert( rc==SQLITE_BUSY || rc==SQLITE_OK || rc==SQLITE_ERROR );
66190 if( rc==SQLITE_BUSY ){
66191 p->rc = rc = SQLITE_BUSY;
66192 }else{
66193 assert( rc==SQLITE_OK || (p->rc&0xff)==SQLITE_CONSTRAINT );
66194 assert( rc==SQLITE_OK || db->nDeferredCons>0 || db->nDeferredImmCons>0 );
66195 rc = p->rc ? SQLITE_ERROR : SQLITE_DONE;
66196 }
66197 goto vdbe_return;
66198 }
66199
@@ -68028,10 +68085,11 @@
68085
68086 /* Link the new savepoint into the database handle's list. */
68087 u.as.pNew->pNext = db->pSavepoint;
68088 db->pSavepoint = u.as.pNew;
68089 u.as.pNew->nDeferredCons = db->nDeferredCons;
68090 u.as.pNew->nDeferredImmCons = db->nDeferredImmCons;
68091 }
68092 }
68093 }else{
68094 u.as.iSavepoint = 0;
68095
@@ -68115,10 +68173,11 @@
68173 if( !isTransaction ){
68174 db->nSavepoint--;
68175 }
68176 }else{
68177 db->nDeferredCons = u.as.pSavepoint->nDeferredCons;
68178 db->nDeferredImmCons = u.as.pSavepoint->nDeferredImmCons;
68179 }
68180
68181 if( !isTransaction ){
68182 rc = sqlite3VtabSavepoint(db, u.as.p1, u.as.iSavepoint);
68183 if( rc!=SQLITE_OK ) goto abort_due_to_error;
@@ -68244,10 +68303,14 @@
68303
68304 assert( p->bIsReader );
68305 assert( p->readOnly==0 || pOp->p2==0 );
68306 assert( pOp->p1>=0 && pOp->p1<db->nDb );
68307 assert( (p->btreeMask & (((yDbMask)1)<<pOp->p1))!=0 );
68308 if( pOp->p2 && (db->flags & SQLITE_QueryOnly)!=0 ){
68309 rc = SQLITE_READONLY;
68310 goto abort_due_to_error;
68311 }
68312 u.au.pBt = db->aDb[pOp->p1].pBt;
68313
68314 if( u.au.pBt ){
68315 rc = sqlite3BtreeBeginTrans(u.au.pBt, pOp->p2);
68316 if( rc==SQLITE_BUSY ){
@@ -68276,10 +68339,11 @@
68339
68340 /* Store the current value of the database handles deferred constraint
68341 ** counter. If the statement transaction needs to be rolled back,
68342 ** the value of this counter needs to be restored too. */
68343 p->nStmtDefCons = db->nDeferredCons;
68344 p->nStmtDefImmCons = db->nDeferredImmCons;
68345 }
68346 }
68347 break;
68348 }
68349
@@ -69851,11 +69915,10 @@
69915 #if 0 /* local variables moved into u.br */
69916 VdbeCursor *pC;
69917 int res;
69918 #endif /* local variables moved into u.br */
69919
 
69920 assert( pOp->p1>=0 && pOp->p1<p->nCursor );
69921 assert( pOp->p5<=ArraySize(p->aCounter) );
69922 u.br.pC = p->apCsr[pOp->p1];
69923 if( u.br.pC==0 ){
69924 break; /* See ticket #2273 */
@@ -69880,11 +69943,11 @@
69943 #ifdef SQLITE_TEST
69944 sqlite3_search_count++;
69945 #endif
69946 }
69947 u.br.pC->rowidIsValid = 0;
69948 goto check_for_interrupt;
69949 }
69950
69951 /* Opcode: IdxInsert P1 P2 P3 * P5
69952 **
69953 ** Register P2 holds an SQL index key made using the
@@ -70426,11 +70489,11 @@
70489 */
70490 case OP_RowSetRead: { /* jump, in1, out3 */
70491 #if 0 /* local variables moved into u.cb */
70492 i64 val;
70493 #endif /* local variables moved into u.cb */
70494
70495 pIn1 = &aMem[pOp->p1];
70496 if( (pIn1->flags & MEM_RowSet)==0
70497 || sqlite3RowSetNext(pIn1->u.pRowSet, &u.cb.val)==0
70498 ){
70499 /* The boolean index is empty */
@@ -70438,11 +70501,11 @@
70501 pc = pOp->p2 - 1;
70502 }else{
70503 /* A value was pulled from the index */
70504 sqlite3VdbeMemSetInt64(&aMem[pOp->p3], u.cb.val);
70505 }
70506 goto check_for_interrupt;
70507 }
70508
70509 /* Opcode: RowSetTest P1 P2 P3 P4
70510 **
70511 ** Register P3 is assumed to hold a 64-bit integer value. If register P1
@@ -70658,11 +70721,13 @@
70721 ** If P1 is non-zero, the database constraint counter is incremented
70722 ** (deferred foreign key constraints). Otherwise, if P1 is zero, the
70723 ** statement counter is incremented (immediate foreign key constraints).
70724 */
70725 case OP_FkCounter: {
70726 if( db->flags & SQLITE_DeferFKs ){
70727 db->nDeferredImmCons += pOp->p2;
70728 }else if( pOp->p1 ){
70729 db->nDeferredCons += pOp->p2;
70730 }else{
70731 p->nFkConstraint += pOp->p2;
70732 }
70733 break;
@@ -70679,13 +70744,13 @@
70744 ** zero, the jump is taken if the statement constraint-counter is zero
70745 ** (immediate foreign key constraint violations).
70746 */
70747 case OP_FkIfZero: { /* jump */
70748 if( pOp->p1 ){
70749 if( db->nDeferredCons==0 && db->nDeferredImmCons==0 ) pc = pOp->p2-1;
70750 }else{
70751 if( p->nFkConstraint==0 && db->nDeferredImmCons==0 ) pc = pOp->p2-1;
70752 }
70753 break;
70754 }
70755 #endif /* #ifndef SQLITE_OMIT_FOREIGN_KEY */
70756
@@ -71367,11 +71432,11 @@
71432
71433 if( !u.cp.res ){
71434 /* If there is data, jump to P2 */
71435 pc = pOp->p2 - 1;
71436 }
71437 goto check_for_interrupt;
71438 }
71439 #endif /* SQLITE_OMIT_VIRTUALTABLE */
71440
71441 #ifndef SQLITE_OMIT_VIRTUALTABLE
71442 /* Opcode: VRename P1 * * P4 *
@@ -89262,11 +89327,14 @@
89327 sqlite3ReleaseTempReg(pParse, regRec);
89328 sqlite3ReleaseTempRange(pParse, regTemp, nCol);
89329 }
89330 }
89331
89332 if( !pFKey->isDeferred && !(pParse->db->flags & SQLITE_DeferFKs)
89333 && !pParse->pToplevel
89334 && !pParse->isMultiWrite
89335 ){
89336 /* Special case: If this is an INSERT statement that will insert exactly
89337 ** one row into the table, raise a constraint immediately instead of
89338 ** incrementing a counter. This is necessary as the VM code is being
89339 ** generated for will not open a statement transaction. */
89340 assert( nIncr==1 );
@@ -89653,11 +89721,13 @@
89721 for(pFKey = sqlite3FkReferences(pTab); pFKey; pFKey=pFKey->pNextTo){
89722 Index *pIdx = 0; /* Foreign key index for pFKey */
89723 SrcList *pSrc;
89724 int *aiCol = 0;
89725
89726 if( !pFKey->isDeferred && !(db->flags & SQLITE_DeferFKs)
89727 && !pParse->pToplevel && !pParse->isMultiWrite
89728 ){
89729 assert( regOld==0 && regNew!=0 );
89730 /* Inserting a single row into a parent table cannot cause an immediate
89731 ** foreign key violation. So do nothing in this case. */
89732 continue;
89733 }
@@ -92615,15 +92685,18 @@
92685 #ifndef SQLITE_CORE
92686 /* This case when the file really is being compiled as a loadable
92687 ** extension */
92688 # define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api=0;
92689 # define SQLITE_EXTENSION_INIT2(v) sqlite3_api=v;
92690 # define SQLITE_EXTENSION_INIT3 \
92691 extern const sqlite3_api_routines *sqlite3_api;
92692 #else
92693 /* This case when the file is being statically linked into the
92694 ** application */
92695 # define SQLITE_EXTENSION_INIT1 /*no-op*/
92696 # define SQLITE_EXTENSION_INIT2(v) (void)v; /* unused parameter */
92697 # define SQLITE_EXTENSION_INIT3 /*no-op*/
92698 #endif
92699
92700 #endif /* _SQLITE3EXT_H_ */
92701
92702 /************** End of sqlite3ext.h ******************************************/
@@ -93275,10 +93348,39 @@
93348 sqlite3_mutex_leave(mutex);
93349 assert( (rc&0xff)==rc );
93350 return rc;
93351 }
93352 }
93353
93354 /*
93355 ** Cancel a prior call to sqlite3_auto_extension. Remove xInit from the
93356 ** set of routines that is invoked for each new database connection, if it
93357 ** is currently on the list. If xInit is not on the list, then this
93358 ** routine is a no-op.
93359 **
93360 ** Return 1 if xInit was found on the list and removed. Return 0 if xInit
93361 ** was not on the list.
93362 */
93363 SQLITE_API int sqlite3_cancel_auto_extension(void (*xInit)(void)){
93364 #if SQLITE_THREADSAFE
93365 sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
93366 #endif
93367 int i;
93368 int n = 0;
93369 wsdAutoextInit;
93370 sqlite3_mutex_enter(mutex);
93371 for(i=wsdAutoext.nExt-1; i>=0; i--){
93372 if( wsdAutoext.aExt[i]==xInit ){
93373 wsdAutoext.nExt--;
93374 wsdAutoext.aExt[i] = wsdAutoext.aExt[wsdAutoext.nExt];
93375 n++;
93376 break;
93377 }
93378 }
93379 sqlite3_mutex_leave(mutex);
93380 return n;
93381 }
93382
93383 /*
93384 ** Reset the automatic extension loading mechanism.
93385 */
93386 SQLITE_API void sqlite3_reset_auto_extension(void){
@@ -93516,10 +93618,11 @@
93618 { "empty_result_callbacks", SQLITE_NullCallback },
93619 { "legacy_file_format", SQLITE_LegacyFileFmt },
93620 { "fullfsync", SQLITE_FullFSync },
93621 { "checkpoint_fullfsync", SQLITE_CkptFullFSync },
93622 { "reverse_unordered_selects", SQLITE_ReverseOrder },
93623 { "query_only", SQLITE_QueryOnly },
93624 #ifndef SQLITE_OMIT_AUTOMATIC_INDEX
93625 { "automatic_index", SQLITE_AutoIndex },
93626 #endif
93627 #ifdef SQLITE_DEBUG
93628 { "sql_trace", SQLITE_SqlTrace },
@@ -93536,16 +93639,17 @@
93639 { "writable_schema", SQLITE_WriteSchema|SQLITE_RecoveryMode },
93640
93641 /* TODO: Maybe it shouldn't be possible to change the ReadUncommitted
93642 ** flag if there are any active statements. */
93643 { "read_uncommitted", SQLITE_ReadUncommitted },
93644 { "recursive_triggers", SQLITE_RecTriggers },
93645
93646 /* This flag may only be set if both foreign-key and trigger support
93647 ** are present in the build. */
93648 #if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
93649 { "foreign_keys", SQLITE_ForeignKeys },
93650 { "defer_foreign_keys", SQLITE_DeferFKs },
93651 #endif
93652 };
93653 int i;
93654 const struct sPragmaType *p;
93655 for(i=0, p=aPragma; i<ArraySize(aPragma); i++, p++){
@@ -93567,10 +93671,11 @@
93671
93672 if( sqlite3GetBoolean(zRight, 0) ){
93673 db->flags |= mask;
93674 }else{
93675 db->flags &= ~mask;
93676 if( mask==SQLITE_DeferFKs ) db->nDeferredImmCons = 0;
93677 }
93678
93679 /* Many of the flag-pragmas modify the code generated by the SQL
93680 ** compiler (eg. count_changes). So add an opcode to expire all
93681 ** compiled SQL statements after modifying a pragma value.
@@ -95979,10 +96084,16 @@
96084
96085 assert( ppStmt );
96086 *ppStmt = 0;
96087 if( !sqlite3SafetyCheckOk(db) ){
96088 return SQLITE_MISUSE_BKPT;
96089 }
96090 if( nBytes>=0 ){
96091 int sz;
96092 const char *z = (const char*)zSql;
96093 for(sz=0; sz<nBytes && (z[sz]!=0 || z[sz+1]!=0); sz += 2){}
96094 nBytes = sz;
96095 }
96096 sqlite3_mutex_enter(db->mutex);
96097 zSql8 = sqlite3Utf16to8(db, zSql, nBytes, SQLITE_UTF16NATIVE);
96098 if( zSql8 ){
96099 rc = sqlite3LockAndPrepare(db, zSql8, -1, saveSqlFlag, 0, ppStmt, &zTail8);
@@ -104070,12 +104181,12 @@
104181 int (*x)(sqlite3_vtab *);
104182 sqlite3_vtab *pVtab = aVTrans[i]->pVtab;
104183 if( pVtab && (x = pVtab->pModule->xSync)!=0 ){
104184 rc = x(pVtab);
104185 sqlite3DbFree(db, *pzErrmsg);
104186 *pzErrmsg = pVtab->zErrMsg;
104187 pVtab->zErrMsg = 0;
104188 }
104189 }
104190 db->aVTrans = aVTrans;
104191 return rc;
104192 }
@@ -104391,10 +104502,12 @@
104502 typedef struct WhereLoop WhereLoop;
104503 typedef struct WherePath WherePath;
104504 typedef struct WhereTerm WhereTerm;
104505 typedef struct WhereLoopBuilder WhereLoopBuilder;
104506 typedef struct WhereScan WhereScan;
104507 typedef struct WhereOrCost WhereOrCost;
104508 typedef struct WhereOrSet WhereOrSet;
104509
104510 /*
104511 ** Cost X is tracked as 10*log2(X) stored in a 16-bit integer. The
104512 ** maximum cost for ordinary tables is 64*(2**63) which becomes 6900.
104513 ** (Virtual tables can return a larger cost, but let's assume they do not.)
@@ -104497,10 +104610,31 @@
104610 u16 nLSlot; /* Number of slots allocated for aLTerm[] */
104611 WhereTerm **aLTerm; /* WhereTerms used */
104612 WhereLoop *pNextLoop; /* Next WhereLoop object in the WhereClause */
104613 WhereTerm *aLTermSpace[4]; /* Initial aLTerm[] space */
104614 };
104615
104616 /* This object holds the prerequisites and the cost of running a
104617 ** subquery on one operand of an OR operator in the WHERE clause.
104618 ** See WhereOrSet for additional information
104619 */
104620 struct WhereOrCost {
104621 Bitmask prereq; /* Prerequisites */
104622 WhereCost rRun; /* Cost of running this subquery */
104623 WhereCost nOut; /* Number of outputs for this subquery */
104624 };
104625
104626 /* The WhereOrSet object holds a set of possible WhereOrCosts that
104627 ** correspond to the subquery(s) of OR-clause processing. At most
104628 ** favorable N_OR_COST elements are retained.
104629 */
104630 #define N_OR_COST 3
104631 struct WhereOrSet {
104632 u16 n; /* Number of valid a[] entries */
104633 WhereOrCost a[N_OR_COST]; /* Set of best costs */
104634 };
104635
104636
104637 /* Forward declaration of methods */
104638 static int whereLoopResize(sqlite3*, WhereLoop*, int);
104639
104640 /*
@@ -104712,11 +104846,11 @@
104846 struct WhereLoopBuilder {
104847 WhereInfo *pWInfo; /* Information about this WHERE */
104848 WhereClause *pWC; /* WHERE clause terms */
104849 ExprList *pOrderBy; /* ORDER BY clause */
104850 WhereLoop *pNew; /* Template WhereLoop */
104851 WhereOrSet *pOrSet; /* Record best loops here, if not NULL */
104852 };
104853
104854 /*
104855 ** The WHERE clause processing routine has two halves. The
104856 ** first part does the start of the WHERE loop and the second
@@ -104854,10 +104988,58 @@
104988 ** UPDATE or DELETE might change subsequent WHERE clause results.
104989 */
104990 SQLITE_PRIVATE int sqlite3WhereOkOnePass(WhereInfo *pWInfo){
104991 return pWInfo->okOnePass;
104992 }
104993
104994 /*
104995 ** Move the content of pSrc into pDest
104996 */
104997 static void whereOrMove(WhereOrSet *pDest, WhereOrSet *pSrc){
104998 pDest->n = pSrc->n;
104999 memcpy(pDest->a, pSrc->a, pDest->n*sizeof(pDest->a[0]));
105000 }
105001
105002 /*
105003 ** Try to insert a new prerequisite/cost entry into the WhereOrSet pSet.
105004 **
105005 ** The new entry might overwrite an existing entry, or it might be
105006 ** appended, or it might be discarded. Do whatever is the right thing
105007 ** so that pSet keeps the N_OR_COST best entries seen so far.
105008 */
105009 static int whereOrInsert(
105010 WhereOrSet *pSet, /* The WhereOrSet to be updated */
105011 Bitmask prereq, /* Prerequisites of the new entry */
105012 WhereCost rRun, /* Run-cost of the new entry */
105013 WhereCost nOut /* Number of outputs for the new entry */
105014 ){
105015 u16 i;
105016 WhereOrCost *p;
105017 for(i=pSet->n, p=pSet->a; i>0; i--, p++){
105018 if( rRun<=p->rRun && (prereq & p->prereq)==prereq ){
105019 goto whereOrInsert_done;
105020 }
105021 if( p->rRun<=rRun && (p->prereq & prereq)==p->prereq ){
105022 return 0;
105023 }
105024 }
105025 if( pSet->n<N_OR_COST ){
105026 p = &pSet->a[pSet->n++];
105027 p->nOut = nOut;
105028 }else{
105029 p = pSet->a;
105030 for(i=1; i<pSet->n; i++){
105031 if( p->rRun>pSet->a[i].rRun ) p = pSet->a + i;
105032 }
105033 if( p->rRun<=rRun ) return 0;
105034 }
105035 whereOrInsert_done:
105036 p->prereq = prereq;
105037 p->rRun = rRun;
105038 if( p->nOut>nOut ) p->nOut = nOut;
105039 return 1;
105040 }
105041
105042 /*
105043 ** Initialize a preallocated WhereClause structure.
105044 */
105045 static void whereClauseInit(
@@ -108089,12 +108271,13 @@
108271 */
108272 if( pWC->nTerm>1 ){
108273 int iTerm;
108274 for(iTerm=0; iTerm<pWC->nTerm; iTerm++){
108275 Expr *pExpr = pWC->a[iTerm].pExpr;
108276 if( &pWC->a[iTerm] == pTerm ) continue;
108277 if( ExprHasProperty(pExpr, EP_FromJoin) ) continue;
108278 if( pWC->a[iTerm].wtFlags & (TERM_ORINFO) ) continue;
108279 if( (pWC->a[iTerm].eOperator & WO_ALL)==0 ) continue;
108280 pExpr = sqlite3ExprDup(pParse->db, pExpr, 0);
108281 pAndExpr = sqlite3ExprAnd(pParse->db, pAndExpr, pExpr);
108282 }
108283 if( pAndExpr ){
@@ -108418,16 +108601,16 @@
108601 ** is better and has fewer dependencies. Or the template will be ignored
108602 ** and no insert will occur if an existing WhereLoop is faster and has
108603 ** fewer dependencies than the template. Otherwise a new WhereLoop is
108604 ** added based on the template.
108605 **
108606 ** If pBuilder->pOrSet is not NULL then we only care about only the
108607 ** prerequisites and rRun and nOut costs of the N best loops. That
108608 ** information is gathered in the pBuilder->pOrSet object. This special
108609 ** processing mode is used only for OR clause processing.
108610 **
108611 ** When accumulating multiple loops (when pBuilder->pOrSet is NULL) we
108612 ** still might overwrite similar loops with the new template if the
108613 ** template is better. Loops may be overwritten if the following
108614 ** conditions are met:
108615 **
108616 ** (1) They have the same iTab.
@@ -108440,34 +108623,26 @@
108623 static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){
108624 WhereLoop **ppPrev, *p, *pNext = 0;
108625 WhereInfo *pWInfo = pBuilder->pWInfo;
108626 sqlite3 *db = pWInfo->pParse->db;
108627
108628 /* If pBuilder->pOrSet is defined, then only keep track of the costs
108629 ** and prereqs.
 
 
108630 */
108631 if( pBuilder->pOrSet!=0 ){
108632 #if WHERETRACE_ENABLED
108633 u16 n = pBuilder->pOrSet->n;
108634 int x =
108635 #endif
108636 whereOrInsert(pBuilder->pOrSet, pTemplate->prereq, pTemplate->rRun,
108637 pTemplate->nOut);
 
 
 
 
 
108638 #if WHERETRACE_ENABLED
108639 if( sqlite3WhereTrace & 0x8 ){
108640 sqlite3DebugPrintf(x?" or-%d: ":" or-X: ", n);
108641 whereLoopPrint(pTemplate, pWInfo->pTabList);
108642 }
108643 #endif
 
108644 return SQLITE_OK;
108645 }
108646
108647 /* Search for an existing WhereLoop to overwrite, or which takes
108648 ** priority over pTemplate.
@@ -108557,11 +108732,11 @@
108732
108733 /* Jump here if the insert is a no-op */
108734 whereLoopInsert_noop:
108735 #if WHERETRACE_ENABLED
108736 if( sqlite3WhereTrace & 0x8 ){
108737 sqlite3DebugPrintf("ins-noop: ");
108738 whereLoopPrint(pTemplate, pWInfo->pTabList);
108739 }
108740 #endif
108741 return SQLITE_OK;
108742 }
@@ -108839,11 +109014,11 @@
109014 }
109015 rSize = whereCost(pSrc->pTab->nRowEst);
109016 rLogSize = estLog(rSize);
109017
109018 /* Automatic indexes */
109019 if( !pBuilder->pOrSet
109020 && (pWInfo->pParse->db->flags & SQLITE_AutoIndex)!=0
109021 && pSrc->pIndex==0
109022 && !pSrc->viaCoroutine
109023 && !pSrc->notIndexed
109024 && !pSrc->isCorrelated
@@ -109125,11 +109300,11 @@
109300 WhereTerm *pTerm, *pWCEnd;
109301 int rc = SQLITE_OK;
109302 int iCur;
109303 WhereClause tempWC;
109304 WhereLoopBuilder sSubBuild;
109305 WhereOrSet sSum, sCur, sPrev;
109306 struct SrcList_item *pItem;
109307
109308 pWC = pBuilder->pWC;
109309 if( pWInfo->wctrlFlags & WHERE_AND_ONLY ) return SQLITE_OK;
109310 pWCEnd = pWC->a + pWC->nTerm;
@@ -109140,20 +109315,18 @@
109315 && (pTerm->u.pOrInfo->indexable & pNew->maskSelf)!=0
109316 ){
109317 WhereClause * const pOrWC = &pTerm->u.pOrInfo->wc;
109318 WhereTerm * const pOrWCEnd = &pOrWC->a[pOrWC->nTerm];
109319 WhereTerm *pOrTerm;
109320 int once = 1;
109321 int i, j;
 
109322
 
109323 pItem = pWInfo->pTabList->a + pNew->iTab;
109324 iCur = pItem->iCursor;
109325 sSubBuild = *pBuilder;
109326 sSubBuild.pOrderBy = 0;
109327 sSubBuild.pOrSet = &sCur;
109328
109329 for(pOrTerm=pOrWC->a; pOrTerm<pOrWCEnd; pOrTerm++){
109330 if( (pOrTerm->eOperator & WO_AND)!=0 ){
109331 sSubBuild.pWC = &pOrTerm->u.pAndInfo->wc;
109332 }else if( pOrTerm->leftCursor==iCur ){
@@ -109164,43 +109337,52 @@
109337 tempWC.a = pOrTerm;
109338 sSubBuild.pWC = &tempWC;
109339 }else{
109340 continue;
109341 }
109342 sCur.n = 0;
 
 
109343 #ifndef SQLITE_OMIT_VIRTUALTABLE
109344 if( IsVirtual(pItem->pTab) ){
109345 rc = whereLoopAddVirtual(&sSubBuild);
109346 for(i=0; i<sCur.n; i++) sCur.a[i].prereq |= mExtra;
109347 }else
109348 #endif
109349 {
109350 rc = whereLoopAddBtree(&sSubBuild, mExtra);
109351 }
109352 assert( rc==SQLITE_OK || sCur.n==0 );
109353 if( sCur.n==0 ){
109354 sSum.n = 0;
109355 break;
109356 }else if( once ){
109357 whereOrMove(&sSum, &sCur);
109358 once = 0;
109359 }else{
109360 whereOrMove(&sPrev, &sSum);
109361 sSum.n = 0;
109362 for(i=0; i<sPrev.n; i++){
109363 for(j=0; j<sCur.n; j++){
109364 whereOrInsert(&sSum, sPrev.a[i].prereq | sCur.a[j].prereq,
109365 whereCostAdd(sPrev.a[i].rRun, sCur.a[j].rRun),
109366 whereCostAdd(sPrev.a[i].nOut, sCur.a[j].nOut));
109367 }
109368 }
109369 }
109370 }
109371 pNew->nLTerm = 1;
109372 pNew->aLTerm[0] = pTerm;
109373 pNew->wsFlags = WHERE_MULTI_OR;
109374 pNew->rSetup = 0;
109375 pNew->iSortIdx = 0;
109376 memset(&pNew->u, 0, sizeof(pNew->u));
109377 for(i=0; rc==SQLITE_OK && i<sSum.n; i++){
109378 /* TUNING: Multiple by 3.5 for the secondary table lookup */
109379 pNew->rRun = sSum.a[i].rRun + 18;
109380 pNew->nOut = sSum.a[i].nOut;
109381 pNew->prereq = sSum.a[i].prereq;
 
109382 rc = whereLoopInsert(pBuilder, pNew);
109383 }
 
109384 }
109385 }
109386 return rc;
109387 }
109388
@@ -110003,11 +110185,12 @@
110185 pWInfo->wctrlFlags = wctrlFlags;
110186 pWInfo->savedNQueryLoop = pParse->nQueryLoop;
110187 pMaskSet = &pWInfo->sMaskSet;
110188 sWLB.pWInfo = pWInfo;
110189 sWLB.pWC = &pWInfo->sWC;
110190 sWLB.pNew = (WhereLoop*)(((char*)pWInfo)+nByteWInfo);
110191 assert( EIGHT_BYTE_ALIGNMENT(sWLB.pNew) );
110192 whereLoopInit(sWLB.pNew);
110193 #ifdef SQLITE_DEBUG
110194 sWLB.pNew->cId = '*';
110195 #endif
110196
@@ -116127,10 +116310,12 @@
116310 }
116311 sqlite3BtreeLeaveAll(db);
116312
116313 /* Any deferred constraint violations have now been resolved. */
116314 db->nDeferredCons = 0;
116315 db->nDeferredImmCons = 0;
116316 db->flags &= ~SQLITE_DeferFKs;
116317
116318 /* If one has been configured, invoke the rollback-hook callback */
116319 if( db->xRollbackCallback && (inTrans || !db->autoCommit) ){
116320 db->xRollbackCallback(db->pRollbackArg);
116321 }
@@ -116388,11 +116573,11 @@
116573 void *pArg
116574 ){
116575 sqlite3_mutex_enter(db->mutex);
116576 if( nOps>0 ){
116577 db->xProgress = xProgress;
116578 db->nProgressOps = (unsigned)nOps;
116579 db->pProgressArg = pArg;
116580 }else{
116581 db->xProgress = 0;
116582 db->nProgressOps = 0;
116583 db->pProgressArg = 0;
@@ -119087,11 +119272,11 @@
119272
119273 #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3)
119274
119275 /* If not building as part of the core, include sqlite3ext.h. */
119276 #ifndef SQLITE_CORE
119277 SQLITE_EXTENSION_INIT3
119278 #endif
119279
119280 /************** Include fts3_tokenizer.h in the middle of fts3Int.h **********/
119281 /************** Begin file fts3_tokenizer.h **********************************/
119282 /*
@@ -124995,11 +125180,14 @@
125180
125181 #if !SQLITE_CORE
125182 /*
125183 ** Initialize API pointer table, if required.
125184 */
125185 #ifdef _WIN32
125186 __declspec(dllexport)
125187 #endif
125188 SQLITE_API int sqlite3_fts3_init(
125189 sqlite3 *db,
125190 char **pzErrMsg,
125191 const sqlite3_api_routines *pApi
125192 ){
125193 SQLITE_EXTENSION_INIT2(pApi)
@@ -140042,11 +140230,14 @@
140230 (void *)pGeomCtx, geomCallback, 0, 0, doSqlite3Free
140231 );
140232 }
140233
140234 #if !SQLITE_CORE
140235 #ifdef _WIN32
140236 __declspec(dllexport)
140237 #endif
140238 SQLITE_API int sqlite3_rtree_init(
140239 sqlite3 *db,
140240 char **pzErrMsg,
140241 const sqlite3_api_routines *pApi
140242 ){
140243 SQLITE_EXTENSION_INIT2(pApi)
@@ -140544,11 +140735,14 @@
140735
140736 return rc;
140737 }
140738
140739 #if !SQLITE_CORE
140740 #ifdef _WIN32
140741 __declspec(dllexport)
140742 #endif
140743 SQLITE_API int sqlite3_icu_init(
140744 sqlite3 *db,
140745 char **pzErrMsg,
140746 const sqlite3_api_routines *pApi
140747 ){
140748 SQLITE_EXTENSION_INIT2(pApi)
140749
+47 -18
--- src/sqlite3.h
+++ src/sqlite3.h
@@ -107,11 +107,11 @@
107107
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
108108
** [sqlite_version()] and [sqlite_source_id()].
109109
*/
110110
#define SQLITE_VERSION "3.8.0"
111111
#define SQLITE_VERSION_NUMBER 3008000
112
-#define SQLITE_SOURCE_ID "2013-07-09 03:04:32 52a49cbc1621094b2fe2b021209b768d29e0426b"
112
+#define SQLITE_SOURCE_ID "2013-07-18 14:50:56 5dcffa671f592ae9355628afa439ae9a2d26f0cd"
113113
114114
/*
115115
** CAPI3REF: Run-Time Library Version Numbers
116116
** KEYWORDS: sqlite3_version, sqlite3_sourceid
117117
**
@@ -2557,11 +2557,11 @@
25572557
** [sqlite3_exec()], [sqlite3_step()] and [sqlite3_get_table()] for
25582558
** database connection D. An example use for this
25592559
** interface is to keep a GUI updated during a large query.
25602560
**
25612561
** ^The parameter P is passed through as the only parameter to the
2562
-** callback function X. ^The parameter N is the number of
2562
+** callback function X. ^The parameter N is the approximate number of
25632563
** [virtual machine instructions] that are evaluated between successive
25642564
** invocations of the callback X.
25652565
**
25662566
** ^Only a single progress handler may be defined at one time per
25672567
** [database connection]; setting a new progress handler cancels the
@@ -4182,12 +4182,12 @@
41824182
** CAPI3REF: Function Auxiliary Data
41834183
**
41844184
** The following two functions may be used by scalar SQL functions to
41854185
** associate metadata with argument values. If the same value is passed to
41864186
** multiple invocations of the same SQL function during query execution, under
4187
-** some circumstances the associated metadata may be preserved. This may
4188
-** be used, for example, to add a regular-expression matching scalar
4187
+** some circumstances the associated metadata may be preserved. This might
4188
+** be used, for example, in a regular-expression matching
41894189
** function. The compiled version of the regular expression is stored as
41904190
** metadata associated with the SQL value passed as the regular expression
41914191
** pattern. The compiled regular expression can be reused on multiple
41924192
** invocations of the same function so that the original pattern string
41934193
** does not need to be recompiled on each invocation.
@@ -4197,27 +4197,36 @@
41974197
** value to the application-defined function. ^If no metadata has been ever
41984198
** been set for the Nth argument of the function, or if the corresponding
41994199
** function parameter has changed since the meta-data was set,
42004200
** then sqlite3_get_auxdata() returns a NULL pointer.
42014201
**
4202
-** ^The sqlite3_set_auxdata() interface saves the metadata
4203
-** pointed to by its 3rd parameter as the metadata for the N-th
4204
-** argument of the application-defined function. Subsequent
4205
-** calls to sqlite3_get_auxdata() might return this data, if it has
4206
-** not been destroyed.
4207
-** ^If it is not NULL, SQLite will invoke the destructor
4208
-** function given by the 4th parameter to sqlite3_set_auxdata() on
4209
-** the metadata when the corresponding function parameter changes
4210
-** or when the SQL statement completes, whichever comes first.
4202
+** ^The sqlite3_set_auxdata(C,N,P,X) interface saves P as metadata for the N-th
4203
+** argument of the application-defined function. ^Subsequent
4204
+** calls to sqlite3_get_auxdata(C,N) return P from the most recent
4205
+** sqlite3_set_auxdata(C,N,P,X) call if the data has not been dropped, or
4206
+** NULL if the data has been dropped.
4207
+** ^(If it is not NULL, SQLite will invoke the destructor
4208
+** function X passed to sqlite3_set_auxdata(C,N,P,X) when <ul>
4209
+** <li> the corresponding function parameter changes,
4210
+** <li> [sqlite3_reset()] or [sqlite3_finalize()] is called for the
4211
+** SQL statement,
4212
+** <li> sqlite3_set_auxdata() is invoked again on the same parameter, or
4213
+** <li> a memory allocation error occurs. </ul>)^
42114214
**
42124215
** SQLite is free to call the destructor and drop metadata on any
42134216
** parameter of any function at any time. ^The only guarantee is that
4214
-** the destructor will be called before the metadata is dropped.
4217
+** the destructor will be called when the [prepared statement] is destroyed.
4218
+** Note in particular that the destructor X in the call to
4219
+** sqlite3_set_auxdata(C,N,P,X) might be called immediately, before
4220
+** the sqlite3_set_auxdata() call even returns. Hence sqlite3_set_auxdata()
4221
+** should be called near the end of the function implementation and the
4222
+** implementation should not make any use of P after sqlite3_set_auxdata()
4223
+** has been called.
42154224
**
42164225
** ^(In practice, metadata is preserved between function calls for
4217
-** expressions that are constant at compile time. This includes literal
4218
-** values and [parameters].)^
4226
+** function parameters that are compile-time constants, including literal
4227
+** values and [parameters] and expressions composed from the same.)^
42194228
**
42204229
** These routines must be called from the same thread in which
42214230
** the SQL function is running.
42224231
*/
42234232
SQLITE_API void *sqlite3_get_auxdata(sqlite3_context*, int N);
@@ -5126,14 +5135,27 @@
51265135
**
51275136
** ^Calling sqlite3_auto_extension(X) with an entry point X that is already
51285137
** on the list of automatic extensions is a harmless no-op. ^No entry point
51295138
** will be called more than once for each database connection that is opened.
51305139
**
5131
-** See also: [sqlite3_reset_auto_extension()].
5140
+** See also: [sqlite3_reset_auto_extension()]
5141
+** and [sqlite3_cancel_auto_extension()]
51325142
*/
51335143
SQLITE_API int sqlite3_auto_extension(void (*xEntryPoint)(void));
51345144
5145
+/*
5146
+** CAPI3REF: Cancel Automatic Extension Loading
5147
+**
5148
+** ^The [sqlite3_cancel_auto_extension(X)] interface unregisters the
5149
+** initialization routine X that was registered using a prior call to
5150
+** [sqlite3_auto_extension(X)]. ^The [sqlite3_cancel_auto_extension(X)]
5151
+** routine returns 1 if initialization routine X was successfully
5152
+** unregistered and it returns 0 if X was not on the list of initialization
5153
+** routines.
5154
+*/
5155
+SQLITE_API int sqlite3_cancel_auto_extension(void (*xEntryPoint)(void));
5156
+
51355157
/*
51365158
** CAPI3REF: Reset Automatic Extension Loading
51375159
**
51385160
** ^This interface disables all automatic extensions previously
51395161
** registered using [sqlite3_auto_extension()].
@@ -6242,10 +6264,16 @@
62426264
** transaction rollback or database recovery operations are not included.
62436265
** If an IO or other error occurs while writing a page to disk, the effect
62446266
** on subsequent SQLITE_DBSTATUS_CACHE_WRITE requests is undefined.)^ ^The
62456267
** highwater mark associated with SQLITE_DBSTATUS_CACHE_WRITE is always 0.
62466268
** </dd>
6269
+**
6270
+** [[SQLITE_DBSTATUS_DEFERRED_FKS]] ^(<dt>SQLITE_DBSTATUS_DEFERRED_FKS</dt>
6271
+** <dd>This parameter returns the zero for the current value if and only if
6272
+** there all foreign key constraints (deferred or immediate) have been
6273
+** resolved. The highwater mark is always 0.
6274
+** </dd>
62476275
** </dl>
62486276
*/
62496277
#define SQLITE_DBSTATUS_LOOKASIDE_USED 0
62506278
#define SQLITE_DBSTATUS_CACHE_USED 1
62516279
#define SQLITE_DBSTATUS_SCHEMA_USED 2
@@ -6254,11 +6282,12 @@
62546282
#define SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE 5
62556283
#define SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL 6
62566284
#define SQLITE_DBSTATUS_CACHE_HIT 7
62576285
#define SQLITE_DBSTATUS_CACHE_MISS 8
62586286
#define SQLITE_DBSTATUS_CACHE_WRITE 9
6259
-#define SQLITE_DBSTATUS_MAX 9 /* Largest defined DBSTATUS */
6287
+#define SQLITE_DBSTATUS_DEFERRED_FKS 10
6288
+#define SQLITE_DBSTATUS_MAX 10 /* Largest defined DBSTATUS */
62606289
62616290
62626291
/*
62636292
** CAPI3REF: Prepared Statement Status
62646293
**
62656294
--- src/sqlite3.h
+++ src/sqlite3.h
@@ -107,11 +107,11 @@
107 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
108 ** [sqlite_version()] and [sqlite_source_id()].
109 */
110 #define SQLITE_VERSION "3.8.0"
111 #define SQLITE_VERSION_NUMBER 3008000
112 #define SQLITE_SOURCE_ID "2013-07-09 03:04:32 52a49cbc1621094b2fe2b021209b768d29e0426b"
113
114 /*
115 ** CAPI3REF: Run-Time Library Version Numbers
116 ** KEYWORDS: sqlite3_version, sqlite3_sourceid
117 **
@@ -2557,11 +2557,11 @@
2557 ** [sqlite3_exec()], [sqlite3_step()] and [sqlite3_get_table()] for
2558 ** database connection D. An example use for this
2559 ** interface is to keep a GUI updated during a large query.
2560 **
2561 ** ^The parameter P is passed through as the only parameter to the
2562 ** callback function X. ^The parameter N is the number of
2563 ** [virtual machine instructions] that are evaluated between successive
2564 ** invocations of the callback X.
2565 **
2566 ** ^Only a single progress handler may be defined at one time per
2567 ** [database connection]; setting a new progress handler cancels the
@@ -4182,12 +4182,12 @@
4182 ** CAPI3REF: Function Auxiliary Data
4183 **
4184 ** The following two functions may be used by scalar SQL functions to
4185 ** associate metadata with argument values. If the same value is passed to
4186 ** multiple invocations of the same SQL function during query execution, under
4187 ** some circumstances the associated metadata may be preserved. This may
4188 ** be used, for example, to add a regular-expression matching scalar
4189 ** function. The compiled version of the regular expression is stored as
4190 ** metadata associated with the SQL value passed as the regular expression
4191 ** pattern. The compiled regular expression can be reused on multiple
4192 ** invocations of the same function so that the original pattern string
4193 ** does not need to be recompiled on each invocation.
@@ -4197,27 +4197,36 @@
4197 ** value to the application-defined function. ^If no metadata has been ever
4198 ** been set for the Nth argument of the function, or if the corresponding
4199 ** function parameter has changed since the meta-data was set,
4200 ** then sqlite3_get_auxdata() returns a NULL pointer.
4201 **
4202 ** ^The sqlite3_set_auxdata() interface saves the metadata
4203 ** pointed to by its 3rd parameter as the metadata for the N-th
4204 ** argument of the application-defined function. Subsequent
4205 ** calls to sqlite3_get_auxdata() might return this data, if it has
4206 ** not been destroyed.
4207 ** ^If it is not NULL, SQLite will invoke the destructor
4208 ** function given by the 4th parameter to sqlite3_set_auxdata() on
4209 ** the metadata when the corresponding function parameter changes
4210 ** or when the SQL statement completes, whichever comes first.
 
 
 
4211 **
4212 ** SQLite is free to call the destructor and drop metadata on any
4213 ** parameter of any function at any time. ^The only guarantee is that
4214 ** the destructor will be called before the metadata is dropped.
 
 
 
 
 
 
4215 **
4216 ** ^(In practice, metadata is preserved between function calls for
4217 ** expressions that are constant at compile time. This includes literal
4218 ** values and [parameters].)^
4219 **
4220 ** These routines must be called from the same thread in which
4221 ** the SQL function is running.
4222 */
4223 SQLITE_API void *sqlite3_get_auxdata(sqlite3_context*, int N);
@@ -5126,14 +5135,27 @@
5126 **
5127 ** ^Calling sqlite3_auto_extension(X) with an entry point X that is already
5128 ** on the list of automatic extensions is a harmless no-op. ^No entry point
5129 ** will be called more than once for each database connection that is opened.
5130 **
5131 ** See also: [sqlite3_reset_auto_extension()].
 
5132 */
5133 SQLITE_API int sqlite3_auto_extension(void (*xEntryPoint)(void));
5134
 
 
 
 
 
 
 
 
 
 
 
 
5135 /*
5136 ** CAPI3REF: Reset Automatic Extension Loading
5137 **
5138 ** ^This interface disables all automatic extensions previously
5139 ** registered using [sqlite3_auto_extension()].
@@ -6242,10 +6264,16 @@
6242 ** transaction rollback or database recovery operations are not included.
6243 ** If an IO or other error occurs while writing a page to disk, the effect
6244 ** on subsequent SQLITE_DBSTATUS_CACHE_WRITE requests is undefined.)^ ^The
6245 ** highwater mark associated with SQLITE_DBSTATUS_CACHE_WRITE is always 0.
6246 ** </dd>
 
 
 
 
 
 
6247 ** </dl>
6248 */
6249 #define SQLITE_DBSTATUS_LOOKASIDE_USED 0
6250 #define SQLITE_DBSTATUS_CACHE_USED 1
6251 #define SQLITE_DBSTATUS_SCHEMA_USED 2
@@ -6254,11 +6282,12 @@
6254 #define SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE 5
6255 #define SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL 6
6256 #define SQLITE_DBSTATUS_CACHE_HIT 7
6257 #define SQLITE_DBSTATUS_CACHE_MISS 8
6258 #define SQLITE_DBSTATUS_CACHE_WRITE 9
6259 #define SQLITE_DBSTATUS_MAX 9 /* Largest defined DBSTATUS */
 
6260
6261
6262 /*
6263 ** CAPI3REF: Prepared Statement Status
6264 **
6265
--- src/sqlite3.h
+++ src/sqlite3.h
@@ -107,11 +107,11 @@
107 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
108 ** [sqlite_version()] and [sqlite_source_id()].
109 */
110 #define SQLITE_VERSION "3.8.0"
111 #define SQLITE_VERSION_NUMBER 3008000
112 #define SQLITE_SOURCE_ID "2013-07-18 14:50:56 5dcffa671f592ae9355628afa439ae9a2d26f0cd"
113
114 /*
115 ** CAPI3REF: Run-Time Library Version Numbers
116 ** KEYWORDS: sqlite3_version, sqlite3_sourceid
117 **
@@ -2557,11 +2557,11 @@
2557 ** [sqlite3_exec()], [sqlite3_step()] and [sqlite3_get_table()] for
2558 ** database connection D. An example use for this
2559 ** interface is to keep a GUI updated during a large query.
2560 **
2561 ** ^The parameter P is passed through as the only parameter to the
2562 ** callback function X. ^The parameter N is the approximate number of
2563 ** [virtual machine instructions] that are evaluated between successive
2564 ** invocations of the callback X.
2565 **
2566 ** ^Only a single progress handler may be defined at one time per
2567 ** [database connection]; setting a new progress handler cancels the
@@ -4182,12 +4182,12 @@
4182 ** CAPI3REF: Function Auxiliary Data
4183 **
4184 ** The following two functions may be used by scalar SQL functions to
4185 ** associate metadata with argument values. If the same value is passed to
4186 ** multiple invocations of the same SQL function during query execution, under
4187 ** some circumstances the associated metadata may be preserved. This might
4188 ** be used, for example, in a regular-expression matching
4189 ** function. The compiled version of the regular expression is stored as
4190 ** metadata associated with the SQL value passed as the regular expression
4191 ** pattern. The compiled regular expression can be reused on multiple
4192 ** invocations of the same function so that the original pattern string
4193 ** does not need to be recompiled on each invocation.
@@ -4197,27 +4197,36 @@
4197 ** value to the application-defined function. ^If no metadata has been ever
4198 ** been set for the Nth argument of the function, or if the corresponding
4199 ** function parameter has changed since the meta-data was set,
4200 ** then sqlite3_get_auxdata() returns a NULL pointer.
4201 **
4202 ** ^The sqlite3_set_auxdata(C,N,P,X) interface saves P as metadata for the N-th
4203 ** argument of the application-defined function. ^Subsequent
4204 ** calls to sqlite3_get_auxdata(C,N) return P from the most recent
4205 ** sqlite3_set_auxdata(C,N,P,X) call if the data has not been dropped, or
4206 ** NULL if the data has been dropped.
4207 ** ^(If it is not NULL, SQLite will invoke the destructor
4208 ** function X passed to sqlite3_set_auxdata(C,N,P,X) when <ul>
4209 ** <li> the corresponding function parameter changes,
4210 ** <li> [sqlite3_reset()] or [sqlite3_finalize()] is called for the
4211 ** SQL statement,
4212 ** <li> sqlite3_set_auxdata() is invoked again on the same parameter, or
4213 ** <li> a memory allocation error occurs. </ul>)^
4214 **
4215 ** SQLite is free to call the destructor and drop metadata on any
4216 ** parameter of any function at any time. ^The only guarantee is that
4217 ** the destructor will be called when the [prepared statement] is destroyed.
4218 ** Note in particular that the destructor X in the call to
4219 ** sqlite3_set_auxdata(C,N,P,X) might be called immediately, before
4220 ** the sqlite3_set_auxdata() call even returns. Hence sqlite3_set_auxdata()
4221 ** should be called near the end of the function implementation and the
4222 ** implementation should not make any use of P after sqlite3_set_auxdata()
4223 ** has been called.
4224 **
4225 ** ^(In practice, metadata is preserved between function calls for
4226 ** function parameters that are compile-time constants, including literal
4227 ** values and [parameters] and expressions composed from the same.)^
4228 **
4229 ** These routines must be called from the same thread in which
4230 ** the SQL function is running.
4231 */
4232 SQLITE_API void *sqlite3_get_auxdata(sqlite3_context*, int N);
@@ -5126,14 +5135,27 @@
5135 **
5136 ** ^Calling sqlite3_auto_extension(X) with an entry point X that is already
5137 ** on the list of automatic extensions is a harmless no-op. ^No entry point
5138 ** will be called more than once for each database connection that is opened.
5139 **
5140 ** See also: [sqlite3_reset_auto_extension()]
5141 ** and [sqlite3_cancel_auto_extension()]
5142 */
5143 SQLITE_API int sqlite3_auto_extension(void (*xEntryPoint)(void));
5144
5145 /*
5146 ** CAPI3REF: Cancel Automatic Extension Loading
5147 **
5148 ** ^The [sqlite3_cancel_auto_extension(X)] interface unregisters the
5149 ** initialization routine X that was registered using a prior call to
5150 ** [sqlite3_auto_extension(X)]. ^The [sqlite3_cancel_auto_extension(X)]
5151 ** routine returns 1 if initialization routine X was successfully
5152 ** unregistered and it returns 0 if X was not on the list of initialization
5153 ** routines.
5154 */
5155 SQLITE_API int sqlite3_cancel_auto_extension(void (*xEntryPoint)(void));
5156
5157 /*
5158 ** CAPI3REF: Reset Automatic Extension Loading
5159 **
5160 ** ^This interface disables all automatic extensions previously
5161 ** registered using [sqlite3_auto_extension()].
@@ -6242,10 +6264,16 @@
6264 ** transaction rollback or database recovery operations are not included.
6265 ** If an IO or other error occurs while writing a page to disk, the effect
6266 ** on subsequent SQLITE_DBSTATUS_CACHE_WRITE requests is undefined.)^ ^The
6267 ** highwater mark associated with SQLITE_DBSTATUS_CACHE_WRITE is always 0.
6268 ** </dd>
6269 **
6270 ** [[SQLITE_DBSTATUS_DEFERRED_FKS]] ^(<dt>SQLITE_DBSTATUS_DEFERRED_FKS</dt>
6271 ** <dd>This parameter returns the zero for the current value if and only if
6272 ** there all foreign key constraints (deferred or immediate) have been
6273 ** resolved. The highwater mark is always 0.
6274 ** </dd>
6275 ** </dl>
6276 */
6277 #define SQLITE_DBSTATUS_LOOKASIDE_USED 0
6278 #define SQLITE_DBSTATUS_CACHE_USED 1
6279 #define SQLITE_DBSTATUS_SCHEMA_USED 2
@@ -6254,11 +6282,12 @@
6282 #define SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE 5
6283 #define SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL 6
6284 #define SQLITE_DBSTATUS_CACHE_HIT 7
6285 #define SQLITE_DBSTATUS_CACHE_MISS 8
6286 #define SQLITE_DBSTATUS_CACHE_WRITE 9
6287 #define SQLITE_DBSTATUS_DEFERRED_FKS 10
6288 #define SQLITE_DBSTATUS_MAX 10 /* Largest defined DBSTATUS */
6289
6290
6291 /*
6292 ** CAPI3REF: Prepared Statement Status
6293 **
6294
+47 -9
--- src/style.c
+++ src/style.c
@@ -462,11 +462,11 @@
462462
;
463463
464464
/*
465465
** The default Cascading Style Sheet.
466466
** It's assembled by different strings for each class.
467
-** The default css conatains all definitions.
467
+** The default css contains all definitions.
468468
** The style sheet, send to the client only contains the ones,
469469
** not defined in the user defined css.
470470
*/
471471
const char zDefaultCSS[] =
472472
@ /* General settings for the entire page */
@@ -965,20 +965,43 @@
965965
{ "ul.filelist",
966966
"List of files in a timeline",
967967
@ margin-top: 3px;
968968
@ line-height: 100%;
969969
},
970
- { "div.sbsdiff",
971
- "side-by-side diff display",
972
- @ font-family: monospace;
970
+ { "table.sbsdiffcols",
971
+ "side-by-side diff display (column-based)",
972
+ @ border-spacing: 0;
973973
@ font-size: xx-small;
974
- @ white-space: pre;
974
+ },
975
+ { "table.sbsdiffcols td",
976
+ "sbs diff table cell",
977
+ @ padding: 0;
978
+ @ vertical-align: top;
979
+ },
980
+ { "table.sbsdiffcols pre",
981
+ "sbs diff pre block",
982
+ @ margin: 0;
983
+ @ padding: 0;
984
+ @ border: 0;
985
+ @ font-size: inherit;
986
+ @ background: inherit;
987
+ @ color: inherit;
988
+ },
989
+ { "div.difflncol",
990
+ "diff line number column",
991
+ @ padding-right: 1em;
992
+ @ text-align: right;
993
+ @ color: #a0a0a0;
994
+ },
995
+ { "div.difftxtcol",
996
+ "diff text column",
997
+ @ width: 45em;
998
+ @ overflow-x: auto;
975999
},
976
- { "div.udiff",
977
- "context diff display",
978
- @ font-family: monospace;
979
- @ white-space: pre;
1000
+ { "div.diffmkrcol",
1001
+ "diff marker column",
1002
+ @ padding: 0 1em;
9801003
},
9811004
{ "span.diffchng",
9821005
"changes in a diff",
9831006
@ background-color: #c0c0ff;
9841007
},
@@ -990,10 +1013,12 @@
9901013
"deleted in a diff",
9911014
@ background-color: #ffc8c8;
9921015
},
9931016
{ "span.diffhr",
9941017
"suppressed lines in a diff",
1018
+ @ display: inline-block;
1019
+ @ margin: .5em 0 1em;
9951020
@ color: #0000ff;
9961021
},
9971022
{ "span.diffln",
9981023
"line numbers in a diff",
9991024
@ color: #a0a0a0;
@@ -1033,10 +1058,23 @@
10331058
@ padding: 0.1em 1em 0.1em 1em;
10341059
},
10351060
{ ".statistics-report-row-year",
10361061
"",
10371062
@ text-align: left;
1063
+ },
1064
+ { ".statistics-report-graph-line",
1065
+ "for the /stats_report views",
1066
+ @ background-color: #446979;
1067
+ },
1068
+ { ".statistics-report-week-number-label",
1069
+ "for the /stats_report views",
1070
+ @ text-align: right;
1071
+ @ font-size: 0.8em;
1072
+ },
1073
+ { ".statistics-report-week-of-year-list",
1074
+ "for the /stats_report views",
1075
+ @ font-size: 0.8em;
10381076
},
10391077
{ "tr.row0",
10401078
"even table row color",
10411079
@ /* use default */
10421080
},
10431081
--- src/style.c
+++ src/style.c
@@ -462,11 +462,11 @@
462 ;
463
464 /*
465 ** The default Cascading Style Sheet.
466 ** It's assembled by different strings for each class.
467 ** The default css conatains all definitions.
468 ** The style sheet, send to the client only contains the ones,
469 ** not defined in the user defined css.
470 */
471 const char zDefaultCSS[] =
472 @ /* General settings for the entire page */
@@ -965,20 +965,43 @@
965 { "ul.filelist",
966 "List of files in a timeline",
967 @ margin-top: 3px;
968 @ line-height: 100%;
969 },
970 { "div.sbsdiff",
971 "side-by-side diff display",
972 @ font-family: monospace;
973 @ font-size: xx-small;
974 @ white-space: pre;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
975 },
976 { "div.udiff",
977 "context diff display",
978 @ font-family: monospace;
979 @ white-space: pre;
980 },
981 { "span.diffchng",
982 "changes in a diff",
983 @ background-color: #c0c0ff;
984 },
@@ -990,10 +1013,12 @@
990 "deleted in a diff",
991 @ background-color: #ffc8c8;
992 },
993 { "span.diffhr",
994 "suppressed lines in a diff",
 
 
995 @ color: #0000ff;
996 },
997 { "span.diffln",
998 "line numbers in a diff",
999 @ color: #a0a0a0;
@@ -1033,10 +1058,23 @@
1033 @ padding: 0.1em 1em 0.1em 1em;
1034 },
1035 { ".statistics-report-row-year",
1036 "",
1037 @ text-align: left;
 
 
 
 
 
 
 
 
 
 
 
 
 
1038 },
1039 { "tr.row0",
1040 "even table row color",
1041 @ /* use default */
1042 },
1043
--- src/style.c
+++ src/style.c
@@ -462,11 +462,11 @@
462 ;
463
464 /*
465 ** The default Cascading Style Sheet.
466 ** It's assembled by different strings for each class.
467 ** The default css contains all definitions.
468 ** The style sheet, send to the client only contains the ones,
469 ** not defined in the user defined css.
470 */
471 const char zDefaultCSS[] =
472 @ /* General settings for the entire page */
@@ -965,20 +965,43 @@
965 { "ul.filelist",
966 "List of files in a timeline",
967 @ margin-top: 3px;
968 @ line-height: 100%;
969 },
970 { "table.sbsdiffcols",
971 "side-by-side diff display (column-based)",
972 @ border-spacing: 0;
973 @ font-size: xx-small;
974 },
975 { "table.sbsdiffcols td",
976 "sbs diff table cell",
977 @ padding: 0;
978 @ vertical-align: top;
979 },
980 { "table.sbsdiffcols pre",
981 "sbs diff pre block",
982 @ margin: 0;
983 @ padding: 0;
984 @ border: 0;
985 @ font-size: inherit;
986 @ background: inherit;
987 @ color: inherit;
988 },
989 { "div.difflncol",
990 "diff line number column",
991 @ padding-right: 1em;
992 @ text-align: right;
993 @ color: #a0a0a0;
994 },
995 { "div.difftxtcol",
996 "diff text column",
997 @ width: 45em;
998 @ overflow-x: auto;
999 },
1000 { "div.diffmkrcol",
1001 "diff marker column",
1002 @ padding: 0 1em;
 
1003 },
1004 { "span.diffchng",
1005 "changes in a diff",
1006 @ background-color: #c0c0ff;
1007 },
@@ -990,10 +1013,12 @@
1013 "deleted in a diff",
1014 @ background-color: #ffc8c8;
1015 },
1016 { "span.diffhr",
1017 "suppressed lines in a diff",
1018 @ display: inline-block;
1019 @ margin: .5em 0 1em;
1020 @ color: #0000ff;
1021 },
1022 { "span.diffln",
1023 "line numbers in a diff",
1024 @ color: #a0a0a0;
@@ -1033,10 +1058,23 @@
1058 @ padding: 0.1em 1em 0.1em 1em;
1059 },
1060 { ".statistics-report-row-year",
1061 "",
1062 @ text-align: left;
1063 },
1064 { ".statistics-report-graph-line",
1065 "for the /stats_report views",
1066 @ background-color: #446979;
1067 },
1068 { ".statistics-report-week-number-label",
1069 "for the /stats_report views",
1070 @ text-align: right;
1071 @ font-size: 0.8em;
1072 },
1073 { ".statistics-report-week-of-year-list",
1074 "for the /stats_report views",
1075 @ font-size: 0.8em;
1076 },
1077 { "tr.row0",
1078 "even table row color",
1079 @ /* use default */
1080 },
1081
+228 -39
--- src/timeline.c
+++ src/timeline.c
@@ -1032,10 +1032,11 @@
10321032
const char *zTagName = P("t"); /* Show events with this tag */
10331033
const char *zBrName = P("r"); /* Show events related to this tag */
10341034
const char *zSearch = P("s"); /* Search string */
10351035
const char *zUses = P("uf"); /* Only show checkins hold this file */
10361036
const char *zYearMonth = P("ym"); /* Show checkins for the given YYYY-MM */
1037
+ const char *zYearWeek = P("yw"); /* Show checkins for the given YYYY-WW (weak-of-year) */
10371038
int useDividers = P("nd")==0; /* Show dividers if "nd" is missing */
10381039
int renameOnly = P("namechng")!=0; /* Show only checkins that rename files */
10391040
int tagid; /* Tag ID */
10401041
int tmFlags; /* Timeline flags */
10411042
const char *zThisTag = 0; /* Suppress links to this tag */
@@ -1218,10 +1219,14 @@
12181219
}
12191220
if( zYearMonth ){
12201221
blob_appendf(&sql, " AND %Q=strftime('%%Y-%%m',event.mtime) ",
12211222
zYearMonth);
12221223
}
1224
+ else if( zYearWeek ){
1225
+ blob_appendf(&sql, " AND %Q=strftime('%%Y-%%W',event.mtime) ",
1226
+ zYearWeek);
1227
+ }
12231228
if( tagid>0 ){
12241229
blob_appendf(&sql,
12251230
"AND (EXISTS(SELECT 1 FROM tagxref"
12261231
" WHERE tagid=%d AND tagtype>0 AND rid=blob.rid)", tagid);
12271232
@@ -1350,10 +1355,12 @@
13501355
db_multi_exec("%s", blob_str(&sql));
13511356
13521357
n = db_int(0, "SELECT count(*) FROM timeline WHERE etype!='div' /*scan*/");
13531358
if( zYearMonth ){
13541359
blob_appendf(&desc, "%s events for %h", zEType, zYearMonth);
1360
+ }else if( zYearWeek ){
1361
+ blob_appendf(&desc, "%s events for year/week %h", zEType, zYearWeek);
13551362
}else if( zAfter==0 && zBefore==0 && zCirca==0 ){
13561363
blob_appendf(&desc, "%d most recent %ss", n, zEType);
13571364
}else{
13581365
blob_appendf(&desc, "%d %ss", n, zEType);
13591366
}
@@ -1829,36 +1836,64 @@
18291836
}
18301837
db_finalize(&q);
18311838
style_footer();
18321839
}
18331840
1834
-
1841
+/*
1842
+** Helper for stats_report_by_month_year(), which generates a list of
1843
+** week numbers. zTimeframe should be either a timeframe in the form YYYY
1844
+** or YYYY-MM.
1845
+*/
1846
+static void stats_report_output_week_links(const char * zTimeframe){
1847
+ Stmt stWeek = empty_Stmt;
1848
+ char yearPart[5] = {0,0,0,0,0};
1849
+ memcpy(yearPart, zTimeframe, 4);
1850
+ db_prepare(&stWeek,
1851
+ "SELECT DISTINCT strftime('%%W',mtime) AS wk, "
1852
+ "count(*) AS n, "
1853
+ "substr(date(mtime),1,%d) AS ym "
1854
+ "FROM event "
1855
+ "WHERE ym=%Q AND mtime < current_timestamp "
1856
+ "GROUP BY wk ORDER BY wk",
1857
+ strlen(zTimeframe),
1858
+ zTimeframe);
1859
+ while( SQLITE_ROW == db_step(&stWeek) ){
1860
+ const char * zWeek = db_column_text(&stWeek,0);
1861
+ const int nCount = db_column_int(&stWeek,1);
1862
+ cgi_printf("<a href='%s/timeline?"
1863
+ "yw=%t-%t&n=%d'>%s</a>",
1864
+ g.zTop, yearPart, zWeek,
1865
+ nCount, zWeek);
1866
+ }
1867
+ db_finalize(&stWeek);
1868
+}
18351869
18361870
/*
18371871
** Implements the "byyear" and "bymonth" reports for /stats_report.
18381872
** If includeMonth is true then it generates the "bymonth" report,
18391873
** else the "byyear" report. If zUserName is not NULL and not empty
18401874
** then the report is restricted to events created by the named user
18411875
** account.
18421876
*/
18431877
static void stats_report_by_month_year(char includeMonth,
1844
- char const * zUserName){
1878
+ char includeWeeks,
1879
+ const char * zUserName){
18451880
Stmt query = empty_Stmt;
1846
- int const nPixelsPerEvent = 1; /* for sizing the "graph" part */
18471881
int nRowNumber = 0; /* current TR number */
18481882
int nEventTotal = 0; /* Total event count */
18491883
int rowClass = 0; /* counter for alternating
18501884
row colors */
18511885
Blob sql = empty_blob; /* SQL */
1852
- char const * zTimeLabel = includeMonth ? "Year/Month" : "Year";
1886
+ const char * zTimeLabel = includeMonth ? "Year/Month" : "Year";
18531887
char zPrevYear[5] = {0}; /* For keeping track of when
18541888
we change years while looping */
1855
- int nEventsPerYear = 0; /* Total even count for the
1889
+ int nEventsPerYear = 0; /* Total event count for the
18561890
current year */
18571891
char showYearTotal = 0; /* Flag telling us when to show
18581892
the per-year event totals */
18591893
Blob header = empty_blob; /* Page header text */
1894
+ int nMaxEvents = 1; /* for calculating length of graph bars. */
18601895
18611896
blob_appendf(&header, "Timeline Events by year%s",
18621897
(includeMonth ? "/month" : ""));
18631898
blob_appendf(&sql,
18641899
"SELECT substr(date(mtime),1,%d) AS timeframe, "
@@ -1879,18 +1914,31 @@
18791914
@ <table class='statistics-report-table-events' border='0' cellpadding='2'
18801915
@ cellspacing='0' id='statsTable'>
18811916
@ <thead>
18821917
@ <th>%s(zTimeLabel)</th>
18831918
@ <th>Events</th>
1884
- @ <th><!-- relative commits graph --></th>
1919
+ @ <th width='90%%'><!-- relative commits graph --></th>
18851920
@ </thead><tbody>
18861921
blob_reset(&header);
1922
+ /*
1923
+ Run the query twice. The first time we calculate the maximum
1924
+ number of events for a given row. Maybe someone with better SQL
1925
+ Fu can re-implement this with a single query.
1926
+ */
1927
+ while( SQLITE_ROW == db_step(&query) ){
1928
+ const int nCount = db_column_int(&query, 1);
1929
+ if(nCount>nMaxEvents){
1930
+ nMaxEvents = nCount;
1931
+ }
1932
+ }
1933
+ db_reset(&query);
18871934
while( SQLITE_ROW == db_step(&query) ){
1888
- char const * zTimeframe = db_column_text(&query, 0);
1889
- int const nCount = db_column_int(&query, 1);
1890
- int const nSize = 1 + ((nPixelsPerEvent * nCount)
1891
- / (includeMonth ? 1 : 10));
1935
+ const char * zTimeframe = db_column_text(&query, 0);
1936
+ const int nCount = db_column_int(&query, 1);
1937
+ const int nSize = nCount
1938
+ ? (int)(100 * nCount / nMaxEvents)
1939
+ : 1;
18921940
showYearTotal = 0;
18931941
if(includeMonth){
18941942
/* For Month/year view, add a separator for each distinct year. */
18951943
if(!*zPrevYear ||
18961944
(0!=fossil_strncmp(zPrevYear,zTimeframe,4))){
@@ -1906,17 +1954,17 @@
19061954
memcpy(zPrevYear,zTimeframe,4);
19071955
rowClass = ++nRowNumber % 2;
19081956
@ <tr class='row%d(rowClass)'>
19091957
@ <th colspan='3' class='statistics-report-row-year'>%s(zPrevYear)</th>
19101958
@ </tr>
1911
- }
1912
- }
1913
- rowClass = ++nRowNumber % 2;
1914
- nEventTotal += nCount;
1915
- nEventsPerYear += nCount;
1916
- @<tr class='row%d(rowClass)'>
1917
- @ <td>
1959
+ }
1960
+ }
1961
+ rowClass = ++nRowNumber % 2;
1962
+ nEventTotal += nCount;
1963
+ nEventsPerYear += nCount;
1964
+ @<tr class='row%d(rowClass)'>
1965
+ @ <td>
19181966
if(includeMonth){
19191967
cgi_printf("<a href='%s/timeline?"
19201968
"ym=%t&n=%d",
19211969
g.zTop, zTimeframe, nCount );
19221970
/* Reminder: n=nCount is not actually correct for bymonth unless
@@ -1925,41 +1973,51 @@
19251973
if( zUserName && *zUserName ){
19261974
cgi_printf("&u=%t", zUserName);
19271975
}
19281976
cgi_printf("' target='_new'>%s</a>",zTimeframe);
19291977
}else {
1930
- @ %s(zTimeframe)
1978
+ cgi_printf("<a href='?view=byweek&y=%s", zTimeframe);
1979
+ if(zUserName && *zUserName){
1980
+ cgi_printf("&u=%t", zUserName);
1981
+ }
1982
+ cgi_printf("'>%s</a>", zTimeframe);
19311983
}
19321984
@ </td><td>%d(nCount)</td>
19331985
@ <td>
19341986
@ <div class='statistics-report-graph-line'
1935
- @ style='height:16px;width:%d(nSize)px;'>
1987
+ @ style='height:16px;width:%d(nSize)%%;'>
19361988
@ </div></td>
19371989
@</tr>
1990
+ if(includeWeeks){
1991
+ /* This part works fine for months but it terribly slow (4.5s on my PC),
1992
+ so it's only shown for by-year for now. Suggestions/patches for
1993
+ a better/faster layout are welcomed. */
1994
+ @ <tr class='row%d(rowClass)'>
1995
+ @ <td colspan='2' class='statistics-report-week-number-label'>Week #:</td>
1996
+ @ <td class='statistics-report-week-of-year-list'>
1997
+ stats_report_output_week_links(zTimeframe);
1998
+ @ </td></tr>
1999
+ }
19382000
19392001
/*
19402002
Potential improvement: calculate the min/max event counts and
19412003
use percent-based graph bars.
19422004
*/
19432005
}
1944
-
2006
+ db_finalize(&query);
19452007
if(includeMonth && !showYearTotal && *zPrevYear){
19462008
/* Add final year total separator. */
19472009
rowClass = ++nRowNumber % 2;
19482010
@ <tr class='row%d(rowClass)'>
19492011
@ <td></td>
19502012
@ <td colspan='2'>Yearly total: %d(nEventsPerYear)</td>
19512013
@</tr>
19522014
}
1953
-#if 0
1954
- rowClass = ++nRowNumber % 2;
1955
- @ <tr class='row%d(rowClass)'>
1956
- @ <td colspan='3'>Total events: %d(nEventTotal)</td>
1957
- @ </tr>
1958
-#endif
19592015
@ </tbody></table>
1960
- db_finalize(&query);
2016
+ if(nEventTotal){
2017
+ @ <br><div>Total events: %d(nEventTotal)</div>
2018
+ }
19612019
if( !includeMonth ){
19622020
output_table_sorting_javascript("statsTable","tnx");
19632021
}
19642022
}
19652023
@@ -1966,16 +2024,17 @@
19662024
/*
19672025
** Implements the "byuser" view for /stats_report.
19682026
*/
19692027
static void stats_report_by_user(){
19702028
Stmt query = empty_Stmt;
1971
- int const nPixelsPerEvent = 1; /* for sizing the "graph" part */
19722029
int nRowNumber = 0; /* current TR number */
19732030
int nEventTotal = 0; /* Total event count */
19742031
int rowClass = 0; /* counter for alternating
19752032
row colors */
19762033
Blob sql = empty_blob; /* SQL */
2034
+ int nMaxEvents = 1; /* max number of events for
2035
+ all rows. */
19772036
blob_append(&sql,
19782037
"SELECT user, "
19792038
"COUNT(*) AS eventCount "
19802039
"FROM event "
19812040
"GROUP BY user ORDER BY eventCount DESC",
@@ -1986,26 +2045,35 @@
19862045
@ <table class='statistics-report-table-events' border='0'
19872046
@ cellpadding='2' cellspacing='0' id='statsTable'>
19882047
@ <thead><tr>
19892048
@ <th>User</th>
19902049
@ <th>Events</th>
1991
- @ <th><!-- relative commits graph --></th>
2050
+ @ <th width='90%%'><!-- relative commits graph --></th>
19922051
@ </tr></thead><tbody>
19932052
while( SQLITE_ROW == db_step(&query) ){
1994
- char const * zUser = db_column_text(&query, 0);
1995
- int const nCount = db_column_int(&query, 1);
1996
- int const nSize = 1+((nPixelsPerEvent * nCount) / 10);
1997
- if(!nCount) continue /* arguable! */;
2053
+ const int nCount = db_column_int(&query, 1);
2054
+ if(nCount>nMaxEvents){
2055
+ nMaxEvents = nCount;
2056
+ }
2057
+ }
2058
+ db_reset(&query);
2059
+ while( SQLITE_ROW == db_step(&query) ){
2060
+ const char * zUser = db_column_text(&query, 0);
2061
+ const int nCount = db_column_int(&query, 1);
2062
+ const int nSize = nCount
2063
+ ? (int)(100 * nCount / nMaxEvents)
2064
+ : 0;
2065
+ if(!nCount) continue /* arguable! Possible? */;
19982066
rowClass = ++nRowNumber % 2;
19992067
nEventTotal += nCount;
20002068
@<tr class='row%d(rowClass)'>
20012069
@ <td>
20022070
@ <a href="?view=bymonth&user=%h(zUser)" target="_new">%h(zUser)</a>
20032071
@ </td><td>%d(nCount)</td>
20042072
@ <td>
20052073
@ <div class='statistics-report-graph-line'
2006
- @ style='height:16px;width:%d(nSize)px;'>
2074
+ @ style='height:16px;width:%d(nSize)%%;'>
20072075
@ </div></td>
20082076
@</tr>
20092077
/*
20102078
Potential improvement: calculate the min/max event counts and
20112079
use percent-based graph bars.
@@ -2014,10 +2082,128 @@
20142082
@ </tbody></table>
20152083
db_finalize(&query);
20162084
output_table_sorting_javascript("statsTable","tnx");
20172085
}
20182086
2087
+
2088
+/*
2089
+** Helper for stats_report_by_month_year(), which generates a list of
2090
+** week numbers. zTimeframe should be either a timeframe in the form YYYY
2091
+** or YYYY-MM.
2092
+*/
2093
+static void stats_report_year_weeks(const char * zUserName){
2094
+ const char * zYear = P("y");
2095
+ int nYear = zYear ? strlen(zYear) : 0;
2096
+ int i = 0;
2097
+ Stmt qYears = empty_Stmt;
2098
+ char * zDefaultYear = NULL;
2099
+ Blob sql = empty_blob;
2100
+ int nMaxEvents = 1; /* max number of events for
2101
+ all rows. */
2102
+
2103
+ cgi_printf("Select year: ");
2104
+ blob_append(&sql,
2105
+ "SELECT DISTINCT substr(date(mtime),1,4) AS y "
2106
+ "FROM event WHERE 1 ", -1);
2107
+ if(zUserName&&*zUserName){
2108
+ blob_appendf(&sql,"AND user=%Q ", zUserName);
2109
+ }
2110
+ blob_append(&sql,"GROUP BY y ORDER BY y", -1);
2111
+ db_prepare(&qYears, blob_str(&sql));
2112
+ blob_reset(&sql);
2113
+ while( SQLITE_ROW == db_step(&qYears) ){
2114
+ const char * zT = db_column_text(&qYears, 0);
2115
+ if( i++ ){
2116
+ cgi_printf(" ");
2117
+ }
2118
+ cgi_printf("<a href='?view=byweek&y=%s", zT);
2119
+ if(zUserName && *zUserName){
2120
+ cgi_printf("&user=%t",zUserName);
2121
+ }
2122
+ cgi_printf("'>%s</a>",zT);
2123
+ }
2124
+ db_finalize(&qYears);
2125
+ cgi_printf("<br/>");
2126
+ if(!zYear || !*zYear){
2127
+ zDefaultYear = db_text("????", "SELECT strftime('%%Y')");
2128
+ zYear = zDefaultYear;
2129
+ nYear = 4;
2130
+ }
2131
+ if(4 == nYear){
2132
+ Stmt stWeek = empty_Stmt;
2133
+ int rowCount = 0;
2134
+ int total = 0;
2135
+ Blob header = empty_blob;
2136
+ blob_appendf(&header, "Timeline events for the calendar weeks "
2137
+ "of %h", zYear);
2138
+ blob_appendf(&sql,
2139
+ "SELECT DISTINCT strftime('%%%%W',mtime) AS wk, "
2140
+ "count(*) AS n "
2141
+ "FROM event "
2142
+ "WHERE %Q=substr(date(mtime),1,4) "
2143
+ "AND mtime < current_timestamp ",
2144
+ zYear);
2145
+ if(zUserName&&*zUserName){
2146
+ blob_appendf(&sql, " AND user=%Q ", zUserName);
2147
+ blob_appendf(&header," for user %h", zUserName);
2148
+ }
2149
+ blob_appendf(&sql, "GROUP BY wk ORDER BY wk DESC");
2150
+ cgi_printf("<h1>%h</h1>", blob_str(&header));
2151
+ blob_reset(&header);
2152
+ cgi_printf("<table class='statistics-report-table-events' "
2153
+ "border='0' cellpadding='2' width='100%%' "
2154
+ "cellspacing='0' id='statsTable'>");
2155
+ cgi_printf("<thead><tr>"
2156
+ "<th>Week</th>"
2157
+ "<th>Events</th>"
2158
+ "<th width='90%%'><!-- relative commits graph --></th>"
2159
+ "</tr></thead>"
2160
+ "<tbody>");
2161
+ db_prepare(&stWeek, blob_str(&sql));
2162
+ blob_reset(&sql);
2163
+ while( SQLITE_ROW == db_step(&stWeek) ){
2164
+ const int nCount = db_column_int(&stWeek, 1);
2165
+ if(nCount>nMaxEvents){
2166
+ nMaxEvents = nCount;
2167
+ }
2168
+ }
2169
+ db_reset(&stWeek);
2170
+ while( SQLITE_ROW == db_step(&stWeek) ){
2171
+ const char * zWeek = db_column_text(&stWeek,0);
2172
+ const int nCount = db_column_int(&stWeek,1);
2173
+ const int nSize = nCount
2174
+ ? (int)(100 * nCount / nMaxEvents)
2175
+ : 0;
2176
+ total += nCount;
2177
+ cgi_printf("<tr class='row%d'>", ++rowCount % 2 );
2178
+ cgi_printf("<td><a href='%s/timeline?yw=%t-%s&n=%d",
2179
+ g.zTop, zYear, zWeek, nCount);
2180
+ if(zUserName && *zUserName){
2181
+ cgi_printf("&u=%t",zUserName);
2182
+ }
2183
+ cgi_printf("'>%s</a></td>",zWeek);
2184
+
2185
+ cgi_printf("<td>%d</td>",nCount);
2186
+ cgi_printf("<td>");
2187
+ if(nCount){
2188
+ cgi_printf("<div class='statistics-report-graph-line'"
2189
+ "style='height:16px;width:%d%%;'></div>",
2190
+ nSize);
2191
+ }
2192
+ cgi_printf("</td></tr>");
2193
+ }
2194
+ db_finalize(&stWeek);
2195
+ free(zDefaultYear);
2196
+ cgi_printf("</tbody></table>");
2197
+ if(total){
2198
+ cgi_printf("<br><div>Total events: %d</div>",
2199
+ total);
2200
+ }
2201
+ output_table_sorting_javascript("statsTable","tnx");
2202
+ }
2203
+}
2204
+
20192205
/*
20202206
** WEBPAGE: stats_report
20212207
**
20222208
** Shows activity reports for the repository.
20232209
**
@@ -2026,37 +2212,40 @@
20262212
** view=REPORT_NAME Valid values: bymonth, byyear, byuser
20272213
** user=NAME Restricts statistics to the given user
20282214
*/
20292215
void stats_report_page(){
20302216
HQuery url; /* URL for various branch links */
2031
- char const * zView = P("view"); /* Which view/report to show. */
2032
- char const *zUserName = P("user");
2217
+ const char * zView = P("view"); /* Which view/report to show. */
2218
+ const char *zUserName = P("user");
2219
+ if(!zUserName) zUserName = P("u");
20332220
url_initialize(&url, "stats_report");
20342221
20352222
if(zUserName && *zUserName){
20362223
url_add_parameter(&url,"user", zUserName);
20372224
timeline_submenu(&url, "(Remove User Flag)", "view", zView, "user");
20382225
}
20392226
timeline_submenu(&url, "By Year", "view", "byyear", 0);
20402227
timeline_submenu(&url, "By Month", "view", "bymonth", 0);
2228
+ timeline_submenu(&url, "By Week", "view", "byweek", 0);
20412229
timeline_submenu(&url, "By User", "view", "byuser", "user");
20422230
url_reset(&url);
20432231
style_header("Activity Reports");
20442232
if(0==fossil_strcmp(zView,"byyear")){
2045
- stats_report_by_month_year(0, zUserName);
2233
+ stats_report_by_month_year(0, 0, zUserName);
20462234
}else if(0==fossil_strcmp(zView,"bymonth")){
2047
- stats_report_by_month_year(1, zUserName);
2235
+ stats_report_by_month_year(1, 0, zUserName);
20482236
}else if(0==fossil_strcmp(zView,"byweek")){
2049
- @ TODO: by-week report.
2237
+ stats_report_year_weeks(zUserName);
20502238
}else if(0==fossil_strcmp(zView,"byuser")){
20512239
stats_report_by_user();
20522240
}else{
20532241
@ <h1>Select a report to show:</h1>
20542242
@ <ul>
20552243
@ <li><a href='?view=byyear'>Events by year</a></li>
20562244
@ <li><a href='?view=bymonth'>Events by month</a></li>
2245
+ @ <li><a href='?view=byweek'>Events by calendar week</a></li>
20572246
@ <li><a href='?view=byuser'>Events by user</a></li>
20582247
@ </ul>
20592248
}
20602249
20612250
style_footer();
20622251
}
20632252
--- src/timeline.c
+++ src/timeline.c
@@ -1032,10 +1032,11 @@
1032 const char *zTagName = P("t"); /* Show events with this tag */
1033 const char *zBrName = P("r"); /* Show events related to this tag */
1034 const char *zSearch = P("s"); /* Search string */
1035 const char *zUses = P("uf"); /* Only show checkins hold this file */
1036 const char *zYearMonth = P("ym"); /* Show checkins for the given YYYY-MM */
 
1037 int useDividers = P("nd")==0; /* Show dividers if "nd" is missing */
1038 int renameOnly = P("namechng")!=0; /* Show only checkins that rename files */
1039 int tagid; /* Tag ID */
1040 int tmFlags; /* Timeline flags */
1041 const char *zThisTag = 0; /* Suppress links to this tag */
@@ -1218,10 +1219,14 @@
1218 }
1219 if( zYearMonth ){
1220 blob_appendf(&sql, " AND %Q=strftime('%%Y-%%m',event.mtime) ",
1221 zYearMonth);
1222 }
 
 
 
 
1223 if( tagid>0 ){
1224 blob_appendf(&sql,
1225 "AND (EXISTS(SELECT 1 FROM tagxref"
1226 " WHERE tagid=%d AND tagtype>0 AND rid=blob.rid)", tagid);
1227
@@ -1350,10 +1355,12 @@
1350 db_multi_exec("%s", blob_str(&sql));
1351
1352 n = db_int(0, "SELECT count(*) FROM timeline WHERE etype!='div' /*scan*/");
1353 if( zYearMonth ){
1354 blob_appendf(&desc, "%s events for %h", zEType, zYearMonth);
 
 
1355 }else if( zAfter==0 && zBefore==0 && zCirca==0 ){
1356 blob_appendf(&desc, "%d most recent %ss", n, zEType);
1357 }else{
1358 blob_appendf(&desc, "%d %ss", n, zEType);
1359 }
@@ -1829,36 +1836,64 @@
1829 }
1830 db_finalize(&q);
1831 style_footer();
1832 }
1833
1834
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1835
1836 /*
1837 ** Implements the "byyear" and "bymonth" reports for /stats_report.
1838 ** If includeMonth is true then it generates the "bymonth" report,
1839 ** else the "byyear" report. If zUserName is not NULL and not empty
1840 ** then the report is restricted to events created by the named user
1841 ** account.
1842 */
1843 static void stats_report_by_month_year(char includeMonth,
1844 char const * zUserName){
 
1845 Stmt query = empty_Stmt;
1846 int const nPixelsPerEvent = 1; /* for sizing the "graph" part */
1847 int nRowNumber = 0; /* current TR number */
1848 int nEventTotal = 0; /* Total event count */
1849 int rowClass = 0; /* counter for alternating
1850 row colors */
1851 Blob sql = empty_blob; /* SQL */
1852 char const * zTimeLabel = includeMonth ? "Year/Month" : "Year";
1853 char zPrevYear[5] = {0}; /* For keeping track of when
1854 we change years while looping */
1855 int nEventsPerYear = 0; /* Total even count for the
1856 current year */
1857 char showYearTotal = 0; /* Flag telling us when to show
1858 the per-year event totals */
1859 Blob header = empty_blob; /* Page header text */
 
1860
1861 blob_appendf(&header, "Timeline Events by year%s",
1862 (includeMonth ? "/month" : ""));
1863 blob_appendf(&sql,
1864 "SELECT substr(date(mtime),1,%d) AS timeframe, "
@@ -1879,18 +1914,31 @@
1879 @ <table class='statistics-report-table-events' border='0' cellpadding='2'
1880 @ cellspacing='0' id='statsTable'>
1881 @ <thead>
1882 @ <th>%s(zTimeLabel)</th>
1883 @ <th>Events</th>
1884 @ <th><!-- relative commits graph --></th>
1885 @ </thead><tbody>
1886 blob_reset(&header);
 
 
 
 
 
 
 
 
 
 
 
 
1887 while( SQLITE_ROW == db_step(&query) ){
1888 char const * zTimeframe = db_column_text(&query, 0);
1889 int const nCount = db_column_int(&query, 1);
1890 int const nSize = 1 + ((nPixelsPerEvent * nCount)
1891 / (includeMonth ? 1 : 10));
 
1892 showYearTotal = 0;
1893 if(includeMonth){
1894 /* For Month/year view, add a separator for each distinct year. */
1895 if(!*zPrevYear ||
1896 (0!=fossil_strncmp(zPrevYear,zTimeframe,4))){
@@ -1906,17 +1954,17 @@
1906 memcpy(zPrevYear,zTimeframe,4);
1907 rowClass = ++nRowNumber % 2;
1908 @ <tr class='row%d(rowClass)'>
1909 @ <th colspan='3' class='statistics-report-row-year'>%s(zPrevYear)</th>
1910 @ </tr>
1911 }
1912 }
1913 rowClass = ++nRowNumber % 2;
1914 nEventTotal += nCount;
1915 nEventsPerYear += nCount;
1916 @<tr class='row%d(rowClass)'>
1917 @ <td>
1918 if(includeMonth){
1919 cgi_printf("<a href='%s/timeline?"
1920 "ym=%t&n=%d",
1921 g.zTop, zTimeframe, nCount );
1922 /* Reminder: n=nCount is not actually correct for bymonth unless
@@ -1925,41 +1973,51 @@
1925 if( zUserName && *zUserName ){
1926 cgi_printf("&u=%t", zUserName);
1927 }
1928 cgi_printf("' target='_new'>%s</a>",zTimeframe);
1929 }else {
1930 @ %s(zTimeframe)
 
 
 
 
1931 }
1932 @ </td><td>%d(nCount)</td>
1933 @ <td>
1934 @ <div class='statistics-report-graph-line'
1935 @ style='height:16px;width:%d(nSize)px;'>
1936 @ </div></td>
1937 @</tr>
 
 
 
 
 
 
 
 
 
 
1938
1939 /*
1940 Potential improvement: calculate the min/max event counts and
1941 use percent-based graph bars.
1942 */
1943 }
1944
1945 if(includeMonth && !showYearTotal && *zPrevYear){
1946 /* Add final year total separator. */
1947 rowClass = ++nRowNumber % 2;
1948 @ <tr class='row%d(rowClass)'>
1949 @ <td></td>
1950 @ <td colspan='2'>Yearly total: %d(nEventsPerYear)</td>
1951 @</tr>
1952 }
1953 #if 0
1954 rowClass = ++nRowNumber % 2;
1955 @ <tr class='row%d(rowClass)'>
1956 @ <td colspan='3'>Total events: %d(nEventTotal)</td>
1957 @ </tr>
1958 #endif
1959 @ </tbody></table>
1960 db_finalize(&query);
 
 
1961 if( !includeMonth ){
1962 output_table_sorting_javascript("statsTable","tnx");
1963 }
1964 }
1965
@@ -1966,16 +2024,17 @@
1966 /*
1967 ** Implements the "byuser" view for /stats_report.
1968 */
1969 static void stats_report_by_user(){
1970 Stmt query = empty_Stmt;
1971 int const nPixelsPerEvent = 1; /* for sizing the "graph" part */
1972 int nRowNumber = 0; /* current TR number */
1973 int nEventTotal = 0; /* Total event count */
1974 int rowClass = 0; /* counter for alternating
1975 row colors */
1976 Blob sql = empty_blob; /* SQL */
 
 
1977 blob_append(&sql,
1978 "SELECT user, "
1979 "COUNT(*) AS eventCount "
1980 "FROM event "
1981 "GROUP BY user ORDER BY eventCount DESC",
@@ -1986,26 +2045,35 @@
1986 @ <table class='statistics-report-table-events' border='0'
1987 @ cellpadding='2' cellspacing='0' id='statsTable'>
1988 @ <thead><tr>
1989 @ <th>User</th>
1990 @ <th>Events</th>
1991 @ <th><!-- relative commits graph --></th>
1992 @ </tr></thead><tbody>
1993 while( SQLITE_ROW == db_step(&query) ){
1994 char const * zUser = db_column_text(&query, 0);
1995 int const nCount = db_column_int(&query, 1);
1996 int const nSize = 1+((nPixelsPerEvent * nCount) / 10);
1997 if(!nCount) continue /* arguable! */;
 
 
 
 
 
 
 
 
 
1998 rowClass = ++nRowNumber % 2;
1999 nEventTotal += nCount;
2000 @<tr class='row%d(rowClass)'>
2001 @ <td>
2002 @ <a href="?view=bymonth&user=%h(zUser)" target="_new">%h(zUser)</a>
2003 @ </td><td>%d(nCount)</td>
2004 @ <td>
2005 @ <div class='statistics-report-graph-line'
2006 @ style='height:16px;width:%d(nSize)px;'>
2007 @ </div></td>
2008 @</tr>
2009 /*
2010 Potential improvement: calculate the min/max event counts and
2011 use percent-based graph bars.
@@ -2014,10 +2082,128 @@
2014 @ </tbody></table>
2015 db_finalize(&query);
2016 output_table_sorting_javascript("statsTable","tnx");
2017 }
2018
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2019 /*
2020 ** WEBPAGE: stats_report
2021 **
2022 ** Shows activity reports for the repository.
2023 **
@@ -2026,37 +2212,40 @@
2026 ** view=REPORT_NAME Valid values: bymonth, byyear, byuser
2027 ** user=NAME Restricts statistics to the given user
2028 */
2029 void stats_report_page(){
2030 HQuery url; /* URL for various branch links */
2031 char const * zView = P("view"); /* Which view/report to show. */
2032 char const *zUserName = P("user");
 
2033 url_initialize(&url, "stats_report");
2034
2035 if(zUserName && *zUserName){
2036 url_add_parameter(&url,"user", zUserName);
2037 timeline_submenu(&url, "(Remove User Flag)", "view", zView, "user");
2038 }
2039 timeline_submenu(&url, "By Year", "view", "byyear", 0);
2040 timeline_submenu(&url, "By Month", "view", "bymonth", 0);
 
2041 timeline_submenu(&url, "By User", "view", "byuser", "user");
2042 url_reset(&url);
2043 style_header("Activity Reports");
2044 if(0==fossil_strcmp(zView,"byyear")){
2045 stats_report_by_month_year(0, zUserName);
2046 }else if(0==fossil_strcmp(zView,"bymonth")){
2047 stats_report_by_month_year(1, zUserName);
2048 }else if(0==fossil_strcmp(zView,"byweek")){
2049 @ TODO: by-week report.
2050 }else if(0==fossil_strcmp(zView,"byuser")){
2051 stats_report_by_user();
2052 }else{
2053 @ <h1>Select a report to show:</h1>
2054 @ <ul>
2055 @ <li><a href='?view=byyear'>Events by year</a></li>
2056 @ <li><a href='?view=bymonth'>Events by month</a></li>
 
2057 @ <li><a href='?view=byuser'>Events by user</a></li>
2058 @ </ul>
2059 }
2060
2061 style_footer();
2062 }
2063
--- src/timeline.c
+++ src/timeline.c
@@ -1032,10 +1032,11 @@
1032 const char *zTagName = P("t"); /* Show events with this tag */
1033 const char *zBrName = P("r"); /* Show events related to this tag */
1034 const char *zSearch = P("s"); /* Search string */
1035 const char *zUses = P("uf"); /* Only show checkins hold this file */
1036 const char *zYearMonth = P("ym"); /* Show checkins for the given YYYY-MM */
1037 const char *zYearWeek = P("yw"); /* Show checkins for the given YYYY-WW (weak-of-year) */
1038 int useDividers = P("nd")==0; /* Show dividers if "nd" is missing */
1039 int renameOnly = P("namechng")!=0; /* Show only checkins that rename files */
1040 int tagid; /* Tag ID */
1041 int tmFlags; /* Timeline flags */
1042 const char *zThisTag = 0; /* Suppress links to this tag */
@@ -1218,10 +1219,14 @@
1219 }
1220 if( zYearMonth ){
1221 blob_appendf(&sql, " AND %Q=strftime('%%Y-%%m',event.mtime) ",
1222 zYearMonth);
1223 }
1224 else if( zYearWeek ){
1225 blob_appendf(&sql, " AND %Q=strftime('%%Y-%%W',event.mtime) ",
1226 zYearWeek);
1227 }
1228 if( tagid>0 ){
1229 blob_appendf(&sql,
1230 "AND (EXISTS(SELECT 1 FROM tagxref"
1231 " WHERE tagid=%d AND tagtype>0 AND rid=blob.rid)", tagid);
1232
@@ -1350,10 +1355,12 @@
1355 db_multi_exec("%s", blob_str(&sql));
1356
1357 n = db_int(0, "SELECT count(*) FROM timeline WHERE etype!='div' /*scan*/");
1358 if( zYearMonth ){
1359 blob_appendf(&desc, "%s events for %h", zEType, zYearMonth);
1360 }else if( zYearWeek ){
1361 blob_appendf(&desc, "%s events for year/week %h", zEType, zYearWeek);
1362 }else if( zAfter==0 && zBefore==0 && zCirca==0 ){
1363 blob_appendf(&desc, "%d most recent %ss", n, zEType);
1364 }else{
1365 blob_appendf(&desc, "%d %ss", n, zEType);
1366 }
@@ -1829,36 +1836,64 @@
1836 }
1837 db_finalize(&q);
1838 style_footer();
1839 }
1840
1841 /*
1842 ** Helper for stats_report_by_month_year(), which generates a list of
1843 ** week numbers. zTimeframe should be either a timeframe in the form YYYY
1844 ** or YYYY-MM.
1845 */
1846 static void stats_report_output_week_links(const char * zTimeframe){
1847 Stmt stWeek = empty_Stmt;
1848 char yearPart[5] = {0,0,0,0,0};
1849 memcpy(yearPart, zTimeframe, 4);
1850 db_prepare(&stWeek,
1851 "SELECT DISTINCT strftime('%%W',mtime) AS wk, "
1852 "count(*) AS n, "
1853 "substr(date(mtime),1,%d) AS ym "
1854 "FROM event "
1855 "WHERE ym=%Q AND mtime < current_timestamp "
1856 "GROUP BY wk ORDER BY wk",
1857 strlen(zTimeframe),
1858 zTimeframe);
1859 while( SQLITE_ROW == db_step(&stWeek) ){
1860 const char * zWeek = db_column_text(&stWeek,0);
1861 const int nCount = db_column_int(&stWeek,1);
1862 cgi_printf("<a href='%s/timeline?"
1863 "yw=%t-%t&n=%d'>%s</a>",
1864 g.zTop, yearPart, zWeek,
1865 nCount, zWeek);
1866 }
1867 db_finalize(&stWeek);
1868 }
1869
1870 /*
1871 ** Implements the "byyear" and "bymonth" reports for /stats_report.
1872 ** If includeMonth is true then it generates the "bymonth" report,
1873 ** else the "byyear" report. If zUserName is not NULL and not empty
1874 ** then the report is restricted to events created by the named user
1875 ** account.
1876 */
1877 static void stats_report_by_month_year(char includeMonth,
1878 char includeWeeks,
1879 const char * zUserName){
1880 Stmt query = empty_Stmt;
 
1881 int nRowNumber = 0; /* current TR number */
1882 int nEventTotal = 0; /* Total event count */
1883 int rowClass = 0; /* counter for alternating
1884 row colors */
1885 Blob sql = empty_blob; /* SQL */
1886 const char * zTimeLabel = includeMonth ? "Year/Month" : "Year";
1887 char zPrevYear[5] = {0}; /* For keeping track of when
1888 we change years while looping */
1889 int nEventsPerYear = 0; /* Total event count for the
1890 current year */
1891 char showYearTotal = 0; /* Flag telling us when to show
1892 the per-year event totals */
1893 Blob header = empty_blob; /* Page header text */
1894 int nMaxEvents = 1; /* for calculating length of graph bars. */
1895
1896 blob_appendf(&header, "Timeline Events by year%s",
1897 (includeMonth ? "/month" : ""));
1898 blob_appendf(&sql,
1899 "SELECT substr(date(mtime),1,%d) AS timeframe, "
@@ -1879,18 +1914,31 @@
1914 @ <table class='statistics-report-table-events' border='0' cellpadding='2'
1915 @ cellspacing='0' id='statsTable'>
1916 @ <thead>
1917 @ <th>%s(zTimeLabel)</th>
1918 @ <th>Events</th>
1919 @ <th width='90%%'><!-- relative commits graph --></th>
1920 @ </thead><tbody>
1921 blob_reset(&header);
1922 /*
1923 Run the query twice. The first time we calculate the maximum
1924 number of events for a given row. Maybe someone with better SQL
1925 Fu can re-implement this with a single query.
1926 */
1927 while( SQLITE_ROW == db_step(&query) ){
1928 const int nCount = db_column_int(&query, 1);
1929 if(nCount>nMaxEvents){
1930 nMaxEvents = nCount;
1931 }
1932 }
1933 db_reset(&query);
1934 while( SQLITE_ROW == db_step(&query) ){
1935 const char * zTimeframe = db_column_text(&query, 0);
1936 const int nCount = db_column_int(&query, 1);
1937 const int nSize = nCount
1938 ? (int)(100 * nCount / nMaxEvents)
1939 : 1;
1940 showYearTotal = 0;
1941 if(includeMonth){
1942 /* For Month/year view, add a separator for each distinct year. */
1943 if(!*zPrevYear ||
1944 (0!=fossil_strncmp(zPrevYear,zTimeframe,4))){
@@ -1906,17 +1954,17 @@
1954 memcpy(zPrevYear,zTimeframe,4);
1955 rowClass = ++nRowNumber % 2;
1956 @ <tr class='row%d(rowClass)'>
1957 @ <th colspan='3' class='statistics-report-row-year'>%s(zPrevYear)</th>
1958 @ </tr>
1959 }
1960 }
1961 rowClass = ++nRowNumber % 2;
1962 nEventTotal += nCount;
1963 nEventsPerYear += nCount;
1964 @<tr class='row%d(rowClass)'>
1965 @ <td>
1966 if(includeMonth){
1967 cgi_printf("<a href='%s/timeline?"
1968 "ym=%t&n=%d",
1969 g.zTop, zTimeframe, nCount );
1970 /* Reminder: n=nCount is not actually correct for bymonth unless
@@ -1925,41 +1973,51 @@
1973 if( zUserName && *zUserName ){
1974 cgi_printf("&u=%t", zUserName);
1975 }
1976 cgi_printf("' target='_new'>%s</a>",zTimeframe);
1977 }else {
1978 cgi_printf("<a href='?view=byweek&y=%s", zTimeframe);
1979 if(zUserName && *zUserName){
1980 cgi_printf("&u=%t", zUserName);
1981 }
1982 cgi_printf("'>%s</a>", zTimeframe);
1983 }
1984 @ </td><td>%d(nCount)</td>
1985 @ <td>
1986 @ <div class='statistics-report-graph-line'
1987 @ style='height:16px;width:%d(nSize)%%;'>
1988 @ </div></td>
1989 @</tr>
1990 if(includeWeeks){
1991 /* This part works fine for months but it terribly slow (4.5s on my PC),
1992 so it's only shown for by-year for now. Suggestions/patches for
1993 a better/faster layout are welcomed. */
1994 @ <tr class='row%d(rowClass)'>
1995 @ <td colspan='2' class='statistics-report-week-number-label'>Week #:</td>
1996 @ <td class='statistics-report-week-of-year-list'>
1997 stats_report_output_week_links(zTimeframe);
1998 @ </td></tr>
1999 }
2000
2001 /*
2002 Potential improvement: calculate the min/max event counts and
2003 use percent-based graph bars.
2004 */
2005 }
2006 db_finalize(&query);
2007 if(includeMonth && !showYearTotal && *zPrevYear){
2008 /* Add final year total separator. */
2009 rowClass = ++nRowNumber % 2;
2010 @ <tr class='row%d(rowClass)'>
2011 @ <td></td>
2012 @ <td colspan='2'>Yearly total: %d(nEventsPerYear)</td>
2013 @</tr>
2014 }
 
 
 
 
 
 
2015 @ </tbody></table>
2016 if(nEventTotal){
2017 @ <br><div>Total events: %d(nEventTotal)</div>
2018 }
2019 if( !includeMonth ){
2020 output_table_sorting_javascript("statsTable","tnx");
2021 }
2022 }
2023
@@ -1966,16 +2024,17 @@
2024 /*
2025 ** Implements the "byuser" view for /stats_report.
2026 */
2027 static void stats_report_by_user(){
2028 Stmt query = empty_Stmt;
 
2029 int nRowNumber = 0; /* current TR number */
2030 int nEventTotal = 0; /* Total event count */
2031 int rowClass = 0; /* counter for alternating
2032 row colors */
2033 Blob sql = empty_blob; /* SQL */
2034 int nMaxEvents = 1; /* max number of events for
2035 all rows. */
2036 blob_append(&sql,
2037 "SELECT user, "
2038 "COUNT(*) AS eventCount "
2039 "FROM event "
2040 "GROUP BY user ORDER BY eventCount DESC",
@@ -1986,26 +2045,35 @@
2045 @ <table class='statistics-report-table-events' border='0'
2046 @ cellpadding='2' cellspacing='0' id='statsTable'>
2047 @ <thead><tr>
2048 @ <th>User</th>
2049 @ <th>Events</th>
2050 @ <th width='90%%'><!-- relative commits graph --></th>
2051 @ </tr></thead><tbody>
2052 while( SQLITE_ROW == db_step(&query) ){
2053 const int nCount = db_column_int(&query, 1);
2054 if(nCount>nMaxEvents){
2055 nMaxEvents = nCount;
2056 }
2057 }
2058 db_reset(&query);
2059 while( SQLITE_ROW == db_step(&query) ){
2060 const char * zUser = db_column_text(&query, 0);
2061 const int nCount = db_column_int(&query, 1);
2062 const int nSize = nCount
2063 ? (int)(100 * nCount / nMaxEvents)
2064 : 0;
2065 if(!nCount) continue /* arguable! Possible? */;
2066 rowClass = ++nRowNumber % 2;
2067 nEventTotal += nCount;
2068 @<tr class='row%d(rowClass)'>
2069 @ <td>
2070 @ <a href="?view=bymonth&user=%h(zUser)" target="_new">%h(zUser)</a>
2071 @ </td><td>%d(nCount)</td>
2072 @ <td>
2073 @ <div class='statistics-report-graph-line'
2074 @ style='height:16px;width:%d(nSize)%%;'>
2075 @ </div></td>
2076 @</tr>
2077 /*
2078 Potential improvement: calculate the min/max event counts and
2079 use percent-based graph bars.
@@ -2014,10 +2082,128 @@
2082 @ </tbody></table>
2083 db_finalize(&query);
2084 output_table_sorting_javascript("statsTable","tnx");
2085 }
2086
2087
2088 /*
2089 ** Helper for stats_report_by_month_year(), which generates a list of
2090 ** week numbers. zTimeframe should be either a timeframe in the form YYYY
2091 ** or YYYY-MM.
2092 */
2093 static void stats_report_year_weeks(const char * zUserName){
2094 const char * zYear = P("y");
2095 int nYear = zYear ? strlen(zYear) : 0;
2096 int i = 0;
2097 Stmt qYears = empty_Stmt;
2098 char * zDefaultYear = NULL;
2099 Blob sql = empty_blob;
2100 int nMaxEvents = 1; /* max number of events for
2101 all rows. */
2102
2103 cgi_printf("Select year: ");
2104 blob_append(&sql,
2105 "SELECT DISTINCT substr(date(mtime),1,4) AS y "
2106 "FROM event WHERE 1 ", -1);
2107 if(zUserName&&*zUserName){
2108 blob_appendf(&sql,"AND user=%Q ", zUserName);
2109 }
2110 blob_append(&sql,"GROUP BY y ORDER BY y", -1);
2111 db_prepare(&qYears, blob_str(&sql));
2112 blob_reset(&sql);
2113 while( SQLITE_ROW == db_step(&qYears) ){
2114 const char * zT = db_column_text(&qYears, 0);
2115 if( i++ ){
2116 cgi_printf(" ");
2117 }
2118 cgi_printf("<a href='?view=byweek&y=%s", zT);
2119 if(zUserName && *zUserName){
2120 cgi_printf("&user=%t",zUserName);
2121 }
2122 cgi_printf("'>%s</a>",zT);
2123 }
2124 db_finalize(&qYears);
2125 cgi_printf("<br/>");
2126 if(!zYear || !*zYear){
2127 zDefaultYear = db_text("????", "SELECT strftime('%%Y')");
2128 zYear = zDefaultYear;
2129 nYear = 4;
2130 }
2131 if(4 == nYear){
2132 Stmt stWeek = empty_Stmt;
2133 int rowCount = 0;
2134 int total = 0;
2135 Blob header = empty_blob;
2136 blob_appendf(&header, "Timeline events for the calendar weeks "
2137 "of %h", zYear);
2138 blob_appendf(&sql,
2139 "SELECT DISTINCT strftime('%%%%W',mtime) AS wk, "
2140 "count(*) AS n "
2141 "FROM event "
2142 "WHERE %Q=substr(date(mtime),1,4) "
2143 "AND mtime < current_timestamp ",
2144 zYear);
2145 if(zUserName&&*zUserName){
2146 blob_appendf(&sql, " AND user=%Q ", zUserName);
2147 blob_appendf(&header," for user %h", zUserName);
2148 }
2149 blob_appendf(&sql, "GROUP BY wk ORDER BY wk DESC");
2150 cgi_printf("<h1>%h</h1>", blob_str(&header));
2151 blob_reset(&header);
2152 cgi_printf("<table class='statistics-report-table-events' "
2153 "border='0' cellpadding='2' width='100%%' "
2154 "cellspacing='0' id='statsTable'>");
2155 cgi_printf("<thead><tr>"
2156 "<th>Week</th>"
2157 "<th>Events</th>"
2158 "<th width='90%%'><!-- relative commits graph --></th>"
2159 "</tr></thead>"
2160 "<tbody>");
2161 db_prepare(&stWeek, blob_str(&sql));
2162 blob_reset(&sql);
2163 while( SQLITE_ROW == db_step(&stWeek) ){
2164 const int nCount = db_column_int(&stWeek, 1);
2165 if(nCount>nMaxEvents){
2166 nMaxEvents = nCount;
2167 }
2168 }
2169 db_reset(&stWeek);
2170 while( SQLITE_ROW == db_step(&stWeek) ){
2171 const char * zWeek = db_column_text(&stWeek,0);
2172 const int nCount = db_column_int(&stWeek,1);
2173 const int nSize = nCount
2174 ? (int)(100 * nCount / nMaxEvents)
2175 : 0;
2176 total += nCount;
2177 cgi_printf("<tr class='row%d'>", ++rowCount % 2 );
2178 cgi_printf("<td><a href='%s/timeline?yw=%t-%s&n=%d",
2179 g.zTop, zYear, zWeek, nCount);
2180 if(zUserName && *zUserName){
2181 cgi_printf("&u=%t",zUserName);
2182 }
2183 cgi_printf("'>%s</a></td>",zWeek);
2184
2185 cgi_printf("<td>%d</td>",nCount);
2186 cgi_printf("<td>");
2187 if(nCount){
2188 cgi_printf("<div class='statistics-report-graph-line'"
2189 "style='height:16px;width:%d%%;'></div>",
2190 nSize);
2191 }
2192 cgi_printf("</td></tr>");
2193 }
2194 db_finalize(&stWeek);
2195 free(zDefaultYear);
2196 cgi_printf("</tbody></table>");
2197 if(total){
2198 cgi_printf("<br><div>Total events: %d</div>",
2199 total);
2200 }
2201 output_table_sorting_javascript("statsTable","tnx");
2202 }
2203 }
2204
2205 /*
2206 ** WEBPAGE: stats_report
2207 **
2208 ** Shows activity reports for the repository.
2209 **
@@ -2026,37 +2212,40 @@
2212 ** view=REPORT_NAME Valid values: bymonth, byyear, byuser
2213 ** user=NAME Restricts statistics to the given user
2214 */
2215 void stats_report_page(){
2216 HQuery url; /* URL for various branch links */
2217 const char * zView = P("view"); /* Which view/report to show. */
2218 const char *zUserName = P("user");
2219 if(!zUserName) zUserName = P("u");
2220 url_initialize(&url, "stats_report");
2221
2222 if(zUserName && *zUserName){
2223 url_add_parameter(&url,"user", zUserName);
2224 timeline_submenu(&url, "(Remove User Flag)", "view", zView, "user");
2225 }
2226 timeline_submenu(&url, "By Year", "view", "byyear", 0);
2227 timeline_submenu(&url, "By Month", "view", "bymonth", 0);
2228 timeline_submenu(&url, "By Week", "view", "byweek", 0);
2229 timeline_submenu(&url, "By User", "view", "byuser", "user");
2230 url_reset(&url);
2231 style_header("Activity Reports");
2232 if(0==fossil_strcmp(zView,"byyear")){
2233 stats_report_by_month_year(0, 0, zUserName);
2234 }else if(0==fossil_strcmp(zView,"bymonth")){
2235 stats_report_by_month_year(1, 0, zUserName);
2236 }else if(0==fossil_strcmp(zView,"byweek")){
2237 stats_report_year_weeks(zUserName);
2238 }else if(0==fossil_strcmp(zView,"byuser")){
2239 stats_report_by_user();
2240 }else{
2241 @ <h1>Select a report to show:</h1>
2242 @ <ul>
2243 @ <li><a href='?view=byyear'>Events by year</a></li>
2244 @ <li><a href='?view=bymonth'>Events by month</a></li>
2245 @ <li><a href='?view=byweek'>Events by calendar week</a></li>
2246 @ <li><a href='?view=byuser'>Events by user</a></li>
2247 @ </ul>
2248 }
2249
2250 style_footer();
2251 }
2252
--- src/translate.c
+++ src/translate.c
@@ -30,10 +30,25 @@
3030
**
3131
** This tool allows us to put raw HTML, without the special codes, in
3232
** the middle of a C program. This program then translates the text
3333
** into standard C by inserting all necessary backslashes and other
3434
** punctuation.
35
+**
36
+** Enhancement #1:
37
+**
38
+** If the last non-whitespace character prior to the first "@" of a
39
+** @-block is "=" or "," then the @-block is a string literal initializer
40
+** rather than text that is to be output via cgi_printf(). Render it
41
+** as such.
42
+**
43
+** Enhancement #2:
44
+**
45
+** Comments of the form: "/* @-comment: CC" cause CC to become a
46
+** comment character for the @-substitution. Typical values for CC are
47
+** "--" (for SQL text) or "#" (for TCL script) or "//" (for C++ code).
48
+** Lines of subsequent @-blocks that begin with CC are omitted from the
49
+** output.
3550
**
3651
*/
3752
#include <stdio.h>
3853
#include <ctype.h>
3954
#include <stdlib.h>
4055
--- src/translate.c
+++ src/translate.c
@@ -30,10 +30,25 @@
30 **
31 ** This tool allows us to put raw HTML, without the special codes, in
32 ** the middle of a C program. This program then translates the text
33 ** into standard C by inserting all necessary backslashes and other
34 ** punctuation.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35 **
36 */
37 #include <stdio.h>
38 #include <ctype.h>
39 #include <stdlib.h>
40
--- src/translate.c
+++ src/translate.c
@@ -30,10 +30,25 @@
30 **
31 ** This tool allows us to put raw HTML, without the special codes, in
32 ** the middle of a C program. This program then translates the text
33 ** into standard C by inserting all necessary backslashes and other
34 ** punctuation.
35 **
36 ** Enhancement #1:
37 **
38 ** If the last non-whitespace character prior to the first "@" of a
39 ** @-block is "=" or "," then the @-block is a string literal initializer
40 ** rather than text that is to be output via cgi_printf(). Render it
41 ** as such.
42 **
43 ** Enhancement #2:
44 **
45 ** Comments of the form: "/* @-comment: CC" cause CC to become a
46 ** comment character for the @-substitution. Typical values for CC are
47 ** "--" (for SQL text) or "#" (for TCL script) or "//" (for C++ code).
48 ** Lines of subsequent @-blocks that begin with CC are omitted from the
49 ** output.
50 **
51 */
52 #include <stdio.h>
53 #include <ctype.h>
54 #include <stdlib.h>
55
+2 -2
--- src/wiki.c
+++ src/wiki.c
@@ -786,13 +786,13 @@
786786
blob_init(&w2, pW2->zWiki, -1);
787787
}
788788
blob_zero(&d);
789789
diffFlags = construct_diff_flags(1,0);
790790
text_diff(&w2, &w1, &d, 0, diffFlags | DIFF_HTML | DIFF_LINENO);
791
- @ <div class="udiff">
791
+ @ <pre class="udiff">
792792
@ %s(blob_str(&d))
793
- @ </div>
793
+ @ <pre>
794794
manifest_destroy(pW1);
795795
manifest_destroy(pW2);
796796
style_footer();
797797
}
798798
799799
--- src/wiki.c
+++ src/wiki.c
@@ -786,13 +786,13 @@
786 blob_init(&w2, pW2->zWiki, -1);
787 }
788 blob_zero(&d);
789 diffFlags = construct_diff_flags(1,0);
790 text_diff(&w2, &w1, &d, 0, diffFlags | DIFF_HTML | DIFF_LINENO);
791 @ <div class="udiff">
792 @ %s(blob_str(&d))
793 @ </div>
794 manifest_destroy(pW1);
795 manifest_destroy(pW2);
796 style_footer();
797 }
798
799
--- src/wiki.c
+++ src/wiki.c
@@ -786,13 +786,13 @@
786 blob_init(&w2, pW2->zWiki, -1);
787 }
788 blob_zero(&d);
789 diffFlags = construct_diff_flags(1,0);
790 text_diff(&w2, &w1, &d, 0, diffFlags | DIFF_HTML | DIFF_LINENO);
791 @ <pre class="udiff">
792 @ %s(blob_str(&d))
793 @ <pre>
794 manifest_destroy(pW1);
795 manifest_destroy(pW2);
796 style_footer();
797 }
798
799
--- test/diff-test-1.wiki
+++ test/diff-test-1.wiki
@@ -2,11 +2,11 @@
22
33
This page contains list of URLs of interesting diffs.
44
Click on all URLs, one by one, to verify
55
the correct operation of the diff logic.
66
7
- * <a href="../../../info/030035345c#chunk59" target="testwindow">
7
+ * <a href="../../../info/030035345c#chunk73" target="testwindow">
88
Multiple edits on a single line.</a> This is an SQLite version
99
update diff. It is a large diff and contains many other interesting
1010
features. Scan the whole diff.
1111
* <a href="../../../fdiff?v1=6da016415dc52d61&v2=af6df3466e3c4a88"
1212
target="testwindow">Tricky alignment and multiple edits per line</a>.
@@ -15,12 +15,12 @@
1515
* <a href="../../../fdiff?v1=d1c60722e0b9d775&v2=58d1a8991bacb113"
1616
target="testwindow">Column alignment with multibyte characters.</a>
1717
The edit of a line with multibyte characters is the first chunk.
1818
* <a href="../../../fdiff?v1=57b0d8183cab0e3d&v2=37b3ef49d73cdfe6"
1919
target="testwindow">Large diff of sqlite3.c</a>. This diff was very
20
- slow prior to the preformance enhancement change [9e15437e97].
21
- * <a href="../../../info/bda00cbada#chunk42" target="testwindow">
20
+ slow prior to the performance enhancement change [9e15437e97].
21
+ * <a href="../../../info/bda00cbada#chunk49" target="testwindow">
2222
A difficult indentation change.
2323
* <a href="../../../fdiff?v1=955cc67ace8fb622&v2=e2e1c87b86664b45#chunk13"
2424
target="testwindow">Another tricky indentation.</a> Notice especially
2525
lines 59398 and 59407 on the left.
2626
* <a href="../../../fdiff?v2=955cc67ace8fb622&v1=e2e1c87b86664b45#chunk13"
2727
--- test/diff-test-1.wiki
+++ test/diff-test-1.wiki
@@ -2,11 +2,11 @@
2
3 This page contains list of URLs of interesting diffs.
4 Click on all URLs, one by one, to verify
5 the correct operation of the diff logic.
6
7 * <a href="../../../info/030035345c#chunk59" target="testwindow">
8 Multiple edits on a single line.</a> This is an SQLite version
9 update diff. It is a large diff and contains many other interesting
10 features. Scan the whole diff.
11 * <a href="../../../fdiff?v1=6da016415dc52d61&v2=af6df3466e3c4a88"
12 target="testwindow">Tricky alignment and multiple edits per line</a>.
@@ -15,12 +15,12 @@
15 * <a href="../../../fdiff?v1=d1c60722e0b9d775&v2=58d1a8991bacb113"
16 target="testwindow">Column alignment with multibyte characters.</a>
17 The edit of a line with multibyte characters is the first chunk.
18 * <a href="../../../fdiff?v1=57b0d8183cab0e3d&v2=37b3ef49d73cdfe6"
19 target="testwindow">Large diff of sqlite3.c</a>. This diff was very
20 slow prior to the preformance enhancement change [9e15437e97].
21 * <a href="../../../info/bda00cbada#chunk42" target="testwindow">
22 A difficult indentation change.
23 * <a href="../../../fdiff?v1=955cc67ace8fb622&v2=e2e1c87b86664b45#chunk13"
24 target="testwindow">Another tricky indentation.</a> Notice especially
25 lines 59398 and 59407 on the left.
26 * <a href="../../../fdiff?v2=955cc67ace8fb622&v1=e2e1c87b86664b45#chunk13"
27
--- test/diff-test-1.wiki
+++ test/diff-test-1.wiki
@@ -2,11 +2,11 @@
2
3 This page contains list of URLs of interesting diffs.
4 Click on all URLs, one by one, to verify
5 the correct operation of the diff logic.
6
7 * <a href="../../../info/030035345c#chunk73" target="testwindow">
8 Multiple edits on a single line.</a> This is an SQLite version
9 update diff. It is a large diff and contains many other interesting
10 features. Scan the whole diff.
11 * <a href="../../../fdiff?v1=6da016415dc52d61&v2=af6df3466e3c4a88"
12 target="testwindow">Tricky alignment and multiple edits per line</a>.
@@ -15,12 +15,12 @@
15 * <a href="../../../fdiff?v1=d1c60722e0b9d775&v2=58d1a8991bacb113"
16 target="testwindow">Column alignment with multibyte characters.</a>
17 The edit of a line with multibyte characters is the first chunk.
18 * <a href="../../../fdiff?v1=57b0d8183cab0e3d&v2=37b3ef49d73cdfe6"
19 target="testwindow">Large diff of sqlite3.c</a>. This diff was very
20 slow prior to the performance enhancement change [9e15437e97].
21 * <a href="../../../info/bda00cbada#chunk49" target="testwindow">
22 A difficult indentation change.
23 * <a href="../../../fdiff?v1=955cc67ace8fb622&v2=e2e1c87b86664b45#chunk13"
24 target="testwindow">Another tricky indentation.</a> Notice especially
25 lines 59398 and 59407 on the left.
26 * <a href="../../../fdiff?v2=955cc67ace8fb622&v1=e2e1c87b86664b45#chunk13"
27
+14 -14
--- test/merge1.test
+++ test/merge1.test
@@ -44,13 +44,13 @@
4444
222 - The second line program line in code - 2222
4545
333 - This is a test OF THE merging algohm - 3333
4646
444 - If all goes well, we will be pleased - 4444
4747
555 - we think it well and other stuff too - 5555
4848
}
49
-fossil test-3 t1 t3 t2 a32
49
+fossil 3-way-merge t1 t3 t2 a32
5050
test merge1-1.1 {[same_file t23 a32]}
51
-fossil test-3 t1 t2 t3 a23
51
+fossil 3-way-merge t1 t2 t3 a23
5252
test merge1-1.2 {[same_file t23 a23]}
5353
5454
write_file_indented t1 {
5555
111 - This is line one of the demo program - 1111
5656
222 - The second line program line in code - 2222
@@ -96,13 +96,13 @@
9696
222 - The second line program line in code - 2222
9797
333 - This is a test of the merging algohm - 3333
9898
444 - If all goes well, we will be pleased - 4444
9999
555 - we think it well and other stuff too - 5555
100100
}
101
-fossil test-3 t1 t3 t2 a32
101
+fossil 3-way-merge t1 t3 t2 a32
102102
test merge1-2.1 {[same_file t32 a32]}
103
-fossil test-3 t1 t2 t3 a23
103
+fossil 3-way-merge t1 t2 t3 a23
104104
test merge1-2.2 {[same_file t23 a23]}
105105
106106
write_file_indented t1 {
107107
111 - This is line one of the demo program - 1111
108108
222 - The second line program line in code - 2222
@@ -129,13 +129,13 @@
129129
222 - The second line program line in code - 2222
130130
333 - This is a test of the merging algohm - 3333
131131
444 - If all goes well, we will be pleased - 4444
132132
555 - we think it well and other stuff too - 5555
133133
}
134
-fossil test-3 t1 t3 t2 a32
134
+fossil 3-way-merge t1 t3 t2 a32
135135
test merge1-3.1 {[same_file t23 a32]}
136
-fossil test-3 t1 t2 t3 a23
136
+fossil 3-way-merge t1 t2 t3 a23
137137
test merge1-3.2 {[same_file t23 a23]}
138138
139139
write_file_indented t1 {
140140
111 - This is line one of the demo program - 1111
141141
222 - The second line program line in code - 2222
@@ -181,13 +181,13 @@
181181
222 - The second line program line in code - 2222
182182
333 - This is a test of the merging algohm - 3333
183183
444 - If all goes well, we will be pleased - 4444
184184
555 - we think it well and other stuff too - 5555
185185
}
186
-fossil test-3 t1 t3 t2 a32
186
+fossil 3-way-merge t1 t3 t2 a32
187187
test merge1-4.1 {[same_file t32 a32]}
188
-fossil test-3 t1 t2 t3 a23
188
+fossil 3-way-merge t1 t2 t3 a23
189189
test merge1-4.2 {[same_file t23 a23]}
190190
191191
write_file_indented t1 {
192192
111 - This is line one of the demo program - 1111
193193
222 - The second line program line in code - 2222
@@ -214,13 +214,13 @@
214214
333 - This is a test of the merging algohm - 3333
215215
444 - If all goes well, we will be pleased - 4444
216216
555 - we think it well and other stuff too - 5555
217217
666 - Extra line at the end of the file wi - 6666
218218
}
219
-fossil test-3 t1 t3 t2 a32
219
+fossil 3-way-merge t1 t3 t2 a32
220220
test merge1-5.1 {[same_file t32 a32]}
221
-fossil test-3 t1 t2 t3 a23
221
+fossil 3-way-merge t1 t2 t3 a23
222222
test merge1-5.2 {[same_file t32 a23]}
223223
224224
write_file_indented t1 {
225225
111 - This is line one of the demo program - 1111
226226
222 - The second line program line in code - 2222
@@ -243,13 +243,13 @@
243243
write_file_indented t32 {
244244
111 - This is line one of the demo program - 1111
245245
333 - This is a test of the merging algohm - 3333
246246
555 - we think it well and other stuff too - 5555
247247
}
248
-fossil test-3 t1 t3 t2 a32
248
+fossil 3-way-merge t1 t3 t2 a32
249249
test merge1-6.1 {[same_file t32 a32]}
250
-fossil test-3 t1 t2 t3 a23
250
+fossil 3-way-merge t1 t2 t3 a23
251251
test merge1-6.2 {[same_file t32 a23]}
252252
253253
write_file_indented t1 {
254254
abcd
255255
efgh
@@ -328,11 +328,11 @@
328328
KLMN
329329
OPQR
330330
STUV
331331
XYZ.
332332
}
333
-fossil test-3 t1 t2 t3 a23
333
+fossil 3-way-merge t1 t2 t3 a23
334334
test merge1-7.1 {[same_file t23 a23]}
335335
336336
write_file_indented t2 {
337337
abcd
338338
efgh 2
@@ -396,7 +396,7 @@
396396
KLMN
397397
OPQR
398398
STUV
399399
XYZ.
400400
}
401
-fossil test-3 t1 t2 t3 a23
401
+fossil 3-way-merge t1 t2 t3 a23
402402
test merge1-7.2 {[same_file t23 a23]}
403403
--- test/merge1.test
+++ test/merge1.test
@@ -44,13 +44,13 @@
44 222 - The second line program line in code - 2222
45 333 - This is a test OF THE merging algohm - 3333
46 444 - If all goes well, we will be pleased - 4444
47 555 - we think it well and other stuff too - 5555
48 }
49 fossil test-3 t1 t3 t2 a32
50 test merge1-1.1 {[same_file t23 a32]}
51 fossil test-3 t1 t2 t3 a23
52 test merge1-1.2 {[same_file t23 a23]}
53
54 write_file_indented t1 {
55 111 - This is line one of the demo program - 1111
56 222 - The second line program line in code - 2222
@@ -96,13 +96,13 @@
96 222 - The second line program line in code - 2222
97 333 - This is a test of the merging algohm - 3333
98 444 - If all goes well, we will be pleased - 4444
99 555 - we think it well and other stuff too - 5555
100 }
101 fossil test-3 t1 t3 t2 a32
102 test merge1-2.1 {[same_file t32 a32]}
103 fossil test-3 t1 t2 t3 a23
104 test merge1-2.2 {[same_file t23 a23]}
105
106 write_file_indented t1 {
107 111 - This is line one of the demo program - 1111
108 222 - The second line program line in code - 2222
@@ -129,13 +129,13 @@
129 222 - The second line program line in code - 2222
130 333 - This is a test of the merging algohm - 3333
131 444 - If all goes well, we will be pleased - 4444
132 555 - we think it well and other stuff too - 5555
133 }
134 fossil test-3 t1 t3 t2 a32
135 test merge1-3.1 {[same_file t23 a32]}
136 fossil test-3 t1 t2 t3 a23
137 test merge1-3.2 {[same_file t23 a23]}
138
139 write_file_indented t1 {
140 111 - This is line one of the demo program - 1111
141 222 - The second line program line in code - 2222
@@ -181,13 +181,13 @@
181 222 - The second line program line in code - 2222
182 333 - This is a test of the merging algohm - 3333
183 444 - If all goes well, we will be pleased - 4444
184 555 - we think it well and other stuff too - 5555
185 }
186 fossil test-3 t1 t3 t2 a32
187 test merge1-4.1 {[same_file t32 a32]}
188 fossil test-3 t1 t2 t3 a23
189 test merge1-4.2 {[same_file t23 a23]}
190
191 write_file_indented t1 {
192 111 - This is line one of the demo program - 1111
193 222 - The second line program line in code - 2222
@@ -214,13 +214,13 @@
214 333 - This is a test of the merging algohm - 3333
215 444 - If all goes well, we will be pleased - 4444
216 555 - we think it well and other stuff too - 5555
217 666 - Extra line at the end of the file wi - 6666
218 }
219 fossil test-3 t1 t3 t2 a32
220 test merge1-5.1 {[same_file t32 a32]}
221 fossil test-3 t1 t2 t3 a23
222 test merge1-5.2 {[same_file t32 a23]}
223
224 write_file_indented t1 {
225 111 - This is line one of the demo program - 1111
226 222 - The second line program line in code - 2222
@@ -243,13 +243,13 @@
243 write_file_indented t32 {
244 111 - This is line one of the demo program - 1111
245 333 - This is a test of the merging algohm - 3333
246 555 - we think it well and other stuff too - 5555
247 }
248 fossil test-3 t1 t3 t2 a32
249 test merge1-6.1 {[same_file t32 a32]}
250 fossil test-3 t1 t2 t3 a23
251 test merge1-6.2 {[same_file t32 a23]}
252
253 write_file_indented t1 {
254 abcd
255 efgh
@@ -328,11 +328,11 @@
328 KLMN
329 OPQR
330 STUV
331 XYZ.
332 }
333 fossil test-3 t1 t2 t3 a23
334 test merge1-7.1 {[same_file t23 a23]}
335
336 write_file_indented t2 {
337 abcd
338 efgh 2
@@ -396,7 +396,7 @@
396 KLMN
397 OPQR
398 STUV
399 XYZ.
400 }
401 fossil test-3 t1 t2 t3 a23
402 test merge1-7.2 {[same_file t23 a23]}
403
--- test/merge1.test
+++ test/merge1.test
@@ -44,13 +44,13 @@
44 222 - The second line program line in code - 2222
45 333 - This is a test OF THE merging algohm - 3333
46 444 - If all goes well, we will be pleased - 4444
47 555 - we think it well and other stuff too - 5555
48 }
49 fossil 3-way-merge t1 t3 t2 a32
50 test merge1-1.1 {[same_file t23 a32]}
51 fossil 3-way-merge t1 t2 t3 a23
52 test merge1-1.2 {[same_file t23 a23]}
53
54 write_file_indented t1 {
55 111 - This is line one of the demo program - 1111
56 222 - The second line program line in code - 2222
@@ -96,13 +96,13 @@
96 222 - The second line program line in code - 2222
97 333 - This is a test of the merging algohm - 3333
98 444 - If all goes well, we will be pleased - 4444
99 555 - we think it well and other stuff too - 5555
100 }
101 fossil 3-way-merge t1 t3 t2 a32
102 test merge1-2.1 {[same_file t32 a32]}
103 fossil 3-way-merge t1 t2 t3 a23
104 test merge1-2.2 {[same_file t23 a23]}
105
106 write_file_indented t1 {
107 111 - This is line one of the demo program - 1111
108 222 - The second line program line in code - 2222
@@ -129,13 +129,13 @@
129 222 - The second line program line in code - 2222
130 333 - This is a test of the merging algohm - 3333
131 444 - If all goes well, we will be pleased - 4444
132 555 - we think it well and other stuff too - 5555
133 }
134 fossil 3-way-merge t1 t3 t2 a32
135 test merge1-3.1 {[same_file t23 a32]}
136 fossil 3-way-merge t1 t2 t3 a23
137 test merge1-3.2 {[same_file t23 a23]}
138
139 write_file_indented t1 {
140 111 - This is line one of the demo program - 1111
141 222 - The second line program line in code - 2222
@@ -181,13 +181,13 @@
181 222 - The second line program line in code - 2222
182 333 - This is a test of the merging algohm - 3333
183 444 - If all goes well, we will be pleased - 4444
184 555 - we think it well and other stuff too - 5555
185 }
186 fossil 3-way-merge t1 t3 t2 a32
187 test merge1-4.1 {[same_file t32 a32]}
188 fossil 3-way-merge t1 t2 t3 a23
189 test merge1-4.2 {[same_file t23 a23]}
190
191 write_file_indented t1 {
192 111 - This is line one of the demo program - 1111
193 222 - The second line program line in code - 2222
@@ -214,13 +214,13 @@
214 333 - This is a test of the merging algohm - 3333
215 444 - If all goes well, we will be pleased - 4444
216 555 - we think it well and other stuff too - 5555
217 666 - Extra line at the end of the file wi - 6666
218 }
219 fossil 3-way-merge t1 t3 t2 a32
220 test merge1-5.1 {[same_file t32 a32]}
221 fossil 3-way-merge t1 t2 t3 a23
222 test merge1-5.2 {[same_file t32 a23]}
223
224 write_file_indented t1 {
225 111 - This is line one of the demo program - 1111
226 222 - The second line program line in code - 2222
@@ -243,13 +243,13 @@
243 write_file_indented t32 {
244 111 - This is line one of the demo program - 1111
245 333 - This is a test of the merging algohm - 3333
246 555 - we think it well and other stuff too - 5555
247 }
248 fossil 3-way-merge t1 t3 t2 a32
249 test merge1-6.1 {[same_file t32 a32]}
250 fossil 3-way-merge t1 t2 t3 a23
251 test merge1-6.2 {[same_file t32 a23]}
252
253 write_file_indented t1 {
254 abcd
255 efgh
@@ -328,11 +328,11 @@
328 KLMN
329 OPQR
330 STUV
331 XYZ.
332 }
333 fossil 3-way-merge t1 t2 t3 a23
334 test merge1-7.1 {[same_file t23 a23]}
335
336 write_file_indented t2 {
337 abcd
338 efgh 2
@@ -396,7 +396,7 @@
396 KLMN
397 OPQR
398 STUV
399 XYZ.
400 }
401 fossil 3-way-merge t1 t2 t3 a23
402 test merge1-7.2 {[same_file t23 a23]}
403
--- test/merge2.test
+++ test/merge2.test
@@ -31,11 +31,11 @@
3131
write_file t3 [set f3 [random_changes $f1 2 4 2 0.1]]
3232
expr {srand($i*2+1)}
3333
write_file t23 [random_changes $f2 2 4 2 0.1]
3434
expr {srand($i*2)}
3535
write_file t32 [random_changes $f3 2 4 0 0.1]
36
- fossil test-3-way-merge t1 t2 t3 a23
36
+ fossil 3-way-merge t1 t2 t3 a23
3737
test merge-$base-$i-23 {[same_file a23 t23]}
38
- fossil test-3-way-merge t1 t3 t2 a32
38
+ fossil 3-way-merge t1 t3 t2 a32
3939
test merge-$base-$i-32 {[same_file a32 t32]}
4040
}
4141
}
4242
--- test/merge2.test
+++ test/merge2.test
@@ -31,11 +31,11 @@
31 write_file t3 [set f3 [random_changes $f1 2 4 2 0.1]]
32 expr {srand($i*2+1)}
33 write_file t23 [random_changes $f2 2 4 2 0.1]
34 expr {srand($i*2)}
35 write_file t32 [random_changes $f3 2 4 0 0.1]
36 fossil test-3-way-merge t1 t2 t3 a23
37 test merge-$base-$i-23 {[same_file a23 t23]}
38 fossil test-3-way-merge t1 t3 t2 a32
39 test merge-$base-$i-32 {[same_file a32 t32]}
40 }
41 }
42
--- test/merge2.test
+++ test/merge2.test
@@ -31,11 +31,11 @@
31 write_file t3 [set f3 [random_changes $f1 2 4 2 0.1]]
32 expr {srand($i*2+1)}
33 write_file t23 [random_changes $f2 2 4 2 0.1]
34 expr {srand($i*2)}
35 write_file t32 [random_changes $f3 2 4 0 0.1]
36 fossil 3-way-merge t1 t2 t3 a23
37 test merge-$base-$i-23 {[same_file a23 t23]}
38 fossil 3-way-merge t1 t3 t2 a32
39 test merge-$base-$i-32 {[same_file a32 t32]}
40 }
41 }
42
--- test/merge3.test
+++ test/merge3.test
@@ -20,11 +20,11 @@
2020
2121
proc merge-test {testid basis v1 v2 result} {
2222
write_file t1 [join [string trim $basis] \n]\n
2323
write_file t2 [join [string trim $v1] \n]\n
2424
write_file t3 [join [string trim $v2] \n]\n
25
- fossil test-3-way-merge t1 t2 t3 t4
25
+ fossil 3-way-merge t1 t2 t3 t4
2626
set x [read_file t4]
2727
regsub -all {<<<<<<< BEGIN MERGE CONFLICT: local copy shown first <+} $x \
2828
{MINE:} x
2929
regsub -all {======= COMMON ANCESTOR content follows =+} $x {COM:} x
3030
regsub -all {======= MERGED IN content follows =+} $x {YOURS:} x
3131
--- test/merge3.test
+++ test/merge3.test
@@ -20,11 +20,11 @@
20
21 proc merge-test {testid basis v1 v2 result} {
22 write_file t1 [join [string trim $basis] \n]\n
23 write_file t2 [join [string trim $v1] \n]\n
24 write_file t3 [join [string trim $v2] \n]\n
25 fossil test-3-way-merge t1 t2 t3 t4
26 set x [read_file t4]
27 regsub -all {<<<<<<< BEGIN MERGE CONFLICT: local copy shown first <+} $x \
28 {MINE:} x
29 regsub -all {======= COMMON ANCESTOR content follows =+} $x {COM:} x
30 regsub -all {======= MERGED IN content follows =+} $x {YOURS:} x
31
--- test/merge3.test
+++ test/merge3.test
@@ -20,11 +20,11 @@
20
21 proc merge-test {testid basis v1 v2 result} {
22 write_file t1 [join [string trim $basis] \n]\n
23 write_file t2 [join [string trim $v1] \n]\n
24 write_file t3 [join [string trim $v2] \n]\n
25 fossil 3-way-merge t1 t2 t3 t4
26 set x [read_file t4]
27 regsub -all {<<<<<<< BEGIN MERGE CONFLICT: local copy shown first <+} $x \
28 {MINE:} x
29 regsub -all {======= COMMON ANCESTOR content follows =+} $x {COM:} x
30 regsub -all {======= MERGED IN content follows =+} $x {YOURS:} x
31
--- test/merge4.test
+++ test/merge4.test
@@ -20,12 +20,12 @@
2020
2121
proc merge-test {testid basis v1 v2 result1 result2} {
2222
write_file t1 [join [string trim $basis] \n]\n
2323
write_file t2 [join [string trim $v1] \n]\n
2424
write_file t3 [join [string trim $v2] \n]\n
25
- fossil test-3-way-merge t1 t2 t3 t4
26
- fossil test-3-way-merge t1 t3 t2 t5
25
+ fossil 3-way-merge t1 t2 t3 t4
26
+ fossil 3-way-merge t1 t3 t2 t5
2727
set x [read_file t4]
2828
regsub -all {<<<<<<< BEGIN MERGE CONFLICT.*<<} $x {>} x
2929
regsub -all {=======.*=======} $x {=} x
3030
regsub -all {>>>>>>> END MERGE CONFLICT.*>>>>} $x {<} x
3131
set x [split [string trim $x] \n]
3232
--- test/merge4.test
+++ test/merge4.test
@@ -20,12 +20,12 @@
20
21 proc merge-test {testid basis v1 v2 result1 result2} {
22 write_file t1 [join [string trim $basis] \n]\n
23 write_file t2 [join [string trim $v1] \n]\n
24 write_file t3 [join [string trim $v2] \n]\n
25 fossil test-3-way-merge t1 t2 t3 t4
26 fossil test-3-way-merge t1 t3 t2 t5
27 set x [read_file t4]
28 regsub -all {<<<<<<< BEGIN MERGE CONFLICT.*<<} $x {>} x
29 regsub -all {=======.*=======} $x {=} x
30 regsub -all {>>>>>>> END MERGE CONFLICT.*>>>>} $x {<} x
31 set x [split [string trim $x] \n]
32
--- test/merge4.test
+++ test/merge4.test
@@ -20,12 +20,12 @@
20
21 proc merge-test {testid basis v1 v2 result1 result2} {
22 write_file t1 [join [string trim $basis] \n]\n
23 write_file t2 [join [string trim $v1] \n]\n
24 write_file t3 [join [string trim $v2] \n]\n
25 fossil 3-way-merge t1 t2 t3 t4
26 fossil 3-way-merge t1 t3 t2 t5
27 set x [read_file t4]
28 regsub -all {<<<<<<< BEGIN MERGE CONFLICT.*<<} $x {>} x
29 regsub -all {=======.*=======} $x {=} x
30 regsub -all {>>>>>>> END MERGE CONFLICT.*>>>>} $x {<} x
31 set x [split [string trim $x] \n]
32
+10 -4
--- win/Makefile.dmc
+++ win/Makefile.dmc
@@ -26,13 +26,13 @@
2626
TCC = $(DMDIR)\bin\dmc $(CFLAGS) $(DMCDEF) $(SSL) $(INCL)
2727
LIBS = $(DMDIR)\extra\lib\ zlib wsock32 advapi32
2828
2929
SQLITE_OPTIONS = -DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_STAT3 -Dlocaltime=fossil_localtime -DSQLITE_ENABLE_LOCKING_STYLE=0
3030
31
-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 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 winhttp_.c wysiwyg_.c xfer_.c xfersetup_.c zip_.c
31
+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 winhttp_.c wysiwyg_.c xfer_.c xfersetup_.c zip_.c
3232
33
-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)\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)\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
33
+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)\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
3434
3535
3636
RC=$(DMDIR)\bin\rcc
3737
RCFLAGS=-32 -w1 -I$(SRCDIR) /D__DMC__
3838
@@ -46,11 +46,11 @@
4646
4747
$(OBJDIR)\fossil.res: $B\win\fossil.rc
4848
$(RC) $(RCFLAGS) -o$@ $**
4949
5050
$(OBJDIR)\link: $B\win\Makefile.dmc $(OBJDIR)\fossil.res
51
- +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 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 winhttp wysiwyg xfer xfersetup zip shell sqlite3 th th_lang > $@
51
+ +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 winhttp wysiwyg xfer xfersetup zip shell sqlite3 th th_lang > $@
5252
+echo fossil >> $@
5353
+echo fossil >> $@
5454
+echo $(LIBS) >> $@
5555
+echo. >> $@
5656
+echo fossil >> $@
@@ -440,10 +440,16 @@
440440
$(OBJDIR)\login$O : login_.c login.h
441441
$(TCC) -o$@ -c login_.c
442442
443443
login_.c : $(SRCDIR)\login.c
444444
+translate$E $** > $@
445
+
446
+$(OBJDIR)\lookslike$O : lookslike_.c lookslike.h
447
+ $(TCC) -o$@ -c lookslike_.c
448
+
449
+lookslike_.c : $(SRCDIR)\lookslike.c
450
+ +translate$E $** > $@
445451
446452
$(OBJDIR)\main$O : main_.c main.h
447453
$(TCC) -o$@ -c main_.c
448454
449455
main_.c : $(SRCDIR)\main.c
@@ -748,7 +754,7 @@
748754
749755
zip_.c : $(SRCDIR)\zip.c
750756
+translate$E $** > $@
751757
752758
headers: makeheaders$E page_index.h VERSION.h
753
- +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 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 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
759
+ +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 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
754760
@copy /Y nul: headers
755761
--- win/Makefile.dmc
+++ win/Makefile.dmc
@@ -26,13 +26,13 @@
26 TCC = $(DMDIR)\bin\dmc $(CFLAGS) $(DMCDEF) $(SSL) $(INCL)
27 LIBS = $(DMDIR)\extra\lib\ zlib wsock32 advapi32
28
29 SQLITE_OPTIONS = -DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_STAT3 -Dlocaltime=fossil_localtime -DSQLITE_ENABLE_LOCKING_STYLE=0
30
31 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 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 winhttp_.c wysiwyg_.c xfer_.c xfersetup_.c zip_.c
32
33 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)\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)\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
34
35
36 RC=$(DMDIR)\bin\rcc
37 RCFLAGS=-32 -w1 -I$(SRCDIR) /D__DMC__
38
@@ -46,11 +46,11 @@
46
47 $(OBJDIR)\fossil.res: $B\win\fossil.rc
48 $(RC) $(RCFLAGS) -o$@ $**
49
50 $(OBJDIR)\link: $B\win\Makefile.dmc $(OBJDIR)\fossil.res
51 +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 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 winhttp wysiwyg xfer xfersetup zip shell sqlite3 th th_lang > $@
52 +echo fossil >> $@
53 +echo fossil >> $@
54 +echo $(LIBS) >> $@
55 +echo. >> $@
56 +echo fossil >> $@
@@ -440,10 +440,16 @@
440 $(OBJDIR)\login$O : login_.c login.h
441 $(TCC) -o$@ -c login_.c
442
443 login_.c : $(SRCDIR)\login.c
444 +translate$E $** > $@
 
 
 
 
 
 
445
446 $(OBJDIR)\main$O : main_.c main.h
447 $(TCC) -o$@ -c main_.c
448
449 main_.c : $(SRCDIR)\main.c
@@ -748,7 +754,7 @@
748
749 zip_.c : $(SRCDIR)\zip.c
750 +translate$E $** > $@
751
752 headers: makeheaders$E page_index.h VERSION.h
753 +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 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 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
754 @copy /Y nul: headers
755
--- win/Makefile.dmc
+++ win/Makefile.dmc
@@ -26,13 +26,13 @@
26 TCC = $(DMDIR)\bin\dmc $(CFLAGS) $(DMCDEF) $(SSL) $(INCL)
27 LIBS = $(DMDIR)\extra\lib\ zlib wsock32 advapi32
28
29 SQLITE_OPTIONS = -DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_STAT3 -Dlocaltime=fossil_localtime -DSQLITE_ENABLE_LOCKING_STYLE=0
30
31 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 winhttp_.c wysiwyg_.c xfer_.c xfersetup_.c zip_.c
32
33 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)\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
34
35
36 RC=$(DMDIR)\bin\rcc
37 RCFLAGS=-32 -w1 -I$(SRCDIR) /D__DMC__
38
@@ -46,11 +46,11 @@
46
47 $(OBJDIR)\fossil.res: $B\win\fossil.rc
48 $(RC) $(RCFLAGS) -o$@ $**
49
50 $(OBJDIR)\link: $B\win\Makefile.dmc $(OBJDIR)\fossil.res
51 +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 winhttp wysiwyg xfer xfersetup zip shell sqlite3 th th_lang > $@
52 +echo fossil >> $@
53 +echo fossil >> $@
54 +echo $(LIBS) >> $@
55 +echo. >> $@
56 +echo fossil >> $@
@@ -440,10 +440,16 @@
440 $(OBJDIR)\login$O : login_.c login.h
441 $(TCC) -o$@ -c login_.c
442
443 login_.c : $(SRCDIR)\login.c
444 +translate$E $** > $@
445
446 $(OBJDIR)\lookslike$O : lookslike_.c lookslike.h
447 $(TCC) -o$@ -c lookslike_.c
448
449 lookslike_.c : $(SRCDIR)\lookslike.c
450 +translate$E $** > $@
451
452 $(OBJDIR)\main$O : main_.c main.h
453 $(TCC) -o$@ -c main_.c
454
455 main_.c : $(SRCDIR)\main.c
@@ -748,7 +754,7 @@
754
755 zip_.c : $(SRCDIR)\zip.c
756 +translate$E $** > $@
757
758 headers: makeheaders$E page_index.h VERSION.h
759 +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 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
760 @copy /Y nul: headers
761
--- win/Makefile.mingw
+++ win/Makefile.mingw
@@ -298,10 +298,11 @@
298298
$(SRCDIR)/json_timeline.c \
299299
$(SRCDIR)/json_user.c \
300300
$(SRCDIR)/json_wiki.c \
301301
$(SRCDIR)/leaf.c \
302302
$(SRCDIR)/login.c \
303
+ $(SRCDIR)/lookslike.c \
303304
$(SRCDIR)/main.c \
304305
$(SRCDIR)/manifest.c \
305306
$(SRCDIR)/markdown.c \
306307
$(SRCDIR)/markdown_html.c \
307308
$(SRCDIR)/md5.c \
@@ -406,10 +407,11 @@
406407
$(OBJDIR)/json_timeline_.c \
407408
$(OBJDIR)/json_user_.c \
408409
$(OBJDIR)/json_wiki_.c \
409410
$(OBJDIR)/leaf_.c \
410411
$(OBJDIR)/login_.c \
412
+ $(OBJDIR)/lookslike_.c \
411413
$(OBJDIR)/main_.c \
412414
$(OBJDIR)/manifest_.c \
413415
$(OBJDIR)/markdown_.c \
414416
$(OBJDIR)/markdown_html_.c \
415417
$(OBJDIR)/md5_.c \
@@ -514,10 +516,11 @@
514516
$(OBJDIR)/json_timeline.o \
515517
$(OBJDIR)/json_user.o \
516518
$(OBJDIR)/json_wiki.o \
517519
$(OBJDIR)/leaf.o \
518520
$(OBJDIR)/login.o \
521
+ $(OBJDIR)/lookslike.o \
519522
$(OBJDIR)/main.o \
520523
$(OBJDIR)/manifest.o \
521524
$(OBJDIR)/markdown.o \
522525
$(OBJDIR)/markdown_html.o \
523526
$(OBJDIR)/md5.o \
@@ -735,10 +738,11 @@
735738
$(OBJDIR)/json_timeline_.c:$(OBJDIR)/json_timeline.h \
736739
$(OBJDIR)/json_user_.c:$(OBJDIR)/json_user.h \
737740
$(OBJDIR)/json_wiki_.c:$(OBJDIR)/json_wiki.h \
738741
$(OBJDIR)/leaf_.c:$(OBJDIR)/leaf.h \
739742
$(OBJDIR)/login_.c:$(OBJDIR)/login.h \
743
+ $(OBJDIR)/lookslike_.c:$(OBJDIR)/lookslike.h \
740744
$(OBJDIR)/main_.c:$(OBJDIR)/main.h \
741745
$(OBJDIR)/manifest_.c:$(OBJDIR)/manifest.h \
742746
$(OBJDIR)/markdown_.c:$(OBJDIR)/markdown.h \
743747
$(OBJDIR)/markdown_html_.c:$(OBJDIR)/markdown_html.h \
744748
$(OBJDIR)/md5_.c:$(OBJDIR)/md5.h \
@@ -1234,10 +1238,18 @@
12341238
12351239
$(OBJDIR)/login.o: $(OBJDIR)/login_.c $(OBJDIR)/login.h $(SRCDIR)/config.h
12361240
$(XTCC) -o $(OBJDIR)/login.o -c $(OBJDIR)/login_.c
12371241
12381242
$(OBJDIR)/login.h: $(OBJDIR)/headers
1243
+
1244
+$(OBJDIR)/lookslike_.c: $(SRCDIR)/lookslike.c $(OBJDIR)/translate
1245
+ $(TRANSLATE) $(SRCDIR)/lookslike.c >$(OBJDIR)/lookslike_.c
1246
+
1247
+$(OBJDIR)/lookslike.o: $(OBJDIR)/lookslike_.c $(OBJDIR)/lookslike.h $(SRCDIR)/config.h
1248
+ $(XTCC) -o $(OBJDIR)/lookslike.o -c $(OBJDIR)/lookslike_.c
1249
+
1250
+$(OBJDIR)/lookslike.h: $(OBJDIR)/headers
12391251
12401252
$(OBJDIR)/main_.c: $(SRCDIR)/main.c $(OBJDIR)/translate
12411253
$(TRANSLATE) $(SRCDIR)/main.c >$(OBJDIR)/main_.c
12421254
12431255
$(OBJDIR)/main.o: $(OBJDIR)/main_.c $(OBJDIR)/main.h $(OBJDIR)/page_index.h $(SRCDIR)/config.h
12441256
--- win/Makefile.mingw
+++ win/Makefile.mingw
@@ -298,10 +298,11 @@
298 $(SRCDIR)/json_timeline.c \
299 $(SRCDIR)/json_user.c \
300 $(SRCDIR)/json_wiki.c \
301 $(SRCDIR)/leaf.c \
302 $(SRCDIR)/login.c \
 
303 $(SRCDIR)/main.c \
304 $(SRCDIR)/manifest.c \
305 $(SRCDIR)/markdown.c \
306 $(SRCDIR)/markdown_html.c \
307 $(SRCDIR)/md5.c \
@@ -406,10 +407,11 @@
406 $(OBJDIR)/json_timeline_.c \
407 $(OBJDIR)/json_user_.c \
408 $(OBJDIR)/json_wiki_.c \
409 $(OBJDIR)/leaf_.c \
410 $(OBJDIR)/login_.c \
 
411 $(OBJDIR)/main_.c \
412 $(OBJDIR)/manifest_.c \
413 $(OBJDIR)/markdown_.c \
414 $(OBJDIR)/markdown_html_.c \
415 $(OBJDIR)/md5_.c \
@@ -514,10 +516,11 @@
514 $(OBJDIR)/json_timeline.o \
515 $(OBJDIR)/json_user.o \
516 $(OBJDIR)/json_wiki.o \
517 $(OBJDIR)/leaf.o \
518 $(OBJDIR)/login.o \
 
519 $(OBJDIR)/main.o \
520 $(OBJDIR)/manifest.o \
521 $(OBJDIR)/markdown.o \
522 $(OBJDIR)/markdown_html.o \
523 $(OBJDIR)/md5.o \
@@ -735,10 +738,11 @@
735 $(OBJDIR)/json_timeline_.c:$(OBJDIR)/json_timeline.h \
736 $(OBJDIR)/json_user_.c:$(OBJDIR)/json_user.h \
737 $(OBJDIR)/json_wiki_.c:$(OBJDIR)/json_wiki.h \
738 $(OBJDIR)/leaf_.c:$(OBJDIR)/leaf.h \
739 $(OBJDIR)/login_.c:$(OBJDIR)/login.h \
 
740 $(OBJDIR)/main_.c:$(OBJDIR)/main.h \
741 $(OBJDIR)/manifest_.c:$(OBJDIR)/manifest.h \
742 $(OBJDIR)/markdown_.c:$(OBJDIR)/markdown.h \
743 $(OBJDIR)/markdown_html_.c:$(OBJDIR)/markdown_html.h \
744 $(OBJDIR)/md5_.c:$(OBJDIR)/md5.h \
@@ -1234,10 +1238,18 @@
1234
1235 $(OBJDIR)/login.o: $(OBJDIR)/login_.c $(OBJDIR)/login.h $(SRCDIR)/config.h
1236 $(XTCC) -o $(OBJDIR)/login.o -c $(OBJDIR)/login_.c
1237
1238 $(OBJDIR)/login.h: $(OBJDIR)/headers
 
 
 
 
 
 
 
 
1239
1240 $(OBJDIR)/main_.c: $(SRCDIR)/main.c $(OBJDIR)/translate
1241 $(TRANSLATE) $(SRCDIR)/main.c >$(OBJDIR)/main_.c
1242
1243 $(OBJDIR)/main.o: $(OBJDIR)/main_.c $(OBJDIR)/main.h $(OBJDIR)/page_index.h $(SRCDIR)/config.h
1244
--- win/Makefile.mingw
+++ win/Makefile.mingw
@@ -298,10 +298,11 @@
298 $(SRCDIR)/json_timeline.c \
299 $(SRCDIR)/json_user.c \
300 $(SRCDIR)/json_wiki.c \
301 $(SRCDIR)/leaf.c \
302 $(SRCDIR)/login.c \
303 $(SRCDIR)/lookslike.c \
304 $(SRCDIR)/main.c \
305 $(SRCDIR)/manifest.c \
306 $(SRCDIR)/markdown.c \
307 $(SRCDIR)/markdown_html.c \
308 $(SRCDIR)/md5.c \
@@ -406,10 +407,11 @@
407 $(OBJDIR)/json_timeline_.c \
408 $(OBJDIR)/json_user_.c \
409 $(OBJDIR)/json_wiki_.c \
410 $(OBJDIR)/leaf_.c \
411 $(OBJDIR)/login_.c \
412 $(OBJDIR)/lookslike_.c \
413 $(OBJDIR)/main_.c \
414 $(OBJDIR)/manifest_.c \
415 $(OBJDIR)/markdown_.c \
416 $(OBJDIR)/markdown_html_.c \
417 $(OBJDIR)/md5_.c \
@@ -514,10 +516,11 @@
516 $(OBJDIR)/json_timeline.o \
517 $(OBJDIR)/json_user.o \
518 $(OBJDIR)/json_wiki.o \
519 $(OBJDIR)/leaf.o \
520 $(OBJDIR)/login.o \
521 $(OBJDIR)/lookslike.o \
522 $(OBJDIR)/main.o \
523 $(OBJDIR)/manifest.o \
524 $(OBJDIR)/markdown.o \
525 $(OBJDIR)/markdown_html.o \
526 $(OBJDIR)/md5.o \
@@ -735,10 +738,11 @@
738 $(OBJDIR)/json_timeline_.c:$(OBJDIR)/json_timeline.h \
739 $(OBJDIR)/json_user_.c:$(OBJDIR)/json_user.h \
740 $(OBJDIR)/json_wiki_.c:$(OBJDIR)/json_wiki.h \
741 $(OBJDIR)/leaf_.c:$(OBJDIR)/leaf.h \
742 $(OBJDIR)/login_.c:$(OBJDIR)/login.h \
743 $(OBJDIR)/lookslike_.c:$(OBJDIR)/lookslike.h \
744 $(OBJDIR)/main_.c:$(OBJDIR)/main.h \
745 $(OBJDIR)/manifest_.c:$(OBJDIR)/manifest.h \
746 $(OBJDIR)/markdown_.c:$(OBJDIR)/markdown.h \
747 $(OBJDIR)/markdown_html_.c:$(OBJDIR)/markdown_html.h \
748 $(OBJDIR)/md5_.c:$(OBJDIR)/md5.h \
@@ -1234,10 +1238,18 @@
1238
1239 $(OBJDIR)/login.o: $(OBJDIR)/login_.c $(OBJDIR)/login.h $(SRCDIR)/config.h
1240 $(XTCC) -o $(OBJDIR)/login.o -c $(OBJDIR)/login_.c
1241
1242 $(OBJDIR)/login.h: $(OBJDIR)/headers
1243
1244 $(OBJDIR)/lookslike_.c: $(SRCDIR)/lookslike.c $(OBJDIR)/translate
1245 $(TRANSLATE) $(SRCDIR)/lookslike.c >$(OBJDIR)/lookslike_.c
1246
1247 $(OBJDIR)/lookslike.o: $(OBJDIR)/lookslike_.c $(OBJDIR)/lookslike.h $(SRCDIR)/config.h
1248 $(XTCC) -o $(OBJDIR)/lookslike.o -c $(OBJDIR)/lookslike_.c
1249
1250 $(OBJDIR)/lookslike.h: $(OBJDIR)/headers
1251
1252 $(OBJDIR)/main_.c: $(SRCDIR)/main.c $(OBJDIR)/translate
1253 $(TRANSLATE) $(SRCDIR)/main.c >$(OBJDIR)/main_.c
1254
1255 $(OBJDIR)/main.o: $(OBJDIR)/main_.c $(OBJDIR)/main.h $(OBJDIR)/page_index.h $(SRCDIR)/config.h
1256
--- win/Makefile.mingw.mistachkin
+++ win/Makefile.mingw.mistachkin
@@ -298,10 +298,11 @@
298298
$(SRCDIR)/json_timeline.c \
299299
$(SRCDIR)/json_user.c \
300300
$(SRCDIR)/json_wiki.c \
301301
$(SRCDIR)/leaf.c \
302302
$(SRCDIR)/login.c \
303
+ $(SRCDIR)/lookslike.c \
303304
$(SRCDIR)/main.c \
304305
$(SRCDIR)/manifest.c \
305306
$(SRCDIR)/markdown.c \
306307
$(SRCDIR)/markdown_html.c \
307308
$(SRCDIR)/md5.c \
@@ -406,10 +407,11 @@
406407
$(OBJDIR)/json_timeline_.c \
407408
$(OBJDIR)/json_user_.c \
408409
$(OBJDIR)/json_wiki_.c \
409410
$(OBJDIR)/leaf_.c \
410411
$(OBJDIR)/login_.c \
412
+ $(OBJDIR)/lookslike_.c \
411413
$(OBJDIR)/main_.c \
412414
$(OBJDIR)/manifest_.c \
413415
$(OBJDIR)/markdown_.c \
414416
$(OBJDIR)/markdown_html_.c \
415417
$(OBJDIR)/md5_.c \
@@ -514,10 +516,11 @@
514516
$(OBJDIR)/json_timeline.o \
515517
$(OBJDIR)/json_user.o \
516518
$(OBJDIR)/json_wiki.o \
517519
$(OBJDIR)/leaf.o \
518520
$(OBJDIR)/login.o \
521
+ $(OBJDIR)/lookslike.o \
519522
$(OBJDIR)/main.o \
520523
$(OBJDIR)/manifest.o \
521524
$(OBJDIR)/markdown.o \
522525
$(OBJDIR)/markdown_html.o \
523526
$(OBJDIR)/md5.o \
@@ -735,10 +738,11 @@
735738
$(OBJDIR)/json_timeline_.c:$(OBJDIR)/json_timeline.h \
736739
$(OBJDIR)/json_user_.c:$(OBJDIR)/json_user.h \
737740
$(OBJDIR)/json_wiki_.c:$(OBJDIR)/json_wiki.h \
738741
$(OBJDIR)/leaf_.c:$(OBJDIR)/leaf.h \
739742
$(OBJDIR)/login_.c:$(OBJDIR)/login.h \
743
+ $(OBJDIR)/lookslike_.c:$(OBJDIR)/lookslike.h \
740744
$(OBJDIR)/main_.c:$(OBJDIR)/main.h \
741745
$(OBJDIR)/manifest_.c:$(OBJDIR)/manifest.h \
742746
$(OBJDIR)/markdown_.c:$(OBJDIR)/markdown.h \
743747
$(OBJDIR)/markdown_html_.c:$(OBJDIR)/markdown_html.h \
744748
$(OBJDIR)/md5_.c:$(OBJDIR)/md5.h \
@@ -1234,10 +1238,18 @@
12341238
12351239
$(OBJDIR)/login.o: $(OBJDIR)/login_.c $(OBJDIR)/login.h $(SRCDIR)/config.h
12361240
$(XTCC) -o $(OBJDIR)/login.o -c $(OBJDIR)/login_.c
12371241
12381242
$(OBJDIR)/login.h: $(OBJDIR)/headers
1243
+
1244
+$(OBJDIR)/lookslike_.c: $(SRCDIR)/lookslike.c $(OBJDIR)/translate
1245
+ $(TRANSLATE) $(SRCDIR)/lookslike.c >$(OBJDIR)/lookslike_.c
1246
+
1247
+$(OBJDIR)/lookslike.o: $(OBJDIR)/lookslike_.c $(OBJDIR)/lookslike.h $(SRCDIR)/config.h
1248
+ $(XTCC) -o $(OBJDIR)/lookslike.o -c $(OBJDIR)/lookslike_.c
1249
+
1250
+$(OBJDIR)/lookslike.h: $(OBJDIR)/headers
12391251
12401252
$(OBJDIR)/main_.c: $(SRCDIR)/main.c $(OBJDIR)/translate
12411253
$(TRANSLATE) $(SRCDIR)/main.c >$(OBJDIR)/main_.c
12421254
12431255
$(OBJDIR)/main.o: $(OBJDIR)/main_.c $(OBJDIR)/main.h $(OBJDIR)/page_index.h $(SRCDIR)/config.h
12441256
--- win/Makefile.mingw.mistachkin
+++ win/Makefile.mingw.mistachkin
@@ -298,10 +298,11 @@
298 $(SRCDIR)/json_timeline.c \
299 $(SRCDIR)/json_user.c \
300 $(SRCDIR)/json_wiki.c \
301 $(SRCDIR)/leaf.c \
302 $(SRCDIR)/login.c \
 
303 $(SRCDIR)/main.c \
304 $(SRCDIR)/manifest.c \
305 $(SRCDIR)/markdown.c \
306 $(SRCDIR)/markdown_html.c \
307 $(SRCDIR)/md5.c \
@@ -406,10 +407,11 @@
406 $(OBJDIR)/json_timeline_.c \
407 $(OBJDIR)/json_user_.c \
408 $(OBJDIR)/json_wiki_.c \
409 $(OBJDIR)/leaf_.c \
410 $(OBJDIR)/login_.c \
 
411 $(OBJDIR)/main_.c \
412 $(OBJDIR)/manifest_.c \
413 $(OBJDIR)/markdown_.c \
414 $(OBJDIR)/markdown_html_.c \
415 $(OBJDIR)/md5_.c \
@@ -514,10 +516,11 @@
514 $(OBJDIR)/json_timeline.o \
515 $(OBJDIR)/json_user.o \
516 $(OBJDIR)/json_wiki.o \
517 $(OBJDIR)/leaf.o \
518 $(OBJDIR)/login.o \
 
519 $(OBJDIR)/main.o \
520 $(OBJDIR)/manifest.o \
521 $(OBJDIR)/markdown.o \
522 $(OBJDIR)/markdown_html.o \
523 $(OBJDIR)/md5.o \
@@ -735,10 +738,11 @@
735 $(OBJDIR)/json_timeline_.c:$(OBJDIR)/json_timeline.h \
736 $(OBJDIR)/json_user_.c:$(OBJDIR)/json_user.h \
737 $(OBJDIR)/json_wiki_.c:$(OBJDIR)/json_wiki.h \
738 $(OBJDIR)/leaf_.c:$(OBJDIR)/leaf.h \
739 $(OBJDIR)/login_.c:$(OBJDIR)/login.h \
 
740 $(OBJDIR)/main_.c:$(OBJDIR)/main.h \
741 $(OBJDIR)/manifest_.c:$(OBJDIR)/manifest.h \
742 $(OBJDIR)/markdown_.c:$(OBJDIR)/markdown.h \
743 $(OBJDIR)/markdown_html_.c:$(OBJDIR)/markdown_html.h \
744 $(OBJDIR)/md5_.c:$(OBJDIR)/md5.h \
@@ -1234,10 +1238,18 @@
1234
1235 $(OBJDIR)/login.o: $(OBJDIR)/login_.c $(OBJDIR)/login.h $(SRCDIR)/config.h
1236 $(XTCC) -o $(OBJDIR)/login.o -c $(OBJDIR)/login_.c
1237
1238 $(OBJDIR)/login.h: $(OBJDIR)/headers
 
 
 
 
 
 
 
 
1239
1240 $(OBJDIR)/main_.c: $(SRCDIR)/main.c $(OBJDIR)/translate
1241 $(TRANSLATE) $(SRCDIR)/main.c >$(OBJDIR)/main_.c
1242
1243 $(OBJDIR)/main.o: $(OBJDIR)/main_.c $(OBJDIR)/main.h $(OBJDIR)/page_index.h $(SRCDIR)/config.h
1244
--- win/Makefile.mingw.mistachkin
+++ win/Makefile.mingw.mistachkin
@@ -298,10 +298,11 @@
298 $(SRCDIR)/json_timeline.c \
299 $(SRCDIR)/json_user.c \
300 $(SRCDIR)/json_wiki.c \
301 $(SRCDIR)/leaf.c \
302 $(SRCDIR)/login.c \
303 $(SRCDIR)/lookslike.c \
304 $(SRCDIR)/main.c \
305 $(SRCDIR)/manifest.c \
306 $(SRCDIR)/markdown.c \
307 $(SRCDIR)/markdown_html.c \
308 $(SRCDIR)/md5.c \
@@ -406,10 +407,11 @@
407 $(OBJDIR)/json_timeline_.c \
408 $(OBJDIR)/json_user_.c \
409 $(OBJDIR)/json_wiki_.c \
410 $(OBJDIR)/leaf_.c \
411 $(OBJDIR)/login_.c \
412 $(OBJDIR)/lookslike_.c \
413 $(OBJDIR)/main_.c \
414 $(OBJDIR)/manifest_.c \
415 $(OBJDIR)/markdown_.c \
416 $(OBJDIR)/markdown_html_.c \
417 $(OBJDIR)/md5_.c \
@@ -514,10 +516,11 @@
516 $(OBJDIR)/json_timeline.o \
517 $(OBJDIR)/json_user.o \
518 $(OBJDIR)/json_wiki.o \
519 $(OBJDIR)/leaf.o \
520 $(OBJDIR)/login.o \
521 $(OBJDIR)/lookslike.o \
522 $(OBJDIR)/main.o \
523 $(OBJDIR)/manifest.o \
524 $(OBJDIR)/markdown.o \
525 $(OBJDIR)/markdown_html.o \
526 $(OBJDIR)/md5.o \
@@ -735,10 +738,11 @@
738 $(OBJDIR)/json_timeline_.c:$(OBJDIR)/json_timeline.h \
739 $(OBJDIR)/json_user_.c:$(OBJDIR)/json_user.h \
740 $(OBJDIR)/json_wiki_.c:$(OBJDIR)/json_wiki.h \
741 $(OBJDIR)/leaf_.c:$(OBJDIR)/leaf.h \
742 $(OBJDIR)/login_.c:$(OBJDIR)/login.h \
743 $(OBJDIR)/lookslike_.c:$(OBJDIR)/lookslike.h \
744 $(OBJDIR)/main_.c:$(OBJDIR)/main.h \
745 $(OBJDIR)/manifest_.c:$(OBJDIR)/manifest.h \
746 $(OBJDIR)/markdown_.c:$(OBJDIR)/markdown.h \
747 $(OBJDIR)/markdown_html_.c:$(OBJDIR)/markdown_html.h \
748 $(OBJDIR)/md5_.c:$(OBJDIR)/md5.h \
@@ -1234,10 +1238,18 @@
1238
1239 $(OBJDIR)/login.o: $(OBJDIR)/login_.c $(OBJDIR)/login.h $(SRCDIR)/config.h
1240 $(XTCC) -o $(OBJDIR)/login.o -c $(OBJDIR)/login_.c
1241
1242 $(OBJDIR)/login.h: $(OBJDIR)/headers
1243
1244 $(OBJDIR)/lookslike_.c: $(SRCDIR)/lookslike.c $(OBJDIR)/translate
1245 $(TRANSLATE) $(SRCDIR)/lookslike.c >$(OBJDIR)/lookslike_.c
1246
1247 $(OBJDIR)/lookslike.o: $(OBJDIR)/lookslike_.c $(OBJDIR)/lookslike.h $(SRCDIR)/config.h
1248 $(XTCC) -o $(OBJDIR)/lookslike.o -c $(OBJDIR)/lookslike_.c
1249
1250 $(OBJDIR)/lookslike.h: $(OBJDIR)/headers
1251
1252 $(OBJDIR)/main_.c: $(SRCDIR)/main.c $(OBJDIR)/translate
1253 $(TRANSLATE) $(SRCDIR)/main.c >$(OBJDIR)/main_.c
1254
1255 $(OBJDIR)/main.o: $(OBJDIR)/main_.c $(OBJDIR)/main.h $(OBJDIR)/page_index.h $(SRCDIR)/config.h
1256
--- win/Makefile.msc
+++ win/Makefile.msc
@@ -116,10 +116,11 @@
116116
json_timeline_.c \
117117
json_user_.c \
118118
json_wiki_.c \
119119
leaf_.c \
120120
login_.c \
121
+ lookslike_.c \
121122
main_.c \
122123
manifest_.c \
123124
markdown_.c \
124125
markdown_html_.c \
125126
md5_.c \
@@ -224,10 +225,11 @@
224225
$(OX)\json_timeline$O \
225226
$(OX)\json_user$O \
226227
$(OX)\json_wiki$O \
227228
$(OX)\leaf$O \
228229
$(OX)\login$O \
230
+ $(OX)\lookslike$O \
229231
$(OX)\main$O \
230232
$(OX)\manifest$O \
231233
$(OX)\markdown$O \
232234
$(OX)\markdown_html$O \
233235
$(OX)\md5$O \
@@ -350,10 +352,11 @@
350352
echo $(OX)\json_timeline.obj >> $@
351353
echo $(OX)\json_user.obj >> $@
352354
echo $(OX)\json_wiki.obj >> $@
353355
echo $(OX)\leaf.obj >> $@
354356
echo $(OX)\login.obj >> $@
357
+ echo $(OX)\lookslike.obj >> $@
355358
echo $(OX)\main.obj >> $@
356359
echo $(OX)\manifest.obj >> $@
357360
echo $(OX)\markdown.obj >> $@
358361
echo $(OX)\markdown_html.obj >> $@
359362
echo $(OX)\md5.obj >> $@
@@ -809,10 +812,16 @@
809812
$(OX)\login$O : login_.c login.h
810813
$(TCC) /Fo$@ -c login_.c
811814
812815
login_.c : $(SRCDIR)\login.c
813816
translate$E $** > $@
817
+
818
+$(OX)\lookslike$O : lookslike_.c lookslike.h
819
+ $(TCC) /Fo$@ -c lookslike_.c
820
+
821
+lookslike_.c : $(SRCDIR)\lookslike.c
822
+ translate$E $** > $@
814823
815824
$(OX)\main$O : main_.c main.h
816825
$(TCC) /Fo$@ -c main_.c
817826
818827
main_.c : $(SRCDIR)\main.c
@@ -1174,10 +1183,11 @@
11741183
json_timeline_.c:json_timeline.h \
11751184
json_user_.c:json_user.h \
11761185
json_wiki_.c:json_wiki.h \
11771186
leaf_.c:leaf.h \
11781187
login_.c:login.h \
1188
+ lookslike_.c:lookslike.h \
11791189
main_.c:main.h \
11801190
manifest_.c:manifest.h \
11811191
markdown_.c:markdown.h \
11821192
markdown_html_.c:markdown_html.h \
11831193
md5_.c:md5.h \
11841194
11851195
ADDED www/adding_code.wiki
--- win/Makefile.msc
+++ win/Makefile.msc
@@ -116,10 +116,11 @@
116 json_timeline_.c \
117 json_user_.c \
118 json_wiki_.c \
119 leaf_.c \
120 login_.c \
 
121 main_.c \
122 manifest_.c \
123 markdown_.c \
124 markdown_html_.c \
125 md5_.c \
@@ -224,10 +225,11 @@
224 $(OX)\json_timeline$O \
225 $(OX)\json_user$O \
226 $(OX)\json_wiki$O \
227 $(OX)\leaf$O \
228 $(OX)\login$O \
 
229 $(OX)\main$O \
230 $(OX)\manifest$O \
231 $(OX)\markdown$O \
232 $(OX)\markdown_html$O \
233 $(OX)\md5$O \
@@ -350,10 +352,11 @@
350 echo $(OX)\json_timeline.obj >> $@
351 echo $(OX)\json_user.obj >> $@
352 echo $(OX)\json_wiki.obj >> $@
353 echo $(OX)\leaf.obj >> $@
354 echo $(OX)\login.obj >> $@
 
355 echo $(OX)\main.obj >> $@
356 echo $(OX)\manifest.obj >> $@
357 echo $(OX)\markdown.obj >> $@
358 echo $(OX)\markdown_html.obj >> $@
359 echo $(OX)\md5.obj >> $@
@@ -809,10 +812,16 @@
809 $(OX)\login$O : login_.c login.h
810 $(TCC) /Fo$@ -c login_.c
811
812 login_.c : $(SRCDIR)\login.c
813 translate$E $** > $@
 
 
 
 
 
 
814
815 $(OX)\main$O : main_.c main.h
816 $(TCC) /Fo$@ -c main_.c
817
818 main_.c : $(SRCDIR)\main.c
@@ -1174,10 +1183,11 @@
1174 json_timeline_.c:json_timeline.h \
1175 json_user_.c:json_user.h \
1176 json_wiki_.c:json_wiki.h \
1177 leaf_.c:leaf.h \
1178 login_.c:login.h \
 
1179 main_.c:main.h \
1180 manifest_.c:manifest.h \
1181 markdown_.c:markdown.h \
1182 markdown_html_.c:markdown_html.h \
1183 md5_.c:md5.h \
1184
1185 DDED www/adding_code.wiki
--- win/Makefile.msc
+++ win/Makefile.msc
@@ -116,10 +116,11 @@
116 json_timeline_.c \
117 json_user_.c \
118 json_wiki_.c \
119 leaf_.c \
120 login_.c \
121 lookslike_.c \
122 main_.c \
123 manifest_.c \
124 markdown_.c \
125 markdown_html_.c \
126 md5_.c \
@@ -224,10 +225,11 @@
225 $(OX)\json_timeline$O \
226 $(OX)\json_user$O \
227 $(OX)\json_wiki$O \
228 $(OX)\leaf$O \
229 $(OX)\login$O \
230 $(OX)\lookslike$O \
231 $(OX)\main$O \
232 $(OX)\manifest$O \
233 $(OX)\markdown$O \
234 $(OX)\markdown_html$O \
235 $(OX)\md5$O \
@@ -350,10 +352,11 @@
352 echo $(OX)\json_timeline.obj >> $@
353 echo $(OX)\json_user.obj >> $@
354 echo $(OX)\json_wiki.obj >> $@
355 echo $(OX)\leaf.obj >> $@
356 echo $(OX)\login.obj >> $@
357 echo $(OX)\lookslike.obj >> $@
358 echo $(OX)\main.obj >> $@
359 echo $(OX)\manifest.obj >> $@
360 echo $(OX)\markdown.obj >> $@
361 echo $(OX)\markdown_html.obj >> $@
362 echo $(OX)\md5.obj >> $@
@@ -809,10 +812,16 @@
812 $(OX)\login$O : login_.c login.h
813 $(TCC) /Fo$@ -c login_.c
814
815 login_.c : $(SRCDIR)\login.c
816 translate$E $** > $@
817
818 $(OX)\lookslike$O : lookslike_.c lookslike.h
819 $(TCC) /Fo$@ -c lookslike_.c
820
821 lookslike_.c : $(SRCDIR)\lookslike.c
822 translate$E $** > $@
823
824 $(OX)\main$O : main_.c main.h
825 $(TCC) /Fo$@ -c main_.c
826
827 main_.c : $(SRCDIR)\main.c
@@ -1174,10 +1183,11 @@
1183 json_timeline_.c:json_timeline.h \
1184 json_user_.c:json_user.h \
1185 json_wiki_.c:json_wiki.h \
1186 leaf_.c:leaf.h \
1187 login_.c:login.h \
1188 lookslike_.c:lookslike.h \
1189 main_.c:main.h \
1190 manifest_.c:manifest.h \
1191 markdown_.c:markdown.h \
1192 markdown_html_.c:markdown_html.h \
1193 md5_.c:md5.h \
1194
1195 DDED www/adding_code.wiki
--- a/www/adding_code.wiki
+++ b/www/adding_code.wiki
@@ -0,0 +1 @@
1
+agt the the
--- a/www/adding_code.wiki
+++ b/www/adding_code.wiki
@@ -0,0 +1 @@
 
--- a/www/adding_code.wiki
+++ b/www/adding_code.wiki
@@ -0,0 +1 @@
1 agt the the
--- www/build.wiki
+++ www/build.wiki
@@ -122,10 +122,17 @@
122122
you, or for some other reason you want to know how to build
123123
Fossil manually, then refer to the
124124
[./makefile.wiki | Fossil Build Process] document which describes
125125
in detail what the makefiles do behind the scenes.
126126
127
+<li><p>
128
+ The fossil executable is self-contained and stand-alone and usually
129
+ requires no special libraries or other software to be installed. However,
130
+ the "--tk" option to the [/help/diff|diff command] requires that Tcl/Tk
131
+ be installed on the local machine. You can get Tcl/Tk from
132
+ [http://www.activestate.com/activetcl|ActiveState].
133
+
127134
<li><p>
128135
To build on older Macs (circa 2002, MacOS 10.2) edit the Makefile
129136
generated by configure to add the following lines:
130137
<blockquote><pre>
131138
TCC += -DSQLITE_WITHOUT_ZONEMALLOC
132139
--- www/build.wiki
+++ www/build.wiki
@@ -122,10 +122,17 @@
122 you, or for some other reason you want to know how to build
123 Fossil manually, then refer to the
124 [./makefile.wiki | Fossil Build Process] document which describes
125 in detail what the makefiles do behind the scenes.
126
 
 
 
 
 
 
 
127 <li><p>
128 To build on older Macs (circa 2002, MacOS 10.2) edit the Makefile
129 generated by configure to add the following lines:
130 <blockquote><pre>
131 TCC += -DSQLITE_WITHOUT_ZONEMALLOC
132
--- www/build.wiki
+++ www/build.wiki
@@ -122,10 +122,17 @@
122 you, or for some other reason you want to know how to build
123 Fossil manually, then refer to the
124 [./makefile.wiki | Fossil Build Process] document which describes
125 in detail what the makefiles do behind the scenes.
126
127 <li><p>
128 The fossil executable is self-contained and stand-alone and usually
129 requires no special libraries or other software to be installed. However,
130 the "--tk" option to the [/help/diff|diff command] requires that Tcl/Tk
131 be installed on the local machine. You can get Tcl/Tk from
132 [http://www.activestate.com/activetcl|ActiveState].
133
134 <li><p>
135 To build on older Macs (circa 2002, MacOS 10.2) edit the Makefile
136 generated by configure to add the following lines:
137 <blockquote><pre>
138 TCC += -DSQLITE_WITHOUT_ZONEMALLOC
139
--- www/contribute.wiki
+++ www/contribute.wiki
@@ -78,5 +78,6 @@
7878
<h2>5.0 See Also</h2>
7979
8080
* [./build.wiki | How To Compile And Install Fossil]
8181
* [./makefile.wiki | The Fossil Build Process]
8282
* [./tech_overview.wiki | A Technical Overview of Fossil]
83
+ * [./adding_code.wiki | Adding Features To Fossil]
8384
--- www/contribute.wiki
+++ www/contribute.wiki
@@ -78,5 +78,6 @@
78 <h2>5.0 See Also</h2>
79
80 * [./build.wiki | How To Compile And Install Fossil]
81 * [./makefile.wiki | The Fossil Build Process]
82 * [./tech_overview.wiki | A Technical Overview of Fossil]
 
83
--- www/contribute.wiki
+++ www/contribute.wiki
@@ -78,5 +78,6 @@
78 <h2>5.0 See Also</h2>
79
80 * [./build.wiki | How To Compile And Install Fossil]
81 * [./makefile.wiki | The Fossil Build Process]
82 * [./tech_overview.wiki | A Technical Overview of Fossil]
83 * [./adding_code.wiki | Adding Features To Fossil]
84
+4 -4
--- www/faq.tcl
+++ www/faq.tcl
@@ -37,13 +37,11 @@
3737
} {
3838
There are lots of ways:
3939
4040
When you are checking in a new change using the <b>[/help/commit|commit]</b>
4141
command, you can add the option "--branch <i>BRANCH-NAME</i>" to
42
- make the new check-in be the first check-in for a new branch. You can
43
- also add the "--bgcolor <i>COLOR</i>" option to give the branch a
44
- specific background color on timelines.
42
+ make the new check-in be the first check-in for a new branch.
4543
4644
If you want to create a new branch whose initial content is the
4745
same as an existing check-in, use this command:
4846
4947
<blockquote>
@@ -70,11 +68,13 @@
7068
} {
7169
There are several ways:
7270
7371
When you are checking in a new change using the <b>[/help/commit|commit]</b>
7472
command, you can add a tag to that check-in using the
75
- "--tag <i>TAGNAME</i>" command-line option.
73
+ "--tag <i>TAGNAME</i>" command-line option. You can repeat the --tag
74
+ option to give a check-in multiple tags. Tags need not be unique. So,
75
+ for example, it is common to give every released version a "release" tag.
7676
7777
If you want add a tag to an existing check-in, you can use the
7878
<b>[/help/tag|tag]</b> command. For example:
7979
8080
<blockquote>
8181
--- www/faq.tcl
+++ www/faq.tcl
@@ -37,13 +37,11 @@
37 } {
38 There are lots of ways:
39
40 When you are checking in a new change using the <b>[/help/commit|commit]</b>
41 command, you can add the option "--branch <i>BRANCH-NAME</i>" to
42 make the new check-in be the first check-in for a new branch. You can
43 also add the "--bgcolor <i>COLOR</i>" option to give the branch a
44 specific background color on timelines.
45
46 If you want to create a new branch whose initial content is the
47 same as an existing check-in, use this command:
48
49 <blockquote>
@@ -70,11 +68,13 @@
70 } {
71 There are several ways:
72
73 When you are checking in a new change using the <b>[/help/commit|commit]</b>
74 command, you can add a tag to that check-in using the
75 "--tag <i>TAGNAME</i>" command-line option.
 
 
76
77 If you want add a tag to an existing check-in, you can use the
78 <b>[/help/tag|tag]</b> command. For example:
79
80 <blockquote>
81
--- www/faq.tcl
+++ www/faq.tcl
@@ -37,13 +37,11 @@
37 } {
38 There are lots of ways:
39
40 When you are checking in a new change using the <b>[/help/commit|commit]</b>
41 command, you can add the option "--branch <i>BRANCH-NAME</i>" to
42 make the new check-in be the first check-in for a new branch.
 
 
43
44 If you want to create a new branch whose initial content is the
45 same as an existing check-in, use this command:
46
47 <blockquote>
@@ -70,11 +68,13 @@
68 } {
69 There are several ways:
70
71 When you are checking in a new change using the <b>[/help/commit|commit]</b>
72 command, you can add a tag to that check-in using the
73 "--tag <i>TAGNAME</i>" command-line option. You can repeat the --tag
74 option to give a check-in multiple tags. Tags need not be unique. So,
75 for example, it is common to give every released version a "release" tag.
76
77 If you want add a tag to an existing check-in, you can use the
78 <b>[/help/tag|tag]</b> command. For example:
79
80 <blockquote>
81
+4 -4
--- www/faq.wiki
+++ www/faq.wiki
@@ -41,13 +41,11 @@
4141
4242
<blockquote>There are lots of ways:
4343
4444
When you are checking in a new change using the <b>[/help/commit|commit]</b>
4545
command, you can add the option "--branch <i>BRANCH-NAME</i>" to
46
-make the new check-in be the first check-in for a new branch. You can
47
-also add the "--bgcolor <i>COLOR</i>" option to give the branch a
48
-specific background color on timelines.
46
+make the new check-in be the first check-in for a new branch.
4947
5048
If you want to create a new branch whose initial content is the
5149
same as an existing check-in, use this command:
5250
5351
<blockquote>
@@ -73,11 +71,13 @@
7371
7472
<blockquote>There are several ways:
7573
7674
When you are checking in a new change using the <b>[/help/commit|commit]</b>
7775
command, you can add a tag to that check-in using the
78
-"--tag <i>TAGNAME</i>" command-line option.
76
+"--tag <i>TAGNAME</i>" command-line option. You can repeat the --tag
77
+option to give a check-in multiple tags. Tags need not be unique. So,
78
+for example, it is common to give every released version a "release" tag.
7979
8080
If you want add a tag to an existing check-in, you can use the
8181
<b>[/help/tag|tag]</b> command. For example:
8282
8383
<blockquote>
8484
--- www/faq.wiki
+++ www/faq.wiki
@@ -41,13 +41,11 @@
41
42 <blockquote>There are lots of ways:
43
44 When you are checking in a new change using the <b>[/help/commit|commit]</b>
45 command, you can add the option "--branch <i>BRANCH-NAME</i>" to
46 make the new check-in be the first check-in for a new branch. You can
47 also add the "--bgcolor <i>COLOR</i>" option to give the branch a
48 specific background color on timelines.
49
50 If you want to create a new branch whose initial content is the
51 same as an existing check-in, use this command:
52
53 <blockquote>
@@ -73,11 +71,13 @@
73
74 <blockquote>There are several ways:
75
76 When you are checking in a new change using the <b>[/help/commit|commit]</b>
77 command, you can add a tag to that check-in using the
78 "--tag <i>TAGNAME</i>" command-line option.
 
 
79
80 If you want add a tag to an existing check-in, you can use the
81 <b>[/help/tag|tag]</b> command. For example:
82
83 <blockquote>
84
--- www/faq.wiki
+++ www/faq.wiki
@@ -41,13 +41,11 @@
41
42 <blockquote>There are lots of ways:
43
44 When you are checking in a new change using the <b>[/help/commit|commit]</b>
45 command, you can add the option "--branch <i>BRANCH-NAME</i>" to
46 make the new check-in be the first check-in for a new branch.
 
 
47
48 If you want to create a new branch whose initial content is the
49 same as an existing check-in, use this command:
50
51 <blockquote>
@@ -73,11 +71,13 @@
71
72 <blockquote>There are several ways:
73
74 When you are checking in a new change using the <b>[/help/commit|commit]</b>
75 command, you can add a tag to that check-in using the
76 "--tag <i>TAGNAME</i>" command-line option. You can repeat the --tag
77 option to give a check-in multiple tags. Tags need not be unique. So,
78 for example, it is common to give every released version a "release" tag.
79
80 If you want add a tag to an existing check-in, you can use the
81 <b>[/help/tag|tag]</b> command. For example:
82
83 <blockquote>
84
--- www/fossil-v-git.wiki
+++ www/fossil-v-git.wiki
@@ -35,11 +35,11 @@
3535
<h3>3.1 Feature Set</h3>
3636
3737
Git provides file versioning services only, whereas Fossil adds an
3838
integrated [./wikitheory.wiki | wiki],
3939
[./bugtheory.wiki | ticketing &amp; bug tracking],
40
-[./embedddeddoc.wiki | embedded documentation], and
40
+[./embeddeddoc.wiki | embedded documentation], and
4141
[./event.wiki | News/Blog features].
4242
These additional capabilities are available for Git as 3rd-party
4343
user-installed add-ons, but with Fossil they are integrated into
4444
the design. One way to describe Fossil is that it is
4545
"[https://github.com/ | github]-in-a-box".
@@ -74,11 +74,11 @@
7474
until they reach the master branch.
7575
7676
Fossil is designed for smaller and non-hierarchical teams where all
7777
developers are operating directly on the master branch, or at most
7878
a small number of well defined branches.
79
-The [concepts.wiki#workflow | autosync] mode of Fossil makes it easy
79
+The [./concepts.wiki#workflow | autosync] mode of Fossil makes it easy
8080
for multiple developers to work on a single branch and maintain
8181
linear development on that branch and avoid needless forking
8282
and merging.
8383
8484
<h3>3.3 Branches</h3>
@@ -115,13 +115,18 @@
115115
The Git approach scales much better for large projects like the Linux
116116
kernel with thousands of contributors who in many cases don't even know
117117
each others names. The integrators serve a gatekeeper role to help keep
118118
undesirable code out of the official Linux source tree. On the other hand,
119119
not many projects are as big or as loosely organized as the Linux kernel.
120
-Most project, have a small team of developers who all know each other
120
+Most projects have a small team of developers who all know each other
121121
well and trust each other, and who enjoy working together collaboratively
122122
without the overhead and hierarchy of integrators.
123
+
124
+One consequence of the "everybody-sees-everything" focus of Fossil is that
125
+branch names are global and are part of the distributed and synchronized
126
+content of a Fossil repository, rather than being private and user-specific
127
+as they are in Git.
123128
124129
<h3>3.4 Complexity</h3>
125130
126131
Git is a complex system. It can be tricky to use and requires a fair
127132
amount of knowledge and experience to master. Fossil strives to be
@@ -139,19 +144,20 @@
139144
Git requires the developer to maintain a more complex mental model than
140145
most other DVCSes. Git takes longer to learn. And you have to spend
141146
more time thinking about what you are doing with Git.
142147
143148
Fossil strives for simplicity. Fossil wants to be easy to learn and to
144
-require little thinking about how to operating it. Reports from the
145
-field indicate that Fossil is mostly successful at this effort.
149
+require little thinking about how to operating it.
150
+[./quotes.wiki | Reports from the field]
151
+indicate that Fossil is mostly successful at this effort.
146152
147153
<h3>3.5 Web Interface</h3>
148154
149155
Git has a web interface, but it requires a fair amount of setup and an
150156
external web server. Fossil comes with a fully functional
151157
[./webui.wiki | built-in web-server]
152
-and a really simple mechanism (the "<tt>fossil ui</tt>" command) to
158
+and a really simple mechanism (the "[/help/ui|fossil ui]" command) to
153159
automatically start the web server and bring up a web browser to navigate
154160
it. The web interface for Fossil is not only easier to set up, it is also
155161
more powerful and easier to use. The web interface to Fossil is a practical
156162
replacement to the 3rd-party "GUI Tools" that users often employ to operate
157163
Git.
@@ -188,22 +194,29 @@
188194
<h3>3.8 Audit Trail</h3>
189195
190196
Git features the "rebase" command which can be used to change the
191197
sequence of check-ins in the repository. Rebase can be used to "clean up"
192198
a complex sequence of check-ins to make their intent easier for others
193
-to understand. From another point of view, rebase can be used to
194
-"rewrite history" - to do what
195
-[http://en.wikipedia.org/wiki/Winston_Smith | Winston Smith] did for
196
-a living in Orwell's novel
197
-[http://en.wikipedia.org/wiki/Nineteen_Eighty-Four | 1984].
198
-
199
-Fossil deliberately avoids rewriting history. Fossil strives to follow
200
-the accountants philosophy of never erasing anything. Mistakes are fixed
201
-by entering a correction, with an explanation of why the correction is
202
-needed. This can make the history of a project messy, but it also
203
-makes it more honest. The lack of a "rebase" function is considered
204
-a feature of Fossil, not a bug.
199
+to understand. This is important if you view the history of a project
200
+as part of the documentation for the project.
201
+
202
+Fossil takes an opposing view. Fossil views history as sacrosanct and
203
+stubornly refuses to change it.
204
+Fossil allows mistakes to be corrected (for example, check-in comments
205
+can be revised, and check-ins can be moved onto new branches even after
206
+the check-in has occurred) but the correction is an addition to the respository
207
+and the original actions are preserved and displayed alongside
208
+the corrections, thus preserving an historically accurate audit trail.
209
+This is analogous to an accountant marking through an incorrect
210
+entry in a ledger and writing in a correction beside it, rather than
211
+erasing and incorrect entry.
212
+
213
+To put it another way, Git remembers what you should have done whereas
214
+Fossil remembers what you actually did.
215
+
216
+The lack of a "rebase" command and the inability to rewrite history
217
+is considered a feature of Fossil, not an omission or bug.
205218
206219
<h3>3.9 License</h3>
207220
208221
Both Git and Fossil are open-source. Git is under
209222
[http://www.gnu.org/licenses/gpl.html | GPL] whereas Fossil is
210223
--- www/fossil-v-git.wiki
+++ www/fossil-v-git.wiki
@@ -35,11 +35,11 @@
35 <h3>3.1 Feature Set</h3>
36
37 Git provides file versioning services only, whereas Fossil adds an
38 integrated [./wikitheory.wiki | wiki],
39 [./bugtheory.wiki | ticketing &amp; bug tracking],
40 [./embedddeddoc.wiki | embedded documentation], and
41 [./event.wiki | News/Blog features].
42 These additional capabilities are available for Git as 3rd-party
43 user-installed add-ons, but with Fossil they are integrated into
44 the design. One way to describe Fossil is that it is
45 "[https://github.com/ | github]-in-a-box".
@@ -74,11 +74,11 @@
74 until they reach the master branch.
75
76 Fossil is designed for smaller and non-hierarchical teams where all
77 developers are operating directly on the master branch, or at most
78 a small number of well defined branches.
79 The [concepts.wiki#workflow | autosync] mode of Fossil makes it easy
80 for multiple developers to work on a single branch and maintain
81 linear development on that branch and avoid needless forking
82 and merging.
83
84 <h3>3.3 Branches</h3>
@@ -115,13 +115,18 @@
115 The Git approach scales much better for large projects like the Linux
116 kernel with thousands of contributors who in many cases don't even know
117 each others names. The integrators serve a gatekeeper role to help keep
118 undesirable code out of the official Linux source tree. On the other hand,
119 not many projects are as big or as loosely organized as the Linux kernel.
120 Most project, have a small team of developers who all know each other
121 well and trust each other, and who enjoy working together collaboratively
122 without the overhead and hierarchy of integrators.
 
 
 
 
 
123
124 <h3>3.4 Complexity</h3>
125
126 Git is a complex system. It can be tricky to use and requires a fair
127 amount of knowledge and experience to master. Fossil strives to be
@@ -139,19 +144,20 @@
139 Git requires the developer to maintain a more complex mental model than
140 most other DVCSes. Git takes longer to learn. And you have to spend
141 more time thinking about what you are doing with Git.
142
143 Fossil strives for simplicity. Fossil wants to be easy to learn and to
144 require little thinking about how to operating it. Reports from the
145 field indicate that Fossil is mostly successful at this effort.
 
146
147 <h3>3.5 Web Interface</h3>
148
149 Git has a web interface, but it requires a fair amount of setup and an
150 external web server. Fossil comes with a fully functional
151 [./webui.wiki | built-in web-server]
152 and a really simple mechanism (the "<tt>fossil ui</tt>" command) to
153 automatically start the web server and bring up a web browser to navigate
154 it. The web interface for Fossil is not only easier to set up, it is also
155 more powerful and easier to use. The web interface to Fossil is a practical
156 replacement to the 3rd-party "GUI Tools" that users often employ to operate
157 Git.
@@ -188,22 +194,29 @@
188 <h3>3.8 Audit Trail</h3>
189
190 Git features the "rebase" command which can be used to change the
191 sequence of check-ins in the repository. Rebase can be used to "clean up"
192 a complex sequence of check-ins to make their intent easier for others
193 to understand. From another point of view, rebase can be used to
194 "rewrite history" - to do what
195 [http://en.wikipedia.org/wiki/Winston_Smith | Winston Smith] did for
196 a living in Orwell's novel
197 [http://en.wikipedia.org/wiki/Nineteen_Eighty-Four | 1984].
198
199 Fossil deliberately avoids rewriting history. Fossil strives to follow
200 the accountants philosophy of never erasing anything. Mistakes are fixed
201 by entering a correction, with an explanation of why the correction is
202 needed. This can make the history of a project messy, but it also
203 makes it more honest. The lack of a "rebase" function is considered
204 a feature of Fossil, not a bug.
 
 
 
 
 
 
 
205
206 <h3>3.9 License</h3>
207
208 Both Git and Fossil are open-source. Git is under
209 [http://www.gnu.org/licenses/gpl.html | GPL] whereas Fossil is
210
--- www/fossil-v-git.wiki
+++ www/fossil-v-git.wiki
@@ -35,11 +35,11 @@
35 <h3>3.1 Feature Set</h3>
36
37 Git provides file versioning services only, whereas Fossil adds an
38 integrated [./wikitheory.wiki | wiki],
39 [./bugtheory.wiki | ticketing &amp; bug tracking],
40 [./embeddeddoc.wiki | embedded documentation], and
41 [./event.wiki | News/Blog features].
42 These additional capabilities are available for Git as 3rd-party
43 user-installed add-ons, but with Fossil they are integrated into
44 the design. One way to describe Fossil is that it is
45 "[https://github.com/ | github]-in-a-box".
@@ -74,11 +74,11 @@
74 until they reach the master branch.
75
76 Fossil is designed for smaller and non-hierarchical teams where all
77 developers are operating directly on the master branch, or at most
78 a small number of well defined branches.
79 The [./concepts.wiki#workflow | autosync] mode of Fossil makes it easy
80 for multiple developers to work on a single branch and maintain
81 linear development on that branch and avoid needless forking
82 and merging.
83
84 <h3>3.3 Branches</h3>
@@ -115,13 +115,18 @@
115 The Git approach scales much better for large projects like the Linux
116 kernel with thousands of contributors who in many cases don't even know
117 each others names. The integrators serve a gatekeeper role to help keep
118 undesirable code out of the official Linux source tree. On the other hand,
119 not many projects are as big or as loosely organized as the Linux kernel.
120 Most projects have a small team of developers who all know each other
121 well and trust each other, and who enjoy working together collaboratively
122 without the overhead and hierarchy of integrators.
123
124 One consequence of the "everybody-sees-everything" focus of Fossil is that
125 branch names are global and are part of the distributed and synchronized
126 content of a Fossil repository, rather than being private and user-specific
127 as they are in Git.
128
129 <h3>3.4 Complexity</h3>
130
131 Git is a complex system. It can be tricky to use and requires a fair
132 amount of knowledge and experience to master. Fossil strives to be
@@ -139,19 +144,20 @@
144 Git requires the developer to maintain a more complex mental model than
145 most other DVCSes. Git takes longer to learn. And you have to spend
146 more time thinking about what you are doing with Git.
147
148 Fossil strives for simplicity. Fossil wants to be easy to learn and to
149 require little thinking about how to operating it.
150 [./quotes.wiki | Reports from the field]
151 indicate that Fossil is mostly successful at this effort.
152
153 <h3>3.5 Web Interface</h3>
154
155 Git has a web interface, but it requires a fair amount of setup and an
156 external web server. Fossil comes with a fully functional
157 [./webui.wiki | built-in web-server]
158 and a really simple mechanism (the "[/help/ui|fossil ui]" command) to
159 automatically start the web server and bring up a web browser to navigate
160 it. The web interface for Fossil is not only easier to set up, it is also
161 more powerful and easier to use. The web interface to Fossil is a practical
162 replacement to the 3rd-party "GUI Tools" that users often employ to operate
163 Git.
@@ -188,22 +194,29 @@
194 <h3>3.8 Audit Trail</h3>
195
196 Git features the "rebase" command which can be used to change the
197 sequence of check-ins in the repository. Rebase can be used to "clean up"
198 a complex sequence of check-ins to make their intent easier for others
199 to understand. This is important if you view the history of a project
200 as part of the documentation for the project.
201
202 Fossil takes an opposing view. Fossil views history as sacrosanct and
203 stubornly refuses to change it.
204 Fossil allows mistakes to be corrected (for example, check-in comments
205 can be revised, and check-ins can be moved onto new branches even after
206 the check-in has occurred) but the correction is an addition to the respository
207 and the original actions are preserved and displayed alongside
208 the corrections, thus preserving an historically accurate audit trail.
209 This is analogous to an accountant marking through an incorrect
210 entry in a ledger and writing in a correction beside it, rather than
211 erasing and incorrect entry.
212
213 To put it another way, Git remembers what you should have done whereas
214 Fossil remembers what you actually did.
215
216 The lack of a "rebase" command and the inability to rewrite history
217 is considered a feature of Fossil, not an omission or bug.
218
219 <h3>3.9 License</h3>
220
221 Both Git and Fossil are open-source. Git is under
222 [http://www.gnu.org/licenses/gpl.html | GPL] whereas Fossil is
223
+5 -3
--- www/hints.wiki
+++ www/hints.wiki
@@ -1,8 +1,8 @@
11
<title>Fossil Tips And Usage Hints</title>
22
3
- 1. Click on nodes of any timeline graph to see diffs between two
3
+ 1. Click on nodes of any timeline graph to see diffs between the two
44
selected versions.
55
66
2. Add the "--tk" option to "[/help?cmd=diff | fossil diff]" commands
77
to get a pop-up
88
window containing a complete side-by-side diff. (NB: The pop-up
@@ -14,13 +14,15 @@
1414
3. The "[/help?cmd=clean | fossil clean -f]" command makes a great
1515
alternative to "make clean".
1616
1717
4. Use "[/help?cmd=all | fossil all changes]" to look for any uncommitted
1818
edits in any of your Fossil projects. Use
19
- "[/help?cmd=all | fossil all sync]" on your laptop
19
+ "[/help?cmd=all | fossil all pull]" on your laptop
2020
prior to going off network (for example, on a long plane ride)
21
- to make sure you have all of content local.
21
+ to make sure you have all the latest content locally. Then run
22
+ "[/help/all|fossil all push]" when you get back online to upload
23
+ your changes.
2224
2325
5. Sub-menu options on Timelines lets you select either 20 or 200
2426
records. But you can manual edit the "n=" query parameter in the
2527
URL to get any number of records you desire. To see a complete
2628
timeline graph, set n to some ridiculously large value like 10000000.
2729
--- www/hints.wiki
+++ www/hints.wiki
@@ -1,8 +1,8 @@
1 <title>Fossil Tips And Usage Hints</title>
2
3 1. Click on nodes of any timeline graph to see diffs between two
4 selected versions.
5
6 2. Add the "--tk" option to "[/help?cmd=diff | fossil diff]" commands
7 to get a pop-up
8 window containing a complete side-by-side diff. (NB: The pop-up
@@ -14,13 +14,15 @@
14 3. The "[/help?cmd=clean | fossil clean -f]" command makes a great
15 alternative to "make clean".
16
17 4. Use "[/help?cmd=all | fossil all changes]" to look for any uncommitted
18 edits in any of your Fossil projects. Use
19 "[/help?cmd=all | fossil all sync]" on your laptop
20 prior to going off network (for example, on a long plane ride)
21 to make sure you have all of content local.
 
 
22
23 5. Sub-menu options on Timelines lets you select either 20 or 200
24 records. But you can manual edit the "n=" query parameter in the
25 URL to get any number of records you desire. To see a complete
26 timeline graph, set n to some ridiculously large value like 10000000.
27
--- www/hints.wiki
+++ www/hints.wiki
@@ -1,8 +1,8 @@
1 <title>Fossil Tips And Usage Hints</title>
2
3 1. Click on nodes of any timeline graph to see diffs between the two
4 selected versions.
5
6 2. Add the "--tk" option to "[/help?cmd=diff | fossil diff]" commands
7 to get a pop-up
8 window containing a complete side-by-side diff. (NB: The pop-up
@@ -14,13 +14,15 @@
14 3. The "[/help?cmd=clean | fossil clean -f]" command makes a great
15 alternative to "make clean".
16
17 4. Use "[/help?cmd=all | fossil all changes]" to look for any uncommitted
18 edits in any of your Fossil projects. Use
19 "[/help?cmd=all | fossil all pull]" on your laptop
20 prior to going off network (for example, on a long plane ride)
21 to make sure you have all the latest content locally. Then run
22 "[/help/all|fossil all push]" when you get back online to upload
23 your changes.
24
25 5. Sub-menu options on Timelines lets you select either 20 or 200
26 records. But you can manual edit the "n=" query parameter in the
27 URL to get any number of records you desire. To see a complete
28 timeline graph, set n to some ridiculously large value like 10000000.
29
--- www/makefile.wiki
+++ www/makefile.wiki
@@ -12,10 +12,11 @@
1212
So must people do not need to be concerned with the
1313
build complexities of Fossil. But hard-core developers who desire
1414
a deep understanding of how Fossil is put together can benefit
1515
from reviewing this article.
1616
17
+<a name="srctour"></a>
1718
<h1>2.0 Source Code Tour</h1>
1819
1920
The source code for Fossil is found in the
2021
[/dir?ci=trunk&name=src | src/] subdirectory of the
2122
source tree. The src/ subdirectory contains all code, including
@@ -117,10 +118,11 @@
117118
directories right. The point is that the manifest.uuid, manifest, and
118119
VERSION files
119120
in the root of the source tree are the three arguments and
120121
the generated VERSION.h file appears on standard output.
121122
123
+<a name="preprocessing"></a>
122124
<h1>4.0 Preprocessing</h1>
123125
124126
There are three preprocessors for the Fossil sources. The mkindex
125127
and translate preprocessors can be run in any order. The makeheaders
126128
preprocessor must be run after translate.
@@ -236,5 +238,10 @@
236238
Fossil needs to be linked against [http://www.zlib.net | zlib]. If
237239
the HTTPS option is enabled, then it will also need to link against
238240
the appropriate SSL implementation. And, of course, Fossil needs to
239241
link against the standard C library. No other libraries or external
240242
dependences are used.
243
+
244
+<h1>7.0 See Also</h1>
245
+
246
+ * [./tech_overview.wiki | A Technical Overview Of Fossil]
247
+ * [./adding_code.wiki | How To Add Features To Fossil]
241248
--- www/makefile.wiki
+++ www/makefile.wiki
@@ -12,10 +12,11 @@
12 So must people do not need to be concerned with the
13 build complexities of Fossil. But hard-core developers who desire
14 a deep understanding of how Fossil is put together can benefit
15 from reviewing this article.
16
 
17 <h1>2.0 Source Code Tour</h1>
18
19 The source code for Fossil is found in the
20 [/dir?ci=trunk&name=src | src/] subdirectory of the
21 source tree. The src/ subdirectory contains all code, including
@@ -117,10 +118,11 @@
117 directories right. The point is that the manifest.uuid, manifest, and
118 VERSION files
119 in the root of the source tree are the three arguments and
120 the generated VERSION.h file appears on standard output.
121
 
122 <h1>4.0 Preprocessing</h1>
123
124 There are three preprocessors for the Fossil sources. The mkindex
125 and translate preprocessors can be run in any order. The makeheaders
126 preprocessor must be run after translate.
@@ -236,5 +238,10 @@
236 Fossil needs to be linked against [http://www.zlib.net | zlib]. If
237 the HTTPS option is enabled, then it will also need to link against
238 the appropriate SSL implementation. And, of course, Fossil needs to
239 link against the standard C library. No other libraries or external
240 dependences are used.
 
 
 
 
 
241
--- www/makefile.wiki
+++ www/makefile.wiki
@@ -12,10 +12,11 @@
12 So must people do not need to be concerned with the
13 build complexities of Fossil. But hard-core developers who desire
14 a deep understanding of how Fossil is put together can benefit
15 from reviewing this article.
16
17 <a name="srctour"></a>
18 <h1>2.0 Source Code Tour</h1>
19
20 The source code for Fossil is found in the
21 [/dir?ci=trunk&name=src | src/] subdirectory of the
22 source tree. The src/ subdirectory contains all code, including
@@ -117,10 +118,11 @@
118 directories right. The point is that the manifest.uuid, manifest, and
119 VERSION files
120 in the root of the source tree are the three arguments and
121 the generated VERSION.h file appears on standard output.
122
123 <a name="preprocessing"></a>
124 <h1>4.0 Preprocessing</h1>
125
126 There are three preprocessors for the Fossil sources. The mkindex
127 and translate preprocessors can be run in any order. The makeheaders
128 preprocessor must be run after translate.
@@ -236,5 +238,10 @@
238 Fossil needs to be linked against [http://www.zlib.net | zlib]. If
239 the HTTPS option is enabled, then it will also need to link against
240 the appropriate SSL implementation. And, of course, Fossil needs to
241 link against the standard C library. No other libraries or external
242 dependences are used.
243
244 <h1>7.0 See Also</h1>
245
246 * [./tech_overview.wiki | A Technical Overview Of Fossil]
247 * [./adding_code.wiki | How To Add Features To Fossil]
248
--- www/mkindex.tcl
+++ www/mkindex.tcl
@@ -5,10 +5,12 @@
55
#
66
# tclsh mkindex.tcl >permutedindex.wiki
77
#
88
99
set doclist {
10
+ adding_code.wiki {Adding New Features To Fossil}
11
+ adding_code.wiki {Hacking Fossil}
1012
antibot.wiki {Defense against Spiders and Bots}
1113
bugtheory.wiki {Bug Tracking In Fossil}
1214
branching.wiki {Branching, Forking, Merging, and Tagging}
1315
build.wiki {Compiling and Installing Fossil}
1416
checkin_names.wiki {Checkin And Version Names}
1517
--- www/mkindex.tcl
+++ www/mkindex.tcl
@@ -5,10 +5,12 @@
5 #
6 # tclsh mkindex.tcl >permutedindex.wiki
7 #
8
9 set doclist {
 
 
10 antibot.wiki {Defense against Spiders and Bots}
11 bugtheory.wiki {Bug Tracking In Fossil}
12 branching.wiki {Branching, Forking, Merging, and Tagging}
13 build.wiki {Compiling and Installing Fossil}
14 checkin_names.wiki {Checkin And Version Names}
15
--- www/mkindex.tcl
+++ www/mkindex.tcl
@@ -5,10 +5,12 @@
5 #
6 # tclsh mkindex.tcl >permutedindex.wiki
7 #
8
9 set doclist {
10 adding_code.wiki {Adding New Features To Fossil}
11 adding_code.wiki {Hacking Fossil}
12 antibot.wiki {Defense against Spiders and Bots}
13 bugtheory.wiki {Bug Tracking In Fossil}
14 branching.wiki {Branching, Forking, Merging, and Tagging}
15 build.wiki {Compiling and Installing Fossil}
16 checkin_names.wiki {Checkin And Version Names}
17
--- www/permutedindex.wiki
+++ www/permutedindex.wiki
@@ -13,10 +13,11 @@
1313
<h2>Permuted Index:</h2>
1414
<ul>
1515
<li><a href="fiveminutes.wiki">5 Minutes as a Single User &mdash; Update and Running in</a></li>
1616
<li><a href="fossil-from-msvc.wiki">2010 IDE &mdash; Integrating Fossil in the Microsoft Express</a></li>
1717
<li><a href="tech_overview.wiki">A Technical Overview Of The Design And Implementation Of Fossil</a></li>
18
+<li><a href="adding_code.wiki">Adding New Features To Fossil</a></li>
1819
<li><a href="antibot.wiki">against Spiders and Bots &mdash; Defense</a></li>
1920
<li><a href="copyright-release.html">Agreement &mdash; Contributor License</a></li>
2021
<li><a href="delta_encoder_algorithm.wiki">Algorithm &mdash; Fossil Delta Encoding</a></li>
2122
<li><a href="fiveminutes.wiki">as a Single User &mdash; Update and Running in 5 Minutes</a></li>
2223
<li><a href="faq.wiki">Asked Questions &mdash; Frequently</a></li>
@@ -61,10 +62,11 @@
6162
<li><a href="embeddeddoc.wiki">Embedded Project Documentation</a></li>
6263
<li><a href="delta_encoder_algorithm.wiki">Encoding Algorithm &mdash; Fossil Delta</a></li>
6364
<li><a href="event.wiki">Events</a></li>
6465
<li><a href="inout.wiki">Export To And From Git &mdash; Import And</a></li>
6566
<li><a href="fossil-from-msvc.wiki">Express 2010 IDE &mdash; Integrating Fossil in the Microsoft</a></li>
67
+<li><a href="adding_code.wiki">Features To Fossil &mdash; Adding New</a></li>
6668
<li><a href="fileformat.wiki">File Format &mdash; Fossil</a></li>
6769
<li><a href="branching.wiki">Forking, Merging, and Tagging &mdash; Branching,</a></li>
6870
<li><a href="delta_format.wiki">Format &mdash; Fossil Delta</a></li>
6971
<li><a href="fileformat.wiki">Format &mdash; Fossil File</a></li>
7072
<li><a href="changes.wiki">Fossil Changelog</a></li>
@@ -86,10 +88,11 @@
8688
<li><a href="fossil-v-git.wiki">Git &mdash; Fossil Versus</a></li>
8789
<li><a href="inout.wiki">Git &mdash; Import And Export To And From</a></li>
8890
<li><a href="quotes.wiki">Git, and DVCSes in General &mdash; Quotes: What People Are Saying About Fossil,</a></li>
8991
<li><a href="quickstart.wiki">Guide &mdash; Fossil Quick Start</a></li>
9092
<li><a href="style.wiki">Guidelines &mdash; Source Code Style</a></li>
93
+<li><a href="adding_code.wiki">Hacking Fossil</a></li>
9194
<li><a href="hints.wiki">Hints &mdash; Fossil Tips And Usage</a></li>
9295
<li><a href="index.wiki">Home Page</a></li>
9396
<li><a href="selfhost.wiki">Hosting Repositories &mdash; Fossil Self</a></li>
9497
<li><a href="server.wiki">How To Configure A Fossil Server</a></li>
9598
<li><a href="newrepo.wiki">How To Create A New Fossil Repository</a></li>
@@ -104,10 +107,11 @@
104107
<li><a href="password.wiki">Management And Authentication &mdash; Password</a></li>
105108
<li><a href="branching.wiki">Merging, and Tagging &mdash; Branching, Forking,</a></li>
106109
<li><a href="fossil-from-msvc.wiki">Microsoft Express 2010 IDE &mdash; Integrating Fossil in the</a></li>
107110
<li><a href="fiveminutes.wiki">Minutes as a Single User &mdash; Update and Running in 5</a></li>
108111
<li><a href="checkin_names.wiki">Names &mdash; Checkin And Version</a></li>
112
+<li><a href="adding_code.wiki">New Features To Fossil &mdash; Adding</a></li>
109113
<li><a href="newrepo.wiki">New Fossil Repository &mdash; How To Create A</a></li>
110114
<li><a href="foss-cklist.wiki">Open-Source Projects &mdash; Checklist For Successful</a></li>
111115
<li><a href="pop.wiki">Operations &mdash; Principles Of</a></li>
112116
<li><a href="tech_overview.wiki">Overview Of The Design And Implementation Of Fossil &mdash; A Technical</a></li>
113117
<li><a href="index.wiki">Page &mdash; Home</a></li>
114118
--- www/permutedindex.wiki
+++ www/permutedindex.wiki
@@ -13,10 +13,11 @@
13 <h2>Permuted Index:</h2>
14 <ul>
15 <li><a href="fiveminutes.wiki">5 Minutes as a Single User &mdash; Update and Running in</a></li>
16 <li><a href="fossil-from-msvc.wiki">2010 IDE &mdash; Integrating Fossil in the Microsoft Express</a></li>
17 <li><a href="tech_overview.wiki">A Technical Overview Of The Design And Implementation Of Fossil</a></li>
 
18 <li><a href="antibot.wiki">against Spiders and Bots &mdash; Defense</a></li>
19 <li><a href="copyright-release.html">Agreement &mdash; Contributor License</a></li>
20 <li><a href="delta_encoder_algorithm.wiki">Algorithm &mdash; Fossil Delta Encoding</a></li>
21 <li><a href="fiveminutes.wiki">as a Single User &mdash; Update and Running in 5 Minutes</a></li>
22 <li><a href="faq.wiki">Asked Questions &mdash; Frequently</a></li>
@@ -61,10 +62,11 @@
61 <li><a href="embeddeddoc.wiki">Embedded Project Documentation</a></li>
62 <li><a href="delta_encoder_algorithm.wiki">Encoding Algorithm &mdash; Fossil Delta</a></li>
63 <li><a href="event.wiki">Events</a></li>
64 <li><a href="inout.wiki">Export To And From Git &mdash; Import And</a></li>
65 <li><a href="fossil-from-msvc.wiki">Express 2010 IDE &mdash; Integrating Fossil in the Microsoft</a></li>
 
66 <li><a href="fileformat.wiki">File Format &mdash; Fossil</a></li>
67 <li><a href="branching.wiki">Forking, Merging, and Tagging &mdash; Branching,</a></li>
68 <li><a href="delta_format.wiki">Format &mdash; Fossil Delta</a></li>
69 <li><a href="fileformat.wiki">Format &mdash; Fossil File</a></li>
70 <li><a href="changes.wiki">Fossil Changelog</a></li>
@@ -86,10 +88,11 @@
86 <li><a href="fossil-v-git.wiki">Git &mdash; Fossil Versus</a></li>
87 <li><a href="inout.wiki">Git &mdash; Import And Export To And From</a></li>
88 <li><a href="quotes.wiki">Git, and DVCSes in General &mdash; Quotes: What People Are Saying About Fossil,</a></li>
89 <li><a href="quickstart.wiki">Guide &mdash; Fossil Quick Start</a></li>
90 <li><a href="style.wiki">Guidelines &mdash; Source Code Style</a></li>
 
91 <li><a href="hints.wiki">Hints &mdash; Fossil Tips And Usage</a></li>
92 <li><a href="index.wiki">Home Page</a></li>
93 <li><a href="selfhost.wiki">Hosting Repositories &mdash; Fossil Self</a></li>
94 <li><a href="server.wiki">How To Configure A Fossil Server</a></li>
95 <li><a href="newrepo.wiki">How To Create A New Fossil Repository</a></li>
@@ -104,10 +107,11 @@
104 <li><a href="password.wiki">Management And Authentication &mdash; Password</a></li>
105 <li><a href="branching.wiki">Merging, and Tagging &mdash; Branching, Forking,</a></li>
106 <li><a href="fossil-from-msvc.wiki">Microsoft Express 2010 IDE &mdash; Integrating Fossil in the</a></li>
107 <li><a href="fiveminutes.wiki">Minutes as a Single User &mdash; Update and Running in 5</a></li>
108 <li><a href="checkin_names.wiki">Names &mdash; Checkin And Version</a></li>
 
109 <li><a href="newrepo.wiki">New Fossil Repository &mdash; How To Create A</a></li>
110 <li><a href="foss-cklist.wiki">Open-Source Projects &mdash; Checklist For Successful</a></li>
111 <li><a href="pop.wiki">Operations &mdash; Principles Of</a></li>
112 <li><a href="tech_overview.wiki">Overview Of The Design And Implementation Of Fossil &mdash; A Technical</a></li>
113 <li><a href="index.wiki">Page &mdash; Home</a></li>
114
--- www/permutedindex.wiki
+++ www/permutedindex.wiki
@@ -13,10 +13,11 @@
13 <h2>Permuted Index:</h2>
14 <ul>
15 <li><a href="fiveminutes.wiki">5 Minutes as a Single User &mdash; Update and Running in</a></li>
16 <li><a href="fossil-from-msvc.wiki">2010 IDE &mdash; Integrating Fossil in the Microsoft Express</a></li>
17 <li><a href="tech_overview.wiki">A Technical Overview Of The Design And Implementation Of Fossil</a></li>
18 <li><a href="adding_code.wiki">Adding New Features To Fossil</a></li>
19 <li><a href="antibot.wiki">against Spiders and Bots &mdash; Defense</a></li>
20 <li><a href="copyright-release.html">Agreement &mdash; Contributor License</a></li>
21 <li><a href="delta_encoder_algorithm.wiki">Algorithm &mdash; Fossil Delta Encoding</a></li>
22 <li><a href="fiveminutes.wiki">as a Single User &mdash; Update and Running in 5 Minutes</a></li>
23 <li><a href="faq.wiki">Asked Questions &mdash; Frequently</a></li>
@@ -61,10 +62,11 @@
62 <li><a href="embeddeddoc.wiki">Embedded Project Documentation</a></li>
63 <li><a href="delta_encoder_algorithm.wiki">Encoding Algorithm &mdash; Fossil Delta</a></li>
64 <li><a href="event.wiki">Events</a></li>
65 <li><a href="inout.wiki">Export To And From Git &mdash; Import And</a></li>
66 <li><a href="fossil-from-msvc.wiki">Express 2010 IDE &mdash; Integrating Fossil in the Microsoft</a></li>
67 <li><a href="adding_code.wiki">Features To Fossil &mdash; Adding New</a></li>
68 <li><a href="fileformat.wiki">File Format &mdash; Fossil</a></li>
69 <li><a href="branching.wiki">Forking, Merging, and Tagging &mdash; Branching,</a></li>
70 <li><a href="delta_format.wiki">Format &mdash; Fossil Delta</a></li>
71 <li><a href="fileformat.wiki">Format &mdash; Fossil File</a></li>
72 <li><a href="changes.wiki">Fossil Changelog</a></li>
@@ -86,10 +88,11 @@
88 <li><a href="fossil-v-git.wiki">Git &mdash; Fossil Versus</a></li>
89 <li><a href="inout.wiki">Git &mdash; Import And Export To And From</a></li>
90 <li><a href="quotes.wiki">Git, and DVCSes in General &mdash; Quotes: What People Are Saying About Fossil,</a></li>
91 <li><a href="quickstart.wiki">Guide &mdash; Fossil Quick Start</a></li>
92 <li><a href="style.wiki">Guidelines &mdash; Source Code Style</a></li>
93 <li><a href="adding_code.wiki">Hacking Fossil</a></li>
94 <li><a href="hints.wiki">Hints &mdash; Fossil Tips And Usage</a></li>
95 <li><a href="index.wiki">Home Page</a></li>
96 <li><a href="selfhost.wiki">Hosting Repositories &mdash; Fossil Self</a></li>
97 <li><a href="server.wiki">How To Configure A Fossil Server</a></li>
98 <li><a href="newrepo.wiki">How To Create A New Fossil Repository</a></li>
@@ -104,10 +107,11 @@
107 <li><a href="password.wiki">Management And Authentication &mdash; Password</a></li>
108 <li><a href="branching.wiki">Merging, and Tagging &mdash; Branching, Forking,</a></li>
109 <li><a href="fossil-from-msvc.wiki">Microsoft Express 2010 IDE &mdash; Integrating Fossil in the</a></li>
110 <li><a href="fiveminutes.wiki">Minutes as a Single User &mdash; Update and Running in 5</a></li>
111 <li><a href="checkin_names.wiki">Names &mdash; Checkin And Version</a></li>
112 <li><a href="adding_code.wiki">New Features To Fossil &mdash; Adding</a></li>
113 <li><a href="newrepo.wiki">New Fossil Repository &mdash; How To Create A</a></li>
114 <li><a href="foss-cklist.wiki">Open-Source Projects &mdash; Checklist For Successful</a></li>
115 <li><a href="pop.wiki">Operations &mdash; Principles Of</a></li>
116 <li><a href="tech_overview.wiki">Overview Of The Design And Implementation Of Fossil &mdash; A Technical</a></li>
117 <li><a href="index.wiki">Page &mdash; Home</a></li>
118
--- www/quickstart.wiki
+++ www/quickstart.wiki
@@ -173,13 +173,21 @@
173173
</blockquote>
174174
175175
<p>You will be prompted for check-in comments using whatever editor
176176
is specified by your VISUAL or EDITOR environment variable.</p>
177177
178
+ In the default configuration, the [/help/commit|commit]
179
+ command will also automatically [/help/push|push] your changes, but that
180
+ feature can be disabled. (More information about
181
+ [./concepts.wiki#workflow|autosync] and how to disable it.)
182
+ Remember that your coworkers can not see your changes until you
183
+ commit and push them.</p>
184
+
178185
<h2>Sharing Changes</h2>
179186
180
- <p>The changes you [/help/commit | commit] are only
187
+ <p>When [./concepts.wiki#workflow|autosync] is turned off,
188
+ the changes you [/help/commit | commit] are only
181189
on your local repository.
182190
To share those changes with other repositories, do:</p>
183191
184192
<blockquote>
185193
<b>[/help/push | fossil push]</b> <i>URL</i>
@@ -212,10 +220,17 @@
212220
date/time stamp. ([./checkin_names.wiki | more info])
213221
If you omit
214222
the <i>VERSION</i>, then fossil moves you to the
215223
latest version of the branch your are currently on.</p>
216224
225
+ <p>The default behaviors is for [./concepts.wiki#workflow|autosync] to
226
+ be turned on. That means that a [/help/pull|pull] automatically occurs
227
+ when you run [/help/update|update] and a [/help/push|push] happens
228
+ automatically after you [/help/commit|commit]. So in normal practice,
229
+ the push, pull, and sync commands are rarely used. But it is important
230
+ to know about them, all the same.</p>
231
+
217232
<h2>Branching And Merging</h2>
218233
219234
<p>Use the --branch option to the [/help/commit | commit] command
220235
to start a new branch. Note that in Fossil, branches are normally
221236
created when you commit, not before you start editing. You can
@@ -222,36 +237,43 @@
222237
use the [/help/branch | branch new] command to create a new branch
223238
before you start editing, if you want, but most people just wait
224239
until they are ready to commit.
225240
226241
To merge two branches back together, first
227
- [/help/update | update] to the leaf of one branch. Then do a
228
- [/help/merge | merge] of the leaf of the other branch:</p>
242
+ [/help/update | update] to the branch you want to merge into.
243
+ Then do a [/help/merge|merge] another branch that you want to incorporate
244
+ the changes from. For example, to merge "featureX" changes into "trunk"
245
+ do this:</p>
229246
230247
<blockquote>
231
- <b>[/help/merge | fossil merge]</b> <i>VERSION</i>
248
+ <b>fossil [/help/update|update] trunk</b><br>
249
+ <b>fossil [/help/merge|merge] featureX</b><br>
250
+ <i># make sure the merge didn't break anything...</i><br>
251
+ <b>fossil [/help/commit|commit]
232252
</blockquote>
233253
234
- <p>The <i>VERSION</i> can be any of the forms allowed for
235
- [/help/update | update].
236
- After performing the merge, you will normally want to test it to
237
- make sure it does not break anything, then
238
- [/help/commit | commit] your changes.
239
- In the default configuration, the [/help/commit|commit]
240
- command will also automatically [/help/push|push] your changes, but that
241
- feature can be disabled. (More information about
242
- [./concepts.wiki#workflow|autosync] and how to disable it.)
243
- Remember that your coworkers can not see your changes until you
244
- commit and push them.</p>
245
-
246
- <p>The merge command has options to cherrypick individual
247
- changes, or to back out individual changes.</p>
248
-
249
- <p>Note that the merge command changes only your local check-out.
250
- The merge command does <em>not</em> modify the repository in any way.
251
- You must do a separate [/help/commit | commit] after the merge in order
252
- to put the merged code back into the repository.</p>
254
+ <p>The argument to the [/help/merge|merge] command can be any of the
255
+ version identifier forms that work for [/help/update|update].
256
+ ([./checkin_names.wiki|more info].)
257
+ The merge command has options to cherrypick individual
258
+ changes, or to back out individual changes, if you don't want to
259
+ do a full merge.</p>
260
+
261
+ The merge command puts all changes in your working check-out.
262
+ No changes are made to the repository.
263
+ You must run [/help/commit|commit] separately
264
+ to add the merge changes into your repository to make them persistent
265
+ and so that your coworkers can see them.
266
+ But before you do that, you will normally want to run a few tests
267
+ to verify that the merge didn't cause logic breaks in your code.
268
+
269
+ The same branch can be merged multiple times without trouble. Fossil
270
+ automatically keeps up with things and avoids conflicts when doing
271
+ multiple merges. So even if you have merged the featureX branch
272
+ into trunk previously, you can do so again and Fossil will automatically
273
+ know to pull in only those changes that have occurred since the previous
274
+ merge.
253275
254276
<p>If a merge or update doesn't work out (perhaps something breaks or
255277
there are many merge conflicts) then you back up using:</p>
256278
257279
<blockquote>
@@ -280,11 +302,11 @@
280302
<b>[/help/ui | fossil ui]</b> <i>repository-filename</i>
281303
</blockquote>
282304
283305
<p>The <b>ui</b> command is intended for accessing the web interface
284306
from a local desktop. The <b>ui</b> command binds to the loopback IP
285
- address only (and is thus makes the web interface visible only on the
307
+ address only (and thus makes the web interface visible only on the
286308
local machine) and it automatically start your web browser pointing at the
287309
server. For cross-machine collaboration, use the <b>server</b> command,
288310
which binds on all IP addresses and does not try to start a web browser.
289311
You can omit the <i>repository-filename</i> if you are within
290312
a checked-out local tree. The <b>server</b> uses port 8080 by default
@@ -321,11 +343,11 @@
321343
<p>Adjust the paths to suit your installation, of course. Notice that
322344
fossil runs as root. This is not required - you can run it as an
323345
unprivileged user. But it is more secure to run fossil as root.
324346
When you do run fossil as root, it automatically puts itself in a
325347
chroot jail in the same directory as the repository, then drops
326
- root privileges prior to reading any information from the request.</p>
348
+ root privileges prior to reading any information from the socket.</p>
327349
328350
<a name="proxy"></a>
329351
<h2>HTTP Proxies</h2>
330352
331353
<p>If you are behind a restrictive firewall that requires you to use
@@ -369,8 +391,11 @@
369391
<b>fossil sync http://192.168.1.36:8080/ --proxy off</b>
370392
</blockquote>
371393
372394
<h2>More Hints</h2>
373395
374
- <p>A [/help | complete list of commands] is available.
396
+ <p>A [/help | complete list of commands] is available, as is the
397
+ [./hints.wiki|helpful hints] document. See the
398
+ [./permutedindex.wiki#pindex|permuted index] for additional
399
+ documentation.
375400
376401
<p>Explore and have fun!</p>
377402
--- www/quickstart.wiki
+++ www/quickstart.wiki
@@ -173,13 +173,21 @@
173 </blockquote>
174
175 <p>You will be prompted for check-in comments using whatever editor
176 is specified by your VISUAL or EDITOR environment variable.</p>
177
 
 
 
 
 
 
 
178 <h2>Sharing Changes</h2>
179
180 <p>The changes you [/help/commit | commit] are only
 
181 on your local repository.
182 To share those changes with other repositories, do:</p>
183
184 <blockquote>
185 <b>[/help/push | fossil push]</b> <i>URL</i>
@@ -212,10 +220,17 @@
212 date/time stamp. ([./checkin_names.wiki | more info])
213 If you omit
214 the <i>VERSION</i>, then fossil moves you to the
215 latest version of the branch your are currently on.</p>
216
 
 
 
 
 
 
 
217 <h2>Branching And Merging</h2>
218
219 <p>Use the --branch option to the [/help/commit | commit] command
220 to start a new branch. Note that in Fossil, branches are normally
221 created when you commit, not before you start editing. You can
@@ -222,36 +237,43 @@
222 use the [/help/branch | branch new] command to create a new branch
223 before you start editing, if you want, but most people just wait
224 until they are ready to commit.
225
226 To merge two branches back together, first
227 [/help/update | update] to the leaf of one branch. Then do a
228 [/help/merge | merge] of the leaf of the other branch:</p>
 
 
229
230 <blockquote>
231 <b>[/help/merge | fossil merge]</b> <i>VERSION</i>
 
 
 
232 </blockquote>
233
234 <p>The <i>VERSION</i> can be any of the forms allowed for
235 [/help/update | update].
236 After performing the merge, you will normally want to test it to
237 make sure it does not break anything, then
238 [/help/commit | commit] your changes.
239 In the default configuration, the [/help/commit|commit]
240 command will also automatically [/help/push|push] your changes, but that
241 feature can be disabled. (More information about
242 [./concepts.wiki#workflow|autosync] and how to disable it.)
243 Remember that your coworkers can not see your changes until you
244 commit and push them.</p>
245
246 <p>The merge command has options to cherrypick individual
247 changes, or to back out individual changes.</p>
248
249 <p>Note that the merge command changes only your local check-out.
250 The merge command does <em>not</em> modify the repository in any way.
251 You must do a separate [/help/commit | commit] after the merge in order
252 to put the merged code back into the repository.</p>
 
 
253
254 <p>If a merge or update doesn't work out (perhaps something breaks or
255 there are many merge conflicts) then you back up using:</p>
256
257 <blockquote>
@@ -280,11 +302,11 @@
280 <b>[/help/ui | fossil ui]</b> <i>repository-filename</i>
281 </blockquote>
282
283 <p>The <b>ui</b> command is intended for accessing the web interface
284 from a local desktop. The <b>ui</b> command binds to the loopback IP
285 address only (and is thus makes the web interface visible only on the
286 local machine) and it automatically start your web browser pointing at the
287 server. For cross-machine collaboration, use the <b>server</b> command,
288 which binds on all IP addresses and does not try to start a web browser.
289 You can omit the <i>repository-filename</i> if you are within
290 a checked-out local tree. The <b>server</b> uses port 8080 by default
@@ -321,11 +343,11 @@
321 <p>Adjust the paths to suit your installation, of course. Notice that
322 fossil runs as root. This is not required - you can run it as an
323 unprivileged user. But it is more secure to run fossil as root.
324 When you do run fossil as root, it automatically puts itself in a
325 chroot jail in the same directory as the repository, then drops
326 root privileges prior to reading any information from the request.</p>
327
328 <a name="proxy"></a>
329 <h2>HTTP Proxies</h2>
330
331 <p>If you are behind a restrictive firewall that requires you to use
@@ -369,8 +391,11 @@
369 <b>fossil sync http://192.168.1.36:8080/ --proxy off</b>
370 </blockquote>
371
372 <h2>More Hints</h2>
373
374 <p>A [/help | complete list of commands] is available.
 
 
 
375
376 <p>Explore and have fun!</p>
377
--- www/quickstart.wiki
+++ www/quickstart.wiki
@@ -173,13 +173,21 @@
173 </blockquote>
174
175 <p>You will be prompted for check-in comments using whatever editor
176 is specified by your VISUAL or EDITOR environment variable.</p>
177
178 In the default configuration, the [/help/commit|commit]
179 command will also automatically [/help/push|push] your changes, but that
180 feature can be disabled. (More information about
181 [./concepts.wiki#workflow|autosync] and how to disable it.)
182 Remember that your coworkers can not see your changes until you
183 commit and push them.</p>
184
185 <h2>Sharing Changes</h2>
186
187 <p>When [./concepts.wiki#workflow|autosync] is turned off,
188 the changes you [/help/commit | commit] are only
189 on your local repository.
190 To share those changes with other repositories, do:</p>
191
192 <blockquote>
193 <b>[/help/push | fossil push]</b> <i>URL</i>
@@ -212,10 +220,17 @@
220 date/time stamp. ([./checkin_names.wiki | more info])
221 If you omit
222 the <i>VERSION</i>, then fossil moves you to the
223 latest version of the branch your are currently on.</p>
224
225 <p>The default behaviors is for [./concepts.wiki#workflow|autosync] to
226 be turned on. That means that a [/help/pull|pull] automatically occurs
227 when you run [/help/update|update] and a [/help/push|push] happens
228 automatically after you [/help/commit|commit]. So in normal practice,
229 the push, pull, and sync commands are rarely used. But it is important
230 to know about them, all the same.</p>
231
232 <h2>Branching And Merging</h2>
233
234 <p>Use the --branch option to the [/help/commit | commit] command
235 to start a new branch. Note that in Fossil, branches are normally
236 created when you commit, not before you start editing. You can
@@ -222,36 +237,43 @@
237 use the [/help/branch | branch new] command to create a new branch
238 before you start editing, if you want, but most people just wait
239 until they are ready to commit.
240
241 To merge two branches back together, first
242 [/help/update | update] to the branch you want to merge into.
243 Then do a [/help/merge|merge] another branch that you want to incorporate
244 the changes from. For example, to merge "featureX" changes into "trunk"
245 do this:</p>
246
247 <blockquote>
248 <b>fossil [/help/update|update] trunk</b><br>
249 <b>fossil [/help/merge|merge] featureX</b><br>
250 <i># make sure the merge didn't break anything...</i><br>
251 <b>fossil [/help/commit|commit]
252 </blockquote>
253
254 <p>The argument to the [/help/merge|merge] command can be any of the
255 version identifier forms that work for [/help/update|update].
256 ([./checkin_names.wiki|more info].)
257 The merge command has options to cherrypick individual
258 changes, or to back out individual changes, if you don't want to
259 do a full merge.</p>
260
261 The merge command puts all changes in your working check-out.
262 No changes are made to the repository.
263 You must run [/help/commit|commit] separately
264 to add the merge changes into your repository to make them persistent
265 and so that your coworkers can see them.
266 But before you do that, you will normally want to run a few tests
267 to verify that the merge didn't cause logic breaks in your code.
268
269 The same branch can be merged multiple times without trouble. Fossil
270 automatically keeps up with things and avoids conflicts when doing
271 multiple merges. So even if you have merged the featureX branch
272 into trunk previously, you can do so again and Fossil will automatically
273 know to pull in only those changes that have occurred since the previous
274 merge.
275
276 <p>If a merge or update doesn't work out (perhaps something breaks or
277 there are many merge conflicts) then you back up using:</p>
278
279 <blockquote>
@@ -280,11 +302,11 @@
302 <b>[/help/ui | fossil ui]</b> <i>repository-filename</i>
303 </blockquote>
304
305 <p>The <b>ui</b> command is intended for accessing the web interface
306 from a local desktop. The <b>ui</b> command binds to the loopback IP
307 address only (and thus makes the web interface visible only on the
308 local machine) and it automatically start your web browser pointing at the
309 server. For cross-machine collaboration, use the <b>server</b> command,
310 which binds on all IP addresses and does not try to start a web browser.
311 You can omit the <i>repository-filename</i> if you are within
312 a checked-out local tree. The <b>server</b> uses port 8080 by default
@@ -321,11 +343,11 @@
343 <p>Adjust the paths to suit your installation, of course. Notice that
344 fossil runs as root. This is not required - you can run it as an
345 unprivileged user. But it is more secure to run fossil as root.
346 When you do run fossil as root, it automatically puts itself in a
347 chroot jail in the same directory as the repository, then drops
348 root privileges prior to reading any information from the socket.</p>
349
350 <a name="proxy"></a>
351 <h2>HTTP Proxies</h2>
352
353 <p>If you are behind a restrictive firewall that requires you to use
@@ -369,8 +391,11 @@
391 <b>fossil sync http://192.168.1.36:8080/ --proxy off</b>
392 </blockquote>
393
394 <h2>More Hints</h2>
395
396 <p>A [/help | complete list of commands] is available, as is the
397 [./hints.wiki|helpful hints] document. See the
398 [./permutedindex.wiki#pindex|permuted index] for additional
399 documentation.
400
401 <p>Explore and have fun!</p>
402
+2 -1
--- www/server.wiki
+++ www/server.wiki
@@ -107,11 +107,12 @@
107107
<h2>Various security concerns with hosted repositories</h2><blockquote>
108108
<p>
109109
There are two main concerns relating to usage of Fossil for sharing sensitive information (source or any other data):
110110
<ul>
111111
<li>Interception of the Fossil synchronization stream, thereby capturing data, and
112
-</ul>Direct access to the Fossil repository on the server
112
+<li>Direct access to the Fossil repository on the server
113
+</ul>
113114
</p>
114115
<p>
115116
Regarding the first, it is adequate to secure the server using SSL, and disallowing any non-SSL access. The data stream will be encrypted by the HTTPS protocol, rendering the data reasonably secure. The truly paranoid may wish to deploy <i>ssh</i> encrypted tunnels, but that is quite a bit more difficult and cumbersome to set up (particularly for a larger number of users).
116117
</p>
117118
<p>
118119
--- www/server.wiki
+++ www/server.wiki
@@ -107,11 +107,12 @@
107 <h2>Various security concerns with hosted repositories</h2><blockquote>
108 <p>
109 There are two main concerns relating to usage of Fossil for sharing sensitive information (source or any other data):
110 <ul>
111 <li>Interception of the Fossil synchronization stream, thereby capturing data, and
112 </ul>Direct access to the Fossil repository on the server
 
113 </p>
114 <p>
115 Regarding the first, it is adequate to secure the server using SSL, and disallowing any non-SSL access. The data stream will be encrypted by the HTTPS protocol, rendering the data reasonably secure. The truly paranoid may wish to deploy <i>ssh</i> encrypted tunnels, but that is quite a bit more difficult and cumbersome to set up (particularly for a larger number of users).
116 </p>
117 <p>
118
--- www/server.wiki
+++ www/server.wiki
@@ -107,11 +107,12 @@
107 <h2>Various security concerns with hosted repositories</h2><blockquote>
108 <p>
109 There are two main concerns relating to usage of Fossil for sharing sensitive information (source or any other data):
110 <ul>
111 <li>Interception of the Fossil synchronization stream, thereby capturing data, and
112 <li>Direct access to the Fossil repository on the server
113 </ul>
114 </p>
115 <p>
116 Regarding the first, it is adequate to secure the server using SSL, and disallowing any non-SSL access. The data stream will be encrypted by the HTTPS protocol, rendering the data reasonably secure. The truly paranoid may wish to deploy <i>ssh</i> encrypted tunnels, but that is quite a bit more difficult and cumbersome to set up (particularly for a larger number of users).
117 </p>
118 <p>
119
--- www/tech_overview.wiki
+++ www/tech_overview.wiki
@@ -332,5 +332,11 @@
332332
333333
Note that the stash, the undo stack, and the state of the bisect command
334334
are all contained within the checkout database. That means that the
335335
fossil close command will delete all stash content, the undo stack, and
336336
the bisect state. The close command is not undoable. Use it with care.
337
+
338
+<h2>3.0 See Also</h2>
339
+
340
+ * [./makefile.wiki | The Fossil Build Process]
341
+ * [./contribute.wiki | How To Contribute Code To Fossil]
342
+ * [./adding_code.wiki | Adding New Features To Fossil]
337343
--- www/tech_overview.wiki
+++ www/tech_overview.wiki
@@ -332,5 +332,11 @@
332
333 Note that the stash, the undo stack, and the state of the bisect command
334 are all contained within the checkout database. That means that the
335 fossil close command will delete all stash content, the undo stack, and
336 the bisect state. The close command is not undoable. Use it with care.
 
 
 
 
 
 
337
--- www/tech_overview.wiki
+++ www/tech_overview.wiki
@@ -332,5 +332,11 @@
332
333 Note that the stash, the undo stack, and the state of the bisect command
334 are all contained within the checkout database. That means that the
335 fossil close command will delete all stash content, the undo stack, and
336 the bisect state. The close command is not undoable. Use it with care.
337
338 <h2>3.0 See Also</h2>
339
340 * [./makefile.wiki | The Fossil Build Process]
341 * [./contribute.wiki | How To Contribute Code To Fossil]
342 * [./adding_code.wiki | Adding New Features To Fossil]
343

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button