Fossil SCM

Merging from trunk to get the annotate fixes. Trivial conflict solved.

viriketo 2013-03-14 14:48 annotate_links merge
Commit f14798e0e3d0fe9866b7ca82e1d08c0ea7323e2d
+2 -2
--- src/add.c
+++ src/add.c
@@ -262,11 +262,11 @@
262262
if( vid==0 ){
263263
fossil_panic("no checkout to add to");
264264
}
265265
db_begin_transaction();
266266
db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)");
267
-#if defined(_WIN32)
267
+#if defined(_WIN32) || defined(__CYGWIN__)
268268
db_multi_exec(
269269
"CREATE INDEX IF NOT EXISTS vfile_pathname "
270270
" ON vfile(pathname COLLATE nocase)"
271271
);
272272
#endif
@@ -388,11 +388,11 @@
388388
if( once ){
389389
once = 0;
390390
if( zCaseSensitive ){
391391
caseSensitive = is_truth(zCaseSensitive);
392392
}else{
393
-#if !defined(_WIN32) && !defined(__DARWIN__) && !defined(__APPLE__)
393
+#if !defined(_WIN32) && !defined(__CYGWIN__) && !defined(__DARWIN__) && !defined(__APPLE__)
394394
caseSensitive = 1; /* Unix */
395395
#else
396396
caseSensitive = 0; /* Windows and Mac */
397397
#endif
398398
caseSensitive = db_get_boolean("case-sensitive",caseSensitive);
399399
--- src/add.c
+++ src/add.c
@@ -262,11 +262,11 @@
262 if( vid==0 ){
263 fossil_panic("no checkout to add to");
264 }
265 db_begin_transaction();
266 db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)");
267 #if defined(_WIN32)
268 db_multi_exec(
269 "CREATE INDEX IF NOT EXISTS vfile_pathname "
270 " ON vfile(pathname COLLATE nocase)"
271 );
272 #endif
@@ -388,11 +388,11 @@
388 if( once ){
389 once = 0;
390 if( zCaseSensitive ){
391 caseSensitive = is_truth(zCaseSensitive);
392 }else{
393 #if !defined(_WIN32) && !defined(__DARWIN__) && !defined(__APPLE__)
394 caseSensitive = 1; /* Unix */
395 #else
396 caseSensitive = 0; /* Windows and Mac */
397 #endif
398 caseSensitive = db_get_boolean("case-sensitive",caseSensitive);
399
--- src/add.c
+++ src/add.c
@@ -262,11 +262,11 @@
262 if( vid==0 ){
263 fossil_panic("no checkout to add to");
264 }
265 db_begin_transaction();
266 db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)");
267 #if defined(_WIN32) || defined(__CYGWIN__)
268 db_multi_exec(
269 "CREATE INDEX IF NOT EXISTS vfile_pathname "
270 " ON vfile(pathname COLLATE nocase)"
271 );
272 #endif
@@ -388,11 +388,11 @@
388 if( once ){
389 once = 0;
390 if( zCaseSensitive ){
391 caseSensitive = is_truth(zCaseSensitive);
392 }else{
393 #if !defined(_WIN32) && !defined(__CYGWIN__) && !defined(__DARWIN__) && !defined(__APPLE__)
394 caseSensitive = 1; /* Unix */
395 #else
396 caseSensitive = 0; /* Windows and Mac */
397 #endif
398 caseSensitive = db_get_boolean("case-sensitive",caseSensitive);
399
+1 -1
--- src/attach.c
+++ src/attach.c
@@ -94,11 +94,11 @@
9494
}
9595
@ <br><a href="/attachview?%s(zUrlTail)">%h(zFilename)</a>
9696
@ [<a href="/attachdownload/%t(zFilename)?%s(zUrlTail)">download</a>]<br />
9797
if( zComment ) while( fossil_isspace(zComment[0]) ) zComment++;
9898
if( zComment && zComment[0] ){
99
- @ %w(zComment)<br />
99
+ @ %!w(zComment)<br />
100100
}
101101
if( zPage==0 && zTkt==0 ){
102102
if( zSrc==0 || zSrc[0]==0 ){
103103
zSrc = "Deleted from";
104104
}else {
105105
--- src/attach.c
+++ src/attach.c
@@ -94,11 +94,11 @@
94 }
95 @ <br><a href="/attachview?%s(zUrlTail)">%h(zFilename)</a>
96 @ [<a href="/attachdownload/%t(zFilename)?%s(zUrlTail)">download</a>]<br />
97 if( zComment ) while( fossil_isspace(zComment[0]) ) zComment++;
98 if( zComment && zComment[0] ){
99 @ %w(zComment)<br />
100 }
101 if( zPage==0 && zTkt==0 ){
102 if( zSrc==0 || zSrc[0]==0 ){
103 zSrc = "Deleted from";
104 }else {
105
--- src/attach.c
+++ src/attach.c
@@ -94,11 +94,11 @@
94 }
95 @ <br><a href="/attachview?%s(zUrlTail)">%h(zFilename)</a>
96 @ [<a href="/attachdownload/%t(zFilename)?%s(zUrlTail)">download</a>]<br />
97 if( zComment ) while( fossil_isspace(zComment[0]) ) zComment++;
98 if( zComment && zComment[0] ){
99 @ %!w(zComment)<br />
100 }
101 if( zPage==0 && zTkt==0 ){
102 if( zSrc==0 || zSrc[0]==0 ){
103 zSrc = "Deleted from";
104 }else {
105
+9 -6
--- src/blob.c
+++ src/blob.c
@@ -792,11 +792,11 @@
792792
}
793793
nName = file_simplify_name(zName, nName, 0);
794794
for(i=1; i<nName; i++){
795795
if( zName[i]=='/' ){
796796
zName[i] = 0;
797
-#if defined(_WIN32)
797
+#if defined(_WIN32) || defined(__CYGWIN__)
798798
/*
799799
** On Windows, local path looks like: C:/develop/project/file.txt
800800
** The if stops us from trying to create a directory of a drive letter
801801
** C: in this example.
802802
*/
@@ -804,11 +804,11 @@
804804
#endif
805805
if( file_mkdir(zName, 1) && file_isdir(zName)!=1 ){
806806
fossil_fatal_recursive("unable to create directory %s", zName);
807807
return 0;
808808
}
809
-#if defined(_WIN32)
809
+#if defined(_WIN32) || defined(__CYGWIN__)
810810
}
811811
#endif
812812
zName[i] = '/';
813813
}
814814
}
@@ -1096,24 +1096,25 @@
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
+ int bomReverse = 0;
11011102
if( starts_with_utf8_bom(pBlob, &bomSize) ){
11021103
struct Blob temp;
11031104
zUtf8 = blob_str(pBlob) + bomSize;
11041105
blob_zero(&temp);
11051106
blob_append(&temp, zUtf8, -1);
11061107
blob_swap(pBlob, &temp);
11071108
blob_reset(&temp);
1108
-#ifdef _WIN32
1109
- }else if( starts_with_utf16_bom(pBlob, &bomSize) ){
1109
+#if defined(_WIN32) || defined(__CYGWIN__)
1110
+ }else if( starts_with_utf16_bom(pBlob, &bomSize, &bomReverse) ){
11101111
zUtf8 = blob_buffer(pBlob);
1111
- if (*((unsigned short *)zUtf8) == 0xfffe) {
1112
+ if( bomReverse ){
11121113
/* Found BOM, but with reversed bytes */
11131114
unsigned int i = blob_size(pBlob);
1114
- while( i > 0 ){
1115
+ while( i>0 ){
11151116
/* swap bytes of unicode representation */
11161117
char zTemp = zUtf8[--i];
11171118
zUtf8[i] = zUtf8[i-1];
11181119
zUtf8[--i] = zTemp;
11191120
}
@@ -1123,13 +1124,15 @@
11231124
zUtf8 = blob_str(pBlob) + bomSize;
11241125
zUtf8 = fossil_unicode_to_utf8(zUtf8);
11251126
blob_zero(pBlob);
11261127
blob_append(pBlob, zUtf8, -1);
11271128
fossil_unicode_free(zUtf8);
1129
+#endif /* _WIN32 || __CYGWIN__ */
1130
+#if defined(_WIN32)
11281131
}else if( useMbcs ){
11291132
zUtf8 = fossil_mbcs_to_utf8(blob_str(pBlob));
11301133
blob_reset(pBlob);
11311134
blob_append(pBlob, zUtf8, -1);
11321135
fossil_mbcs_free(zUtf8);
11331136
#endif /* _WIN32 */
11341137
}
11351138
}
11361139
--- src/blob.c
+++ src/blob.c
@@ -792,11 +792,11 @@
792 }
793 nName = file_simplify_name(zName, nName, 0);
794 for(i=1; i<nName; i++){
795 if( zName[i]=='/' ){
796 zName[i] = 0;
797 #if defined(_WIN32)
798 /*
799 ** On Windows, local path looks like: C:/develop/project/file.txt
800 ** The if stops us from trying to create a directory of a drive letter
801 ** C: in this example.
802 */
@@ -804,11 +804,11 @@
804 #endif
805 if( file_mkdir(zName, 1) && file_isdir(zName)!=1 ){
806 fossil_fatal_recursive("unable to create directory %s", zName);
807 return 0;
808 }
809 #if defined(_WIN32)
810 }
811 #endif
812 zName[i] = '/';
813 }
814 }
@@ -1096,24 +1096,25 @@
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( starts_with_utf8_bom(pBlob, &bomSize) ){
1102 struct Blob temp;
1103 zUtf8 = blob_str(pBlob) + bomSize;
1104 blob_zero(&temp);
1105 blob_append(&temp, zUtf8, -1);
1106 blob_swap(pBlob, &temp);
1107 blob_reset(&temp);
1108 #ifdef _WIN32
1109 }else if( starts_with_utf16_bom(pBlob, &bomSize) ){
1110 zUtf8 = blob_buffer(pBlob);
1111 if (*((unsigned short *)zUtf8) == 0xfffe) {
1112 /* Found BOM, but with reversed bytes */
1113 unsigned int i = blob_size(pBlob);
1114 while( i > 0 ){
1115 /* swap bytes of unicode representation */
1116 char zTemp = zUtf8[--i];
1117 zUtf8[i] = zUtf8[i-1];
1118 zUtf8[--i] = zTemp;
1119 }
@@ -1123,13 +1124,15 @@
1123 zUtf8 = blob_str(pBlob) + bomSize;
1124 zUtf8 = fossil_unicode_to_utf8(zUtf8);
1125 blob_zero(pBlob);
1126 blob_append(pBlob, zUtf8, -1);
1127 fossil_unicode_free(zUtf8);
 
 
1128 }else if( useMbcs ){
1129 zUtf8 = fossil_mbcs_to_utf8(blob_str(pBlob));
1130 blob_reset(pBlob);
1131 blob_append(pBlob, zUtf8, -1);
1132 fossil_mbcs_free(zUtf8);
1133 #endif /* _WIN32 */
1134 }
1135 }
1136
--- src/blob.c
+++ src/blob.c
@@ -792,11 +792,11 @@
792 }
793 nName = file_simplify_name(zName, nName, 0);
794 for(i=1; i<nName; i++){
795 if( zName[i]=='/' ){
796 zName[i] = 0;
797 #if defined(_WIN32) || defined(__CYGWIN__)
798 /*
799 ** On Windows, local path looks like: C:/develop/project/file.txt
800 ** The if stops us from trying to create a directory of a drive letter
801 ** C: in this example.
802 */
@@ -804,11 +804,11 @@
804 #endif
805 if( file_mkdir(zName, 1) && file_isdir(zName)!=1 ){
806 fossil_fatal_recursive("unable to create directory %s", zName);
807 return 0;
808 }
809 #if defined(_WIN32) || defined(__CYGWIN__)
810 }
811 #endif
812 zName[i] = '/';
813 }
814 }
@@ -1096,24 +1096,25 @@
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 blob_swap(pBlob, &temp);
1108 blob_reset(&temp);
1109 #if defined(_WIN32) || defined(__CYGWIN__)
1110 }else if( starts_with_utf16_bom(pBlob, &bomSize, &bomReverse) ){
1111 zUtf8 = blob_buffer(pBlob);
1112 if( bomReverse ){
1113 /* Found BOM, but with reversed bytes */
1114 unsigned int i = blob_size(pBlob);
1115 while( i>0 ){
1116 /* swap bytes of unicode representation */
1117 char zTemp = zUtf8[--i];
1118 zUtf8[i] = zUtf8[i-1];
1119 zUtf8[--i] = zTemp;
1120 }
@@ -1123,13 +1124,15 @@
1124 zUtf8 = blob_str(pBlob) + bomSize;
1125 zUtf8 = fossil_unicode_to_utf8(zUtf8);
1126 blob_zero(pBlob);
1127 blob_append(pBlob, zUtf8, -1);
1128 fossil_unicode_free(zUtf8);
1129 #endif /* _WIN32 || __CYGWIN__ */
1130 #if defined(_WIN32)
1131 }else if( useMbcs ){
1132 zUtf8 = fossil_mbcs_to_utf8(blob_str(pBlob));
1133 blob_reset(pBlob);
1134 blob_append(pBlob, zUtf8, -1);
1135 fossil_mbcs_free(zUtf8);
1136 #endif /* _WIN32 */
1137 }
1138 }
1139
+12 -2
--- src/cgi.c
+++ src/cgi.c
@@ -1272,11 +1272,16 @@
12721272
** The parent never returns from this procedure.
12731273
**
12741274
** Return 0 to each child as it runs. If unable to establish a
12751275
** listening socket, return non-zero.
12761276
*/
1277
-int cgi_http_server(int mnPort, int mxPort, char *zBrowser, int flags){
1277
+int cgi_http_server(
1278
+ int mnPort, int mxPort, /* Range of TCP ports to try */
1279
+ const char *zBrowser, /* Run this browser, if not NULL */
1280
+ const char *zIpAddr, /* Bind to this IP address, if not null */
1281
+ int flags /* HTTP_SERVER_* flags */
1282
+){
12781283
#if defined(_WIN32)
12791284
/* Use win32_http_server() instead */
12801285
fossil_exit(1);
12811286
#else
12821287
int listener = -1; /* The server socket */
@@ -1291,11 +1296,16 @@
12911296
int iPort = mnPort;
12921297
12931298
while( iPort<=mxPort ){
12941299
memset(&inaddr, 0, sizeof(inaddr));
12951300
inaddr.sin_family = AF_INET;
1296
- if( flags & HTTP_SERVER_LOCALHOST ){
1301
+ if( zIpAddr ){
1302
+ inaddr.sin_addr.s_addr = inet_addr(zIpAddr);
1303
+ if( inaddr.sin_addr.s_addr == (-1) ){
1304
+ fossil_fatal("not a valid IP address: %s", zIpAddr);
1305
+ }
1306
+ }else if( flags & HTTP_SERVER_LOCALHOST ){
12971307
inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
12981308
}else{
12991309
inaddr.sin_addr.s_addr = htonl(INADDR_ANY);
13001310
}
13011311
inaddr.sin_port = htons(iPort);
13021312
--- src/cgi.c
+++ src/cgi.c
@@ -1272,11 +1272,16 @@
1272 ** The parent never returns from this procedure.
1273 **
1274 ** Return 0 to each child as it runs. If unable to establish a
1275 ** listening socket, return non-zero.
1276 */
1277 int cgi_http_server(int mnPort, int mxPort, char *zBrowser, int flags){
 
 
 
 
 
1278 #if defined(_WIN32)
1279 /* Use win32_http_server() instead */
1280 fossil_exit(1);
1281 #else
1282 int listener = -1; /* The server socket */
@@ -1291,11 +1296,16 @@
1291 int iPort = mnPort;
1292
1293 while( iPort<=mxPort ){
1294 memset(&inaddr, 0, sizeof(inaddr));
1295 inaddr.sin_family = AF_INET;
1296 if( flags & HTTP_SERVER_LOCALHOST ){
 
 
 
 
 
1297 inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
1298 }else{
1299 inaddr.sin_addr.s_addr = htonl(INADDR_ANY);
1300 }
1301 inaddr.sin_port = htons(iPort);
1302
--- src/cgi.c
+++ src/cgi.c
@@ -1272,11 +1272,16 @@
1272 ** The parent never returns from this procedure.
1273 **
1274 ** Return 0 to each child as it runs. If unable to establish a
1275 ** listening socket, return non-zero.
1276 */
1277 int cgi_http_server(
1278 int mnPort, int mxPort, /* Range of TCP ports to try */
1279 const char *zBrowser, /* Run this browser, if not NULL */
1280 const char *zIpAddr, /* Bind to this IP address, if not null */
1281 int flags /* HTTP_SERVER_* flags */
1282 ){
1283 #if defined(_WIN32)
1284 /* Use win32_http_server() instead */
1285 fossil_exit(1);
1286 #else
1287 int listener = -1; /* The server socket */
@@ -1291,11 +1296,16 @@
1296 int iPort = mnPort;
1297
1298 while( iPort<=mxPort ){
1299 memset(&inaddr, 0, sizeof(inaddr));
1300 inaddr.sin_family = AF_INET;
1301 if( zIpAddr ){
1302 inaddr.sin_addr.s_addr = inet_addr(zIpAddr);
1303 if( inaddr.sin_addr.s_addr == (-1) ){
1304 fossil_fatal("not a valid IP address: %s", zIpAddr);
1305 }
1306 }else if( flags & HTTP_SERVER_LOCALHOST ){
1307 inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
1308 }else{
1309 inaddr.sin_addr.s_addr = htonl(INADDR_ANY);
1310 }
1311 inaddr.sin_port = htons(iPort);
1312
+46 -28
--- src/checkin.c
+++ src/checkin.c
@@ -177,10 +177,11 @@
177177
if( showHdr && blob_size(&report)>0 ){
178178
fossil_print("Changes for %s at %s:\n", db_get("project-name","???"),
179179
g.zLocalRoot);
180180
}
181181
blob_write_to_file(&report, "-");
182
+ blob_reset(&report);
182183
}
183184
184185
/*
185186
** COMMAND: status
186187
**
@@ -205,22 +206,20 @@
205206
int vid;
206207
db_must_be_within_tree();
207208
/* 012345678901234 */
208209
fossil_print("repository: %s\n", db_repository_filename());
209210
fossil_print("local-root: %s\n", g.zLocalRoot);
211
+ if( g.zConfigDbName ){
212
+ fossil_print("config-db: %s\n", g.zConfigDbName);
213
+ }
210214
vid = db_lget_int("checkout", 0);
211215
if( vid ){
212216
show_common_info(vid, "checkout:", 1, 1);
213217
}
214218
db_record_repository_filename(0);
215219
changes_cmd();
216220
}
217
-
218
-/*
219
-** Implementation of the checkin_mtime SQL function
220
-*/
221
-
222221
223222
/*
224223
** COMMAND: ls
225224
**
226225
** Usage: %fossil ls ?OPTIONS? ?VERSION?
@@ -442,24 +441,26 @@
442441
}
443442
db_multi_exec("DELETE FROM sfile WHERE x IN (SELECT pathname FROM vfile)");
444443
while( db_step(&q)==SQLITE_ROW ){
445444
if( testFlag ){
446445
fossil_print("%s\n", db_column_text(&q,0));
447
- }else if( allFlag ){
448
- file_delete(db_column_text(&q, 0));
449
- }else{
446
+ continue;
447
+ }else if( !allFlag ){
450448
Blob ans;
451449
char cReply;
452
- char *prompt = mprintf("remove unmanaged file \"%s\" (y/N)? ",
450
+ char *prompt = mprintf("remove unmanaged file \"%s\" (a=all/y/N)? ",
453451
db_column_text(&q, 0));
454452
blob_zero(&ans);
455453
prompt_user(prompt, &ans);
456454
cReply = blob_str(&ans)[0];
457
- if( cReply=='y' || cReply=='Y' ){
458
- file_delete(db_column_text(&q, 0));
455
+ if( cReply=='a' || cReply=='A' ){
456
+ allFlag = 1;
457
+ }else if( cReply!='y' && cReply!='Y' ){
458
+ continue;
459459
}
460460
}
461
+ file_delete(db_column_text(&q, 0));
461462
}
462463
db_finalize(&q);
463464
}
464465
465466
/*
@@ -909,58 +910,75 @@
909910
int encodingOk, /* Non-zero if encoding warnings should be disabled. */
910911
const char *zFilename /* The full name of the file being committed. */
911912
){
912913
int eType; /* return value of looks_like_utf8/utf16() */
913914
int fUnicode; /* return value of starts_with_utf16_bom() */
915
+ int lookFlags; /* output flags from looks_like_utf8/utf16() */
916
+ int fHasCrLf; /* the blob contains one or more CR/LF pairs */
914917
char *zMsg; /* Warning message */
915918
Blob fname; /* Relative pathname of the file */
916919
static int allOk = 0; /* Set to true to disable this routine */
917920
918921
if( allOk ) return 0;
919
- fUnicode = starts_with_utf16_bom(p, 0);
920
- eType = fUnicode ? looks_like_utf16(p) : looks_like_utf8(p);
921
- if( eType==0 || eType==-1 || fUnicode ){
922
+ fUnicode = starts_with_utf16_bom(p, 0, 0);
923
+ if( fUnicode ){
924
+ eType = looks_like_utf16(p, &lookFlags);
925
+ if( lookFlags&LOOK_ODD ){
926
+ /* Content with an odd number of bytes cannot be UTF-16. */
927
+ fUnicode = 0;
928
+ /* Therefore, check if the content appears to be UTF-8. */
929
+ eType = looks_like_utf8(p, &lookFlags);
930
+ }
931
+ }else{
932
+ eType = looks_like_utf8(p, &lookFlags);
933
+ }
934
+ fHasCrLf = (lookFlags & LOOK_CRLF);
935
+ if( eType==0 || fHasCrLf || fUnicode ){
922936
const char *zWarning;
923937
const char *zDisable;
924938
const char *zConvert = "c=convert/";
925939
Blob ans;
926940
char cReply;
927941
928
- if( eType==-1 && fUnicode ){
929
- if ( crnlOk && encodingOk ){
942
+ if( eType==0 ){
943
+ if( binOk ){
944
+ return 0; /* We don't want binary warnings for this file. */
945
+ }
946
+ if( (lookFlags&LOOK_LENGTH) && !(lookFlags&LOOK_NUL) ){
947
+ zWarning = "long lines";
948
+ }else{
949
+ zWarning = "binary data";
950
+ }
951
+ zDisable = "\"binary-glob\" setting";
952
+ zConvert = ""; /* We cannot convert binary files. */
953
+ }else if( fHasCrLf && fUnicode ){
954
+ if( crnlOk && encodingOk ){
930955
return 0; /* We don't want CR/NL and Unicode warnings for this file. */
931956
}
932957
zWarning = "CR/NL line endings and Unicode";
933958
zDisable = "\"crnl-glob\" and \"encoding-glob\" settings";
934
- }else if( eType==-1 ){
959
+ }else if( fHasCrLf ){
935960
if( crnlOk ){
936961
return 0; /* We don't want CR/NL warnings for this file. */
937962
}
938963
zWarning = "CR/NL line endings";
939964
zDisable = "\"crnl-glob\" setting";
940
- }else if( eType==0 ){
941
- if( binOk ){
942
- return 0; /* We don't want binary warnings for this file. */
943
- }
944
- zWarning = "binary data";
945
- zDisable = "\"binary-glob\" setting";
946
- zConvert = ""; /* We cannot convert binary files. */
947965
}else{
948
- if ( encodingOk ){
966
+ if( encodingOk ){
949967
return 0; /* We don't want encoding warnings for this file. */
950968
}
951969
zWarning = "Unicode";
952970
zDisable = "\"encoding-glob\" setting";
953
-#ifndef _WIN32
971
+#if !defined(_WIN32) && !defined(__CYGWIN__)
954972
zConvert = ""; /* On Unix, we cannot easily convert Unicode files. */
955973
#endif
956974
}
957975
file_relative_name(zFilename, &fname, 0);
958976
blob_zero(&ans);
959977
zMsg = mprintf(
960978
"%s contains %s. Use --no-warnings or the %s to disable this warning.\n"
961
- "Commit anyhow (a=all/%sy/N)? ",
979
+ "Commit anyhow (a=all/%sy/N)? ",
962980
blob_str(&fname), zWarning, zDisable, zConvert);
963981
prompt_user(zMsg, &ans);
964982
fossil_free(zMsg);
965983
cReply = blob_str(&ans)[0];
966984
if( cReply=='a' || cReply=='A' ){
@@ -1208,11 +1226,11 @@
12081226
** After the following function call has returned, the Global.aCommitFile[]
12091227
** array is allocated to contain the "id" field from the vfile table
12101228
** for each file to be committed. Or, if aCommitFile is NULL, all files
12111229
** should be committed.
12121230
*/
1213
- if ( select_commit_files() ){
1231
+ if( select_commit_files() ){
12141232
blob_zero(&ans);
12151233
prompt_user("continue (y/N)? ", &ans);
12161234
cReply = blob_str(&ans)[0];
12171235
if( cReply!='y' && cReply!='Y' ) fossil_exit(1);;
12181236
}
12191237
--- src/checkin.c
+++ src/checkin.c
@@ -177,10 +177,11 @@
177 if( showHdr && blob_size(&report)>0 ){
178 fossil_print("Changes for %s at %s:\n", db_get("project-name","???"),
179 g.zLocalRoot);
180 }
181 blob_write_to_file(&report, "-");
 
182 }
183
184 /*
185 ** COMMAND: status
186 **
@@ -205,22 +206,20 @@
205 int vid;
206 db_must_be_within_tree();
207 /* 012345678901234 */
208 fossil_print("repository: %s\n", db_repository_filename());
209 fossil_print("local-root: %s\n", g.zLocalRoot);
 
 
 
210 vid = db_lget_int("checkout", 0);
211 if( vid ){
212 show_common_info(vid, "checkout:", 1, 1);
213 }
214 db_record_repository_filename(0);
215 changes_cmd();
216 }
217
218 /*
219 ** Implementation of the checkin_mtime SQL function
220 */
221
222
223 /*
224 ** COMMAND: ls
225 **
226 ** Usage: %fossil ls ?OPTIONS? ?VERSION?
@@ -442,24 +441,26 @@
442 }
443 db_multi_exec("DELETE FROM sfile WHERE x IN (SELECT pathname FROM vfile)");
444 while( db_step(&q)==SQLITE_ROW ){
445 if( testFlag ){
446 fossil_print("%s\n", db_column_text(&q,0));
447 }else if( allFlag ){
448 file_delete(db_column_text(&q, 0));
449 }else{
450 Blob ans;
451 char cReply;
452 char *prompt = mprintf("remove unmanaged file \"%s\" (y/N)? ",
453 db_column_text(&q, 0));
454 blob_zero(&ans);
455 prompt_user(prompt, &ans);
456 cReply = blob_str(&ans)[0];
457 if( cReply=='y' || cReply=='Y' ){
458 file_delete(db_column_text(&q, 0));
 
 
459 }
460 }
 
461 }
462 db_finalize(&q);
463 }
464
465 /*
@@ -909,58 +910,75 @@
909 int encodingOk, /* Non-zero if encoding warnings should be disabled. */
910 const char *zFilename /* The full name of the file being committed. */
911 ){
912 int eType; /* return value of looks_like_utf8/utf16() */
913 int fUnicode; /* return value of starts_with_utf16_bom() */
 
 
914 char *zMsg; /* Warning message */
915 Blob fname; /* Relative pathname of the file */
916 static int allOk = 0; /* Set to true to disable this routine */
917
918 if( allOk ) return 0;
919 fUnicode = starts_with_utf16_bom(p, 0);
920 eType = fUnicode ? looks_like_utf16(p) : looks_like_utf8(p);
921 if( eType==0 || eType==-1 || fUnicode ){
 
 
 
 
 
 
 
 
 
 
 
922 const char *zWarning;
923 const char *zDisable;
924 const char *zConvert = "c=convert/";
925 Blob ans;
926 char cReply;
927
928 if( eType==-1 && fUnicode ){
929 if ( crnlOk && encodingOk ){
 
 
 
 
 
 
 
 
 
 
 
930 return 0; /* We don't want CR/NL and Unicode warnings for this file. */
931 }
932 zWarning = "CR/NL line endings and Unicode";
933 zDisable = "\"crnl-glob\" and \"encoding-glob\" settings";
934 }else if( eType==-1 ){
935 if( crnlOk ){
936 return 0; /* We don't want CR/NL warnings for this file. */
937 }
938 zWarning = "CR/NL line endings";
939 zDisable = "\"crnl-glob\" setting";
940 }else if( eType==0 ){
941 if( binOk ){
942 return 0; /* We don't want binary warnings for this file. */
943 }
944 zWarning = "binary data";
945 zDisable = "\"binary-glob\" setting";
946 zConvert = ""; /* We cannot convert binary files. */
947 }else{
948 if ( encodingOk ){
949 return 0; /* We don't want encoding warnings for this file. */
950 }
951 zWarning = "Unicode";
952 zDisable = "\"encoding-glob\" setting";
953 #ifndef _WIN32
954 zConvert = ""; /* On Unix, we cannot easily convert Unicode files. */
955 #endif
956 }
957 file_relative_name(zFilename, &fname, 0);
958 blob_zero(&ans);
959 zMsg = mprintf(
960 "%s contains %s. Use --no-warnings or the %s to disable this warning.\n"
961 "Commit anyhow (a=all/%sy/N)? ",
962 blob_str(&fname), zWarning, zDisable, zConvert);
963 prompt_user(zMsg, &ans);
964 fossil_free(zMsg);
965 cReply = blob_str(&ans)[0];
966 if( cReply=='a' || cReply=='A' ){
@@ -1208,11 +1226,11 @@
1208 ** After the following function call has returned, the Global.aCommitFile[]
1209 ** array is allocated to contain the "id" field from the vfile table
1210 ** for each file to be committed. Or, if aCommitFile is NULL, all files
1211 ** should be committed.
1212 */
1213 if ( select_commit_files() ){
1214 blob_zero(&ans);
1215 prompt_user("continue (y/N)? ", &ans);
1216 cReply = blob_str(&ans)[0];
1217 if( cReply!='y' && cReply!='Y' ) fossil_exit(1);;
1218 }
1219
--- src/checkin.c
+++ src/checkin.c
@@ -177,10 +177,11 @@
177 if( showHdr && blob_size(&report)>0 ){
178 fossil_print("Changes for %s at %s:\n", db_get("project-name","???"),
179 g.zLocalRoot);
180 }
181 blob_write_to_file(&report, "-");
182 blob_reset(&report);
183 }
184
185 /*
186 ** COMMAND: status
187 **
@@ -205,22 +206,20 @@
206 int vid;
207 db_must_be_within_tree();
208 /* 012345678901234 */
209 fossil_print("repository: %s\n", db_repository_filename());
210 fossil_print("local-root: %s\n", g.zLocalRoot);
211 if( g.zConfigDbName ){
212 fossil_print("config-db: %s\n", g.zConfigDbName);
213 }
214 vid = db_lget_int("checkout", 0);
215 if( vid ){
216 show_common_info(vid, "checkout:", 1, 1);
217 }
218 db_record_repository_filename(0);
219 changes_cmd();
220 }
 
 
 
 
 
221
222 /*
223 ** COMMAND: ls
224 **
225 ** Usage: %fossil ls ?OPTIONS? ?VERSION?
@@ -442,24 +441,26 @@
441 }
442 db_multi_exec("DELETE FROM sfile WHERE x IN (SELECT pathname FROM vfile)");
443 while( db_step(&q)==SQLITE_ROW ){
444 if( testFlag ){
445 fossil_print("%s\n", db_column_text(&q,0));
446 continue;
447 }else if( !allFlag ){
 
448 Blob ans;
449 char cReply;
450 char *prompt = mprintf("remove unmanaged file \"%s\" (a=all/y/N)? ",
451 db_column_text(&q, 0));
452 blob_zero(&ans);
453 prompt_user(prompt, &ans);
454 cReply = blob_str(&ans)[0];
455 if( cReply=='a' || cReply=='A' ){
456 allFlag = 1;
457 }else if( cReply!='y' && cReply!='Y' ){
458 continue;
459 }
460 }
461 file_delete(db_column_text(&q, 0));
462 }
463 db_finalize(&q);
464 }
465
466 /*
@@ -909,58 +910,75 @@
910 int encodingOk, /* Non-zero if encoding warnings should be disabled. */
911 const char *zFilename /* The full name of the file being committed. */
912 ){
913 int eType; /* return value of looks_like_utf8/utf16() */
914 int fUnicode; /* return value of starts_with_utf16_bom() */
915 int lookFlags; /* output flags from looks_like_utf8/utf16() */
916 int fHasCrLf; /* the blob contains one or more CR/LF pairs */
917 char *zMsg; /* Warning message */
918 Blob fname; /* Relative pathname of the file */
919 static int allOk = 0; /* Set to true to disable this routine */
920
921 if( allOk ) return 0;
922 fUnicode = starts_with_utf16_bom(p, 0, 0);
923 if( fUnicode ){
924 eType = looks_like_utf16(p, &lookFlags);
925 if( lookFlags&LOOK_ODD ){
926 /* Content with an odd number of bytes cannot be UTF-16. */
927 fUnicode = 0;
928 /* Therefore, check if the content appears to be UTF-8. */
929 eType = looks_like_utf8(p, &lookFlags);
930 }
931 }else{
932 eType = looks_like_utf8(p, &lookFlags);
933 }
934 fHasCrLf = (lookFlags & LOOK_CRLF);
935 if( eType==0 || fHasCrLf || fUnicode ){
936 const char *zWarning;
937 const char *zDisable;
938 const char *zConvert = "c=convert/";
939 Blob ans;
940 char cReply;
941
942 if( eType==0 ){
943 if( binOk ){
944 return 0; /* We don't want binary warnings for this file. */
945 }
946 if( (lookFlags&LOOK_LENGTH) && !(lookFlags&LOOK_NUL) ){
947 zWarning = "long lines";
948 }else{
949 zWarning = "binary data";
950 }
951 zDisable = "\"binary-glob\" setting";
952 zConvert = ""; /* We cannot convert binary files. */
953 }else if( fHasCrLf && fUnicode ){
954 if( crnlOk && encodingOk ){
955 return 0; /* We don't want CR/NL and Unicode warnings for this file. */
956 }
957 zWarning = "CR/NL line endings and Unicode";
958 zDisable = "\"crnl-glob\" and \"encoding-glob\" settings";
959 }else if( fHasCrLf ){
960 if( crnlOk ){
961 return 0; /* We don't want CR/NL warnings for this file. */
962 }
963 zWarning = "CR/NL line endings";
964 zDisable = "\"crnl-glob\" setting";
 
 
 
 
 
 
 
965 }else{
966 if( encodingOk ){
967 return 0; /* We don't want encoding warnings for this file. */
968 }
969 zWarning = "Unicode";
970 zDisable = "\"encoding-glob\" setting";
971 #if !defined(_WIN32) && !defined(__CYGWIN__)
972 zConvert = ""; /* On Unix, we cannot easily convert Unicode files. */
973 #endif
974 }
975 file_relative_name(zFilename, &fname, 0);
976 blob_zero(&ans);
977 zMsg = mprintf(
978 "%s contains %s. Use --no-warnings or the %s to disable this warning.\n"
979 "Commit anyhow (a=all/%sy/N)? ",
980 blob_str(&fname), zWarning, zDisable, zConvert);
981 prompt_user(zMsg, &ans);
982 fossil_free(zMsg);
983 cReply = blob_str(&ans)[0];
984 if( cReply=='a' || cReply=='A' ){
@@ -1208,11 +1226,11 @@
1226 ** After the following function call has returned, the Global.aCommitFile[]
1227 ** array is allocated to contain the "id" field from the vfile table
1228 ** for each file to be committed. Or, if aCommitFile is NULL, all files
1229 ** should be committed.
1230 */
1231 if( select_commit_files() ){
1232 blob_zero(&ans);
1233 prompt_user("continue (y/N)? ", &ans);
1234 cReply = blob_str(&ans)[0];
1235 if( cReply!='y' && cReply!='Y' ) fossil_exit(1);;
1236 }
1237
+46 -28
--- src/checkin.c
+++ src/checkin.c
@@ -177,10 +177,11 @@
177177
if( showHdr && blob_size(&report)>0 ){
178178
fossil_print("Changes for %s at %s:\n", db_get("project-name","???"),
179179
g.zLocalRoot);
180180
}
181181
blob_write_to_file(&report, "-");
182
+ blob_reset(&report);
182183
}
183184
184185
/*
185186
** COMMAND: status
186187
**
@@ -205,22 +206,20 @@
205206
int vid;
206207
db_must_be_within_tree();
207208
/* 012345678901234 */
208209
fossil_print("repository: %s\n", db_repository_filename());
209210
fossil_print("local-root: %s\n", g.zLocalRoot);
211
+ if( g.zConfigDbName ){
212
+ fossil_print("config-db: %s\n", g.zConfigDbName);
213
+ }
210214
vid = db_lget_int("checkout", 0);
211215
if( vid ){
212216
show_common_info(vid, "checkout:", 1, 1);
213217
}
214218
db_record_repository_filename(0);
215219
changes_cmd();
216220
}
217
-
218
-/*
219
-** Implementation of the checkin_mtime SQL function
220
-*/
221
-
222221
223222
/*
224223
** COMMAND: ls
225224
**
226225
** Usage: %fossil ls ?OPTIONS? ?VERSION?
@@ -442,24 +441,26 @@
442441
}
443442
db_multi_exec("DELETE FROM sfile WHERE x IN (SELECT pathname FROM vfile)");
444443
while( db_step(&q)==SQLITE_ROW ){
445444
if( testFlag ){
446445
fossil_print("%s\n", db_column_text(&q,0));
447
- }else if( allFlag ){
448
- file_delete(db_column_text(&q, 0));
449
- }else{
446
+ continue;
447
+ }else if( !allFlag ){
450448
Blob ans;
451449
char cReply;
452
- char *prompt = mprintf("remove unmanaged file \"%s\" (y/N)? ",
450
+ char *prompt = mprintf("remove unmanaged file \"%s\" (a=all/y/N)? ",
453451
db_column_text(&q, 0));
454452
blob_zero(&ans);
455453
prompt_user(prompt, &ans);
456454
cReply = blob_str(&ans)[0];
457
- if( cReply=='y' || cReply=='Y' ){
458
- file_delete(db_column_text(&q, 0));
455
+ if( cReply=='a' || cReply=='A' ){
456
+ allFlag = 1;
457
+ }else if( cReply!='y' && cReply!='Y' ){
458
+ continue;
459459
}
460460
}
461
+ file_delete(db_column_text(&q, 0));
461462
}
462463
db_finalize(&q);
463464
}
464465
465466
/*
@@ -909,58 +910,75 @@
909910
int encodingOk, /* Non-zero if encoding warnings should be disabled. */
910911
const char *zFilename /* The full name of the file being committed. */
911912
){
912913
int eType; /* return value of looks_like_utf8/utf16() */
913914
int fUnicode; /* return value of starts_with_utf16_bom() */
915
+ int lookFlags; /* output flags from looks_like_utf8/utf16() */
916
+ int fHasCrLf; /* the blob contains one or more CR/LF pairs */
914917
char *zMsg; /* Warning message */
915918
Blob fname; /* Relative pathname of the file */
916919
static int allOk = 0; /* Set to true to disable this routine */
917920
918921
if( allOk ) return 0;
919
- fUnicode = starts_with_utf16_bom(p, 0);
920
- eType = fUnicode ? looks_like_utf16(p) : looks_like_utf8(p);
921
- if( eType==0 || eType==-1 || fUnicode ){
922
+ fUnicode = starts_with_utf16_bom(p, 0, 0);
923
+ if( fUnicode ){
924
+ eType = looks_like_utf16(p, &lookFlags);
925
+ if( lookFlags&LOOK_ODD ){
926
+ /* Content with an odd number of bytes cannot be UTF-16. */
927
+ fUnicode = 0;
928
+ /* Therefore, check if the content appears to be UTF-8. */
929
+ eType = looks_like_utf8(p, &lookFlags);
930
+ }
931
+ }else{
932
+ eType = looks_like_utf8(p, &lookFlags);
933
+ }
934
+ fHasCrLf = (lookFlags & LOOK_CRLF);
935
+ if( eType==0 || fHasCrLf || fUnicode ){
922936
const char *zWarning;
923937
const char *zDisable;
924938
const char *zConvert = "c=convert/";
925939
Blob ans;
926940
char cReply;
927941
928
- if( eType==-1 && fUnicode ){
929
- if ( crnlOk && encodingOk ){
942
+ if( eType==0 ){
943
+ if( binOk ){
944
+ return 0; /* We don't want binary warnings for this file. */
945
+ }
946
+ if( (lookFlags&LOOK_LENGTH) && !(lookFlags&LOOK_NUL) ){
947
+ zWarning = "long lines";
948
+ }else{
949
+ zWarning = "binary data";
950
+ }
951
+ zDisable = "\"binary-glob\" setting";
952
+ zConvert = ""; /* We cannot convert binary files. */
953
+ }else if( fHasCrLf && fUnicode ){
954
+ if( crnlOk && encodingOk ){
930955
return 0; /* We don't want CR/NL and Unicode warnings for this file. */
931956
}
932957
zWarning = "CR/NL line endings and Unicode";
933958
zDisable = "\"crnl-glob\" and \"encoding-glob\" settings";
934
- }else if( eType==-1 ){
959
+ }else if( fHasCrLf ){
935960
if( crnlOk ){
936961
return 0; /* We don't want CR/NL warnings for this file. */
937962
}
938963
zWarning = "CR/NL line endings";
939964
zDisable = "\"crnl-glob\" setting";
940
- }else if( eType==0 ){
941
- if( binOk ){
942
- return 0; /* We don't want binary warnings for this file. */
943
- }
944
- zWarning = "binary data";
945
- zDisable = "\"binary-glob\" setting";
946
- zConvert = ""; /* We cannot convert binary files. */
947965
}else{
948
- if ( encodingOk ){
966
+ if( encodingOk ){
949967
return 0; /* We don't want encoding warnings for this file. */
950968
}
951969
zWarning = "Unicode";
952970
zDisable = "\"encoding-glob\" setting";
953
-#ifndef _WIN32
971
+#if !defined(_WIN32) && !defined(__CYGWIN__)
954972
zConvert = ""; /* On Unix, we cannot easily convert Unicode files. */
955973
#endif
956974
}
957975
file_relative_name(zFilename, &fname, 0);
958976
blob_zero(&ans);
959977
zMsg = mprintf(
960978
"%s contains %s. Use --no-warnings or the %s to disable this warning.\n"
961
- "Commit anyhow (a=all/%sy/N)? ",
979
+ "Commit anyhow (a=all/%sy/N)? ",
962980
blob_str(&fname), zWarning, zDisable, zConvert);
963981
prompt_user(zMsg, &ans);
964982
fossil_free(zMsg);
965983
cReply = blob_str(&ans)[0];
966984
if( cReply=='a' || cReply=='A' ){
@@ -1208,11 +1226,11 @@
12081226
** After the following function call has returned, the Global.aCommitFile[]
12091227
** array is allocated to contain the "id" field from the vfile table
12101228
** for each file to be committed. Or, if aCommitFile is NULL, all files
12111229
** should be committed.
12121230
*/
1213
- if ( select_commit_files() ){
1231
+ if( select_commit_files() ){
12141232
blob_zero(&ans);
12151233
prompt_user("continue (y/N)? ", &ans);
12161234
cReply = blob_str(&ans)[0];
12171235
if( cReply!='y' && cReply!='Y' ) fossil_exit(1);;
12181236
}
12191237
--- src/checkin.c
+++ src/checkin.c
@@ -177,10 +177,11 @@
177 if( showHdr && blob_size(&report)>0 ){
178 fossil_print("Changes for %s at %s:\n", db_get("project-name","???"),
179 g.zLocalRoot);
180 }
181 blob_write_to_file(&report, "-");
 
182 }
183
184 /*
185 ** COMMAND: status
186 **
@@ -205,22 +206,20 @@
205 int vid;
206 db_must_be_within_tree();
207 /* 012345678901234 */
208 fossil_print("repository: %s\n", db_repository_filename());
209 fossil_print("local-root: %s\n", g.zLocalRoot);
 
 
 
210 vid = db_lget_int("checkout", 0);
211 if( vid ){
212 show_common_info(vid, "checkout:", 1, 1);
213 }
214 db_record_repository_filename(0);
215 changes_cmd();
216 }
217
218 /*
219 ** Implementation of the checkin_mtime SQL function
220 */
221
222
223 /*
224 ** COMMAND: ls
225 **
226 ** Usage: %fossil ls ?OPTIONS? ?VERSION?
@@ -442,24 +441,26 @@
442 }
443 db_multi_exec("DELETE FROM sfile WHERE x IN (SELECT pathname FROM vfile)");
444 while( db_step(&q)==SQLITE_ROW ){
445 if( testFlag ){
446 fossil_print("%s\n", db_column_text(&q,0));
447 }else if( allFlag ){
448 file_delete(db_column_text(&q, 0));
449 }else{
450 Blob ans;
451 char cReply;
452 char *prompt = mprintf("remove unmanaged file \"%s\" (y/N)? ",
453 db_column_text(&q, 0));
454 blob_zero(&ans);
455 prompt_user(prompt, &ans);
456 cReply = blob_str(&ans)[0];
457 if( cReply=='y' || cReply=='Y' ){
458 file_delete(db_column_text(&q, 0));
 
 
459 }
460 }
 
461 }
462 db_finalize(&q);
463 }
464
465 /*
@@ -909,58 +910,75 @@
909 int encodingOk, /* Non-zero if encoding warnings should be disabled. */
910 const char *zFilename /* The full name of the file being committed. */
911 ){
912 int eType; /* return value of looks_like_utf8/utf16() */
913 int fUnicode; /* return value of starts_with_utf16_bom() */
 
 
914 char *zMsg; /* Warning message */
915 Blob fname; /* Relative pathname of the file */
916 static int allOk = 0; /* Set to true to disable this routine */
917
918 if( allOk ) return 0;
919 fUnicode = starts_with_utf16_bom(p, 0);
920 eType = fUnicode ? looks_like_utf16(p) : looks_like_utf8(p);
921 if( eType==0 || eType==-1 || fUnicode ){
 
 
 
 
 
 
 
 
 
 
 
922 const char *zWarning;
923 const char *zDisable;
924 const char *zConvert = "c=convert/";
925 Blob ans;
926 char cReply;
927
928 if( eType==-1 && fUnicode ){
929 if ( crnlOk && encodingOk ){
 
 
 
 
 
 
 
 
 
 
 
930 return 0; /* We don't want CR/NL and Unicode warnings for this file. */
931 }
932 zWarning = "CR/NL line endings and Unicode";
933 zDisable = "\"crnl-glob\" and \"encoding-glob\" settings";
934 }else if( eType==-1 ){
935 if( crnlOk ){
936 return 0; /* We don't want CR/NL warnings for this file. */
937 }
938 zWarning = "CR/NL line endings";
939 zDisable = "\"crnl-glob\" setting";
940 }else if( eType==0 ){
941 if( binOk ){
942 return 0; /* We don't want binary warnings for this file. */
943 }
944 zWarning = "binary data";
945 zDisable = "\"binary-glob\" setting";
946 zConvert = ""; /* We cannot convert binary files. */
947 }else{
948 if ( encodingOk ){
949 return 0; /* We don't want encoding warnings for this file. */
950 }
951 zWarning = "Unicode";
952 zDisable = "\"encoding-glob\" setting";
953 #ifndef _WIN32
954 zConvert = ""; /* On Unix, we cannot easily convert Unicode files. */
955 #endif
956 }
957 file_relative_name(zFilename, &fname, 0);
958 blob_zero(&ans);
959 zMsg = mprintf(
960 "%s contains %s. Use --no-warnings or the %s to disable this warning.\n"
961 "Commit anyhow (a=all/%sy/N)? ",
962 blob_str(&fname), zWarning, zDisable, zConvert);
963 prompt_user(zMsg, &ans);
964 fossil_free(zMsg);
965 cReply = blob_str(&ans)[0];
966 if( cReply=='a' || cReply=='A' ){
@@ -1208,11 +1226,11 @@
1208 ** After the following function call has returned, the Global.aCommitFile[]
1209 ** array is allocated to contain the "id" field from the vfile table
1210 ** for each file to be committed. Or, if aCommitFile is NULL, all files
1211 ** should be committed.
1212 */
1213 if ( select_commit_files() ){
1214 blob_zero(&ans);
1215 prompt_user("continue (y/N)? ", &ans);
1216 cReply = blob_str(&ans)[0];
1217 if( cReply!='y' && cReply!='Y' ) fossil_exit(1);;
1218 }
1219
--- src/checkin.c
+++ src/checkin.c
@@ -177,10 +177,11 @@
177 if( showHdr && blob_size(&report)>0 ){
178 fossil_print("Changes for %s at %s:\n", db_get("project-name","???"),
179 g.zLocalRoot);
180 }
181 blob_write_to_file(&report, "-");
182 blob_reset(&report);
183 }
184
185 /*
186 ** COMMAND: status
187 **
@@ -205,22 +206,20 @@
206 int vid;
207 db_must_be_within_tree();
208 /* 012345678901234 */
209 fossil_print("repository: %s\n", db_repository_filename());
210 fossil_print("local-root: %s\n", g.zLocalRoot);
211 if( g.zConfigDbName ){
212 fossil_print("config-db: %s\n", g.zConfigDbName);
213 }
214 vid = db_lget_int("checkout", 0);
215 if( vid ){
216 show_common_info(vid, "checkout:", 1, 1);
217 }
218 db_record_repository_filename(0);
219 changes_cmd();
220 }
 
 
 
 
 
221
222 /*
223 ** COMMAND: ls
224 **
225 ** Usage: %fossil ls ?OPTIONS? ?VERSION?
@@ -442,24 +441,26 @@
441 }
442 db_multi_exec("DELETE FROM sfile WHERE x IN (SELECT pathname FROM vfile)");
443 while( db_step(&q)==SQLITE_ROW ){
444 if( testFlag ){
445 fossil_print("%s\n", db_column_text(&q,0));
446 continue;
447 }else if( !allFlag ){
 
448 Blob ans;
449 char cReply;
450 char *prompt = mprintf("remove unmanaged file \"%s\" (a=all/y/N)? ",
451 db_column_text(&q, 0));
452 blob_zero(&ans);
453 prompt_user(prompt, &ans);
454 cReply = blob_str(&ans)[0];
455 if( cReply=='a' || cReply=='A' ){
456 allFlag = 1;
457 }else if( cReply!='y' && cReply!='Y' ){
458 continue;
459 }
460 }
461 file_delete(db_column_text(&q, 0));
462 }
463 db_finalize(&q);
464 }
465
466 /*
@@ -909,58 +910,75 @@
910 int encodingOk, /* Non-zero if encoding warnings should be disabled. */
911 const char *zFilename /* The full name of the file being committed. */
912 ){
913 int eType; /* return value of looks_like_utf8/utf16() */
914 int fUnicode; /* return value of starts_with_utf16_bom() */
915 int lookFlags; /* output flags from looks_like_utf8/utf16() */
916 int fHasCrLf; /* the blob contains one or more CR/LF pairs */
917 char *zMsg; /* Warning message */
918 Blob fname; /* Relative pathname of the file */
919 static int allOk = 0; /* Set to true to disable this routine */
920
921 if( allOk ) return 0;
922 fUnicode = starts_with_utf16_bom(p, 0, 0);
923 if( fUnicode ){
924 eType = looks_like_utf16(p, &lookFlags);
925 if( lookFlags&LOOK_ODD ){
926 /* Content with an odd number of bytes cannot be UTF-16. */
927 fUnicode = 0;
928 /* Therefore, check if the content appears to be UTF-8. */
929 eType = looks_like_utf8(p, &lookFlags);
930 }
931 }else{
932 eType = looks_like_utf8(p, &lookFlags);
933 }
934 fHasCrLf = (lookFlags & LOOK_CRLF);
935 if( eType==0 || fHasCrLf || fUnicode ){
936 const char *zWarning;
937 const char *zDisable;
938 const char *zConvert = "c=convert/";
939 Blob ans;
940 char cReply;
941
942 if( eType==0 ){
943 if( binOk ){
944 return 0; /* We don't want binary warnings for this file. */
945 }
946 if( (lookFlags&LOOK_LENGTH) && !(lookFlags&LOOK_NUL) ){
947 zWarning = "long lines";
948 }else{
949 zWarning = "binary data";
950 }
951 zDisable = "\"binary-glob\" setting";
952 zConvert = ""; /* We cannot convert binary files. */
953 }else if( fHasCrLf && fUnicode ){
954 if( crnlOk && encodingOk ){
955 return 0; /* We don't want CR/NL and Unicode warnings for this file. */
956 }
957 zWarning = "CR/NL line endings and Unicode";
958 zDisable = "\"crnl-glob\" and \"encoding-glob\" settings";
959 }else if( fHasCrLf ){
960 if( crnlOk ){
961 return 0; /* We don't want CR/NL warnings for this file. */
962 }
963 zWarning = "CR/NL line endings";
964 zDisable = "\"crnl-glob\" setting";
 
 
 
 
 
 
 
965 }else{
966 if( encodingOk ){
967 return 0; /* We don't want encoding warnings for this file. */
968 }
969 zWarning = "Unicode";
970 zDisable = "\"encoding-glob\" setting";
971 #if !defined(_WIN32) && !defined(__CYGWIN__)
972 zConvert = ""; /* On Unix, we cannot easily convert Unicode files. */
973 #endif
974 }
975 file_relative_name(zFilename, &fname, 0);
976 blob_zero(&ans);
977 zMsg = mprintf(
978 "%s contains %s. Use --no-warnings or the %s to disable this warning.\n"
979 "Commit anyhow (a=all/%sy/N)? ",
980 blob_str(&fname), zWarning, zDisable, zConvert);
981 prompt_user(zMsg, &ans);
982 fossil_free(zMsg);
983 cReply = blob_str(&ans)[0];
984 if( cReply=='a' || cReply=='A' ){
@@ -1208,11 +1226,11 @@
1226 ** After the following function call has returned, the Global.aCommitFile[]
1227 ** array is allocated to contain the "id" field from the vfile table
1228 ** for each file to be committed. Or, if aCommitFile is NULL, all files
1229 ** should be committed.
1230 */
1231 if( select_commit_files() ){
1232 blob_zero(&ans);
1233 prompt_user("continue (y/N)? ", &ans);
1234 cReply = blob_str(&ans)[0];
1235 if( cReply!='y' && cReply!='Y' ) fossil_exit(1);;
1236 }
1237
+3 -13
--- src/clone.c
+++ src/clone.c
@@ -99,11 +99,10 @@
9999
** See also: init
100100
*/
101101
void clone_cmd(void){
102102
char *zPassword;
103103
const char *zDefaultUser; /* Optional name of the default user */
104
- const char *zPw; /* The user clone password */
105104
int nErr = 0;
106105
int bPrivate = 0; /* Also clone private branches */
107106
108107
if( find_option("private",0,0)!=0 ) bPrivate = SYNC_PRIVATE;
109108
url_proxy_options();
@@ -115,23 +114,17 @@
115114
fossil_panic("file already exists: %s", g.argv[3]);
116115
}
117116
118117
zDefaultUser = find_option("admin-user","A",1);
119118
120
- url_parse(g.argv[2]);
119
+ url_parse(g.argv[2], URL_PROMPT_PW|URL_ASK_REMEMBER_PW);
121120
if( g.urlIsFile ){
122121
file_copy(g.urlName, g.argv[3]);
123122
db_close(1);
124123
db_open_repository(g.argv[3]);
125124
db_record_repository_filename(g.argv[3]);
126
- db_multi_exec(
127
- "REPLACE INTO config(name,value,mtime)"
128
- " VALUES('server-code', lower(hex(randomblob(20))),now());"
129
- "REPLACE INTO config(name,value,mtime)"
130
- " VALUES('last-sync-url', '%q',now());",
131
- g.urlCanonical
132
- );
125
+ url_remember();
133126
if( !bPrivate ) delete_private_content();
134127
shun_artifacts();
135128
db_create_default_users(1, zDefaultUser);
136129
if( zDefaultUser ){
137130
g.zLogin = zDefaultUser;
@@ -146,11 +139,11 @@
146139
db_record_repository_filename(g.argv[3]);
147140
db_initial_setup(0, 0, zDefaultUser, 0);
148141
user_select();
149142
db_set("content-schema", CONTENT_SCHEMA, 0);
150143
db_set("aux-schema", AUX_SCHEMA, 0);
151
- db_set("last-sync-url", g.argv[2], 0);
144
+ url_remember();
152145
if( g.zSSLIdentity!=0 ){
153146
/* If the --ssl-identity option was specified, store it as a setting */
154147
Blob fn;
155148
blob_zero(&fn);
156149
file_canonical_name(g.zSSLIdentity, &fn, 0);
@@ -177,12 +170,9 @@
177170
}
178171
db_begin_transaction();
179172
fossil_print("Rebuilding repository meta-data...\n");
180173
rebuild_db(0, 1, 0);
181174
fossil_print("project-id: %s\n", db_get("project-code", 0));
182
- fossil_print("server-id: %s\n", db_get("server-code", 0));
183175
zPassword = db_text(0, "SELECT pw FROM user WHERE login=%Q", g.zLogin);
184176
fossil_print("admin-user: %s (password is \"%s\")\n", g.zLogin, zPassword);
185
- zPw = g.urlPasswd;
186
- if( !g.dontKeepUrl && zPw) db_set("last-sync-pw", obscure(zPw), 0);
187177
db_end_transaction(0);
188178
}
189179
--- src/clone.c
+++ src/clone.c
@@ -99,11 +99,10 @@
99 ** See also: init
100 */
101 void clone_cmd(void){
102 char *zPassword;
103 const char *zDefaultUser; /* Optional name of the default user */
104 const char *zPw; /* The user clone password */
105 int nErr = 0;
106 int bPrivate = 0; /* Also clone private branches */
107
108 if( find_option("private",0,0)!=0 ) bPrivate = SYNC_PRIVATE;
109 url_proxy_options();
@@ -115,23 +114,17 @@
115 fossil_panic("file already exists: %s", g.argv[3]);
116 }
117
118 zDefaultUser = find_option("admin-user","A",1);
119
120 url_parse(g.argv[2]);
121 if( g.urlIsFile ){
122 file_copy(g.urlName, g.argv[3]);
123 db_close(1);
124 db_open_repository(g.argv[3]);
125 db_record_repository_filename(g.argv[3]);
126 db_multi_exec(
127 "REPLACE INTO config(name,value,mtime)"
128 " VALUES('server-code', lower(hex(randomblob(20))),now());"
129 "REPLACE INTO config(name,value,mtime)"
130 " VALUES('last-sync-url', '%q',now());",
131 g.urlCanonical
132 );
133 if( !bPrivate ) delete_private_content();
134 shun_artifacts();
135 db_create_default_users(1, zDefaultUser);
136 if( zDefaultUser ){
137 g.zLogin = zDefaultUser;
@@ -146,11 +139,11 @@
146 db_record_repository_filename(g.argv[3]);
147 db_initial_setup(0, 0, zDefaultUser, 0);
148 user_select();
149 db_set("content-schema", CONTENT_SCHEMA, 0);
150 db_set("aux-schema", AUX_SCHEMA, 0);
151 db_set("last-sync-url", g.argv[2], 0);
152 if( g.zSSLIdentity!=0 ){
153 /* If the --ssl-identity option was specified, store it as a setting */
154 Blob fn;
155 blob_zero(&fn);
156 file_canonical_name(g.zSSLIdentity, &fn, 0);
@@ -177,12 +170,9 @@
177 }
178 db_begin_transaction();
179 fossil_print("Rebuilding repository meta-data...\n");
180 rebuild_db(0, 1, 0);
181 fossil_print("project-id: %s\n", db_get("project-code", 0));
182 fossil_print("server-id: %s\n", db_get("server-code", 0));
183 zPassword = db_text(0, "SELECT pw FROM user WHERE login=%Q", g.zLogin);
184 fossil_print("admin-user: %s (password is \"%s\")\n", g.zLogin, zPassword);
185 zPw = g.urlPasswd;
186 if( !g.dontKeepUrl && zPw) db_set("last-sync-pw", obscure(zPw), 0);
187 db_end_transaction(0);
188 }
189
--- src/clone.c
+++ src/clone.c
@@ -99,11 +99,10 @@
99 ** See also: init
100 */
101 void clone_cmd(void){
102 char *zPassword;
103 const char *zDefaultUser; /* Optional name of the default user */
 
104 int nErr = 0;
105 int bPrivate = 0; /* Also clone private branches */
106
107 if( find_option("private",0,0)!=0 ) bPrivate = SYNC_PRIVATE;
108 url_proxy_options();
@@ -115,23 +114,17 @@
114 fossil_panic("file already exists: %s", g.argv[3]);
115 }
116
117 zDefaultUser = find_option("admin-user","A",1);
118
119 url_parse(g.argv[2], URL_PROMPT_PW|URL_ASK_REMEMBER_PW);
120 if( g.urlIsFile ){
121 file_copy(g.urlName, g.argv[3]);
122 db_close(1);
123 db_open_repository(g.argv[3]);
124 db_record_repository_filename(g.argv[3]);
125 url_remember();
 
 
 
 
 
 
126 if( !bPrivate ) delete_private_content();
127 shun_artifacts();
128 db_create_default_users(1, zDefaultUser);
129 if( zDefaultUser ){
130 g.zLogin = zDefaultUser;
@@ -146,11 +139,11 @@
139 db_record_repository_filename(g.argv[3]);
140 db_initial_setup(0, 0, zDefaultUser, 0);
141 user_select();
142 db_set("content-schema", CONTENT_SCHEMA, 0);
143 db_set("aux-schema", AUX_SCHEMA, 0);
144 url_remember();
145 if( g.zSSLIdentity!=0 ){
146 /* If the --ssl-identity option was specified, store it as a setting */
147 Blob fn;
148 blob_zero(&fn);
149 file_canonical_name(g.zSSLIdentity, &fn, 0);
@@ -177,12 +170,9 @@
170 }
171 db_begin_transaction();
172 fossil_print("Rebuilding repository meta-data...\n");
173 rebuild_db(0, 1, 0);
174 fossil_print("project-id: %s\n", db_get("project-code", 0));
 
175 zPassword = db_text(0, "SELECT pw FROM user WHERE login=%Q", g.zLogin);
176 fossil_print("admin-user: %s (password is \"%s\")\n", g.zLogin, zPassword);
 
 
177 db_end_transaction(0);
178 }
179
+6 -14
--- src/configure.c
+++ src/configure.c
@@ -878,36 +878,28 @@
878878
if( strncmp(zMethod, "pull", n)==0
879879
|| strncmp(zMethod, "push", n)==0
880880
|| strncmp(zMethod, "sync", n)==0
881881
){
882882
int mask;
883
- const char *zServer;
884
- const char *zPw;
883
+ const char *zServer = 0;
885884
int legacyFlag = 0;
886885
int overwriteFlag = 0;
886
+
887887
if( zMethod[0]!='s' ) legacyFlag = find_option("legacy",0,0)!=0;
888888
if( strncmp(zMethod,"pull",n)==0 ){
889889
overwriteFlag = find_option("overwrite",0,0)!=0;
890890
}
891891
url_proxy_options();
892892
if( g.argc!=4 && g.argc!=5 ){
893
- usage("pull AREA ?URL?");
893
+ usage(mprintf("%s AREA ?URL?", zMethod));
894894
}
895895
mask = configure_name_to_mask(g.argv[3], 1);
896896
if( g.argc==5 ){
897897
zServer = g.argv[4];
898
- zPw = 0;
899
- g.dontKeepUrl = 1;
900
- }else{
901
- zServer = db_get("last-sync-url", 0);
902
- if( zServer==0 ){
903
- fossil_fatal("no server specified");
904
- }
905
- zPw = unobscure(db_get("last-sync-pw", 0));
906
- }
907
- url_parse(zServer);
908
- if( g.urlPasswd==0 && zPw ) g.urlPasswd = mprintf("%s", zPw);
898
+ }
899
+ url_parse(zServer, URL_PROMPT_PW);
900
+ if( g.urlProtocol==0 ) fossil_fatal("no server URL specified");
909901
user_select();
910902
url_enable_proxy("via proxy: ");
911903
if( legacyFlag ) mask |= CONFIGSET_OLDFORMAT;
912904
if( overwriteFlag ) mask |= CONFIGSET_OVERWRITE;
913905
if( strncmp(zMethod, "push", n)==0 ){
914906
--- src/configure.c
+++ src/configure.c
@@ -878,36 +878,28 @@
878 if( strncmp(zMethod, "pull", n)==0
879 || strncmp(zMethod, "push", n)==0
880 || strncmp(zMethod, "sync", n)==0
881 ){
882 int mask;
883 const char *zServer;
884 const char *zPw;
885 int legacyFlag = 0;
886 int overwriteFlag = 0;
 
887 if( zMethod[0]!='s' ) legacyFlag = find_option("legacy",0,0)!=0;
888 if( strncmp(zMethod,"pull",n)==0 ){
889 overwriteFlag = find_option("overwrite",0,0)!=0;
890 }
891 url_proxy_options();
892 if( g.argc!=4 && g.argc!=5 ){
893 usage("pull AREA ?URL?");
894 }
895 mask = configure_name_to_mask(g.argv[3], 1);
896 if( g.argc==5 ){
897 zServer = g.argv[4];
898 zPw = 0;
899 g.dontKeepUrl = 1;
900 }else{
901 zServer = db_get("last-sync-url", 0);
902 if( zServer==0 ){
903 fossil_fatal("no server specified");
904 }
905 zPw = unobscure(db_get("last-sync-pw", 0));
906 }
907 url_parse(zServer);
908 if( g.urlPasswd==0 && zPw ) g.urlPasswd = mprintf("%s", zPw);
909 user_select();
910 url_enable_proxy("via proxy: ");
911 if( legacyFlag ) mask |= CONFIGSET_OLDFORMAT;
912 if( overwriteFlag ) mask |= CONFIGSET_OVERWRITE;
913 if( strncmp(zMethod, "push", n)==0 ){
914
--- src/configure.c
+++ src/configure.c
@@ -878,36 +878,28 @@
878 if( strncmp(zMethod, "pull", n)==0
879 || strncmp(zMethod, "push", n)==0
880 || strncmp(zMethod, "sync", n)==0
881 ){
882 int mask;
883 const char *zServer = 0;
 
884 int legacyFlag = 0;
885 int overwriteFlag = 0;
886
887 if( zMethod[0]!='s' ) legacyFlag = find_option("legacy",0,0)!=0;
888 if( strncmp(zMethod,"pull",n)==0 ){
889 overwriteFlag = find_option("overwrite",0,0)!=0;
890 }
891 url_proxy_options();
892 if( g.argc!=4 && g.argc!=5 ){
893 usage(mprintf("%s AREA ?URL?", zMethod));
894 }
895 mask = configure_name_to_mask(g.argv[3], 1);
896 if( g.argc==5 ){
897 zServer = g.argv[4];
898 }
899 url_parse(zServer, URL_PROMPT_PW);
900 if( g.urlProtocol==0 ) fossil_fatal("no server URL specified");
 
 
 
 
 
 
 
 
901 user_select();
902 url_enable_proxy("via proxy: ");
903 if( legacyFlag ) mask |= CONFIGSET_OLDFORMAT;
904 if( overwriteFlag ) mask |= CONFIGSET_OVERWRITE;
905 if( strncmp(zMethod, "push", n)==0 ){
906
+69 -37
--- src/db.c
+++ src/db.c
@@ -221,11 +221,11 @@
221221
** rolls back rather than commit. It is the responsibility of the
222222
** hooks themselves to issue any error messages.
223223
*/
224224
void db_commit_hook(int (*x)(void), int sequence){
225225
int i;
226
- assert( db.nCommitHook < sizeof(db.aHook)/sizeof(db.aHook[1]) );
226
+ assert( db.nCommitHook < count(db.aHook) );
227227
for(i=0; i<db.nCommitHook; i++){
228228
assert( x!=db.aHook[i].xHook );
229229
if( db.aHook[i].sequence>sequence ){
230230
int s = sequence;
231231
int (*xS)(void) = x;
@@ -769,15 +769,15 @@
769769
){
770770
if( !g.db ){
771771
assert( g.zMainDbType==0 );
772772
g.db = db_open(zDbName);
773773
g.zMainDbType = zLabel;
774
- if ( pWasAttached ) *pWasAttached = 0;
774
+ if( pWasAttached ) *pWasAttached = 0;
775775
}else{
776776
assert( g.zMainDbType!=0 );
777777
db_attach(zDbName, zLabel);
778
- if ( pWasAttached ) *pWasAttached = 1;
778
+ if( pWasAttached ) *pWasAttached = 1;
779779
}
780780
}
781781
782782
/*
783783
** Open the user database in "~/.fossil". Create the database anew if
@@ -791,13 +791,13 @@
791791
** connection so that we can join between the various databases. In that
792792
** case, invoke this routine with useAttach as 1.
793793
*/
794794
void db_open_config(int useAttach){
795795
char *zDbName;
796
- const char *zHome;
797
- if( g.configOpen ) return;
798
-#if defined(_WIN32)
796
+ char *zHome;
797
+ if( g.zConfigDbName ) return;
798
+#if defined(_WIN32) || defined(__CYGWIN__)
799799
zHome = fossil_getenv("LOCALAPPDATA");
800800
if( zHome==0 ){
801801
zHome = fossil_getenv("APPDATA");
802802
if( zHome==0 ){
803803
char *zDrive = fossil_getenv("HOMEDRIVE");
@@ -818,36 +818,37 @@
818818
}
819819
#endif
820820
if( file_isdir(zHome)!=1 ){
821821
fossil_fatal("invalid home directory: %s", zHome);
822822
}
823
-#ifndef _WIN32
824
- if( access(zHome, W_OK) ){
825
- fossil_fatal("home directory %s must be writeable", zHome);
826
- }
827
-#endif
828
- g.zHome = mprintf("%/", zHome);
829
-#if defined(_WIN32)
823
+#if defined(_WIN32) || defined(__CYGWIN__)
830824
/* . filenames give some window systems problems and many apps problems */
831825
zDbName = mprintf("%//_fossil", zHome);
832826
#else
827
+ if( file_access(zHome, W_OK) ){
828
+ fossil_fatal("home directory %s must be writeable", zHome);
829
+ }
833830
zDbName = mprintf("%s/.fossil", zHome);
834831
#endif
835832
if( file_size(zDbName)<1024*3 ){
836833
db_init_database(zDbName, zConfigSchema, (char*)0);
837834
}
835
+#if defined(_WIN32) || defined(__CYGWIN__)
836
+ if( file_access(zDbName, W_OK) ){
837
+ fossil_fatal("configuration file %s must be writeable", zDbName);
838
+ }
839
+#endif
838840
if( useAttach ){
839841
db_open_or_attach(zDbName, "configdb", &g.useAttach);
840842
g.dbConfig = 0;
841843
g.zConfigDbType = 0;
842844
}else{
843845
g.useAttach = 0;
844846
g.dbConfig = db_open(zDbName);
845847
g.zConfigDbType = "configdb";
846848
}
847
- g.configOpen = 1;
848
- free(zDbName);
849
+ g.zConfigDbName = zDbName;
849850
}
850851
851852
852853
/*
853854
** Returns TRUE if zTable exists in the local database but lacks column
@@ -882,10 +883,11 @@
882883
lsize = file_size(zDbName);
883884
if( lsize%1024!=0 || lsize<4096 ) return 0;
884885
db_open_or_attach(zDbName, "localdb", 0);
885886
zVFileDef = db_text(0, "SELECT sql FROM %s.sqlite_master"
886887
" WHERE name=='vfile'", db_name("localdb"));
888
+ if( zVFileDef==0 ) return 0;
887889
888890
/* If the "isexe" column is missing from the vfile table, then
889891
** add it now. This code added on 2010-03-06. After all users have
890892
** upgraded, this code can be safely deleted.
891893
*/
@@ -918,32 +920,31 @@
918920
** that contains a valid repository database.
919921
**
920922
** For legacy, also look for ".fos". The use of ".fos" is deprecated
921923
** since "fos" has negative connotations in Hungarian, we are told.
922924
**
923
-** If no valid _FOSSIL_ or .fos file is found, we move up one level and
925
+** If no valid _FOSSIL_ or .fslckout file is found, we move up one level and
924926
** try again. Once the file is found, the g.zLocalRoot variable is set
925927
** to the root of the repository tree and this routine returns 1. If
926928
** no database is found, then this routine return 0.
927929
**
928930
** This routine always opens the user database regardless of whether or
929
-** not the repository database is found. If the _FOSSIL_ or .fos file
931
+** not the repository database is found. If the _FOSSIL_ or .fslckout file
930932
** is found, it is attached to the open database connection too.
931933
*/
932934
int db_open_local(void){
933935
int i, n;
934936
char zPwd[2000];
935
- static const char *const aDbName[] = { "/_FOSSIL_", "/.fslckout", "/.fos" };
937
+ static const char aDbName[][10] = { "_FOSSIL_", ".fslckout", ".fos" };
936938
937939
if( g.localOpen) return 1;
938940
file_getcwd(zPwd, sizeof(zPwd)-20);
939941
n = strlen(zPwd);
940942
if( n==1 && zPwd[0]=='/' ) zPwd[0] = '.';
941943
while( n>0 ){
942
- if( file_access(zPwd, W_OK) ) break;
943
- for(i=0; i<sizeof(aDbName)/sizeof(aDbName[0]); i++){
944
- sqlite3_snprintf(sizeof(zPwd)-n, &zPwd[n], "%s", aDbName[i]);
944
+ for(i=0; i<count(aDbName); i++){
945
+ sqlite3_snprintf(sizeof(zPwd)-n, &zPwd[n], "/%s", aDbName[i]);
945946
if( isValidLocalDb(zPwd) ){
946947
/* Found a valid checkout database file */
947948
zPwd[n] = 0;
948949
while( n>1 && zPwd[n-1]=='/' ){
949950
n--;
@@ -1202,11 +1203,11 @@
12021203
fossil_warning("unfinalized SQL statement: [%s]", sqlite3_sql(pStmt));
12031204
}
12041205
}
12051206
g.repositoryOpen = 0;
12061207
g.localOpen = 0;
1207
- g.configOpen = 0;
1208
+ g.zConfigDbName = NULL;
12081209
sqlite3_wal_checkpoint(g.db, 0);
12091210
sqlite3_close(g.db);
12101211
g.db = 0;
12111212
g.zMainDbType = 0;
12121213
if( g.dbConfig ){
@@ -1262,17 +1263,17 @@
12621263
"UPDATE user SET cap='s', pw=lower(hex(randomblob(3)))"
12631264
" WHERE login=%Q", zUser
12641265
);
12651266
if( !setupUserOnly ){
12661267
db_multi_exec(
1267
- "INSERT INTO user(login,pw,cap,info)"
1268
+ "INSERT OR IGNORE INTO user(login,pw,cap,info)"
12681269
" VALUES('anonymous',hex(randomblob(8)),'hmncz','Anon');"
1269
- "INSERT INTO user(login,pw,cap,info)"
1270
+ "INSERT OR IGNORE INTO user(login,pw,cap,info)"
12701271
" VALUES('nobody','','gjor','Nobody');"
1271
- "INSERT INTO user(login,pw,cap,info)"
1272
+ "INSERT OR IGNORE INTO user(login,pw,cap,info)"
12721273
" VALUES('developer','','dei','Dev');"
1273
- "INSERT INTO user(login,pw,cap,info)"
1274
+ "INSERT OR IGNORE INTO user(login,pw,cap,info)"
12741275
" VALUES('reader','','kptw','Reader');"
12751276
);
12761277
}
12771278
}
12781279
@@ -1626,19 +1627,19 @@
16261627
** Return true if the string zVal represents "true" (or "false").
16271628
*/
16281629
int is_truth(const char *zVal){
16291630
static const char *const azOn[] = { "on", "yes", "true", "1" };
16301631
int i;
1631
- for(i=0; i<sizeof(azOn)/sizeof(azOn[0]); i++){
1632
+ for(i=0; i<count(azOn); i++){
16321633
if( fossil_stricmp(zVal,azOn[i])==0 ) return 1;
16331634
}
16341635
return 0;
16351636
}
16361637
int is_false(const char *zVal){
16371638
static const char *const azOff[] = { "off", "no", "false", "0" };
16381639
int i;
1639
- for(i=0; i<sizeof(azOff)/sizeof(azOff[0]); i++){
1640
+ for(i=0; i<count(azOff); i++){
16401641
if( fossil_stricmp(zVal,azOff[i])==0 ) return 1;
16411642
}
16421643
return 0;
16431644
}
16441645
@@ -1765,17 +1766,18 @@
17651766
}
17661767
}
17671768
if( g.repositoryOpen ){
17681769
z = db_text(0, "SELECT value FROM config WHERE name=%Q", zName);
17691770
}
1770
- if( z==0 && g.configOpen ){
1771
+ if( z==0 && g.zConfigDbName ){
17711772
db_swap_connections();
17721773
z = db_text(0, "SELECT value FROM global_config WHERE name=%Q", zName);
17731774
db_swap_connections();
17741775
}
17751776
if( ctrlSetting!=0 && ctrlSetting->versionable && g.localOpen ){
1776
- /* This is a versionable setting, try and get the info from a checked out file */
1777
+ /* This is a versionable setting, try and get the info from a
1778
+ ** checked out file */
17771779
z = db_get_do_versionable(zName, z);
17781780
}
17791781
if( z==0 ){
17801782
z = zDefault;
17811783
}
@@ -1811,11 +1813,11 @@
18111813
}
18121814
db_end_transaction(0);
18131815
}
18141816
int db_is_global(const char *zName){
18151817
int rc = 0;
1816
- if( g.configOpen ){
1818
+ if( g.zConfigDbName ){
18171819
db_swap_connections();
18181820
rc = db_exists("SELECT 1 FROM global_config WHERE name=%Q", zName);
18191821
db_swap_connections();
18201822
}
18211823
return rc;
@@ -1832,11 +1834,11 @@
18321834
}
18331835
db_finalize(&q);
18341836
}else{
18351837
rc = SQLITE_DONE;
18361838
}
1837
- if( rc==SQLITE_DONE && g.configOpen ){
1839
+ if( rc==SQLITE_DONE && g.zConfigDbName ){
18381840
db_swap_connections();
18391841
v = db_int(dflt, "SELECT value FROM global_config WHERE name=%Q", zName);
18401842
db_swap_connections();
18411843
}
18421844
return v;
@@ -1872,10 +1874,31 @@
18721874
return db_int(dflt, "SELECT value FROM vvar WHERE name=%Q", zName);
18731875
}
18741876
void db_lset_int(const char *zName, int value){
18751877
db_multi_exec("REPLACE INTO vvar(name,value) VALUES(%Q,%d)", zName, value);
18761878
}
1879
+
1880
+/*
1881
+** Returns non-0 if the database (which must be open) table identified
1882
+** by zTableName has a column named zColName (case-sensitive), else
1883
+** returns 0.
1884
+*/
1885
+int db_table_has_column( char const *zTableName, char const *zColName ){
1886
+ Stmt q = empty_Stmt;
1887
+ int rc = 0;
1888
+ db_prepare( &q, "PRAGMA table_info(%Q)", zTableName );
1889
+ while(SQLITE_ROW == db_step(&q)){
1890
+ /* Columns: (cid, name, type, notnull, dflt_value, pk) */
1891
+ char const * zCol = db_column_text(&q, 1);
1892
+ if(0==fossil_strcmp(zColName, zCol)){
1893
+ rc = 1;
1894
+ break;
1895
+ }
1896
+ }
1897
+ db_finalize(&q);
1898
+ return rc;
1899
+}
18771900
18781901
/*
18791902
** Record the name of a local repository in the global_config() database.
18801903
** The repository filename %s is recorded as an entry with a "name" field
18811904
** of the following form:
@@ -1958,16 +1981,20 @@
19581981
if( !allowNested && db_open_local() ){
19591982
fossil_panic("already within an open tree rooted at %s", g.zLocalRoot);
19601983
}
19611984
file_canonical_name(g.argv[2], &path, 0);
19621985
db_open_repository(blob_str(&path));
1963
-#if defined(_WIN32)
1986
+#if defined(_WIN32) || defined(__CYGWIN__)
19641987
# define LOCALDB_NAME "./_FOSSIL_"
19651988
#else
19661989
# define LOCALDB_NAME "./.fslckout"
19671990
#endif
1968
- db_init_database(LOCALDB_NAME, zLocalSchema, (char*)0);
1991
+ db_init_database(LOCALDB_NAME, zLocalSchema,
1992
+#ifdef FOSSIL_LOCAL_WAL
1993
+ "COMMIT; PRAGMA journal_mode=WAL; BEGIN;",
1994
+#endif
1995
+ (char*)0);
19691996
db_delete_on_failure(LOCALDB_NAME);
19701997
db_open_local();
19711998
db_lset("repository", g.argv[2]);
19721999
db_record_repository_filename(blob_str(&path));
19732000
vid = db_int(0, "SELECT pid FROM plink y"
@@ -1996,11 +2023,14 @@
19962023
}
19972024
19982025
/*
19992026
** Print the value of a setting named zName
20002027
*/
2001
-static void print_setting(const struct stControlSettings *ctrlSetting, int localOpen){
2028
+static void print_setting(
2029
+ const struct stControlSettings *ctrlSetting,
2030
+ int localOpen
2031
+){
20022032
Stmt q;
20032033
if( g.repositoryOpen ){
20042034
db_prepare(&q,
20052035
"SELECT '(local)', value FROM config WHERE name=%Q"
20062036
" UNION ALL "
@@ -2021,13 +2051,15 @@
20212051
}
20222052
if( ctrlSetting->versionable && localOpen ){
20232053
/* Check to see if this is overridden by a versionable settings file */
20242054
Blob versionedPathname;
20252055
blob_zero(&versionedPathname);
2026
- blob_appendf(&versionedPathname, "%s/.fossil-settings/%s", g.zLocalRoot, ctrlSetting->name);
2056
+ blob_appendf(&versionedPathname, "%s/.fossil-settings/%s",
2057
+ g.zLocalRoot, ctrlSetting->name);
20272058
if( file_size(blob_str(&versionedPathname))>=0 ){
2028
- fossil_print(" (overridden by contents of file .fossil-settings/%s)\n", ctrlSetting->name);
2059
+ fossil_print(" (overridden by contents of file .fossil-settings/%s)\n",
2060
+ ctrlSetting->name);
20292061
}
20302062
}
20312063
db_finalize(&q);
20322064
}
20332065
20342066
--- src/db.c
+++ src/db.c
@@ -221,11 +221,11 @@
221 ** rolls back rather than commit. It is the responsibility of the
222 ** hooks themselves to issue any error messages.
223 */
224 void db_commit_hook(int (*x)(void), int sequence){
225 int i;
226 assert( db.nCommitHook < sizeof(db.aHook)/sizeof(db.aHook[1]) );
227 for(i=0; i<db.nCommitHook; i++){
228 assert( x!=db.aHook[i].xHook );
229 if( db.aHook[i].sequence>sequence ){
230 int s = sequence;
231 int (*xS)(void) = x;
@@ -769,15 +769,15 @@
769 ){
770 if( !g.db ){
771 assert( g.zMainDbType==0 );
772 g.db = db_open(zDbName);
773 g.zMainDbType = zLabel;
774 if ( pWasAttached ) *pWasAttached = 0;
775 }else{
776 assert( g.zMainDbType!=0 );
777 db_attach(zDbName, zLabel);
778 if ( pWasAttached ) *pWasAttached = 1;
779 }
780 }
781
782 /*
783 ** Open the user database in "~/.fossil". Create the database anew if
@@ -791,13 +791,13 @@
791 ** connection so that we can join between the various databases. In that
792 ** case, invoke this routine with useAttach as 1.
793 */
794 void db_open_config(int useAttach){
795 char *zDbName;
796 const char *zHome;
797 if( g.configOpen ) return;
798 #if defined(_WIN32)
799 zHome = fossil_getenv("LOCALAPPDATA");
800 if( zHome==0 ){
801 zHome = fossil_getenv("APPDATA");
802 if( zHome==0 ){
803 char *zDrive = fossil_getenv("HOMEDRIVE");
@@ -818,36 +818,37 @@
818 }
819 #endif
820 if( file_isdir(zHome)!=1 ){
821 fossil_fatal("invalid home directory: %s", zHome);
822 }
823 #ifndef _WIN32
824 if( access(zHome, W_OK) ){
825 fossil_fatal("home directory %s must be writeable", zHome);
826 }
827 #endif
828 g.zHome = mprintf("%/", zHome);
829 #if defined(_WIN32)
830 /* . filenames give some window systems problems and many apps problems */
831 zDbName = mprintf("%//_fossil", zHome);
832 #else
 
 
 
833 zDbName = mprintf("%s/.fossil", zHome);
834 #endif
835 if( file_size(zDbName)<1024*3 ){
836 db_init_database(zDbName, zConfigSchema, (char*)0);
837 }
 
 
 
 
 
838 if( useAttach ){
839 db_open_or_attach(zDbName, "configdb", &g.useAttach);
840 g.dbConfig = 0;
841 g.zConfigDbType = 0;
842 }else{
843 g.useAttach = 0;
844 g.dbConfig = db_open(zDbName);
845 g.zConfigDbType = "configdb";
846 }
847 g.configOpen = 1;
848 free(zDbName);
849 }
850
851
852 /*
853 ** Returns TRUE if zTable exists in the local database but lacks column
@@ -882,10 +883,11 @@
882 lsize = file_size(zDbName);
883 if( lsize%1024!=0 || lsize<4096 ) return 0;
884 db_open_or_attach(zDbName, "localdb", 0);
885 zVFileDef = db_text(0, "SELECT sql FROM %s.sqlite_master"
886 " WHERE name=='vfile'", db_name("localdb"));
 
887
888 /* If the "isexe" column is missing from the vfile table, then
889 ** add it now. This code added on 2010-03-06. After all users have
890 ** upgraded, this code can be safely deleted.
891 */
@@ -918,32 +920,31 @@
918 ** that contains a valid repository database.
919 **
920 ** For legacy, also look for ".fos". The use of ".fos" is deprecated
921 ** since "fos" has negative connotations in Hungarian, we are told.
922 **
923 ** If no valid _FOSSIL_ or .fos file is found, we move up one level and
924 ** try again. Once the file is found, the g.zLocalRoot variable is set
925 ** to the root of the repository tree and this routine returns 1. If
926 ** no database is found, then this routine return 0.
927 **
928 ** This routine always opens the user database regardless of whether or
929 ** not the repository database is found. If the _FOSSIL_ or .fos file
930 ** is found, it is attached to the open database connection too.
931 */
932 int db_open_local(void){
933 int i, n;
934 char zPwd[2000];
935 static const char *const aDbName[] = { "/_FOSSIL_", "/.fslckout", "/.fos" };
936
937 if( g.localOpen) return 1;
938 file_getcwd(zPwd, sizeof(zPwd)-20);
939 n = strlen(zPwd);
940 if( n==1 && zPwd[0]=='/' ) zPwd[0] = '.';
941 while( n>0 ){
942 if( file_access(zPwd, W_OK) ) break;
943 for(i=0; i<sizeof(aDbName)/sizeof(aDbName[0]); i++){
944 sqlite3_snprintf(sizeof(zPwd)-n, &zPwd[n], "%s", aDbName[i]);
945 if( isValidLocalDb(zPwd) ){
946 /* Found a valid checkout database file */
947 zPwd[n] = 0;
948 while( n>1 && zPwd[n-1]=='/' ){
949 n--;
@@ -1202,11 +1203,11 @@
1202 fossil_warning("unfinalized SQL statement: [%s]", sqlite3_sql(pStmt));
1203 }
1204 }
1205 g.repositoryOpen = 0;
1206 g.localOpen = 0;
1207 g.configOpen = 0;
1208 sqlite3_wal_checkpoint(g.db, 0);
1209 sqlite3_close(g.db);
1210 g.db = 0;
1211 g.zMainDbType = 0;
1212 if( g.dbConfig ){
@@ -1262,17 +1263,17 @@
1262 "UPDATE user SET cap='s', pw=lower(hex(randomblob(3)))"
1263 " WHERE login=%Q", zUser
1264 );
1265 if( !setupUserOnly ){
1266 db_multi_exec(
1267 "INSERT INTO user(login,pw,cap,info)"
1268 " VALUES('anonymous',hex(randomblob(8)),'hmncz','Anon');"
1269 "INSERT INTO user(login,pw,cap,info)"
1270 " VALUES('nobody','','gjor','Nobody');"
1271 "INSERT INTO user(login,pw,cap,info)"
1272 " VALUES('developer','','dei','Dev');"
1273 "INSERT INTO user(login,pw,cap,info)"
1274 " VALUES('reader','','kptw','Reader');"
1275 );
1276 }
1277 }
1278
@@ -1626,19 +1627,19 @@
1626 ** Return true if the string zVal represents "true" (or "false").
1627 */
1628 int is_truth(const char *zVal){
1629 static const char *const azOn[] = { "on", "yes", "true", "1" };
1630 int i;
1631 for(i=0; i<sizeof(azOn)/sizeof(azOn[0]); i++){
1632 if( fossil_stricmp(zVal,azOn[i])==0 ) return 1;
1633 }
1634 return 0;
1635 }
1636 int is_false(const char *zVal){
1637 static const char *const azOff[] = { "off", "no", "false", "0" };
1638 int i;
1639 for(i=0; i<sizeof(azOff)/sizeof(azOff[0]); i++){
1640 if( fossil_stricmp(zVal,azOff[i])==0 ) return 1;
1641 }
1642 return 0;
1643 }
1644
@@ -1765,17 +1766,18 @@
1765 }
1766 }
1767 if( g.repositoryOpen ){
1768 z = db_text(0, "SELECT value FROM config WHERE name=%Q", zName);
1769 }
1770 if( z==0 && g.configOpen ){
1771 db_swap_connections();
1772 z = db_text(0, "SELECT value FROM global_config WHERE name=%Q", zName);
1773 db_swap_connections();
1774 }
1775 if( ctrlSetting!=0 && ctrlSetting->versionable && g.localOpen ){
1776 /* This is a versionable setting, try and get the info from a checked out file */
 
1777 z = db_get_do_versionable(zName, z);
1778 }
1779 if( z==0 ){
1780 z = zDefault;
1781 }
@@ -1811,11 +1813,11 @@
1811 }
1812 db_end_transaction(0);
1813 }
1814 int db_is_global(const char *zName){
1815 int rc = 0;
1816 if( g.configOpen ){
1817 db_swap_connections();
1818 rc = db_exists("SELECT 1 FROM global_config WHERE name=%Q", zName);
1819 db_swap_connections();
1820 }
1821 return rc;
@@ -1832,11 +1834,11 @@
1832 }
1833 db_finalize(&q);
1834 }else{
1835 rc = SQLITE_DONE;
1836 }
1837 if( rc==SQLITE_DONE && g.configOpen ){
1838 db_swap_connections();
1839 v = db_int(dflt, "SELECT value FROM global_config WHERE name=%Q", zName);
1840 db_swap_connections();
1841 }
1842 return v;
@@ -1872,10 +1874,31 @@
1872 return db_int(dflt, "SELECT value FROM vvar WHERE name=%Q", zName);
1873 }
1874 void db_lset_int(const char *zName, int value){
1875 db_multi_exec("REPLACE INTO vvar(name,value) VALUES(%Q,%d)", zName, value);
1876 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1877
1878 /*
1879 ** Record the name of a local repository in the global_config() database.
1880 ** The repository filename %s is recorded as an entry with a "name" field
1881 ** of the following form:
@@ -1958,16 +1981,20 @@
1958 if( !allowNested && db_open_local() ){
1959 fossil_panic("already within an open tree rooted at %s", g.zLocalRoot);
1960 }
1961 file_canonical_name(g.argv[2], &path, 0);
1962 db_open_repository(blob_str(&path));
1963 #if defined(_WIN32)
1964 # define LOCALDB_NAME "./_FOSSIL_"
1965 #else
1966 # define LOCALDB_NAME "./.fslckout"
1967 #endif
1968 db_init_database(LOCALDB_NAME, zLocalSchema, (char*)0);
 
 
 
 
1969 db_delete_on_failure(LOCALDB_NAME);
1970 db_open_local();
1971 db_lset("repository", g.argv[2]);
1972 db_record_repository_filename(blob_str(&path));
1973 vid = db_int(0, "SELECT pid FROM plink y"
@@ -1996,11 +2023,14 @@
1996 }
1997
1998 /*
1999 ** Print the value of a setting named zName
2000 */
2001 static void print_setting(const struct stControlSettings *ctrlSetting, int localOpen){
 
 
 
2002 Stmt q;
2003 if( g.repositoryOpen ){
2004 db_prepare(&q,
2005 "SELECT '(local)', value FROM config WHERE name=%Q"
2006 " UNION ALL "
@@ -2021,13 +2051,15 @@
2021 }
2022 if( ctrlSetting->versionable && localOpen ){
2023 /* Check to see if this is overridden by a versionable settings file */
2024 Blob versionedPathname;
2025 blob_zero(&versionedPathname);
2026 blob_appendf(&versionedPathname, "%s/.fossil-settings/%s", g.zLocalRoot, ctrlSetting->name);
 
2027 if( file_size(blob_str(&versionedPathname))>=0 ){
2028 fossil_print(" (overridden by contents of file .fossil-settings/%s)\n", ctrlSetting->name);
 
2029 }
2030 }
2031 db_finalize(&q);
2032 }
2033
2034
--- src/db.c
+++ src/db.c
@@ -221,11 +221,11 @@
221 ** rolls back rather than commit. It is the responsibility of the
222 ** hooks themselves to issue any error messages.
223 */
224 void db_commit_hook(int (*x)(void), int sequence){
225 int i;
226 assert( db.nCommitHook < count(db.aHook) );
227 for(i=0; i<db.nCommitHook; i++){
228 assert( x!=db.aHook[i].xHook );
229 if( db.aHook[i].sequence>sequence ){
230 int s = sequence;
231 int (*xS)(void) = x;
@@ -769,15 +769,15 @@
769 ){
770 if( !g.db ){
771 assert( g.zMainDbType==0 );
772 g.db = db_open(zDbName);
773 g.zMainDbType = zLabel;
774 if( pWasAttached ) *pWasAttached = 0;
775 }else{
776 assert( g.zMainDbType!=0 );
777 db_attach(zDbName, zLabel);
778 if( pWasAttached ) *pWasAttached = 1;
779 }
780 }
781
782 /*
783 ** Open the user database in "~/.fossil". Create the database anew if
@@ -791,13 +791,13 @@
791 ** connection so that we can join between the various databases. In that
792 ** case, invoke this routine with useAttach as 1.
793 */
794 void db_open_config(int useAttach){
795 char *zDbName;
796 char *zHome;
797 if( g.zConfigDbName ) return;
798 #if defined(_WIN32) || defined(__CYGWIN__)
799 zHome = fossil_getenv("LOCALAPPDATA");
800 if( zHome==0 ){
801 zHome = fossil_getenv("APPDATA");
802 if( zHome==0 ){
803 char *zDrive = fossil_getenv("HOMEDRIVE");
@@ -818,36 +818,37 @@
818 }
819 #endif
820 if( file_isdir(zHome)!=1 ){
821 fossil_fatal("invalid home directory: %s", zHome);
822 }
823 #if defined(_WIN32) || defined(__CYGWIN__)
 
 
 
 
 
 
824 /* . filenames give some window systems problems and many apps problems */
825 zDbName = mprintf("%//_fossil", zHome);
826 #else
827 if( file_access(zHome, W_OK) ){
828 fossil_fatal("home directory %s must be writeable", zHome);
829 }
830 zDbName = mprintf("%s/.fossil", zHome);
831 #endif
832 if( file_size(zDbName)<1024*3 ){
833 db_init_database(zDbName, zConfigSchema, (char*)0);
834 }
835 #if defined(_WIN32) || defined(__CYGWIN__)
836 if( file_access(zDbName, W_OK) ){
837 fossil_fatal("configuration file %s must be writeable", zDbName);
838 }
839 #endif
840 if( useAttach ){
841 db_open_or_attach(zDbName, "configdb", &g.useAttach);
842 g.dbConfig = 0;
843 g.zConfigDbType = 0;
844 }else{
845 g.useAttach = 0;
846 g.dbConfig = db_open(zDbName);
847 g.zConfigDbType = "configdb";
848 }
849 g.zConfigDbName = zDbName;
 
850 }
851
852
853 /*
854 ** Returns TRUE if zTable exists in the local database but lacks column
@@ -882,10 +883,11 @@
883 lsize = file_size(zDbName);
884 if( lsize%1024!=0 || lsize<4096 ) return 0;
885 db_open_or_attach(zDbName, "localdb", 0);
886 zVFileDef = db_text(0, "SELECT sql FROM %s.sqlite_master"
887 " WHERE name=='vfile'", db_name("localdb"));
888 if( zVFileDef==0 ) return 0;
889
890 /* If the "isexe" column is missing from the vfile table, then
891 ** add it now. This code added on 2010-03-06. After all users have
892 ** upgraded, this code can be safely deleted.
893 */
@@ -918,32 +920,31 @@
920 ** that contains a valid repository database.
921 **
922 ** For legacy, also look for ".fos". The use of ".fos" is deprecated
923 ** since "fos" has negative connotations in Hungarian, we are told.
924 **
925 ** If no valid _FOSSIL_ or .fslckout file is found, we move up one level and
926 ** try again. Once the file is found, the g.zLocalRoot variable is set
927 ** to the root of the repository tree and this routine returns 1. If
928 ** no database is found, then this routine return 0.
929 **
930 ** This routine always opens the user database regardless of whether or
931 ** not the repository database is found. If the _FOSSIL_ or .fslckout file
932 ** is found, it is attached to the open database connection too.
933 */
934 int db_open_local(void){
935 int i, n;
936 char zPwd[2000];
937 static const char aDbName[][10] = { "_FOSSIL_", ".fslckout", ".fos" };
938
939 if( g.localOpen) return 1;
940 file_getcwd(zPwd, sizeof(zPwd)-20);
941 n = strlen(zPwd);
942 if( n==1 && zPwd[0]=='/' ) zPwd[0] = '.';
943 while( n>0 ){
944 for(i=0; i<count(aDbName); i++){
945 sqlite3_snprintf(sizeof(zPwd)-n, &zPwd[n], "/%s", aDbName[i]);
 
946 if( isValidLocalDb(zPwd) ){
947 /* Found a valid checkout database file */
948 zPwd[n] = 0;
949 while( n>1 && zPwd[n-1]=='/' ){
950 n--;
@@ -1202,11 +1203,11 @@
1203 fossil_warning("unfinalized SQL statement: [%s]", sqlite3_sql(pStmt));
1204 }
1205 }
1206 g.repositoryOpen = 0;
1207 g.localOpen = 0;
1208 g.zConfigDbName = NULL;
1209 sqlite3_wal_checkpoint(g.db, 0);
1210 sqlite3_close(g.db);
1211 g.db = 0;
1212 g.zMainDbType = 0;
1213 if( g.dbConfig ){
@@ -1262,17 +1263,17 @@
1263 "UPDATE user SET cap='s', pw=lower(hex(randomblob(3)))"
1264 " WHERE login=%Q", zUser
1265 );
1266 if( !setupUserOnly ){
1267 db_multi_exec(
1268 "INSERT OR IGNORE INTO user(login,pw,cap,info)"
1269 " VALUES('anonymous',hex(randomblob(8)),'hmncz','Anon');"
1270 "INSERT OR IGNORE INTO user(login,pw,cap,info)"
1271 " VALUES('nobody','','gjor','Nobody');"
1272 "INSERT OR IGNORE INTO user(login,pw,cap,info)"
1273 " VALUES('developer','','dei','Dev');"
1274 "INSERT OR IGNORE INTO user(login,pw,cap,info)"
1275 " VALUES('reader','','kptw','Reader');"
1276 );
1277 }
1278 }
1279
@@ -1626,19 +1627,19 @@
1627 ** Return true if the string zVal represents "true" (or "false").
1628 */
1629 int is_truth(const char *zVal){
1630 static const char *const azOn[] = { "on", "yes", "true", "1" };
1631 int i;
1632 for(i=0; i<count(azOn); i++){
1633 if( fossil_stricmp(zVal,azOn[i])==0 ) return 1;
1634 }
1635 return 0;
1636 }
1637 int is_false(const char *zVal){
1638 static const char *const azOff[] = { "off", "no", "false", "0" };
1639 int i;
1640 for(i=0; i<count(azOff); i++){
1641 if( fossil_stricmp(zVal,azOff[i])==0 ) return 1;
1642 }
1643 return 0;
1644 }
1645
@@ -1765,17 +1766,18 @@
1766 }
1767 }
1768 if( g.repositoryOpen ){
1769 z = db_text(0, "SELECT value FROM config WHERE name=%Q", zName);
1770 }
1771 if( z==0 && g.zConfigDbName ){
1772 db_swap_connections();
1773 z = db_text(0, "SELECT value FROM global_config WHERE name=%Q", zName);
1774 db_swap_connections();
1775 }
1776 if( ctrlSetting!=0 && ctrlSetting->versionable && g.localOpen ){
1777 /* This is a versionable setting, try and get the info from a
1778 ** checked out file */
1779 z = db_get_do_versionable(zName, z);
1780 }
1781 if( z==0 ){
1782 z = zDefault;
1783 }
@@ -1811,11 +1813,11 @@
1813 }
1814 db_end_transaction(0);
1815 }
1816 int db_is_global(const char *zName){
1817 int rc = 0;
1818 if( g.zConfigDbName ){
1819 db_swap_connections();
1820 rc = db_exists("SELECT 1 FROM global_config WHERE name=%Q", zName);
1821 db_swap_connections();
1822 }
1823 return rc;
@@ -1832,11 +1834,11 @@
1834 }
1835 db_finalize(&q);
1836 }else{
1837 rc = SQLITE_DONE;
1838 }
1839 if( rc==SQLITE_DONE && g.zConfigDbName ){
1840 db_swap_connections();
1841 v = db_int(dflt, "SELECT value FROM global_config WHERE name=%Q", zName);
1842 db_swap_connections();
1843 }
1844 return v;
@@ -1872,10 +1874,31 @@
1874 return db_int(dflt, "SELECT value FROM vvar WHERE name=%Q", zName);
1875 }
1876 void db_lset_int(const char *zName, int value){
1877 db_multi_exec("REPLACE INTO vvar(name,value) VALUES(%Q,%d)", zName, value);
1878 }
1879
1880 /*
1881 ** Returns non-0 if the database (which must be open) table identified
1882 ** by zTableName has a column named zColName (case-sensitive), else
1883 ** returns 0.
1884 */
1885 int db_table_has_column( char const *zTableName, char const *zColName ){
1886 Stmt q = empty_Stmt;
1887 int rc = 0;
1888 db_prepare( &q, "PRAGMA table_info(%Q)", zTableName );
1889 while(SQLITE_ROW == db_step(&q)){
1890 /* Columns: (cid, name, type, notnull, dflt_value, pk) */
1891 char const * zCol = db_column_text(&q, 1);
1892 if(0==fossil_strcmp(zColName, zCol)){
1893 rc = 1;
1894 break;
1895 }
1896 }
1897 db_finalize(&q);
1898 return rc;
1899 }
1900
1901 /*
1902 ** Record the name of a local repository in the global_config() database.
1903 ** The repository filename %s is recorded as an entry with a "name" field
1904 ** of the following form:
@@ -1958,16 +1981,20 @@
1981 if( !allowNested && db_open_local() ){
1982 fossil_panic("already within an open tree rooted at %s", g.zLocalRoot);
1983 }
1984 file_canonical_name(g.argv[2], &path, 0);
1985 db_open_repository(blob_str(&path));
1986 #if defined(_WIN32) || defined(__CYGWIN__)
1987 # define LOCALDB_NAME "./_FOSSIL_"
1988 #else
1989 # define LOCALDB_NAME "./.fslckout"
1990 #endif
1991 db_init_database(LOCALDB_NAME, zLocalSchema,
1992 #ifdef FOSSIL_LOCAL_WAL
1993 "COMMIT; PRAGMA journal_mode=WAL; BEGIN;",
1994 #endif
1995 (char*)0);
1996 db_delete_on_failure(LOCALDB_NAME);
1997 db_open_local();
1998 db_lset("repository", g.argv[2]);
1999 db_record_repository_filename(blob_str(&path));
2000 vid = db_int(0, "SELECT pid FROM plink y"
@@ -1996,11 +2023,14 @@
2023 }
2024
2025 /*
2026 ** Print the value of a setting named zName
2027 */
2028 static void print_setting(
2029 const struct stControlSettings *ctrlSetting,
2030 int localOpen
2031 ){
2032 Stmt q;
2033 if( g.repositoryOpen ){
2034 db_prepare(&q,
2035 "SELECT '(local)', value FROM config WHERE name=%Q"
2036 " UNION ALL "
@@ -2021,13 +2051,15 @@
2051 }
2052 if( ctrlSetting->versionable && localOpen ){
2053 /* Check to see if this is overridden by a versionable settings file */
2054 Blob versionedPathname;
2055 blob_zero(&versionedPathname);
2056 blob_appendf(&versionedPathname, "%s/.fossil-settings/%s",
2057 g.zLocalRoot, ctrlSetting->name);
2058 if( file_size(blob_str(&versionedPathname))>=0 ){
2059 fossil_print(" (overridden by contents of file .fossil-settings/%s)\n",
2060 ctrlSetting->name);
2061 }
2062 }
2063 db_finalize(&q);
2064 }
2065
2066
+69 -37
--- src/db.c
+++ src/db.c
@@ -221,11 +221,11 @@
221221
** rolls back rather than commit. It is the responsibility of the
222222
** hooks themselves to issue any error messages.
223223
*/
224224
void db_commit_hook(int (*x)(void), int sequence){
225225
int i;
226
- assert( db.nCommitHook < sizeof(db.aHook)/sizeof(db.aHook[1]) );
226
+ assert( db.nCommitHook < count(db.aHook) );
227227
for(i=0; i<db.nCommitHook; i++){
228228
assert( x!=db.aHook[i].xHook );
229229
if( db.aHook[i].sequence>sequence ){
230230
int s = sequence;
231231
int (*xS)(void) = x;
@@ -769,15 +769,15 @@
769769
){
770770
if( !g.db ){
771771
assert( g.zMainDbType==0 );
772772
g.db = db_open(zDbName);
773773
g.zMainDbType = zLabel;
774
- if ( pWasAttached ) *pWasAttached = 0;
774
+ if( pWasAttached ) *pWasAttached = 0;
775775
}else{
776776
assert( g.zMainDbType!=0 );
777777
db_attach(zDbName, zLabel);
778
- if ( pWasAttached ) *pWasAttached = 1;
778
+ if( pWasAttached ) *pWasAttached = 1;
779779
}
780780
}
781781
782782
/*
783783
** Open the user database in "~/.fossil". Create the database anew if
@@ -791,13 +791,13 @@
791791
** connection so that we can join between the various databases. In that
792792
** case, invoke this routine with useAttach as 1.
793793
*/
794794
void db_open_config(int useAttach){
795795
char *zDbName;
796
- const char *zHome;
797
- if( g.configOpen ) return;
798
-#if defined(_WIN32)
796
+ char *zHome;
797
+ if( g.zConfigDbName ) return;
798
+#if defined(_WIN32) || defined(__CYGWIN__)
799799
zHome = fossil_getenv("LOCALAPPDATA");
800800
if( zHome==0 ){
801801
zHome = fossil_getenv("APPDATA");
802802
if( zHome==0 ){
803803
char *zDrive = fossil_getenv("HOMEDRIVE");
@@ -818,36 +818,37 @@
818818
}
819819
#endif
820820
if( file_isdir(zHome)!=1 ){
821821
fossil_fatal("invalid home directory: %s", zHome);
822822
}
823
-#ifndef _WIN32
824
- if( access(zHome, W_OK) ){
825
- fossil_fatal("home directory %s must be writeable", zHome);
826
- }
827
-#endif
828
- g.zHome = mprintf("%/", zHome);
829
-#if defined(_WIN32)
823
+#if defined(_WIN32) || defined(__CYGWIN__)
830824
/* . filenames give some window systems problems and many apps problems */
831825
zDbName = mprintf("%//_fossil", zHome);
832826
#else
827
+ if( file_access(zHome, W_OK) ){
828
+ fossil_fatal("home directory %s must be writeable", zHome);
829
+ }
833830
zDbName = mprintf("%s/.fossil", zHome);
834831
#endif
835832
if( file_size(zDbName)<1024*3 ){
836833
db_init_database(zDbName, zConfigSchema, (char*)0);
837834
}
835
+#if defined(_WIN32) || defined(__CYGWIN__)
836
+ if( file_access(zDbName, W_OK) ){
837
+ fossil_fatal("configuration file %s must be writeable", zDbName);
838
+ }
839
+#endif
838840
if( useAttach ){
839841
db_open_or_attach(zDbName, "configdb", &g.useAttach);
840842
g.dbConfig = 0;
841843
g.zConfigDbType = 0;
842844
}else{
843845
g.useAttach = 0;
844846
g.dbConfig = db_open(zDbName);
845847
g.zConfigDbType = "configdb";
846848
}
847
- g.configOpen = 1;
848
- free(zDbName);
849
+ g.zConfigDbName = zDbName;
849850
}
850851
851852
852853
/*
853854
** Returns TRUE if zTable exists in the local database but lacks column
@@ -882,10 +883,11 @@
882883
lsize = file_size(zDbName);
883884
if( lsize%1024!=0 || lsize<4096 ) return 0;
884885
db_open_or_attach(zDbName, "localdb", 0);
885886
zVFileDef = db_text(0, "SELECT sql FROM %s.sqlite_master"
886887
" WHERE name=='vfile'", db_name("localdb"));
888
+ if( zVFileDef==0 ) return 0;
887889
888890
/* If the "isexe" column is missing from the vfile table, then
889891
** add it now. This code added on 2010-03-06. After all users have
890892
** upgraded, this code can be safely deleted.
891893
*/
@@ -918,32 +920,31 @@
918920
** that contains a valid repository database.
919921
**
920922
** For legacy, also look for ".fos". The use of ".fos" is deprecated
921923
** since "fos" has negative connotations in Hungarian, we are told.
922924
**
923
-** If no valid _FOSSIL_ or .fos file is found, we move up one level and
925
+** If no valid _FOSSIL_ or .fslckout file is found, we move up one level and
924926
** try again. Once the file is found, the g.zLocalRoot variable is set
925927
** to the root of the repository tree and this routine returns 1. If
926928
** no database is found, then this routine return 0.
927929
**
928930
** This routine always opens the user database regardless of whether or
929
-** not the repository database is found. If the _FOSSIL_ or .fos file
931
+** not the repository database is found. If the _FOSSIL_ or .fslckout file
930932
** is found, it is attached to the open database connection too.
931933
*/
932934
int db_open_local(void){
933935
int i, n;
934936
char zPwd[2000];
935
- static const char *const aDbName[] = { "/_FOSSIL_", "/.fslckout", "/.fos" };
937
+ static const char aDbName[][10] = { "_FOSSIL_", ".fslckout", ".fos" };
936938
937939
if( g.localOpen) return 1;
938940
file_getcwd(zPwd, sizeof(zPwd)-20);
939941
n = strlen(zPwd);
940942
if( n==1 && zPwd[0]=='/' ) zPwd[0] = '.';
941943
while( n>0 ){
942
- if( file_access(zPwd, W_OK) ) break;
943
- for(i=0; i<sizeof(aDbName)/sizeof(aDbName[0]); i++){
944
- sqlite3_snprintf(sizeof(zPwd)-n, &zPwd[n], "%s", aDbName[i]);
944
+ for(i=0; i<count(aDbName); i++){
945
+ sqlite3_snprintf(sizeof(zPwd)-n, &zPwd[n], "/%s", aDbName[i]);
945946
if( isValidLocalDb(zPwd) ){
946947
/* Found a valid checkout database file */
947948
zPwd[n] = 0;
948949
while( n>1 && zPwd[n-1]=='/' ){
949950
n--;
@@ -1202,11 +1203,11 @@
12021203
fossil_warning("unfinalized SQL statement: [%s]", sqlite3_sql(pStmt));
12031204
}
12041205
}
12051206
g.repositoryOpen = 0;
12061207
g.localOpen = 0;
1207
- g.configOpen = 0;
1208
+ g.zConfigDbName = NULL;
12081209
sqlite3_wal_checkpoint(g.db, 0);
12091210
sqlite3_close(g.db);
12101211
g.db = 0;
12111212
g.zMainDbType = 0;
12121213
if( g.dbConfig ){
@@ -1262,17 +1263,17 @@
12621263
"UPDATE user SET cap='s', pw=lower(hex(randomblob(3)))"
12631264
" WHERE login=%Q", zUser
12641265
);
12651266
if( !setupUserOnly ){
12661267
db_multi_exec(
1267
- "INSERT INTO user(login,pw,cap,info)"
1268
+ "INSERT OR IGNORE INTO user(login,pw,cap,info)"
12681269
" VALUES('anonymous',hex(randomblob(8)),'hmncz','Anon');"
1269
- "INSERT INTO user(login,pw,cap,info)"
1270
+ "INSERT OR IGNORE INTO user(login,pw,cap,info)"
12701271
" VALUES('nobody','','gjor','Nobody');"
1271
- "INSERT INTO user(login,pw,cap,info)"
1272
+ "INSERT OR IGNORE INTO user(login,pw,cap,info)"
12721273
" VALUES('developer','','dei','Dev');"
1273
- "INSERT INTO user(login,pw,cap,info)"
1274
+ "INSERT OR IGNORE INTO user(login,pw,cap,info)"
12741275
" VALUES('reader','','kptw','Reader');"
12751276
);
12761277
}
12771278
}
12781279
@@ -1626,19 +1627,19 @@
16261627
** Return true if the string zVal represents "true" (or "false").
16271628
*/
16281629
int is_truth(const char *zVal){
16291630
static const char *const azOn[] = { "on", "yes", "true", "1" };
16301631
int i;
1631
- for(i=0; i<sizeof(azOn)/sizeof(azOn[0]); i++){
1632
+ for(i=0; i<count(azOn); i++){
16321633
if( fossil_stricmp(zVal,azOn[i])==0 ) return 1;
16331634
}
16341635
return 0;
16351636
}
16361637
int is_false(const char *zVal){
16371638
static const char *const azOff[] = { "off", "no", "false", "0" };
16381639
int i;
1639
- for(i=0; i<sizeof(azOff)/sizeof(azOff[0]); i++){
1640
+ for(i=0; i<count(azOff); i++){
16401641
if( fossil_stricmp(zVal,azOff[i])==0 ) return 1;
16411642
}
16421643
return 0;
16431644
}
16441645
@@ -1765,17 +1766,18 @@
17651766
}
17661767
}
17671768
if( g.repositoryOpen ){
17681769
z = db_text(0, "SELECT value FROM config WHERE name=%Q", zName);
17691770
}
1770
- if( z==0 && g.configOpen ){
1771
+ if( z==0 && g.zConfigDbName ){
17711772
db_swap_connections();
17721773
z = db_text(0, "SELECT value FROM global_config WHERE name=%Q", zName);
17731774
db_swap_connections();
17741775
}
17751776
if( ctrlSetting!=0 && ctrlSetting->versionable && g.localOpen ){
1776
- /* This is a versionable setting, try and get the info from a checked out file */
1777
+ /* This is a versionable setting, try and get the info from a
1778
+ ** checked out file */
17771779
z = db_get_do_versionable(zName, z);
17781780
}
17791781
if( z==0 ){
17801782
z = zDefault;
17811783
}
@@ -1811,11 +1813,11 @@
18111813
}
18121814
db_end_transaction(0);
18131815
}
18141816
int db_is_global(const char *zName){
18151817
int rc = 0;
1816
- if( g.configOpen ){
1818
+ if( g.zConfigDbName ){
18171819
db_swap_connections();
18181820
rc = db_exists("SELECT 1 FROM global_config WHERE name=%Q", zName);
18191821
db_swap_connections();
18201822
}
18211823
return rc;
@@ -1832,11 +1834,11 @@
18321834
}
18331835
db_finalize(&q);
18341836
}else{
18351837
rc = SQLITE_DONE;
18361838
}
1837
- if( rc==SQLITE_DONE && g.configOpen ){
1839
+ if( rc==SQLITE_DONE && g.zConfigDbName ){
18381840
db_swap_connections();
18391841
v = db_int(dflt, "SELECT value FROM global_config WHERE name=%Q", zName);
18401842
db_swap_connections();
18411843
}
18421844
return v;
@@ -1872,10 +1874,31 @@
18721874
return db_int(dflt, "SELECT value FROM vvar WHERE name=%Q", zName);
18731875
}
18741876
void db_lset_int(const char *zName, int value){
18751877
db_multi_exec("REPLACE INTO vvar(name,value) VALUES(%Q,%d)", zName, value);
18761878
}
1879
+
1880
+/*
1881
+** Returns non-0 if the database (which must be open) table identified
1882
+** by zTableName has a column named zColName (case-sensitive), else
1883
+** returns 0.
1884
+*/
1885
+int db_table_has_column( char const *zTableName, char const *zColName ){
1886
+ Stmt q = empty_Stmt;
1887
+ int rc = 0;
1888
+ db_prepare( &q, "PRAGMA table_info(%Q)", zTableName );
1889
+ while(SQLITE_ROW == db_step(&q)){
1890
+ /* Columns: (cid, name, type, notnull, dflt_value, pk) */
1891
+ char const * zCol = db_column_text(&q, 1);
1892
+ if(0==fossil_strcmp(zColName, zCol)){
1893
+ rc = 1;
1894
+ break;
1895
+ }
1896
+ }
1897
+ db_finalize(&q);
1898
+ return rc;
1899
+}
18771900
18781901
/*
18791902
** Record the name of a local repository in the global_config() database.
18801903
** The repository filename %s is recorded as an entry with a "name" field
18811904
** of the following form:
@@ -1958,16 +1981,20 @@
19581981
if( !allowNested && db_open_local() ){
19591982
fossil_panic("already within an open tree rooted at %s", g.zLocalRoot);
19601983
}
19611984
file_canonical_name(g.argv[2], &path, 0);
19621985
db_open_repository(blob_str(&path));
1963
-#if defined(_WIN32)
1986
+#if defined(_WIN32) || defined(__CYGWIN__)
19641987
# define LOCALDB_NAME "./_FOSSIL_"
19651988
#else
19661989
# define LOCALDB_NAME "./.fslckout"
19671990
#endif
1968
- db_init_database(LOCALDB_NAME, zLocalSchema, (char*)0);
1991
+ db_init_database(LOCALDB_NAME, zLocalSchema,
1992
+#ifdef FOSSIL_LOCAL_WAL
1993
+ "COMMIT; PRAGMA journal_mode=WAL; BEGIN;",
1994
+#endif
1995
+ (char*)0);
19691996
db_delete_on_failure(LOCALDB_NAME);
19701997
db_open_local();
19711998
db_lset("repository", g.argv[2]);
19721999
db_record_repository_filename(blob_str(&path));
19732000
vid = db_int(0, "SELECT pid FROM plink y"
@@ -1996,11 +2023,14 @@
19962023
}
19972024
19982025
/*
19992026
** Print the value of a setting named zName
20002027
*/
2001
-static void print_setting(const struct stControlSettings *ctrlSetting, int localOpen){
2028
+static void print_setting(
2029
+ const struct stControlSettings *ctrlSetting,
2030
+ int localOpen
2031
+){
20022032
Stmt q;
20032033
if( g.repositoryOpen ){
20042034
db_prepare(&q,
20052035
"SELECT '(local)', value FROM config WHERE name=%Q"
20062036
" UNION ALL "
@@ -2021,13 +2051,15 @@
20212051
}
20222052
if( ctrlSetting->versionable && localOpen ){
20232053
/* Check to see if this is overridden by a versionable settings file */
20242054
Blob versionedPathname;
20252055
blob_zero(&versionedPathname);
2026
- blob_appendf(&versionedPathname, "%s/.fossil-settings/%s", g.zLocalRoot, ctrlSetting->name);
2056
+ blob_appendf(&versionedPathname, "%s/.fossil-settings/%s",
2057
+ g.zLocalRoot, ctrlSetting->name);
20272058
if( file_size(blob_str(&versionedPathname))>=0 ){
2028
- fossil_print(" (overridden by contents of file .fossil-settings/%s)\n", ctrlSetting->name);
2059
+ fossil_print(" (overridden by contents of file .fossil-settings/%s)\n",
2060
+ ctrlSetting->name);
20292061
}
20302062
}
20312063
db_finalize(&q);
20322064
}
20332065
20342066
--- src/db.c
+++ src/db.c
@@ -221,11 +221,11 @@
221 ** rolls back rather than commit. It is the responsibility of the
222 ** hooks themselves to issue any error messages.
223 */
224 void db_commit_hook(int (*x)(void), int sequence){
225 int i;
226 assert( db.nCommitHook < sizeof(db.aHook)/sizeof(db.aHook[1]) );
227 for(i=0; i<db.nCommitHook; i++){
228 assert( x!=db.aHook[i].xHook );
229 if( db.aHook[i].sequence>sequence ){
230 int s = sequence;
231 int (*xS)(void) = x;
@@ -769,15 +769,15 @@
769 ){
770 if( !g.db ){
771 assert( g.zMainDbType==0 );
772 g.db = db_open(zDbName);
773 g.zMainDbType = zLabel;
774 if ( pWasAttached ) *pWasAttached = 0;
775 }else{
776 assert( g.zMainDbType!=0 );
777 db_attach(zDbName, zLabel);
778 if ( pWasAttached ) *pWasAttached = 1;
779 }
780 }
781
782 /*
783 ** Open the user database in "~/.fossil". Create the database anew if
@@ -791,13 +791,13 @@
791 ** connection so that we can join between the various databases. In that
792 ** case, invoke this routine with useAttach as 1.
793 */
794 void db_open_config(int useAttach){
795 char *zDbName;
796 const char *zHome;
797 if( g.configOpen ) return;
798 #if defined(_WIN32)
799 zHome = fossil_getenv("LOCALAPPDATA");
800 if( zHome==0 ){
801 zHome = fossil_getenv("APPDATA");
802 if( zHome==0 ){
803 char *zDrive = fossil_getenv("HOMEDRIVE");
@@ -818,36 +818,37 @@
818 }
819 #endif
820 if( file_isdir(zHome)!=1 ){
821 fossil_fatal("invalid home directory: %s", zHome);
822 }
823 #ifndef _WIN32
824 if( access(zHome, W_OK) ){
825 fossil_fatal("home directory %s must be writeable", zHome);
826 }
827 #endif
828 g.zHome = mprintf("%/", zHome);
829 #if defined(_WIN32)
830 /* . filenames give some window systems problems and many apps problems */
831 zDbName = mprintf("%//_fossil", zHome);
832 #else
 
 
 
833 zDbName = mprintf("%s/.fossil", zHome);
834 #endif
835 if( file_size(zDbName)<1024*3 ){
836 db_init_database(zDbName, zConfigSchema, (char*)0);
837 }
 
 
 
 
 
838 if( useAttach ){
839 db_open_or_attach(zDbName, "configdb", &g.useAttach);
840 g.dbConfig = 0;
841 g.zConfigDbType = 0;
842 }else{
843 g.useAttach = 0;
844 g.dbConfig = db_open(zDbName);
845 g.zConfigDbType = "configdb";
846 }
847 g.configOpen = 1;
848 free(zDbName);
849 }
850
851
852 /*
853 ** Returns TRUE if zTable exists in the local database but lacks column
@@ -882,10 +883,11 @@
882 lsize = file_size(zDbName);
883 if( lsize%1024!=0 || lsize<4096 ) return 0;
884 db_open_or_attach(zDbName, "localdb", 0);
885 zVFileDef = db_text(0, "SELECT sql FROM %s.sqlite_master"
886 " WHERE name=='vfile'", db_name("localdb"));
 
887
888 /* If the "isexe" column is missing from the vfile table, then
889 ** add it now. This code added on 2010-03-06. After all users have
890 ** upgraded, this code can be safely deleted.
891 */
@@ -918,32 +920,31 @@
918 ** that contains a valid repository database.
919 **
920 ** For legacy, also look for ".fos". The use of ".fos" is deprecated
921 ** since "fos" has negative connotations in Hungarian, we are told.
922 **
923 ** If no valid _FOSSIL_ or .fos file is found, we move up one level and
924 ** try again. Once the file is found, the g.zLocalRoot variable is set
925 ** to the root of the repository tree and this routine returns 1. If
926 ** no database is found, then this routine return 0.
927 **
928 ** This routine always opens the user database regardless of whether or
929 ** not the repository database is found. If the _FOSSIL_ or .fos file
930 ** is found, it is attached to the open database connection too.
931 */
932 int db_open_local(void){
933 int i, n;
934 char zPwd[2000];
935 static const char *const aDbName[] = { "/_FOSSIL_", "/.fslckout", "/.fos" };
936
937 if( g.localOpen) return 1;
938 file_getcwd(zPwd, sizeof(zPwd)-20);
939 n = strlen(zPwd);
940 if( n==1 && zPwd[0]=='/' ) zPwd[0] = '.';
941 while( n>0 ){
942 if( file_access(zPwd, W_OK) ) break;
943 for(i=0; i<sizeof(aDbName)/sizeof(aDbName[0]); i++){
944 sqlite3_snprintf(sizeof(zPwd)-n, &zPwd[n], "%s", aDbName[i]);
945 if( isValidLocalDb(zPwd) ){
946 /* Found a valid checkout database file */
947 zPwd[n] = 0;
948 while( n>1 && zPwd[n-1]=='/' ){
949 n--;
@@ -1202,11 +1203,11 @@
1202 fossil_warning("unfinalized SQL statement: [%s]", sqlite3_sql(pStmt));
1203 }
1204 }
1205 g.repositoryOpen = 0;
1206 g.localOpen = 0;
1207 g.configOpen = 0;
1208 sqlite3_wal_checkpoint(g.db, 0);
1209 sqlite3_close(g.db);
1210 g.db = 0;
1211 g.zMainDbType = 0;
1212 if( g.dbConfig ){
@@ -1262,17 +1263,17 @@
1262 "UPDATE user SET cap='s', pw=lower(hex(randomblob(3)))"
1263 " WHERE login=%Q", zUser
1264 );
1265 if( !setupUserOnly ){
1266 db_multi_exec(
1267 "INSERT INTO user(login,pw,cap,info)"
1268 " VALUES('anonymous',hex(randomblob(8)),'hmncz','Anon');"
1269 "INSERT INTO user(login,pw,cap,info)"
1270 " VALUES('nobody','','gjor','Nobody');"
1271 "INSERT INTO user(login,pw,cap,info)"
1272 " VALUES('developer','','dei','Dev');"
1273 "INSERT INTO user(login,pw,cap,info)"
1274 " VALUES('reader','','kptw','Reader');"
1275 );
1276 }
1277 }
1278
@@ -1626,19 +1627,19 @@
1626 ** Return true if the string zVal represents "true" (or "false").
1627 */
1628 int is_truth(const char *zVal){
1629 static const char *const azOn[] = { "on", "yes", "true", "1" };
1630 int i;
1631 for(i=0; i<sizeof(azOn)/sizeof(azOn[0]); i++){
1632 if( fossil_stricmp(zVal,azOn[i])==0 ) return 1;
1633 }
1634 return 0;
1635 }
1636 int is_false(const char *zVal){
1637 static const char *const azOff[] = { "off", "no", "false", "0" };
1638 int i;
1639 for(i=0; i<sizeof(azOff)/sizeof(azOff[0]); i++){
1640 if( fossil_stricmp(zVal,azOff[i])==0 ) return 1;
1641 }
1642 return 0;
1643 }
1644
@@ -1765,17 +1766,18 @@
1765 }
1766 }
1767 if( g.repositoryOpen ){
1768 z = db_text(0, "SELECT value FROM config WHERE name=%Q", zName);
1769 }
1770 if( z==0 && g.configOpen ){
1771 db_swap_connections();
1772 z = db_text(0, "SELECT value FROM global_config WHERE name=%Q", zName);
1773 db_swap_connections();
1774 }
1775 if( ctrlSetting!=0 && ctrlSetting->versionable && g.localOpen ){
1776 /* This is a versionable setting, try and get the info from a checked out file */
 
1777 z = db_get_do_versionable(zName, z);
1778 }
1779 if( z==0 ){
1780 z = zDefault;
1781 }
@@ -1811,11 +1813,11 @@
1811 }
1812 db_end_transaction(0);
1813 }
1814 int db_is_global(const char *zName){
1815 int rc = 0;
1816 if( g.configOpen ){
1817 db_swap_connections();
1818 rc = db_exists("SELECT 1 FROM global_config WHERE name=%Q", zName);
1819 db_swap_connections();
1820 }
1821 return rc;
@@ -1832,11 +1834,11 @@
1832 }
1833 db_finalize(&q);
1834 }else{
1835 rc = SQLITE_DONE;
1836 }
1837 if( rc==SQLITE_DONE && g.configOpen ){
1838 db_swap_connections();
1839 v = db_int(dflt, "SELECT value FROM global_config WHERE name=%Q", zName);
1840 db_swap_connections();
1841 }
1842 return v;
@@ -1872,10 +1874,31 @@
1872 return db_int(dflt, "SELECT value FROM vvar WHERE name=%Q", zName);
1873 }
1874 void db_lset_int(const char *zName, int value){
1875 db_multi_exec("REPLACE INTO vvar(name,value) VALUES(%Q,%d)", zName, value);
1876 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1877
1878 /*
1879 ** Record the name of a local repository in the global_config() database.
1880 ** The repository filename %s is recorded as an entry with a "name" field
1881 ** of the following form:
@@ -1958,16 +1981,20 @@
1958 if( !allowNested && db_open_local() ){
1959 fossil_panic("already within an open tree rooted at %s", g.zLocalRoot);
1960 }
1961 file_canonical_name(g.argv[2], &path, 0);
1962 db_open_repository(blob_str(&path));
1963 #if defined(_WIN32)
1964 # define LOCALDB_NAME "./_FOSSIL_"
1965 #else
1966 # define LOCALDB_NAME "./.fslckout"
1967 #endif
1968 db_init_database(LOCALDB_NAME, zLocalSchema, (char*)0);
 
 
 
 
1969 db_delete_on_failure(LOCALDB_NAME);
1970 db_open_local();
1971 db_lset("repository", g.argv[2]);
1972 db_record_repository_filename(blob_str(&path));
1973 vid = db_int(0, "SELECT pid FROM plink y"
@@ -1996,11 +2023,14 @@
1996 }
1997
1998 /*
1999 ** Print the value of a setting named zName
2000 */
2001 static void print_setting(const struct stControlSettings *ctrlSetting, int localOpen){
 
 
 
2002 Stmt q;
2003 if( g.repositoryOpen ){
2004 db_prepare(&q,
2005 "SELECT '(local)', value FROM config WHERE name=%Q"
2006 " UNION ALL "
@@ -2021,13 +2051,15 @@
2021 }
2022 if( ctrlSetting->versionable && localOpen ){
2023 /* Check to see if this is overridden by a versionable settings file */
2024 Blob versionedPathname;
2025 blob_zero(&versionedPathname);
2026 blob_appendf(&versionedPathname, "%s/.fossil-settings/%s", g.zLocalRoot, ctrlSetting->name);
 
2027 if( file_size(blob_str(&versionedPathname))>=0 ){
2028 fossil_print(" (overridden by contents of file .fossil-settings/%s)\n", ctrlSetting->name);
 
2029 }
2030 }
2031 db_finalize(&q);
2032 }
2033
2034
--- src/db.c
+++ src/db.c
@@ -221,11 +221,11 @@
221 ** rolls back rather than commit. It is the responsibility of the
222 ** hooks themselves to issue any error messages.
223 */
224 void db_commit_hook(int (*x)(void), int sequence){
225 int i;
226 assert( db.nCommitHook < count(db.aHook) );
227 for(i=0; i<db.nCommitHook; i++){
228 assert( x!=db.aHook[i].xHook );
229 if( db.aHook[i].sequence>sequence ){
230 int s = sequence;
231 int (*xS)(void) = x;
@@ -769,15 +769,15 @@
769 ){
770 if( !g.db ){
771 assert( g.zMainDbType==0 );
772 g.db = db_open(zDbName);
773 g.zMainDbType = zLabel;
774 if( pWasAttached ) *pWasAttached = 0;
775 }else{
776 assert( g.zMainDbType!=0 );
777 db_attach(zDbName, zLabel);
778 if( pWasAttached ) *pWasAttached = 1;
779 }
780 }
781
782 /*
783 ** Open the user database in "~/.fossil". Create the database anew if
@@ -791,13 +791,13 @@
791 ** connection so that we can join between the various databases. In that
792 ** case, invoke this routine with useAttach as 1.
793 */
794 void db_open_config(int useAttach){
795 char *zDbName;
796 char *zHome;
797 if( g.zConfigDbName ) return;
798 #if defined(_WIN32) || defined(__CYGWIN__)
799 zHome = fossil_getenv("LOCALAPPDATA");
800 if( zHome==0 ){
801 zHome = fossil_getenv("APPDATA");
802 if( zHome==0 ){
803 char *zDrive = fossil_getenv("HOMEDRIVE");
@@ -818,36 +818,37 @@
818 }
819 #endif
820 if( file_isdir(zHome)!=1 ){
821 fossil_fatal("invalid home directory: %s", zHome);
822 }
823 #if defined(_WIN32) || defined(__CYGWIN__)
 
 
 
 
 
 
824 /* . filenames give some window systems problems and many apps problems */
825 zDbName = mprintf("%//_fossil", zHome);
826 #else
827 if( file_access(zHome, W_OK) ){
828 fossil_fatal("home directory %s must be writeable", zHome);
829 }
830 zDbName = mprintf("%s/.fossil", zHome);
831 #endif
832 if( file_size(zDbName)<1024*3 ){
833 db_init_database(zDbName, zConfigSchema, (char*)0);
834 }
835 #if defined(_WIN32) || defined(__CYGWIN__)
836 if( file_access(zDbName, W_OK) ){
837 fossil_fatal("configuration file %s must be writeable", zDbName);
838 }
839 #endif
840 if( useAttach ){
841 db_open_or_attach(zDbName, "configdb", &g.useAttach);
842 g.dbConfig = 0;
843 g.zConfigDbType = 0;
844 }else{
845 g.useAttach = 0;
846 g.dbConfig = db_open(zDbName);
847 g.zConfigDbType = "configdb";
848 }
849 g.zConfigDbName = zDbName;
 
850 }
851
852
853 /*
854 ** Returns TRUE if zTable exists in the local database but lacks column
@@ -882,10 +883,11 @@
883 lsize = file_size(zDbName);
884 if( lsize%1024!=0 || lsize<4096 ) return 0;
885 db_open_or_attach(zDbName, "localdb", 0);
886 zVFileDef = db_text(0, "SELECT sql FROM %s.sqlite_master"
887 " WHERE name=='vfile'", db_name("localdb"));
888 if( zVFileDef==0 ) return 0;
889
890 /* If the "isexe" column is missing from the vfile table, then
891 ** add it now. This code added on 2010-03-06. After all users have
892 ** upgraded, this code can be safely deleted.
893 */
@@ -918,32 +920,31 @@
920 ** that contains a valid repository database.
921 **
922 ** For legacy, also look for ".fos". The use of ".fos" is deprecated
923 ** since "fos" has negative connotations in Hungarian, we are told.
924 **
925 ** If no valid _FOSSIL_ or .fslckout file is found, we move up one level and
926 ** try again. Once the file is found, the g.zLocalRoot variable is set
927 ** to the root of the repository tree and this routine returns 1. If
928 ** no database is found, then this routine return 0.
929 **
930 ** This routine always opens the user database regardless of whether or
931 ** not the repository database is found. If the _FOSSIL_ or .fslckout file
932 ** is found, it is attached to the open database connection too.
933 */
934 int db_open_local(void){
935 int i, n;
936 char zPwd[2000];
937 static const char aDbName[][10] = { "_FOSSIL_", ".fslckout", ".fos" };
938
939 if( g.localOpen) return 1;
940 file_getcwd(zPwd, sizeof(zPwd)-20);
941 n = strlen(zPwd);
942 if( n==1 && zPwd[0]=='/' ) zPwd[0] = '.';
943 while( n>0 ){
944 for(i=0; i<count(aDbName); i++){
945 sqlite3_snprintf(sizeof(zPwd)-n, &zPwd[n], "/%s", aDbName[i]);
 
946 if( isValidLocalDb(zPwd) ){
947 /* Found a valid checkout database file */
948 zPwd[n] = 0;
949 while( n>1 && zPwd[n-1]=='/' ){
950 n--;
@@ -1202,11 +1203,11 @@
1203 fossil_warning("unfinalized SQL statement: [%s]", sqlite3_sql(pStmt));
1204 }
1205 }
1206 g.repositoryOpen = 0;
1207 g.localOpen = 0;
1208 g.zConfigDbName = NULL;
1209 sqlite3_wal_checkpoint(g.db, 0);
1210 sqlite3_close(g.db);
1211 g.db = 0;
1212 g.zMainDbType = 0;
1213 if( g.dbConfig ){
@@ -1262,17 +1263,17 @@
1263 "UPDATE user SET cap='s', pw=lower(hex(randomblob(3)))"
1264 " WHERE login=%Q", zUser
1265 );
1266 if( !setupUserOnly ){
1267 db_multi_exec(
1268 "INSERT OR IGNORE INTO user(login,pw,cap,info)"
1269 " VALUES('anonymous',hex(randomblob(8)),'hmncz','Anon');"
1270 "INSERT OR IGNORE INTO user(login,pw,cap,info)"
1271 " VALUES('nobody','','gjor','Nobody');"
1272 "INSERT OR IGNORE INTO user(login,pw,cap,info)"
1273 " VALUES('developer','','dei','Dev');"
1274 "INSERT OR IGNORE INTO user(login,pw,cap,info)"
1275 " VALUES('reader','','kptw','Reader');"
1276 );
1277 }
1278 }
1279
@@ -1626,19 +1627,19 @@
1627 ** Return true if the string zVal represents "true" (or "false").
1628 */
1629 int is_truth(const char *zVal){
1630 static const char *const azOn[] = { "on", "yes", "true", "1" };
1631 int i;
1632 for(i=0; i<count(azOn); i++){
1633 if( fossil_stricmp(zVal,azOn[i])==0 ) return 1;
1634 }
1635 return 0;
1636 }
1637 int is_false(const char *zVal){
1638 static const char *const azOff[] = { "off", "no", "false", "0" };
1639 int i;
1640 for(i=0; i<count(azOff); i++){
1641 if( fossil_stricmp(zVal,azOff[i])==0 ) return 1;
1642 }
1643 return 0;
1644 }
1645
@@ -1765,17 +1766,18 @@
1766 }
1767 }
1768 if( g.repositoryOpen ){
1769 z = db_text(0, "SELECT value FROM config WHERE name=%Q", zName);
1770 }
1771 if( z==0 && g.zConfigDbName ){
1772 db_swap_connections();
1773 z = db_text(0, "SELECT value FROM global_config WHERE name=%Q", zName);
1774 db_swap_connections();
1775 }
1776 if( ctrlSetting!=0 && ctrlSetting->versionable && g.localOpen ){
1777 /* This is a versionable setting, try and get the info from a
1778 ** checked out file */
1779 z = db_get_do_versionable(zName, z);
1780 }
1781 if( z==0 ){
1782 z = zDefault;
1783 }
@@ -1811,11 +1813,11 @@
1813 }
1814 db_end_transaction(0);
1815 }
1816 int db_is_global(const char *zName){
1817 int rc = 0;
1818 if( g.zConfigDbName ){
1819 db_swap_connections();
1820 rc = db_exists("SELECT 1 FROM global_config WHERE name=%Q", zName);
1821 db_swap_connections();
1822 }
1823 return rc;
@@ -1832,11 +1834,11 @@
1834 }
1835 db_finalize(&q);
1836 }else{
1837 rc = SQLITE_DONE;
1838 }
1839 if( rc==SQLITE_DONE && g.zConfigDbName ){
1840 db_swap_connections();
1841 v = db_int(dflt, "SELECT value FROM global_config WHERE name=%Q", zName);
1842 db_swap_connections();
1843 }
1844 return v;
@@ -1872,10 +1874,31 @@
1874 return db_int(dflt, "SELECT value FROM vvar WHERE name=%Q", zName);
1875 }
1876 void db_lset_int(const char *zName, int value){
1877 db_multi_exec("REPLACE INTO vvar(name,value) VALUES(%Q,%d)", zName, value);
1878 }
1879
1880 /*
1881 ** Returns non-0 if the database (which must be open) table identified
1882 ** by zTableName has a column named zColName (case-sensitive), else
1883 ** returns 0.
1884 */
1885 int db_table_has_column( char const *zTableName, char const *zColName ){
1886 Stmt q = empty_Stmt;
1887 int rc = 0;
1888 db_prepare( &q, "PRAGMA table_info(%Q)", zTableName );
1889 while(SQLITE_ROW == db_step(&q)){
1890 /* Columns: (cid, name, type, notnull, dflt_value, pk) */
1891 char const * zCol = db_column_text(&q, 1);
1892 if(0==fossil_strcmp(zColName, zCol)){
1893 rc = 1;
1894 break;
1895 }
1896 }
1897 db_finalize(&q);
1898 return rc;
1899 }
1900
1901 /*
1902 ** Record the name of a local repository in the global_config() database.
1903 ** The repository filename %s is recorded as an entry with a "name" field
1904 ** of the following form:
@@ -1958,16 +1981,20 @@
1981 if( !allowNested && db_open_local() ){
1982 fossil_panic("already within an open tree rooted at %s", g.zLocalRoot);
1983 }
1984 file_canonical_name(g.argv[2], &path, 0);
1985 db_open_repository(blob_str(&path));
1986 #if defined(_WIN32) || defined(__CYGWIN__)
1987 # define LOCALDB_NAME "./_FOSSIL_"
1988 #else
1989 # define LOCALDB_NAME "./.fslckout"
1990 #endif
1991 db_init_database(LOCALDB_NAME, zLocalSchema,
1992 #ifdef FOSSIL_LOCAL_WAL
1993 "COMMIT; PRAGMA journal_mode=WAL; BEGIN;",
1994 #endif
1995 (char*)0);
1996 db_delete_on_failure(LOCALDB_NAME);
1997 db_open_local();
1998 db_lset("repository", g.argv[2]);
1999 db_record_repository_filename(blob_str(&path));
2000 vid = db_int(0, "SELECT pid FROM plink y"
@@ -1996,11 +2023,14 @@
2023 }
2024
2025 /*
2026 ** Print the value of a setting named zName
2027 */
2028 static void print_setting(
2029 const struct stControlSettings *ctrlSetting,
2030 int localOpen
2031 ){
2032 Stmt q;
2033 if( g.repositoryOpen ){
2034 db_prepare(&q,
2035 "SELECT '(local)', value FROM config WHERE name=%Q"
2036 " UNION ALL "
@@ -2021,13 +2051,15 @@
2051 }
2052 if( ctrlSetting->versionable && localOpen ){
2053 /* Check to see if this is overridden by a versionable settings file */
2054 Blob versionedPathname;
2055 blob_zero(&versionedPathname);
2056 blob_appendf(&versionedPathname, "%s/.fossil-settings/%s",
2057 g.zLocalRoot, ctrlSetting->name);
2058 if( file_size(blob_str(&versionedPathname))>=0 ){
2059 fossil_print(" (overridden by contents of file .fossil-settings/%s)\n",
2060 ctrlSetting->name);
2061 }
2062 }
2063 db_finalize(&q);
2064 }
2065
2066
+248 -107
--- src/diff.c
+++ src/diff.c
@@ -39,10 +39,11 @@
3939
#define DIFF_LINENO ((u64)0x20000000) /* Show line numbers */
4040
#define DIFF_WS_WARNING ((u64)0x40000000) /* Warn about whitespace */
4141
#define DIFF_NOOPT (((u64)0x01)<<32) /* Suppress optimizations (debug) */
4242
#define DIFF_INVERT (((u64)0x02)<<32) /* Invert the diff (debug) */
4343
#define DIFF_CONTEXT_EX (((u64)0x04)<<32) /* Use context even if zero */
44
+#define DIFF_NOTTOOBIG (((u64)0x08)<<32) /* Only display if not too big */
4445
4546
/*
4647
** These error messages are shared in multiple locations. They are defined
4748
** here for consistency.
4849
*/
@@ -50,11 +51,35 @@
5051
"cannot compute difference between binary files\n"
5152
5253
#define DIFF_CANNOT_COMPUTE_SYMLINK \
5354
"cannot compute difference between symlink and regular file\n"
5455
55
-#define looks_like_binary(blob) (looks_like_utf8((blob)) == 0)
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) (looks_like_utf8((blob), 0) == 0)
67
+
68
+/*
69
+** Output flags for the looks_like_utf8() and looks_like_utf16() routines used
70
+** to convey status information about the blob content.
71
+*/
72
+#define LOOK_NONE ((int)0x00000000) /* Nothing special was found. */
73
+#define LOOK_NUL ((int)0x00000001) /* One or more NUL chars were found. */
74
+#define LOOK_LONE_CR ((int)0x00000002) /* An unpaired CR char was found. */
75
+#define LOOK_LONE_LF ((int)0x00000004) /* An unpaired LF char was found. */
76
+#define LOOK_CRLF ((int)0x00000008) /* One or more CR/LF pairs were found. */
77
+#define LOOK_LENGTH ((int)0x00000010) /* An over length line was found. */
78
+#define LOOK_ODD ((int)0x00000020) /* An odd number of bytes was found. */
79
+#define LOOK_CR (LOOK_LONE_CR|LOOK_CRLF) /* One or more CR chars were found. */
80
+#define LOOK_LF (LOOK_LONE_LF|LOOK_CRLF) /* One or more LF chars were found. */
5681
#endif /* INTERFACE */
5782
5883
/*
5984
** Maximum length of a line in a text file, in bytes. (2**13 = 8192 bytes)
6085
*/
@@ -180,63 +205,73 @@
180205
/*
181206
** This function attempts to scan each logical line within the blob to
182207
** determine the type of content it appears to contain. Possible return
183208
** values are:
184209
**
185
-** (1) -- The content appears to consist entirely of text, with lines
186
-** delimited by line-feed characters; however, the encoding may
187
-** not be UTF-8.
210
+** (1) -- The content appears to consist entirely of text; however, the
211
+** encoding may not be UTF-8.
188212
**
189213
** (0) -- The content appears to be binary because it contains embedded
190214
** NUL characters or an extremely long line. Since this function
191215
** does not understand UTF-16, it may falsely consider UTF-16 text
192216
** to be binary.
193217
**
194
-** (-1) -- The content appears to consist entirely of text, with lines
195
-** delimited by carriage-return, line-feed pairs; however, the
196
-** encoding may not be UTF-8.
197
-**
198218
************************************ WARNING **********************************
199219
**
200220
** This function does not validate that the blob content is properly formed
201221
** UTF-8. It assumes that all code points are the same size. It does not
202222
** validate any code points. It makes no attempt to detect if any [invalid]
203223
** switches between UTF-8 and other encodings occur.
204224
**
205225
** The only code points that this function cares about are the NUL character,
206226
** carriage-return, and line-feed.
227
+**
228
+** Whether or not this function examines the entire contents of the blob is
229
+** officially unspecified.
207230
**
208231
************************************ WARNING **********************************
209232
*/
210
-int looks_like_utf8(const Blob *pContent){
233
+int looks_like_utf8(const Blob *pContent, int *pFlags){
211234
const char *z = blob_buffer(pContent);
212235
unsigned int n = blob_size(pContent);
213
- int j, c;
214
- int result = 1; /* Assume UTF-8 text with no CR/NL */
236
+ int j, c, result = 1; /* Assume UTF-8 text, prove otherwise */
215237
216
- /* Check individual lines.
217
- */
238
+ if( pFlags ) *pFlags = LOOK_NONE;
218239
if( n==0 ) return result; /* Empty file -> text */
219240
c = *z;
220
- if( c==0 ) return 0; /* Zero byte in a file -> binary */
221
- j = (c!='\n');
222
- while( --n>0 ){
223
- c = *++z; ++j;
224
- if( c==0 ) return 0; /* Zero byte in a file -> binary */
225
- if( c=='\n' ){
226
- int c2 = z[-1];
227
- if( c2=='\r' ){
228
- result = -1; /* Contains CR/NL, continue */
229
- }
230
- if( j>LENGTH_MASK ){
231
- return 0; /* Very long line -> binary */
232
- }
233
- j = 0;
234
- }
235
- }
236
- if( j>LENGTH_MASK ){
237
- return 0; /* Very long line -> binary */
241
+ if( c==0 ){
242
+ if( pFlags ) *pFlags |= LOOK_NUL;
243
+ result = 0; /* NUL character in a file -> binary */
244
+ }
245
+ j = (c!='\n');
246
+ if( !j && pFlags ) *pFlags |= LOOK_LONE_LF;
247
+ while( --n>0 ){
248
+ int c2 = c;
249
+ c = *++z; ++j;
250
+ if( c==0 ){
251
+ if( pFlags ) *pFlags |= LOOK_NUL;
252
+ result = 0; /* NUL character in a file -> binary */
253
+ }
254
+ if( c=='\n' ){
255
+ if( pFlags ){
256
+ *pFlags |= (c2=='\r')?LOOK_CRLF:LOOK_LONE_LF;
257
+ }
258
+ if( j>LENGTH_MASK ){
259
+ if( pFlags ) *pFlags |= LOOK_LENGTH;
260
+ result = 0; /* Very long line -> binary */
261
+ }
262
+ j = 0;
263
+ }else if( c2=='\r' && pFlags ){
264
+ *pFlags |= LOOK_LONE_CR;
265
+ }
266
+ }
267
+ if( c=='\r' && pFlags ){
268
+ *pFlags |= LOOK_LONE_CR;
269
+ }
270
+ if( j>LENGTH_MASK ){
271
+ if( pFlags ) *pFlags |= LOOK_LENGTH;
272
+ result = 0; /* Very long line -> binary */
238273
}
239274
return result; /* No problems seen -> not binary */
240275
}
241276
242277
/*
@@ -270,64 +305,80 @@
270305
/*
271306
** This function attempts to scan each logical line within the blob to
272307
** determine the type of content it appears to contain. Possible return
273308
** values are:
274309
**
275
-** (1) -- The content appears to consist entirely of text, with lines
276
-** delimited by line-feed characters; however, the encoding may
277
-** not be UTF-16.
310
+** (1) -- The content appears to consist entirely of text; however, the
311
+** encoding may not be UTF-16.
278312
**
279313
** (0) -- The content appears to be binary because it contains embedded
280314
** NUL characters or an extremely long line. Since this function
281315
** does not understand UTF-8, it may falsely consider UTF-8 text
282316
** to be binary.
283317
**
284
-** (-1) -- The content appears to consist entirely of text, with lines
285
-** delimited by carriage-return, line-feed pairs; however, the
286
-** encoding may not be UTF-16.
287
-**
288318
************************************ WARNING **********************************
289319
**
290320
** This function does not validate that the blob content is properly formed
291321
** UTF-16. It assumes that all code points are the same size. It does not
292322
** validate any code points. It makes no attempt to detect if any [invalid]
293323
** switches between the UTF-16be and UTF-16le encodings occur.
294324
**
295325
** The only code points that this function cares about are the NUL character,
296326
** carriage-return, and line-feed.
327
+**
328
+** Whether or not this function examines the entire contents of the blob is
329
+** officially unspecified.
297330
**
298331
************************************ WARNING **********************************
299332
*/
300
-int looks_like_utf16(const Blob *pContent){
333
+int looks_like_utf16(const Blob *pContent, int *pFlags){
301334
const WCHAR_T *z = (WCHAR_T *)blob_buffer(pContent);
302335
unsigned int n = blob_size(pContent);
303
- int j, c;
304
- int result = 1; /* Assume UTF-16 text with no CR/NL */
305
-
306
- /* Check individual lines.
307
- */
308
- if( n==0 ) return result; /* Empty file -> text */
309
- if( n%2 ) return 0; /* Odd number of bytes -> binary (or UTF-8) */
310
- c = *z;
311
- if( c==0 ) return 0; /* NUL character in a file -> binary */
312
- j = ((c!=UTF16BE_LF) && (c!=UTF16LE_LF));
313
- while( (n-=2)>0 ){
314
- c = *++z; ++j;
315
- if( c==0 ) return 0; /* NUL character in a file -> binary */
316
- if( c==UTF16BE_LF || c==UTF16LE_LF ){
317
- int c2 = z[-1];
318
- if( c2==UTF16BE_CR || c2==UTF16LE_CR ){
319
- result = -1; /* Contains CR/NL, continue */
320
- }
321
- if( j>UTF16_LENGTH_MASK ){
322
- return 0; /* Very long line -> binary */
323
- }
324
- j = 0;
325
- }
326
- }
327
- if( j>UTF16_LENGTH_MASK ){
328
- return 0; /* Very long line -> binary */
336
+ int j, c, result = 1; /* Assume UTF-16 text, prove otherwise */
337
+
338
+ if( pFlags ) *pFlags = LOOK_NONE;
339
+ if( n==0 ) return result; /* Empty file -> text */
340
+ if( n%sizeof(WCHAR_T) ){
341
+ if( pFlags ) *pFlags |= LOOK_ODD;
342
+ result = 0; /* Odd number of bytes -> binary (UTF-8?) */
343
+ if( n<sizeof(WCHAR_T) ) return result; /* One byte -> binary (UTF-8?) */
344
+ }
345
+ c = *z;
346
+ if( c==0 ){
347
+ if( pFlags ) *pFlags |= LOOK_NUL;
348
+ result = 0; /* NUL character in a file -> binary */
349
+ }
350
+ j = ((c!=UTF16BE_LF) && (c!=UTF16LE_LF));
351
+ if( !j && pFlags ) *pFlags |= LOOK_LONE_LF;
352
+ while( 1 ){
353
+ int c2 = c;
354
+ if( n<sizeof(WCHAR_T) ) break;
355
+ n -= sizeof(WCHAR_T);
356
+ c = *++z; ++j;
357
+ if( c==0 ){
358
+ if( pFlags ) *pFlags |= LOOK_NUL;
359
+ result = 0; /* NUL character in a file -> binary */
360
+ }
361
+ if( c==UTF16BE_LF || c==UTF16LE_LF ){
362
+ if( pFlags ){
363
+ *pFlags |= (c2==UTF16BE_CR||c2==UTF16LE_CR)?LOOK_CRLF:LOOK_LONE_LF;
364
+ }
365
+ if( j>UTF16_LENGTH_MASK ){
366
+ if( pFlags ) *pFlags |= LOOK_LENGTH;
367
+ result = 0; /* Very long line -> binary */
368
+ }
369
+ j = 0;
370
+ }else if( (c2==UTF16BE_CR || c2==UTF16LE_CR) && pFlags ){
371
+ *pFlags |= LOOK_LONE_CR;
372
+ }
373
+ }
374
+ if( (c==UTF16BE_CR || c==UTF16LE_CR) && pFlags ){
375
+ *pFlags |= LOOK_LONE_CR;
376
+ }
377
+ if( j>UTF16_LENGTH_MASK ){
378
+ if( pFlags ) *pFlags |= LOOK_LENGTH;
379
+ result = 0; /* Very long line -> binary */
329380
}
330381
return result; /* No problems seen -> not binary */
331382
}
332383
333384
/*
@@ -355,26 +406,36 @@
355406
if( blob_size(pContent)<bomSize ) return 0;
356407
return memcmp(z, bom, bomSize)==0;
357408
}
358409
359410
/*
360
-** This function returns non-zero if the blob starts with a UTF-16le or
361
-** UTF-16be byte-order-mark (BOM).
411
+** This function returns non-zero if the blob starts with a UTF-16
412
+** byte-order-mark (BOM), either in the endianness of the machine
413
+** or in reversed byte order. The UTF-32 BOM is ruled out by checking
414
+** if the UTF-16 BOM is not immediately followed by (utf16) 0.
415
+** pnByte and pbReverse are only set when the function returns 1.
362416
*/
363
-int starts_with_utf16_bom(const Blob *pContent, int *pnByte){
364
- const char *z = blob_buffer(pContent);
365
- int c1;
366
-
367
- if( pnByte ) *pnByte = 2;
368
- if( (blob_size(pContent)<2) || (blob_size(pContent)&1)) return 0;
369
- c1 = ((unsigned short *)z)[0];
370
- if( (c1==0xfeff) || (c1==0xfffe) ){
371
- if( blob_size(pContent) < 4 ) return 1;
372
- c1 = ((unsigned short *)z)[1];
373
- if( c1 != 0 ) return 1;
374
- }
375
- return 0;
417
+int starts_with_utf16_bom(
418
+ const Blob *pContent, /* IN: Blob content to perform BOM detection on. */
419
+ int *pnByte, /* OUT: The number of bytes used for the BOM. */
420
+ int *pbReverse /* OUT: Non-zero for BOM in reverse byte-order. */
421
+){
422
+ const unsigned short *z = (unsigned short *)blob_buffer(pContent);
423
+ int bomSize = sizeof(unsigned short);
424
+ int size = blob_size(pContent);
425
+
426
+ if( size<bomSize ) return 0; /* No: cannot read BOM. */
427
+ if( size>=(2*bomSize) && z[1]==0 ) return 0; /* No: possible UTF-32. */
428
+ if( z[0]==0xfffe ){
429
+ if( pbReverse ) *pbReverse = 1;
430
+ }else if( z[0]==0xfeff ){
431
+ if( pbReverse ) *pbReverse = 0;
432
+ }else{
433
+ return 0; /* No: UTF-16 byte-order-mark not found. */
434
+ }
435
+ if( pnByte ) *pnByte = bomSize;
436
+ return 1; /* Yes. */
376437
}
377438
378439
/*
379440
** Return true if two DLine elements are identical.
380441
*/
@@ -516,11 +577,11 @@
516577
a = xa;
517578
b = xb;
518579
continue;
519580
}
520581
}
521
-
582
+
522583
/* For the current block comprising nr triples, figure out
523584
** how many lines of A and B are to be displayed
524585
*/
525586
if( R[r]>nContext ){
526587
na = nb = nContext;
@@ -871,21 +932,33 @@
871932
/*
872933
** Simplify iStart and iStart2:
873934
**
874935
** * If iStart is a null-change then move iStart2 into iStart
875936
** * Make sure any null-changes are in canonoical form.
937
+** * Make sure all changes are at character boundaries for
938
+** multi-byte characters.
876939
*/
877
-static void sbsSimplifyLine(SbsLine *p){
878
- if( p->iStart2==p->iEnd2 ) p->iStart2 = p->iEnd2 = 0;
940
+static void sbsSimplifyLine(SbsLine *p, const char *z){
941
+ if( p->iStart2==p->iEnd2 ){
942
+ p->iStart2 = p->iEnd2 = 0;
943
+ }else if( p->iStart2 ){
944
+ while( p->iStart2>0 && (z[p->iStart2]&0xc0)==0x80 ) p->iStart2--;
945
+ while( (z[p->iEnd2]&0xc0)==0x80 ) p->iEnd2++;
946
+ }
879947
if( p->iStart==p->iEnd ){
880948
p->iStart = p->iStart2;
881949
p->iEnd = p->iEnd2;
882950
p->zStart = p->zStart2;
883951
p->iStart2 = 0;
884952
p->iEnd2 = 0;
885953
}
886
- if( p->iStart==p->iEnd ) p->iStart = p->iEnd = -1;
954
+ if( p->iStart==p->iEnd ){
955
+ p->iStart = p->iEnd = -1;
956
+ }else if( p->iStart>0 ){
957
+ while( p->iStart>0 && (z[p->iStart]&0xc0)==0x80 ) p->iStart--;
958
+ while( (z[p->iEnd]&0xc0)==0x80 ) p->iEnd++;
959
+ }
887960
}
888961
889962
/*
890963
** Write out lines that have been edited. Adjust the highlight to cover
891964
** only those parts of the line that actually changed.
@@ -897,10 +970,11 @@
897970
DLine *pRight, /* Right line of the change */
898971
int lnRight /* Line number of the right line */
899972
){
900973
int nLeft; /* Length of left line in bytes */
901974
int nRight; /* Length of right line in bytes */
975
+ int nShort; /* Shortest of left and right */
902976
int nPrefix; /* Length of common prefix */
903977
int nSuffix; /* Length of common suffix */
904978
const char *zLeft; /* Text of the left line */
905979
const char *zRight; /* Text of the right line */
906980
int nLeftDiff; /* nLeft - nPrefix - nSuffix */
@@ -912,25 +986,31 @@
912986
913987
nLeft = pLeft->h & LENGTH_MASK;
914988
zLeft = pLeft->z;
915989
nRight = pRight->h & LENGTH_MASK;
916990
zRight = pRight->z;
991
+ nShort = nLeft<nRight ? nLeft : nRight;
917992
918993
nPrefix = 0;
919
- while( nPrefix<nLeft && nPrefix<nRight && zLeft[nPrefix]==zRight[nPrefix] ){
994
+ while( nPrefix<nShort && zLeft[nPrefix]==zRight[nPrefix] ){
920995
nPrefix++;
921996
}
997
+ if( nPrefix<nShort ){
998
+ while( nPrefix>0 && (zLeft[nPrefix]&0xc0)==0x80 ) nPrefix--;
999
+ }
9221000
nSuffix = 0;
923
- if( nPrefix<nLeft && nPrefix<nRight ){
924
- while( nSuffix<nLeft && nSuffix<nRight
925
- && zLeft[nLeft-nSuffix-1]==zRight[nRight-nSuffix-1] ){
1001
+ if( nPrefix<nShort ){
1002
+ while( nSuffix<nShort && zLeft[nLeft-nSuffix-1]==zRight[nRight-nSuffix-1] ){
9261003
nSuffix++;
9271004
}
1005
+ if( nSuffix<nShort ){
1006
+ while( nSuffix>0 && (zLeft[nLeft-nSuffix]&0xc0)==0x80 ) nSuffix--;
1007
+ }
9281008
if( nSuffix==nLeft || nSuffix==nRight ) nPrefix = 0;
9291009
}
930
- if( nPrefix+nSuffix > nLeft ) nSuffix = nLeft - nPrefix;
931
- if( nPrefix+nSuffix > nRight ) nSuffix = nRight - nPrefix;
1010
+ if( nPrefix+nSuffix > nShort ) nPrefix = nShort - nSuffix;
1011
+
9321012
9331013
/* A single chunk of text inserted on the right */
9341014
if( nPrefix+nSuffix==nLeft ){
9351015
sbsWriteLineno(p, lnLeft);
9361016
p->iStart2 = p->iEnd2 = 0;
@@ -986,11 +1066,11 @@
9861066
p->zStart = zClassChng;
9871067
}
9881068
p->iStart2 = nPrefix + aLCS[1];
9891069
p->iEnd2 = nLeft - nSuffix;
9901070
p->zStart2 = aLCS[3]==nRightDiff ? zClassRm : zClassChng;
991
- sbsSimplifyLine(p);
1071
+ sbsSimplifyLine(p, zLeft+nPrefix);
9921072
sbsWriteText(p, pLeft, SBS_PAD);
9931073
sbsWrite(p, " | ", 3);
9941074
sbsWriteLineno(p, lnRight);
9951075
p->iStart = nPrefix;
9961076
p->iEnd = nPrefix + aLCS[2];
@@ -1001,11 +1081,11 @@
10011081
p->zStart = zClassChng;
10021082
}
10031083
p->iStart2 = nPrefix + aLCS[3];
10041084
p->iEnd2 = nRight - nSuffix;
10051085
p->zStart2 = aLCS[1]==nLeftDiff ? zClassAdd : zClassChng;
1006
- sbsSimplifyLine(p);
1086
+ sbsSimplifyLine(p, zRight+nPrefix);
10071087
sbsWriteText(p, pRight, SBS_NEWLINE);
10081088
return;
10091089
}
10101090
10111091
/* If all else fails, show a single big change between left and right */
@@ -1220,11 +1300,11 @@
12201300
** Then this is probably an alignment that will be difficult for humans
12211301
** to read. So instead, just show all of the right side inserted followed
12221302
** by all of the left side deleted.
12231303
**
12241304
** The coefficients for conditions (1) and (2) above are determined by
1225
- ** experimentation.
1305
+ ** experimentation.
12261306
*/
12271307
mxLen = nLeft>nRight ? nLeft : nRight;
12281308
if( i*4>mxLen*5 && (nMatch==0 || iMatch/nMatch>15) ){
12291309
memset(aM, 4, mnLen);
12301310
if( nLeft>mnLen ) memset(aM+mnLen, 1, nLeft-mnLen);
@@ -1406,11 +1486,11 @@
14061486
/* Delete one line from the left */
14071487
s.n = 0;
14081488
sbsWriteLineno(&s, a);
14091489
s.iStart = 0;
14101490
s.zStart = "<span class=\"diffrm\">";
1411
- s.iEnd = s.width;
1491
+ s.iEnd = LENGTH(&A[a]);
14121492
sbsWriteText(&s, &A[a], SBS_PAD);
14131493
if( s.escHtml ){
14141494
sbsWrite(&s, " &lt;\n", 6);
14151495
}else{
14161496
sbsWrite(&s, " <\n", 3);
@@ -1439,11 +1519,11 @@
14391519
sbsWrite(&s, " > ", 3);
14401520
}
14411521
sbsWriteLineno(&s, b);
14421522
s.iStart = 0;
14431523
s.zStart = "<span class=\"diffadd\">";
1444
- s.iEnd = s.width;
1524
+ s.iEnd = LENGTH(&B[b]);
14451525
sbsWriteText(&s, &B[b], SBS_NEWLINE);
14461526
blob_append(pOut, s.zLine, s.n);
14471527
assert( mb>0 );
14481528
mb--;
14491529
b++;
@@ -1451,25 +1531,25 @@
14511531
/* Delete from the left and insert on the right */
14521532
s.n = 0;
14531533
sbsWriteLineno(&s, a);
14541534
s.iStart = 0;
14551535
s.zStart = "<span class=\"diffrm\">";
1456
- s.iEnd = s.width;
1536
+ s.iEnd = LENGTH(&A[a]);
14571537
sbsWriteText(&s, &A[a], SBS_PAD);
14581538
sbsWrite(&s, " | ", 3);
14591539
sbsWriteLineno(&s, b);
14601540
s.iStart = 0;
14611541
s.zStart = "<span class=\"diffadd\">";
1462
- s.iEnd = s.width;
1542
+ s.iEnd = LENGTH(&B[b]);
14631543
sbsWriteText(&s, &B[b], SBS_NEWLINE);
14641544
blob_append(pOut, s.zLine, s.n);
14651545
ma--;
14661546
mb--;
14671547
a++;
14681548
b++;
14691549
}
1470
-
1550
+
14711551
}
14721552
fossil_free(alignment);
14731553
if( i<nr-1 ){
14741554
m = R[r+i*3+3];
14751555
for(j=0; j<m; j++){
@@ -1954,11 +2034,30 @@
19542034
return 0;
19552035
}
19562036
19572037
/* Compute the difference */
19582038
diff_all(&c);
1959
- if( (diffFlags & DIFF_NOOPT)==0 ) diff_optimize(&c);
2039
+ if( (diffFlags & DIFF_NOTTOOBIG)!=0 ){
2040
+ int i, m, n;
2041
+ int *a = c.aEdit;
2042
+ int mx = c.nEdit;
2043
+ for(i=m=n=0; i<mx; i+=3){ m += a[i]; n += a[i+1]+a[i+2]; }
2044
+ if( n>10000 ){
2045
+ fossil_free(c.aFrom);
2046
+ fossil_free(c.aTo);
2047
+ fossil_free(c.aEdit);
2048
+ if( diffFlags & DIFF_HTML ){
2049
+ blob_append(pOut, DIFF_TOO_MANY_CHANGES_HTML, -1);
2050
+ }else{
2051
+ blob_append(pOut, DIFF_TOO_MANY_CHANGES_TXT, -1);
2052
+ }
2053
+ return 0;
2054
+ }
2055
+ }
2056
+ if( (diffFlags & DIFF_NOOPT)==0 ){
2057
+ diff_optimize(&c);
2058
+ }
19602059
19612060
if( pOut ){
19622061
/* Compute a context or side-by-side diff into pOut */
19632062
if( diffFlags & DIFF_SIDEBYSIDE ){
19642063
sbsDiff(&c, pOut, pRe, diffFlags);
@@ -2205,11 +2304,12 @@
22052304
fossil_print("%10s: %.*s\n", zSrc, x.aOrig[i].n, x.aOrig[i].z);
22062305
}
22072306
}
22082307
22092308
/* Annotation flags */
2210
-#define ANN_FILE_VERS 0x001 /* Show file version rather than commit version */
2309
+#define ANN_FILE_VERS 0x01 /* Show file vers rather than commit vers */
2310
+#define ANN_FILE_ANCEST 0x02 /* Prefer check-ins in the ANCESTOR table */
22112311
22122312
/*
22132313
** Compute a complete annotation on a file. The file is identified
22142314
** by its filename number (filename.fnid) and the baseline in which
22152315
** it was checked in (mlink.mid).
@@ -2243,11 +2343,11 @@
22432343
if( !content_get(rid, &toAnnotate) ){
22442344
fossil_panic("unable to retrieve content of artifact #%d", rid);
22452345
}
22462346
if( iLimit<=0 ) iLimit = 1000000000;
22472347
annotation_start(p, &toAnnotate);
2248
-
2348
+
22492349
db_prepare(&q,
22502350
"SELECT (SELECT uuid FROM blob WHERE rid=mlink.%s),"
22512351
" (SELECT uuid FROM blob WHERE rid=mlink.fid),"
22522352
" (SELECT uuid FROM blob WHERE rid=mlink.pid),"
22532353
" date(event.mtime),"
@@ -2254,14 +2354,16 @@
22542354
" coalesce(event.euser,event.user),"
22552355
" mlink.pid"
22562356
" FROM mlink, event"
22572357
" WHERE mlink.fid=:rid"
22582358
" AND event.objid=mlink.mid"
2259
- " ORDER BY event.mtime",
2260
- (annFlags & ANN_FILE_VERS)!=0 ? "fid" : "mid"
2359
+ " ORDER BY %s event.mtime",
2360
+ (annFlags & ANN_FILE_VERS)!=0 ? "fid" : "mid",
2361
+ (annFlags & ANN_FILE_ANCEST)!=0 ?
2362
+ "(mlink.mid IN (SELECT rid FROM ancestor)) DESC,":""
22612363
);
2262
-
2364
+
22632365
db_bind_int(&q, ":rid", rid);
22642366
if( iLimit==0 ) iLimit = 1000000000;
22652367
while( rid && iLimit>cnt && db_step(&q)==SQLITE_ROW ){
22662368
const char *zUuid = db_column_text(&q, 0);
22672369
const char *zUuidFile = db_column_text(&q, 1);
@@ -2313,11 +2415,11 @@
23132415
void annotation_page(void){
23142416
int mid;
23152417
int fnid;
23162418
int i;
23172419
int iLimit;
2318
- int annFlags = 0;
2420
+ int annFlags = ANN_FILE_ANCEST;
23192421
int showLn = 0; /* True if line numbers should be shown */
23202422
char zLn[10]; /* Line number buffer */
23212423
char zFormat[10]; /* Format string for line numbers */
23222424
Annotator ann;
23232425
@@ -2329,10 +2431,11 @@
23292431
if( mid==0 || fnid==0 ){ fossil_redirect_home(); }
23302432
iLimit = atoi(PD("limit","-1"));
23312433
if( !db_exists("SELECT 1 FROM mlink WHERE mid=%d AND fnid=%d",mid,fnid) ){
23322434
fossil_redirect_home();
23332435
}
2436
+ compute_direct_ancestors(mid, 10000000);
23342437
style_header("File Annotation");
23352438
if( P("filevers") ) annFlags |= ANN_FILE_VERS;
23362439
annotate_file(&ann, P("filename"), fnid, mid, g.perm.Hyperlink, iLimit, annFlags);
23372440
if( P("log") ){
23382441
int i;
@@ -2395,11 +2498,11 @@
23952498
if( zLimit==0 || zLimit[0]==0 ) zLimit = "-1";
23962499
iLimit = atoi(zLimit);
23972500
showLog = find_option("log",0,0)!=0;
23982501
fileVers = find_option("filevers",0,0)!=0;
23992502
db_must_be_within_tree();
2400
- if (g.argc<3) {
2503
+ if( g.argc<3 ) {
24012504
usage("FILENAME");
24022505
}
24032506
file_tree_name(g.argv[2], &treename, 1);
24042507
zFilename = blob_str(&treename);
24052508
fnid = db_int(0, "SELECT fnid FROM filename WHERE name=%Q", zFilename);
@@ -2409,11 +2512,11 @@
24092512
fid = db_int(0, "SELECT rid FROM vfile WHERE pathname=%Q", zFilename);
24102513
if( fid==0 ){
24112514
fossil_fatal("not part of current checkout: %s", zFilename);
24122515
}
24132516
cid = db_lget_int("checkout", 0);
2414
- if (cid == 0){
2517
+ if( cid == 0 ){
24152518
fossil_fatal("Not in a checkout");
24162519
}
24172520
if( iLimit<=0 ) iLimit = 1000000000;
24182521
compute_direct_ancestors(cid, iLimit);
24192522
mid = db_int(0, "SELECT mlink.mid FROM mlink, ancestor "
@@ -2422,10 +2525,11 @@
24222525
fid, fnid);
24232526
if( mid==0 ){
24242527
fossil_panic("unable to find manifest");
24252528
}
24262529
if( fileVers ) annFlags |= ANN_FILE_VERS;
2530
+ annFlags |= ANN_FILE_ANCEST;
24272531
annotate_file(&ann, zFilename, fnid, mid, 0, iLimit, annFlags);
24282532
if( showLog ){
24292533
for(i=0; i<ann.nVers; i++){
24302534
printf("version %3d: %s\n", i+1, ann.azVers[i]);
24312535
}
@@ -2434,5 +2538,42 @@
24342538
for(i=0; i<ann.nOrig; i++){
24352539
fossil_print("%s: %.*s\n",
24362540
ann.aOrig[i].zSrc, ann.aOrig[i].n, ann.aOrig[i].z);
24372541
}
24382542
}
2543
+
2544
+/*
2545
+** COMMAND: test-looks-like-utf
2546
+**
2547
+** Usage: %fossil test-looks-like-utf FILENAME
2548
+**
2549
+** FILENAME is the name of a file to check for textual content in the UTF-8
2550
+** and/or UTF-16 encodings.
2551
+*/
2552
+void looks_like_utf_test_cmd(void){
2553
+ Blob blob; /* the contents of the specified file */
2554
+ int eType; /* return value of looks_like_utf8/utf16() */
2555
+ int fUtf8; /* return value of starts_with_utf8_bom() */
2556
+ int fUtf16; /* return value of starts_with_utf16_bom() */
2557
+ int lookFlags; /* output flags from looks_like_utf8/utf16() */
2558
+ if( g.argc<3 ) usage("FILENAME");
2559
+ blob_read_from_file(&blob, g.argv[2]);
2560
+ fUtf8 = starts_with_utf8_bom(&blob, 0);
2561
+ fUtf16 = starts_with_utf16_bom(&blob, 0, 0);
2562
+ eType = fUtf16 ? looks_like_utf16(&blob, &lookFlags) :
2563
+ looks_like_utf8(&blob, &lookFlags);
2564
+ fossil_print("File \"%s\" has %d bytes.\n",g.argv[2],blob_size(&blob));
2565
+ fossil_print("Starts with UTF-8 BOM: %s\n",fUtf8?"yes":"no");
2566
+ fossil_print("Starts with UTF-16 BOM: %s\n",fUtf16?"yes":"no");
2567
+ fossil_print("Looks like UTF-%s: %s\n",fUtf16?"16":"8",eType?"yes":"no");
2568
+ fossil_print("Has flag LOOK_NUL: %s\n",(lookFlags&LOOK_NUL)?"yes":"no");
2569
+ fossil_print("Has flag LOOK_CR: %s\n",(lookFlags&LOOK_CR)?"yes":"no");
2570
+ fossil_print("Has flag LOOK_LONE_CR: %s\n",
2571
+ (lookFlags&LOOK_LONE_CR)?"yes":"no");
2572
+ fossil_print("Has flag LOOK_LF: %s\n",(lookFlags&LOOK_LF)?"yes":"no");
2573
+ fossil_print("Has flag LOOK_LONE_LF: %s\n",
2574
+ (lookFlags&LOOK_LONE_LF)?"yes":"no");
2575
+ fossil_print("Has flag LOOK_CRLF: %s\n",(lookFlags&LOOK_CRLF)?"yes":"no");
2576
+ fossil_print("Has flag LOOK_LENGTH: %s\n",(lookFlags&LOOK_LENGTH)?"yes":"no");
2577
+ fossil_print("Has flag LOOK_ODD: %s\n",(lookFlags&LOOK_ODD)?"yes":"no");
2578
+ blob_reset(&blob);
2579
+}
24392580
--- src/diff.c
+++ src/diff.c
@@ -39,10 +39,11 @@
39 #define DIFF_LINENO ((u64)0x20000000) /* Show line numbers */
40 #define DIFF_WS_WARNING ((u64)0x40000000) /* Warn about whitespace */
41 #define DIFF_NOOPT (((u64)0x01)<<32) /* Suppress optimizations (debug) */
42 #define DIFF_INVERT (((u64)0x02)<<32) /* Invert the diff (debug) */
43 #define DIFF_CONTEXT_EX (((u64)0x04)<<32) /* Use context even if zero */
 
44
45 /*
46 ** These error messages are shared in multiple locations. They are defined
47 ** here for consistency.
48 */
@@ -50,11 +51,35 @@
50 "cannot compute difference between binary files\n"
51
52 #define DIFF_CANNOT_COMPUTE_SYMLINK \
53 "cannot compute difference between symlink and regular file\n"
54
55 #define looks_like_binary(blob) (looks_like_utf8((blob)) == 0)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
56 #endif /* INTERFACE */
57
58 /*
59 ** Maximum length of a line in a text file, in bytes. (2**13 = 8192 bytes)
60 */
@@ -180,63 +205,73 @@
180 /*
181 ** This function attempts to scan each logical line within the blob to
182 ** determine the type of content it appears to contain. Possible return
183 ** values are:
184 **
185 ** (1) -- The content appears to consist entirely of text, with lines
186 ** delimited by line-feed characters; however, the encoding may
187 ** not be UTF-8.
188 **
189 ** (0) -- The content appears to be binary because it contains embedded
190 ** NUL characters or an extremely long line. Since this function
191 ** does not understand UTF-16, it may falsely consider UTF-16 text
192 ** to be binary.
193 **
194 ** (-1) -- The content appears to consist entirely of text, with lines
195 ** delimited by carriage-return, line-feed pairs; however, the
196 ** encoding may not be UTF-8.
197 **
198 ************************************ WARNING **********************************
199 **
200 ** This function does not validate that the blob content is properly formed
201 ** UTF-8. It assumes that all code points are the same size. It does not
202 ** validate any code points. It makes no attempt to detect if any [invalid]
203 ** switches between UTF-8 and other encodings occur.
204 **
205 ** The only code points that this function cares about are the NUL character,
206 ** carriage-return, and line-feed.
 
 
 
207 **
208 ************************************ WARNING **********************************
209 */
210 int looks_like_utf8(const Blob *pContent){
211 const char *z = blob_buffer(pContent);
212 unsigned int n = blob_size(pContent);
213 int j, c;
214 int result = 1; /* Assume UTF-8 text with no CR/NL */
215
216 /* Check individual lines.
217 */
218 if( n==0 ) return result; /* Empty file -> text */
219 c = *z;
220 if( c==0 ) return 0; /* Zero byte in a file -> binary */
221 j = (c!='\n');
222 while( --n>0 ){
223 c = *++z; ++j;
224 if( c==0 ) return 0; /* Zero byte in a file -> binary */
225 if( c=='\n' ){
226 int c2 = z[-1];
227 if( c2=='\r' ){
228 result = -1; /* Contains CR/NL, continue */
229 }
230 if( j>LENGTH_MASK ){
231 return 0; /* Very long line -> binary */
232 }
233 j = 0;
234 }
235 }
236 if( j>LENGTH_MASK ){
237 return 0; /* Very long line -> binary */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
238 }
239 return result; /* No problems seen -> not binary */
240 }
241
242 /*
@@ -270,64 +305,80 @@
270 /*
271 ** This function attempts to scan each logical line within the blob to
272 ** determine the type of content it appears to contain. Possible return
273 ** values are:
274 **
275 ** (1) -- The content appears to consist entirely of text, with lines
276 ** delimited by line-feed characters; however, the encoding may
277 ** not be UTF-16.
278 **
279 ** (0) -- The content appears to be binary because it contains embedded
280 ** NUL characters or an extremely long line. Since this function
281 ** does not understand UTF-8, it may falsely consider UTF-8 text
282 ** to be binary.
283 **
284 ** (-1) -- The content appears to consist entirely of text, with lines
285 ** delimited by carriage-return, line-feed pairs; however, the
286 ** encoding may not be UTF-16.
287 **
288 ************************************ WARNING **********************************
289 **
290 ** This function does not validate that the blob content is properly formed
291 ** UTF-16. It assumes that all code points are the same size. It does not
292 ** validate any code points. It makes no attempt to detect if any [invalid]
293 ** switches between the UTF-16be and UTF-16le encodings occur.
294 **
295 ** The only code points that this function cares about are the NUL character,
296 ** carriage-return, and line-feed.
 
 
 
297 **
298 ************************************ WARNING **********************************
299 */
300 int looks_like_utf16(const Blob *pContent){
301 const WCHAR_T *z = (WCHAR_T *)blob_buffer(pContent);
302 unsigned int n = blob_size(pContent);
303 int j, c;
304 int result = 1; /* Assume UTF-16 text with no CR/NL */
305
306 /* Check individual lines.
307 */
308 if( n==0 ) return result; /* Empty file -> text */
309 if( n%2 ) return 0; /* Odd number of bytes -> binary (or UTF-8) */
310 c = *z;
311 if( c==0 ) return 0; /* NUL character in a file -> binary */
312 j = ((c!=UTF16BE_LF) && (c!=UTF16LE_LF));
313 while( (n-=2)>0 ){
314 c = *++z; ++j;
315 if( c==0 ) return 0; /* NUL character in a file -> binary */
316 if( c==UTF16BE_LF || c==UTF16LE_LF ){
317 int c2 = z[-1];
318 if( c2==UTF16BE_CR || c2==UTF16LE_CR ){
319 result = -1; /* Contains CR/NL, continue */
320 }
321 if( j>UTF16_LENGTH_MASK ){
322 return 0; /* Very long line -> binary */
323 }
324 j = 0;
325 }
326 }
327 if( j>UTF16_LENGTH_MASK ){
328 return 0; /* Very long line -> binary */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
329 }
330 return result; /* No problems seen -> not binary */
331 }
332
333 /*
@@ -355,26 +406,36 @@
355 if( blob_size(pContent)<bomSize ) return 0;
356 return memcmp(z, bom, bomSize)==0;
357 }
358
359 /*
360 ** This function returns non-zero if the blob starts with a UTF-16le or
361 ** UTF-16be byte-order-mark (BOM).
 
 
 
362 */
363 int starts_with_utf16_bom(const Blob *pContent, int *pnByte){
364 const char *z = blob_buffer(pContent);
365 int c1;
366
367 if( pnByte ) *pnByte = 2;
368 if( (blob_size(pContent)<2) || (blob_size(pContent)&1)) return 0;
369 c1 = ((unsigned short *)z)[0];
370 if( (c1==0xfeff) || (c1==0xfffe) ){
371 if( blob_size(pContent) < 4 ) return 1;
372 c1 = ((unsigned short *)z)[1];
373 if( c1 != 0 ) return 1;
374 }
375 return 0;
 
 
 
 
 
 
 
376 }
377
378 /*
379 ** Return true if two DLine elements are identical.
380 */
@@ -516,11 +577,11 @@
516 a = xa;
517 b = xb;
518 continue;
519 }
520 }
521
522 /* For the current block comprising nr triples, figure out
523 ** how many lines of A and B are to be displayed
524 */
525 if( R[r]>nContext ){
526 na = nb = nContext;
@@ -871,21 +932,33 @@
871 /*
872 ** Simplify iStart and iStart2:
873 **
874 ** * If iStart is a null-change then move iStart2 into iStart
875 ** * Make sure any null-changes are in canonoical form.
 
 
876 */
877 static void sbsSimplifyLine(SbsLine *p){
878 if( p->iStart2==p->iEnd2 ) p->iStart2 = p->iEnd2 = 0;
 
 
 
 
 
879 if( p->iStart==p->iEnd ){
880 p->iStart = p->iStart2;
881 p->iEnd = p->iEnd2;
882 p->zStart = p->zStart2;
883 p->iStart2 = 0;
884 p->iEnd2 = 0;
885 }
886 if( p->iStart==p->iEnd ) p->iStart = p->iEnd = -1;
 
 
 
 
 
887 }
888
889 /*
890 ** Write out lines that have been edited. Adjust the highlight to cover
891 ** only those parts of the line that actually changed.
@@ -897,10 +970,11 @@
897 DLine *pRight, /* Right line of the change */
898 int lnRight /* Line number of the right line */
899 ){
900 int nLeft; /* Length of left line in bytes */
901 int nRight; /* Length of right line in bytes */
 
902 int nPrefix; /* Length of common prefix */
903 int nSuffix; /* Length of common suffix */
904 const char *zLeft; /* Text of the left line */
905 const char *zRight; /* Text of the right line */
906 int nLeftDiff; /* nLeft - nPrefix - nSuffix */
@@ -912,25 +986,31 @@
912
913 nLeft = pLeft->h & LENGTH_MASK;
914 zLeft = pLeft->z;
915 nRight = pRight->h & LENGTH_MASK;
916 zRight = pRight->z;
 
917
918 nPrefix = 0;
919 while( nPrefix<nLeft && nPrefix<nRight && zLeft[nPrefix]==zRight[nPrefix] ){
920 nPrefix++;
921 }
 
 
 
922 nSuffix = 0;
923 if( nPrefix<nLeft && nPrefix<nRight ){
924 while( nSuffix<nLeft && nSuffix<nRight
925 && zLeft[nLeft-nSuffix-1]==zRight[nRight-nSuffix-1] ){
926 nSuffix++;
927 }
 
 
 
928 if( nSuffix==nLeft || nSuffix==nRight ) nPrefix = 0;
929 }
930 if( nPrefix+nSuffix > nLeft ) nSuffix = nLeft - nPrefix;
931 if( nPrefix+nSuffix > nRight ) nSuffix = nRight - nPrefix;
932
933 /* A single chunk of text inserted on the right */
934 if( nPrefix+nSuffix==nLeft ){
935 sbsWriteLineno(p, lnLeft);
936 p->iStart2 = p->iEnd2 = 0;
@@ -986,11 +1066,11 @@
986 p->zStart = zClassChng;
987 }
988 p->iStart2 = nPrefix + aLCS[1];
989 p->iEnd2 = nLeft - nSuffix;
990 p->zStart2 = aLCS[3]==nRightDiff ? zClassRm : zClassChng;
991 sbsSimplifyLine(p);
992 sbsWriteText(p, pLeft, SBS_PAD);
993 sbsWrite(p, " | ", 3);
994 sbsWriteLineno(p, lnRight);
995 p->iStart = nPrefix;
996 p->iEnd = nPrefix + aLCS[2];
@@ -1001,11 +1081,11 @@
1001 p->zStart = zClassChng;
1002 }
1003 p->iStart2 = nPrefix + aLCS[3];
1004 p->iEnd2 = nRight - nSuffix;
1005 p->zStart2 = aLCS[1]==nLeftDiff ? zClassAdd : zClassChng;
1006 sbsSimplifyLine(p);
1007 sbsWriteText(p, pRight, SBS_NEWLINE);
1008 return;
1009 }
1010
1011 /* If all else fails, show a single big change between left and right */
@@ -1220,11 +1300,11 @@
1220 ** Then this is probably an alignment that will be difficult for humans
1221 ** to read. So instead, just show all of the right side inserted followed
1222 ** by all of the left side deleted.
1223 **
1224 ** The coefficients for conditions (1) and (2) above are determined by
1225 ** experimentation.
1226 */
1227 mxLen = nLeft>nRight ? nLeft : nRight;
1228 if( i*4>mxLen*5 && (nMatch==0 || iMatch/nMatch>15) ){
1229 memset(aM, 4, mnLen);
1230 if( nLeft>mnLen ) memset(aM+mnLen, 1, nLeft-mnLen);
@@ -1406,11 +1486,11 @@
1406 /* Delete one line from the left */
1407 s.n = 0;
1408 sbsWriteLineno(&s, a);
1409 s.iStart = 0;
1410 s.zStart = "<span class=\"diffrm\">";
1411 s.iEnd = s.width;
1412 sbsWriteText(&s, &A[a], SBS_PAD);
1413 if( s.escHtml ){
1414 sbsWrite(&s, " &lt;\n", 6);
1415 }else{
1416 sbsWrite(&s, " <\n", 3);
@@ -1439,11 +1519,11 @@
1439 sbsWrite(&s, " > ", 3);
1440 }
1441 sbsWriteLineno(&s, b);
1442 s.iStart = 0;
1443 s.zStart = "<span class=\"diffadd\">";
1444 s.iEnd = s.width;
1445 sbsWriteText(&s, &B[b], SBS_NEWLINE);
1446 blob_append(pOut, s.zLine, s.n);
1447 assert( mb>0 );
1448 mb--;
1449 b++;
@@ -1451,25 +1531,25 @@
1451 /* Delete from the left and insert on the right */
1452 s.n = 0;
1453 sbsWriteLineno(&s, a);
1454 s.iStart = 0;
1455 s.zStart = "<span class=\"diffrm\">";
1456 s.iEnd = s.width;
1457 sbsWriteText(&s, &A[a], SBS_PAD);
1458 sbsWrite(&s, " | ", 3);
1459 sbsWriteLineno(&s, b);
1460 s.iStart = 0;
1461 s.zStart = "<span class=\"diffadd\">";
1462 s.iEnd = s.width;
1463 sbsWriteText(&s, &B[b], SBS_NEWLINE);
1464 blob_append(pOut, s.zLine, s.n);
1465 ma--;
1466 mb--;
1467 a++;
1468 b++;
1469 }
1470
1471 }
1472 fossil_free(alignment);
1473 if( i<nr-1 ){
1474 m = R[r+i*3+3];
1475 for(j=0; j<m; j++){
@@ -1954,11 +2034,30 @@
1954 return 0;
1955 }
1956
1957 /* Compute the difference */
1958 diff_all(&c);
1959 if( (diffFlags & DIFF_NOOPT)==0 ) diff_optimize(&c);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1960
1961 if( pOut ){
1962 /* Compute a context or side-by-side diff into pOut */
1963 if( diffFlags & DIFF_SIDEBYSIDE ){
1964 sbsDiff(&c, pOut, pRe, diffFlags);
@@ -2205,11 +2304,12 @@
2205 fossil_print("%10s: %.*s\n", zSrc, x.aOrig[i].n, x.aOrig[i].z);
2206 }
2207 }
2208
2209 /* Annotation flags */
2210 #define ANN_FILE_VERS 0x001 /* Show file version rather than commit version */
 
2211
2212 /*
2213 ** Compute a complete annotation on a file. The file is identified
2214 ** by its filename number (filename.fnid) and the baseline in which
2215 ** it was checked in (mlink.mid).
@@ -2243,11 +2343,11 @@
2243 if( !content_get(rid, &toAnnotate) ){
2244 fossil_panic("unable to retrieve content of artifact #%d", rid);
2245 }
2246 if( iLimit<=0 ) iLimit = 1000000000;
2247 annotation_start(p, &toAnnotate);
2248
2249 db_prepare(&q,
2250 "SELECT (SELECT uuid FROM blob WHERE rid=mlink.%s),"
2251 " (SELECT uuid FROM blob WHERE rid=mlink.fid),"
2252 " (SELECT uuid FROM blob WHERE rid=mlink.pid),"
2253 " date(event.mtime),"
@@ -2254,14 +2354,16 @@
2254 " coalesce(event.euser,event.user),"
2255 " mlink.pid"
2256 " FROM mlink, event"
2257 " WHERE mlink.fid=:rid"
2258 " AND event.objid=mlink.mid"
2259 " ORDER BY event.mtime",
2260 (annFlags & ANN_FILE_VERS)!=0 ? "fid" : "mid"
 
 
2261 );
2262
2263 db_bind_int(&q, ":rid", rid);
2264 if( iLimit==0 ) iLimit = 1000000000;
2265 while( rid && iLimit>cnt && db_step(&q)==SQLITE_ROW ){
2266 const char *zUuid = db_column_text(&q, 0);
2267 const char *zUuidFile = db_column_text(&q, 1);
@@ -2313,11 +2415,11 @@
2313 void annotation_page(void){
2314 int mid;
2315 int fnid;
2316 int i;
2317 int iLimit;
2318 int annFlags = 0;
2319 int showLn = 0; /* True if line numbers should be shown */
2320 char zLn[10]; /* Line number buffer */
2321 char zFormat[10]; /* Format string for line numbers */
2322 Annotator ann;
2323
@@ -2329,10 +2431,11 @@
2329 if( mid==0 || fnid==0 ){ fossil_redirect_home(); }
2330 iLimit = atoi(PD("limit","-1"));
2331 if( !db_exists("SELECT 1 FROM mlink WHERE mid=%d AND fnid=%d",mid,fnid) ){
2332 fossil_redirect_home();
2333 }
 
2334 style_header("File Annotation");
2335 if( P("filevers") ) annFlags |= ANN_FILE_VERS;
2336 annotate_file(&ann, P("filename"), fnid, mid, g.perm.Hyperlink, iLimit, annFlags);
2337 if( P("log") ){
2338 int i;
@@ -2395,11 +2498,11 @@
2395 if( zLimit==0 || zLimit[0]==0 ) zLimit = "-1";
2396 iLimit = atoi(zLimit);
2397 showLog = find_option("log",0,0)!=0;
2398 fileVers = find_option("filevers",0,0)!=0;
2399 db_must_be_within_tree();
2400 if (g.argc<3) {
2401 usage("FILENAME");
2402 }
2403 file_tree_name(g.argv[2], &treename, 1);
2404 zFilename = blob_str(&treename);
2405 fnid = db_int(0, "SELECT fnid FROM filename WHERE name=%Q", zFilename);
@@ -2409,11 +2512,11 @@
2409 fid = db_int(0, "SELECT rid FROM vfile WHERE pathname=%Q", zFilename);
2410 if( fid==0 ){
2411 fossil_fatal("not part of current checkout: %s", zFilename);
2412 }
2413 cid = db_lget_int("checkout", 0);
2414 if (cid == 0){
2415 fossil_fatal("Not in a checkout");
2416 }
2417 if( iLimit<=0 ) iLimit = 1000000000;
2418 compute_direct_ancestors(cid, iLimit);
2419 mid = db_int(0, "SELECT mlink.mid FROM mlink, ancestor "
@@ -2422,10 +2525,11 @@
2422 fid, fnid);
2423 if( mid==0 ){
2424 fossil_panic("unable to find manifest");
2425 }
2426 if( fileVers ) annFlags |= ANN_FILE_VERS;
 
2427 annotate_file(&ann, zFilename, fnid, mid, 0, iLimit, annFlags);
2428 if( showLog ){
2429 for(i=0; i<ann.nVers; i++){
2430 printf("version %3d: %s\n", i+1, ann.azVers[i]);
2431 }
@@ -2434,5 +2538,42 @@
2434 for(i=0; i<ann.nOrig; i++){
2435 fossil_print("%s: %.*s\n",
2436 ann.aOrig[i].zSrc, ann.aOrig[i].n, ann.aOrig[i].z);
2437 }
2438 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2439
--- src/diff.c
+++ src/diff.c
@@ -39,10 +39,11 @@
39 #define DIFF_LINENO ((u64)0x20000000) /* Show line numbers */
40 #define DIFF_WS_WARNING ((u64)0x40000000) /* Warn about whitespace */
41 #define DIFF_NOOPT (((u64)0x01)<<32) /* Suppress optimizations (debug) */
42 #define DIFF_INVERT (((u64)0x02)<<32) /* Invert the diff (debug) */
43 #define DIFF_CONTEXT_EX (((u64)0x04)<<32) /* Use context even if zero */
44 #define DIFF_NOTTOOBIG (((u64)0x08)<<32) /* Only display if not too big */
45
46 /*
47 ** These error messages are shared in multiple locations. They are defined
48 ** here for consistency.
49 */
@@ -50,11 +51,35 @@
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) (looks_like_utf8((blob), 0) == 0)
67
68 /*
69 ** Output flags for the looks_like_utf8() and looks_like_utf16() routines used
70 ** to convey status information about the blob content.
71 */
72 #define LOOK_NONE ((int)0x00000000) /* Nothing special was found. */
73 #define LOOK_NUL ((int)0x00000001) /* One or more NUL chars were found. */
74 #define LOOK_LONE_CR ((int)0x00000002) /* An unpaired CR char was found. */
75 #define LOOK_LONE_LF ((int)0x00000004) /* An unpaired LF char was found. */
76 #define LOOK_CRLF ((int)0x00000008) /* One or more CR/LF pairs were found. */
77 #define LOOK_LENGTH ((int)0x00000010) /* An over length line was found. */
78 #define LOOK_ODD ((int)0x00000020) /* An odd number of bytes was found. */
79 #define LOOK_CR (LOOK_LONE_CR|LOOK_CRLF) /* One or more CR chars were found. */
80 #define LOOK_LF (LOOK_LONE_LF|LOOK_CRLF) /* One or more LF chars were found. */
81 #endif /* INTERFACE */
82
83 /*
84 ** Maximum length of a line in a text file, in bytes. (2**13 = 8192 bytes)
85 */
@@ -180,63 +205,73 @@
205 /*
206 ** This function attempts to scan each logical line within the blob to
207 ** determine the type of content it appears to contain. Possible return
208 ** values are:
209 **
210 ** (1) -- The content appears to consist entirely of text; however, the
211 ** encoding may not be UTF-8.
 
212 **
213 ** (0) -- The content appears to be binary because it contains embedded
214 ** NUL characters or an extremely long line. Since this function
215 ** does not understand UTF-16, it may falsely consider UTF-16 text
216 ** to be binary.
217 **
 
 
 
 
218 ************************************ WARNING **********************************
219 **
220 ** This function does not validate that the blob content is properly formed
221 ** UTF-8. It assumes that all code points are the same size. It does not
222 ** validate any code points. It makes no attempt to detect if any [invalid]
223 ** switches between UTF-8 and other encodings occur.
224 **
225 ** The only code points that this function cares about are the NUL character,
226 ** carriage-return, and line-feed.
227 **
228 ** Whether or not this function examines the entire contents of the blob is
229 ** officially unspecified.
230 **
231 ************************************ WARNING **********************************
232 */
233 int looks_like_utf8(const Blob *pContent, int *pFlags){
234 const char *z = blob_buffer(pContent);
235 unsigned int n = blob_size(pContent);
236 int j, c, result = 1; /* Assume UTF-8 text, prove otherwise */
 
237
238 if( pFlags ) *pFlags = LOOK_NONE;
 
239 if( n==0 ) return result; /* Empty file -> text */
240 c = *z;
241 if( c==0 ){
242 if( pFlags ) *pFlags |= LOOK_NUL;
243 result = 0; /* NUL character in a file -> binary */
244 }
245 j = (c!='\n');
246 if( !j && pFlags ) *pFlags |= LOOK_LONE_LF;
247 while( --n>0 ){
248 int c2 = c;
249 c = *++z; ++j;
250 if( c==0 ){
251 if( pFlags ) *pFlags |= LOOK_NUL;
252 result = 0; /* NUL character in a file -> binary */
253 }
254 if( c=='\n' ){
255 if( pFlags ){
256 *pFlags |= (c2=='\r')?LOOK_CRLF:LOOK_LONE_LF;
257 }
258 if( j>LENGTH_MASK ){
259 if( pFlags ) *pFlags |= LOOK_LENGTH;
260 result = 0; /* Very long line -> binary */
261 }
262 j = 0;
263 }else if( c2=='\r' && pFlags ){
264 *pFlags |= LOOK_LONE_CR;
265 }
266 }
267 if( c=='\r' && pFlags ){
268 *pFlags |= LOOK_LONE_CR;
269 }
270 if( j>LENGTH_MASK ){
271 if( pFlags ) *pFlags |= LOOK_LENGTH;
272 result = 0; /* Very long line -> binary */
273 }
274 return result; /* No problems seen -> not binary */
275 }
276
277 /*
@@ -270,64 +305,80 @@
305 /*
306 ** This function attempts to scan each logical line within the blob to
307 ** determine the type of content it appears to contain. Possible return
308 ** values are:
309 **
310 ** (1) -- The content appears to consist entirely of text; however, the
311 ** encoding may not be UTF-16.
 
312 **
313 ** (0) -- The content appears to be binary because it contains embedded
314 ** NUL characters or an extremely long line. Since this function
315 ** does not understand UTF-8, it may falsely consider UTF-8 text
316 ** to be binary.
317 **
 
 
 
 
318 ************************************ WARNING **********************************
319 **
320 ** This function does not validate that the blob content is properly formed
321 ** UTF-16. It assumes that all code points are the same size. It does not
322 ** validate any code points. It makes no attempt to detect if any [invalid]
323 ** switches between the UTF-16be and UTF-16le encodings occur.
324 **
325 ** The only code points that this function cares about are the NUL character,
326 ** carriage-return, and line-feed.
327 **
328 ** Whether or not this function examines the entire contents of the blob is
329 ** officially unspecified.
330 **
331 ************************************ WARNING **********************************
332 */
333 int looks_like_utf16(const Blob *pContent, int *pFlags){
334 const WCHAR_T *z = (WCHAR_T *)blob_buffer(pContent);
335 unsigned int n = blob_size(pContent);
336 int j, c, result = 1; /* Assume UTF-16 text, prove otherwise */
337
338 if( pFlags ) *pFlags = LOOK_NONE;
339 if( n==0 ) return result; /* Empty file -> text */
340 if( n%sizeof(WCHAR_T) ){
341 if( pFlags ) *pFlags |= LOOK_ODD;
342 result = 0; /* Odd number of bytes -> binary (UTF-8?) */
343 if( n<sizeof(WCHAR_T) ) return result; /* One byte -> binary (UTF-8?) */
344 }
345 c = *z;
346 if( c==0 ){
347 if( pFlags ) *pFlags |= LOOK_NUL;
348 result = 0; /* NUL character in a file -> binary */
349 }
350 j = ((c!=UTF16BE_LF) && (c!=UTF16LE_LF));
351 if( !j && pFlags ) *pFlags |= LOOK_LONE_LF;
352 while( 1 ){
353 int c2 = c;
354 if( n<sizeof(WCHAR_T) ) break;
355 n -= sizeof(WCHAR_T);
356 c = *++z; ++j;
357 if( c==0 ){
358 if( pFlags ) *pFlags |= LOOK_NUL;
359 result = 0; /* NUL character in a file -> binary */
360 }
361 if( c==UTF16BE_LF || c==UTF16LE_LF ){
362 if( pFlags ){
363 *pFlags |= (c2==UTF16BE_CR||c2==UTF16LE_CR)?LOOK_CRLF:LOOK_LONE_LF;
364 }
365 if( j>UTF16_LENGTH_MASK ){
366 if( pFlags ) *pFlags |= LOOK_LENGTH;
367 result = 0; /* Very long line -> binary */
368 }
369 j = 0;
370 }else if( (c2==UTF16BE_CR || c2==UTF16LE_CR) && pFlags ){
371 *pFlags |= LOOK_LONE_CR;
372 }
373 }
374 if( (c==UTF16BE_CR || c==UTF16LE_CR) && pFlags ){
375 *pFlags |= LOOK_LONE_CR;
376 }
377 if( j>UTF16_LENGTH_MASK ){
378 if( pFlags ) *pFlags |= LOOK_LENGTH;
379 result = 0; /* Very long line -> binary */
380 }
381 return result; /* No problems seen -> not binary */
382 }
383
384 /*
@@ -355,26 +406,36 @@
406 if( blob_size(pContent)<bomSize ) return 0;
407 return memcmp(z, bom, bomSize)==0;
408 }
409
410 /*
411 ** This function returns non-zero if the blob starts with a UTF-16
412 ** byte-order-mark (BOM), either in the endianness of the machine
413 ** or in reversed byte order. The UTF-32 BOM is ruled out by checking
414 ** if the UTF-16 BOM is not immediately followed by (utf16) 0.
415 ** pnByte and pbReverse are only set when the function returns 1.
416 */
417 int starts_with_utf16_bom(
418 const Blob *pContent, /* IN: Blob content to perform BOM detection on. */
419 int *pnByte, /* OUT: The number of bytes used for the BOM. */
420 int *pbReverse /* OUT: Non-zero for BOM in reverse byte-order. */
421 ){
422 const unsigned short *z = (unsigned short *)blob_buffer(pContent);
423 int bomSize = sizeof(unsigned short);
424 int size = blob_size(pContent);
425
426 if( size<bomSize ) return 0; /* No: cannot read BOM. */
427 if( size>=(2*bomSize) && z[1]==0 ) return 0; /* No: possible UTF-32. */
428 if( z[0]==0xfffe ){
429 if( pbReverse ) *pbReverse = 1;
430 }else if( z[0]==0xfeff ){
431 if( pbReverse ) *pbReverse = 0;
432 }else{
433 return 0; /* No: UTF-16 byte-order-mark not found. */
434 }
435 if( pnByte ) *pnByte = bomSize;
436 return 1; /* Yes. */
437 }
438
439 /*
440 ** Return true if two DLine elements are identical.
441 */
@@ -516,11 +577,11 @@
577 a = xa;
578 b = xb;
579 continue;
580 }
581 }
582
583 /* For the current block comprising nr triples, figure out
584 ** how many lines of A and B are to be displayed
585 */
586 if( R[r]>nContext ){
587 na = nb = nContext;
@@ -871,21 +932,33 @@
932 /*
933 ** Simplify iStart and iStart2:
934 **
935 ** * If iStart is a null-change then move iStart2 into iStart
936 ** * Make sure any null-changes are in canonoical form.
937 ** * Make sure all changes are at character boundaries for
938 ** multi-byte characters.
939 */
940 static void sbsSimplifyLine(SbsLine *p, const char *z){
941 if( p->iStart2==p->iEnd2 ){
942 p->iStart2 = p->iEnd2 = 0;
943 }else if( p->iStart2 ){
944 while( p->iStart2>0 && (z[p->iStart2]&0xc0)==0x80 ) p->iStart2--;
945 while( (z[p->iEnd2]&0xc0)==0x80 ) p->iEnd2++;
946 }
947 if( p->iStart==p->iEnd ){
948 p->iStart = p->iStart2;
949 p->iEnd = p->iEnd2;
950 p->zStart = p->zStart2;
951 p->iStart2 = 0;
952 p->iEnd2 = 0;
953 }
954 if( p->iStart==p->iEnd ){
955 p->iStart = p->iEnd = -1;
956 }else if( p->iStart>0 ){
957 while( p->iStart>0 && (z[p->iStart]&0xc0)==0x80 ) p->iStart--;
958 while( (z[p->iEnd]&0xc0)==0x80 ) p->iEnd++;
959 }
960 }
961
962 /*
963 ** Write out lines that have been edited. Adjust the highlight to cover
964 ** only those parts of the line that actually changed.
@@ -897,10 +970,11 @@
970 DLine *pRight, /* Right line of the change */
971 int lnRight /* Line number of the right line */
972 ){
973 int nLeft; /* Length of left line in bytes */
974 int nRight; /* Length of right line in bytes */
975 int nShort; /* Shortest of left and right */
976 int nPrefix; /* Length of common prefix */
977 int nSuffix; /* Length of common suffix */
978 const char *zLeft; /* Text of the left line */
979 const char *zRight; /* Text of the right line */
980 int nLeftDiff; /* nLeft - nPrefix - nSuffix */
@@ -912,25 +986,31 @@
986
987 nLeft = pLeft->h & LENGTH_MASK;
988 zLeft = pLeft->z;
989 nRight = pRight->h & LENGTH_MASK;
990 zRight = pRight->z;
991 nShort = nLeft<nRight ? nLeft : nRight;
992
993 nPrefix = 0;
994 while( nPrefix<nShort && zLeft[nPrefix]==zRight[nPrefix] ){
995 nPrefix++;
996 }
997 if( nPrefix<nShort ){
998 while( nPrefix>0 && (zLeft[nPrefix]&0xc0)==0x80 ) nPrefix--;
999 }
1000 nSuffix = 0;
1001 if( nPrefix<nShort ){
1002 while( nSuffix<nShort && zLeft[nLeft-nSuffix-1]==zRight[nRight-nSuffix-1] ){
 
1003 nSuffix++;
1004 }
1005 if( nSuffix<nShort ){
1006 while( nSuffix>0 && (zLeft[nLeft-nSuffix]&0xc0)==0x80 ) nSuffix--;
1007 }
1008 if( nSuffix==nLeft || nSuffix==nRight ) nPrefix = 0;
1009 }
1010 if( nPrefix+nSuffix > nShort ) nPrefix = nShort - nSuffix;
1011
1012
1013 /* A single chunk of text inserted on the right */
1014 if( nPrefix+nSuffix==nLeft ){
1015 sbsWriteLineno(p, lnLeft);
1016 p->iStart2 = p->iEnd2 = 0;
@@ -986,11 +1066,11 @@
1066 p->zStart = zClassChng;
1067 }
1068 p->iStart2 = nPrefix + aLCS[1];
1069 p->iEnd2 = nLeft - nSuffix;
1070 p->zStart2 = aLCS[3]==nRightDiff ? zClassRm : zClassChng;
1071 sbsSimplifyLine(p, zLeft+nPrefix);
1072 sbsWriteText(p, pLeft, SBS_PAD);
1073 sbsWrite(p, " | ", 3);
1074 sbsWriteLineno(p, lnRight);
1075 p->iStart = nPrefix;
1076 p->iEnd = nPrefix + aLCS[2];
@@ -1001,11 +1081,11 @@
1081 p->zStart = zClassChng;
1082 }
1083 p->iStart2 = nPrefix + aLCS[3];
1084 p->iEnd2 = nRight - nSuffix;
1085 p->zStart2 = aLCS[1]==nLeftDiff ? zClassAdd : zClassChng;
1086 sbsSimplifyLine(p, zRight+nPrefix);
1087 sbsWriteText(p, pRight, SBS_NEWLINE);
1088 return;
1089 }
1090
1091 /* If all else fails, show a single big change between left and right */
@@ -1220,11 +1300,11 @@
1300 ** Then this is probably an alignment that will be difficult for humans
1301 ** to read. So instead, just show all of the right side inserted followed
1302 ** by all of the left side deleted.
1303 **
1304 ** The coefficients for conditions (1) and (2) above are determined by
1305 ** experimentation.
1306 */
1307 mxLen = nLeft>nRight ? nLeft : nRight;
1308 if( i*4>mxLen*5 && (nMatch==0 || iMatch/nMatch>15) ){
1309 memset(aM, 4, mnLen);
1310 if( nLeft>mnLen ) memset(aM+mnLen, 1, nLeft-mnLen);
@@ -1406,11 +1486,11 @@
1486 /* Delete one line from the left */
1487 s.n = 0;
1488 sbsWriteLineno(&s, a);
1489 s.iStart = 0;
1490 s.zStart = "<span class=\"diffrm\">";
1491 s.iEnd = LENGTH(&A[a]);
1492 sbsWriteText(&s, &A[a], SBS_PAD);
1493 if( s.escHtml ){
1494 sbsWrite(&s, " &lt;\n", 6);
1495 }else{
1496 sbsWrite(&s, " <\n", 3);
@@ -1439,11 +1519,11 @@
1519 sbsWrite(&s, " > ", 3);
1520 }
1521 sbsWriteLineno(&s, b);
1522 s.iStart = 0;
1523 s.zStart = "<span class=\"diffadd\">";
1524 s.iEnd = LENGTH(&B[b]);
1525 sbsWriteText(&s, &B[b], SBS_NEWLINE);
1526 blob_append(pOut, s.zLine, s.n);
1527 assert( mb>0 );
1528 mb--;
1529 b++;
@@ -1451,25 +1531,25 @@
1531 /* Delete from the left and insert on the right */
1532 s.n = 0;
1533 sbsWriteLineno(&s, a);
1534 s.iStart = 0;
1535 s.zStart = "<span class=\"diffrm\">";
1536 s.iEnd = LENGTH(&A[a]);
1537 sbsWriteText(&s, &A[a], SBS_PAD);
1538 sbsWrite(&s, " | ", 3);
1539 sbsWriteLineno(&s, b);
1540 s.iStart = 0;
1541 s.zStart = "<span class=\"diffadd\">";
1542 s.iEnd = LENGTH(&B[b]);
1543 sbsWriteText(&s, &B[b], SBS_NEWLINE);
1544 blob_append(pOut, s.zLine, s.n);
1545 ma--;
1546 mb--;
1547 a++;
1548 b++;
1549 }
1550
1551 }
1552 fossil_free(alignment);
1553 if( i<nr-1 ){
1554 m = R[r+i*3+3];
1555 for(j=0; j<m; j++){
@@ -1954,11 +2034,30 @@
2034 return 0;
2035 }
2036
2037 /* Compute the difference */
2038 diff_all(&c);
2039 if( (diffFlags & DIFF_NOTTOOBIG)!=0 ){
2040 int i, m, n;
2041 int *a = c.aEdit;
2042 int mx = c.nEdit;
2043 for(i=m=n=0; i<mx; i+=3){ m += a[i]; n += a[i+1]+a[i+2]; }
2044 if( n>10000 ){
2045 fossil_free(c.aFrom);
2046 fossil_free(c.aTo);
2047 fossil_free(c.aEdit);
2048 if( diffFlags & DIFF_HTML ){
2049 blob_append(pOut, DIFF_TOO_MANY_CHANGES_HTML, -1);
2050 }else{
2051 blob_append(pOut, DIFF_TOO_MANY_CHANGES_TXT, -1);
2052 }
2053 return 0;
2054 }
2055 }
2056 if( (diffFlags & DIFF_NOOPT)==0 ){
2057 diff_optimize(&c);
2058 }
2059
2060 if( pOut ){
2061 /* Compute a context or side-by-side diff into pOut */
2062 if( diffFlags & DIFF_SIDEBYSIDE ){
2063 sbsDiff(&c, pOut, pRe, diffFlags);
@@ -2205,11 +2304,12 @@
2304 fossil_print("%10s: %.*s\n", zSrc, x.aOrig[i].n, x.aOrig[i].z);
2305 }
2306 }
2307
2308 /* Annotation flags */
2309 #define ANN_FILE_VERS 0x01 /* Show file vers rather than commit vers */
2310 #define ANN_FILE_ANCEST 0x02 /* Prefer check-ins in the ANCESTOR table */
2311
2312 /*
2313 ** Compute a complete annotation on a file. The file is identified
2314 ** by its filename number (filename.fnid) and the baseline in which
2315 ** it was checked in (mlink.mid).
@@ -2243,11 +2343,11 @@
2343 if( !content_get(rid, &toAnnotate) ){
2344 fossil_panic("unable to retrieve content of artifact #%d", rid);
2345 }
2346 if( iLimit<=0 ) iLimit = 1000000000;
2347 annotation_start(p, &toAnnotate);
2348
2349 db_prepare(&q,
2350 "SELECT (SELECT uuid FROM blob WHERE rid=mlink.%s),"
2351 " (SELECT uuid FROM blob WHERE rid=mlink.fid),"
2352 " (SELECT uuid FROM blob WHERE rid=mlink.pid),"
2353 " date(event.mtime),"
@@ -2254,14 +2354,16 @@
2354 " coalesce(event.euser,event.user),"
2355 " mlink.pid"
2356 " FROM mlink, event"
2357 " WHERE mlink.fid=:rid"
2358 " AND event.objid=mlink.mid"
2359 " ORDER BY %s event.mtime",
2360 (annFlags & ANN_FILE_VERS)!=0 ? "fid" : "mid",
2361 (annFlags & ANN_FILE_ANCEST)!=0 ?
2362 "(mlink.mid IN (SELECT rid FROM ancestor)) DESC,":""
2363 );
2364
2365 db_bind_int(&q, ":rid", rid);
2366 if( iLimit==0 ) iLimit = 1000000000;
2367 while( rid && iLimit>cnt && db_step(&q)==SQLITE_ROW ){
2368 const char *zUuid = db_column_text(&q, 0);
2369 const char *zUuidFile = db_column_text(&q, 1);
@@ -2313,11 +2415,11 @@
2415 void annotation_page(void){
2416 int mid;
2417 int fnid;
2418 int i;
2419 int iLimit;
2420 int annFlags = ANN_FILE_ANCEST;
2421 int showLn = 0; /* True if line numbers should be shown */
2422 char zLn[10]; /* Line number buffer */
2423 char zFormat[10]; /* Format string for line numbers */
2424 Annotator ann;
2425
@@ -2329,10 +2431,11 @@
2431 if( mid==0 || fnid==0 ){ fossil_redirect_home(); }
2432 iLimit = atoi(PD("limit","-1"));
2433 if( !db_exists("SELECT 1 FROM mlink WHERE mid=%d AND fnid=%d",mid,fnid) ){
2434 fossil_redirect_home();
2435 }
2436 compute_direct_ancestors(mid, 10000000);
2437 style_header("File Annotation");
2438 if( P("filevers") ) annFlags |= ANN_FILE_VERS;
2439 annotate_file(&ann, P("filename"), fnid, mid, g.perm.Hyperlink, iLimit, annFlags);
2440 if( P("log") ){
2441 int i;
@@ -2395,11 +2498,11 @@
2498 if( zLimit==0 || zLimit[0]==0 ) zLimit = "-1";
2499 iLimit = atoi(zLimit);
2500 showLog = find_option("log",0,0)!=0;
2501 fileVers = find_option("filevers",0,0)!=0;
2502 db_must_be_within_tree();
2503 if( g.argc<3 ) {
2504 usage("FILENAME");
2505 }
2506 file_tree_name(g.argv[2], &treename, 1);
2507 zFilename = blob_str(&treename);
2508 fnid = db_int(0, "SELECT fnid FROM filename WHERE name=%Q", zFilename);
@@ -2409,11 +2512,11 @@
2512 fid = db_int(0, "SELECT rid FROM vfile WHERE pathname=%Q", zFilename);
2513 if( fid==0 ){
2514 fossil_fatal("not part of current checkout: %s", zFilename);
2515 }
2516 cid = db_lget_int("checkout", 0);
2517 if( cid == 0 ){
2518 fossil_fatal("Not in a checkout");
2519 }
2520 if( iLimit<=0 ) iLimit = 1000000000;
2521 compute_direct_ancestors(cid, iLimit);
2522 mid = db_int(0, "SELECT mlink.mid FROM mlink, ancestor "
@@ -2422,10 +2525,11 @@
2525 fid, fnid);
2526 if( mid==0 ){
2527 fossil_panic("unable to find manifest");
2528 }
2529 if( fileVers ) annFlags |= ANN_FILE_VERS;
2530 annFlags |= ANN_FILE_ANCEST;
2531 annotate_file(&ann, zFilename, fnid, mid, 0, iLimit, annFlags);
2532 if( showLog ){
2533 for(i=0; i<ann.nVers; i++){
2534 printf("version %3d: %s\n", i+1, ann.azVers[i]);
2535 }
@@ -2434,5 +2538,42 @@
2538 for(i=0; i<ann.nOrig; i++){
2539 fossil_print("%s: %.*s\n",
2540 ann.aOrig[i].zSrc, ann.aOrig[i].n, ann.aOrig[i].z);
2541 }
2542 }
2543
2544 /*
2545 ** COMMAND: test-looks-like-utf
2546 **
2547 ** Usage: %fossil test-looks-like-utf FILENAME
2548 **
2549 ** FILENAME is the name of a file to check for textual content in the UTF-8
2550 ** and/or UTF-16 encodings.
2551 */
2552 void looks_like_utf_test_cmd(void){
2553 Blob blob; /* the contents of the specified file */
2554 int eType; /* return value of looks_like_utf8/utf16() */
2555 int fUtf8; /* return value of starts_with_utf8_bom() */
2556 int fUtf16; /* return value of starts_with_utf16_bom() */
2557 int lookFlags; /* output flags from looks_like_utf8/utf16() */
2558 if( g.argc<3 ) usage("FILENAME");
2559 blob_read_from_file(&blob, g.argv[2]);
2560 fUtf8 = starts_with_utf8_bom(&blob, 0);
2561 fUtf16 = starts_with_utf16_bom(&blob, 0, 0);
2562 eType = fUtf16 ? looks_like_utf16(&blob, &lookFlags) :
2563 looks_like_utf8(&blob, &lookFlags);
2564 fossil_print("File \"%s\" has %d bytes.\n",g.argv[2],blob_size(&blob));
2565 fossil_print("Starts with UTF-8 BOM: %s\n",fUtf8?"yes":"no");
2566 fossil_print("Starts with UTF-16 BOM: %s\n",fUtf16?"yes":"no");
2567 fossil_print("Looks like UTF-%s: %s\n",fUtf16?"16":"8",eType?"yes":"no");
2568 fossil_print("Has flag LOOK_NUL: %s\n",(lookFlags&LOOK_NUL)?"yes":"no");
2569 fossil_print("Has flag LOOK_CR: %s\n",(lookFlags&LOOK_CR)?"yes":"no");
2570 fossil_print("Has flag LOOK_LONE_CR: %s\n",
2571 (lookFlags&LOOK_LONE_CR)?"yes":"no");
2572 fossil_print("Has flag LOOK_LF: %s\n",(lookFlags&LOOK_LF)?"yes":"no");
2573 fossil_print("Has flag LOOK_LONE_LF: %s\n",
2574 (lookFlags&LOOK_LONE_LF)?"yes":"no");
2575 fossil_print("Has flag LOOK_CRLF: %s\n",(lookFlags&LOOK_CRLF)?"yes":"no");
2576 fossil_print("Has flag LOOK_LENGTH: %s\n",(lookFlags&LOOK_LENGTH)?"yes":"no");
2577 fossil_print("Has flag LOOK_ODD: %s\n",(lookFlags&LOOK_ODD)?"yes":"no");
2578 blob_reset(&blob);
2579 }
2580
+248 -107
--- src/diff.c
+++ src/diff.c
@@ -39,10 +39,11 @@
3939
#define DIFF_LINENO ((u64)0x20000000) /* Show line numbers */
4040
#define DIFF_WS_WARNING ((u64)0x40000000) /* Warn about whitespace */
4141
#define DIFF_NOOPT (((u64)0x01)<<32) /* Suppress optimizations (debug) */
4242
#define DIFF_INVERT (((u64)0x02)<<32) /* Invert the diff (debug) */
4343
#define DIFF_CONTEXT_EX (((u64)0x04)<<32) /* Use context even if zero */
44
+#define DIFF_NOTTOOBIG (((u64)0x08)<<32) /* Only display if not too big */
4445
4546
/*
4647
** These error messages are shared in multiple locations. They are defined
4748
** here for consistency.
4849
*/
@@ -50,11 +51,35 @@
5051
"cannot compute difference between binary files\n"
5152
5253
#define DIFF_CANNOT_COMPUTE_SYMLINK \
5354
"cannot compute difference between symlink and regular file\n"
5455
55
-#define looks_like_binary(blob) (looks_like_utf8((blob)) == 0)
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) (looks_like_utf8((blob), 0) == 0)
67
+
68
+/*
69
+** Output flags for the looks_like_utf8() and looks_like_utf16() routines used
70
+** to convey status information about the blob content.
71
+*/
72
+#define LOOK_NONE ((int)0x00000000) /* Nothing special was found. */
73
+#define LOOK_NUL ((int)0x00000001) /* One or more NUL chars were found. */
74
+#define LOOK_LONE_CR ((int)0x00000002) /* An unpaired CR char was found. */
75
+#define LOOK_LONE_LF ((int)0x00000004) /* An unpaired LF char was found. */
76
+#define LOOK_CRLF ((int)0x00000008) /* One or more CR/LF pairs were found. */
77
+#define LOOK_LENGTH ((int)0x00000010) /* An over length line was found. */
78
+#define LOOK_ODD ((int)0x00000020) /* An odd number of bytes was found. */
79
+#define LOOK_CR (LOOK_LONE_CR|LOOK_CRLF) /* One or more CR chars were found. */
80
+#define LOOK_LF (LOOK_LONE_LF|LOOK_CRLF) /* One or more LF chars were found. */
5681
#endif /* INTERFACE */
5782
5883
/*
5984
** Maximum length of a line in a text file, in bytes. (2**13 = 8192 bytes)
6085
*/
@@ -180,63 +205,73 @@
180205
/*
181206
** This function attempts to scan each logical line within the blob to
182207
** determine the type of content it appears to contain. Possible return
183208
** values are:
184209
**
185
-** (1) -- The content appears to consist entirely of text, with lines
186
-** delimited by line-feed characters; however, the encoding may
187
-** not be UTF-8.
210
+** (1) -- The content appears to consist entirely of text; however, the
211
+** encoding may not be UTF-8.
188212
**
189213
** (0) -- The content appears to be binary because it contains embedded
190214
** NUL characters or an extremely long line. Since this function
191215
** does not understand UTF-16, it may falsely consider UTF-16 text
192216
** to be binary.
193217
**
194
-** (-1) -- The content appears to consist entirely of text, with lines
195
-** delimited by carriage-return, line-feed pairs; however, the
196
-** encoding may not be UTF-8.
197
-**
198218
************************************ WARNING **********************************
199219
**
200220
** This function does not validate that the blob content is properly formed
201221
** UTF-8. It assumes that all code points are the same size. It does not
202222
** validate any code points. It makes no attempt to detect if any [invalid]
203223
** switches between UTF-8 and other encodings occur.
204224
**
205225
** The only code points that this function cares about are the NUL character,
206226
** carriage-return, and line-feed.
227
+**
228
+** Whether or not this function examines the entire contents of the blob is
229
+** officially unspecified.
207230
**
208231
************************************ WARNING **********************************
209232
*/
210
-int looks_like_utf8(const Blob *pContent){
233
+int looks_like_utf8(const Blob *pContent, int *pFlags){
211234
const char *z = blob_buffer(pContent);
212235
unsigned int n = blob_size(pContent);
213
- int j, c;
214
- int result = 1; /* Assume UTF-8 text with no CR/NL */
236
+ int j, c, result = 1; /* Assume UTF-8 text, prove otherwise */
215237
216
- /* Check individual lines.
217
- */
238
+ if( pFlags ) *pFlags = LOOK_NONE;
218239
if( n==0 ) return result; /* Empty file -> text */
219240
c = *z;
220
- if( c==0 ) return 0; /* Zero byte in a file -> binary */
221
- j = (c!='\n');
222
- while( --n>0 ){
223
- c = *++z; ++j;
224
- if( c==0 ) return 0; /* Zero byte in a file -> binary */
225
- if( c=='\n' ){
226
- int c2 = z[-1];
227
- if( c2=='\r' ){
228
- result = -1; /* Contains CR/NL, continue */
229
- }
230
- if( j>LENGTH_MASK ){
231
- return 0; /* Very long line -> binary */
232
- }
233
- j = 0;
234
- }
235
- }
236
- if( j>LENGTH_MASK ){
237
- return 0; /* Very long line -> binary */
241
+ if( c==0 ){
242
+ if( pFlags ) *pFlags |= LOOK_NUL;
243
+ result = 0; /* NUL character in a file -> binary */
244
+ }
245
+ j = (c!='\n');
246
+ if( !j && pFlags ) *pFlags |= LOOK_LONE_LF;
247
+ while( --n>0 ){
248
+ int c2 = c;
249
+ c = *++z; ++j;
250
+ if( c==0 ){
251
+ if( pFlags ) *pFlags |= LOOK_NUL;
252
+ result = 0; /* NUL character in a file -> binary */
253
+ }
254
+ if( c=='\n' ){
255
+ if( pFlags ){
256
+ *pFlags |= (c2=='\r')?LOOK_CRLF:LOOK_LONE_LF;
257
+ }
258
+ if( j>LENGTH_MASK ){
259
+ if( pFlags ) *pFlags |= LOOK_LENGTH;
260
+ result = 0; /* Very long line -> binary */
261
+ }
262
+ j = 0;
263
+ }else if( c2=='\r' && pFlags ){
264
+ *pFlags |= LOOK_LONE_CR;
265
+ }
266
+ }
267
+ if( c=='\r' && pFlags ){
268
+ *pFlags |= LOOK_LONE_CR;
269
+ }
270
+ if( j>LENGTH_MASK ){
271
+ if( pFlags ) *pFlags |= LOOK_LENGTH;
272
+ result = 0; /* Very long line -> binary */
238273
}
239274
return result; /* No problems seen -> not binary */
240275
}
241276
242277
/*
@@ -270,64 +305,80 @@
270305
/*
271306
** This function attempts to scan each logical line within the blob to
272307
** determine the type of content it appears to contain. Possible return
273308
** values are:
274309
**
275
-** (1) -- The content appears to consist entirely of text, with lines
276
-** delimited by line-feed characters; however, the encoding may
277
-** not be UTF-16.
310
+** (1) -- The content appears to consist entirely of text; however, the
311
+** encoding may not be UTF-16.
278312
**
279313
** (0) -- The content appears to be binary because it contains embedded
280314
** NUL characters or an extremely long line. Since this function
281315
** does not understand UTF-8, it may falsely consider UTF-8 text
282316
** to be binary.
283317
**
284
-** (-1) -- The content appears to consist entirely of text, with lines
285
-** delimited by carriage-return, line-feed pairs; however, the
286
-** encoding may not be UTF-16.
287
-**
288318
************************************ WARNING **********************************
289319
**
290320
** This function does not validate that the blob content is properly formed
291321
** UTF-16. It assumes that all code points are the same size. It does not
292322
** validate any code points. It makes no attempt to detect if any [invalid]
293323
** switches between the UTF-16be and UTF-16le encodings occur.
294324
**
295325
** The only code points that this function cares about are the NUL character,
296326
** carriage-return, and line-feed.
327
+**
328
+** Whether or not this function examines the entire contents of the blob is
329
+** officially unspecified.
297330
**
298331
************************************ WARNING **********************************
299332
*/
300
-int looks_like_utf16(const Blob *pContent){
333
+int looks_like_utf16(const Blob *pContent, int *pFlags){
301334
const WCHAR_T *z = (WCHAR_T *)blob_buffer(pContent);
302335
unsigned int n = blob_size(pContent);
303
- int j, c;
304
- int result = 1; /* Assume UTF-16 text with no CR/NL */
305
-
306
- /* Check individual lines.
307
- */
308
- if( n==0 ) return result; /* Empty file -> text */
309
- if( n%2 ) return 0; /* Odd number of bytes -> binary (or UTF-8) */
310
- c = *z;
311
- if( c==0 ) return 0; /* NUL character in a file -> binary */
312
- j = ((c!=UTF16BE_LF) && (c!=UTF16LE_LF));
313
- while( (n-=2)>0 ){
314
- c = *++z; ++j;
315
- if( c==0 ) return 0; /* NUL character in a file -> binary */
316
- if( c==UTF16BE_LF || c==UTF16LE_LF ){
317
- int c2 = z[-1];
318
- if( c2==UTF16BE_CR || c2==UTF16LE_CR ){
319
- result = -1; /* Contains CR/NL, continue */
320
- }
321
- if( j>UTF16_LENGTH_MASK ){
322
- return 0; /* Very long line -> binary */
323
- }
324
- j = 0;
325
- }
326
- }
327
- if( j>UTF16_LENGTH_MASK ){
328
- return 0; /* Very long line -> binary */
336
+ int j, c, result = 1; /* Assume UTF-16 text, prove otherwise */
337
+
338
+ if( pFlags ) *pFlags = LOOK_NONE;
339
+ if( n==0 ) return result; /* Empty file -> text */
340
+ if( n%sizeof(WCHAR_T) ){
341
+ if( pFlags ) *pFlags |= LOOK_ODD;
342
+ result = 0; /* Odd number of bytes -> binary (UTF-8?) */
343
+ if( n<sizeof(WCHAR_T) ) return result; /* One byte -> binary (UTF-8?) */
344
+ }
345
+ c = *z;
346
+ if( c==0 ){
347
+ if( pFlags ) *pFlags |= LOOK_NUL;
348
+ result = 0; /* NUL character in a file -> binary */
349
+ }
350
+ j = ((c!=UTF16BE_LF) && (c!=UTF16LE_LF));
351
+ if( !j && pFlags ) *pFlags |= LOOK_LONE_LF;
352
+ while( 1 ){
353
+ int c2 = c;
354
+ if( n<sizeof(WCHAR_T) ) break;
355
+ n -= sizeof(WCHAR_T);
356
+ c = *++z; ++j;
357
+ if( c==0 ){
358
+ if( pFlags ) *pFlags |= LOOK_NUL;
359
+ result = 0; /* NUL character in a file -> binary */
360
+ }
361
+ if( c==UTF16BE_LF || c==UTF16LE_LF ){
362
+ if( pFlags ){
363
+ *pFlags |= (c2==UTF16BE_CR||c2==UTF16LE_CR)?LOOK_CRLF:LOOK_LONE_LF;
364
+ }
365
+ if( j>UTF16_LENGTH_MASK ){
366
+ if( pFlags ) *pFlags |= LOOK_LENGTH;
367
+ result = 0; /* Very long line -> binary */
368
+ }
369
+ j = 0;
370
+ }else if( (c2==UTF16BE_CR || c2==UTF16LE_CR) && pFlags ){
371
+ *pFlags |= LOOK_LONE_CR;
372
+ }
373
+ }
374
+ if( (c==UTF16BE_CR || c==UTF16LE_CR) && pFlags ){
375
+ *pFlags |= LOOK_LONE_CR;
376
+ }
377
+ if( j>UTF16_LENGTH_MASK ){
378
+ if( pFlags ) *pFlags |= LOOK_LENGTH;
379
+ result = 0; /* Very long line -> binary */
329380
}
330381
return result; /* No problems seen -> not binary */
331382
}
332383
333384
/*
@@ -355,26 +406,36 @@
355406
if( blob_size(pContent)<bomSize ) return 0;
356407
return memcmp(z, bom, bomSize)==0;
357408
}
358409
359410
/*
360
-** This function returns non-zero if the blob starts with a UTF-16le or
361
-** UTF-16be byte-order-mark (BOM).
411
+** This function returns non-zero if the blob starts with a UTF-16
412
+** byte-order-mark (BOM), either in the endianness of the machine
413
+** or in reversed byte order. The UTF-32 BOM is ruled out by checking
414
+** if the UTF-16 BOM is not immediately followed by (utf16) 0.
415
+** pnByte and pbReverse are only set when the function returns 1.
362416
*/
363
-int starts_with_utf16_bom(const Blob *pContent, int *pnByte){
364
- const char *z = blob_buffer(pContent);
365
- int c1;
366
-
367
- if( pnByte ) *pnByte = 2;
368
- if( (blob_size(pContent)<2) || (blob_size(pContent)&1)) return 0;
369
- c1 = ((unsigned short *)z)[0];
370
- if( (c1==0xfeff) || (c1==0xfffe) ){
371
- if( blob_size(pContent) < 4 ) return 1;
372
- c1 = ((unsigned short *)z)[1];
373
- if( c1 != 0 ) return 1;
374
- }
375
- return 0;
417
+int starts_with_utf16_bom(
418
+ const Blob *pContent, /* IN: Blob content to perform BOM detection on. */
419
+ int *pnByte, /* OUT: The number of bytes used for the BOM. */
420
+ int *pbReverse /* OUT: Non-zero for BOM in reverse byte-order. */
421
+){
422
+ const unsigned short *z = (unsigned short *)blob_buffer(pContent);
423
+ int bomSize = sizeof(unsigned short);
424
+ int size = blob_size(pContent);
425
+
426
+ if( size<bomSize ) return 0; /* No: cannot read BOM. */
427
+ if( size>=(2*bomSize) && z[1]==0 ) return 0; /* No: possible UTF-32. */
428
+ if( z[0]==0xfffe ){
429
+ if( pbReverse ) *pbReverse = 1;
430
+ }else if( z[0]==0xfeff ){
431
+ if( pbReverse ) *pbReverse = 0;
432
+ }else{
433
+ return 0; /* No: UTF-16 byte-order-mark not found. */
434
+ }
435
+ if( pnByte ) *pnByte = bomSize;
436
+ return 1; /* Yes. */
376437
}
377438
378439
/*
379440
** Return true if two DLine elements are identical.
380441
*/
@@ -516,11 +577,11 @@
516577
a = xa;
517578
b = xb;
518579
continue;
519580
}
520581
}
521
-
582
+
522583
/* For the current block comprising nr triples, figure out
523584
** how many lines of A and B are to be displayed
524585
*/
525586
if( R[r]>nContext ){
526587
na = nb = nContext;
@@ -871,21 +932,33 @@
871932
/*
872933
** Simplify iStart and iStart2:
873934
**
874935
** * If iStart is a null-change then move iStart2 into iStart
875936
** * Make sure any null-changes are in canonoical form.
937
+** * Make sure all changes are at character boundaries for
938
+** multi-byte characters.
876939
*/
877
-static void sbsSimplifyLine(SbsLine *p){
878
- if( p->iStart2==p->iEnd2 ) p->iStart2 = p->iEnd2 = 0;
940
+static void sbsSimplifyLine(SbsLine *p, const char *z){
941
+ if( p->iStart2==p->iEnd2 ){
942
+ p->iStart2 = p->iEnd2 = 0;
943
+ }else if( p->iStart2 ){
944
+ while( p->iStart2>0 && (z[p->iStart2]&0xc0)==0x80 ) p->iStart2--;
945
+ while( (z[p->iEnd2]&0xc0)==0x80 ) p->iEnd2++;
946
+ }
879947
if( p->iStart==p->iEnd ){
880948
p->iStart = p->iStart2;
881949
p->iEnd = p->iEnd2;
882950
p->zStart = p->zStart2;
883951
p->iStart2 = 0;
884952
p->iEnd2 = 0;
885953
}
886
- if( p->iStart==p->iEnd ) p->iStart = p->iEnd = -1;
954
+ if( p->iStart==p->iEnd ){
955
+ p->iStart = p->iEnd = -1;
956
+ }else if( p->iStart>0 ){
957
+ while( p->iStart>0 && (z[p->iStart]&0xc0)==0x80 ) p->iStart--;
958
+ while( (z[p->iEnd]&0xc0)==0x80 ) p->iEnd++;
959
+ }
887960
}
888961
889962
/*
890963
** Write out lines that have been edited. Adjust the highlight to cover
891964
** only those parts of the line that actually changed.
@@ -897,10 +970,11 @@
897970
DLine *pRight, /* Right line of the change */
898971
int lnRight /* Line number of the right line */
899972
){
900973
int nLeft; /* Length of left line in bytes */
901974
int nRight; /* Length of right line in bytes */
975
+ int nShort; /* Shortest of left and right */
902976
int nPrefix; /* Length of common prefix */
903977
int nSuffix; /* Length of common suffix */
904978
const char *zLeft; /* Text of the left line */
905979
const char *zRight; /* Text of the right line */
906980
int nLeftDiff; /* nLeft - nPrefix - nSuffix */
@@ -912,25 +986,31 @@
912986
913987
nLeft = pLeft->h & LENGTH_MASK;
914988
zLeft = pLeft->z;
915989
nRight = pRight->h & LENGTH_MASK;
916990
zRight = pRight->z;
991
+ nShort = nLeft<nRight ? nLeft : nRight;
917992
918993
nPrefix = 0;
919
- while( nPrefix<nLeft && nPrefix<nRight && zLeft[nPrefix]==zRight[nPrefix] ){
994
+ while( nPrefix<nShort && zLeft[nPrefix]==zRight[nPrefix] ){
920995
nPrefix++;
921996
}
997
+ if( nPrefix<nShort ){
998
+ while( nPrefix>0 && (zLeft[nPrefix]&0xc0)==0x80 ) nPrefix--;
999
+ }
9221000
nSuffix = 0;
923
- if( nPrefix<nLeft && nPrefix<nRight ){
924
- while( nSuffix<nLeft && nSuffix<nRight
925
- && zLeft[nLeft-nSuffix-1]==zRight[nRight-nSuffix-1] ){
1001
+ if( nPrefix<nShort ){
1002
+ while( nSuffix<nShort && zLeft[nLeft-nSuffix-1]==zRight[nRight-nSuffix-1] ){
9261003
nSuffix++;
9271004
}
1005
+ if( nSuffix<nShort ){
1006
+ while( nSuffix>0 && (zLeft[nLeft-nSuffix]&0xc0)==0x80 ) nSuffix--;
1007
+ }
9281008
if( nSuffix==nLeft || nSuffix==nRight ) nPrefix = 0;
9291009
}
930
- if( nPrefix+nSuffix > nLeft ) nSuffix = nLeft - nPrefix;
931
- if( nPrefix+nSuffix > nRight ) nSuffix = nRight - nPrefix;
1010
+ if( nPrefix+nSuffix > nShort ) nPrefix = nShort - nSuffix;
1011
+
9321012
9331013
/* A single chunk of text inserted on the right */
9341014
if( nPrefix+nSuffix==nLeft ){
9351015
sbsWriteLineno(p, lnLeft);
9361016
p->iStart2 = p->iEnd2 = 0;
@@ -986,11 +1066,11 @@
9861066
p->zStart = zClassChng;
9871067
}
9881068
p->iStart2 = nPrefix + aLCS[1];
9891069
p->iEnd2 = nLeft - nSuffix;
9901070
p->zStart2 = aLCS[3]==nRightDiff ? zClassRm : zClassChng;
991
- sbsSimplifyLine(p);
1071
+ sbsSimplifyLine(p, zLeft+nPrefix);
9921072
sbsWriteText(p, pLeft, SBS_PAD);
9931073
sbsWrite(p, " | ", 3);
9941074
sbsWriteLineno(p, lnRight);
9951075
p->iStart = nPrefix;
9961076
p->iEnd = nPrefix + aLCS[2];
@@ -1001,11 +1081,11 @@
10011081
p->zStart = zClassChng;
10021082
}
10031083
p->iStart2 = nPrefix + aLCS[3];
10041084
p->iEnd2 = nRight - nSuffix;
10051085
p->zStart2 = aLCS[1]==nLeftDiff ? zClassAdd : zClassChng;
1006
- sbsSimplifyLine(p);
1086
+ sbsSimplifyLine(p, zRight+nPrefix);
10071087
sbsWriteText(p, pRight, SBS_NEWLINE);
10081088
return;
10091089
}
10101090
10111091
/* If all else fails, show a single big change between left and right */
@@ -1220,11 +1300,11 @@
12201300
** Then this is probably an alignment that will be difficult for humans
12211301
** to read. So instead, just show all of the right side inserted followed
12221302
** by all of the left side deleted.
12231303
**
12241304
** The coefficients for conditions (1) and (2) above are determined by
1225
- ** experimentation.
1305
+ ** experimentation.
12261306
*/
12271307
mxLen = nLeft>nRight ? nLeft : nRight;
12281308
if( i*4>mxLen*5 && (nMatch==0 || iMatch/nMatch>15) ){
12291309
memset(aM, 4, mnLen);
12301310
if( nLeft>mnLen ) memset(aM+mnLen, 1, nLeft-mnLen);
@@ -1406,11 +1486,11 @@
14061486
/* Delete one line from the left */
14071487
s.n = 0;
14081488
sbsWriteLineno(&s, a);
14091489
s.iStart = 0;
14101490
s.zStart = "<span class=\"diffrm\">";
1411
- s.iEnd = s.width;
1491
+ s.iEnd = LENGTH(&A[a]);
14121492
sbsWriteText(&s, &A[a], SBS_PAD);
14131493
if( s.escHtml ){
14141494
sbsWrite(&s, " &lt;\n", 6);
14151495
}else{
14161496
sbsWrite(&s, " <\n", 3);
@@ -1439,11 +1519,11 @@
14391519
sbsWrite(&s, " > ", 3);
14401520
}
14411521
sbsWriteLineno(&s, b);
14421522
s.iStart = 0;
14431523
s.zStart = "<span class=\"diffadd\">";
1444
- s.iEnd = s.width;
1524
+ s.iEnd = LENGTH(&B[b]);
14451525
sbsWriteText(&s, &B[b], SBS_NEWLINE);
14461526
blob_append(pOut, s.zLine, s.n);
14471527
assert( mb>0 );
14481528
mb--;
14491529
b++;
@@ -1451,25 +1531,25 @@
14511531
/* Delete from the left and insert on the right */
14521532
s.n = 0;
14531533
sbsWriteLineno(&s, a);
14541534
s.iStart = 0;
14551535
s.zStart = "<span class=\"diffrm\">";
1456
- s.iEnd = s.width;
1536
+ s.iEnd = LENGTH(&A[a]);
14571537
sbsWriteText(&s, &A[a], SBS_PAD);
14581538
sbsWrite(&s, " | ", 3);
14591539
sbsWriteLineno(&s, b);
14601540
s.iStart = 0;
14611541
s.zStart = "<span class=\"diffadd\">";
1462
- s.iEnd = s.width;
1542
+ s.iEnd = LENGTH(&B[b]);
14631543
sbsWriteText(&s, &B[b], SBS_NEWLINE);
14641544
blob_append(pOut, s.zLine, s.n);
14651545
ma--;
14661546
mb--;
14671547
a++;
14681548
b++;
14691549
}
1470
-
1550
+
14711551
}
14721552
fossil_free(alignment);
14731553
if( i<nr-1 ){
14741554
m = R[r+i*3+3];
14751555
for(j=0; j<m; j++){
@@ -1954,11 +2034,30 @@
19542034
return 0;
19552035
}
19562036
19572037
/* Compute the difference */
19582038
diff_all(&c);
1959
- if( (diffFlags & DIFF_NOOPT)==0 ) diff_optimize(&c);
2039
+ if( (diffFlags & DIFF_NOTTOOBIG)!=0 ){
2040
+ int i, m, n;
2041
+ int *a = c.aEdit;
2042
+ int mx = c.nEdit;
2043
+ for(i=m=n=0; i<mx; i+=3){ m += a[i]; n += a[i+1]+a[i+2]; }
2044
+ if( n>10000 ){
2045
+ fossil_free(c.aFrom);
2046
+ fossil_free(c.aTo);
2047
+ fossil_free(c.aEdit);
2048
+ if( diffFlags & DIFF_HTML ){
2049
+ blob_append(pOut, DIFF_TOO_MANY_CHANGES_HTML, -1);
2050
+ }else{
2051
+ blob_append(pOut, DIFF_TOO_MANY_CHANGES_TXT, -1);
2052
+ }
2053
+ return 0;
2054
+ }
2055
+ }
2056
+ if( (diffFlags & DIFF_NOOPT)==0 ){
2057
+ diff_optimize(&c);
2058
+ }
19602059
19612060
if( pOut ){
19622061
/* Compute a context or side-by-side diff into pOut */
19632062
if( diffFlags & DIFF_SIDEBYSIDE ){
19642063
sbsDiff(&c, pOut, pRe, diffFlags);
@@ -2205,11 +2304,12 @@
22052304
fossil_print("%10s: %.*s\n", zSrc, x.aOrig[i].n, x.aOrig[i].z);
22062305
}
22072306
}
22082307
22092308
/* Annotation flags */
2210
-#define ANN_FILE_VERS 0x001 /* Show file version rather than commit version */
2309
+#define ANN_FILE_VERS 0x01 /* Show file vers rather than commit vers */
2310
+#define ANN_FILE_ANCEST 0x02 /* Prefer check-ins in the ANCESTOR table */
22112311
22122312
/*
22132313
** Compute a complete annotation on a file. The file is identified
22142314
** by its filename number (filename.fnid) and the baseline in which
22152315
** it was checked in (mlink.mid).
@@ -2243,11 +2343,11 @@
22432343
if( !content_get(rid, &toAnnotate) ){
22442344
fossil_panic("unable to retrieve content of artifact #%d", rid);
22452345
}
22462346
if( iLimit<=0 ) iLimit = 1000000000;
22472347
annotation_start(p, &toAnnotate);
2248
-
2348
+
22492349
db_prepare(&q,
22502350
"SELECT (SELECT uuid FROM blob WHERE rid=mlink.%s),"
22512351
" (SELECT uuid FROM blob WHERE rid=mlink.fid),"
22522352
" (SELECT uuid FROM blob WHERE rid=mlink.pid),"
22532353
" date(event.mtime),"
@@ -2254,14 +2354,16 @@
22542354
" coalesce(event.euser,event.user),"
22552355
" mlink.pid"
22562356
" FROM mlink, event"
22572357
" WHERE mlink.fid=:rid"
22582358
" AND event.objid=mlink.mid"
2259
- " ORDER BY event.mtime",
2260
- (annFlags & ANN_FILE_VERS)!=0 ? "fid" : "mid"
2359
+ " ORDER BY %s event.mtime",
2360
+ (annFlags & ANN_FILE_VERS)!=0 ? "fid" : "mid",
2361
+ (annFlags & ANN_FILE_ANCEST)!=0 ?
2362
+ "(mlink.mid IN (SELECT rid FROM ancestor)) DESC,":""
22612363
);
2262
-
2364
+
22632365
db_bind_int(&q, ":rid", rid);
22642366
if( iLimit==0 ) iLimit = 1000000000;
22652367
while( rid && iLimit>cnt && db_step(&q)==SQLITE_ROW ){
22662368
const char *zUuid = db_column_text(&q, 0);
22672369
const char *zUuidFile = db_column_text(&q, 1);
@@ -2313,11 +2415,11 @@
23132415
void annotation_page(void){
23142416
int mid;
23152417
int fnid;
23162418
int i;
23172419
int iLimit;
2318
- int annFlags = 0;
2420
+ int annFlags = ANN_FILE_ANCEST;
23192421
int showLn = 0; /* True if line numbers should be shown */
23202422
char zLn[10]; /* Line number buffer */
23212423
char zFormat[10]; /* Format string for line numbers */
23222424
Annotator ann;
23232425
@@ -2329,10 +2431,11 @@
23292431
if( mid==0 || fnid==0 ){ fossil_redirect_home(); }
23302432
iLimit = atoi(PD("limit","-1"));
23312433
if( !db_exists("SELECT 1 FROM mlink WHERE mid=%d AND fnid=%d",mid,fnid) ){
23322434
fossil_redirect_home();
23332435
}
2436
+ compute_direct_ancestors(mid, 10000000);
23342437
style_header("File Annotation");
23352438
if( P("filevers") ) annFlags |= ANN_FILE_VERS;
23362439
annotate_file(&ann, P("filename"), fnid, mid, g.perm.Hyperlink, iLimit, annFlags);
23372440
if( P("log") ){
23382441
int i;
@@ -2395,11 +2498,11 @@
23952498
if( zLimit==0 || zLimit[0]==0 ) zLimit = "-1";
23962499
iLimit = atoi(zLimit);
23972500
showLog = find_option("log",0,0)!=0;
23982501
fileVers = find_option("filevers",0,0)!=0;
23992502
db_must_be_within_tree();
2400
- if (g.argc<3) {
2503
+ if( g.argc<3 ) {
24012504
usage("FILENAME");
24022505
}
24032506
file_tree_name(g.argv[2], &treename, 1);
24042507
zFilename = blob_str(&treename);
24052508
fnid = db_int(0, "SELECT fnid FROM filename WHERE name=%Q", zFilename);
@@ -2409,11 +2512,11 @@
24092512
fid = db_int(0, "SELECT rid FROM vfile WHERE pathname=%Q", zFilename);
24102513
if( fid==0 ){
24112514
fossil_fatal("not part of current checkout: %s", zFilename);
24122515
}
24132516
cid = db_lget_int("checkout", 0);
2414
- if (cid == 0){
2517
+ if( cid == 0 ){
24152518
fossil_fatal("Not in a checkout");
24162519
}
24172520
if( iLimit<=0 ) iLimit = 1000000000;
24182521
compute_direct_ancestors(cid, iLimit);
24192522
mid = db_int(0, "SELECT mlink.mid FROM mlink, ancestor "
@@ -2422,10 +2525,11 @@
24222525
fid, fnid);
24232526
if( mid==0 ){
24242527
fossil_panic("unable to find manifest");
24252528
}
24262529
if( fileVers ) annFlags |= ANN_FILE_VERS;
2530
+ annFlags |= ANN_FILE_ANCEST;
24272531
annotate_file(&ann, zFilename, fnid, mid, 0, iLimit, annFlags);
24282532
if( showLog ){
24292533
for(i=0; i<ann.nVers; i++){
24302534
printf("version %3d: %s\n", i+1, ann.azVers[i]);
24312535
}
@@ -2434,5 +2538,42 @@
24342538
for(i=0; i<ann.nOrig; i++){
24352539
fossil_print("%s: %.*s\n",
24362540
ann.aOrig[i].zSrc, ann.aOrig[i].n, ann.aOrig[i].z);
24372541
}
24382542
}
2543
+
2544
+/*
2545
+** COMMAND: test-looks-like-utf
2546
+**
2547
+** Usage: %fossil test-looks-like-utf FILENAME
2548
+**
2549
+** FILENAME is the name of a file to check for textual content in the UTF-8
2550
+** and/or UTF-16 encodings.
2551
+*/
2552
+void looks_like_utf_test_cmd(void){
2553
+ Blob blob; /* the contents of the specified file */
2554
+ int eType; /* return value of looks_like_utf8/utf16() */
2555
+ int fUtf8; /* return value of starts_with_utf8_bom() */
2556
+ int fUtf16; /* return value of starts_with_utf16_bom() */
2557
+ int lookFlags; /* output flags from looks_like_utf8/utf16() */
2558
+ if( g.argc<3 ) usage("FILENAME");
2559
+ blob_read_from_file(&blob, g.argv[2]);
2560
+ fUtf8 = starts_with_utf8_bom(&blob, 0);
2561
+ fUtf16 = starts_with_utf16_bom(&blob, 0, 0);
2562
+ eType = fUtf16 ? looks_like_utf16(&blob, &lookFlags) :
2563
+ looks_like_utf8(&blob, &lookFlags);
2564
+ fossil_print("File \"%s\" has %d bytes.\n",g.argv[2],blob_size(&blob));
2565
+ fossil_print("Starts with UTF-8 BOM: %s\n",fUtf8?"yes":"no");
2566
+ fossil_print("Starts with UTF-16 BOM: %s\n",fUtf16?"yes":"no");
2567
+ fossil_print("Looks like UTF-%s: %s\n",fUtf16?"16":"8",eType?"yes":"no");
2568
+ fossil_print("Has flag LOOK_NUL: %s\n",(lookFlags&LOOK_NUL)?"yes":"no");
2569
+ fossil_print("Has flag LOOK_CR: %s\n",(lookFlags&LOOK_CR)?"yes":"no");
2570
+ fossil_print("Has flag LOOK_LONE_CR: %s\n",
2571
+ (lookFlags&LOOK_LONE_CR)?"yes":"no");
2572
+ fossil_print("Has flag LOOK_LF: %s\n",(lookFlags&LOOK_LF)?"yes":"no");
2573
+ fossil_print("Has flag LOOK_LONE_LF: %s\n",
2574
+ (lookFlags&LOOK_LONE_LF)?"yes":"no");
2575
+ fossil_print("Has flag LOOK_CRLF: %s\n",(lookFlags&LOOK_CRLF)?"yes":"no");
2576
+ fossil_print("Has flag LOOK_LENGTH: %s\n",(lookFlags&LOOK_LENGTH)?"yes":"no");
2577
+ fossil_print("Has flag LOOK_ODD: %s\n",(lookFlags&LOOK_ODD)?"yes":"no");
2578
+ blob_reset(&blob);
2579
+}
24392580
--- src/diff.c
+++ src/diff.c
@@ -39,10 +39,11 @@
39 #define DIFF_LINENO ((u64)0x20000000) /* Show line numbers */
40 #define DIFF_WS_WARNING ((u64)0x40000000) /* Warn about whitespace */
41 #define DIFF_NOOPT (((u64)0x01)<<32) /* Suppress optimizations (debug) */
42 #define DIFF_INVERT (((u64)0x02)<<32) /* Invert the diff (debug) */
43 #define DIFF_CONTEXT_EX (((u64)0x04)<<32) /* Use context even if zero */
 
44
45 /*
46 ** These error messages are shared in multiple locations. They are defined
47 ** here for consistency.
48 */
@@ -50,11 +51,35 @@
50 "cannot compute difference between binary files\n"
51
52 #define DIFF_CANNOT_COMPUTE_SYMLINK \
53 "cannot compute difference between symlink and regular file\n"
54
55 #define looks_like_binary(blob) (looks_like_utf8((blob)) == 0)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
56 #endif /* INTERFACE */
57
58 /*
59 ** Maximum length of a line in a text file, in bytes. (2**13 = 8192 bytes)
60 */
@@ -180,63 +205,73 @@
180 /*
181 ** This function attempts to scan each logical line within the blob to
182 ** determine the type of content it appears to contain. Possible return
183 ** values are:
184 **
185 ** (1) -- The content appears to consist entirely of text, with lines
186 ** delimited by line-feed characters; however, the encoding may
187 ** not be UTF-8.
188 **
189 ** (0) -- The content appears to be binary because it contains embedded
190 ** NUL characters or an extremely long line. Since this function
191 ** does not understand UTF-16, it may falsely consider UTF-16 text
192 ** to be binary.
193 **
194 ** (-1) -- The content appears to consist entirely of text, with lines
195 ** delimited by carriage-return, line-feed pairs; however, the
196 ** encoding may not be UTF-8.
197 **
198 ************************************ WARNING **********************************
199 **
200 ** This function does not validate that the blob content is properly formed
201 ** UTF-8. It assumes that all code points are the same size. It does not
202 ** validate any code points. It makes no attempt to detect if any [invalid]
203 ** switches between UTF-8 and other encodings occur.
204 **
205 ** The only code points that this function cares about are the NUL character,
206 ** carriage-return, and line-feed.
 
 
 
207 **
208 ************************************ WARNING **********************************
209 */
210 int looks_like_utf8(const Blob *pContent){
211 const char *z = blob_buffer(pContent);
212 unsigned int n = blob_size(pContent);
213 int j, c;
214 int result = 1; /* Assume UTF-8 text with no CR/NL */
215
216 /* Check individual lines.
217 */
218 if( n==0 ) return result; /* Empty file -> text */
219 c = *z;
220 if( c==0 ) return 0; /* Zero byte in a file -> binary */
221 j = (c!='\n');
222 while( --n>0 ){
223 c = *++z; ++j;
224 if( c==0 ) return 0; /* Zero byte in a file -> binary */
225 if( c=='\n' ){
226 int c2 = z[-1];
227 if( c2=='\r' ){
228 result = -1; /* Contains CR/NL, continue */
229 }
230 if( j>LENGTH_MASK ){
231 return 0; /* Very long line -> binary */
232 }
233 j = 0;
234 }
235 }
236 if( j>LENGTH_MASK ){
237 return 0; /* Very long line -> binary */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
238 }
239 return result; /* No problems seen -> not binary */
240 }
241
242 /*
@@ -270,64 +305,80 @@
270 /*
271 ** This function attempts to scan each logical line within the blob to
272 ** determine the type of content it appears to contain. Possible return
273 ** values are:
274 **
275 ** (1) -- The content appears to consist entirely of text, with lines
276 ** delimited by line-feed characters; however, the encoding may
277 ** not be UTF-16.
278 **
279 ** (0) -- The content appears to be binary because it contains embedded
280 ** NUL characters or an extremely long line. Since this function
281 ** does not understand UTF-8, it may falsely consider UTF-8 text
282 ** to be binary.
283 **
284 ** (-1) -- The content appears to consist entirely of text, with lines
285 ** delimited by carriage-return, line-feed pairs; however, the
286 ** encoding may not be UTF-16.
287 **
288 ************************************ WARNING **********************************
289 **
290 ** This function does not validate that the blob content is properly formed
291 ** UTF-16. It assumes that all code points are the same size. It does not
292 ** validate any code points. It makes no attempt to detect if any [invalid]
293 ** switches between the UTF-16be and UTF-16le encodings occur.
294 **
295 ** The only code points that this function cares about are the NUL character,
296 ** carriage-return, and line-feed.
 
 
 
297 **
298 ************************************ WARNING **********************************
299 */
300 int looks_like_utf16(const Blob *pContent){
301 const WCHAR_T *z = (WCHAR_T *)blob_buffer(pContent);
302 unsigned int n = blob_size(pContent);
303 int j, c;
304 int result = 1; /* Assume UTF-16 text with no CR/NL */
305
306 /* Check individual lines.
307 */
308 if( n==0 ) return result; /* Empty file -> text */
309 if( n%2 ) return 0; /* Odd number of bytes -> binary (or UTF-8) */
310 c = *z;
311 if( c==0 ) return 0; /* NUL character in a file -> binary */
312 j = ((c!=UTF16BE_LF) && (c!=UTF16LE_LF));
313 while( (n-=2)>0 ){
314 c = *++z; ++j;
315 if( c==0 ) return 0; /* NUL character in a file -> binary */
316 if( c==UTF16BE_LF || c==UTF16LE_LF ){
317 int c2 = z[-1];
318 if( c2==UTF16BE_CR || c2==UTF16LE_CR ){
319 result = -1; /* Contains CR/NL, continue */
320 }
321 if( j>UTF16_LENGTH_MASK ){
322 return 0; /* Very long line -> binary */
323 }
324 j = 0;
325 }
326 }
327 if( j>UTF16_LENGTH_MASK ){
328 return 0; /* Very long line -> binary */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
329 }
330 return result; /* No problems seen -> not binary */
331 }
332
333 /*
@@ -355,26 +406,36 @@
355 if( blob_size(pContent)<bomSize ) return 0;
356 return memcmp(z, bom, bomSize)==0;
357 }
358
359 /*
360 ** This function returns non-zero if the blob starts with a UTF-16le or
361 ** UTF-16be byte-order-mark (BOM).
 
 
 
362 */
363 int starts_with_utf16_bom(const Blob *pContent, int *pnByte){
364 const char *z = blob_buffer(pContent);
365 int c1;
366
367 if( pnByte ) *pnByte = 2;
368 if( (blob_size(pContent)<2) || (blob_size(pContent)&1)) return 0;
369 c1 = ((unsigned short *)z)[0];
370 if( (c1==0xfeff) || (c1==0xfffe) ){
371 if( blob_size(pContent) < 4 ) return 1;
372 c1 = ((unsigned short *)z)[1];
373 if( c1 != 0 ) return 1;
374 }
375 return 0;
 
 
 
 
 
 
 
376 }
377
378 /*
379 ** Return true if two DLine elements are identical.
380 */
@@ -516,11 +577,11 @@
516 a = xa;
517 b = xb;
518 continue;
519 }
520 }
521
522 /* For the current block comprising nr triples, figure out
523 ** how many lines of A and B are to be displayed
524 */
525 if( R[r]>nContext ){
526 na = nb = nContext;
@@ -871,21 +932,33 @@
871 /*
872 ** Simplify iStart and iStart2:
873 **
874 ** * If iStart is a null-change then move iStart2 into iStart
875 ** * Make sure any null-changes are in canonoical form.
 
 
876 */
877 static void sbsSimplifyLine(SbsLine *p){
878 if( p->iStart2==p->iEnd2 ) p->iStart2 = p->iEnd2 = 0;
 
 
 
 
 
879 if( p->iStart==p->iEnd ){
880 p->iStart = p->iStart2;
881 p->iEnd = p->iEnd2;
882 p->zStart = p->zStart2;
883 p->iStart2 = 0;
884 p->iEnd2 = 0;
885 }
886 if( p->iStart==p->iEnd ) p->iStart = p->iEnd = -1;
 
 
 
 
 
887 }
888
889 /*
890 ** Write out lines that have been edited. Adjust the highlight to cover
891 ** only those parts of the line that actually changed.
@@ -897,10 +970,11 @@
897 DLine *pRight, /* Right line of the change */
898 int lnRight /* Line number of the right line */
899 ){
900 int nLeft; /* Length of left line in bytes */
901 int nRight; /* Length of right line in bytes */
 
902 int nPrefix; /* Length of common prefix */
903 int nSuffix; /* Length of common suffix */
904 const char *zLeft; /* Text of the left line */
905 const char *zRight; /* Text of the right line */
906 int nLeftDiff; /* nLeft - nPrefix - nSuffix */
@@ -912,25 +986,31 @@
912
913 nLeft = pLeft->h & LENGTH_MASK;
914 zLeft = pLeft->z;
915 nRight = pRight->h & LENGTH_MASK;
916 zRight = pRight->z;
 
917
918 nPrefix = 0;
919 while( nPrefix<nLeft && nPrefix<nRight && zLeft[nPrefix]==zRight[nPrefix] ){
920 nPrefix++;
921 }
 
 
 
922 nSuffix = 0;
923 if( nPrefix<nLeft && nPrefix<nRight ){
924 while( nSuffix<nLeft && nSuffix<nRight
925 && zLeft[nLeft-nSuffix-1]==zRight[nRight-nSuffix-1] ){
926 nSuffix++;
927 }
 
 
 
928 if( nSuffix==nLeft || nSuffix==nRight ) nPrefix = 0;
929 }
930 if( nPrefix+nSuffix > nLeft ) nSuffix = nLeft - nPrefix;
931 if( nPrefix+nSuffix > nRight ) nSuffix = nRight - nPrefix;
932
933 /* A single chunk of text inserted on the right */
934 if( nPrefix+nSuffix==nLeft ){
935 sbsWriteLineno(p, lnLeft);
936 p->iStart2 = p->iEnd2 = 0;
@@ -986,11 +1066,11 @@
986 p->zStart = zClassChng;
987 }
988 p->iStart2 = nPrefix + aLCS[1];
989 p->iEnd2 = nLeft - nSuffix;
990 p->zStart2 = aLCS[3]==nRightDiff ? zClassRm : zClassChng;
991 sbsSimplifyLine(p);
992 sbsWriteText(p, pLeft, SBS_PAD);
993 sbsWrite(p, " | ", 3);
994 sbsWriteLineno(p, lnRight);
995 p->iStart = nPrefix;
996 p->iEnd = nPrefix + aLCS[2];
@@ -1001,11 +1081,11 @@
1001 p->zStart = zClassChng;
1002 }
1003 p->iStart2 = nPrefix + aLCS[3];
1004 p->iEnd2 = nRight - nSuffix;
1005 p->zStart2 = aLCS[1]==nLeftDiff ? zClassAdd : zClassChng;
1006 sbsSimplifyLine(p);
1007 sbsWriteText(p, pRight, SBS_NEWLINE);
1008 return;
1009 }
1010
1011 /* If all else fails, show a single big change between left and right */
@@ -1220,11 +1300,11 @@
1220 ** Then this is probably an alignment that will be difficult for humans
1221 ** to read. So instead, just show all of the right side inserted followed
1222 ** by all of the left side deleted.
1223 **
1224 ** The coefficients for conditions (1) and (2) above are determined by
1225 ** experimentation.
1226 */
1227 mxLen = nLeft>nRight ? nLeft : nRight;
1228 if( i*4>mxLen*5 && (nMatch==0 || iMatch/nMatch>15) ){
1229 memset(aM, 4, mnLen);
1230 if( nLeft>mnLen ) memset(aM+mnLen, 1, nLeft-mnLen);
@@ -1406,11 +1486,11 @@
1406 /* Delete one line from the left */
1407 s.n = 0;
1408 sbsWriteLineno(&s, a);
1409 s.iStart = 0;
1410 s.zStart = "<span class=\"diffrm\">";
1411 s.iEnd = s.width;
1412 sbsWriteText(&s, &A[a], SBS_PAD);
1413 if( s.escHtml ){
1414 sbsWrite(&s, " &lt;\n", 6);
1415 }else{
1416 sbsWrite(&s, " <\n", 3);
@@ -1439,11 +1519,11 @@
1439 sbsWrite(&s, " > ", 3);
1440 }
1441 sbsWriteLineno(&s, b);
1442 s.iStart = 0;
1443 s.zStart = "<span class=\"diffadd\">";
1444 s.iEnd = s.width;
1445 sbsWriteText(&s, &B[b], SBS_NEWLINE);
1446 blob_append(pOut, s.zLine, s.n);
1447 assert( mb>0 );
1448 mb--;
1449 b++;
@@ -1451,25 +1531,25 @@
1451 /* Delete from the left and insert on the right */
1452 s.n = 0;
1453 sbsWriteLineno(&s, a);
1454 s.iStart = 0;
1455 s.zStart = "<span class=\"diffrm\">";
1456 s.iEnd = s.width;
1457 sbsWriteText(&s, &A[a], SBS_PAD);
1458 sbsWrite(&s, " | ", 3);
1459 sbsWriteLineno(&s, b);
1460 s.iStart = 0;
1461 s.zStart = "<span class=\"diffadd\">";
1462 s.iEnd = s.width;
1463 sbsWriteText(&s, &B[b], SBS_NEWLINE);
1464 blob_append(pOut, s.zLine, s.n);
1465 ma--;
1466 mb--;
1467 a++;
1468 b++;
1469 }
1470
1471 }
1472 fossil_free(alignment);
1473 if( i<nr-1 ){
1474 m = R[r+i*3+3];
1475 for(j=0; j<m; j++){
@@ -1954,11 +2034,30 @@
1954 return 0;
1955 }
1956
1957 /* Compute the difference */
1958 diff_all(&c);
1959 if( (diffFlags & DIFF_NOOPT)==0 ) diff_optimize(&c);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1960
1961 if( pOut ){
1962 /* Compute a context or side-by-side diff into pOut */
1963 if( diffFlags & DIFF_SIDEBYSIDE ){
1964 sbsDiff(&c, pOut, pRe, diffFlags);
@@ -2205,11 +2304,12 @@
2205 fossil_print("%10s: %.*s\n", zSrc, x.aOrig[i].n, x.aOrig[i].z);
2206 }
2207 }
2208
2209 /* Annotation flags */
2210 #define ANN_FILE_VERS 0x001 /* Show file version rather than commit version */
 
2211
2212 /*
2213 ** Compute a complete annotation on a file. The file is identified
2214 ** by its filename number (filename.fnid) and the baseline in which
2215 ** it was checked in (mlink.mid).
@@ -2243,11 +2343,11 @@
2243 if( !content_get(rid, &toAnnotate) ){
2244 fossil_panic("unable to retrieve content of artifact #%d", rid);
2245 }
2246 if( iLimit<=0 ) iLimit = 1000000000;
2247 annotation_start(p, &toAnnotate);
2248
2249 db_prepare(&q,
2250 "SELECT (SELECT uuid FROM blob WHERE rid=mlink.%s),"
2251 " (SELECT uuid FROM blob WHERE rid=mlink.fid),"
2252 " (SELECT uuid FROM blob WHERE rid=mlink.pid),"
2253 " date(event.mtime),"
@@ -2254,14 +2354,16 @@
2254 " coalesce(event.euser,event.user),"
2255 " mlink.pid"
2256 " FROM mlink, event"
2257 " WHERE mlink.fid=:rid"
2258 " AND event.objid=mlink.mid"
2259 " ORDER BY event.mtime",
2260 (annFlags & ANN_FILE_VERS)!=0 ? "fid" : "mid"
 
 
2261 );
2262
2263 db_bind_int(&q, ":rid", rid);
2264 if( iLimit==0 ) iLimit = 1000000000;
2265 while( rid && iLimit>cnt && db_step(&q)==SQLITE_ROW ){
2266 const char *zUuid = db_column_text(&q, 0);
2267 const char *zUuidFile = db_column_text(&q, 1);
@@ -2313,11 +2415,11 @@
2313 void annotation_page(void){
2314 int mid;
2315 int fnid;
2316 int i;
2317 int iLimit;
2318 int annFlags = 0;
2319 int showLn = 0; /* True if line numbers should be shown */
2320 char zLn[10]; /* Line number buffer */
2321 char zFormat[10]; /* Format string for line numbers */
2322 Annotator ann;
2323
@@ -2329,10 +2431,11 @@
2329 if( mid==0 || fnid==0 ){ fossil_redirect_home(); }
2330 iLimit = atoi(PD("limit","-1"));
2331 if( !db_exists("SELECT 1 FROM mlink WHERE mid=%d AND fnid=%d",mid,fnid) ){
2332 fossil_redirect_home();
2333 }
 
2334 style_header("File Annotation");
2335 if( P("filevers") ) annFlags |= ANN_FILE_VERS;
2336 annotate_file(&ann, P("filename"), fnid, mid, g.perm.Hyperlink, iLimit, annFlags);
2337 if( P("log") ){
2338 int i;
@@ -2395,11 +2498,11 @@
2395 if( zLimit==0 || zLimit[0]==0 ) zLimit = "-1";
2396 iLimit = atoi(zLimit);
2397 showLog = find_option("log",0,0)!=0;
2398 fileVers = find_option("filevers",0,0)!=0;
2399 db_must_be_within_tree();
2400 if (g.argc<3) {
2401 usage("FILENAME");
2402 }
2403 file_tree_name(g.argv[2], &treename, 1);
2404 zFilename = blob_str(&treename);
2405 fnid = db_int(0, "SELECT fnid FROM filename WHERE name=%Q", zFilename);
@@ -2409,11 +2512,11 @@
2409 fid = db_int(0, "SELECT rid FROM vfile WHERE pathname=%Q", zFilename);
2410 if( fid==0 ){
2411 fossil_fatal("not part of current checkout: %s", zFilename);
2412 }
2413 cid = db_lget_int("checkout", 0);
2414 if (cid == 0){
2415 fossil_fatal("Not in a checkout");
2416 }
2417 if( iLimit<=0 ) iLimit = 1000000000;
2418 compute_direct_ancestors(cid, iLimit);
2419 mid = db_int(0, "SELECT mlink.mid FROM mlink, ancestor "
@@ -2422,10 +2525,11 @@
2422 fid, fnid);
2423 if( mid==0 ){
2424 fossil_panic("unable to find manifest");
2425 }
2426 if( fileVers ) annFlags |= ANN_FILE_VERS;
 
2427 annotate_file(&ann, zFilename, fnid, mid, 0, iLimit, annFlags);
2428 if( showLog ){
2429 for(i=0; i<ann.nVers; i++){
2430 printf("version %3d: %s\n", i+1, ann.azVers[i]);
2431 }
@@ -2434,5 +2538,42 @@
2434 for(i=0; i<ann.nOrig; i++){
2435 fossil_print("%s: %.*s\n",
2436 ann.aOrig[i].zSrc, ann.aOrig[i].n, ann.aOrig[i].z);
2437 }
2438 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2439
--- src/diff.c
+++ src/diff.c
@@ -39,10 +39,11 @@
39 #define DIFF_LINENO ((u64)0x20000000) /* Show line numbers */
40 #define DIFF_WS_WARNING ((u64)0x40000000) /* Warn about whitespace */
41 #define DIFF_NOOPT (((u64)0x01)<<32) /* Suppress optimizations (debug) */
42 #define DIFF_INVERT (((u64)0x02)<<32) /* Invert the diff (debug) */
43 #define DIFF_CONTEXT_EX (((u64)0x04)<<32) /* Use context even if zero */
44 #define DIFF_NOTTOOBIG (((u64)0x08)<<32) /* Only display if not too big */
45
46 /*
47 ** These error messages are shared in multiple locations. They are defined
48 ** here for consistency.
49 */
@@ -50,11 +51,35 @@
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) (looks_like_utf8((blob), 0) == 0)
67
68 /*
69 ** Output flags for the looks_like_utf8() and looks_like_utf16() routines used
70 ** to convey status information about the blob content.
71 */
72 #define LOOK_NONE ((int)0x00000000) /* Nothing special was found. */
73 #define LOOK_NUL ((int)0x00000001) /* One or more NUL chars were found. */
74 #define LOOK_LONE_CR ((int)0x00000002) /* An unpaired CR char was found. */
75 #define LOOK_LONE_LF ((int)0x00000004) /* An unpaired LF char was found. */
76 #define LOOK_CRLF ((int)0x00000008) /* One or more CR/LF pairs were found. */
77 #define LOOK_LENGTH ((int)0x00000010) /* An over length line was found. */
78 #define LOOK_ODD ((int)0x00000020) /* An odd number of bytes was found. */
79 #define LOOK_CR (LOOK_LONE_CR|LOOK_CRLF) /* One or more CR chars were found. */
80 #define LOOK_LF (LOOK_LONE_LF|LOOK_CRLF) /* One or more LF chars were found. */
81 #endif /* INTERFACE */
82
83 /*
84 ** Maximum length of a line in a text file, in bytes. (2**13 = 8192 bytes)
85 */
@@ -180,63 +205,73 @@
205 /*
206 ** This function attempts to scan each logical line within the blob to
207 ** determine the type of content it appears to contain. Possible return
208 ** values are:
209 **
210 ** (1) -- The content appears to consist entirely of text; however, the
211 ** encoding may not be UTF-8.
 
212 **
213 ** (0) -- The content appears to be binary because it contains embedded
214 ** NUL characters or an extremely long line. Since this function
215 ** does not understand UTF-16, it may falsely consider UTF-16 text
216 ** to be binary.
217 **
 
 
 
 
218 ************************************ WARNING **********************************
219 **
220 ** This function does not validate that the blob content is properly formed
221 ** UTF-8. It assumes that all code points are the same size. It does not
222 ** validate any code points. It makes no attempt to detect if any [invalid]
223 ** switches between UTF-8 and other encodings occur.
224 **
225 ** The only code points that this function cares about are the NUL character,
226 ** carriage-return, and line-feed.
227 **
228 ** Whether or not this function examines the entire contents of the blob is
229 ** officially unspecified.
230 **
231 ************************************ WARNING **********************************
232 */
233 int looks_like_utf8(const Blob *pContent, int *pFlags){
234 const char *z = blob_buffer(pContent);
235 unsigned int n = blob_size(pContent);
236 int j, c, result = 1; /* Assume UTF-8 text, prove otherwise */
 
237
238 if( pFlags ) *pFlags = LOOK_NONE;
 
239 if( n==0 ) return result; /* Empty file -> text */
240 c = *z;
241 if( c==0 ){
242 if( pFlags ) *pFlags |= LOOK_NUL;
243 result = 0; /* NUL character in a file -> binary */
244 }
245 j = (c!='\n');
246 if( !j && pFlags ) *pFlags |= LOOK_LONE_LF;
247 while( --n>0 ){
248 int c2 = c;
249 c = *++z; ++j;
250 if( c==0 ){
251 if( pFlags ) *pFlags |= LOOK_NUL;
252 result = 0; /* NUL character in a file -> binary */
253 }
254 if( c=='\n' ){
255 if( pFlags ){
256 *pFlags |= (c2=='\r')?LOOK_CRLF:LOOK_LONE_LF;
257 }
258 if( j>LENGTH_MASK ){
259 if( pFlags ) *pFlags |= LOOK_LENGTH;
260 result = 0; /* Very long line -> binary */
261 }
262 j = 0;
263 }else if( c2=='\r' && pFlags ){
264 *pFlags |= LOOK_LONE_CR;
265 }
266 }
267 if( c=='\r' && pFlags ){
268 *pFlags |= LOOK_LONE_CR;
269 }
270 if( j>LENGTH_MASK ){
271 if( pFlags ) *pFlags |= LOOK_LENGTH;
272 result = 0; /* Very long line -> binary */
273 }
274 return result; /* No problems seen -> not binary */
275 }
276
277 /*
@@ -270,64 +305,80 @@
305 /*
306 ** This function attempts to scan each logical line within the blob to
307 ** determine the type of content it appears to contain. Possible return
308 ** values are:
309 **
310 ** (1) -- The content appears to consist entirely of text; however, the
311 ** encoding may not be UTF-16.
 
312 **
313 ** (0) -- The content appears to be binary because it contains embedded
314 ** NUL characters or an extremely long line. Since this function
315 ** does not understand UTF-8, it may falsely consider UTF-8 text
316 ** to be binary.
317 **
 
 
 
 
318 ************************************ WARNING **********************************
319 **
320 ** This function does not validate that the blob content is properly formed
321 ** UTF-16. It assumes that all code points are the same size. It does not
322 ** validate any code points. It makes no attempt to detect if any [invalid]
323 ** switches between the UTF-16be and UTF-16le encodings occur.
324 **
325 ** The only code points that this function cares about are the NUL character,
326 ** carriage-return, and line-feed.
327 **
328 ** Whether or not this function examines the entire contents of the blob is
329 ** officially unspecified.
330 **
331 ************************************ WARNING **********************************
332 */
333 int looks_like_utf16(const Blob *pContent, int *pFlags){
334 const WCHAR_T *z = (WCHAR_T *)blob_buffer(pContent);
335 unsigned int n = blob_size(pContent);
336 int j, c, result = 1; /* Assume UTF-16 text, prove otherwise */
337
338 if( pFlags ) *pFlags = LOOK_NONE;
339 if( n==0 ) return result; /* Empty file -> text */
340 if( n%sizeof(WCHAR_T) ){
341 if( pFlags ) *pFlags |= LOOK_ODD;
342 result = 0; /* Odd number of bytes -> binary (UTF-8?) */
343 if( n<sizeof(WCHAR_T) ) return result; /* One byte -> binary (UTF-8?) */
344 }
345 c = *z;
346 if( c==0 ){
347 if( pFlags ) *pFlags |= LOOK_NUL;
348 result = 0; /* NUL character in a file -> binary */
349 }
350 j = ((c!=UTF16BE_LF) && (c!=UTF16LE_LF));
351 if( !j && pFlags ) *pFlags |= LOOK_LONE_LF;
352 while( 1 ){
353 int c2 = c;
354 if( n<sizeof(WCHAR_T) ) break;
355 n -= sizeof(WCHAR_T);
356 c = *++z; ++j;
357 if( c==0 ){
358 if( pFlags ) *pFlags |= LOOK_NUL;
359 result = 0; /* NUL character in a file -> binary */
360 }
361 if( c==UTF16BE_LF || c==UTF16LE_LF ){
362 if( pFlags ){
363 *pFlags |= (c2==UTF16BE_CR||c2==UTF16LE_CR)?LOOK_CRLF:LOOK_LONE_LF;
364 }
365 if( j>UTF16_LENGTH_MASK ){
366 if( pFlags ) *pFlags |= LOOK_LENGTH;
367 result = 0; /* Very long line -> binary */
368 }
369 j = 0;
370 }else if( (c2==UTF16BE_CR || c2==UTF16LE_CR) && pFlags ){
371 *pFlags |= LOOK_LONE_CR;
372 }
373 }
374 if( (c==UTF16BE_CR || c==UTF16LE_CR) && pFlags ){
375 *pFlags |= LOOK_LONE_CR;
376 }
377 if( j>UTF16_LENGTH_MASK ){
378 if( pFlags ) *pFlags |= LOOK_LENGTH;
379 result = 0; /* Very long line -> binary */
380 }
381 return result; /* No problems seen -> not binary */
382 }
383
384 /*
@@ -355,26 +406,36 @@
406 if( blob_size(pContent)<bomSize ) return 0;
407 return memcmp(z, bom, bomSize)==0;
408 }
409
410 /*
411 ** This function returns non-zero if the blob starts with a UTF-16
412 ** byte-order-mark (BOM), either in the endianness of the machine
413 ** or in reversed byte order. The UTF-32 BOM is ruled out by checking
414 ** if the UTF-16 BOM is not immediately followed by (utf16) 0.
415 ** pnByte and pbReverse are only set when the function returns 1.
416 */
417 int starts_with_utf16_bom(
418 const Blob *pContent, /* IN: Blob content to perform BOM detection on. */
419 int *pnByte, /* OUT: The number of bytes used for the BOM. */
420 int *pbReverse /* OUT: Non-zero for BOM in reverse byte-order. */
421 ){
422 const unsigned short *z = (unsigned short *)blob_buffer(pContent);
423 int bomSize = sizeof(unsigned short);
424 int size = blob_size(pContent);
425
426 if( size<bomSize ) return 0; /* No: cannot read BOM. */
427 if( size>=(2*bomSize) && z[1]==0 ) return 0; /* No: possible UTF-32. */
428 if( z[0]==0xfffe ){
429 if( pbReverse ) *pbReverse = 1;
430 }else if( z[0]==0xfeff ){
431 if( pbReverse ) *pbReverse = 0;
432 }else{
433 return 0; /* No: UTF-16 byte-order-mark not found. */
434 }
435 if( pnByte ) *pnByte = bomSize;
436 return 1; /* Yes. */
437 }
438
439 /*
440 ** Return true if two DLine elements are identical.
441 */
@@ -516,11 +577,11 @@
577 a = xa;
578 b = xb;
579 continue;
580 }
581 }
582
583 /* For the current block comprising nr triples, figure out
584 ** how many lines of A and B are to be displayed
585 */
586 if( R[r]>nContext ){
587 na = nb = nContext;
@@ -871,21 +932,33 @@
932 /*
933 ** Simplify iStart and iStart2:
934 **
935 ** * If iStart is a null-change then move iStart2 into iStart
936 ** * Make sure any null-changes are in canonoical form.
937 ** * Make sure all changes are at character boundaries for
938 ** multi-byte characters.
939 */
940 static void sbsSimplifyLine(SbsLine *p, const char *z){
941 if( p->iStart2==p->iEnd2 ){
942 p->iStart2 = p->iEnd2 = 0;
943 }else if( p->iStart2 ){
944 while( p->iStart2>0 && (z[p->iStart2]&0xc0)==0x80 ) p->iStart2--;
945 while( (z[p->iEnd2]&0xc0)==0x80 ) p->iEnd2++;
946 }
947 if( p->iStart==p->iEnd ){
948 p->iStart = p->iStart2;
949 p->iEnd = p->iEnd2;
950 p->zStart = p->zStart2;
951 p->iStart2 = 0;
952 p->iEnd2 = 0;
953 }
954 if( p->iStart==p->iEnd ){
955 p->iStart = p->iEnd = -1;
956 }else if( p->iStart>0 ){
957 while( p->iStart>0 && (z[p->iStart]&0xc0)==0x80 ) p->iStart--;
958 while( (z[p->iEnd]&0xc0)==0x80 ) p->iEnd++;
959 }
960 }
961
962 /*
963 ** Write out lines that have been edited. Adjust the highlight to cover
964 ** only those parts of the line that actually changed.
@@ -897,10 +970,11 @@
970 DLine *pRight, /* Right line of the change */
971 int lnRight /* Line number of the right line */
972 ){
973 int nLeft; /* Length of left line in bytes */
974 int nRight; /* Length of right line in bytes */
975 int nShort; /* Shortest of left and right */
976 int nPrefix; /* Length of common prefix */
977 int nSuffix; /* Length of common suffix */
978 const char *zLeft; /* Text of the left line */
979 const char *zRight; /* Text of the right line */
980 int nLeftDiff; /* nLeft - nPrefix - nSuffix */
@@ -912,25 +986,31 @@
986
987 nLeft = pLeft->h & LENGTH_MASK;
988 zLeft = pLeft->z;
989 nRight = pRight->h & LENGTH_MASK;
990 zRight = pRight->z;
991 nShort = nLeft<nRight ? nLeft : nRight;
992
993 nPrefix = 0;
994 while( nPrefix<nShort && zLeft[nPrefix]==zRight[nPrefix] ){
995 nPrefix++;
996 }
997 if( nPrefix<nShort ){
998 while( nPrefix>0 && (zLeft[nPrefix]&0xc0)==0x80 ) nPrefix--;
999 }
1000 nSuffix = 0;
1001 if( nPrefix<nShort ){
1002 while( nSuffix<nShort && zLeft[nLeft-nSuffix-1]==zRight[nRight-nSuffix-1] ){
 
1003 nSuffix++;
1004 }
1005 if( nSuffix<nShort ){
1006 while( nSuffix>0 && (zLeft[nLeft-nSuffix]&0xc0)==0x80 ) nSuffix--;
1007 }
1008 if( nSuffix==nLeft || nSuffix==nRight ) nPrefix = 0;
1009 }
1010 if( nPrefix+nSuffix > nShort ) nPrefix = nShort - nSuffix;
1011
1012
1013 /* A single chunk of text inserted on the right */
1014 if( nPrefix+nSuffix==nLeft ){
1015 sbsWriteLineno(p, lnLeft);
1016 p->iStart2 = p->iEnd2 = 0;
@@ -986,11 +1066,11 @@
1066 p->zStart = zClassChng;
1067 }
1068 p->iStart2 = nPrefix + aLCS[1];
1069 p->iEnd2 = nLeft - nSuffix;
1070 p->zStart2 = aLCS[3]==nRightDiff ? zClassRm : zClassChng;
1071 sbsSimplifyLine(p, zLeft+nPrefix);
1072 sbsWriteText(p, pLeft, SBS_PAD);
1073 sbsWrite(p, " | ", 3);
1074 sbsWriteLineno(p, lnRight);
1075 p->iStart = nPrefix;
1076 p->iEnd = nPrefix + aLCS[2];
@@ -1001,11 +1081,11 @@
1081 p->zStart = zClassChng;
1082 }
1083 p->iStart2 = nPrefix + aLCS[3];
1084 p->iEnd2 = nRight - nSuffix;
1085 p->zStart2 = aLCS[1]==nLeftDiff ? zClassAdd : zClassChng;
1086 sbsSimplifyLine(p, zRight+nPrefix);
1087 sbsWriteText(p, pRight, SBS_NEWLINE);
1088 return;
1089 }
1090
1091 /* If all else fails, show a single big change between left and right */
@@ -1220,11 +1300,11 @@
1300 ** Then this is probably an alignment that will be difficult for humans
1301 ** to read. So instead, just show all of the right side inserted followed
1302 ** by all of the left side deleted.
1303 **
1304 ** The coefficients for conditions (1) and (2) above are determined by
1305 ** experimentation.
1306 */
1307 mxLen = nLeft>nRight ? nLeft : nRight;
1308 if( i*4>mxLen*5 && (nMatch==0 || iMatch/nMatch>15) ){
1309 memset(aM, 4, mnLen);
1310 if( nLeft>mnLen ) memset(aM+mnLen, 1, nLeft-mnLen);
@@ -1406,11 +1486,11 @@
1486 /* Delete one line from the left */
1487 s.n = 0;
1488 sbsWriteLineno(&s, a);
1489 s.iStart = 0;
1490 s.zStart = "<span class=\"diffrm\">";
1491 s.iEnd = LENGTH(&A[a]);
1492 sbsWriteText(&s, &A[a], SBS_PAD);
1493 if( s.escHtml ){
1494 sbsWrite(&s, " &lt;\n", 6);
1495 }else{
1496 sbsWrite(&s, " <\n", 3);
@@ -1439,11 +1519,11 @@
1519 sbsWrite(&s, " > ", 3);
1520 }
1521 sbsWriteLineno(&s, b);
1522 s.iStart = 0;
1523 s.zStart = "<span class=\"diffadd\">";
1524 s.iEnd = LENGTH(&B[b]);
1525 sbsWriteText(&s, &B[b], SBS_NEWLINE);
1526 blob_append(pOut, s.zLine, s.n);
1527 assert( mb>0 );
1528 mb--;
1529 b++;
@@ -1451,25 +1531,25 @@
1531 /* Delete from the left and insert on the right */
1532 s.n = 0;
1533 sbsWriteLineno(&s, a);
1534 s.iStart = 0;
1535 s.zStart = "<span class=\"diffrm\">";
1536 s.iEnd = LENGTH(&A[a]);
1537 sbsWriteText(&s, &A[a], SBS_PAD);
1538 sbsWrite(&s, " | ", 3);
1539 sbsWriteLineno(&s, b);
1540 s.iStart = 0;
1541 s.zStart = "<span class=\"diffadd\">";
1542 s.iEnd = LENGTH(&B[b]);
1543 sbsWriteText(&s, &B[b], SBS_NEWLINE);
1544 blob_append(pOut, s.zLine, s.n);
1545 ma--;
1546 mb--;
1547 a++;
1548 b++;
1549 }
1550
1551 }
1552 fossil_free(alignment);
1553 if( i<nr-1 ){
1554 m = R[r+i*3+3];
1555 for(j=0; j<m; j++){
@@ -1954,11 +2034,30 @@
2034 return 0;
2035 }
2036
2037 /* Compute the difference */
2038 diff_all(&c);
2039 if( (diffFlags & DIFF_NOTTOOBIG)!=0 ){
2040 int i, m, n;
2041 int *a = c.aEdit;
2042 int mx = c.nEdit;
2043 for(i=m=n=0; i<mx; i+=3){ m += a[i]; n += a[i+1]+a[i+2]; }
2044 if( n>10000 ){
2045 fossil_free(c.aFrom);
2046 fossil_free(c.aTo);
2047 fossil_free(c.aEdit);
2048 if( diffFlags & DIFF_HTML ){
2049 blob_append(pOut, DIFF_TOO_MANY_CHANGES_HTML, -1);
2050 }else{
2051 blob_append(pOut, DIFF_TOO_MANY_CHANGES_TXT, -1);
2052 }
2053 return 0;
2054 }
2055 }
2056 if( (diffFlags & DIFF_NOOPT)==0 ){
2057 diff_optimize(&c);
2058 }
2059
2060 if( pOut ){
2061 /* Compute a context or side-by-side diff into pOut */
2062 if( diffFlags & DIFF_SIDEBYSIDE ){
2063 sbsDiff(&c, pOut, pRe, diffFlags);
@@ -2205,11 +2304,12 @@
2304 fossil_print("%10s: %.*s\n", zSrc, x.aOrig[i].n, x.aOrig[i].z);
2305 }
2306 }
2307
2308 /* Annotation flags */
2309 #define ANN_FILE_VERS 0x01 /* Show file vers rather than commit vers */
2310 #define ANN_FILE_ANCEST 0x02 /* Prefer check-ins in the ANCESTOR table */
2311
2312 /*
2313 ** Compute a complete annotation on a file. The file is identified
2314 ** by its filename number (filename.fnid) and the baseline in which
2315 ** it was checked in (mlink.mid).
@@ -2243,11 +2343,11 @@
2343 if( !content_get(rid, &toAnnotate) ){
2344 fossil_panic("unable to retrieve content of artifact #%d", rid);
2345 }
2346 if( iLimit<=0 ) iLimit = 1000000000;
2347 annotation_start(p, &toAnnotate);
2348
2349 db_prepare(&q,
2350 "SELECT (SELECT uuid FROM blob WHERE rid=mlink.%s),"
2351 " (SELECT uuid FROM blob WHERE rid=mlink.fid),"
2352 " (SELECT uuid FROM blob WHERE rid=mlink.pid),"
2353 " date(event.mtime),"
@@ -2254,14 +2354,16 @@
2354 " coalesce(event.euser,event.user),"
2355 " mlink.pid"
2356 " FROM mlink, event"
2357 " WHERE mlink.fid=:rid"
2358 " AND event.objid=mlink.mid"
2359 " ORDER BY %s event.mtime",
2360 (annFlags & ANN_FILE_VERS)!=0 ? "fid" : "mid",
2361 (annFlags & ANN_FILE_ANCEST)!=0 ?
2362 "(mlink.mid IN (SELECT rid FROM ancestor)) DESC,":""
2363 );
2364
2365 db_bind_int(&q, ":rid", rid);
2366 if( iLimit==0 ) iLimit = 1000000000;
2367 while( rid && iLimit>cnt && db_step(&q)==SQLITE_ROW ){
2368 const char *zUuid = db_column_text(&q, 0);
2369 const char *zUuidFile = db_column_text(&q, 1);
@@ -2313,11 +2415,11 @@
2415 void annotation_page(void){
2416 int mid;
2417 int fnid;
2418 int i;
2419 int iLimit;
2420 int annFlags = ANN_FILE_ANCEST;
2421 int showLn = 0; /* True if line numbers should be shown */
2422 char zLn[10]; /* Line number buffer */
2423 char zFormat[10]; /* Format string for line numbers */
2424 Annotator ann;
2425
@@ -2329,10 +2431,11 @@
2431 if( mid==0 || fnid==0 ){ fossil_redirect_home(); }
2432 iLimit = atoi(PD("limit","-1"));
2433 if( !db_exists("SELECT 1 FROM mlink WHERE mid=%d AND fnid=%d",mid,fnid) ){
2434 fossil_redirect_home();
2435 }
2436 compute_direct_ancestors(mid, 10000000);
2437 style_header("File Annotation");
2438 if( P("filevers") ) annFlags |= ANN_FILE_VERS;
2439 annotate_file(&ann, P("filename"), fnid, mid, g.perm.Hyperlink, iLimit, annFlags);
2440 if( P("log") ){
2441 int i;
@@ -2395,11 +2498,11 @@
2498 if( zLimit==0 || zLimit[0]==0 ) zLimit = "-1";
2499 iLimit = atoi(zLimit);
2500 showLog = find_option("log",0,0)!=0;
2501 fileVers = find_option("filevers",0,0)!=0;
2502 db_must_be_within_tree();
2503 if( g.argc<3 ) {
2504 usage("FILENAME");
2505 }
2506 file_tree_name(g.argv[2], &treename, 1);
2507 zFilename = blob_str(&treename);
2508 fnid = db_int(0, "SELECT fnid FROM filename WHERE name=%Q", zFilename);
@@ -2409,11 +2512,11 @@
2512 fid = db_int(0, "SELECT rid FROM vfile WHERE pathname=%Q", zFilename);
2513 if( fid==0 ){
2514 fossil_fatal("not part of current checkout: %s", zFilename);
2515 }
2516 cid = db_lget_int("checkout", 0);
2517 if( cid == 0 ){
2518 fossil_fatal("Not in a checkout");
2519 }
2520 if( iLimit<=0 ) iLimit = 1000000000;
2521 compute_direct_ancestors(cid, iLimit);
2522 mid = db_int(0, "SELECT mlink.mid FROM mlink, ancestor "
@@ -2422,10 +2525,11 @@
2525 fid, fnid);
2526 if( mid==0 ){
2527 fossil_panic("unable to find manifest");
2528 }
2529 if( fileVers ) annFlags |= ANN_FILE_VERS;
2530 annFlags |= ANN_FILE_ANCEST;
2531 annotate_file(&ann, zFilename, fnid, mid, 0, iLimit, annFlags);
2532 if( showLog ){
2533 for(i=0; i<ann.nVers; i++){
2534 printf("version %3d: %s\n", i+1, ann.azVers[i]);
2535 }
@@ -2434,5 +2538,42 @@
2538 for(i=0; i<ann.nOrig; i++){
2539 fossil_print("%s: %.*s\n",
2540 ann.aOrig[i].zSrc, ann.aOrig[i].n, ann.aOrig[i].z);
2541 }
2542 }
2543
2544 /*
2545 ** COMMAND: test-looks-like-utf
2546 **
2547 ** Usage: %fossil test-looks-like-utf FILENAME
2548 **
2549 ** FILENAME is the name of a file to check for textual content in the UTF-8
2550 ** and/or UTF-16 encodings.
2551 */
2552 void looks_like_utf_test_cmd(void){
2553 Blob blob; /* the contents of the specified file */
2554 int eType; /* return value of looks_like_utf8/utf16() */
2555 int fUtf8; /* return value of starts_with_utf8_bom() */
2556 int fUtf16; /* return value of starts_with_utf16_bom() */
2557 int lookFlags; /* output flags from looks_like_utf8/utf16() */
2558 if( g.argc<3 ) usage("FILENAME");
2559 blob_read_from_file(&blob, g.argv[2]);
2560 fUtf8 = starts_with_utf8_bom(&blob, 0);
2561 fUtf16 = starts_with_utf16_bom(&blob, 0, 0);
2562 eType = fUtf16 ? looks_like_utf16(&blob, &lookFlags) :
2563 looks_like_utf8(&blob, &lookFlags);
2564 fossil_print("File \"%s\" has %d bytes.\n",g.argv[2],blob_size(&blob));
2565 fossil_print("Starts with UTF-8 BOM: %s\n",fUtf8?"yes":"no");
2566 fossil_print("Starts with UTF-16 BOM: %s\n",fUtf16?"yes":"no");
2567 fossil_print("Looks like UTF-%s: %s\n",fUtf16?"16":"8",eType?"yes":"no");
2568 fossil_print("Has flag LOOK_NUL: %s\n",(lookFlags&LOOK_NUL)?"yes":"no");
2569 fossil_print("Has flag LOOK_CR: %s\n",(lookFlags&LOOK_CR)?"yes":"no");
2570 fossil_print("Has flag LOOK_LONE_CR: %s\n",
2571 (lookFlags&LOOK_LONE_CR)?"yes":"no");
2572 fossil_print("Has flag LOOK_LF: %s\n",(lookFlags&LOOK_LF)?"yes":"no");
2573 fossil_print("Has flag LOOK_LONE_LF: %s\n",
2574 (lookFlags&LOOK_LONE_LF)?"yes":"no");
2575 fossil_print("Has flag LOOK_CRLF: %s\n",(lookFlags&LOOK_CRLF)?"yes":"no");
2576 fossil_print("Has flag LOOK_LENGTH: %s\n",(lookFlags&LOOK_LENGTH)?"yes":"no");
2577 fossil_print("Has flag LOOK_ODD: %s\n",(lookFlags&LOOK_ODD)?"yes":"no");
2578 blob_reset(&blob);
2579 }
2580
+46 -38
--- src/file.c
+++ src/file.c
@@ -64,23 +64,24 @@
6464
** Fill stat buf with information received from stat() or lstat().
6565
** lstat() is called on Unix if isWd is TRUE and allow-symlinks setting is on.
6666
**
6767
*/
6868
static int fossil_stat(const char *zFilename, struct stat *buf, int isWd){
69
+ int rc;
6970
#if !defined(_WIN32)
71
+ char *zMbcs = fossil_utf8_to_filename(zFilename);
7072
if( isWd && g.allowSymlinks ){
71
- return lstat(zFilename, buf);
73
+ rc = lstat(zMbcs, buf);
7274
}else{
73
- return stat(zFilename, buf);
75
+ rc = stat(zMbcs, buf);
7476
}
7577
#else
76
- int rc = 0;
77
- wchar_t *zMbcs = fossil_utf8_to_unicode(zFilename);
78
+ wchar_t *zMbcs = fossil_utf8_to_filename(zFilename);
7879
rc = _wstati64(zMbcs, buf);
79
- fossil_unicode_free(zMbcs);
80
- return rc;
8180
#endif
81
+ fossil_filename_free(zMbcs);
82
+ return rc;
8283
}
8384
8485
/*
8586
** Fill in the fileStat variable for the file named zFilename.
8687
** If zFilename==0, then use the previous value of fileStat if
@@ -303,16 +304,17 @@
303304
/*
304305
** Wrapper around the access() system call.
305306
*/
306307
int file_access(const char *zFilename, int flags){
307308
#ifdef _WIN32
308
- wchar_t *zMbcs = fossil_utf8_to_unicode(zFilename);
309
+ wchar_t *zMbcs = fossil_utf8_to_filename(zFilename);
309310
int rc = _waccess(zMbcs, flags);
310
- fossil_unicode_free(zMbcs);
311311
#else
312
- int rc = access(zFilename, flags);
312
+ char *zMbcs = fossil_utf8_to_filename(zFilename);
313
+ int rc = access(zMbcs, flags);
313314
#endif
315
+ fossil_filename_free(zMbcs);
314316
return rc;
315317
}
316318
317319
/*
318320
** Find an unused filename similar to zBase with zSuffix appended.
@@ -402,19 +404,20 @@
402404
#if !defined(_WIN32)
403405
struct timeval tv[2];
404406
memset(tv, 0, sizeof(tv[0])*2);
405407
tv[0].tv_sec = newMTime;
406408
tv[1].tv_sec = newMTime;
407
- utimes(zFilename, tv);
409
+ char *zMbcs = fossil_utf8_to_filename(zFilename);
410
+ utimes(zMbcs, tv);
408411
#else
409412
struct _utimbuf tb;
410
- wchar_t *zMbcs = fossil_utf8_to_unicode(zFilename);
413
+ wchar_t *zMbcs = fossil_utf8_to_filename(zFilename);
411414
tb.actime = newMTime;
412415
tb.modtime = newMTime;
413416
_wutime(zMbcs, &tb);
414
- fossil_unicode_free(zMbcs);
415417
#endif
418
+ fossil_filename_free(zMbcs);
416419
}
417420
418421
/*
419422
** COMMAND: test-set-mtime
420423
**
@@ -441,16 +444,17 @@
441444
/*
442445
** Delete a file.
443446
*/
444447
void file_delete(const char *zFilename){
445448
#ifdef _WIN32
446
- wchar_t *z = fossil_utf8_to_unicode(zFilename);
449
+ wchar_t *z = fossil_utf8_to_filename(zFilename);
447450
_wunlink(z);
448
- fossil_unicode_free(z);
449451
#else
452
+ char *z = fossil_utf8_to_filename(zFilename);
450453
unlink(zFilename);
451454
#endif
455
+ fossil_filename_free(z);
452456
}
453457
454458
/*
455459
** Create the directory named in the argument, if it does not already
456460
** exist. If forceFlag is 1, delete any prior non-directory object
@@ -464,18 +468,18 @@
464468
if( !forceFlag ) return 1;
465469
file_delete(zName);
466470
}
467471
if( rc!=1 ){
468472
#if defined(_WIN32)
469
- int rc;
470
- wchar_t *zMbcs = fossil_utf8_to_unicode(zName);
473
+ wchar_t *zMbcs = fossil_utf8_to_filename(zName);
471474
rc = _wmkdir(zMbcs);
472
- fossil_unicode_free(zMbcs);
473
- return rc;
474475
#else
475
- return mkdir(zName, 0755);
476
+ char *zMbcs = fossil_utf8_to_filename(zName);
477
+ rc = mkdir(zName, 0755);
476478
#endif
479
+ fossil_filename_free(zMbcs);
480
+ return rc;
477481
}
478482
return 0;
479483
}
480484
481485
/*
@@ -580,11 +584,11 @@
580584
}
581585
582586
/*
583587
** Simplify a filename by
584588
**
585
-** * Convert all \ into / on windows
589
+** * Convert all \ into / on windows and cygwin
586590
** * removing any trailing and duplicate /
587591
** * removing /./
588592
** * removing /A/../
589593
**
590594
** Changes are made in-place. Return the new name length.
@@ -593,12 +597,12 @@
593597
*/
594598
int file_simplify_name(char *z, int n, int slash){
595599
int i, j;
596600
if( n<0 ) n = strlen(z);
597601
598
- /* On windows convert all \ characters to / */
599
-#if defined(_WIN32)
602
+ /* On windows and cygwin convert all \ characters to / */
603
+#if defined(_WIN32) || defined(__CYGWIN__)
600604
for(i=0; i<n; i++){
601605
if( z[i]=='\\' ) z[i] = '/';
602606
}
603607
#endif
604608
@@ -705,13 +709,13 @@
705709
** Return true if zPath is an absolute pathname. Return false
706710
** if it is relative.
707711
*/
708712
int file_is_absolute_path(const char *zPath){
709713
if( zPath[0]=='/'
710
-#if defined(_WIN32)
714
+#if defined(_WIN32) || defined(__CYGWIN__)
711715
|| zPath[0]=='\\'
712
- || (strlen(zPath)>3 && zPath[1]==':'
716
+ || (fossil_isalpha(zPath[0]) && zPath[1]==':'
713717
&& (zPath[2]=='\\' || zPath[2]=='/'))
714718
#endif
715719
){
716720
return 1;
717721
}else{
@@ -728,21 +732,21 @@
728732
** If the slash parameter is non-zero, the trailing slash, if any,
729733
** is retained.
730734
*/
731735
void file_canonical_name(const char *zOrigName, Blob *pOut, int slash){
732736
if( file_is_absolute_path(zOrigName) ){
733
-#if defined(_WIN32)
737
+#if defined(_WIN32) || defined(__CYGWIN__)
734738
char *zOut;
735739
#endif
736740
blob_set(pOut, zOrigName);
737741
blob_materialize(pOut);
738
-#if defined(_WIN32)
742
+#if defined(_WIN32) || defined(__CYGWIN__)
739743
/*
740
- ** On Windows, normalize the drive letter to upper case.
744
+ ** On Windows/cygwin, normalize the drive letter to upper case.
741745
*/
742746
zOut = blob_str(pOut);
743
- if( fossil_isalpha(zOut[0]) && zOut[1]==':' ){
747
+ if( fossil_islower(zOut[0]) && zOut[1]==':' ){
744748
zOut[0] = fossil_toupper(zOut[0]);
745749
}
746750
#endif
747751
}else{
748752
char zPwd[2000];
@@ -749,11 +753,11 @@
749753
file_getcwd(zPwd, sizeof(zPwd)-strlen(zOrigName));
750754
#if defined(_WIN32)
751755
/*
752756
** On Windows, normalize the drive letter to upper case.
753757
*/
754
- if( fossil_isalpha(zPwd[0]) && zPwd[1]==':' ){
758
+ if( fossil_islower(zPwd[0]) && zPwd[1]==':' ){
755759
zPwd[0] = fossil_toupper(zPwd[0]);
756760
}
757761
#endif
758762
blob_zero(pOut);
759763
blob_appendf(pOut, "%//%/", zPwd, zOrigName);
@@ -798,12 +802,12 @@
798802
** contain no "/./" or "/../" terms.
799803
*/
800804
int file_is_canonical(const char *z){
801805
int i;
802806
if( z[0]!='/'
803
-#if defined(_WIN32)
804
- && (z[0]==0 || z[1]!=':' || z[2]!='/')
807
+#if defined(_WIN32) || defined(__CYGWIN__)
808
+ && (!fossil_isupper(z[0]) || z[1]!=':' || z[2]!='/')
805809
#endif
806810
) return 0;
807811
808812
for(i=0; z[i]; i++){
809813
if( z[i]=='\\' ) return 0;
@@ -846,11 +850,11 @@
846850
char zBuf[2000];
847851
zPwd = zBuf;
848852
file_getcwd(zBuf, sizeof(zBuf)-20);
849853
zPwd = file_without_drive_letter(zBuf);
850854
i = 1;
851
-#ifdef _WIN32
855
+#if defined(_WIN32) || defined(__CYGWIN__)
852856
while( zPath[i] && fossil_tolower(zPwd[i])==fossil_tolower(zPath[i]) ) i++;
853857
#else
854858
while( zPath[i] && zPwd[i]==zPath[i] ) i++;
855859
#endif
856860
if( zPath[i]==0 ){
@@ -1011,23 +1015,26 @@
10111015
10121016
/*
10131017
** Construct a random temporary filename into zBuf[].
10141018
*/
10151019
void file_tempname(int nBuf, char *zBuf){
1016
- static const char *azDirs[] = {
10171020
#if defined(_WIN32)
1021
+ const char *azDirs[] = {
10181022
0, /* GetTempPath */
10191023
0, /* TEMP */
10201024
0, /* TMP */
1025
+ ".",
1026
+ };
10211027
#else
1028
+ static const char *const azDirs[] = {
10221029
"/var/tmp",
10231030
"/usr/tmp",
10241031
"/tmp",
10251032
"/temp",
1026
-#endif
10271033
".",
10281034
};
1035
+#endif
10291036
static const unsigned char zChars[] =
10301037
"abcdefghijklmnopqrstuvwxyz"
10311038
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
10321039
"0123456789";
10331040
unsigned int i, j;
@@ -1070,12 +1077,13 @@
10701077
}
10711078
zBuf[j] = 0;
10721079
}while( file_size(zBuf)>=0 );
10731080
10741081
#if defined(_WIN32)
1075
- fossil_unicode_free((char *)azDirs[1]);
1076
- fossil_unicode_free((char *)azDirs[2]);
1082
+ fossil_filename_free((char *)azDirs[0]);
1083
+ fossil_filename_free((char *)azDirs[1]);
1084
+ fossil_filename_free((char *)azDirs[2]);
10771085
#endif
10781086
}
10791087
10801088
10811089
/*
@@ -1137,14 +1145,14 @@
11371145
** Like fopen() but always takes a UTF8 argument.
11381146
*/
11391147
FILE *fossil_fopen(const char *zName, const char *zMode){
11401148
#ifdef _WIN32
11411149
wchar_t *uMode = fossil_utf8_to_unicode(zMode);
1142
- wchar_t *uName = fossil_utf8_to_unicode(zName);
1150
+ wchar_t *uName = fossil_utf8_to_filename(zName);
11431151
FILE *f = _wfopen(uName, uMode);
1144
- fossil_unicode_free(uName);
1152
+ fossil_filename_free(uName);
11451153
fossil_unicode_free(uMode);
11461154
#else
11471155
FILE *f = fopen(zName, zMode);
11481156
#endif
11491157
return f;
11501158
}
11511159
--- src/file.c
+++ src/file.c
@@ -64,23 +64,24 @@
64 ** Fill stat buf with information received from stat() or lstat().
65 ** lstat() is called on Unix if isWd is TRUE and allow-symlinks setting is on.
66 **
67 */
68 static int fossil_stat(const char *zFilename, struct stat *buf, int isWd){
 
69 #if !defined(_WIN32)
 
70 if( isWd && g.allowSymlinks ){
71 return lstat(zFilename, buf);
72 }else{
73 return stat(zFilename, buf);
74 }
75 #else
76 int rc = 0;
77 wchar_t *zMbcs = fossil_utf8_to_unicode(zFilename);
78 rc = _wstati64(zMbcs, buf);
79 fossil_unicode_free(zMbcs);
80 return rc;
81 #endif
 
 
82 }
83
84 /*
85 ** Fill in the fileStat variable for the file named zFilename.
86 ** If zFilename==0, then use the previous value of fileStat if
@@ -303,16 +304,17 @@
303 /*
304 ** Wrapper around the access() system call.
305 */
306 int file_access(const char *zFilename, int flags){
307 #ifdef _WIN32
308 wchar_t *zMbcs = fossil_utf8_to_unicode(zFilename);
309 int rc = _waccess(zMbcs, flags);
310 fossil_unicode_free(zMbcs);
311 #else
312 int rc = access(zFilename, flags);
 
313 #endif
 
314 return rc;
315 }
316
317 /*
318 ** Find an unused filename similar to zBase with zSuffix appended.
@@ -402,19 +404,20 @@
402 #if !defined(_WIN32)
403 struct timeval tv[2];
404 memset(tv, 0, sizeof(tv[0])*2);
405 tv[0].tv_sec = newMTime;
406 tv[1].tv_sec = newMTime;
407 utimes(zFilename, tv);
 
408 #else
409 struct _utimbuf tb;
410 wchar_t *zMbcs = fossil_utf8_to_unicode(zFilename);
411 tb.actime = newMTime;
412 tb.modtime = newMTime;
413 _wutime(zMbcs, &tb);
414 fossil_unicode_free(zMbcs);
415 #endif
 
416 }
417
418 /*
419 ** COMMAND: test-set-mtime
420 **
@@ -441,16 +444,17 @@
441 /*
442 ** Delete a file.
443 */
444 void file_delete(const char *zFilename){
445 #ifdef _WIN32
446 wchar_t *z = fossil_utf8_to_unicode(zFilename);
447 _wunlink(z);
448 fossil_unicode_free(z);
449 #else
 
450 unlink(zFilename);
451 #endif
 
452 }
453
454 /*
455 ** Create the directory named in the argument, if it does not already
456 ** exist. If forceFlag is 1, delete any prior non-directory object
@@ -464,18 +468,18 @@
464 if( !forceFlag ) return 1;
465 file_delete(zName);
466 }
467 if( rc!=1 ){
468 #if defined(_WIN32)
469 int rc;
470 wchar_t *zMbcs = fossil_utf8_to_unicode(zName);
471 rc = _wmkdir(zMbcs);
472 fossil_unicode_free(zMbcs);
473 return rc;
474 #else
475 return mkdir(zName, 0755);
 
476 #endif
 
 
477 }
478 return 0;
479 }
480
481 /*
@@ -580,11 +584,11 @@
580 }
581
582 /*
583 ** Simplify a filename by
584 **
585 ** * Convert all \ into / on windows
586 ** * removing any trailing and duplicate /
587 ** * removing /./
588 ** * removing /A/../
589 **
590 ** Changes are made in-place. Return the new name length.
@@ -593,12 +597,12 @@
593 */
594 int file_simplify_name(char *z, int n, int slash){
595 int i, j;
596 if( n<0 ) n = strlen(z);
597
598 /* On windows convert all \ characters to / */
599 #if defined(_WIN32)
600 for(i=0; i<n; i++){
601 if( z[i]=='\\' ) z[i] = '/';
602 }
603 #endif
604
@@ -705,13 +709,13 @@
705 ** Return true if zPath is an absolute pathname. Return false
706 ** if it is relative.
707 */
708 int file_is_absolute_path(const char *zPath){
709 if( zPath[0]=='/'
710 #if defined(_WIN32)
711 || zPath[0]=='\\'
712 || (strlen(zPath)>3 && zPath[1]==':'
713 && (zPath[2]=='\\' || zPath[2]=='/'))
714 #endif
715 ){
716 return 1;
717 }else{
@@ -728,21 +732,21 @@
728 ** If the slash parameter is non-zero, the trailing slash, if any,
729 ** is retained.
730 */
731 void file_canonical_name(const char *zOrigName, Blob *pOut, int slash){
732 if( file_is_absolute_path(zOrigName) ){
733 #if defined(_WIN32)
734 char *zOut;
735 #endif
736 blob_set(pOut, zOrigName);
737 blob_materialize(pOut);
738 #if defined(_WIN32)
739 /*
740 ** On Windows, normalize the drive letter to upper case.
741 */
742 zOut = blob_str(pOut);
743 if( fossil_isalpha(zOut[0]) && zOut[1]==':' ){
744 zOut[0] = fossil_toupper(zOut[0]);
745 }
746 #endif
747 }else{
748 char zPwd[2000];
@@ -749,11 +753,11 @@
749 file_getcwd(zPwd, sizeof(zPwd)-strlen(zOrigName));
750 #if defined(_WIN32)
751 /*
752 ** On Windows, normalize the drive letter to upper case.
753 */
754 if( fossil_isalpha(zPwd[0]) && zPwd[1]==':' ){
755 zPwd[0] = fossil_toupper(zPwd[0]);
756 }
757 #endif
758 blob_zero(pOut);
759 blob_appendf(pOut, "%//%/", zPwd, zOrigName);
@@ -798,12 +802,12 @@
798 ** contain no "/./" or "/../" terms.
799 */
800 int file_is_canonical(const char *z){
801 int i;
802 if( z[0]!='/'
803 #if defined(_WIN32)
804 && (z[0]==0 || z[1]!=':' || z[2]!='/')
805 #endif
806 ) return 0;
807
808 for(i=0; z[i]; i++){
809 if( z[i]=='\\' ) return 0;
@@ -846,11 +850,11 @@
846 char zBuf[2000];
847 zPwd = zBuf;
848 file_getcwd(zBuf, sizeof(zBuf)-20);
849 zPwd = file_without_drive_letter(zBuf);
850 i = 1;
851 #ifdef _WIN32
852 while( zPath[i] && fossil_tolower(zPwd[i])==fossil_tolower(zPath[i]) ) i++;
853 #else
854 while( zPath[i] && zPwd[i]==zPath[i] ) i++;
855 #endif
856 if( zPath[i]==0 ){
@@ -1011,23 +1015,26 @@
1011
1012 /*
1013 ** Construct a random temporary filename into zBuf[].
1014 */
1015 void file_tempname(int nBuf, char *zBuf){
1016 static const char *azDirs[] = {
1017 #if defined(_WIN32)
 
1018 0, /* GetTempPath */
1019 0, /* TEMP */
1020 0, /* TMP */
 
 
1021 #else
 
1022 "/var/tmp",
1023 "/usr/tmp",
1024 "/tmp",
1025 "/temp",
1026 #endif
1027 ".",
1028 };
 
1029 static const unsigned char zChars[] =
1030 "abcdefghijklmnopqrstuvwxyz"
1031 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
1032 "0123456789";
1033 unsigned int i, j;
@@ -1070,12 +1077,13 @@
1070 }
1071 zBuf[j] = 0;
1072 }while( file_size(zBuf)>=0 );
1073
1074 #if defined(_WIN32)
1075 fossil_unicode_free((char *)azDirs[1]);
1076 fossil_unicode_free((char *)azDirs[2]);
 
1077 #endif
1078 }
1079
1080
1081 /*
@@ -1137,14 +1145,14 @@
1137 ** Like fopen() but always takes a UTF8 argument.
1138 */
1139 FILE *fossil_fopen(const char *zName, const char *zMode){
1140 #ifdef _WIN32
1141 wchar_t *uMode = fossil_utf8_to_unicode(zMode);
1142 wchar_t *uName = fossil_utf8_to_unicode(zName);
1143 FILE *f = _wfopen(uName, uMode);
1144 fossil_unicode_free(uName);
1145 fossil_unicode_free(uMode);
1146 #else
1147 FILE *f = fopen(zName, zMode);
1148 #endif
1149 return f;
1150 }
1151
--- src/file.c
+++ src/file.c
@@ -64,23 +64,24 @@
64 ** Fill stat buf with information received from stat() or lstat().
65 ** lstat() is called on Unix if isWd is TRUE and allow-symlinks setting is on.
66 **
67 */
68 static int fossil_stat(const char *zFilename, struct stat *buf, int isWd){
69 int rc;
70 #if !defined(_WIN32)
71 char *zMbcs = fossil_utf8_to_filename(zFilename);
72 if( isWd && g.allowSymlinks ){
73 rc = lstat(zMbcs, buf);
74 }else{
75 rc = stat(zMbcs, buf);
76 }
77 #else
78 wchar_t *zMbcs = fossil_utf8_to_filename(zFilename);
 
79 rc = _wstati64(zMbcs, buf);
 
 
80 #endif
81 fossil_filename_free(zMbcs);
82 return rc;
83 }
84
85 /*
86 ** Fill in the fileStat variable for the file named zFilename.
87 ** If zFilename==0, then use the previous value of fileStat if
@@ -303,16 +304,17 @@
304 /*
305 ** Wrapper around the access() system call.
306 */
307 int file_access(const char *zFilename, int flags){
308 #ifdef _WIN32
309 wchar_t *zMbcs = fossil_utf8_to_filename(zFilename);
310 int rc = _waccess(zMbcs, flags);
 
311 #else
312 char *zMbcs = fossil_utf8_to_filename(zFilename);
313 int rc = access(zMbcs, flags);
314 #endif
315 fossil_filename_free(zMbcs);
316 return rc;
317 }
318
319 /*
320 ** Find an unused filename similar to zBase with zSuffix appended.
@@ -402,19 +404,20 @@
404 #if !defined(_WIN32)
405 struct timeval tv[2];
406 memset(tv, 0, sizeof(tv[0])*2);
407 tv[0].tv_sec = newMTime;
408 tv[1].tv_sec = newMTime;
409 char *zMbcs = fossil_utf8_to_filename(zFilename);
410 utimes(zMbcs, tv);
411 #else
412 struct _utimbuf tb;
413 wchar_t *zMbcs = fossil_utf8_to_filename(zFilename);
414 tb.actime = newMTime;
415 tb.modtime = newMTime;
416 _wutime(zMbcs, &tb);
 
417 #endif
418 fossil_filename_free(zMbcs);
419 }
420
421 /*
422 ** COMMAND: test-set-mtime
423 **
@@ -441,16 +444,17 @@
444 /*
445 ** Delete a file.
446 */
447 void file_delete(const char *zFilename){
448 #ifdef _WIN32
449 wchar_t *z = fossil_utf8_to_filename(zFilename);
450 _wunlink(z);
 
451 #else
452 char *z = fossil_utf8_to_filename(zFilename);
453 unlink(zFilename);
454 #endif
455 fossil_filename_free(z);
456 }
457
458 /*
459 ** Create the directory named in the argument, if it does not already
460 ** exist. If forceFlag is 1, delete any prior non-directory object
@@ -464,18 +468,18 @@
468 if( !forceFlag ) return 1;
469 file_delete(zName);
470 }
471 if( rc!=1 ){
472 #if defined(_WIN32)
473 wchar_t *zMbcs = fossil_utf8_to_filename(zName);
 
474 rc = _wmkdir(zMbcs);
 
 
475 #else
476 char *zMbcs = fossil_utf8_to_filename(zName);
477 rc = mkdir(zName, 0755);
478 #endif
479 fossil_filename_free(zMbcs);
480 return rc;
481 }
482 return 0;
483 }
484
485 /*
@@ -580,11 +584,11 @@
584 }
585
586 /*
587 ** Simplify a filename by
588 **
589 ** * Convert all \ into / on windows and cygwin
590 ** * removing any trailing and duplicate /
591 ** * removing /./
592 ** * removing /A/../
593 **
594 ** Changes are made in-place. Return the new name length.
@@ -593,12 +597,12 @@
597 */
598 int file_simplify_name(char *z, int n, int slash){
599 int i, j;
600 if( n<0 ) n = strlen(z);
601
602 /* On windows and cygwin convert all \ characters to / */
603 #if defined(_WIN32) || defined(__CYGWIN__)
604 for(i=0; i<n; i++){
605 if( z[i]=='\\' ) z[i] = '/';
606 }
607 #endif
608
@@ -705,13 +709,13 @@
709 ** Return true if zPath is an absolute pathname. Return false
710 ** if it is relative.
711 */
712 int file_is_absolute_path(const char *zPath){
713 if( zPath[0]=='/'
714 #if defined(_WIN32) || defined(__CYGWIN__)
715 || zPath[0]=='\\'
716 || (fossil_isalpha(zPath[0]) && zPath[1]==':'
717 && (zPath[2]=='\\' || zPath[2]=='/'))
718 #endif
719 ){
720 return 1;
721 }else{
@@ -728,21 +732,21 @@
732 ** If the slash parameter is non-zero, the trailing slash, if any,
733 ** is retained.
734 */
735 void file_canonical_name(const char *zOrigName, Blob *pOut, int slash){
736 if( file_is_absolute_path(zOrigName) ){
737 #if defined(_WIN32) || defined(__CYGWIN__)
738 char *zOut;
739 #endif
740 blob_set(pOut, zOrigName);
741 blob_materialize(pOut);
742 #if defined(_WIN32) || defined(__CYGWIN__)
743 /*
744 ** On Windows/cygwin, normalize the drive letter to upper case.
745 */
746 zOut = blob_str(pOut);
747 if( fossil_islower(zOut[0]) && zOut[1]==':' ){
748 zOut[0] = fossil_toupper(zOut[0]);
749 }
750 #endif
751 }else{
752 char zPwd[2000];
@@ -749,11 +753,11 @@
753 file_getcwd(zPwd, sizeof(zPwd)-strlen(zOrigName));
754 #if defined(_WIN32)
755 /*
756 ** On Windows, normalize the drive letter to upper case.
757 */
758 if( fossil_islower(zPwd[0]) && zPwd[1]==':' ){
759 zPwd[0] = fossil_toupper(zPwd[0]);
760 }
761 #endif
762 blob_zero(pOut);
763 blob_appendf(pOut, "%//%/", zPwd, zOrigName);
@@ -798,12 +802,12 @@
802 ** contain no "/./" or "/../" terms.
803 */
804 int file_is_canonical(const char *z){
805 int i;
806 if( z[0]!='/'
807 #if defined(_WIN32) || defined(__CYGWIN__)
808 && (!fossil_isupper(z[0]) || z[1]!=':' || z[2]!='/')
809 #endif
810 ) return 0;
811
812 for(i=0; z[i]; i++){
813 if( z[i]=='\\' ) return 0;
@@ -846,11 +850,11 @@
850 char zBuf[2000];
851 zPwd = zBuf;
852 file_getcwd(zBuf, sizeof(zBuf)-20);
853 zPwd = file_without_drive_letter(zBuf);
854 i = 1;
855 #if defined(_WIN32) || defined(__CYGWIN__)
856 while( zPath[i] && fossil_tolower(zPwd[i])==fossil_tolower(zPath[i]) ) i++;
857 #else
858 while( zPath[i] && zPwd[i]==zPath[i] ) i++;
859 #endif
860 if( zPath[i]==0 ){
@@ -1011,23 +1015,26 @@
1015
1016 /*
1017 ** Construct a random temporary filename into zBuf[].
1018 */
1019 void file_tempname(int nBuf, char *zBuf){
 
1020 #if defined(_WIN32)
1021 const char *azDirs[] = {
1022 0, /* GetTempPath */
1023 0, /* TEMP */
1024 0, /* TMP */
1025 ".",
1026 };
1027 #else
1028 static const char *const azDirs[] = {
1029 "/var/tmp",
1030 "/usr/tmp",
1031 "/tmp",
1032 "/temp",
 
1033 ".",
1034 };
1035 #endif
1036 static const unsigned char zChars[] =
1037 "abcdefghijklmnopqrstuvwxyz"
1038 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
1039 "0123456789";
1040 unsigned int i, j;
@@ -1070,12 +1077,13 @@
1077 }
1078 zBuf[j] = 0;
1079 }while( file_size(zBuf)>=0 );
1080
1081 #if defined(_WIN32)
1082 fossil_filename_free((char *)azDirs[0]);
1083 fossil_filename_free((char *)azDirs[1]);
1084 fossil_filename_free((char *)azDirs[2]);
1085 #endif
1086 }
1087
1088
1089 /*
@@ -1137,14 +1145,14 @@
1145 ** Like fopen() but always takes a UTF8 argument.
1146 */
1147 FILE *fossil_fopen(const char *zName, const char *zMode){
1148 #ifdef _WIN32
1149 wchar_t *uMode = fossil_utf8_to_unicode(zMode);
1150 wchar_t *uName = fossil_utf8_to_filename(zName);
1151 FILE *f = _wfopen(uName, uMode);
1152 fossil_filename_free(uName);
1153 fossil_unicode_free(uMode);
1154 #else
1155 FILE *f = fopen(zName, zMode);
1156 #endif
1157 return f;
1158 }
1159
+8 -8
--- src/finfo.c
+++ src/finfo.c
@@ -20,11 +20,11 @@
2020
#include "config.h"
2121
#include "finfo.h"
2222
2323
/*
2424
** COMMAND: finfo
25
-**
25
+**
2626
** Usage: %fossil finfo ?OPTIONS? FILENAME
2727
**
2828
** Print the complete change history for a single file going backwards
2929
** in time. The default mode is -l.
3030
**
@@ -55,11 +55,11 @@
5555
** See also: artifact, cat, descendants, info, leaves
5656
*/
5757
void finfo_cmd(void){
5858
capture_case_sensitive_option();
5959
db_must_be_within_tree();
60
- if (find_option("status","s",0)) {
60
+ if( find_option("status","s",0) ){
6161
Stmt q;
6262
Blob line;
6363
Blob fname;
6464
int vid;
6565
@@ -73,11 +73,11 @@
7373
db_prepare(&q,
7474
"SELECT pathname, deleted, rid, chnged, coalesce(origname!=pathname,0)"
7575
" FROM vfile WHERE vfile.pathname=%B %s",
7676
&fname, filename_collation());
7777
blob_zero(&line);
78
- if ( db_step(&q)==SQLITE_ROW ) {
78
+ if( db_step(&q)==SQLITE_ROW ) {
7979
Blob uuid;
8080
int isDeleted = db_column_int(&q, 1);
8181
int isNew = db_column_int(&q,2) == 0;
8282
int chnged = db_column_int(&q,3);
8383
int renamed = db_column_int(&q,4);
@@ -247,11 +247,11 @@
247247
248248
/*
249249
** WEBPAGE: finfo
250250
** URL: /finfo?name=FILENAME
251251
**
252
-** Show the change history for a single file.
252
+** Show the change history for a single file.
253253
**
254254
** Additional query parameters:
255255
**
256256
** a=DATE Only show changes after DATE
257257
** b=DATE Only show changes before DATE
@@ -265,11 +265,11 @@
265265
const char *zFilename;
266266
char zPrevDate[20];
267267
const char *zA;
268268
const char *zB;
269269
int n;
270
-
270
+
271271
Blob title;
272272
Blob sql;
273273
HQuery url;
274274
GraphContext *pGraph;
275275
int brBg = P("brbg")!=0;
@@ -288,11 +288,11 @@
288288
289289
zPrevDate[0] = 0;
290290
zFilename = PD("name","");
291291
url_add_parameter(&url, "name", zFilename);
292292
blob_zero(&sql);
293
- blob_appendf(&sql,
293
+ blob_appendf(&sql,
294294
"SELECT"
295295
" datetime(event.mtime,'localtime')," /* Date of change */
296296
" coalesce(event.ecomment, event.comment)," /* Check-in comment */
297297
" coalesce(event.euser, event.user)," /* User who made chng */
298298
" mlink.pid," /* Parent rid */
@@ -403,11 +403,11 @@
403403
@ %z(href("%R/finfo?name=%t", zPrevName))%h(zPrevName)</a>
404404
}
405405
@ %z(href("%R/artifact/%s",zUuid))[%S(zUuid)]</a> part of check-in
406406
}else{
407407
char *zNewName;
408
- zNewName = db_text(0,
408
+ zNewName = db_text(0,
409409
"SELECT name FROM filename WHERE fnid = "
410410
" (SELECT fnid FROM mlink"
411411
" WHERE mid=%d"
412412
" AND pfnid IN (SELECT fnid FROM filename WHERE name=%Q %s))",
413413
fmid, zFilename, filename_collation());
@@ -418,11 +418,11 @@
418418
}else{
419419
@ <b>Deleted</b> by check-in
420420
}
421421
}
422422
hyperlink_to_uuid(zShortCkin);
423
- @ %h(zCom) (user:
423
+ @ %w(zCom) (user:
424424
hyperlink_to_user(zUser, zDate, "");
425425
@ branch: %h(zBr))
426426
if( g.perm.Hyperlink && zUuid ){
427427
const char *z = zFilename;
428428
if( fpid ){
429429
--- src/finfo.c
+++ src/finfo.c
@@ -20,11 +20,11 @@
20 #include "config.h"
21 #include "finfo.h"
22
23 /*
24 ** COMMAND: finfo
25 **
26 ** Usage: %fossil finfo ?OPTIONS? FILENAME
27 **
28 ** Print the complete change history for a single file going backwards
29 ** in time. The default mode is -l.
30 **
@@ -55,11 +55,11 @@
55 ** See also: artifact, cat, descendants, info, leaves
56 */
57 void finfo_cmd(void){
58 capture_case_sensitive_option();
59 db_must_be_within_tree();
60 if (find_option("status","s",0)) {
61 Stmt q;
62 Blob line;
63 Blob fname;
64 int vid;
65
@@ -73,11 +73,11 @@
73 db_prepare(&q,
74 "SELECT pathname, deleted, rid, chnged, coalesce(origname!=pathname,0)"
75 " FROM vfile WHERE vfile.pathname=%B %s",
76 &fname, filename_collation());
77 blob_zero(&line);
78 if ( db_step(&q)==SQLITE_ROW ) {
79 Blob uuid;
80 int isDeleted = db_column_int(&q, 1);
81 int isNew = db_column_int(&q,2) == 0;
82 int chnged = db_column_int(&q,3);
83 int renamed = db_column_int(&q,4);
@@ -247,11 +247,11 @@
247
248 /*
249 ** WEBPAGE: finfo
250 ** URL: /finfo?name=FILENAME
251 **
252 ** Show the change history for a single file.
253 **
254 ** Additional query parameters:
255 **
256 ** a=DATE Only show changes after DATE
257 ** b=DATE Only show changes before DATE
@@ -265,11 +265,11 @@
265 const char *zFilename;
266 char zPrevDate[20];
267 const char *zA;
268 const char *zB;
269 int n;
270
271 Blob title;
272 Blob sql;
273 HQuery url;
274 GraphContext *pGraph;
275 int brBg = P("brbg")!=0;
@@ -288,11 +288,11 @@
288
289 zPrevDate[0] = 0;
290 zFilename = PD("name","");
291 url_add_parameter(&url, "name", zFilename);
292 blob_zero(&sql);
293 blob_appendf(&sql,
294 "SELECT"
295 " datetime(event.mtime,'localtime')," /* Date of change */
296 " coalesce(event.ecomment, event.comment)," /* Check-in comment */
297 " coalesce(event.euser, event.user)," /* User who made chng */
298 " mlink.pid," /* Parent rid */
@@ -403,11 +403,11 @@
403 @ %z(href("%R/finfo?name=%t", zPrevName))%h(zPrevName)</a>
404 }
405 @ %z(href("%R/artifact/%s",zUuid))[%S(zUuid)]</a> part of check-in
406 }else{
407 char *zNewName;
408 zNewName = db_text(0,
409 "SELECT name FROM filename WHERE fnid = "
410 " (SELECT fnid FROM mlink"
411 " WHERE mid=%d"
412 " AND pfnid IN (SELECT fnid FROM filename WHERE name=%Q %s))",
413 fmid, zFilename, filename_collation());
@@ -418,11 +418,11 @@
418 }else{
419 @ <b>Deleted</b> by check-in
420 }
421 }
422 hyperlink_to_uuid(zShortCkin);
423 @ %h(zCom) (user:
424 hyperlink_to_user(zUser, zDate, "");
425 @ branch: %h(zBr))
426 if( g.perm.Hyperlink && zUuid ){
427 const char *z = zFilename;
428 if( fpid ){
429
--- src/finfo.c
+++ src/finfo.c
@@ -20,11 +20,11 @@
20 #include "config.h"
21 #include "finfo.h"
22
23 /*
24 ** COMMAND: finfo
25 **
26 ** Usage: %fossil finfo ?OPTIONS? FILENAME
27 **
28 ** Print the complete change history for a single file going backwards
29 ** in time. The default mode is -l.
30 **
@@ -55,11 +55,11 @@
55 ** See also: artifact, cat, descendants, info, leaves
56 */
57 void finfo_cmd(void){
58 capture_case_sensitive_option();
59 db_must_be_within_tree();
60 if( find_option("status","s",0) ){
61 Stmt q;
62 Blob line;
63 Blob fname;
64 int vid;
65
@@ -73,11 +73,11 @@
73 db_prepare(&q,
74 "SELECT pathname, deleted, rid, chnged, coalesce(origname!=pathname,0)"
75 " FROM vfile WHERE vfile.pathname=%B %s",
76 &fname, filename_collation());
77 blob_zero(&line);
78 if( db_step(&q)==SQLITE_ROW ) {
79 Blob uuid;
80 int isDeleted = db_column_int(&q, 1);
81 int isNew = db_column_int(&q,2) == 0;
82 int chnged = db_column_int(&q,3);
83 int renamed = db_column_int(&q,4);
@@ -247,11 +247,11 @@
247
248 /*
249 ** WEBPAGE: finfo
250 ** URL: /finfo?name=FILENAME
251 **
252 ** Show the change history for a single file.
253 **
254 ** Additional query parameters:
255 **
256 ** a=DATE Only show changes after DATE
257 ** b=DATE Only show changes before DATE
@@ -265,11 +265,11 @@
265 const char *zFilename;
266 char zPrevDate[20];
267 const char *zA;
268 const char *zB;
269 int n;
270
271 Blob title;
272 Blob sql;
273 HQuery url;
274 GraphContext *pGraph;
275 int brBg = P("brbg")!=0;
@@ -288,11 +288,11 @@
288
289 zPrevDate[0] = 0;
290 zFilename = PD("name","");
291 url_add_parameter(&url, "name", zFilename);
292 blob_zero(&sql);
293 blob_appendf(&sql,
294 "SELECT"
295 " datetime(event.mtime,'localtime')," /* Date of change */
296 " coalesce(event.ecomment, event.comment)," /* Check-in comment */
297 " coalesce(event.euser, event.user)," /* User who made chng */
298 " mlink.pid," /* Parent rid */
@@ -403,11 +403,11 @@
403 @ %z(href("%R/finfo?name=%t", zPrevName))%h(zPrevName)</a>
404 }
405 @ %z(href("%R/artifact/%s",zUuid))[%S(zUuid)]</a> part of check-in
406 }else{
407 char *zNewName;
408 zNewName = db_text(0,
409 "SELECT name FROM filename WHERE fnid = "
410 " (SELECT fnid FROM mlink"
411 " WHERE mid=%d"
412 " AND pfnid IN (SELECT fnid FROM filename WHERE name=%Q %s))",
413 fmid, zFilename, filename_collation());
@@ -418,11 +418,11 @@
418 }else{
419 @ <b>Deleted</b> by check-in
420 }
421 }
422 hyperlink_to_uuid(zShortCkin);
423 @ %w(zCom) (user:
424 hyperlink_to_user(zUser, zDate, "");
425 @ branch: %h(zBr))
426 if( g.perm.Hyperlink && zUuid ){
427 const char *z = zFilename;
428 if( fpid ){
429
+40 -24
--- src/glob.c
+++ src/glob.c
@@ -29,16 +29,17 @@
2929
** zVal: "x"
3030
** zGlobList: "*.o,*.obj"
3131
**
3232
** Result: "(x GLOB '*.o' OR x GLOB '*.obj')"
3333
**
34
-** Each element of the GLOB list may optionally be enclosed in either '...'
35
-** or "...". This allows commas in the expression. Whitespace at the
36
-** beginning and end of each GLOB pattern is ignored, except when enclosed
37
-** within '...' or "...".
34
+** Commas and whitespace are considered to be element delimters. Each
35
+** element of the GLOB list may optionally be enclosed in either '...' or
36
+** "...". This allows commas and/or whitespace to be used in the elements
37
+** themselves.
3838
**
39
-** This routine makes no effort to free the memory space it uses.
39
+** This routine makes no effort to free the memory space it uses, which
40
+** currently consists of a blob object and its contents.
4041
*/
4142
char *glob_expr(const char *zVal, const char *zGlobList){
4243
Blob expr;
4344
char *zSep = "(";
4445
int nTerm = 0;
@@ -46,21 +47,24 @@
4647
int cTerm;
4748
4849
if( zGlobList==0 || zGlobList[0]==0 ) return "0";
4950
blob_zero(&expr);
5051
while( zGlobList[0] ){
51
- while( fossil_isspace(zGlobList[0]) || zGlobList[0]==',' ) zGlobList++;
52
+ while( fossil_isspace(zGlobList[0]) || zGlobList[0]==',' ){
53
+ zGlobList++; /* Skip leading commas, spaces, and newlines */
54
+ }
5255
if( zGlobList[0]==0 ) break;
5356
if( zGlobList[0]=='\'' || zGlobList[0]=='"' ){
5457
cTerm = zGlobList[0];
5558
zGlobList++;
5659
}else{
5760
cTerm = ',';
5861
}
59
- for(i=0; zGlobList[i] && zGlobList[i]!=cTerm; i++){}
60
- if( cTerm==',' ){
61
- while( i>0 && fossil_isspace(zGlobList[i-1]) ){ i--; }
62
+ /* Find the next delimter (or the end of the string). */
63
+ for(i=0; zGlobList[i] && zGlobList[i]!=cTerm; i++){
64
+ if( cTerm!=',' ) continue; /* If quoted, keep going. */
65
+ if( fossil_isspace(zGlobList[i]) ) break; /* If space, stop. */
6266
}
6367
blob_appendf(&expr, "%s%s GLOB '%#q'", zSep, zVal, i, zGlobList);
6468
zSep = " OR ";
6569
if( cTerm!=',' && zGlobList[i] ) i++;
6670
zGlobList += i;
@@ -85,24 +89,24 @@
8589
char **azPattern; /* Array of pointers to patterns */
8690
};
8791
#endif /* INTERFACE */
8892
8993
/*
90
-** zPatternList is a comma-separate list of glob patterns. Parse up
94
+** zPatternList is a comma-separated list of glob patterns. Parse up
9195
** that list and use it to create a new Glob object.
9296
**
9397
** Elements of the glob list may be optionally enclosed in single our
94
-** double-quotes. This allows a comma to be part of a glob.
98
+** double-quotes. This allows a comma to be part of a glob pattern.
9599
**
96100
** Leading and trailing spaces on unquoted glob patterns are ignored.
97101
**
98102
** An empty or null pattern list results in a null glob, which will
99103
** match nothing.
100104
*/
101105
Glob *glob_create(const char *zPatternList){
102106
int nList; /* Size of zPatternList in bytes */
103
- int i, j; /* Loop counters */
107
+ int i; /* Loop counters */
104108
Glob *p; /* The glob being created */
105109
char *z; /* Copy of the pattern list */
106110
char delimiter; /* '\'' or '\"' or 0 */
107111
108112
if( zPatternList==0 || zPatternList[0]==0 ) return 0;
@@ -110,27 +114,26 @@
110114
p = fossil_malloc( sizeof(*p) + nList+1 );
111115
memset(p, 0, sizeof(*p));
112116
z = (char*)&p[1];
113117
memcpy(z, zPatternList, nList+1);
114118
while( z[0] ){
115
- while( z[0]==',' || z[0]==' ' || z[0]=='\n' || z[0]=='\r' ){
116
- z++; /* Skip leading spaces and newlines */
119
+ while( fossil_isspace(z[0]) || z[0]==',' ){
120
+ z++; /* Skip leading commas, spaces, and newlines */
117121
}
122
+ if( z[0]==0 ) break;
118123
if( z[0]=='\'' || z[0]=='"' ){
119124
delimiter = z[0];
120125
z++;
121126
}else{
122127
delimiter = ',';
123128
}
124
- if( z[0]==0 ) break;
125129
p->azPattern = fossil_realloc(p->azPattern, (p->nPattern+1)*sizeof(char*) );
126130
p->azPattern[p->nPattern++] = z;
127
- for(i=0; z[i] && z[i]!=delimiter && z[i]!='\n' && z[i]!='\r'; i++){}
128
- if( delimiter==',' ){
129
- /* Remove trailing spaces / newlines on a comma-delimited pattern */
130
- for(j=i; j>1 && (z[j-1]==' ' || z[j-1]=='\n' || z[j-1]=='\r'); j--){}
131
- if( j<i ) z[j] = 0;
131
+ /* Find the next delimter (or the end of the string). */
132
+ for(i=0; z[i] && z[i]!=delimiter; i++){
133
+ if( delimiter!=',' ) continue; /* If quoted, keep going. */
134
+ if( fossil_isspace(z[i]) ) break; /* If space, stop. */
132135
}
133136
if( z[i]==0 ) break;
134137
z[i] = 0;
135138
z += i+1;
136139
}
@@ -245,22 +248,35 @@
245248
/*
246249
** COMMAND: test-glob
247250
**
248251
** Usage: %fossil test-glob PATTERN STRING...
249252
**
250
-** PATTERN is a comma-separated list of glob patterns. Show which of
251
-** the STRINGs that follow match the PATTERN.
253
+** PATTERN is a comma- and whitespace-separated list of optionally
254
+** quoted glob patterns. Show which of the STRINGs that follow match
255
+** the PATTERN.
256
+**
257
+** If PATTERN begins with "@" the the rest of the pattern is understood
258
+** to be a setting name (such as binary-glob, crln-glob, or encoding-glob)
259
+** and the value of that setting is used as the actually glob pattern.
252260
*/
253261
void glob_test_cmd(void){
254262
Glob *pGlob;
255263
int i;
264
+ char *zPattern;
256265
if( g.argc<4 ) usage("PATTERN STRING ...");
257
- fossil_print("SQL expression: %s\n", glob_expr("x", g.argv[2]));
258
- pGlob = glob_create(g.argv[2]);
266
+ zPattern = g.argv[2];
267
+ if( zPattern[0]=='@' ){
268
+ db_find_and_open_repository(OPEN_ANY_SCHEMA,0);
269
+ zPattern = db_get(zPattern+1, 0);
270
+ if( zPattern==0 ) fossil_fatal("no such setting: %s", g.argv[2]+1);
271
+ fossil_print("GLOB pattern: %s\n", zPattern);
272
+ }
273
+ fossil_print("SQL expression: %s\n", glob_expr("x", zPattern));
274
+ pGlob = glob_create(zPattern);
259275
for(i=0; i<pGlob->nPattern; i++){
260276
fossil_print("pattern[%d] = [%s]\n", i, pGlob->azPattern[i]);
261277
}
262278
for(i=3; i<g.argc; i++){
263279
fossil_print("%d %s\n", glob_match(pGlob, g.argv[i]), g.argv[i]);
264280
}
265281
glob_free(pGlob);
266282
}
267283
--- src/glob.c
+++ src/glob.c
@@ -29,16 +29,17 @@
29 ** zVal: "x"
30 ** zGlobList: "*.o,*.obj"
31 **
32 ** Result: "(x GLOB '*.o' OR x GLOB '*.obj')"
33 **
34 ** Each element of the GLOB list may optionally be enclosed in either '...'
35 ** or "...". This allows commas in the expression. Whitespace at the
36 ** beginning and end of each GLOB pattern is ignored, except when enclosed
37 ** within '...' or "...".
38 **
39 ** This routine makes no effort to free the memory space it uses.
 
40 */
41 char *glob_expr(const char *zVal, const char *zGlobList){
42 Blob expr;
43 char *zSep = "(";
44 int nTerm = 0;
@@ -46,21 +47,24 @@
46 int cTerm;
47
48 if( zGlobList==0 || zGlobList[0]==0 ) return "0";
49 blob_zero(&expr);
50 while( zGlobList[0] ){
51 while( fossil_isspace(zGlobList[0]) || zGlobList[0]==',' ) zGlobList++;
 
 
52 if( zGlobList[0]==0 ) break;
53 if( zGlobList[0]=='\'' || zGlobList[0]=='"' ){
54 cTerm = zGlobList[0];
55 zGlobList++;
56 }else{
57 cTerm = ',';
58 }
59 for(i=0; zGlobList[i] && zGlobList[i]!=cTerm; i++){}
60 if( cTerm==',' ){
61 while( i>0 && fossil_isspace(zGlobList[i-1]) ){ i--; }
 
62 }
63 blob_appendf(&expr, "%s%s GLOB '%#q'", zSep, zVal, i, zGlobList);
64 zSep = " OR ";
65 if( cTerm!=',' && zGlobList[i] ) i++;
66 zGlobList += i;
@@ -85,24 +89,24 @@
85 char **azPattern; /* Array of pointers to patterns */
86 };
87 #endif /* INTERFACE */
88
89 /*
90 ** zPatternList is a comma-separate list of glob patterns. Parse up
91 ** that list and use it to create a new Glob object.
92 **
93 ** Elements of the glob list may be optionally enclosed in single our
94 ** double-quotes. This allows a comma to be part of a glob.
95 **
96 ** Leading and trailing spaces on unquoted glob patterns are ignored.
97 **
98 ** An empty or null pattern list results in a null glob, which will
99 ** match nothing.
100 */
101 Glob *glob_create(const char *zPatternList){
102 int nList; /* Size of zPatternList in bytes */
103 int i, j; /* Loop counters */
104 Glob *p; /* The glob being created */
105 char *z; /* Copy of the pattern list */
106 char delimiter; /* '\'' or '\"' or 0 */
107
108 if( zPatternList==0 || zPatternList[0]==0 ) return 0;
@@ -110,27 +114,26 @@
110 p = fossil_malloc( sizeof(*p) + nList+1 );
111 memset(p, 0, sizeof(*p));
112 z = (char*)&p[1];
113 memcpy(z, zPatternList, nList+1);
114 while( z[0] ){
115 while( z[0]==',' || z[0]==' ' || z[0]=='\n' || z[0]=='\r' ){
116 z++; /* Skip leading spaces and newlines */
117 }
 
118 if( z[0]=='\'' || z[0]=='"' ){
119 delimiter = z[0];
120 z++;
121 }else{
122 delimiter = ',';
123 }
124 if( z[0]==0 ) break;
125 p->azPattern = fossil_realloc(p->azPattern, (p->nPattern+1)*sizeof(char*) );
126 p->azPattern[p->nPattern++] = z;
127 for(i=0; z[i] && z[i]!=delimiter && z[i]!='\n' && z[i]!='\r'; i++){}
128 if( delimiter==',' ){
129 /* Remove trailing spaces / newlines on a comma-delimited pattern */
130 for(j=i; j>1 && (z[j-1]==' ' || z[j-1]=='\n' || z[j-1]=='\r'); j--){}
131 if( j<i ) z[j] = 0;
132 }
133 if( z[i]==0 ) break;
134 z[i] = 0;
135 z += i+1;
136 }
@@ -245,22 +248,35 @@
245 /*
246 ** COMMAND: test-glob
247 **
248 ** Usage: %fossil test-glob PATTERN STRING...
249 **
250 ** PATTERN is a comma-separated list of glob patterns. Show which of
251 ** the STRINGs that follow match the PATTERN.
 
 
 
 
 
252 */
253 void glob_test_cmd(void){
254 Glob *pGlob;
255 int i;
 
256 if( g.argc<4 ) usage("PATTERN STRING ...");
257 fossil_print("SQL expression: %s\n", glob_expr("x", g.argv[2]));
258 pGlob = glob_create(g.argv[2]);
 
 
 
 
 
 
 
259 for(i=0; i<pGlob->nPattern; i++){
260 fossil_print("pattern[%d] = [%s]\n", i, pGlob->azPattern[i]);
261 }
262 for(i=3; i<g.argc; i++){
263 fossil_print("%d %s\n", glob_match(pGlob, g.argv[i]), g.argv[i]);
264 }
265 glob_free(pGlob);
266 }
267
--- src/glob.c
+++ src/glob.c
@@ -29,16 +29,17 @@
29 ** zVal: "x"
30 ** zGlobList: "*.o,*.obj"
31 **
32 ** Result: "(x GLOB '*.o' OR x GLOB '*.obj')"
33 **
34 ** Commas and whitespace are considered to be element delimters. Each
35 ** element of the GLOB list may optionally be enclosed in either '...' or
36 ** "...". This allows commas and/or whitespace to be used in the elements
37 ** themselves.
38 **
39 ** This routine makes no effort to free the memory space it uses, which
40 ** currently consists of a blob object and its contents.
41 */
42 char *glob_expr(const char *zVal, const char *zGlobList){
43 Blob expr;
44 char *zSep = "(";
45 int nTerm = 0;
@@ -46,21 +47,24 @@
47 int cTerm;
48
49 if( zGlobList==0 || zGlobList[0]==0 ) return "0";
50 blob_zero(&expr);
51 while( zGlobList[0] ){
52 while( fossil_isspace(zGlobList[0]) || zGlobList[0]==',' ){
53 zGlobList++; /* Skip leading commas, spaces, and newlines */
54 }
55 if( zGlobList[0]==0 ) break;
56 if( zGlobList[0]=='\'' || zGlobList[0]=='"' ){
57 cTerm = zGlobList[0];
58 zGlobList++;
59 }else{
60 cTerm = ',';
61 }
62 /* Find the next delimter (or the end of the string). */
63 for(i=0; zGlobList[i] && zGlobList[i]!=cTerm; i++){
64 if( cTerm!=',' ) continue; /* If quoted, keep going. */
65 if( fossil_isspace(zGlobList[i]) ) break; /* If space, stop. */
66 }
67 blob_appendf(&expr, "%s%s GLOB '%#q'", zSep, zVal, i, zGlobList);
68 zSep = " OR ";
69 if( cTerm!=',' && zGlobList[i] ) i++;
70 zGlobList += i;
@@ -85,24 +89,24 @@
89 char **azPattern; /* Array of pointers to patterns */
90 };
91 #endif /* INTERFACE */
92
93 /*
94 ** zPatternList is a comma-separated list of glob patterns. Parse up
95 ** that list and use it to create a new Glob object.
96 **
97 ** Elements of the glob list may be optionally enclosed in single our
98 ** double-quotes. This allows a comma to be part of a glob pattern.
99 **
100 ** Leading and trailing spaces on unquoted glob patterns are ignored.
101 **
102 ** An empty or null pattern list results in a null glob, which will
103 ** match nothing.
104 */
105 Glob *glob_create(const char *zPatternList){
106 int nList; /* Size of zPatternList in bytes */
107 int i; /* Loop counters */
108 Glob *p; /* The glob being created */
109 char *z; /* Copy of the pattern list */
110 char delimiter; /* '\'' or '\"' or 0 */
111
112 if( zPatternList==0 || zPatternList[0]==0 ) return 0;
@@ -110,27 +114,26 @@
114 p = fossil_malloc( sizeof(*p) + nList+1 );
115 memset(p, 0, sizeof(*p));
116 z = (char*)&p[1];
117 memcpy(z, zPatternList, nList+1);
118 while( z[0] ){
119 while( fossil_isspace(z[0]) || z[0]==',' ){
120 z++; /* Skip leading commas, spaces, and newlines */
121 }
122 if( z[0]==0 ) break;
123 if( z[0]=='\'' || z[0]=='"' ){
124 delimiter = z[0];
125 z++;
126 }else{
127 delimiter = ',';
128 }
 
129 p->azPattern = fossil_realloc(p->azPattern, (p->nPattern+1)*sizeof(char*) );
130 p->azPattern[p->nPattern++] = z;
131 /* Find the next delimter (or the end of the string). */
132 for(i=0; z[i] && z[i]!=delimiter; i++){
133 if( delimiter!=',' ) continue; /* If quoted, keep going. */
134 if( fossil_isspace(z[i]) ) break; /* If space, stop. */
 
135 }
136 if( z[i]==0 ) break;
137 z[i] = 0;
138 z += i+1;
139 }
@@ -245,22 +248,35 @@
248 /*
249 ** COMMAND: test-glob
250 **
251 ** Usage: %fossil test-glob PATTERN STRING...
252 **
253 ** PATTERN is a comma- and whitespace-separated list of optionally
254 ** quoted glob patterns. Show which of the STRINGs that follow match
255 ** the PATTERN.
256 **
257 ** If PATTERN begins with "@" the the rest of the pattern is understood
258 ** to be a setting name (such as binary-glob, crln-glob, or encoding-glob)
259 ** and the value of that setting is used as the actually glob pattern.
260 */
261 void glob_test_cmd(void){
262 Glob *pGlob;
263 int i;
264 char *zPattern;
265 if( g.argc<4 ) usage("PATTERN STRING ...");
266 zPattern = g.argv[2];
267 if( zPattern[0]=='@' ){
268 db_find_and_open_repository(OPEN_ANY_SCHEMA,0);
269 zPattern = db_get(zPattern+1, 0);
270 if( zPattern==0 ) fossil_fatal("no such setting: %s", g.argv[2]+1);
271 fossil_print("GLOB pattern: %s\n", zPattern);
272 }
273 fossil_print("SQL expression: %s\n", glob_expr("x", zPattern));
274 pGlob = glob_create(zPattern);
275 for(i=0; i<pGlob->nPattern; i++){
276 fossil_print("pattern[%d] = [%s]\n", i, pGlob->azPattern[i]);
277 }
278 for(i=3; i<g.argc; i++){
279 fossil_print("%d %s\n", glob_match(pGlob, g.argv[i]), g.argv[i]);
280 }
281 glob_free(pGlob);
282 }
283
+2 -2
--- src/http.c
+++ src/http.c
@@ -60,11 +60,10 @@
6060
zPw = 0;
6161
}else{
6262
/* Password failure while doing a sync from the command-line interface */
6363
url_prompt_for_password();
6464
zPw = g.urlPasswd;
65
- if( !g.dontKeepUrl ) db_set("last-sync-pw", obscure(zPw), 0);
6665
}
6766
6867
/* If the first character of the password is "#", then that character is
6968
** not really part of the password - it is an indicator that we should
7069
** use Basic Authentication. So skip that character.
@@ -72,10 +71,11 @@
7271
if( zPw && zPw[0]=='#' ) zPw++;
7372
7473
/* The login card wants the SHA1 hash of the password, so convert the
7574
** password to its SHA1 hash it it isn't already a SHA1 hash.
7675
*/
76
+ /* fossil_print("\nzPw=[%s]\n", zPw); // TESTING ONLY */
7777
if( zPw && zPw[0] ) zPw = sha1_shared_secret(zPw, zLogin, 0);
7878
7979
blob_append(&pw, zPw, -1);
8080
sha1sum_blob(&pw, &sig);
8181
blob_appendf(pLogin, "login %F %b %b\n", zLogin, &nonce, &sig);
@@ -243,11 +243,11 @@
243243
while( j>4 && fossil_strcmp(&zLine[j-4],"/xfer")==0 ){
244244
j -= 4;
245245
zLine[j] = 0;
246246
}
247247
fossil_print("redirect to %s\n", &zLine[i]);
248
- url_parse(&zLine[i]);
248
+ url_parse(&zLine[i], 0);
249249
transport_close();
250250
return http_exchange(pSend, pReply, useLogin, maxRedirect);
251251
}else if( fossil_strnicmp(zLine, "content-type: ", 14)==0 ){
252252
if( fossil_strnicmp(&zLine[14], "application/x-fossil-debug", -1)==0 ){
253253
isCompressed = 0;
254254
--- src/http.c
+++ src/http.c
@@ -60,11 +60,10 @@
60 zPw = 0;
61 }else{
62 /* Password failure while doing a sync from the command-line interface */
63 url_prompt_for_password();
64 zPw = g.urlPasswd;
65 if( !g.dontKeepUrl ) db_set("last-sync-pw", obscure(zPw), 0);
66 }
67
68 /* If the first character of the password is "#", then that character is
69 ** not really part of the password - it is an indicator that we should
70 ** use Basic Authentication. So skip that character.
@@ -72,10 +71,11 @@
72 if( zPw && zPw[0]=='#' ) zPw++;
73
74 /* The login card wants the SHA1 hash of the password, so convert the
75 ** password to its SHA1 hash it it isn't already a SHA1 hash.
76 */
 
77 if( zPw && zPw[0] ) zPw = sha1_shared_secret(zPw, zLogin, 0);
78
79 blob_append(&pw, zPw, -1);
80 sha1sum_blob(&pw, &sig);
81 blob_appendf(pLogin, "login %F %b %b\n", zLogin, &nonce, &sig);
@@ -243,11 +243,11 @@
243 while( j>4 && fossil_strcmp(&zLine[j-4],"/xfer")==0 ){
244 j -= 4;
245 zLine[j] = 0;
246 }
247 fossil_print("redirect to %s\n", &zLine[i]);
248 url_parse(&zLine[i]);
249 transport_close();
250 return http_exchange(pSend, pReply, useLogin, maxRedirect);
251 }else if( fossil_strnicmp(zLine, "content-type: ", 14)==0 ){
252 if( fossil_strnicmp(&zLine[14], "application/x-fossil-debug", -1)==0 ){
253 isCompressed = 0;
254
--- src/http.c
+++ src/http.c
@@ -60,11 +60,10 @@
60 zPw = 0;
61 }else{
62 /* Password failure while doing a sync from the command-line interface */
63 url_prompt_for_password();
64 zPw = g.urlPasswd;
 
65 }
66
67 /* If the first character of the password is "#", then that character is
68 ** not really part of the password - it is an indicator that we should
69 ** use Basic Authentication. So skip that character.
@@ -72,10 +71,11 @@
71 if( zPw && zPw[0]=='#' ) zPw++;
72
73 /* The login card wants the SHA1 hash of the password, so convert the
74 ** password to its SHA1 hash it it isn't already a SHA1 hash.
75 */
76 /* fossil_print("\nzPw=[%s]\n", zPw); // TESTING ONLY */
77 if( zPw && zPw[0] ) zPw = sha1_shared_secret(zPw, zLogin, 0);
78
79 blob_append(&pw, zPw, -1);
80 sha1sum_blob(&pw, &sig);
81 blob_appendf(pLogin, "login %F %b %b\n", zLogin, &nonce, &sig);
@@ -243,11 +243,11 @@
243 while( j>4 && fossil_strcmp(&zLine[j-4],"/xfer")==0 ){
244 j -= 4;
245 zLine[j] = 0;
246 }
247 fossil_print("redirect to %s\n", &zLine[i]);
248 url_parse(&zLine[i], 0);
249 transport_close();
250 return http_exchange(pSend, pReply, useLogin, maxRedirect);
251 }else if( fossil_strnicmp(zLine, "content-type: ", 14)==0 ){
252 if( fossil_strnicmp(&zLine[14], "application/x-fossil-debug", -1)==0 ){
253 isCompressed = 0;
254
--- src/http_transport.c
+++ src/http_transport.c
@@ -312,11 +312,11 @@
312312
sqlite3_randomness(sizeof(iRandId), &iRandId);
313313
transport.zOutFile = mprintf("%s-%llu-out.http",
314314
g.zRepositoryName, iRandId);
315315
transport.zInFile = mprintf("%s-%llu-in.http",
316316
g.zRepositoryName, iRandId);
317
- transport.pFile = fopen(transport.zOutFile, "wb");
317
+ transport.pFile = fossil_fopen(transport.zOutFile, "wb");
318318
if( transport.pFile==0 ){
319319
fossil_fatal("cannot output temporary file: %s", transport.zOutFile);
320320
}
321321
transport.isOpen = 1;
322322
}else{
@@ -409,11 +409,11 @@
409409
zCmd = mprintf("\"%s\" http \"%s\" \"%s\" \"%s\" 127.0.0.1 --localauth",
410410
g.nameOfExe, g.urlName, transport.zOutFile, transport.zInFile
411411
);
412412
fossil_system(zCmd);
413413
free(zCmd);
414
- transport.pFile = fopen(transport.zInFile, "rb");
414
+ transport.pFile = fossil_fopen(transport.zInFile, "rb");
415415
}
416416
}
417417
418418
/*
419419
** Log all input to a file. The transport layer will take responsibility
420420
--- src/http_transport.c
+++ src/http_transport.c
@@ -312,11 +312,11 @@
312 sqlite3_randomness(sizeof(iRandId), &iRandId);
313 transport.zOutFile = mprintf("%s-%llu-out.http",
314 g.zRepositoryName, iRandId);
315 transport.zInFile = mprintf("%s-%llu-in.http",
316 g.zRepositoryName, iRandId);
317 transport.pFile = fopen(transport.zOutFile, "wb");
318 if( transport.pFile==0 ){
319 fossil_fatal("cannot output temporary file: %s", transport.zOutFile);
320 }
321 transport.isOpen = 1;
322 }else{
@@ -409,11 +409,11 @@
409 zCmd = mprintf("\"%s\" http \"%s\" \"%s\" \"%s\" 127.0.0.1 --localauth",
410 g.nameOfExe, g.urlName, transport.zOutFile, transport.zInFile
411 );
412 fossil_system(zCmd);
413 free(zCmd);
414 transport.pFile = fopen(transport.zInFile, "rb");
415 }
416 }
417
418 /*
419 ** Log all input to a file. The transport layer will take responsibility
420
--- src/http_transport.c
+++ src/http_transport.c
@@ -312,11 +312,11 @@
312 sqlite3_randomness(sizeof(iRandId), &iRandId);
313 transport.zOutFile = mprintf("%s-%llu-out.http",
314 g.zRepositoryName, iRandId);
315 transport.zInFile = mprintf("%s-%llu-in.http",
316 g.zRepositoryName, iRandId);
317 transport.pFile = fossil_fopen(transport.zOutFile, "wb");
318 if( transport.pFile==0 ){
319 fossil_fatal("cannot output temporary file: %s", transport.zOutFile);
320 }
321 transport.isOpen = 1;
322 }else{
@@ -409,11 +409,11 @@
409 zCmd = mprintf("\"%s\" http \"%s\" \"%s\" \"%s\" 127.0.0.1 --localauth",
410 g.nameOfExe, g.urlName, transport.zOutFile, transport.zInFile
411 );
412 fossil_system(zCmd);
413 free(zCmd);
414 transport.pFile = fossil_fopen(transport.zInFile, "rb");
415 }
416 }
417
418 /*
419 ** Log all input to a file. The transport layer will take responsibility
420
+24 -76
--- src/info.c
+++ src/info.c
@@ -198,22 +198,20 @@
198198
if( g.localOpen ){
199199
fossil_print("repository: %s\n", db_repository_filename());
200200
fossil_print("local-root: %s\n", g.zLocalRoot);
201201
}
202202
if( bDetail ) extraRepoInfo();
203
-#if defined(_WIN32)
204
- if( g.zHome ){
205
- fossil_print("user-home: %s\n", g.zHome);
203
+ if( g.zConfigDbName ){
204
+ fossil_print("config-db: %s\n", g.zConfigDbName);
206205
}
207
-#endif
208206
fossil_print("project-code: %s\n", db_get("project-code", ""));
209207
vid = g.localOpen ? db_lget_int("checkout", 0) : 0;
210208
if( vid ){
211209
show_common_info(vid, "checkout:", 1, 1);
212210
}
213211
fossil_print("checkins: %d\n",
214
- db_int(-1, "SELECT count(distinct mid) FROM mlink /*scan*/"));
212
+ db_int(-1, "SELECT count(*) FROM event WHERE type='ci' /*scan*/"));
215213
}else{
216214
int rid;
217215
rid = name_to_rid(g.argv[2]);
218216
if( rid==0 ){
219217
fossil_panic("no such object: %s\n", g.argv[2]);
@@ -314,16 +312,17 @@
314312
}else{
315313
blob_zero(&to);
316314
}
317315
blob_zero(&out);
318316
if( diffFlags & DIFF_SIDEBYSIDE ){
319
- text_diff(&from, &to, &out, pRe, diffFlags | DIFF_HTML);
317
+ text_diff(&from, &to, &out, pRe, diffFlags | DIFF_HTML | DIFF_NOTTOOBIG);
320318
@ <div class="sbsdiff">
321319
@ %s(blob_str(&out))
322320
@ </div>
323321
}else{
324
- text_diff(&from, &to, &out, pRe, diffFlags | DIFF_LINENO | DIFF_HTML);
322
+ text_diff(&from, &to, &out, pRe,
323
+ diffFlags | DIFF_LINENO | DIFF_HTML | DIFF_NOTTOOBIG);
325324
@ <div class="udiff">
326325
@ %s(blob_str(&out))
327326
@ </div>
328327
}
329328
blob_reset(&from);
@@ -492,15 +491,10 @@
492491
char *zEUser, *zEComment;
493492
const char *zUser;
494493
const char *zComment;
495494
const char *zDate;
496495
const char *zOrigDate;
497
-#if 0
498
- char *zThisBranch;
499
- double thisMtime;
500
- int seenDiffTitle = 0;
501
-#endif
502496
503497
style_header(zTitle);
504498
login_anonymous_available();
505499
free(zTitle);
506500
zEUser = db_text(0,
@@ -511,13 +505,10 @@
511505
TAG_COMMENT, rid);
512506
zUser = db_column_text(&q, 2);
513507
zComment = db_column_text(&q, 3);
514508
zDate = db_column_text(&q,1);
515509
zOrigDate = db_column_text(&q, 4);
516
-#if 0
517
- thisMtime = db_column_double(&q, 5);
518
-#endif
519510
@ <div class="section">Overview</div>
520511
@ <table class="label-value">
521512
@ <tr><th>SHA1&nbsp;Hash:</th><td>%s(zUuid)
522513
if( g.perm.Setup ){
523514
@ (Record ID: %d(rid))
@@ -537,14 +528,14 @@
537528
}else{
538529
@ <tr><th>User:</th><td>
539530
hyperlink_to_user(zUser,zDate,"</td></tr>");
540531
}
541532
if( zEComment ){
542
- @ <tr><th>Edited&nbsp;Comment:</th><td>%w(zEComment)</td></tr>
543
- @ <tr><th>Original&nbsp;Comment:</th><td>%w(zComment)</td></tr>
533
+ @ <tr><th>Edited&nbsp;Comment:</th><td>%!w(zEComment)</td></tr>
534
+ @ <tr><th>Original&nbsp;Comment:</th><td>%!w(zComment)</td></tr>
544535
}else{
545
- @ <tr><th>Comment:</th><td>%w(zComment)</td></tr>
536
+ @ <tr><th>Comment:</th><td>%!w(zComment)</td></tr>
546537
}
547538
if( g.perm.Admin ){
548539
db_prepare(&q,
549540
"SELECT rcvfrom.ipaddr, user.login, datetime(rcvfrom.mtime)"
550541
" FROM blob JOIN rcvfrom USING(rcvid) LEFT JOIN user USING(uid)"
@@ -582,61 +573,10 @@
582573
const char *zTagName = db_column_text(&q, 0);
583574
@ | %z(href("%R/timeline?r=%T",zTagName))%h(zTagName)</a>
584575
}
585576
db_finalize(&q);
586577
587
-#if 0
588
- /* Select a few other branches to diff against */
589
- zThisBranch = db_text("trunk", "SELECT value FROM tagxref"
590
- " WHERE tagid=%d AND tagtype>0"
591
- " AND rid=%d",
592
- TAG_BRANCH, rid);
593
-
594
- /* Find nearby leaves to offer to diff against */
595
- db_prepare(&q,
596
- "SELECT tagxref.value, blob.uuid, min(%.17g-event.mtime)"
597
- " FROM leaf, event, tagxref, blob"
598
- " WHERE event.mtime BETWEEN %.17g AND %.17g"
599
- " AND event.type='ci'"
600
- " AND event.objid=leaf.rid"
601
- " AND NOT %z"
602
- " AND tagxref.rid=event.objid"
603
- " AND tagxref.tagid=%d AND tagxref.tagtype>0"
604
- " AND tagxref.value!=%Q"
605
- " AND blob.rid=tagxref.rid"
606
- " GROUP BY 1 ORDER BY 3",
607
- thisMtime, thisMtime-7, thisMtime+7,
608
- leaf_is_closed_sql("leaf.rid"),
609
- TAG_BRANCH, zThisBranch
610
- );
611
- while( db_step(&q)==SQLITE_ROW ){
612
- const char *zBr = db_column_text(&q, 0);
613
- const char *zId = db_column_text(&q, 1);
614
- if( !seenDiffTitle ){
615
- @ <tr><th valign="top">Diffs:</th><td valign="top">
616
- seenDiffTitle = 1;
617
- }else{
618
- @ |
619
- }
620
- @ %z(href("%R/vdiff?from=%S&to=%S",zId, zUuid))%h(zBr)</a>
621
- }
622
- db_finalize(&q);
623
-
624
- if( fossil_strcmp(zThisBranch,"trunk")!=0 ){
625
- if( !seenDiffTitle ){
626
- @ <tr><th valign="top">Diffs:</th><td valign="top">
627
- seenDiffTitle = 1;
628
- }else{
629
- @ |
630
- }
631
- @ %z(href("%R/vdiff?from=root:%S&to=%S",zUuid,zUuid))root of
632
- @ this branch</a>
633
- }
634
- if( seenDiffTitle ){
635
- @ </td></tr>
636
- }
637
-#endif
638578
639579
/* The Download: line */
640580
if( g.perm.Zip ){
641581
char *zUrl = mprintf("%R/tarball/%t-%S.tar.gz?uuid=%s",
642582
zProjName, zUuid, zUuid);
@@ -1150,11 +1090,11 @@
11501090
@ - part of checkin
11511091
hyperlink_to_uuid(zVers);
11521092
if( zBr && zBr[0] ){
11531093
@ on branch %z(href("%R/timeline?r=%T",zBr))%h(zBr)</a>
11541094
}
1155
- @ - %w(zCom) (user:
1095
+ @ - %!w(zCom) (user:
11561096
hyperlink_to_user(zUser,zDate,")");
11571097
if( g.perm.Hyperlink ){
11581098
@ %z(href("%R/annotate?checkin=%S&filename=%T",zVers,zName))
11591099
@ [annotate]</a>
11601100
}
@@ -1233,11 +1173,11 @@
12331173
@ Control file referencing
12341174
}
12351175
if( zType[0]!='e' ){
12361176
hyperlink_to_uuid(zUuid);
12371177
}
1238
- @ - %w(zCom) by
1178
+ @ - %!w(zCom) by
12391179
hyperlink_to_user(zUser,zDate," on");
12401180
hyperlink_to_date(zDate, ".");
12411181
if( pDownloadName && blob_size(pDownloadName)==0 ){
12421182
blob_appendf(pDownloadName, "%.10s.txt", zUuid);
12431183
}
@@ -1740,11 +1680,11 @@
17401680
const char *zUuid;
17411681
char zTktName[UUID_SIZE+1];
17421682
Manifest *pTktChng;
17431683
int modPending;
17441684
const char *zModAction;
1745
-
1685
+ char *zTktTitle;
17461686
login_check_credentials();
17471687
if( !g.perm.RdTkt ){ login_needed(); return; }
17481688
rid = name_to_rid_www("name");
17491689
if( rid==0 ){ fossil_redirect_home(); }
17501690
zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid);
@@ -1769,10 +1709,13 @@
17691709
}
17701710
if( strcmp(zModAction,"approve")==0 ){
17711711
moderation_approve(rid);
17721712
}
17731713
}
1714
+ zTktTitle = db_table_has_column( "ticket", "title" )
1715
+ ? db_text("(No title)", "SELECT title FROM ticket WHERE tkt_uuid=%Q", zTktName)
1716
+ : 0;
17741717
style_header("Ticket Change Details");
17751718
style_submenu_element("Raw", "Raw", "%R/artifact/%S", zUuid);
17761719
style_submenu_element("History", "History", "%R/tkthistory/%s", zTktName);
17771720
style_submenu_element("Page", "Page", "%R/tktview/%t", zTktName);
17781721
style_submenu_element("Timeline", "Timeline", "%R/tkttimeline/%t", zTktName);
@@ -1793,18 +1736,23 @@
17931736
modPending = moderation_pending(rid);
17941737
if( modPending ){
17951738
@ <span class="modpending">*** Awaiting Moderator Approval ***</span>
17961739
}
17971740
@ <tr><th>Ticket:</th>
1798
- @ <td>%z(href("%R/tktview/%s",zTktName))%s(zTktName)</a></td></tr>
1741
+ @ <td>%z(href("%R/tktview/%s",zTktName))%s(zTktName)</a>
1742
+ if(zTktTitle){
1743
+ @<br>%h(zTktTitle)
1744
+ }
1745
+ @</td></tr>
17991746
@ <tr><th>Date:</th><td>
18001747
hyperlink_to_date(zDate, "</td></tr>");
18011748
@ <tr><th>User:</th><td>
18021749
hyperlink_to_user(pTktChng->zUser, zDate, "</td></tr>");
18031750
@ </table>
18041751
free(zDate);
1805
-
1752
+ free(zTktTitle);
1753
+
18061754
if( g.perm.ModTkt && modPending ){
18071755
@ <div class="section">Moderation</div>
18081756
@ <blockquote>
18091757
@ <form method="POST" action="%R/tinfo/%s(zUuid)">
18101758
@ <label><input type="radio" name="modaction" value="delete">
@@ -1993,11 +1941,11 @@
19931941
if( (i%8)==7 && i+1<nColor ){
19941942
@ </tr><tr>
19951943
}
19961944
}
19971945
@ </tr><tr>
1998
- if (stdClrFound){
1946
+ if( stdClrFound ){
19991947
@ <td colspan="6">
20001948
@ <input type="radio" name="%s(zId)" value="%h(aColor[nColor].zColor)" />
20011949
}else{
20021950
@ <td style="background-color: %h(zDefaultColor);" colspan="6">
20031951
@ <input type="radio" name="%s(zId)" value="%h(aColor[nColor].zColor)"
@@ -2222,11 +2170,11 @@
22222170
if( zNewColor && zNewColor[0] ){
22232171
@ <tr><td style="background-color: %h(zNewColor);">
22242172
}else{
22252173
@ <tr><td>
22262174
}
2227
- @ %w(blob_str(&comment))
2175
+ @ %!w(blob_str(&comment))
22282176
blob_zero(&suffix);
22292177
blob_appendf(&suffix, "(user: %h", zNewUser);
22302178
db_prepare(&q, "SELECT substr(tagname,5) FROM tagxref, tag"
22312179
" WHERE tagname GLOB 'sym-*' AND tagxref.rid=%d"
22322180
" AND tagtype>1 AND tag.tagid=tagxref.tagid",
22332181
--- src/info.c
+++ src/info.c
@@ -198,22 +198,20 @@
198 if( g.localOpen ){
199 fossil_print("repository: %s\n", db_repository_filename());
200 fossil_print("local-root: %s\n", g.zLocalRoot);
201 }
202 if( bDetail ) extraRepoInfo();
203 #if defined(_WIN32)
204 if( g.zHome ){
205 fossil_print("user-home: %s\n", g.zHome);
206 }
207 #endif
208 fossil_print("project-code: %s\n", db_get("project-code", ""));
209 vid = g.localOpen ? db_lget_int("checkout", 0) : 0;
210 if( vid ){
211 show_common_info(vid, "checkout:", 1, 1);
212 }
213 fossil_print("checkins: %d\n",
214 db_int(-1, "SELECT count(distinct mid) FROM mlink /*scan*/"));
215 }else{
216 int rid;
217 rid = name_to_rid(g.argv[2]);
218 if( rid==0 ){
219 fossil_panic("no such object: %s\n", g.argv[2]);
@@ -314,16 +312,17 @@
314 }else{
315 blob_zero(&to);
316 }
317 blob_zero(&out);
318 if( diffFlags & DIFF_SIDEBYSIDE ){
319 text_diff(&from, &to, &out, pRe, diffFlags | DIFF_HTML);
320 @ <div class="sbsdiff">
321 @ %s(blob_str(&out))
322 @ </div>
323 }else{
324 text_diff(&from, &to, &out, pRe, diffFlags | DIFF_LINENO | DIFF_HTML);
 
325 @ <div class="udiff">
326 @ %s(blob_str(&out))
327 @ </div>
328 }
329 blob_reset(&from);
@@ -492,15 +491,10 @@
492 char *zEUser, *zEComment;
493 const char *zUser;
494 const char *zComment;
495 const char *zDate;
496 const char *zOrigDate;
497 #if 0
498 char *zThisBranch;
499 double thisMtime;
500 int seenDiffTitle = 0;
501 #endif
502
503 style_header(zTitle);
504 login_anonymous_available();
505 free(zTitle);
506 zEUser = db_text(0,
@@ -511,13 +505,10 @@
511 TAG_COMMENT, rid);
512 zUser = db_column_text(&q, 2);
513 zComment = db_column_text(&q, 3);
514 zDate = db_column_text(&q,1);
515 zOrigDate = db_column_text(&q, 4);
516 #if 0
517 thisMtime = db_column_double(&q, 5);
518 #endif
519 @ <div class="section">Overview</div>
520 @ <table class="label-value">
521 @ <tr><th>SHA1&nbsp;Hash:</th><td>%s(zUuid)
522 if( g.perm.Setup ){
523 @ (Record ID: %d(rid))
@@ -537,14 +528,14 @@
537 }else{
538 @ <tr><th>User:</th><td>
539 hyperlink_to_user(zUser,zDate,"</td></tr>");
540 }
541 if( zEComment ){
542 @ <tr><th>Edited&nbsp;Comment:</th><td>%w(zEComment)</td></tr>
543 @ <tr><th>Original&nbsp;Comment:</th><td>%w(zComment)</td></tr>
544 }else{
545 @ <tr><th>Comment:</th><td>%w(zComment)</td></tr>
546 }
547 if( g.perm.Admin ){
548 db_prepare(&q,
549 "SELECT rcvfrom.ipaddr, user.login, datetime(rcvfrom.mtime)"
550 " FROM blob JOIN rcvfrom USING(rcvid) LEFT JOIN user USING(uid)"
@@ -582,61 +573,10 @@
582 const char *zTagName = db_column_text(&q, 0);
583 @ | %z(href("%R/timeline?r=%T",zTagName))%h(zTagName)</a>
584 }
585 db_finalize(&q);
586
587 #if 0
588 /* Select a few other branches to diff against */
589 zThisBranch = db_text("trunk", "SELECT value FROM tagxref"
590 " WHERE tagid=%d AND tagtype>0"
591 " AND rid=%d",
592 TAG_BRANCH, rid);
593
594 /* Find nearby leaves to offer to diff against */
595 db_prepare(&q,
596 "SELECT tagxref.value, blob.uuid, min(%.17g-event.mtime)"
597 " FROM leaf, event, tagxref, blob"
598 " WHERE event.mtime BETWEEN %.17g AND %.17g"
599 " AND event.type='ci'"
600 " AND event.objid=leaf.rid"
601 " AND NOT %z"
602 " AND tagxref.rid=event.objid"
603 " AND tagxref.tagid=%d AND tagxref.tagtype>0"
604 " AND tagxref.value!=%Q"
605 " AND blob.rid=tagxref.rid"
606 " GROUP BY 1 ORDER BY 3",
607 thisMtime, thisMtime-7, thisMtime+7,
608 leaf_is_closed_sql("leaf.rid"),
609 TAG_BRANCH, zThisBranch
610 );
611 while( db_step(&q)==SQLITE_ROW ){
612 const char *zBr = db_column_text(&q, 0);
613 const char *zId = db_column_text(&q, 1);
614 if( !seenDiffTitle ){
615 @ <tr><th valign="top">Diffs:</th><td valign="top">
616 seenDiffTitle = 1;
617 }else{
618 @ |
619 }
620 @ %z(href("%R/vdiff?from=%S&to=%S",zId, zUuid))%h(zBr)</a>
621 }
622 db_finalize(&q);
623
624 if( fossil_strcmp(zThisBranch,"trunk")!=0 ){
625 if( !seenDiffTitle ){
626 @ <tr><th valign="top">Diffs:</th><td valign="top">
627 seenDiffTitle = 1;
628 }else{
629 @ |
630 }
631 @ %z(href("%R/vdiff?from=root:%S&to=%S",zUuid,zUuid))root of
632 @ this branch</a>
633 }
634 if( seenDiffTitle ){
635 @ </td></tr>
636 }
637 #endif
638
639 /* The Download: line */
640 if( g.perm.Zip ){
641 char *zUrl = mprintf("%R/tarball/%t-%S.tar.gz?uuid=%s",
642 zProjName, zUuid, zUuid);
@@ -1150,11 +1090,11 @@
1150 @ - part of checkin
1151 hyperlink_to_uuid(zVers);
1152 if( zBr && zBr[0] ){
1153 @ on branch %z(href("%R/timeline?r=%T",zBr))%h(zBr)</a>
1154 }
1155 @ - %w(zCom) (user:
1156 hyperlink_to_user(zUser,zDate,")");
1157 if( g.perm.Hyperlink ){
1158 @ %z(href("%R/annotate?checkin=%S&filename=%T",zVers,zName))
1159 @ [annotate]</a>
1160 }
@@ -1233,11 +1173,11 @@
1233 @ Control file referencing
1234 }
1235 if( zType[0]!='e' ){
1236 hyperlink_to_uuid(zUuid);
1237 }
1238 @ - %w(zCom) by
1239 hyperlink_to_user(zUser,zDate," on");
1240 hyperlink_to_date(zDate, ".");
1241 if( pDownloadName && blob_size(pDownloadName)==0 ){
1242 blob_appendf(pDownloadName, "%.10s.txt", zUuid);
1243 }
@@ -1740,11 +1680,11 @@
1740 const char *zUuid;
1741 char zTktName[UUID_SIZE+1];
1742 Manifest *pTktChng;
1743 int modPending;
1744 const char *zModAction;
1745
1746 login_check_credentials();
1747 if( !g.perm.RdTkt ){ login_needed(); return; }
1748 rid = name_to_rid_www("name");
1749 if( rid==0 ){ fossil_redirect_home(); }
1750 zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid);
@@ -1769,10 +1709,13 @@
1769 }
1770 if( strcmp(zModAction,"approve")==0 ){
1771 moderation_approve(rid);
1772 }
1773 }
 
 
 
1774 style_header("Ticket Change Details");
1775 style_submenu_element("Raw", "Raw", "%R/artifact/%S", zUuid);
1776 style_submenu_element("History", "History", "%R/tkthistory/%s", zTktName);
1777 style_submenu_element("Page", "Page", "%R/tktview/%t", zTktName);
1778 style_submenu_element("Timeline", "Timeline", "%R/tkttimeline/%t", zTktName);
@@ -1793,18 +1736,23 @@
1793 modPending = moderation_pending(rid);
1794 if( modPending ){
1795 @ <span class="modpending">*** Awaiting Moderator Approval ***</span>
1796 }
1797 @ <tr><th>Ticket:</th>
1798 @ <td>%z(href("%R/tktview/%s",zTktName))%s(zTktName)</a></td></tr>
 
 
 
 
1799 @ <tr><th>Date:</th><td>
1800 hyperlink_to_date(zDate, "</td></tr>");
1801 @ <tr><th>User:</th><td>
1802 hyperlink_to_user(pTktChng->zUser, zDate, "</td></tr>");
1803 @ </table>
1804 free(zDate);
1805
 
1806 if( g.perm.ModTkt && modPending ){
1807 @ <div class="section">Moderation</div>
1808 @ <blockquote>
1809 @ <form method="POST" action="%R/tinfo/%s(zUuid)">
1810 @ <label><input type="radio" name="modaction" value="delete">
@@ -1993,11 +1941,11 @@
1993 if( (i%8)==7 && i+1<nColor ){
1994 @ </tr><tr>
1995 }
1996 }
1997 @ </tr><tr>
1998 if (stdClrFound){
1999 @ <td colspan="6">
2000 @ <input type="radio" name="%s(zId)" value="%h(aColor[nColor].zColor)" />
2001 }else{
2002 @ <td style="background-color: %h(zDefaultColor);" colspan="6">
2003 @ <input type="radio" name="%s(zId)" value="%h(aColor[nColor].zColor)"
@@ -2222,11 +2170,11 @@
2222 if( zNewColor && zNewColor[0] ){
2223 @ <tr><td style="background-color: %h(zNewColor);">
2224 }else{
2225 @ <tr><td>
2226 }
2227 @ %w(blob_str(&comment))
2228 blob_zero(&suffix);
2229 blob_appendf(&suffix, "(user: %h", zNewUser);
2230 db_prepare(&q, "SELECT substr(tagname,5) FROM tagxref, tag"
2231 " WHERE tagname GLOB 'sym-*' AND tagxref.rid=%d"
2232 " AND tagtype>1 AND tag.tagid=tagxref.tagid",
2233
--- src/info.c
+++ src/info.c
@@ -198,22 +198,20 @@
198 if( g.localOpen ){
199 fossil_print("repository: %s\n", db_repository_filename());
200 fossil_print("local-root: %s\n", g.zLocalRoot);
201 }
202 if( bDetail ) extraRepoInfo();
203 if( g.zConfigDbName ){
204 fossil_print("config-db: %s\n", g.zConfigDbName);
 
205 }
 
206 fossil_print("project-code: %s\n", db_get("project-code", ""));
207 vid = g.localOpen ? db_lget_int("checkout", 0) : 0;
208 if( vid ){
209 show_common_info(vid, "checkout:", 1, 1);
210 }
211 fossil_print("checkins: %d\n",
212 db_int(-1, "SELECT count(*) FROM event WHERE type='ci' /*scan*/"));
213 }else{
214 int rid;
215 rid = name_to_rid(g.argv[2]);
216 if( rid==0 ){
217 fossil_panic("no such object: %s\n", g.argv[2]);
@@ -314,16 +312,17 @@
312 }else{
313 blob_zero(&to);
314 }
315 blob_zero(&out);
316 if( diffFlags & DIFF_SIDEBYSIDE ){
317 text_diff(&from, &to, &out, pRe, diffFlags | DIFF_HTML | DIFF_NOTTOOBIG);
318 @ <div class="sbsdiff">
319 @ %s(blob_str(&out))
320 @ </div>
321 }else{
322 text_diff(&from, &to, &out, pRe,
323 diffFlags | DIFF_LINENO | DIFF_HTML | DIFF_NOTTOOBIG);
324 @ <div class="udiff">
325 @ %s(blob_str(&out))
326 @ </div>
327 }
328 blob_reset(&from);
@@ -492,15 +491,10 @@
491 char *zEUser, *zEComment;
492 const char *zUser;
493 const char *zComment;
494 const char *zDate;
495 const char *zOrigDate;
 
 
 
 
 
496
497 style_header(zTitle);
498 login_anonymous_available();
499 free(zTitle);
500 zEUser = db_text(0,
@@ -511,13 +505,10 @@
505 TAG_COMMENT, rid);
506 zUser = db_column_text(&q, 2);
507 zComment = db_column_text(&q, 3);
508 zDate = db_column_text(&q,1);
509 zOrigDate = db_column_text(&q, 4);
 
 
 
510 @ <div class="section">Overview</div>
511 @ <table class="label-value">
512 @ <tr><th>SHA1&nbsp;Hash:</th><td>%s(zUuid)
513 if( g.perm.Setup ){
514 @ (Record ID: %d(rid))
@@ -537,14 +528,14 @@
528 }else{
529 @ <tr><th>User:</th><td>
530 hyperlink_to_user(zUser,zDate,"</td></tr>");
531 }
532 if( zEComment ){
533 @ <tr><th>Edited&nbsp;Comment:</th><td>%!w(zEComment)</td></tr>
534 @ <tr><th>Original&nbsp;Comment:</th><td>%!w(zComment)</td></tr>
535 }else{
536 @ <tr><th>Comment:</th><td>%!w(zComment)</td></tr>
537 }
538 if( g.perm.Admin ){
539 db_prepare(&q,
540 "SELECT rcvfrom.ipaddr, user.login, datetime(rcvfrom.mtime)"
541 " FROM blob JOIN rcvfrom USING(rcvid) LEFT JOIN user USING(uid)"
@@ -582,61 +573,10 @@
573 const char *zTagName = db_column_text(&q, 0);
574 @ | %z(href("%R/timeline?r=%T",zTagName))%h(zTagName)</a>
575 }
576 db_finalize(&q);
577
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
578
579 /* The Download: line */
580 if( g.perm.Zip ){
581 char *zUrl = mprintf("%R/tarball/%t-%S.tar.gz?uuid=%s",
582 zProjName, zUuid, zUuid);
@@ -1150,11 +1090,11 @@
1090 @ - part of checkin
1091 hyperlink_to_uuid(zVers);
1092 if( zBr && zBr[0] ){
1093 @ on branch %z(href("%R/timeline?r=%T",zBr))%h(zBr)</a>
1094 }
1095 @ - %!w(zCom) (user:
1096 hyperlink_to_user(zUser,zDate,")");
1097 if( g.perm.Hyperlink ){
1098 @ %z(href("%R/annotate?checkin=%S&filename=%T",zVers,zName))
1099 @ [annotate]</a>
1100 }
@@ -1233,11 +1173,11 @@
1173 @ Control file referencing
1174 }
1175 if( zType[0]!='e' ){
1176 hyperlink_to_uuid(zUuid);
1177 }
1178 @ - %!w(zCom) by
1179 hyperlink_to_user(zUser,zDate," on");
1180 hyperlink_to_date(zDate, ".");
1181 if( pDownloadName && blob_size(pDownloadName)==0 ){
1182 blob_appendf(pDownloadName, "%.10s.txt", zUuid);
1183 }
@@ -1740,11 +1680,11 @@
1680 const char *zUuid;
1681 char zTktName[UUID_SIZE+1];
1682 Manifest *pTktChng;
1683 int modPending;
1684 const char *zModAction;
1685 char *zTktTitle;
1686 login_check_credentials();
1687 if( !g.perm.RdTkt ){ login_needed(); return; }
1688 rid = name_to_rid_www("name");
1689 if( rid==0 ){ fossil_redirect_home(); }
1690 zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid);
@@ -1769,10 +1709,13 @@
1709 }
1710 if( strcmp(zModAction,"approve")==0 ){
1711 moderation_approve(rid);
1712 }
1713 }
1714 zTktTitle = db_table_has_column( "ticket", "title" )
1715 ? db_text("(No title)", "SELECT title FROM ticket WHERE tkt_uuid=%Q", zTktName)
1716 : 0;
1717 style_header("Ticket Change Details");
1718 style_submenu_element("Raw", "Raw", "%R/artifact/%S", zUuid);
1719 style_submenu_element("History", "History", "%R/tkthistory/%s", zTktName);
1720 style_submenu_element("Page", "Page", "%R/tktview/%t", zTktName);
1721 style_submenu_element("Timeline", "Timeline", "%R/tkttimeline/%t", zTktName);
@@ -1793,18 +1736,23 @@
1736 modPending = moderation_pending(rid);
1737 if( modPending ){
1738 @ <span class="modpending">*** Awaiting Moderator Approval ***</span>
1739 }
1740 @ <tr><th>Ticket:</th>
1741 @ <td>%z(href("%R/tktview/%s",zTktName))%s(zTktName)</a>
1742 if(zTktTitle){
1743 @<br>%h(zTktTitle)
1744 }
1745 @</td></tr>
1746 @ <tr><th>Date:</th><td>
1747 hyperlink_to_date(zDate, "</td></tr>");
1748 @ <tr><th>User:</th><td>
1749 hyperlink_to_user(pTktChng->zUser, zDate, "</td></tr>");
1750 @ </table>
1751 free(zDate);
1752 free(zTktTitle);
1753
1754 if( g.perm.ModTkt && modPending ){
1755 @ <div class="section">Moderation</div>
1756 @ <blockquote>
1757 @ <form method="POST" action="%R/tinfo/%s(zUuid)">
1758 @ <label><input type="radio" name="modaction" value="delete">
@@ -1993,11 +1941,11 @@
1941 if( (i%8)==7 && i+1<nColor ){
1942 @ </tr><tr>
1943 }
1944 }
1945 @ </tr><tr>
1946 if( stdClrFound ){
1947 @ <td colspan="6">
1948 @ <input type="radio" name="%s(zId)" value="%h(aColor[nColor].zColor)" />
1949 }else{
1950 @ <td style="background-color: %h(zDefaultColor);" colspan="6">
1951 @ <input type="radio" name="%s(zId)" value="%h(aColor[nColor].zColor)"
@@ -2222,11 +2170,11 @@
2170 if( zNewColor && zNewColor[0] ){
2171 @ <tr><td style="background-color: %h(zNewColor);">
2172 }else{
2173 @ <tr><td>
2174 }
2175 @ %!w(blob_str(&comment))
2176 blob_zero(&suffix);
2177 blob_appendf(&suffix, "(user: %h", zNewUser);
2178 db_prepare(&q, "SELECT substr(tagname,5) FROM tagxref, tag"
2179 " WHERE tagname GLOB 'sym-*' AND tagxref.rid=%d"
2180 " AND tagtype>1 AND tag.tagid=tagxref.tagid",
2181
+24 -76
--- src/info.c
+++ src/info.c
@@ -198,22 +198,20 @@
198198
if( g.localOpen ){
199199
fossil_print("repository: %s\n", db_repository_filename());
200200
fossil_print("local-root: %s\n", g.zLocalRoot);
201201
}
202202
if( bDetail ) extraRepoInfo();
203
-#if defined(_WIN32)
204
- if( g.zHome ){
205
- fossil_print("user-home: %s\n", g.zHome);
203
+ if( g.zConfigDbName ){
204
+ fossil_print("config-db: %s\n", g.zConfigDbName);
206205
}
207
-#endif
208206
fossil_print("project-code: %s\n", db_get("project-code", ""));
209207
vid = g.localOpen ? db_lget_int("checkout", 0) : 0;
210208
if( vid ){
211209
show_common_info(vid, "checkout:", 1, 1);
212210
}
213211
fossil_print("checkins: %d\n",
214
- db_int(-1, "SELECT count(distinct mid) FROM mlink /*scan*/"));
212
+ db_int(-1, "SELECT count(*) FROM event WHERE type='ci' /*scan*/"));
215213
}else{
216214
int rid;
217215
rid = name_to_rid(g.argv[2]);
218216
if( rid==0 ){
219217
fossil_panic("no such object: %s\n", g.argv[2]);
@@ -314,16 +312,17 @@
314312
}else{
315313
blob_zero(&to);
316314
}
317315
blob_zero(&out);
318316
if( diffFlags & DIFF_SIDEBYSIDE ){
319
- text_diff(&from, &to, &out, pRe, diffFlags | DIFF_HTML);
317
+ text_diff(&from, &to, &out, pRe, diffFlags | DIFF_HTML | DIFF_NOTTOOBIG);
320318
@ <div class="sbsdiff">
321319
@ %s(blob_str(&out))
322320
@ </div>
323321
}else{
324
- text_diff(&from, &to, &out, pRe, diffFlags | DIFF_LINENO | DIFF_HTML);
322
+ text_diff(&from, &to, &out, pRe,
323
+ diffFlags | DIFF_LINENO | DIFF_HTML | DIFF_NOTTOOBIG);
325324
@ <div class="udiff">
326325
@ %s(blob_str(&out))
327326
@ </div>
328327
}
329328
blob_reset(&from);
@@ -492,15 +491,10 @@
492491
char *zEUser, *zEComment;
493492
const char *zUser;
494493
const char *zComment;
495494
const char *zDate;
496495
const char *zOrigDate;
497
-#if 0
498
- char *zThisBranch;
499
- double thisMtime;
500
- int seenDiffTitle = 0;
501
-#endif
502496
503497
style_header(zTitle);
504498
login_anonymous_available();
505499
free(zTitle);
506500
zEUser = db_text(0,
@@ -511,13 +505,10 @@
511505
TAG_COMMENT, rid);
512506
zUser = db_column_text(&q, 2);
513507
zComment = db_column_text(&q, 3);
514508
zDate = db_column_text(&q,1);
515509
zOrigDate = db_column_text(&q, 4);
516
-#if 0
517
- thisMtime = db_column_double(&q, 5);
518
-#endif
519510
@ <div class="section">Overview</div>
520511
@ <table class="label-value">
521512
@ <tr><th>SHA1&nbsp;Hash:</th><td>%s(zUuid)
522513
if( g.perm.Setup ){
523514
@ (Record ID: %d(rid))
@@ -537,14 +528,14 @@
537528
}else{
538529
@ <tr><th>User:</th><td>
539530
hyperlink_to_user(zUser,zDate,"</td></tr>");
540531
}
541532
if( zEComment ){
542
- @ <tr><th>Edited&nbsp;Comment:</th><td>%w(zEComment)</td></tr>
543
- @ <tr><th>Original&nbsp;Comment:</th><td>%w(zComment)</td></tr>
533
+ @ <tr><th>Edited&nbsp;Comment:</th><td>%!w(zEComment)</td></tr>
534
+ @ <tr><th>Original&nbsp;Comment:</th><td>%!w(zComment)</td></tr>
544535
}else{
545
- @ <tr><th>Comment:</th><td>%w(zComment)</td></tr>
536
+ @ <tr><th>Comment:</th><td>%!w(zComment)</td></tr>
546537
}
547538
if( g.perm.Admin ){
548539
db_prepare(&q,
549540
"SELECT rcvfrom.ipaddr, user.login, datetime(rcvfrom.mtime)"
550541
" FROM blob JOIN rcvfrom USING(rcvid) LEFT JOIN user USING(uid)"
@@ -582,61 +573,10 @@
582573
const char *zTagName = db_column_text(&q, 0);
583574
@ | %z(href("%R/timeline?r=%T",zTagName))%h(zTagName)</a>
584575
}
585576
db_finalize(&q);
586577
587
-#if 0
588
- /* Select a few other branches to diff against */
589
- zThisBranch = db_text("trunk", "SELECT value FROM tagxref"
590
- " WHERE tagid=%d AND tagtype>0"
591
- " AND rid=%d",
592
- TAG_BRANCH, rid);
593
-
594
- /* Find nearby leaves to offer to diff against */
595
- db_prepare(&q,
596
- "SELECT tagxref.value, blob.uuid, min(%.17g-event.mtime)"
597
- " FROM leaf, event, tagxref, blob"
598
- " WHERE event.mtime BETWEEN %.17g AND %.17g"
599
- " AND event.type='ci'"
600
- " AND event.objid=leaf.rid"
601
- " AND NOT %z"
602
- " AND tagxref.rid=event.objid"
603
- " AND tagxref.tagid=%d AND tagxref.tagtype>0"
604
- " AND tagxref.value!=%Q"
605
- " AND blob.rid=tagxref.rid"
606
- " GROUP BY 1 ORDER BY 3",
607
- thisMtime, thisMtime-7, thisMtime+7,
608
- leaf_is_closed_sql("leaf.rid"),
609
- TAG_BRANCH, zThisBranch
610
- );
611
- while( db_step(&q)==SQLITE_ROW ){
612
- const char *zBr = db_column_text(&q, 0);
613
- const char *zId = db_column_text(&q, 1);
614
- if( !seenDiffTitle ){
615
- @ <tr><th valign="top">Diffs:</th><td valign="top">
616
- seenDiffTitle = 1;
617
- }else{
618
- @ |
619
- }
620
- @ %z(href("%R/vdiff?from=%S&to=%S",zId, zUuid))%h(zBr)</a>
621
- }
622
- db_finalize(&q);
623
-
624
- if( fossil_strcmp(zThisBranch,"trunk")!=0 ){
625
- if( !seenDiffTitle ){
626
- @ <tr><th valign="top">Diffs:</th><td valign="top">
627
- seenDiffTitle = 1;
628
- }else{
629
- @ |
630
- }
631
- @ %z(href("%R/vdiff?from=root:%S&to=%S",zUuid,zUuid))root of
632
- @ this branch</a>
633
- }
634
- if( seenDiffTitle ){
635
- @ </td></tr>
636
- }
637
-#endif
638578
639579
/* The Download: line */
640580
if( g.perm.Zip ){
641581
char *zUrl = mprintf("%R/tarball/%t-%S.tar.gz?uuid=%s",
642582
zProjName, zUuid, zUuid);
@@ -1150,11 +1090,11 @@
11501090
@ - part of checkin
11511091
hyperlink_to_uuid(zVers);
11521092
if( zBr && zBr[0] ){
11531093
@ on branch %z(href("%R/timeline?r=%T",zBr))%h(zBr)</a>
11541094
}
1155
- @ - %w(zCom) (user:
1095
+ @ - %!w(zCom) (user:
11561096
hyperlink_to_user(zUser,zDate,")");
11571097
if( g.perm.Hyperlink ){
11581098
@ %z(href("%R/annotate?checkin=%S&filename=%T",zVers,zName))
11591099
@ [annotate]</a>
11601100
}
@@ -1233,11 +1173,11 @@
12331173
@ Control file referencing
12341174
}
12351175
if( zType[0]!='e' ){
12361176
hyperlink_to_uuid(zUuid);
12371177
}
1238
- @ - %w(zCom) by
1178
+ @ - %!w(zCom) by
12391179
hyperlink_to_user(zUser,zDate," on");
12401180
hyperlink_to_date(zDate, ".");
12411181
if( pDownloadName && blob_size(pDownloadName)==0 ){
12421182
blob_appendf(pDownloadName, "%.10s.txt", zUuid);
12431183
}
@@ -1740,11 +1680,11 @@
17401680
const char *zUuid;
17411681
char zTktName[UUID_SIZE+1];
17421682
Manifest *pTktChng;
17431683
int modPending;
17441684
const char *zModAction;
1745
-
1685
+ char *zTktTitle;
17461686
login_check_credentials();
17471687
if( !g.perm.RdTkt ){ login_needed(); return; }
17481688
rid = name_to_rid_www("name");
17491689
if( rid==0 ){ fossil_redirect_home(); }
17501690
zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid);
@@ -1769,10 +1709,13 @@
17691709
}
17701710
if( strcmp(zModAction,"approve")==0 ){
17711711
moderation_approve(rid);
17721712
}
17731713
}
1714
+ zTktTitle = db_table_has_column( "ticket", "title" )
1715
+ ? db_text("(No title)", "SELECT title FROM ticket WHERE tkt_uuid=%Q", zTktName)
1716
+ : 0;
17741717
style_header("Ticket Change Details");
17751718
style_submenu_element("Raw", "Raw", "%R/artifact/%S", zUuid);
17761719
style_submenu_element("History", "History", "%R/tkthistory/%s", zTktName);
17771720
style_submenu_element("Page", "Page", "%R/tktview/%t", zTktName);
17781721
style_submenu_element("Timeline", "Timeline", "%R/tkttimeline/%t", zTktName);
@@ -1793,18 +1736,23 @@
17931736
modPending = moderation_pending(rid);
17941737
if( modPending ){
17951738
@ <span class="modpending">*** Awaiting Moderator Approval ***</span>
17961739
}
17971740
@ <tr><th>Ticket:</th>
1798
- @ <td>%z(href("%R/tktview/%s",zTktName))%s(zTktName)</a></td></tr>
1741
+ @ <td>%z(href("%R/tktview/%s",zTktName))%s(zTktName)</a>
1742
+ if(zTktTitle){
1743
+ @<br>%h(zTktTitle)
1744
+ }
1745
+ @</td></tr>
17991746
@ <tr><th>Date:</th><td>
18001747
hyperlink_to_date(zDate, "</td></tr>");
18011748
@ <tr><th>User:</th><td>
18021749
hyperlink_to_user(pTktChng->zUser, zDate, "</td></tr>");
18031750
@ </table>
18041751
free(zDate);
1805
-
1752
+ free(zTktTitle);
1753
+
18061754
if( g.perm.ModTkt && modPending ){
18071755
@ <div class="section">Moderation</div>
18081756
@ <blockquote>
18091757
@ <form method="POST" action="%R/tinfo/%s(zUuid)">
18101758
@ <label><input type="radio" name="modaction" value="delete">
@@ -1993,11 +1941,11 @@
19931941
if( (i%8)==7 && i+1<nColor ){
19941942
@ </tr><tr>
19951943
}
19961944
}
19971945
@ </tr><tr>
1998
- if (stdClrFound){
1946
+ if( stdClrFound ){
19991947
@ <td colspan="6">
20001948
@ <input type="radio" name="%s(zId)" value="%h(aColor[nColor].zColor)" />
20011949
}else{
20021950
@ <td style="background-color: %h(zDefaultColor);" colspan="6">
20031951
@ <input type="radio" name="%s(zId)" value="%h(aColor[nColor].zColor)"
@@ -2222,11 +2170,11 @@
22222170
if( zNewColor && zNewColor[0] ){
22232171
@ <tr><td style="background-color: %h(zNewColor);">
22242172
}else{
22252173
@ <tr><td>
22262174
}
2227
- @ %w(blob_str(&comment))
2175
+ @ %!w(blob_str(&comment))
22282176
blob_zero(&suffix);
22292177
blob_appendf(&suffix, "(user: %h", zNewUser);
22302178
db_prepare(&q, "SELECT substr(tagname,5) FROM tagxref, tag"
22312179
" WHERE tagname GLOB 'sym-*' AND tagxref.rid=%d"
22322180
" AND tagtype>1 AND tag.tagid=tagxref.tagid",
22332181
--- src/info.c
+++ src/info.c
@@ -198,22 +198,20 @@
198 if( g.localOpen ){
199 fossil_print("repository: %s\n", db_repository_filename());
200 fossil_print("local-root: %s\n", g.zLocalRoot);
201 }
202 if( bDetail ) extraRepoInfo();
203 #if defined(_WIN32)
204 if( g.zHome ){
205 fossil_print("user-home: %s\n", g.zHome);
206 }
207 #endif
208 fossil_print("project-code: %s\n", db_get("project-code", ""));
209 vid = g.localOpen ? db_lget_int("checkout", 0) : 0;
210 if( vid ){
211 show_common_info(vid, "checkout:", 1, 1);
212 }
213 fossil_print("checkins: %d\n",
214 db_int(-1, "SELECT count(distinct mid) FROM mlink /*scan*/"));
215 }else{
216 int rid;
217 rid = name_to_rid(g.argv[2]);
218 if( rid==0 ){
219 fossil_panic("no such object: %s\n", g.argv[2]);
@@ -314,16 +312,17 @@
314 }else{
315 blob_zero(&to);
316 }
317 blob_zero(&out);
318 if( diffFlags & DIFF_SIDEBYSIDE ){
319 text_diff(&from, &to, &out, pRe, diffFlags | DIFF_HTML);
320 @ <div class="sbsdiff">
321 @ %s(blob_str(&out))
322 @ </div>
323 }else{
324 text_diff(&from, &to, &out, pRe, diffFlags | DIFF_LINENO | DIFF_HTML);
 
325 @ <div class="udiff">
326 @ %s(blob_str(&out))
327 @ </div>
328 }
329 blob_reset(&from);
@@ -492,15 +491,10 @@
492 char *zEUser, *zEComment;
493 const char *zUser;
494 const char *zComment;
495 const char *zDate;
496 const char *zOrigDate;
497 #if 0
498 char *zThisBranch;
499 double thisMtime;
500 int seenDiffTitle = 0;
501 #endif
502
503 style_header(zTitle);
504 login_anonymous_available();
505 free(zTitle);
506 zEUser = db_text(0,
@@ -511,13 +505,10 @@
511 TAG_COMMENT, rid);
512 zUser = db_column_text(&q, 2);
513 zComment = db_column_text(&q, 3);
514 zDate = db_column_text(&q,1);
515 zOrigDate = db_column_text(&q, 4);
516 #if 0
517 thisMtime = db_column_double(&q, 5);
518 #endif
519 @ <div class="section">Overview</div>
520 @ <table class="label-value">
521 @ <tr><th>SHA1&nbsp;Hash:</th><td>%s(zUuid)
522 if( g.perm.Setup ){
523 @ (Record ID: %d(rid))
@@ -537,14 +528,14 @@
537 }else{
538 @ <tr><th>User:</th><td>
539 hyperlink_to_user(zUser,zDate,"</td></tr>");
540 }
541 if( zEComment ){
542 @ <tr><th>Edited&nbsp;Comment:</th><td>%w(zEComment)</td></tr>
543 @ <tr><th>Original&nbsp;Comment:</th><td>%w(zComment)</td></tr>
544 }else{
545 @ <tr><th>Comment:</th><td>%w(zComment)</td></tr>
546 }
547 if( g.perm.Admin ){
548 db_prepare(&q,
549 "SELECT rcvfrom.ipaddr, user.login, datetime(rcvfrom.mtime)"
550 " FROM blob JOIN rcvfrom USING(rcvid) LEFT JOIN user USING(uid)"
@@ -582,61 +573,10 @@
582 const char *zTagName = db_column_text(&q, 0);
583 @ | %z(href("%R/timeline?r=%T",zTagName))%h(zTagName)</a>
584 }
585 db_finalize(&q);
586
587 #if 0
588 /* Select a few other branches to diff against */
589 zThisBranch = db_text("trunk", "SELECT value FROM tagxref"
590 " WHERE tagid=%d AND tagtype>0"
591 " AND rid=%d",
592 TAG_BRANCH, rid);
593
594 /* Find nearby leaves to offer to diff against */
595 db_prepare(&q,
596 "SELECT tagxref.value, blob.uuid, min(%.17g-event.mtime)"
597 " FROM leaf, event, tagxref, blob"
598 " WHERE event.mtime BETWEEN %.17g AND %.17g"
599 " AND event.type='ci'"
600 " AND event.objid=leaf.rid"
601 " AND NOT %z"
602 " AND tagxref.rid=event.objid"
603 " AND tagxref.tagid=%d AND tagxref.tagtype>0"
604 " AND tagxref.value!=%Q"
605 " AND blob.rid=tagxref.rid"
606 " GROUP BY 1 ORDER BY 3",
607 thisMtime, thisMtime-7, thisMtime+7,
608 leaf_is_closed_sql("leaf.rid"),
609 TAG_BRANCH, zThisBranch
610 );
611 while( db_step(&q)==SQLITE_ROW ){
612 const char *zBr = db_column_text(&q, 0);
613 const char *zId = db_column_text(&q, 1);
614 if( !seenDiffTitle ){
615 @ <tr><th valign="top">Diffs:</th><td valign="top">
616 seenDiffTitle = 1;
617 }else{
618 @ |
619 }
620 @ %z(href("%R/vdiff?from=%S&to=%S",zId, zUuid))%h(zBr)</a>
621 }
622 db_finalize(&q);
623
624 if( fossil_strcmp(zThisBranch,"trunk")!=0 ){
625 if( !seenDiffTitle ){
626 @ <tr><th valign="top">Diffs:</th><td valign="top">
627 seenDiffTitle = 1;
628 }else{
629 @ |
630 }
631 @ %z(href("%R/vdiff?from=root:%S&to=%S",zUuid,zUuid))root of
632 @ this branch</a>
633 }
634 if( seenDiffTitle ){
635 @ </td></tr>
636 }
637 #endif
638
639 /* The Download: line */
640 if( g.perm.Zip ){
641 char *zUrl = mprintf("%R/tarball/%t-%S.tar.gz?uuid=%s",
642 zProjName, zUuid, zUuid);
@@ -1150,11 +1090,11 @@
1150 @ - part of checkin
1151 hyperlink_to_uuid(zVers);
1152 if( zBr && zBr[0] ){
1153 @ on branch %z(href("%R/timeline?r=%T",zBr))%h(zBr)</a>
1154 }
1155 @ - %w(zCom) (user:
1156 hyperlink_to_user(zUser,zDate,")");
1157 if( g.perm.Hyperlink ){
1158 @ %z(href("%R/annotate?checkin=%S&filename=%T",zVers,zName))
1159 @ [annotate]</a>
1160 }
@@ -1233,11 +1173,11 @@
1233 @ Control file referencing
1234 }
1235 if( zType[0]!='e' ){
1236 hyperlink_to_uuid(zUuid);
1237 }
1238 @ - %w(zCom) by
1239 hyperlink_to_user(zUser,zDate," on");
1240 hyperlink_to_date(zDate, ".");
1241 if( pDownloadName && blob_size(pDownloadName)==0 ){
1242 blob_appendf(pDownloadName, "%.10s.txt", zUuid);
1243 }
@@ -1740,11 +1680,11 @@
1740 const char *zUuid;
1741 char zTktName[UUID_SIZE+1];
1742 Manifest *pTktChng;
1743 int modPending;
1744 const char *zModAction;
1745
1746 login_check_credentials();
1747 if( !g.perm.RdTkt ){ login_needed(); return; }
1748 rid = name_to_rid_www("name");
1749 if( rid==0 ){ fossil_redirect_home(); }
1750 zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid);
@@ -1769,10 +1709,13 @@
1769 }
1770 if( strcmp(zModAction,"approve")==0 ){
1771 moderation_approve(rid);
1772 }
1773 }
 
 
 
1774 style_header("Ticket Change Details");
1775 style_submenu_element("Raw", "Raw", "%R/artifact/%S", zUuid);
1776 style_submenu_element("History", "History", "%R/tkthistory/%s", zTktName);
1777 style_submenu_element("Page", "Page", "%R/tktview/%t", zTktName);
1778 style_submenu_element("Timeline", "Timeline", "%R/tkttimeline/%t", zTktName);
@@ -1793,18 +1736,23 @@
1793 modPending = moderation_pending(rid);
1794 if( modPending ){
1795 @ <span class="modpending">*** Awaiting Moderator Approval ***</span>
1796 }
1797 @ <tr><th>Ticket:</th>
1798 @ <td>%z(href("%R/tktview/%s",zTktName))%s(zTktName)</a></td></tr>
 
 
 
 
1799 @ <tr><th>Date:</th><td>
1800 hyperlink_to_date(zDate, "</td></tr>");
1801 @ <tr><th>User:</th><td>
1802 hyperlink_to_user(pTktChng->zUser, zDate, "</td></tr>");
1803 @ </table>
1804 free(zDate);
1805
 
1806 if( g.perm.ModTkt && modPending ){
1807 @ <div class="section">Moderation</div>
1808 @ <blockquote>
1809 @ <form method="POST" action="%R/tinfo/%s(zUuid)">
1810 @ <label><input type="radio" name="modaction" value="delete">
@@ -1993,11 +1941,11 @@
1993 if( (i%8)==7 && i+1<nColor ){
1994 @ </tr><tr>
1995 }
1996 }
1997 @ </tr><tr>
1998 if (stdClrFound){
1999 @ <td colspan="6">
2000 @ <input type="radio" name="%s(zId)" value="%h(aColor[nColor].zColor)" />
2001 }else{
2002 @ <td style="background-color: %h(zDefaultColor);" colspan="6">
2003 @ <input type="radio" name="%s(zId)" value="%h(aColor[nColor].zColor)"
@@ -2222,11 +2170,11 @@
2222 if( zNewColor && zNewColor[0] ){
2223 @ <tr><td style="background-color: %h(zNewColor);">
2224 }else{
2225 @ <tr><td>
2226 }
2227 @ %w(blob_str(&comment))
2228 blob_zero(&suffix);
2229 blob_appendf(&suffix, "(user: %h", zNewUser);
2230 db_prepare(&q, "SELECT substr(tagname,5) FROM tagxref, tag"
2231 " WHERE tagname GLOB 'sym-*' AND tagxref.rid=%d"
2232 " AND tagtype>1 AND tag.tagid=tagxref.tagid",
2233
--- src/info.c
+++ src/info.c
@@ -198,22 +198,20 @@
198 if( g.localOpen ){
199 fossil_print("repository: %s\n", db_repository_filename());
200 fossil_print("local-root: %s\n", g.zLocalRoot);
201 }
202 if( bDetail ) extraRepoInfo();
203 if( g.zConfigDbName ){
204 fossil_print("config-db: %s\n", g.zConfigDbName);
 
205 }
 
206 fossil_print("project-code: %s\n", db_get("project-code", ""));
207 vid = g.localOpen ? db_lget_int("checkout", 0) : 0;
208 if( vid ){
209 show_common_info(vid, "checkout:", 1, 1);
210 }
211 fossil_print("checkins: %d\n",
212 db_int(-1, "SELECT count(*) FROM event WHERE type='ci' /*scan*/"));
213 }else{
214 int rid;
215 rid = name_to_rid(g.argv[2]);
216 if( rid==0 ){
217 fossil_panic("no such object: %s\n", g.argv[2]);
@@ -314,16 +312,17 @@
312 }else{
313 blob_zero(&to);
314 }
315 blob_zero(&out);
316 if( diffFlags & DIFF_SIDEBYSIDE ){
317 text_diff(&from, &to, &out, pRe, diffFlags | DIFF_HTML | DIFF_NOTTOOBIG);
318 @ <div class="sbsdiff">
319 @ %s(blob_str(&out))
320 @ </div>
321 }else{
322 text_diff(&from, &to, &out, pRe,
323 diffFlags | DIFF_LINENO | DIFF_HTML | DIFF_NOTTOOBIG);
324 @ <div class="udiff">
325 @ %s(blob_str(&out))
326 @ </div>
327 }
328 blob_reset(&from);
@@ -492,15 +491,10 @@
491 char *zEUser, *zEComment;
492 const char *zUser;
493 const char *zComment;
494 const char *zDate;
495 const char *zOrigDate;
 
 
 
 
 
496
497 style_header(zTitle);
498 login_anonymous_available();
499 free(zTitle);
500 zEUser = db_text(0,
@@ -511,13 +505,10 @@
505 TAG_COMMENT, rid);
506 zUser = db_column_text(&q, 2);
507 zComment = db_column_text(&q, 3);
508 zDate = db_column_text(&q,1);
509 zOrigDate = db_column_text(&q, 4);
 
 
 
510 @ <div class="section">Overview</div>
511 @ <table class="label-value">
512 @ <tr><th>SHA1&nbsp;Hash:</th><td>%s(zUuid)
513 if( g.perm.Setup ){
514 @ (Record ID: %d(rid))
@@ -537,14 +528,14 @@
528 }else{
529 @ <tr><th>User:</th><td>
530 hyperlink_to_user(zUser,zDate,"</td></tr>");
531 }
532 if( zEComment ){
533 @ <tr><th>Edited&nbsp;Comment:</th><td>%!w(zEComment)</td></tr>
534 @ <tr><th>Original&nbsp;Comment:</th><td>%!w(zComment)</td></tr>
535 }else{
536 @ <tr><th>Comment:</th><td>%!w(zComment)</td></tr>
537 }
538 if( g.perm.Admin ){
539 db_prepare(&q,
540 "SELECT rcvfrom.ipaddr, user.login, datetime(rcvfrom.mtime)"
541 " FROM blob JOIN rcvfrom USING(rcvid) LEFT JOIN user USING(uid)"
@@ -582,61 +573,10 @@
573 const char *zTagName = db_column_text(&q, 0);
574 @ | %z(href("%R/timeline?r=%T",zTagName))%h(zTagName)</a>
575 }
576 db_finalize(&q);
577
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
578
579 /* The Download: line */
580 if( g.perm.Zip ){
581 char *zUrl = mprintf("%R/tarball/%t-%S.tar.gz?uuid=%s",
582 zProjName, zUuid, zUuid);
@@ -1150,11 +1090,11 @@
1090 @ - part of checkin
1091 hyperlink_to_uuid(zVers);
1092 if( zBr && zBr[0] ){
1093 @ on branch %z(href("%R/timeline?r=%T",zBr))%h(zBr)</a>
1094 }
1095 @ - %!w(zCom) (user:
1096 hyperlink_to_user(zUser,zDate,")");
1097 if( g.perm.Hyperlink ){
1098 @ %z(href("%R/annotate?checkin=%S&filename=%T",zVers,zName))
1099 @ [annotate]</a>
1100 }
@@ -1233,11 +1173,11 @@
1173 @ Control file referencing
1174 }
1175 if( zType[0]!='e' ){
1176 hyperlink_to_uuid(zUuid);
1177 }
1178 @ - %!w(zCom) by
1179 hyperlink_to_user(zUser,zDate," on");
1180 hyperlink_to_date(zDate, ".");
1181 if( pDownloadName && blob_size(pDownloadName)==0 ){
1182 blob_appendf(pDownloadName, "%.10s.txt", zUuid);
1183 }
@@ -1740,11 +1680,11 @@
1680 const char *zUuid;
1681 char zTktName[UUID_SIZE+1];
1682 Manifest *pTktChng;
1683 int modPending;
1684 const char *zModAction;
1685 char *zTktTitle;
1686 login_check_credentials();
1687 if( !g.perm.RdTkt ){ login_needed(); return; }
1688 rid = name_to_rid_www("name");
1689 if( rid==0 ){ fossil_redirect_home(); }
1690 zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid);
@@ -1769,10 +1709,13 @@
1709 }
1710 if( strcmp(zModAction,"approve")==0 ){
1711 moderation_approve(rid);
1712 }
1713 }
1714 zTktTitle = db_table_has_column( "ticket", "title" )
1715 ? db_text("(No title)", "SELECT title FROM ticket WHERE tkt_uuid=%Q", zTktName)
1716 : 0;
1717 style_header("Ticket Change Details");
1718 style_submenu_element("Raw", "Raw", "%R/artifact/%S", zUuid);
1719 style_submenu_element("History", "History", "%R/tkthistory/%s", zTktName);
1720 style_submenu_element("Page", "Page", "%R/tktview/%t", zTktName);
1721 style_submenu_element("Timeline", "Timeline", "%R/tkttimeline/%t", zTktName);
@@ -1793,18 +1736,23 @@
1736 modPending = moderation_pending(rid);
1737 if( modPending ){
1738 @ <span class="modpending">*** Awaiting Moderator Approval ***</span>
1739 }
1740 @ <tr><th>Ticket:</th>
1741 @ <td>%z(href("%R/tktview/%s",zTktName))%s(zTktName)</a>
1742 if(zTktTitle){
1743 @<br>%h(zTktTitle)
1744 }
1745 @</td></tr>
1746 @ <tr><th>Date:</th><td>
1747 hyperlink_to_date(zDate, "</td></tr>");
1748 @ <tr><th>User:</th><td>
1749 hyperlink_to_user(pTktChng->zUser, zDate, "</td></tr>");
1750 @ </table>
1751 free(zDate);
1752 free(zTktTitle);
1753
1754 if( g.perm.ModTkt && modPending ){
1755 @ <div class="section">Moderation</div>
1756 @ <blockquote>
1757 @ <form method="POST" action="%R/tinfo/%s(zUuid)">
1758 @ <label><input type="radio" name="modaction" value="delete">
@@ -1993,11 +1941,11 @@
1941 if( (i%8)==7 && i+1<nColor ){
1942 @ </tr><tr>
1943 }
1944 }
1945 @ </tr><tr>
1946 if( stdClrFound ){
1947 @ <td colspan="6">
1948 @ <input type="radio" name="%s(zId)" value="%h(aColor[nColor].zColor)" />
1949 }else{
1950 @ <td style="background-color: %h(zDefaultColor);" colspan="6">
1951 @ <input type="radio" name="%s(zId)" value="%h(aColor[nColor].zColor)"
@@ -2222,11 +2170,11 @@
2170 if( zNewColor && zNewColor[0] ){
2171 @ <tr><td style="background-color: %h(zNewColor);">
2172 }else{
2173 @ <tr><td>
2174 }
2175 @ %!w(blob_str(&comment))
2176 blob_zero(&suffix);
2177 blob_appendf(&suffix, "(user: %h", zNewUser);
2178 db_prepare(&q, "SELECT substr(tagname,5) FROM tagxref, tag"
2179 " WHERE tagname GLOB 'sym-*' AND tagxref.rid=%d"
2180 " AND tagtype>1 AND tag.tagid=tagxref.tagid",
2181
+14 -8
--- src/json.c
+++ src/json.c
@@ -239,10 +239,11 @@
239239
C(STMT_EXEC,"Statement execution/stepping failed");
240240
C(DB_LOCKED,"Database is locked");
241241
C(DB_NEEDS_REBUILD,"Fossil repository needs to be rebuilt");
242242
C(DB_NOT_FOUND,"Fossil repository db file could not be found.");
243243
C(DB_NOT_VALID, "Fossil repository db file is not valid.");
244
+ C(DB_NEEDS_CHECKOUT, "Command requires a local checkout.");
244245
#undef C
245246
default:
246247
return "Unknown Error";
247248
}
248249
}
@@ -1371,11 +1372,11 @@
13711372
#define VAL(K,V) cson_object_set(o, #K, (V) ? (V) : cson_value_null())
13721373
VAL(capabilities, json_cap_value());
13731374
INT(g, argc);
13741375
INT(g, isConst);
13751376
INT(g, useAttach);
1376
- INT(g, configOpen);
1377
+ CSTR(g, zConfigDbName);
13771378
INT(g, repositoryOpen);
13781379
INT(g, localOpen);
13791380
INT(g, minPrefix);
13801381
INT(g, fSqlTrace);
13811382
INT(g, fSqlStats);
@@ -1397,11 +1398,10 @@
13971398
INT(g, urlIsFile);
13981399
INT(g, urlIsHttps);
13991400
INT(g, urlIsSsh);
14001401
INT(g, urlPort);
14011402
INT(g, urlDfltPort);
1402
- INT(g, dontKeepUrl);
14031403
INT(g, useLocalauth);
14041404
INT(g, noPswd);
14051405
INT(g, userUid);
14061406
INT(g, rcvid);
14071407
INT(g, okCsrf);
@@ -1410,11 +1410,10 @@
14101410
INT(g, nAux);
14111411
INT(g, allowSymlinks);
14121412
14131413
CSTR(g, zMainDbType);
14141414
CSTR(g, zConfigDbType);
1415
- CSTR(g, zHome);
14161415
CSTR(g, zLocalRoot);
14171416
CSTR(g, zPath);
14181417
CSTR(g, zExtra);
14191418
CSTR(g, zBaseURL);
14201419
CSTR(g, zTop);
@@ -2118,18 +2117,22 @@
21182117
** taken from zPages. zPages must be an array of objects
21192118
** whose final entry MUST have a NULL name value or results
21202119
** are undefined.
21212120
**
21222121
** The list is appended to pOut. The number of items (not bytes)
2123
-** appended are returned.
2122
+** appended are returned. If filterByMode is non-0 then the result
2123
+** list will contain only commands which are able to run in the the
2124
+** current run mode (CLI vs. HTTP).
21242125
*/
21252126
static int json_pagedefs_to_string(JsonPageDef const * zPages,
2126
- Blob * pOut){
2127
+ Blob * pOut, int filterByMode){
21272128
int i = 0;
21282129
for( ; zPages->name; ++zPages, ++i ){
2129
- if(g.isHTTP && zPages->runMode < 0) continue;
2130
- else if(zPages->runMode > 0) continue;
2130
+ if(filterByMode){
2131
+ if(g.isHTTP && zPages->runMode < 0) continue;
2132
+ else if(zPages->runMode > 0) continue;
2133
+ }
21312134
blob_appendf(pOut, zPages->name, -1);
21322135
if((zPages+1)->name){
21332136
blob_append(pOut, ", ",2);
21342137
}
21352138
}
@@ -2153,11 +2156,11 @@
21532156
blob_init(&cmdNames,NULL,0);
21542157
if( !zErrPrefix ) {
21552158
zErrPrefix = "Try one of: ";
21562159
}
21572160
blob_append( &cmdNames, zErrPrefix, strlen(zErrPrefix) );
2158
- json_pagedefs_to_string(pCommands, &cmdNames);
2161
+ json_pagedefs_to_string(pCommands, &cmdNames, 1);
21592162
json_set_err(FSL_JSON_E_MISSING_ARGS, "%s",
21602163
blob_str(&cmdNames));
21612164
blob_reset(&cmdNames);
21622165
}
21632166
@@ -2246,10 +2249,12 @@
22462249
cson_value * json_page_user();
22472250
/* Impl in json_config.c. */
22482251
cson_value * json_page_config();
22492252
/* Impl in json_finfo.c. */
22502253
cson_value * json_page_finfo();
2254
+/* Impl in json_status.c. */
2255
+cson_value * json_page_status();
22512256
22522257
/*
22532258
** Mapping of names to JSON pages/commands. Each name is a subpath of
22542259
** /json (in CGI mode) or a subcommand of the json command in CLI mode
22552260
*/
@@ -2270,10 +2275,11 @@
22702275
{"query",json_page_query,0},
22712276
{"rebuild",json_page_rebuild,0},
22722277
{"report", json_page_report, 0},
22732278
{"resultCodes", json_page_resultCodes,0},
22742279
{"stat",json_page_stat,0},
2280
+{"status", json_page_status, 0},
22752281
{"tag", json_page_tag,0},
22762282
/*{"ticket", json_page_nyi,0},*/
22772283
{"timeline", json_page_timeline,0},
22782284
{"user",json_page_user,0},
22792285
{"version",json_page_version,0},
22802286
--- src/json.c
+++ src/json.c
@@ -239,10 +239,11 @@
239 C(STMT_EXEC,"Statement execution/stepping failed");
240 C(DB_LOCKED,"Database is locked");
241 C(DB_NEEDS_REBUILD,"Fossil repository needs to be rebuilt");
242 C(DB_NOT_FOUND,"Fossil repository db file could not be found.");
243 C(DB_NOT_VALID, "Fossil repository db file is not valid.");
 
244 #undef C
245 default:
246 return "Unknown Error";
247 }
248 }
@@ -1371,11 +1372,11 @@
1371 #define VAL(K,V) cson_object_set(o, #K, (V) ? (V) : cson_value_null())
1372 VAL(capabilities, json_cap_value());
1373 INT(g, argc);
1374 INT(g, isConst);
1375 INT(g, useAttach);
1376 INT(g, configOpen);
1377 INT(g, repositoryOpen);
1378 INT(g, localOpen);
1379 INT(g, minPrefix);
1380 INT(g, fSqlTrace);
1381 INT(g, fSqlStats);
@@ -1397,11 +1398,10 @@
1397 INT(g, urlIsFile);
1398 INT(g, urlIsHttps);
1399 INT(g, urlIsSsh);
1400 INT(g, urlPort);
1401 INT(g, urlDfltPort);
1402 INT(g, dontKeepUrl);
1403 INT(g, useLocalauth);
1404 INT(g, noPswd);
1405 INT(g, userUid);
1406 INT(g, rcvid);
1407 INT(g, okCsrf);
@@ -1410,11 +1410,10 @@
1410 INT(g, nAux);
1411 INT(g, allowSymlinks);
1412
1413 CSTR(g, zMainDbType);
1414 CSTR(g, zConfigDbType);
1415 CSTR(g, zHome);
1416 CSTR(g, zLocalRoot);
1417 CSTR(g, zPath);
1418 CSTR(g, zExtra);
1419 CSTR(g, zBaseURL);
1420 CSTR(g, zTop);
@@ -2118,18 +2117,22 @@
2118 ** taken from zPages. zPages must be an array of objects
2119 ** whose final entry MUST have a NULL name value or results
2120 ** are undefined.
2121 **
2122 ** The list is appended to pOut. The number of items (not bytes)
2123 ** appended are returned.
 
 
2124 */
2125 static int json_pagedefs_to_string(JsonPageDef const * zPages,
2126 Blob * pOut){
2127 int i = 0;
2128 for( ; zPages->name; ++zPages, ++i ){
2129 if(g.isHTTP && zPages->runMode < 0) continue;
2130 else if(zPages->runMode > 0) continue;
 
 
2131 blob_appendf(pOut, zPages->name, -1);
2132 if((zPages+1)->name){
2133 blob_append(pOut, ", ",2);
2134 }
2135 }
@@ -2153,11 +2156,11 @@
2153 blob_init(&cmdNames,NULL,0);
2154 if( !zErrPrefix ) {
2155 zErrPrefix = "Try one of: ";
2156 }
2157 blob_append( &cmdNames, zErrPrefix, strlen(zErrPrefix) );
2158 json_pagedefs_to_string(pCommands, &cmdNames);
2159 json_set_err(FSL_JSON_E_MISSING_ARGS, "%s",
2160 blob_str(&cmdNames));
2161 blob_reset(&cmdNames);
2162 }
2163
@@ -2246,10 +2249,12 @@
2246 cson_value * json_page_user();
2247 /* Impl in json_config.c. */
2248 cson_value * json_page_config();
2249 /* Impl in json_finfo.c. */
2250 cson_value * json_page_finfo();
 
 
2251
2252 /*
2253 ** Mapping of names to JSON pages/commands. Each name is a subpath of
2254 ** /json (in CGI mode) or a subcommand of the json command in CLI mode
2255 */
@@ -2270,10 +2275,11 @@
2270 {"query",json_page_query,0},
2271 {"rebuild",json_page_rebuild,0},
2272 {"report", json_page_report, 0},
2273 {"resultCodes", json_page_resultCodes,0},
2274 {"stat",json_page_stat,0},
 
2275 {"tag", json_page_tag,0},
2276 /*{"ticket", json_page_nyi,0},*/
2277 {"timeline", json_page_timeline,0},
2278 {"user",json_page_user,0},
2279 {"version",json_page_version,0},
2280
--- src/json.c
+++ src/json.c
@@ -239,10 +239,11 @@
239 C(STMT_EXEC,"Statement execution/stepping failed");
240 C(DB_LOCKED,"Database is locked");
241 C(DB_NEEDS_REBUILD,"Fossil repository needs to be rebuilt");
242 C(DB_NOT_FOUND,"Fossil repository db file could not be found.");
243 C(DB_NOT_VALID, "Fossil repository db file is not valid.");
244 C(DB_NEEDS_CHECKOUT, "Command requires a local checkout.");
245 #undef C
246 default:
247 return "Unknown Error";
248 }
249 }
@@ -1371,11 +1372,11 @@
1372 #define VAL(K,V) cson_object_set(o, #K, (V) ? (V) : cson_value_null())
1373 VAL(capabilities, json_cap_value());
1374 INT(g, argc);
1375 INT(g, isConst);
1376 INT(g, useAttach);
1377 CSTR(g, zConfigDbName);
1378 INT(g, repositoryOpen);
1379 INT(g, localOpen);
1380 INT(g, minPrefix);
1381 INT(g, fSqlTrace);
1382 INT(g, fSqlStats);
@@ -1397,11 +1398,10 @@
1398 INT(g, urlIsFile);
1399 INT(g, urlIsHttps);
1400 INT(g, urlIsSsh);
1401 INT(g, urlPort);
1402 INT(g, urlDfltPort);
 
1403 INT(g, useLocalauth);
1404 INT(g, noPswd);
1405 INT(g, userUid);
1406 INT(g, rcvid);
1407 INT(g, okCsrf);
@@ -1410,11 +1410,10 @@
1410 INT(g, nAux);
1411 INT(g, allowSymlinks);
1412
1413 CSTR(g, zMainDbType);
1414 CSTR(g, zConfigDbType);
 
1415 CSTR(g, zLocalRoot);
1416 CSTR(g, zPath);
1417 CSTR(g, zExtra);
1418 CSTR(g, zBaseURL);
1419 CSTR(g, zTop);
@@ -2118,18 +2117,22 @@
2117 ** taken from zPages. zPages must be an array of objects
2118 ** whose final entry MUST have a NULL name value or results
2119 ** are undefined.
2120 **
2121 ** The list is appended to pOut. The number of items (not bytes)
2122 ** appended are returned. If filterByMode is non-0 then the result
2123 ** list will contain only commands which are able to run in the the
2124 ** current run mode (CLI vs. HTTP).
2125 */
2126 static int json_pagedefs_to_string(JsonPageDef const * zPages,
2127 Blob * pOut, int filterByMode){
2128 int i = 0;
2129 for( ; zPages->name; ++zPages, ++i ){
2130 if(filterByMode){
2131 if(g.isHTTP && zPages->runMode < 0) continue;
2132 else if(zPages->runMode > 0) continue;
2133 }
2134 blob_appendf(pOut, zPages->name, -1);
2135 if((zPages+1)->name){
2136 blob_append(pOut, ", ",2);
2137 }
2138 }
@@ -2153,11 +2156,11 @@
2156 blob_init(&cmdNames,NULL,0);
2157 if( !zErrPrefix ) {
2158 zErrPrefix = "Try one of: ";
2159 }
2160 blob_append( &cmdNames, zErrPrefix, strlen(zErrPrefix) );
2161 json_pagedefs_to_string(pCommands, &cmdNames, 1);
2162 json_set_err(FSL_JSON_E_MISSING_ARGS, "%s",
2163 blob_str(&cmdNames));
2164 blob_reset(&cmdNames);
2165 }
2166
@@ -2246,10 +2249,12 @@
2249 cson_value * json_page_user();
2250 /* Impl in json_config.c. */
2251 cson_value * json_page_config();
2252 /* Impl in json_finfo.c. */
2253 cson_value * json_page_finfo();
2254 /* Impl in json_status.c. */
2255 cson_value * json_page_status();
2256
2257 /*
2258 ** Mapping of names to JSON pages/commands. Each name is a subpath of
2259 ** /json (in CGI mode) or a subcommand of the json command in CLI mode
2260 */
@@ -2270,10 +2275,11 @@
2275 {"query",json_page_query,0},
2276 {"rebuild",json_page_rebuild,0},
2277 {"report", json_page_report, 0},
2278 {"resultCodes", json_page_resultCodes,0},
2279 {"stat",json_page_stat,0},
2280 {"status", json_page_status, 0},
2281 {"tag", json_page_tag,0},
2282 /*{"ticket", json_page_nyi,0},*/
2283 {"timeline", json_page_timeline,0},
2284 {"user",json_page_user,0},
2285 {"version",json_page_version,0},
2286
--- src/json_detail.h
+++ src/json_detail.h
@@ -103,12 +103,18 @@
103103
FSL_JSON_E_STMT_EXEC /*+3*/,
104104
FSL_JSON_E_DB_LOCKED /*+4*/,
105105
106106
FSL_JSON_E_DB_NEEDS_REBUILD = FSL_JSON_E_DB + 101,
107107
FSL_JSON_E_DB_NOT_FOUND = FSL_JSON_E_DB + 102,
108
-FSL_JSON_E_DB_NOT_VALID = FSL_JSON_E_DB + 103
109
-
108
+FSL_JSON_E_DB_NOT_VALID = FSL_JSON_E_DB + 103,
109
+/*
110
+** Maintenance reminder: FSL_JSON_E_DB_NOT_FOUND gets triggered in the
111
+** bootstrapping process before we know whether we need to check for
112
+** FSL_JSON_E_DB_NEEDS_CHECKOUT. Thus the former error trumps the
113
+** latter.
114
+*/
115
+FSL_JSON_E_DB_NEEDS_CHECKOUT = FSL_JSON_E_DB + 104
110116
};
111117
112118
113119
/*
114120
** Signature for JSON page/command callbacks. Each callback is
@@ -177,13 +183,10 @@
177183
** <0 = CLI only, >0 = HTTP only, 0==both
178184
**
179185
** Now that we can simulate POST in CLI mode, the distinction
180186
** between them has disappeared in most (or all) cases, so 0 is
181187
** the standard value.
182
- **
183
- ** 201207: this is not needed any more. We can get rid of it. Or
184
- ** keep it around in case it becomes useful again at some point.
185188
*/
186189
char runMode;
187190
} JsonPageDef;
188191
189192
/*
190193
191194
ADDED src/json_status.c
--- src/json_detail.h
+++ src/json_detail.h
@@ -103,12 +103,18 @@
103 FSL_JSON_E_STMT_EXEC /*+3*/,
104 FSL_JSON_E_DB_LOCKED /*+4*/,
105
106 FSL_JSON_E_DB_NEEDS_REBUILD = FSL_JSON_E_DB + 101,
107 FSL_JSON_E_DB_NOT_FOUND = FSL_JSON_E_DB + 102,
108 FSL_JSON_E_DB_NOT_VALID = FSL_JSON_E_DB + 103
109
 
 
 
 
 
 
110 };
111
112
113 /*
114 ** Signature for JSON page/command callbacks. Each callback is
@@ -177,13 +183,10 @@
177 ** <0 = CLI only, >0 = HTTP only, 0==both
178 **
179 ** Now that we can simulate POST in CLI mode, the distinction
180 ** between them has disappeared in most (or all) cases, so 0 is
181 ** the standard value.
182 **
183 ** 201207: this is not needed any more. We can get rid of it. Or
184 ** keep it around in case it becomes useful again at some point.
185 */
186 char runMode;
187 } JsonPageDef;
188
189 /*
190
191 DDED src/json_status.c
--- src/json_detail.h
+++ src/json_detail.h
@@ -103,12 +103,18 @@
103 FSL_JSON_E_STMT_EXEC /*+3*/,
104 FSL_JSON_E_DB_LOCKED /*+4*/,
105
106 FSL_JSON_E_DB_NEEDS_REBUILD = FSL_JSON_E_DB + 101,
107 FSL_JSON_E_DB_NOT_FOUND = FSL_JSON_E_DB + 102,
108 FSL_JSON_E_DB_NOT_VALID = FSL_JSON_E_DB + 103,
109 /*
110 ** Maintenance reminder: FSL_JSON_E_DB_NOT_FOUND gets triggered in the
111 ** bootstrapping process before we know whether we need to check for
112 ** FSL_JSON_E_DB_NEEDS_CHECKOUT. Thus the former error trumps the
113 ** latter.
114 */
115 FSL_JSON_E_DB_NEEDS_CHECKOUT = FSL_JSON_E_DB + 104
116 };
117
118
119 /*
120 ** Signature for JSON page/command callbacks. Each callback is
@@ -177,13 +183,10 @@
183 ** <0 = CLI only, >0 = HTTP only, 0==both
184 **
185 ** Now that we can simulate POST in CLI mode, the distinction
186 ** between them has disappeared in most (or all) cases, so 0 is
187 ** the standard value.
 
 
 
188 */
189 char runMode;
190 } JsonPageDef;
191
192 /*
193
194 DDED src/json_status.c
--- a/src/json_status.c
+++ b/src/json_status.c
@@ -0,0 +1,130 @@
1
+#ifdef FOSSIL_ENABLE_JSON
2
+/*
3
+** Copyright (c) 2013 D. Richard Hipp
4
+**
5
+** This program is free software; you can redistribute it and/or
6
+** modify it under the terms of the Simplified BSD License (also
7
+** known as the "2-Clause License" or "FreeBSD License".)
8
+**
9
+** This program is distributed in the hope that it will be useful,
10
+** but without any warranty; without even the implied warranty of
11
+** merchantability or fitness for a particular purpose.
12
+**
13
+** Author contact information:
14
+** [email protected]
15
+** http://www.hwaci.com/drh/
16
+**
17
+*/
18
+
19
+#include "config.h"
20
+#include "json_status.h"
21
+
22
+#if INTERFACE
23
+#include "json_detail.h"
24
+#endif
25
+
26
+/*
27
+Reminder to check if a column exists:
28
+
29
+PRAGMA table_info(table_name)
30
+
31
+and search for a row where the 'name' field matches.
32
+
33
+That assumes, of course, that table_info()'s output format
34
+is stable.
35
+*/
36
+
37
+/*
38
+** Implementation of the /json/status page.
39
+**
40
+*/
41
+cson_value * json_page_status(){
42
+ Stmt q = empty_Stmt;
43
+ cson_object * oPay;
44
+ /*cson_object * files;*/
45
+ int vid, nErr = 0;
46
+ cson_object * tmpO;
47
+ char * zTmp;
48
+ i64 iMtime;
49
+ cson_array * aFiles;
50
+
51
+ if(!db_o open_loal(0)){
52
+ json_set_er,urn NULL;
53
+ }
54
+ oPay = cson_new_object();
55
+ cson_object_set(oPay, "repository",
56
+ json_new_string(db_repository_filename()));
57
+ cson_object_set(oPay, "localRoot",
58
+ json_new_string(g.zLocalRoot));
59
+ vid = db_lget_int("checkout", 0);
60
+ if(!vid){
61
+ json_set_err( FSL_JSON_E_UNKNOWN, "Can this even happen?" );
62
+ return 0;
63
+ }
64
+ vfile_check_signature(vid, 0);
65
+ /* TODO:show_common_info() state */
66
+ tmpO = cson_new_object();
67
+ cson_???object();
68
+ cson_object_set(oPay, "checkout", cson_object_value(tmpO));
69
+
70
+ zTmp = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", vid);
71
+ cson_object_set(tmpO, "uuid", json_new_string(zTmp) );
72
+ free(zTmp);
73
+
74
+ cson_object_set( tmpO, "tags", json_tags_for_checkin_rid(vi,wd 0t(0, "Spen_local(0)){
75
+ json_set_erct();
76
+ cson_object_set(oPay, "repository",
77
+ json_new_string(db_repository_filename()));
78
+ cson_object_set(oPay, "localRoot",
79
+ et_int("checkout", 0);
80
+ if(!vid){
81
+ json_set_err( FSL_JSON_E_UNKNOWN, "Can this even happen?" );
82
+ return 0;
83
+ }
84
+ vfile_check_sig#ifdef FOSSIL_ENABLE_JSON
85
+/*
86
+** Copyright (c) 2013 D. Richard Hipp
87
+**
88
+** This program is free software; you can redistribute it and/or
89
+** modify it under the terms of the Simplified BSD License (also
90
+** known as the "2-Clause License" or "FreeBSD License".)
91
+**
92
+** This program is distributed in the hope that it will be useful,
93
+** but without any warranty; without even the implied warranty of
94
+** merchantability or fitness for a particular purpose.
95
+**
96
+** Author contact information:
97
+** [email protected]
98
+** http://www.hwaci.com/drh/
99
+**
100
+*/
101
+
102
+#include "config.h"
103
+#include "json_status.h"
104
+
105
+#if INTERFACE
106
+#include "json_detail.h"
107
+#endif
108
+
109
+/*
110
+Reminder to check if a column exists:
111
+
112
+PRAGMA table_info(table_name)
113
+
114
+and search for a row where the 'name' field matches.
115
+
116
+That assumes, of course, that table_info()'s output format
117
+is stable.
118
+*/
119
+
120
+/*
121
+** Implementation of the /json/status page.
122
+**
123
+*/
124
+cson_value * json_page_status(){
125
+ Stmt q = empty_Stmt;
126
+ cson_object * oPay;
127
+ /*cson_object * files;*/
128
+ int vid, nErr = 0;
129
+ cson_object * tmpO;
130
+ char * zTC
--- a/src/json_status.c
+++ b/src/json_status.c
@@ -0,0 +1,130 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
--- a/src/json_status.c
+++ b/src/json_status.c
@@ -0,0 +1,130 @@
1 #ifdef FOSSIL_ENABLE_JSON
2 /*
3 ** Copyright (c) 2013 D. Richard Hipp
4 **
5 ** This program is free software; you can redistribute it and/or
6 ** modify it under the terms of the Simplified BSD License (also
7 ** known as the "2-Clause License" or "FreeBSD License".)
8 **
9 ** This program is distributed in the hope that it will be useful,
10 ** but without any warranty; without even the implied warranty of
11 ** merchantability or fitness for a particular purpose.
12 **
13 ** Author contact information:
14 ** [email protected]
15 ** http://www.hwaci.com/drh/
16 **
17 */
18
19 #include "config.h"
20 #include "json_status.h"
21
22 #if INTERFACE
23 #include "json_detail.h"
24 #endif
25
26 /*
27 Reminder to check if a column exists:
28
29 PRAGMA table_info(table_name)
30
31 and search for a row where the 'name' field matches.
32
33 That assumes, of course, that table_info()'s output format
34 is stable.
35 */
36
37 /*
38 ** Implementation of the /json/status page.
39 **
40 */
41 cson_value * json_page_status(){
42 Stmt q = empty_Stmt;
43 cson_object * oPay;
44 /*cson_object * files;*/
45 int vid, nErr = 0;
46 cson_object * tmpO;
47 char * zTmp;
48 i64 iMtime;
49 cson_array * aFiles;
50
51 if(!db_o open_loal(0)){
52 json_set_er,urn NULL;
53 }
54 oPay = cson_new_object();
55 cson_object_set(oPay, "repository",
56 json_new_string(db_repository_filename()));
57 cson_object_set(oPay, "localRoot",
58 json_new_string(g.zLocalRoot));
59 vid = db_lget_int("checkout", 0);
60 if(!vid){
61 json_set_err( FSL_JSON_E_UNKNOWN, "Can this even happen?" );
62 return 0;
63 }
64 vfile_check_signature(vid, 0);
65 /* TODO:show_common_info() state */
66 tmpO = cson_new_object();
67 cson_???object();
68 cson_object_set(oPay, "checkout", cson_object_value(tmpO));
69
70 zTmp = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", vid);
71 cson_object_set(tmpO, "uuid", json_new_string(zTmp) );
72 free(zTmp);
73
74 cson_object_set( tmpO, "tags", json_tags_for_checkin_rid(vi,wd 0t(0, "Spen_local(0)){
75 json_set_erct();
76 cson_object_set(oPay, "repository",
77 json_new_string(db_repository_filename()));
78 cson_object_set(oPay, "localRoot",
79 et_int("checkout", 0);
80 if(!vid){
81 json_set_err( FSL_JSON_E_UNKNOWN, "Can this even happen?" );
82 return 0;
83 }
84 vfile_check_sig#ifdef FOSSIL_ENABLE_JSON
85 /*
86 ** Copyright (c) 2013 D. Richard Hipp
87 **
88 ** This program is free software; you can redistribute it and/or
89 ** modify it under the terms of the Simplified BSD License (also
90 ** known as the "2-Clause License" or "FreeBSD License".)
91 **
92 ** This program is distributed in the hope that it will be useful,
93 ** but without any warranty; without even the implied warranty of
94 ** merchantability or fitness for a particular purpose.
95 **
96 ** Author contact information:
97 ** [email protected]
98 ** http://www.hwaci.com/drh/
99 **
100 */
101
102 #include "config.h"
103 #include "json_status.h"
104
105 #if INTERFACE
106 #include "json_detail.h"
107 #endif
108
109 /*
110 Reminder to check if a column exists:
111
112 PRAGMA table_info(table_name)
113
114 and search for a row where the 'name' field matches.
115
116 That assumes, of course, that table_info()'s output format
117 is stable.
118 */
119
120 /*
121 ** Implementation of the /json/status page.
122 **
123 */
124 cson_value * json_page_status(){
125 Stmt q = empty_Stmt;
126 cson_object * oPay;
127 /*cson_object * files;*/
128 int vid, nErr = 0;
129 cson_object * tmpO;
130 char * zTC
+199 -337
--- src/main.c
+++ src/main.c
@@ -31,11 +31,11 @@
3131
#else
3232
# include <errno.h> /* errno global */
3333
#endif
3434
#if INTERFACE
3535
#ifdef FOSSIL_ENABLE_JSON
36
-# include "cson_amalgamation.h" /* JSON API. Needed inside the INTERFACE block! */
36
+# include "cson_amalgamation.h" /* JSON API. */
3737
# include "json_detail.h"
3838
#endif
3939
#ifdef FOSSIL_ENABLE_TCL
4040
#include "tcl.h"
4141
#endif
@@ -114,17 +114,16 @@
114114
char *nameOfExe; /* Full path of executable. */
115115
int isConst; /* True if the output is unchanging */
116116
sqlite3 *db; /* The connection to the databases */
117117
sqlite3 *dbConfig; /* Separate connection for global_config table */
118118
int useAttach; /* True if global_config is attached to repository */
119
- int configOpen; /* True if the config database is open */
119
+ const char *zConfigDbName;/* Path of the config database. NULL if not open */
120120
sqlite3_int64 now; /* Seconds since 1970 */
121121
int repositoryOpen; /* True if the main repository database is open */
122122
char *zRepositoryName; /* Name of the repository database */
123123
const char *zMainDbType;/* "configdb", "localdb", or "repository" */
124124
const char *zConfigDbType; /* "configdb", "localdb", or "repository" */
125
- const char *zHome; /* Name of user home directory */
126125
int localOpen; /* True if the local database is open */
127126
char *zLocalRoot; /* The directory holding the local database */
128127
int minPrefix; /* Number of digits needed for a distinct UUID */
129128
int fSqlTrace; /* True if --sqltrace flag is present */
130129
int fSqlStats; /* True if --sqltrace or --sqlstats are present */
@@ -172,14 +171,15 @@
172171
char *urlPasswd; /* Password for http: */
173172
char *urlCanonical; /* Canonical representation of the URL */
174173
char *urlProxyAuth; /* Proxy-Authorizer: string */
175174
char *urlFossil; /* The fossil query parameter on ssh: */
176175
char *urlShell; /* The shell query parameter on ssh: */
177
- int dontKeepUrl; /* Do not persist the URL */
176
+ unsigned urlFlags; /* Boolean flags controlling URL processing */
178177
179178
const char *zLogin; /* Login name. "" if not logged in. */
180
- const char *zSSLIdentity; /* Value of --ssl-identity option, filename of SSL client identity */
179
+ const char *zSSLIdentity; /* Value of --ssl-identity option, filename of
180
+ ** SSL client identity */
181181
int useLocalauth; /* No login required if from 127.0.0.1 */
182182
int noPswd; /* Logged in without password (on 127.0.0.1) */
183183
int userUid; /* Integer user id */
184184
185185
/* Information used to populate the RCVFROM table */
@@ -223,11 +223,12 @@
223223
reported. In JSON mode we try to
224224
always output JSON-form error
225225
responses and always exit() with
226226
code 0 to avoid an HTTP 500 error.
227227
*/
228
- int resultCode; /* used for passing back specific codes from /json callbacks. */
228
+ int resultCode; /* used for passing back specific codes
229
+ ** from /json callbacks. */
229230
int errorDetailParanoia; /* 0=full error codes, 1=%10, 2=%100, 3=%1000 */
230231
cson_output_opt outOpt; /* formatting options for JSON mode. */
231232
cson_value * authToken; /* authentication token */
232233
char const * jsonp; /* Name of JSONP function wrapper. */
233234
unsigned char dispatchDepth /* Tells JSON command dispatching
@@ -252,14 +253,11 @@
252253
} cmd;
253254
struct { /* JSON POST data. */
254255
cson_value * v;
255256
cson_object * o;
256257
} post;
257
- struct { /* GET/COOKIE params in JSON mode.
258
- FIXME (stephan): verify that this is
259
- still used and remove if it is not.
260
- */
258
+ struct { /* GET/COOKIE params in JSON mode. */
261259
cson_value * v;
262260
cson_object * o;
263261
} param;
264262
struct {
265263
cson_value * v;
@@ -335,11 +333,11 @@
335333
336334
/*
337335
** atexit() handler which frees up "some" of the resources
338336
** used by fossil.
339337
*/
340
-void fossil_atexit(void) {
338
+static void fossil_atexit(void) {
341339
#ifdef FOSSIL_ENABLE_JSON
342340
cson_value_free(g.json.gc.v);
343341
memset(&g.json, 0, sizeof(g.json));
344342
#endif
345343
free(g.zErrMsg);
@@ -368,11 +366,11 @@
368366
char *z; /* General use string pointer */
369367
char **newArgv; /* New expanded g.argv under construction */
370368
char const * zFileName; /* input file name */
371369
FILE * zInFile; /* input FILE */
372370
#if defined(_WIN32)
373
- WCHAR buf[MAX_PATH];
371
+ wchar_t buf[MAX_PATH];
374372
#endif
375373
376374
g.argc = argc;
377375
g.argv = argv;
378376
sqlite3_initialize();
@@ -456,10 +454,49 @@
456454
}
457455
return zNewArgv;
458456
}
459457
#endif
460458
459
+/*
460
+** Return a name for an SQLite error code
461
+*/
462
+static const char *sqlite_error_code_name(int iCode){
463
+ static char zCode[30];
464
+ switch( iCode & 0xff ){
465
+ case SQLITE_OK: return "SQLITE_OK";
466
+ case SQLITE_ERROR: return "SQLITE_ERROR";
467
+ case SQLITE_PERM: return "SQLITE_PERM";
468
+ case SQLITE_ABORT: return "SQLITE_ABORT";
469
+ case SQLITE_BUSY: return "SQLITE_BUSY";
470
+ case SQLITE_NOMEM: return "SQLITE_NOMEM";
471
+ case SQLITE_READONLY: return "SQLITE_READONLY";
472
+ case SQLITE_INTERRUPT: return "SQLITE_INTERRUPT";
473
+ case SQLITE_IOERR: return "SQLITE_IOERR";
474
+ case SQLITE_CORRUPT: return "SQLITE_CORRUPT";
475
+ case SQLITE_FULL: return "SQLITE_FULL";
476
+ case SQLITE_CANTOPEN: return "SQLITE_CANTOPEN";
477
+ case SQLITE_PROTOCOL: return "SQLITE_PROTOCOL";
478
+ case SQLITE_EMPTY: return "SQLITE_EMPTY";
479
+ case SQLITE_SCHEMA: return "SQLITE_SCHEMA";
480
+ case SQLITE_CONSTRAINT: return "SQLITE_CONSTRAINT";
481
+ case SQLITE_MISMATCH: return "SQLITE_MISMATCH";
482
+ case SQLITE_MISUSE: return "SQLITE_MISUSE";
483
+ case SQLITE_NOLFS: return "SQLITE_NOLFS";
484
+ case SQLITE_FORMAT: return "SQLITE_FORMAT";
485
+ case SQLITE_RANGE: return "SQLITE_RANGE";
486
+ case SQLITE_NOTADB: return "SQLITE_NOTADB";
487
+ default: {
488
+ sqlite3_snprintf(sizeof(zCode),zCode,"error code %d",iCode);
489
+ }
490
+ }
491
+ return zCode;
492
+}
493
+
494
+/* Error logs from SQLite */
495
+static void fossil_sqlite_log(void *notUsed, int iCode, const char *zErrmsg){
496
+ fossil_warning("%s: %s", sqlite_error_code_name(iCode), zErrmsg);
497
+}
461498
462499
/*
463500
** This procedure runs first.
464501
*/
465502
#if defined(_WIN32) && !defined(BROKEN_MINGW_CMDLINE)
@@ -563,263 +600,21 @@
563600
fossil_exit(0);
564601
/*NOT_REACHED*/
565602
return 0;
566603
}
567604
568
-/*
569
-** The following variable becomes true while processing a fatal error
570
-** or a panic. If additional "recursive-fatal" errors occur while
571
-** shutting down, the recursive errors are silently ignored.
572
-*/
573
-static int mainInFatalError = 0;
574
-
575
-/*
576
-** Exit. Take care to close the database first.
577
-*/
578
-NORETURN void fossil_exit(int rc){
579
- db_close(1);
580
- exit(rc);
581
-}
582
-
583
-/*
584
-** Print an error message, rollback all databases, and quit. These
585
-** routines never return.
586
-*/
587
-NORETURN void fossil_panic(const char *zFormat, ...){
588
- char *z;
589
- va_list ap;
590
- int rc = 1;
591
- static int once = 1;
592
- mainInFatalError = 1;
593
- va_start(ap, zFormat);
594
- z = vmprintf(zFormat, ap);
595
- va_end(ap);
596
-#ifdef FOSSIL_ENABLE_JSON
597
- if( g.json.isJsonMode ){
598
- json_err( 0, z, 1 );
599
- if( g.isHTTP ){
600
- rc = 0 /* avoid HTTP 500 */;
601
- }
602
- }
603
- else
604
-#endif
605
- {
606
- if( g.cgiOutput && once ){
607
- once = 0;
608
- cgi_printf("<p class=\"generalError\">%h</p>", z);
609
- cgi_reply();
610
- }else if( !g.fQuiet ){
611
- fossil_trace("%s: %s\n", g.argv[0], z);
612
- }
613
- }
614
- free(z);
615
- db_force_rollback();
616
- fossil_exit(rc);
617
-}
618
-
619
-NORETURN void fossil_fatal(const char *zFormat, ...){
620
- char *z;
621
- int rc = 1;
622
- va_list ap;
623
- mainInFatalError = 1;
624
- va_start(ap, zFormat);
625
- z = vmprintf(zFormat, ap);
626
- va_end(ap);
627
-#ifdef FOSSIL_ENABLE_JSON
628
- if( g.json.isJsonMode ){
629
- json_err( g.json.resultCode, z, 1 );
630
- if( g.isHTTP ){
631
- rc = 0 /* avoid HTTP 500 */;
632
- }
633
- }
634
- else
635
-#endif
636
- {
637
- if( g.cgiOutput ){
638
- g.cgiOutput = 0;
639
- cgi_printf("<p class=\"generalError\">\n%h\n</p>\n", z);
640
- cgi_reply();
641
- }else if( !g.fQuiet ){
642
- fossil_trace("%s: %s\n", g.argv[0], z);
643
- }
644
- }
645
- free(z);
646
- db_force_rollback();
647
- fossil_exit(rc);
648
-}
649
-
650
-/* This routine works like fossil_fatal() except that if called
651
-** recursively, the recursive call is a no-op.
652
-**
653
-** Use this in places where an error might occur while doing
654
-** fatal error shutdown processing. Unlike fossil_panic() and
655
-** fossil_fatal() which never return, this routine might return if
656
-** the fatal error handing is already in process. The caller must
657
-** be prepared for this routine to return.
658
-*/
659
-void fossil_fatal_recursive(const char *zFormat, ...){
660
- char *z;
661
- va_list ap;
662
- int rc = 1;
663
- if( mainInFatalError ) return;
664
- mainInFatalError = 1;
665
- va_start(ap, zFormat);
666
- z = vmprintf(zFormat, ap);
667
- va_end(ap);
668
-#ifdef FOSSIL_ENABLE_JSON
669
- if( g.json.isJsonMode ){
670
- json_err( g.json.resultCode, z, 1 );
671
- if( g.isHTTP ){
672
- rc = 0 /* avoid HTTP 500 */;
673
- }
674
- } else
675
-#endif
676
- {
677
- if( g.cgiOutput ){
678
- g.cgiOutput = 0;
679
- cgi_printf("<p class=\"generalError\">\n%h\n</p>\n", z);
680
- cgi_reply();
681
- }else{
682
- fossil_trace("%s: %s\n", g.argv[0], z);
683
- }
684
- }
685
- db_force_rollback();
686
- fossil_exit(rc);
687
-}
688
-
689
-
690
-/* Print a warning message */
691
-void fossil_warning(const char *zFormat, ...){
692
- char *z;
693
- va_list ap;
694
- va_start(ap, zFormat);
695
- z = vmprintf(zFormat, ap);
696
- va_end(ap);
697
-#ifdef FOSSIL_ENABLE_JSON
698
- if(g.json.isJsonMode){
699
- json_warn( FSL_JSON_W_UNKNOWN, z );
700
- }else
701
-#endif
702
- {
703
- if( g.cgiOutput ){
704
- cgi_printf("<p class=\"generalError\">\n%h\n</p>\n", z);
705
- }else{
706
- fossil_trace("%s: %s\n", g.argv[0], z);
707
- }
708
- }
709
- free(z);
710
-}
711
-
712
-/*
713
-** Malloc and free routines that cannot fail
714
-*/
715
-void *fossil_malloc(size_t n){
716
- void *p = malloc(n==0 ? 1 : n);
717
- if( p==0 ) fossil_panic("out of memory");
718
- return p;
719
-}
720
-void fossil_free(void *p){
721
- free(p);
722
-}
723
-void *fossil_realloc(void *p, size_t n){
724
- p = realloc(p, n);
725
- if( p==0 ) fossil_panic("out of memory");
726
- return p;
727
-}
728
-
729
-/*
730
-** This function implements a cross-platform "system()" interface.
731
-*/
732
-int fossil_system(const char *zOrigCmd){
733
- int rc;
734
-#if defined(_WIN32)
735
- /* On windows, we have to put double-quotes around the entire command.
736
- ** Who knows why - this is just the way windows works.
737
- */
738
- char *zNewCmd = mprintf("\"%s\"", zOrigCmd);
739
- WCHAR *zUnicode = fossil_utf8_to_unicode(zNewCmd);
740
- if( g.fSystemTrace ) {
741
- fossil_trace("SYSTEM: %s\n", zNewCmd);
742
- }
743
- rc = _wsystem(zUnicode);
744
- fossil_unicode_free(zUnicode);
745
- free(zNewCmd);
746
-#else
747
- /* On unix, evaluate the command directly.
748
- */
749
- if( g.fSystemTrace ) fprintf(stderr, "SYSTEM: %s\n", zOrigCmd);
750
- rc = system(zOrigCmd);
751
-#endif
752
- return rc;
753
-}
754
-
755
-/*
756
-** Turn off any NL to CRNL translation on the stream given as an
757
-** argument. This is a no-op on unix but is necessary on windows.
758
-*/
759
-void fossil_binary_mode(FILE *p){
760
-#if defined(_WIN32)
761
- _setmode(_fileno(p), _O_BINARY);
762
-#endif
763
-#ifdef __EMX__ /* OS/2 */
764
- setmode(fileno(p), O_BINARY);
765
-#endif
766
-}
767
-
768
-
769
-
770
-/*
771
-** Return a name for an SQLite error code
772
-*/
773
-static const char *sqlite_error_code_name(int iCode){
774
- static char zCode[30];
775
- switch( iCode & 0xff ){
776
- case SQLITE_OK: return "SQLITE_OK";
777
- case SQLITE_ERROR: return "SQLITE_ERROR";
778
- case SQLITE_PERM: return "SQLITE_PERM";
779
- case SQLITE_ABORT: return "SQLITE_ABORT";
780
- case SQLITE_BUSY: return "SQLITE_BUSY";
781
- case SQLITE_NOMEM: return "SQLITE_NOMEM";
782
- case SQLITE_READONLY: return "SQLITE_READONLY";
783
- case SQLITE_INTERRUPT: return "SQLITE_INTERRUPT";
784
- case SQLITE_IOERR: return "SQLITE_IOERR";
785
- case SQLITE_CORRUPT: return "SQLITE_CORRUPT";
786
- case SQLITE_FULL: return "SQLITE_FULL";
787
- case SQLITE_CANTOPEN: return "SQLITE_CANTOPEN";
788
- case SQLITE_PROTOCOL: return "SQLITE_PROTOCOL";
789
- case SQLITE_EMPTY: return "SQLITE_EMPTY";
790
- case SQLITE_SCHEMA: return "SQLITE_SCHEMA";
791
- case SQLITE_CONSTRAINT: return "SQLITE_CONSTRAINT";
792
- case SQLITE_MISMATCH: return "SQLITE_MISMATCH";
793
- case SQLITE_MISUSE: return "SQLITE_MISUSE";
794
- case SQLITE_NOLFS: return "SQLITE_NOLFS";
795
- case SQLITE_FORMAT: return "SQLITE_FORMAT";
796
- case SQLITE_RANGE: return "SQLITE_RANGE";
797
- case SQLITE_NOTADB: return "SQLITE_NOTADB";
798
- default: {
799
- sqlite3_snprintf(sizeof(zCode),zCode,"error code %d",iCode);
800
- }
801
- }
802
- return zCode;
803
-}
804
-
805
-/* Error logs from SQLite */
806
-void fossil_sqlite_log(void *notUsed, int iCode, const char *zErrmsg){
807
- fossil_warning("%s: %s", sqlite_error_code_name(iCode), zErrmsg);
808
-}
809
-
810605
/*
811606
** Print a usage comment and quit
812607
*/
813608
void usage(const char *zFormat){
814
- fossil_fatal("Usage: %s %s %s\n", g.argv[0], g.argv[1], zFormat);
609
+ fossil_fatal("Usage: %s %s %s", g.argv[0], g.argv[1], zFormat);
815610
}
816611
817612
/*
818613
** Remove n elements from g.argv beginning with the i-th element.
819614
*/
820
-void remove_from_argv(int i, int n){
615
+static void remove_from_argv(int i, int n){
821616
int j;
822617
for(j=i+n; j<g.argc; i++, j++){
823618
g.argv[i] = g.argv[j];
824619
}
825620
g.argc = i;
@@ -840,11 +635,11 @@
840635
const char *zReturn = 0;
841636
assert( hasArg==0 || hasArg==1 );
842637
nLong = strlen(zLong);
843638
for(i=1; i<g.argc; i++){
844639
char *z;
845
- if (i+hasArg >= g.argc) break;
640
+ if( i+hasArg >= g.argc ) break;
846641
z = g.argv[i];
847642
if( z[0]!='-' ) continue;
848643
z++;
849644
if( z[0]=='-' ){
850645
if( z[1]==0 ){
@@ -934,14 +729,17 @@
934729
**
935730
** List all web pages
936731
*/
937732
void cmd_test_webpage_list(void){
938733
int i, nCmd;
939
- const char *aCmd[count(aWebpage)];
940
- for(i=nCmd=0; i<count(aWebpage); i++){
941
- aCmd[nCmd++] = aWebpage[i].zName;
734
+ const char *aCmd[count(aCommand)];
735
+ for(i=nCmd=0; i<count(aCommand); i++){
736
+ if(0x08 & aCommand[i].cmdFlags){
737
+ aCmd[nCmd++] = aWebpage[i].zName;
738
+ }
942739
}
740
+ assert(nCmd && "page list is empty?");
943741
multi_column_list(aCmd, nCmd);
944742
}
945743
946744
/*
947745
** COMMAND: version
@@ -967,14 +765,17 @@
967765
**
968766
** %fossil help Show common commands
969767
** %fossil help --all Show both common and auxiliary commands
970768
** %fossil help --test Show test commands only
971769
** %fossil help --aux Show auxiliary commands only
770
+** %fossil help --www Show list of WWW pages
972771
*/
973772
void help_cmd(void){
974
- int rc, idx;
773
+ int rc, idx, isPage = 0;
975774
const char *z;
775
+ char const * zCmdOrPage;
776
+ char const * zCmdOrPagePlural;
976777
if( g.argc<3 ){
977778
z = g.argv[0];
978779
fossil_print(
979780
"Usage: %s help COMMAND\n"
980781
"Common COMMANDs: (use \"%s help --all\" for a complete list)\n",
@@ -985,33 +786,46 @@
985786
}
986787
if( find_option("all",0,0) ){
987788
command_list(0, CMDFLAG_1ST_TIER | CMDFLAG_2ND_TIER);
988789
return;
989790
}
990
- if( find_option("aux",0,0) ){
791
+ else if( find_option("www",0,0) ){
792
+ command_list(0, CMDFLAG_WEBPAGE);
793
+ return;
794
+ }
795
+ else if( find_option("aux",0,0) ){
991796
command_list(0, CMDFLAG_2ND_TIER);
992797
return;
993798
}
994
- if( find_option("test",0,0) ){
799
+ else if( find_option("test",0,0) ){
995800
command_list(0, CMDFLAG_TEST);
996801
return;
802
+ }
803
+ isPage = ('/' == *g.argv[2]) ? 1 : 0;
804
+ if(isPage){
805
+ zCmdOrPage = "page";
806
+ zCmdOrPagePlural = "pages";
807
+ }else{
808
+ zCmdOrPage = "command";
809
+ zCmdOrPagePlural = "commands";
997810
}
998811
rc = name_search(g.argv[2], aCommand, count(aCommand), &idx);
999812
if( rc==1 ){
1000
- fossil_print("unknown command: %s\nAvailable commands:\n", g.argv[2]);
1001
- command_list(0, 0xff);
813
+ fossil_print("unknown %s: %s\nAvailable %s:\n",
814
+ zCmdOrPage, g.argv[2], zCmdOrPagePlural);
815
+ command_list(0, isPage ? CMDFLAG_WEBPAGE : (0xff & ~CMDFLAG_WEBPAGE));
1002816
fossil_exit(1);
1003817
}else if( rc==2 ){
1004
- fossil_print("ambiguous command prefix: %s\nMatching commands:\n",
1005
- g.argv[2]);
818
+ fossil_print("ambiguous %s prefix: %s\nMatching %s:\n",
819
+ zCmdOrPage, g.argv[2], zCmdOrPagePlural);
1006820
command_list(g.argv[2], 0xff);
1007821
fossil_exit(1);
1008822
}
1009
- z = aCmdHelp[idx];
823
+ z = aCmdHelp[idx].zText;
1010824
if( z==0 ){
1011
- fossil_fatal("no help available for the %s command",
1012
- aCommand[idx].zName);
825
+ fossil_fatal("no help available for the %s %s",
826
+ aCommand[idx].zName, zCmdOrPage);
1013827
}
1014828
while( *z ){
1015829
if( *z=='%' && strncmp(z, "%fossil", 7)==0 ){
1016830
fossil_print("%s", g.argv[0]);
1017831
z += 7;
@@ -1033,20 +847,20 @@
1033847
if( zCmd==0 ) zCmd = P("name");
1034848
style_header("Command-line Help");
1035849
if( zCmd ){
1036850
int rc, idx;
1037851
char *z, *s, *d;
1038
-
852
+ char const * zCmdOrPage = ('/'==*zCmd) ? "page" : "command";
1039853
style_submenu_element("Command-List", "Command-List", "%s/help", g.zTop);
1040
- @ <h1>The "%s(zCmd)" command:</h1>
854
+ @ <h1>The "%s(zCmd)" %s(zCmdOrPage):</h1>
1041855
rc = name_search(zCmd, aCommand, count(aCommand), &idx);
1042856
if( rc==1 ){
1043857
@ unknown command: %s(zCmd)
1044858
}else if( rc==2 ){
1045859
@ ambiguous command prefix: %s(zCmd)
1046860
}else{
1047
- z = (char*)aCmdHelp[idx];
861
+ z = (char*)aCmdHelp[idx].zText;
1048862
if( z==0 ){
1049863
@ no help available for the %s(aCommand[idx].zName) command
1050864
}else{
1051865
z=s=d=mprintf("%s",z);
1052866
while( *s ){
@@ -1068,21 +882,52 @@
1068882
1069883
@ <h1>Available commands:</h1>
1070884
@ <table border="0"><tr>
1071885
for(i=j=0; i<count(aCommand); i++){
1072886
const char *z = aCommand[i].zName;
1073
- if( strncmp(z,"test",4)==0 ) continue;
887
+ if( '/'==*z || strncmp(z,"test",4)==0 ) continue;
1074888
j++;
1075889
}
1076890
n = (j+6)/7;
1077891
for(i=j=0; i<count(aCommand); i++){
1078892
const char *z = aCommand[i].zName;
1079
- if( strncmp(z,"test",4)==0 ) continue;
893
+ if( '/'==*z || strncmp(z,"test",4)==0 ) continue;
894
+ if( j==0 ){
895
+ @ <td valign="top"><ul>
896
+ }
897
+ @ <li><a href="%s(g.zTop)/help?cmd=%s(z)">%s(z)</a></li>
898
+ j++;
899
+ if( j>=n ){
900
+ @ </ul></td>
901
+ j = 0;
902
+ }
903
+ }
904
+ if( j>0 ){
905
+ @ </ul></td>
906
+ }
907
+ @ </tr></table>
908
+
909
+ @ <h1>Available pages:</h1>
910
+ @ (Only pages with help text are linked.)
911
+ @ <table border="0"><tr>
912
+ for(i=j=0; i<count(aCommand); i++){
913
+ const char *z = aCommand[i].zName;
914
+ if( '/'!=*z ) continue;
915
+ j++;
916
+ }
917
+ n = (j+4)/5;
918
+ for(i=j=0; i<count(aCommand); i++){
919
+ const char *z = aCommand[i].zName;
920
+ if( '/'!=*z ) continue;
1080921
if( j==0 ){
1081922
@ <td valign="top"><ul>
1082923
}
1083
- @ <li><a href="%s(g.zTop)/help?cmd=%s(z)">%s(z)</a>
924
+ if( aCmdHelp[i].zText && *aCmdHelp[i].zText ){
925
+ @ <li><a href="%s(g.zTop)/help?cmd=%s(z)">%s(z+1)</a></li>
926
+ }else{
927
+ @ <li>%s(z+1)</li>
928
+ }
1084929
j++;
1085930
if( j>=n ){
1086931
@ </ul></td>
1087932
j = 0;
1088933
}
@@ -1089,10 +934,11 @@
1089934
}
1090935
if( j>0 ){
1091936
@ </ul></td>
1092937
}
1093938
@ </tr></table>
939
+
1094940
}
1095941
style_footer();
1096942
}
1097943
1098944
/*
@@ -1105,11 +951,11 @@
1105951
style_header("Testpage: All Help Text");
1106952
for(i=0; i<count(aCommand); i++){
1107953
if( memcmp(aCommand[i].zName, "test", 4)==0 ) continue;
1108954
@ <h2>%s(aCommand[i].zName):</h2>
1109955
@ <blockquote><pre>
1110
- @ %h(aCmdHelp[i])
956
+ @ %h(aCmdHelp[i].zText)
1111957
@ </pre></blockquote>
1112958
}
1113959
style_footer();
1114960
}
1115961
@@ -1285,11 +1131,11 @@
12851131
zRepo = zToFree = mprintf("%s%.*s.fossil",g.zRepositoryName,i,zPathInfo);
12861132
12871133
/* To avoid mischief, make sure the repository basename contains no
12881134
** characters other than alphanumerics, "/", "_", "-", and ".", and
12891135
** that "-" never occurs immediately after a "/" and that "." is always
1290
- ** surrounded by two alphanumerics. Any character that does not
1136
+ ** surrounded by two alphanumerics. Any character that does not
12911137
** satisfy these constraints is converted into "_".
12921138
*/
12931139
szFile = 0;
12941140
for(j=strlen(g.zRepositoryName)+1, k=0; zRepo[j] && k<i-1; j++, k++){
12951141
char c = zRepo[j];
@@ -1504,10 +1350,61 @@
15041350
15051351
/* Return the result.
15061352
*/
15071353
cgi_reply();
15081354
}
1355
+
1356
+/* If the CGI program contains one or more lines of the form
1357
+**
1358
+** redirect: repository-filename http://hostname/path/%s
1359
+**
1360
+** then control jumps here. Search each repository for an artifact ID
1361
+** that matches the "name" CGI parameter and for the first match,
1362
+** redirect to the corresponding URL with the "name" CGI parameter
1363
+** inserted. Paint an error page if no match is found.
1364
+**
1365
+** If there is a line of the form:
1366
+**
1367
+** redirect: * URL
1368
+**
1369
+** Then a redirect is made to URL if no match is found. Otherwise a
1370
+** very primitive error message is returned.
1371
+*/
1372
+static void redirect_web_page(int nRedirect, char **azRedirect){
1373
+ int i; /* Loop counter */
1374
+ const char *zNotFound = 0; /* Not found URL */
1375
+ const char *zName = P("name");
1376
+ set_base_url(0);
1377
+ if( zName==0 ){
1378
+ zName = P("SCRIPT_NAME");
1379
+ if( zName && zName[0]=='/' ) zName++;
1380
+ }
1381
+ if( zName && validate16(zName, strlen(zName)) ){
1382
+ for(i=0; i<nRedirect; i++){
1383
+ if( fossil_strcmp(azRedirect[i*2],"*")==0 ){
1384
+ zNotFound = azRedirect[i*2+1];
1385
+ continue;
1386
+ }
1387
+ db_open_repository(azRedirect[i*2]);
1388
+ if( db_exists("SELECT 1 FROM blob WHERE uuid GLOB '%s*'", zName) ){
1389
+ cgi_redirectf(azRedirect[i*2+1], zName);
1390
+ return;
1391
+ }
1392
+ db_close(1);
1393
+ }
1394
+ }
1395
+ if( zNotFound ){
1396
+ cgi_redirectf(zNotFound, zName);
1397
+ }else{
1398
+ @ <html>
1399
+ @ <head><title>No Such Object</title></head>
1400
+ @ <body>
1401
+ @ <p>No such object: <b>%h(zName)</b></p>
1402
+ @ </body>
1403
+ cgi_reply();
1404
+ }
1405
+}
15091406
15101407
/*
15111408
** COMMAND: cgi*
15121409
**
15131410
** Usage: %fossil ?cgi? SCRIPT
@@ -1604,61 +1501,10 @@
16041501
}else{
16051502
process_one_web_page(zNotFound, pFileGlob);
16061503
}
16071504
}
16081505
1609
-/* If the CGI program contains one or more lines of the form
1610
-**
1611
-** redirect: repository-filename http://hostname/path/%s
1612
-**
1613
-** then control jumps here. Search each repository for an artifact ID
1614
-** that matches the "name" CGI parameter and for the first match,
1615
-** redirect to the corresponding URL with the "name" CGI parameter
1616
-** inserted. Paint an error page if no match is found.
1617
-**
1618
-** If there is a line of the form:
1619
-**
1620
-** redirect: * URL
1621
-**
1622
-** Then a redirect is made to URL if no match is found. Otherwise a
1623
-** very primitive error message is returned.
1624
-*/
1625
-void redirect_web_page(int nRedirect, char **azRedirect){
1626
- int i; /* Loop counter */
1627
- const char *zNotFound = 0; /* Not found URL */
1628
- const char *zName = P("name");
1629
- set_base_url(0);
1630
- if( zName==0 ){
1631
- zName = P("SCRIPT_NAME");
1632
- if( zName && zName[0]=='/' ) zName++;
1633
- }
1634
- if( zName && validate16(zName, strlen(zName)) ){
1635
- for(i=0; i<nRedirect; i++){
1636
- if( fossil_strcmp(azRedirect[i*2],"*")==0 ){
1637
- zNotFound = azRedirect[i*2+1];
1638
- continue;
1639
- }
1640
- db_open_repository(azRedirect[i*2]);
1641
- if( db_exists("SELECT 1 FROM blob WHERE uuid GLOB '%s*'", zName) ){
1642
- cgi_redirectf(azRedirect[i*2+1], zName);
1643
- return;
1644
- }
1645
- db_close(1);
1646
- }
1647
- }
1648
- if( zNotFound ){
1649
- cgi_redirectf(zNotFound, zName);
1650
- }else{
1651
- @ <html>
1652
- @ <head><title>No Such Object</title></head>
1653
- @ <body>
1654
- @ <p>No such object: <b>%h(zName)</b></p>
1655
- @ </body>
1656
- cgi_reply();
1657
- }
1658
-}
1659
-
16601506
/*
16611507
** If g.argv[2] exists then it is either the name of a repository
16621508
** that will be used by a server, or else it is a directory that
16631509
** contains multiple repositories that can be served. If g.argv[2]
16641510
** is a directory, the repositories it contains must be named
@@ -1745,11 +1591,11 @@
17451591
const char *zHost;
17461592
const char *zAltBase;
17471593
const char *zFileGlob;
17481594
17491595
/* The winhttp module passes the --files option as --files-urlenc with
1750
- ** the argument being URL encoded, to avoid wildcard expansion in the
1596
+ ** the argument being URL encoded, to avoid wildcard expansion in the
17511597
** shell. This option is for internal use and is undocumented.
17521598
*/
17531599
zFileGlob = find_option("files-urlenc",0,1);
17541600
if( zFileGlob ){
17551601
char *z = mprintf("%s", zFileGlob);
@@ -1849,12 +1695,12 @@
18491695
**
18501696
** The "ui" command automatically starts a web browser after initializing
18511697
** the web server. The "ui" command also binds to 127.0.0.1 and so will
18521698
** only process HTTP traffic from the local machine.
18531699
**
1854
-** The REPOSITORY can be a directory (aka folder) that contains one or
1855
-** more repositories with names ending in ".fossil". In this case, the
1700
+** The REPOSITORY can be a directory (aka folder) that contains one or
1701
+** more repositories with names ending in ".fossil". In this case, the
18561702
** a prefix of the URL pathname is used to search the directory for an
18571703
** appropriate repository. To thwart mischief, the pathname in the URL must
18581704
** contain only alphanumerics, "_", "/", "-", and ".", and no "-" may
18591705
** occur after "/", and every "." must be surrounded on both sides by
18601706
** alphanumerics. Any pathname that does not satisfy these constraints
@@ -1891,10 +1737,11 @@
18911737
int isUiCmd; /* True if command is "ui", not "server' */
18921738
const char *zNotFound; /* The --notfound option or NULL */
18931739
int flags = 0; /* Server flags */
18941740
const char *zAltBase; /* Argument to the --baseurl option */
18951741
const char *zFileGlob; /* Static content must match this */
1742
+ char *zIpAddr = 0; /* Bind to this IP address */
18961743
18971744
#if defined(_WIN32)
18981745
const char *zStopperFile; /* Name of file used to terminate server */
18991746
zStopperFile = find_option("stopper", 0, 1);
19001747
#endif
@@ -1917,10 +1764,16 @@
19171764
flags |= HTTP_SERVER_LOCALHOST;
19181765
g.useLocalauth = 1;
19191766
}
19201767
find_server_repository(isUiCmd && zNotFound==0);
19211768
if( zPort ){
1769
+ int i;
1770
+ for(i=strlen(zPort)-1; i>=0 && zPort[i]!=':'; i--){}
1771
+ if( i>0 ){
1772
+ zIpAddr = mprintf("%.*s", i, zPort);
1773
+ zPort += i+1;
1774
+ }
19221775
iPort = mxPort = atoi(zPort);
19231776
}else{
19241777
iPort = db_get_int("http-port", 8080);
19251778
mxPort = iPort+100;
19261779
}
@@ -1928,11 +1781,12 @@
19281781
/* Unix implementation */
19291782
if( isUiCmd ){
19301783
#if !defined(__DARWIN__) && !defined(__APPLE__) && !defined(__HAIKU__)
19311784
zBrowser = db_get("web-browser", 0);
19321785
if( zBrowser==0 ){
1933
- static const char *const azBrowserProg[] = { "xdg-open", "gnome-open", "firefox" };
1786
+ static const char *const azBrowserProg[] =
1787
+ { "xdg-open", "gnome-open", "firefox", "google-chrome" };
19341788
int i;
19351789
zBrowser = "echo";
19361790
for(i=0; i<sizeof(azBrowserProg)/sizeof(azBrowserProg[0]); i++){
19371791
if( binaryOnPath(azBrowserProg[i]) ){
19381792
zBrowser = azBrowserProg[i];
@@ -1941,14 +1795,18 @@
19411795
}
19421796
}
19431797
#else
19441798
zBrowser = db_get("web-browser", "open");
19451799
#endif
1946
- zBrowserCmd = mprintf("%s http://localhost:%%d/ &", zBrowser);
1800
+ if( zIpAddr ){
1801
+ zBrowserCmd = mprintf("%s http://%s:%%d/ &", zBrowser, zIpAddr);
1802
+ }else{
1803
+ zBrowserCmd = mprintf("%s http://localhost:%%d/ &", zBrowser);
1804
+ }
19471805
}
19481806
db_close(1);
1949
- if( cgi_http_server(iPort, mxPort, zBrowserCmd, flags) ){
1807
+ if( cgi_http_server(iPort, mxPort, zBrowserCmd, zIpAddr, flags) ){
19501808
fossil_fatal("unable to listen on TCP socket %d", iPort);
19511809
}
19521810
g.sslNotAvailable = 1;
19531811
g.httpIn = stdin;
19541812
g.httpOut = stdout;
@@ -1962,16 +1820,20 @@
19621820
process_one_web_page(zNotFound, glob_create(zFileGlob));
19631821
#else
19641822
/* Win32 implementation */
19651823
if( isUiCmd ){
19661824
zBrowser = db_get("web-browser", "start");
1967
- zBrowserCmd = mprintf("%s http://127.0.0.1:%%d/", zBrowser);
1825
+ if( zIpAddr ){
1826
+ zBrowserCmd = mprintf("%s http://%s:%%d/ &", zBrowser, zIpAddr);
1827
+ }else{
1828
+ zBrowserCmd = mprintf("%s http://localhost:%%d/ &", zBrowser);
1829
+ }
19681830
}
19691831
db_close(1);
19701832
if( win32_http_service(iPort, zNotFound, zFileGlob, flags) ){
19711833
win32_http_server(iPort, mxPort, zBrowserCmd,
1972
- zStopperFile, zNotFound, zFileGlob, flags);
1834
+ zStopperFile, zNotFound, zFileGlob, zIpAddr, flags);
19731835
}
19741836
#endif
19751837
}
19761838
19771839
/*
19781840
--- src/main.c
+++ src/main.c
@@ -31,11 +31,11 @@
31 #else
32 # include <errno.h> /* errno global */
33 #endif
34 #if INTERFACE
35 #ifdef FOSSIL_ENABLE_JSON
36 # include "cson_amalgamation.h" /* JSON API. Needed inside the INTERFACE block! */
37 # include "json_detail.h"
38 #endif
39 #ifdef FOSSIL_ENABLE_TCL
40 #include "tcl.h"
41 #endif
@@ -114,17 +114,16 @@
114 char *nameOfExe; /* Full path of executable. */
115 int isConst; /* True if the output is unchanging */
116 sqlite3 *db; /* The connection to the databases */
117 sqlite3 *dbConfig; /* Separate connection for global_config table */
118 int useAttach; /* True if global_config is attached to repository */
119 int configOpen; /* True if the config database is open */
120 sqlite3_int64 now; /* Seconds since 1970 */
121 int repositoryOpen; /* True if the main repository database is open */
122 char *zRepositoryName; /* Name of the repository database */
123 const char *zMainDbType;/* "configdb", "localdb", or "repository" */
124 const char *zConfigDbType; /* "configdb", "localdb", or "repository" */
125 const char *zHome; /* Name of user home directory */
126 int localOpen; /* True if the local database is open */
127 char *zLocalRoot; /* The directory holding the local database */
128 int minPrefix; /* Number of digits needed for a distinct UUID */
129 int fSqlTrace; /* True if --sqltrace flag is present */
130 int fSqlStats; /* True if --sqltrace or --sqlstats are present */
@@ -172,14 +171,15 @@
172 char *urlPasswd; /* Password for http: */
173 char *urlCanonical; /* Canonical representation of the URL */
174 char *urlProxyAuth; /* Proxy-Authorizer: string */
175 char *urlFossil; /* The fossil query parameter on ssh: */
176 char *urlShell; /* The shell query parameter on ssh: */
177 int dontKeepUrl; /* Do not persist the URL */
178
179 const char *zLogin; /* Login name. "" if not logged in. */
180 const char *zSSLIdentity; /* Value of --ssl-identity option, filename of SSL client identity */
 
181 int useLocalauth; /* No login required if from 127.0.0.1 */
182 int noPswd; /* Logged in without password (on 127.0.0.1) */
183 int userUid; /* Integer user id */
184
185 /* Information used to populate the RCVFROM table */
@@ -223,11 +223,12 @@
223 reported. In JSON mode we try to
224 always output JSON-form error
225 responses and always exit() with
226 code 0 to avoid an HTTP 500 error.
227 */
228 int resultCode; /* used for passing back specific codes from /json callbacks. */
 
229 int errorDetailParanoia; /* 0=full error codes, 1=%10, 2=%100, 3=%1000 */
230 cson_output_opt outOpt; /* formatting options for JSON mode. */
231 cson_value * authToken; /* authentication token */
232 char const * jsonp; /* Name of JSONP function wrapper. */
233 unsigned char dispatchDepth /* Tells JSON command dispatching
@@ -252,14 +253,11 @@
252 } cmd;
253 struct { /* JSON POST data. */
254 cson_value * v;
255 cson_object * o;
256 } post;
257 struct { /* GET/COOKIE params in JSON mode.
258 FIXME (stephan): verify that this is
259 still used and remove if it is not.
260 */
261 cson_value * v;
262 cson_object * o;
263 } param;
264 struct {
265 cson_value * v;
@@ -335,11 +333,11 @@
335
336 /*
337 ** atexit() handler which frees up "some" of the resources
338 ** used by fossil.
339 */
340 void fossil_atexit(void) {
341 #ifdef FOSSIL_ENABLE_JSON
342 cson_value_free(g.json.gc.v);
343 memset(&g.json, 0, sizeof(g.json));
344 #endif
345 free(g.zErrMsg);
@@ -368,11 +366,11 @@
368 char *z; /* General use string pointer */
369 char **newArgv; /* New expanded g.argv under construction */
370 char const * zFileName; /* input file name */
371 FILE * zInFile; /* input FILE */
372 #if defined(_WIN32)
373 WCHAR buf[MAX_PATH];
374 #endif
375
376 g.argc = argc;
377 g.argv = argv;
378 sqlite3_initialize();
@@ -456,10 +454,49 @@
456 }
457 return zNewArgv;
458 }
459 #endif
460
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
461
462 /*
463 ** This procedure runs first.
464 */
465 #if defined(_WIN32) && !defined(BROKEN_MINGW_CMDLINE)
@@ -563,263 +600,21 @@
563 fossil_exit(0);
564 /*NOT_REACHED*/
565 return 0;
566 }
567
568 /*
569 ** The following variable becomes true while processing a fatal error
570 ** or a panic. If additional "recursive-fatal" errors occur while
571 ** shutting down, the recursive errors are silently ignored.
572 */
573 static int mainInFatalError = 0;
574
575 /*
576 ** Exit. Take care to close the database first.
577 */
578 NORETURN void fossil_exit(int rc){
579 db_close(1);
580 exit(rc);
581 }
582
583 /*
584 ** Print an error message, rollback all databases, and quit. These
585 ** routines never return.
586 */
587 NORETURN void fossil_panic(const char *zFormat, ...){
588 char *z;
589 va_list ap;
590 int rc = 1;
591 static int once = 1;
592 mainInFatalError = 1;
593 va_start(ap, zFormat);
594 z = vmprintf(zFormat, ap);
595 va_end(ap);
596 #ifdef FOSSIL_ENABLE_JSON
597 if( g.json.isJsonMode ){
598 json_err( 0, z, 1 );
599 if( g.isHTTP ){
600 rc = 0 /* avoid HTTP 500 */;
601 }
602 }
603 else
604 #endif
605 {
606 if( g.cgiOutput && once ){
607 once = 0;
608 cgi_printf("<p class=\"generalError\">%h</p>", z);
609 cgi_reply();
610 }else if( !g.fQuiet ){
611 fossil_trace("%s: %s\n", g.argv[0], z);
612 }
613 }
614 free(z);
615 db_force_rollback();
616 fossil_exit(rc);
617 }
618
619 NORETURN void fossil_fatal(const char *zFormat, ...){
620 char *z;
621 int rc = 1;
622 va_list ap;
623 mainInFatalError = 1;
624 va_start(ap, zFormat);
625 z = vmprintf(zFormat, ap);
626 va_end(ap);
627 #ifdef FOSSIL_ENABLE_JSON
628 if( g.json.isJsonMode ){
629 json_err( g.json.resultCode, z, 1 );
630 if( g.isHTTP ){
631 rc = 0 /* avoid HTTP 500 */;
632 }
633 }
634 else
635 #endif
636 {
637 if( g.cgiOutput ){
638 g.cgiOutput = 0;
639 cgi_printf("<p class=\"generalError\">\n%h\n</p>\n", z);
640 cgi_reply();
641 }else if( !g.fQuiet ){
642 fossil_trace("%s: %s\n", g.argv[0], z);
643 }
644 }
645 free(z);
646 db_force_rollback();
647 fossil_exit(rc);
648 }
649
650 /* This routine works like fossil_fatal() except that if called
651 ** recursively, the recursive call is a no-op.
652 **
653 ** Use this in places where an error might occur while doing
654 ** fatal error shutdown processing. Unlike fossil_panic() and
655 ** fossil_fatal() which never return, this routine might return if
656 ** the fatal error handing is already in process. The caller must
657 ** be prepared for this routine to return.
658 */
659 void fossil_fatal_recursive(const char *zFormat, ...){
660 char *z;
661 va_list ap;
662 int rc = 1;
663 if( mainInFatalError ) return;
664 mainInFatalError = 1;
665 va_start(ap, zFormat);
666 z = vmprintf(zFormat, ap);
667 va_end(ap);
668 #ifdef FOSSIL_ENABLE_JSON
669 if( g.json.isJsonMode ){
670 json_err( g.json.resultCode, z, 1 );
671 if( g.isHTTP ){
672 rc = 0 /* avoid HTTP 500 */;
673 }
674 } else
675 #endif
676 {
677 if( g.cgiOutput ){
678 g.cgiOutput = 0;
679 cgi_printf("<p class=\"generalError\">\n%h\n</p>\n", z);
680 cgi_reply();
681 }else{
682 fossil_trace("%s: %s\n", g.argv[0], z);
683 }
684 }
685 db_force_rollback();
686 fossil_exit(rc);
687 }
688
689
690 /* Print a warning message */
691 void fossil_warning(const char *zFormat, ...){
692 char *z;
693 va_list ap;
694 va_start(ap, zFormat);
695 z = vmprintf(zFormat, ap);
696 va_end(ap);
697 #ifdef FOSSIL_ENABLE_JSON
698 if(g.json.isJsonMode){
699 json_warn( FSL_JSON_W_UNKNOWN, z );
700 }else
701 #endif
702 {
703 if( g.cgiOutput ){
704 cgi_printf("<p class=\"generalError\">\n%h\n</p>\n", z);
705 }else{
706 fossil_trace("%s: %s\n", g.argv[0], z);
707 }
708 }
709 free(z);
710 }
711
712 /*
713 ** Malloc and free routines that cannot fail
714 */
715 void *fossil_malloc(size_t n){
716 void *p = malloc(n==0 ? 1 : n);
717 if( p==0 ) fossil_panic("out of memory");
718 return p;
719 }
720 void fossil_free(void *p){
721 free(p);
722 }
723 void *fossil_realloc(void *p, size_t n){
724 p = realloc(p, n);
725 if( p==0 ) fossil_panic("out of memory");
726 return p;
727 }
728
729 /*
730 ** This function implements a cross-platform "system()" interface.
731 */
732 int fossil_system(const char *zOrigCmd){
733 int rc;
734 #if defined(_WIN32)
735 /* On windows, we have to put double-quotes around the entire command.
736 ** Who knows why - this is just the way windows works.
737 */
738 char *zNewCmd = mprintf("\"%s\"", zOrigCmd);
739 WCHAR *zUnicode = fossil_utf8_to_unicode(zNewCmd);
740 if( g.fSystemTrace ) {
741 fossil_trace("SYSTEM: %s\n", zNewCmd);
742 }
743 rc = _wsystem(zUnicode);
744 fossil_unicode_free(zUnicode);
745 free(zNewCmd);
746 #else
747 /* On unix, evaluate the command directly.
748 */
749 if( g.fSystemTrace ) fprintf(stderr, "SYSTEM: %s\n", zOrigCmd);
750 rc = system(zOrigCmd);
751 #endif
752 return rc;
753 }
754
755 /*
756 ** Turn off any NL to CRNL translation on the stream given as an
757 ** argument. This is a no-op on unix but is necessary on windows.
758 */
759 void fossil_binary_mode(FILE *p){
760 #if defined(_WIN32)
761 _setmode(_fileno(p), _O_BINARY);
762 #endif
763 #ifdef __EMX__ /* OS/2 */
764 setmode(fileno(p), O_BINARY);
765 #endif
766 }
767
768
769
770 /*
771 ** Return a name for an SQLite error code
772 */
773 static const char *sqlite_error_code_name(int iCode){
774 static char zCode[30];
775 switch( iCode & 0xff ){
776 case SQLITE_OK: return "SQLITE_OK";
777 case SQLITE_ERROR: return "SQLITE_ERROR";
778 case SQLITE_PERM: return "SQLITE_PERM";
779 case SQLITE_ABORT: return "SQLITE_ABORT";
780 case SQLITE_BUSY: return "SQLITE_BUSY";
781 case SQLITE_NOMEM: return "SQLITE_NOMEM";
782 case SQLITE_READONLY: return "SQLITE_READONLY";
783 case SQLITE_INTERRUPT: return "SQLITE_INTERRUPT";
784 case SQLITE_IOERR: return "SQLITE_IOERR";
785 case SQLITE_CORRUPT: return "SQLITE_CORRUPT";
786 case SQLITE_FULL: return "SQLITE_FULL";
787 case SQLITE_CANTOPEN: return "SQLITE_CANTOPEN";
788 case SQLITE_PROTOCOL: return "SQLITE_PROTOCOL";
789 case SQLITE_EMPTY: return "SQLITE_EMPTY";
790 case SQLITE_SCHEMA: return "SQLITE_SCHEMA";
791 case SQLITE_CONSTRAINT: return "SQLITE_CONSTRAINT";
792 case SQLITE_MISMATCH: return "SQLITE_MISMATCH";
793 case SQLITE_MISUSE: return "SQLITE_MISUSE";
794 case SQLITE_NOLFS: return "SQLITE_NOLFS";
795 case SQLITE_FORMAT: return "SQLITE_FORMAT";
796 case SQLITE_RANGE: return "SQLITE_RANGE";
797 case SQLITE_NOTADB: return "SQLITE_NOTADB";
798 default: {
799 sqlite3_snprintf(sizeof(zCode),zCode,"error code %d",iCode);
800 }
801 }
802 return zCode;
803 }
804
805 /* Error logs from SQLite */
806 void fossil_sqlite_log(void *notUsed, int iCode, const char *zErrmsg){
807 fossil_warning("%s: %s", sqlite_error_code_name(iCode), zErrmsg);
808 }
809
810 /*
811 ** Print a usage comment and quit
812 */
813 void usage(const char *zFormat){
814 fossil_fatal("Usage: %s %s %s\n", g.argv[0], g.argv[1], zFormat);
815 }
816
817 /*
818 ** Remove n elements from g.argv beginning with the i-th element.
819 */
820 void remove_from_argv(int i, int n){
821 int j;
822 for(j=i+n; j<g.argc; i++, j++){
823 g.argv[i] = g.argv[j];
824 }
825 g.argc = i;
@@ -840,11 +635,11 @@
840 const char *zReturn = 0;
841 assert( hasArg==0 || hasArg==1 );
842 nLong = strlen(zLong);
843 for(i=1; i<g.argc; i++){
844 char *z;
845 if (i+hasArg >= g.argc) break;
846 z = g.argv[i];
847 if( z[0]!='-' ) continue;
848 z++;
849 if( z[0]=='-' ){
850 if( z[1]==0 ){
@@ -934,14 +729,17 @@
934 **
935 ** List all web pages
936 */
937 void cmd_test_webpage_list(void){
938 int i, nCmd;
939 const char *aCmd[count(aWebpage)];
940 for(i=nCmd=0; i<count(aWebpage); i++){
941 aCmd[nCmd++] = aWebpage[i].zName;
 
 
942 }
 
943 multi_column_list(aCmd, nCmd);
944 }
945
946 /*
947 ** COMMAND: version
@@ -967,14 +765,17 @@
967 **
968 ** %fossil help Show common commands
969 ** %fossil help --all Show both common and auxiliary commands
970 ** %fossil help --test Show test commands only
971 ** %fossil help --aux Show auxiliary commands only
 
972 */
973 void help_cmd(void){
974 int rc, idx;
975 const char *z;
 
 
976 if( g.argc<3 ){
977 z = g.argv[0];
978 fossil_print(
979 "Usage: %s help COMMAND\n"
980 "Common COMMANDs: (use \"%s help --all\" for a complete list)\n",
@@ -985,33 +786,46 @@
985 }
986 if( find_option("all",0,0) ){
987 command_list(0, CMDFLAG_1ST_TIER | CMDFLAG_2ND_TIER);
988 return;
989 }
990 if( find_option("aux",0,0) ){
 
 
 
 
991 command_list(0, CMDFLAG_2ND_TIER);
992 return;
993 }
994 if( find_option("test",0,0) ){
995 command_list(0, CMDFLAG_TEST);
996 return;
 
 
 
 
 
 
 
 
997 }
998 rc = name_search(g.argv[2], aCommand, count(aCommand), &idx);
999 if( rc==1 ){
1000 fossil_print("unknown command: %s\nAvailable commands:\n", g.argv[2]);
1001 command_list(0, 0xff);
 
1002 fossil_exit(1);
1003 }else if( rc==2 ){
1004 fossil_print("ambiguous command prefix: %s\nMatching commands:\n",
1005 g.argv[2]);
1006 command_list(g.argv[2], 0xff);
1007 fossil_exit(1);
1008 }
1009 z = aCmdHelp[idx];
1010 if( z==0 ){
1011 fossil_fatal("no help available for the %s command",
1012 aCommand[idx].zName);
1013 }
1014 while( *z ){
1015 if( *z=='%' && strncmp(z, "%fossil", 7)==0 ){
1016 fossil_print("%s", g.argv[0]);
1017 z += 7;
@@ -1033,20 +847,20 @@
1033 if( zCmd==0 ) zCmd = P("name");
1034 style_header("Command-line Help");
1035 if( zCmd ){
1036 int rc, idx;
1037 char *z, *s, *d;
1038
1039 style_submenu_element("Command-List", "Command-List", "%s/help", g.zTop);
1040 @ <h1>The "%s(zCmd)" command:</h1>
1041 rc = name_search(zCmd, aCommand, count(aCommand), &idx);
1042 if( rc==1 ){
1043 @ unknown command: %s(zCmd)
1044 }else if( rc==2 ){
1045 @ ambiguous command prefix: %s(zCmd)
1046 }else{
1047 z = (char*)aCmdHelp[idx];
1048 if( z==0 ){
1049 @ no help available for the %s(aCommand[idx].zName) command
1050 }else{
1051 z=s=d=mprintf("%s",z);
1052 while( *s ){
@@ -1068,21 +882,52 @@
1068
1069 @ <h1>Available commands:</h1>
1070 @ <table border="0"><tr>
1071 for(i=j=0; i<count(aCommand); i++){
1072 const char *z = aCommand[i].zName;
1073 if( strncmp(z,"test",4)==0 ) continue;
1074 j++;
1075 }
1076 n = (j+6)/7;
1077 for(i=j=0; i<count(aCommand); i++){
1078 const char *z = aCommand[i].zName;
1079 if( strncmp(z,"test",4)==0 ) continue;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1080 if( j==0 ){
1081 @ <td valign="top"><ul>
1082 }
1083 @ <li><a href="%s(g.zTop)/help?cmd=%s(z)">%s(z)</a>
 
 
 
 
1084 j++;
1085 if( j>=n ){
1086 @ </ul></td>
1087 j = 0;
1088 }
@@ -1089,10 +934,11 @@
1089 }
1090 if( j>0 ){
1091 @ </ul></td>
1092 }
1093 @ </tr></table>
 
1094 }
1095 style_footer();
1096 }
1097
1098 /*
@@ -1105,11 +951,11 @@
1105 style_header("Testpage: All Help Text");
1106 for(i=0; i<count(aCommand); i++){
1107 if( memcmp(aCommand[i].zName, "test", 4)==0 ) continue;
1108 @ <h2>%s(aCommand[i].zName):</h2>
1109 @ <blockquote><pre>
1110 @ %h(aCmdHelp[i])
1111 @ </pre></blockquote>
1112 }
1113 style_footer();
1114 }
1115
@@ -1285,11 +1131,11 @@
1285 zRepo = zToFree = mprintf("%s%.*s.fossil",g.zRepositoryName,i,zPathInfo);
1286
1287 /* To avoid mischief, make sure the repository basename contains no
1288 ** characters other than alphanumerics, "/", "_", "-", and ".", and
1289 ** that "-" never occurs immediately after a "/" and that "." is always
1290 ** surrounded by two alphanumerics. Any character that does not
1291 ** satisfy these constraints is converted into "_".
1292 */
1293 szFile = 0;
1294 for(j=strlen(g.zRepositoryName)+1, k=0; zRepo[j] && k<i-1; j++, k++){
1295 char c = zRepo[j];
@@ -1504,10 +1350,61 @@
1504
1505 /* Return the result.
1506 */
1507 cgi_reply();
1508 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1509
1510 /*
1511 ** COMMAND: cgi*
1512 **
1513 ** Usage: %fossil ?cgi? SCRIPT
@@ -1604,61 +1501,10 @@
1604 }else{
1605 process_one_web_page(zNotFound, pFileGlob);
1606 }
1607 }
1608
1609 /* If the CGI program contains one or more lines of the form
1610 **
1611 ** redirect: repository-filename http://hostname/path/%s
1612 **
1613 ** then control jumps here. Search each repository for an artifact ID
1614 ** that matches the "name" CGI parameter and for the first match,
1615 ** redirect to the corresponding URL with the "name" CGI parameter
1616 ** inserted. Paint an error page if no match is found.
1617 **
1618 ** If there is a line of the form:
1619 **
1620 ** redirect: * URL
1621 **
1622 ** Then a redirect is made to URL if no match is found. Otherwise a
1623 ** very primitive error message is returned.
1624 */
1625 void redirect_web_page(int nRedirect, char **azRedirect){
1626 int i; /* Loop counter */
1627 const char *zNotFound = 0; /* Not found URL */
1628 const char *zName = P("name");
1629 set_base_url(0);
1630 if( zName==0 ){
1631 zName = P("SCRIPT_NAME");
1632 if( zName && zName[0]=='/' ) zName++;
1633 }
1634 if( zName && validate16(zName, strlen(zName)) ){
1635 for(i=0; i<nRedirect; i++){
1636 if( fossil_strcmp(azRedirect[i*2],"*")==0 ){
1637 zNotFound = azRedirect[i*2+1];
1638 continue;
1639 }
1640 db_open_repository(azRedirect[i*2]);
1641 if( db_exists("SELECT 1 FROM blob WHERE uuid GLOB '%s*'", zName) ){
1642 cgi_redirectf(azRedirect[i*2+1], zName);
1643 return;
1644 }
1645 db_close(1);
1646 }
1647 }
1648 if( zNotFound ){
1649 cgi_redirectf(zNotFound, zName);
1650 }else{
1651 @ <html>
1652 @ <head><title>No Such Object</title></head>
1653 @ <body>
1654 @ <p>No such object: <b>%h(zName)</b></p>
1655 @ </body>
1656 cgi_reply();
1657 }
1658 }
1659
1660 /*
1661 ** If g.argv[2] exists then it is either the name of a repository
1662 ** that will be used by a server, or else it is a directory that
1663 ** contains multiple repositories that can be served. If g.argv[2]
1664 ** is a directory, the repositories it contains must be named
@@ -1745,11 +1591,11 @@
1745 const char *zHost;
1746 const char *zAltBase;
1747 const char *zFileGlob;
1748
1749 /* The winhttp module passes the --files option as --files-urlenc with
1750 ** the argument being URL encoded, to avoid wildcard expansion in the
1751 ** shell. This option is for internal use and is undocumented.
1752 */
1753 zFileGlob = find_option("files-urlenc",0,1);
1754 if( zFileGlob ){
1755 char *z = mprintf("%s", zFileGlob);
@@ -1849,12 +1695,12 @@
1849 **
1850 ** The "ui" command automatically starts a web browser after initializing
1851 ** the web server. The "ui" command also binds to 127.0.0.1 and so will
1852 ** only process HTTP traffic from the local machine.
1853 **
1854 ** The REPOSITORY can be a directory (aka folder) that contains one or
1855 ** more repositories with names ending in ".fossil". In this case, the
1856 ** a prefix of the URL pathname is used to search the directory for an
1857 ** appropriate repository. To thwart mischief, the pathname in the URL must
1858 ** contain only alphanumerics, "_", "/", "-", and ".", and no "-" may
1859 ** occur after "/", and every "." must be surrounded on both sides by
1860 ** alphanumerics. Any pathname that does not satisfy these constraints
@@ -1891,10 +1737,11 @@
1891 int isUiCmd; /* True if command is "ui", not "server' */
1892 const char *zNotFound; /* The --notfound option or NULL */
1893 int flags = 0; /* Server flags */
1894 const char *zAltBase; /* Argument to the --baseurl option */
1895 const char *zFileGlob; /* Static content must match this */
 
1896
1897 #if defined(_WIN32)
1898 const char *zStopperFile; /* Name of file used to terminate server */
1899 zStopperFile = find_option("stopper", 0, 1);
1900 #endif
@@ -1917,10 +1764,16 @@
1917 flags |= HTTP_SERVER_LOCALHOST;
1918 g.useLocalauth = 1;
1919 }
1920 find_server_repository(isUiCmd && zNotFound==0);
1921 if( zPort ){
 
 
 
 
 
 
1922 iPort = mxPort = atoi(zPort);
1923 }else{
1924 iPort = db_get_int("http-port", 8080);
1925 mxPort = iPort+100;
1926 }
@@ -1928,11 +1781,12 @@
1928 /* Unix implementation */
1929 if( isUiCmd ){
1930 #if !defined(__DARWIN__) && !defined(__APPLE__) && !defined(__HAIKU__)
1931 zBrowser = db_get("web-browser", 0);
1932 if( zBrowser==0 ){
1933 static const char *const azBrowserProg[] = { "xdg-open", "gnome-open", "firefox" };
 
1934 int i;
1935 zBrowser = "echo";
1936 for(i=0; i<sizeof(azBrowserProg)/sizeof(azBrowserProg[0]); i++){
1937 if( binaryOnPath(azBrowserProg[i]) ){
1938 zBrowser = azBrowserProg[i];
@@ -1941,14 +1795,18 @@
1941 }
1942 }
1943 #else
1944 zBrowser = db_get("web-browser", "open");
1945 #endif
1946 zBrowserCmd = mprintf("%s http://localhost:%%d/ &", zBrowser);
 
 
 
 
1947 }
1948 db_close(1);
1949 if( cgi_http_server(iPort, mxPort, zBrowserCmd, flags) ){
1950 fossil_fatal("unable to listen on TCP socket %d", iPort);
1951 }
1952 g.sslNotAvailable = 1;
1953 g.httpIn = stdin;
1954 g.httpOut = stdout;
@@ -1962,16 +1820,20 @@
1962 process_one_web_page(zNotFound, glob_create(zFileGlob));
1963 #else
1964 /* Win32 implementation */
1965 if( isUiCmd ){
1966 zBrowser = db_get("web-browser", "start");
1967 zBrowserCmd = mprintf("%s http://127.0.0.1:%%d/", zBrowser);
 
 
 
 
1968 }
1969 db_close(1);
1970 if( win32_http_service(iPort, zNotFound, zFileGlob, flags) ){
1971 win32_http_server(iPort, mxPort, zBrowserCmd,
1972 zStopperFile, zNotFound, zFileGlob, flags);
1973 }
1974 #endif
1975 }
1976
1977 /*
1978
--- src/main.c
+++ src/main.c
@@ -31,11 +31,11 @@
31 #else
32 # include <errno.h> /* errno global */
33 #endif
34 #if INTERFACE
35 #ifdef FOSSIL_ENABLE_JSON
36 # include "cson_amalgamation.h" /* JSON API. */
37 # include "json_detail.h"
38 #endif
39 #ifdef FOSSIL_ENABLE_TCL
40 #include "tcl.h"
41 #endif
@@ -114,17 +114,16 @@
114 char *nameOfExe; /* Full path of executable. */
115 int isConst; /* True if the output is unchanging */
116 sqlite3 *db; /* The connection to the databases */
117 sqlite3 *dbConfig; /* Separate connection for global_config table */
118 int useAttach; /* True if global_config is attached to repository */
119 const char *zConfigDbName;/* Path of the config database. NULL if not open */
120 sqlite3_int64 now; /* Seconds since 1970 */
121 int repositoryOpen; /* True if the main repository database is open */
122 char *zRepositoryName; /* Name of the repository database */
123 const char *zMainDbType;/* "configdb", "localdb", or "repository" */
124 const char *zConfigDbType; /* "configdb", "localdb", or "repository" */
 
125 int localOpen; /* True if the local database is open */
126 char *zLocalRoot; /* The directory holding the local database */
127 int minPrefix; /* Number of digits needed for a distinct UUID */
128 int fSqlTrace; /* True if --sqltrace flag is present */
129 int fSqlStats; /* True if --sqltrace or --sqlstats are present */
@@ -172,14 +171,15 @@
171 char *urlPasswd; /* Password for http: */
172 char *urlCanonical; /* Canonical representation of the URL */
173 char *urlProxyAuth; /* Proxy-Authorizer: string */
174 char *urlFossil; /* The fossil query parameter on ssh: */
175 char *urlShell; /* The shell query parameter on ssh: */
176 unsigned urlFlags; /* Boolean flags controlling URL processing */
177
178 const char *zLogin; /* Login name. "" if not logged in. */
179 const char *zSSLIdentity; /* Value of --ssl-identity option, filename of
180 ** SSL client identity */
181 int useLocalauth; /* No login required if from 127.0.0.1 */
182 int noPswd; /* Logged in without password (on 127.0.0.1) */
183 int userUid; /* Integer user id */
184
185 /* Information used to populate the RCVFROM table */
@@ -223,11 +223,12 @@
223 reported. In JSON mode we try to
224 always output JSON-form error
225 responses and always exit() with
226 code 0 to avoid an HTTP 500 error.
227 */
228 int resultCode; /* used for passing back specific codes
229 ** from /json callbacks. */
230 int errorDetailParanoia; /* 0=full error codes, 1=%10, 2=%100, 3=%1000 */
231 cson_output_opt outOpt; /* formatting options for JSON mode. */
232 cson_value * authToken; /* authentication token */
233 char const * jsonp; /* Name of JSONP function wrapper. */
234 unsigned char dispatchDepth /* Tells JSON command dispatching
@@ -252,14 +253,11 @@
253 } cmd;
254 struct { /* JSON POST data. */
255 cson_value * v;
256 cson_object * o;
257 } post;
258 struct { /* GET/COOKIE params in JSON mode. */
 
 
 
259 cson_value * v;
260 cson_object * o;
261 } param;
262 struct {
263 cson_value * v;
@@ -335,11 +333,11 @@
333
334 /*
335 ** atexit() handler which frees up "some" of the resources
336 ** used by fossil.
337 */
338 static void fossil_atexit(void) {
339 #ifdef FOSSIL_ENABLE_JSON
340 cson_value_free(g.json.gc.v);
341 memset(&g.json, 0, sizeof(g.json));
342 #endif
343 free(g.zErrMsg);
@@ -368,11 +366,11 @@
366 char *z; /* General use string pointer */
367 char **newArgv; /* New expanded g.argv under construction */
368 char const * zFileName; /* input file name */
369 FILE * zInFile; /* input FILE */
370 #if defined(_WIN32)
371 wchar_t buf[MAX_PATH];
372 #endif
373
374 g.argc = argc;
375 g.argv = argv;
376 sqlite3_initialize();
@@ -456,10 +454,49 @@
454 }
455 return zNewArgv;
456 }
457 #endif
458
459 /*
460 ** Return a name for an SQLite error code
461 */
462 static const char *sqlite_error_code_name(int iCode){
463 static char zCode[30];
464 switch( iCode & 0xff ){
465 case SQLITE_OK: return "SQLITE_OK";
466 case SQLITE_ERROR: return "SQLITE_ERROR";
467 case SQLITE_PERM: return "SQLITE_PERM";
468 case SQLITE_ABORT: return "SQLITE_ABORT";
469 case SQLITE_BUSY: return "SQLITE_BUSY";
470 case SQLITE_NOMEM: return "SQLITE_NOMEM";
471 case SQLITE_READONLY: return "SQLITE_READONLY";
472 case SQLITE_INTERRUPT: return "SQLITE_INTERRUPT";
473 case SQLITE_IOERR: return "SQLITE_IOERR";
474 case SQLITE_CORRUPT: return "SQLITE_CORRUPT";
475 case SQLITE_FULL: return "SQLITE_FULL";
476 case SQLITE_CANTOPEN: return "SQLITE_CANTOPEN";
477 case SQLITE_PROTOCOL: return "SQLITE_PROTOCOL";
478 case SQLITE_EMPTY: return "SQLITE_EMPTY";
479 case SQLITE_SCHEMA: return "SQLITE_SCHEMA";
480 case SQLITE_CONSTRAINT: return "SQLITE_CONSTRAINT";
481 case SQLITE_MISMATCH: return "SQLITE_MISMATCH";
482 case SQLITE_MISUSE: return "SQLITE_MISUSE";
483 case SQLITE_NOLFS: return "SQLITE_NOLFS";
484 case SQLITE_FORMAT: return "SQLITE_FORMAT";
485 case SQLITE_RANGE: return "SQLITE_RANGE";
486 case SQLITE_NOTADB: return "SQLITE_NOTADB";
487 default: {
488 sqlite3_snprintf(sizeof(zCode),zCode,"error code %d",iCode);
489 }
490 }
491 return zCode;
492 }
493
494 /* Error logs from SQLite */
495 static void fossil_sqlite_log(void *notUsed, int iCode, const char *zErrmsg){
496 fossil_warning("%s: %s", sqlite_error_code_name(iCode), zErrmsg);
497 }
498
499 /*
500 ** This procedure runs first.
501 */
502 #if defined(_WIN32) && !defined(BROKEN_MINGW_CMDLINE)
@@ -563,263 +600,21 @@
600 fossil_exit(0);
601 /*NOT_REACHED*/
602 return 0;
603 }
604
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
605 /*
606 ** Print a usage comment and quit
607 */
608 void usage(const char *zFormat){
609 fossil_fatal("Usage: %s %s %s", g.argv[0], g.argv[1], zFormat);
610 }
611
612 /*
613 ** Remove n elements from g.argv beginning with the i-th element.
614 */
615 static void remove_from_argv(int i, int n){
616 int j;
617 for(j=i+n; j<g.argc; i++, j++){
618 g.argv[i] = g.argv[j];
619 }
620 g.argc = i;
@@ -840,11 +635,11 @@
635 const char *zReturn = 0;
636 assert( hasArg==0 || hasArg==1 );
637 nLong = strlen(zLong);
638 for(i=1; i<g.argc; i++){
639 char *z;
640 if( i+hasArg >= g.argc ) break;
641 z = g.argv[i];
642 if( z[0]!='-' ) continue;
643 z++;
644 if( z[0]=='-' ){
645 if( z[1]==0 ){
@@ -934,14 +729,17 @@
729 **
730 ** List all web pages
731 */
732 void cmd_test_webpage_list(void){
733 int i, nCmd;
734 const char *aCmd[count(aCommand)];
735 for(i=nCmd=0; i<count(aCommand); i++){
736 if(0x08 & aCommand[i].cmdFlags){
737 aCmd[nCmd++] = aWebpage[i].zName;
738 }
739 }
740 assert(nCmd && "page list is empty?");
741 multi_column_list(aCmd, nCmd);
742 }
743
744 /*
745 ** COMMAND: version
@@ -967,14 +765,17 @@
765 **
766 ** %fossil help Show common commands
767 ** %fossil help --all Show both common and auxiliary commands
768 ** %fossil help --test Show test commands only
769 ** %fossil help --aux Show auxiliary commands only
770 ** %fossil help --www Show list of WWW pages
771 */
772 void help_cmd(void){
773 int rc, idx, isPage = 0;
774 const char *z;
775 char const * zCmdOrPage;
776 char const * zCmdOrPagePlural;
777 if( g.argc<3 ){
778 z = g.argv[0];
779 fossil_print(
780 "Usage: %s help COMMAND\n"
781 "Common COMMANDs: (use \"%s help --all\" for a complete list)\n",
@@ -985,33 +786,46 @@
786 }
787 if( find_option("all",0,0) ){
788 command_list(0, CMDFLAG_1ST_TIER | CMDFLAG_2ND_TIER);
789 return;
790 }
791 else if( find_option("www",0,0) ){
792 command_list(0, CMDFLAG_WEBPAGE);
793 return;
794 }
795 else if( find_option("aux",0,0) ){
796 command_list(0, CMDFLAG_2ND_TIER);
797 return;
798 }
799 else if( find_option("test",0,0) ){
800 command_list(0, CMDFLAG_TEST);
801 return;
802 }
803 isPage = ('/' == *g.argv[2]) ? 1 : 0;
804 if(isPage){
805 zCmdOrPage = "page";
806 zCmdOrPagePlural = "pages";
807 }else{
808 zCmdOrPage = "command";
809 zCmdOrPagePlural = "commands";
810 }
811 rc = name_search(g.argv[2], aCommand, count(aCommand), &idx);
812 if( rc==1 ){
813 fossil_print("unknown %s: %s\nAvailable %s:\n",
814 zCmdOrPage, g.argv[2], zCmdOrPagePlural);
815 command_list(0, isPage ? CMDFLAG_WEBPAGE : (0xff & ~CMDFLAG_WEBPAGE));
816 fossil_exit(1);
817 }else if( rc==2 ){
818 fossil_print("ambiguous %s prefix: %s\nMatching %s:\n",
819 zCmdOrPage, g.argv[2], zCmdOrPagePlural);
820 command_list(g.argv[2], 0xff);
821 fossil_exit(1);
822 }
823 z = aCmdHelp[idx].zText;
824 if( z==0 ){
825 fossil_fatal("no help available for the %s %s",
826 aCommand[idx].zName, zCmdOrPage);
827 }
828 while( *z ){
829 if( *z=='%' && strncmp(z, "%fossil", 7)==0 ){
830 fossil_print("%s", g.argv[0]);
831 z += 7;
@@ -1033,20 +847,20 @@
847 if( zCmd==0 ) zCmd = P("name");
848 style_header("Command-line Help");
849 if( zCmd ){
850 int rc, idx;
851 char *z, *s, *d;
852 char const * zCmdOrPage = ('/'==*zCmd) ? "page" : "command";
853 style_submenu_element("Command-List", "Command-List", "%s/help", g.zTop);
854 @ <h1>The "%s(zCmd)" %s(zCmdOrPage):</h1>
855 rc = name_search(zCmd, aCommand, count(aCommand), &idx);
856 if( rc==1 ){
857 @ unknown command: %s(zCmd)
858 }else if( rc==2 ){
859 @ ambiguous command prefix: %s(zCmd)
860 }else{
861 z = (char*)aCmdHelp[idx].zText;
862 if( z==0 ){
863 @ no help available for the %s(aCommand[idx].zName) command
864 }else{
865 z=s=d=mprintf("%s",z);
866 while( *s ){
@@ -1068,21 +882,52 @@
882
883 @ <h1>Available commands:</h1>
884 @ <table border="0"><tr>
885 for(i=j=0; i<count(aCommand); i++){
886 const char *z = aCommand[i].zName;
887 if( '/'==*z || strncmp(z,"test",4)==0 ) continue;
888 j++;
889 }
890 n = (j+6)/7;
891 for(i=j=0; i<count(aCommand); i++){
892 const char *z = aCommand[i].zName;
893 if( '/'==*z || strncmp(z,"test",4)==0 ) continue;
894 if( j==0 ){
895 @ <td valign="top"><ul>
896 }
897 @ <li><a href="%s(g.zTop)/help?cmd=%s(z)">%s(z)</a></li>
898 j++;
899 if( j>=n ){
900 @ </ul></td>
901 j = 0;
902 }
903 }
904 if( j>0 ){
905 @ </ul></td>
906 }
907 @ </tr></table>
908
909 @ <h1>Available pages:</h1>
910 @ (Only pages with help text are linked.)
911 @ <table border="0"><tr>
912 for(i=j=0; i<count(aCommand); i++){
913 const char *z = aCommand[i].zName;
914 if( '/'!=*z ) continue;
915 j++;
916 }
917 n = (j+4)/5;
918 for(i=j=0; i<count(aCommand); i++){
919 const char *z = aCommand[i].zName;
920 if( '/'!=*z ) continue;
921 if( j==0 ){
922 @ <td valign="top"><ul>
923 }
924 if( aCmdHelp[i].zText && *aCmdHelp[i].zText ){
925 @ <li><a href="%s(g.zTop)/help?cmd=%s(z)">%s(z+1)</a></li>
926 }else{
927 @ <li>%s(z+1)</li>
928 }
929 j++;
930 if( j>=n ){
931 @ </ul></td>
932 j = 0;
933 }
@@ -1089,10 +934,11 @@
934 }
935 if( j>0 ){
936 @ </ul></td>
937 }
938 @ </tr></table>
939
940 }
941 style_footer();
942 }
943
944 /*
@@ -1105,11 +951,11 @@
951 style_header("Testpage: All Help Text");
952 for(i=0; i<count(aCommand); i++){
953 if( memcmp(aCommand[i].zName, "test", 4)==0 ) continue;
954 @ <h2>%s(aCommand[i].zName):</h2>
955 @ <blockquote><pre>
956 @ %h(aCmdHelp[i].zText)
957 @ </pre></blockquote>
958 }
959 style_footer();
960 }
961
@@ -1285,11 +1131,11 @@
1131 zRepo = zToFree = mprintf("%s%.*s.fossil",g.zRepositoryName,i,zPathInfo);
1132
1133 /* To avoid mischief, make sure the repository basename contains no
1134 ** characters other than alphanumerics, "/", "_", "-", and ".", and
1135 ** that "-" never occurs immediately after a "/" and that "." is always
1136 ** surrounded by two alphanumerics. Any character that does not
1137 ** satisfy these constraints is converted into "_".
1138 */
1139 szFile = 0;
1140 for(j=strlen(g.zRepositoryName)+1, k=0; zRepo[j] && k<i-1; j++, k++){
1141 char c = zRepo[j];
@@ -1504,10 +1350,61 @@
1350
1351 /* Return the result.
1352 */
1353 cgi_reply();
1354 }
1355
1356 /* If the CGI program contains one or more lines of the form
1357 **
1358 ** redirect: repository-filename http://hostname/path/%s
1359 **
1360 ** then control jumps here. Search each repository for an artifact ID
1361 ** that matches the "name" CGI parameter and for the first match,
1362 ** redirect to the corresponding URL with the "name" CGI parameter
1363 ** inserted. Paint an error page if no match is found.
1364 **
1365 ** If there is a line of the form:
1366 **
1367 ** redirect: * URL
1368 **
1369 ** Then a redirect is made to URL if no match is found. Otherwise a
1370 ** very primitive error message is returned.
1371 */
1372 static void redirect_web_page(int nRedirect, char **azRedirect){
1373 int i; /* Loop counter */
1374 const char *zNotFound = 0; /* Not found URL */
1375 const char *zName = P("name");
1376 set_base_url(0);
1377 if( zName==0 ){
1378 zName = P("SCRIPT_NAME");
1379 if( zName && zName[0]=='/' ) zName++;
1380 }
1381 if( zName && validate16(zName, strlen(zName)) ){
1382 for(i=0; i<nRedirect; i++){
1383 if( fossil_strcmp(azRedirect[i*2],"*")==0 ){
1384 zNotFound = azRedirect[i*2+1];
1385 continue;
1386 }
1387 db_open_repository(azRedirect[i*2]);
1388 if( db_exists("SELECT 1 FROM blob WHERE uuid GLOB '%s*'", zName) ){
1389 cgi_redirectf(azRedirect[i*2+1], zName);
1390 return;
1391 }
1392 db_close(1);
1393 }
1394 }
1395 if( zNotFound ){
1396 cgi_redirectf(zNotFound, zName);
1397 }else{
1398 @ <html>
1399 @ <head><title>No Such Object</title></head>
1400 @ <body>
1401 @ <p>No such object: <b>%h(zName)</b></p>
1402 @ </body>
1403 cgi_reply();
1404 }
1405 }
1406
1407 /*
1408 ** COMMAND: cgi*
1409 **
1410 ** Usage: %fossil ?cgi? SCRIPT
@@ -1604,61 +1501,10 @@
1501 }else{
1502 process_one_web_page(zNotFound, pFileGlob);
1503 }
1504 }
1505
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1506 /*
1507 ** If g.argv[2] exists then it is either the name of a repository
1508 ** that will be used by a server, or else it is a directory that
1509 ** contains multiple repositories that can be served. If g.argv[2]
1510 ** is a directory, the repositories it contains must be named
@@ -1745,11 +1591,11 @@
1591 const char *zHost;
1592 const char *zAltBase;
1593 const char *zFileGlob;
1594
1595 /* The winhttp module passes the --files option as --files-urlenc with
1596 ** the argument being URL encoded, to avoid wildcard expansion in the
1597 ** shell. This option is for internal use and is undocumented.
1598 */
1599 zFileGlob = find_option("files-urlenc",0,1);
1600 if( zFileGlob ){
1601 char *z = mprintf("%s", zFileGlob);
@@ -1849,12 +1695,12 @@
1695 **
1696 ** The "ui" command automatically starts a web browser after initializing
1697 ** the web server. The "ui" command also binds to 127.0.0.1 and so will
1698 ** only process HTTP traffic from the local machine.
1699 **
1700 ** The REPOSITORY can be a directory (aka folder) that contains one or
1701 ** more repositories with names ending in ".fossil". In this case, the
1702 ** a prefix of the URL pathname is used to search the directory for an
1703 ** appropriate repository. To thwart mischief, the pathname in the URL must
1704 ** contain only alphanumerics, "_", "/", "-", and ".", and no "-" may
1705 ** occur after "/", and every "." must be surrounded on both sides by
1706 ** alphanumerics. Any pathname that does not satisfy these constraints
@@ -1891,10 +1737,11 @@
1737 int isUiCmd; /* True if command is "ui", not "server' */
1738 const char *zNotFound; /* The --notfound option or NULL */
1739 int flags = 0; /* Server flags */
1740 const char *zAltBase; /* Argument to the --baseurl option */
1741 const char *zFileGlob; /* Static content must match this */
1742 char *zIpAddr = 0; /* Bind to this IP address */
1743
1744 #if defined(_WIN32)
1745 const char *zStopperFile; /* Name of file used to terminate server */
1746 zStopperFile = find_option("stopper", 0, 1);
1747 #endif
@@ -1917,10 +1764,16 @@
1764 flags |= HTTP_SERVER_LOCALHOST;
1765 g.useLocalauth = 1;
1766 }
1767 find_server_repository(isUiCmd && zNotFound==0);
1768 if( zPort ){
1769 int i;
1770 for(i=strlen(zPort)-1; i>=0 && zPort[i]!=':'; i--){}
1771 if( i>0 ){
1772 zIpAddr = mprintf("%.*s", i, zPort);
1773 zPort += i+1;
1774 }
1775 iPort = mxPort = atoi(zPort);
1776 }else{
1777 iPort = db_get_int("http-port", 8080);
1778 mxPort = iPort+100;
1779 }
@@ -1928,11 +1781,12 @@
1781 /* Unix implementation */
1782 if( isUiCmd ){
1783 #if !defined(__DARWIN__) && !defined(__APPLE__) && !defined(__HAIKU__)
1784 zBrowser = db_get("web-browser", 0);
1785 if( zBrowser==0 ){
1786 static const char *const azBrowserProg[] =
1787 { "xdg-open", "gnome-open", "firefox", "google-chrome" };
1788 int i;
1789 zBrowser = "echo";
1790 for(i=0; i<sizeof(azBrowserProg)/sizeof(azBrowserProg[0]); i++){
1791 if( binaryOnPath(azBrowserProg[i]) ){
1792 zBrowser = azBrowserProg[i];
@@ -1941,14 +1795,18 @@
1795 }
1796 }
1797 #else
1798 zBrowser = db_get("web-browser", "open");
1799 #endif
1800 if( zIpAddr ){
1801 zBrowserCmd = mprintf("%s http://%s:%%d/ &", zBrowser, zIpAddr);
1802 }else{
1803 zBrowserCmd = mprintf("%s http://localhost:%%d/ &", zBrowser);
1804 }
1805 }
1806 db_close(1);
1807 if( cgi_http_server(iPort, mxPort, zBrowserCmd, zIpAddr, flags) ){
1808 fossil_fatal("unable to listen on TCP socket %d", iPort);
1809 }
1810 g.sslNotAvailable = 1;
1811 g.httpIn = stdin;
1812 g.httpOut = stdout;
@@ -1962,16 +1820,20 @@
1820 process_one_web_page(zNotFound, glob_create(zFileGlob));
1821 #else
1822 /* Win32 implementation */
1823 if( isUiCmd ){
1824 zBrowser = db_get("web-browser", "start");
1825 if( zIpAddr ){
1826 zBrowserCmd = mprintf("%s http://%s:%%d/ &", zBrowser, zIpAddr);
1827 }else{
1828 zBrowserCmd = mprintf("%s http://localhost:%%d/ &", zBrowser);
1829 }
1830 }
1831 db_close(1);
1832 if( win32_http_service(iPort, zNotFound, zFileGlob, flags) ){
1833 win32_http_server(iPort, mxPort, zBrowserCmd,
1834 zStopperFile, zNotFound, zFileGlob, zIpAddr, flags);
1835 }
1836 #endif
1837 }
1838
1839 /*
1840
+22 -2
--- src/main.mk
+++ src/main.mk
@@ -60,10 +60,11 @@
6060
$(SRCDIR)/json_dir.c \
6161
$(SRCDIR)/json_finfo.c \
6262
$(SRCDIR)/json_login.c \
6363
$(SRCDIR)/json_query.c \
6464
$(SRCDIR)/json_report.c \
65
+ $(SRCDIR)/json_status.c \
6566
$(SRCDIR)/json_tag.c \
6667
$(SRCDIR)/json_timeline.c \
6768
$(SRCDIR)/json_user.c \
6869
$(SRCDIR)/json_wiki.c \
6970
$(SRCDIR)/leaf.c \
@@ -107,10 +108,11 @@
107108
$(SRCDIR)/unicode.c \
108109
$(SRCDIR)/update.c \
109110
$(SRCDIR)/url.c \
110111
$(SRCDIR)/user.c \
111112
$(SRCDIR)/utf8.c \
113
+ $(SRCDIR)/util.c \
112114
$(SRCDIR)/verify.c \
113115
$(SRCDIR)/vfile.c \
114116
$(SRCDIR)/wiki.c \
115117
$(SRCDIR)/wikiformat.c \
116118
$(SRCDIR)/winhttp.c \
@@ -166,10 +168,11 @@
166168
$(OBJDIR)/json_dir_.c \
167169
$(OBJDIR)/json_finfo_.c \
168170
$(OBJDIR)/json_login_.c \
169171
$(OBJDIR)/json_query_.c \
170172
$(OBJDIR)/json_report_.c \
173
+ $(OBJDIR)/json_status_.c \
171174
$(OBJDIR)/json_tag_.c \
172175
$(OBJDIR)/json_timeline_.c \
173176
$(OBJDIR)/json_user_.c \
174177
$(OBJDIR)/json_wiki_.c \
175178
$(OBJDIR)/leaf_.c \
@@ -213,10 +216,11 @@
213216
$(OBJDIR)/unicode_.c \
214217
$(OBJDIR)/update_.c \
215218
$(OBJDIR)/url_.c \
216219
$(OBJDIR)/user_.c \
217220
$(OBJDIR)/utf8_.c \
221
+ $(OBJDIR)/util_.c \
218222
$(OBJDIR)/verify_.c \
219223
$(OBJDIR)/vfile_.c \
220224
$(OBJDIR)/wiki_.c \
221225
$(OBJDIR)/wikiformat_.c \
222226
$(OBJDIR)/winhttp_.c \
@@ -272,10 +276,11 @@
272276
$(OBJDIR)/json_dir.o \
273277
$(OBJDIR)/json_finfo.o \
274278
$(OBJDIR)/json_login.o \
275279
$(OBJDIR)/json_query.o \
276280
$(OBJDIR)/json_report.o \
281
+ $(OBJDIR)/json_status.o \
277282
$(OBJDIR)/json_tag.o \
278283
$(OBJDIR)/json_timeline.o \
279284
$(OBJDIR)/json_user.o \
280285
$(OBJDIR)/json_wiki.o \
281286
$(OBJDIR)/leaf.o \
@@ -319,10 +324,11 @@
319324
$(OBJDIR)/unicode.o \
320325
$(OBJDIR)/update.o \
321326
$(OBJDIR)/url.o \
322327
$(OBJDIR)/user.o \
323328
$(OBJDIR)/utf8.o \
329
+ $(OBJDIR)/util.o \
324330
$(OBJDIR)/verify.o \
325331
$(OBJDIR)/vfile.o \
326332
$(OBJDIR)/wiki.o \
327333
$(OBJDIR)/wikiformat.o \
328334
$(OBJDIR)/winhttp.o \
@@ -396,14 +402,14 @@
396402
397403
398404
$(OBJDIR)/page_index.h: $(TRANS_SRC) $(OBJDIR)/mkindex
399405
$(OBJDIR)/mkindex $(TRANS_SRC) >$@
400406
$(OBJDIR)/headers: $(OBJDIR)/page_index.h $(OBJDIR)/makeheaders $(OBJDIR)/VERSION.h
401
- $(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_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)/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
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
402408
touch $(OBJDIR)/headers
403409
$(OBJDIR)/headers: Makefile
404
-$(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_tag.o $(OBJDIR)/json_timeline.o $(OBJDIR)/json_user.o $(OBJDIR)/json_wiki.o : $(SRCDIR)/json_detail.h
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
405411
Makefile:
406412
$(OBJDIR)/add_.c: $(SRCDIR)/add.c $(OBJDIR)/translate
407413
$(OBJDIR)/translate $(SRCDIR)/add.c >$(OBJDIR)/add_.c
408414
409415
$(OBJDIR)/add.o: $(OBJDIR)/add_.c $(OBJDIR)/add.h $(SRCDIR)/config.h
@@ -737,10 +743,17 @@
737743
738744
$(OBJDIR)/json_report.o: $(OBJDIR)/json_report_.c $(OBJDIR)/json_report.h $(SRCDIR)/config.h
739745
$(XTCC) -o $(OBJDIR)/json_report.o -c $(OBJDIR)/json_report_.c
740746
741747
$(OBJDIR)/json_report.h: $(OBJDIR)/headers
748
+$(OBJDIR)/json_status_.c: $(SRCDIR)/json_status.c $(OBJDIR)/translate
749
+ $(OBJDIR)/translate $(SRCDIR)/json_status.c >$(OBJDIR)/json_status_.c
750
+
751
+$(OBJDIR)/json_status.o: $(OBJDIR)/json_status_.c $(OBJDIR)/json_status.h $(SRCDIR)/config.h
752
+ $(XTCC) -o $(OBJDIR)/json_status.o -c $(OBJDIR)/json_status_.c
753
+
754
+$(OBJDIR)/json_status.h: $(OBJDIR)/headers
742755
$(OBJDIR)/json_tag_.c: $(SRCDIR)/json_tag.c $(OBJDIR)/translate
743756
$(OBJDIR)/translate $(SRCDIR)/json_tag.c >$(OBJDIR)/json_tag_.c
744757
745758
$(OBJDIR)/json_tag.o: $(OBJDIR)/json_tag_.c $(OBJDIR)/json_tag.h $(SRCDIR)/config.h
746759
$(XTCC) -o $(OBJDIR)/json_tag.o -c $(OBJDIR)/json_tag_.c
@@ -1066,10 +1079,17 @@
10661079
10671080
$(OBJDIR)/utf8.o: $(OBJDIR)/utf8_.c $(OBJDIR)/utf8.h $(SRCDIR)/config.h
10681081
$(XTCC) -o $(OBJDIR)/utf8.o -c $(OBJDIR)/utf8_.c
10691082
10701083
$(OBJDIR)/utf8.h: $(OBJDIR)/headers
1084
+$(OBJDIR)/util_.c: $(SRCDIR)/util.c $(OBJDIR)/translate
1085
+ $(OBJDIR)/translate $(SRCDIR)/util.c >$(OBJDIR)/util_.c
1086
+
1087
+$(OBJDIR)/util.o: $(OBJDIR)/util_.c $(OBJDIR)/util.h $(SRCDIR)/config.h
1088
+ $(XTCC) -o $(OBJDIR)/util.o -c $(OBJDIR)/util_.c
1089
+
1090
+$(OBJDIR)/util.h: $(OBJDIR)/headers
10711091
$(OBJDIR)/verify_.c: $(SRCDIR)/verify.c $(OBJDIR)/translate
10721092
$(OBJDIR)/translate $(SRCDIR)/verify.c >$(OBJDIR)/verify_.c
10731093
10741094
$(OBJDIR)/verify.o: $(OBJDIR)/verify_.c $(OBJDIR)/verify.h $(SRCDIR)/config.h
10751095
$(XTCC) -o $(OBJDIR)/verify.o -c $(OBJDIR)/verify_.c
10761096
--- src/main.mk
+++ src/main.mk
@@ -60,10 +60,11 @@
60 $(SRCDIR)/json_dir.c \
61 $(SRCDIR)/json_finfo.c \
62 $(SRCDIR)/json_login.c \
63 $(SRCDIR)/json_query.c \
64 $(SRCDIR)/json_report.c \
 
65 $(SRCDIR)/json_tag.c \
66 $(SRCDIR)/json_timeline.c \
67 $(SRCDIR)/json_user.c \
68 $(SRCDIR)/json_wiki.c \
69 $(SRCDIR)/leaf.c \
@@ -107,10 +108,11 @@
107 $(SRCDIR)/unicode.c \
108 $(SRCDIR)/update.c \
109 $(SRCDIR)/url.c \
110 $(SRCDIR)/user.c \
111 $(SRCDIR)/utf8.c \
 
112 $(SRCDIR)/verify.c \
113 $(SRCDIR)/vfile.c \
114 $(SRCDIR)/wiki.c \
115 $(SRCDIR)/wikiformat.c \
116 $(SRCDIR)/winhttp.c \
@@ -166,10 +168,11 @@
166 $(OBJDIR)/json_dir_.c \
167 $(OBJDIR)/json_finfo_.c \
168 $(OBJDIR)/json_login_.c \
169 $(OBJDIR)/json_query_.c \
170 $(OBJDIR)/json_report_.c \
 
171 $(OBJDIR)/json_tag_.c \
172 $(OBJDIR)/json_timeline_.c \
173 $(OBJDIR)/json_user_.c \
174 $(OBJDIR)/json_wiki_.c \
175 $(OBJDIR)/leaf_.c \
@@ -213,10 +216,11 @@
213 $(OBJDIR)/unicode_.c \
214 $(OBJDIR)/update_.c \
215 $(OBJDIR)/url_.c \
216 $(OBJDIR)/user_.c \
217 $(OBJDIR)/utf8_.c \
 
218 $(OBJDIR)/verify_.c \
219 $(OBJDIR)/vfile_.c \
220 $(OBJDIR)/wiki_.c \
221 $(OBJDIR)/wikiformat_.c \
222 $(OBJDIR)/winhttp_.c \
@@ -272,10 +276,11 @@
272 $(OBJDIR)/json_dir.o \
273 $(OBJDIR)/json_finfo.o \
274 $(OBJDIR)/json_login.o \
275 $(OBJDIR)/json_query.o \
276 $(OBJDIR)/json_report.o \
 
277 $(OBJDIR)/json_tag.o \
278 $(OBJDIR)/json_timeline.o \
279 $(OBJDIR)/json_user.o \
280 $(OBJDIR)/json_wiki.o \
281 $(OBJDIR)/leaf.o \
@@ -319,10 +324,11 @@
319 $(OBJDIR)/unicode.o \
320 $(OBJDIR)/update.o \
321 $(OBJDIR)/url.o \
322 $(OBJDIR)/user.o \
323 $(OBJDIR)/utf8.o \
 
324 $(OBJDIR)/verify.o \
325 $(OBJDIR)/vfile.o \
326 $(OBJDIR)/wiki.o \
327 $(OBJDIR)/wikiformat.o \
328 $(OBJDIR)/winhttp.o \
@@ -396,14 +402,14 @@
396
397
398 $(OBJDIR)/page_index.h: $(TRANS_SRC) $(OBJDIR)/mkindex
399 $(OBJDIR)/mkindex $(TRANS_SRC) >$@
400 $(OBJDIR)/headers: $(OBJDIR)/page_index.h $(OBJDIR)/makeheaders $(OBJDIR)/VERSION.h
401 $(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_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)/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
402 touch $(OBJDIR)/headers
403 $(OBJDIR)/headers: Makefile
404 $(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_tag.o $(OBJDIR)/json_timeline.o $(OBJDIR)/json_user.o $(OBJDIR)/json_wiki.o : $(SRCDIR)/json_detail.h
405 Makefile:
406 $(OBJDIR)/add_.c: $(SRCDIR)/add.c $(OBJDIR)/translate
407 $(OBJDIR)/translate $(SRCDIR)/add.c >$(OBJDIR)/add_.c
408
409 $(OBJDIR)/add.o: $(OBJDIR)/add_.c $(OBJDIR)/add.h $(SRCDIR)/config.h
@@ -737,10 +743,17 @@
737
738 $(OBJDIR)/json_report.o: $(OBJDIR)/json_report_.c $(OBJDIR)/json_report.h $(SRCDIR)/config.h
739 $(XTCC) -o $(OBJDIR)/json_report.o -c $(OBJDIR)/json_report_.c
740
741 $(OBJDIR)/json_report.h: $(OBJDIR)/headers
 
 
 
 
 
 
 
742 $(OBJDIR)/json_tag_.c: $(SRCDIR)/json_tag.c $(OBJDIR)/translate
743 $(OBJDIR)/translate $(SRCDIR)/json_tag.c >$(OBJDIR)/json_tag_.c
744
745 $(OBJDIR)/json_tag.o: $(OBJDIR)/json_tag_.c $(OBJDIR)/json_tag.h $(SRCDIR)/config.h
746 $(XTCC) -o $(OBJDIR)/json_tag.o -c $(OBJDIR)/json_tag_.c
@@ -1066,10 +1079,17 @@
1066
1067 $(OBJDIR)/utf8.o: $(OBJDIR)/utf8_.c $(OBJDIR)/utf8.h $(SRCDIR)/config.h
1068 $(XTCC) -o $(OBJDIR)/utf8.o -c $(OBJDIR)/utf8_.c
1069
1070 $(OBJDIR)/utf8.h: $(OBJDIR)/headers
 
 
 
 
 
 
 
1071 $(OBJDIR)/verify_.c: $(SRCDIR)/verify.c $(OBJDIR)/translate
1072 $(OBJDIR)/translate $(SRCDIR)/verify.c >$(OBJDIR)/verify_.c
1073
1074 $(OBJDIR)/verify.o: $(OBJDIR)/verify_.c $(OBJDIR)/verify.h $(SRCDIR)/config.h
1075 $(XTCC) -o $(OBJDIR)/verify.o -c $(OBJDIR)/verify_.c
1076
--- src/main.mk
+++ src/main.mk
@@ -60,10 +60,11 @@
60 $(SRCDIR)/json_dir.c \
61 $(SRCDIR)/json_finfo.c \
62 $(SRCDIR)/json_login.c \
63 $(SRCDIR)/json_query.c \
64 $(SRCDIR)/json_report.c \
65 $(SRCDIR)/json_status.c \
66 $(SRCDIR)/json_tag.c \
67 $(SRCDIR)/json_timeline.c \
68 $(SRCDIR)/json_user.c \
69 $(SRCDIR)/json_wiki.c \
70 $(SRCDIR)/leaf.c \
@@ -107,10 +108,11 @@
108 $(SRCDIR)/unicode.c \
109 $(SRCDIR)/update.c \
110 $(SRCDIR)/url.c \
111 $(SRCDIR)/user.c \
112 $(SRCDIR)/utf8.c \
113 $(SRCDIR)/util.c \
114 $(SRCDIR)/verify.c \
115 $(SRCDIR)/vfile.c \
116 $(SRCDIR)/wiki.c \
117 $(SRCDIR)/wikiformat.c \
118 $(SRCDIR)/winhttp.c \
@@ -166,10 +168,11 @@
168 $(OBJDIR)/json_dir_.c \
169 $(OBJDIR)/json_finfo_.c \
170 $(OBJDIR)/json_login_.c \
171 $(OBJDIR)/json_query_.c \
172 $(OBJDIR)/json_report_.c \
173 $(OBJDIR)/json_status_.c \
174 $(OBJDIR)/json_tag_.c \
175 $(OBJDIR)/json_timeline_.c \
176 $(OBJDIR)/json_user_.c \
177 $(OBJDIR)/json_wiki_.c \
178 $(OBJDIR)/leaf_.c \
@@ -213,10 +216,11 @@
216 $(OBJDIR)/unicode_.c \
217 $(OBJDIR)/update_.c \
218 $(OBJDIR)/url_.c \
219 $(OBJDIR)/user_.c \
220 $(OBJDIR)/utf8_.c \
221 $(OBJDIR)/util_.c \
222 $(OBJDIR)/verify_.c \
223 $(OBJDIR)/vfile_.c \
224 $(OBJDIR)/wiki_.c \
225 $(OBJDIR)/wikiformat_.c \
226 $(OBJDIR)/winhttp_.c \
@@ -272,10 +276,11 @@
276 $(OBJDIR)/json_dir.o \
277 $(OBJDIR)/json_finfo.o \
278 $(OBJDIR)/json_login.o \
279 $(OBJDIR)/json_query.o \
280 $(OBJDIR)/json_report.o \
281 $(OBJDIR)/json_status.o \
282 $(OBJDIR)/json_tag.o \
283 $(OBJDIR)/json_timeline.o \
284 $(OBJDIR)/json_user.o \
285 $(OBJDIR)/json_wiki.o \
286 $(OBJDIR)/leaf.o \
@@ -319,10 +324,11 @@
324 $(OBJDIR)/unicode.o \
325 $(OBJDIR)/update.o \
326 $(OBJDIR)/url.o \
327 $(OBJDIR)/user.o \
328 $(OBJDIR)/utf8.o \
329 $(OBJDIR)/util.o \
330 $(OBJDIR)/verify.o \
331 $(OBJDIR)/vfile.o \
332 $(OBJDIR)/wiki.o \
333 $(OBJDIR)/wikiformat.o \
334 $(OBJDIR)/winhttp.o \
@@ -396,14 +402,14 @@
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
413 $(OBJDIR)/translate $(SRCDIR)/add.c >$(OBJDIR)/add_.c
414
415 $(OBJDIR)/add.o: $(OBJDIR)/add_.c $(OBJDIR)/add.h $(SRCDIR)/config.h
@@ -737,10 +743,17 @@
743
744 $(OBJDIR)/json_report.o: $(OBJDIR)/json_report_.c $(OBJDIR)/json_report.h $(SRCDIR)/config.h
745 $(XTCC) -o $(OBJDIR)/json_report.o -c $(OBJDIR)/json_report_.c
746
747 $(OBJDIR)/json_report.h: $(OBJDIR)/headers
748 $(OBJDIR)/json_status_.c: $(SRCDIR)/json_status.c $(OBJDIR)/translate
749 $(OBJDIR)/translate $(SRCDIR)/json_status.c >$(OBJDIR)/json_status_.c
750
751 $(OBJDIR)/json_status.o: $(OBJDIR)/json_status_.c $(OBJDIR)/json_status.h $(SRCDIR)/config.h
752 $(XTCC) -o $(OBJDIR)/json_status.o -c $(OBJDIR)/json_status_.c
753
754 $(OBJDIR)/json_status.h: $(OBJDIR)/headers
755 $(OBJDIR)/json_tag_.c: $(SRCDIR)/json_tag.c $(OBJDIR)/translate
756 $(OBJDIR)/translate $(SRCDIR)/json_tag.c >$(OBJDIR)/json_tag_.c
757
758 $(OBJDIR)/json_tag.o: $(OBJDIR)/json_tag_.c $(OBJDIR)/json_tag.h $(SRCDIR)/config.h
759 $(XTCC) -o $(OBJDIR)/json_tag.o -c $(OBJDIR)/json_tag_.c
@@ -1066,10 +1079,17 @@
1079
1080 $(OBJDIR)/utf8.o: $(OBJDIR)/utf8_.c $(OBJDIR)/utf8.h $(SRCDIR)/config.h
1081 $(XTCC) -o $(OBJDIR)/utf8.o -c $(OBJDIR)/utf8_.c
1082
1083 $(OBJDIR)/utf8.h: $(OBJDIR)/headers
1084 $(OBJDIR)/util_.c: $(SRCDIR)/util.c $(OBJDIR)/translate
1085 $(OBJDIR)/translate $(SRCDIR)/util.c >$(OBJDIR)/util_.c
1086
1087 $(OBJDIR)/util.o: $(OBJDIR)/util_.c $(OBJDIR)/util.h $(SRCDIR)/config.h
1088 $(XTCC) -o $(OBJDIR)/util.o -c $(OBJDIR)/util_.c
1089
1090 $(OBJDIR)/util.h: $(OBJDIR)/headers
1091 $(OBJDIR)/verify_.c: $(SRCDIR)/verify.c $(OBJDIR)/translate
1092 $(OBJDIR)/translate $(SRCDIR)/verify.c >$(OBJDIR)/verify_.c
1093
1094 $(OBJDIR)/verify.o: $(OBJDIR)/verify_.c $(OBJDIR)/verify.h $(SRCDIR)/config.h
1095 $(XTCC) -o $(OBJDIR)/verify.o -c $(OBJDIR)/verify_.c
1096
--- src/makemake.tcl
+++ src/makemake.tcl
@@ -63,10 +63,11 @@
6363
json_dir
6464
json_finfo
6565
json_login
6666
json_query
6767
json_report
68
+ json_status
6869
json_tag
6970
json_timeline
7071
json_user
7172
json_wiki
7273
leaf
@@ -110,10 +111,11 @@
110111
unicode
111112
update
112113
url
113114
user
114115
utf8
116
+ util
115117
verify
116118
vfile
117119
wiki
118120
wikiformat
119121
winhttp
@@ -268,11 +270,11 @@
268270
writeln "\t\$(OBJDIR)/mkindex \$(TRANS_SRC) >$@"
269271
writeln "\$(OBJDIR)/headers:\t\$(OBJDIR)/page_index.h \$(OBJDIR)/makeheaders \$(OBJDIR)/VERSION.h"
270272
writeln "\t\$(OBJDIR)/makeheaders $mhargs"
271273
writeln "\ttouch \$(OBJDIR)/headers"
272274
writeln "\$(OBJDIR)/headers: Makefile"
273
-writeln "\$(OBJDIR)/json.o \$(OBJDIR)/json_artifact.o \$(OBJDIR)/json_branch.o \$(OBJDIR)/json_config.o \$(OBJDIR)/json_diff.o \$(OBJDIR)/json_dir.o \$(OBJDIR)/json_finfo.o \$(OBJDIR)/json_login.o \$(OBJDIR)/json_query.o \$(OBJDIR)/json_report.o \$(OBJDIR)/json_tag.o \$(OBJDIR)/json_timeline.o \$(OBJDIR)/json_user.o \$(OBJDIR)/json_wiki.o : \$(SRCDIR)/json_detail.h"
275
+writeln "\$(OBJDIR)/json.o \$(OBJDIR)/json_artifact.o \$(OBJDIR)/json_branch.o \$(OBJDIR)/json_config.o \$(OBJDIR)/json_diff.o \$(OBJDIR)/json_dir.o \$(OBJDIR)/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"
274276
writeln "Makefile:"
275277
set extra_h(main) \$(OBJDIR)/page_index.h
276278
277279
foreach s [lsort $src] {
278280
writeln "\$(OBJDIR)/${s}_.c:\t\$(SRCDIR)/$s.c \$(OBJDIR)/translate"
@@ -418,12 +420,12 @@
418420
#### The directories where the OpenSSL include and library files are located.
419421
# The recommended usage here is to use the Sysinternals junction tool
420422
# to create a hard link between an "openssl-1.x" sub-directory of the
421423
# Fossil source code directory and the target OpenSSL source directory.
422424
#
423
-OPENSSLINCDIR = $(SRCDIR)/../openssl-1.0.1c/include
424
-OPENSSLLIBDIR = $(SRCDIR)/../openssl-1.0.1c
425
+OPENSSLINCDIR = $(SRCDIR)/../openssl-1.0.1e/include
426
+OPENSSLLIBDIR = $(SRCDIR)/../openssl-1.0.1e
425427
426428
#### Either the directory where the Tcl library is installed or the Tcl
427429
# source code directory resides (depending on the value of the macro
428430
# FOSSIL_TCL_SOURCE). If this points to the Tcl install directory,
429431
# this directory must have "include" and "lib" sub-directories. If
@@ -752,11 +754,11 @@
752754
writeln "\t\$(XTCC) $opt -c \$(SRCDIR)/sqlite3.c -o \$(OBJDIR)/sqlite3.o\n"
753755
754756
set opt {}
755757
writeln "\$(OBJDIR)/cson_amalgamation.o:\t\$(SRCDIR)/cson_amalgamation.c"
756758
writeln "\t\$(XTCC) $opt -c \$(SRCDIR)/cson_amalgamation.c -o \$(OBJDIR)/cson_amalgamation.o\n"
757
-writeln "\$(OBJDIR)/json.o \$(OBJDIR)/json_artifact.o \$(OBJDIR)/json_branch.o \$(OBJDIR)/json_config.o \$(OBJDIR)/json_diff.o \$(OBJDIR)/json_dir.o \$(OBJDIR)/jsos_finfo.o \$(OBJDIR)/json_login.o \$(OBJDIR)/json_query.o \$(OBJDIR)/json_report.o \$(OBJDIR)/json_tag.o \$(OBJDIR)/json_timeline.o \$(OBJDIR)/json_user.o \$(OBJDIR)/json_wiki.o : \$(SRCDIR)/json_detail.h\n"
759
+writeln "\$(OBJDIR)/json.o \$(OBJDIR)/json_artifact.o \$(OBJDIR)/json_branch.o \$(OBJDIR)/json_config.o \$(OBJDIR)/json_diff.o \$(OBJDIR)/json_dir.o \$(OBJDIR)/jsos_finfo.o \$(OBJDIR)/json_login.o \$(OBJDIR)/json_query.o \$(OBJDIR)/json_report.o \$(OBJDIR)/json_status.o \$(OBJDIR)/json_tag.o \$(OBJDIR)/json_timeline.o \$(OBJDIR)/json_user.o \$(OBJDIR)/json_wiki.o : \$(SRCDIR)/json_detail.h\n"
758760
759761
writeln "\$(OBJDIR)/shell.o:\t\$(SRCDIR)/shell.c \$(SRCDIR)/sqlite3.h"
760762
set opt {-Dmain=sqlite3_shell}
761763
append opt " -DSQLITE_OMIT_LOAD_EXTENSION=1"
762764
writeln "\t\$(XTCC) $opt -c \$(SRCDIR)/shell.c -o \$(OBJDIR)/shell.o\n"
@@ -900,10 +902,11 @@
900902
$(OBJDIR)\json_dir$O : $(SRCDIR)\json_detail.h
901903
$(OBJDIR)\json_finfo$O : $(SRCDIR)\json_detail.h
902904
$(OBJDIR)\json_login$O : $(SRCDIR)\json_detail.h
903905
$(OBJDIR)\json_query$O : $(SRCDIR)\json_detail.h
904906
$(OBJDIR)\json_report$O : $(SRCDIR)\json_detail.h
907
+$(OBJDIR)\json_status$O : $(SRCDIR)\json_detail.h
905908
$(OBJDIR)\json_tag$O : $(SRCDIR)\json_detail.h
906909
$(OBJDIR)\json_timeline$O : $(SRCDIR)\json_detail.h
907910
$(OBJDIR)\json_user$O : $(SRCDIR)\json_detail.h
908911
$(OBJDIR)\json_wiki$O : $(SRCDIR)\json_detail.h
909912
@@ -1096,10 +1099,11 @@
10961099
$(OBJDIR)\json_dir$O : $(SRCDIR)\json_detail.h
10971100
$(OBJDIR)\json_finfo$O : $(SRCDIR)\json_detail.h
10981101
$(OBJDIR)\json_login$O : $(SRCDIR)\json_detail.h
10991102
$(OBJDIR)\json_query$O : $(SRCDIR)\json_detail.h
11001103
$(OBJDIR)\json_report$O : $(SRCDIR)\json_detail.h
1104
+$(OBJDIR)\json_status$O : $(SRCDIR)\json_detail.h
11011105
$(OBJDIR)\json_tag$O : $(SRCDIR)\json_detail.h
11021106
$(OBJDIR)\json_timeline$O : $(SRCDIR)\json_detail.h
11031107
$(OBJDIR)\json_user$O : $(SRCDIR)\json_detail.h
11041108
$(OBJDIR)\json_wiki$O : $(SRCDIR)\json_detail.h
11051109
11061110
--- src/makemake.tcl
+++ src/makemake.tcl
@@ -63,10 +63,11 @@
63 json_dir
64 json_finfo
65 json_login
66 json_query
67 json_report
 
68 json_tag
69 json_timeline
70 json_user
71 json_wiki
72 leaf
@@ -110,10 +111,11 @@
110 unicode
111 update
112 url
113 user
114 utf8
 
115 verify
116 vfile
117 wiki
118 wikiformat
119 winhttp
@@ -268,11 +270,11 @@
268 writeln "\t\$(OBJDIR)/mkindex \$(TRANS_SRC) >$@"
269 writeln "\$(OBJDIR)/headers:\t\$(OBJDIR)/page_index.h \$(OBJDIR)/makeheaders \$(OBJDIR)/VERSION.h"
270 writeln "\t\$(OBJDIR)/makeheaders $mhargs"
271 writeln "\ttouch \$(OBJDIR)/headers"
272 writeln "\$(OBJDIR)/headers: Makefile"
273 writeln "\$(OBJDIR)/json.o \$(OBJDIR)/json_artifact.o \$(OBJDIR)/json_branch.o \$(OBJDIR)/json_config.o \$(OBJDIR)/json_diff.o \$(OBJDIR)/json_dir.o \$(OBJDIR)/json_finfo.o \$(OBJDIR)/json_login.o \$(OBJDIR)/json_query.o \$(OBJDIR)/json_report.o \$(OBJDIR)/json_tag.o \$(OBJDIR)/json_timeline.o \$(OBJDIR)/json_user.o \$(OBJDIR)/json_wiki.o : \$(SRCDIR)/json_detail.h"
274 writeln "Makefile:"
275 set extra_h(main) \$(OBJDIR)/page_index.h
276
277 foreach s [lsort $src] {
278 writeln "\$(OBJDIR)/${s}_.c:\t\$(SRCDIR)/$s.c \$(OBJDIR)/translate"
@@ -418,12 +420,12 @@
418 #### The directories where the OpenSSL include and library files are located.
419 # The recommended usage here is to use the Sysinternals junction tool
420 # to create a hard link between an "openssl-1.x" sub-directory of the
421 # Fossil source code directory and the target OpenSSL source directory.
422 #
423 OPENSSLINCDIR = $(SRCDIR)/../openssl-1.0.1c/include
424 OPENSSLLIBDIR = $(SRCDIR)/../openssl-1.0.1c
425
426 #### Either the directory where the Tcl library is installed or the Tcl
427 # source code directory resides (depending on the value of the macro
428 # FOSSIL_TCL_SOURCE). If this points to the Tcl install directory,
429 # this directory must have "include" and "lib" sub-directories. If
@@ -752,11 +754,11 @@
752 writeln "\t\$(XTCC) $opt -c \$(SRCDIR)/sqlite3.c -o \$(OBJDIR)/sqlite3.o\n"
753
754 set opt {}
755 writeln "\$(OBJDIR)/cson_amalgamation.o:\t\$(SRCDIR)/cson_amalgamation.c"
756 writeln "\t\$(XTCC) $opt -c \$(SRCDIR)/cson_amalgamation.c -o \$(OBJDIR)/cson_amalgamation.o\n"
757 writeln "\$(OBJDIR)/json.o \$(OBJDIR)/json_artifact.o \$(OBJDIR)/json_branch.o \$(OBJDIR)/json_config.o \$(OBJDIR)/json_diff.o \$(OBJDIR)/json_dir.o \$(OBJDIR)/jsos_finfo.o \$(OBJDIR)/json_login.o \$(OBJDIR)/json_query.o \$(OBJDIR)/json_report.o \$(OBJDIR)/json_tag.o \$(OBJDIR)/json_timeline.o \$(OBJDIR)/json_user.o \$(OBJDIR)/json_wiki.o : \$(SRCDIR)/json_detail.h\n"
758
759 writeln "\$(OBJDIR)/shell.o:\t\$(SRCDIR)/shell.c \$(SRCDIR)/sqlite3.h"
760 set opt {-Dmain=sqlite3_shell}
761 append opt " -DSQLITE_OMIT_LOAD_EXTENSION=1"
762 writeln "\t\$(XTCC) $opt -c \$(SRCDIR)/shell.c -o \$(OBJDIR)/shell.o\n"
@@ -900,10 +902,11 @@
900 $(OBJDIR)\json_dir$O : $(SRCDIR)\json_detail.h
901 $(OBJDIR)\json_finfo$O : $(SRCDIR)\json_detail.h
902 $(OBJDIR)\json_login$O : $(SRCDIR)\json_detail.h
903 $(OBJDIR)\json_query$O : $(SRCDIR)\json_detail.h
904 $(OBJDIR)\json_report$O : $(SRCDIR)\json_detail.h
 
905 $(OBJDIR)\json_tag$O : $(SRCDIR)\json_detail.h
906 $(OBJDIR)\json_timeline$O : $(SRCDIR)\json_detail.h
907 $(OBJDIR)\json_user$O : $(SRCDIR)\json_detail.h
908 $(OBJDIR)\json_wiki$O : $(SRCDIR)\json_detail.h
909
@@ -1096,10 +1099,11 @@
1096 $(OBJDIR)\json_dir$O : $(SRCDIR)\json_detail.h
1097 $(OBJDIR)\json_finfo$O : $(SRCDIR)\json_detail.h
1098 $(OBJDIR)\json_login$O : $(SRCDIR)\json_detail.h
1099 $(OBJDIR)\json_query$O : $(SRCDIR)\json_detail.h
1100 $(OBJDIR)\json_report$O : $(SRCDIR)\json_detail.h
 
1101 $(OBJDIR)\json_tag$O : $(SRCDIR)\json_detail.h
1102 $(OBJDIR)\json_timeline$O : $(SRCDIR)\json_detail.h
1103 $(OBJDIR)\json_user$O : $(SRCDIR)\json_detail.h
1104 $(OBJDIR)\json_wiki$O : $(SRCDIR)\json_detail.h
1105
1106
--- src/makemake.tcl
+++ src/makemake.tcl
@@ -63,10 +63,11 @@
63 json_dir
64 json_finfo
65 json_login
66 json_query
67 json_report
68 json_status
69 json_tag
70 json_timeline
71 json_user
72 json_wiki
73 leaf
@@ -110,10 +111,11 @@
111 unicode
112 update
113 url
114 user
115 utf8
116 util
117 verify
118 vfile
119 wiki
120 wikiformat
121 winhttp
@@ -268,11 +270,11 @@
270 writeln "\t\$(OBJDIR)/mkindex \$(TRANS_SRC) >$@"
271 writeln "\$(OBJDIR)/headers:\t\$(OBJDIR)/page_index.h \$(OBJDIR)/makeheaders \$(OBJDIR)/VERSION.h"
272 writeln "\t\$(OBJDIR)/makeheaders $mhargs"
273 writeln "\ttouch \$(OBJDIR)/headers"
274 writeln "\$(OBJDIR)/headers: Makefile"
275 writeln "\$(OBJDIR)/json.o \$(OBJDIR)/json_artifact.o \$(OBJDIR)/json_branch.o \$(OBJDIR)/json_config.o \$(OBJDIR)/json_diff.o \$(OBJDIR)/json_dir.o \$(OBJDIR)/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"
276 writeln "Makefile:"
277 set extra_h(main) \$(OBJDIR)/page_index.h
278
279 foreach s [lsort $src] {
280 writeln "\$(OBJDIR)/${s}_.c:\t\$(SRCDIR)/$s.c \$(OBJDIR)/translate"
@@ -418,12 +420,12 @@
420 #### The directories where the OpenSSL include and library files are located.
421 # The recommended usage here is to use the Sysinternals junction tool
422 # to create a hard link between an "openssl-1.x" sub-directory of the
423 # Fossil source code directory and the target OpenSSL source directory.
424 #
425 OPENSSLINCDIR = $(SRCDIR)/../openssl-1.0.1e/include
426 OPENSSLLIBDIR = $(SRCDIR)/../openssl-1.0.1e
427
428 #### Either the directory where the Tcl library is installed or the Tcl
429 # source code directory resides (depending on the value of the macro
430 # FOSSIL_TCL_SOURCE). If this points to the Tcl install directory,
431 # this directory must have "include" and "lib" sub-directories. If
@@ -752,11 +754,11 @@
754 writeln "\t\$(XTCC) $opt -c \$(SRCDIR)/sqlite3.c -o \$(OBJDIR)/sqlite3.o\n"
755
756 set opt {}
757 writeln "\$(OBJDIR)/cson_amalgamation.o:\t\$(SRCDIR)/cson_amalgamation.c"
758 writeln "\t\$(XTCC) $opt -c \$(SRCDIR)/cson_amalgamation.c -o \$(OBJDIR)/cson_amalgamation.o\n"
759 writeln "\$(OBJDIR)/json.o \$(OBJDIR)/json_artifact.o \$(OBJDIR)/json_branch.o \$(OBJDIR)/json_config.o \$(OBJDIR)/json_diff.o \$(OBJDIR)/json_dir.o \$(OBJDIR)/jsos_finfo.o \$(OBJDIR)/json_login.o \$(OBJDIR)/json_query.o \$(OBJDIR)/json_report.o \$(OBJDIR)/json_status.o \$(OBJDIR)/json_tag.o \$(OBJDIR)/json_timeline.o \$(OBJDIR)/json_user.o \$(OBJDIR)/json_wiki.o : \$(SRCDIR)/json_detail.h\n"
760
761 writeln "\$(OBJDIR)/shell.o:\t\$(SRCDIR)/shell.c \$(SRCDIR)/sqlite3.h"
762 set opt {-Dmain=sqlite3_shell}
763 append opt " -DSQLITE_OMIT_LOAD_EXTENSION=1"
764 writeln "\t\$(XTCC) $opt -c \$(SRCDIR)/shell.c -o \$(OBJDIR)/shell.o\n"
@@ -900,10 +902,11 @@
902 $(OBJDIR)\json_dir$O : $(SRCDIR)\json_detail.h
903 $(OBJDIR)\json_finfo$O : $(SRCDIR)\json_detail.h
904 $(OBJDIR)\json_login$O : $(SRCDIR)\json_detail.h
905 $(OBJDIR)\json_query$O : $(SRCDIR)\json_detail.h
906 $(OBJDIR)\json_report$O : $(SRCDIR)\json_detail.h
907 $(OBJDIR)\json_status$O : $(SRCDIR)\json_detail.h
908 $(OBJDIR)\json_tag$O : $(SRCDIR)\json_detail.h
909 $(OBJDIR)\json_timeline$O : $(SRCDIR)\json_detail.h
910 $(OBJDIR)\json_user$O : $(SRCDIR)\json_detail.h
911 $(OBJDIR)\json_wiki$O : $(SRCDIR)\json_detail.h
912
@@ -1096,10 +1099,11 @@
1099 $(OBJDIR)\json_dir$O : $(SRCDIR)\json_detail.h
1100 $(OBJDIR)\json_finfo$O : $(SRCDIR)\json_detail.h
1101 $(OBJDIR)\json_login$O : $(SRCDIR)\json_detail.h
1102 $(OBJDIR)\json_query$O : $(SRCDIR)\json_detail.h
1103 $(OBJDIR)\json_report$O : $(SRCDIR)\json_detail.h
1104 $(OBJDIR)\json_status$O : $(SRCDIR)\json_detail.h
1105 $(OBJDIR)\json_tag$O : $(SRCDIR)\json_detail.h
1106 $(OBJDIR)\json_timeline$O : $(SRCDIR)\json_detail.h
1107 $(OBJDIR)\json_user$O : $(SRCDIR)\json_detail.h
1108 $(OBJDIR)\json_wiki$O : $(SRCDIR)\json_detail.h
1109
1110
+1 -2
--- src/md5.c
+++ src/md5.c
@@ -258,12 +258,11 @@
258258
memset(p, 0, count-8);
259259
}
260260
byteReverse(ctx->in, 14);
261261
262262
/* Append length in bits and transform */
263
- ((uint32 *)ctx->in)[ 14 ] = ctx->bits[0];
264
- ((uint32 *)ctx->in)[ 15 ] = ctx->bits[1];
263
+ memcpy(&ctx->in[14*sizeof(uint32)], ctx->bits, 2*sizeof(uint32));
265264
266265
MD5Transform(ctx->buf, (uint32 *)ctx->in);
267266
byteReverse((unsigned char *)ctx->buf, 4);
268267
memcpy(digest, ctx->buf, 16);
269268
memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */
270269
--- src/md5.c
+++ src/md5.c
@@ -258,12 +258,11 @@
258 memset(p, 0, count-8);
259 }
260 byteReverse(ctx->in, 14);
261
262 /* Append length in bits and transform */
263 ((uint32 *)ctx->in)[ 14 ] = ctx->bits[0];
264 ((uint32 *)ctx->in)[ 15 ] = ctx->bits[1];
265
266 MD5Transform(ctx->buf, (uint32 *)ctx->in);
267 byteReverse((unsigned char *)ctx->buf, 4);
268 memcpy(digest, ctx->buf, 16);
269 memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */
270
--- src/md5.c
+++ src/md5.c
@@ -258,12 +258,11 @@
258 memset(p, 0, count-8);
259 }
260 byteReverse(ctx->in, 14);
261
262 /* Append length in bits and transform */
263 memcpy(&ctx->in[14*sizeof(uint32)], ctx->bits, 2*sizeof(uint32));
 
264
265 MD5Transform(ctx->buf, (uint32 *)ctx->in);
266 byteReverse((unsigned char *)ctx->buf, 4);
267 memcpy(digest, ctx->buf, 16);
268 memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */
269
+22 -17
--- src/mkindex.c
+++ src/mkindex.c
@@ -174,10 +174,11 @@
174174
if( strncmp(zLine, "**", 2)==0
175175
&& isspace(zLine[2])
176176
&& strlen(zLine)<sizeof(zHelp)-nHelp-1
177177
&& nUsed>nFixed
178178
&& memcmp(zLine,"** COMMAND:",11)!=0
179
+ && memcmp(zLine,"** WEBPAGE:",11)!=0
179180
){
180181
if( zLine[2]=='\n' ){
181182
zHelp[nHelp++] = '\n';
182183
}else{
183184
if( strncmp(&zLine[3], "Usage: ", 6)==0 ) nHelp = 0;
@@ -242,11 +243,10 @@
242243
/*
243244
** Build the binary search table.
244245
*/
245246
void build_table(void){
246247
int i;
247
- int nType0;
248248
249249
qsort(aEntry, nFixed, sizeof(aEntry[0]), e_compare);
250250
for(i=0; i<nFixed; i++){
251251
if( aEntry[i].zIf ) printf("%s", aEntry[i].zIf);
252252
printf("extern void %s(void);\n", aEntry[i].zFunc);
@@ -260,10 +260,11 @@
260260
" char cmdFlags;\n"
261261
"};\n"
262262
"#define CMDFLAG_1ST_TIER 0x01\n"
263263
"#define CMDFLAG_2ND_TIER 0x02\n"
264264
"#define CMDFLAG_TEST 0x04\n"
265
+ "#define CMDFLAG_WEBPAGE 0x08\n"
265266
"static const NameMap aWebpage[] = {\n"
266267
);
267268
for(i=0; i<nFixed && aEntry[i].eType==0; i++){
268269
const char *z = aEntry[i].zPath;
269270
int n = strlen(z);
@@ -275,36 +276,38 @@
275276
(int)(35-strlen(aEntry[i].zFunc)), ""
276277
);
277278
if( aEntry[i].zIf ) printf("#endif\n");
278279
}
279280
printf("};\n");
280
- nType0 = i;
281281
printf(
282282
"static const NameMap aCommand[] = {\n"
283283
);
284
- for(i=nType0; i<nFixed && aEntry[i].eType==1; i++){
284
+ for(i=0; i<nFixed /*&& aEntry[i].eType==1*/; i++){
285285
const char *z = aEntry[i].zPath;
286286
int n = strlen(z);
287
- int cmdFlags = 0x01;
288
- if( z[n-1]=='*' ){
289
- n--;
290
- cmdFlags = 0x02;
291
- }else if( memcmp(z, "test-", 5)==0 ){
292
- cmdFlags = 0x04;
287
+ int cmdFlags = (1==aEntry[i].eType) ? 0x01 : 0x08;
288
+ if(0x01==cmdFlags){
289
+ if( z[n-1]=='*' ){
290
+ n--;
291
+ cmdFlags = 0x02;
292
+ }else if( memcmp(z, "test-", 5)==0 ){
293
+ cmdFlags = 0x04;
294
+ }
293295
}
294296
if( aEntry[i].zIf ) printf("%s", aEntry[i].zIf);
295
- printf(" { \"%.*s\",%*s %s,%*s %d },\n",
297
+ printf(" { \"%s%.*s\",%*s %s,%*s %d },\n",
298
+ (0x08 & cmdFlags) ? "/" : "",
296299
n, z,
297300
25-n, "",
298301
aEntry[i].zFunc,
299302
(int)(35-strlen(aEntry[i].zFunc)), "",
300303
cmdFlags
301304
);
302305
if( aEntry[i].zIf ) printf("#endif\n");
303306
}
304307
printf("};\n");
305
- for(i=nType0; i<nFixed; i++){
308
+ for(i=0; i<nFixed; i++){
306309
char *z = aEntry[i].zHelp;
307310
if( z && z[0] ){
308311
if( aEntry[i].zIf ) printf("%s", aEntry[i].zIf);
309312
printf("static const char zHelp_%s[] = \n", aEntry[i].zFunc);
310313
printf(" \"");
@@ -321,19 +324,21 @@
321324
printf("\";\n");
322325
if( aEntry[i].zIf ) printf("#endif\n");
323326
aEntry[i].zHelp[0] = 0;
324327
}
325328
}
326
- printf(
327
- "static const char * const aCmdHelp[] = {\n"
328
- );
329
- for(i=nType0; i<nFixed; i++){
329
+ puts("struct CmdHelp {"
330
+ "int eType; "
331
+ "char const * zText;"
332
+ "};");
333
+ puts("static struct CmdHelp aCmdHelp[] = {");
334
+ for(i=0; i<nFixed; i++){
330335
if( aEntry[i].zIf ) printf("%s", aEntry[i].zIf);
331336
if( aEntry[i].zHelp==0 ){
332
- printf(" 0,\n");
337
+ printf("{%d, 0},\n", aEntry[i].eType);
333338
}else{
334
- printf(" zHelp_%s,\n", aEntry[i].zFunc);
339
+ printf("{%d, zHelp_%s},\n", aEntry[i].eType, aEntry[i].zFunc);
335340
}
336341
if( aEntry[i].zIf ) printf("#endif\n");
337342
}
338343
printf("};\n");
339344
}
340345
--- src/mkindex.c
+++ src/mkindex.c
@@ -174,10 +174,11 @@
174 if( strncmp(zLine, "**", 2)==0
175 && isspace(zLine[2])
176 && strlen(zLine)<sizeof(zHelp)-nHelp-1
177 && nUsed>nFixed
178 && memcmp(zLine,"** COMMAND:",11)!=0
 
179 ){
180 if( zLine[2]=='\n' ){
181 zHelp[nHelp++] = '\n';
182 }else{
183 if( strncmp(&zLine[3], "Usage: ", 6)==0 ) nHelp = 0;
@@ -242,11 +243,10 @@
242 /*
243 ** Build the binary search table.
244 */
245 void build_table(void){
246 int i;
247 int nType0;
248
249 qsort(aEntry, nFixed, sizeof(aEntry[0]), e_compare);
250 for(i=0; i<nFixed; i++){
251 if( aEntry[i].zIf ) printf("%s", aEntry[i].zIf);
252 printf("extern void %s(void);\n", aEntry[i].zFunc);
@@ -260,10 +260,11 @@
260 " char cmdFlags;\n"
261 "};\n"
262 "#define CMDFLAG_1ST_TIER 0x01\n"
263 "#define CMDFLAG_2ND_TIER 0x02\n"
264 "#define CMDFLAG_TEST 0x04\n"
 
265 "static const NameMap aWebpage[] = {\n"
266 );
267 for(i=0; i<nFixed && aEntry[i].eType==0; i++){
268 const char *z = aEntry[i].zPath;
269 int n = strlen(z);
@@ -275,36 +276,38 @@
275 (int)(35-strlen(aEntry[i].zFunc)), ""
276 );
277 if( aEntry[i].zIf ) printf("#endif\n");
278 }
279 printf("};\n");
280 nType0 = i;
281 printf(
282 "static const NameMap aCommand[] = {\n"
283 );
284 for(i=nType0; i<nFixed && aEntry[i].eType==1; i++){
285 const char *z = aEntry[i].zPath;
286 int n = strlen(z);
287 int cmdFlags = 0x01;
288 if( z[n-1]=='*' ){
289 n--;
290 cmdFlags = 0x02;
291 }else if( memcmp(z, "test-", 5)==0 ){
292 cmdFlags = 0x04;
 
 
293 }
294 if( aEntry[i].zIf ) printf("%s", aEntry[i].zIf);
295 printf(" { \"%.*s\",%*s %s,%*s %d },\n",
 
296 n, z,
297 25-n, "",
298 aEntry[i].zFunc,
299 (int)(35-strlen(aEntry[i].zFunc)), "",
300 cmdFlags
301 );
302 if( aEntry[i].zIf ) printf("#endif\n");
303 }
304 printf("};\n");
305 for(i=nType0; i<nFixed; i++){
306 char *z = aEntry[i].zHelp;
307 if( z && z[0] ){
308 if( aEntry[i].zIf ) printf("%s", aEntry[i].zIf);
309 printf("static const char zHelp_%s[] = \n", aEntry[i].zFunc);
310 printf(" \"");
@@ -321,19 +324,21 @@
321 printf("\";\n");
322 if( aEntry[i].zIf ) printf("#endif\n");
323 aEntry[i].zHelp[0] = 0;
324 }
325 }
326 printf(
327 "static const char * const aCmdHelp[] = {\n"
328 );
329 for(i=nType0; i<nFixed; i++){
 
 
330 if( aEntry[i].zIf ) printf("%s", aEntry[i].zIf);
331 if( aEntry[i].zHelp==0 ){
332 printf(" 0,\n");
333 }else{
334 printf(" zHelp_%s,\n", aEntry[i].zFunc);
335 }
336 if( aEntry[i].zIf ) printf("#endif\n");
337 }
338 printf("};\n");
339 }
340
--- src/mkindex.c
+++ src/mkindex.c
@@ -174,10 +174,11 @@
174 if( strncmp(zLine, "**", 2)==0
175 && isspace(zLine[2])
176 && strlen(zLine)<sizeof(zHelp)-nHelp-1
177 && nUsed>nFixed
178 && memcmp(zLine,"** COMMAND:",11)!=0
179 && memcmp(zLine,"** WEBPAGE:",11)!=0
180 ){
181 if( zLine[2]=='\n' ){
182 zHelp[nHelp++] = '\n';
183 }else{
184 if( strncmp(&zLine[3], "Usage: ", 6)==0 ) nHelp = 0;
@@ -242,11 +243,10 @@
243 /*
244 ** Build the binary search table.
245 */
246 void build_table(void){
247 int i;
 
248
249 qsort(aEntry, nFixed, sizeof(aEntry[0]), e_compare);
250 for(i=0; i<nFixed; i++){
251 if( aEntry[i].zIf ) printf("%s", aEntry[i].zIf);
252 printf("extern void %s(void);\n", aEntry[i].zFunc);
@@ -260,10 +260,11 @@
260 " char cmdFlags;\n"
261 "};\n"
262 "#define CMDFLAG_1ST_TIER 0x01\n"
263 "#define CMDFLAG_2ND_TIER 0x02\n"
264 "#define CMDFLAG_TEST 0x04\n"
265 "#define CMDFLAG_WEBPAGE 0x08\n"
266 "static const NameMap aWebpage[] = {\n"
267 );
268 for(i=0; i<nFixed && aEntry[i].eType==0; i++){
269 const char *z = aEntry[i].zPath;
270 int n = strlen(z);
@@ -275,36 +276,38 @@
276 (int)(35-strlen(aEntry[i].zFunc)), ""
277 );
278 if( aEntry[i].zIf ) printf("#endif\n");
279 }
280 printf("};\n");
 
281 printf(
282 "static const NameMap aCommand[] = {\n"
283 );
284 for(i=0; i<nFixed /*&& aEntry[i].eType==1*/; i++){
285 const char *z = aEntry[i].zPath;
286 int n = strlen(z);
287 int cmdFlags = (1==aEntry[i].eType) ? 0x01 : 0x08;
288 if(0x01==cmdFlags){
289 if( z[n-1]=='*' ){
290 n--;
291 cmdFlags = 0x02;
292 }else if( memcmp(z, "test-", 5)==0 ){
293 cmdFlags = 0x04;
294 }
295 }
296 if( aEntry[i].zIf ) printf("%s", aEntry[i].zIf);
297 printf(" { \"%s%.*s\",%*s %s,%*s %d },\n",
298 (0x08 & cmdFlags) ? "/" : "",
299 n, z,
300 25-n, "",
301 aEntry[i].zFunc,
302 (int)(35-strlen(aEntry[i].zFunc)), "",
303 cmdFlags
304 );
305 if( aEntry[i].zIf ) printf("#endif\n");
306 }
307 printf("};\n");
308 for(i=0; i<nFixed; i++){
309 char *z = aEntry[i].zHelp;
310 if( z && z[0] ){
311 if( aEntry[i].zIf ) printf("%s", aEntry[i].zIf);
312 printf("static const char zHelp_%s[] = \n", aEntry[i].zFunc);
313 printf(" \"");
@@ -321,19 +324,21 @@
324 printf("\";\n");
325 if( aEntry[i].zIf ) printf("#endif\n");
326 aEntry[i].zHelp[0] = 0;
327 }
328 }
329 puts("struct CmdHelp {"
330 "int eType; "
331 "char const * zText;"
332 "};");
333 puts("static struct CmdHelp aCmdHelp[] = {");
334 for(i=0; i<nFixed; i++){
335 if( aEntry[i].zIf ) printf("%s", aEntry[i].zIf);
336 if( aEntry[i].zHelp==0 ){
337 printf("{%d, 0},\n", aEntry[i].eType);
338 }else{
339 printf("{%d, zHelp_%s},\n", aEntry[i].eType, aEntry[i].zFunc);
340 }
341 if( aEntry[i].zIf ) printf("#endif\n");
342 }
343 printf("};\n");
344 }
345
+166 -68
--- src/printf.c
+++ src/printf.c
@@ -13,14 +13,19 @@
1313
** [email protected]
1414
** http://www.hwaci.com/drh/
1515
**
1616
*******************************************************************************
1717
**
18
-** An implementation of printf() with extra conversion fields.
18
+** This file contains implementions of routines for formatting output
19
+** (ex: mprintf()) and for output to the console.
1920
*/
2021
#include "config.h"
2122
#include "printf.h"
23
+#if defined(_WIN32)
24
+# include <io.h>
25
+# include <fcntl.h>
26
+#endif
2227
2328
/*
2429
** Conversion types fall into various categories as defined by the
2530
** following enumeration.
2631
*/
@@ -159,15 +164,20 @@
159164
160165
/*
161166
** Return an appropriate set of flags for wiki_convert() for displaying
162167
** comments on a timeline. These flag settings are determined by
163168
** configuration parameters.
169
+**
170
+** The altForm2 argument is true for "%!w" (with the "!" alternate-form-2
171
+** flags) and is false for plain "%w". The ! indicates that the text is
172
+** to be rendered on a form rather than the timeline and that block markup
173
+** is acceptable even if the "timeline-block-markup" setting is false.
164174
*/
165
-static int wiki_convert_flags(void){
175
+static int wiki_convert_flags(int altForm2){
166176
static int wikiFlags = 0;
167177
if( wikiFlags==0 ){
168
- if( db_get_boolean("timeline-block-markup", 0) ){
178
+ if( altForm2 || db_get_boolean("timeline-block-markup", 0) ){
169179
wikiFlags = WIKI_INLINE | WIKI_NOBADLINKS;
170180
}else{
171181
wikiFlags = WIKI_INLINE | WIKI_NOBLOCK | WIKI_NOBADLINKS;
172182
}
173183
if( db_get_boolean("timeline-plaintext", 0) ){
@@ -717,11 +727,11 @@
717727
case etWIKISTR: {
718728
int limit = flag_alternateform ? va_arg(ap,int) : -1;
719729
char *zWiki = va_arg(ap, char*);
720730
Blob wiki;
721731
blob_init(&wiki, zWiki, limit);
722
- wiki_convert(&wiki, pBlob, wiki_convert_flags());
732
+ wiki_convert(&wiki, pBlob, wiki_convert_flags(flag_altform2));
723733
blob_reset(&wiki);
724734
length = width = 0;
725735
break;
726736
}
727737
case etERROR:
@@ -888,70 +898,158 @@
888898
fossil_puts(blob_str(&b), 1);
889899
blob_reset(&b);
890900
va_end(ap);
891901
}
892902
893
-/*
894
-** Like strcmp() except that it accepts NULL pointers. NULL sorts before
895
-** all non-NULL string pointers. Also, this strcmp() is a binary comparison
896
-** that does not consider locale.
897
-*/
898
-int fossil_strcmp(const char *zA, const char *zB){
899
- if( zA==0 ){
900
- if( zB==0 ) return 0;
901
- return -1;
902
- }else if( zB==0 ){
903
- return +1;
904
- }else{
905
- int a, b;
906
- do{
907
- a = *zA++;
908
- b = *zB++;
909
- }while( a==b && a!=0 );
910
- return ((unsigned char)a) - (unsigned char)b;
911
- }
912
-}
913
-int fossil_strncmp(const char *zA, const char *zB, int nByte){
914
- if( zA==0 ){
915
- if( zB==0 ) return 0;
916
- return -1;
917
- }else if( zB==0 ){
918
- return +1;
919
- }else if( nByte>0 ){
920
- int a, b;
921
- do{
922
- a = *zA++;
923
- b = *zB++;
924
- }while( a==b && a!=0 && (--nByte)>0 );
925
- return ((unsigned char)a) - (unsigned char)b;
926
- }else{
927
- return 0;
928
- }
929
-}
930
-
931
-/*
932
-** Case insensitive string comparison.
933
-*/
934
-int fossil_strnicmp(const char *zA, const char *zB, int nByte){
935
- if( zA==0 ){
936
- if( zB==0 ) return 0;
937
- return -1;
938
- }else if( zB==0 ){
939
- return +1;
940
- }
941
- if( nByte<0 ) nByte = strlen(zB);
942
- return sqlite3_strnicmp(zA, zB, nByte);
943
-}
944
-int fossil_stricmp(const char *zA, const char *zB){
945
- int nByte;
946
- int rc;
947
- if( zA==0 ){
948
- if( zB==0 ) return 0;
949
- return -1;
950
- }else if( zB==0 ){
951
- return +1;
952
- }
953
- nByte = strlen(zB);
954
- rc = sqlite3_strnicmp(zA, zB, nByte);
955
- if( rc==0 && zA[nByte] ) rc = 1;
956
- return rc;
903
+
904
+/*
905
+** The following variable becomes true while processing a fatal error
906
+** or a panic. If additional "recursive-fatal" errors occur while
907
+** shutting down, the recursive errors are silently ignored.
908
+*/
909
+static int mainInFatalError = 0;
910
+
911
+/*
912
+** Print an error message, rollback all databases, and quit. These
913
+** routines never return.
914
+*/
915
+NORETURN void fossil_panic(const char *zFormat, ...){
916
+ char *z;
917
+ va_list ap;
918
+ int rc = 1;
919
+ static int once = 1;
920
+ mainInFatalError = 1;
921
+ va_start(ap, zFormat);
922
+ z = vmprintf(zFormat, ap);
923
+ va_end(ap);
924
+#ifdef FOSSIL_ENABLE_JSON
925
+ if( g.json.isJsonMode ){
926
+ json_err( 0, z, 1 );
927
+ if( g.isHTTP ){
928
+ rc = 0 /* avoid HTTP 500 */;
929
+ }
930
+ }
931
+ else
932
+#endif
933
+ {
934
+ if( g.cgiOutput && once ){
935
+ once = 0;
936
+ cgi_printf("<p class=\"generalError\">%h</p>", z);
937
+ cgi_reply();
938
+ }else if( !g.fQuiet ){
939
+ fossil_force_newline();
940
+ fossil_trace("Fossil internal error: %s\n", z);
941
+ }
942
+ }
943
+ free(z);
944
+ db_force_rollback();
945
+ fossil_exit(rc);
946
+}
947
+
948
+NORETURN void fossil_fatal(const char *zFormat, ...){
949
+ char *z;
950
+ int rc = 1;
951
+ va_list ap;
952
+ mainInFatalError = 1;
953
+ va_start(ap, zFormat);
954
+ z = vmprintf(zFormat, ap);
955
+ va_end(ap);
956
+#ifdef FOSSIL_ENABLE_JSON
957
+ if( g.json.isJsonMode ){
958
+ json_err( g.json.resultCode, z, 1 );
959
+ if( g.isHTTP ){
960
+ rc = 0 /* avoid HTTP 500 */;
961
+ }
962
+ }
963
+ else
964
+#endif
965
+ {
966
+ if( g.cgiOutput ){
967
+ g.cgiOutput = 0;
968
+ cgi_printf("<p class=\"generalError\">\n%h\n</p>\n", z);
969
+ cgi_reply();
970
+ }else if( !g.fQuiet ){
971
+ fossil_force_newline();
972
+ fossil_trace("%s\n", z);
973
+ }
974
+ }
975
+ free(z);
976
+ db_force_rollback();
977
+ fossil_exit(rc);
978
+}
979
+
980
+/* This routine works like fossil_fatal() except that if called
981
+** recursively, the recursive call is a no-op.
982
+**
983
+** Use this in places where an error might occur while doing
984
+** fatal error shutdown processing. Unlike fossil_panic() and
985
+** fossil_fatal() which never return, this routine might return if
986
+** the fatal error handing is already in process. The caller must
987
+** be prepared for this routine to return.
988
+*/
989
+void fossil_fatal_recursive(const char *zFormat, ...){
990
+ char *z;
991
+ va_list ap;
992
+ int rc = 1;
993
+ if( mainInFatalError ) return;
994
+ mainInFatalError = 1;
995
+ va_start(ap, zFormat);
996
+ z = vmprintf(zFormat, ap);
997
+ va_end(ap);
998
+#ifdef FOSSIL_ENABLE_JSON
999
+ if( g.json.isJsonMode ){
1000
+ json_err( g.json.resultCode, z, 1 );
1001
+ if( g.isHTTP ){
1002
+ rc = 0 /* avoid HTTP 500 */;
1003
+ }
1004
+ } else
1005
+#endif
1006
+ {
1007
+ if( g.cgiOutput ){
1008
+ g.cgiOutput = 0;
1009
+ cgi_printf("<p class=\"generalError\">\n%h\n</p>\n", z);
1010
+ cgi_reply();
1011
+ }else{
1012
+ fossil_force_newline();
1013
+ fossil_trace("%s\n", z);
1014
+ }
1015
+ }
1016
+ db_force_rollback();
1017
+ fossil_exit(rc);
1018
+}
1019
+
1020
+
1021
+/* Print a warning message */
1022
+void fossil_warning(const char *zFormat, ...){
1023
+ char *z;
1024
+ va_list ap;
1025
+ va_start(ap, zFormat);
1026
+ z = vmprintf(zFormat, ap);
1027
+ va_end(ap);
1028
+#ifdef FOSSIL_ENABLE_JSON
1029
+ if(g.json.isJsonMode){
1030
+ json_warn( FSL_JSON_W_UNKNOWN, z );
1031
+ }else
1032
+#endif
1033
+ {
1034
+ if( g.cgiOutput ){
1035
+ cgi_printf("<p class=\"generalError\">\n%h\n</p>\n", z);
1036
+ }else{
1037
+ fossil_force_newline();
1038
+ fossil_trace("%s\n", z);
1039
+ }
1040
+ }
1041
+ free(z);
1042
+}
1043
+
1044
+/*
1045
+** Turn off any NL to CRNL translation on the stream given as an
1046
+** argument. This is a no-op on unix but is necessary on windows.
1047
+*/
1048
+void fossil_binary_mode(FILE *p){
1049
+#if defined(_WIN32)
1050
+ _setmode(_fileno(p), _O_BINARY);
1051
+#endif
1052
+#ifdef __EMX__ /* OS/2 */
1053
+ setmode(fileno(p), O_BINARY);
1054
+#endif
9571055
}
9581056
--- src/printf.c
+++ src/printf.c
@@ -13,14 +13,19 @@
13 ** [email protected]
14 ** http://www.hwaci.com/drh/
15 **
16 *******************************************************************************
17 **
18 ** An implementation of printf() with extra conversion fields.
 
19 */
20 #include "config.h"
21 #include "printf.h"
 
 
 
 
22
23 /*
24 ** Conversion types fall into various categories as defined by the
25 ** following enumeration.
26 */
@@ -159,15 +164,20 @@
159
160 /*
161 ** Return an appropriate set of flags for wiki_convert() for displaying
162 ** comments on a timeline. These flag settings are determined by
163 ** configuration parameters.
 
 
 
 
 
164 */
165 static int wiki_convert_flags(void){
166 static int wikiFlags = 0;
167 if( wikiFlags==0 ){
168 if( db_get_boolean("timeline-block-markup", 0) ){
169 wikiFlags = WIKI_INLINE | WIKI_NOBADLINKS;
170 }else{
171 wikiFlags = WIKI_INLINE | WIKI_NOBLOCK | WIKI_NOBADLINKS;
172 }
173 if( db_get_boolean("timeline-plaintext", 0) ){
@@ -717,11 +727,11 @@
717 case etWIKISTR: {
718 int limit = flag_alternateform ? va_arg(ap,int) : -1;
719 char *zWiki = va_arg(ap, char*);
720 Blob wiki;
721 blob_init(&wiki, zWiki, limit);
722 wiki_convert(&wiki, pBlob, wiki_convert_flags());
723 blob_reset(&wiki);
724 length = width = 0;
725 break;
726 }
727 case etERROR:
@@ -888,70 +898,158 @@
888 fossil_puts(blob_str(&b), 1);
889 blob_reset(&b);
890 va_end(ap);
891 }
892
893 /*
894 ** Like strcmp() except that it accepts NULL pointers. NULL sorts before
895 ** all non-NULL string pointers. Also, this strcmp() is a binary comparison
896 ** that does not consider locale.
897 */
898 int fossil_strcmp(const char *zA, const char *zB){
899 if( zA==0 ){
900 if( zB==0 ) return 0;
901 return -1;
902 }else if( zB==0 ){
903 return +1;
904 }else{
905 int a, b;
906 do{
907 a = *zA++;
908 b = *zB++;
909 }while( a==b && a!=0 );
910 return ((unsigned char)a) - (unsigned char)b;
911 }
912 }
913 int fossil_strncmp(const char *zA, const char *zB, int nByte){
914 if( zA==0 ){
915 if( zB==0 ) return 0;
916 return -1;
917 }else if( zB==0 ){
918 return +1;
919 }else if( nByte>0 ){
920 int a, b;
921 do{
922 a = *zA++;
923 b = *zB++;
924 }while( a==b && a!=0 && (--nByte)>0 );
925 return ((unsigned char)a) - (unsigned char)b;
926 }else{
927 return 0;
928 }
929 }
930
931 /*
932 ** Case insensitive string comparison.
933 */
934 int fossil_strnicmp(const char *zA, const char *zB, int nByte){
935 if( zA==0 ){
936 if( zB==0 ) return 0;
937 return -1;
938 }else if( zB==0 ){
939 return +1;
940 }
941 if( nByte<0 ) nByte = strlen(zB);
942 return sqlite3_strnicmp(zA, zB, nByte);
943 }
944 int fossil_stricmp(const char *zA, const char *zB){
945 int nByte;
946 int rc;
947 if( zA==0 ){
948 if( zB==0 ) return 0;
949 return -1;
950 }else if( zB==0 ){
951 return +1;
952 }
953 nByte = strlen(zB);
954 rc = sqlite3_strnicmp(zA, zB, nByte);
955 if( rc==0 && zA[nByte] ) rc = 1;
956 return rc;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
957 }
958
--- src/printf.c
+++ src/printf.c
@@ -13,14 +13,19 @@
13 ** [email protected]
14 ** http://www.hwaci.com/drh/
15 **
16 *******************************************************************************
17 **
18 ** This file contains implementions of routines for formatting output
19 ** (ex: mprintf()) and for output to the console.
20 */
21 #include "config.h"
22 #include "printf.h"
23 #if defined(_WIN32)
24 # include <io.h>
25 # include <fcntl.h>
26 #endif
27
28 /*
29 ** Conversion types fall into various categories as defined by the
30 ** following enumeration.
31 */
@@ -159,15 +164,20 @@
164
165 /*
166 ** Return an appropriate set of flags for wiki_convert() for displaying
167 ** comments on a timeline. These flag settings are determined by
168 ** configuration parameters.
169 **
170 ** The altForm2 argument is true for "%!w" (with the "!" alternate-form-2
171 ** flags) and is false for plain "%w". The ! indicates that the text is
172 ** to be rendered on a form rather than the timeline and that block markup
173 ** is acceptable even if the "timeline-block-markup" setting is false.
174 */
175 static int wiki_convert_flags(int altForm2){
176 static int wikiFlags = 0;
177 if( wikiFlags==0 ){
178 if( altForm2 || db_get_boolean("timeline-block-markup", 0) ){
179 wikiFlags = WIKI_INLINE | WIKI_NOBADLINKS;
180 }else{
181 wikiFlags = WIKI_INLINE | WIKI_NOBLOCK | WIKI_NOBADLINKS;
182 }
183 if( db_get_boolean("timeline-plaintext", 0) ){
@@ -717,11 +727,11 @@
727 case etWIKISTR: {
728 int limit = flag_alternateform ? va_arg(ap,int) : -1;
729 char *zWiki = va_arg(ap, char*);
730 Blob wiki;
731 blob_init(&wiki, zWiki, limit);
732 wiki_convert(&wiki, pBlob, wiki_convert_flags(flag_altform2));
733 blob_reset(&wiki);
734 length = width = 0;
735 break;
736 }
737 case etERROR:
@@ -888,70 +898,158 @@
898 fossil_puts(blob_str(&b), 1);
899 blob_reset(&b);
900 va_end(ap);
901 }
902
903
904 /*
905 ** The following variable becomes true while processing a fatal error
906 ** or a panic. If additional "recursive-fatal" errors occur while
907 ** shutting down, the recursive errors are silently ignored.
908 */
909 static int mainInFatalError = 0;
910
911 /*
912 ** Print an error message, rollback all databases, and quit. These
913 ** routines never return.
914 */
915 NORETURN void fossil_panic(const char *zFormat, ...){
916 char *z;
917 va_list ap;
918 int rc = 1;
919 static int once = 1;
920 mainInFatalError = 1;
921 va_start(ap, zFormat);
922 z = vmprintf(zFormat, ap);
923 va_end(ap);
924 #ifdef FOSSIL_ENABLE_JSON
925 if( g.json.isJsonMode ){
926 json_err( 0, z, 1 );
927 if( g.isHTTP ){
928 rc = 0 /* avoid HTTP 500 */;
929 }
930 }
931 else
932 #endif
933 {
934 if( g.cgiOutput && once ){
935 once = 0;
936 cgi_printf("<p class=\"generalError\">%h</p>", z);
937 cgi_reply();
938 }else if( !g.fQuiet ){
939 fossil_force_newline();
940 fossil_trace("Fossil internal error: %s\n", z);
941 }
942 }
943 free(z);
944 db_force_rollback();
945 fossil_exit(rc);
946 }
947
948 NORETURN void fossil_fatal(const char *zFormat, ...){
949 char *z;
950 int rc = 1;
951 va_list ap;
952 mainInFatalError = 1;
953 va_start(ap, zFormat);
954 z = vmprintf(zFormat, ap);
955 va_end(ap);
956 #ifdef FOSSIL_ENABLE_JSON
957 if( g.json.isJsonMode ){
958 json_err( g.json.resultCode, z, 1 );
959 if( g.isHTTP ){
960 rc = 0 /* avoid HTTP 500 */;
961 }
962 }
963 else
964 #endif
965 {
966 if( g.cgiOutput ){
967 g.cgiOutput = 0;
968 cgi_printf("<p class=\"generalError\">\n%h\n</p>\n", z);
969 cgi_reply();
970 }else if( !g.fQuiet ){
971 fossil_force_newline();
972 fossil_trace("%s\n", z);
973 }
974 }
975 free(z);
976 db_force_rollback();
977 fossil_exit(rc);
978 }
979
980 /* This routine works like fossil_fatal() except that if called
981 ** recursively, the recursive call is a no-op.
982 **
983 ** Use this in places where an error might occur while doing
984 ** fatal error shutdown processing. Unlike fossil_panic() and
985 ** fossil_fatal() which never return, this routine might return if
986 ** the fatal error handing is already in process. The caller must
987 ** be prepared for this routine to return.
988 */
989 void fossil_fatal_recursive(const char *zFormat, ...){
990 char *z;
991 va_list ap;
992 int rc = 1;
993 if( mainInFatalError ) return;
994 mainInFatalError = 1;
995 va_start(ap, zFormat);
996 z = vmprintf(zFormat, ap);
997 va_end(ap);
998 #ifdef FOSSIL_ENABLE_JSON
999 if( g.json.isJsonMode ){
1000 json_err( g.json.resultCode, z, 1 );
1001 if( g.isHTTP ){
1002 rc = 0 /* avoid HTTP 500 */;
1003 }
1004 } else
1005 #endif
1006 {
1007 if( g.cgiOutput ){
1008 g.cgiOutput = 0;
1009 cgi_printf("<p class=\"generalError\">\n%h\n</p>\n", z);
1010 cgi_reply();
1011 }else{
1012 fossil_force_newline();
1013 fossil_trace("%s\n", z);
1014 }
1015 }
1016 db_force_rollback();
1017 fossil_exit(rc);
1018 }
1019
1020
1021 /* Print a warning message */
1022 void fossil_warning(const char *zFormat, ...){
1023 char *z;
1024 va_list ap;
1025 va_start(ap, zFormat);
1026 z = vmprintf(zFormat, ap);
1027 va_end(ap);
1028 #ifdef FOSSIL_ENABLE_JSON
1029 if(g.json.isJsonMode){
1030 json_warn( FSL_JSON_W_UNKNOWN, z );
1031 }else
1032 #endif
1033 {
1034 if( g.cgiOutput ){
1035 cgi_printf("<p class=\"generalError\">\n%h\n</p>\n", z);
1036 }else{
1037 fossil_force_newline();
1038 fossil_trace("%s\n", z);
1039 }
1040 }
1041 free(z);
1042 }
1043
1044 /*
1045 ** Turn off any NL to CRNL translation on the stream given as an
1046 ** argument. This is a no-op on unix but is necessary on windows.
1047 */
1048 void fossil_binary_mode(FILE *p){
1049 #if defined(_WIN32)
1050 _setmode(_fileno(p), _O_BINARY);
1051 #endif
1052 #ifdef __EMX__ /* OS/2 */
1053 setmode(fileno(p), O_BINARY);
1054 #endif
1055 }
1056
+4 -2
--- src/rebuild.c
+++ src/rebuild.c
@@ -785,10 +785,12 @@
785785
int bVerily = find_option("verily",0,0)!=0;
786786
int bForce = find_option("force", "f", 0)!=0;
787787
int privateOnly = find_option("private",0,0)!=0;
788788
int bNeedRebuild = 0;
789789
db_find_and_open_repository(OPEN_ANY_SCHEMA, 2);
790
+ db_close(1);
791
+ db_open_repository(g.zRepositoryName);
790792
if( !bForce ){
791793
Blob ans;
792794
char cReply;
793795
blob_zero(&ans);
794796
prompt_user(
@@ -841,11 +843,11 @@
841843
Blob aContent; /* content of the just read artifact */
842844
static int nFileRead = 0;
843845
void *zUnicodePath;
844846
char *zUtf8Name;
845847
846
- zUnicodePath = fossil_utf8_to_unicode(zPath);
848
+ zUnicodePath = fossil_utf8_to_filename(zPath);
847849
d = opendir(zUnicodePath);
848850
if( d ){
849851
while( (pEntry=readdir(d))!=0 ){
850852
Blob path;
851853
char *zSubpath;
@@ -875,11 +877,11 @@
875877
closedir(d);
876878
}else {
877879
fossil_panic("encountered error %d while trying to open \"%s\".",
878880
errno, g.argv[3]);
879881
}
880
- fossil_unicode_free(zUnicodePath);
882
+ fossil_filename_free(zUnicodePath);
881883
}
882884
883885
/*
884886
** COMMAND: reconstruct*
885887
**
886888
--- src/rebuild.c
+++ src/rebuild.c
@@ -785,10 +785,12 @@
785 int bVerily = find_option("verily",0,0)!=0;
786 int bForce = find_option("force", "f", 0)!=0;
787 int privateOnly = find_option("private",0,0)!=0;
788 int bNeedRebuild = 0;
789 db_find_and_open_repository(OPEN_ANY_SCHEMA, 2);
 
 
790 if( !bForce ){
791 Blob ans;
792 char cReply;
793 blob_zero(&ans);
794 prompt_user(
@@ -841,11 +843,11 @@
841 Blob aContent; /* content of the just read artifact */
842 static int nFileRead = 0;
843 void *zUnicodePath;
844 char *zUtf8Name;
845
846 zUnicodePath = fossil_utf8_to_unicode(zPath);
847 d = opendir(zUnicodePath);
848 if( d ){
849 while( (pEntry=readdir(d))!=0 ){
850 Blob path;
851 char *zSubpath;
@@ -875,11 +877,11 @@
875 closedir(d);
876 }else {
877 fossil_panic("encountered error %d while trying to open \"%s\".",
878 errno, g.argv[3]);
879 }
880 fossil_unicode_free(zUnicodePath);
881 }
882
883 /*
884 ** COMMAND: reconstruct*
885 **
886
--- src/rebuild.c
+++ src/rebuild.c
@@ -785,10 +785,12 @@
785 int bVerily = find_option("verily",0,0)!=0;
786 int bForce = find_option("force", "f", 0)!=0;
787 int privateOnly = find_option("private",0,0)!=0;
788 int bNeedRebuild = 0;
789 db_find_and_open_repository(OPEN_ANY_SCHEMA, 2);
790 db_close(1);
791 db_open_repository(g.zRepositoryName);
792 if( !bForce ){
793 Blob ans;
794 char cReply;
795 blob_zero(&ans);
796 prompt_user(
@@ -841,11 +843,11 @@
843 Blob aContent; /* content of the just read artifact */
844 static int nFileRead = 0;
845 void *zUnicodePath;
846 char *zUtf8Name;
847
848 zUnicodePath = fossil_utf8_to_filename(zPath);
849 d = opendir(zUnicodePath);
850 if( d ){
851 while( (pEntry=readdir(d))!=0 ){
852 Blob path;
853 char *zSubpath;
@@ -875,11 +877,11 @@
877 closedir(d);
878 }else {
879 fossil_panic("encountered error %d while trying to open \"%s\".",
880 errno, g.argv[3]);
881 }
882 fossil_filename_free(zUnicodePath);
883 }
884
885 /*
886 ** COMMAND: reconstruct*
887 **
888
+3 -2
--- src/regexp.c
+++ src/regexp.c
@@ -111,11 +111,11 @@
111111
ReInput sIn; /* Regular expression text */
112112
const char *zErr; /* Error message to return */
113113
char *aOp; /* Operators for the virtual machine */
114114
int *aArg; /* Arguments to each operator */
115115
unsigned (*xNextChar)(ReInput*); /* Next character function */
116
- char zInit[12]; /* Initial text to match */
116
+ unsigned char zInit[12]; /* Initial text to match */
117117
int nInit; /* Number of characters in zInit */
118118
unsigned nState; /* Number of entries in aOp[] and aArg[] */
119119
unsigned nAlloc; /* Slots allocated for aOp[] and aArg[] */
120120
};
121121
#endif
@@ -197,11 +197,12 @@
197197
198198
/* Look for the initial prefix match, if there is one. */
199199
if( pRe->nInit ){
200200
unsigned char x = pRe->zInit[0];
201201
while( in.i+pRe->nInit<=in.mx
202
- && (zIn[in.i]!=x || memcmp(zIn+in.i, pRe->zInit, pRe->nInit)!=0)
202
+ && (zIn[in.i]!=x ||
203
+ strncmp((const char*)zIn+in.i, (const char*)pRe->zInit, pRe->nInit)!=0)
203204
){
204205
in.i++;
205206
}
206207
if( in.i+pRe->nInit>in.mx ) return 0;
207208
}
208209
--- src/regexp.c
+++ src/regexp.c
@@ -111,11 +111,11 @@
111 ReInput sIn; /* Regular expression text */
112 const char *zErr; /* Error message to return */
113 char *aOp; /* Operators for the virtual machine */
114 int *aArg; /* Arguments to each operator */
115 unsigned (*xNextChar)(ReInput*); /* Next character function */
116 char zInit[12]; /* Initial text to match */
117 int nInit; /* Number of characters in zInit */
118 unsigned nState; /* Number of entries in aOp[] and aArg[] */
119 unsigned nAlloc; /* Slots allocated for aOp[] and aArg[] */
120 };
121 #endif
@@ -197,11 +197,12 @@
197
198 /* Look for the initial prefix match, if there is one. */
199 if( pRe->nInit ){
200 unsigned char x = pRe->zInit[0];
201 while( in.i+pRe->nInit<=in.mx
202 && (zIn[in.i]!=x || memcmp(zIn+in.i, pRe->zInit, pRe->nInit)!=0)
 
203 ){
204 in.i++;
205 }
206 if( in.i+pRe->nInit>in.mx ) return 0;
207 }
208
--- src/regexp.c
+++ src/regexp.c
@@ -111,11 +111,11 @@
111 ReInput sIn; /* Regular expression text */
112 const char *zErr; /* Error message to return */
113 char *aOp; /* Operators for the virtual machine */
114 int *aArg; /* Arguments to each operator */
115 unsigned (*xNextChar)(ReInput*); /* Next character function */
116 unsigned char zInit[12]; /* Initial text to match */
117 int nInit; /* Number of characters in zInit */
118 unsigned nState; /* Number of entries in aOp[] and aArg[] */
119 unsigned nAlloc; /* Slots allocated for aOp[] and aArg[] */
120 };
121 #endif
@@ -197,11 +197,12 @@
197
198 /* Look for the initial prefix match, if there is one. */
199 if( pRe->nInit ){
200 unsigned char x = pRe->zInit[0];
201 while( in.i+pRe->nInit<=in.mx
202 && (zIn[in.i]!=x ||
203 strncmp((const char*)zIn+in.i, (const char*)pRe->zInit, pRe->nInit)!=0)
204 ){
205 in.i++;
206 }
207 if( in.i+pRe->nInit>in.mx ) return 0;
208 }
209
+56
--- src/rss.c
+++ src/rss.c
@@ -22,18 +22,37 @@
2222
#include "rss.h"
2323
#include <assert.h>
2424
2525
/*
2626
** WEBPAGE: timeline.rss
27
+** URL: /timeline.rss?y=TYPE&n=LIMIT&tkt=UUID&tag=TAG&wiki=NAME&name=FILENAME
28
+**
29
+** Produce an RSS feed of the timeline.
30
+**
31
+** TYPE may be: all, ci (show checkins only), t (show tickets only),
32
+** w (show wiki only). LIMIT is the number of items to show.
33
+**
34
+** tkt=UUID filters for only those events for the specified ticket. tag=TAG
35
+** filters for a tag, and wiki=NAME for a wiki page. Only one may be used.
36
+**
37
+** In addition, name=FILENAME filters for a specific file. This may be
38
+** combined with one of the other filters (useful for looking at a specific
39
+** branch).
2740
*/
41
+
2842
void page_timeline_rss(void){
2943
Stmt q;
3044
int nLine=0;
3145
char *zPubDate, *zProjectName, *zProjectDescr, *zFreeProjectName=0;
3246
Blob bSQL;
3347
const char *zType = PD("y","all"); /* Type of events. All if NULL */
48
+ const char *zTicketUuid = PD("tkt",NULL);
49
+ const char *zTag = PD("tag",NULL);
50
+ const char *zFilename = PD("name",NULL);
51
+ const char *zWiki = PD("wiki",NULL);
3452
int nLimit = atoi(PD("n","20"));
53
+ int nTagId;
3554
const char zSQL1[] =
3655
@ SELECT
3756
@ blob.rid,
3857
@ uuid,
3958
@ event.mtime,
@@ -62,10 +81,11 @@
6281
if( !g.perm.Read ){
6382
if( g.perm.RdTkt && g.perm.RdWiki ){
6483
blob_append(&bSQL, " AND event.type!='ci'", -1);
6584
}else if( g.perm.RdTkt ){
6685
blob_append(&bSQL, " AND event.type=='t'", -1);
86
+
6787
}else{
6888
blob_append(&bSQL, " AND event.type=='w'", -1);
6989
}
7090
}else if( !g.perm.RdWiki ){
7191
if( g.perm.RdTkt ){
@@ -76,10 +96,46 @@
7696
}else if( !g.perm.RdTkt ){
7797
assert( !g.perm.RdTkt &&& g.perm.Read && g.perm.RdWiki );
7898
blob_append(&bSQL, " AND event.type!='t'", -1);
7999
}
80100
}
101
+
102
+ if( zTicketUuid ){
103
+ nTagId = db_int(0, "SELECT tagid FROM tag WHERE tagname GLOB 'tkt-%q*'",
104
+ zTicketUuid);
105
+ if ( nTagId==0 ){
106
+ nTagId = -1;
107
+ }
108
+ }else if( zTag ){
109
+ nTagId = db_int(0, "SELECT tagid FROM tag WHERE tagname GLOB 'sym-%q*'",
110
+ zTag);
111
+ if ( nTagId==0 ){
112
+ nTagId = -1;
113
+ }
114
+ }else if( zWiki ){
115
+ nTagId = db_int(0, "SELECT tagid FROM tag WHERE tagname GLOB 'wiki-%q*'",
116
+ zWiki);
117
+ if ( nTagId==0 ){
118
+ nTagId = -1;
119
+ }
120
+ }else{
121
+ nTagId = 0;
122
+ }
123
+
124
+ if( nTagId==-1 ){
125
+ blob_appendf(&bSQL, " AND 0");
126
+ }else if( nTagId!=0 ){
127
+ blob_appendf(&bSQL, " AND (EXISTS(SELECT 1 FROM tagxref"
128
+ " WHERE tagid=%d AND tagtype>0 AND rid=blob.rid))", nTagId);
129
+ }
130
+
131
+ if( zFilename ){
132
+ blob_appendf(&bSQL,
133
+ " AND (SELECT mlink.fnid FROM mlink WHERE event.objid=mlink.mid) IN (SELECT fnid FROM filename WHERE name=%Q %s)",
134
+ zFilename, filename_collation()
135
+ );
136
+ }
81137
82138
blob_append( &bSQL, " ORDER BY event.mtime DESC", -1 );
83139
84140
cgi_set_content_type("application/rss+xml");
85141
86142
--- src/rss.c
+++ src/rss.c
@@ -22,18 +22,37 @@
22 #include "rss.h"
23 #include <assert.h>
24
25 /*
26 ** WEBPAGE: timeline.rss
 
 
 
 
 
 
 
 
 
 
 
 
 
27 */
 
28 void page_timeline_rss(void){
29 Stmt q;
30 int nLine=0;
31 char *zPubDate, *zProjectName, *zProjectDescr, *zFreeProjectName=0;
32 Blob bSQL;
33 const char *zType = PD("y","all"); /* Type of events. All if NULL */
 
 
 
 
34 int nLimit = atoi(PD("n","20"));
 
35 const char zSQL1[] =
36 @ SELECT
37 @ blob.rid,
38 @ uuid,
39 @ event.mtime,
@@ -62,10 +81,11 @@
62 if( !g.perm.Read ){
63 if( g.perm.RdTkt && g.perm.RdWiki ){
64 blob_append(&bSQL, " AND event.type!='ci'", -1);
65 }else if( g.perm.RdTkt ){
66 blob_append(&bSQL, " AND event.type=='t'", -1);
 
67 }else{
68 blob_append(&bSQL, " AND event.type=='w'", -1);
69 }
70 }else if( !g.perm.RdWiki ){
71 if( g.perm.RdTkt ){
@@ -76,10 +96,46 @@
76 }else if( !g.perm.RdTkt ){
77 assert( !g.perm.RdTkt &&& g.perm.Read && g.perm.RdWiki );
78 blob_append(&bSQL, " AND event.type!='t'", -1);
79 }
80 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
81
82 blob_append( &bSQL, " ORDER BY event.mtime DESC", -1 );
83
84 cgi_set_content_type("application/rss+xml");
85
86
--- src/rss.c
+++ src/rss.c
@@ -22,18 +22,37 @@
22 #include "rss.h"
23 #include <assert.h>
24
25 /*
26 ** WEBPAGE: timeline.rss
27 ** URL: /timeline.rss?y=TYPE&n=LIMIT&tkt=UUID&tag=TAG&wiki=NAME&name=FILENAME
28 **
29 ** Produce an RSS feed of the timeline.
30 **
31 ** TYPE may be: all, ci (show checkins only), t (show tickets only),
32 ** w (show wiki only). LIMIT is the number of items to show.
33 **
34 ** tkt=UUID filters for only those events for the specified ticket. tag=TAG
35 ** filters for a tag, and wiki=NAME for a wiki page. Only one may be used.
36 **
37 ** In addition, name=FILENAME filters for a specific file. This may be
38 ** combined with one of the other filters (useful for looking at a specific
39 ** branch).
40 */
41
42 void page_timeline_rss(void){
43 Stmt q;
44 int nLine=0;
45 char *zPubDate, *zProjectName, *zProjectDescr, *zFreeProjectName=0;
46 Blob bSQL;
47 const char *zType = PD("y","all"); /* Type of events. All if NULL */
48 const char *zTicketUuid = PD("tkt",NULL);
49 const char *zTag = PD("tag",NULL);
50 const char *zFilename = PD("name",NULL);
51 const char *zWiki = PD("wiki",NULL);
52 int nLimit = atoi(PD("n","20"));
53 int nTagId;
54 const char zSQL1[] =
55 @ SELECT
56 @ blob.rid,
57 @ uuid,
58 @ event.mtime,
@@ -62,10 +81,11 @@
81 if( !g.perm.Read ){
82 if( g.perm.RdTkt && g.perm.RdWiki ){
83 blob_append(&bSQL, " AND event.type!='ci'", -1);
84 }else if( g.perm.RdTkt ){
85 blob_append(&bSQL, " AND event.type=='t'", -1);
86
87 }else{
88 blob_append(&bSQL, " AND event.type=='w'", -1);
89 }
90 }else if( !g.perm.RdWiki ){
91 if( g.perm.RdTkt ){
@@ -76,10 +96,46 @@
96 }else if( !g.perm.RdTkt ){
97 assert( !g.perm.RdTkt &&& g.perm.Read && g.perm.RdWiki );
98 blob_append(&bSQL, " AND event.type!='t'", -1);
99 }
100 }
101
102 if( zTicketUuid ){
103 nTagId = db_int(0, "SELECT tagid FROM tag WHERE tagname GLOB 'tkt-%q*'",
104 zTicketUuid);
105 if ( nTagId==0 ){
106 nTagId = -1;
107 }
108 }else if( zTag ){
109 nTagId = db_int(0, "SELECT tagid FROM tag WHERE tagname GLOB 'sym-%q*'",
110 zTag);
111 if ( nTagId==0 ){
112 nTagId = -1;
113 }
114 }else if( zWiki ){
115 nTagId = db_int(0, "SELECT tagid FROM tag WHERE tagname GLOB 'wiki-%q*'",
116 zWiki);
117 if ( nTagId==0 ){
118 nTagId = -1;
119 }
120 }else{
121 nTagId = 0;
122 }
123
124 if( nTagId==-1 ){
125 blob_appendf(&bSQL, " AND 0");
126 }else if( nTagId!=0 ){
127 blob_appendf(&bSQL, " AND (EXISTS(SELECT 1 FROM tagxref"
128 " WHERE tagid=%d AND tagtype>0 AND rid=blob.rid))", nTagId);
129 }
130
131 if( zFilename ){
132 blob_appendf(&bSQL,
133 " AND (SELECT mlink.fnid FROM mlink WHERE event.objid=mlink.mid) IN (SELECT fnid FROM filename WHERE name=%Q %s)",
134 zFilename, filename_collation()
135 );
136 }
137
138 blob_append( &bSQL, " ORDER BY event.mtime DESC", -1 );
139
140 cgi_set_content_type("application/rss+xml");
141
142
+20 -20
--- src/setup.c
+++ src/setup.c
@@ -139,11 +139,11 @@
139139
@ <table class="usetupLayoutTable">
140140
@ <tr><td class="usetupColumnLayout">
141141
@ <span class="note">Users:</span>
142142
@ <table class="usetupUserList">
143143
prevLevel = 0;
144
- db_prepare(&s,
144
+ db_prepare(&s,
145145
"SELECT uid, login, cap, info, 1 FROM user"
146146
" WHERE login IN ('anonymous','nobody','developer','reader') "
147147
" UNION ALL "
148148
"SELECT uid, login, cap, info, 2 FROM user"
149149
" WHERE login NOT IN ('anonymous','nobody','developer','reader') "
@@ -250,11 +250,11 @@
250250
@ <td><i>Write-Tkt:</i> Edit tickets</td></tr>
251251
@ <tr><td valign="top"><b>x</b></td>
252252
@ <td><i>Private:</i> Push and/or pull private branches</td></tr>
253253
@ <tr><td valign="top"><b>z</b></td>
254254
@ <td><i>Zip download:</i> Download a baseline via the
255
- @ <tt>/zip</tt> URL even without
255
+ @ <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>
259259
@ </li>
260260
@
@@ -357,11 +357,11 @@
357357
style_header("User Creation Error");
358358
@ <span class="loginError">Empty login not allowed.</span>
359359
@
360360
@ <p><a href="setup_uedit?id=%d(uid)">[Bummer]</a></p>
361361
style_footer();
362
- return;
362
+ return;
363363
}
364364
if( isValidPwString(zPw) ){
365365
zPw = sha1_shared_secret(zPw, zLogin, 0);
366366
}else{
367367
zPw = db_text(0, "SELECT pw FROM user WHERE uid=%d", uid);
@@ -394,11 +394,11 @@
394394
" SELECT %Q WHERE NOT EXISTS(SELECT 1 FROM user WHERE login=%Q);",
395395
zLogin, zLogin
396396
);
397397
zOldLogin = zLogin;
398398
}
399
- blob_appendf(&sql,
399
+ blob_appendf(&sql,
400400
"UPDATE user SET login=%Q,"
401401
" pw=coalesce(shared_secret(%Q,%Q,"
402402
"(SELECT value FROM config WHERE name='project-code')),pw),"
403403
" info=%Q,"
404404
" cap=%Q,"
@@ -643,11 +643,11 @@
643643
@ </p></li>
644644
@
645645
@ <li><p>
646646
@ The <span class="capability">Delete</span> privilege give the user the
647647
@ ability to erase wiki, tickets, and attachments that have been added
648
- @ by anonymous users. This capability is intended for deletion of spam.
648
+ @ by anonymous users. This capability is intended for deletion of spam.
649649
@ The delete capability is only in effect for 24 hours after the item
650650
@ is first posted. The <span class="usertype">Setup</span> user can
651651
@ delete anything at any time.
652652
@ </p></li>
653653
@
@@ -700,11 +700,11 @@
700700
@ </p></li>
701701
@
702702
@ <li><p>
703703
@ The <span class="capability">EMail</span> privilege allows the display of
704704
@ sensitive information such as the email address of users and contact
705
- @ information on tickets. Recommended OFF for
705
+ @ information on tickets. Recommended OFF for
706706
@ <span class="usertype">anonymous</span> and for
707707
@ <span class="usertype">nobody</span> but ON for
708708
@ <span class="usertype">developer</span>.
709709
@ </p></li>
710710
@
@@ -724,11 +724,11 @@
724724
@ <ul>
725725
@ <li><p>
726726
@ No login is required for user <span class="usertype">nobody</span>. The
727727
@ capabilities of the <span class="usertype">nobody</span> user are
728728
@ inherited by all users, regardless of whether or not they are logged in.
729
- @ To disable universal access to the repository, make sure no user named
729
+ @ To disable universal access to the repository, make sure no user named
730730
@ <span class="usertype">nobody</span> exists or that the
731731
@ <span class="usertype">nobody</span> user has no capabilities
732732
@ enabled. The password for <span class="usertype">nobody</span> is ignore.
733733
@ To avoid problems with spiders overloading the server, it is recommended
734734
@ that the <span class="capability">h</span> (Hyperlinks) capability be
@@ -749,13 +749,13 @@
749749
@
750750
@ <li><p>
751751
@ The <span class="usertype">developer</span> user is intended as a template
752752
@ for trusted users with check-in privileges. When adding new trusted users,
753753
@ simply select the <span class="capability">developer</span> privilege to
754
- @ cause the new user to inherit all privileges of the
754
+ @ cause the new user to inherit all privileges of the
755755
@ <span class="usertype">developer</span>
756
- @ user. Similarly, the <span class="usertype">reader</span> user is a
756
+ @ user. Similarly, the <span class="usertype">reader</span> user is a
757757
@ template for users who are allowed more access than
758758
@ <span class="usertype">anonymous</span>,
759759
@ but less than a <span class="usertype">developer</span>.
760760
@ </p></li>
761761
@ </ul>
@@ -833,11 +833,11 @@
833833
z = zQ;
834834
}
835835
if( rows>0 && cols>0 ){
836836
@ <textarea id="id%s(zQP)" name="%s(zQP)" rows="%d(rows)"
837837
@ cols="%d(cols)">%h(z)</textarea>
838
- if (zLabel && *zLabel){
838
+ if( zLabel && *zLabel ){
839839
@ <span class="textareaLabel">%s(zLabel)</span>
840840
}
841841
}
842842
}
843843
@@ -895,11 +895,11 @@
895895
@ login name of a valid user and no other login credentials are available,
896896
@ then the REMOTE_USER is accepted as an authenticated user.
897897
@ </p>
898898
@
899899
@ <hr />
900
- entry_attribute("IP address terms used in login cookie", 3,
900
+ entry_attribute("IP address terms used in login cookie", 3,
901901
"ip-prefix-terms", "ipt", "2");
902902
@ <p>The number of octets of of the IP address used in the login cookie.
903903
@ Set to zero to omit the IP address from the login cookie. A value of
904904
@ 2 is recommended.
905905
@ </p>
@@ -958,23 +958,23 @@
958958
entry_attribute("Public pages", 30, "public-pages",
959959
"pubpage", "");
960960
@ <p>A comma-separated list of glob patterns for pages that are accessible
961961
@ without needing a login and using the privileges given by the
962962
@ "Default privileges" setting below. Example use case: Set this field
963
- @ to "/doc/trunk/www/*" to give anonymous users read-only permission to the
963
+ @ to "/doc/trunk/www/*" to give anonymous users read-only permission to the
964964
@ latest version of the embedded documentation in the www/ folder without
965965
@ allowing them to see the rest of the source code.
966966
@ </p>
967967
968968
@ <hr />
969969
onoff_attribute("Allow users to register themselves",
970970
"self-register", "selfregister", 0);
971
- @ <p>Allow users to register themselves through the HTTP UI.
972
- @ The registration form always requires filling in a CAPTCHA
971
+ @ <p>Allow users to register themselves through the HTTP UI.
972
+ @ The registration form always requires filling in a CAPTCHA
973973
@ (<em>auto-captcha</em> setting is ignored). Still, bear in mind that anyone
974974
@ can register under any user name. This option is useful for public projects
975
- @ where you do not want everyone in any ticket discussion to be named
975
+ @ where you do not want everyone in any ticket discussion to be named
976976
@ "Anonymous".</p>
977977
978978
@ <hr />
979979
entry_attribute("Default privileges", 10, "default-perms",
980980
"defaultperms", "u");
@@ -1128,11 +1128,11 @@
11281128
"timeline-utc", "utc", 1);
11291129
@ <p>Show times as UTC (also sometimes called Greenwich Mean Time (GMT) or
11301130
@ Zulu) instead of in local time. On this server, local time is currently
11311131
g.fTimeFormat = 2;
11321132
tmDiff = db_double(0.0, "SELECT julianday('now')");
1133
- tmDiff = db_double(0.0,
1133
+ tmDiff = db_double(0.0,
11341134
"SELECT (julianday(%.17g,'localtime')-julianday(%.17g))*24.0",
11351135
tmDiff, tmDiff);
11361136
sqlite3_snprintf(sizeof(zTmDiff), zTmDiff, "%.1f", tmDiff);
11371137
if( strcmp(zTmDiff, "0.0")==0 ){
11381138
@ the same as UTC and so this setting will make no difference in
@@ -1450,11 +1450,11 @@
14501450
onoff_attribute("Moderate ticket changes",
14511451
"modreq-tkt", "modreq-tkt", 0);
14521452
@ <p>When enabled, any change to tickets is subject to the approval
14531453
@ a ticket moderator - a user with the "q" or Mod-Tkt privilege.
14541454
@ Ticket changes enter the system and are shown locally, but are not
1455
- @ synced until they are approved. The moderator has the option to
1455
+ @ synced until they are approved. The moderator has the option to
14561456
@ delete the change rather than approve it. Ticket changes made by
14571457
@ a user who hwas the Mod-Tkt privilege are never subject to
14581458
@ moderation.
14591459
@
14601460
@ <hr />
@@ -1461,16 +1461,16 @@
14611461
onoff_attribute("Moderate wiki changes",
14621462
"modreq-wiki", "modreq-wiki", 0);
14631463
@ <p>When enabled, any change to wiki is subject to the approval
14641464
@ a ticket moderator - a user with the "l" or Mod-Wiki privilege.
14651465
@ Wiki changes enter the system and are shown locally, but are not
1466
- @ synced until they are approved. The moderator has the option to
1466
+ @ synced until they are approved. The moderator has the option to
14671467
@ delete the change rather than approve it. Wiki changes made by
14681468
@ a user who has the Mod-Wiki privilege are never subject to
14691469
@ moderation.
14701470
@ </p>
1471
-
1471
+
14721472
@ <hr />
14731473
@ <p><input type="submit" name="submit" value="Apply Changes" /></p>
14741474
@ </div></form>
14751475
db_end_transaction(0);
14761476
style_footer();
@@ -1678,11 +1678,11 @@
16781678
@
16791679
@ <p>Only a the first statement in the entry box will be run.
16801680
@ Any subsequent statements will be silently ignored.</p>
16811681
@
16821682
@ <p>Database names:<ul><li>repository &rarr; %s(db_name("repository"))
1683
- if( g.configOpen ){
1683
+ if( g.zConfigDbName ){
16841684
@ <li>config &rarr; %s(db_name("configdb"))
16851685
}
16861686
if( g.localOpen ){
16871687
@ <li>local-checkout &rarr; %s(db_name("localdb"))
16881688
}
16891689
--- src/setup.c
+++ src/setup.c
@@ -139,11 +139,11 @@
139 @ <table class="usetupLayoutTable">
140 @ <tr><td class="usetupColumnLayout">
141 @ <span class="note">Users:</span>
142 @ <table class="usetupUserList">
143 prevLevel = 0;
144 db_prepare(&s,
145 "SELECT uid, login, cap, info, 1 FROM user"
146 " WHERE login IN ('anonymous','nobody','developer','reader') "
147 " UNION ALL "
148 "SELECT uid, login, cap, info, 2 FROM user"
149 " WHERE login NOT IN ('anonymous','nobody','developer','reader') "
@@ -250,11 +250,11 @@
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>
259 @ </li>
260 @
@@ -357,11 +357,11 @@
357 style_header("User Creation Error");
358 @ <span class="loginError">Empty login not allowed.</span>
359 @
360 @ <p><a href="setup_uedit?id=%d(uid)">[Bummer]</a></p>
361 style_footer();
362 return;
363 }
364 if( isValidPwString(zPw) ){
365 zPw = sha1_shared_secret(zPw, zLogin, 0);
366 }else{
367 zPw = db_text(0, "SELECT pw FROM user WHERE uid=%d", uid);
@@ -394,11 +394,11 @@
394 " SELECT %Q WHERE NOT EXISTS(SELECT 1 FROM user WHERE login=%Q);",
395 zLogin, zLogin
396 );
397 zOldLogin = zLogin;
398 }
399 blob_appendf(&sql,
400 "UPDATE user SET login=%Q,"
401 " pw=coalesce(shared_secret(%Q,%Q,"
402 "(SELECT value FROM config WHERE name='project-code')),pw),"
403 " info=%Q,"
404 " cap=%Q,"
@@ -643,11 +643,11 @@
643 @ </p></li>
644 @
645 @ <li><p>
646 @ The <span class="capability">Delete</span> privilege give the user the
647 @ ability to erase wiki, tickets, and attachments that have been added
648 @ by anonymous users. This capability is intended for deletion of spam.
649 @ The delete capability is only in effect for 24 hours after the item
650 @ is first posted. The <span class="usertype">Setup</span> user can
651 @ delete anything at any time.
652 @ </p></li>
653 @
@@ -700,11 +700,11 @@
700 @ </p></li>
701 @
702 @ <li><p>
703 @ The <span class="capability">EMail</span> privilege allows the display of
704 @ sensitive information such as the email address of users and contact
705 @ information on tickets. Recommended OFF for
706 @ <span class="usertype">anonymous</span> and for
707 @ <span class="usertype">nobody</span> but ON for
708 @ <span class="usertype">developer</span>.
709 @ </p></li>
710 @
@@ -724,11 +724,11 @@
724 @ <ul>
725 @ <li><p>
726 @ No login is required for user <span class="usertype">nobody</span>. The
727 @ capabilities of the <span class="usertype">nobody</span> user are
728 @ inherited by all users, regardless of whether or not they are logged in.
729 @ To disable universal access to the repository, make sure no user named
730 @ <span class="usertype">nobody</span> exists or that the
731 @ <span class="usertype">nobody</span> user has no capabilities
732 @ enabled. The password for <span class="usertype">nobody</span> is ignore.
733 @ To avoid problems with spiders overloading the server, it is recommended
734 @ that the <span class="capability">h</span> (Hyperlinks) capability be
@@ -749,13 +749,13 @@
749 @
750 @ <li><p>
751 @ The <span class="usertype">developer</span> user is intended as a template
752 @ for trusted users with check-in privileges. When adding new trusted users,
753 @ simply select the <span class="capability">developer</span> privilege to
754 @ cause the new user to inherit all privileges of the
755 @ <span class="usertype">developer</span>
756 @ user. Similarly, the <span class="usertype">reader</span> user is a
757 @ template for users who are allowed more access than
758 @ <span class="usertype">anonymous</span>,
759 @ but less than a <span class="usertype">developer</span>.
760 @ </p></li>
761 @ </ul>
@@ -833,11 +833,11 @@
833 z = zQ;
834 }
835 if( rows>0 && cols>0 ){
836 @ <textarea id="id%s(zQP)" name="%s(zQP)" rows="%d(rows)"
837 @ cols="%d(cols)">%h(z)</textarea>
838 if (zLabel && *zLabel){
839 @ <span class="textareaLabel">%s(zLabel)</span>
840 }
841 }
842 }
843
@@ -895,11 +895,11 @@
895 @ login name of a valid user and no other login credentials are available,
896 @ then the REMOTE_USER is accepted as an authenticated user.
897 @ </p>
898 @
899 @ <hr />
900 entry_attribute("IP address terms used in login cookie", 3,
901 "ip-prefix-terms", "ipt", "2");
902 @ <p>The number of octets of of the IP address used in the login cookie.
903 @ Set to zero to omit the IP address from the login cookie. A value of
904 @ 2 is recommended.
905 @ </p>
@@ -958,23 +958,23 @@
958 entry_attribute("Public pages", 30, "public-pages",
959 "pubpage", "");
960 @ <p>A comma-separated list of glob patterns for pages that are accessible
961 @ without needing a login and using the privileges given by the
962 @ "Default privileges" setting below. Example use case: Set this field
963 @ to "/doc/trunk/www/*" to give anonymous users read-only permission to the
964 @ latest version of the embedded documentation in the www/ folder without
965 @ allowing them to see the rest of the source code.
966 @ </p>
967
968 @ <hr />
969 onoff_attribute("Allow users to register themselves",
970 "self-register", "selfregister", 0);
971 @ <p>Allow users to register themselves through the HTTP UI.
972 @ The registration form always requires filling in a CAPTCHA
973 @ (<em>auto-captcha</em> setting is ignored). Still, bear in mind that anyone
974 @ can register under any user name. This option is useful for public projects
975 @ where you do not want everyone in any ticket discussion to be named
976 @ "Anonymous".</p>
977
978 @ <hr />
979 entry_attribute("Default privileges", 10, "default-perms",
980 "defaultperms", "u");
@@ -1128,11 +1128,11 @@
1128 "timeline-utc", "utc", 1);
1129 @ <p>Show times as UTC (also sometimes called Greenwich Mean Time (GMT) or
1130 @ Zulu) instead of in local time. On this server, local time is currently
1131 g.fTimeFormat = 2;
1132 tmDiff = db_double(0.0, "SELECT julianday('now')");
1133 tmDiff = db_double(0.0,
1134 "SELECT (julianday(%.17g,'localtime')-julianday(%.17g))*24.0",
1135 tmDiff, tmDiff);
1136 sqlite3_snprintf(sizeof(zTmDiff), zTmDiff, "%.1f", tmDiff);
1137 if( strcmp(zTmDiff, "0.0")==0 ){
1138 @ the same as UTC and so this setting will make no difference in
@@ -1450,11 +1450,11 @@
1450 onoff_attribute("Moderate ticket changes",
1451 "modreq-tkt", "modreq-tkt", 0);
1452 @ <p>When enabled, any change to tickets is subject to the approval
1453 @ a ticket moderator - a user with the "q" or Mod-Tkt privilege.
1454 @ Ticket changes enter the system and are shown locally, but are not
1455 @ synced until they are approved. The moderator has the option to
1456 @ delete the change rather than approve it. Ticket changes made by
1457 @ a user who hwas the Mod-Tkt privilege are never subject to
1458 @ moderation.
1459 @
1460 @ <hr />
@@ -1461,16 +1461,16 @@
1461 onoff_attribute("Moderate wiki changes",
1462 "modreq-wiki", "modreq-wiki", 0);
1463 @ <p>When enabled, any change to wiki is subject to the approval
1464 @ a ticket moderator - a user with the "l" or Mod-Wiki privilege.
1465 @ Wiki changes enter the system and are shown locally, but are not
1466 @ synced until they are approved. The moderator has the option to
1467 @ delete the change rather than approve it. Wiki changes made by
1468 @ a user who has the Mod-Wiki privilege are never subject to
1469 @ moderation.
1470 @ </p>
1471
1472 @ <hr />
1473 @ <p><input type="submit" name="submit" value="Apply Changes" /></p>
1474 @ </div></form>
1475 db_end_transaction(0);
1476 style_footer();
@@ -1678,11 +1678,11 @@
1678 @
1679 @ <p>Only a the first statement in the entry box will be run.
1680 @ Any subsequent statements will be silently ignored.</p>
1681 @
1682 @ <p>Database names:<ul><li>repository &rarr; %s(db_name("repository"))
1683 if( g.configOpen ){
1684 @ <li>config &rarr; %s(db_name("configdb"))
1685 }
1686 if( g.localOpen ){
1687 @ <li>local-checkout &rarr; %s(db_name("localdb"))
1688 }
1689
--- src/setup.c
+++ src/setup.c
@@ -139,11 +139,11 @@
139 @ <table class="usetupLayoutTable">
140 @ <tr><td class="usetupColumnLayout">
141 @ <span class="note">Users:</span>
142 @ <table class="usetupUserList">
143 prevLevel = 0;
144 db_prepare(&s,
145 "SELECT uid, login, cap, info, 1 FROM user"
146 " WHERE login IN ('anonymous','nobody','developer','reader') "
147 " UNION ALL "
148 "SELECT uid, login, cap, info, 2 FROM user"
149 " WHERE login NOT IN ('anonymous','nobody','developer','reader') "
@@ -250,11 +250,11 @@
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>
259 @ </li>
260 @
@@ -357,11 +357,11 @@
357 style_header("User Creation Error");
358 @ <span class="loginError">Empty login not allowed.</span>
359 @
360 @ <p><a href="setup_uedit?id=%d(uid)">[Bummer]</a></p>
361 style_footer();
362 return;
363 }
364 if( isValidPwString(zPw) ){
365 zPw = sha1_shared_secret(zPw, zLogin, 0);
366 }else{
367 zPw = db_text(0, "SELECT pw FROM user WHERE uid=%d", uid);
@@ -394,11 +394,11 @@
394 " SELECT %Q WHERE NOT EXISTS(SELECT 1 FROM user WHERE login=%Q);",
395 zLogin, zLogin
396 );
397 zOldLogin = zLogin;
398 }
399 blob_appendf(&sql,
400 "UPDATE user SET login=%Q,"
401 " pw=coalesce(shared_secret(%Q,%Q,"
402 "(SELECT value FROM config WHERE name='project-code')),pw),"
403 " info=%Q,"
404 " cap=%Q,"
@@ -643,11 +643,11 @@
643 @ </p></li>
644 @
645 @ <li><p>
646 @ The <span class="capability">Delete</span> privilege give the user the
647 @ ability to erase wiki, tickets, and attachments that have been added
648 @ by anonymous users. This capability is intended for deletion of spam.
649 @ The delete capability is only in effect for 24 hours after the item
650 @ is first posted. The <span class="usertype">Setup</span> user can
651 @ delete anything at any time.
652 @ </p></li>
653 @
@@ -700,11 +700,11 @@
700 @ </p></li>
701 @
702 @ <li><p>
703 @ The <span class="capability">EMail</span> privilege allows the display of
704 @ sensitive information such as the email address of users and contact
705 @ information on tickets. Recommended OFF for
706 @ <span class="usertype">anonymous</span> and for
707 @ <span class="usertype">nobody</span> but ON for
708 @ <span class="usertype">developer</span>.
709 @ </p></li>
710 @
@@ -724,11 +724,11 @@
724 @ <ul>
725 @ <li><p>
726 @ No login is required for user <span class="usertype">nobody</span>. The
727 @ capabilities of the <span class="usertype">nobody</span> user are
728 @ inherited by all users, regardless of whether or not they are logged in.
729 @ To disable universal access to the repository, make sure no user named
730 @ <span class="usertype">nobody</span> exists or that the
731 @ <span class="usertype">nobody</span> user has no capabilities
732 @ enabled. The password for <span class="usertype">nobody</span> is ignore.
733 @ To avoid problems with spiders overloading the server, it is recommended
734 @ that the <span class="capability">h</span> (Hyperlinks) capability be
@@ -749,13 +749,13 @@
749 @
750 @ <li><p>
751 @ The <span class="usertype">developer</span> user is intended as a template
752 @ for trusted users with check-in privileges. When adding new trusted users,
753 @ simply select the <span class="capability">developer</span> privilege to
754 @ cause the new user to inherit all privileges of the
755 @ <span class="usertype">developer</span>
756 @ user. Similarly, the <span class="usertype">reader</span> user is a
757 @ template for users who are allowed more access than
758 @ <span class="usertype">anonymous</span>,
759 @ but less than a <span class="usertype">developer</span>.
760 @ </p></li>
761 @ </ul>
@@ -833,11 +833,11 @@
833 z = zQ;
834 }
835 if( rows>0 && cols>0 ){
836 @ <textarea id="id%s(zQP)" name="%s(zQP)" rows="%d(rows)"
837 @ cols="%d(cols)">%h(z)</textarea>
838 if( zLabel && *zLabel ){
839 @ <span class="textareaLabel">%s(zLabel)</span>
840 }
841 }
842 }
843
@@ -895,11 +895,11 @@
895 @ login name of a valid user and no other login credentials are available,
896 @ then the REMOTE_USER is accepted as an authenticated user.
897 @ </p>
898 @
899 @ <hr />
900 entry_attribute("IP address terms used in login cookie", 3,
901 "ip-prefix-terms", "ipt", "2");
902 @ <p>The number of octets of of the IP address used in the login cookie.
903 @ Set to zero to omit the IP address from the login cookie. A value of
904 @ 2 is recommended.
905 @ </p>
@@ -958,23 +958,23 @@
958 entry_attribute("Public pages", 30, "public-pages",
959 "pubpage", "");
960 @ <p>A comma-separated list of glob patterns for pages that are accessible
961 @ without needing a login and using the privileges given by the
962 @ "Default privileges" setting below. Example use case: Set this field
963 @ to "/doc/trunk/www/*" to give anonymous users read-only permission to the
964 @ latest version of the embedded documentation in the www/ folder without
965 @ allowing them to see the rest of the source code.
966 @ </p>
967
968 @ <hr />
969 onoff_attribute("Allow users to register themselves",
970 "self-register", "selfregister", 0);
971 @ <p>Allow users to register themselves through the HTTP UI.
972 @ The registration form always requires filling in a CAPTCHA
973 @ (<em>auto-captcha</em> setting is ignored). Still, bear in mind that anyone
974 @ can register under any user name. This option is useful for public projects
975 @ where you do not want everyone in any ticket discussion to be named
976 @ "Anonymous".</p>
977
978 @ <hr />
979 entry_attribute("Default privileges", 10, "default-perms",
980 "defaultperms", "u");
@@ -1128,11 +1128,11 @@
1128 "timeline-utc", "utc", 1);
1129 @ <p>Show times as UTC (also sometimes called Greenwich Mean Time (GMT) or
1130 @ Zulu) instead of in local time. On this server, local time is currently
1131 g.fTimeFormat = 2;
1132 tmDiff = db_double(0.0, "SELECT julianday('now')");
1133 tmDiff = db_double(0.0,
1134 "SELECT (julianday(%.17g,'localtime')-julianday(%.17g))*24.0",
1135 tmDiff, tmDiff);
1136 sqlite3_snprintf(sizeof(zTmDiff), zTmDiff, "%.1f", tmDiff);
1137 if( strcmp(zTmDiff, "0.0")==0 ){
1138 @ the same as UTC and so this setting will make no difference in
@@ -1450,11 +1450,11 @@
1450 onoff_attribute("Moderate ticket changes",
1451 "modreq-tkt", "modreq-tkt", 0);
1452 @ <p>When enabled, any change to tickets is subject to the approval
1453 @ a ticket moderator - a user with the "q" or Mod-Tkt privilege.
1454 @ Ticket changes enter the system and are shown locally, but are not
1455 @ synced until they are approved. The moderator has the option to
1456 @ delete the change rather than approve it. Ticket changes made by
1457 @ a user who hwas the Mod-Tkt privilege are never subject to
1458 @ moderation.
1459 @
1460 @ <hr />
@@ -1461,16 +1461,16 @@
1461 onoff_attribute("Moderate wiki changes",
1462 "modreq-wiki", "modreq-wiki", 0);
1463 @ <p>When enabled, any change to wiki is subject to the approval
1464 @ a ticket moderator - a user with the "l" or Mod-Wiki privilege.
1465 @ Wiki changes enter the system and are shown locally, but are not
1466 @ synced until they are approved. The moderator has the option to
1467 @ delete the change rather than approve it. Wiki changes made by
1468 @ a user who has the Mod-Wiki privilege are never subject to
1469 @ moderation.
1470 @ </p>
1471
1472 @ <hr />
1473 @ <p><input type="submit" name="submit" value="Apply Changes" /></p>
1474 @ </div></form>
1475 db_end_transaction(0);
1476 style_footer();
@@ -1678,11 +1678,11 @@
1678 @
1679 @ <p>Only a the first statement in the entry box will be run.
1680 @ Any subsequent statements will be silently ignored.</p>
1681 @
1682 @ <p>Database names:<ul><li>repository &rarr; %s(db_name("repository"))
1683 if( g.zConfigDbName ){
1684 @ <li>config &rarr; %s(db_name("configdb"))
1685 }
1686 if( g.localOpen ){
1687 @ <li>local-checkout &rarr; %s(db_name("localdb"))
1688 }
1689
+57 -22
--- src/shell.c
+++ src/shell.c
@@ -88,11 +88,12 @@
8888
/* ctype macros that work with signed characters */
8989
#define IsSpace(X) isspace((unsigned char)X)
9090
#define IsDigit(X) isdigit((unsigned char)X)
9191
#define ToLower(X) (char)tolower((unsigned char)X)
9292
93
-#if !defined(_WIN32) && !defined(WIN32) && !defined(_WRS_KERNEL)
93
+#if !defined(_WIN32) && !defined(WIN32) && !defined(_WRS_KERNEL) \
94
+ && !defined(__minux)
9495
#include <sys/time.h>
9596
#include <sys/resource.h>
9697
9798
/* Saved resource information for the beginning of an operation */
9899
static struct rusage sBegin;
@@ -1484,10 +1485,16 @@
14841485
{
14851486
extern int sqlite3_add_regexp_func(sqlite3*);
14861487
sqlite3_add_regexp_func(db);
14871488
}
14881489
#endif
1490
+#ifdef SQLITE_ENABLE_SPELLFIX
1491
+ {
1492
+ extern int sqlite3_spellfix1_register(sqlite3*);
1493
+ sqlite3_spellfix1_register(db);
1494
+ }
1495
+#endif
14891496
}
14901497
}
14911498
14921499
/*
14931500
** Do C-language style dequoting.
@@ -1529,21 +1536,22 @@
15291536
15301537
/*
15311538
** Interpret zArg as a boolean value. Return either 0 or 1.
15321539
*/
15331540
static int booleanValue(char *zArg){
1534
- int val = atoi(zArg);
1535
- int j;
1536
- for(j=0; zArg[j]; j++){
1537
- zArg[j] = ToLower(zArg[j]);
1538
- }
1539
- if( strcmp(zArg,"on")==0 ){
1540
- val = 1;
1541
- }else if( strcmp(zArg,"yes")==0 ){
1542
- val = 1;
1543
- }
1544
- return val;
1541
+ int i;
1542
+ for(i=0; zArg[i]>='0' && zArg[i]<='9'; i++){}
1543
+ if( i>0 && zArg[i]==0 ) return atoi(zArg);
1544
+ if( sqlite3_stricmp(zArg, "on")==0 || sqlite3_stricmp(zArg,"yes")==0 ){
1545
+ return 1;
1546
+ }
1547
+ if( sqlite3_stricmp(zArg, "off")==0 || sqlite3_stricmp(zArg,"no")==0 ){
1548
+ return 0;
1549
+ }
1550
+ fprintf(stderr, "ERROR: Not a boolean value: \"%s\". Assuming \"no\".\n",
1551
+ zArg);
1552
+ return 0;
15451553
}
15461554
15471555
/*
15481556
** Close an output file, assuming it is not stderr or stdout
15491557
*/
@@ -1627,28 +1635,54 @@
16271635
/* Process the input line.
16281636
*/
16291637
if( nArg==0 ) return 0; /* no tokens, no error */
16301638
n = strlen30(azArg[0]);
16311639
c = azArg[0][0];
1632
- if( c=='b' && n>=3 && strncmp(azArg[0], "backup", n)==0 && nArg>1 && nArg<4){
1633
- const char *zDestFile;
1634
- const char *zDb;
1640
+ if( c=='b' && n>=3 && strncmp(azArg[0], "backup", n)==0 ){
1641
+ const char *zDestFile = 0;
1642
+ const char *zDb = 0;
1643
+ const char *zKey = 0;
16351644
sqlite3 *pDest;
16361645
sqlite3_backup *pBackup;
1637
- if( nArg==2 ){
1638
- zDestFile = azArg[1];
1639
- zDb = "main";
1640
- }else{
1641
- zDestFile = azArg[2];
1642
- zDb = azArg[1];
1646
+ int j;
1647
+ for(j=1; j<nArg; j++){
1648
+ const char *z = azArg[j];
1649
+ if( z[0]=='-' ){
1650
+ while( z[0]=='-' ) z++;
1651
+ if( strcmp(z,"key")==0 && j<nArg-1 ){
1652
+ zKey = azArg[++j];
1653
+ }else
1654
+ {
1655
+ fprintf(stderr, "unknown option: %s\n", azArg[j]);
1656
+ return 1;
1657
+ }
1658
+ }else if( zDestFile==0 ){
1659
+ zDestFile = azArg[j];
1660
+ }else if( zDb==0 ){
1661
+ zDb = zDestFile;
1662
+ zDestFile = azArg[j];
1663
+ }else{
1664
+ fprintf(stderr, "too many arguments to .backup\n");
1665
+ return 1;
1666
+ }
1667
+ }
1668
+ if( zDestFile==0 ){
1669
+ fprintf(stderr, "missing FILENAME argument on .backup\n");
1670
+ return 1;
16431671
}
1672
+ if( zDb==0 ) zDb = "main";
16441673
rc = sqlite3_open(zDestFile, &pDest);
16451674
if( rc!=SQLITE_OK ){
16461675
fprintf(stderr, "Error: cannot open \"%s\"\n", zDestFile);
16471676
sqlite3_close(pDest);
16481677
return 1;
16491678
}
1679
+#ifdef SQLITE_HAS_CODEC
1680
+ sqlite3_key(pDest, zKey, (int)strlen(zKey));
1681
+#else
1682
+ (void)zKey;
1683
+#endif
16501684
open_db(p);
16511685
pBackup = sqlite3_backup_init(pDest, "main", p->db, zDb);
16521686
if( pBackup==0 ){
16531687
fprintf(stderr, "Error: %s\n", sqlite3_errmsg(pDest));
16541688
sqlite3_close(pDest);
@@ -1746,11 +1780,12 @@
17461780
17471781
if( c=='e' && strncmp(azArg[0], "echo", n)==0 && nArg>1 && nArg<3 ){
17481782
p->echoOn = booleanValue(azArg[1]);
17491783
}else
17501784
1751
- if( c=='e' && strncmp(azArg[0], "exit", n)==0 && nArg==1 ){
1785
+ if( c=='e' && strncmp(azArg[0], "exit", n)==0 ){
1786
+ if( nArg>1 && (rc = atoi(azArg[1]))!=0 ) exit(rc);
17521787
rc = 2;
17531788
}else
17541789
17551790
if( c=='e' && strncmp(azArg[0], "explain", n)==0 && nArg<3 ){
17561791
int val = nArg>=2 ? booleanValue(azArg[1]) : 1;
17571792
--- src/shell.c
+++ src/shell.c
@@ -88,11 +88,12 @@
88 /* ctype macros that work with signed characters */
89 #define IsSpace(X) isspace((unsigned char)X)
90 #define IsDigit(X) isdigit((unsigned char)X)
91 #define ToLower(X) (char)tolower((unsigned char)X)
92
93 #if !defined(_WIN32) && !defined(WIN32) && !defined(_WRS_KERNEL)
 
94 #include <sys/time.h>
95 #include <sys/resource.h>
96
97 /* Saved resource information for the beginning of an operation */
98 static struct rusage sBegin;
@@ -1484,10 +1485,16 @@
1484 {
1485 extern int sqlite3_add_regexp_func(sqlite3*);
1486 sqlite3_add_regexp_func(db);
1487 }
1488 #endif
 
 
 
 
 
 
1489 }
1490 }
1491
1492 /*
1493 ** Do C-language style dequoting.
@@ -1529,21 +1536,22 @@
1529
1530 /*
1531 ** Interpret zArg as a boolean value. Return either 0 or 1.
1532 */
1533 static int booleanValue(char *zArg){
1534 int val = atoi(zArg);
1535 int j;
1536 for(j=0; zArg[j]; j++){
1537 zArg[j] = ToLower(zArg[j]);
1538 }
1539 if( strcmp(zArg,"on")==0 ){
1540 val = 1;
1541 }else if( strcmp(zArg,"yes")==0 ){
1542 val = 1;
1543 }
1544 return val;
 
1545 }
1546
1547 /*
1548 ** Close an output file, assuming it is not stderr or stdout
1549 */
@@ -1627,28 +1635,54 @@
1627 /* Process the input line.
1628 */
1629 if( nArg==0 ) return 0; /* no tokens, no error */
1630 n = strlen30(azArg[0]);
1631 c = azArg[0][0];
1632 if( c=='b' && n>=3 && strncmp(azArg[0], "backup", n)==0 && nArg>1 && nArg<4){
1633 const char *zDestFile;
1634 const char *zDb;
 
1635 sqlite3 *pDest;
1636 sqlite3_backup *pBackup;
1637 if( nArg==2 ){
1638 zDestFile = azArg[1];
1639 zDb = "main";
1640 }else{
1641 zDestFile = azArg[2];
1642 zDb = azArg[1];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1643 }
 
1644 rc = sqlite3_open(zDestFile, &pDest);
1645 if( rc!=SQLITE_OK ){
1646 fprintf(stderr, "Error: cannot open \"%s\"\n", zDestFile);
1647 sqlite3_close(pDest);
1648 return 1;
1649 }
 
 
 
 
 
1650 open_db(p);
1651 pBackup = sqlite3_backup_init(pDest, "main", p->db, zDb);
1652 if( pBackup==0 ){
1653 fprintf(stderr, "Error: %s\n", sqlite3_errmsg(pDest));
1654 sqlite3_close(pDest);
@@ -1746,11 +1780,12 @@
1746
1747 if( c=='e' && strncmp(azArg[0], "echo", n)==0 && nArg>1 && nArg<3 ){
1748 p->echoOn = booleanValue(azArg[1]);
1749 }else
1750
1751 if( c=='e' && strncmp(azArg[0], "exit", n)==0 && nArg==1 ){
 
1752 rc = 2;
1753 }else
1754
1755 if( c=='e' && strncmp(azArg[0], "explain", n)==0 && nArg<3 ){
1756 int val = nArg>=2 ? booleanValue(azArg[1]) : 1;
1757
--- src/shell.c
+++ src/shell.c
@@ -88,11 +88,12 @@
88 /* ctype macros that work with signed characters */
89 #define IsSpace(X) isspace((unsigned char)X)
90 #define IsDigit(X) isdigit((unsigned char)X)
91 #define ToLower(X) (char)tolower((unsigned char)X)
92
93 #if !defined(_WIN32) && !defined(WIN32) && !defined(_WRS_KERNEL) \
94 && !defined(__minux)
95 #include <sys/time.h>
96 #include <sys/resource.h>
97
98 /* Saved resource information for the beginning of an operation */
99 static struct rusage sBegin;
@@ -1484,10 +1485,16 @@
1485 {
1486 extern int sqlite3_add_regexp_func(sqlite3*);
1487 sqlite3_add_regexp_func(db);
1488 }
1489 #endif
1490 #ifdef SQLITE_ENABLE_SPELLFIX
1491 {
1492 extern int sqlite3_spellfix1_register(sqlite3*);
1493 sqlite3_spellfix1_register(db);
1494 }
1495 #endif
1496 }
1497 }
1498
1499 /*
1500 ** Do C-language style dequoting.
@@ -1529,21 +1536,22 @@
1536
1537 /*
1538 ** Interpret zArg as a boolean value. Return either 0 or 1.
1539 */
1540 static int booleanValue(char *zArg){
1541 int i;
1542 for(i=0; zArg[i]>='0' && zArg[i]<='9'; i++){}
1543 if( i>0 && zArg[i]==0 ) return atoi(zArg);
1544 if( sqlite3_stricmp(zArg, "on")==0 || sqlite3_stricmp(zArg,"yes")==0 ){
1545 return 1;
1546 }
1547 if( sqlite3_stricmp(zArg, "off")==0 || sqlite3_stricmp(zArg,"no")==0 ){
1548 return 0;
1549 }
1550 fprintf(stderr, "ERROR: Not a boolean value: \"%s\". Assuming \"no\".\n",
1551 zArg);
1552 return 0;
1553 }
1554
1555 /*
1556 ** Close an output file, assuming it is not stderr or stdout
1557 */
@@ -1627,28 +1635,54 @@
1635 /* Process the input line.
1636 */
1637 if( nArg==0 ) return 0; /* no tokens, no error */
1638 n = strlen30(azArg[0]);
1639 c = azArg[0][0];
1640 if( c=='b' && n>=3 && strncmp(azArg[0], "backup", n)==0 ){
1641 const char *zDestFile = 0;
1642 const char *zDb = 0;
1643 const char *zKey = 0;
1644 sqlite3 *pDest;
1645 sqlite3_backup *pBackup;
1646 int j;
1647 for(j=1; j<nArg; j++){
1648 const char *z = azArg[j];
1649 if( z[0]=='-' ){
1650 while( z[0]=='-' ) z++;
1651 if( strcmp(z,"key")==0 && j<nArg-1 ){
1652 zKey = azArg[++j];
1653 }else
1654 {
1655 fprintf(stderr, "unknown option: %s\n", azArg[j]);
1656 return 1;
1657 }
1658 }else if( zDestFile==0 ){
1659 zDestFile = azArg[j];
1660 }else if( zDb==0 ){
1661 zDb = zDestFile;
1662 zDestFile = azArg[j];
1663 }else{
1664 fprintf(stderr, "too many arguments to .backup\n");
1665 return 1;
1666 }
1667 }
1668 if( zDestFile==0 ){
1669 fprintf(stderr, "missing FILENAME argument on .backup\n");
1670 return 1;
1671 }
1672 if( zDb==0 ) zDb = "main";
1673 rc = sqlite3_open(zDestFile, &pDest);
1674 if( rc!=SQLITE_OK ){
1675 fprintf(stderr, "Error: cannot open \"%s\"\n", zDestFile);
1676 sqlite3_close(pDest);
1677 return 1;
1678 }
1679 #ifdef SQLITE_HAS_CODEC
1680 sqlite3_key(pDest, zKey, (int)strlen(zKey));
1681 #else
1682 (void)zKey;
1683 #endif
1684 open_db(p);
1685 pBackup = sqlite3_backup_init(pDest, "main", p->db, zDb);
1686 if( pBackup==0 ){
1687 fprintf(stderr, "Error: %s\n", sqlite3_errmsg(pDest));
1688 sqlite3_close(pDest);
@@ -1746,11 +1780,12 @@
1780
1781 if( c=='e' && strncmp(azArg[0], "echo", n)==0 && nArg>1 && nArg<3 ){
1782 p->echoOn = booleanValue(azArg[1]);
1783 }else
1784
1785 if( c=='e' && strncmp(azArg[0], "exit", n)==0 ){
1786 if( nArg>1 && (rc = atoi(azArg[1]))!=0 ) exit(rc);
1787 rc = 2;
1788 }else
1789
1790 if( c=='e' && strncmp(azArg[0], "explain", n)==0 && nArg<3 ){
1791 int val = nArg>=2 ? booleanValue(azArg[1]) : 1;
1792
+632 -351
--- src/sqlite3.c
+++ src/sqlite3.c
@@ -304,10 +304,14 @@
304304
/* Needed for various definitions... */
305305
#ifndef _GNU_SOURCE
306306
# define _GNU_SOURCE
307307
#endif
308308
309
+#if defined(__OpenBSD__) && !defined(_BSD_SOURCE)
310
+# define _BSD_SOURCE
311
+#endif
312
+
309313
/*
310314
** Include standard header files as necessary
311315
*/
312316
#ifdef HAVE_STDINT_H
313317
#include <stdint.h>
@@ -438,11 +442,12 @@
438442
** if it is already defined or if it is unneeded because we are
439443
** not doing a threadsafe build. Ticket #2681.
440444
**
441445
** See also ticket #2741.
442446
*/
443
-#if !defined(_XOPEN_SOURCE) && !defined(__DARWIN__) && !defined(__APPLE__) && SQLITE_THREADSAFE
447
+#if !defined(_XOPEN_SOURCE) && !defined(__DARWIN__) \
448
+ && !defined(__APPLE__) && SQLITE_THREADSAFE
444449
# define _XOPEN_SOURCE 500 /* Needed to enable pthread recursive mutexes */
445450
#endif
446451
447452
/*
448453
** The TCL headers are only needed when compiling the TCL bindings.
@@ -673,11 +678,11 @@
673678
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
674679
** [sqlite_version()] and [sqlite_source_id()].
675680
*/
676681
#define SQLITE_VERSION "3.7.16"
677682
#define SQLITE_VERSION_NUMBER 3007016
678
-#define SQLITE_SOURCE_ID "2013-01-17 17:20:49 38852f158ab20bb4d7b264af987ec1538052bec3"
683
+#define SQLITE_SOURCE_ID "2013-03-13 00:13:25 839aa91faf1db7025d90fa3c65e50efb829b053b"
679684
680685
/*
681686
** CAPI3REF: Run-Time Library Version Numbers
682687
** KEYWORDS: sqlite3_version, sqlite3_sourceid
683688
**
@@ -852,11 +857,11 @@
852857
**
853858
** Applications should [sqlite3_finalize | finalize] all [prepared statements],
854859
** [sqlite3_blob_close | close] all [BLOB handles], and
855860
** [sqlite3_backup_finish | finish] all [sqlite3_backup] objects associated
856861
** with the [sqlite3] object prior to attempting to close the object. ^If
857
-** sqlite3_close() is called on a [database connection] that still has
862
+** sqlite3_close_v2() is called on a [database connection] that still has
858863
** outstanding [prepared statements], [BLOB handles], and/or
859864
** [sqlite3_backup] objects then it returns SQLITE_OK but the deallocation
860865
** of resources is deferred until all [prepared statements], [BLOB handles],
861866
** and [sqlite3_backup] objects are also destroyed.
862867
**
@@ -1047,11 +1052,21 @@
10471052
#define SQLITE_CANTOPEN_ISDIR (SQLITE_CANTOPEN | (2<<8))
10481053
#define SQLITE_CANTOPEN_FULLPATH (SQLITE_CANTOPEN | (3<<8))
10491054
#define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1<<8))
10501055
#define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1<<8))
10511056
#define SQLITE_READONLY_CANTLOCK (SQLITE_READONLY | (2<<8))
1057
+#define SQLITE_READONLY_ROLLBACK (SQLITE_READONLY | (3<<8))
10521058
#define SQLITE_ABORT_ROLLBACK (SQLITE_ABORT | (2<<8))
1059
+#define SQLITE_CONSTRAINT_CHECK (SQLITE_CONSTRAINT | (1<<8))
1060
+#define SQLITE_CONSTRAINT_COMMITHOOK (SQLITE_CONSTRAINT | (2<<8))
1061
+#define SQLITE_CONSTRAINT_FOREIGNKEY (SQLITE_CONSTRAINT | (3<<8))
1062
+#define SQLITE_CONSTRAINT_FUNCTION (SQLITE_CONSTRAINT | (4<<8))
1063
+#define SQLITE_CONSTRAINT_NOTNULL (SQLITE_CONSTRAINT | (5<<8))
1064
+#define SQLITE_CONSTRAINT_PRIMARYKEY (SQLITE_CONSTRAINT | (6<<8))
1065
+#define SQLITE_CONSTRAINT_TRIGGER (SQLITE_CONSTRAINT | (7<<8))
1066
+#define SQLITE_CONSTRAINT_UNIQUE (SQLITE_CONSTRAINT | (8<<8))
1067
+#define SQLITE_CONSTRAINT_VTAB (SQLITE_CONSTRAINT | (9<<8))
10531068
10541069
/*
10551070
** CAPI3REF: Flags For File Open Operations
10561071
**
10571072
** These bit values are intended for use in the
@@ -10018,11 +10033,11 @@
1001810033
#define SQLITE_NullCallback 0x00000020 /* Invoke the callback once if the */
1001910034
/* result set is empty */
1002010035
#define SQLITE_SqlTrace 0x00000040 /* Debug print SQL as it executes */
1002110036
#define SQLITE_VdbeListing 0x00000080 /* Debug listings of VDBE programs */
1002210037
#define SQLITE_WriteSchema 0x00000100 /* OK to update SQLITE_MASTER */
10023
- /* 0x00000200 Unused */
10038
+#define SQLITE_VdbeAddopTrace 0x00000200 /* Trace sqlite3VdbeAddOp() calls */
1002410039
#define SQLITE_IgnoreChecks 0x00000400 /* Do not enforce check constraints */
1002510040
#define SQLITE_ReadUncommitted 0x0000800 /* For shared-cache mode */
1002610041
#define SQLITE_LegacyFileFmt 0x00001000 /* Create new databases in format 1 */
1002710042
#define SQLITE_FullFSync 0x00002000 /* Use full fsync on the backend */
1002810043
#define SQLITE_CkptFullFSync 0x00004000 /* Use full fsync for checkpoint */
@@ -11034,10 +11049,11 @@
1103411049
struct {
1103511050
int nIn; /* Number of entries in aInLoop[] */
1103611051
struct InLoop {
1103711052
int iCur; /* The VDBE cursor used by this IN operator */
1103811053
int addrInTop; /* Top of the IN loop */
11054
+ u8 eEndLoopOp; /* IN Loop terminator. OP_Next or OP_Prev */
1103911055
} *aInLoop; /* Information about each nested IN operator */
1104011056
} in; /* Used when plan.wsFlags&WHERE_IN_ABLE */
1104111057
Index *pCovidx; /* Possible covering index for WHERE_MULTI_OR */
1104211058
} u;
1104311059
double rOptCost; /* "Optimal" cost for this level */
@@ -11905,11 +11921,11 @@
1190511921
SQLITE_PRIVATE void sqlite3SelectDelete(sqlite3*, Select*);
1190611922
SQLITE_PRIVATE Table *sqlite3SrcListLookup(Parse*, SrcList*);
1190711923
SQLITE_PRIVATE int sqlite3IsReadOnly(Parse*, Table*, int);
1190811924
SQLITE_PRIVATE void sqlite3OpenTable(Parse*, int iCur, int iDb, Table*, int);
1190911925
#if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) && !defined(SQLITE_OMIT_SUBQUERY)
11910
-SQLITE_PRIVATE Expr *sqlite3LimitWhere(Parse *, SrcList *, Expr *, ExprList *, Expr *, Expr *, char *);
11926
+SQLITE_PRIVATE Expr *sqlite3LimitWhere(Parse*,SrcList*,Expr*,ExprList*,Expr*,Expr*,char*);
1191111927
#endif
1191211928
SQLITE_PRIVATE void sqlite3DeleteFrom(Parse*, SrcList*, Expr*);
1191311929
SQLITE_PRIVATE void sqlite3Update(Parse*, SrcList*, ExprList*, Expr*, int);
1191411930
SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(Parse*,SrcList*,Expr*,ExprList*,ExprList*,u16,int);
1191511931
SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo*);
@@ -11973,11 +11989,11 @@
1197311989
SQLITE_PRIVATE void sqlite3CompleteInsertion(Parse*, Table*, int, int, int*, int, int, int);
1197411990
SQLITE_PRIVATE int sqlite3OpenTableAndIndices(Parse*, Table*, int, int);
1197511991
SQLITE_PRIVATE void sqlite3BeginWriteOperation(Parse*, int, int);
1197611992
SQLITE_PRIVATE void sqlite3MultiWrite(Parse*);
1197711993
SQLITE_PRIVATE void sqlite3MayAbort(Parse*);
11978
-SQLITE_PRIVATE void sqlite3HaltConstraint(Parse*, int, char*, int);
11994
+SQLITE_PRIVATE void sqlite3HaltConstraint(Parse*, int, int, char*, int);
1197911995
SQLITE_PRIVATE Expr *sqlite3ExprDup(sqlite3*,Expr*,int);
1198011996
SQLITE_PRIVATE ExprList *sqlite3ExprListDup(sqlite3*,ExprList*,int);
1198111997
SQLITE_PRIVATE SrcList *sqlite3SrcListDup(sqlite3*,SrcList*,int);
1198211998
SQLITE_PRIVATE IdList *sqlite3IdListDup(sqlite3*,IdList*);
1198311999
SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3*,Select*,int);
@@ -12086,12 +12102,15 @@
1208612102
**
1208712103
** x = getVarint32( A, B );
1208812104
** x = putVarint32( A, B );
1208912105
**
1209012106
*/
12091
-#define getVarint32(A,B) (u8)((*(A)<(u8)0x80) ? ((B) = (u32)*(A)),1 : sqlite3GetVarint32((A), (u32 *)&(B)))
12092
-#define putVarint32(A,B) (u8)(((u32)(B)<(u32)0x80) ? (*(A) = (unsigned char)(B)),1 : sqlite3PutVarint32((A), (B)))
12107
+#define getVarint32(A,B) \
12108
+ (u8)((*(A)<(u8)0x80)?((B)=(u32)*(A)),1:sqlite3GetVarint32((A),(u32 *)&(B)))
12109
+#define putVarint32(A,B) \
12110
+ (u8)(((u32)(B)<(u32)0x80)?(*(A)=(unsigned char)(B)),1:\
12111
+ sqlite3PutVarint32((A),(B)))
1209312112
#define getVarint sqlite3GetVarint
1209412113
#define putVarint sqlite3PutVarint
1209512114
1209612115
1209712116
SQLITE_PRIVATE const char *sqlite3IndexAffinityStr(Vdbe *, Index *);
@@ -12323,11 +12342,12 @@
1232312342
#define sqlite3EndBenignMalloc()
1232412343
#endif
1232512344
1232612345
#define IN_INDEX_ROWID 1
1232712346
#define IN_INDEX_EPH 2
12328
-#define IN_INDEX_INDEX 3
12347
+#define IN_INDEX_INDEX_ASC 3
12348
+#define IN_INDEX_INDEX_DESC 4
1232912349
SQLITE_PRIVATE int sqlite3FindInIndex(Parse *, Expr *, int*);
1233012350
1233112351
#ifdef SQLITE_ENABLE_ATOMIC_WRITE
1233212352
SQLITE_PRIVATE int sqlite3JournalOpen(sqlite3_vfs *, const char *, sqlite3_file *, int, int);
1233312353
SQLITE_PRIVATE int sqlite3JournalSize(sqlite3_vfs *);
@@ -13208,11 +13228,11 @@
1320813228
Mem *aMem; /* Array of memory cells for parent frame */
1320913229
u8 *aOnceFlag; /* Array of OP_Once flags for parent frame */
1321013230
VdbeCursor **apCsr; /* Array of Vdbe cursors for parent frame */
1321113231
void *token; /* Copy of SubProgram.token */
1321213232
i64 lastRowid; /* Last insert rowid (sqlite3.lastRowid) */
13213
- u16 nCursor; /* Number of entries in apCsr */
13233
+ int nCursor; /* Number of entries in apCsr */
1321413234
int pc; /* Program Counter in parent (calling) frame */
1321513235
int nOp; /* Size of aOp array */
1321613236
int nMem; /* Number of entries in aMem */
1321713237
int nOnceFlag; /* Number of entries in aOnceFlag */
1321813238
int nChildMem; /* Number of memory cells for child frame */
@@ -13394,11 +13414,11 @@
1339413414
int nOp; /* Number of instructions in the program */
1339513415
int nOpAlloc; /* Number of slots allocated for aOp[] */
1339613416
int nLabel; /* Number of labels used */
1339713417
int *aLabel; /* Space to hold the labels */
1339813418
u16 nResColumn; /* Number of columns in one row of the result set */
13399
- u16 nCursor; /* Number of slots in apCsr[] */
13419
+ int nCursor; /* Number of slots in apCsr[] */
1340013420
u32 magic; /* Magic number for sanity checking */
1340113421
char *zErrMsg; /* Error message written here */
1340213422
Vdbe *pPrev,*pNext; /* Linked list of VDBEs with the same Vdbe.db */
1340313423
VdbeCursor **apCsr; /* One element of this array for each open cursor */
1340413424
Mem *aVar; /* Values for the OP_Variable opcode. */
@@ -23445,11 +23465,14 @@
2344523465
#endif
2344623466
}while( fd<0 && errno==EINTR );
2344723467
if( fd>=0 ){
2344823468
if( m!=0 ){
2344923469
struct stat statbuf;
23450
- if( osFstat(fd, &statbuf)==0 && (statbuf.st_mode&0777)!=m ){
23470
+ if( osFstat(fd, &statbuf)==0
23471
+ && statbuf.st_size==0
23472
+ && (statbuf.st_mode&0777)!=m
23473
+ ){
2345123474
osFchmod(fd, m);
2345223475
}
2345323476
}
2345423477
#if defined(FD_CLOEXEC) && (!defined(O_CLOEXEC) || O_CLOEXEC==0)
2345523478
osFcntl(fd, F_SETFD, osFcntl(fd, F_GETFD, 0) | FD_CLOEXEC);
@@ -27645,11 +27668,11 @@
2764527668
pNew->ctrlFlags = (u8)ctrlFlags;
2764627669
if( sqlite3_uri_boolean(((ctrlFlags & UNIXFILE_URI) ? zFilename : 0),
2764727670
"psow", SQLITE_POWERSAFE_OVERWRITE) ){
2764827671
pNew->ctrlFlags |= UNIXFILE_PSOW;
2764927672
}
27650
- if( memcmp(pVfs->zName,"unix-excl",10)==0 ){
27673
+ if( strcmp(pVfs->zName,"unix-excl")==0 ){
2765127674
pNew->ctrlFlags |= UNIXFILE_EXCL;
2765227675
}
2765327676
2765427677
#if OS_VXWORKS
2765527678
pNew->pId = vxworksFindFileId(zFilename);
@@ -31099,11 +31122,11 @@
3109931122
/*
3110031123
** This function outputs the specified (ANSI) string to the Win32 debugger
3110131124
** (if available).
3110231125
*/
3110331126
31104
-SQLITE_API void sqlite3_win32_write_debug(char *zBuf, int nBuf){
31127
+SQLITE_API void sqlite3_win32_write_debug(const char *zBuf, int nBuf){
3110531128
char zDbgBuf[SQLITE_WIN32_DBG_BUF_SIZE];
3110631129
int nMin = MIN(nBuf, (SQLITE_WIN32_DBG_BUF_SIZE - 1)); /* may be negative. */
3110731130
if( nMin<-1 ) nMin = -1; /* all negative values become -1. */
3110831131
assert( nMin==-1 || nMin==0 || nMin<SQLITE_WIN32_DBG_BUF_SIZE );
3110931132
#if defined(SQLITE_WIN32_HAS_ANSI)
@@ -31732,13 +31755,14 @@
3173231755
3173331756
#if SQLITE_OS_WINCE
3173431757
/*************************************************************************
3173531758
** This section contains code for WinCE only.
3173631759
*/
31760
+#if !defined(SQLITE_MSVC_LOCALTIME_API) || !SQLITE_MSVC_LOCALTIME_API
3173731761
/*
31738
-** Windows CE does not have a localtime() function. So create a
31739
-** substitute.
31762
+** The MSVC CRT on Windows CE may not have a localtime() function. So
31763
+** create a substitute.
3174031764
*/
3174131765
/* #include <time.h> */
3174231766
struct tm *__cdecl localtime(const time_t *t)
3174331767
{
3174431768
static struct tm y;
@@ -31758,10 +31782,11 @@
3175831782
y.tm_hour = pTm.wHour;
3175931783
y.tm_min = pTm.wMinute;
3176031784
y.tm_sec = pTm.wSecond;
3176131785
return &y;
3176231786
}
31787
+#endif
3176331788
3176431789
#define HANDLE_TO_WINFILE(a) (winFile*)&((char*)a)[-(int)offsetof(winFile,h)]
3176531790
3176631791
/*
3176731792
** Acquire a lock on the handle h
@@ -31779,19 +31804,21 @@
3177931804
3178031805
/*
3178131806
** Create the mutex and shared memory used for locking in the file
3178231807
** descriptor pFile
3178331808
*/
31784
-static BOOL winceCreateLock(const char *zFilename, winFile *pFile){
31809
+static int winceCreateLock(const char *zFilename, winFile *pFile){
3178531810
LPWSTR zTok;
3178631811
LPWSTR zName;
31812
+ DWORD lastErrno;
31813
+ BOOL bLogged = FALSE;
3178731814
BOOL bInit = TRUE;
3178831815
3178931816
zName = utf8ToUnicode(zFilename);
3179031817
if( zName==0 ){
3179131818
/* out of memory */
31792
- return FALSE;
31819
+ return SQLITE_IOERR_NOMEM;
3179331820
}
3179431821
3179531822
/* Initialize the local lockdata */
3179631823
memset(&pFile->local, 0, sizeof(pFile->local));
3179731824
@@ -31804,13 +31831,14 @@
3180431831
3180531832
/* Create/open the named mutex */
3180631833
pFile->hMutex = osCreateMutexW(NULL, FALSE, zName);
3180731834
if (!pFile->hMutex){
3180831835
pFile->lastErrno = osGetLastError();
31809
- winLogError(SQLITE_ERROR, pFile->lastErrno, "winceCreateLock1", zFilename);
31836
+ winLogError(SQLITE_IOERR, pFile->lastErrno,
31837
+ "winceCreateLock1", zFilename);
3181031838
sqlite3_free(zName);
31811
- return FALSE;
31839
+ return SQLITE_IOERR;
3181231840
}
3181331841
3181431842
/* Acquire the mutex before continuing */
3181531843
winceMutexAcquire(pFile->hMutex);
3181631844
@@ -31823,45 +31851,53 @@
3182331851
PAGE_READWRITE, 0, sizeof(winceLock),
3182431852
zName);
3182531853
3182631854
/* Set a flag that indicates we're the first to create the memory so it
3182731855
** must be zero-initialized */
31828
- if (osGetLastError() == ERROR_ALREADY_EXISTS){
31856
+ lastErrno = osGetLastError();
31857
+ if (lastErrno == ERROR_ALREADY_EXISTS){
3182931858
bInit = FALSE;
3183031859
}
3183131860
3183231861
sqlite3_free(zName);
3183331862
3183431863
/* If we succeeded in making the shared memory handle, map it. */
31835
- if (pFile->hShared){
31864
+ if( pFile->hShared ){
3183631865
pFile->shared = (winceLock*)osMapViewOfFile(pFile->hShared,
3183731866
FILE_MAP_READ|FILE_MAP_WRITE, 0, 0, sizeof(winceLock));
3183831867
/* If mapping failed, close the shared memory handle and erase it */
31839
- if (!pFile->shared){
31868
+ if( !pFile->shared ){
3184031869
pFile->lastErrno = osGetLastError();
31841
- winLogError(SQLITE_ERROR, pFile->lastErrno,
31842
- "winceCreateLock2", zFilename);
31870
+ winLogError(SQLITE_IOERR, pFile->lastErrno,
31871
+ "winceCreateLock2", zFilename);
31872
+ bLogged = TRUE;
3184331873
osCloseHandle(pFile->hShared);
3184431874
pFile->hShared = NULL;
3184531875
}
3184631876
}
3184731877
3184831878
/* If shared memory could not be created, then close the mutex and fail */
31849
- if (pFile->hShared == NULL){
31879
+ if( pFile->hShared==NULL ){
31880
+ if( !bLogged ){
31881
+ pFile->lastErrno = lastErrno;
31882
+ winLogError(SQLITE_IOERR, pFile->lastErrno,
31883
+ "winceCreateLock3", zFilename);
31884
+ bLogged = TRUE;
31885
+ }
3185031886
winceMutexRelease(pFile->hMutex);
3185131887
osCloseHandle(pFile->hMutex);
3185231888
pFile->hMutex = NULL;
31853
- return FALSE;
31889
+ return SQLITE_IOERR;
3185431890
}
3185531891
3185631892
/* Initialize the shared memory if we're supposed to */
31857
- if (bInit) {
31893
+ if( bInit ){
3185831894
memset(pFile->shared, 0, sizeof(winceLock));
3185931895
}
3186031896
3186131897
winceMutexRelease(pFile->hMutex);
31862
- return TRUE;
31898
+ return SQLITE_OK;
3186331899
}
3186431900
3186531901
/*
3186631902
** Destroy the part of winFile that deals with wince locks
3186731903
*/
@@ -31936,21 +31972,23 @@
3193631972
bReturn = TRUE;
3193731973
}
3193831974
}
3193931975
3194031976
/* Want a pending lock? */
31941
- else if (dwFileOffsetLow == (DWORD)PENDING_BYTE && nNumberOfBytesToLockLow == 1){
31977
+ else if (dwFileOffsetLow == (DWORD)PENDING_BYTE
31978
+ && nNumberOfBytesToLockLow == 1){
3194231979
/* If no pending lock has been acquired, then acquire it */
3194331980
if (pFile->shared->bPending == 0) {
3194431981
pFile->shared->bPending = TRUE;
3194531982
pFile->local.bPending = TRUE;
3194631983
bReturn = TRUE;
3194731984
}
3194831985
}
3194931986
3195031987
/* Want a reserved lock? */
31951
- else if (dwFileOffsetLow == (DWORD)RESERVED_BYTE && nNumberOfBytesToLockLow == 1){
31988
+ else if (dwFileOffsetLow == (DWORD)RESERVED_BYTE
31989
+ && nNumberOfBytesToLockLow == 1){
3195231990
if (pFile->shared->bReserved == 0) {
3195331991
pFile->shared->bReserved = TRUE;
3195431992
pFile->local.bReserved = TRUE;
3195531993
bReturn = TRUE;
3195631994
}
@@ -31989,11 +32027,12 @@
3198932027
bReturn = TRUE;
3199032028
}
3199132029
3199232030
/* Did we just have a reader lock? */
3199332031
else if (pFile->local.nReaders){
31994
- assert(nNumberOfBytesToUnlockLow == (DWORD)SHARED_SIZE || nNumberOfBytesToUnlockLow == 1);
32032
+ assert(nNumberOfBytesToUnlockLow == (DWORD)SHARED_SIZE
32033
+ || nNumberOfBytesToUnlockLow == 1);
3199532034
pFile->local.nReaders --;
3199632035
if (pFile->local.nReaders == 0)
3199732036
{
3199832037
pFile->shared->nReaders --;
3199932038
}
@@ -32000,19 +32039,21 @@
3200032039
bReturn = TRUE;
3200132040
}
3200232041
}
3200332042
3200432043
/* Releasing a pending lock */
32005
- else if (dwFileOffsetLow == (DWORD)PENDING_BYTE && nNumberOfBytesToUnlockLow == 1){
32044
+ else if (dwFileOffsetLow == (DWORD)PENDING_BYTE
32045
+ && nNumberOfBytesToUnlockLow == 1){
3200632046
if (pFile->local.bPending){
3200732047
pFile->local.bPending = FALSE;
3200832048
pFile->shared->bPending = FALSE;
3200932049
bReturn = TRUE;
3201032050
}
3201132051
}
3201232052
/* Releasing a reserved lock */
32013
- else if (dwFileOffsetLow == (DWORD)RESERVED_BYTE && nNumberOfBytesToUnlockLow == 1){
32053
+ else if (dwFileOffsetLow == (DWORD)RESERVED_BYTE
32054
+ && nNumberOfBytesToUnlockLow == 1){
3201432055
if (pFile->local.bReserved) {
3201532056
pFile->local.bReserved = FALSE;
3201632057
pFile->shared->bReserved = FALSE;
3201732058
bReturn = TRUE;
3201832059
}
@@ -32174,10 +32215,11 @@
3217432215
assert( id!=0 );
3217532216
#ifndef SQLITE_OMIT_WAL
3217632217
assert( pFile->pShm==0 );
3217732218
#endif
3217832219
OSTRACE(("CLOSE %d\n", pFile->h));
32220
+ assert( pFile->h!=NULL && pFile->h!=INVALID_HANDLE_VALUE );
3217932221
do{
3218032222
rc = osCloseHandle(pFile->h);
3218132223
/* SimulateIOError( rc=0; cnt=MX_CLOSE_ATTEMPT; ); */
3218232224
}while( rc==0 && ++cnt < MX_CLOSE_ATTEMPT && (sqlite3_win32_sleep(100), 1) );
3218332225
#if SQLITE_OS_WINCE
@@ -32866,11 +32908,11 @@
3286632908
a[1] = win32IoerrRetryDelay;
3286732909
}
3286832910
return SQLITE_OK;
3286932911
}
3287032912
case SQLITE_FCNTL_TEMPFILENAME: {
32871
- char *zTFile = sqlite3_malloc( pFile->pVfs->mxPathname );
32913
+ char *zTFile = sqlite3MallocZero( pFile->pVfs->mxPathname );
3287232914
if( zTFile ){
3287332915
getTempname(pFile->pVfs->mxPathname, zTFile);
3287432916
*(char**)pArg = zTFile;
3287532917
}
3287632918
return SQLITE_OK;
@@ -33090,11 +33132,11 @@
3309033132
bRc = osCloseHandle(p->aRegion[i].hMap);
3309133133
OSTRACE(("SHM-PURGE pid-%d close region=%d %s\n",
3309233134
(int)osGetCurrentProcessId(), i,
3309333135
bRc ? "ok" : "failed"));
3309433136
}
33095
- if( p->hFile.h != INVALID_HANDLE_VALUE ){
33137
+ if( p->hFile.h!=NULL && p->hFile.h!=INVALID_HANDLE_VALUE ){
3309633138
SimulateIOErrorBenign(1);
3309733139
winClose((sqlite3_file *)&p->hFile);
3309833140
SimulateIOErrorBenign(0);
3309933141
}
3310033142
if( deleteFlag ){
@@ -33170,11 +33212,11 @@
3317033212
}
3317133213
3317233214
rc = winOpen(pDbFd->pVfs,
3317333215
pShmNode->zFilename, /* Name of the file (UTF-8) */
3317433216
(sqlite3_file*)&pShmNode->hFile, /* File handle here */
33175
- SQLITE_OPEN_WAL | SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, /* Mode flags */
33217
+ SQLITE_OPEN_WAL | SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
3317633218
0);
3317733219
if( SQLITE_OK!=rc ){
3317833220
goto shm_open_err;
3317933221
}
3318033222
@@ -33785,27 +33827,27 @@
3378533827
|| eType==SQLITE_OPEN_MAIN_JOURNAL || eType==SQLITE_OPEN_TEMP_JOURNAL
3378633828
|| eType==SQLITE_OPEN_SUBJOURNAL || eType==SQLITE_OPEN_MASTER_JOURNAL
3378733829
|| eType==SQLITE_OPEN_TRANSIENT_DB || eType==SQLITE_OPEN_WAL
3378833830
);
3378933831
33790
- assert( id!=0 );
33791
- UNUSED_PARAMETER(pVfs);
33832
+ assert( pFile!=0 );
33833
+ memset(pFile, 0, sizeof(winFile));
33834
+ pFile->h = INVALID_HANDLE_VALUE;
3379233835
3379333836
#if SQLITE_OS_WINRT
3379433837
if( !sqlite3_temp_directory ){
3379533838
sqlite3_log(SQLITE_ERROR,
3379633839
"sqlite3_temp_directory variable should be set for WinRT");
3379733840
}
3379833841
#endif
3379933842
33800
- pFile->h = INVALID_HANDLE_VALUE;
33801
-
3380233843
/* If the second argument to this function is NULL, generate a
3380333844
** temporary file name to use
3380433845
*/
3380533846
if( !zUtf8Name ){
3380633847
assert(isDelete && !isOpenJournal);
33848
+ memset(zTmpname, 0, MAX_PATH+2);
3380733849
rc = getTempname(MAX_PATH+2, zTmpname);
3380833850
if( rc!=SQLITE_OK ){
3380933851
return rc;
3381033852
}
3381133853
zUtf8Name = zTmpname;
@@ -33924,11 +33966,13 @@
3392433966
pFile->lastErrno = lastErrno;
3392533967
winLogError(SQLITE_CANTOPEN, pFile->lastErrno, "winOpen", zUtf8Name);
3392633968
sqlite3_free(zConverted);
3392733969
if( isReadWrite && !isExclusive ){
3392833970
return winOpen(pVfs, zName, id,
33929
- ((flags|SQLITE_OPEN_READONLY)&~(SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE)), pOutFlags);
33971
+ ((flags|SQLITE_OPEN_READONLY) &
33972
+ ~(SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE)),
33973
+ pOutFlags);
3393033974
}else{
3393133975
return SQLITE_CANTOPEN_BKPT;
3393233976
}
3393333977
}
3393433978
@@ -33938,38 +33982,34 @@
3393833982
}else{
3393933983
*pOutFlags = SQLITE_OPEN_READONLY;
3394033984
}
3394133985
}
3394233986
33943
- memset(pFile, 0, sizeof(*pFile));
33944
- pFile->pMethod = &winIoMethod;
33945
- pFile->h = h;
33946
- pFile->lastErrno = NO_ERROR;
33947
- pFile->pVfs = pVfs;
33948
-#ifndef SQLITE_OMIT_WAL
33949
- pFile->pShm = 0;
33950
-#endif
33951
- pFile->zPath = zName;
33952
- if( sqlite3_uri_boolean(zName, "psow", SQLITE_POWERSAFE_OVERWRITE) ){
33953
- pFile->ctrlFlags |= WINFILE_PSOW;
33954
- }
33955
-
3395633987
#if SQLITE_OS_WINCE
3395733988
if( isReadWrite && eType==SQLITE_OPEN_MAIN_DB
33958
- && !winceCreateLock(zName, pFile)
33989
+ && (rc = winceCreateLock(zName, pFile))!=SQLITE_OK
3395933990
){
3396033991
osCloseHandle(h);
3396133992
sqlite3_free(zConverted);
33962
- return SQLITE_CANTOPEN_BKPT;
33993
+ return rc;
3396333994
}
3396433995
if( isTemp ){
3396533996
pFile->zDeleteOnClose = zConverted;
3396633997
}else
3396733998
#endif
3396833999
{
3396934000
sqlite3_free(zConverted);
3397034001
}
34002
+
34003
+ pFile->pMethod = &winIoMethod;
34004
+ pFile->pVfs = pVfs;
34005
+ pFile->h = h;
34006
+ if( sqlite3_uri_boolean(zName, "psow", SQLITE_POWERSAFE_OVERWRITE) ){
34007
+ pFile->ctrlFlags |= WINFILE_PSOW;
34008
+ }
34009
+ pFile->lastErrno = NO_ERROR;
34010
+ pFile->zPath = zName;
3397134011
3397234012
OpenCounter(+1);
3397334013
return rc;
3397434014
}
3397534015
@@ -34011,11 +34051,12 @@
3401134051
if ( osGetFileAttributesExW(zConverted, GetFileExInfoStandard,
3401234052
&sAttrData) ){
3401334053
attr = sAttrData.dwFileAttributes;
3401434054
}else{
3401534055
lastErrno = osGetLastError();
34016
- if( lastErrno==ERROR_FILE_NOT_FOUND || lastErrno==ERROR_PATH_NOT_FOUND ){
34056
+ if( lastErrno==ERROR_FILE_NOT_FOUND
34057
+ || lastErrno==ERROR_PATH_NOT_FOUND ){
3401734058
rc = SQLITE_IOERR_DELETE_NOENT; /* Already gone? */
3401834059
}else{
3401934060
rc = SQLITE_ERROR;
3402034061
}
3402134062
break;
@@ -34023,11 +34064,12 @@
3402334064
#else
3402434065
attr = osGetFileAttributesW(zConverted);
3402534066
#endif
3402634067
if ( attr==INVALID_FILE_ATTRIBUTES ){
3402734068
lastErrno = osGetLastError();
34028
- if( lastErrno==ERROR_FILE_NOT_FOUND || lastErrno==ERROR_PATH_NOT_FOUND ){
34069
+ if( lastErrno==ERROR_FILE_NOT_FOUND
34070
+ || lastErrno==ERROR_PATH_NOT_FOUND ){
3402934071
rc = SQLITE_IOERR_DELETE_NOENT; /* Already gone? */
3403034072
}else{
3403134073
rc = SQLITE_ERROR;
3403234074
}
3403334075
break;
@@ -34050,11 +34092,12 @@
3405034092
else{
3405134093
do {
3405234094
attr = osGetFileAttributesA(zConverted);
3405334095
if ( attr==INVALID_FILE_ATTRIBUTES ){
3405434096
lastErrno = osGetLastError();
34055
- if( lastErrno==ERROR_FILE_NOT_FOUND || lastErrno==ERROR_PATH_NOT_FOUND ){
34097
+ if( lastErrno==ERROR_FILE_NOT_FOUND
34098
+ || lastErrno==ERROR_PATH_NOT_FOUND ){
3405634099
rc = SQLITE_IOERR_DELETE_NOENT; /* Already gone? */
3405734100
}else{
3405834101
rc = SQLITE_ERROR;
3405934102
}
3406034103
break;
@@ -34218,20 +34261,16 @@
3421834261
** for converting the relative path name to an absolute
3421934262
** one by prepending the data directory and a slash.
3422034263
*/
3422134264
char zOut[MAX_PATH+1];
3422234265
memset(zOut, 0, MAX_PATH+1);
34223
- cygwin_conv_to_win32_path(zRelative, zOut); /* POSIX to Win32 */
34266
+ cygwin_conv_path(CCP_POSIX_TO_WIN_A|CCP_RELATIVE, zRelative, zOut,
34267
+ MAX_PATH+1);
3422434268
sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s\\%s",
3422534269
sqlite3_data_directory, zOut);
3422634270
}else{
34227
- /*
34228
- ** NOTE: The Cygwin docs state that the maximum length needed
34229
- ** for the buffer passed to cygwin_conv_to_full_win32_path
34230
- ** is MAX_PATH.
34231
- */
34232
- cygwin_conv_to_full_win32_path(zRelative, zFull);
34271
+ cygwin_conv_path(CCP_POSIX_TO_WIN_A, zRelative, zFull, nFull);
3423334272
}
3423434273
return SQLITE_OK;
3423534274
#endif
3423634275
3423734276
#if (SQLITE_OS_WINCE || SQLITE_OS_WINRT) && !defined(__CYGWIN__)
@@ -34385,13 +34424,13 @@
3438534424
}
3438634425
static void winDlError(sqlite3_vfs *pVfs, int nBuf, char *zBufOut){
3438734426
UNUSED_PARAMETER(pVfs);
3438834427
getLastErrorMsg(osGetLastError(), nBuf, zBufOut);
3438934428
}
34390
-static void (*winDlSym(sqlite3_vfs *pVfs, void *pHandle, const char *zSymbol))(void){
34429
+static void (*winDlSym(sqlite3_vfs *pVfs,void *pH,const char *zSym))(void){
3439134430
UNUSED_PARAMETER(pVfs);
34392
- return (void(*)(void))osGetProcAddressA((HANDLE)pHandle, zSymbol);
34431
+ return (void(*)(void))osGetProcAddressA((HANDLE)pH, zSym);
3439334432
}
3439434433
static void winDlClose(sqlite3_vfs *pVfs, void *pHandle){
3439534434
UNUSED_PARAMETER(pVfs);
3439634435
osFreeLibrary((HANDLE)pHandle);
3439734436
}
@@ -34485,11 +34524,12 @@
3448534524
#ifdef SQLITE_TEST
3448634525
static const sqlite3_int64 unixEpoch = 24405875*(sqlite3_int64)8640000;
3448734526
#endif
3448834527
/* 2^32 - to avoid use of LL and warnings in gcc */
3448934528
static const sqlite3_int64 max32BitValue =
34490
- (sqlite3_int64)2000000000 + (sqlite3_int64)2000000000 + (sqlite3_int64)294967296;
34529
+ (sqlite3_int64)2000000000 + (sqlite3_int64)2000000000 +
34530
+ (sqlite3_int64)294967296;
3449134531
3449234532
#if SQLITE_OS_WINCE
3449334533
SYSTEMTIME time;
3449434534
osGetSystemTime(&time);
3449534535
/* if SystemTimeToFileTime() fails, it returns zero. */
@@ -39163,10 +39203,12 @@
3916339203
pPager->eState = PAGER_ERROR;
3916439204
}
3916539205
return rc;
3916639206
}
3916739207
39208
+static int pager_truncate(Pager *pPager, Pgno nPage);
39209
+
3916839210
/*
3916939211
** This routine ends a transaction. A transaction is usually ended by
3917039212
** either a COMMIT or a ROLLBACK operation. This routine may be called
3917139213
** after rollback of a hot-journal, or if an error occurs while opening
3917239214
** the journal file or writing the very first journal-header of a
@@ -39216,11 +39258,11 @@
3921639258
** tries to unlock the database file if not in exclusive mode. If the
3921739259
** unlock operation fails as well, then the first error code related
3921839260
** to the first error encountered (the journal finalization one) is
3921939261
** returned.
3922039262
*/
39221
-static int pager_end_transaction(Pager *pPager, int hasMaster){
39263
+static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){
3922239264
int rc = SQLITE_OK; /* Error code from journal finalization operation */
3922339265
int rc2 = SQLITE_OK; /* Error code from db file unlock operation */
3922439266
3922539267
/* Do nothing if the pager does not have an open write transaction
3922639268
** or at least a RESERVED lock. This function may be called when there
@@ -39302,11 +39344,21 @@
3930239344
** locking_mode=exclusive mode but is no longer, drop the EXCLUSIVE
3930339345
** lock held on the database file.
3930439346
*/
3930539347
rc2 = sqlite3WalEndWriteTransaction(pPager->pWal);
3930639348
assert( rc2==SQLITE_OK );
39349
+ }else if( rc==SQLITE_OK && bCommit && pPager->dbFileSize>pPager->dbSize ){
39350
+ /* This branch is taken when committing a transaction in rollback-journal
39351
+ ** mode if the database file on disk is larger than the database image.
39352
+ ** At this point the journal has been finalized and the transaction
39353
+ ** successfully committed, but the EXCLUSIVE lock is still held on the
39354
+ ** file. So it is safe to truncate the database file to its minimum
39355
+ ** required size. */
39356
+ assert( pPager->eLock==EXCLUSIVE_LOCK );
39357
+ rc = pager_truncate(pPager, pPager->dbSize);
3930739358
}
39359
+
3930839360
if( !pPager->exclusiveMode
3930939361
&& (!pagerUseWal(pPager) || sqlite3WalExclusiveMode(pPager->pWal, 0))
3931039362
){
3931139363
rc2 = pagerUnlockDb(pPager, SHARED_LOCK);
3931239364
pPager->changeCountDone = 0;
@@ -39341,11 +39393,11 @@
3934139393
sqlite3BeginBenignMalloc();
3934239394
sqlite3PagerRollback(pPager);
3934339395
sqlite3EndBenignMalloc();
3934439396
}else if( !pPager->exclusiveMode ){
3934539397
assert( pPager->eState==PAGER_READER );
39346
- pager_end_transaction(pPager, 0);
39398
+ pager_end_transaction(pPager, 0, 0);
3934739399
}
3934839400
}
3934939401
pager_unlock(pPager);
3935039402
}
3935139403
@@ -40116,11 +40168,11 @@
4011640168
&& (pPager->eState>=PAGER_WRITER_DBMOD || pPager->eState==PAGER_OPEN)
4011740169
){
4011840170
rc = sqlite3PagerSync(pPager);
4011940171
}
4012040172
if( rc==SQLITE_OK ){
40121
- rc = pager_end_transaction(pPager, zMaster[0]!='\0');
40173
+ rc = pager_end_transaction(pPager, zMaster[0]!='\0', 0);
4012240174
testcase( rc!=SQLITE_OK );
4012340175
}
4012440176
if( rc==SQLITE_OK && zMaster[0] && res ){
4012540177
/* If there was a master journal and this routine will return success,
4012640178
** see if it is possible to delete the master journal.
@@ -41068,16 +41120,30 @@
4106841120
/*
4106941121
** Truncate the in-memory database file image to nPage pages. This
4107041122
** function does not actually modify the database file on disk. It
4107141123
** just sets the internal state of the pager object so that the
4107241124
** truncation will be done when the current transaction is committed.
41125
+**
41126
+** This function is only called right before committing a transaction.
41127
+** Once this function has been called, the transaction must either be
41128
+** rolled back or committed. It is not safe to call this function and
41129
+** then continue writing to the database.
4107341130
*/
4107441131
SQLITE_PRIVATE void sqlite3PagerTruncateImage(Pager *pPager, Pgno nPage){
4107541132
assert( pPager->dbSize>=nPage );
4107641133
assert( pPager->eState>=PAGER_WRITER_CACHEMOD );
4107741134
pPager->dbSize = nPage;
41078
- assertTruncateConstraint(pPager);
41135
+
41136
+ /* At one point the code here called assertTruncateConstraint() to
41137
+ ** ensure that all pages being truncated away by this operation are,
41138
+ ** if one or more savepoints are open, present in the savepoint
41139
+ ** journal so that they can be restored if the savepoint is rolled
41140
+ ** back. This is no longer necessary as this function is now only
41141
+ ** called right before committing a transaction. So although the
41142
+ ** Pager object may still have open savepoints (Pager.nSavepoint!=0),
41143
+ ** they cannot be rolled back. So the assertTruncateConstraint() call
41144
+ ** is no longer correct. */
4107941145
}
4108041146
4108141147
4108241148
/*
4108341149
** This function is called before attempting a hot-journal rollback. It
@@ -42126,10 +42192,15 @@
4212642192
}
4212742193
if( rc!=SQLITE_OK ){
4212842194
goto failed;
4212942195
}
4213042196
if( bHotJournal ){
42197
+ if( pPager->readOnly ){
42198
+ rc = SQLITE_READONLY_ROLLBACK;
42199
+ goto failed;
42200
+ }
42201
+
4213142202
/* Get an EXCLUSIVE lock on the database file. At this point it is
4213242203
** important that a RESERVED lock is not obtained on the way to the
4213342204
** EXCLUSIVE lock. If it were, another process might open the
4213442205
** database file, detect the RESERVED lock, and conclude that the
4213542206
** database is safe to read while this process is still rolling the
@@ -43210,40 +43281,10 @@
4321043281
#else
4321143282
rc = pager_incr_changecounter(pPager, 0);
4321243283
#endif
4321343284
if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
4321443285
43215
- /* If this transaction has made the database smaller, then all pages
43216
- ** being discarded by the truncation must be written to the journal
43217
- ** file.
43218
- **
43219
- ** Before reading the pages with page numbers larger than the
43220
- ** current value of Pager.dbSize, set dbSize back to the value
43221
- ** that it took at the start of the transaction. Otherwise, the
43222
- ** calls to sqlite3PagerGet() return zeroed pages instead of
43223
- ** reading data from the database file.
43224
- */
43225
- if( pPager->dbSize<pPager->dbOrigSize
43226
- && pPager->journalMode!=PAGER_JOURNALMODE_OFF
43227
- ){
43228
- Pgno i; /* Iterator variable */
43229
- const Pgno iSkip = PAGER_MJ_PGNO(pPager); /* Pending lock page */
43230
- const Pgno dbSize = pPager->dbSize; /* Database image size */
43231
- pPager->dbSize = pPager->dbOrigSize;
43232
- for( i=dbSize+1; i<=pPager->dbOrigSize; i++ ){
43233
- if( !sqlite3BitvecTest(pPager->pInJournal, i) && i!=iSkip ){
43234
- PgHdr *pPage; /* Page to journal */
43235
- rc = sqlite3PagerGet(pPager, i, &pPage);
43236
- if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
43237
- rc = sqlite3PagerWrite(pPage);
43238
- sqlite3PagerUnref(pPage);
43239
- if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
43240
- }
43241
- }
43242
- pPager->dbSize = dbSize;
43243
- }
43244
-
4324543286
/* Write the master journal name into the journal file. If a master
4324643287
** journal file name has already been written to the journal file,
4324743288
** or if zMaster is NULL (no master journal), then this call is a no-op.
4324843289
*/
4324943290
rc = writeMasterJournal(pPager, zMaster);
@@ -43267,15 +43308,18 @@
4326743308
if( rc!=SQLITE_OK ){
4326843309
assert( rc!=SQLITE_IOERR_BLOCKED );
4326943310
goto commit_phase_one_exit;
4327043311
}
4327143312
sqlite3PcacheCleanAll(pPager->pPCache);
43272
-
43273
- /* If the file on disk is not the same size as the database image,
43274
- ** then use pager_truncate to grow or shrink the file here.
43275
- */
43276
- if( pPager->dbSize!=pPager->dbFileSize ){
43313
+
43314
+ /* If the file on disk is smaller than the database image, use
43315
+ ** pager_truncate to grow the file here. This can happen if the database
43316
+ ** image was extended as part of the current transaction and then the
43317
+ ** last page in the db image moved to the free-list. In this case the
43318
+ ** last page is never written out to disk, leaving the database file
43319
+ ** undersized. Fix this now if it is the case. */
43320
+ if( pPager->dbSize>pPager->dbFileSize ){
4327743321
Pgno nNew = pPager->dbSize - (pPager->dbSize==PAGER_MJ_PGNO(pPager));
4327843322
assert( pPager->eState==PAGER_WRITER_DBMOD );
4327943323
rc = pager_truncate(pPager, nNew);
4328043324
if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
4328143325
}
@@ -43344,11 +43388,11 @@
4334443388
pPager->eState = PAGER_READER;
4334543389
return SQLITE_OK;
4334643390
}
4334743391
4334843392
PAGERTRACE(("COMMIT %d\n", PAGERID(pPager)));
43349
- rc = pager_end_transaction(pPager, pPager->setMaster);
43393
+ rc = pager_end_transaction(pPager, pPager->setMaster, 1);
4335043394
return pager_error(pPager, rc);
4335143395
}
4335243396
4335343397
/*
4335443398
** If a write transaction is open, then all changes made within the
@@ -43389,15 +43433,15 @@
4338943433
if( pPager->eState<=PAGER_READER ) return SQLITE_OK;
4339043434
4339143435
if( pagerUseWal(pPager) ){
4339243436
int rc2;
4339343437
rc = sqlite3PagerSavepoint(pPager, SAVEPOINT_ROLLBACK, -1);
43394
- rc2 = pager_end_transaction(pPager, pPager->setMaster);
43438
+ rc2 = pager_end_transaction(pPager, pPager->setMaster, 0);
4339543439
if( rc==SQLITE_OK ) rc = rc2;
4339643440
}else if( !isOpen(pPager->jfd) || pPager->eState==PAGER_WRITER_LOCKED ){
4339743441
int eState = pPager->eState;
43398
- rc = pager_end_transaction(pPager, 0);
43442
+ rc = pager_end_transaction(pPager, 0, 0);
4339943443
if( !MEMDB && eState>PAGER_WRITER_LOCKED ){
4340043444
/* This can happen using journal_mode=off. Move the pager to the error
4340143445
** state to indicate that the contents of the cache may not be trusted.
4340243446
** Any active readers will get SQLITE_ABORT.
4340343447
*/
@@ -43791,11 +43835,12 @@
4379143835
** the journal needs to be sync()ed before database page pPg->pgno
4379243836
** can be written to. The caller has already promised not to write to it.
4379343837
*/
4379443838
if( (pPg->flags&PGHDR_NEED_SYNC) && !isCommit ){
4379543839
needSyncPgno = pPg->pgno;
43796
- assert( pageInJournal(pPg) || pPg->pgno>pPager->dbOrigSize );
43840
+ assert( pPager->journalMode==PAGER_JOURNALMODE_OFF ||
43841
+ pageInJournal(pPg) || pPg->pgno>pPager->dbOrigSize );
4379743842
assert( pPg->flags&PGHDR_DIRTY );
4379843843
}
4379943844
4380043845
/* If the cache contains a page with page-number pgno, remove it
4380143846
** from its hash chain. Also, if the PGHDR_NEED_SYNC flag was set for
@@ -47795,10 +47840,11 @@
4779547840
MemPage *pPage1; /* First page of the database */
4779647841
u8 openFlags; /* Flags to sqlite3BtreeOpen() */
4779747842
#ifndef SQLITE_OMIT_AUTOVACUUM
4779847843
u8 autoVacuum; /* True if auto-vacuum is enabled */
4779947844
u8 incrVacuum; /* True if incr-vacuum is enabled */
47845
+ u8 bDoTruncate; /* True to truncate db on commit */
4780047846
#endif
4780147847
u8 inTransaction; /* Transaction state */
4780247848
u8 max1bytePayload; /* Maximum first byte of cell for a 1-byte payload */
4780347849
u16 btsFlags; /* Boolean parameters. See BTS_* macros below */
4780447850
u16 maxLocal; /* Maximum local payload in non-LEAFDATA tables */
@@ -48361,10 +48407,29 @@
4836148407
** is empty, the offset should be 65536, but the 2-byte value stores zero.
4836248408
** This routine makes the necessary adjustment to 65536.
4836348409
*/
4836448410
#define get2byteNotZero(X) (((((int)get2byte(X))-1)&0xffff)+1)
4836548411
48412
+/*
48413
+** Values passed as the 5th argument to allocateBtreePage()
48414
+*/
48415
+#define BTALLOC_ANY 0 /* Allocate any page */
48416
+#define BTALLOC_EXACT 1 /* Allocate exact page if possible */
48417
+#define BTALLOC_LE 2 /* Allocate any page <= the parameter */
48418
+
48419
+/*
48420
+** Macro IfNotOmitAV(x) returns (x) if SQLITE_OMIT_AUTOVACUUM is not
48421
+** defined, or 0 if it is. For example:
48422
+**
48423
+** bIncrVacuum = IfNotOmitAV(pBtShared->incrVacuum);
48424
+*/
48425
+#ifndef SQLITE_OMIT_AUTOVACUUM
48426
+#define IfNotOmitAV(expr) (expr)
48427
+#else
48428
+#define IfNotOmitAV(expr) 0
48429
+#endif
48430
+
4836648431
#ifndef SQLITE_OMIT_SHARED_CACHE
4836748432
/*
4836848433
** A list of BtShared objects that are eligible for participation
4836948434
** in shared cache. This variable has file scope during normal builds,
4837048435
** but the test harness needs to access it so we make it global for
@@ -50913,10 +50978,11 @@
5091350978
** is requested, this is a no-op.
5091450979
*/
5091550980
if( p->inTrans==TRANS_WRITE || (p->inTrans==TRANS_READ && !wrflag) ){
5091650981
goto trans_begun;
5091750982
}
50983
+ assert( IfNotOmitAV(pBt->bDoTruncate)==0 );
5091850984
5091950985
/* Write transactions are not possible on a read-only database */
5092050986
if( (pBt->btsFlags & BTS_READ_ONLY)!=0 && wrflag ){
5092150987
rc = SQLITE_READONLY;
5092250988
goto trans_begun;
@@ -51229,28 +51295,27 @@
5122951295
5123051296
/* Forward declaration required by incrVacuumStep(). */
5123151297
static int allocateBtreePage(BtShared *, MemPage **, Pgno *, Pgno, u8);
5123251298
5123351299
/*
51234
-** Perform a single step of an incremental-vacuum. If successful,
51235
-** return SQLITE_OK. If there is no work to do (and therefore no
51236
-** point in calling this function again), return SQLITE_DONE.
51237
-**
51238
-** More specificly, this function attempts to re-organize the
51239
-** database so that the last page of the file currently in use
51240
-** is no longer in use.
51241
-**
51242
-** If the nFin parameter is non-zero, this function assumes
51243
-** that the caller will keep calling incrVacuumStep() until
51244
-** it returns SQLITE_DONE or an error, and that nFin is the
51245
-** number of pages the database file will contain after this
51246
-** process is complete. If nFin is zero, it is assumed that
51247
-** incrVacuumStep() will be called a finite amount of times
51248
-** which may or may not empty the freelist. A full autovacuum
51249
-** has nFin>0. A "PRAGMA incremental_vacuum" has nFin==0.
51250
-*/
51251
-static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg){
51300
+** Perform a single step of an incremental-vacuum. If successful, return
51301
+** SQLITE_OK. If there is no work to do (and therefore no point in
51302
+** calling this function again), return SQLITE_DONE. Or, if an error
51303
+** occurs, return some other error code.
51304
+**
51305
+** More specificly, this function attempts to re-organize the database so
51306
+** that the last page of the file currently in use is no longer in use.
51307
+**
51308
+** Parameter nFin is the number of pages that this database would contain
51309
+** were this function called until it returns SQLITE_DONE.
51310
+**
51311
+** If the bCommit parameter is non-zero, this function assumes that the
51312
+** caller will keep calling incrVacuumStep() until it returns SQLITE_DONE
51313
+** or an error. bCommit is passed true for an auto-vacuum-on-commmit
51314
+** operation, or false for an incremental vacuum.
51315
+*/
51316
+static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg, int bCommit){
5125251317
Pgno nFreeList; /* Number of pages still on the free-list */
5125351318
int rc;
5125451319
5125551320
assert( sqlite3_mutex_held(pBt->mutex) );
5125651321
assert( iLastPg>nFin );
@@ -51271,85 +51336,98 @@
5127151336
if( eType==PTRMAP_ROOTPAGE ){
5127251337
return SQLITE_CORRUPT_BKPT;
5127351338
}
5127451339
5127551340
if( eType==PTRMAP_FREEPAGE ){
51276
- if( nFin==0 ){
51341
+ if( bCommit==0 ){
5127751342
/* Remove the page from the files free-list. This is not required
51278
- ** if nFin is non-zero. In that case, the free-list will be
51343
+ ** if bCommit is non-zero. In that case, the free-list will be
5127951344
** truncated to zero after this function returns, so it doesn't
5128051345
** matter if it still contains some garbage entries.
5128151346
*/
5128251347
Pgno iFreePg;
5128351348
MemPage *pFreePg;
51284
- rc = allocateBtreePage(pBt, &pFreePg, &iFreePg, iLastPg, 1);
51349
+ rc = allocateBtreePage(pBt, &pFreePg, &iFreePg, iLastPg, BTALLOC_EXACT);
5128551350
if( rc!=SQLITE_OK ){
5128651351
return rc;
5128751352
}
5128851353
assert( iFreePg==iLastPg );
5128951354
releasePage(pFreePg);
5129051355
}
5129151356
} else {
5129251357
Pgno iFreePg; /* Index of free page to move pLastPg to */
5129351358
MemPage *pLastPg;
51359
+ u8 eMode = BTALLOC_ANY; /* Mode parameter for allocateBtreePage() */
51360
+ Pgno iNear = 0; /* nearby parameter for allocateBtreePage() */
5129451361
5129551362
rc = btreeGetPage(pBt, iLastPg, &pLastPg, 0);
5129651363
if( rc!=SQLITE_OK ){
5129751364
return rc;
5129851365
}
5129951366
51300
- /* If nFin is zero, this loop runs exactly once and page pLastPg
51367
+ /* If bCommit is zero, this loop runs exactly once and page pLastPg
5130151368
** is swapped with the first free page pulled off the free list.
5130251369
**
51303
- ** On the other hand, if nFin is greater than zero, then keep
51370
+ ** On the other hand, if bCommit is greater than zero, then keep
5130451371
** looping until a free-page located within the first nFin pages
5130551372
** of the file is found.
5130651373
*/
51374
+ if( bCommit==0 ){
51375
+ eMode = BTALLOC_LE;
51376
+ iNear = nFin;
51377
+ }
5130751378
do {
5130851379
MemPage *pFreePg;
51309
- rc = allocateBtreePage(pBt, &pFreePg, &iFreePg, 0, 0);
51380
+ rc = allocateBtreePage(pBt, &pFreePg, &iFreePg, iNear, eMode);
5131051381
if( rc!=SQLITE_OK ){
5131151382
releasePage(pLastPg);
5131251383
return rc;
5131351384
}
5131451385
releasePage(pFreePg);
51315
- }while( nFin!=0 && iFreePg>nFin );
51386
+ }while( bCommit && iFreePg>nFin );
5131651387
assert( iFreePg<iLastPg );
5131751388
51318
- rc = sqlite3PagerWrite(pLastPg->pDbPage);
51319
- if( rc==SQLITE_OK ){
51320
- rc = relocatePage(pBt, pLastPg, eType, iPtrPage, iFreePg, nFin!=0);
51321
- }
51389
+ rc = relocatePage(pBt, pLastPg, eType, iPtrPage, iFreePg, bCommit);
5132251390
releasePage(pLastPg);
5132351391
if( rc!=SQLITE_OK ){
5132451392
return rc;
5132551393
}
5132651394
}
5132751395
}
5132851396
51329
- if( nFin==0 ){
51330
- iLastPg--;
51331
- while( iLastPg==PENDING_BYTE_PAGE(pBt)||PTRMAP_ISPAGE(pBt, iLastPg) ){
51332
- if( PTRMAP_ISPAGE(pBt, iLastPg) ){
51333
- MemPage *pPg;
51334
- rc = btreeGetPage(pBt, iLastPg, &pPg, 0);
51335
- if( rc!=SQLITE_OK ){
51336
- return rc;
51337
- }
51338
- rc = sqlite3PagerWrite(pPg->pDbPage);
51339
- releasePage(pPg);
51340
- if( rc!=SQLITE_OK ){
51341
- return rc;
51342
- }
51343
- }
51344
- iLastPg--;
51345
- }
51346
- sqlite3PagerTruncateImage(pBt->pPager, iLastPg);
51397
+ if( bCommit==0 ){
51398
+ do {
51399
+ iLastPg--;
51400
+ }while( iLastPg==PENDING_BYTE_PAGE(pBt) || PTRMAP_ISPAGE(pBt, iLastPg) );
51401
+ pBt->bDoTruncate = 1;
5134751402
pBt->nPage = iLastPg;
5134851403
}
5134951404
return SQLITE_OK;
5135051405
}
51406
+
51407
+/*
51408
+** The database opened by the first argument is an auto-vacuum database
51409
+** nOrig pages in size containing nFree free pages. Return the expected
51410
+** size of the database in pages following an auto-vacuum operation.
51411
+*/
51412
+static Pgno finalDbSize(BtShared *pBt, Pgno nOrig, Pgno nFree){
51413
+ int nEntry; /* Number of entries on one ptrmap page */
51414
+ Pgno nPtrmap; /* Number of PtrMap pages to be freed */
51415
+ Pgno nFin; /* Return value */
51416
+
51417
+ nEntry = pBt->usableSize/5;
51418
+ nPtrmap = (nFree-nOrig+PTRMAP_PAGENO(pBt, nOrig)+nEntry)/nEntry;
51419
+ nFin = nOrig - nFree - nPtrmap;
51420
+ if( nOrig>PENDING_BYTE_PAGE(pBt) && nFin<PENDING_BYTE_PAGE(pBt) ){
51421
+ nFin--;
51422
+ }
51423
+ while( PTRMAP_ISPAGE(pBt, nFin) || nFin==PENDING_BYTE_PAGE(pBt) ){
51424
+ nFin--;
51425
+ }
51426
+
51427
+ return nFin;
51428
+}
5135151429
5135251430
/*
5135351431
** A write-transaction must be opened before calling this function.
5135451432
** It performs a single unit of work towards an incremental vacuum.
5135551433
**
@@ -51364,15 +51442,25 @@
5136451442
sqlite3BtreeEnter(p);
5136551443
assert( pBt->inTransaction==TRANS_WRITE && p->inTrans==TRANS_WRITE );
5136651444
if( !pBt->autoVacuum ){
5136751445
rc = SQLITE_DONE;
5136851446
}else{
51369
- invalidateAllOverflowCache(pBt);
51370
- rc = incrVacuumStep(pBt, 0, btreePagecount(pBt));
51371
- if( rc==SQLITE_OK ){
51372
- rc = sqlite3PagerWrite(pBt->pPage1->pDbPage);
51373
- put4byte(&pBt->pPage1->aData[28], pBt->nPage);
51447
+ Pgno nOrig = btreePagecount(pBt);
51448
+ Pgno nFree = get4byte(&pBt->pPage1->aData[36]);
51449
+ Pgno nFin = finalDbSize(pBt, nOrig, nFree);
51450
+
51451
+ if( nOrig<nFin ){
51452
+ rc = SQLITE_CORRUPT_BKPT;
51453
+ }else if( nFree>0 ){
51454
+ invalidateAllOverflowCache(pBt);
51455
+ rc = incrVacuumStep(pBt, nFin, nOrig, 0);
51456
+ if( rc==SQLITE_OK ){
51457
+ rc = sqlite3PagerWrite(pBt->pPage1->pDbPage);
51458
+ put4byte(&pBt->pPage1->aData[28], pBt->nPage);
51459
+ }
51460
+ }else{
51461
+ rc = SQLITE_DONE;
5137451462
}
5137551463
}
5137651464
sqlite3BtreeLeave(p);
5137751465
return rc;
5137851466
}
@@ -51395,13 +51483,11 @@
5139551483
invalidateAllOverflowCache(pBt);
5139651484
assert(pBt->autoVacuum);
5139751485
if( !pBt->incrVacuum ){
5139851486
Pgno nFin; /* Number of pages in database after autovacuuming */
5139951487
Pgno nFree; /* Number of pages on the freelist initially */
51400
- Pgno nPtrmap; /* Number of PtrMap pages to be freed */
5140151488
Pgno iFree; /* The next page to be freed */
51402
- int nEntry; /* Number of entries on one ptrmap page */
5140351489
Pgno nOrig; /* Database size before freeing */
5140451490
5140551491
nOrig = btreePagecount(pBt);
5140651492
if( PTRMAP_ISPAGE(pBt, nOrig) || nOrig==PENDING_BYTE_PAGE(pBt) ){
5140751493
/* It is not possible to create a database for which the final page
@@ -51410,30 +51496,22 @@
5141051496
*/
5141151497
return SQLITE_CORRUPT_BKPT;
5141251498
}
5141351499
5141451500
nFree = get4byte(&pBt->pPage1->aData[36]);
51415
- nEntry = pBt->usableSize/5;
51416
- nPtrmap = (nFree-nOrig+PTRMAP_PAGENO(pBt, nOrig)+nEntry)/nEntry;
51417
- nFin = nOrig - nFree - nPtrmap;
51418
- if( nOrig>PENDING_BYTE_PAGE(pBt) && nFin<PENDING_BYTE_PAGE(pBt) ){
51419
- nFin--;
51420
- }
51421
- while( PTRMAP_ISPAGE(pBt, nFin) || nFin==PENDING_BYTE_PAGE(pBt) ){
51422
- nFin--;
51423
- }
51501
+ nFin = finalDbSize(pBt, nOrig, nFree);
5142451502
if( nFin>nOrig ) return SQLITE_CORRUPT_BKPT;
5142551503
5142651504
for(iFree=nOrig; iFree>nFin && rc==SQLITE_OK; iFree--){
51427
- rc = incrVacuumStep(pBt, nFin, iFree);
51505
+ rc = incrVacuumStep(pBt, nFin, iFree, 1);
5142851506
}
5142951507
if( (rc==SQLITE_DONE || rc==SQLITE_OK) && nFree>0 ){
5143051508
rc = sqlite3PagerWrite(pBt->pPage1->pDbPage);
5143151509
put4byte(&pBt->pPage1->aData[32], 0);
5143251510
put4byte(&pBt->pPage1->aData[36], 0);
5143351511
put4byte(&pBt->pPage1->aData[28], nFin);
51434
- sqlite3PagerTruncateImage(pBt->pPager, nFin);
51512
+ pBt->bDoTruncate = 1;
5143551513
pBt->nPage = nFin;
5143651514
}
5143751515
if( rc!=SQLITE_OK ){
5143851516
sqlite3PagerRollback(pPager);
5143951517
}
@@ -51484,10 +51562,13 @@
5148451562
if( rc!=SQLITE_OK ){
5148551563
sqlite3BtreeLeave(p);
5148651564
return rc;
5148751565
}
5148851566
}
51567
+ if( pBt->bDoTruncate ){
51568
+ sqlite3PagerTruncateImage(pBt->pPager, pBt->nPage);
51569
+ }
5148951570
#endif
5149051571
rc = sqlite3PagerCommitPhaseOne(pBt->pPager, zMaster, 0);
5149151572
sqlite3BtreeLeave(p);
5149251573
}
5149351574
return rc;
@@ -51499,10 +51580,13 @@
5149951580
*/
5150051581
static void btreeEndTransaction(Btree *p){
5150151582
BtShared *pBt = p->pBt;
5150251583
assert( sqlite3BtreeHoldsMutex(p) );
5150351584
51585
+#ifndef SQLITE_OMIT_AUTOVACUUM
51586
+ pBt->bDoTruncate = 0;
51587
+#endif
5150451588
btreeClearHasContent(pBt);
5150551589
if( p->inTrans>TRANS_NONE && p->db->activeVdbeCnt>1 ){
5150651590
/* If there are other active statements that belong to this database
5150751591
** handle, downgrade to a read-only transaction. The other statements
5150851592
** may still be reading from the database. */
@@ -53171,25 +53255,27 @@
5317153255
**
5317253256
** SQLITE_OK is returned on success. Any other return value indicates
5317353257
** an error. *ppPage and *pPgno are undefined in the event of an error.
5317453258
** Do not invoke sqlite3PagerUnref() on *ppPage if an error is returned.
5317553259
**
53176
-** If the "nearby" parameter is not 0, then a (feeble) effort is made to
53260
+** If the "nearby" parameter is not 0, then an effort is made to
5317753261
** locate a page close to the page number "nearby". This can be used in an
5317853262
** attempt to keep related pages close to each other in the database file,
5317953263
** which in turn can make database access faster.
5318053264
**
53181
-** If the "exact" parameter is not 0, and the page-number nearby exists
53182
-** anywhere on the free-list, then it is guarenteed to be returned. This
53183
-** is only used by auto-vacuum databases when allocating a new table.
53265
+** If the eMode parameter is BTALLOC_EXACT and the nearby page exists
53266
+** anywhere on the free-list, then it is guaranteed to be returned. If
53267
+** eMode is BTALLOC_LT then the page returned will be less than or equal
53268
+** to nearby if any such page exists. If eMode is BTALLOC_ANY then there
53269
+** are no restrictions on which page is returned.
5318453270
*/
5318553271
static int allocateBtreePage(
53186
- BtShared *pBt,
53187
- MemPage **ppPage,
53188
- Pgno *pPgno,
53189
- Pgno nearby,
53190
- u8 exact
53272
+ BtShared *pBt, /* The btree */
53273
+ MemPage **ppPage, /* Store pointer to the allocated page here */
53274
+ Pgno *pPgno, /* Store the page number here */
53275
+ Pgno nearby, /* Search for a page near this one */
53276
+ u8 eMode /* BTALLOC_EXACT, BTALLOC_LT, or BTALLOC_ANY */
5319153277
){
5319253278
MemPage *pPage1;
5319353279
int rc;
5319453280
u32 n; /* Number of pages on the freelist */
5319553281
u32 k; /* Number of leaves on the trunk of the freelist */
@@ -53196,10 +53282,11 @@
5319653282
MemPage *pTrunk = 0;
5319753283
MemPage *pPrevTrunk = 0;
5319853284
Pgno mxPage; /* Total size of the database file */
5319953285
5320053286
assert( sqlite3_mutex_held(pBt->mutex) );
53287
+ assert( eMode==BTALLOC_ANY || (nearby>0 && IfNotOmitAV(pBt->autoVacuum)) );
5320153288
pPage1 = pBt->pPage1;
5320253289
mxPage = btreePagecount(pBt);
5320353290
n = get4byte(&pPage1->aData[36]);
5320453291
testcase( n==mxPage-1 );
5320553292
if( n>=mxPage ){
@@ -53208,25 +53295,28 @@
5320853295
if( n>0 ){
5320953296
/* There are pages on the freelist. Reuse one of those pages. */
5321053297
Pgno iTrunk;
5321153298
u8 searchList = 0; /* If the free-list must be searched for 'nearby' */
5321253299
53213
- /* If the 'exact' parameter was true and a query of the pointer-map
53300
+ /* If eMode==BTALLOC_EXACT and a query of the pointer-map
5321453301
** shows that the page 'nearby' is somewhere on the free-list, then
5321553302
** the entire-list will be searched for that page.
5321653303
*/
5321753304
#ifndef SQLITE_OMIT_AUTOVACUUM
53218
- if( exact && nearby<=mxPage ){
53219
- u8 eType;
53220
- assert( nearby>0 );
53221
- assert( pBt->autoVacuum );
53222
- rc = ptrmapGet(pBt, nearby, &eType, 0);
53223
- if( rc ) return rc;
53224
- if( eType==PTRMAP_FREEPAGE ){
53225
- searchList = 1;
53226
- }
53227
- *pPgno = nearby;
53305
+ if( eMode==BTALLOC_EXACT ){
53306
+ if( nearby<=mxPage ){
53307
+ u8 eType;
53308
+ assert( nearby>0 );
53309
+ assert( pBt->autoVacuum );
53310
+ rc = ptrmapGet(pBt, nearby, &eType, 0);
53311
+ if( rc ) return rc;
53312
+ if( eType==PTRMAP_FREEPAGE ){
53313
+ searchList = 1;
53314
+ }
53315
+ }
53316
+ }else if( eMode==BTALLOC_LE ){
53317
+ searchList = 1;
5322853318
}
5322953319
#endif
5323053320
5323153321
/* Decrement the free-list count by 1. Set iTrunk to the index of the
5323253322
** first free-list trunk page. iPrevTrunk is initially 1.
@@ -53235,11 +53325,12 @@
5323553325
if( rc ) return rc;
5323653326
put4byte(&pPage1->aData[36], n-1);
5323753327
5323853328
/* The code within this loop is run only once if the 'searchList' variable
5323953329
** is not true. Otherwise, it runs once for each trunk-page on the
53240
- ** free-list until the page 'nearby' is located.
53330
+ ** free-list until the page 'nearby' is located (eMode==BTALLOC_EXACT)
53331
+ ** or until a page less than 'nearby' is located (eMode==BTALLOC_LT)
5324153332
*/
5324253333
do {
5324353334
pPrevTrunk = pTrunk;
5324453335
if( pPrevTrunk ){
5324553336
iTrunk = get4byte(&pPrevTrunk->aData[0]);
@@ -53277,15 +53368,17 @@
5327753368
}else if( k>(u32)(pBt->usableSize/4 - 2) ){
5327853369
/* Value of k is out of range. Database corruption */
5327953370
rc = SQLITE_CORRUPT_BKPT;
5328053371
goto end_allocate_page;
5328153372
#ifndef SQLITE_OMIT_AUTOVACUUM
53282
- }else if( searchList && nearby==iTrunk ){
53373
+ }else if( searchList
53374
+ && (nearby==iTrunk || (iTrunk<nearby && eMode==BTALLOC_LE))
53375
+ ){
5328353376
/* The list is being searched and this trunk page is the page
5328453377
** to allocate, regardless of whether it has leaves.
5328553378
*/
53286
- assert( *pPgno==iTrunk );
53379
+ *pPgno = iTrunk;
5328753380
*ppPage = pTrunk;
5328853381
searchList = 0;
5328953382
rc = sqlite3PagerWrite(pTrunk->pDbPage);
5329053383
if( rc ){
5329153384
goto end_allocate_page;
@@ -53344,18 +53437,28 @@
5334453437
u32 closest;
5334553438
Pgno iPage;
5334653439
unsigned char *aData = pTrunk->aData;
5334753440
if( nearby>0 ){
5334853441
u32 i;
53349
- int dist;
5335053442
closest = 0;
53351
- dist = sqlite3AbsInt32(get4byte(&aData[8]) - nearby);
53352
- for(i=1; i<k; i++){
53353
- int d2 = sqlite3AbsInt32(get4byte(&aData[8+i*4]) - nearby);
53354
- if( d2<dist ){
53355
- closest = i;
53356
- dist = d2;
53443
+ if( eMode==BTALLOC_LE ){
53444
+ for(i=0; i<k; i++){
53445
+ iPage = get4byte(&aData[8+i*4]);
53446
+ if( iPage<=nearby ){
53447
+ closest = i;
53448
+ break;
53449
+ }
53450
+ }
53451
+ }else{
53452
+ int dist;
53453
+ dist = sqlite3AbsInt32(get4byte(&aData[8]) - nearby);
53454
+ for(i=1; i<k; i++){
53455
+ int d2 = sqlite3AbsInt32(get4byte(&aData[8+i*4]) - nearby);
53456
+ if( d2<dist ){
53457
+ closest = i;
53458
+ dist = d2;
53459
+ }
5335753460
}
5335853461
}
5335953462
}else{
5336053463
closest = 0;
5336153464
}
@@ -53365,11 +53468,13 @@
5336553468
if( iPage>mxPage ){
5336653469
rc = SQLITE_CORRUPT_BKPT;
5336753470
goto end_allocate_page;
5336853471
}
5336953472
testcase( iPage==mxPage );
53370
- if( !searchList || iPage==nearby ){
53473
+ if( !searchList
53474
+ || (iPage==nearby || (iPage<nearby && eMode==BTALLOC_LE))
53475
+ ){
5337153476
int noContent;
5337253477
*pPgno = iPage;
5337353478
TRACE(("ALLOCATE: %d was leaf %d of %d on trunk %d"
5337453479
": %d more free pages\n",
5337553480
*pPgno, closest+1, k, pTrunk->pgno, n-1));
@@ -53392,12 +53497,30 @@
5339253497
}
5339353498
releasePage(pPrevTrunk);
5339453499
pPrevTrunk = 0;
5339553500
}while( searchList );
5339653501
}else{
53397
- /* There are no pages on the freelist, so create a new page at the
53398
- ** end of the file */
53502
+ /* There are no pages on the freelist, so append a new page to the
53503
+ ** database image.
53504
+ **
53505
+ ** Normally, new pages allocated by this block can be requested from the
53506
+ ** pager layer with the 'no-content' flag set. This prevents the pager
53507
+ ** from trying to read the pages content from disk. However, if the
53508
+ ** current transaction has already run one or more incremental-vacuum
53509
+ ** steps, then the page we are about to allocate may contain content
53510
+ ** that is required in the event of a rollback. In this case, do
53511
+ ** not set the no-content flag. This causes the pager to load and journal
53512
+ ** the current page content before overwriting it.
53513
+ **
53514
+ ** Note that the pager will not actually attempt to load or journal
53515
+ ** content for any page that really does lie past the end of the database
53516
+ ** file on disk. So the effects of disabling the no-content optimization
53517
+ ** here are confined to those pages that lie between the end of the
53518
+ ** database image and the end of the database file.
53519
+ */
53520
+ int bNoContent = (0==IfNotOmitAV(pBt->bDoTruncate));
53521
+
5339953522
rc = sqlite3PagerWrite(pBt->pPage1->pDbPage);
5340053523
if( rc ) return rc;
5340153524
pBt->nPage++;
5340253525
if( pBt->nPage==PENDING_BYTE_PAGE(pBt) ) pBt->nPage++;
5340353526
@@ -53408,11 +53531,11 @@
5340853531
** becomes a new pointer-map page, the second is used by the caller.
5340953532
*/
5341053533
MemPage *pPg = 0;
5341153534
TRACE(("ALLOCATE: %d from end of file (pointer-map page)\n", pBt->nPage));
5341253535
assert( pBt->nPage!=PENDING_BYTE_PAGE(pBt) );
53413
- rc = btreeGetPage(pBt, pBt->nPage, &pPg, 1);
53536
+ rc = btreeGetPage(pBt, pBt->nPage, &pPg, bNoContent);
5341453537
if( rc==SQLITE_OK ){
5341553538
rc = sqlite3PagerWrite(pPg->pDbPage);
5341653539
releasePage(pPg);
5341753540
}
5341853541
if( rc ) return rc;
@@ -53422,11 +53545,11 @@
5342253545
#endif
5342353546
put4byte(28 + (u8*)pBt->pPage1->aData, pBt->nPage);
5342453547
*pPgno = pBt->nPage;
5342553548
5342653549
assert( *pPgno!=PENDING_BYTE_PAGE(pBt) );
53427
- rc = btreeGetPage(pBt, *pPgno, ppPage, 1);
53550
+ rc = btreeGetPage(pBt, *pPgno, ppPage, bNoContent);
5342853551
if( rc ) return rc;
5342953552
rc = sqlite3PagerWrite((*ppPage)->pDbPage);
5343053553
if( rc!=SQLITE_OK ){
5343153554
releasePage(*ppPage);
5343253555
}
@@ -55437,11 +55560,11 @@
5543755560
5543855561
/* Allocate a page. The page that currently resides at pgnoRoot will
5543955562
** be moved to the allocated page (unless the allocated page happens
5544055563
** to reside at pgnoRoot).
5544155564
*/
55442
- rc = allocateBtreePage(pBt, &pPageMove, &pgnoMove, pgnoRoot, 1);
55565
+ rc = allocateBtreePage(pBt, &pPageMove, &pgnoMove, pgnoRoot, BTALLOC_EXACT);
5544355566
if( rc!=SQLITE_OK ){
5544455567
return rc;
5544555568
}
5544655569
5544755570
if( pgnoMove!=pgnoRoot ){
@@ -57129,11 +57252,10 @@
5712957252
}
5713057253
}else{
5713157254
nDestTruncate = nSrcPage * (pgszSrc/pgszDest);
5713257255
}
5713357256
assert( nDestTruncate>0 );
57134
- sqlite3PagerTruncateImage(pDestPager, nDestTruncate);
5713557257
5713657258
if( pgszSrc<pgszDest ){
5713757259
/* If the source page-size is smaller than the destination page-size,
5713857260
** two extra things may need to happen:
5713957261
**
@@ -57143,10 +57265,12 @@
5714357265
** pending-byte page in the source database may need to be
5714457266
** copied into the destination database.
5714557267
*/
5714657268
const i64 iSize = (i64)pgszSrc * (i64)nSrcPage;
5714757269
sqlite3_file * const pFile = sqlite3PagerFile(pDestPager);
57270
+ Pgno iPg;
57271
+ int nDstPage;
5714857272
i64 iOff;
5714957273
i64 iEnd;
5715057274
5715157275
assert( pFile );
5715257276
assert( nDestTruncate==0
@@ -57153,17 +57277,30 @@
5715357277
|| (i64)nDestTruncate*(i64)pgszDest >= iSize || (
5715457278
nDestTruncate==(int)(PENDING_BYTE_PAGE(p->pDest->pBt)-1)
5715557279
&& iSize>=PENDING_BYTE && iSize<=PENDING_BYTE+pgszDest
5715657280
));
5715757281
57158
- /* This call ensures that all data required to recreate the original
57282
+ /* This block ensures that all data required to recreate the original
5715957283
** database has been stored in the journal for pDestPager and the
5716057284
** journal synced to disk. So at this point we may safely modify
5716157285
** the database file in any way, knowing that if a power failure
5716257286
** occurs, the original database will be reconstructed from the
5716357287
** journal file. */
57164
- rc = sqlite3PagerCommitPhaseOne(pDestPager, 0, 1);
57288
+ sqlite3PagerPagecount(pDestPager, &nDstPage);
57289
+ for(iPg=nDestTruncate; rc==SQLITE_OK && iPg<=(Pgno)nDstPage; iPg++){
57290
+ if( iPg!=PENDING_BYTE_PAGE(p->pDest->pBt) ){
57291
+ DbPage *pPg;
57292
+ rc = sqlite3PagerGet(pDestPager, iPg, &pPg);
57293
+ if( rc==SQLITE_OK ){
57294
+ rc = sqlite3PagerWrite(pPg);
57295
+ sqlite3PagerUnref(pPg);
57296
+ }
57297
+ }
57298
+ }
57299
+ if( rc==SQLITE_OK ){
57300
+ rc = sqlite3PagerCommitPhaseOne(pDestPager, 0, 1);
57301
+ }
5716557302
5716657303
/* Write the extra pages and truncate the database file as required */
5716757304
iEnd = MIN(PENDING_BYTE + pgszDest, iSize);
5716857305
for(
5716957306
iOff=PENDING_BYTE+pgszSrc;
@@ -57186,10 +57323,11 @@
5718657323
/* Sync the database file to disk. */
5718757324
if( rc==SQLITE_OK ){
5718857325
rc = sqlite3PagerSync(pDestPager);
5718957326
}
5719057327
}else{
57328
+ sqlite3PagerTruncateImage(pDestPager, nDestTruncate);
5719157329
rc = sqlite3PagerCommitPhaseOne(pDestPager, 0, 0);
5719257330
}
5719357331
5719457332
/* Finish committing the transaction to the destination database. */
5719557333
if( SQLITE_OK==rc
@@ -57437,11 +57575,13 @@
5743757575
** SQLITE_OK is returned if the conversion is successful (or not required).
5743857576
** SQLITE_NOMEM may be returned if a malloc() fails during conversion
5743957577
** between formats.
5744057578
*/
5744157579
SQLITE_PRIVATE int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){
57580
+#ifndef SQLITE_OMIT_UTF16
5744257581
int rc;
57582
+#endif
5744357583
assert( (pMem->flags&MEM_RowSet)==0 );
5744457584
assert( desiredEnc==SQLITE_UTF8 || desiredEnc==SQLITE_UTF16LE
5744557585
|| desiredEnc==SQLITE_UTF16BE );
5744657586
if( !(pMem->flags&MEM_Str) || pMem->enc==desiredEnc ){
5744757587
return SQLITE_OK;
@@ -58582,22 +58722,10 @@
5858258722
** a VDBE (or an "sqlite3_stmt" as it is known to the outside world.) Prior
5858358723
** to version 2.8.7, all this code was combined into the vdbe.c source file.
5858458724
** But that file was getting too big so this subroutines were split out.
5858558725
*/
5858658726
58587
-
58588
-
58589
-/*
58590
-** When debugging the code generator in a symbolic debugger, one can
58591
-** set the sqlite3VdbeAddopTrace to 1 and all opcodes will be printed
58592
-** as they are added to the instruction stream.
58593
-*/
58594
-#ifdef SQLITE_DEBUG
58595
-SQLITE_PRIVATE int sqlite3VdbeAddopTrace = 0;
58596
-#endif
58597
-
58598
-
5859958727
/*
5860058728
** Create a new virtual database engine.
5860158729
*/
5860258730
SQLITE_PRIVATE Vdbe *sqlite3VdbeCreate(sqlite3 *db){
5860358731
Vdbe *p;
@@ -58723,11 +58851,13 @@
5872358851
pOp->p3 = p3;
5872458852
pOp->p4.p = 0;
5872558853
pOp->p4type = P4_NOTUSED;
5872658854
#ifdef SQLITE_DEBUG
5872758855
pOp->zComment = 0;
58728
- if( sqlite3VdbeAddopTrace ) sqlite3VdbePrintOp(0, i, &p->aOp[i]);
58856
+ if( p->db->flags & SQLITE_VdbeAddopTrace ){
58857
+ sqlite3VdbePrintOp(0, i, &p->aOp[i]);
58858
+ }
5872958859
#endif
5873058860
#ifdef VDBE_PROFILE
5873158861
pOp->cycles = 0;
5873258862
pOp->cnt = 0;
5873358863
#endif
@@ -58942,11 +59072,11 @@
5894259072
if( opcode==OP_Destroy || opcode==OP_VUpdate || opcode==OP_VRename
5894359073
#ifndef SQLITE_OMIT_FOREIGN_KEY
5894459074
|| (opcode==OP_FkCounter && pOp->p1==0 && pOp->p2==1)
5894559075
#endif
5894659076
|| ((opcode==OP_Halt || opcode==OP_HaltIfNull)
58947
- && (pOp->p1==SQLITE_CONSTRAINT && pOp->p2==OE_Abort))
59077
+ && ((pOp->p1&0xff)==SQLITE_CONSTRAINT && pOp->p2==OE_Abort))
5894859078
){
5894959079
hasAbort = 1;
5895059080
break;
5895159081
}
5895259082
}
@@ -59077,11 +59207,11 @@
5907759207
pOut->p4type = P4_NOTUSED;
5907859208
pOut->p4.p = 0;
5907959209
pOut->p5 = 0;
5908059210
#ifdef SQLITE_DEBUG
5908159211
pOut->zComment = 0;
59082
- if( sqlite3VdbeAddopTrace ){
59212
+ if( p->db->flags & SQLITE_VdbeAddopTrace ){
5908359213
sqlite3VdbePrintOp(0, i+addr, &p->aOp[i+addr]);
5908459214
}
5908559215
#endif
5908659216
}
5908759217
p->nOp += nOp;
@@ -60103,11 +60233,11 @@
6010360233
}
6010460234
zCsr = p->pFree;
6010560235
zEnd = &zCsr[nByte];
6010660236
}while( nByte && !db->mallocFailed );
6010760237
60108
- p->nCursor = (u16)nCursor;
60238
+ p->nCursor = nCursor;
6010960239
p->nOnceFlag = nOnce;
6011060240
if( p->aVar ){
6011160241
p->nVar = (ynVar)nVar;
6011260242
for(n=0; n<nVar; n++){
6011360243
p->aVar[n].flags = MEM_Null;
@@ -60345,11 +60475,11 @@
6034560475
6034660476
/* If there are any write-transactions at all, invoke the commit hook */
6034760477
if( needXcommit && db->xCommitCallback ){
6034860478
rc = db->xCommitCallback(db->pCommitArg);
6034960479
if( rc ){
60350
- return SQLITE_CONSTRAINT;
60480
+ return SQLITE_CONSTRAINT_COMMITHOOK;
6035160481
}
6035260482
}
6035360483
6035460484
/* The simple case - no more than one database file (not counting the
6035560485
** TEMP database) has a transaction active. There is no need for the
@@ -60637,18 +60767,18 @@
6063760767
** handle associated with the VM passed as an argument is about to be
6063860768
** committed. If there are outstanding deferred foreign key constraint
6063960769
** violations, return SQLITE_ERROR. Otherwise, SQLITE_OK.
6064060770
**
6064160771
** If there are outstanding FK violations and this function returns
60642
-** SQLITE_ERROR, set the result of the VM to SQLITE_CONSTRAINT and write
60643
-** an error message to it. Then return SQLITE_ERROR.
60772
+** SQLITE_ERROR, set the result of the VM to SQLITE_CONSTRAINT_FOREIGNKEY
60773
+** and write an error message to it. Then return SQLITE_ERROR.
6064460774
*/
6064560775
#ifndef SQLITE_OMIT_FOREIGN_KEY
6064660776
SQLITE_PRIVATE int sqlite3VdbeCheckFk(Vdbe *p, int deferred){
6064760777
sqlite3 *db = p->db;
6064860778
if( (deferred && db->nDeferredCons>0) || (!deferred && p->nFkConstraint>0) ){
60649
- p->rc = SQLITE_CONSTRAINT;
60779
+ p->rc = SQLITE_CONSTRAINT_FOREIGNKEY;
6065060780
p->errorAction = OE_Abort;
6065160781
sqlite3SetString(&p->zErrMsg, db, "foreign key constraint failed");
6065260782
return SQLITE_ERROR;
6065360783
}
6065460784
return SQLITE_OK;
@@ -60759,11 +60889,11 @@
6075960889
if( rc!=SQLITE_OK ){
6076060890
if( NEVER(p->readOnly) ){
6076160891
sqlite3VdbeLeave(p);
6076260892
return SQLITE_ERROR;
6076360893
}
60764
- rc = SQLITE_CONSTRAINT;
60894
+ rc = SQLITE_CONSTRAINT_FOREIGNKEY;
6076560895
}else{
6076660896
/* The auto-commit flag is true, the vdbe program was successful
6076760897
** or hit an 'OR FAIL' constraint and there are no deferred foreign
6076860898
** key constraints to hold up the transaction. This means a commit
6076960899
** is required. */
@@ -60802,11 +60932,11 @@
6080260932
** current statement error code.
6080360933
*/
6080460934
if( eStatementOp ){
6080560935
rc = sqlite3VdbeCloseStatement(p, eStatementOp);
6080660936
if( rc ){
60807
- if( p->rc==SQLITE_OK || p->rc==SQLITE_CONSTRAINT ){
60937
+ if( p->rc==SQLITE_OK || (p->rc&0xff)==SQLITE_CONSTRAINT ){
6080860938
p->rc = rc;
6080960939
sqlite3DbFree(db, p->zErrMsg);
6081060940
p->zErrMsg = 0;
6081160941
}
6081260942
sqlite3RollbackAll(db, SQLITE_ABORT_ROLLBACK);
@@ -61043,11 +61173,11 @@
6104361173
sqlite3DbFree(db, p->aLabel);
6104461174
sqlite3DbFree(db, p->aColName);
6104561175
sqlite3DbFree(db, p->zSql);
6104661176
sqlite3DbFree(db, p->pFree);
6104761177
#if defined(SQLITE_ENABLE_TREE_EXPLAIN)
61048
- sqlite3_free(p->zExplain);
61178
+ sqlite3DbFree(db, p->zExplain);
6104961179
sqlite3DbFree(db, p->pExplain);
6105061180
#endif
6105161181
}
6105261182
6105361183
/*
@@ -63025,11 +63155,11 @@
6302563155
return 0;
6302663156
}
6302763157
if( zName ){
6302863158
for(i=0; i<p->nzVar; i++){
6302963159
const char *z = p->azVar[i];
63030
- if( z && memcmp(z,zName,nName)==0 && z[nName]==0 ){
63160
+ if( z && strncmp(z,zName,nName)==0 && z[nName]==0 ){
6303163161
return i+1;
6303263162
}
6303363163
}
6303463164
}
6303563165
return 0;
@@ -64799,11 +64929,11 @@
6479964929
rc = sqlite3VdbeHalt(p);
6480064930
assert( rc==SQLITE_BUSY || rc==SQLITE_OK || rc==SQLITE_ERROR );
6480164931
if( rc==SQLITE_BUSY ){
6480264932
p->rc = rc = SQLITE_BUSY;
6480364933
}else{
64804
- assert( rc==SQLITE_OK || p->rc==SQLITE_CONSTRAINT );
64934
+ assert( rc==SQLITE_OK || (p->rc&0xff)==SQLITE_CONSTRAINT );
6480564935
assert( rc==SQLITE_OK || db->nDeferredCons>0 );
6480664936
rc = p->rc ? SQLITE_ERROR : SQLITE_DONE;
6480764937
}
6480864938
goto vdbe_return;
6480964939
}
@@ -70131,11 +70261,11 @@
7013170261
importVtabErrMsg(p, u.cr.pVtab);
7013270262
if( rc==SQLITE_OK && pOp->p1 ){
7013370263
assert( u.cr.nArg>1 && u.cr.apArg[0] && (u.cr.apArg[0]->flags&MEM_Null) );
7013470264
db->lastRowid = lastRowid = u.cr.rowid;
7013570265
}
70136
- if( rc==SQLITE_CONSTRAINT && pOp->p4.pVtab->bConstraint ){
70266
+ if( (rc&0xff)==SQLITE_CONSTRAINT && pOp->p4.pVtab->bConstraint ){
7013770267
if( pOp->p5==OE_Ignore ){
7013870268
rc = SQLITE_OK;
7013970269
}else{
7014070270
p->errorAction = ((pOp->p5==OE_Replace) ? OE_Abort : pOp->p5);
7014170271
}
@@ -72677,16 +72807,16 @@
7267772807
const char *zTab,
7267872808
const char *zDb
7267972809
){
7268072810
int n;
7268172811
for(n=0; ALWAYS(zSpan[n]) && zSpan[n]!='.'; n++){}
72682
- if( zDb && sqlite3StrNICmp(zSpan, zDb, n)!=0 ){
72812
+ if( zDb && (sqlite3StrNICmp(zSpan, zDb, n)!=0 || zDb[n]!=0) ){
7268372813
return 0;
7268472814
}
7268572815
zSpan += n+1;
7268672816
for(n=0; ALWAYS(zSpan[n]) && zSpan[n]!='.'; n++){}
72687
- if( zTab && sqlite3StrNICmp(zSpan, zTab, n)!=0 ){
72817
+ if( zTab && (sqlite3StrNICmp(zSpan, zTab, n)!=0 || zTab[n]!=0) ){
7268872818
return 0;
7268972819
}
7269072820
zSpan += n+1;
7269172821
if( zCol && sqlite3StrICmp(zSpan, zCol)!=0 ){
7269272822
return 0;
@@ -72775,12 +72905,12 @@
7277572905
7277672906
pTab = pItem->pTab;
7277772907
assert( pTab!=0 && pTab->zName!=0 );
7277872908
assert( pTab->nCol>0 );
7277972909
if( pItem->pSelect && (pItem->pSelect->selFlags & SF_NestedFrom)!=0 ){
72780
- ExprList *pEList = pItem->pSelect->pEList;
7278172910
int hit = 0;
72911
+ pEList = pItem->pSelect->pEList;
7278272912
for(j=0; j<pEList->nExpr; j++){
7278372913
if( sqlite3MatchSpanName(pEList->a[j].zSpan, zCol, zTab, zDb) ){
7278472914
cnt++;
7278572915
cntTab = 2;
7278672916
pMatch = pItem;
@@ -74479,11 +74609,11 @@
7447974609
** number as the prior appearance of the same name, or if the name
7448074610
** has never appeared before, reuse the same variable number
7448174611
*/
7448274612
ynVar i;
7448374613
for(i=0; i<pParse->nzVar; i++){
74484
- if( pParse->azVar[i] && memcmp(pParse->azVar[i],z,n+1)==0 ){
74614
+ if( pParse->azVar[i] && strcmp(pParse->azVar[i],z)==0 ){
7448574615
pExpr->iColumn = x = (ynVar)i+1;
7448674616
break;
7448774617
}
7448874618
}
7448974619
if( x==0 ) x = pExpr->iColumn = (ynVar)(++pParse->nVar);
@@ -75297,14 +75427,15 @@
7529775427
** A cursor is opened on the b-tree object that the RHS of the IN operator
7529875428
** and pX->iTable is set to the index of that cursor.
7529975429
**
7530075430
** The returned value of this function indicates the b-tree type, as follows:
7530175431
**
75302
-** IN_INDEX_ROWID - The cursor was opened on a database table.
75303
-** IN_INDEX_INDEX - The cursor was opened on a database index.
75304
-** IN_INDEX_EPH - The cursor was opened on a specially created and
75305
-** populated epheremal table.
75432
+** IN_INDEX_ROWID - The cursor was opened on a database table.
75433
+** IN_INDEX_INDEX_ASC - The cursor was opened on an ascending index.
75434
+** IN_INDEX_INDEX_DESC - The cursor was opened on a descending index.
75435
+** IN_INDEX_EPH - The cursor was opened on a specially created and
75436
+** populated epheremal table.
7530675437
**
7530775438
** An existing b-tree might be used if the RHS expression pX is a simple
7530875439
** subquery such as:
7530975440
**
7531075441
** SELECT <column> FROM <table>
@@ -75423,11 +75554,12 @@
7542375554
iAddr = sqlite3CodeOnce(pParse);
7542475555
7542575556
sqlite3VdbeAddOp4(v, OP_OpenRead, iTab, pIdx->tnum, iDb,
7542675557
pKey,P4_KEYINFO_HANDOFF);
7542775558
VdbeComment((v, "%s", pIdx->zName));
75428
- eType = IN_INDEX_INDEX;
75559
+ assert( IN_INDEX_INDEX_DESC == IN_INDEX_INDEX_ASC+1 );
75560
+ eType = IN_INDEX_INDEX_ASC + pIdx->aSortOrder[0];
7542975561
7543075562
sqlite3VdbeJumpHere(v, iAddr);
7543175563
if( prNotFound && !pTab->aCol[iCol].notNull ){
7543275564
*prNotFound = ++pParse->nMem;
7543375565
sqlite3VdbeAddOp2(v, OP_Null, 0, *prNotFound);
@@ -76776,11 +76908,12 @@
7677676908
assert( !ExprHasProperty(pExpr, EP_IntValue) );
7677776909
if( pExpr->affinity==OE_Ignore ){
7677876910
sqlite3VdbeAddOp4(
7677976911
v, OP_Halt, SQLITE_OK, OE_Ignore, 0, pExpr->u.zToken,0);
7678076912
}else{
76781
- sqlite3HaltConstraint(pParse, pExpr->affinity, pExpr->u.zToken, 0);
76913
+ sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_TRIGGER,
76914
+ pExpr->affinity, pExpr->u.zToken, 0);
7678276915
}
7678376916
7678476917
break;
7678576918
}
7678676919
#endif
@@ -79335,11 +79468,11 @@
7933579468
}
7933679469
if( pTab->tnum==0 ){
7933779470
/* Do not gather statistics on views or virtual tables */
7933879471
return;
7933979472
}
79340
- if( memcmp(pTab->zName, "sqlite_", 7)==0 ){
79473
+ if( sqlite3_strnicmp(pTab->zName, "sqlite_", 7)==0 ){
7934179474
/* Do not gather statistics on system tables */
7934279475
return;
7934379476
}
7934479477
assert( sqlite3BtreeHoldsAllMutexes(db) );
7934579478
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
@@ -79745,11 +79878,11 @@
7974579878
}
7974679879
if( i==0 ) pTable->nRowEst = v;
7974779880
if( pIndex==0 ) break;
7974879881
pIndex->aiRowEst[i] = v;
7974979882
if( *z==' ' ) z++;
79750
- if( memcmp(z, "unordered", 10)==0 ){
79883
+ if( strcmp(z, "unordered")==0 ){
7975179884
pIndex->bUnordered = 1;
7975279885
break;
7975379886
}
7975479887
}
7975579888
return 0;
@@ -83247,12 +83380,12 @@
8324783380
if( pIndex->onError!=OE_None ){
8324883381
int j2 = sqlite3VdbeCurrentAddr(v) + 3;
8324983382
sqlite3VdbeAddOp2(v, OP_Goto, 0, j2);
8325083383
addr2 = sqlite3VdbeCurrentAddr(v);
8325183384
sqlite3VdbeAddOp3(v, OP_SorterCompare, iSorter, j2, regRecord);
83252
- sqlite3HaltConstraint(
83253
- pParse, OE_Abort, "indexed columns are not unique", P4_STATIC
83385
+ sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_UNIQUE,
83386
+ OE_Abort, "indexed columns are not unique", P4_STATIC
8325483387
);
8325583388
}else{
8325683389
addr2 = sqlite3VdbeCurrentAddr(v);
8325783390
}
8325883391
sqlite3VdbeAddOp2(v, OP_SorterData, iSorter, regRecord);
@@ -83274,12 +83407,12 @@
8327483407
** opcode use the values stored within seems dangerous. However, since
8327583408
** we can be sure that no other temp registers have been allocated
8327683409
** since sqlite3ReleaseTempRange() was called, it is safe to do so.
8327783410
*/
8327883411
sqlite3VdbeAddOp4(v, OP_IsUnique, iIdx, j2, regRowid, pRegKey, P4_INT32);
83279
- sqlite3HaltConstraint(
83280
- pParse, OE_Abort, "indexed columns are not unique", P4_STATIC);
83412
+ sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_UNIQUE,
83413
+ "indexed columns are not unique", P4_STATIC);
8328183414
}
8328283415
sqlite3VdbeAddOp3(v, OP_IdxInsert, iIdx, regRecord, 0);
8328383416
sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
8328483417
#endif
8328583418
sqlite3ReleaseTempReg(pParse, regRecord);
@@ -83394,11 +83527,11 @@
8339483527
pDb = &db->aDb[iDb];
8339583528
8339683529
assert( pTab!=0 );
8339783530
assert( pParse->nErr==0 );
8339883531
if( sqlite3StrNICmp(pTab->zName, "sqlite_", 7)==0
83399
- && memcmp(&pTab->zName[7],"altertab_",9)!=0 ){
83532
+ && sqlite3StrNICmp(&pTab->zName[7],"altertab_",9)!=0 ){
8340083533
sqlite3ErrorMsg(pParse, "table %s may not be indexed", pTab->zName);
8340183534
goto exit_create_index;
8340283535
}
8340383536
#ifndef SQLITE_OMIT_VIEW
8340483537
if( pTab->pSelect ){
@@ -84492,16 +84625,23 @@
8449284625
/*
8449384626
** Code an OP_Halt that causes the vdbe to return an SQLITE_CONSTRAINT
8449484627
** error. The onError parameter determines which (if any) of the statement
8449584628
** and/or current transaction is rolled back.
8449684629
*/
84497
-SQLITE_PRIVATE void sqlite3HaltConstraint(Parse *pParse, int onError, char *p4, int p4type){
84630
+SQLITE_PRIVATE void sqlite3HaltConstraint(
84631
+ Parse *pParse, /* Parsing context */
84632
+ int errCode, /* extended error code */
84633
+ int onError, /* Constraint type */
84634
+ char *p4, /* Error message */
84635
+ int p4type /* P4_STATIC or P4_TRANSIENT */
84636
+){
8449884637
Vdbe *v = sqlite3GetVdbe(pParse);
84638
+ assert( (errCode&0xff)==SQLITE_CONSTRAINT );
8449984639
if( onError==OE_Abort ){
8450084640
sqlite3MayAbort(pParse);
8450184641
}
84502
- sqlite3VdbeAddOp4(v, OP_Halt, SQLITE_CONSTRAINT, onError, 0, p4, p4type);
84642
+ sqlite3VdbeAddOp4(v, OP_Halt, errCode, onError, 0, p4, p4type);
8450384643
}
8450484644
8450584645
/*
8450684646
** Check to see if pIndex uses the collating sequence pColl. Return
8450784647
** true if it does and false if it does not.
@@ -85242,34 +85382,32 @@
8524285382
Table *pView, /* View definition */
8524385383
Expr *pWhere, /* Optional WHERE clause to be added */
8524485384
int iCur /* Cursor number for ephemerial table */
8524585385
){
8524685386
SelectDest dest;
85247
- Select *pDup;
85387
+ Select *pSel;
85388
+ SrcList *pFrom;
8524885389
sqlite3 *db = pParse->db;
85249
-
85250
- pDup = sqlite3SelectDup(db, pView->pSelect, 0);
85251
- if( pWhere ){
85252
- SrcList *pFrom;
85253
-
85254
- pWhere = sqlite3ExprDup(db, pWhere, 0);
85255
- pFrom = sqlite3SrcListAppend(db, 0, 0, 0);
85256
- if( pFrom ){
85257
- assert( pFrom->nSrc==1 );
85258
- pFrom->a[0].zAlias = sqlite3DbStrDup(db, pView->zName);
85259
- pFrom->a[0].pSelect = pDup;
85260
- assert( pFrom->a[0].pOn==0 );
85261
- assert( pFrom->a[0].pUsing==0 );
85262
- }else{
85263
- sqlite3SelectDelete(db, pDup);
85264
- }
85265
- pDup = sqlite3SelectNew(pParse, 0, pFrom, pWhere, 0, 0, 0, 0, 0, 0);
85266
- if( pDup ) pDup->selFlags |= SF_Materialize;
85267
- }
85390
+ int iDb = sqlite3SchemaToIndex(db, pView->pSchema);
85391
+
85392
+ pWhere = sqlite3ExprDup(db, pWhere, 0);
85393
+ pFrom = sqlite3SrcListAppend(db, 0, 0, 0);
85394
+
85395
+ if( pFrom ){
85396
+ assert( pFrom->nSrc==1 );
85397
+ pFrom->a[0].zName = sqlite3DbStrDup(db, pView->zName);
85398
+ pFrom->a[0].zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zName);
85399
+ assert( pFrom->a[0].pOn==0 );
85400
+ assert( pFrom->a[0].pUsing==0 );
85401
+ }
85402
+
85403
+ pSel = sqlite3SelectNew(pParse, 0, pFrom, pWhere, 0, 0, 0, 0, 0, 0);
85404
+ if( pSel ) pSel->selFlags |= SF_Materialize;
85405
+
8526885406
sqlite3SelectDestInit(&dest, SRT_EphemTab, iCur);
85269
- sqlite3Select(pParse, pDup, &dest);
85270
- sqlite3SelectDelete(db, pDup);
85407
+ sqlite3Select(pParse, pSel, &dest);
85408
+ sqlite3SelectDelete(db, pSel);
8527185409
}
8527285410
#endif /* !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER) */
8527385411
8527485412
#if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) && !defined(SQLITE_OMIT_SUBQUERY)
8527585413
/*
@@ -86765,10 +86903,66 @@
8676586903
sqlite3_result_text(context, "NULL", 4, SQLITE_STATIC);
8676686904
break;
8676786905
}
8676886906
}
8676986907
}
86908
+
86909
+/*
86910
+** The unicode() function. Return the integer unicode code-point value
86911
+** for the first character of the input string.
86912
+*/
86913
+static void unicodeFunc(
86914
+ sqlite3_context *context,
86915
+ int argc,
86916
+ sqlite3_value **argv
86917
+){
86918
+ const unsigned char *z = sqlite3_value_text(argv[0]);
86919
+ (void)argc;
86920
+ if( z && z[0] ) sqlite3_result_int(context, sqlite3Utf8Read(&z));
86921
+}
86922
+
86923
+/*
86924
+** The char() function takes zero or more arguments, each of which is
86925
+** an integer. It constructs a string where each character of the string
86926
+** is the unicode character for the corresponding integer argument.
86927
+*/
86928
+static void charFunc(
86929
+ sqlite3_context *context,
86930
+ int argc,
86931
+ sqlite3_value **argv
86932
+){
86933
+ unsigned char *z, *zOut;
86934
+ int i;
86935
+ zOut = z = sqlite3_malloc( argc*4 );
86936
+ if( z==0 ){
86937
+ sqlite3_result_error_nomem(context);
86938
+ return;
86939
+ }
86940
+ for(i=0; i<argc; i++){
86941
+ sqlite3_int64 x;
86942
+ unsigned c;
86943
+ x = sqlite3_value_int64(argv[i]);
86944
+ if( x<0 || x>0x10ffff ) x = 0xfffd;
86945
+ c = (unsigned)(x & 0x1fffff);
86946
+ if( c<0x00080 ){
86947
+ *zOut++ = (u8)(c&0xFF);
86948
+ }else if( c<0x00800 ){
86949
+ *zOut++ = 0xC0 + (u8)((c>>6)&0x1F);
86950
+ *zOut++ = 0x80 + (u8)(c & 0x3F);
86951
+ }else if( c<0x10000 ){
86952
+ *zOut++ = 0xE0 + (u8)((c>>12)&0x0F);
86953
+ *zOut++ = 0x80 + (u8)((c>>6) & 0x3F);
86954
+ *zOut++ = 0x80 + (u8)(c & 0x3F);
86955
+ }else{
86956
+ *zOut++ = 0xF0 + (u8)((c>>18) & 0x07);
86957
+ *zOut++ = 0x80 + (u8)((c>>12) & 0x3F);
86958
+ *zOut++ = 0x80 + (u8)((c>>6) & 0x3F);
86959
+ *zOut++ = 0x80 + (u8)(c & 0x3F);
86960
+ } \
86961
+ }
86962
+ sqlite3_result_text(context, (char*)z, (int)(zOut-z), sqlite3_free);
86963
+}
8677086964
8677186965
/*
8677286966
** The hex() function. Interpret the argument as a blob. Return
8677386967
** a hexadecimal rendering as text.
8677486968
*/
@@ -87393,10 +87587,12 @@
8739387587
FUNCTION2(typeof, 1, 0, 0, typeofFunc, SQLITE_FUNC_TYPEOF),
8739487588
FUNCTION2(length, 1, 0, 0, lengthFunc, SQLITE_FUNC_LENGTH),
8739587589
FUNCTION(instr, 2, 0, 0, instrFunc ),
8739687590
FUNCTION(substr, 2, 0, 0, substrFunc ),
8739787591
FUNCTION(substr, 3, 0, 0, substrFunc ),
87592
+ FUNCTION(unicode, 1, 0, 0, unicodeFunc ),
87593
+ FUNCTION(char, -1, 0, 0, charFunc ),
8739887594
FUNCTION(abs, 1, 0, 0, absFunc ),
8739987595
#ifndef SQLITE_OMIT_FLOATING_POINT
8740087596
FUNCTION(round, 1, 0, 0, roundFunc ),
8740187597
FUNCTION(round, 2, 0, 0, roundFunc ),
8740287598
#endif
@@ -87484,12 +87680,13 @@
8748487680
/*
8748587681
** Deferred and Immediate FKs
8748687682
** --------------------------
8748787683
**
8748887684
** Foreign keys in SQLite come in two flavours: deferred and immediate.
87489
-** If an immediate foreign key constraint is violated, SQLITE_CONSTRAINT
87490
-** is returned and the current statement transaction rolled back. If a
87685
+** If an immediate foreign key constraint is violated,
87686
+** SQLITE_CONSTRAINT_FOREIGNKEY is returned and the current
87687
+** statement transaction rolled back. If a
8749187688
** deferred foreign key constraint is violated, no action is taken
8749287689
** immediately. However if the application attempts to commit the
8749387690
** transaction before fixing the constraint violation, the attempt fails.
8749487691
**
8749587692
** Deferred constraints are implemented using a simple counter associated
@@ -87549,11 +87746,12 @@
8754987746
** row is inserted.
8755087747
**
8755187748
** Immediate constraints are usually handled similarly. The only difference
8755287749
** is that the counter used is stored as part of each individual statement
8755387750
** object (struct Vdbe). If, after the statement has run, its immediate
87554
-** constraint counter is greater than zero, it returns SQLITE_CONSTRAINT
87751
+** constraint counter is greater than zero,
87752
+** it returns SQLITE_CONSTRAINT_FOREIGNKEY
8755587753
** and the statement transaction is rolled back. An exception is an INSERT
8755687754
** statement that inserts a single row only (no triggers). In this case,
8755787755
** instead of using a counter, an exception is thrown immediately if the
8755887756
** INSERT violates a foreign key constraint. This is necessary as such
8755987757
** an INSERT does not open a statement transaction.
@@ -87889,12 +88087,12 @@
8788988087
/* Special case: If this is an INSERT statement that will insert exactly
8789088088
** one row into the table, raise a constraint immediately instead of
8789188089
** incrementing a counter. This is necessary as the VM code is being
8789288090
** generated for will not open a statement transaction. */
8789388091
assert( nIncr==1 );
87894
- sqlite3HaltConstraint(
87895
- pParse, OE_Abort, "foreign key constraint failed", P4_STATIC
88092
+ sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_FOREIGNKEY,
88093
+ OE_Abort, "foreign key constraint failed", P4_STATIC
8789688094
);
8789788095
}else{
8789888096
if( nIncr>0 && pFKey->isDeferred==0 ){
8789988097
sqlite3ParseToplevel(pParse)->mayAbort = 1;
8790088098
}
@@ -88130,12 +88328,12 @@
8813088328
/* If the DELETE has generated immediate foreign key constraint
8813188329
** violations, halt the VDBE and return an error at this point, before
8813288330
** any modifications to the schema are made. This is because statement
8813388331
** transactions are not able to rollback schema changes. */
8813488332
sqlite3VdbeAddOp2(v, OP_FkIfZero, 0, sqlite3VdbeCurrentAddr(v)+2);
88135
- sqlite3HaltConstraint(
88136
- pParse, OE_Abort, "foreign key constraint failed", P4_STATIC
88333
+ sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_FOREIGNKEY,
88334
+ OE_Abort, "foreign key constraint failed", P4_STATIC
8813788335
);
8813888336
8813988337
if( iSkip ){
8814088338
sqlite3VdbeResolveLabel(v, iSkip);
8814188339
}
@@ -89935,11 +90133,11 @@
8993590133
sqlite3MayAbort(pParse);
8993690134
case OE_Rollback:
8993790135
case OE_Fail: {
8993890136
char *zMsg;
8993990137
sqlite3VdbeAddOp3(v, OP_HaltIfNull,
89940
- SQLITE_CONSTRAINT, onError, regData+i);
90138
+ SQLITE_CONSTRAINT_NOTNULL, onError, regData+i);
8994190139
zMsg = sqlite3MPrintf(db, "%s.%s may not be NULL",
8994290140
pTab->zName, pTab->aCol[i].zName);
8994390141
sqlite3VdbeChangeP4(v, -1, zMsg, P4_DYNAMIC);
8994490142
break;
8994590143
}
@@ -89975,11 +90173,12 @@
8997590173
if( zConsName ){
8997690174
zConsName = sqlite3MPrintf(db, "constraint %s failed", zConsName);
8997790175
}else{
8997890176
zConsName = 0;
8997990177
}
89980
- sqlite3HaltConstraint(pParse, onError, zConsName, P4_DYNAMIC);
90178
+ sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_CHECK,
90179
+ onError, zConsName, P4_DYNAMIC);
8998190180
}
8998290181
sqlite3VdbeResolveLabel(v, allOk);
8998390182
}
8998490183
}
8998590184
#endif /* !defined(SQLITE_OMIT_CHECK) */
@@ -90006,12 +90205,12 @@
9000690205
/* Fall thru into the next case */
9000790206
}
9000890207
case OE_Rollback:
9000990208
case OE_Abort:
9001090209
case OE_Fail: {
90011
- sqlite3HaltConstraint(
90012
- pParse, onError, "PRIMARY KEY must be unique", P4_STATIC);
90210
+ sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_PRIMARYKEY,
90211
+ onError, "PRIMARY KEY must be unique", P4_STATIC);
9001390212
break;
9001490213
}
9001590214
case OE_Replace: {
9001690215
/* If there are DELETE triggers on this table and the
9001790216
** recursive-triggers flag is set, call GenerateRowDelete() to
@@ -90134,11 +90333,12 @@
9013490333
sqlite3StrAccumAppend(&errMsg, zCol, -1);
9013590334
}
9013690335
sqlite3StrAccumAppend(&errMsg,
9013790336
pIdx->nColumn>1 ? " are not unique" : " is not unique", -1);
9013890337
zErr = sqlite3StrAccumFinish(&errMsg);
90139
- sqlite3HaltConstraint(pParse, onError, zErr, 0);
90338
+ sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_UNIQUE,
90339
+ onError, zErr, 0);
9014090340
sqlite3DbFree(errMsg.db, zErr);
9014190341
break;
9014290342
}
9014390343
case OE_Ignore: {
9014490344
assert( seenReplace==0 );
@@ -90542,12 +90742,12 @@
9054290742
regData = sqlite3GetTempReg(pParse);
9054390743
regRowid = sqlite3GetTempReg(pParse);
9054490744
if( pDest->iPKey>=0 ){
9054590745
addr1 = sqlite3VdbeAddOp2(v, OP_Rowid, iSrc, regRowid);
9054690746
addr2 = sqlite3VdbeAddOp3(v, OP_NotExists, iDest, 0, regRowid);
90547
- sqlite3HaltConstraint(
90548
- pParse, onError, "PRIMARY KEY must be unique", P4_STATIC);
90747
+ sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_PRIMARYKEY,
90748
+ onError, "PRIMARY KEY must be unique", P4_STATIC);
9054990749
sqlite3VdbeJumpHere(v, addr2);
9055090750
autoIncStep(pParse, regAutoinc, regRowid);
9055190751
}else if( pDest->pIndex==0 ){
9055290752
addr1 = sqlite3VdbeAddOp2(v, OP_NewRowid, iDest, regRowid);
9055390753
}else{
@@ -91000,10 +91200,24 @@
9100091200
int (*wal_checkpoint)(sqlite3*,const char*);
9100191201
void *(*wal_hook)(sqlite3*,int(*)(void*,sqlite3*,const char*,int),void*);
9100291202
int (*blob_reopen)(sqlite3_blob*,sqlite3_int64);
9100391203
int (*vtab_config)(sqlite3*,int op,...);
9100491204
int (*vtab_on_conflict)(sqlite3*);
91205
+ /* Version 3.7.16 and later */
91206
+ int (*close_v2)(sqlite3*);
91207
+ const char *(*db_filename)(sqlite3*,const char*);
91208
+ int (*db_readonly)(sqlite3*,const char*);
91209
+ int (*db_release_memory)(sqlite3*);
91210
+ const char *(*errstr)(int);
91211
+ int (*stmt_busy)(sqlite3_stmt*);
91212
+ int (*stmt_readonly)(sqlite3_stmt*);
91213
+ int (*stricmp)(const char*,const char*);
91214
+ int (*uri_boolean)(const char*,const char*,int);
91215
+ sqlite3_int64 (*uri_int64)(const char*,const char*,sqlite3_int64);
91216
+ const char *(*uri_parameter)(const char*,const char*);
91217
+ char *(*vsnprintf)(int,char*,const char*,va_list);
91218
+ int (*wal_checkpoint_v2)(sqlite3*,const char*,int,int*,int*);
9100591219
};
9100691220
9100791221
/*
9100891222
** The following macros redefine the API routines so that they are
9100991223
** redirected throught the global sqlite3_api structure.
@@ -91203,10 +91417,24 @@
9120391417
#define sqlite3_wal_checkpoint sqlite3_api->wal_checkpoint
9120491418
#define sqlite3_wal_hook sqlite3_api->wal_hook
9120591419
#define sqlite3_blob_reopen sqlite3_api->blob_reopen
9120691420
#define sqlite3_vtab_config sqlite3_api->vtab_config
9120791421
#define sqlite3_vtab_on_conflict sqlite3_api->vtab_on_conflict
91422
+/* Version 3.7.16 and later */
91423
+#define sqlite3_close_v2 sqlite3_api->close_v2
91424
+#define sqlite3_db_filename sqlite3_api->db_filename
91425
+#define sqlite3_db_readonly sqlite3_api->db_readonly
91426
+#define sqlite3_db_release_memory sqlite3_api->db_release_memory
91427
+#define sqlite3_errstr sqlite3_api->errstr
91428
+#define sqlite3_stmt_busy sqlite3_api->stmt_busy
91429
+#define sqlite3_stmt_readonly sqlite3_api->stmt_readonly
91430
+#define sqlite3_stricmp sqlite3_api->stricmp
91431
+#define sqlite3_uri_boolean sqlite3_api->uri_boolean
91432
+#define sqlite3_uri_int64 sqlite3_api->uri_int64
91433
+#define sqlite3_uri_parameter sqlite3_api->uri_parameter
91434
+#define sqlite3_uri_vsnprintf sqlite3_api->vsnprintf
91435
+#define sqlite3_wal_checkpoint_v2 sqlite3_api->wal_checkpoint_v2
9120891436
#endif /* SQLITE_CORE */
9120991437
9121091438
#define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api = 0;
9121191439
#define SQLITE_EXTENSION_INIT2(v) sqlite3_api = v;
9121291440
@@ -91572,10 +91800,23 @@
9157291800
0,
9157391801
#endif
9157491802
sqlite3_blob_reopen,
9157591803
sqlite3_vtab_config,
9157691804
sqlite3_vtab_on_conflict,
91805
+ sqlite3_close_v2,
91806
+ sqlite3_db_filename,
91807
+ sqlite3_db_readonly,
91808
+ sqlite3_db_release_memory,
91809
+ sqlite3_errstr,
91810
+ sqlite3_stmt_busy,
91811
+ sqlite3_stmt_readonly,
91812
+ sqlite3_stricmp,
91813
+ sqlite3_uri_boolean,
91814
+ sqlite3_uri_int64,
91815
+ sqlite3_uri_parameter,
91816
+ sqlite3_vsnprintf,
91817
+ sqlite3_wal_checkpoint_v2
9157791818
};
9157891819
9157991820
/*
9158091821
** Attempt to load an SQLite extension library contained in the file
9158191822
** zFile. The entry point is zProc. zProc may be 0 in which case a
@@ -92038,10 +92279,13 @@
9203892279
#endif
9203992280
#ifdef SQLITE_DEBUG
9204092281
{ "sql_trace", SQLITE_SqlTrace },
9204192282
{ "vdbe_listing", SQLITE_VdbeListing },
9204292283
{ "vdbe_trace", SQLITE_VdbeTrace },
92284
+ { "vdbe_addoptrace", SQLITE_VdbeAddopTrace},
92285
+ { "vdbe_debug", SQLITE_SqlTrace | SQLITE_VdbeListing
92286
+ | SQLITE_VdbeTrace },
9204392287
#endif
9204492288
#ifndef SQLITE_OMIT_CHECK
9204592289
{ "ignore_check_constraints", SQLITE_IgnoreChecks },
9204692290
#endif
9204792291
/* The following is VERY experimental */
@@ -92809,10 +93053,11 @@
9280993053
Column *pCol;
9281093054
Index *pPk;
9281193055
for(pPk=pTab->pIndex; pPk && pPk->autoIndex!=2; pPk=pPk->pNext){}
9281293056
sqlite3VdbeSetNumCols(v, 6);
9281393057
pParse->nMem = 6;
93058
+ sqlite3CodeVerifySchema(pParse, iDb);
9281493059
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "cid", SQLITE_STATIC);
9281593060
sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", SQLITE_STATIC);
9281693061
sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "type", SQLITE_STATIC);
9281793062
sqlite3VdbeSetColName(v, 3, COLNAME_NAME, "notnull", SQLITE_STATIC);
9281893063
sqlite3VdbeSetColName(v, 4, COLNAME_NAME, "dflt_value", SQLITE_STATIC);
@@ -92854,10 +93099,11 @@
9285493099
if( pIdx ){
9285593100
int i;
9285693101
pTab = pIdx->pTable;
9285793102
sqlite3VdbeSetNumCols(v, 3);
9285893103
pParse->nMem = 3;
93104
+ sqlite3CodeVerifySchema(pParse, iDb);
9285993105
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seqno", SQLITE_STATIC);
9286093106
sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "cid", SQLITE_STATIC);
9286193107
sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "name", SQLITE_STATIC);
9286293108
for(i=0; i<pIdx->nColumn; i++){
9286393109
int cnum = pIdx->aiColumn[i];
@@ -92880,10 +93126,11 @@
9288093126
pIdx = pTab->pIndex;
9288193127
if( pIdx ){
9288293128
int i = 0;
9288393129
sqlite3VdbeSetNumCols(v, 3);
9288493130
pParse->nMem = 3;
93131
+ sqlite3CodeVerifySchema(pParse, iDb);
9288593132
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seq", SQLITE_STATIC);
9288693133
sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", SQLITE_STATIC);
9288793134
sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "unique", SQLITE_STATIC);
9288893135
while(pIdx){
9288993136
sqlite3VdbeAddOp2(v, OP_Integer, i, 1);
@@ -92943,10 +93190,11 @@
9294393190
pFK = pTab->pFKey;
9294493191
if( pFK ){
9294593192
int i = 0;
9294693193
sqlite3VdbeSetNumCols(v, 8);
9294793194
pParse->nMem = 8;
93195
+ sqlite3CodeVerifySchema(pParse, iDb);
9294893196
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "id", SQLITE_STATIC);
9294993197
sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "seq", SQLITE_STATIC);
9295093198
sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "table", SQLITE_STATIC);
9295193199
sqlite3VdbeSetColName(v, 3, COLNAME_NAME, "from", SQLITE_STATIC);
9295293200
sqlite3VdbeSetColName(v, 4, COLNAME_NAME, "to", SQLITE_STATIC);
@@ -92977,10 +93225,11 @@
9297793225
}
9297893226
}else
9297993227
#endif /* !defined(SQLITE_OMIT_FOREIGN_KEY) */
9298093228
9298193229
#ifndef SQLITE_OMIT_FOREIGN_KEY
93230
+#ifndef SQLITE_OMIT_TRIGGER
9298293231
if( sqlite3StrICmp(zLeft, "foreign_key_check")==0 ){
9298393232
FKey *pFK; /* A foreign key constraint */
9298493233
Table *pTab; /* Child table contain "REFERENCES" keyword */
9298593234
Table *pParent; /* Parent table that child points to */
9298693235
Index *pIdx; /* Index in the parent table */
@@ -93088,10 +93337,11 @@
9308893337
}
9308993338
sqlite3VdbeAddOp2(v, OP_Next, 0, addrTop+1);
9309093339
sqlite3VdbeJumpHere(v, addrTop);
9309193340
}
9309293341
}else
93342
+#endif /* !defined(SQLITE_OMIT_TRIGGER) */
9309393343
#endif /* !defined(SQLITE_OMIT_FOREIGN_KEY) */
9309493344
9309593345
#ifndef NDEBUG
9309693346
if( sqlite3StrICmp(zLeft, "parser_trace")==0 ){
9309793347
if( zRight ){
@@ -93884,15 +94134,19 @@
9388494134
** For an attached db, it is an error if the encoding is not the same
9388594135
** as sqlite3.enc.
9388694136
*/
9388794137
if( meta[BTREE_TEXT_ENCODING-1] ){ /* text encoding */
9388894138
if( iDb==0 ){
94139
+#ifndef SQLITE_OMIT_UTF16
9388994140
u8 encoding;
9389094141
/* If opening the main database, set ENC(db). */
9389194142
encoding = (u8)meta[BTREE_TEXT_ENCODING-1] & 3;
9389294143
if( encoding==0 ) encoding = SQLITE_UTF8;
9389394144
ENC(db) = encoding;
94145
+#else
94146
+ ENC(db) = SQLITE_UTF8;
94147
+#endif
9389494148
}else{
9389594149
/* If opening an attached database, the encoding much match ENC(db) */
9389694150
if( meta[BTREE_TEXT_ENCODING-1]!=ENC(db) ){
9389794151
sqlite3SetString(pzErrMsg, db, "attached databases must use the same"
9389894152
" text encoding as main database");
@@ -96198,10 +96452,12 @@
9619896452
switch( p->op ){
9619996453
case TK_ALL: {
9620096454
int addr = 0;
9620196455
int nLimit;
9620296456
assert( !pPrior->pLimit );
96457
+ pPrior->iLimit = p->iLimit;
96458
+ pPrior->iOffset = p->iOffset;
9620396459
pPrior->pLimit = p->pLimit;
9620496460
pPrior->pOffset = p->pOffset;
9620596461
explainSetInteger(iSub1, pParse->iNextSelectId);
9620696462
rc = sqlite3Select(pParse, pPrior, &dest);
9620796463
p->pLimit = 0;
@@ -96855,11 +97111,12 @@
9685597111
if( op==TK_ALL ){
9685697112
regPrev = 0;
9685797113
}else{
9685897114
int nExpr = p->pEList->nExpr;
9685997115
assert( nOrderBy>=nExpr || db->mallocFailed );
96860
- regPrev = sqlite3GetTempRange(pParse, nExpr+1);
97116
+ regPrev = pParse->nMem+1;
97117
+ pParse->nMem += nExpr+1;
9686197118
sqlite3VdbeAddOp2(v, OP_Integer, 0, regPrev);
9686297119
pKeyDup = sqlite3DbMallocZero(db,
9686397120
sizeof(*pKeyDup) + nExpr*(sizeof(CollSeq*)+1) );
9686497121
if( pKeyDup ){
9686597122
pKeyDup->aSortOrder = (u8*)&pKeyDup->aColl[nExpr];
@@ -97037,16 +97294,10 @@
9703797294
sqlite3VdbeAddOp4(v, OP_Compare, destA.iSdst, destB.iSdst, nOrderBy,
9703897295
(char*)pKeyMerge, P4_KEYINFO_HANDOFF);
9703997296
sqlite3VdbeChangeP5(v, OPFLAG_PERMUTE);
9704097297
sqlite3VdbeAddOp3(v, OP_Jump, addrAltB, addrAeqB, addrAgtB);
9704197298
97042
- /* Release temporary registers
97043
- */
97044
- if( regPrev ){
97045
- sqlite3ReleaseTempRange(pParse, regPrev, nOrderBy+1);
97046
- }
97047
-
9704897299
/* Jump to the this point in order to terminate the query.
9704997300
*/
9705097301
sqlite3VdbeResolveLabel(v, labelEnd);
9705197302
9705297303
/* Set the number of output columns
@@ -97454,16 +97705,19 @@
9745497705
*/
9745597706
for(pSub=pSub->pPrior; pSub; pSub=pSub->pPrior){
9745697707
Select *pNew;
9745797708
ExprList *pOrderBy = p->pOrderBy;
9745897709
Expr *pLimit = p->pLimit;
97710
+ Expr *pOffset = p->pOffset;
9745997711
Select *pPrior = p->pPrior;
9746097712
p->pOrderBy = 0;
9746197713
p->pSrc = 0;
9746297714
p->pPrior = 0;
9746397715
p->pLimit = 0;
97716
+ p->pOffset = 0;
9746497717
pNew = sqlite3SelectDup(db, p, 0);
97718
+ p->pOffset = pOffset;
9746597719
p->pLimit = pLimit;
9746697720
p->pOrderBy = pOrderBy;
9746797721
p->pSrc = pSrc;
9746897722
p->op = TK_ALL;
9746997723
p->pRightmost = 0;
@@ -97784,18 +98038,19 @@
9778498038
SrcList *pTabList;
9778598039
ExprList *pEList;
9778698040
struct SrcList_item *pFrom;
9778798041
sqlite3 *db = pParse->db;
9778898042
Expr *pE, *pRight, *pExpr;
98043
+ u16 selFlags = p->selFlags;
9778998044
98045
+ p->selFlags |= SF_Expanded;
9779098046
if( db->mallocFailed ){
9779198047
return WRC_Abort;
9779298048
}
97793
- if( NEVER(p->pSrc==0) || (p->selFlags & SF_Expanded)!=0 ){
98049
+ if( NEVER(p->pSrc==0) || (selFlags & SF_Expanded)!=0 ){
9779498050
return WRC_Prune;
9779598051
}
97796
- p->selFlags |= SF_Expanded;
9779798052
pTabList = p->pSrc;
9779898053
pEList = p->pEList;
9779998054
9780098055
/* Make sure cursor numbers have been assigned to all entries in
9780198056
** the FROM clause of the SELECT statement.
@@ -97834,10 +98089,16 @@
9783498089
}else{
9783598090
/* An ordinary table or view name in the FROM clause */
9783698091
assert( pFrom->pTab==0 );
9783798092
pFrom->pTab = pTab = sqlite3LocateTableItem(pParse, 0, pFrom);
9783898093
if( pTab==0 ) return WRC_Abort;
98094
+ if( pTab->nRef==0xffff ){
98095
+ sqlite3ErrorMsg(pParse, "too many references to \"%s\": max 65535",
98096
+ pTab->zName);
98097
+ pFrom->pTab = 0;
98098
+ return WRC_Abort;
98099
+ }
9783998100
pTab->nRef++;
9784098101
#if !defined(SQLITE_OMIT_VIEW) || !defined (SQLITE_OMIT_VIRTUALTABLE)
9784198102
if( pTab->pSelect || IsVirtual(pTab) ){
9784298103
/* We reach here if the named table is a really a view */
9784398104
if( sqlite3ViewGetColumnNames(pParse, pTab) ) return WRC_Abort;
@@ -98146,10 +98407,11 @@
9814698407
NameContext *pOuterNC /* Name context for container */
9814798408
){
9814898409
sqlite3 *db;
9814998410
if( NEVER(p==0) ) return;
9815098411
db = pParse->db;
98412
+ if( db->mallocFailed ) return;
9815198413
if( p->selFlags & SF_HasTypeInfo ) return;
9815298414
sqlite3SelectExpand(pParse, p);
9815398415
if( pParse->nErr || db->mallocFailed ) return;
9815498416
sqlite3ResolveSelectNames(pParse, p, pOuterNC);
9815598417
if( pParse->nErr || db->mallocFailed ) return;
@@ -99231,11 +99493,14 @@
9923199493
SQLITE_PRIVATE void sqlite3ExplainSelect(Vdbe *pVdbe, Select *p){
9923299494
if( p==0 ){
9923399495
sqlite3ExplainPrintf(pVdbe, "(null-select)");
9923499496
return;
9923599497
}
99236
- while( p->pPrior ) p = p->pPrior;
99498
+ while( p->pPrior ){
99499
+ p->pPrior->pNext = p;
99500
+ p = p->pPrior;
99501
+ }
9923799502
sqlite3ExplainPush(pVdbe);
9923899503
while( p ){
9923999504
explainOneSelect(pVdbe, p);
9924099505
p = p->pNext;
9924199506
if( p==0 ) break;
@@ -102850,11 +103115,10 @@
102850103115
** subclauses points to the WhereClause object for the whole clause.
102851103116
*/
102852103117
struct WhereClause {
102853103118
Parse *pParse; /* The parser context */
102854103119
WhereMaskSet *pMaskSet; /* Mapping of table cursor numbers to bitmasks */
102855
- Bitmask vmask; /* Bitmask identifying virtual table cursors */
102856103120
WhereClause *pOuter; /* Outer conjunction */
102857103121
u8 op; /* Split operator. TK_AND or TK_OR */
102858103122
u16 wctrlFlags; /* Might include WHERE_AND_ONLY */
102859103123
int nTerm; /* Number of terms */
102860103124
int nSlot; /* Number of entries in a[] */
@@ -103027,11 +103291,10 @@
103027103291
pWC->pMaskSet = pMaskSet;
103028103292
pWC->pOuter = 0;
103029103293
pWC->nTerm = 0;
103030103294
pWC->nSlot = ArraySize(pWC->aStatic);
103031103295
pWC->a = pWC->aStatic;
103032
- pWC->vmask = 0;
103033103296
pWC->wctrlFlags = wctrlFlags;
103034103297
}
103035103298
103036103299
/* Forward reference */
103037103300
static void whereClauseClear(WhereClause*);
@@ -103355,13 +103618,12 @@
103355103618
**
103356103619
** If there are multiple terms in the WHERE clause of the form "X <op> <expr>"
103357103620
** then try for the one with no dependencies on <expr> - in other words where
103358103621
** <expr> is a constant expression of some kind. Only return entries of
103359103622
** the form "X <op> Y" where Y is a column in another table if no terms of
103360
-** the form "X <op> <const-expr>" exist. Other than this priority, if there
103361
-** are two or more terms that match, then the choice of which term to return
103362
-** is arbitrary.
103623
+** the form "X <op> <const-expr>" exist. If no terms with a constant RHS
103624
+** exist, try to return a term that does not use WO_EQUIV.
103363103625
*/
103364103626
static WhereTerm *findTerm(
103365103627
WhereClause *pWC, /* The WHERE clause to be searched */
103366103628
int iCur, /* Cursor number of LHS */
103367103629
int iColumn, /* Column number of LHS */
@@ -103416,12 +103678,16 @@
103416103678
}
103417103679
if( sqlite3StrICmp(pColl->zName, pIdx->azColl[j]) ){
103418103680
continue;
103419103681
}
103420103682
}
103421
- pResult = pTerm;
103422
- if( pTerm->prereqRight==0 ) goto findTerm_success;
103683
+ if( pTerm->prereqRight==0 ){
103684
+ pResult = pTerm;
103685
+ goto findTerm_success;
103686
+ }else if( pResult==0 ){
103687
+ pResult = pTerm;
103688
+ }
103423103689
}
103424103690
if( (pTerm->eOperator & WO_EQUIV)!=0
103425103691
&& nEquiv<ArraySize(aEquiv)
103426103692
){
103427103693
pX = sqlite3ExprSkipCollate(pTerm->pExpr->pRight);
@@ -103627,11 +103893,11 @@
103627103893
** (D) x=expr1 OR (y>11 AND y<22 AND z LIKE '*hello*')
103628103894
** (E) (p.a=1 AND q.b=2 AND r.c=3) OR (p.x=4 AND q.y=5 AND r.z=6)
103629103895
**
103630103896
** CASE 1:
103631103897
**
103632
-** If all subterms are of the form T.C=expr for some single column of C
103898
+** If all subterms are of the form T.C=expr for some single column of C and
103633103899
** a single table T (as shown in example B above) then create a new virtual
103634103900
** term that is an equivalent IN expression. In other words, if the term
103635103901
** being analyzed is:
103636103902
**
103637103903
** x = expr1 OR expr2 = x OR x = expr3
@@ -103715,11 +103981,11 @@
103715103981
103716103982
/*
103717103983
** Compute the set of tables that might satisfy cases 1 or 2.
103718103984
*/
103719103985
indexable = ~(Bitmask)0;
103720
- chngToIN = ~(pWC->vmask);
103986
+ chngToIN = ~(Bitmask)0;
103721103987
for(i=pOrWc->nTerm-1, pOrTerm=pOrWc->a; i>=0 && indexable; i--, pOrTerm++){
103722103988
if( (pOrTerm->eOperator & WO_SINGLE)==0 ){
103723103989
WhereAndInfo *pAndInfo;
103724103990
assert( (pOrTerm->wtFlags & (TERM_ANDINFO|TERM_ORINFO))==0 );
103725103991
chngToIN = 0;
@@ -104982,12 +105248,13 @@
104982105248
Table *pTab = pSrc->pTab;
104983105249
sqlite3_index_info *pIdxInfo;
104984105250
struct sqlite3_index_constraint *pIdxCons;
104985105251
struct sqlite3_index_constraint_usage *pUsage;
104986105252
WhereTerm *pTerm;
104987
- int i, j;
105253
+ int i, j, k;
104988105254
int nOrderBy;
105255
+ int sortOrder; /* Sort order for IN clauses */
104989105256
int bAllowIN; /* Allow IN optimizations */
104990105257
double rCost;
104991105258
104992105259
/* Make sure wsFlags is initialized to some sane value. Otherwise, if the
104993105260
** malloc in allocateIndexInfo() fails and this function returns leaving
@@ -105082,22 +105349,31 @@
105082105349
105083105350
if( vtabBestIndex(pParse, pTab, pIdxInfo) ){
105084105351
return;
105085105352
}
105086105353
105354
+ sortOrder = SQLITE_SO_ASC;
105087105355
pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint;
105088105356
for(i=0; i<pIdxInfo->nConstraint; i++, pIdxCons++){
105089105357
if( pUsage[i].argvIndex>0 ){
105090105358
j = pIdxCons->iTermOffset;
105091105359
pTerm = &pWC->a[j];
105092105360
p->cost.used |= pTerm->prereqRight;
105093
- if( (pTerm->eOperator & WO_IN)!=0 && pUsage[i].omit==0 ){
105094
- /* Do not attempt to use an IN constraint if the virtual table
105095
- ** says that the equivalent EQ constraint cannot be safely omitted.
105096
- ** If we do attempt to use such a constraint, some rows might be
105097
- ** repeated in the output. */
105098
- break;
105361
+ if( (pTerm->eOperator & WO_IN)!=0 ){
105362
+ if( pUsage[i].omit==0 ){
105363
+ /* Do not attempt to use an IN constraint if the virtual table
105364
+ ** says that the equivalent EQ constraint cannot be safely omitted.
105365
+ ** If we do attempt to use such a constraint, some rows might be
105366
+ ** repeated in the output. */
105367
+ break;
105368
+ }
105369
+ for(k=0; k<pIdxInfo->nOrderBy; k++){
105370
+ if( pIdxInfo->aOrderBy[k].iColumn==pIdxCons->iColumn ){
105371
+ sortOrder = pIdxInfo->aOrderBy[k].desc;
105372
+ break;
105373
+ }
105374
+ }
105099105375
}
105100105376
}
105101105377
}
105102105378
if( i>=pIdxInfo->nConstraint ) break;
105103105379
}
@@ -105123,11 +105399,12 @@
105123105399
}else{
105124105400
p->cost.rCost = rCost;
105125105401
}
105126105402
p->cost.plan.u.pVtabIdx = pIdxInfo;
105127105403
if( pIdxInfo->orderByConsumed ){
105128
- p->cost.plan.wsFlags |= WHERE_ORDERED;
105404
+ assert( sortOrder==0 || sortOrder==1 );
105405
+ p->cost.plan.wsFlags |= WHERE_ORDERED + sortOrder*WHERE_REVERSE;
105129105406
p->cost.plan.nOBSat = nOrderBy;
105130105407
}else{
105131105408
p->cost.plan.nOBSat = p->i ? p->aLevel[p->i-1].plan.nOBSat : 0;
105132105409
}
105133105410
p->cost.plan.nEq = 0;
@@ -105720,14 +105997,11 @@
105720105997
pConstraint = findTerm(p->pWC, base, iColumn, p->notReady,
105721105998
WO_EQ|WO_ISNULL|WO_IN, pIdx);
105722105999
if( pConstraint==0 ){
105723106000
isEq = 0;
105724106001
}else if( (pConstraint->eOperator & WO_IN)!=0 ){
105725
- /* Constraints of the form: "X IN ..." cannot be used with an ORDER BY
105726
- ** because we do not know in what order the values on the RHS of the IN
105727
- ** operator will occur. */
105728
- break;
106002
+ isEq = 0;
105729106003
}else if( (pConstraint->eOperator & WO_ISNULL)!=0 ){
105730106004
uniqueNotNull = 0;
105731106005
isEq = 1; /* "X IS NULL" means X has only a single value */
105732106006
}else if( pConstraint->prereqRight==0 ){
105733106007
isEq = 1; /* Constraint "X=constant" means X has only a single value */
@@ -106027,12 +106301,12 @@
106027106301
** constraint for all columns in the index, then this search will find
106028106302
** at most a single row. In this case set the WHERE_UNIQUE flag to
106029106303
** indicate this to the caller.
106030106304
**
106031106305
** Otherwise, if the search may find more than one row, test to see if
106032
- ** there is a range constraint on indexed column (pc.plan.nEq+1) that can be
106033
- ** optimized using the index.
106306
+ ** there is a range constraint on indexed column (pc.plan.nEq+1) that
106307
+ ** can be optimized using the index.
106034106308
*/
106035106309
if( pc.plan.nEq==pProbe->nColumn && pProbe->onError!=OE_None ){
106036106310
testcase( pc.plan.wsFlags & WHERE_COLUMN_IN );
106037106311
testcase( pc.plan.wsFlags & WHERE_COLUMN_NULL );
106038106312
if( (pc.plan.wsFlags & (WHERE_COLUMN_IN|WHERE_COLUMN_NULL))==0 ){
@@ -106369,11 +106643,12 @@
106369106643
#ifndef SQLITE_OMIT_VIRTUALTABLE
106370106644
if( IsVirtual(p->pSrc->pTab) ){
106371106645
sqlite3_index_info *pIdxInfo = 0;
106372106646
p->ppIdxInfo = &pIdxInfo;
106373106647
bestVirtualIndex(p);
106374
- if( pIdxInfo->needToFreeIdxStr ){
106648
+ assert( pIdxInfo!=0 || p->pParse->db->mallocFailed );
106649
+ if( pIdxInfo && pIdxInfo->needToFreeIdxStr ){
106375106650
sqlite3_free(pIdxInfo->idxStr);
106376106651
}
106377106652
sqlite3DbFree(p->pParse->db, pIdxInfo);
106378106653
}else
106379106654
#endif
@@ -106475,11 +106750,12 @@
106475106750
** this routine sets up a loop that will iterate over all values of X.
106476106751
*/
106477106752
static int codeEqualityTerm(
106478106753
Parse *pParse, /* The parsing context */
106479106754
WhereTerm *pTerm, /* The term of the WHERE clause to be coded */
106480
- WhereLevel *pLevel, /* When level of the FROM clause we are working on */
106755
+ WhereLevel *pLevel, /* The level of the FROM clause we are working on */
106756
+ int iEq, /* Index of the equality term within this level */
106481106757
int iTarget /* Attempt to leave results in this register */
106482106758
){
106483106759
Expr *pX = pTerm->pExpr;
106484106760
Vdbe *v = pParse->pVdbe;
106485106761
int iReg; /* Register holding results */
@@ -106493,16 +106769,30 @@
106493106769
#ifndef SQLITE_OMIT_SUBQUERY
106494106770
}else{
106495106771
int eType;
106496106772
int iTab;
106497106773
struct InLoop *pIn;
106774
+ u8 bRev = (pLevel->plan.wsFlags & WHERE_REVERSE)!=0;
106498106775
106776
+ if( (pLevel->plan.wsFlags & WHERE_INDEXED)!=0
106777
+ && pLevel->plan.u.pIdx->aSortOrder[iEq]
106778
+ ){
106779
+ testcase( iEq==0 );
106780
+ testcase( iEq==pLevel->plan.u.pIdx->nColumn-1 );
106781
+ testcase( iEq>0 && iEq+1<pLevel->plan.u.pIdx->nColumn );
106782
+ testcase( bRev );
106783
+ bRev = !bRev;
106784
+ }
106499106785
assert( pX->op==TK_IN );
106500106786
iReg = iTarget;
106501106787
eType = sqlite3FindInIndex(pParse, pX, 0);
106788
+ if( eType==IN_INDEX_INDEX_DESC ){
106789
+ testcase( bRev );
106790
+ bRev = !bRev;
106791
+ }
106502106792
iTab = pX->iTable;
106503
- sqlite3VdbeAddOp2(v, OP_Rewind, iTab, 0);
106793
+ sqlite3VdbeAddOp2(v, bRev ? OP_Last : OP_Rewind, iTab, 0);
106504106794
assert( pLevel->plan.wsFlags & WHERE_IN_ABLE );
106505106795
if( pLevel->u.in.nIn==0 ){
106506106796
pLevel->addrNxt = sqlite3VdbeMakeLabel(v);
106507106797
}
106508106798
pLevel->u.in.nIn++;
@@ -106516,10 +106806,11 @@
106516106806
if( eType==IN_INDEX_ROWID ){
106517106807
pIn->addrInTop = sqlite3VdbeAddOp2(v, OP_Rowid, iTab, iReg);
106518106808
}else{
106519106809
pIn->addrInTop = sqlite3VdbeAddOp3(v, OP_Column, iTab, 0, iReg);
106520106810
}
106811
+ pIn->eEndLoopOp = bRev ? OP_Prev : OP_Next;
106521106812
sqlite3VdbeAddOp1(v, OP_IsNull, iReg);
106522106813
}else{
106523106814
pLevel->u.in.nIn = 0;
106524106815
}
106525106816
#endif
@@ -106610,11 +106901,11 @@
106610106901
if( pTerm==0 ) break;
106611106902
/* The following true for indices with redundant columns.
106612106903
** Ex: CREATE INDEX i1 ON t1(a,b,a); SELECT * FROM t1 WHERE a=0 AND b=0; */
106613106904
testcase( (pTerm->wtFlags & TERM_CODED)!=0 );
106614106905
testcase( pTerm->wtFlags & TERM_VIRTUAL ); /* EV: R-30575-11662 */
106615
- r1 = codeEqualityTerm(pParse, pTerm, pLevel, regBase+j);
106906
+ r1 = codeEqualityTerm(pParse, pTerm, pLevel, j, regBase+j);
106616106907
if( r1!=regBase+j ){
106617106908
if( nReg==1 ){
106618106909
sqlite3ReleaseTempReg(pParse, regBase);
106619106910
regBase = r1;
106620106911
}else{
@@ -106884,14 +107175,14 @@
106884107175
iReg = sqlite3GetTempRange(pParse, nConstraint+2);
106885107176
addrNotFound = pLevel->addrBrk;
106886107177
for(j=1; j<=nConstraint; j++){
106887107178
for(k=0; k<nConstraint; k++){
106888107179
if( aUsage[k].argvIndex==j ){
106889
- WhereTerm *pTerm = &pWC->a[aConstraint[k].iTermOffset];
106890107180
int iTarget = iReg+j+1;
107181
+ pTerm = &pWC->a[aConstraint[k].iTermOffset];
106891107182
if( pTerm->eOperator & WO_IN ){
106892
- codeEqualityTerm(pParse, pTerm, pLevel, iTarget);
107183
+ codeEqualityTerm(pParse, pTerm, pLevel, k, iTarget);
106893107184
addrNotFound = pLevel->addrNxt;
106894107185
}else{
106895107186
sqlite3ExprCode(pParse, pTerm->pExpr->pRight, iTarget);
106896107187
}
106897107188
break;
@@ -106928,14 +107219,15 @@
106928107219
pTerm = findTerm(pWC, iCur, -1, notReady, WO_EQ|WO_IN, 0);
106929107220
assert( pTerm!=0 );
106930107221
assert( pTerm->pExpr!=0 );
106931107222
assert( omitTable==0 );
106932107223
testcase( pTerm->wtFlags & TERM_VIRTUAL ); /* EV: R-30575-11662 */
106933
- iRowidReg = codeEqualityTerm(pParse, pTerm, pLevel, iReleaseReg);
107224
+ iRowidReg = codeEqualityTerm(pParse, pTerm, pLevel, 0, iReleaseReg);
106934107225
addrNxt = pLevel->addrNxt;
106935107226
sqlite3VdbeAddOp2(v, OP_MustBeInt, iRowidReg, addrNxt);
106936107227
sqlite3VdbeAddOp3(v, OP_NotExists, iCur, addrNxt, iRowidReg);
107228
+ sqlite3ExprCacheAffinityChange(pParse, iRowidReg, 1);
106937107229
sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg);
106938107230
VdbeComment((v, "pk"));
106939107231
pLevel->op = OP_Noop;
106940107232
}else if( pLevel->plan.wsFlags & WHERE_ROWID_RANGE ){
106941107233
/* Case 2: We have an inequality comparison against the ROWID field.
@@ -107767,28 +108059,17 @@
107767108059
** its Expr.iRightJoinTable value to find the bitmask of the right table
107768108060
** of the join. Subtracting one from the right table bitmask gives a
107769108061
** bitmask for all tables to the left of the join. Knowing the bitmask
107770108062
** for all tables to the left of a left join is important. Ticket #3015.
107771108063
**
107772
- ** Configure the WhereClause.vmask variable so that bits that correspond
107773
- ** to virtual table cursors are set. This is used to selectively disable
107774
- ** the OR-to-IN transformation in exprAnalyzeOrTerm(). It is not helpful
107775
- ** with virtual tables.
107776
- **
107777108064
** Note that bitmasks are created for all pTabList->nSrc tables in
107778108065
** pTabList, not just the first nTabList tables. nTabList is normally
107779108066
** equal to pTabList->nSrc but might be shortened to 1 if the
107780108067
** WHERE_ONETABLE_ONLY flag is set.
107781108068
*/
107782
- assert( sWBI.pWC->vmask==0 && pMaskSet->n==0 );
107783108069
for(ii=0; ii<pTabList->nSrc; ii++){
107784108070
createMask(pMaskSet, pTabList->a[ii].iCursor);
107785
-#ifndef SQLITE_OMIT_VIRTUALTABLE
107786
- if( ALWAYS(pTabList->a[ii].pTab) && IsVirtual(pTabList->a[ii].pTab) ){
107787
- sWBI.pWC->vmask |= ((Bitmask)1 << ii);
107788
- }
107789
-#endif
107790108071
}
107791108072
#ifndef NDEBUG
107792108073
{
107793108074
Bitmask toTheLeft = 0;
107794108075
for(ii=0; ii<pTabList->nSrc; ii++){
@@ -108268,11 +108549,11 @@
108268108549
struct InLoop *pIn;
108269108550
int j;
108270108551
sqlite3VdbeResolveLabel(v, pLevel->addrNxt);
108271108552
for(j=pLevel->u.in.nIn, pIn=&pLevel->u.in.aInLoop[j-1]; j>0; j--, pIn--){
108272108553
sqlite3VdbeJumpHere(v, pIn->addrInTop+1);
108273
- sqlite3VdbeAddOp2(v, OP_Next, pIn->iCur, pIn->addrInTop);
108554
+ sqlite3VdbeAddOp2(v, pIn->eEndLoopOp, pIn->iCur, pIn->addrInTop);
108274108555
sqlite3VdbeJumpHere(v, pIn->addrInTop-1);
108275108556
}
108276108557
sqlite3DbFree(db, pLevel->u.in.aInLoop);
108277108558
}
108278108559
sqlite3VdbeResolveLabel(v, pLevel->addrBrk);
@@ -114034,11 +114315,11 @@
114034114315
}
114035114316
}
114036114317
sqlite3VtabRollback(db);
114037114318
sqlite3EndBenignMalloc();
114038114319
114039
- if( db->flags&SQLITE_InternChanges ){
114320
+ if( (db->flags&SQLITE_InternChanges)!=0 && db->init.busy==0 ){
114040114321
sqlite3ExpirePreparedStatements(db);
114041114322
sqlite3ResetAllSchemasOfConnection(db);
114042114323
}
114043114324
114044114325
/* Any deferred constraint violations have now been resolved. */
114045114326
--- src/sqlite3.c
+++ src/sqlite3.c
@@ -304,10 +304,14 @@
304 /* Needed for various definitions... */
305 #ifndef _GNU_SOURCE
306 # define _GNU_SOURCE
307 #endif
308
 
 
 
 
309 /*
310 ** Include standard header files as necessary
311 */
312 #ifdef HAVE_STDINT_H
313 #include <stdint.h>
@@ -438,11 +442,12 @@
438 ** if it is already defined or if it is unneeded because we are
439 ** not doing a threadsafe build. Ticket #2681.
440 **
441 ** See also ticket #2741.
442 */
443 #if !defined(_XOPEN_SOURCE) && !defined(__DARWIN__) && !defined(__APPLE__) && SQLITE_THREADSAFE
 
444 # define _XOPEN_SOURCE 500 /* Needed to enable pthread recursive mutexes */
445 #endif
446
447 /*
448 ** The TCL headers are only needed when compiling the TCL bindings.
@@ -673,11 +678,11 @@
673 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
674 ** [sqlite_version()] and [sqlite_source_id()].
675 */
676 #define SQLITE_VERSION "3.7.16"
677 #define SQLITE_VERSION_NUMBER 3007016
678 #define SQLITE_SOURCE_ID "2013-01-17 17:20:49 38852f158ab20bb4d7b264af987ec1538052bec3"
679
680 /*
681 ** CAPI3REF: Run-Time Library Version Numbers
682 ** KEYWORDS: sqlite3_version, sqlite3_sourceid
683 **
@@ -852,11 +857,11 @@
852 **
853 ** Applications should [sqlite3_finalize | finalize] all [prepared statements],
854 ** [sqlite3_blob_close | close] all [BLOB handles], and
855 ** [sqlite3_backup_finish | finish] all [sqlite3_backup] objects associated
856 ** with the [sqlite3] object prior to attempting to close the object. ^If
857 ** sqlite3_close() is called on a [database connection] that still has
858 ** outstanding [prepared statements], [BLOB handles], and/or
859 ** [sqlite3_backup] objects then it returns SQLITE_OK but the deallocation
860 ** of resources is deferred until all [prepared statements], [BLOB handles],
861 ** and [sqlite3_backup] objects are also destroyed.
862 **
@@ -1047,11 +1052,21 @@
1047 #define SQLITE_CANTOPEN_ISDIR (SQLITE_CANTOPEN | (2<<8))
1048 #define SQLITE_CANTOPEN_FULLPATH (SQLITE_CANTOPEN | (3<<8))
1049 #define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1<<8))
1050 #define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1<<8))
1051 #define SQLITE_READONLY_CANTLOCK (SQLITE_READONLY | (2<<8))
 
1052 #define SQLITE_ABORT_ROLLBACK (SQLITE_ABORT | (2<<8))
 
 
 
 
 
 
 
 
 
1053
1054 /*
1055 ** CAPI3REF: Flags For File Open Operations
1056 **
1057 ** These bit values are intended for use in the
@@ -10018,11 +10033,11 @@
10018 #define SQLITE_NullCallback 0x00000020 /* Invoke the callback once if the */
10019 /* result set is empty */
10020 #define SQLITE_SqlTrace 0x00000040 /* Debug print SQL as it executes */
10021 #define SQLITE_VdbeListing 0x00000080 /* Debug listings of VDBE programs */
10022 #define SQLITE_WriteSchema 0x00000100 /* OK to update SQLITE_MASTER */
10023 /* 0x00000200 Unused */
10024 #define SQLITE_IgnoreChecks 0x00000400 /* Do not enforce check constraints */
10025 #define SQLITE_ReadUncommitted 0x0000800 /* For shared-cache mode */
10026 #define SQLITE_LegacyFileFmt 0x00001000 /* Create new databases in format 1 */
10027 #define SQLITE_FullFSync 0x00002000 /* Use full fsync on the backend */
10028 #define SQLITE_CkptFullFSync 0x00004000 /* Use full fsync for checkpoint */
@@ -11034,10 +11049,11 @@
11034 struct {
11035 int nIn; /* Number of entries in aInLoop[] */
11036 struct InLoop {
11037 int iCur; /* The VDBE cursor used by this IN operator */
11038 int addrInTop; /* Top of the IN loop */
 
11039 } *aInLoop; /* Information about each nested IN operator */
11040 } in; /* Used when plan.wsFlags&WHERE_IN_ABLE */
11041 Index *pCovidx; /* Possible covering index for WHERE_MULTI_OR */
11042 } u;
11043 double rOptCost; /* "Optimal" cost for this level */
@@ -11905,11 +11921,11 @@
11905 SQLITE_PRIVATE void sqlite3SelectDelete(sqlite3*, Select*);
11906 SQLITE_PRIVATE Table *sqlite3SrcListLookup(Parse*, SrcList*);
11907 SQLITE_PRIVATE int sqlite3IsReadOnly(Parse*, Table*, int);
11908 SQLITE_PRIVATE void sqlite3OpenTable(Parse*, int iCur, int iDb, Table*, int);
11909 #if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) && !defined(SQLITE_OMIT_SUBQUERY)
11910 SQLITE_PRIVATE Expr *sqlite3LimitWhere(Parse *, SrcList *, Expr *, ExprList *, Expr *, Expr *, char *);
11911 #endif
11912 SQLITE_PRIVATE void sqlite3DeleteFrom(Parse*, SrcList*, Expr*);
11913 SQLITE_PRIVATE void sqlite3Update(Parse*, SrcList*, ExprList*, Expr*, int);
11914 SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(Parse*,SrcList*,Expr*,ExprList*,ExprList*,u16,int);
11915 SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo*);
@@ -11973,11 +11989,11 @@
11973 SQLITE_PRIVATE void sqlite3CompleteInsertion(Parse*, Table*, int, int, int*, int, int, int);
11974 SQLITE_PRIVATE int sqlite3OpenTableAndIndices(Parse*, Table*, int, int);
11975 SQLITE_PRIVATE void sqlite3BeginWriteOperation(Parse*, int, int);
11976 SQLITE_PRIVATE void sqlite3MultiWrite(Parse*);
11977 SQLITE_PRIVATE void sqlite3MayAbort(Parse*);
11978 SQLITE_PRIVATE void sqlite3HaltConstraint(Parse*, int, char*, int);
11979 SQLITE_PRIVATE Expr *sqlite3ExprDup(sqlite3*,Expr*,int);
11980 SQLITE_PRIVATE ExprList *sqlite3ExprListDup(sqlite3*,ExprList*,int);
11981 SQLITE_PRIVATE SrcList *sqlite3SrcListDup(sqlite3*,SrcList*,int);
11982 SQLITE_PRIVATE IdList *sqlite3IdListDup(sqlite3*,IdList*);
11983 SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3*,Select*,int);
@@ -12086,12 +12102,15 @@
12086 **
12087 ** x = getVarint32( A, B );
12088 ** x = putVarint32( A, B );
12089 **
12090 */
12091 #define getVarint32(A,B) (u8)((*(A)<(u8)0x80) ? ((B) = (u32)*(A)),1 : sqlite3GetVarint32((A), (u32 *)&(B)))
12092 #define putVarint32(A,B) (u8)(((u32)(B)<(u32)0x80) ? (*(A) = (unsigned char)(B)),1 : sqlite3PutVarint32((A), (B)))
 
 
 
12093 #define getVarint sqlite3GetVarint
12094 #define putVarint sqlite3PutVarint
12095
12096
12097 SQLITE_PRIVATE const char *sqlite3IndexAffinityStr(Vdbe *, Index *);
@@ -12323,11 +12342,12 @@
12323 #define sqlite3EndBenignMalloc()
12324 #endif
12325
12326 #define IN_INDEX_ROWID 1
12327 #define IN_INDEX_EPH 2
12328 #define IN_INDEX_INDEX 3
 
12329 SQLITE_PRIVATE int sqlite3FindInIndex(Parse *, Expr *, int*);
12330
12331 #ifdef SQLITE_ENABLE_ATOMIC_WRITE
12332 SQLITE_PRIVATE int sqlite3JournalOpen(sqlite3_vfs *, const char *, sqlite3_file *, int, int);
12333 SQLITE_PRIVATE int sqlite3JournalSize(sqlite3_vfs *);
@@ -13208,11 +13228,11 @@
13208 Mem *aMem; /* Array of memory cells for parent frame */
13209 u8 *aOnceFlag; /* Array of OP_Once flags for parent frame */
13210 VdbeCursor **apCsr; /* Array of Vdbe cursors for parent frame */
13211 void *token; /* Copy of SubProgram.token */
13212 i64 lastRowid; /* Last insert rowid (sqlite3.lastRowid) */
13213 u16 nCursor; /* Number of entries in apCsr */
13214 int pc; /* Program Counter in parent (calling) frame */
13215 int nOp; /* Size of aOp array */
13216 int nMem; /* Number of entries in aMem */
13217 int nOnceFlag; /* Number of entries in aOnceFlag */
13218 int nChildMem; /* Number of memory cells for child frame */
@@ -13394,11 +13414,11 @@
13394 int nOp; /* Number of instructions in the program */
13395 int nOpAlloc; /* Number of slots allocated for aOp[] */
13396 int nLabel; /* Number of labels used */
13397 int *aLabel; /* Space to hold the labels */
13398 u16 nResColumn; /* Number of columns in one row of the result set */
13399 u16 nCursor; /* Number of slots in apCsr[] */
13400 u32 magic; /* Magic number for sanity checking */
13401 char *zErrMsg; /* Error message written here */
13402 Vdbe *pPrev,*pNext; /* Linked list of VDBEs with the same Vdbe.db */
13403 VdbeCursor **apCsr; /* One element of this array for each open cursor */
13404 Mem *aVar; /* Values for the OP_Variable opcode. */
@@ -23445,11 +23465,14 @@
23445 #endif
23446 }while( fd<0 && errno==EINTR );
23447 if( fd>=0 ){
23448 if( m!=0 ){
23449 struct stat statbuf;
23450 if( osFstat(fd, &statbuf)==0 && (statbuf.st_mode&0777)!=m ){
 
 
 
23451 osFchmod(fd, m);
23452 }
23453 }
23454 #if defined(FD_CLOEXEC) && (!defined(O_CLOEXEC) || O_CLOEXEC==0)
23455 osFcntl(fd, F_SETFD, osFcntl(fd, F_GETFD, 0) | FD_CLOEXEC);
@@ -27645,11 +27668,11 @@
27645 pNew->ctrlFlags = (u8)ctrlFlags;
27646 if( sqlite3_uri_boolean(((ctrlFlags & UNIXFILE_URI) ? zFilename : 0),
27647 "psow", SQLITE_POWERSAFE_OVERWRITE) ){
27648 pNew->ctrlFlags |= UNIXFILE_PSOW;
27649 }
27650 if( memcmp(pVfs->zName,"unix-excl",10)==0 ){
27651 pNew->ctrlFlags |= UNIXFILE_EXCL;
27652 }
27653
27654 #if OS_VXWORKS
27655 pNew->pId = vxworksFindFileId(zFilename);
@@ -31099,11 +31122,11 @@
31099 /*
31100 ** This function outputs the specified (ANSI) string to the Win32 debugger
31101 ** (if available).
31102 */
31103
31104 SQLITE_API void sqlite3_win32_write_debug(char *zBuf, int nBuf){
31105 char zDbgBuf[SQLITE_WIN32_DBG_BUF_SIZE];
31106 int nMin = MIN(nBuf, (SQLITE_WIN32_DBG_BUF_SIZE - 1)); /* may be negative. */
31107 if( nMin<-1 ) nMin = -1; /* all negative values become -1. */
31108 assert( nMin==-1 || nMin==0 || nMin<SQLITE_WIN32_DBG_BUF_SIZE );
31109 #if defined(SQLITE_WIN32_HAS_ANSI)
@@ -31732,13 +31755,14 @@
31732
31733 #if SQLITE_OS_WINCE
31734 /*************************************************************************
31735 ** This section contains code for WinCE only.
31736 */
 
31737 /*
31738 ** Windows CE does not have a localtime() function. So create a
31739 ** substitute.
31740 */
31741 /* #include <time.h> */
31742 struct tm *__cdecl localtime(const time_t *t)
31743 {
31744 static struct tm y;
@@ -31758,10 +31782,11 @@
31758 y.tm_hour = pTm.wHour;
31759 y.tm_min = pTm.wMinute;
31760 y.tm_sec = pTm.wSecond;
31761 return &y;
31762 }
 
31763
31764 #define HANDLE_TO_WINFILE(a) (winFile*)&((char*)a)[-(int)offsetof(winFile,h)]
31765
31766 /*
31767 ** Acquire a lock on the handle h
@@ -31779,19 +31804,21 @@
31779
31780 /*
31781 ** Create the mutex and shared memory used for locking in the file
31782 ** descriptor pFile
31783 */
31784 static BOOL winceCreateLock(const char *zFilename, winFile *pFile){
31785 LPWSTR zTok;
31786 LPWSTR zName;
 
 
31787 BOOL bInit = TRUE;
31788
31789 zName = utf8ToUnicode(zFilename);
31790 if( zName==0 ){
31791 /* out of memory */
31792 return FALSE;
31793 }
31794
31795 /* Initialize the local lockdata */
31796 memset(&pFile->local, 0, sizeof(pFile->local));
31797
@@ -31804,13 +31831,14 @@
31804
31805 /* Create/open the named mutex */
31806 pFile->hMutex = osCreateMutexW(NULL, FALSE, zName);
31807 if (!pFile->hMutex){
31808 pFile->lastErrno = osGetLastError();
31809 winLogError(SQLITE_ERROR, pFile->lastErrno, "winceCreateLock1", zFilename);
 
31810 sqlite3_free(zName);
31811 return FALSE;
31812 }
31813
31814 /* Acquire the mutex before continuing */
31815 winceMutexAcquire(pFile->hMutex);
31816
@@ -31823,45 +31851,53 @@
31823 PAGE_READWRITE, 0, sizeof(winceLock),
31824 zName);
31825
31826 /* Set a flag that indicates we're the first to create the memory so it
31827 ** must be zero-initialized */
31828 if (osGetLastError() == ERROR_ALREADY_EXISTS){
 
31829 bInit = FALSE;
31830 }
31831
31832 sqlite3_free(zName);
31833
31834 /* If we succeeded in making the shared memory handle, map it. */
31835 if (pFile->hShared){
31836 pFile->shared = (winceLock*)osMapViewOfFile(pFile->hShared,
31837 FILE_MAP_READ|FILE_MAP_WRITE, 0, 0, sizeof(winceLock));
31838 /* If mapping failed, close the shared memory handle and erase it */
31839 if (!pFile->shared){
31840 pFile->lastErrno = osGetLastError();
31841 winLogError(SQLITE_ERROR, pFile->lastErrno,
31842 "winceCreateLock2", zFilename);
 
31843 osCloseHandle(pFile->hShared);
31844 pFile->hShared = NULL;
31845 }
31846 }
31847
31848 /* If shared memory could not be created, then close the mutex and fail */
31849 if (pFile->hShared == NULL){
 
 
 
 
 
 
31850 winceMutexRelease(pFile->hMutex);
31851 osCloseHandle(pFile->hMutex);
31852 pFile->hMutex = NULL;
31853 return FALSE;
31854 }
31855
31856 /* Initialize the shared memory if we're supposed to */
31857 if (bInit) {
31858 memset(pFile->shared, 0, sizeof(winceLock));
31859 }
31860
31861 winceMutexRelease(pFile->hMutex);
31862 return TRUE;
31863 }
31864
31865 /*
31866 ** Destroy the part of winFile that deals with wince locks
31867 */
@@ -31936,21 +31972,23 @@
31936 bReturn = TRUE;
31937 }
31938 }
31939
31940 /* Want a pending lock? */
31941 else if (dwFileOffsetLow == (DWORD)PENDING_BYTE && nNumberOfBytesToLockLow == 1){
 
31942 /* If no pending lock has been acquired, then acquire it */
31943 if (pFile->shared->bPending == 0) {
31944 pFile->shared->bPending = TRUE;
31945 pFile->local.bPending = TRUE;
31946 bReturn = TRUE;
31947 }
31948 }
31949
31950 /* Want a reserved lock? */
31951 else if (dwFileOffsetLow == (DWORD)RESERVED_BYTE && nNumberOfBytesToLockLow == 1){
 
31952 if (pFile->shared->bReserved == 0) {
31953 pFile->shared->bReserved = TRUE;
31954 pFile->local.bReserved = TRUE;
31955 bReturn = TRUE;
31956 }
@@ -31989,11 +32027,12 @@
31989 bReturn = TRUE;
31990 }
31991
31992 /* Did we just have a reader lock? */
31993 else if (pFile->local.nReaders){
31994 assert(nNumberOfBytesToUnlockLow == (DWORD)SHARED_SIZE || nNumberOfBytesToUnlockLow == 1);
 
31995 pFile->local.nReaders --;
31996 if (pFile->local.nReaders == 0)
31997 {
31998 pFile->shared->nReaders --;
31999 }
@@ -32000,19 +32039,21 @@
32000 bReturn = TRUE;
32001 }
32002 }
32003
32004 /* Releasing a pending lock */
32005 else if (dwFileOffsetLow == (DWORD)PENDING_BYTE && nNumberOfBytesToUnlockLow == 1){
 
32006 if (pFile->local.bPending){
32007 pFile->local.bPending = FALSE;
32008 pFile->shared->bPending = FALSE;
32009 bReturn = TRUE;
32010 }
32011 }
32012 /* Releasing a reserved lock */
32013 else if (dwFileOffsetLow == (DWORD)RESERVED_BYTE && nNumberOfBytesToUnlockLow == 1){
 
32014 if (pFile->local.bReserved) {
32015 pFile->local.bReserved = FALSE;
32016 pFile->shared->bReserved = FALSE;
32017 bReturn = TRUE;
32018 }
@@ -32174,10 +32215,11 @@
32174 assert( id!=0 );
32175 #ifndef SQLITE_OMIT_WAL
32176 assert( pFile->pShm==0 );
32177 #endif
32178 OSTRACE(("CLOSE %d\n", pFile->h));
 
32179 do{
32180 rc = osCloseHandle(pFile->h);
32181 /* SimulateIOError( rc=0; cnt=MX_CLOSE_ATTEMPT; ); */
32182 }while( rc==0 && ++cnt < MX_CLOSE_ATTEMPT && (sqlite3_win32_sleep(100), 1) );
32183 #if SQLITE_OS_WINCE
@@ -32866,11 +32908,11 @@
32866 a[1] = win32IoerrRetryDelay;
32867 }
32868 return SQLITE_OK;
32869 }
32870 case SQLITE_FCNTL_TEMPFILENAME: {
32871 char *zTFile = sqlite3_malloc( pFile->pVfs->mxPathname );
32872 if( zTFile ){
32873 getTempname(pFile->pVfs->mxPathname, zTFile);
32874 *(char**)pArg = zTFile;
32875 }
32876 return SQLITE_OK;
@@ -33090,11 +33132,11 @@
33090 bRc = osCloseHandle(p->aRegion[i].hMap);
33091 OSTRACE(("SHM-PURGE pid-%d close region=%d %s\n",
33092 (int)osGetCurrentProcessId(), i,
33093 bRc ? "ok" : "failed"));
33094 }
33095 if( p->hFile.h != INVALID_HANDLE_VALUE ){
33096 SimulateIOErrorBenign(1);
33097 winClose((sqlite3_file *)&p->hFile);
33098 SimulateIOErrorBenign(0);
33099 }
33100 if( deleteFlag ){
@@ -33170,11 +33212,11 @@
33170 }
33171
33172 rc = winOpen(pDbFd->pVfs,
33173 pShmNode->zFilename, /* Name of the file (UTF-8) */
33174 (sqlite3_file*)&pShmNode->hFile, /* File handle here */
33175 SQLITE_OPEN_WAL | SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, /* Mode flags */
33176 0);
33177 if( SQLITE_OK!=rc ){
33178 goto shm_open_err;
33179 }
33180
@@ -33785,27 +33827,27 @@
33785 || eType==SQLITE_OPEN_MAIN_JOURNAL || eType==SQLITE_OPEN_TEMP_JOURNAL
33786 || eType==SQLITE_OPEN_SUBJOURNAL || eType==SQLITE_OPEN_MASTER_JOURNAL
33787 || eType==SQLITE_OPEN_TRANSIENT_DB || eType==SQLITE_OPEN_WAL
33788 );
33789
33790 assert( id!=0 );
33791 UNUSED_PARAMETER(pVfs);
 
33792
33793 #if SQLITE_OS_WINRT
33794 if( !sqlite3_temp_directory ){
33795 sqlite3_log(SQLITE_ERROR,
33796 "sqlite3_temp_directory variable should be set for WinRT");
33797 }
33798 #endif
33799
33800 pFile->h = INVALID_HANDLE_VALUE;
33801
33802 /* If the second argument to this function is NULL, generate a
33803 ** temporary file name to use
33804 */
33805 if( !zUtf8Name ){
33806 assert(isDelete && !isOpenJournal);
 
33807 rc = getTempname(MAX_PATH+2, zTmpname);
33808 if( rc!=SQLITE_OK ){
33809 return rc;
33810 }
33811 zUtf8Name = zTmpname;
@@ -33924,11 +33966,13 @@
33924 pFile->lastErrno = lastErrno;
33925 winLogError(SQLITE_CANTOPEN, pFile->lastErrno, "winOpen", zUtf8Name);
33926 sqlite3_free(zConverted);
33927 if( isReadWrite && !isExclusive ){
33928 return winOpen(pVfs, zName, id,
33929 ((flags|SQLITE_OPEN_READONLY)&~(SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE)), pOutFlags);
 
 
33930 }else{
33931 return SQLITE_CANTOPEN_BKPT;
33932 }
33933 }
33934
@@ -33938,38 +33982,34 @@
33938 }else{
33939 *pOutFlags = SQLITE_OPEN_READONLY;
33940 }
33941 }
33942
33943 memset(pFile, 0, sizeof(*pFile));
33944 pFile->pMethod = &winIoMethod;
33945 pFile->h = h;
33946 pFile->lastErrno = NO_ERROR;
33947 pFile->pVfs = pVfs;
33948 #ifndef SQLITE_OMIT_WAL
33949 pFile->pShm = 0;
33950 #endif
33951 pFile->zPath = zName;
33952 if( sqlite3_uri_boolean(zName, "psow", SQLITE_POWERSAFE_OVERWRITE) ){
33953 pFile->ctrlFlags |= WINFILE_PSOW;
33954 }
33955
33956 #if SQLITE_OS_WINCE
33957 if( isReadWrite && eType==SQLITE_OPEN_MAIN_DB
33958 && !winceCreateLock(zName, pFile)
33959 ){
33960 osCloseHandle(h);
33961 sqlite3_free(zConverted);
33962 return SQLITE_CANTOPEN_BKPT;
33963 }
33964 if( isTemp ){
33965 pFile->zDeleteOnClose = zConverted;
33966 }else
33967 #endif
33968 {
33969 sqlite3_free(zConverted);
33970 }
 
 
 
 
 
 
 
 
 
33971
33972 OpenCounter(+1);
33973 return rc;
33974 }
33975
@@ -34011,11 +34051,12 @@
34011 if ( osGetFileAttributesExW(zConverted, GetFileExInfoStandard,
34012 &sAttrData) ){
34013 attr = sAttrData.dwFileAttributes;
34014 }else{
34015 lastErrno = osGetLastError();
34016 if( lastErrno==ERROR_FILE_NOT_FOUND || lastErrno==ERROR_PATH_NOT_FOUND ){
 
34017 rc = SQLITE_IOERR_DELETE_NOENT; /* Already gone? */
34018 }else{
34019 rc = SQLITE_ERROR;
34020 }
34021 break;
@@ -34023,11 +34064,12 @@
34023 #else
34024 attr = osGetFileAttributesW(zConverted);
34025 #endif
34026 if ( attr==INVALID_FILE_ATTRIBUTES ){
34027 lastErrno = osGetLastError();
34028 if( lastErrno==ERROR_FILE_NOT_FOUND || lastErrno==ERROR_PATH_NOT_FOUND ){
 
34029 rc = SQLITE_IOERR_DELETE_NOENT; /* Already gone? */
34030 }else{
34031 rc = SQLITE_ERROR;
34032 }
34033 break;
@@ -34050,11 +34092,12 @@
34050 else{
34051 do {
34052 attr = osGetFileAttributesA(zConverted);
34053 if ( attr==INVALID_FILE_ATTRIBUTES ){
34054 lastErrno = osGetLastError();
34055 if( lastErrno==ERROR_FILE_NOT_FOUND || lastErrno==ERROR_PATH_NOT_FOUND ){
 
34056 rc = SQLITE_IOERR_DELETE_NOENT; /* Already gone? */
34057 }else{
34058 rc = SQLITE_ERROR;
34059 }
34060 break;
@@ -34218,20 +34261,16 @@
34218 ** for converting the relative path name to an absolute
34219 ** one by prepending the data directory and a slash.
34220 */
34221 char zOut[MAX_PATH+1];
34222 memset(zOut, 0, MAX_PATH+1);
34223 cygwin_conv_to_win32_path(zRelative, zOut); /* POSIX to Win32 */
 
34224 sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s\\%s",
34225 sqlite3_data_directory, zOut);
34226 }else{
34227 /*
34228 ** NOTE: The Cygwin docs state that the maximum length needed
34229 ** for the buffer passed to cygwin_conv_to_full_win32_path
34230 ** is MAX_PATH.
34231 */
34232 cygwin_conv_to_full_win32_path(zRelative, zFull);
34233 }
34234 return SQLITE_OK;
34235 #endif
34236
34237 #if (SQLITE_OS_WINCE || SQLITE_OS_WINRT) && !defined(__CYGWIN__)
@@ -34385,13 +34424,13 @@
34385 }
34386 static void winDlError(sqlite3_vfs *pVfs, int nBuf, char *zBufOut){
34387 UNUSED_PARAMETER(pVfs);
34388 getLastErrorMsg(osGetLastError(), nBuf, zBufOut);
34389 }
34390 static void (*winDlSym(sqlite3_vfs *pVfs, void *pHandle, const char *zSymbol))(void){
34391 UNUSED_PARAMETER(pVfs);
34392 return (void(*)(void))osGetProcAddressA((HANDLE)pHandle, zSymbol);
34393 }
34394 static void winDlClose(sqlite3_vfs *pVfs, void *pHandle){
34395 UNUSED_PARAMETER(pVfs);
34396 osFreeLibrary((HANDLE)pHandle);
34397 }
@@ -34485,11 +34524,12 @@
34485 #ifdef SQLITE_TEST
34486 static const sqlite3_int64 unixEpoch = 24405875*(sqlite3_int64)8640000;
34487 #endif
34488 /* 2^32 - to avoid use of LL and warnings in gcc */
34489 static const sqlite3_int64 max32BitValue =
34490 (sqlite3_int64)2000000000 + (sqlite3_int64)2000000000 + (sqlite3_int64)294967296;
 
34491
34492 #if SQLITE_OS_WINCE
34493 SYSTEMTIME time;
34494 osGetSystemTime(&time);
34495 /* if SystemTimeToFileTime() fails, it returns zero. */
@@ -39163,10 +39203,12 @@
39163 pPager->eState = PAGER_ERROR;
39164 }
39165 return rc;
39166 }
39167
 
 
39168 /*
39169 ** This routine ends a transaction. A transaction is usually ended by
39170 ** either a COMMIT or a ROLLBACK operation. This routine may be called
39171 ** after rollback of a hot-journal, or if an error occurs while opening
39172 ** the journal file or writing the very first journal-header of a
@@ -39216,11 +39258,11 @@
39216 ** tries to unlock the database file if not in exclusive mode. If the
39217 ** unlock operation fails as well, then the first error code related
39218 ** to the first error encountered (the journal finalization one) is
39219 ** returned.
39220 */
39221 static int pager_end_transaction(Pager *pPager, int hasMaster){
39222 int rc = SQLITE_OK; /* Error code from journal finalization operation */
39223 int rc2 = SQLITE_OK; /* Error code from db file unlock operation */
39224
39225 /* Do nothing if the pager does not have an open write transaction
39226 ** or at least a RESERVED lock. This function may be called when there
@@ -39302,11 +39344,21 @@
39302 ** locking_mode=exclusive mode but is no longer, drop the EXCLUSIVE
39303 ** lock held on the database file.
39304 */
39305 rc2 = sqlite3WalEndWriteTransaction(pPager->pWal);
39306 assert( rc2==SQLITE_OK );
 
 
 
 
 
 
 
 
 
39307 }
 
39308 if( !pPager->exclusiveMode
39309 && (!pagerUseWal(pPager) || sqlite3WalExclusiveMode(pPager->pWal, 0))
39310 ){
39311 rc2 = pagerUnlockDb(pPager, SHARED_LOCK);
39312 pPager->changeCountDone = 0;
@@ -39341,11 +39393,11 @@
39341 sqlite3BeginBenignMalloc();
39342 sqlite3PagerRollback(pPager);
39343 sqlite3EndBenignMalloc();
39344 }else if( !pPager->exclusiveMode ){
39345 assert( pPager->eState==PAGER_READER );
39346 pager_end_transaction(pPager, 0);
39347 }
39348 }
39349 pager_unlock(pPager);
39350 }
39351
@@ -40116,11 +40168,11 @@
40116 && (pPager->eState>=PAGER_WRITER_DBMOD || pPager->eState==PAGER_OPEN)
40117 ){
40118 rc = sqlite3PagerSync(pPager);
40119 }
40120 if( rc==SQLITE_OK ){
40121 rc = pager_end_transaction(pPager, zMaster[0]!='\0');
40122 testcase( rc!=SQLITE_OK );
40123 }
40124 if( rc==SQLITE_OK && zMaster[0] && res ){
40125 /* If there was a master journal and this routine will return success,
40126 ** see if it is possible to delete the master journal.
@@ -41068,16 +41120,30 @@
41068 /*
41069 ** Truncate the in-memory database file image to nPage pages. This
41070 ** function does not actually modify the database file on disk. It
41071 ** just sets the internal state of the pager object so that the
41072 ** truncation will be done when the current transaction is committed.
 
 
 
 
 
41073 */
41074 SQLITE_PRIVATE void sqlite3PagerTruncateImage(Pager *pPager, Pgno nPage){
41075 assert( pPager->dbSize>=nPage );
41076 assert( pPager->eState>=PAGER_WRITER_CACHEMOD );
41077 pPager->dbSize = nPage;
41078 assertTruncateConstraint(pPager);
 
 
 
 
 
 
 
 
 
41079 }
41080
41081
41082 /*
41083 ** This function is called before attempting a hot-journal rollback. It
@@ -42126,10 +42192,15 @@
42126 }
42127 if( rc!=SQLITE_OK ){
42128 goto failed;
42129 }
42130 if( bHotJournal ){
 
 
 
 
 
42131 /* Get an EXCLUSIVE lock on the database file. At this point it is
42132 ** important that a RESERVED lock is not obtained on the way to the
42133 ** EXCLUSIVE lock. If it were, another process might open the
42134 ** database file, detect the RESERVED lock, and conclude that the
42135 ** database is safe to read while this process is still rolling the
@@ -43210,40 +43281,10 @@
43210 #else
43211 rc = pager_incr_changecounter(pPager, 0);
43212 #endif
43213 if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
43214
43215 /* If this transaction has made the database smaller, then all pages
43216 ** being discarded by the truncation must be written to the journal
43217 ** file.
43218 **
43219 ** Before reading the pages with page numbers larger than the
43220 ** current value of Pager.dbSize, set dbSize back to the value
43221 ** that it took at the start of the transaction. Otherwise, the
43222 ** calls to sqlite3PagerGet() return zeroed pages instead of
43223 ** reading data from the database file.
43224 */
43225 if( pPager->dbSize<pPager->dbOrigSize
43226 && pPager->journalMode!=PAGER_JOURNALMODE_OFF
43227 ){
43228 Pgno i; /* Iterator variable */
43229 const Pgno iSkip = PAGER_MJ_PGNO(pPager); /* Pending lock page */
43230 const Pgno dbSize = pPager->dbSize; /* Database image size */
43231 pPager->dbSize = pPager->dbOrigSize;
43232 for( i=dbSize+1; i<=pPager->dbOrigSize; i++ ){
43233 if( !sqlite3BitvecTest(pPager->pInJournal, i) && i!=iSkip ){
43234 PgHdr *pPage; /* Page to journal */
43235 rc = sqlite3PagerGet(pPager, i, &pPage);
43236 if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
43237 rc = sqlite3PagerWrite(pPage);
43238 sqlite3PagerUnref(pPage);
43239 if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
43240 }
43241 }
43242 pPager->dbSize = dbSize;
43243 }
43244
43245 /* Write the master journal name into the journal file. If a master
43246 ** journal file name has already been written to the journal file,
43247 ** or if zMaster is NULL (no master journal), then this call is a no-op.
43248 */
43249 rc = writeMasterJournal(pPager, zMaster);
@@ -43267,15 +43308,18 @@
43267 if( rc!=SQLITE_OK ){
43268 assert( rc!=SQLITE_IOERR_BLOCKED );
43269 goto commit_phase_one_exit;
43270 }
43271 sqlite3PcacheCleanAll(pPager->pPCache);
43272
43273 /* If the file on disk is not the same size as the database image,
43274 ** then use pager_truncate to grow or shrink the file here.
43275 */
43276 if( pPager->dbSize!=pPager->dbFileSize ){
 
 
 
43277 Pgno nNew = pPager->dbSize - (pPager->dbSize==PAGER_MJ_PGNO(pPager));
43278 assert( pPager->eState==PAGER_WRITER_DBMOD );
43279 rc = pager_truncate(pPager, nNew);
43280 if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
43281 }
@@ -43344,11 +43388,11 @@
43344 pPager->eState = PAGER_READER;
43345 return SQLITE_OK;
43346 }
43347
43348 PAGERTRACE(("COMMIT %d\n", PAGERID(pPager)));
43349 rc = pager_end_transaction(pPager, pPager->setMaster);
43350 return pager_error(pPager, rc);
43351 }
43352
43353 /*
43354 ** If a write transaction is open, then all changes made within the
@@ -43389,15 +43433,15 @@
43389 if( pPager->eState<=PAGER_READER ) return SQLITE_OK;
43390
43391 if( pagerUseWal(pPager) ){
43392 int rc2;
43393 rc = sqlite3PagerSavepoint(pPager, SAVEPOINT_ROLLBACK, -1);
43394 rc2 = pager_end_transaction(pPager, pPager->setMaster);
43395 if( rc==SQLITE_OK ) rc = rc2;
43396 }else if( !isOpen(pPager->jfd) || pPager->eState==PAGER_WRITER_LOCKED ){
43397 int eState = pPager->eState;
43398 rc = pager_end_transaction(pPager, 0);
43399 if( !MEMDB && eState>PAGER_WRITER_LOCKED ){
43400 /* This can happen using journal_mode=off. Move the pager to the error
43401 ** state to indicate that the contents of the cache may not be trusted.
43402 ** Any active readers will get SQLITE_ABORT.
43403 */
@@ -43791,11 +43835,12 @@
43791 ** the journal needs to be sync()ed before database page pPg->pgno
43792 ** can be written to. The caller has already promised not to write to it.
43793 */
43794 if( (pPg->flags&PGHDR_NEED_SYNC) && !isCommit ){
43795 needSyncPgno = pPg->pgno;
43796 assert( pageInJournal(pPg) || pPg->pgno>pPager->dbOrigSize );
 
43797 assert( pPg->flags&PGHDR_DIRTY );
43798 }
43799
43800 /* If the cache contains a page with page-number pgno, remove it
43801 ** from its hash chain. Also, if the PGHDR_NEED_SYNC flag was set for
@@ -47795,10 +47840,11 @@
47795 MemPage *pPage1; /* First page of the database */
47796 u8 openFlags; /* Flags to sqlite3BtreeOpen() */
47797 #ifndef SQLITE_OMIT_AUTOVACUUM
47798 u8 autoVacuum; /* True if auto-vacuum is enabled */
47799 u8 incrVacuum; /* True if incr-vacuum is enabled */
 
47800 #endif
47801 u8 inTransaction; /* Transaction state */
47802 u8 max1bytePayload; /* Maximum first byte of cell for a 1-byte payload */
47803 u16 btsFlags; /* Boolean parameters. See BTS_* macros below */
47804 u16 maxLocal; /* Maximum local payload in non-LEAFDATA tables */
@@ -48361,10 +48407,29 @@
48361 ** is empty, the offset should be 65536, but the 2-byte value stores zero.
48362 ** This routine makes the necessary adjustment to 65536.
48363 */
48364 #define get2byteNotZero(X) (((((int)get2byte(X))-1)&0xffff)+1)
48365
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
48366 #ifndef SQLITE_OMIT_SHARED_CACHE
48367 /*
48368 ** A list of BtShared objects that are eligible for participation
48369 ** in shared cache. This variable has file scope during normal builds,
48370 ** but the test harness needs to access it so we make it global for
@@ -50913,10 +50978,11 @@
50913 ** is requested, this is a no-op.
50914 */
50915 if( p->inTrans==TRANS_WRITE || (p->inTrans==TRANS_READ && !wrflag) ){
50916 goto trans_begun;
50917 }
 
50918
50919 /* Write transactions are not possible on a read-only database */
50920 if( (pBt->btsFlags & BTS_READ_ONLY)!=0 && wrflag ){
50921 rc = SQLITE_READONLY;
50922 goto trans_begun;
@@ -51229,28 +51295,27 @@
51229
51230 /* Forward declaration required by incrVacuumStep(). */
51231 static int allocateBtreePage(BtShared *, MemPage **, Pgno *, Pgno, u8);
51232
51233 /*
51234 ** Perform a single step of an incremental-vacuum. If successful,
51235 ** return SQLITE_OK. If there is no work to do (and therefore no
51236 ** point in calling this function again), return SQLITE_DONE.
51237 **
51238 ** More specificly, this function attempts to re-organize the
51239 ** database so that the last page of the file currently in use
51240 ** is no longer in use.
51241 **
51242 ** If the nFin parameter is non-zero, this function assumes
51243 ** that the caller will keep calling incrVacuumStep() until
51244 ** it returns SQLITE_DONE or an error, and that nFin is the
51245 ** number of pages the database file will contain after this
51246 ** process is complete. If nFin is zero, it is assumed that
51247 ** incrVacuumStep() will be called a finite amount of times
51248 ** which may or may not empty the freelist. A full autovacuum
51249 ** has nFin>0. A "PRAGMA incremental_vacuum" has nFin==0.
51250 */
51251 static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg){
51252 Pgno nFreeList; /* Number of pages still on the free-list */
51253 int rc;
51254
51255 assert( sqlite3_mutex_held(pBt->mutex) );
51256 assert( iLastPg>nFin );
@@ -51271,85 +51336,98 @@
51271 if( eType==PTRMAP_ROOTPAGE ){
51272 return SQLITE_CORRUPT_BKPT;
51273 }
51274
51275 if( eType==PTRMAP_FREEPAGE ){
51276 if( nFin==0 ){
51277 /* Remove the page from the files free-list. This is not required
51278 ** if nFin is non-zero. In that case, the free-list will be
51279 ** truncated to zero after this function returns, so it doesn't
51280 ** matter if it still contains some garbage entries.
51281 */
51282 Pgno iFreePg;
51283 MemPage *pFreePg;
51284 rc = allocateBtreePage(pBt, &pFreePg, &iFreePg, iLastPg, 1);
51285 if( rc!=SQLITE_OK ){
51286 return rc;
51287 }
51288 assert( iFreePg==iLastPg );
51289 releasePage(pFreePg);
51290 }
51291 } else {
51292 Pgno iFreePg; /* Index of free page to move pLastPg to */
51293 MemPage *pLastPg;
 
 
51294
51295 rc = btreeGetPage(pBt, iLastPg, &pLastPg, 0);
51296 if( rc!=SQLITE_OK ){
51297 return rc;
51298 }
51299
51300 /* If nFin is zero, this loop runs exactly once and page pLastPg
51301 ** is swapped with the first free page pulled off the free list.
51302 **
51303 ** On the other hand, if nFin is greater than zero, then keep
51304 ** looping until a free-page located within the first nFin pages
51305 ** of the file is found.
51306 */
 
 
 
 
51307 do {
51308 MemPage *pFreePg;
51309 rc = allocateBtreePage(pBt, &pFreePg, &iFreePg, 0, 0);
51310 if( rc!=SQLITE_OK ){
51311 releasePage(pLastPg);
51312 return rc;
51313 }
51314 releasePage(pFreePg);
51315 }while( nFin!=0 && iFreePg>nFin );
51316 assert( iFreePg<iLastPg );
51317
51318 rc = sqlite3PagerWrite(pLastPg->pDbPage);
51319 if( rc==SQLITE_OK ){
51320 rc = relocatePage(pBt, pLastPg, eType, iPtrPage, iFreePg, nFin!=0);
51321 }
51322 releasePage(pLastPg);
51323 if( rc!=SQLITE_OK ){
51324 return rc;
51325 }
51326 }
51327 }
51328
51329 if( nFin==0 ){
51330 iLastPg--;
51331 while( iLastPg==PENDING_BYTE_PAGE(pBt)||PTRMAP_ISPAGE(pBt, iLastPg) ){
51332 if( PTRMAP_ISPAGE(pBt, iLastPg) ){
51333 MemPage *pPg;
51334 rc = btreeGetPage(pBt, iLastPg, &pPg, 0);
51335 if( rc!=SQLITE_OK ){
51336 return rc;
51337 }
51338 rc = sqlite3PagerWrite(pPg->pDbPage);
51339 releasePage(pPg);
51340 if( rc!=SQLITE_OK ){
51341 return rc;
51342 }
51343 }
51344 iLastPg--;
51345 }
51346 sqlite3PagerTruncateImage(pBt->pPager, iLastPg);
51347 pBt->nPage = iLastPg;
51348 }
51349 return SQLITE_OK;
51350 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
51351
51352 /*
51353 ** A write-transaction must be opened before calling this function.
51354 ** It performs a single unit of work towards an incremental vacuum.
51355 **
@@ -51364,15 +51442,25 @@
51364 sqlite3BtreeEnter(p);
51365 assert( pBt->inTransaction==TRANS_WRITE && p->inTrans==TRANS_WRITE );
51366 if( !pBt->autoVacuum ){
51367 rc = SQLITE_DONE;
51368 }else{
51369 invalidateAllOverflowCache(pBt);
51370 rc = incrVacuumStep(pBt, 0, btreePagecount(pBt));
51371 if( rc==SQLITE_OK ){
51372 rc = sqlite3PagerWrite(pBt->pPage1->pDbPage);
51373 put4byte(&pBt->pPage1->aData[28], pBt->nPage);
 
 
 
 
 
 
 
 
 
 
51374 }
51375 }
51376 sqlite3BtreeLeave(p);
51377 return rc;
51378 }
@@ -51395,13 +51483,11 @@
51395 invalidateAllOverflowCache(pBt);
51396 assert(pBt->autoVacuum);
51397 if( !pBt->incrVacuum ){
51398 Pgno nFin; /* Number of pages in database after autovacuuming */
51399 Pgno nFree; /* Number of pages on the freelist initially */
51400 Pgno nPtrmap; /* Number of PtrMap pages to be freed */
51401 Pgno iFree; /* The next page to be freed */
51402 int nEntry; /* Number of entries on one ptrmap page */
51403 Pgno nOrig; /* Database size before freeing */
51404
51405 nOrig = btreePagecount(pBt);
51406 if( PTRMAP_ISPAGE(pBt, nOrig) || nOrig==PENDING_BYTE_PAGE(pBt) ){
51407 /* It is not possible to create a database for which the final page
@@ -51410,30 +51496,22 @@
51410 */
51411 return SQLITE_CORRUPT_BKPT;
51412 }
51413
51414 nFree = get4byte(&pBt->pPage1->aData[36]);
51415 nEntry = pBt->usableSize/5;
51416 nPtrmap = (nFree-nOrig+PTRMAP_PAGENO(pBt, nOrig)+nEntry)/nEntry;
51417 nFin = nOrig - nFree - nPtrmap;
51418 if( nOrig>PENDING_BYTE_PAGE(pBt) && nFin<PENDING_BYTE_PAGE(pBt) ){
51419 nFin--;
51420 }
51421 while( PTRMAP_ISPAGE(pBt, nFin) || nFin==PENDING_BYTE_PAGE(pBt) ){
51422 nFin--;
51423 }
51424 if( nFin>nOrig ) return SQLITE_CORRUPT_BKPT;
51425
51426 for(iFree=nOrig; iFree>nFin && rc==SQLITE_OK; iFree--){
51427 rc = incrVacuumStep(pBt, nFin, iFree);
51428 }
51429 if( (rc==SQLITE_DONE || rc==SQLITE_OK) && nFree>0 ){
51430 rc = sqlite3PagerWrite(pBt->pPage1->pDbPage);
51431 put4byte(&pBt->pPage1->aData[32], 0);
51432 put4byte(&pBt->pPage1->aData[36], 0);
51433 put4byte(&pBt->pPage1->aData[28], nFin);
51434 sqlite3PagerTruncateImage(pBt->pPager, nFin);
51435 pBt->nPage = nFin;
51436 }
51437 if( rc!=SQLITE_OK ){
51438 sqlite3PagerRollback(pPager);
51439 }
@@ -51484,10 +51562,13 @@
51484 if( rc!=SQLITE_OK ){
51485 sqlite3BtreeLeave(p);
51486 return rc;
51487 }
51488 }
 
 
 
51489 #endif
51490 rc = sqlite3PagerCommitPhaseOne(pBt->pPager, zMaster, 0);
51491 sqlite3BtreeLeave(p);
51492 }
51493 return rc;
@@ -51499,10 +51580,13 @@
51499 */
51500 static void btreeEndTransaction(Btree *p){
51501 BtShared *pBt = p->pBt;
51502 assert( sqlite3BtreeHoldsMutex(p) );
51503
 
 
 
51504 btreeClearHasContent(pBt);
51505 if( p->inTrans>TRANS_NONE && p->db->activeVdbeCnt>1 ){
51506 /* If there are other active statements that belong to this database
51507 ** handle, downgrade to a read-only transaction. The other statements
51508 ** may still be reading from the database. */
@@ -53171,25 +53255,27 @@
53171 **
53172 ** SQLITE_OK is returned on success. Any other return value indicates
53173 ** an error. *ppPage and *pPgno are undefined in the event of an error.
53174 ** Do not invoke sqlite3PagerUnref() on *ppPage if an error is returned.
53175 **
53176 ** If the "nearby" parameter is not 0, then a (feeble) effort is made to
53177 ** locate a page close to the page number "nearby". This can be used in an
53178 ** attempt to keep related pages close to each other in the database file,
53179 ** which in turn can make database access faster.
53180 **
53181 ** If the "exact" parameter is not 0, and the page-number nearby exists
53182 ** anywhere on the free-list, then it is guarenteed to be returned. This
53183 ** is only used by auto-vacuum databases when allocating a new table.
 
 
53184 */
53185 static int allocateBtreePage(
53186 BtShared *pBt,
53187 MemPage **ppPage,
53188 Pgno *pPgno,
53189 Pgno nearby,
53190 u8 exact
53191 ){
53192 MemPage *pPage1;
53193 int rc;
53194 u32 n; /* Number of pages on the freelist */
53195 u32 k; /* Number of leaves on the trunk of the freelist */
@@ -53196,10 +53282,11 @@
53196 MemPage *pTrunk = 0;
53197 MemPage *pPrevTrunk = 0;
53198 Pgno mxPage; /* Total size of the database file */
53199
53200 assert( sqlite3_mutex_held(pBt->mutex) );
 
53201 pPage1 = pBt->pPage1;
53202 mxPage = btreePagecount(pBt);
53203 n = get4byte(&pPage1->aData[36]);
53204 testcase( n==mxPage-1 );
53205 if( n>=mxPage ){
@@ -53208,25 +53295,28 @@
53208 if( n>0 ){
53209 /* There are pages on the freelist. Reuse one of those pages. */
53210 Pgno iTrunk;
53211 u8 searchList = 0; /* If the free-list must be searched for 'nearby' */
53212
53213 /* If the 'exact' parameter was true and a query of the pointer-map
53214 ** shows that the page 'nearby' is somewhere on the free-list, then
53215 ** the entire-list will be searched for that page.
53216 */
53217 #ifndef SQLITE_OMIT_AUTOVACUUM
53218 if( exact && nearby<=mxPage ){
53219 u8 eType;
53220 assert( nearby>0 );
53221 assert( pBt->autoVacuum );
53222 rc = ptrmapGet(pBt, nearby, &eType, 0);
53223 if( rc ) return rc;
53224 if( eType==PTRMAP_FREEPAGE ){
53225 searchList = 1;
53226 }
53227 *pPgno = nearby;
 
 
 
53228 }
53229 #endif
53230
53231 /* Decrement the free-list count by 1. Set iTrunk to the index of the
53232 ** first free-list trunk page. iPrevTrunk is initially 1.
@@ -53235,11 +53325,12 @@
53235 if( rc ) return rc;
53236 put4byte(&pPage1->aData[36], n-1);
53237
53238 /* The code within this loop is run only once if the 'searchList' variable
53239 ** is not true. Otherwise, it runs once for each trunk-page on the
53240 ** free-list until the page 'nearby' is located.
 
53241 */
53242 do {
53243 pPrevTrunk = pTrunk;
53244 if( pPrevTrunk ){
53245 iTrunk = get4byte(&pPrevTrunk->aData[0]);
@@ -53277,15 +53368,17 @@
53277 }else if( k>(u32)(pBt->usableSize/4 - 2) ){
53278 /* Value of k is out of range. Database corruption */
53279 rc = SQLITE_CORRUPT_BKPT;
53280 goto end_allocate_page;
53281 #ifndef SQLITE_OMIT_AUTOVACUUM
53282 }else if( searchList && nearby==iTrunk ){
 
 
53283 /* The list is being searched and this trunk page is the page
53284 ** to allocate, regardless of whether it has leaves.
53285 */
53286 assert( *pPgno==iTrunk );
53287 *ppPage = pTrunk;
53288 searchList = 0;
53289 rc = sqlite3PagerWrite(pTrunk->pDbPage);
53290 if( rc ){
53291 goto end_allocate_page;
@@ -53344,18 +53437,28 @@
53344 u32 closest;
53345 Pgno iPage;
53346 unsigned char *aData = pTrunk->aData;
53347 if( nearby>0 ){
53348 u32 i;
53349 int dist;
53350 closest = 0;
53351 dist = sqlite3AbsInt32(get4byte(&aData[8]) - nearby);
53352 for(i=1; i<k; i++){
53353 int d2 = sqlite3AbsInt32(get4byte(&aData[8+i*4]) - nearby);
53354 if( d2<dist ){
53355 closest = i;
53356 dist = d2;
 
 
 
 
 
 
 
 
 
 
 
53357 }
53358 }
53359 }else{
53360 closest = 0;
53361 }
@@ -53365,11 +53468,13 @@
53365 if( iPage>mxPage ){
53366 rc = SQLITE_CORRUPT_BKPT;
53367 goto end_allocate_page;
53368 }
53369 testcase( iPage==mxPage );
53370 if( !searchList || iPage==nearby ){
 
 
53371 int noContent;
53372 *pPgno = iPage;
53373 TRACE(("ALLOCATE: %d was leaf %d of %d on trunk %d"
53374 ": %d more free pages\n",
53375 *pPgno, closest+1, k, pTrunk->pgno, n-1));
@@ -53392,12 +53497,30 @@
53392 }
53393 releasePage(pPrevTrunk);
53394 pPrevTrunk = 0;
53395 }while( searchList );
53396 }else{
53397 /* There are no pages on the freelist, so create a new page at the
53398 ** end of the file */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53399 rc = sqlite3PagerWrite(pBt->pPage1->pDbPage);
53400 if( rc ) return rc;
53401 pBt->nPage++;
53402 if( pBt->nPage==PENDING_BYTE_PAGE(pBt) ) pBt->nPage++;
53403
@@ -53408,11 +53531,11 @@
53408 ** becomes a new pointer-map page, the second is used by the caller.
53409 */
53410 MemPage *pPg = 0;
53411 TRACE(("ALLOCATE: %d from end of file (pointer-map page)\n", pBt->nPage));
53412 assert( pBt->nPage!=PENDING_BYTE_PAGE(pBt) );
53413 rc = btreeGetPage(pBt, pBt->nPage, &pPg, 1);
53414 if( rc==SQLITE_OK ){
53415 rc = sqlite3PagerWrite(pPg->pDbPage);
53416 releasePage(pPg);
53417 }
53418 if( rc ) return rc;
@@ -53422,11 +53545,11 @@
53422 #endif
53423 put4byte(28 + (u8*)pBt->pPage1->aData, pBt->nPage);
53424 *pPgno = pBt->nPage;
53425
53426 assert( *pPgno!=PENDING_BYTE_PAGE(pBt) );
53427 rc = btreeGetPage(pBt, *pPgno, ppPage, 1);
53428 if( rc ) return rc;
53429 rc = sqlite3PagerWrite((*ppPage)->pDbPage);
53430 if( rc!=SQLITE_OK ){
53431 releasePage(*ppPage);
53432 }
@@ -55437,11 +55560,11 @@
55437
55438 /* Allocate a page. The page that currently resides at pgnoRoot will
55439 ** be moved to the allocated page (unless the allocated page happens
55440 ** to reside at pgnoRoot).
55441 */
55442 rc = allocateBtreePage(pBt, &pPageMove, &pgnoMove, pgnoRoot, 1);
55443 if( rc!=SQLITE_OK ){
55444 return rc;
55445 }
55446
55447 if( pgnoMove!=pgnoRoot ){
@@ -57129,11 +57252,10 @@
57129 }
57130 }else{
57131 nDestTruncate = nSrcPage * (pgszSrc/pgszDest);
57132 }
57133 assert( nDestTruncate>0 );
57134 sqlite3PagerTruncateImage(pDestPager, nDestTruncate);
57135
57136 if( pgszSrc<pgszDest ){
57137 /* If the source page-size is smaller than the destination page-size,
57138 ** two extra things may need to happen:
57139 **
@@ -57143,10 +57265,12 @@
57143 ** pending-byte page in the source database may need to be
57144 ** copied into the destination database.
57145 */
57146 const i64 iSize = (i64)pgszSrc * (i64)nSrcPage;
57147 sqlite3_file * const pFile = sqlite3PagerFile(pDestPager);
 
 
57148 i64 iOff;
57149 i64 iEnd;
57150
57151 assert( pFile );
57152 assert( nDestTruncate==0
@@ -57153,17 +57277,30 @@
57153 || (i64)nDestTruncate*(i64)pgszDest >= iSize || (
57154 nDestTruncate==(int)(PENDING_BYTE_PAGE(p->pDest->pBt)-1)
57155 && iSize>=PENDING_BYTE && iSize<=PENDING_BYTE+pgszDest
57156 ));
57157
57158 /* This call ensures that all data required to recreate the original
57159 ** database has been stored in the journal for pDestPager and the
57160 ** journal synced to disk. So at this point we may safely modify
57161 ** the database file in any way, knowing that if a power failure
57162 ** occurs, the original database will be reconstructed from the
57163 ** journal file. */
57164 rc = sqlite3PagerCommitPhaseOne(pDestPager, 0, 1);
 
 
 
 
 
 
 
 
 
 
 
 
 
57165
57166 /* Write the extra pages and truncate the database file as required */
57167 iEnd = MIN(PENDING_BYTE + pgszDest, iSize);
57168 for(
57169 iOff=PENDING_BYTE+pgszSrc;
@@ -57186,10 +57323,11 @@
57186 /* Sync the database file to disk. */
57187 if( rc==SQLITE_OK ){
57188 rc = sqlite3PagerSync(pDestPager);
57189 }
57190 }else{
 
57191 rc = sqlite3PagerCommitPhaseOne(pDestPager, 0, 0);
57192 }
57193
57194 /* Finish committing the transaction to the destination database. */
57195 if( SQLITE_OK==rc
@@ -57437,11 +57575,13 @@
57437 ** SQLITE_OK is returned if the conversion is successful (or not required).
57438 ** SQLITE_NOMEM may be returned if a malloc() fails during conversion
57439 ** between formats.
57440 */
57441 SQLITE_PRIVATE int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){
 
57442 int rc;
 
57443 assert( (pMem->flags&MEM_RowSet)==0 );
57444 assert( desiredEnc==SQLITE_UTF8 || desiredEnc==SQLITE_UTF16LE
57445 || desiredEnc==SQLITE_UTF16BE );
57446 if( !(pMem->flags&MEM_Str) || pMem->enc==desiredEnc ){
57447 return SQLITE_OK;
@@ -58582,22 +58722,10 @@
58582 ** a VDBE (or an "sqlite3_stmt" as it is known to the outside world.) Prior
58583 ** to version 2.8.7, all this code was combined into the vdbe.c source file.
58584 ** But that file was getting too big so this subroutines were split out.
58585 */
58586
58587
58588
58589 /*
58590 ** When debugging the code generator in a symbolic debugger, one can
58591 ** set the sqlite3VdbeAddopTrace to 1 and all opcodes will be printed
58592 ** as they are added to the instruction stream.
58593 */
58594 #ifdef SQLITE_DEBUG
58595 SQLITE_PRIVATE int sqlite3VdbeAddopTrace = 0;
58596 #endif
58597
58598
58599 /*
58600 ** Create a new virtual database engine.
58601 */
58602 SQLITE_PRIVATE Vdbe *sqlite3VdbeCreate(sqlite3 *db){
58603 Vdbe *p;
@@ -58723,11 +58851,13 @@
58723 pOp->p3 = p3;
58724 pOp->p4.p = 0;
58725 pOp->p4type = P4_NOTUSED;
58726 #ifdef SQLITE_DEBUG
58727 pOp->zComment = 0;
58728 if( sqlite3VdbeAddopTrace ) sqlite3VdbePrintOp(0, i, &p->aOp[i]);
 
 
58729 #endif
58730 #ifdef VDBE_PROFILE
58731 pOp->cycles = 0;
58732 pOp->cnt = 0;
58733 #endif
@@ -58942,11 +59072,11 @@
58942 if( opcode==OP_Destroy || opcode==OP_VUpdate || opcode==OP_VRename
58943 #ifndef SQLITE_OMIT_FOREIGN_KEY
58944 || (opcode==OP_FkCounter && pOp->p1==0 && pOp->p2==1)
58945 #endif
58946 || ((opcode==OP_Halt || opcode==OP_HaltIfNull)
58947 && (pOp->p1==SQLITE_CONSTRAINT && pOp->p2==OE_Abort))
58948 ){
58949 hasAbort = 1;
58950 break;
58951 }
58952 }
@@ -59077,11 +59207,11 @@
59077 pOut->p4type = P4_NOTUSED;
59078 pOut->p4.p = 0;
59079 pOut->p5 = 0;
59080 #ifdef SQLITE_DEBUG
59081 pOut->zComment = 0;
59082 if( sqlite3VdbeAddopTrace ){
59083 sqlite3VdbePrintOp(0, i+addr, &p->aOp[i+addr]);
59084 }
59085 #endif
59086 }
59087 p->nOp += nOp;
@@ -60103,11 +60233,11 @@
60103 }
60104 zCsr = p->pFree;
60105 zEnd = &zCsr[nByte];
60106 }while( nByte && !db->mallocFailed );
60107
60108 p->nCursor = (u16)nCursor;
60109 p->nOnceFlag = nOnce;
60110 if( p->aVar ){
60111 p->nVar = (ynVar)nVar;
60112 for(n=0; n<nVar; n++){
60113 p->aVar[n].flags = MEM_Null;
@@ -60345,11 +60475,11 @@
60345
60346 /* If there are any write-transactions at all, invoke the commit hook */
60347 if( needXcommit && db->xCommitCallback ){
60348 rc = db->xCommitCallback(db->pCommitArg);
60349 if( rc ){
60350 return SQLITE_CONSTRAINT;
60351 }
60352 }
60353
60354 /* The simple case - no more than one database file (not counting the
60355 ** TEMP database) has a transaction active. There is no need for the
@@ -60637,18 +60767,18 @@
60637 ** handle associated with the VM passed as an argument is about to be
60638 ** committed. If there are outstanding deferred foreign key constraint
60639 ** violations, return SQLITE_ERROR. Otherwise, SQLITE_OK.
60640 **
60641 ** If there are outstanding FK violations and this function returns
60642 ** SQLITE_ERROR, set the result of the VM to SQLITE_CONSTRAINT and write
60643 ** an error message to it. Then return SQLITE_ERROR.
60644 */
60645 #ifndef SQLITE_OMIT_FOREIGN_KEY
60646 SQLITE_PRIVATE int sqlite3VdbeCheckFk(Vdbe *p, int deferred){
60647 sqlite3 *db = p->db;
60648 if( (deferred && db->nDeferredCons>0) || (!deferred && p->nFkConstraint>0) ){
60649 p->rc = SQLITE_CONSTRAINT;
60650 p->errorAction = OE_Abort;
60651 sqlite3SetString(&p->zErrMsg, db, "foreign key constraint failed");
60652 return SQLITE_ERROR;
60653 }
60654 return SQLITE_OK;
@@ -60759,11 +60889,11 @@
60759 if( rc!=SQLITE_OK ){
60760 if( NEVER(p->readOnly) ){
60761 sqlite3VdbeLeave(p);
60762 return SQLITE_ERROR;
60763 }
60764 rc = SQLITE_CONSTRAINT;
60765 }else{
60766 /* The auto-commit flag is true, the vdbe program was successful
60767 ** or hit an 'OR FAIL' constraint and there are no deferred foreign
60768 ** key constraints to hold up the transaction. This means a commit
60769 ** is required. */
@@ -60802,11 +60932,11 @@
60802 ** current statement error code.
60803 */
60804 if( eStatementOp ){
60805 rc = sqlite3VdbeCloseStatement(p, eStatementOp);
60806 if( rc ){
60807 if( p->rc==SQLITE_OK || p->rc==SQLITE_CONSTRAINT ){
60808 p->rc = rc;
60809 sqlite3DbFree(db, p->zErrMsg);
60810 p->zErrMsg = 0;
60811 }
60812 sqlite3RollbackAll(db, SQLITE_ABORT_ROLLBACK);
@@ -61043,11 +61173,11 @@
61043 sqlite3DbFree(db, p->aLabel);
61044 sqlite3DbFree(db, p->aColName);
61045 sqlite3DbFree(db, p->zSql);
61046 sqlite3DbFree(db, p->pFree);
61047 #if defined(SQLITE_ENABLE_TREE_EXPLAIN)
61048 sqlite3_free(p->zExplain);
61049 sqlite3DbFree(db, p->pExplain);
61050 #endif
61051 }
61052
61053 /*
@@ -63025,11 +63155,11 @@
63025 return 0;
63026 }
63027 if( zName ){
63028 for(i=0; i<p->nzVar; i++){
63029 const char *z = p->azVar[i];
63030 if( z && memcmp(z,zName,nName)==0 && z[nName]==0 ){
63031 return i+1;
63032 }
63033 }
63034 }
63035 return 0;
@@ -64799,11 +64929,11 @@
64799 rc = sqlite3VdbeHalt(p);
64800 assert( rc==SQLITE_BUSY || rc==SQLITE_OK || rc==SQLITE_ERROR );
64801 if( rc==SQLITE_BUSY ){
64802 p->rc = rc = SQLITE_BUSY;
64803 }else{
64804 assert( rc==SQLITE_OK || p->rc==SQLITE_CONSTRAINT );
64805 assert( rc==SQLITE_OK || db->nDeferredCons>0 );
64806 rc = p->rc ? SQLITE_ERROR : SQLITE_DONE;
64807 }
64808 goto vdbe_return;
64809 }
@@ -70131,11 +70261,11 @@
70131 importVtabErrMsg(p, u.cr.pVtab);
70132 if( rc==SQLITE_OK && pOp->p1 ){
70133 assert( u.cr.nArg>1 && u.cr.apArg[0] && (u.cr.apArg[0]->flags&MEM_Null) );
70134 db->lastRowid = lastRowid = u.cr.rowid;
70135 }
70136 if( rc==SQLITE_CONSTRAINT && pOp->p4.pVtab->bConstraint ){
70137 if( pOp->p5==OE_Ignore ){
70138 rc = SQLITE_OK;
70139 }else{
70140 p->errorAction = ((pOp->p5==OE_Replace) ? OE_Abort : pOp->p5);
70141 }
@@ -72677,16 +72807,16 @@
72677 const char *zTab,
72678 const char *zDb
72679 ){
72680 int n;
72681 for(n=0; ALWAYS(zSpan[n]) && zSpan[n]!='.'; n++){}
72682 if( zDb && sqlite3StrNICmp(zSpan, zDb, n)!=0 ){
72683 return 0;
72684 }
72685 zSpan += n+1;
72686 for(n=0; ALWAYS(zSpan[n]) && zSpan[n]!='.'; n++){}
72687 if( zTab && sqlite3StrNICmp(zSpan, zTab, n)!=0 ){
72688 return 0;
72689 }
72690 zSpan += n+1;
72691 if( zCol && sqlite3StrICmp(zSpan, zCol)!=0 ){
72692 return 0;
@@ -72775,12 +72905,12 @@
72775
72776 pTab = pItem->pTab;
72777 assert( pTab!=0 && pTab->zName!=0 );
72778 assert( pTab->nCol>0 );
72779 if( pItem->pSelect && (pItem->pSelect->selFlags & SF_NestedFrom)!=0 ){
72780 ExprList *pEList = pItem->pSelect->pEList;
72781 int hit = 0;
 
72782 for(j=0; j<pEList->nExpr; j++){
72783 if( sqlite3MatchSpanName(pEList->a[j].zSpan, zCol, zTab, zDb) ){
72784 cnt++;
72785 cntTab = 2;
72786 pMatch = pItem;
@@ -74479,11 +74609,11 @@
74479 ** number as the prior appearance of the same name, or if the name
74480 ** has never appeared before, reuse the same variable number
74481 */
74482 ynVar i;
74483 for(i=0; i<pParse->nzVar; i++){
74484 if( pParse->azVar[i] && memcmp(pParse->azVar[i],z,n+1)==0 ){
74485 pExpr->iColumn = x = (ynVar)i+1;
74486 break;
74487 }
74488 }
74489 if( x==0 ) x = pExpr->iColumn = (ynVar)(++pParse->nVar);
@@ -75297,14 +75427,15 @@
75297 ** A cursor is opened on the b-tree object that the RHS of the IN operator
75298 ** and pX->iTable is set to the index of that cursor.
75299 **
75300 ** The returned value of this function indicates the b-tree type, as follows:
75301 **
75302 ** IN_INDEX_ROWID - The cursor was opened on a database table.
75303 ** IN_INDEX_INDEX - The cursor was opened on a database index.
75304 ** IN_INDEX_EPH - The cursor was opened on a specially created and
75305 ** populated epheremal table.
 
75306 **
75307 ** An existing b-tree might be used if the RHS expression pX is a simple
75308 ** subquery such as:
75309 **
75310 ** SELECT <column> FROM <table>
@@ -75423,11 +75554,12 @@
75423 iAddr = sqlite3CodeOnce(pParse);
75424
75425 sqlite3VdbeAddOp4(v, OP_OpenRead, iTab, pIdx->tnum, iDb,
75426 pKey,P4_KEYINFO_HANDOFF);
75427 VdbeComment((v, "%s", pIdx->zName));
75428 eType = IN_INDEX_INDEX;
 
75429
75430 sqlite3VdbeJumpHere(v, iAddr);
75431 if( prNotFound && !pTab->aCol[iCol].notNull ){
75432 *prNotFound = ++pParse->nMem;
75433 sqlite3VdbeAddOp2(v, OP_Null, 0, *prNotFound);
@@ -76776,11 +76908,12 @@
76776 assert( !ExprHasProperty(pExpr, EP_IntValue) );
76777 if( pExpr->affinity==OE_Ignore ){
76778 sqlite3VdbeAddOp4(
76779 v, OP_Halt, SQLITE_OK, OE_Ignore, 0, pExpr->u.zToken,0);
76780 }else{
76781 sqlite3HaltConstraint(pParse, pExpr->affinity, pExpr->u.zToken, 0);
 
76782 }
76783
76784 break;
76785 }
76786 #endif
@@ -79335,11 +79468,11 @@
79335 }
79336 if( pTab->tnum==0 ){
79337 /* Do not gather statistics on views or virtual tables */
79338 return;
79339 }
79340 if( memcmp(pTab->zName, "sqlite_", 7)==0 ){
79341 /* Do not gather statistics on system tables */
79342 return;
79343 }
79344 assert( sqlite3BtreeHoldsAllMutexes(db) );
79345 iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
@@ -79745,11 +79878,11 @@
79745 }
79746 if( i==0 ) pTable->nRowEst = v;
79747 if( pIndex==0 ) break;
79748 pIndex->aiRowEst[i] = v;
79749 if( *z==' ' ) z++;
79750 if( memcmp(z, "unordered", 10)==0 ){
79751 pIndex->bUnordered = 1;
79752 break;
79753 }
79754 }
79755 return 0;
@@ -83247,12 +83380,12 @@
83247 if( pIndex->onError!=OE_None ){
83248 int j2 = sqlite3VdbeCurrentAddr(v) + 3;
83249 sqlite3VdbeAddOp2(v, OP_Goto, 0, j2);
83250 addr2 = sqlite3VdbeCurrentAddr(v);
83251 sqlite3VdbeAddOp3(v, OP_SorterCompare, iSorter, j2, regRecord);
83252 sqlite3HaltConstraint(
83253 pParse, OE_Abort, "indexed columns are not unique", P4_STATIC
83254 );
83255 }else{
83256 addr2 = sqlite3VdbeCurrentAddr(v);
83257 }
83258 sqlite3VdbeAddOp2(v, OP_SorterData, iSorter, regRecord);
@@ -83274,12 +83407,12 @@
83274 ** opcode use the values stored within seems dangerous. However, since
83275 ** we can be sure that no other temp registers have been allocated
83276 ** since sqlite3ReleaseTempRange() was called, it is safe to do so.
83277 */
83278 sqlite3VdbeAddOp4(v, OP_IsUnique, iIdx, j2, regRowid, pRegKey, P4_INT32);
83279 sqlite3HaltConstraint(
83280 pParse, OE_Abort, "indexed columns are not unique", P4_STATIC);
83281 }
83282 sqlite3VdbeAddOp3(v, OP_IdxInsert, iIdx, regRecord, 0);
83283 sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
83284 #endif
83285 sqlite3ReleaseTempReg(pParse, regRecord);
@@ -83394,11 +83527,11 @@
83394 pDb = &db->aDb[iDb];
83395
83396 assert( pTab!=0 );
83397 assert( pParse->nErr==0 );
83398 if( sqlite3StrNICmp(pTab->zName, "sqlite_", 7)==0
83399 && memcmp(&pTab->zName[7],"altertab_",9)!=0 ){
83400 sqlite3ErrorMsg(pParse, "table %s may not be indexed", pTab->zName);
83401 goto exit_create_index;
83402 }
83403 #ifndef SQLITE_OMIT_VIEW
83404 if( pTab->pSelect ){
@@ -84492,16 +84625,23 @@
84492 /*
84493 ** Code an OP_Halt that causes the vdbe to return an SQLITE_CONSTRAINT
84494 ** error. The onError parameter determines which (if any) of the statement
84495 ** and/or current transaction is rolled back.
84496 */
84497 SQLITE_PRIVATE void sqlite3HaltConstraint(Parse *pParse, int onError, char *p4, int p4type){
 
 
 
 
 
 
84498 Vdbe *v = sqlite3GetVdbe(pParse);
 
84499 if( onError==OE_Abort ){
84500 sqlite3MayAbort(pParse);
84501 }
84502 sqlite3VdbeAddOp4(v, OP_Halt, SQLITE_CONSTRAINT, onError, 0, p4, p4type);
84503 }
84504
84505 /*
84506 ** Check to see if pIndex uses the collating sequence pColl. Return
84507 ** true if it does and false if it does not.
@@ -85242,34 +85382,32 @@
85242 Table *pView, /* View definition */
85243 Expr *pWhere, /* Optional WHERE clause to be added */
85244 int iCur /* Cursor number for ephemerial table */
85245 ){
85246 SelectDest dest;
85247 Select *pDup;
 
85248 sqlite3 *db = pParse->db;
85249
85250 pDup = sqlite3SelectDup(db, pView->pSelect, 0);
85251 if( pWhere ){
85252 SrcList *pFrom;
85253
85254 pWhere = sqlite3ExprDup(db, pWhere, 0);
85255 pFrom = sqlite3SrcListAppend(db, 0, 0, 0);
85256 if( pFrom ){
85257 assert( pFrom->nSrc==1 );
85258 pFrom->a[0].zAlias = sqlite3DbStrDup(db, pView->zName);
85259 pFrom->a[0].pSelect = pDup;
85260 assert( pFrom->a[0].pOn==0 );
85261 assert( pFrom->a[0].pUsing==0 );
85262 }else{
85263 sqlite3SelectDelete(db, pDup);
85264 }
85265 pDup = sqlite3SelectNew(pParse, 0, pFrom, pWhere, 0, 0, 0, 0, 0, 0);
85266 if( pDup ) pDup->selFlags |= SF_Materialize;
85267 }
85268 sqlite3SelectDestInit(&dest, SRT_EphemTab, iCur);
85269 sqlite3Select(pParse, pDup, &dest);
85270 sqlite3SelectDelete(db, pDup);
85271 }
85272 #endif /* !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER) */
85273
85274 #if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) && !defined(SQLITE_OMIT_SUBQUERY)
85275 /*
@@ -86765,10 +86903,66 @@
86765 sqlite3_result_text(context, "NULL", 4, SQLITE_STATIC);
86766 break;
86767 }
86768 }
86769 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
86770
86771 /*
86772 ** The hex() function. Interpret the argument as a blob. Return
86773 ** a hexadecimal rendering as text.
86774 */
@@ -87393,10 +87587,12 @@
87393 FUNCTION2(typeof, 1, 0, 0, typeofFunc, SQLITE_FUNC_TYPEOF),
87394 FUNCTION2(length, 1, 0, 0, lengthFunc, SQLITE_FUNC_LENGTH),
87395 FUNCTION(instr, 2, 0, 0, instrFunc ),
87396 FUNCTION(substr, 2, 0, 0, substrFunc ),
87397 FUNCTION(substr, 3, 0, 0, substrFunc ),
 
 
87398 FUNCTION(abs, 1, 0, 0, absFunc ),
87399 #ifndef SQLITE_OMIT_FLOATING_POINT
87400 FUNCTION(round, 1, 0, 0, roundFunc ),
87401 FUNCTION(round, 2, 0, 0, roundFunc ),
87402 #endif
@@ -87484,12 +87680,13 @@
87484 /*
87485 ** Deferred and Immediate FKs
87486 ** --------------------------
87487 **
87488 ** Foreign keys in SQLite come in two flavours: deferred and immediate.
87489 ** If an immediate foreign key constraint is violated, SQLITE_CONSTRAINT
87490 ** is returned and the current statement transaction rolled back. If a
 
87491 ** deferred foreign key constraint is violated, no action is taken
87492 ** immediately. However if the application attempts to commit the
87493 ** transaction before fixing the constraint violation, the attempt fails.
87494 **
87495 ** Deferred constraints are implemented using a simple counter associated
@@ -87549,11 +87746,12 @@
87549 ** row is inserted.
87550 **
87551 ** Immediate constraints are usually handled similarly. The only difference
87552 ** is that the counter used is stored as part of each individual statement
87553 ** object (struct Vdbe). If, after the statement has run, its immediate
87554 ** constraint counter is greater than zero, it returns SQLITE_CONSTRAINT
 
87555 ** and the statement transaction is rolled back. An exception is an INSERT
87556 ** statement that inserts a single row only (no triggers). In this case,
87557 ** instead of using a counter, an exception is thrown immediately if the
87558 ** INSERT violates a foreign key constraint. This is necessary as such
87559 ** an INSERT does not open a statement transaction.
@@ -87889,12 +88087,12 @@
87889 /* Special case: If this is an INSERT statement that will insert exactly
87890 ** one row into the table, raise a constraint immediately instead of
87891 ** incrementing a counter. This is necessary as the VM code is being
87892 ** generated for will not open a statement transaction. */
87893 assert( nIncr==1 );
87894 sqlite3HaltConstraint(
87895 pParse, OE_Abort, "foreign key constraint failed", P4_STATIC
87896 );
87897 }else{
87898 if( nIncr>0 && pFKey->isDeferred==0 ){
87899 sqlite3ParseToplevel(pParse)->mayAbort = 1;
87900 }
@@ -88130,12 +88328,12 @@
88130 /* If the DELETE has generated immediate foreign key constraint
88131 ** violations, halt the VDBE and return an error at this point, before
88132 ** any modifications to the schema are made. This is because statement
88133 ** transactions are not able to rollback schema changes. */
88134 sqlite3VdbeAddOp2(v, OP_FkIfZero, 0, sqlite3VdbeCurrentAddr(v)+2);
88135 sqlite3HaltConstraint(
88136 pParse, OE_Abort, "foreign key constraint failed", P4_STATIC
88137 );
88138
88139 if( iSkip ){
88140 sqlite3VdbeResolveLabel(v, iSkip);
88141 }
@@ -89935,11 +90133,11 @@
89935 sqlite3MayAbort(pParse);
89936 case OE_Rollback:
89937 case OE_Fail: {
89938 char *zMsg;
89939 sqlite3VdbeAddOp3(v, OP_HaltIfNull,
89940 SQLITE_CONSTRAINT, onError, regData+i);
89941 zMsg = sqlite3MPrintf(db, "%s.%s may not be NULL",
89942 pTab->zName, pTab->aCol[i].zName);
89943 sqlite3VdbeChangeP4(v, -1, zMsg, P4_DYNAMIC);
89944 break;
89945 }
@@ -89975,11 +90173,12 @@
89975 if( zConsName ){
89976 zConsName = sqlite3MPrintf(db, "constraint %s failed", zConsName);
89977 }else{
89978 zConsName = 0;
89979 }
89980 sqlite3HaltConstraint(pParse, onError, zConsName, P4_DYNAMIC);
 
89981 }
89982 sqlite3VdbeResolveLabel(v, allOk);
89983 }
89984 }
89985 #endif /* !defined(SQLITE_OMIT_CHECK) */
@@ -90006,12 +90205,12 @@
90006 /* Fall thru into the next case */
90007 }
90008 case OE_Rollback:
90009 case OE_Abort:
90010 case OE_Fail: {
90011 sqlite3HaltConstraint(
90012 pParse, onError, "PRIMARY KEY must be unique", P4_STATIC);
90013 break;
90014 }
90015 case OE_Replace: {
90016 /* If there are DELETE triggers on this table and the
90017 ** recursive-triggers flag is set, call GenerateRowDelete() to
@@ -90134,11 +90333,12 @@
90134 sqlite3StrAccumAppend(&errMsg, zCol, -1);
90135 }
90136 sqlite3StrAccumAppend(&errMsg,
90137 pIdx->nColumn>1 ? " are not unique" : " is not unique", -1);
90138 zErr = sqlite3StrAccumFinish(&errMsg);
90139 sqlite3HaltConstraint(pParse, onError, zErr, 0);
 
90140 sqlite3DbFree(errMsg.db, zErr);
90141 break;
90142 }
90143 case OE_Ignore: {
90144 assert( seenReplace==0 );
@@ -90542,12 +90742,12 @@
90542 regData = sqlite3GetTempReg(pParse);
90543 regRowid = sqlite3GetTempReg(pParse);
90544 if( pDest->iPKey>=0 ){
90545 addr1 = sqlite3VdbeAddOp2(v, OP_Rowid, iSrc, regRowid);
90546 addr2 = sqlite3VdbeAddOp3(v, OP_NotExists, iDest, 0, regRowid);
90547 sqlite3HaltConstraint(
90548 pParse, onError, "PRIMARY KEY must be unique", P4_STATIC);
90549 sqlite3VdbeJumpHere(v, addr2);
90550 autoIncStep(pParse, regAutoinc, regRowid);
90551 }else if( pDest->pIndex==0 ){
90552 addr1 = sqlite3VdbeAddOp2(v, OP_NewRowid, iDest, regRowid);
90553 }else{
@@ -91000,10 +91200,24 @@
91000 int (*wal_checkpoint)(sqlite3*,const char*);
91001 void *(*wal_hook)(sqlite3*,int(*)(void*,sqlite3*,const char*,int),void*);
91002 int (*blob_reopen)(sqlite3_blob*,sqlite3_int64);
91003 int (*vtab_config)(sqlite3*,int op,...);
91004 int (*vtab_on_conflict)(sqlite3*);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
91005 };
91006
91007 /*
91008 ** The following macros redefine the API routines so that they are
91009 ** redirected throught the global sqlite3_api structure.
@@ -91203,10 +91417,24 @@
91203 #define sqlite3_wal_checkpoint sqlite3_api->wal_checkpoint
91204 #define sqlite3_wal_hook sqlite3_api->wal_hook
91205 #define sqlite3_blob_reopen sqlite3_api->blob_reopen
91206 #define sqlite3_vtab_config sqlite3_api->vtab_config
91207 #define sqlite3_vtab_on_conflict sqlite3_api->vtab_on_conflict
 
 
 
 
 
 
 
 
 
 
 
 
 
 
91208 #endif /* SQLITE_CORE */
91209
91210 #define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api = 0;
91211 #define SQLITE_EXTENSION_INIT2(v) sqlite3_api = v;
91212
@@ -91572,10 +91800,23 @@
91572 0,
91573 #endif
91574 sqlite3_blob_reopen,
91575 sqlite3_vtab_config,
91576 sqlite3_vtab_on_conflict,
 
 
 
 
 
 
 
 
 
 
 
 
 
91577 };
91578
91579 /*
91580 ** Attempt to load an SQLite extension library contained in the file
91581 ** zFile. The entry point is zProc. zProc may be 0 in which case a
@@ -92038,10 +92279,13 @@
92038 #endif
92039 #ifdef SQLITE_DEBUG
92040 { "sql_trace", SQLITE_SqlTrace },
92041 { "vdbe_listing", SQLITE_VdbeListing },
92042 { "vdbe_trace", SQLITE_VdbeTrace },
 
 
 
92043 #endif
92044 #ifndef SQLITE_OMIT_CHECK
92045 { "ignore_check_constraints", SQLITE_IgnoreChecks },
92046 #endif
92047 /* The following is VERY experimental */
@@ -92809,10 +93053,11 @@
92809 Column *pCol;
92810 Index *pPk;
92811 for(pPk=pTab->pIndex; pPk && pPk->autoIndex!=2; pPk=pPk->pNext){}
92812 sqlite3VdbeSetNumCols(v, 6);
92813 pParse->nMem = 6;
 
92814 sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "cid", SQLITE_STATIC);
92815 sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", SQLITE_STATIC);
92816 sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "type", SQLITE_STATIC);
92817 sqlite3VdbeSetColName(v, 3, COLNAME_NAME, "notnull", SQLITE_STATIC);
92818 sqlite3VdbeSetColName(v, 4, COLNAME_NAME, "dflt_value", SQLITE_STATIC);
@@ -92854,10 +93099,11 @@
92854 if( pIdx ){
92855 int i;
92856 pTab = pIdx->pTable;
92857 sqlite3VdbeSetNumCols(v, 3);
92858 pParse->nMem = 3;
 
92859 sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seqno", SQLITE_STATIC);
92860 sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "cid", SQLITE_STATIC);
92861 sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "name", SQLITE_STATIC);
92862 for(i=0; i<pIdx->nColumn; i++){
92863 int cnum = pIdx->aiColumn[i];
@@ -92880,10 +93126,11 @@
92880 pIdx = pTab->pIndex;
92881 if( pIdx ){
92882 int i = 0;
92883 sqlite3VdbeSetNumCols(v, 3);
92884 pParse->nMem = 3;
 
92885 sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seq", SQLITE_STATIC);
92886 sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", SQLITE_STATIC);
92887 sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "unique", SQLITE_STATIC);
92888 while(pIdx){
92889 sqlite3VdbeAddOp2(v, OP_Integer, i, 1);
@@ -92943,10 +93190,11 @@
92943 pFK = pTab->pFKey;
92944 if( pFK ){
92945 int i = 0;
92946 sqlite3VdbeSetNumCols(v, 8);
92947 pParse->nMem = 8;
 
92948 sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "id", SQLITE_STATIC);
92949 sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "seq", SQLITE_STATIC);
92950 sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "table", SQLITE_STATIC);
92951 sqlite3VdbeSetColName(v, 3, COLNAME_NAME, "from", SQLITE_STATIC);
92952 sqlite3VdbeSetColName(v, 4, COLNAME_NAME, "to", SQLITE_STATIC);
@@ -92977,10 +93225,11 @@
92977 }
92978 }else
92979 #endif /* !defined(SQLITE_OMIT_FOREIGN_KEY) */
92980
92981 #ifndef SQLITE_OMIT_FOREIGN_KEY
 
92982 if( sqlite3StrICmp(zLeft, "foreign_key_check")==0 ){
92983 FKey *pFK; /* A foreign key constraint */
92984 Table *pTab; /* Child table contain "REFERENCES" keyword */
92985 Table *pParent; /* Parent table that child points to */
92986 Index *pIdx; /* Index in the parent table */
@@ -93088,10 +93337,11 @@
93088 }
93089 sqlite3VdbeAddOp2(v, OP_Next, 0, addrTop+1);
93090 sqlite3VdbeJumpHere(v, addrTop);
93091 }
93092 }else
 
93093 #endif /* !defined(SQLITE_OMIT_FOREIGN_KEY) */
93094
93095 #ifndef NDEBUG
93096 if( sqlite3StrICmp(zLeft, "parser_trace")==0 ){
93097 if( zRight ){
@@ -93884,15 +94134,19 @@
93884 ** For an attached db, it is an error if the encoding is not the same
93885 ** as sqlite3.enc.
93886 */
93887 if( meta[BTREE_TEXT_ENCODING-1] ){ /* text encoding */
93888 if( iDb==0 ){
 
93889 u8 encoding;
93890 /* If opening the main database, set ENC(db). */
93891 encoding = (u8)meta[BTREE_TEXT_ENCODING-1] & 3;
93892 if( encoding==0 ) encoding = SQLITE_UTF8;
93893 ENC(db) = encoding;
 
 
 
93894 }else{
93895 /* If opening an attached database, the encoding much match ENC(db) */
93896 if( meta[BTREE_TEXT_ENCODING-1]!=ENC(db) ){
93897 sqlite3SetString(pzErrMsg, db, "attached databases must use the same"
93898 " text encoding as main database");
@@ -96198,10 +96452,12 @@
96198 switch( p->op ){
96199 case TK_ALL: {
96200 int addr = 0;
96201 int nLimit;
96202 assert( !pPrior->pLimit );
 
 
96203 pPrior->pLimit = p->pLimit;
96204 pPrior->pOffset = p->pOffset;
96205 explainSetInteger(iSub1, pParse->iNextSelectId);
96206 rc = sqlite3Select(pParse, pPrior, &dest);
96207 p->pLimit = 0;
@@ -96855,11 +97111,12 @@
96855 if( op==TK_ALL ){
96856 regPrev = 0;
96857 }else{
96858 int nExpr = p->pEList->nExpr;
96859 assert( nOrderBy>=nExpr || db->mallocFailed );
96860 regPrev = sqlite3GetTempRange(pParse, nExpr+1);
 
96861 sqlite3VdbeAddOp2(v, OP_Integer, 0, regPrev);
96862 pKeyDup = sqlite3DbMallocZero(db,
96863 sizeof(*pKeyDup) + nExpr*(sizeof(CollSeq*)+1) );
96864 if( pKeyDup ){
96865 pKeyDup->aSortOrder = (u8*)&pKeyDup->aColl[nExpr];
@@ -97037,16 +97294,10 @@
97037 sqlite3VdbeAddOp4(v, OP_Compare, destA.iSdst, destB.iSdst, nOrderBy,
97038 (char*)pKeyMerge, P4_KEYINFO_HANDOFF);
97039 sqlite3VdbeChangeP5(v, OPFLAG_PERMUTE);
97040 sqlite3VdbeAddOp3(v, OP_Jump, addrAltB, addrAeqB, addrAgtB);
97041
97042 /* Release temporary registers
97043 */
97044 if( regPrev ){
97045 sqlite3ReleaseTempRange(pParse, regPrev, nOrderBy+1);
97046 }
97047
97048 /* Jump to the this point in order to terminate the query.
97049 */
97050 sqlite3VdbeResolveLabel(v, labelEnd);
97051
97052 /* Set the number of output columns
@@ -97454,16 +97705,19 @@
97454 */
97455 for(pSub=pSub->pPrior; pSub; pSub=pSub->pPrior){
97456 Select *pNew;
97457 ExprList *pOrderBy = p->pOrderBy;
97458 Expr *pLimit = p->pLimit;
 
97459 Select *pPrior = p->pPrior;
97460 p->pOrderBy = 0;
97461 p->pSrc = 0;
97462 p->pPrior = 0;
97463 p->pLimit = 0;
 
97464 pNew = sqlite3SelectDup(db, p, 0);
 
97465 p->pLimit = pLimit;
97466 p->pOrderBy = pOrderBy;
97467 p->pSrc = pSrc;
97468 p->op = TK_ALL;
97469 p->pRightmost = 0;
@@ -97784,18 +98038,19 @@
97784 SrcList *pTabList;
97785 ExprList *pEList;
97786 struct SrcList_item *pFrom;
97787 sqlite3 *db = pParse->db;
97788 Expr *pE, *pRight, *pExpr;
 
97789
 
97790 if( db->mallocFailed ){
97791 return WRC_Abort;
97792 }
97793 if( NEVER(p->pSrc==0) || (p->selFlags & SF_Expanded)!=0 ){
97794 return WRC_Prune;
97795 }
97796 p->selFlags |= SF_Expanded;
97797 pTabList = p->pSrc;
97798 pEList = p->pEList;
97799
97800 /* Make sure cursor numbers have been assigned to all entries in
97801 ** the FROM clause of the SELECT statement.
@@ -97834,10 +98089,16 @@
97834 }else{
97835 /* An ordinary table or view name in the FROM clause */
97836 assert( pFrom->pTab==0 );
97837 pFrom->pTab = pTab = sqlite3LocateTableItem(pParse, 0, pFrom);
97838 if( pTab==0 ) return WRC_Abort;
 
 
 
 
 
 
97839 pTab->nRef++;
97840 #if !defined(SQLITE_OMIT_VIEW) || !defined (SQLITE_OMIT_VIRTUALTABLE)
97841 if( pTab->pSelect || IsVirtual(pTab) ){
97842 /* We reach here if the named table is a really a view */
97843 if( sqlite3ViewGetColumnNames(pParse, pTab) ) return WRC_Abort;
@@ -98146,10 +98407,11 @@
98146 NameContext *pOuterNC /* Name context for container */
98147 ){
98148 sqlite3 *db;
98149 if( NEVER(p==0) ) return;
98150 db = pParse->db;
 
98151 if( p->selFlags & SF_HasTypeInfo ) return;
98152 sqlite3SelectExpand(pParse, p);
98153 if( pParse->nErr || db->mallocFailed ) return;
98154 sqlite3ResolveSelectNames(pParse, p, pOuterNC);
98155 if( pParse->nErr || db->mallocFailed ) return;
@@ -99231,11 +99493,14 @@
99231 SQLITE_PRIVATE void sqlite3ExplainSelect(Vdbe *pVdbe, Select *p){
99232 if( p==0 ){
99233 sqlite3ExplainPrintf(pVdbe, "(null-select)");
99234 return;
99235 }
99236 while( p->pPrior ) p = p->pPrior;
 
 
 
99237 sqlite3ExplainPush(pVdbe);
99238 while( p ){
99239 explainOneSelect(pVdbe, p);
99240 p = p->pNext;
99241 if( p==0 ) break;
@@ -102850,11 +103115,10 @@
102850 ** subclauses points to the WhereClause object for the whole clause.
102851 */
102852 struct WhereClause {
102853 Parse *pParse; /* The parser context */
102854 WhereMaskSet *pMaskSet; /* Mapping of table cursor numbers to bitmasks */
102855 Bitmask vmask; /* Bitmask identifying virtual table cursors */
102856 WhereClause *pOuter; /* Outer conjunction */
102857 u8 op; /* Split operator. TK_AND or TK_OR */
102858 u16 wctrlFlags; /* Might include WHERE_AND_ONLY */
102859 int nTerm; /* Number of terms */
102860 int nSlot; /* Number of entries in a[] */
@@ -103027,11 +103291,10 @@
103027 pWC->pMaskSet = pMaskSet;
103028 pWC->pOuter = 0;
103029 pWC->nTerm = 0;
103030 pWC->nSlot = ArraySize(pWC->aStatic);
103031 pWC->a = pWC->aStatic;
103032 pWC->vmask = 0;
103033 pWC->wctrlFlags = wctrlFlags;
103034 }
103035
103036 /* Forward reference */
103037 static void whereClauseClear(WhereClause*);
@@ -103355,13 +103618,12 @@
103355 **
103356 ** If there are multiple terms in the WHERE clause of the form "X <op> <expr>"
103357 ** then try for the one with no dependencies on <expr> - in other words where
103358 ** <expr> is a constant expression of some kind. Only return entries of
103359 ** the form "X <op> Y" where Y is a column in another table if no terms of
103360 ** the form "X <op> <const-expr>" exist. Other than this priority, if there
103361 ** are two or more terms that match, then the choice of which term to return
103362 ** is arbitrary.
103363 */
103364 static WhereTerm *findTerm(
103365 WhereClause *pWC, /* The WHERE clause to be searched */
103366 int iCur, /* Cursor number of LHS */
103367 int iColumn, /* Column number of LHS */
@@ -103416,12 +103678,16 @@
103416 }
103417 if( sqlite3StrICmp(pColl->zName, pIdx->azColl[j]) ){
103418 continue;
103419 }
103420 }
103421 pResult = pTerm;
103422 if( pTerm->prereqRight==0 ) goto findTerm_success;
 
 
 
 
103423 }
103424 if( (pTerm->eOperator & WO_EQUIV)!=0
103425 && nEquiv<ArraySize(aEquiv)
103426 ){
103427 pX = sqlite3ExprSkipCollate(pTerm->pExpr->pRight);
@@ -103627,11 +103893,11 @@
103627 ** (D) x=expr1 OR (y>11 AND y<22 AND z LIKE '*hello*')
103628 ** (E) (p.a=1 AND q.b=2 AND r.c=3) OR (p.x=4 AND q.y=5 AND r.z=6)
103629 **
103630 ** CASE 1:
103631 **
103632 ** If all subterms are of the form T.C=expr for some single column of C
103633 ** a single table T (as shown in example B above) then create a new virtual
103634 ** term that is an equivalent IN expression. In other words, if the term
103635 ** being analyzed is:
103636 **
103637 ** x = expr1 OR expr2 = x OR x = expr3
@@ -103715,11 +103981,11 @@
103715
103716 /*
103717 ** Compute the set of tables that might satisfy cases 1 or 2.
103718 */
103719 indexable = ~(Bitmask)0;
103720 chngToIN = ~(pWC->vmask);
103721 for(i=pOrWc->nTerm-1, pOrTerm=pOrWc->a; i>=0 && indexable; i--, pOrTerm++){
103722 if( (pOrTerm->eOperator & WO_SINGLE)==0 ){
103723 WhereAndInfo *pAndInfo;
103724 assert( (pOrTerm->wtFlags & (TERM_ANDINFO|TERM_ORINFO))==0 );
103725 chngToIN = 0;
@@ -104982,12 +105248,13 @@
104982 Table *pTab = pSrc->pTab;
104983 sqlite3_index_info *pIdxInfo;
104984 struct sqlite3_index_constraint *pIdxCons;
104985 struct sqlite3_index_constraint_usage *pUsage;
104986 WhereTerm *pTerm;
104987 int i, j;
104988 int nOrderBy;
 
104989 int bAllowIN; /* Allow IN optimizations */
104990 double rCost;
104991
104992 /* Make sure wsFlags is initialized to some sane value. Otherwise, if the
104993 ** malloc in allocateIndexInfo() fails and this function returns leaving
@@ -105082,22 +105349,31 @@
105082
105083 if( vtabBestIndex(pParse, pTab, pIdxInfo) ){
105084 return;
105085 }
105086
 
105087 pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint;
105088 for(i=0; i<pIdxInfo->nConstraint; i++, pIdxCons++){
105089 if( pUsage[i].argvIndex>0 ){
105090 j = pIdxCons->iTermOffset;
105091 pTerm = &pWC->a[j];
105092 p->cost.used |= pTerm->prereqRight;
105093 if( (pTerm->eOperator & WO_IN)!=0 && pUsage[i].omit==0 ){
105094 /* Do not attempt to use an IN constraint if the virtual table
105095 ** says that the equivalent EQ constraint cannot be safely omitted.
105096 ** If we do attempt to use such a constraint, some rows might be
105097 ** repeated in the output. */
105098 break;
 
 
 
 
 
 
 
 
105099 }
105100 }
105101 }
105102 if( i>=pIdxInfo->nConstraint ) break;
105103 }
@@ -105123,11 +105399,12 @@
105123 }else{
105124 p->cost.rCost = rCost;
105125 }
105126 p->cost.plan.u.pVtabIdx = pIdxInfo;
105127 if( pIdxInfo->orderByConsumed ){
105128 p->cost.plan.wsFlags |= WHERE_ORDERED;
 
105129 p->cost.plan.nOBSat = nOrderBy;
105130 }else{
105131 p->cost.plan.nOBSat = p->i ? p->aLevel[p->i-1].plan.nOBSat : 0;
105132 }
105133 p->cost.plan.nEq = 0;
@@ -105720,14 +105997,11 @@
105720 pConstraint = findTerm(p->pWC, base, iColumn, p->notReady,
105721 WO_EQ|WO_ISNULL|WO_IN, pIdx);
105722 if( pConstraint==0 ){
105723 isEq = 0;
105724 }else if( (pConstraint->eOperator & WO_IN)!=0 ){
105725 /* Constraints of the form: "X IN ..." cannot be used with an ORDER BY
105726 ** because we do not know in what order the values on the RHS of the IN
105727 ** operator will occur. */
105728 break;
105729 }else if( (pConstraint->eOperator & WO_ISNULL)!=0 ){
105730 uniqueNotNull = 0;
105731 isEq = 1; /* "X IS NULL" means X has only a single value */
105732 }else if( pConstraint->prereqRight==0 ){
105733 isEq = 1; /* Constraint "X=constant" means X has only a single value */
@@ -106027,12 +106301,12 @@
106027 ** constraint for all columns in the index, then this search will find
106028 ** at most a single row. In this case set the WHERE_UNIQUE flag to
106029 ** indicate this to the caller.
106030 **
106031 ** Otherwise, if the search may find more than one row, test to see if
106032 ** there is a range constraint on indexed column (pc.plan.nEq+1) that can be
106033 ** optimized using the index.
106034 */
106035 if( pc.plan.nEq==pProbe->nColumn && pProbe->onError!=OE_None ){
106036 testcase( pc.plan.wsFlags & WHERE_COLUMN_IN );
106037 testcase( pc.plan.wsFlags & WHERE_COLUMN_NULL );
106038 if( (pc.plan.wsFlags & (WHERE_COLUMN_IN|WHERE_COLUMN_NULL))==0 ){
@@ -106369,11 +106643,12 @@
106369 #ifndef SQLITE_OMIT_VIRTUALTABLE
106370 if( IsVirtual(p->pSrc->pTab) ){
106371 sqlite3_index_info *pIdxInfo = 0;
106372 p->ppIdxInfo = &pIdxInfo;
106373 bestVirtualIndex(p);
106374 if( pIdxInfo->needToFreeIdxStr ){
 
106375 sqlite3_free(pIdxInfo->idxStr);
106376 }
106377 sqlite3DbFree(p->pParse->db, pIdxInfo);
106378 }else
106379 #endif
@@ -106475,11 +106750,12 @@
106475 ** this routine sets up a loop that will iterate over all values of X.
106476 */
106477 static int codeEqualityTerm(
106478 Parse *pParse, /* The parsing context */
106479 WhereTerm *pTerm, /* The term of the WHERE clause to be coded */
106480 WhereLevel *pLevel, /* When level of the FROM clause we are working on */
 
106481 int iTarget /* Attempt to leave results in this register */
106482 ){
106483 Expr *pX = pTerm->pExpr;
106484 Vdbe *v = pParse->pVdbe;
106485 int iReg; /* Register holding results */
@@ -106493,16 +106769,30 @@
106493 #ifndef SQLITE_OMIT_SUBQUERY
106494 }else{
106495 int eType;
106496 int iTab;
106497 struct InLoop *pIn;
 
106498
 
 
 
 
 
 
 
 
 
106499 assert( pX->op==TK_IN );
106500 iReg = iTarget;
106501 eType = sqlite3FindInIndex(pParse, pX, 0);
 
 
 
 
106502 iTab = pX->iTable;
106503 sqlite3VdbeAddOp2(v, OP_Rewind, iTab, 0);
106504 assert( pLevel->plan.wsFlags & WHERE_IN_ABLE );
106505 if( pLevel->u.in.nIn==0 ){
106506 pLevel->addrNxt = sqlite3VdbeMakeLabel(v);
106507 }
106508 pLevel->u.in.nIn++;
@@ -106516,10 +106806,11 @@
106516 if( eType==IN_INDEX_ROWID ){
106517 pIn->addrInTop = sqlite3VdbeAddOp2(v, OP_Rowid, iTab, iReg);
106518 }else{
106519 pIn->addrInTop = sqlite3VdbeAddOp3(v, OP_Column, iTab, 0, iReg);
106520 }
 
106521 sqlite3VdbeAddOp1(v, OP_IsNull, iReg);
106522 }else{
106523 pLevel->u.in.nIn = 0;
106524 }
106525 #endif
@@ -106610,11 +106901,11 @@
106610 if( pTerm==0 ) break;
106611 /* The following true for indices with redundant columns.
106612 ** Ex: CREATE INDEX i1 ON t1(a,b,a); SELECT * FROM t1 WHERE a=0 AND b=0; */
106613 testcase( (pTerm->wtFlags & TERM_CODED)!=0 );
106614 testcase( pTerm->wtFlags & TERM_VIRTUAL ); /* EV: R-30575-11662 */
106615 r1 = codeEqualityTerm(pParse, pTerm, pLevel, regBase+j);
106616 if( r1!=regBase+j ){
106617 if( nReg==1 ){
106618 sqlite3ReleaseTempReg(pParse, regBase);
106619 regBase = r1;
106620 }else{
@@ -106884,14 +107175,14 @@
106884 iReg = sqlite3GetTempRange(pParse, nConstraint+2);
106885 addrNotFound = pLevel->addrBrk;
106886 for(j=1; j<=nConstraint; j++){
106887 for(k=0; k<nConstraint; k++){
106888 if( aUsage[k].argvIndex==j ){
106889 WhereTerm *pTerm = &pWC->a[aConstraint[k].iTermOffset];
106890 int iTarget = iReg+j+1;
 
106891 if( pTerm->eOperator & WO_IN ){
106892 codeEqualityTerm(pParse, pTerm, pLevel, iTarget);
106893 addrNotFound = pLevel->addrNxt;
106894 }else{
106895 sqlite3ExprCode(pParse, pTerm->pExpr->pRight, iTarget);
106896 }
106897 break;
@@ -106928,14 +107219,15 @@
106928 pTerm = findTerm(pWC, iCur, -1, notReady, WO_EQ|WO_IN, 0);
106929 assert( pTerm!=0 );
106930 assert( pTerm->pExpr!=0 );
106931 assert( omitTable==0 );
106932 testcase( pTerm->wtFlags & TERM_VIRTUAL ); /* EV: R-30575-11662 */
106933 iRowidReg = codeEqualityTerm(pParse, pTerm, pLevel, iReleaseReg);
106934 addrNxt = pLevel->addrNxt;
106935 sqlite3VdbeAddOp2(v, OP_MustBeInt, iRowidReg, addrNxt);
106936 sqlite3VdbeAddOp3(v, OP_NotExists, iCur, addrNxt, iRowidReg);
 
106937 sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg);
106938 VdbeComment((v, "pk"));
106939 pLevel->op = OP_Noop;
106940 }else if( pLevel->plan.wsFlags & WHERE_ROWID_RANGE ){
106941 /* Case 2: We have an inequality comparison against the ROWID field.
@@ -107767,28 +108059,17 @@
107767 ** its Expr.iRightJoinTable value to find the bitmask of the right table
107768 ** of the join. Subtracting one from the right table bitmask gives a
107769 ** bitmask for all tables to the left of the join. Knowing the bitmask
107770 ** for all tables to the left of a left join is important. Ticket #3015.
107771 **
107772 ** Configure the WhereClause.vmask variable so that bits that correspond
107773 ** to virtual table cursors are set. This is used to selectively disable
107774 ** the OR-to-IN transformation in exprAnalyzeOrTerm(). It is not helpful
107775 ** with virtual tables.
107776 **
107777 ** Note that bitmasks are created for all pTabList->nSrc tables in
107778 ** pTabList, not just the first nTabList tables. nTabList is normally
107779 ** equal to pTabList->nSrc but might be shortened to 1 if the
107780 ** WHERE_ONETABLE_ONLY flag is set.
107781 */
107782 assert( sWBI.pWC->vmask==0 && pMaskSet->n==0 );
107783 for(ii=0; ii<pTabList->nSrc; ii++){
107784 createMask(pMaskSet, pTabList->a[ii].iCursor);
107785 #ifndef SQLITE_OMIT_VIRTUALTABLE
107786 if( ALWAYS(pTabList->a[ii].pTab) && IsVirtual(pTabList->a[ii].pTab) ){
107787 sWBI.pWC->vmask |= ((Bitmask)1 << ii);
107788 }
107789 #endif
107790 }
107791 #ifndef NDEBUG
107792 {
107793 Bitmask toTheLeft = 0;
107794 for(ii=0; ii<pTabList->nSrc; ii++){
@@ -108268,11 +108549,11 @@
108268 struct InLoop *pIn;
108269 int j;
108270 sqlite3VdbeResolveLabel(v, pLevel->addrNxt);
108271 for(j=pLevel->u.in.nIn, pIn=&pLevel->u.in.aInLoop[j-1]; j>0; j--, pIn--){
108272 sqlite3VdbeJumpHere(v, pIn->addrInTop+1);
108273 sqlite3VdbeAddOp2(v, OP_Next, pIn->iCur, pIn->addrInTop);
108274 sqlite3VdbeJumpHere(v, pIn->addrInTop-1);
108275 }
108276 sqlite3DbFree(db, pLevel->u.in.aInLoop);
108277 }
108278 sqlite3VdbeResolveLabel(v, pLevel->addrBrk);
@@ -114034,11 +114315,11 @@
114034 }
114035 }
114036 sqlite3VtabRollback(db);
114037 sqlite3EndBenignMalloc();
114038
114039 if( db->flags&SQLITE_InternChanges ){
114040 sqlite3ExpirePreparedStatements(db);
114041 sqlite3ResetAllSchemasOfConnection(db);
114042 }
114043
114044 /* Any deferred constraint violations have now been resolved. */
114045
--- src/sqlite3.c
+++ src/sqlite3.c
@@ -304,10 +304,14 @@
304 /* Needed for various definitions... */
305 #ifndef _GNU_SOURCE
306 # define _GNU_SOURCE
307 #endif
308
309 #if defined(__OpenBSD__) && !defined(_BSD_SOURCE)
310 # define _BSD_SOURCE
311 #endif
312
313 /*
314 ** Include standard header files as necessary
315 */
316 #ifdef HAVE_STDINT_H
317 #include <stdint.h>
@@ -438,11 +442,12 @@
442 ** if it is already defined or if it is unneeded because we are
443 ** not doing a threadsafe build. Ticket #2681.
444 **
445 ** See also ticket #2741.
446 */
447 #if !defined(_XOPEN_SOURCE) && !defined(__DARWIN__) \
448 && !defined(__APPLE__) && SQLITE_THREADSAFE
449 # define _XOPEN_SOURCE 500 /* Needed to enable pthread recursive mutexes */
450 #endif
451
452 /*
453 ** The TCL headers are only needed when compiling the TCL bindings.
@@ -673,11 +678,11 @@
678 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
679 ** [sqlite_version()] and [sqlite_source_id()].
680 */
681 #define SQLITE_VERSION "3.7.16"
682 #define SQLITE_VERSION_NUMBER 3007016
683 #define SQLITE_SOURCE_ID "2013-03-13 00:13:25 839aa91faf1db7025d90fa3c65e50efb829b053b"
684
685 /*
686 ** CAPI3REF: Run-Time Library Version Numbers
687 ** KEYWORDS: sqlite3_version, sqlite3_sourceid
688 **
@@ -852,11 +857,11 @@
857 **
858 ** Applications should [sqlite3_finalize | finalize] all [prepared statements],
859 ** [sqlite3_blob_close | close] all [BLOB handles], and
860 ** [sqlite3_backup_finish | finish] all [sqlite3_backup] objects associated
861 ** with the [sqlite3] object prior to attempting to close the object. ^If
862 ** sqlite3_close_v2() is called on a [database connection] that still has
863 ** outstanding [prepared statements], [BLOB handles], and/or
864 ** [sqlite3_backup] objects then it returns SQLITE_OK but the deallocation
865 ** of resources is deferred until all [prepared statements], [BLOB handles],
866 ** and [sqlite3_backup] objects are also destroyed.
867 **
@@ -1047,11 +1052,21 @@
1052 #define SQLITE_CANTOPEN_ISDIR (SQLITE_CANTOPEN | (2<<8))
1053 #define SQLITE_CANTOPEN_FULLPATH (SQLITE_CANTOPEN | (3<<8))
1054 #define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1<<8))
1055 #define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1<<8))
1056 #define SQLITE_READONLY_CANTLOCK (SQLITE_READONLY | (2<<8))
1057 #define SQLITE_READONLY_ROLLBACK (SQLITE_READONLY | (3<<8))
1058 #define SQLITE_ABORT_ROLLBACK (SQLITE_ABORT | (2<<8))
1059 #define SQLITE_CONSTRAINT_CHECK (SQLITE_CONSTRAINT | (1<<8))
1060 #define SQLITE_CONSTRAINT_COMMITHOOK (SQLITE_CONSTRAINT | (2<<8))
1061 #define SQLITE_CONSTRAINT_FOREIGNKEY (SQLITE_CONSTRAINT | (3<<8))
1062 #define SQLITE_CONSTRAINT_FUNCTION (SQLITE_CONSTRAINT | (4<<8))
1063 #define SQLITE_CONSTRAINT_NOTNULL (SQLITE_CONSTRAINT | (5<<8))
1064 #define SQLITE_CONSTRAINT_PRIMARYKEY (SQLITE_CONSTRAINT | (6<<8))
1065 #define SQLITE_CONSTRAINT_TRIGGER (SQLITE_CONSTRAINT | (7<<8))
1066 #define SQLITE_CONSTRAINT_UNIQUE (SQLITE_CONSTRAINT | (8<<8))
1067 #define SQLITE_CONSTRAINT_VTAB (SQLITE_CONSTRAINT | (9<<8))
1068
1069 /*
1070 ** CAPI3REF: Flags For File Open Operations
1071 **
1072 ** These bit values are intended for use in the
@@ -10018,11 +10033,11 @@
10033 #define SQLITE_NullCallback 0x00000020 /* Invoke the callback once if the */
10034 /* result set is empty */
10035 #define SQLITE_SqlTrace 0x00000040 /* Debug print SQL as it executes */
10036 #define SQLITE_VdbeListing 0x00000080 /* Debug listings of VDBE programs */
10037 #define SQLITE_WriteSchema 0x00000100 /* OK to update SQLITE_MASTER */
10038 #define SQLITE_VdbeAddopTrace 0x00000200 /* Trace sqlite3VdbeAddOp() calls */
10039 #define SQLITE_IgnoreChecks 0x00000400 /* Do not enforce check constraints */
10040 #define SQLITE_ReadUncommitted 0x0000800 /* For shared-cache mode */
10041 #define SQLITE_LegacyFileFmt 0x00001000 /* Create new databases in format 1 */
10042 #define SQLITE_FullFSync 0x00002000 /* Use full fsync on the backend */
10043 #define SQLITE_CkptFullFSync 0x00004000 /* Use full fsync for checkpoint */
@@ -11034,10 +11049,11 @@
11049 struct {
11050 int nIn; /* Number of entries in aInLoop[] */
11051 struct InLoop {
11052 int iCur; /* The VDBE cursor used by this IN operator */
11053 int addrInTop; /* Top of the IN loop */
11054 u8 eEndLoopOp; /* IN Loop terminator. OP_Next or OP_Prev */
11055 } *aInLoop; /* Information about each nested IN operator */
11056 } in; /* Used when plan.wsFlags&WHERE_IN_ABLE */
11057 Index *pCovidx; /* Possible covering index for WHERE_MULTI_OR */
11058 } u;
11059 double rOptCost; /* "Optimal" cost for this level */
@@ -11905,11 +11921,11 @@
11921 SQLITE_PRIVATE void sqlite3SelectDelete(sqlite3*, Select*);
11922 SQLITE_PRIVATE Table *sqlite3SrcListLookup(Parse*, SrcList*);
11923 SQLITE_PRIVATE int sqlite3IsReadOnly(Parse*, Table*, int);
11924 SQLITE_PRIVATE void sqlite3OpenTable(Parse*, int iCur, int iDb, Table*, int);
11925 #if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) && !defined(SQLITE_OMIT_SUBQUERY)
11926 SQLITE_PRIVATE Expr *sqlite3LimitWhere(Parse*,SrcList*,Expr*,ExprList*,Expr*,Expr*,char*);
11927 #endif
11928 SQLITE_PRIVATE void sqlite3DeleteFrom(Parse*, SrcList*, Expr*);
11929 SQLITE_PRIVATE void sqlite3Update(Parse*, SrcList*, ExprList*, Expr*, int);
11930 SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(Parse*,SrcList*,Expr*,ExprList*,ExprList*,u16,int);
11931 SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo*);
@@ -11973,11 +11989,11 @@
11989 SQLITE_PRIVATE void sqlite3CompleteInsertion(Parse*, Table*, int, int, int*, int, int, int);
11990 SQLITE_PRIVATE int sqlite3OpenTableAndIndices(Parse*, Table*, int, int);
11991 SQLITE_PRIVATE void sqlite3BeginWriteOperation(Parse*, int, int);
11992 SQLITE_PRIVATE void sqlite3MultiWrite(Parse*);
11993 SQLITE_PRIVATE void sqlite3MayAbort(Parse*);
11994 SQLITE_PRIVATE void sqlite3HaltConstraint(Parse*, int, int, char*, int);
11995 SQLITE_PRIVATE Expr *sqlite3ExprDup(sqlite3*,Expr*,int);
11996 SQLITE_PRIVATE ExprList *sqlite3ExprListDup(sqlite3*,ExprList*,int);
11997 SQLITE_PRIVATE SrcList *sqlite3SrcListDup(sqlite3*,SrcList*,int);
11998 SQLITE_PRIVATE IdList *sqlite3IdListDup(sqlite3*,IdList*);
11999 SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3*,Select*,int);
@@ -12086,12 +12102,15 @@
12102 **
12103 ** x = getVarint32( A, B );
12104 ** x = putVarint32( A, B );
12105 **
12106 */
12107 #define getVarint32(A,B) \
12108 (u8)((*(A)<(u8)0x80)?((B)=(u32)*(A)),1:sqlite3GetVarint32((A),(u32 *)&(B)))
12109 #define putVarint32(A,B) \
12110 (u8)(((u32)(B)<(u32)0x80)?(*(A)=(unsigned char)(B)),1:\
12111 sqlite3PutVarint32((A),(B)))
12112 #define getVarint sqlite3GetVarint
12113 #define putVarint sqlite3PutVarint
12114
12115
12116 SQLITE_PRIVATE const char *sqlite3IndexAffinityStr(Vdbe *, Index *);
@@ -12323,11 +12342,12 @@
12342 #define sqlite3EndBenignMalloc()
12343 #endif
12344
12345 #define IN_INDEX_ROWID 1
12346 #define IN_INDEX_EPH 2
12347 #define IN_INDEX_INDEX_ASC 3
12348 #define IN_INDEX_INDEX_DESC 4
12349 SQLITE_PRIVATE int sqlite3FindInIndex(Parse *, Expr *, int*);
12350
12351 #ifdef SQLITE_ENABLE_ATOMIC_WRITE
12352 SQLITE_PRIVATE int sqlite3JournalOpen(sqlite3_vfs *, const char *, sqlite3_file *, int, int);
12353 SQLITE_PRIVATE int sqlite3JournalSize(sqlite3_vfs *);
@@ -13208,11 +13228,11 @@
13228 Mem *aMem; /* Array of memory cells for parent frame */
13229 u8 *aOnceFlag; /* Array of OP_Once flags for parent frame */
13230 VdbeCursor **apCsr; /* Array of Vdbe cursors for parent frame */
13231 void *token; /* Copy of SubProgram.token */
13232 i64 lastRowid; /* Last insert rowid (sqlite3.lastRowid) */
13233 int nCursor; /* Number of entries in apCsr */
13234 int pc; /* Program Counter in parent (calling) frame */
13235 int nOp; /* Size of aOp array */
13236 int nMem; /* Number of entries in aMem */
13237 int nOnceFlag; /* Number of entries in aOnceFlag */
13238 int nChildMem; /* Number of memory cells for child frame */
@@ -13394,11 +13414,11 @@
13414 int nOp; /* Number of instructions in the program */
13415 int nOpAlloc; /* Number of slots allocated for aOp[] */
13416 int nLabel; /* Number of labels used */
13417 int *aLabel; /* Space to hold the labels */
13418 u16 nResColumn; /* Number of columns in one row of the result set */
13419 int nCursor; /* Number of slots in apCsr[] */
13420 u32 magic; /* Magic number for sanity checking */
13421 char *zErrMsg; /* Error message written here */
13422 Vdbe *pPrev,*pNext; /* Linked list of VDBEs with the same Vdbe.db */
13423 VdbeCursor **apCsr; /* One element of this array for each open cursor */
13424 Mem *aVar; /* Values for the OP_Variable opcode. */
@@ -23445,11 +23465,14 @@
23465 #endif
23466 }while( fd<0 && errno==EINTR );
23467 if( fd>=0 ){
23468 if( m!=0 ){
23469 struct stat statbuf;
23470 if( osFstat(fd, &statbuf)==0
23471 && statbuf.st_size==0
23472 && (statbuf.st_mode&0777)!=m
23473 ){
23474 osFchmod(fd, m);
23475 }
23476 }
23477 #if defined(FD_CLOEXEC) && (!defined(O_CLOEXEC) || O_CLOEXEC==0)
23478 osFcntl(fd, F_SETFD, osFcntl(fd, F_GETFD, 0) | FD_CLOEXEC);
@@ -27645,11 +27668,11 @@
27668 pNew->ctrlFlags = (u8)ctrlFlags;
27669 if( sqlite3_uri_boolean(((ctrlFlags & UNIXFILE_URI) ? zFilename : 0),
27670 "psow", SQLITE_POWERSAFE_OVERWRITE) ){
27671 pNew->ctrlFlags |= UNIXFILE_PSOW;
27672 }
27673 if( strcmp(pVfs->zName,"unix-excl")==0 ){
27674 pNew->ctrlFlags |= UNIXFILE_EXCL;
27675 }
27676
27677 #if OS_VXWORKS
27678 pNew->pId = vxworksFindFileId(zFilename);
@@ -31099,11 +31122,11 @@
31122 /*
31123 ** This function outputs the specified (ANSI) string to the Win32 debugger
31124 ** (if available).
31125 */
31126
31127 SQLITE_API void sqlite3_win32_write_debug(const char *zBuf, int nBuf){
31128 char zDbgBuf[SQLITE_WIN32_DBG_BUF_SIZE];
31129 int nMin = MIN(nBuf, (SQLITE_WIN32_DBG_BUF_SIZE - 1)); /* may be negative. */
31130 if( nMin<-1 ) nMin = -1; /* all negative values become -1. */
31131 assert( nMin==-1 || nMin==0 || nMin<SQLITE_WIN32_DBG_BUF_SIZE );
31132 #if defined(SQLITE_WIN32_HAS_ANSI)
@@ -31732,13 +31755,14 @@
31755
31756 #if SQLITE_OS_WINCE
31757 /*************************************************************************
31758 ** This section contains code for WinCE only.
31759 */
31760 #if !defined(SQLITE_MSVC_LOCALTIME_API) || !SQLITE_MSVC_LOCALTIME_API
31761 /*
31762 ** The MSVC CRT on Windows CE may not have a localtime() function. So
31763 ** create a substitute.
31764 */
31765 /* #include <time.h> */
31766 struct tm *__cdecl localtime(const time_t *t)
31767 {
31768 static struct tm y;
@@ -31758,10 +31782,11 @@
31782 y.tm_hour = pTm.wHour;
31783 y.tm_min = pTm.wMinute;
31784 y.tm_sec = pTm.wSecond;
31785 return &y;
31786 }
31787 #endif
31788
31789 #define HANDLE_TO_WINFILE(a) (winFile*)&((char*)a)[-(int)offsetof(winFile,h)]
31790
31791 /*
31792 ** Acquire a lock on the handle h
@@ -31779,19 +31804,21 @@
31804
31805 /*
31806 ** Create the mutex and shared memory used for locking in the file
31807 ** descriptor pFile
31808 */
31809 static int winceCreateLock(const char *zFilename, winFile *pFile){
31810 LPWSTR zTok;
31811 LPWSTR zName;
31812 DWORD lastErrno;
31813 BOOL bLogged = FALSE;
31814 BOOL bInit = TRUE;
31815
31816 zName = utf8ToUnicode(zFilename);
31817 if( zName==0 ){
31818 /* out of memory */
31819 return SQLITE_IOERR_NOMEM;
31820 }
31821
31822 /* Initialize the local lockdata */
31823 memset(&pFile->local, 0, sizeof(pFile->local));
31824
@@ -31804,13 +31831,14 @@
31831
31832 /* Create/open the named mutex */
31833 pFile->hMutex = osCreateMutexW(NULL, FALSE, zName);
31834 if (!pFile->hMutex){
31835 pFile->lastErrno = osGetLastError();
31836 winLogError(SQLITE_IOERR, pFile->lastErrno,
31837 "winceCreateLock1", zFilename);
31838 sqlite3_free(zName);
31839 return SQLITE_IOERR;
31840 }
31841
31842 /* Acquire the mutex before continuing */
31843 winceMutexAcquire(pFile->hMutex);
31844
@@ -31823,45 +31851,53 @@
31851 PAGE_READWRITE, 0, sizeof(winceLock),
31852 zName);
31853
31854 /* Set a flag that indicates we're the first to create the memory so it
31855 ** must be zero-initialized */
31856 lastErrno = osGetLastError();
31857 if (lastErrno == ERROR_ALREADY_EXISTS){
31858 bInit = FALSE;
31859 }
31860
31861 sqlite3_free(zName);
31862
31863 /* If we succeeded in making the shared memory handle, map it. */
31864 if( pFile->hShared ){
31865 pFile->shared = (winceLock*)osMapViewOfFile(pFile->hShared,
31866 FILE_MAP_READ|FILE_MAP_WRITE, 0, 0, sizeof(winceLock));
31867 /* If mapping failed, close the shared memory handle and erase it */
31868 if( !pFile->shared ){
31869 pFile->lastErrno = osGetLastError();
31870 winLogError(SQLITE_IOERR, pFile->lastErrno,
31871 "winceCreateLock2", zFilename);
31872 bLogged = TRUE;
31873 osCloseHandle(pFile->hShared);
31874 pFile->hShared = NULL;
31875 }
31876 }
31877
31878 /* If shared memory could not be created, then close the mutex and fail */
31879 if( pFile->hShared==NULL ){
31880 if( !bLogged ){
31881 pFile->lastErrno = lastErrno;
31882 winLogError(SQLITE_IOERR, pFile->lastErrno,
31883 "winceCreateLock3", zFilename);
31884 bLogged = TRUE;
31885 }
31886 winceMutexRelease(pFile->hMutex);
31887 osCloseHandle(pFile->hMutex);
31888 pFile->hMutex = NULL;
31889 return SQLITE_IOERR;
31890 }
31891
31892 /* Initialize the shared memory if we're supposed to */
31893 if( bInit ){
31894 memset(pFile->shared, 0, sizeof(winceLock));
31895 }
31896
31897 winceMutexRelease(pFile->hMutex);
31898 return SQLITE_OK;
31899 }
31900
31901 /*
31902 ** Destroy the part of winFile that deals with wince locks
31903 */
@@ -31936,21 +31972,23 @@
31972 bReturn = TRUE;
31973 }
31974 }
31975
31976 /* Want a pending lock? */
31977 else if (dwFileOffsetLow == (DWORD)PENDING_BYTE
31978 && nNumberOfBytesToLockLow == 1){
31979 /* If no pending lock has been acquired, then acquire it */
31980 if (pFile->shared->bPending == 0) {
31981 pFile->shared->bPending = TRUE;
31982 pFile->local.bPending = TRUE;
31983 bReturn = TRUE;
31984 }
31985 }
31986
31987 /* Want a reserved lock? */
31988 else if (dwFileOffsetLow == (DWORD)RESERVED_BYTE
31989 && nNumberOfBytesToLockLow == 1){
31990 if (pFile->shared->bReserved == 0) {
31991 pFile->shared->bReserved = TRUE;
31992 pFile->local.bReserved = TRUE;
31993 bReturn = TRUE;
31994 }
@@ -31989,11 +32027,12 @@
32027 bReturn = TRUE;
32028 }
32029
32030 /* Did we just have a reader lock? */
32031 else if (pFile->local.nReaders){
32032 assert(nNumberOfBytesToUnlockLow == (DWORD)SHARED_SIZE
32033 || nNumberOfBytesToUnlockLow == 1);
32034 pFile->local.nReaders --;
32035 if (pFile->local.nReaders == 0)
32036 {
32037 pFile->shared->nReaders --;
32038 }
@@ -32000,19 +32039,21 @@
32039 bReturn = TRUE;
32040 }
32041 }
32042
32043 /* Releasing a pending lock */
32044 else if (dwFileOffsetLow == (DWORD)PENDING_BYTE
32045 && nNumberOfBytesToUnlockLow == 1){
32046 if (pFile->local.bPending){
32047 pFile->local.bPending = FALSE;
32048 pFile->shared->bPending = FALSE;
32049 bReturn = TRUE;
32050 }
32051 }
32052 /* Releasing a reserved lock */
32053 else if (dwFileOffsetLow == (DWORD)RESERVED_BYTE
32054 && nNumberOfBytesToUnlockLow == 1){
32055 if (pFile->local.bReserved) {
32056 pFile->local.bReserved = FALSE;
32057 pFile->shared->bReserved = FALSE;
32058 bReturn = TRUE;
32059 }
@@ -32174,10 +32215,11 @@
32215 assert( id!=0 );
32216 #ifndef SQLITE_OMIT_WAL
32217 assert( pFile->pShm==0 );
32218 #endif
32219 OSTRACE(("CLOSE %d\n", pFile->h));
32220 assert( pFile->h!=NULL && pFile->h!=INVALID_HANDLE_VALUE );
32221 do{
32222 rc = osCloseHandle(pFile->h);
32223 /* SimulateIOError( rc=0; cnt=MX_CLOSE_ATTEMPT; ); */
32224 }while( rc==0 && ++cnt < MX_CLOSE_ATTEMPT && (sqlite3_win32_sleep(100), 1) );
32225 #if SQLITE_OS_WINCE
@@ -32866,11 +32908,11 @@
32908 a[1] = win32IoerrRetryDelay;
32909 }
32910 return SQLITE_OK;
32911 }
32912 case SQLITE_FCNTL_TEMPFILENAME: {
32913 char *zTFile = sqlite3MallocZero( pFile->pVfs->mxPathname );
32914 if( zTFile ){
32915 getTempname(pFile->pVfs->mxPathname, zTFile);
32916 *(char**)pArg = zTFile;
32917 }
32918 return SQLITE_OK;
@@ -33090,11 +33132,11 @@
33132 bRc = osCloseHandle(p->aRegion[i].hMap);
33133 OSTRACE(("SHM-PURGE pid-%d close region=%d %s\n",
33134 (int)osGetCurrentProcessId(), i,
33135 bRc ? "ok" : "failed"));
33136 }
33137 if( p->hFile.h!=NULL && p->hFile.h!=INVALID_HANDLE_VALUE ){
33138 SimulateIOErrorBenign(1);
33139 winClose((sqlite3_file *)&p->hFile);
33140 SimulateIOErrorBenign(0);
33141 }
33142 if( deleteFlag ){
@@ -33170,11 +33212,11 @@
33212 }
33213
33214 rc = winOpen(pDbFd->pVfs,
33215 pShmNode->zFilename, /* Name of the file (UTF-8) */
33216 (sqlite3_file*)&pShmNode->hFile, /* File handle here */
33217 SQLITE_OPEN_WAL | SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
33218 0);
33219 if( SQLITE_OK!=rc ){
33220 goto shm_open_err;
33221 }
33222
@@ -33785,27 +33827,27 @@
33827 || eType==SQLITE_OPEN_MAIN_JOURNAL || eType==SQLITE_OPEN_TEMP_JOURNAL
33828 || eType==SQLITE_OPEN_SUBJOURNAL || eType==SQLITE_OPEN_MASTER_JOURNAL
33829 || eType==SQLITE_OPEN_TRANSIENT_DB || eType==SQLITE_OPEN_WAL
33830 );
33831
33832 assert( pFile!=0 );
33833 memset(pFile, 0, sizeof(winFile));
33834 pFile->h = INVALID_HANDLE_VALUE;
33835
33836 #if SQLITE_OS_WINRT
33837 if( !sqlite3_temp_directory ){
33838 sqlite3_log(SQLITE_ERROR,
33839 "sqlite3_temp_directory variable should be set for WinRT");
33840 }
33841 #endif
33842
 
 
33843 /* If the second argument to this function is NULL, generate a
33844 ** temporary file name to use
33845 */
33846 if( !zUtf8Name ){
33847 assert(isDelete && !isOpenJournal);
33848 memset(zTmpname, 0, MAX_PATH+2);
33849 rc = getTempname(MAX_PATH+2, zTmpname);
33850 if( rc!=SQLITE_OK ){
33851 return rc;
33852 }
33853 zUtf8Name = zTmpname;
@@ -33924,11 +33966,13 @@
33966 pFile->lastErrno = lastErrno;
33967 winLogError(SQLITE_CANTOPEN, pFile->lastErrno, "winOpen", zUtf8Name);
33968 sqlite3_free(zConverted);
33969 if( isReadWrite && !isExclusive ){
33970 return winOpen(pVfs, zName, id,
33971 ((flags|SQLITE_OPEN_READONLY) &
33972 ~(SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE)),
33973 pOutFlags);
33974 }else{
33975 return SQLITE_CANTOPEN_BKPT;
33976 }
33977 }
33978
@@ -33938,38 +33982,34 @@
33982 }else{
33983 *pOutFlags = SQLITE_OPEN_READONLY;
33984 }
33985 }
33986
 
 
 
 
 
 
 
 
 
 
 
 
 
33987 #if SQLITE_OS_WINCE
33988 if( isReadWrite && eType==SQLITE_OPEN_MAIN_DB
33989 && (rc = winceCreateLock(zName, pFile))!=SQLITE_OK
33990 ){
33991 osCloseHandle(h);
33992 sqlite3_free(zConverted);
33993 return rc;
33994 }
33995 if( isTemp ){
33996 pFile->zDeleteOnClose = zConverted;
33997 }else
33998 #endif
33999 {
34000 sqlite3_free(zConverted);
34001 }
34002
34003 pFile->pMethod = &winIoMethod;
34004 pFile->pVfs = pVfs;
34005 pFile->h = h;
34006 if( sqlite3_uri_boolean(zName, "psow", SQLITE_POWERSAFE_OVERWRITE) ){
34007 pFile->ctrlFlags |= WINFILE_PSOW;
34008 }
34009 pFile->lastErrno = NO_ERROR;
34010 pFile->zPath = zName;
34011
34012 OpenCounter(+1);
34013 return rc;
34014 }
34015
@@ -34011,11 +34051,12 @@
34051 if ( osGetFileAttributesExW(zConverted, GetFileExInfoStandard,
34052 &sAttrData) ){
34053 attr = sAttrData.dwFileAttributes;
34054 }else{
34055 lastErrno = osGetLastError();
34056 if( lastErrno==ERROR_FILE_NOT_FOUND
34057 || lastErrno==ERROR_PATH_NOT_FOUND ){
34058 rc = SQLITE_IOERR_DELETE_NOENT; /* Already gone? */
34059 }else{
34060 rc = SQLITE_ERROR;
34061 }
34062 break;
@@ -34023,11 +34064,12 @@
34064 #else
34065 attr = osGetFileAttributesW(zConverted);
34066 #endif
34067 if ( attr==INVALID_FILE_ATTRIBUTES ){
34068 lastErrno = osGetLastError();
34069 if( lastErrno==ERROR_FILE_NOT_FOUND
34070 || lastErrno==ERROR_PATH_NOT_FOUND ){
34071 rc = SQLITE_IOERR_DELETE_NOENT; /* Already gone? */
34072 }else{
34073 rc = SQLITE_ERROR;
34074 }
34075 break;
@@ -34050,11 +34092,12 @@
34092 else{
34093 do {
34094 attr = osGetFileAttributesA(zConverted);
34095 if ( attr==INVALID_FILE_ATTRIBUTES ){
34096 lastErrno = osGetLastError();
34097 if( lastErrno==ERROR_FILE_NOT_FOUND
34098 || lastErrno==ERROR_PATH_NOT_FOUND ){
34099 rc = SQLITE_IOERR_DELETE_NOENT; /* Already gone? */
34100 }else{
34101 rc = SQLITE_ERROR;
34102 }
34103 break;
@@ -34218,20 +34261,16 @@
34261 ** for converting the relative path name to an absolute
34262 ** one by prepending the data directory and a slash.
34263 */
34264 char zOut[MAX_PATH+1];
34265 memset(zOut, 0, MAX_PATH+1);
34266 cygwin_conv_path(CCP_POSIX_TO_WIN_A|CCP_RELATIVE, zRelative, zOut,
34267 MAX_PATH+1);
34268 sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s\\%s",
34269 sqlite3_data_directory, zOut);
34270 }else{
34271 cygwin_conv_path(CCP_POSIX_TO_WIN_A, zRelative, zFull, nFull);
 
 
 
 
 
34272 }
34273 return SQLITE_OK;
34274 #endif
34275
34276 #if (SQLITE_OS_WINCE || SQLITE_OS_WINRT) && !defined(__CYGWIN__)
@@ -34385,13 +34424,13 @@
34424 }
34425 static void winDlError(sqlite3_vfs *pVfs, int nBuf, char *zBufOut){
34426 UNUSED_PARAMETER(pVfs);
34427 getLastErrorMsg(osGetLastError(), nBuf, zBufOut);
34428 }
34429 static void (*winDlSym(sqlite3_vfs *pVfs,void *pH,const char *zSym))(void){
34430 UNUSED_PARAMETER(pVfs);
34431 return (void(*)(void))osGetProcAddressA((HANDLE)pH, zSym);
34432 }
34433 static void winDlClose(sqlite3_vfs *pVfs, void *pHandle){
34434 UNUSED_PARAMETER(pVfs);
34435 osFreeLibrary((HANDLE)pHandle);
34436 }
@@ -34485,11 +34524,12 @@
34524 #ifdef SQLITE_TEST
34525 static const sqlite3_int64 unixEpoch = 24405875*(sqlite3_int64)8640000;
34526 #endif
34527 /* 2^32 - to avoid use of LL and warnings in gcc */
34528 static const sqlite3_int64 max32BitValue =
34529 (sqlite3_int64)2000000000 + (sqlite3_int64)2000000000 +
34530 (sqlite3_int64)294967296;
34531
34532 #if SQLITE_OS_WINCE
34533 SYSTEMTIME time;
34534 osGetSystemTime(&time);
34535 /* if SystemTimeToFileTime() fails, it returns zero. */
@@ -39163,10 +39203,12 @@
39203 pPager->eState = PAGER_ERROR;
39204 }
39205 return rc;
39206 }
39207
39208 static int pager_truncate(Pager *pPager, Pgno nPage);
39209
39210 /*
39211 ** This routine ends a transaction. A transaction is usually ended by
39212 ** either a COMMIT or a ROLLBACK operation. This routine may be called
39213 ** after rollback of a hot-journal, or if an error occurs while opening
39214 ** the journal file or writing the very first journal-header of a
@@ -39216,11 +39258,11 @@
39258 ** tries to unlock the database file if not in exclusive mode. If the
39259 ** unlock operation fails as well, then the first error code related
39260 ** to the first error encountered (the journal finalization one) is
39261 ** returned.
39262 */
39263 static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){
39264 int rc = SQLITE_OK; /* Error code from journal finalization operation */
39265 int rc2 = SQLITE_OK; /* Error code from db file unlock operation */
39266
39267 /* Do nothing if the pager does not have an open write transaction
39268 ** or at least a RESERVED lock. This function may be called when there
@@ -39302,11 +39344,21 @@
39344 ** locking_mode=exclusive mode but is no longer, drop the EXCLUSIVE
39345 ** lock held on the database file.
39346 */
39347 rc2 = sqlite3WalEndWriteTransaction(pPager->pWal);
39348 assert( rc2==SQLITE_OK );
39349 }else if( rc==SQLITE_OK && bCommit && pPager->dbFileSize>pPager->dbSize ){
39350 /* This branch is taken when committing a transaction in rollback-journal
39351 ** mode if the database file on disk is larger than the database image.
39352 ** At this point the journal has been finalized and the transaction
39353 ** successfully committed, but the EXCLUSIVE lock is still held on the
39354 ** file. So it is safe to truncate the database file to its minimum
39355 ** required size. */
39356 assert( pPager->eLock==EXCLUSIVE_LOCK );
39357 rc = pager_truncate(pPager, pPager->dbSize);
39358 }
39359
39360 if( !pPager->exclusiveMode
39361 && (!pagerUseWal(pPager) || sqlite3WalExclusiveMode(pPager->pWal, 0))
39362 ){
39363 rc2 = pagerUnlockDb(pPager, SHARED_LOCK);
39364 pPager->changeCountDone = 0;
@@ -39341,11 +39393,11 @@
39393 sqlite3BeginBenignMalloc();
39394 sqlite3PagerRollback(pPager);
39395 sqlite3EndBenignMalloc();
39396 }else if( !pPager->exclusiveMode ){
39397 assert( pPager->eState==PAGER_READER );
39398 pager_end_transaction(pPager, 0, 0);
39399 }
39400 }
39401 pager_unlock(pPager);
39402 }
39403
@@ -40116,11 +40168,11 @@
40168 && (pPager->eState>=PAGER_WRITER_DBMOD || pPager->eState==PAGER_OPEN)
40169 ){
40170 rc = sqlite3PagerSync(pPager);
40171 }
40172 if( rc==SQLITE_OK ){
40173 rc = pager_end_transaction(pPager, zMaster[0]!='\0', 0);
40174 testcase( rc!=SQLITE_OK );
40175 }
40176 if( rc==SQLITE_OK && zMaster[0] && res ){
40177 /* If there was a master journal and this routine will return success,
40178 ** see if it is possible to delete the master journal.
@@ -41068,16 +41120,30 @@
41120 /*
41121 ** Truncate the in-memory database file image to nPage pages. This
41122 ** function does not actually modify the database file on disk. It
41123 ** just sets the internal state of the pager object so that the
41124 ** truncation will be done when the current transaction is committed.
41125 **
41126 ** This function is only called right before committing a transaction.
41127 ** Once this function has been called, the transaction must either be
41128 ** rolled back or committed. It is not safe to call this function and
41129 ** then continue writing to the database.
41130 */
41131 SQLITE_PRIVATE void sqlite3PagerTruncateImage(Pager *pPager, Pgno nPage){
41132 assert( pPager->dbSize>=nPage );
41133 assert( pPager->eState>=PAGER_WRITER_CACHEMOD );
41134 pPager->dbSize = nPage;
41135
41136 /* At one point the code here called assertTruncateConstraint() to
41137 ** ensure that all pages being truncated away by this operation are,
41138 ** if one or more savepoints are open, present in the savepoint
41139 ** journal so that they can be restored if the savepoint is rolled
41140 ** back. This is no longer necessary as this function is now only
41141 ** called right before committing a transaction. So although the
41142 ** Pager object may still have open savepoints (Pager.nSavepoint!=0),
41143 ** they cannot be rolled back. So the assertTruncateConstraint() call
41144 ** is no longer correct. */
41145 }
41146
41147
41148 /*
41149 ** This function is called before attempting a hot-journal rollback. It
@@ -42126,10 +42192,15 @@
42192 }
42193 if( rc!=SQLITE_OK ){
42194 goto failed;
42195 }
42196 if( bHotJournal ){
42197 if( pPager->readOnly ){
42198 rc = SQLITE_READONLY_ROLLBACK;
42199 goto failed;
42200 }
42201
42202 /* Get an EXCLUSIVE lock on the database file. At this point it is
42203 ** important that a RESERVED lock is not obtained on the way to the
42204 ** EXCLUSIVE lock. If it were, another process might open the
42205 ** database file, detect the RESERVED lock, and conclude that the
42206 ** database is safe to read while this process is still rolling the
@@ -43210,40 +43281,10 @@
43281 #else
43282 rc = pager_incr_changecounter(pPager, 0);
43283 #endif
43284 if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
43285
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43286 /* Write the master journal name into the journal file. If a master
43287 ** journal file name has already been written to the journal file,
43288 ** or if zMaster is NULL (no master journal), then this call is a no-op.
43289 */
43290 rc = writeMasterJournal(pPager, zMaster);
@@ -43267,15 +43308,18 @@
43308 if( rc!=SQLITE_OK ){
43309 assert( rc!=SQLITE_IOERR_BLOCKED );
43310 goto commit_phase_one_exit;
43311 }
43312 sqlite3PcacheCleanAll(pPager->pPCache);
43313
43314 /* If the file on disk is smaller than the database image, use
43315 ** pager_truncate to grow the file here. This can happen if the database
43316 ** image was extended as part of the current transaction and then the
43317 ** last page in the db image moved to the free-list. In this case the
43318 ** last page is never written out to disk, leaving the database file
43319 ** undersized. Fix this now if it is the case. */
43320 if( pPager->dbSize>pPager->dbFileSize ){
43321 Pgno nNew = pPager->dbSize - (pPager->dbSize==PAGER_MJ_PGNO(pPager));
43322 assert( pPager->eState==PAGER_WRITER_DBMOD );
43323 rc = pager_truncate(pPager, nNew);
43324 if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
43325 }
@@ -43344,11 +43388,11 @@
43388 pPager->eState = PAGER_READER;
43389 return SQLITE_OK;
43390 }
43391
43392 PAGERTRACE(("COMMIT %d\n", PAGERID(pPager)));
43393 rc = pager_end_transaction(pPager, pPager->setMaster, 1);
43394 return pager_error(pPager, rc);
43395 }
43396
43397 /*
43398 ** If a write transaction is open, then all changes made within the
@@ -43389,15 +43433,15 @@
43433 if( pPager->eState<=PAGER_READER ) return SQLITE_OK;
43434
43435 if( pagerUseWal(pPager) ){
43436 int rc2;
43437 rc = sqlite3PagerSavepoint(pPager, SAVEPOINT_ROLLBACK, -1);
43438 rc2 = pager_end_transaction(pPager, pPager->setMaster, 0);
43439 if( rc==SQLITE_OK ) rc = rc2;
43440 }else if( !isOpen(pPager->jfd) || pPager->eState==PAGER_WRITER_LOCKED ){
43441 int eState = pPager->eState;
43442 rc = pager_end_transaction(pPager, 0, 0);
43443 if( !MEMDB && eState>PAGER_WRITER_LOCKED ){
43444 /* This can happen using journal_mode=off. Move the pager to the error
43445 ** state to indicate that the contents of the cache may not be trusted.
43446 ** Any active readers will get SQLITE_ABORT.
43447 */
@@ -43791,11 +43835,12 @@
43835 ** the journal needs to be sync()ed before database page pPg->pgno
43836 ** can be written to. The caller has already promised not to write to it.
43837 */
43838 if( (pPg->flags&PGHDR_NEED_SYNC) && !isCommit ){
43839 needSyncPgno = pPg->pgno;
43840 assert( pPager->journalMode==PAGER_JOURNALMODE_OFF ||
43841 pageInJournal(pPg) || pPg->pgno>pPager->dbOrigSize );
43842 assert( pPg->flags&PGHDR_DIRTY );
43843 }
43844
43845 /* If the cache contains a page with page-number pgno, remove it
43846 ** from its hash chain. Also, if the PGHDR_NEED_SYNC flag was set for
@@ -47795,10 +47840,11 @@
47840 MemPage *pPage1; /* First page of the database */
47841 u8 openFlags; /* Flags to sqlite3BtreeOpen() */
47842 #ifndef SQLITE_OMIT_AUTOVACUUM
47843 u8 autoVacuum; /* True if auto-vacuum is enabled */
47844 u8 incrVacuum; /* True if incr-vacuum is enabled */
47845 u8 bDoTruncate; /* True to truncate db on commit */
47846 #endif
47847 u8 inTransaction; /* Transaction state */
47848 u8 max1bytePayload; /* Maximum first byte of cell for a 1-byte payload */
47849 u16 btsFlags; /* Boolean parameters. See BTS_* macros below */
47850 u16 maxLocal; /* Maximum local payload in non-LEAFDATA tables */
@@ -48361,10 +48407,29 @@
48407 ** is empty, the offset should be 65536, but the 2-byte value stores zero.
48408 ** This routine makes the necessary adjustment to 65536.
48409 */
48410 #define get2byteNotZero(X) (((((int)get2byte(X))-1)&0xffff)+1)
48411
48412 /*
48413 ** Values passed as the 5th argument to allocateBtreePage()
48414 */
48415 #define BTALLOC_ANY 0 /* Allocate any page */
48416 #define BTALLOC_EXACT 1 /* Allocate exact page if possible */
48417 #define BTALLOC_LE 2 /* Allocate any page <= the parameter */
48418
48419 /*
48420 ** Macro IfNotOmitAV(x) returns (x) if SQLITE_OMIT_AUTOVACUUM is not
48421 ** defined, or 0 if it is. For example:
48422 **
48423 ** bIncrVacuum = IfNotOmitAV(pBtShared->incrVacuum);
48424 */
48425 #ifndef SQLITE_OMIT_AUTOVACUUM
48426 #define IfNotOmitAV(expr) (expr)
48427 #else
48428 #define IfNotOmitAV(expr) 0
48429 #endif
48430
48431 #ifndef SQLITE_OMIT_SHARED_CACHE
48432 /*
48433 ** A list of BtShared objects that are eligible for participation
48434 ** in shared cache. This variable has file scope during normal builds,
48435 ** but the test harness needs to access it so we make it global for
@@ -50913,10 +50978,11 @@
50978 ** is requested, this is a no-op.
50979 */
50980 if( p->inTrans==TRANS_WRITE || (p->inTrans==TRANS_READ && !wrflag) ){
50981 goto trans_begun;
50982 }
50983 assert( IfNotOmitAV(pBt->bDoTruncate)==0 );
50984
50985 /* Write transactions are not possible on a read-only database */
50986 if( (pBt->btsFlags & BTS_READ_ONLY)!=0 && wrflag ){
50987 rc = SQLITE_READONLY;
50988 goto trans_begun;
@@ -51229,28 +51295,27 @@
51295
51296 /* Forward declaration required by incrVacuumStep(). */
51297 static int allocateBtreePage(BtShared *, MemPage **, Pgno *, Pgno, u8);
51298
51299 /*
51300 ** Perform a single step of an incremental-vacuum. If successful, return
51301 ** SQLITE_OK. If there is no work to do (and therefore no point in
51302 ** calling this function again), return SQLITE_DONE. Or, if an error
51303 ** occurs, return some other error code.
51304 **
51305 ** More specificly, this function attempts to re-organize the database so
51306 ** that the last page of the file currently in use is no longer in use.
51307 **
51308 ** Parameter nFin is the number of pages that this database would contain
51309 ** were this function called until it returns SQLITE_DONE.
51310 **
51311 ** If the bCommit parameter is non-zero, this function assumes that the
51312 ** caller will keep calling incrVacuumStep() until it returns SQLITE_DONE
51313 ** or an error. bCommit is passed true for an auto-vacuum-on-commmit
51314 ** operation, or false for an incremental vacuum.
51315 */
51316 static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg, int bCommit){
 
51317 Pgno nFreeList; /* Number of pages still on the free-list */
51318 int rc;
51319
51320 assert( sqlite3_mutex_held(pBt->mutex) );
51321 assert( iLastPg>nFin );
@@ -51271,85 +51336,98 @@
51336 if( eType==PTRMAP_ROOTPAGE ){
51337 return SQLITE_CORRUPT_BKPT;
51338 }
51339
51340 if( eType==PTRMAP_FREEPAGE ){
51341 if( bCommit==0 ){
51342 /* Remove the page from the files free-list. This is not required
51343 ** if bCommit is non-zero. In that case, the free-list will be
51344 ** truncated to zero after this function returns, so it doesn't
51345 ** matter if it still contains some garbage entries.
51346 */
51347 Pgno iFreePg;
51348 MemPage *pFreePg;
51349 rc = allocateBtreePage(pBt, &pFreePg, &iFreePg, iLastPg, BTALLOC_EXACT);
51350 if( rc!=SQLITE_OK ){
51351 return rc;
51352 }
51353 assert( iFreePg==iLastPg );
51354 releasePage(pFreePg);
51355 }
51356 } else {
51357 Pgno iFreePg; /* Index of free page to move pLastPg to */
51358 MemPage *pLastPg;
51359 u8 eMode = BTALLOC_ANY; /* Mode parameter for allocateBtreePage() */
51360 Pgno iNear = 0; /* nearby parameter for allocateBtreePage() */
51361
51362 rc = btreeGetPage(pBt, iLastPg, &pLastPg, 0);
51363 if( rc!=SQLITE_OK ){
51364 return rc;
51365 }
51366
51367 /* If bCommit is zero, this loop runs exactly once and page pLastPg
51368 ** is swapped with the first free page pulled off the free list.
51369 **
51370 ** On the other hand, if bCommit is greater than zero, then keep
51371 ** looping until a free-page located within the first nFin pages
51372 ** of the file is found.
51373 */
51374 if( bCommit==0 ){
51375 eMode = BTALLOC_LE;
51376 iNear = nFin;
51377 }
51378 do {
51379 MemPage *pFreePg;
51380 rc = allocateBtreePage(pBt, &pFreePg, &iFreePg, iNear, eMode);
51381 if( rc!=SQLITE_OK ){
51382 releasePage(pLastPg);
51383 return rc;
51384 }
51385 releasePage(pFreePg);
51386 }while( bCommit && iFreePg>nFin );
51387 assert( iFreePg<iLastPg );
51388
51389 rc = relocatePage(pBt, pLastPg, eType, iPtrPage, iFreePg, bCommit);
 
 
 
51390 releasePage(pLastPg);
51391 if( rc!=SQLITE_OK ){
51392 return rc;
51393 }
51394 }
51395 }
51396
51397 if( bCommit==0 ){
51398 do {
51399 iLastPg--;
51400 }while( iLastPg==PENDING_BYTE_PAGE(pBt) || PTRMAP_ISPAGE(pBt, iLastPg) );
51401 pBt->bDoTruncate = 1;
 
 
 
 
 
 
 
 
 
 
 
 
 
51402 pBt->nPage = iLastPg;
51403 }
51404 return SQLITE_OK;
51405 }
51406
51407 /*
51408 ** The database opened by the first argument is an auto-vacuum database
51409 ** nOrig pages in size containing nFree free pages. Return the expected
51410 ** size of the database in pages following an auto-vacuum operation.
51411 */
51412 static Pgno finalDbSize(BtShared *pBt, Pgno nOrig, Pgno nFree){
51413 int nEntry; /* Number of entries on one ptrmap page */
51414 Pgno nPtrmap; /* Number of PtrMap pages to be freed */
51415 Pgno nFin; /* Return value */
51416
51417 nEntry = pBt->usableSize/5;
51418 nPtrmap = (nFree-nOrig+PTRMAP_PAGENO(pBt, nOrig)+nEntry)/nEntry;
51419 nFin = nOrig - nFree - nPtrmap;
51420 if( nOrig>PENDING_BYTE_PAGE(pBt) && nFin<PENDING_BYTE_PAGE(pBt) ){
51421 nFin--;
51422 }
51423 while( PTRMAP_ISPAGE(pBt, nFin) || nFin==PENDING_BYTE_PAGE(pBt) ){
51424 nFin--;
51425 }
51426
51427 return nFin;
51428 }
51429
51430 /*
51431 ** A write-transaction must be opened before calling this function.
51432 ** It performs a single unit of work towards an incremental vacuum.
51433 **
@@ -51364,15 +51442,25 @@
51442 sqlite3BtreeEnter(p);
51443 assert( pBt->inTransaction==TRANS_WRITE && p->inTrans==TRANS_WRITE );
51444 if( !pBt->autoVacuum ){
51445 rc = SQLITE_DONE;
51446 }else{
51447 Pgno nOrig = btreePagecount(pBt);
51448 Pgno nFree = get4byte(&pBt->pPage1->aData[36]);
51449 Pgno nFin = finalDbSize(pBt, nOrig, nFree);
51450
51451 if( nOrig<nFin ){
51452 rc = SQLITE_CORRUPT_BKPT;
51453 }else if( nFree>0 ){
51454 invalidateAllOverflowCache(pBt);
51455 rc = incrVacuumStep(pBt, nFin, nOrig, 0);
51456 if( rc==SQLITE_OK ){
51457 rc = sqlite3PagerWrite(pBt->pPage1->pDbPage);
51458 put4byte(&pBt->pPage1->aData[28], pBt->nPage);
51459 }
51460 }else{
51461 rc = SQLITE_DONE;
51462 }
51463 }
51464 sqlite3BtreeLeave(p);
51465 return rc;
51466 }
@@ -51395,13 +51483,11 @@
51483 invalidateAllOverflowCache(pBt);
51484 assert(pBt->autoVacuum);
51485 if( !pBt->incrVacuum ){
51486 Pgno nFin; /* Number of pages in database after autovacuuming */
51487 Pgno nFree; /* Number of pages on the freelist initially */
 
51488 Pgno iFree; /* The next page to be freed */
 
51489 Pgno nOrig; /* Database size before freeing */
51490
51491 nOrig = btreePagecount(pBt);
51492 if( PTRMAP_ISPAGE(pBt, nOrig) || nOrig==PENDING_BYTE_PAGE(pBt) ){
51493 /* It is not possible to create a database for which the final page
@@ -51410,30 +51496,22 @@
51496 */
51497 return SQLITE_CORRUPT_BKPT;
51498 }
51499
51500 nFree = get4byte(&pBt->pPage1->aData[36]);
51501 nFin = finalDbSize(pBt, nOrig, nFree);
 
 
 
 
 
 
 
 
51502 if( nFin>nOrig ) return SQLITE_CORRUPT_BKPT;
51503
51504 for(iFree=nOrig; iFree>nFin && rc==SQLITE_OK; iFree--){
51505 rc = incrVacuumStep(pBt, nFin, iFree, 1);
51506 }
51507 if( (rc==SQLITE_DONE || rc==SQLITE_OK) && nFree>0 ){
51508 rc = sqlite3PagerWrite(pBt->pPage1->pDbPage);
51509 put4byte(&pBt->pPage1->aData[32], 0);
51510 put4byte(&pBt->pPage1->aData[36], 0);
51511 put4byte(&pBt->pPage1->aData[28], nFin);
51512 pBt->bDoTruncate = 1;
51513 pBt->nPage = nFin;
51514 }
51515 if( rc!=SQLITE_OK ){
51516 sqlite3PagerRollback(pPager);
51517 }
@@ -51484,10 +51562,13 @@
51562 if( rc!=SQLITE_OK ){
51563 sqlite3BtreeLeave(p);
51564 return rc;
51565 }
51566 }
51567 if( pBt->bDoTruncate ){
51568 sqlite3PagerTruncateImage(pBt->pPager, pBt->nPage);
51569 }
51570 #endif
51571 rc = sqlite3PagerCommitPhaseOne(pBt->pPager, zMaster, 0);
51572 sqlite3BtreeLeave(p);
51573 }
51574 return rc;
@@ -51499,10 +51580,13 @@
51580 */
51581 static void btreeEndTransaction(Btree *p){
51582 BtShared *pBt = p->pBt;
51583 assert( sqlite3BtreeHoldsMutex(p) );
51584
51585 #ifndef SQLITE_OMIT_AUTOVACUUM
51586 pBt->bDoTruncate = 0;
51587 #endif
51588 btreeClearHasContent(pBt);
51589 if( p->inTrans>TRANS_NONE && p->db->activeVdbeCnt>1 ){
51590 /* If there are other active statements that belong to this database
51591 ** handle, downgrade to a read-only transaction. The other statements
51592 ** may still be reading from the database. */
@@ -53171,25 +53255,27 @@
53255 **
53256 ** SQLITE_OK is returned on success. Any other return value indicates
53257 ** an error. *ppPage and *pPgno are undefined in the event of an error.
53258 ** Do not invoke sqlite3PagerUnref() on *ppPage if an error is returned.
53259 **
53260 ** If the "nearby" parameter is not 0, then an effort is made to
53261 ** locate a page close to the page number "nearby". This can be used in an
53262 ** attempt to keep related pages close to each other in the database file,
53263 ** which in turn can make database access faster.
53264 **
53265 ** If the eMode parameter is BTALLOC_EXACT and the nearby page exists
53266 ** anywhere on the free-list, then it is guaranteed to be returned. If
53267 ** eMode is BTALLOC_LT then the page returned will be less than or equal
53268 ** to nearby if any such page exists. If eMode is BTALLOC_ANY then there
53269 ** are no restrictions on which page is returned.
53270 */
53271 static int allocateBtreePage(
53272 BtShared *pBt, /* The btree */
53273 MemPage **ppPage, /* Store pointer to the allocated page here */
53274 Pgno *pPgno, /* Store the page number here */
53275 Pgno nearby, /* Search for a page near this one */
53276 u8 eMode /* BTALLOC_EXACT, BTALLOC_LT, or BTALLOC_ANY */
53277 ){
53278 MemPage *pPage1;
53279 int rc;
53280 u32 n; /* Number of pages on the freelist */
53281 u32 k; /* Number of leaves on the trunk of the freelist */
@@ -53196,10 +53282,11 @@
53282 MemPage *pTrunk = 0;
53283 MemPage *pPrevTrunk = 0;
53284 Pgno mxPage; /* Total size of the database file */
53285
53286 assert( sqlite3_mutex_held(pBt->mutex) );
53287 assert( eMode==BTALLOC_ANY || (nearby>0 && IfNotOmitAV(pBt->autoVacuum)) );
53288 pPage1 = pBt->pPage1;
53289 mxPage = btreePagecount(pBt);
53290 n = get4byte(&pPage1->aData[36]);
53291 testcase( n==mxPage-1 );
53292 if( n>=mxPage ){
@@ -53208,25 +53295,28 @@
53295 if( n>0 ){
53296 /* There are pages on the freelist. Reuse one of those pages. */
53297 Pgno iTrunk;
53298 u8 searchList = 0; /* If the free-list must be searched for 'nearby' */
53299
53300 /* If eMode==BTALLOC_EXACT and a query of the pointer-map
53301 ** shows that the page 'nearby' is somewhere on the free-list, then
53302 ** the entire-list will be searched for that page.
53303 */
53304 #ifndef SQLITE_OMIT_AUTOVACUUM
53305 if( eMode==BTALLOC_EXACT ){
53306 if( nearby<=mxPage ){
53307 u8 eType;
53308 assert( nearby>0 );
53309 assert( pBt->autoVacuum );
53310 rc = ptrmapGet(pBt, nearby, &eType, 0);
53311 if( rc ) return rc;
53312 if( eType==PTRMAP_FREEPAGE ){
53313 searchList = 1;
53314 }
53315 }
53316 }else if( eMode==BTALLOC_LE ){
53317 searchList = 1;
53318 }
53319 #endif
53320
53321 /* Decrement the free-list count by 1. Set iTrunk to the index of the
53322 ** first free-list trunk page. iPrevTrunk is initially 1.
@@ -53235,11 +53325,12 @@
53325 if( rc ) return rc;
53326 put4byte(&pPage1->aData[36], n-1);
53327
53328 /* The code within this loop is run only once if the 'searchList' variable
53329 ** is not true. Otherwise, it runs once for each trunk-page on the
53330 ** free-list until the page 'nearby' is located (eMode==BTALLOC_EXACT)
53331 ** or until a page less than 'nearby' is located (eMode==BTALLOC_LT)
53332 */
53333 do {
53334 pPrevTrunk = pTrunk;
53335 if( pPrevTrunk ){
53336 iTrunk = get4byte(&pPrevTrunk->aData[0]);
@@ -53277,15 +53368,17 @@
53368 }else if( k>(u32)(pBt->usableSize/4 - 2) ){
53369 /* Value of k is out of range. Database corruption */
53370 rc = SQLITE_CORRUPT_BKPT;
53371 goto end_allocate_page;
53372 #ifndef SQLITE_OMIT_AUTOVACUUM
53373 }else if( searchList
53374 && (nearby==iTrunk || (iTrunk<nearby && eMode==BTALLOC_LE))
53375 ){
53376 /* The list is being searched and this trunk page is the page
53377 ** to allocate, regardless of whether it has leaves.
53378 */
53379 *pPgno = iTrunk;
53380 *ppPage = pTrunk;
53381 searchList = 0;
53382 rc = sqlite3PagerWrite(pTrunk->pDbPage);
53383 if( rc ){
53384 goto end_allocate_page;
@@ -53344,18 +53437,28 @@
53437 u32 closest;
53438 Pgno iPage;
53439 unsigned char *aData = pTrunk->aData;
53440 if( nearby>0 ){
53441 u32 i;
 
53442 closest = 0;
53443 if( eMode==BTALLOC_LE ){
53444 for(i=0; i<k; i++){
53445 iPage = get4byte(&aData[8+i*4]);
53446 if( iPage<=nearby ){
53447 closest = i;
53448 break;
53449 }
53450 }
53451 }else{
53452 int dist;
53453 dist = sqlite3AbsInt32(get4byte(&aData[8]) - nearby);
53454 for(i=1; i<k; i++){
53455 int d2 = sqlite3AbsInt32(get4byte(&aData[8+i*4]) - nearby);
53456 if( d2<dist ){
53457 closest = i;
53458 dist = d2;
53459 }
53460 }
53461 }
53462 }else{
53463 closest = 0;
53464 }
@@ -53365,11 +53468,13 @@
53468 if( iPage>mxPage ){
53469 rc = SQLITE_CORRUPT_BKPT;
53470 goto end_allocate_page;
53471 }
53472 testcase( iPage==mxPage );
53473 if( !searchList
53474 || (iPage==nearby || (iPage<nearby && eMode==BTALLOC_LE))
53475 ){
53476 int noContent;
53477 *pPgno = iPage;
53478 TRACE(("ALLOCATE: %d was leaf %d of %d on trunk %d"
53479 ": %d more free pages\n",
53480 *pPgno, closest+1, k, pTrunk->pgno, n-1));
@@ -53392,12 +53497,30 @@
53497 }
53498 releasePage(pPrevTrunk);
53499 pPrevTrunk = 0;
53500 }while( searchList );
53501 }else{
53502 /* There are no pages on the freelist, so append a new page to the
53503 ** database image.
53504 **
53505 ** Normally, new pages allocated by this block can be requested from the
53506 ** pager layer with the 'no-content' flag set. This prevents the pager
53507 ** from trying to read the pages content from disk. However, if the
53508 ** current transaction has already run one or more incremental-vacuum
53509 ** steps, then the page we are about to allocate may contain content
53510 ** that is required in the event of a rollback. In this case, do
53511 ** not set the no-content flag. This causes the pager to load and journal
53512 ** the current page content before overwriting it.
53513 **
53514 ** Note that the pager will not actually attempt to load or journal
53515 ** content for any page that really does lie past the end of the database
53516 ** file on disk. So the effects of disabling the no-content optimization
53517 ** here are confined to those pages that lie between the end of the
53518 ** database image and the end of the database file.
53519 */
53520 int bNoContent = (0==IfNotOmitAV(pBt->bDoTruncate));
53521
53522 rc = sqlite3PagerWrite(pBt->pPage1->pDbPage);
53523 if( rc ) return rc;
53524 pBt->nPage++;
53525 if( pBt->nPage==PENDING_BYTE_PAGE(pBt) ) pBt->nPage++;
53526
@@ -53408,11 +53531,11 @@
53531 ** becomes a new pointer-map page, the second is used by the caller.
53532 */
53533 MemPage *pPg = 0;
53534 TRACE(("ALLOCATE: %d from end of file (pointer-map page)\n", pBt->nPage));
53535 assert( pBt->nPage!=PENDING_BYTE_PAGE(pBt) );
53536 rc = btreeGetPage(pBt, pBt->nPage, &pPg, bNoContent);
53537 if( rc==SQLITE_OK ){
53538 rc = sqlite3PagerWrite(pPg->pDbPage);
53539 releasePage(pPg);
53540 }
53541 if( rc ) return rc;
@@ -53422,11 +53545,11 @@
53545 #endif
53546 put4byte(28 + (u8*)pBt->pPage1->aData, pBt->nPage);
53547 *pPgno = pBt->nPage;
53548
53549 assert( *pPgno!=PENDING_BYTE_PAGE(pBt) );
53550 rc = btreeGetPage(pBt, *pPgno, ppPage, bNoContent);
53551 if( rc ) return rc;
53552 rc = sqlite3PagerWrite((*ppPage)->pDbPage);
53553 if( rc!=SQLITE_OK ){
53554 releasePage(*ppPage);
53555 }
@@ -55437,11 +55560,11 @@
55560
55561 /* Allocate a page. The page that currently resides at pgnoRoot will
55562 ** be moved to the allocated page (unless the allocated page happens
55563 ** to reside at pgnoRoot).
55564 */
55565 rc = allocateBtreePage(pBt, &pPageMove, &pgnoMove, pgnoRoot, BTALLOC_EXACT);
55566 if( rc!=SQLITE_OK ){
55567 return rc;
55568 }
55569
55570 if( pgnoMove!=pgnoRoot ){
@@ -57129,11 +57252,10 @@
57252 }
57253 }else{
57254 nDestTruncate = nSrcPage * (pgszSrc/pgszDest);
57255 }
57256 assert( nDestTruncate>0 );
 
57257
57258 if( pgszSrc<pgszDest ){
57259 /* If the source page-size is smaller than the destination page-size,
57260 ** two extra things may need to happen:
57261 **
@@ -57143,10 +57265,12 @@
57265 ** pending-byte page in the source database may need to be
57266 ** copied into the destination database.
57267 */
57268 const i64 iSize = (i64)pgszSrc * (i64)nSrcPage;
57269 sqlite3_file * const pFile = sqlite3PagerFile(pDestPager);
57270 Pgno iPg;
57271 int nDstPage;
57272 i64 iOff;
57273 i64 iEnd;
57274
57275 assert( pFile );
57276 assert( nDestTruncate==0
@@ -57153,17 +57277,30 @@
57277 || (i64)nDestTruncate*(i64)pgszDest >= iSize || (
57278 nDestTruncate==(int)(PENDING_BYTE_PAGE(p->pDest->pBt)-1)
57279 && iSize>=PENDING_BYTE && iSize<=PENDING_BYTE+pgszDest
57280 ));
57281
57282 /* This block ensures that all data required to recreate the original
57283 ** database has been stored in the journal for pDestPager and the
57284 ** journal synced to disk. So at this point we may safely modify
57285 ** the database file in any way, knowing that if a power failure
57286 ** occurs, the original database will be reconstructed from the
57287 ** journal file. */
57288 sqlite3PagerPagecount(pDestPager, &nDstPage);
57289 for(iPg=nDestTruncate; rc==SQLITE_OK && iPg<=(Pgno)nDstPage; iPg++){
57290 if( iPg!=PENDING_BYTE_PAGE(p->pDest->pBt) ){
57291 DbPage *pPg;
57292 rc = sqlite3PagerGet(pDestPager, iPg, &pPg);
57293 if( rc==SQLITE_OK ){
57294 rc = sqlite3PagerWrite(pPg);
57295 sqlite3PagerUnref(pPg);
57296 }
57297 }
57298 }
57299 if( rc==SQLITE_OK ){
57300 rc = sqlite3PagerCommitPhaseOne(pDestPager, 0, 1);
57301 }
57302
57303 /* Write the extra pages and truncate the database file as required */
57304 iEnd = MIN(PENDING_BYTE + pgszDest, iSize);
57305 for(
57306 iOff=PENDING_BYTE+pgszSrc;
@@ -57186,10 +57323,11 @@
57323 /* Sync the database file to disk. */
57324 if( rc==SQLITE_OK ){
57325 rc = sqlite3PagerSync(pDestPager);
57326 }
57327 }else{
57328 sqlite3PagerTruncateImage(pDestPager, nDestTruncate);
57329 rc = sqlite3PagerCommitPhaseOne(pDestPager, 0, 0);
57330 }
57331
57332 /* Finish committing the transaction to the destination database. */
57333 if( SQLITE_OK==rc
@@ -57437,11 +57575,13 @@
57575 ** SQLITE_OK is returned if the conversion is successful (or not required).
57576 ** SQLITE_NOMEM may be returned if a malloc() fails during conversion
57577 ** between formats.
57578 */
57579 SQLITE_PRIVATE int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){
57580 #ifndef SQLITE_OMIT_UTF16
57581 int rc;
57582 #endif
57583 assert( (pMem->flags&MEM_RowSet)==0 );
57584 assert( desiredEnc==SQLITE_UTF8 || desiredEnc==SQLITE_UTF16LE
57585 || desiredEnc==SQLITE_UTF16BE );
57586 if( !(pMem->flags&MEM_Str) || pMem->enc==desiredEnc ){
57587 return SQLITE_OK;
@@ -58582,22 +58722,10 @@
58722 ** a VDBE (or an "sqlite3_stmt" as it is known to the outside world.) Prior
58723 ** to version 2.8.7, all this code was combined into the vdbe.c source file.
58724 ** But that file was getting too big so this subroutines were split out.
58725 */
58726
 
 
 
 
 
 
 
 
 
 
 
 
58727 /*
58728 ** Create a new virtual database engine.
58729 */
58730 SQLITE_PRIVATE Vdbe *sqlite3VdbeCreate(sqlite3 *db){
58731 Vdbe *p;
@@ -58723,11 +58851,13 @@
58851 pOp->p3 = p3;
58852 pOp->p4.p = 0;
58853 pOp->p4type = P4_NOTUSED;
58854 #ifdef SQLITE_DEBUG
58855 pOp->zComment = 0;
58856 if( p->db->flags & SQLITE_VdbeAddopTrace ){
58857 sqlite3VdbePrintOp(0, i, &p->aOp[i]);
58858 }
58859 #endif
58860 #ifdef VDBE_PROFILE
58861 pOp->cycles = 0;
58862 pOp->cnt = 0;
58863 #endif
@@ -58942,11 +59072,11 @@
59072 if( opcode==OP_Destroy || opcode==OP_VUpdate || opcode==OP_VRename
59073 #ifndef SQLITE_OMIT_FOREIGN_KEY
59074 || (opcode==OP_FkCounter && pOp->p1==0 && pOp->p2==1)
59075 #endif
59076 || ((opcode==OP_Halt || opcode==OP_HaltIfNull)
59077 && ((pOp->p1&0xff)==SQLITE_CONSTRAINT && pOp->p2==OE_Abort))
59078 ){
59079 hasAbort = 1;
59080 break;
59081 }
59082 }
@@ -59077,11 +59207,11 @@
59207 pOut->p4type = P4_NOTUSED;
59208 pOut->p4.p = 0;
59209 pOut->p5 = 0;
59210 #ifdef SQLITE_DEBUG
59211 pOut->zComment = 0;
59212 if( p->db->flags & SQLITE_VdbeAddopTrace ){
59213 sqlite3VdbePrintOp(0, i+addr, &p->aOp[i+addr]);
59214 }
59215 #endif
59216 }
59217 p->nOp += nOp;
@@ -60103,11 +60233,11 @@
60233 }
60234 zCsr = p->pFree;
60235 zEnd = &zCsr[nByte];
60236 }while( nByte && !db->mallocFailed );
60237
60238 p->nCursor = nCursor;
60239 p->nOnceFlag = nOnce;
60240 if( p->aVar ){
60241 p->nVar = (ynVar)nVar;
60242 for(n=0; n<nVar; n++){
60243 p->aVar[n].flags = MEM_Null;
@@ -60345,11 +60475,11 @@
60475
60476 /* If there are any write-transactions at all, invoke the commit hook */
60477 if( needXcommit && db->xCommitCallback ){
60478 rc = db->xCommitCallback(db->pCommitArg);
60479 if( rc ){
60480 return SQLITE_CONSTRAINT_COMMITHOOK;
60481 }
60482 }
60483
60484 /* The simple case - no more than one database file (not counting the
60485 ** TEMP database) has a transaction active. There is no need for the
@@ -60637,18 +60767,18 @@
60767 ** handle associated with the VM passed as an argument is about to be
60768 ** committed. If there are outstanding deferred foreign key constraint
60769 ** violations, return SQLITE_ERROR. Otherwise, SQLITE_OK.
60770 **
60771 ** If there are outstanding FK violations and this function returns
60772 ** SQLITE_ERROR, set the result of the VM to SQLITE_CONSTRAINT_FOREIGNKEY
60773 ** and write an error message to it. Then return SQLITE_ERROR.
60774 */
60775 #ifndef SQLITE_OMIT_FOREIGN_KEY
60776 SQLITE_PRIVATE int sqlite3VdbeCheckFk(Vdbe *p, int deferred){
60777 sqlite3 *db = p->db;
60778 if( (deferred && db->nDeferredCons>0) || (!deferred && p->nFkConstraint>0) ){
60779 p->rc = SQLITE_CONSTRAINT_FOREIGNKEY;
60780 p->errorAction = OE_Abort;
60781 sqlite3SetString(&p->zErrMsg, db, "foreign key constraint failed");
60782 return SQLITE_ERROR;
60783 }
60784 return SQLITE_OK;
@@ -60759,11 +60889,11 @@
60889 if( rc!=SQLITE_OK ){
60890 if( NEVER(p->readOnly) ){
60891 sqlite3VdbeLeave(p);
60892 return SQLITE_ERROR;
60893 }
60894 rc = SQLITE_CONSTRAINT_FOREIGNKEY;
60895 }else{
60896 /* The auto-commit flag is true, the vdbe program was successful
60897 ** or hit an 'OR FAIL' constraint and there are no deferred foreign
60898 ** key constraints to hold up the transaction. This means a commit
60899 ** is required. */
@@ -60802,11 +60932,11 @@
60932 ** current statement error code.
60933 */
60934 if( eStatementOp ){
60935 rc = sqlite3VdbeCloseStatement(p, eStatementOp);
60936 if( rc ){
60937 if( p->rc==SQLITE_OK || (p->rc&0xff)==SQLITE_CONSTRAINT ){
60938 p->rc = rc;
60939 sqlite3DbFree(db, p->zErrMsg);
60940 p->zErrMsg = 0;
60941 }
60942 sqlite3RollbackAll(db, SQLITE_ABORT_ROLLBACK);
@@ -61043,11 +61173,11 @@
61173 sqlite3DbFree(db, p->aLabel);
61174 sqlite3DbFree(db, p->aColName);
61175 sqlite3DbFree(db, p->zSql);
61176 sqlite3DbFree(db, p->pFree);
61177 #if defined(SQLITE_ENABLE_TREE_EXPLAIN)
61178 sqlite3DbFree(db, p->zExplain);
61179 sqlite3DbFree(db, p->pExplain);
61180 #endif
61181 }
61182
61183 /*
@@ -63025,11 +63155,11 @@
63155 return 0;
63156 }
63157 if( zName ){
63158 for(i=0; i<p->nzVar; i++){
63159 const char *z = p->azVar[i];
63160 if( z && strncmp(z,zName,nName)==0 && z[nName]==0 ){
63161 return i+1;
63162 }
63163 }
63164 }
63165 return 0;
@@ -64799,11 +64929,11 @@
64929 rc = sqlite3VdbeHalt(p);
64930 assert( rc==SQLITE_BUSY || rc==SQLITE_OK || rc==SQLITE_ERROR );
64931 if( rc==SQLITE_BUSY ){
64932 p->rc = rc = SQLITE_BUSY;
64933 }else{
64934 assert( rc==SQLITE_OK || (p->rc&0xff)==SQLITE_CONSTRAINT );
64935 assert( rc==SQLITE_OK || db->nDeferredCons>0 );
64936 rc = p->rc ? SQLITE_ERROR : SQLITE_DONE;
64937 }
64938 goto vdbe_return;
64939 }
@@ -70131,11 +70261,11 @@
70261 importVtabErrMsg(p, u.cr.pVtab);
70262 if( rc==SQLITE_OK && pOp->p1 ){
70263 assert( u.cr.nArg>1 && u.cr.apArg[0] && (u.cr.apArg[0]->flags&MEM_Null) );
70264 db->lastRowid = lastRowid = u.cr.rowid;
70265 }
70266 if( (rc&0xff)==SQLITE_CONSTRAINT && pOp->p4.pVtab->bConstraint ){
70267 if( pOp->p5==OE_Ignore ){
70268 rc = SQLITE_OK;
70269 }else{
70270 p->errorAction = ((pOp->p5==OE_Replace) ? OE_Abort : pOp->p5);
70271 }
@@ -72677,16 +72807,16 @@
72807 const char *zTab,
72808 const char *zDb
72809 ){
72810 int n;
72811 for(n=0; ALWAYS(zSpan[n]) && zSpan[n]!='.'; n++){}
72812 if( zDb && (sqlite3StrNICmp(zSpan, zDb, n)!=0 || zDb[n]!=0) ){
72813 return 0;
72814 }
72815 zSpan += n+1;
72816 for(n=0; ALWAYS(zSpan[n]) && zSpan[n]!='.'; n++){}
72817 if( zTab && (sqlite3StrNICmp(zSpan, zTab, n)!=0 || zTab[n]!=0) ){
72818 return 0;
72819 }
72820 zSpan += n+1;
72821 if( zCol && sqlite3StrICmp(zSpan, zCol)!=0 ){
72822 return 0;
@@ -72775,12 +72905,12 @@
72905
72906 pTab = pItem->pTab;
72907 assert( pTab!=0 && pTab->zName!=0 );
72908 assert( pTab->nCol>0 );
72909 if( pItem->pSelect && (pItem->pSelect->selFlags & SF_NestedFrom)!=0 ){
 
72910 int hit = 0;
72911 pEList = pItem->pSelect->pEList;
72912 for(j=0; j<pEList->nExpr; j++){
72913 if( sqlite3MatchSpanName(pEList->a[j].zSpan, zCol, zTab, zDb) ){
72914 cnt++;
72915 cntTab = 2;
72916 pMatch = pItem;
@@ -74479,11 +74609,11 @@
74609 ** number as the prior appearance of the same name, or if the name
74610 ** has never appeared before, reuse the same variable number
74611 */
74612 ynVar i;
74613 for(i=0; i<pParse->nzVar; i++){
74614 if( pParse->azVar[i] && strcmp(pParse->azVar[i],z)==0 ){
74615 pExpr->iColumn = x = (ynVar)i+1;
74616 break;
74617 }
74618 }
74619 if( x==0 ) x = pExpr->iColumn = (ynVar)(++pParse->nVar);
@@ -75297,14 +75427,15 @@
75427 ** A cursor is opened on the b-tree object that the RHS of the IN operator
75428 ** and pX->iTable is set to the index of that cursor.
75429 **
75430 ** The returned value of this function indicates the b-tree type, as follows:
75431 **
75432 ** IN_INDEX_ROWID - The cursor was opened on a database table.
75433 ** IN_INDEX_INDEX_ASC - The cursor was opened on an ascending index.
75434 ** IN_INDEX_INDEX_DESC - The cursor was opened on a descending index.
75435 ** IN_INDEX_EPH - The cursor was opened on a specially created and
75436 ** populated epheremal table.
75437 **
75438 ** An existing b-tree might be used if the RHS expression pX is a simple
75439 ** subquery such as:
75440 **
75441 ** SELECT <column> FROM <table>
@@ -75423,11 +75554,12 @@
75554 iAddr = sqlite3CodeOnce(pParse);
75555
75556 sqlite3VdbeAddOp4(v, OP_OpenRead, iTab, pIdx->tnum, iDb,
75557 pKey,P4_KEYINFO_HANDOFF);
75558 VdbeComment((v, "%s", pIdx->zName));
75559 assert( IN_INDEX_INDEX_DESC == IN_INDEX_INDEX_ASC+1 );
75560 eType = IN_INDEX_INDEX_ASC + pIdx->aSortOrder[0];
75561
75562 sqlite3VdbeJumpHere(v, iAddr);
75563 if( prNotFound && !pTab->aCol[iCol].notNull ){
75564 *prNotFound = ++pParse->nMem;
75565 sqlite3VdbeAddOp2(v, OP_Null, 0, *prNotFound);
@@ -76776,11 +76908,12 @@
76908 assert( !ExprHasProperty(pExpr, EP_IntValue) );
76909 if( pExpr->affinity==OE_Ignore ){
76910 sqlite3VdbeAddOp4(
76911 v, OP_Halt, SQLITE_OK, OE_Ignore, 0, pExpr->u.zToken,0);
76912 }else{
76913 sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_TRIGGER,
76914 pExpr->affinity, pExpr->u.zToken, 0);
76915 }
76916
76917 break;
76918 }
76919 #endif
@@ -79335,11 +79468,11 @@
79468 }
79469 if( pTab->tnum==0 ){
79470 /* Do not gather statistics on views or virtual tables */
79471 return;
79472 }
79473 if( sqlite3_strnicmp(pTab->zName, "sqlite_", 7)==0 ){
79474 /* Do not gather statistics on system tables */
79475 return;
79476 }
79477 assert( sqlite3BtreeHoldsAllMutexes(db) );
79478 iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
@@ -79745,11 +79878,11 @@
79878 }
79879 if( i==0 ) pTable->nRowEst = v;
79880 if( pIndex==0 ) break;
79881 pIndex->aiRowEst[i] = v;
79882 if( *z==' ' ) z++;
79883 if( strcmp(z, "unordered")==0 ){
79884 pIndex->bUnordered = 1;
79885 break;
79886 }
79887 }
79888 return 0;
@@ -83247,12 +83380,12 @@
83380 if( pIndex->onError!=OE_None ){
83381 int j2 = sqlite3VdbeCurrentAddr(v) + 3;
83382 sqlite3VdbeAddOp2(v, OP_Goto, 0, j2);
83383 addr2 = sqlite3VdbeCurrentAddr(v);
83384 sqlite3VdbeAddOp3(v, OP_SorterCompare, iSorter, j2, regRecord);
83385 sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_UNIQUE,
83386 OE_Abort, "indexed columns are not unique", P4_STATIC
83387 );
83388 }else{
83389 addr2 = sqlite3VdbeCurrentAddr(v);
83390 }
83391 sqlite3VdbeAddOp2(v, OP_SorterData, iSorter, regRecord);
@@ -83274,12 +83407,12 @@
83407 ** opcode use the values stored within seems dangerous. However, since
83408 ** we can be sure that no other temp registers have been allocated
83409 ** since sqlite3ReleaseTempRange() was called, it is safe to do so.
83410 */
83411 sqlite3VdbeAddOp4(v, OP_IsUnique, iIdx, j2, regRowid, pRegKey, P4_INT32);
83412 sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_UNIQUE,
83413 "indexed columns are not unique", P4_STATIC);
83414 }
83415 sqlite3VdbeAddOp3(v, OP_IdxInsert, iIdx, regRecord, 0);
83416 sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
83417 #endif
83418 sqlite3ReleaseTempReg(pParse, regRecord);
@@ -83394,11 +83527,11 @@
83527 pDb = &db->aDb[iDb];
83528
83529 assert( pTab!=0 );
83530 assert( pParse->nErr==0 );
83531 if( sqlite3StrNICmp(pTab->zName, "sqlite_", 7)==0
83532 && sqlite3StrNICmp(&pTab->zName[7],"altertab_",9)!=0 ){
83533 sqlite3ErrorMsg(pParse, "table %s may not be indexed", pTab->zName);
83534 goto exit_create_index;
83535 }
83536 #ifndef SQLITE_OMIT_VIEW
83537 if( pTab->pSelect ){
@@ -84492,16 +84625,23 @@
84625 /*
84626 ** Code an OP_Halt that causes the vdbe to return an SQLITE_CONSTRAINT
84627 ** error. The onError parameter determines which (if any) of the statement
84628 ** and/or current transaction is rolled back.
84629 */
84630 SQLITE_PRIVATE void sqlite3HaltConstraint(
84631 Parse *pParse, /* Parsing context */
84632 int errCode, /* extended error code */
84633 int onError, /* Constraint type */
84634 char *p4, /* Error message */
84635 int p4type /* P4_STATIC or P4_TRANSIENT */
84636 ){
84637 Vdbe *v = sqlite3GetVdbe(pParse);
84638 assert( (errCode&0xff)==SQLITE_CONSTRAINT );
84639 if( onError==OE_Abort ){
84640 sqlite3MayAbort(pParse);
84641 }
84642 sqlite3VdbeAddOp4(v, OP_Halt, errCode, onError, 0, p4, p4type);
84643 }
84644
84645 /*
84646 ** Check to see if pIndex uses the collating sequence pColl. Return
84647 ** true if it does and false if it does not.
@@ -85242,34 +85382,32 @@
85382 Table *pView, /* View definition */
85383 Expr *pWhere, /* Optional WHERE clause to be added */
85384 int iCur /* Cursor number for ephemerial table */
85385 ){
85386 SelectDest dest;
85387 Select *pSel;
85388 SrcList *pFrom;
85389 sqlite3 *db = pParse->db;
85390 int iDb = sqlite3SchemaToIndex(db, pView->pSchema);
85391
85392 pWhere = sqlite3ExprDup(db, pWhere, 0);
85393 pFrom = sqlite3SrcListAppend(db, 0, 0, 0);
85394
85395 if( pFrom ){
85396 assert( pFrom->nSrc==1 );
85397 pFrom->a[0].zName = sqlite3DbStrDup(db, pView->zName);
85398 pFrom->a[0].zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zName);
85399 assert( pFrom->a[0].pOn==0 );
85400 assert( pFrom->a[0].pUsing==0 );
85401 }
85402
85403 pSel = sqlite3SelectNew(pParse, 0, pFrom, pWhere, 0, 0, 0, 0, 0, 0);
85404 if( pSel ) pSel->selFlags |= SF_Materialize;
85405
 
 
 
85406 sqlite3SelectDestInit(&dest, SRT_EphemTab, iCur);
85407 sqlite3Select(pParse, pSel, &dest);
85408 sqlite3SelectDelete(db, pSel);
85409 }
85410 #endif /* !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER) */
85411
85412 #if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) && !defined(SQLITE_OMIT_SUBQUERY)
85413 /*
@@ -86765,10 +86903,66 @@
86903 sqlite3_result_text(context, "NULL", 4, SQLITE_STATIC);
86904 break;
86905 }
86906 }
86907 }
86908
86909 /*
86910 ** The unicode() function. Return the integer unicode code-point value
86911 ** for the first character of the input string.
86912 */
86913 static void unicodeFunc(
86914 sqlite3_context *context,
86915 int argc,
86916 sqlite3_value **argv
86917 ){
86918 const unsigned char *z = sqlite3_value_text(argv[0]);
86919 (void)argc;
86920 if( z && z[0] ) sqlite3_result_int(context, sqlite3Utf8Read(&z));
86921 }
86922
86923 /*
86924 ** The char() function takes zero or more arguments, each of which is
86925 ** an integer. It constructs a string where each character of the string
86926 ** is the unicode character for the corresponding integer argument.
86927 */
86928 static void charFunc(
86929 sqlite3_context *context,
86930 int argc,
86931 sqlite3_value **argv
86932 ){
86933 unsigned char *z, *zOut;
86934 int i;
86935 zOut = z = sqlite3_malloc( argc*4 );
86936 if( z==0 ){
86937 sqlite3_result_error_nomem(context);
86938 return;
86939 }
86940 for(i=0; i<argc; i++){
86941 sqlite3_int64 x;
86942 unsigned c;
86943 x = sqlite3_value_int64(argv[i]);
86944 if( x<0 || x>0x10ffff ) x = 0xfffd;
86945 c = (unsigned)(x & 0x1fffff);
86946 if( c<0x00080 ){
86947 *zOut++ = (u8)(c&0xFF);
86948 }else if( c<0x00800 ){
86949 *zOut++ = 0xC0 + (u8)((c>>6)&0x1F);
86950 *zOut++ = 0x80 + (u8)(c & 0x3F);
86951 }else if( c<0x10000 ){
86952 *zOut++ = 0xE0 + (u8)((c>>12)&0x0F);
86953 *zOut++ = 0x80 + (u8)((c>>6) & 0x3F);
86954 *zOut++ = 0x80 + (u8)(c & 0x3F);
86955 }else{
86956 *zOut++ = 0xF0 + (u8)((c>>18) & 0x07);
86957 *zOut++ = 0x80 + (u8)((c>>12) & 0x3F);
86958 *zOut++ = 0x80 + (u8)((c>>6) & 0x3F);
86959 *zOut++ = 0x80 + (u8)(c & 0x3F);
86960 } \
86961 }
86962 sqlite3_result_text(context, (char*)z, (int)(zOut-z), sqlite3_free);
86963 }
86964
86965 /*
86966 ** The hex() function. Interpret the argument as a blob. Return
86967 ** a hexadecimal rendering as text.
86968 */
@@ -87393,10 +87587,12 @@
87587 FUNCTION2(typeof, 1, 0, 0, typeofFunc, SQLITE_FUNC_TYPEOF),
87588 FUNCTION2(length, 1, 0, 0, lengthFunc, SQLITE_FUNC_LENGTH),
87589 FUNCTION(instr, 2, 0, 0, instrFunc ),
87590 FUNCTION(substr, 2, 0, 0, substrFunc ),
87591 FUNCTION(substr, 3, 0, 0, substrFunc ),
87592 FUNCTION(unicode, 1, 0, 0, unicodeFunc ),
87593 FUNCTION(char, -1, 0, 0, charFunc ),
87594 FUNCTION(abs, 1, 0, 0, absFunc ),
87595 #ifndef SQLITE_OMIT_FLOATING_POINT
87596 FUNCTION(round, 1, 0, 0, roundFunc ),
87597 FUNCTION(round, 2, 0, 0, roundFunc ),
87598 #endif
@@ -87484,12 +87680,13 @@
87680 /*
87681 ** Deferred and Immediate FKs
87682 ** --------------------------
87683 **
87684 ** Foreign keys in SQLite come in two flavours: deferred and immediate.
87685 ** If an immediate foreign key constraint is violated,
87686 ** SQLITE_CONSTRAINT_FOREIGNKEY is returned and the current
87687 ** statement transaction rolled back. If a
87688 ** deferred foreign key constraint is violated, no action is taken
87689 ** immediately. However if the application attempts to commit the
87690 ** transaction before fixing the constraint violation, the attempt fails.
87691 **
87692 ** Deferred constraints are implemented using a simple counter associated
@@ -87549,11 +87746,12 @@
87746 ** row is inserted.
87747 **
87748 ** Immediate constraints are usually handled similarly. The only difference
87749 ** is that the counter used is stored as part of each individual statement
87750 ** object (struct Vdbe). If, after the statement has run, its immediate
87751 ** constraint counter is greater than zero,
87752 ** it returns SQLITE_CONSTRAINT_FOREIGNKEY
87753 ** and the statement transaction is rolled back. An exception is an INSERT
87754 ** statement that inserts a single row only (no triggers). In this case,
87755 ** instead of using a counter, an exception is thrown immediately if the
87756 ** INSERT violates a foreign key constraint. This is necessary as such
87757 ** an INSERT does not open a statement transaction.
@@ -87889,12 +88087,12 @@
88087 /* Special case: If this is an INSERT statement that will insert exactly
88088 ** one row into the table, raise a constraint immediately instead of
88089 ** incrementing a counter. This is necessary as the VM code is being
88090 ** generated for will not open a statement transaction. */
88091 assert( nIncr==1 );
88092 sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_FOREIGNKEY,
88093 OE_Abort, "foreign key constraint failed", P4_STATIC
88094 );
88095 }else{
88096 if( nIncr>0 && pFKey->isDeferred==0 ){
88097 sqlite3ParseToplevel(pParse)->mayAbort = 1;
88098 }
@@ -88130,12 +88328,12 @@
88328 /* If the DELETE has generated immediate foreign key constraint
88329 ** violations, halt the VDBE and return an error at this point, before
88330 ** any modifications to the schema are made. This is because statement
88331 ** transactions are not able to rollback schema changes. */
88332 sqlite3VdbeAddOp2(v, OP_FkIfZero, 0, sqlite3VdbeCurrentAddr(v)+2);
88333 sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_FOREIGNKEY,
88334 OE_Abort, "foreign key constraint failed", P4_STATIC
88335 );
88336
88337 if( iSkip ){
88338 sqlite3VdbeResolveLabel(v, iSkip);
88339 }
@@ -89935,11 +90133,11 @@
90133 sqlite3MayAbort(pParse);
90134 case OE_Rollback:
90135 case OE_Fail: {
90136 char *zMsg;
90137 sqlite3VdbeAddOp3(v, OP_HaltIfNull,
90138 SQLITE_CONSTRAINT_NOTNULL, onError, regData+i);
90139 zMsg = sqlite3MPrintf(db, "%s.%s may not be NULL",
90140 pTab->zName, pTab->aCol[i].zName);
90141 sqlite3VdbeChangeP4(v, -1, zMsg, P4_DYNAMIC);
90142 break;
90143 }
@@ -89975,11 +90173,12 @@
90173 if( zConsName ){
90174 zConsName = sqlite3MPrintf(db, "constraint %s failed", zConsName);
90175 }else{
90176 zConsName = 0;
90177 }
90178 sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_CHECK,
90179 onError, zConsName, P4_DYNAMIC);
90180 }
90181 sqlite3VdbeResolveLabel(v, allOk);
90182 }
90183 }
90184 #endif /* !defined(SQLITE_OMIT_CHECK) */
@@ -90006,12 +90205,12 @@
90205 /* Fall thru into the next case */
90206 }
90207 case OE_Rollback:
90208 case OE_Abort:
90209 case OE_Fail: {
90210 sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_PRIMARYKEY,
90211 onError, "PRIMARY KEY must be unique", P4_STATIC);
90212 break;
90213 }
90214 case OE_Replace: {
90215 /* If there are DELETE triggers on this table and the
90216 ** recursive-triggers flag is set, call GenerateRowDelete() to
@@ -90134,11 +90333,12 @@
90333 sqlite3StrAccumAppend(&errMsg, zCol, -1);
90334 }
90335 sqlite3StrAccumAppend(&errMsg,
90336 pIdx->nColumn>1 ? " are not unique" : " is not unique", -1);
90337 zErr = sqlite3StrAccumFinish(&errMsg);
90338 sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_UNIQUE,
90339 onError, zErr, 0);
90340 sqlite3DbFree(errMsg.db, zErr);
90341 break;
90342 }
90343 case OE_Ignore: {
90344 assert( seenReplace==0 );
@@ -90542,12 +90742,12 @@
90742 regData = sqlite3GetTempReg(pParse);
90743 regRowid = sqlite3GetTempReg(pParse);
90744 if( pDest->iPKey>=0 ){
90745 addr1 = sqlite3VdbeAddOp2(v, OP_Rowid, iSrc, regRowid);
90746 addr2 = sqlite3VdbeAddOp3(v, OP_NotExists, iDest, 0, regRowid);
90747 sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_PRIMARYKEY,
90748 onError, "PRIMARY KEY must be unique", P4_STATIC);
90749 sqlite3VdbeJumpHere(v, addr2);
90750 autoIncStep(pParse, regAutoinc, regRowid);
90751 }else if( pDest->pIndex==0 ){
90752 addr1 = sqlite3VdbeAddOp2(v, OP_NewRowid, iDest, regRowid);
90753 }else{
@@ -91000,10 +91200,24 @@
91200 int (*wal_checkpoint)(sqlite3*,const char*);
91201 void *(*wal_hook)(sqlite3*,int(*)(void*,sqlite3*,const char*,int),void*);
91202 int (*blob_reopen)(sqlite3_blob*,sqlite3_int64);
91203 int (*vtab_config)(sqlite3*,int op,...);
91204 int (*vtab_on_conflict)(sqlite3*);
91205 /* Version 3.7.16 and later */
91206 int (*close_v2)(sqlite3*);
91207 const char *(*db_filename)(sqlite3*,const char*);
91208 int (*db_readonly)(sqlite3*,const char*);
91209 int (*db_release_memory)(sqlite3*);
91210 const char *(*errstr)(int);
91211 int (*stmt_busy)(sqlite3_stmt*);
91212 int (*stmt_readonly)(sqlite3_stmt*);
91213 int (*stricmp)(const char*,const char*);
91214 int (*uri_boolean)(const char*,const char*,int);
91215 sqlite3_int64 (*uri_int64)(const char*,const char*,sqlite3_int64);
91216 const char *(*uri_parameter)(const char*,const char*);
91217 char *(*vsnprintf)(int,char*,const char*,va_list);
91218 int (*wal_checkpoint_v2)(sqlite3*,const char*,int,int*,int*);
91219 };
91220
91221 /*
91222 ** The following macros redefine the API routines so that they are
91223 ** redirected throught the global sqlite3_api structure.
@@ -91203,10 +91417,24 @@
91417 #define sqlite3_wal_checkpoint sqlite3_api->wal_checkpoint
91418 #define sqlite3_wal_hook sqlite3_api->wal_hook
91419 #define sqlite3_blob_reopen sqlite3_api->blob_reopen
91420 #define sqlite3_vtab_config sqlite3_api->vtab_config
91421 #define sqlite3_vtab_on_conflict sqlite3_api->vtab_on_conflict
91422 /* Version 3.7.16 and later */
91423 #define sqlite3_close_v2 sqlite3_api->close_v2
91424 #define sqlite3_db_filename sqlite3_api->db_filename
91425 #define sqlite3_db_readonly sqlite3_api->db_readonly
91426 #define sqlite3_db_release_memory sqlite3_api->db_release_memory
91427 #define sqlite3_errstr sqlite3_api->errstr
91428 #define sqlite3_stmt_busy sqlite3_api->stmt_busy
91429 #define sqlite3_stmt_readonly sqlite3_api->stmt_readonly
91430 #define sqlite3_stricmp sqlite3_api->stricmp
91431 #define sqlite3_uri_boolean sqlite3_api->uri_boolean
91432 #define sqlite3_uri_int64 sqlite3_api->uri_int64
91433 #define sqlite3_uri_parameter sqlite3_api->uri_parameter
91434 #define sqlite3_uri_vsnprintf sqlite3_api->vsnprintf
91435 #define sqlite3_wal_checkpoint_v2 sqlite3_api->wal_checkpoint_v2
91436 #endif /* SQLITE_CORE */
91437
91438 #define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api = 0;
91439 #define SQLITE_EXTENSION_INIT2(v) sqlite3_api = v;
91440
@@ -91572,10 +91800,23 @@
91800 0,
91801 #endif
91802 sqlite3_blob_reopen,
91803 sqlite3_vtab_config,
91804 sqlite3_vtab_on_conflict,
91805 sqlite3_close_v2,
91806 sqlite3_db_filename,
91807 sqlite3_db_readonly,
91808 sqlite3_db_release_memory,
91809 sqlite3_errstr,
91810 sqlite3_stmt_busy,
91811 sqlite3_stmt_readonly,
91812 sqlite3_stricmp,
91813 sqlite3_uri_boolean,
91814 sqlite3_uri_int64,
91815 sqlite3_uri_parameter,
91816 sqlite3_vsnprintf,
91817 sqlite3_wal_checkpoint_v2
91818 };
91819
91820 /*
91821 ** Attempt to load an SQLite extension library contained in the file
91822 ** zFile. The entry point is zProc. zProc may be 0 in which case a
@@ -92038,10 +92279,13 @@
92279 #endif
92280 #ifdef SQLITE_DEBUG
92281 { "sql_trace", SQLITE_SqlTrace },
92282 { "vdbe_listing", SQLITE_VdbeListing },
92283 { "vdbe_trace", SQLITE_VdbeTrace },
92284 { "vdbe_addoptrace", SQLITE_VdbeAddopTrace},
92285 { "vdbe_debug", SQLITE_SqlTrace | SQLITE_VdbeListing
92286 | SQLITE_VdbeTrace },
92287 #endif
92288 #ifndef SQLITE_OMIT_CHECK
92289 { "ignore_check_constraints", SQLITE_IgnoreChecks },
92290 #endif
92291 /* The following is VERY experimental */
@@ -92809,10 +93053,11 @@
93053 Column *pCol;
93054 Index *pPk;
93055 for(pPk=pTab->pIndex; pPk && pPk->autoIndex!=2; pPk=pPk->pNext){}
93056 sqlite3VdbeSetNumCols(v, 6);
93057 pParse->nMem = 6;
93058 sqlite3CodeVerifySchema(pParse, iDb);
93059 sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "cid", SQLITE_STATIC);
93060 sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", SQLITE_STATIC);
93061 sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "type", SQLITE_STATIC);
93062 sqlite3VdbeSetColName(v, 3, COLNAME_NAME, "notnull", SQLITE_STATIC);
93063 sqlite3VdbeSetColName(v, 4, COLNAME_NAME, "dflt_value", SQLITE_STATIC);
@@ -92854,10 +93099,11 @@
93099 if( pIdx ){
93100 int i;
93101 pTab = pIdx->pTable;
93102 sqlite3VdbeSetNumCols(v, 3);
93103 pParse->nMem = 3;
93104 sqlite3CodeVerifySchema(pParse, iDb);
93105 sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seqno", SQLITE_STATIC);
93106 sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "cid", SQLITE_STATIC);
93107 sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "name", SQLITE_STATIC);
93108 for(i=0; i<pIdx->nColumn; i++){
93109 int cnum = pIdx->aiColumn[i];
@@ -92880,10 +93126,11 @@
93126 pIdx = pTab->pIndex;
93127 if( pIdx ){
93128 int i = 0;
93129 sqlite3VdbeSetNumCols(v, 3);
93130 pParse->nMem = 3;
93131 sqlite3CodeVerifySchema(pParse, iDb);
93132 sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seq", SQLITE_STATIC);
93133 sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", SQLITE_STATIC);
93134 sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "unique", SQLITE_STATIC);
93135 while(pIdx){
93136 sqlite3VdbeAddOp2(v, OP_Integer, i, 1);
@@ -92943,10 +93190,11 @@
93190 pFK = pTab->pFKey;
93191 if( pFK ){
93192 int i = 0;
93193 sqlite3VdbeSetNumCols(v, 8);
93194 pParse->nMem = 8;
93195 sqlite3CodeVerifySchema(pParse, iDb);
93196 sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "id", SQLITE_STATIC);
93197 sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "seq", SQLITE_STATIC);
93198 sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "table", SQLITE_STATIC);
93199 sqlite3VdbeSetColName(v, 3, COLNAME_NAME, "from", SQLITE_STATIC);
93200 sqlite3VdbeSetColName(v, 4, COLNAME_NAME, "to", SQLITE_STATIC);
@@ -92977,10 +93225,11 @@
93225 }
93226 }else
93227 #endif /* !defined(SQLITE_OMIT_FOREIGN_KEY) */
93228
93229 #ifndef SQLITE_OMIT_FOREIGN_KEY
93230 #ifndef SQLITE_OMIT_TRIGGER
93231 if( sqlite3StrICmp(zLeft, "foreign_key_check")==0 ){
93232 FKey *pFK; /* A foreign key constraint */
93233 Table *pTab; /* Child table contain "REFERENCES" keyword */
93234 Table *pParent; /* Parent table that child points to */
93235 Index *pIdx; /* Index in the parent table */
@@ -93088,10 +93337,11 @@
93337 }
93338 sqlite3VdbeAddOp2(v, OP_Next, 0, addrTop+1);
93339 sqlite3VdbeJumpHere(v, addrTop);
93340 }
93341 }else
93342 #endif /* !defined(SQLITE_OMIT_TRIGGER) */
93343 #endif /* !defined(SQLITE_OMIT_FOREIGN_KEY) */
93344
93345 #ifndef NDEBUG
93346 if( sqlite3StrICmp(zLeft, "parser_trace")==0 ){
93347 if( zRight ){
@@ -93884,15 +94134,19 @@
94134 ** For an attached db, it is an error if the encoding is not the same
94135 ** as sqlite3.enc.
94136 */
94137 if( meta[BTREE_TEXT_ENCODING-1] ){ /* text encoding */
94138 if( iDb==0 ){
94139 #ifndef SQLITE_OMIT_UTF16
94140 u8 encoding;
94141 /* If opening the main database, set ENC(db). */
94142 encoding = (u8)meta[BTREE_TEXT_ENCODING-1] & 3;
94143 if( encoding==0 ) encoding = SQLITE_UTF8;
94144 ENC(db) = encoding;
94145 #else
94146 ENC(db) = SQLITE_UTF8;
94147 #endif
94148 }else{
94149 /* If opening an attached database, the encoding much match ENC(db) */
94150 if( meta[BTREE_TEXT_ENCODING-1]!=ENC(db) ){
94151 sqlite3SetString(pzErrMsg, db, "attached databases must use the same"
94152 " text encoding as main database");
@@ -96198,10 +96452,12 @@
96452 switch( p->op ){
96453 case TK_ALL: {
96454 int addr = 0;
96455 int nLimit;
96456 assert( !pPrior->pLimit );
96457 pPrior->iLimit = p->iLimit;
96458 pPrior->iOffset = p->iOffset;
96459 pPrior->pLimit = p->pLimit;
96460 pPrior->pOffset = p->pOffset;
96461 explainSetInteger(iSub1, pParse->iNextSelectId);
96462 rc = sqlite3Select(pParse, pPrior, &dest);
96463 p->pLimit = 0;
@@ -96855,11 +97111,12 @@
97111 if( op==TK_ALL ){
97112 regPrev = 0;
97113 }else{
97114 int nExpr = p->pEList->nExpr;
97115 assert( nOrderBy>=nExpr || db->mallocFailed );
97116 regPrev = pParse->nMem+1;
97117 pParse->nMem += nExpr+1;
97118 sqlite3VdbeAddOp2(v, OP_Integer, 0, regPrev);
97119 pKeyDup = sqlite3DbMallocZero(db,
97120 sizeof(*pKeyDup) + nExpr*(sizeof(CollSeq*)+1) );
97121 if( pKeyDup ){
97122 pKeyDup->aSortOrder = (u8*)&pKeyDup->aColl[nExpr];
@@ -97037,16 +97294,10 @@
97294 sqlite3VdbeAddOp4(v, OP_Compare, destA.iSdst, destB.iSdst, nOrderBy,
97295 (char*)pKeyMerge, P4_KEYINFO_HANDOFF);
97296 sqlite3VdbeChangeP5(v, OPFLAG_PERMUTE);
97297 sqlite3VdbeAddOp3(v, OP_Jump, addrAltB, addrAeqB, addrAgtB);
97298
 
 
 
 
 
 
97299 /* Jump to the this point in order to terminate the query.
97300 */
97301 sqlite3VdbeResolveLabel(v, labelEnd);
97302
97303 /* Set the number of output columns
@@ -97454,16 +97705,19 @@
97705 */
97706 for(pSub=pSub->pPrior; pSub; pSub=pSub->pPrior){
97707 Select *pNew;
97708 ExprList *pOrderBy = p->pOrderBy;
97709 Expr *pLimit = p->pLimit;
97710 Expr *pOffset = p->pOffset;
97711 Select *pPrior = p->pPrior;
97712 p->pOrderBy = 0;
97713 p->pSrc = 0;
97714 p->pPrior = 0;
97715 p->pLimit = 0;
97716 p->pOffset = 0;
97717 pNew = sqlite3SelectDup(db, p, 0);
97718 p->pOffset = pOffset;
97719 p->pLimit = pLimit;
97720 p->pOrderBy = pOrderBy;
97721 p->pSrc = pSrc;
97722 p->op = TK_ALL;
97723 p->pRightmost = 0;
@@ -97784,18 +98038,19 @@
98038 SrcList *pTabList;
98039 ExprList *pEList;
98040 struct SrcList_item *pFrom;
98041 sqlite3 *db = pParse->db;
98042 Expr *pE, *pRight, *pExpr;
98043 u16 selFlags = p->selFlags;
98044
98045 p->selFlags |= SF_Expanded;
98046 if( db->mallocFailed ){
98047 return WRC_Abort;
98048 }
98049 if( NEVER(p->pSrc==0) || (selFlags & SF_Expanded)!=0 ){
98050 return WRC_Prune;
98051 }
 
98052 pTabList = p->pSrc;
98053 pEList = p->pEList;
98054
98055 /* Make sure cursor numbers have been assigned to all entries in
98056 ** the FROM clause of the SELECT statement.
@@ -97834,10 +98089,16 @@
98089 }else{
98090 /* An ordinary table or view name in the FROM clause */
98091 assert( pFrom->pTab==0 );
98092 pFrom->pTab = pTab = sqlite3LocateTableItem(pParse, 0, pFrom);
98093 if( pTab==0 ) return WRC_Abort;
98094 if( pTab->nRef==0xffff ){
98095 sqlite3ErrorMsg(pParse, "too many references to \"%s\": max 65535",
98096 pTab->zName);
98097 pFrom->pTab = 0;
98098 return WRC_Abort;
98099 }
98100 pTab->nRef++;
98101 #if !defined(SQLITE_OMIT_VIEW) || !defined (SQLITE_OMIT_VIRTUALTABLE)
98102 if( pTab->pSelect || IsVirtual(pTab) ){
98103 /* We reach here if the named table is a really a view */
98104 if( sqlite3ViewGetColumnNames(pParse, pTab) ) return WRC_Abort;
@@ -98146,10 +98407,11 @@
98407 NameContext *pOuterNC /* Name context for container */
98408 ){
98409 sqlite3 *db;
98410 if( NEVER(p==0) ) return;
98411 db = pParse->db;
98412 if( db->mallocFailed ) return;
98413 if( p->selFlags & SF_HasTypeInfo ) return;
98414 sqlite3SelectExpand(pParse, p);
98415 if( pParse->nErr || db->mallocFailed ) return;
98416 sqlite3ResolveSelectNames(pParse, p, pOuterNC);
98417 if( pParse->nErr || db->mallocFailed ) return;
@@ -99231,11 +99493,14 @@
99493 SQLITE_PRIVATE void sqlite3ExplainSelect(Vdbe *pVdbe, Select *p){
99494 if( p==0 ){
99495 sqlite3ExplainPrintf(pVdbe, "(null-select)");
99496 return;
99497 }
99498 while( p->pPrior ){
99499 p->pPrior->pNext = p;
99500 p = p->pPrior;
99501 }
99502 sqlite3ExplainPush(pVdbe);
99503 while( p ){
99504 explainOneSelect(pVdbe, p);
99505 p = p->pNext;
99506 if( p==0 ) break;
@@ -102850,11 +103115,10 @@
103115 ** subclauses points to the WhereClause object for the whole clause.
103116 */
103117 struct WhereClause {
103118 Parse *pParse; /* The parser context */
103119 WhereMaskSet *pMaskSet; /* Mapping of table cursor numbers to bitmasks */
 
103120 WhereClause *pOuter; /* Outer conjunction */
103121 u8 op; /* Split operator. TK_AND or TK_OR */
103122 u16 wctrlFlags; /* Might include WHERE_AND_ONLY */
103123 int nTerm; /* Number of terms */
103124 int nSlot; /* Number of entries in a[] */
@@ -103027,11 +103291,10 @@
103291 pWC->pMaskSet = pMaskSet;
103292 pWC->pOuter = 0;
103293 pWC->nTerm = 0;
103294 pWC->nSlot = ArraySize(pWC->aStatic);
103295 pWC->a = pWC->aStatic;
 
103296 pWC->wctrlFlags = wctrlFlags;
103297 }
103298
103299 /* Forward reference */
103300 static void whereClauseClear(WhereClause*);
@@ -103355,13 +103618,12 @@
103618 **
103619 ** If there are multiple terms in the WHERE clause of the form "X <op> <expr>"
103620 ** then try for the one with no dependencies on <expr> - in other words where
103621 ** <expr> is a constant expression of some kind. Only return entries of
103622 ** the form "X <op> Y" where Y is a column in another table if no terms of
103623 ** the form "X <op> <const-expr>" exist. If no terms with a constant RHS
103624 ** exist, try to return a term that does not use WO_EQUIV.
 
103625 */
103626 static WhereTerm *findTerm(
103627 WhereClause *pWC, /* The WHERE clause to be searched */
103628 int iCur, /* Cursor number of LHS */
103629 int iColumn, /* Column number of LHS */
@@ -103416,12 +103678,16 @@
103678 }
103679 if( sqlite3StrICmp(pColl->zName, pIdx->azColl[j]) ){
103680 continue;
103681 }
103682 }
103683 if( pTerm->prereqRight==0 ){
103684 pResult = pTerm;
103685 goto findTerm_success;
103686 }else if( pResult==0 ){
103687 pResult = pTerm;
103688 }
103689 }
103690 if( (pTerm->eOperator & WO_EQUIV)!=0
103691 && nEquiv<ArraySize(aEquiv)
103692 ){
103693 pX = sqlite3ExprSkipCollate(pTerm->pExpr->pRight);
@@ -103627,11 +103893,11 @@
103893 ** (D) x=expr1 OR (y>11 AND y<22 AND z LIKE '*hello*')
103894 ** (E) (p.a=1 AND q.b=2 AND r.c=3) OR (p.x=4 AND q.y=5 AND r.z=6)
103895 **
103896 ** CASE 1:
103897 **
103898 ** If all subterms are of the form T.C=expr for some single column of C and
103899 ** a single table T (as shown in example B above) then create a new virtual
103900 ** term that is an equivalent IN expression. In other words, if the term
103901 ** being analyzed is:
103902 **
103903 ** x = expr1 OR expr2 = x OR x = expr3
@@ -103715,11 +103981,11 @@
103981
103982 /*
103983 ** Compute the set of tables that might satisfy cases 1 or 2.
103984 */
103985 indexable = ~(Bitmask)0;
103986 chngToIN = ~(Bitmask)0;
103987 for(i=pOrWc->nTerm-1, pOrTerm=pOrWc->a; i>=0 && indexable; i--, pOrTerm++){
103988 if( (pOrTerm->eOperator & WO_SINGLE)==0 ){
103989 WhereAndInfo *pAndInfo;
103990 assert( (pOrTerm->wtFlags & (TERM_ANDINFO|TERM_ORINFO))==0 );
103991 chngToIN = 0;
@@ -104982,12 +105248,13 @@
105248 Table *pTab = pSrc->pTab;
105249 sqlite3_index_info *pIdxInfo;
105250 struct sqlite3_index_constraint *pIdxCons;
105251 struct sqlite3_index_constraint_usage *pUsage;
105252 WhereTerm *pTerm;
105253 int i, j, k;
105254 int nOrderBy;
105255 int sortOrder; /* Sort order for IN clauses */
105256 int bAllowIN; /* Allow IN optimizations */
105257 double rCost;
105258
105259 /* Make sure wsFlags is initialized to some sane value. Otherwise, if the
105260 ** malloc in allocateIndexInfo() fails and this function returns leaving
@@ -105082,22 +105349,31 @@
105349
105350 if( vtabBestIndex(pParse, pTab, pIdxInfo) ){
105351 return;
105352 }
105353
105354 sortOrder = SQLITE_SO_ASC;
105355 pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint;
105356 for(i=0; i<pIdxInfo->nConstraint; i++, pIdxCons++){
105357 if( pUsage[i].argvIndex>0 ){
105358 j = pIdxCons->iTermOffset;
105359 pTerm = &pWC->a[j];
105360 p->cost.used |= pTerm->prereqRight;
105361 if( (pTerm->eOperator & WO_IN)!=0 ){
105362 if( pUsage[i].omit==0 ){
105363 /* Do not attempt to use an IN constraint if the virtual table
105364 ** says that the equivalent EQ constraint cannot be safely omitted.
105365 ** If we do attempt to use such a constraint, some rows might be
105366 ** repeated in the output. */
105367 break;
105368 }
105369 for(k=0; k<pIdxInfo->nOrderBy; k++){
105370 if( pIdxInfo->aOrderBy[k].iColumn==pIdxCons->iColumn ){
105371 sortOrder = pIdxInfo->aOrderBy[k].desc;
105372 break;
105373 }
105374 }
105375 }
105376 }
105377 }
105378 if( i>=pIdxInfo->nConstraint ) break;
105379 }
@@ -105123,11 +105399,12 @@
105399 }else{
105400 p->cost.rCost = rCost;
105401 }
105402 p->cost.plan.u.pVtabIdx = pIdxInfo;
105403 if( pIdxInfo->orderByConsumed ){
105404 assert( sortOrder==0 || sortOrder==1 );
105405 p->cost.plan.wsFlags |= WHERE_ORDERED + sortOrder*WHERE_REVERSE;
105406 p->cost.plan.nOBSat = nOrderBy;
105407 }else{
105408 p->cost.plan.nOBSat = p->i ? p->aLevel[p->i-1].plan.nOBSat : 0;
105409 }
105410 p->cost.plan.nEq = 0;
@@ -105720,14 +105997,11 @@
105997 pConstraint = findTerm(p->pWC, base, iColumn, p->notReady,
105998 WO_EQ|WO_ISNULL|WO_IN, pIdx);
105999 if( pConstraint==0 ){
106000 isEq = 0;
106001 }else if( (pConstraint->eOperator & WO_IN)!=0 ){
106002 isEq = 0;
 
 
 
106003 }else if( (pConstraint->eOperator & WO_ISNULL)!=0 ){
106004 uniqueNotNull = 0;
106005 isEq = 1; /* "X IS NULL" means X has only a single value */
106006 }else if( pConstraint->prereqRight==0 ){
106007 isEq = 1; /* Constraint "X=constant" means X has only a single value */
@@ -106027,12 +106301,12 @@
106301 ** constraint for all columns in the index, then this search will find
106302 ** at most a single row. In this case set the WHERE_UNIQUE flag to
106303 ** indicate this to the caller.
106304 **
106305 ** Otherwise, if the search may find more than one row, test to see if
106306 ** there is a range constraint on indexed column (pc.plan.nEq+1) that
106307 ** can be optimized using the index.
106308 */
106309 if( pc.plan.nEq==pProbe->nColumn && pProbe->onError!=OE_None ){
106310 testcase( pc.plan.wsFlags & WHERE_COLUMN_IN );
106311 testcase( pc.plan.wsFlags & WHERE_COLUMN_NULL );
106312 if( (pc.plan.wsFlags & (WHERE_COLUMN_IN|WHERE_COLUMN_NULL))==0 ){
@@ -106369,11 +106643,12 @@
106643 #ifndef SQLITE_OMIT_VIRTUALTABLE
106644 if( IsVirtual(p->pSrc->pTab) ){
106645 sqlite3_index_info *pIdxInfo = 0;
106646 p->ppIdxInfo = &pIdxInfo;
106647 bestVirtualIndex(p);
106648 assert( pIdxInfo!=0 || p->pParse->db->mallocFailed );
106649 if( pIdxInfo && pIdxInfo->needToFreeIdxStr ){
106650 sqlite3_free(pIdxInfo->idxStr);
106651 }
106652 sqlite3DbFree(p->pParse->db, pIdxInfo);
106653 }else
106654 #endif
@@ -106475,11 +106750,12 @@
106750 ** this routine sets up a loop that will iterate over all values of X.
106751 */
106752 static int codeEqualityTerm(
106753 Parse *pParse, /* The parsing context */
106754 WhereTerm *pTerm, /* The term of the WHERE clause to be coded */
106755 WhereLevel *pLevel, /* The level of the FROM clause we are working on */
106756 int iEq, /* Index of the equality term within this level */
106757 int iTarget /* Attempt to leave results in this register */
106758 ){
106759 Expr *pX = pTerm->pExpr;
106760 Vdbe *v = pParse->pVdbe;
106761 int iReg; /* Register holding results */
@@ -106493,16 +106769,30 @@
106769 #ifndef SQLITE_OMIT_SUBQUERY
106770 }else{
106771 int eType;
106772 int iTab;
106773 struct InLoop *pIn;
106774 u8 bRev = (pLevel->plan.wsFlags & WHERE_REVERSE)!=0;
106775
106776 if( (pLevel->plan.wsFlags & WHERE_INDEXED)!=0
106777 && pLevel->plan.u.pIdx->aSortOrder[iEq]
106778 ){
106779 testcase( iEq==0 );
106780 testcase( iEq==pLevel->plan.u.pIdx->nColumn-1 );
106781 testcase( iEq>0 && iEq+1<pLevel->plan.u.pIdx->nColumn );
106782 testcase( bRev );
106783 bRev = !bRev;
106784 }
106785 assert( pX->op==TK_IN );
106786 iReg = iTarget;
106787 eType = sqlite3FindInIndex(pParse, pX, 0);
106788 if( eType==IN_INDEX_INDEX_DESC ){
106789 testcase( bRev );
106790 bRev = !bRev;
106791 }
106792 iTab = pX->iTable;
106793 sqlite3VdbeAddOp2(v, bRev ? OP_Last : OP_Rewind, iTab, 0);
106794 assert( pLevel->plan.wsFlags & WHERE_IN_ABLE );
106795 if( pLevel->u.in.nIn==0 ){
106796 pLevel->addrNxt = sqlite3VdbeMakeLabel(v);
106797 }
106798 pLevel->u.in.nIn++;
@@ -106516,10 +106806,11 @@
106806 if( eType==IN_INDEX_ROWID ){
106807 pIn->addrInTop = sqlite3VdbeAddOp2(v, OP_Rowid, iTab, iReg);
106808 }else{
106809 pIn->addrInTop = sqlite3VdbeAddOp3(v, OP_Column, iTab, 0, iReg);
106810 }
106811 pIn->eEndLoopOp = bRev ? OP_Prev : OP_Next;
106812 sqlite3VdbeAddOp1(v, OP_IsNull, iReg);
106813 }else{
106814 pLevel->u.in.nIn = 0;
106815 }
106816 #endif
@@ -106610,11 +106901,11 @@
106901 if( pTerm==0 ) break;
106902 /* The following true for indices with redundant columns.
106903 ** Ex: CREATE INDEX i1 ON t1(a,b,a); SELECT * FROM t1 WHERE a=0 AND b=0; */
106904 testcase( (pTerm->wtFlags & TERM_CODED)!=0 );
106905 testcase( pTerm->wtFlags & TERM_VIRTUAL ); /* EV: R-30575-11662 */
106906 r1 = codeEqualityTerm(pParse, pTerm, pLevel, j, regBase+j);
106907 if( r1!=regBase+j ){
106908 if( nReg==1 ){
106909 sqlite3ReleaseTempReg(pParse, regBase);
106910 regBase = r1;
106911 }else{
@@ -106884,14 +107175,14 @@
107175 iReg = sqlite3GetTempRange(pParse, nConstraint+2);
107176 addrNotFound = pLevel->addrBrk;
107177 for(j=1; j<=nConstraint; j++){
107178 for(k=0; k<nConstraint; k++){
107179 if( aUsage[k].argvIndex==j ){
 
107180 int iTarget = iReg+j+1;
107181 pTerm = &pWC->a[aConstraint[k].iTermOffset];
107182 if( pTerm->eOperator & WO_IN ){
107183 codeEqualityTerm(pParse, pTerm, pLevel, k, iTarget);
107184 addrNotFound = pLevel->addrNxt;
107185 }else{
107186 sqlite3ExprCode(pParse, pTerm->pExpr->pRight, iTarget);
107187 }
107188 break;
@@ -106928,14 +107219,15 @@
107219 pTerm = findTerm(pWC, iCur, -1, notReady, WO_EQ|WO_IN, 0);
107220 assert( pTerm!=0 );
107221 assert( pTerm->pExpr!=0 );
107222 assert( omitTable==0 );
107223 testcase( pTerm->wtFlags & TERM_VIRTUAL ); /* EV: R-30575-11662 */
107224 iRowidReg = codeEqualityTerm(pParse, pTerm, pLevel, 0, iReleaseReg);
107225 addrNxt = pLevel->addrNxt;
107226 sqlite3VdbeAddOp2(v, OP_MustBeInt, iRowidReg, addrNxt);
107227 sqlite3VdbeAddOp3(v, OP_NotExists, iCur, addrNxt, iRowidReg);
107228 sqlite3ExprCacheAffinityChange(pParse, iRowidReg, 1);
107229 sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg);
107230 VdbeComment((v, "pk"));
107231 pLevel->op = OP_Noop;
107232 }else if( pLevel->plan.wsFlags & WHERE_ROWID_RANGE ){
107233 /* Case 2: We have an inequality comparison against the ROWID field.
@@ -107767,28 +108059,17 @@
108059 ** its Expr.iRightJoinTable value to find the bitmask of the right table
108060 ** of the join. Subtracting one from the right table bitmask gives a
108061 ** bitmask for all tables to the left of the join. Knowing the bitmask
108062 ** for all tables to the left of a left join is important. Ticket #3015.
108063 **
 
 
 
 
 
108064 ** Note that bitmasks are created for all pTabList->nSrc tables in
108065 ** pTabList, not just the first nTabList tables. nTabList is normally
108066 ** equal to pTabList->nSrc but might be shortened to 1 if the
108067 ** WHERE_ONETABLE_ONLY flag is set.
108068 */
 
108069 for(ii=0; ii<pTabList->nSrc; ii++){
108070 createMask(pMaskSet, pTabList->a[ii].iCursor);
 
 
 
 
 
108071 }
108072 #ifndef NDEBUG
108073 {
108074 Bitmask toTheLeft = 0;
108075 for(ii=0; ii<pTabList->nSrc; ii++){
@@ -108268,11 +108549,11 @@
108549 struct InLoop *pIn;
108550 int j;
108551 sqlite3VdbeResolveLabel(v, pLevel->addrNxt);
108552 for(j=pLevel->u.in.nIn, pIn=&pLevel->u.in.aInLoop[j-1]; j>0; j--, pIn--){
108553 sqlite3VdbeJumpHere(v, pIn->addrInTop+1);
108554 sqlite3VdbeAddOp2(v, pIn->eEndLoopOp, pIn->iCur, pIn->addrInTop);
108555 sqlite3VdbeJumpHere(v, pIn->addrInTop-1);
108556 }
108557 sqlite3DbFree(db, pLevel->u.in.aInLoop);
108558 }
108559 sqlite3VdbeResolveLabel(v, pLevel->addrBrk);
@@ -114034,11 +114315,11 @@
114315 }
114316 }
114317 sqlite3VtabRollback(db);
114318 sqlite3EndBenignMalloc();
114319
114320 if( (db->flags&SQLITE_InternChanges)!=0 && db->init.busy==0 ){
114321 sqlite3ExpirePreparedStatements(db);
114322 sqlite3ResetAllSchemasOfConnection(db);
114323 }
114324
114325 /* Any deferred constraint violations have now been resolved. */
114326
+12 -2
--- 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.7.16"
111111
#define SQLITE_VERSION_NUMBER 3007016
112
-#define SQLITE_SOURCE_ID "2013-01-17 17:20:49 38852f158ab20bb4d7b264af987ec1538052bec3"
112
+#define SQLITE_SOURCE_ID "2013-03-13 00:13:25 839aa91faf1db7025d90fa3c65e50efb829b053b"
113113
114114
/*
115115
** CAPI3REF: Run-Time Library Version Numbers
116116
** KEYWORDS: sqlite3_version, sqlite3_sourceid
117117
**
@@ -286,11 +286,11 @@
286286
**
287287
** Applications should [sqlite3_finalize | finalize] all [prepared statements],
288288
** [sqlite3_blob_close | close] all [BLOB handles], and
289289
** [sqlite3_backup_finish | finish] all [sqlite3_backup] objects associated
290290
** with the [sqlite3] object prior to attempting to close the object. ^If
291
-** sqlite3_close() is called on a [database connection] that still has
291
+** sqlite3_close_v2() is called on a [database connection] that still has
292292
** outstanding [prepared statements], [BLOB handles], and/or
293293
** [sqlite3_backup] objects then it returns SQLITE_OK but the deallocation
294294
** of resources is deferred until all [prepared statements], [BLOB handles],
295295
** and [sqlite3_backup] objects are also destroyed.
296296
**
@@ -481,11 +481,21 @@
481481
#define SQLITE_CANTOPEN_ISDIR (SQLITE_CANTOPEN | (2<<8))
482482
#define SQLITE_CANTOPEN_FULLPATH (SQLITE_CANTOPEN | (3<<8))
483483
#define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1<<8))
484484
#define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1<<8))
485485
#define SQLITE_READONLY_CANTLOCK (SQLITE_READONLY | (2<<8))
486
+#define SQLITE_READONLY_ROLLBACK (SQLITE_READONLY | (3<<8))
486487
#define SQLITE_ABORT_ROLLBACK (SQLITE_ABORT | (2<<8))
488
+#define SQLITE_CONSTRAINT_CHECK (SQLITE_CONSTRAINT | (1<<8))
489
+#define SQLITE_CONSTRAINT_COMMITHOOK (SQLITE_CONSTRAINT | (2<<8))
490
+#define SQLITE_CONSTRAINT_FOREIGNKEY (SQLITE_CONSTRAINT | (3<<8))
491
+#define SQLITE_CONSTRAINT_FUNCTION (SQLITE_CONSTRAINT | (4<<8))
492
+#define SQLITE_CONSTRAINT_NOTNULL (SQLITE_CONSTRAINT | (5<<8))
493
+#define SQLITE_CONSTRAINT_PRIMARYKEY (SQLITE_CONSTRAINT | (6<<8))
494
+#define SQLITE_CONSTRAINT_TRIGGER (SQLITE_CONSTRAINT | (7<<8))
495
+#define SQLITE_CONSTRAINT_UNIQUE (SQLITE_CONSTRAINT | (8<<8))
496
+#define SQLITE_CONSTRAINT_VTAB (SQLITE_CONSTRAINT | (9<<8))
487497
488498
/*
489499
** CAPI3REF: Flags For File Open Operations
490500
**
491501
** These bit values are intended for use in the
492502
--- 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.7.16"
111 #define SQLITE_VERSION_NUMBER 3007016
112 #define SQLITE_SOURCE_ID "2013-01-17 17:20:49 38852f158ab20bb4d7b264af987ec1538052bec3"
113
114 /*
115 ** CAPI3REF: Run-Time Library Version Numbers
116 ** KEYWORDS: sqlite3_version, sqlite3_sourceid
117 **
@@ -286,11 +286,11 @@
286 **
287 ** Applications should [sqlite3_finalize | finalize] all [prepared statements],
288 ** [sqlite3_blob_close | close] all [BLOB handles], and
289 ** [sqlite3_backup_finish | finish] all [sqlite3_backup] objects associated
290 ** with the [sqlite3] object prior to attempting to close the object. ^If
291 ** sqlite3_close() is called on a [database connection] that still has
292 ** outstanding [prepared statements], [BLOB handles], and/or
293 ** [sqlite3_backup] objects then it returns SQLITE_OK but the deallocation
294 ** of resources is deferred until all [prepared statements], [BLOB handles],
295 ** and [sqlite3_backup] objects are also destroyed.
296 **
@@ -481,11 +481,21 @@
481 #define SQLITE_CANTOPEN_ISDIR (SQLITE_CANTOPEN | (2<<8))
482 #define SQLITE_CANTOPEN_FULLPATH (SQLITE_CANTOPEN | (3<<8))
483 #define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1<<8))
484 #define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1<<8))
485 #define SQLITE_READONLY_CANTLOCK (SQLITE_READONLY | (2<<8))
 
486 #define SQLITE_ABORT_ROLLBACK (SQLITE_ABORT | (2<<8))
 
 
 
 
 
 
 
 
 
487
488 /*
489 ** CAPI3REF: Flags For File Open Operations
490 **
491 ** These bit values are intended for use in the
492
--- 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.7.16"
111 #define SQLITE_VERSION_NUMBER 3007016
112 #define SQLITE_SOURCE_ID "2013-03-13 00:13:25 839aa91faf1db7025d90fa3c65e50efb829b053b"
113
114 /*
115 ** CAPI3REF: Run-Time Library Version Numbers
116 ** KEYWORDS: sqlite3_version, sqlite3_sourceid
117 **
@@ -286,11 +286,11 @@
286 **
287 ** Applications should [sqlite3_finalize | finalize] all [prepared statements],
288 ** [sqlite3_blob_close | close] all [BLOB handles], and
289 ** [sqlite3_backup_finish | finish] all [sqlite3_backup] objects associated
290 ** with the [sqlite3] object prior to attempting to close the object. ^If
291 ** sqlite3_close_v2() is called on a [database connection] that still has
292 ** outstanding [prepared statements], [BLOB handles], and/or
293 ** [sqlite3_backup] objects then it returns SQLITE_OK but the deallocation
294 ** of resources is deferred until all [prepared statements], [BLOB handles],
295 ** and [sqlite3_backup] objects are also destroyed.
296 **
@@ -481,11 +481,21 @@
481 #define SQLITE_CANTOPEN_ISDIR (SQLITE_CANTOPEN | (2<<8))
482 #define SQLITE_CANTOPEN_FULLPATH (SQLITE_CANTOPEN | (3<<8))
483 #define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1<<8))
484 #define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1<<8))
485 #define SQLITE_READONLY_CANTLOCK (SQLITE_READONLY | (2<<8))
486 #define SQLITE_READONLY_ROLLBACK (SQLITE_READONLY | (3<<8))
487 #define SQLITE_ABORT_ROLLBACK (SQLITE_ABORT | (2<<8))
488 #define SQLITE_CONSTRAINT_CHECK (SQLITE_CONSTRAINT | (1<<8))
489 #define SQLITE_CONSTRAINT_COMMITHOOK (SQLITE_CONSTRAINT | (2<<8))
490 #define SQLITE_CONSTRAINT_FOREIGNKEY (SQLITE_CONSTRAINT | (3<<8))
491 #define SQLITE_CONSTRAINT_FUNCTION (SQLITE_CONSTRAINT | (4<<8))
492 #define SQLITE_CONSTRAINT_NOTNULL (SQLITE_CONSTRAINT | (5<<8))
493 #define SQLITE_CONSTRAINT_PRIMARYKEY (SQLITE_CONSTRAINT | (6<<8))
494 #define SQLITE_CONSTRAINT_TRIGGER (SQLITE_CONSTRAINT | (7<<8))
495 #define SQLITE_CONSTRAINT_UNIQUE (SQLITE_CONSTRAINT | (8<<8))
496 #define SQLITE_CONSTRAINT_VTAB (SQLITE_CONSTRAINT | (9<<8))
497
498 /*
499 ** CAPI3REF: Flags For File Open Operations
500 **
501 ** These bit values are intended for use in the
502
+6 -6
--- src/stat.c
+++ src/stat.c
@@ -156,11 +156,11 @@
156156
int n, m;
157157
int szMax, szAvg;
158158
const char *zDb;
159159
int brief;
160160
char zBuf[100];
161
- const int colWidth = -20 /* printf alignment/width for left column */;
161
+ const int colWidth = -19 /* printf alignment/width for left column */;
162162
brief = find_option("brief", "b",0)!=0;
163163
db_find_and_open_repository(0,0);
164164
fsize = file_size(g.zRepositoryName);
165165
bigSizeName(sizeof(zBuf), zBuf, fsize);
166166
fossil_print( "%*s%s\n", colWidth, "repository-size:", zBuf );
@@ -179,12 +179,12 @@
179179
t = db_column_int64(&q, 0);
180180
szAvg = db_column_int(&q, 1);
181181
szMax = db_column_int(&q, 2);
182182
db_finalize(&q);
183183
bigSizeName(sizeof(zBuf), zBuf, t);
184
- fossil_print( "%*s%d bytes average, "
185
- "%d bytes max, %s total\n",
184
+ fossil_print( "%*s%d average, "
185
+ "%d max, %s total\n",
186186
colWidth, "artifact-sizes:",
187187
szAvg, szMax, zBuf);
188188
if( t/fsize < 5 ){
189189
b = 10;
190190
fsize /= 10;
@@ -214,20 +214,20 @@
214214
n = db_int(0, "SELECT julianday('now') - (SELECT min(mtime) FROM event)"
215215
" + 0.99");
216216
fossil_print("%*s%d days or approximately %.2f years.\n",
217217
colWidth, "project-age:", n, n/365.2425);
218218
fossil_print("%*s%s\n", colWidth, "project-id:", db_get("project-code",""));
219
- fossil_print("%*s%s %s %s (%s)\n",
219
+ fossil_print("%*s%s %s [%s] (%s)\n",
220220
colWidth, "fossil-version:",
221
- RELEASE_VERSION, MANIFEST_DATE, MANIFEST_VERSION,
221
+ MANIFEST_DATE, MANIFEST_VERSION, RELEASE_VERSION,
222222
COMPILER_NAME);
223223
fossil_print("%*s%.19s [%.10s] (%s)\n",
224224
colWidth, "sqlite-version:",
225225
SQLITE_SOURCE_ID, &SQLITE_SOURCE_ID[20],
226226
SQLITE_VERSION);
227227
zDb = db_name("repository");
228
- fossil_print("%*s%d pages, %d bytes/page, %d free pages, "
228
+ fossil_print("%*s%d pages, %d bytes/pg, %d free pages, "
229229
"%s, %s mode\n",
230230
colWidth, "database-stats:",
231231
db_int(0, "PRAGMA %s.page_count", zDb),
232232
db_int(0, "PRAGMA %s.page_size", zDb),
233233
db_int(0, "PRAGMA %s.freelist_count", zDb),
234234
--- src/stat.c
+++ src/stat.c
@@ -156,11 +156,11 @@
156 int n, m;
157 int szMax, szAvg;
158 const char *zDb;
159 int brief;
160 char zBuf[100];
161 const int colWidth = -20 /* printf alignment/width for left column */;
162 brief = find_option("brief", "b",0)!=0;
163 db_find_and_open_repository(0,0);
164 fsize = file_size(g.zRepositoryName);
165 bigSizeName(sizeof(zBuf), zBuf, fsize);
166 fossil_print( "%*s%s\n", colWidth, "repository-size:", zBuf );
@@ -179,12 +179,12 @@
179 t = db_column_int64(&q, 0);
180 szAvg = db_column_int(&q, 1);
181 szMax = db_column_int(&q, 2);
182 db_finalize(&q);
183 bigSizeName(sizeof(zBuf), zBuf, t);
184 fossil_print( "%*s%d bytes average, "
185 "%d bytes max, %s total\n",
186 colWidth, "artifact-sizes:",
187 szAvg, szMax, zBuf);
188 if( t/fsize < 5 ){
189 b = 10;
190 fsize /= 10;
@@ -214,20 +214,20 @@
214 n = db_int(0, "SELECT julianday('now') - (SELECT min(mtime) FROM event)"
215 " + 0.99");
216 fossil_print("%*s%d days or approximately %.2f years.\n",
217 colWidth, "project-age:", n, n/365.2425);
218 fossil_print("%*s%s\n", colWidth, "project-id:", db_get("project-code",""));
219 fossil_print("%*s%s %s %s (%s)\n",
220 colWidth, "fossil-version:",
221 RELEASE_VERSION, MANIFEST_DATE, MANIFEST_VERSION,
222 COMPILER_NAME);
223 fossil_print("%*s%.19s [%.10s] (%s)\n",
224 colWidth, "sqlite-version:",
225 SQLITE_SOURCE_ID, &SQLITE_SOURCE_ID[20],
226 SQLITE_VERSION);
227 zDb = db_name("repository");
228 fossil_print("%*s%d pages, %d bytes/page, %d free pages, "
229 "%s, %s mode\n",
230 colWidth, "database-stats:",
231 db_int(0, "PRAGMA %s.page_count", zDb),
232 db_int(0, "PRAGMA %s.page_size", zDb),
233 db_int(0, "PRAGMA %s.freelist_count", zDb),
234
--- src/stat.c
+++ src/stat.c
@@ -156,11 +156,11 @@
156 int n, m;
157 int szMax, szAvg;
158 const char *zDb;
159 int brief;
160 char zBuf[100];
161 const int colWidth = -19 /* printf alignment/width for left column */;
162 brief = find_option("brief", "b",0)!=0;
163 db_find_and_open_repository(0,0);
164 fsize = file_size(g.zRepositoryName);
165 bigSizeName(sizeof(zBuf), zBuf, fsize);
166 fossil_print( "%*s%s\n", colWidth, "repository-size:", zBuf );
@@ -179,12 +179,12 @@
179 t = db_column_int64(&q, 0);
180 szAvg = db_column_int(&q, 1);
181 szMax = db_column_int(&q, 2);
182 db_finalize(&q);
183 bigSizeName(sizeof(zBuf), zBuf, t);
184 fossil_print( "%*s%d average, "
185 "%d max, %s total\n",
186 colWidth, "artifact-sizes:",
187 szAvg, szMax, zBuf);
188 if( t/fsize < 5 ){
189 b = 10;
190 fsize /= 10;
@@ -214,20 +214,20 @@
214 n = db_int(0, "SELECT julianday('now') - (SELECT min(mtime) FROM event)"
215 " + 0.99");
216 fossil_print("%*s%d days or approximately %.2f years.\n",
217 colWidth, "project-age:", n, n/365.2425);
218 fossil_print("%*s%s\n", colWidth, "project-id:", db_get("project-code",""));
219 fossil_print("%*s%s %s [%s] (%s)\n",
220 colWidth, "fossil-version:",
221 MANIFEST_DATE, MANIFEST_VERSION, RELEASE_VERSION,
222 COMPILER_NAME);
223 fossil_print("%*s%.19s [%.10s] (%s)\n",
224 colWidth, "sqlite-version:",
225 SQLITE_SOURCE_ID, &SQLITE_SOURCE_ID[20],
226 SQLITE_VERSION);
227 zDb = db_name("repository");
228 fossil_print("%*s%d pages, %d bytes/pg, %d free pages, "
229 "%s, %s mode\n",
230 colWidth, "database-stats:",
231 db_int(0, "PRAGMA %s.page_count", zDb),
232 db_int(0, "PRAGMA %s.page_size", zDb),
233 db_int(0, "PRAGMA %s.freelist_count", zDb),
234
+17 -43
--- src/sync.c
+++ src/sync.c
@@ -27,13 +27,11 @@
2727
** if the argument is false.
2828
**
2929
** Return the number of errors.
3030
*/
3131
int autosync(int flags){
32
- const char *zUrl;
3332
const char *zAutosync;
34
- const char *zPw;
3533
int rc;
3634
int configSync = 0; /* configuration changes transferred */
3735
if( g.fNoSync ){
3836
return 0;
3937
}
@@ -49,18 +47,14 @@
4947
return 0; /* Autosync is completely off */
5048
}
5149
}else{
5250
/* Autosync defaults on. To make it default off, "return" here. */
5351
}
54
- zUrl = db_get("last-sync-url", 0);
55
- if( zUrl==0 ){
56
- return 0; /* No default server */
57
- }
58
- zPw = unobscure(db_get("last-sync-pw", 0));
59
- url_parse(zUrl);
52
+ url_parse(0, URL_REMEMBER);
53
+ if( g.urlProtocol==0 ) return 0;
6054
if( g.urlUser!=0 && g.urlPasswd==0 ){
61
- g.urlPasswd = mprintf("%s", zPw);
55
+ g.urlPasswd = unobscure(db_get("last-sync-pw", 0));
6256
}
6357
#if 0 /* Disabled for now */
6458
if( (flags & AUTOSYNC_PULL)!=0 && db_get_boolean("auto-shun",1) ){
6559
/* When doing an automatic pull, also automatically pull shuns from
6660
** the server if pull_shuns is enabled.
@@ -86,14 +80,18 @@
8680
** of a server to sync against. If no argument is given, use the
8781
** most recently synced URL. Remember the current URL for next time.
8882
*/
8983
static void process_sync_args(unsigned *pConfigFlags, unsigned *pSyncFlags){
9084
const char *zUrl = 0;
91
- const char *zPw = 0;
9285
unsigned configSync = 0;
93
- int urlOptional = find_option("autourl",0,0)!=0;
94
- g.dontKeepUrl = find_option("once",0,0)!=0;
86
+ unsigned urlFlags = URL_REMEMBER | URL_PROMPT_PW;
87
+ int urlOptional = 0;
88
+ if( find_option("autourl",0,0)!=0 ){
89
+ urlOptional = 1;
90
+ urlFlags = 0;
91
+ }
92
+ if( find_option("once",0,0)!=0 ) urlFlags &= ~URL_REMEMBER;
9593
if( find_option("private",0,0)!=0 ){
9694
*pSyncFlags |= SYNC_PRIVATE;
9795
}
9896
if( find_option("verbose","v",0)!=0 ){
9997
*pSyncFlags |= SYNC_VERBOSE;
@@ -100,32 +98,19 @@
10098
}
10199
url_proxy_options();
102100
db_find_and_open_repository(0, 0);
103101
db_open_config(0);
104102
if( g.argc==2 ){
105
- zUrl = db_get("last-sync-url", 0);
106
- zPw = unobscure(db_get("last-sync-pw", 0));
107103
if( db_get_boolean("auto-shun",1) ) configSync = CONFIGSET_SHUN;
108104
}else if( g.argc==3 ){
109105
zUrl = g.argv[2];
110106
}
111
- if( zUrl==0 ){
107
+ url_parse(zUrl, urlFlags);
108
+ if( g.urlProtocol==0 ){
112109
if( urlOptional ) fossil_exit(0);
113110
usage("URL");
114111
}
115
- url_parse(zUrl);
116
- if( g.urlUser!=0 && g.urlPasswd==0 && g.urlIsSsh==0 ){
117
- if( zPw==0 ){
118
- url_prompt_for_password();
119
- }else{
120
- g.urlPasswd = mprintf("%s", zPw);
121
- }
122
- }
123
- if( !g.dontKeepUrl ){
124
- db_set("last-sync-url", g.urlCanonical, 0);
125
- if( g.urlPasswd ) db_set("last-sync-pw", obscure(g.urlPasswd), 0);
126
- }
127112
user_select();
128113
if( g.argc==2 ){
129114
if( ((*pSyncFlags) & (SYNC_PUSH|SYNC_PULL))==(SYNC_PUSH|SYNC_PULL) ){
130115
fossil_print("Sync with %s\n", g.urlCanonical);
131116
}else if( (*pSyncFlags) & SYNC_PUSH ){
@@ -258,30 +243,19 @@
258243
db_find_and_open_repository(0, 0);
259244
if( g.argc!=2 && g.argc!=3 ){
260245
usage("remote-url ?URL|off?");
261246
}
262247
if( g.argc==3 ){
263
- if( fossil_strcmp(g.argv[2],"off")==0 ){
264
- db_unset("last-sync-url", 0);
265
- db_unset("last-sync-pw", 0);
266
- }else{
267
- url_parse(g.argv[2]);
268
- if( g.urlUser && g.urlPasswd==0 && g.urlIsSsh==0 ){
269
- url_prompt_for_password();
270
- }
271
- db_set("last-sync-url", g.urlCanonical, 0);
272
- if( g.urlPasswd ){
273
- db_set("last-sync-pw", obscure(g.urlPasswd), 0);
274
- }else{
275
- db_unset("last-sync-pw", 0);
276
- }
277
- }
248
+ db_unset("last-sync-url", 0);
249
+ db_unset("last-sync-pw", 0);
250
+ if( is_false(g.argv[2]) ) return;
251
+ url_parse(g.argv[2], URL_REMEMBER|URL_PROMPT_PW);
278252
}
279253
zUrl = db_get("last-sync-url", 0);
280254
if( zUrl==0 ){
281255
fossil_print("off\n");
282256
return;
283257
}else{
284
- url_parse(zUrl);
258
+ url_parse(zUrl, 0);
285259
fossil_print("%s\n", g.urlCanonical);
286260
}
287261
}
288262
--- src/sync.c
+++ src/sync.c
@@ -27,13 +27,11 @@
27 ** if the argument is false.
28 **
29 ** Return the number of errors.
30 */
31 int autosync(int flags){
32 const char *zUrl;
33 const char *zAutosync;
34 const char *zPw;
35 int rc;
36 int configSync = 0; /* configuration changes transferred */
37 if( g.fNoSync ){
38 return 0;
39 }
@@ -49,18 +47,14 @@
49 return 0; /* Autosync is completely off */
50 }
51 }else{
52 /* Autosync defaults on. To make it default off, "return" here. */
53 }
54 zUrl = db_get("last-sync-url", 0);
55 if( zUrl==0 ){
56 return 0; /* No default server */
57 }
58 zPw = unobscure(db_get("last-sync-pw", 0));
59 url_parse(zUrl);
60 if( g.urlUser!=0 && g.urlPasswd==0 ){
61 g.urlPasswd = mprintf("%s", zPw);
62 }
63 #if 0 /* Disabled for now */
64 if( (flags & AUTOSYNC_PULL)!=0 && db_get_boolean("auto-shun",1) ){
65 /* When doing an automatic pull, also automatically pull shuns from
66 ** the server if pull_shuns is enabled.
@@ -86,14 +80,18 @@
86 ** of a server to sync against. If no argument is given, use the
87 ** most recently synced URL. Remember the current URL for next time.
88 */
89 static void process_sync_args(unsigned *pConfigFlags, unsigned *pSyncFlags){
90 const char *zUrl = 0;
91 const char *zPw = 0;
92 unsigned configSync = 0;
93 int urlOptional = find_option("autourl",0,0)!=0;
94 g.dontKeepUrl = find_option("once",0,0)!=0;
 
 
 
 
 
95 if( find_option("private",0,0)!=0 ){
96 *pSyncFlags |= SYNC_PRIVATE;
97 }
98 if( find_option("verbose","v",0)!=0 ){
99 *pSyncFlags |= SYNC_VERBOSE;
@@ -100,32 +98,19 @@
100 }
101 url_proxy_options();
102 db_find_and_open_repository(0, 0);
103 db_open_config(0);
104 if( g.argc==2 ){
105 zUrl = db_get("last-sync-url", 0);
106 zPw = unobscure(db_get("last-sync-pw", 0));
107 if( db_get_boolean("auto-shun",1) ) configSync = CONFIGSET_SHUN;
108 }else if( g.argc==3 ){
109 zUrl = g.argv[2];
110 }
111 if( zUrl==0 ){
 
112 if( urlOptional ) fossil_exit(0);
113 usage("URL");
114 }
115 url_parse(zUrl);
116 if( g.urlUser!=0 && g.urlPasswd==0 && g.urlIsSsh==0 ){
117 if( zPw==0 ){
118 url_prompt_for_password();
119 }else{
120 g.urlPasswd = mprintf("%s", zPw);
121 }
122 }
123 if( !g.dontKeepUrl ){
124 db_set("last-sync-url", g.urlCanonical, 0);
125 if( g.urlPasswd ) db_set("last-sync-pw", obscure(g.urlPasswd), 0);
126 }
127 user_select();
128 if( g.argc==2 ){
129 if( ((*pSyncFlags) & (SYNC_PUSH|SYNC_PULL))==(SYNC_PUSH|SYNC_PULL) ){
130 fossil_print("Sync with %s\n", g.urlCanonical);
131 }else if( (*pSyncFlags) & SYNC_PUSH ){
@@ -258,30 +243,19 @@
258 db_find_and_open_repository(0, 0);
259 if( g.argc!=2 && g.argc!=3 ){
260 usage("remote-url ?URL|off?");
261 }
262 if( g.argc==3 ){
263 if( fossil_strcmp(g.argv[2],"off")==0 ){
264 db_unset("last-sync-url", 0);
265 db_unset("last-sync-pw", 0);
266 }else{
267 url_parse(g.argv[2]);
268 if( g.urlUser && g.urlPasswd==0 && g.urlIsSsh==0 ){
269 url_prompt_for_password();
270 }
271 db_set("last-sync-url", g.urlCanonical, 0);
272 if( g.urlPasswd ){
273 db_set("last-sync-pw", obscure(g.urlPasswd), 0);
274 }else{
275 db_unset("last-sync-pw", 0);
276 }
277 }
278 }
279 zUrl = db_get("last-sync-url", 0);
280 if( zUrl==0 ){
281 fossil_print("off\n");
282 return;
283 }else{
284 url_parse(zUrl);
285 fossil_print("%s\n", g.urlCanonical);
286 }
287 }
288
--- src/sync.c
+++ src/sync.c
@@ -27,13 +27,11 @@
27 ** if the argument is false.
28 **
29 ** Return the number of errors.
30 */
31 int autosync(int flags){
 
32 const char *zAutosync;
 
33 int rc;
34 int configSync = 0; /* configuration changes transferred */
35 if( g.fNoSync ){
36 return 0;
37 }
@@ -49,18 +47,14 @@
47 return 0; /* Autosync is completely off */
48 }
49 }else{
50 /* Autosync defaults on. To make it default off, "return" here. */
51 }
52 url_parse(0, URL_REMEMBER);
53 if( g.urlProtocol==0 ) return 0;
 
 
 
 
54 if( g.urlUser!=0 && g.urlPasswd==0 ){
55 g.urlPasswd = unobscure(db_get("last-sync-pw", 0));
56 }
57 #if 0 /* Disabled for now */
58 if( (flags & AUTOSYNC_PULL)!=0 && db_get_boolean("auto-shun",1) ){
59 /* When doing an automatic pull, also automatically pull shuns from
60 ** the server if pull_shuns is enabled.
@@ -86,14 +80,18 @@
80 ** of a server to sync against. If no argument is given, use the
81 ** most recently synced URL. Remember the current URL for next time.
82 */
83 static void process_sync_args(unsigned *pConfigFlags, unsigned *pSyncFlags){
84 const char *zUrl = 0;
 
85 unsigned configSync = 0;
86 unsigned urlFlags = URL_REMEMBER | URL_PROMPT_PW;
87 int urlOptional = 0;
88 if( find_option("autourl",0,0)!=0 ){
89 urlOptional = 1;
90 urlFlags = 0;
91 }
92 if( find_option("once",0,0)!=0 ) urlFlags &= ~URL_REMEMBER;
93 if( find_option("private",0,0)!=0 ){
94 *pSyncFlags |= SYNC_PRIVATE;
95 }
96 if( find_option("verbose","v",0)!=0 ){
97 *pSyncFlags |= SYNC_VERBOSE;
@@ -100,32 +98,19 @@
98 }
99 url_proxy_options();
100 db_find_and_open_repository(0, 0);
101 db_open_config(0);
102 if( g.argc==2 ){
 
 
103 if( db_get_boolean("auto-shun",1) ) configSync = CONFIGSET_SHUN;
104 }else if( g.argc==3 ){
105 zUrl = g.argv[2];
106 }
107 url_parse(zUrl, urlFlags);
108 if( g.urlProtocol==0 ){
109 if( urlOptional ) fossil_exit(0);
110 usage("URL");
111 }
 
 
 
 
 
 
 
 
 
 
 
 
112 user_select();
113 if( g.argc==2 ){
114 if( ((*pSyncFlags) & (SYNC_PUSH|SYNC_PULL))==(SYNC_PUSH|SYNC_PULL) ){
115 fossil_print("Sync with %s\n", g.urlCanonical);
116 }else if( (*pSyncFlags) & SYNC_PUSH ){
@@ -258,30 +243,19 @@
243 db_find_and_open_repository(0, 0);
244 if( g.argc!=2 && g.argc!=3 ){
245 usage("remote-url ?URL|off?");
246 }
247 if( g.argc==3 ){
248 db_unset("last-sync-url", 0);
249 db_unset("last-sync-pw", 0);
250 if( is_false(g.argv[2]) ) return;
251 url_parse(g.argv[2], URL_REMEMBER|URL_PROMPT_PW);
 
 
 
 
 
 
 
 
 
 
 
252 }
253 zUrl = db_get("last-sync-url", 0);
254 if( zUrl==0 ){
255 fossil_print("off\n");
256 return;
257 }else{
258 url_parse(zUrl, 0);
259 fossil_print("%s\n", g.urlCanonical);
260 }
261 }
262
+19 -3
--- src/th_main.c
+++ src/th_main.c
@@ -87,14 +87,14 @@
8787
}
8888
8989
/*
9090
** Return a name for a TH1 return code.
9191
*/
92
-const char *Th_ReturnCodeName(int rc){
92
+const char *Th_ReturnCodeName(int rc, int nullIfOk){
9393
static char zRc[32];
9494
switch( rc ){
95
- case TH_OK: return "TH_OK";
95
+ case TH_OK: return nullIfOk ? 0 : "TH_OK";
9696
case TH_ERROR: return "TH_ERROR";
9797
case TH_BREAK: return "TH_BREAK";
9898
case TH_RETURN: return "TH_RETURN";
9999
case TH_CONTINUE: return "TH_CONTINUE";
100100
default: {
@@ -742,11 +742,11 @@
742742
sendError(zResult, nResult, 0);
743743
}
744744
}
745745
if( g.thTrace ){
746746
Th_Trace("th1-setup {%h} => %h<br />\n", g.th1Setup,
747
- Th_ReturnCodeName(rc));
747
+ Th_ReturnCodeName(rc, 0));
748748
}
749749
}
750750
}
751751
752752
/*
@@ -932,5 +932,21 @@
932932
db_open_config(0); /* Needed for global "tcl" setting. */
933933
blob_zero(&in);
934934
blob_read_from_file(&in, g.argv[2]);
935935
Th_Render(blob_str(&in));
936936
}
937
+
938
+/*
939
+** COMMAND: test-th-eval
940
+*/
941
+void test_th_eval(void){
942
+ int rc;
943
+ const char *zRc;
944
+ if( g.argc!=3 ){
945
+ usage("script");
946
+ }
947
+ Th_FossilInit(0, 0);
948
+ rc = Th_Eval(g.interp, 0, g.argv[2], -1);
949
+ zRc = Th_ReturnCodeName(rc, 1);
950
+ fossil_print("%s%s%s\n", zRc, zRc ? ": " : "",
951
+ Th_GetResult(g.interp, 0));
952
+}
937953
--- src/th_main.c
+++ src/th_main.c
@@ -87,14 +87,14 @@
87 }
88
89 /*
90 ** Return a name for a TH1 return code.
91 */
92 const char *Th_ReturnCodeName(int rc){
93 static char zRc[32];
94 switch( rc ){
95 case TH_OK: return "TH_OK";
96 case TH_ERROR: return "TH_ERROR";
97 case TH_BREAK: return "TH_BREAK";
98 case TH_RETURN: return "TH_RETURN";
99 case TH_CONTINUE: return "TH_CONTINUE";
100 default: {
@@ -742,11 +742,11 @@
742 sendError(zResult, nResult, 0);
743 }
744 }
745 if( g.thTrace ){
746 Th_Trace("th1-setup {%h} => %h<br />\n", g.th1Setup,
747 Th_ReturnCodeName(rc));
748 }
749 }
750 }
751
752 /*
@@ -932,5 +932,21 @@
932 db_open_config(0); /* Needed for global "tcl" setting. */
933 blob_zero(&in);
934 blob_read_from_file(&in, g.argv[2]);
935 Th_Render(blob_str(&in));
936 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
937
--- src/th_main.c
+++ src/th_main.c
@@ -87,14 +87,14 @@
87 }
88
89 /*
90 ** Return a name for a TH1 return code.
91 */
92 const char *Th_ReturnCodeName(int rc, int nullIfOk){
93 static char zRc[32];
94 switch( rc ){
95 case TH_OK: return nullIfOk ? 0 : "TH_OK";
96 case TH_ERROR: return "TH_ERROR";
97 case TH_BREAK: return "TH_BREAK";
98 case TH_RETURN: return "TH_RETURN";
99 case TH_CONTINUE: return "TH_CONTINUE";
100 default: {
@@ -742,11 +742,11 @@
742 sendError(zResult, nResult, 0);
743 }
744 }
745 if( g.thTrace ){
746 Th_Trace("th1-setup {%h} => %h<br />\n", g.th1Setup,
747 Th_ReturnCodeName(rc, 0));
748 }
749 }
750 }
751
752 /*
@@ -932,5 +932,21 @@
932 db_open_config(0); /* Needed for global "tcl" setting. */
933 blob_zero(&in);
934 blob_read_from_file(&in, g.argv[2]);
935 Th_Render(blob_str(&in));
936 }
937
938 /*
939 ** COMMAND: test-th-eval
940 */
941 void test_th_eval(void){
942 int rc;
943 const char *zRc;
944 if( g.argc!=3 ){
945 usage("script");
946 }
947 Th_FossilInit(0, 0);
948 rc = Th_Eval(g.interp, 0, g.argv[2], -1);
949 zRc = Th_ReturnCodeName(rc, 1);
950 fossil_print("%s%s%s\n", zRc, zRc ? ": " : "",
951 Th_GetResult(g.interp, 0));
952 }
953
+7 -10
--- src/timeline.c
+++ src/timeline.c
@@ -593,13 +593,10 @@
593593
cgi_printf("],h:\"%s\"}%s", pRow->zUuid, pRow->pNext ? ",\n" : "];\n");
594594
}
595595
cgi_printf("var nrail = %d\n", pGraph->mxRail+1);
596596
graph_free(pGraph);
597597
@ var canvasDiv = gebi("canvas");
598
-#if 0
599
- @ var realCanvas = null;
600
-#endif
601598
@ function drawBox(color,x0,y0,x1,y1){
602599
@ var n = document.createElement("div");
603600
@ if( x0>x1 ){ var t=x0; x0=x1; x1=t; }
604601
@ if( y0>y1 ){ var t=y0; y0=y1; y1=t; }
605602
@ var w = x1-x0+1;
@@ -636,11 +633,11 @@
636633
@ }
637634
@ return left;
638635
@ }
639636
@ function drawUpArrow(x,y0,y1){
640637
@ drawBox("black",x,y0,x+1,y1);
641
- @ if( y0+8>=y1 ){
638
+ @ if( y0+10>=y1 ){
642639
@ drawBox("black",x-1,y0+1,x+2,y0+2);
643640
@ drawBox("black",x-2,y0+3,x+3,y0+4);
644641
@ }else{
645642
@ drawBox("black",x-1,y0+2,x+2,y0+4);
646643
@ drawBox("black",x-2,y0+5,x+3,y0+7);
@@ -647,28 +644,28 @@
647644
@ }
648645
@ }
649646
@ function drawThinArrow(y,xFrom,xTo){
650647
@ if( xFrom<xTo ){
651648
@ drawBox("black",xFrom,y,xTo,y);
652
- @ drawBox("black",xTo-4,y-1,xTo-2,y+1);
653
- @ if( xTo>xFrom-8 ) drawBox("black",xTo-6,y-2,xTo-5,y+2);
649
+ @ drawBox("black",xTo-3,y-1,xTo-2,y+1);
650
+ @ drawBox("black",xTo-4,y-2,xTo-4,y+2);
654651
@ }else{
655652
@ drawBox("black",xTo,y,xFrom,y);
656
- @ drawBox("black",xTo+2,y-1,xTo+4,y+1);
657
- @ if( xTo+8<xFrom ) drawBox("black",xTo+5,y-2,xTo+6,y+2);
653
+ @ drawBox("black",xTo+2,y-1,xTo+3,y+1);
654
+ @ drawBox("black",xTo+4,y-2,xTo+4,y+2);
658655
@ }
659656
@ }
660657
@ function drawThinLine(x0,y0,x1,y1){
661658
@ drawBox("black",x0,y0,x1,y1);
662659
@ }
663660
@ function drawNode(p, left, btm){
664661
@ drawBox("black",p.x-5,p.y-5,p.x+6,p.y+6);
665662
@ drawBox(p.bg,p.x-4,p.y-4,p.x+5,p.y+5);
666663
@ if( p.u>0 ) drawUpArrow(p.x, rowinfo[p.u-1].y+6, p.y-5);
664
+ @ if( p.f&1 ) drawBox("black",p.x-1,p.y-1,p.x+2,p.y+2);
667665
if( !omitDescenders ){
668666
@ if( p.u==0 ) drawUpArrow(p.x, 0, p.y-5);
669
- @ if( p.f&1 ) drawBox("black",p.x-1,p.y-1,p.x+2,p.y+2);
670667
@ if( p.d ) drawUpArrow(p.x, p.y+6, btm);
671668
}
672669
@ if( p.mo>0 ){
673670
@ var x1 = p.mo + left - 1;
674671
@ var y1 = p.y-3;
@@ -721,11 +718,10 @@
721718
@ while( canvasDiv.hasChildNodes() ){
722719
@ canvasDiv.removeChild(canvasDiv.firstChild);
723720
@ }
724721
@ var canvasY = absoluteY("timelineTable");
725722
@ var left = absoluteX("m"+rowinfo[0].id) - absoluteX("canvas") + 15;
726
- @ var width = nrail*railPitch;
727723
@ for(var i in rowinfo){
728724
@ rowinfo[i].y = absoluteY("m"+rowinfo[i].id) + 10 - canvasY;
729725
@ rowinfo[i].x = left + rowinfo[i].r*railPitch;
730726
@ }
731727
@ var btm = absoluteY("grbtm") + 10 - canvasY;
@@ -1143,10 +1139,11 @@
11431139
db_multi_exec("%s", blob_str(&sql));
11441140
if( useDividers ) timeline_add_dividers(0, f_rid);
11451141
blob_appendf(&desc, "Parents and children of check-in ");
11461142
zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", f_rid);
11471143
blob_appendf(&desc, "%z[%.10s]</a>", href("%R/info/%s", zUuid), zUuid);
1144
+ tmFlags |= TIMELINE_DISJOINT;
11481145
}else{
11491146
/* Otherwise, a timeline based on a span of time */
11501147
int n;
11511148
const char *zEType = "timeline item";
11521149
char *zDate;
11531150
--- src/timeline.c
+++ src/timeline.c
@@ -593,13 +593,10 @@
593 cgi_printf("],h:\"%s\"}%s", pRow->zUuid, pRow->pNext ? ",\n" : "];\n");
594 }
595 cgi_printf("var nrail = %d\n", pGraph->mxRail+1);
596 graph_free(pGraph);
597 @ var canvasDiv = gebi("canvas");
598 #if 0
599 @ var realCanvas = null;
600 #endif
601 @ function drawBox(color,x0,y0,x1,y1){
602 @ var n = document.createElement("div");
603 @ if( x0>x1 ){ var t=x0; x0=x1; x1=t; }
604 @ if( y0>y1 ){ var t=y0; y0=y1; y1=t; }
605 @ var w = x1-x0+1;
@@ -636,11 +633,11 @@
636 @ }
637 @ return left;
638 @ }
639 @ function drawUpArrow(x,y0,y1){
640 @ drawBox("black",x,y0,x+1,y1);
641 @ if( y0+8>=y1 ){
642 @ drawBox("black",x-1,y0+1,x+2,y0+2);
643 @ drawBox("black",x-2,y0+3,x+3,y0+4);
644 @ }else{
645 @ drawBox("black",x-1,y0+2,x+2,y0+4);
646 @ drawBox("black",x-2,y0+5,x+3,y0+7);
@@ -647,28 +644,28 @@
647 @ }
648 @ }
649 @ function drawThinArrow(y,xFrom,xTo){
650 @ if( xFrom<xTo ){
651 @ drawBox("black",xFrom,y,xTo,y);
652 @ drawBox("black",xTo-4,y-1,xTo-2,y+1);
653 @ if( xTo>xFrom-8 ) drawBox("black",xTo-6,y-2,xTo-5,y+2);
654 @ }else{
655 @ drawBox("black",xTo,y,xFrom,y);
656 @ drawBox("black",xTo+2,y-1,xTo+4,y+1);
657 @ if( xTo+8<xFrom ) drawBox("black",xTo+5,y-2,xTo+6,y+2);
658 @ }
659 @ }
660 @ function drawThinLine(x0,y0,x1,y1){
661 @ drawBox("black",x0,y0,x1,y1);
662 @ }
663 @ function drawNode(p, left, btm){
664 @ drawBox("black",p.x-5,p.y-5,p.x+6,p.y+6);
665 @ drawBox(p.bg,p.x-4,p.y-4,p.x+5,p.y+5);
666 @ if( p.u>0 ) drawUpArrow(p.x, rowinfo[p.u-1].y+6, p.y-5);
 
667 if( !omitDescenders ){
668 @ if( p.u==0 ) drawUpArrow(p.x, 0, p.y-5);
669 @ if( p.f&1 ) drawBox("black",p.x-1,p.y-1,p.x+2,p.y+2);
670 @ if( p.d ) drawUpArrow(p.x, p.y+6, btm);
671 }
672 @ if( p.mo>0 ){
673 @ var x1 = p.mo + left - 1;
674 @ var y1 = p.y-3;
@@ -721,11 +718,10 @@
721 @ while( canvasDiv.hasChildNodes() ){
722 @ canvasDiv.removeChild(canvasDiv.firstChild);
723 @ }
724 @ var canvasY = absoluteY("timelineTable");
725 @ var left = absoluteX("m"+rowinfo[0].id) - absoluteX("canvas") + 15;
726 @ var width = nrail*railPitch;
727 @ for(var i in rowinfo){
728 @ rowinfo[i].y = absoluteY("m"+rowinfo[i].id) + 10 - canvasY;
729 @ rowinfo[i].x = left + rowinfo[i].r*railPitch;
730 @ }
731 @ var btm = absoluteY("grbtm") + 10 - canvasY;
@@ -1143,10 +1139,11 @@
1143 db_multi_exec("%s", blob_str(&sql));
1144 if( useDividers ) timeline_add_dividers(0, f_rid);
1145 blob_appendf(&desc, "Parents and children of check-in ");
1146 zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", f_rid);
1147 blob_appendf(&desc, "%z[%.10s]</a>", href("%R/info/%s", zUuid), zUuid);
 
1148 }else{
1149 /* Otherwise, a timeline based on a span of time */
1150 int n;
1151 const char *zEType = "timeline item";
1152 char *zDate;
1153
--- src/timeline.c
+++ src/timeline.c
@@ -593,13 +593,10 @@
593 cgi_printf("],h:\"%s\"}%s", pRow->zUuid, pRow->pNext ? ",\n" : "];\n");
594 }
595 cgi_printf("var nrail = %d\n", pGraph->mxRail+1);
596 graph_free(pGraph);
597 @ var canvasDiv = gebi("canvas");
 
 
 
598 @ function drawBox(color,x0,y0,x1,y1){
599 @ var n = document.createElement("div");
600 @ if( x0>x1 ){ var t=x0; x0=x1; x1=t; }
601 @ if( y0>y1 ){ var t=y0; y0=y1; y1=t; }
602 @ var w = x1-x0+1;
@@ -636,11 +633,11 @@
633 @ }
634 @ return left;
635 @ }
636 @ function drawUpArrow(x,y0,y1){
637 @ drawBox("black",x,y0,x+1,y1);
638 @ if( y0+10>=y1 ){
639 @ drawBox("black",x-1,y0+1,x+2,y0+2);
640 @ drawBox("black",x-2,y0+3,x+3,y0+4);
641 @ }else{
642 @ drawBox("black",x-1,y0+2,x+2,y0+4);
643 @ drawBox("black",x-2,y0+5,x+3,y0+7);
@@ -647,28 +644,28 @@
644 @ }
645 @ }
646 @ function drawThinArrow(y,xFrom,xTo){
647 @ if( xFrom<xTo ){
648 @ drawBox("black",xFrom,y,xTo,y);
649 @ drawBox("black",xTo-3,y-1,xTo-2,y+1);
650 @ drawBox("black",xTo-4,y-2,xTo-4,y+2);
651 @ }else{
652 @ drawBox("black",xTo,y,xFrom,y);
653 @ drawBox("black",xTo+2,y-1,xTo+3,y+1);
654 @ drawBox("black",xTo+4,y-2,xTo+4,y+2);
655 @ }
656 @ }
657 @ function drawThinLine(x0,y0,x1,y1){
658 @ drawBox("black",x0,y0,x1,y1);
659 @ }
660 @ function drawNode(p, left, btm){
661 @ drawBox("black",p.x-5,p.y-5,p.x+6,p.y+6);
662 @ drawBox(p.bg,p.x-4,p.y-4,p.x+5,p.y+5);
663 @ if( p.u>0 ) drawUpArrow(p.x, rowinfo[p.u-1].y+6, p.y-5);
664 @ if( p.f&1 ) drawBox("black",p.x-1,p.y-1,p.x+2,p.y+2);
665 if( !omitDescenders ){
666 @ if( p.u==0 ) drawUpArrow(p.x, 0, p.y-5);
 
667 @ if( p.d ) drawUpArrow(p.x, p.y+6, btm);
668 }
669 @ if( p.mo>0 ){
670 @ var x1 = p.mo + left - 1;
671 @ var y1 = p.y-3;
@@ -721,11 +718,10 @@
718 @ while( canvasDiv.hasChildNodes() ){
719 @ canvasDiv.removeChild(canvasDiv.firstChild);
720 @ }
721 @ var canvasY = absoluteY("timelineTable");
722 @ var left = absoluteX("m"+rowinfo[0].id) - absoluteX("canvas") + 15;
 
723 @ for(var i in rowinfo){
724 @ rowinfo[i].y = absoluteY("m"+rowinfo[i].id) + 10 - canvasY;
725 @ rowinfo[i].x = left + rowinfo[i].r*railPitch;
726 @ }
727 @ var btm = absoluteY("grbtm") + 10 - canvasY;
@@ -1143,10 +1139,11 @@
1139 db_multi_exec("%s", blob_str(&sql));
1140 if( useDividers ) timeline_add_dividers(0, f_rid);
1141 blob_appendf(&desc, "Parents and children of check-in ");
1142 zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", f_rid);
1143 blob_appendf(&desc, "%z[%.10s]</a>", href("%R/info/%s", zUuid), zUuid);
1144 tmFlags |= TIMELINE_DISJOINT;
1145 }else{
1146 /* Otherwise, a timeline based on a span of time */
1147 int n;
1148 const char *zEType = "timeline item";
1149 char *zDate;
1150
+7 -10
--- src/timeline.c
+++ src/timeline.c
@@ -593,13 +593,10 @@
593593
cgi_printf("],h:\"%s\"}%s", pRow->zUuid, pRow->pNext ? ",\n" : "];\n");
594594
}
595595
cgi_printf("var nrail = %d\n", pGraph->mxRail+1);
596596
graph_free(pGraph);
597597
@ var canvasDiv = gebi("canvas");
598
-#if 0
599
- @ var realCanvas = null;
600
-#endif
601598
@ function drawBox(color,x0,y0,x1,y1){
602599
@ var n = document.createElement("div");
603600
@ if( x0>x1 ){ var t=x0; x0=x1; x1=t; }
604601
@ if( y0>y1 ){ var t=y0; y0=y1; y1=t; }
605602
@ var w = x1-x0+1;
@@ -636,11 +633,11 @@
636633
@ }
637634
@ return left;
638635
@ }
639636
@ function drawUpArrow(x,y0,y1){
640637
@ drawBox("black",x,y0,x+1,y1);
641
- @ if( y0+8>=y1 ){
638
+ @ if( y0+10>=y1 ){
642639
@ drawBox("black",x-1,y0+1,x+2,y0+2);
643640
@ drawBox("black",x-2,y0+3,x+3,y0+4);
644641
@ }else{
645642
@ drawBox("black",x-1,y0+2,x+2,y0+4);
646643
@ drawBox("black",x-2,y0+5,x+3,y0+7);
@@ -647,28 +644,28 @@
647644
@ }
648645
@ }
649646
@ function drawThinArrow(y,xFrom,xTo){
650647
@ if( xFrom<xTo ){
651648
@ drawBox("black",xFrom,y,xTo,y);
652
- @ drawBox("black",xTo-4,y-1,xTo-2,y+1);
653
- @ if( xTo>xFrom-8 ) drawBox("black",xTo-6,y-2,xTo-5,y+2);
649
+ @ drawBox("black",xTo-3,y-1,xTo-2,y+1);
650
+ @ drawBox("black",xTo-4,y-2,xTo-4,y+2);
654651
@ }else{
655652
@ drawBox("black",xTo,y,xFrom,y);
656
- @ drawBox("black",xTo+2,y-1,xTo+4,y+1);
657
- @ if( xTo+8<xFrom ) drawBox("black",xTo+5,y-2,xTo+6,y+2);
653
+ @ drawBox("black",xTo+2,y-1,xTo+3,y+1);
654
+ @ drawBox("black",xTo+4,y-2,xTo+4,y+2);
658655
@ }
659656
@ }
660657
@ function drawThinLine(x0,y0,x1,y1){
661658
@ drawBox("black",x0,y0,x1,y1);
662659
@ }
663660
@ function drawNode(p, left, btm){
664661
@ drawBox("black",p.x-5,p.y-5,p.x+6,p.y+6);
665662
@ drawBox(p.bg,p.x-4,p.y-4,p.x+5,p.y+5);
666663
@ if( p.u>0 ) drawUpArrow(p.x, rowinfo[p.u-1].y+6, p.y-5);
664
+ @ if( p.f&1 ) drawBox("black",p.x-1,p.y-1,p.x+2,p.y+2);
667665
if( !omitDescenders ){
668666
@ if( p.u==0 ) drawUpArrow(p.x, 0, p.y-5);
669
- @ if( p.f&1 ) drawBox("black",p.x-1,p.y-1,p.x+2,p.y+2);
670667
@ if( p.d ) drawUpArrow(p.x, p.y+6, btm);
671668
}
672669
@ if( p.mo>0 ){
673670
@ var x1 = p.mo + left - 1;
674671
@ var y1 = p.y-3;
@@ -721,11 +718,10 @@
721718
@ while( canvasDiv.hasChildNodes() ){
722719
@ canvasDiv.removeChild(canvasDiv.firstChild);
723720
@ }
724721
@ var canvasY = absoluteY("timelineTable");
725722
@ var left = absoluteX("m"+rowinfo[0].id) - absoluteX("canvas") + 15;
726
- @ var width = nrail*railPitch;
727723
@ for(var i in rowinfo){
728724
@ rowinfo[i].y = absoluteY("m"+rowinfo[i].id) + 10 - canvasY;
729725
@ rowinfo[i].x = left + rowinfo[i].r*railPitch;
730726
@ }
731727
@ var btm = absoluteY("grbtm") + 10 - canvasY;
@@ -1143,10 +1139,11 @@
11431139
db_multi_exec("%s", blob_str(&sql));
11441140
if( useDividers ) timeline_add_dividers(0, f_rid);
11451141
blob_appendf(&desc, "Parents and children of check-in ");
11461142
zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", f_rid);
11471143
blob_appendf(&desc, "%z[%.10s]</a>", href("%R/info/%s", zUuid), zUuid);
1144
+ tmFlags |= TIMELINE_DISJOINT;
11481145
}else{
11491146
/* Otherwise, a timeline based on a span of time */
11501147
int n;
11511148
const char *zEType = "timeline item";
11521149
char *zDate;
11531150
--- src/timeline.c
+++ src/timeline.c
@@ -593,13 +593,10 @@
593 cgi_printf("],h:\"%s\"}%s", pRow->zUuid, pRow->pNext ? ",\n" : "];\n");
594 }
595 cgi_printf("var nrail = %d\n", pGraph->mxRail+1);
596 graph_free(pGraph);
597 @ var canvasDiv = gebi("canvas");
598 #if 0
599 @ var realCanvas = null;
600 #endif
601 @ function drawBox(color,x0,y0,x1,y1){
602 @ var n = document.createElement("div");
603 @ if( x0>x1 ){ var t=x0; x0=x1; x1=t; }
604 @ if( y0>y1 ){ var t=y0; y0=y1; y1=t; }
605 @ var w = x1-x0+1;
@@ -636,11 +633,11 @@
636 @ }
637 @ return left;
638 @ }
639 @ function drawUpArrow(x,y0,y1){
640 @ drawBox("black",x,y0,x+1,y1);
641 @ if( y0+8>=y1 ){
642 @ drawBox("black",x-1,y0+1,x+2,y0+2);
643 @ drawBox("black",x-2,y0+3,x+3,y0+4);
644 @ }else{
645 @ drawBox("black",x-1,y0+2,x+2,y0+4);
646 @ drawBox("black",x-2,y0+5,x+3,y0+7);
@@ -647,28 +644,28 @@
647 @ }
648 @ }
649 @ function drawThinArrow(y,xFrom,xTo){
650 @ if( xFrom<xTo ){
651 @ drawBox("black",xFrom,y,xTo,y);
652 @ drawBox("black",xTo-4,y-1,xTo-2,y+1);
653 @ if( xTo>xFrom-8 ) drawBox("black",xTo-6,y-2,xTo-5,y+2);
654 @ }else{
655 @ drawBox("black",xTo,y,xFrom,y);
656 @ drawBox("black",xTo+2,y-1,xTo+4,y+1);
657 @ if( xTo+8<xFrom ) drawBox("black",xTo+5,y-2,xTo+6,y+2);
658 @ }
659 @ }
660 @ function drawThinLine(x0,y0,x1,y1){
661 @ drawBox("black",x0,y0,x1,y1);
662 @ }
663 @ function drawNode(p, left, btm){
664 @ drawBox("black",p.x-5,p.y-5,p.x+6,p.y+6);
665 @ drawBox(p.bg,p.x-4,p.y-4,p.x+5,p.y+5);
666 @ if( p.u>0 ) drawUpArrow(p.x, rowinfo[p.u-1].y+6, p.y-5);
 
667 if( !omitDescenders ){
668 @ if( p.u==0 ) drawUpArrow(p.x, 0, p.y-5);
669 @ if( p.f&1 ) drawBox("black",p.x-1,p.y-1,p.x+2,p.y+2);
670 @ if( p.d ) drawUpArrow(p.x, p.y+6, btm);
671 }
672 @ if( p.mo>0 ){
673 @ var x1 = p.mo + left - 1;
674 @ var y1 = p.y-3;
@@ -721,11 +718,10 @@
721 @ while( canvasDiv.hasChildNodes() ){
722 @ canvasDiv.removeChild(canvasDiv.firstChild);
723 @ }
724 @ var canvasY = absoluteY("timelineTable");
725 @ var left = absoluteX("m"+rowinfo[0].id) - absoluteX("canvas") + 15;
726 @ var width = nrail*railPitch;
727 @ for(var i in rowinfo){
728 @ rowinfo[i].y = absoluteY("m"+rowinfo[i].id) + 10 - canvasY;
729 @ rowinfo[i].x = left + rowinfo[i].r*railPitch;
730 @ }
731 @ var btm = absoluteY("grbtm") + 10 - canvasY;
@@ -1143,10 +1139,11 @@
1143 db_multi_exec("%s", blob_str(&sql));
1144 if( useDividers ) timeline_add_dividers(0, f_rid);
1145 blob_appendf(&desc, "Parents and children of check-in ");
1146 zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", f_rid);
1147 blob_appendf(&desc, "%z[%.10s]</a>", href("%R/info/%s", zUuid), zUuid);
 
1148 }else{
1149 /* Otherwise, a timeline based on a span of time */
1150 int n;
1151 const char *zEType = "timeline item";
1152 char *zDate;
1153
--- src/timeline.c
+++ src/timeline.c
@@ -593,13 +593,10 @@
593 cgi_printf("],h:\"%s\"}%s", pRow->zUuid, pRow->pNext ? ",\n" : "];\n");
594 }
595 cgi_printf("var nrail = %d\n", pGraph->mxRail+1);
596 graph_free(pGraph);
597 @ var canvasDiv = gebi("canvas");
 
 
 
598 @ function drawBox(color,x0,y0,x1,y1){
599 @ var n = document.createElement("div");
600 @ if( x0>x1 ){ var t=x0; x0=x1; x1=t; }
601 @ if( y0>y1 ){ var t=y0; y0=y1; y1=t; }
602 @ var w = x1-x0+1;
@@ -636,11 +633,11 @@
633 @ }
634 @ return left;
635 @ }
636 @ function drawUpArrow(x,y0,y1){
637 @ drawBox("black",x,y0,x+1,y1);
638 @ if( y0+10>=y1 ){
639 @ drawBox("black",x-1,y0+1,x+2,y0+2);
640 @ drawBox("black",x-2,y0+3,x+3,y0+4);
641 @ }else{
642 @ drawBox("black",x-1,y0+2,x+2,y0+4);
643 @ drawBox("black",x-2,y0+5,x+3,y0+7);
@@ -647,28 +644,28 @@
644 @ }
645 @ }
646 @ function drawThinArrow(y,xFrom,xTo){
647 @ if( xFrom<xTo ){
648 @ drawBox("black",xFrom,y,xTo,y);
649 @ drawBox("black",xTo-3,y-1,xTo-2,y+1);
650 @ drawBox("black",xTo-4,y-2,xTo-4,y+2);
651 @ }else{
652 @ drawBox("black",xTo,y,xFrom,y);
653 @ drawBox("black",xTo+2,y-1,xTo+3,y+1);
654 @ drawBox("black",xTo+4,y-2,xTo+4,y+2);
655 @ }
656 @ }
657 @ function drawThinLine(x0,y0,x1,y1){
658 @ drawBox("black",x0,y0,x1,y1);
659 @ }
660 @ function drawNode(p, left, btm){
661 @ drawBox("black",p.x-5,p.y-5,p.x+6,p.y+6);
662 @ drawBox(p.bg,p.x-4,p.y-4,p.x+5,p.y+5);
663 @ if( p.u>0 ) drawUpArrow(p.x, rowinfo[p.u-1].y+6, p.y-5);
664 @ if( p.f&1 ) drawBox("black",p.x-1,p.y-1,p.x+2,p.y+2);
665 if( !omitDescenders ){
666 @ if( p.u==0 ) drawUpArrow(p.x, 0, p.y-5);
 
667 @ if( p.d ) drawUpArrow(p.x, p.y+6, btm);
668 }
669 @ if( p.mo>0 ){
670 @ var x1 = p.mo + left - 1;
671 @ var y1 = p.y-3;
@@ -721,11 +718,10 @@
718 @ while( canvasDiv.hasChildNodes() ){
719 @ canvasDiv.removeChild(canvasDiv.firstChild);
720 @ }
721 @ var canvasY = absoluteY("timelineTable");
722 @ var left = absoluteX("m"+rowinfo[0].id) - absoluteX("canvas") + 15;
 
723 @ for(var i in rowinfo){
724 @ rowinfo[i].y = absoluteY("m"+rowinfo[i].id) + 10 - canvasY;
725 @ rowinfo[i].x = left + rowinfo[i].r*railPitch;
726 @ }
727 @ var btm = absoluteY("grbtm") + 10 - canvasY;
@@ -1143,10 +1139,11 @@
1139 db_multi_exec("%s", blob_str(&sql));
1140 if( useDividers ) timeline_add_dividers(0, f_rid);
1141 blob_appendf(&desc, "Parents and children of check-in ");
1142 zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", f_rid);
1143 blob_appendf(&desc, "%z[%.10s]</a>", href("%R/info/%s", zUuid), zUuid);
1144 tmFlags |= TIMELINE_DISJOINT;
1145 }else{
1146 /* Otherwise, a timeline based on a span of time */
1147 int n;
1148 const char *zEType = "timeline item";
1149 char *zDate;
1150
+1 -1
--- src/tkt.c
+++ src/tkt.c
@@ -934,11 +934,11 @@
934934
@
935935
@ <li><p>Delete attachment "%h(zFile)"
936936
}else{
937937
@
938938
@ <li><p>Add attachment
939
- @ "%z(href("%R/artifact/%S",zSrc))%h(zFile)</a>"
939
+ @ "%z(href("%R/artifact/%S",zSrc))%s(zFile)</a>"
940940
}
941941
@ [%z(href("%R/artifact/%T",zChngUuid))%s(zShort)</a>]
942942
@ (rid %d(rid)) by
943943
hyperlink_to_user(zUser,zDate," on");
944944
hyperlink_to_date(zDate, ".</p>");
945945
--- src/tkt.c
+++ src/tkt.c
@@ -934,11 +934,11 @@
934 @
935 @ <li><p>Delete attachment "%h(zFile)"
936 }else{
937 @
938 @ <li><p>Add attachment
939 @ "%z(href("%R/artifact/%S",zSrc))%h(zFile)</a>"
940 }
941 @ [%z(href("%R/artifact/%T",zChngUuid))%s(zShort)</a>]
942 @ (rid %d(rid)) by
943 hyperlink_to_user(zUser,zDate," on");
944 hyperlink_to_date(zDate, ".</p>");
945
--- src/tkt.c
+++ src/tkt.c
@@ -934,11 +934,11 @@
934 @
935 @ <li><p>Delete attachment "%h(zFile)"
936 }else{
937 @
938 @ <li><p>Add attachment
939 @ "%z(href("%R/artifact/%S",zSrc))%s(zFile)</a>"
940 }
941 @ [%z(href("%R/artifact/%T",zChngUuid))%s(zShort)</a>]
942 @ (rid %d(rid)) by
943 hyperlink_to_user(zUser,zDate," on");
944 hyperlink_to_date(zDate, ".</p>");
945
+89 -8
--- src/url.c
+++ src/url.c
@@ -17,10 +17,23 @@
1717
**
1818
** This file contains code for parsing URLs that appear on the command-line
1919
*/
2020
#include "config.h"
2121
#include "url.h"
22
+
23
+#if INTERFACE
24
+/*
25
+** Flags for url_parse()
26
+*/
27
+#define URL_PROMPT_PW 0x001 /* Prompt for password if needed */
28
+#define URL_REMEMBER 0x002 /* Remember the url for later reuse */
29
+#define URL_ASK_REMEMBER_PW 0x004 /* Ask whether to remember prompted pw */
30
+#define URL_REMEMBER_PW 0x008 /* Should remember pw */
31
+#define URL_PROMPTED 0x010 /* Prompted for PW already */
32
+
33
+#endif /* INTERFACE */
34
+
2235
2336
/*
2437
** Convert a string to lower-case.
2538
*/
2639
static void url_tolower(char *z){
@@ -29,11 +42,12 @@
2942
z++;
3043
}
3144
}
3245
3346
/*
34
-** Parse the given URL. Populate variables in the global "g" structure.
47
+** Parse the given URL, which describes a sync server. Populate variables
48
+** in the global "g" structure as follows:
3549
**
3650
** g.urlIsFile True if FILE:
3751
** g.urlIsHttps True if HTTPS:
3852
** g.urlIsSsh True if SSH:
3953
** g.urlProtocol "http" or "https" or "file"
@@ -44,22 +58,32 @@
4458
** g.urlUser Userid.
4559
** g.urlPasswd Password.
4660
** g.urlHostname HOST:PORT or just HOST if port is the default.
4761
** g.urlCanonical The URL in canonical form, omitting the password
4862
**
49
-** HTTP url format is:
63
+** HTTP url format as follows (HTTPS is the same with a different scheme):
5064
**
5165
** http://userid:password@host:port/path
5266
**
5367
** SSH url format is:
5468
**
5569
** ssh://userid:password@host:port/path?fossil=path/to/fossil.exe
5670
**
5771
*/
58
-void url_parse(const char *zUrl){
72
+void url_parse(const char *zUrl, unsigned int urlFlags){
5973
int i, j, c;
6074
char *zFile = 0;
75
+ int bPrompted = 0;
76
+ int bSetUrl = 1;
77
+
78
+ if( zUrl==0 ){
79
+ zUrl = db_get("last-sync-url", 0);
80
+ if( zUrl==0 ) return;
81
+ g.urlPasswd = unobscure(db_get("last-sync-pw", 0));
82
+ bSetUrl = 0;
83
+ }
84
+
6185
if( strncmp(zUrl, "http://", 7)==0
6286
|| strncmp(zUrl, "https://", 8)==0
6387
|| strncmp(zUrl, "ssh://", 6)==0
6488
){
6589
int iStart;
@@ -188,15 +212,16 @@
188212
zFile = mprintf("%s/FOSSIL", zUrl);
189213
if( file_isfile(zFile) ){
190214
g.urlIsFile = 1;
191215
}else{
192216
free(zFile);
193
- fossil_panic("unknown repository: %s", zUrl);
217
+ fossil_fatal("unknown repository: %s", zUrl);
194218
}
195219
}else{
196
- fossil_panic("unknown repository: %s", zUrl);
220
+ fossil_fatal("unknown repository: %s", zUrl);
197221
}
222
+ g.urlFlags = urlFlags;
198223
if( g.urlIsFile ){
199224
Blob cfile;
200225
dehttpize(zFile);
201226
file_canonical_name(zFile, &cfile, 0);
202227
free(zFile);
@@ -203,23 +228,45 @@
203228
g.urlProtocol = "file";
204229
g.urlPath = "";
205230
g.urlName = mprintf("%b", &cfile);
206231
g.urlCanonical = mprintf("file://%T", g.urlName);
207232
blob_reset(&cfile);
233
+ }else if( g.urlUser!=0 && g.urlPasswd==0 && (urlFlags & URL_PROMPT_PW) ){
234
+ url_prompt_for_password();
235
+ bPrompted = 1;
236
+ }
237
+ if( urlFlags & URL_REMEMBER ){
238
+ if( bSetUrl ){
239
+ db_set("last-sync-url", g.urlCanonical, 0);
240
+ }
241
+ if( !bPrompted && g.urlPasswd && g.urlUser ){
242
+ db_set("last-sync-pw", obscure(g.urlPasswd), 0);
243
+ }
208244
}
209245
}
210246
211247
/*
212248
** COMMAND: test-urlparser
249
+**
250
+** Usage: %fossil test-urlparser URL ?options?
251
+**
252
+** --remember Store results in last-sync-url
253
+** --prompt-pw Prompt for password if missing
213254
*/
214255
void cmd_test_urlparser(void){
215256
int i;
257
+ unsigned fg = 0;
216258
url_proxy_options();
259
+ if( find_option("remember",0,0) ){
260
+ db_must_be_within_tree();
261
+ fg |= URL_REMEMBER;
262
+ }
263
+ if( find_option("prompt-pw",0,0) ) fg |= URL_PROMPT_PW;
217264
if( g.argc!=3 && g.argc!=4 ){
218265
usage("URL");
219266
}
220
- url_parse(g.argv[2]);
267
+ url_parse(g.argv[2], fg);
221268
for(i=0; i<2; i++){
222269
fossil_print("g.urlIsFile = %d\n", g.urlIsFile);
223270
fossil_print("g.urlIsHttps = %d\n", g.urlIsHttps);
224271
fossil_print("g.urlIsSsh = %d\n", g.urlIsSsh);
225272
fossil_print("g.urlProtocol = %s\n", g.urlProtocol);
@@ -230,10 +277,11 @@
230277
fossil_print("g.urlPath = %s\n", g.urlPath);
231278
fossil_print("g.urlUser = %s\n", g.urlUser);
232279
fossil_print("g.urlPasswd = %s\n", g.urlPasswd);
233280
fossil_print("g.urlCanonical = %s\n", g.urlCanonical);
234281
fossil_print("g.urlFossil = %s\n", g.urlFossil);
282
+ fossil_print("g.urlFlags = 0x%02x\n", g.urlFlags);
235283
if( g.urlIsFile || g.urlIsSsh ) break;
236284
if( i==0 ){
237285
fossil_print("********\n");
238286
url_enable_proxy("Using proxy: ");
239287
}
@@ -282,13 +330,14 @@
282330
if( zProxy && zProxy[0] && !is_false(zProxy) ){
283331
char *zOriginalUrl = g.urlCanonical;
284332
char *zOriginalHost = g.urlHostname;
285333
char *zOriginalUser = g.urlUser;
286334
char *zOriginalPasswd = g.urlPasswd;
335
+ unsigned uOriginalFlags = g.urlFlags;
287336
g.urlUser = 0;
288337
g.urlPasswd = "";
289
- url_parse(zProxy);
338
+ url_parse(zProxy, 0);
290339
if( zMsg ) fossil_print("%s%s\n", zMsg, g.urlCanonical);
291340
g.urlPath = zOriginalUrl;
292341
g.urlHostname = zOriginalHost;
293342
if( g.urlUser ){
294343
char *zCredentials1 = mprintf("%s:%s", g.urlUser, g.urlPasswd);
@@ -296,10 +345,11 @@
296345
g.urlProxyAuth = mprintf("Basic %z", zCredentials2);
297346
free(zCredentials1);
298347
}
299348
g.urlUser = zOriginalUser;
300349
g.urlPasswd = zOriginalPasswd;
350
+ g.urlFlags = uOriginalFlags;
301351
}
302352
}
303353
304354
#if INTERFACE
305355
/*
@@ -379,22 +429,53 @@
379429
/*
380430
** Prompt the user for the password for g.urlUser. Store the result
381431
** in g.urlPasswd.
382432
*/
383433
void url_prompt_for_password(void){
384
- if( isatty(fileno(stdin)) ){
434
+ if( g.urlIsSsh || g.urlIsFile ) return;
435
+ if( isatty(fileno(stdin))
436
+ && (g.urlFlags & URL_PROMPT_PW)!=0
437
+ && (g.urlFlags & URL_PROMPTED)==0
438
+ ){
385439
char *zPrompt = mprintf("\rpassword for %s: ", g.urlUser);
386440
Blob x;
441
+ fossil_force_newline();
387442
prompt_for_password(zPrompt, &x, 0);
388443
free(zPrompt);
389444
g.urlPasswd = mprintf("%b", &x);
390445
blob_reset(&x);
446
+ g.urlFlags |= URL_PROMPTED;
447
+ if( g.urlPasswd[0]
448
+ && (g.urlFlags & (URL_REMEMBER|URL_ASK_REMEMBER_PW))!=0
449
+ ){
450
+ char c;
451
+ prompt_user("remember password (Y/n)? ", &x);
452
+ c = blob_str(&x)[0];
453
+ blob_reset(&x);
454
+ if( c!='n' && c!='N' ){
455
+ g.urlFlags |= URL_REMEMBER_PW;
456
+ if( g.urlFlags & URL_REMEMBER ){
457
+ db_set("last-sync-pw", obscure(g.urlPasswd), 0);
458
+ }
459
+ }
460
+ }
391461
}else{
392462
fossil_fatal("missing or incorrect password for user \"%s\"",
393463
g.urlUser);
394464
}
395465
}
466
+
467
+/*
468
+** Remember the URL if requested.
469
+*/
470
+void url_remember(void){
471
+ db_set("last-sync-url", g.urlCanonical, 0);
472
+ if( g.urlFlags & URL_REMEMBER_PW ){
473
+ db_set("last-sync-pw", obscure(g.urlPasswd), 0);
474
+ }
475
+ g.urlFlags |= URL_REMEMBER;
476
+}
396477
397478
/* Preemptively prompt for a password if a username is given in the
398479
** URL but no password.
399480
*/
400481
void url_get_password_if_needed(void){
401482
--- src/url.c
+++ src/url.c
@@ -17,10 +17,23 @@
17 **
18 ** This file contains code for parsing URLs that appear on the command-line
19 */
20 #include "config.h"
21 #include "url.h"
 
 
 
 
 
 
 
 
 
 
 
 
 
22
23 /*
24 ** Convert a string to lower-case.
25 */
26 static void url_tolower(char *z){
@@ -29,11 +42,12 @@
29 z++;
30 }
31 }
32
33 /*
34 ** Parse the given URL. Populate variables in the global "g" structure.
 
35 **
36 ** g.urlIsFile True if FILE:
37 ** g.urlIsHttps True if HTTPS:
38 ** g.urlIsSsh True if SSH:
39 ** g.urlProtocol "http" or "https" or "file"
@@ -44,22 +58,32 @@
44 ** g.urlUser Userid.
45 ** g.urlPasswd Password.
46 ** g.urlHostname HOST:PORT or just HOST if port is the default.
47 ** g.urlCanonical The URL in canonical form, omitting the password
48 **
49 ** HTTP url format is:
50 **
51 ** http://userid:password@host:port/path
52 **
53 ** SSH url format is:
54 **
55 ** ssh://userid:password@host:port/path?fossil=path/to/fossil.exe
56 **
57 */
58 void url_parse(const char *zUrl){
59 int i, j, c;
60 char *zFile = 0;
 
 
 
 
 
 
 
 
 
 
61 if( strncmp(zUrl, "http://", 7)==0
62 || strncmp(zUrl, "https://", 8)==0
63 || strncmp(zUrl, "ssh://", 6)==0
64 ){
65 int iStart;
@@ -188,15 +212,16 @@
188 zFile = mprintf("%s/FOSSIL", zUrl);
189 if( file_isfile(zFile) ){
190 g.urlIsFile = 1;
191 }else{
192 free(zFile);
193 fossil_panic("unknown repository: %s", zUrl);
194 }
195 }else{
196 fossil_panic("unknown repository: %s", zUrl);
197 }
 
198 if( g.urlIsFile ){
199 Blob cfile;
200 dehttpize(zFile);
201 file_canonical_name(zFile, &cfile, 0);
202 free(zFile);
@@ -203,23 +228,45 @@
203 g.urlProtocol = "file";
204 g.urlPath = "";
205 g.urlName = mprintf("%b", &cfile);
206 g.urlCanonical = mprintf("file://%T", g.urlName);
207 blob_reset(&cfile);
 
 
 
 
 
 
 
 
 
 
 
208 }
209 }
210
211 /*
212 ** COMMAND: test-urlparser
 
 
 
 
 
213 */
214 void cmd_test_urlparser(void){
215 int i;
 
216 url_proxy_options();
 
 
 
 
 
217 if( g.argc!=3 && g.argc!=4 ){
218 usage("URL");
219 }
220 url_parse(g.argv[2]);
221 for(i=0; i<2; i++){
222 fossil_print("g.urlIsFile = %d\n", g.urlIsFile);
223 fossil_print("g.urlIsHttps = %d\n", g.urlIsHttps);
224 fossil_print("g.urlIsSsh = %d\n", g.urlIsSsh);
225 fossil_print("g.urlProtocol = %s\n", g.urlProtocol);
@@ -230,10 +277,11 @@
230 fossil_print("g.urlPath = %s\n", g.urlPath);
231 fossil_print("g.urlUser = %s\n", g.urlUser);
232 fossil_print("g.urlPasswd = %s\n", g.urlPasswd);
233 fossil_print("g.urlCanonical = %s\n", g.urlCanonical);
234 fossil_print("g.urlFossil = %s\n", g.urlFossil);
 
235 if( g.urlIsFile || g.urlIsSsh ) break;
236 if( i==0 ){
237 fossil_print("********\n");
238 url_enable_proxy("Using proxy: ");
239 }
@@ -282,13 +330,14 @@
282 if( zProxy && zProxy[0] && !is_false(zProxy) ){
283 char *zOriginalUrl = g.urlCanonical;
284 char *zOriginalHost = g.urlHostname;
285 char *zOriginalUser = g.urlUser;
286 char *zOriginalPasswd = g.urlPasswd;
 
287 g.urlUser = 0;
288 g.urlPasswd = "";
289 url_parse(zProxy);
290 if( zMsg ) fossil_print("%s%s\n", zMsg, g.urlCanonical);
291 g.urlPath = zOriginalUrl;
292 g.urlHostname = zOriginalHost;
293 if( g.urlUser ){
294 char *zCredentials1 = mprintf("%s:%s", g.urlUser, g.urlPasswd);
@@ -296,10 +345,11 @@
296 g.urlProxyAuth = mprintf("Basic %z", zCredentials2);
297 free(zCredentials1);
298 }
299 g.urlUser = zOriginalUser;
300 g.urlPasswd = zOriginalPasswd;
 
301 }
302 }
303
304 #if INTERFACE
305 /*
@@ -379,22 +429,53 @@
379 /*
380 ** Prompt the user for the password for g.urlUser. Store the result
381 ** in g.urlPasswd.
382 */
383 void url_prompt_for_password(void){
384 if( isatty(fileno(stdin)) ){
 
 
 
 
385 char *zPrompt = mprintf("\rpassword for %s: ", g.urlUser);
386 Blob x;
 
387 prompt_for_password(zPrompt, &x, 0);
388 free(zPrompt);
389 g.urlPasswd = mprintf("%b", &x);
390 blob_reset(&x);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
391 }else{
392 fossil_fatal("missing or incorrect password for user \"%s\"",
393 g.urlUser);
394 }
395 }
 
 
 
 
 
 
 
 
 
 
 
396
397 /* Preemptively prompt for a password if a username is given in the
398 ** URL but no password.
399 */
400 void url_get_password_if_needed(void){
401
--- src/url.c
+++ src/url.c
@@ -17,10 +17,23 @@
17 **
18 ** This file contains code for parsing URLs that appear on the command-line
19 */
20 #include "config.h"
21 #include "url.h"
22
23 #if INTERFACE
24 /*
25 ** Flags for url_parse()
26 */
27 #define URL_PROMPT_PW 0x001 /* Prompt for password if needed */
28 #define URL_REMEMBER 0x002 /* Remember the url for later reuse */
29 #define URL_ASK_REMEMBER_PW 0x004 /* Ask whether to remember prompted pw */
30 #define URL_REMEMBER_PW 0x008 /* Should remember pw */
31 #define URL_PROMPTED 0x010 /* Prompted for PW already */
32
33 #endif /* INTERFACE */
34
35
36 /*
37 ** Convert a string to lower-case.
38 */
39 static void url_tolower(char *z){
@@ -29,11 +42,12 @@
42 z++;
43 }
44 }
45
46 /*
47 ** Parse the given URL, which describes a sync server. Populate variables
48 ** in the global "g" structure as follows:
49 **
50 ** g.urlIsFile True if FILE:
51 ** g.urlIsHttps True if HTTPS:
52 ** g.urlIsSsh True if SSH:
53 ** g.urlProtocol "http" or "https" or "file"
@@ -44,22 +58,32 @@
58 ** g.urlUser Userid.
59 ** g.urlPasswd Password.
60 ** g.urlHostname HOST:PORT or just HOST if port is the default.
61 ** g.urlCanonical The URL in canonical form, omitting the password
62 **
63 ** HTTP url format as follows (HTTPS is the same with a different scheme):
64 **
65 ** http://userid:password@host:port/path
66 **
67 ** SSH url format is:
68 **
69 ** ssh://userid:password@host:port/path?fossil=path/to/fossil.exe
70 **
71 */
72 void url_parse(const char *zUrl, unsigned int urlFlags){
73 int i, j, c;
74 char *zFile = 0;
75 int bPrompted = 0;
76 int bSetUrl = 1;
77
78 if( zUrl==0 ){
79 zUrl = db_get("last-sync-url", 0);
80 if( zUrl==0 ) return;
81 g.urlPasswd = unobscure(db_get("last-sync-pw", 0));
82 bSetUrl = 0;
83 }
84
85 if( strncmp(zUrl, "http://", 7)==0
86 || strncmp(zUrl, "https://", 8)==0
87 || strncmp(zUrl, "ssh://", 6)==0
88 ){
89 int iStart;
@@ -188,15 +212,16 @@
212 zFile = mprintf("%s/FOSSIL", zUrl);
213 if( file_isfile(zFile) ){
214 g.urlIsFile = 1;
215 }else{
216 free(zFile);
217 fossil_fatal("unknown repository: %s", zUrl);
218 }
219 }else{
220 fossil_fatal("unknown repository: %s", zUrl);
221 }
222 g.urlFlags = urlFlags;
223 if( g.urlIsFile ){
224 Blob cfile;
225 dehttpize(zFile);
226 file_canonical_name(zFile, &cfile, 0);
227 free(zFile);
@@ -203,23 +228,45 @@
228 g.urlProtocol = "file";
229 g.urlPath = "";
230 g.urlName = mprintf("%b", &cfile);
231 g.urlCanonical = mprintf("file://%T", g.urlName);
232 blob_reset(&cfile);
233 }else if( g.urlUser!=0 && g.urlPasswd==0 && (urlFlags & URL_PROMPT_PW) ){
234 url_prompt_for_password();
235 bPrompted = 1;
236 }
237 if( urlFlags & URL_REMEMBER ){
238 if( bSetUrl ){
239 db_set("last-sync-url", g.urlCanonical, 0);
240 }
241 if( !bPrompted && g.urlPasswd && g.urlUser ){
242 db_set("last-sync-pw", obscure(g.urlPasswd), 0);
243 }
244 }
245 }
246
247 /*
248 ** COMMAND: test-urlparser
249 **
250 ** Usage: %fossil test-urlparser URL ?options?
251 **
252 ** --remember Store results in last-sync-url
253 ** --prompt-pw Prompt for password if missing
254 */
255 void cmd_test_urlparser(void){
256 int i;
257 unsigned fg = 0;
258 url_proxy_options();
259 if( find_option("remember",0,0) ){
260 db_must_be_within_tree();
261 fg |= URL_REMEMBER;
262 }
263 if( find_option("prompt-pw",0,0) ) fg |= URL_PROMPT_PW;
264 if( g.argc!=3 && g.argc!=4 ){
265 usage("URL");
266 }
267 url_parse(g.argv[2], fg);
268 for(i=0; i<2; i++){
269 fossil_print("g.urlIsFile = %d\n", g.urlIsFile);
270 fossil_print("g.urlIsHttps = %d\n", g.urlIsHttps);
271 fossil_print("g.urlIsSsh = %d\n", g.urlIsSsh);
272 fossil_print("g.urlProtocol = %s\n", g.urlProtocol);
@@ -230,10 +277,11 @@
277 fossil_print("g.urlPath = %s\n", g.urlPath);
278 fossil_print("g.urlUser = %s\n", g.urlUser);
279 fossil_print("g.urlPasswd = %s\n", g.urlPasswd);
280 fossil_print("g.urlCanonical = %s\n", g.urlCanonical);
281 fossil_print("g.urlFossil = %s\n", g.urlFossil);
282 fossil_print("g.urlFlags = 0x%02x\n", g.urlFlags);
283 if( g.urlIsFile || g.urlIsSsh ) break;
284 if( i==0 ){
285 fossil_print("********\n");
286 url_enable_proxy("Using proxy: ");
287 }
@@ -282,13 +330,14 @@
330 if( zProxy && zProxy[0] && !is_false(zProxy) ){
331 char *zOriginalUrl = g.urlCanonical;
332 char *zOriginalHost = g.urlHostname;
333 char *zOriginalUser = g.urlUser;
334 char *zOriginalPasswd = g.urlPasswd;
335 unsigned uOriginalFlags = g.urlFlags;
336 g.urlUser = 0;
337 g.urlPasswd = "";
338 url_parse(zProxy, 0);
339 if( zMsg ) fossil_print("%s%s\n", zMsg, g.urlCanonical);
340 g.urlPath = zOriginalUrl;
341 g.urlHostname = zOriginalHost;
342 if( g.urlUser ){
343 char *zCredentials1 = mprintf("%s:%s", g.urlUser, g.urlPasswd);
@@ -296,10 +345,11 @@
345 g.urlProxyAuth = mprintf("Basic %z", zCredentials2);
346 free(zCredentials1);
347 }
348 g.urlUser = zOriginalUser;
349 g.urlPasswd = zOriginalPasswd;
350 g.urlFlags = uOriginalFlags;
351 }
352 }
353
354 #if INTERFACE
355 /*
@@ -379,22 +429,53 @@
429 /*
430 ** Prompt the user for the password for g.urlUser. Store the result
431 ** in g.urlPasswd.
432 */
433 void url_prompt_for_password(void){
434 if( g.urlIsSsh || g.urlIsFile ) return;
435 if( isatty(fileno(stdin))
436 && (g.urlFlags & URL_PROMPT_PW)!=0
437 && (g.urlFlags & URL_PROMPTED)==0
438 ){
439 char *zPrompt = mprintf("\rpassword for %s: ", g.urlUser);
440 Blob x;
441 fossil_force_newline();
442 prompt_for_password(zPrompt, &x, 0);
443 free(zPrompt);
444 g.urlPasswd = mprintf("%b", &x);
445 blob_reset(&x);
446 g.urlFlags |= URL_PROMPTED;
447 if( g.urlPasswd[0]
448 && (g.urlFlags & (URL_REMEMBER|URL_ASK_REMEMBER_PW))!=0
449 ){
450 char c;
451 prompt_user("remember password (Y/n)? ", &x);
452 c = blob_str(&x)[0];
453 blob_reset(&x);
454 if( c!='n' && c!='N' ){
455 g.urlFlags |= URL_REMEMBER_PW;
456 if( g.urlFlags & URL_REMEMBER ){
457 db_set("last-sync-pw", obscure(g.urlPasswd), 0);
458 }
459 }
460 }
461 }else{
462 fossil_fatal("missing or incorrect password for user \"%s\"",
463 g.urlUser);
464 }
465 }
466
467 /*
468 ** Remember the URL if requested.
469 */
470 void url_remember(void){
471 db_set("last-sync-url", g.urlCanonical, 0);
472 if( g.urlFlags & URL_REMEMBER_PW ){
473 db_set("last-sync-pw", obscure(g.urlPasswd), 0);
474 }
475 g.urlFlags |= URL_REMEMBER;
476 }
477
478 /* Preemptively prompt for a password if a username is given in the
479 ** URL but no password.
480 */
481 void url_get_password_if_needed(void){
482
+2 -7
--- src/user.c
+++ src/user.c
@@ -314,12 +314,10 @@
314314
** (7) Check if the user can be extracted from the remote URL.
315315
**
316316
** The user name is stored in g.zLogin. The uid is in g.userUid.
317317
*/
318318
void user_select(void){
319
- char *zUrl;
320
-
321319
if( g.userUid ) return;
322320
if( g.zLogin ){
323321
if( attempt_user(g.zLogin)==0 ){
324322
fossil_fatal("no such user: %s", g.zLogin);
325323
}else{
@@ -335,15 +333,12 @@
335333
336334
if( attempt_user(fossil_getenv("USER")) ) return;
337335
338336
if( attempt_user(fossil_getenv("USERNAME")) ) return;
339337
340
- zUrl = db_get("last-sync-url", 0);
341
- if( zUrl ){
342
- url_parse(zUrl);
343
- if( attempt_user(g.urlUser) ) return;
344
- }
338
+ url_parse(0, 0);
339
+ if( g.urlUser && attempt_user(g.urlUser) ) return;
345340
346341
fossil_print(
347342
"Cannot figure out who you are! Consider using the --user\n"
348343
"command line option, setting your USER environment variable,\n"
349344
"or setting a default user with \"fossil user default USER\".\n"
350345
--- src/user.c
+++ src/user.c
@@ -314,12 +314,10 @@
314 ** (7) Check if the user can be extracted from the remote URL.
315 **
316 ** The user name is stored in g.zLogin. The uid is in g.userUid.
317 */
318 void user_select(void){
319 char *zUrl;
320
321 if( g.userUid ) return;
322 if( g.zLogin ){
323 if( attempt_user(g.zLogin)==0 ){
324 fossil_fatal("no such user: %s", g.zLogin);
325 }else{
@@ -335,15 +333,12 @@
335
336 if( attempt_user(fossil_getenv("USER")) ) return;
337
338 if( attempt_user(fossil_getenv("USERNAME")) ) return;
339
340 zUrl = db_get("last-sync-url", 0);
341 if( zUrl ){
342 url_parse(zUrl);
343 if( attempt_user(g.urlUser) ) return;
344 }
345
346 fossil_print(
347 "Cannot figure out who you are! Consider using the --user\n"
348 "command line option, setting your USER environment variable,\n"
349 "or setting a default user with \"fossil user default USER\".\n"
350
--- src/user.c
+++ src/user.c
@@ -314,12 +314,10 @@
314 ** (7) Check if the user can be extracted from the remote URL.
315 **
316 ** The user name is stored in g.zLogin. The uid is in g.userUid.
317 */
318 void user_select(void){
 
 
319 if( g.userUid ) return;
320 if( g.zLogin ){
321 if( attempt_user(g.zLogin)==0 ){
322 fossil_fatal("no such user: %s", g.zLogin);
323 }else{
@@ -335,15 +333,12 @@
333
334 if( attempt_user(fossil_getenv("USER")) ) return;
335
336 if( attempt_user(fossil_getenv("USERNAME")) ) return;
337
338 url_parse(0, 0);
339 if( g.urlUser && attempt_user(g.urlUser) ) return;
 
 
 
340
341 fossil_print(
342 "Cannot figure out who you are! Consider using the --user\n"
343 "command line option, setting your USER environment variable,\n"
344 "or setting a default user with \"fossil user default USER\".\n"
345
+101 -31
--- src/utf8.c
+++ src/utf8.c
@@ -23,97 +23,103 @@
2323
#include "utf8.h"
2424
#include <sqlite3.h>
2525
#ifdef _WIN32
2626
# include <windows.h>
2727
#endif
28
+#ifdef __CYGWIN__
29
+# include <sys/cygwin.h>
30
+# define CP_UTF8 65001
31
+ __declspec(dllimport) extern __stdcall int WideCharToMultiByte(int, int,
32
+ const char *, int, const char *, int, const char *, const char *);
33
+ __declspec(dllimport) extern __stdcall int MultiByteToWideChar(int, int,
34
+ const char *, int, wchar_t*, int);
35
+#endif
2836
37
+#ifdef _WIN32
2938
/*
30
-** Translate MBCS to UTF8. Return a pointer to the translated text.
39
+** Translate MBCS to UTF-8. Return a pointer to the translated text.
3140
** Call fossil_mbcs_free() to deallocate any memory used to store the
3241
** returned pointer when done.
3342
*/
3443
char *fossil_mbcs_to_utf8(const char *zMbcs){
35
-#ifdef _WIN32
3644
extern char *sqlite3_win32_mbcs_to_utf8(const char*);
3745
return sqlite3_win32_mbcs_to_utf8(zMbcs);
38
-#else
39
- return (char*)zMbcs; /* No-op on unix */
40
-#endif
4146
}
4247
4348
/*
44
-** After translating from UTF8 to MBCS, invoke this routine to deallocate
49
+** After translating from UTF-8 to MBCS, invoke this routine to deallocate
4550
** any memory used to hold the translation
4651
*/
4752
void fossil_mbcs_free(char *zOld){
48
-#ifdef _WIN32
4953
sqlite3_free(zOld);
50
-#else
51
- /* No-op on unix */
52
-#endif
5354
}
55
+#endif /* _WIN32 */
5456
5557
/*
56
-** Translate Unicode text into UTF8.
58
+** Translate Unicode text into UTF-8.
5759
** Return a pointer to the translated text.
5860
** Call fossil_unicode_free() to deallocate any memory used to store the
5961
** returned pointer when done.
6062
*/
6163
char *fossil_unicode_to_utf8(const void *zUnicode){
62
-#ifdef _WIN32
64
+#if defined(_WIN32) || defined(__CYGWIN__)
6365
int nByte = WideCharToMultiByte(CP_UTF8, 0, zUnicode, -1, 0, 0, 0, 0);
6466
char *zUtf = sqlite3_malloc( nByte );
6567
if( zUtf==0 ){
6668
return 0;
6769
}
6870
WideCharToMultiByte(CP_UTF8, 0, zUnicode, -1, zUtf, nByte, 0, 0);
6971
return zUtf;
7072
#else
71
- return (char *)zUnicode; /* No-op on unix */
73
+ return fossil_strdup(zUnicode); /* TODO: implement for unix */
7274
#endif
7375
}
7476
7577
/*
76
-** Translate UTF8 to unicode for use in system calls. Return a pointer to the
78
+** Translate UTF-8 to unicode for use in system calls. Return a pointer to the
7779
** translated text.. Call fossil_unicode_free() to deallocate any memory
7880
** used to store the returned pointer when done.
7981
*/
8082
void *fossil_utf8_to_unicode(const char *zUtf8){
81
-#ifdef _WIN32
83
+#if defined(_WIN32) || defined(__CYGWIN__)
8284
int nByte = MultiByteToWideChar(CP_UTF8, 0, zUtf8, -1, 0, 0);
8385
wchar_t *zUnicode = sqlite3_malloc( nByte * 2 );
8486
if( zUnicode==0 ){
8587
return 0;
8688
}
8789
MultiByteToWideChar(CP_UTF8, 0, zUtf8, -1, zUnicode, nByte);
8890
return zUnicode;
8991
#else
90
- return (void *)zUtf8; /* No-op on unix */
92
+ return fossil_strdup(zUtf8); /* TODO: implement for unix */
9193
#endif
9294
}
9395
9496
/*
9597
** Deallocate any memory that was previously allocated by
9698
** fossil_unicode_to_utf8().
9799
*/
98100
void fossil_unicode_free(void *pOld){
99
-#ifdef _WIN32
101
+#if defined(_WIN32) || defined(__CYGWIN__)
100102
sqlite3_free(pOld);
101103
#else
102
- /* No-op on unix */
104
+ fossil_free(pOld);
103105
#endif
104106
}
105107
106108
#if defined(__APPLE__) && !defined(WITHOUT_ICONV)
107109
# include <iconv.h>
108110
#endif
109111
110112
/*
111
-** Translate text from the filename character set into
112
-** to precomposed UTF8. Return a pointer to the translated text.
113
+** Translate text from the filename character set into UTF-8.
114
+** Return a pointer to the translated text.
113115
** Call fossil_filename_free() to deallocate any memory used to store the
114116
** returned pointer when done.
117
+**
118
+** This function must not convert '\' to '/' on windows/cygwin, as it is
119
+** used in places where we are not sure it's really filenames we are handling,
120
+** e.g. fossil_getenv() or handling the argv arguments from main().
115121
*/
116122
char *fossil_filename_to_utf8(const void *zFilename){
117123
#if defined(_WIN32)
118124
int nByte = WideCharToMultiByte(CP_UTF8, 0, zFilename, -1, 0, 0, 0, 0);
119125
char *zUtf = sqlite3_malloc( nByte );
@@ -120,10 +126,14 @@
120126
if( zUtf==0 ){
121127
return 0;
122128
}
123129
WideCharToMultiByte(CP_UTF8, 0, zFilename, -1, zUtf, nByte, 0, 0);
124130
return zUtf;
131
+#elif defined(__CYGWIN__)
132
+ char *zOut;
133
+ zOut = fossil_strdup(zFilename);
134
+ return zOut;
125135
#elif defined(__APPLE__) && !defined(WITHOUT_ICONV)
126136
char *zIn = (char*)zFilename;
127137
char *zOut;
128138
iconv_t cd;
129139
size_t n, x;
@@ -149,34 +159,91 @@
149159
return zOut;
150160
#else
151161
return (char *)zFilename; /* No-op on non-mac unix */
152162
#endif
153163
}
164
+
165
+/*
166
+** Translate text from UTF-8 to the filename character set.
167
+** Return a pointer to the translated text.
168
+** Call fossil_filename_free() to deallocate any memory used to store the
169
+** returned pointer when done.
170
+*/
171
+void *fossil_utf8_to_filename(const char *zUtf8){
172
+#ifdef _WIN32
173
+ int nChar = MultiByteToWideChar(CP_UTF8, 0, zUtf8, -1, 0, 0);
174
+ wchar_t *zUnicode = sqlite3_malloc( nChar * 2 );
175
+ wchar_t *wUnicode = zUnicode;
176
+ if( zUnicode==0 ){
177
+ return 0;
178
+ }
179
+ MultiByteToWideChar(CP_UTF8, 0, zUtf8, -1, zUnicode, nChar);
180
+ while( *wUnicode != '\0' ){
181
+ if( *wUnicode == '/' ){
182
+ *wUnicode = '\\';
183
+ }
184
+ ++wUnicode;
185
+ }
186
+ return zUnicode;
187
+#elif defined(__CYGWIN__)
188
+ char *zPath, *p;
189
+ if( fossil_isalpha(zUtf8[0]) && (zUtf8[1]==':')
190
+ && (zUtf8[2]=='\\' || zUtf8[2]=='/')) {
191
+ /* win32 absolute path starting with drive specifier. */
192
+ int nByte;
193
+ wchar_t zUnicode[2000];
194
+ wchar_t *wUnicode = zUnicode;
195
+ MultiByteToWideChar(CP_UTF8, 0, zUtf8, -1, zUnicode, count(zUnicode));
196
+ while( *wUnicode != '\0' ){
197
+ if( *wUnicode == '/' ){
198
+ *wUnicode = '\\';
199
+ }
200
+ ++wUnicode;
201
+ }
202
+ nByte = cygwin_conv_path(CCP_WIN_W_TO_POSIX, zUnicode, NULL, 0);
203
+ zPath = fossil_malloc(nByte);
204
+ cygwin_conv_path(CCP_WIN_W_TO_POSIX, zUnicode, zPath, nByte);
205
+ } else {
206
+ zPath = fossil_strdup(zUtf8);
207
+ zUtf8 = p = zPath;
208
+ while( (*p = *zUtf8++) != 0){
209
+ if (*p++ == '\\' ) {
210
+ p[-1] = '/';
211
+ }
212
+ }
213
+ }
214
+ return zPath;
215
+#elif defined(__APPLE__) && !defined(WITHOUT_ICONV)
216
+ return fossil_strdup(zUtf8);
217
+#else
218
+ return (void *)zUtf8; /* No-op on unix */
219
+#endif
220
+}
154221
155222
/*
156223
** Deallocate any memory that was previously allocated by
157
-** fossil_filename_to_utf8().
224
+** fossil_filename_to_utf8() or fossil_utf8_to_filename().
158225
*/
159
-void fossil_filename_free(char *pOld){
226
+void fossil_filename_free(void *pOld){
160227
#if defined(_WIN32)
161228
sqlite3_free(pOld);
162
-#elif defined(__APPLE__) && !defined(WITHOUT_ICONV)
229
+#elif (defined(__APPLE__) && !defined(WITHOUT_ICONV)) || defined(__CYGWIN__)
163230
fossil_free(pOld);
164231
#else
165232
/* No-op on all other unix */
166233
#endif
167234
}
168235
169236
/*
170
-** Display UTF8 on the console. Return the number of
237
+** Display UTF-8 on the console. Return the number of
171238
** Characters written. If stdout or stderr is redirected
172239
** to a file, -1 is returned and nothing is written
173240
** to the console.
174241
*/
175242
int fossil_utf8_to_console(const char *zUtf8, int nByte, int toStdErr){
176243
#ifdef _WIN32
177
- int nChar;
244
+ int nChar, written = 0;
178245
wchar_t *zUnicode; /* Unicode version of zUtf8 */
179246
DWORD dummy;
180247
181248
static int istty[2] = { -1, -1 };
182249
if( istty[toStdErr] == -1 ){
@@ -191,17 +258,20 @@
191258
zUnicode = malloc( (nChar + 1) *sizeof(zUnicode[0]) );
192259
if( zUnicode==0 ){
193260
return 0;
194261
}
195262
nChar = MultiByteToWideChar(CP_UTF8, 0, zUtf8, nByte, zUnicode, nChar);
196
- if( nChar==0 ){
197
- free(zUnicode);
198
- return 0;
263
+ /* Split WriteConsoleW call into multiple chunks, if necessary. See:
264
+ * <https://connect.microsoft.com/VisualStudio/feedback/details/635230> */
265
+ while( written < nChar ){
266
+ int size = nChar-written;
267
+ if (size > 26000) size = 26000;
268
+ WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE - toStdErr), zUnicode+written,
269
+ size, &dummy, 0);
270
+ written += size;
199271
}
200
- zUnicode[nChar] = '\0';
201
- WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE - toStdErr), zUnicode, nChar,
202
- &dummy, 0);
272
+ free(zUnicode);
203273
return nChar;
204274
#else
205275
return -1; /* No-op on unix */
206276
#endif
207277
}
208278
209279
ADDED src/util.c
--- src/utf8.c
+++ src/utf8.c
@@ -23,97 +23,103 @@
23 #include "utf8.h"
24 #include <sqlite3.h>
25 #ifdef _WIN32
26 # include <windows.h>
27 #endif
 
 
 
 
 
 
 
 
28
 
29 /*
30 ** Translate MBCS to UTF8. Return a pointer to the translated text.
31 ** Call fossil_mbcs_free() to deallocate any memory used to store the
32 ** returned pointer when done.
33 */
34 char *fossil_mbcs_to_utf8(const char *zMbcs){
35 #ifdef _WIN32
36 extern char *sqlite3_win32_mbcs_to_utf8(const char*);
37 return sqlite3_win32_mbcs_to_utf8(zMbcs);
38 #else
39 return (char*)zMbcs; /* No-op on unix */
40 #endif
41 }
42
43 /*
44 ** After translating from UTF8 to MBCS, invoke this routine to deallocate
45 ** any memory used to hold the translation
46 */
47 void fossil_mbcs_free(char *zOld){
48 #ifdef _WIN32
49 sqlite3_free(zOld);
50 #else
51 /* No-op on unix */
52 #endif
53 }
 
54
55 /*
56 ** Translate Unicode text into UTF8.
57 ** Return a pointer to the translated text.
58 ** Call fossil_unicode_free() to deallocate any memory used to store the
59 ** returned pointer when done.
60 */
61 char *fossil_unicode_to_utf8(const void *zUnicode){
62 #ifdef _WIN32
63 int nByte = WideCharToMultiByte(CP_UTF8, 0, zUnicode, -1, 0, 0, 0, 0);
64 char *zUtf = sqlite3_malloc( nByte );
65 if( zUtf==0 ){
66 return 0;
67 }
68 WideCharToMultiByte(CP_UTF8, 0, zUnicode, -1, zUtf, nByte, 0, 0);
69 return zUtf;
70 #else
71 return (char *)zUnicode; /* No-op on unix */
72 #endif
73 }
74
75 /*
76 ** Translate UTF8 to unicode for use in system calls. Return a pointer to the
77 ** translated text.. Call fossil_unicode_free() to deallocate any memory
78 ** used to store the returned pointer when done.
79 */
80 void *fossil_utf8_to_unicode(const char *zUtf8){
81 #ifdef _WIN32
82 int nByte = MultiByteToWideChar(CP_UTF8, 0, zUtf8, -1, 0, 0);
83 wchar_t *zUnicode = sqlite3_malloc( nByte * 2 );
84 if( zUnicode==0 ){
85 return 0;
86 }
87 MultiByteToWideChar(CP_UTF8, 0, zUtf8, -1, zUnicode, nByte);
88 return zUnicode;
89 #else
90 return (void *)zUtf8; /* No-op on unix */
91 #endif
92 }
93
94 /*
95 ** Deallocate any memory that was previously allocated by
96 ** fossil_unicode_to_utf8().
97 */
98 void fossil_unicode_free(void *pOld){
99 #ifdef _WIN32
100 sqlite3_free(pOld);
101 #else
102 /* No-op on unix */
103 #endif
104 }
105
106 #if defined(__APPLE__) && !defined(WITHOUT_ICONV)
107 # include <iconv.h>
108 #endif
109
110 /*
111 ** Translate text from the filename character set into
112 ** to precomposed UTF8. Return a pointer to the translated text.
113 ** Call fossil_filename_free() to deallocate any memory used to store the
114 ** returned pointer when done.
 
 
 
 
115 */
116 char *fossil_filename_to_utf8(const void *zFilename){
117 #if defined(_WIN32)
118 int nByte = WideCharToMultiByte(CP_UTF8, 0, zFilename, -1, 0, 0, 0, 0);
119 char *zUtf = sqlite3_malloc( nByte );
@@ -120,10 +126,14 @@
120 if( zUtf==0 ){
121 return 0;
122 }
123 WideCharToMultiByte(CP_UTF8, 0, zFilename, -1, zUtf, nByte, 0, 0);
124 return zUtf;
 
 
 
 
125 #elif defined(__APPLE__) && !defined(WITHOUT_ICONV)
126 char *zIn = (char*)zFilename;
127 char *zOut;
128 iconv_t cd;
129 size_t n, x;
@@ -149,34 +159,91 @@
149 return zOut;
150 #else
151 return (char *)zFilename; /* No-op on non-mac unix */
152 #endif
153 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
154
155 /*
156 ** Deallocate any memory that was previously allocated by
157 ** fossil_filename_to_utf8().
158 */
159 void fossil_filename_free(char *pOld){
160 #if defined(_WIN32)
161 sqlite3_free(pOld);
162 #elif defined(__APPLE__) && !defined(WITHOUT_ICONV)
163 fossil_free(pOld);
164 #else
165 /* No-op on all other unix */
166 #endif
167 }
168
169 /*
170 ** Display UTF8 on the console. Return the number of
171 ** Characters written. If stdout or stderr is redirected
172 ** to a file, -1 is returned and nothing is written
173 ** to the console.
174 */
175 int fossil_utf8_to_console(const char *zUtf8, int nByte, int toStdErr){
176 #ifdef _WIN32
177 int nChar;
178 wchar_t *zUnicode; /* Unicode version of zUtf8 */
179 DWORD dummy;
180
181 static int istty[2] = { -1, -1 };
182 if( istty[toStdErr] == -1 ){
@@ -191,17 +258,20 @@
191 zUnicode = malloc( (nChar + 1) *sizeof(zUnicode[0]) );
192 if( zUnicode==0 ){
193 return 0;
194 }
195 nChar = MultiByteToWideChar(CP_UTF8, 0, zUtf8, nByte, zUnicode, nChar);
196 if( nChar==0 ){
197 free(zUnicode);
198 return 0;
 
 
 
 
 
199 }
200 zUnicode[nChar] = '\0';
201 WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE - toStdErr), zUnicode, nChar,
202 &dummy, 0);
203 return nChar;
204 #else
205 return -1; /* No-op on unix */
206 #endif
207 }
208
209 DDED src/util.c
--- src/utf8.c
+++ src/utf8.c
@@ -23,97 +23,103 @@
23 #include "utf8.h"
24 #include <sqlite3.h>
25 #ifdef _WIN32
26 # include <windows.h>
27 #endif
28 #ifdef __CYGWIN__
29 # include <sys/cygwin.h>
30 # define CP_UTF8 65001
31 __declspec(dllimport) extern __stdcall int WideCharToMultiByte(int, int,
32 const char *, int, const char *, int, const char *, const char *);
33 __declspec(dllimport) extern __stdcall int MultiByteToWideChar(int, int,
34 const char *, int, wchar_t*, int);
35 #endif
36
37 #ifdef _WIN32
38 /*
39 ** Translate MBCS to UTF-8. Return a pointer to the translated text.
40 ** Call fossil_mbcs_free() to deallocate any memory used to store the
41 ** returned pointer when done.
42 */
43 char *fossil_mbcs_to_utf8(const char *zMbcs){
 
44 extern char *sqlite3_win32_mbcs_to_utf8(const char*);
45 return sqlite3_win32_mbcs_to_utf8(zMbcs);
 
 
 
46 }
47
48 /*
49 ** After translating from UTF-8 to MBCS, invoke this routine to deallocate
50 ** any memory used to hold the translation
51 */
52 void fossil_mbcs_free(char *zOld){
 
53 sqlite3_free(zOld);
 
 
 
54 }
55 #endif /* _WIN32 */
56
57 /*
58 ** Translate Unicode text into UTF-8.
59 ** Return a pointer to the translated text.
60 ** Call fossil_unicode_free() to deallocate any memory used to store the
61 ** returned pointer when done.
62 */
63 char *fossil_unicode_to_utf8(const void *zUnicode){
64 #if defined(_WIN32) || defined(__CYGWIN__)
65 int nByte = WideCharToMultiByte(CP_UTF8, 0, zUnicode, -1, 0, 0, 0, 0);
66 char *zUtf = sqlite3_malloc( nByte );
67 if( zUtf==0 ){
68 return 0;
69 }
70 WideCharToMultiByte(CP_UTF8, 0, zUnicode, -1, zUtf, nByte, 0, 0);
71 return zUtf;
72 #else
73 return fossil_strdup(zUnicode); /* TODO: implement for unix */
74 #endif
75 }
76
77 /*
78 ** Translate UTF-8 to unicode for use in system calls. Return a pointer to the
79 ** translated text.. Call fossil_unicode_free() to deallocate any memory
80 ** used to store the returned pointer when done.
81 */
82 void *fossil_utf8_to_unicode(const char *zUtf8){
83 #if defined(_WIN32) || defined(__CYGWIN__)
84 int nByte = MultiByteToWideChar(CP_UTF8, 0, zUtf8, -1, 0, 0);
85 wchar_t *zUnicode = sqlite3_malloc( nByte * 2 );
86 if( zUnicode==0 ){
87 return 0;
88 }
89 MultiByteToWideChar(CP_UTF8, 0, zUtf8, -1, zUnicode, nByte);
90 return zUnicode;
91 #else
92 return fossil_strdup(zUtf8); /* TODO: implement for unix */
93 #endif
94 }
95
96 /*
97 ** Deallocate any memory that was previously allocated by
98 ** fossil_unicode_to_utf8().
99 */
100 void fossil_unicode_free(void *pOld){
101 #if defined(_WIN32) || defined(__CYGWIN__)
102 sqlite3_free(pOld);
103 #else
104 fossil_free(pOld);
105 #endif
106 }
107
108 #if defined(__APPLE__) && !defined(WITHOUT_ICONV)
109 # include <iconv.h>
110 #endif
111
112 /*
113 ** Translate text from the filename character set into UTF-8.
114 ** Return a pointer to the translated text.
115 ** Call fossil_filename_free() to deallocate any memory used to store the
116 ** returned pointer when done.
117 **
118 ** This function must not convert '\' to '/' on windows/cygwin, as it is
119 ** used in places where we are not sure it's really filenames we are handling,
120 ** e.g. fossil_getenv() or handling the argv arguments from main().
121 */
122 char *fossil_filename_to_utf8(const void *zFilename){
123 #if defined(_WIN32)
124 int nByte = WideCharToMultiByte(CP_UTF8, 0, zFilename, -1, 0, 0, 0, 0);
125 char *zUtf = sqlite3_malloc( nByte );
@@ -120,10 +126,14 @@
126 if( zUtf==0 ){
127 return 0;
128 }
129 WideCharToMultiByte(CP_UTF8, 0, zFilename, -1, zUtf, nByte, 0, 0);
130 return zUtf;
131 #elif defined(__CYGWIN__)
132 char *zOut;
133 zOut = fossil_strdup(zFilename);
134 return zOut;
135 #elif defined(__APPLE__) && !defined(WITHOUT_ICONV)
136 char *zIn = (char*)zFilename;
137 char *zOut;
138 iconv_t cd;
139 size_t n, x;
@@ -149,34 +159,91 @@
159 return zOut;
160 #else
161 return (char *)zFilename; /* No-op on non-mac unix */
162 #endif
163 }
164
165 /*
166 ** Translate text from UTF-8 to the filename character set.
167 ** Return a pointer to the translated text.
168 ** Call fossil_filename_free() to deallocate any memory used to store the
169 ** returned pointer when done.
170 */
171 void *fossil_utf8_to_filename(const char *zUtf8){
172 #ifdef _WIN32
173 int nChar = MultiByteToWideChar(CP_UTF8, 0, zUtf8, -1, 0, 0);
174 wchar_t *zUnicode = sqlite3_malloc( nChar * 2 );
175 wchar_t *wUnicode = zUnicode;
176 if( zUnicode==0 ){
177 return 0;
178 }
179 MultiByteToWideChar(CP_UTF8, 0, zUtf8, -1, zUnicode, nChar);
180 while( *wUnicode != '\0' ){
181 if( *wUnicode == '/' ){
182 *wUnicode = '\\';
183 }
184 ++wUnicode;
185 }
186 return zUnicode;
187 #elif defined(__CYGWIN__)
188 char *zPath, *p;
189 if( fossil_isalpha(zUtf8[0]) && (zUtf8[1]==':')
190 && (zUtf8[2]=='\\' || zUtf8[2]=='/')) {
191 /* win32 absolute path starting with drive specifier. */
192 int nByte;
193 wchar_t zUnicode[2000];
194 wchar_t *wUnicode = zUnicode;
195 MultiByteToWideChar(CP_UTF8, 0, zUtf8, -1, zUnicode, count(zUnicode));
196 while( *wUnicode != '\0' ){
197 if( *wUnicode == '/' ){
198 *wUnicode = '\\';
199 }
200 ++wUnicode;
201 }
202 nByte = cygwin_conv_path(CCP_WIN_W_TO_POSIX, zUnicode, NULL, 0);
203 zPath = fossil_malloc(nByte);
204 cygwin_conv_path(CCP_WIN_W_TO_POSIX, zUnicode, zPath, nByte);
205 } else {
206 zPath = fossil_strdup(zUtf8);
207 zUtf8 = p = zPath;
208 while( (*p = *zUtf8++) != 0){
209 if (*p++ == '\\' ) {
210 p[-1] = '/';
211 }
212 }
213 }
214 return zPath;
215 #elif defined(__APPLE__) && !defined(WITHOUT_ICONV)
216 return fossil_strdup(zUtf8);
217 #else
218 return (void *)zUtf8; /* No-op on unix */
219 #endif
220 }
221
222 /*
223 ** Deallocate any memory that was previously allocated by
224 ** fossil_filename_to_utf8() or fossil_utf8_to_filename().
225 */
226 void fossil_filename_free(void *pOld){
227 #if defined(_WIN32)
228 sqlite3_free(pOld);
229 #elif (defined(__APPLE__) && !defined(WITHOUT_ICONV)) || defined(__CYGWIN__)
230 fossil_free(pOld);
231 #else
232 /* No-op on all other unix */
233 #endif
234 }
235
236 /*
237 ** Display UTF-8 on the console. Return the number of
238 ** Characters written. If stdout or stderr is redirected
239 ** to a file, -1 is returned and nothing is written
240 ** to the console.
241 */
242 int fossil_utf8_to_console(const char *zUtf8, int nByte, int toStdErr){
243 #ifdef _WIN32
244 int nChar, written = 0;
245 wchar_t *zUnicode; /* Unicode version of zUtf8 */
246 DWORD dummy;
247
248 static int istty[2] = { -1, -1 };
249 if( istty[toStdErr] == -1 ){
@@ -191,17 +258,20 @@
258 zUnicode = malloc( (nChar + 1) *sizeof(zUnicode[0]) );
259 if( zUnicode==0 ){
260 return 0;
261 }
262 nChar = MultiByteToWideChar(CP_UTF8, 0, zUtf8, nByte, zUnicode, nChar);
263 /* Split WriteConsoleW call into multiple chunks, if necessary. See:
264 * <https://connect.microsoft.com/VisualStudio/feedback/details/635230> */
265 while( written < nChar ){
266 int size = nChar-written;
267 if (size > 26000) size = 26000;
268 WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE - toStdErr), zUnicode+written,
269 size, &dummy, 0);
270 written += size;
271 }
272 free(zUnicode);
 
 
273 return nChar;
274 #else
275 return -1; /* No-op on unix */
276 #endif
277 }
278
279 DDED src/util.c

No diff available

+2 -2
--- src/vfile.c
+++ src/vfile.c
@@ -459,11 +459,11 @@
459459
);
460460
}
461461
depth++;
462462
463463
zDir = blob_str(pPath);
464
- zNative = fossil_utf8_to_unicode(zDir);
464
+ zNative = fossil_utf8_to_filename(zDir);
465465
d = opendir(zNative);
466466
if( d ){
467467
while( (pEntry=readdir(d))!=0 ){
468468
char *zPath;
469469
char *zUtf8;
@@ -491,11 +491,11 @@
491491
fossil_filename_free(zUtf8);
492492
blob_resize(pPath, origSize);
493493
}
494494
closedir(d);
495495
}
496
- fossil_unicode_free(zNative);
496
+ fossil_filename_free(zNative);
497497
498498
depth--;
499499
if( depth==0 ){
500500
db_finalize(&ins);
501501
}
502502
--- src/vfile.c
+++ src/vfile.c
@@ -459,11 +459,11 @@
459 );
460 }
461 depth++;
462
463 zDir = blob_str(pPath);
464 zNative = fossil_utf8_to_unicode(zDir);
465 d = opendir(zNative);
466 if( d ){
467 while( (pEntry=readdir(d))!=0 ){
468 char *zPath;
469 char *zUtf8;
@@ -491,11 +491,11 @@
491 fossil_filename_free(zUtf8);
492 blob_resize(pPath, origSize);
493 }
494 closedir(d);
495 }
496 fossil_unicode_free(zNative);
497
498 depth--;
499 if( depth==0 ){
500 db_finalize(&ins);
501 }
502
--- src/vfile.c
+++ src/vfile.c
@@ -459,11 +459,11 @@
459 );
460 }
461 depth++;
462
463 zDir = blob_str(pPath);
464 zNative = fossil_utf8_to_filename(zDir);
465 d = opendir(zNative);
466 if( d ){
467 while( (pEntry=readdir(d))!=0 ){
468 char *zPath;
469 char *zUtf8;
@@ -491,11 +491,11 @@
491 fossil_filename_free(zUtf8);
492 blob_resize(pPath, origSize);
493 }
494 closedir(d);
495 }
496 fossil_filename_free(zNative);
497
498 depth--;
499 if( depth==0 ){
500 db_finalize(&ins);
501 }
502
+12 -5
--- src/winhttp.c
+++ src/winhttp.c
@@ -139,19 +139,20 @@
139139
int mnPort, int mxPort, /* Range of allowed TCP port numbers */
140140
const char *zBrowser, /* Command to launch browser. (Or NULL) */
141141
const char *zStopper, /* Stop server when this file is exists (Or NULL) */
142142
const char *zNotFound, /* The --notfound option, or NULL */
143143
const char *zFileGlob, /* The --fileglob option, or NULL */
144
+ const char *zIpAddr, /* Bind to this IP address, if not NULL */
144145
int flags /* One or more HTTP_SERVER_ flags */
145146
){
146147
WSADATA wd;
147148
SOCKET s = INVALID_SOCKET;
148149
SOCKADDR_IN addr;
149150
int idCnt = 0;
150151
int iPort = mnPort;
151152
Blob options;
152
- WCHAR zTmpPath[MAX_PATH];
153
+ wchar_t zTmpPath[MAX_PATH];
153154
154155
if( zStopper ) file_delete(zStopper);
155156
blob_zero(&options);
156157
if( zNotFound ){
157158
blob_appendf(&options, " --notfound %s", zNotFound);
@@ -170,11 +171,16 @@
170171
if( s==INVALID_SOCKET ){
171172
fossil_fatal("unable to create a socket");
172173
}
173174
addr.sin_family = AF_INET;
174175
addr.sin_port = htons(iPort);
175
- if( flags & HTTP_SERVER_LOCALHOST ){
176
+ if( zIpAddr ){
177
+ addr.sin_addr.s_addr = inet_addr(zIpAddr);
178
+ if( addr.sin_addr.s_addr == (-1) ){
179
+ fossil_fatal("not a valid IP address: %s", zIpAddr);
180
+ }
181
+ }else if( flags & HTTP_SERVER_LOCALHOST ){
176182
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
177183
}else{
178184
addr.sin_addr.s_addr = htonl(INADDR_ANY);
179185
}
180186
if( bind(s, (struct sockaddr*)&addr, sizeof(addr))==SOCKET_ERROR ){
@@ -198,11 +204,12 @@
198204
}
199205
}
200206
if( !GetTempPathW(MAX_PATH, zTmpPath) ){
201207
fossil_fatal("unable to get path to the temporary directory.");
202208
}
203
- zTempPrefix = mprintf("%sfossil_server_P%d_", fossil_unicode_to_utf8(zTmpPath), iPort);
209
+ zTempPrefix = mprintf("%sfossil_server_P%d_",
210
+ fossil_unicode_to_utf8(zTmpPath), iPort);
204211
fossil_print("Listening for HTTP requests on TCP port %d\n", iPort);
205212
if( zBrowser ){
206213
zBrowser = mprintf(zBrowser, iPort);
207214
fossil_print("Launch webbrowser: %s\n", zBrowser);
208215
fossil_system(zBrowser);
@@ -254,11 +261,11 @@
254261
int port; /* Port on which the http server should run */
255262
const char *zNotFound; /* The --notfound option, or NULL */
256263
const char *zFileGlob; /* The --files option, or NULL */
257264
int flags; /* One or more HTTP_SERVER_ flags */
258265
int isRunningAsService; /* Are we running as a service ? */
259
- const WCHAR *zServiceName;/* Name of the service */
266
+ const wchar_t *zServiceName;/* Name of the service */
260267
SOCKET s; /* Socket on which the http server listens */
261268
};
262269
263270
/*
264271
** Variables used for running as windows service.
@@ -402,11 +409,11 @@
402409
ssStatus.dwServiceSpecificExitCode = 0;
403410
win32_report_service_status(SERVICE_START_PENDING, NO_ERROR, 3000);
404411
405412
/* Execute the http server */
406413
win32_http_server(hsData.port, hsData.port,
407
- NULL, NULL, hsData.zNotFound, hsData.zFileGlob,
414
+ NULL, NULL, hsData.zNotFound, hsData.zFileGlob, 0,
408415
hsData.flags);
409416
410417
/* Service has stopped now. */
411418
win32_report_service_status(SERVICE_STOPPED, NO_ERROR, 0);
412419
return;
413420
--- src/winhttp.c
+++ src/winhttp.c
@@ -139,19 +139,20 @@
139 int mnPort, int mxPort, /* Range of allowed TCP port numbers */
140 const char *zBrowser, /* Command to launch browser. (Or NULL) */
141 const char *zStopper, /* Stop server when this file is exists (Or NULL) */
142 const char *zNotFound, /* The --notfound option, or NULL */
143 const char *zFileGlob, /* The --fileglob option, or NULL */
 
144 int flags /* One or more HTTP_SERVER_ flags */
145 ){
146 WSADATA wd;
147 SOCKET s = INVALID_SOCKET;
148 SOCKADDR_IN addr;
149 int idCnt = 0;
150 int iPort = mnPort;
151 Blob options;
152 WCHAR zTmpPath[MAX_PATH];
153
154 if( zStopper ) file_delete(zStopper);
155 blob_zero(&options);
156 if( zNotFound ){
157 blob_appendf(&options, " --notfound %s", zNotFound);
@@ -170,11 +171,16 @@
170 if( s==INVALID_SOCKET ){
171 fossil_fatal("unable to create a socket");
172 }
173 addr.sin_family = AF_INET;
174 addr.sin_port = htons(iPort);
175 if( flags & HTTP_SERVER_LOCALHOST ){
 
 
 
 
 
176 addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
177 }else{
178 addr.sin_addr.s_addr = htonl(INADDR_ANY);
179 }
180 if( bind(s, (struct sockaddr*)&addr, sizeof(addr))==SOCKET_ERROR ){
@@ -198,11 +204,12 @@
198 }
199 }
200 if( !GetTempPathW(MAX_PATH, zTmpPath) ){
201 fossil_fatal("unable to get path to the temporary directory.");
202 }
203 zTempPrefix = mprintf("%sfossil_server_P%d_", fossil_unicode_to_utf8(zTmpPath), iPort);
 
204 fossil_print("Listening for HTTP requests on TCP port %d\n", iPort);
205 if( zBrowser ){
206 zBrowser = mprintf(zBrowser, iPort);
207 fossil_print("Launch webbrowser: %s\n", zBrowser);
208 fossil_system(zBrowser);
@@ -254,11 +261,11 @@
254 int port; /* Port on which the http server should run */
255 const char *zNotFound; /* The --notfound option, or NULL */
256 const char *zFileGlob; /* The --files option, or NULL */
257 int flags; /* One or more HTTP_SERVER_ flags */
258 int isRunningAsService; /* Are we running as a service ? */
259 const WCHAR *zServiceName;/* Name of the service */
260 SOCKET s; /* Socket on which the http server listens */
261 };
262
263 /*
264 ** Variables used for running as windows service.
@@ -402,11 +409,11 @@
402 ssStatus.dwServiceSpecificExitCode = 0;
403 win32_report_service_status(SERVICE_START_PENDING, NO_ERROR, 3000);
404
405 /* Execute the http server */
406 win32_http_server(hsData.port, hsData.port,
407 NULL, NULL, hsData.zNotFound, hsData.zFileGlob,
408 hsData.flags);
409
410 /* Service has stopped now. */
411 win32_report_service_status(SERVICE_STOPPED, NO_ERROR, 0);
412 return;
413
--- src/winhttp.c
+++ src/winhttp.c
@@ -139,19 +139,20 @@
139 int mnPort, int mxPort, /* Range of allowed TCP port numbers */
140 const char *zBrowser, /* Command to launch browser. (Or NULL) */
141 const char *zStopper, /* Stop server when this file is exists (Or NULL) */
142 const char *zNotFound, /* The --notfound option, or NULL */
143 const char *zFileGlob, /* The --fileglob option, or NULL */
144 const char *zIpAddr, /* Bind to this IP address, if not NULL */
145 int flags /* One or more HTTP_SERVER_ flags */
146 ){
147 WSADATA wd;
148 SOCKET s = INVALID_SOCKET;
149 SOCKADDR_IN addr;
150 int idCnt = 0;
151 int iPort = mnPort;
152 Blob options;
153 wchar_t zTmpPath[MAX_PATH];
154
155 if( zStopper ) file_delete(zStopper);
156 blob_zero(&options);
157 if( zNotFound ){
158 blob_appendf(&options, " --notfound %s", zNotFound);
@@ -170,11 +171,16 @@
171 if( s==INVALID_SOCKET ){
172 fossil_fatal("unable to create a socket");
173 }
174 addr.sin_family = AF_INET;
175 addr.sin_port = htons(iPort);
176 if( zIpAddr ){
177 addr.sin_addr.s_addr = inet_addr(zIpAddr);
178 if( addr.sin_addr.s_addr == (-1) ){
179 fossil_fatal("not a valid IP address: %s", zIpAddr);
180 }
181 }else if( flags & HTTP_SERVER_LOCALHOST ){
182 addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
183 }else{
184 addr.sin_addr.s_addr = htonl(INADDR_ANY);
185 }
186 if( bind(s, (struct sockaddr*)&addr, sizeof(addr))==SOCKET_ERROR ){
@@ -198,11 +204,12 @@
204 }
205 }
206 if( !GetTempPathW(MAX_PATH, zTmpPath) ){
207 fossil_fatal("unable to get path to the temporary directory.");
208 }
209 zTempPrefix = mprintf("%sfossil_server_P%d_",
210 fossil_unicode_to_utf8(zTmpPath), iPort);
211 fossil_print("Listening for HTTP requests on TCP port %d\n", iPort);
212 if( zBrowser ){
213 zBrowser = mprintf(zBrowser, iPort);
214 fossil_print("Launch webbrowser: %s\n", zBrowser);
215 fossil_system(zBrowser);
@@ -254,11 +261,11 @@
261 int port; /* Port on which the http server should run */
262 const char *zNotFound; /* The --notfound option, or NULL */
263 const char *zFileGlob; /* The --files option, or NULL */
264 int flags; /* One or more HTTP_SERVER_ flags */
265 int isRunningAsService; /* Are we running as a service ? */
266 const wchar_t *zServiceName;/* Name of the service */
267 SOCKET s; /* Socket on which the http server listens */
268 };
269
270 /*
271 ** Variables used for running as windows service.
@@ -402,11 +409,11 @@
409 ssStatus.dwServiceSpecificExitCode = 0;
410 win32_report_service_status(SERVICE_START_PENDING, NO_ERROR, 3000);
411
412 /* Execute the http server */
413 win32_http_server(hsData.port, hsData.port,
414 NULL, NULL, hsData.zNotFound, hsData.zFileGlob, 0,
415 hsData.flags);
416
417 /* Service has stopped now. */
418 win32_report_service_status(SERVICE_STOPPED, NO_ERROR, 0);
419 return;
420
+12 -7
--- src/xfer.c
+++ src/xfer.c
@@ -1708,12 +1708,14 @@
17081708
defossilize(zMsg);
17091709
if( (syncFlags & SYNC_PUSH) && zMsg && strglob("pull only *", zMsg) ){
17101710
syncFlags &= ~SYNC_PUSH;
17111711
zMsg = 0;
17121712
}
1713
- fossil_force_newline();
1714
- fossil_print("Server says: %s\n", zMsg);
1713
+ if( zMsg && zMsg[0] ){
1714
+ fossil_force_newline();
1715
+ fossil_print("Server says: %s\n", zMsg);
1716
+ }
17151717
}else
17161718
17171719
/* pragma NAME VALUE...
17181720
**
17191721
** The server can send pragmas to try to convey meta-information to
@@ -1736,20 +1738,22 @@
17361738
*/
17371739
if( blob_eq(&xfer.aToken[0],"error") && xfer.nToken==2 ){
17381740
if( (syncFlags & SYNC_CLONE)==0 || nCycle>0 ){
17391741
char *zMsg = blob_terminate(&xfer.aToken[1]);
17401742
defossilize(zMsg);
1743
+ fossil_force_newline();
1744
+ fossil_print("Error: %s\n", zMsg);
17411745
if( fossil_strcmp(zMsg, "login failed")==0 ){
17421746
if( nCycle<2 ){
1743
- if( !g.dontKeepUrl ) db_unset("last-sync-pw", 0);
1747
+ g.urlPasswd = 0;
17441748
go = 1;
1749
+ if( g.cgiOutput==0 ) url_prompt_for_password();
17451750
}
17461751
}else{
1747
- blob_appendf(&xfer.err, "\rserver says: %s", zMsg);
1752
+ blob_appendf(&xfer.err, "server says: %s\n", zMsg);
1753
+ nErr++;
17481754
}
1749
- fossil_warning("\rError: %s", zMsg);
1750
- nErr++;
17511755
break;
17521756
}
17531757
}else
17541758
17551759
/* Unknown message */
@@ -1760,14 +1764,15 @@
17601764
&recv
17611765
);
17621766
nErr++;
17631767
break;
17641768
}
1765
- blob_appendf(&xfer.err, "unknown command: [%b]", &xfer.aToken[0]);
1769
+ blob_appendf(&xfer.err, "unknown command: [%b]\n", &xfer.aToken[0]);
17661770
}
17671771
17681772
if( blob_size(&xfer.err) ){
1773
+ fossil_force_newline();
17691774
fossil_warning("%b", &xfer.err);
17701775
nErr++;
17711776
break;
17721777
}
17731778
blobarray_reset(xfer.aToken, xfer.nToken);
17741779
17751780
ADDED test/Greek-Lipsum-1.txt
17761781
ADDED test/Greek-Lipsum-2.txt
--- src/xfer.c
+++ src/xfer.c
@@ -1708,12 +1708,14 @@
1708 defossilize(zMsg);
1709 if( (syncFlags & SYNC_PUSH) && zMsg && strglob("pull only *", zMsg) ){
1710 syncFlags &= ~SYNC_PUSH;
1711 zMsg = 0;
1712 }
1713 fossil_force_newline();
1714 fossil_print("Server says: %s\n", zMsg);
 
 
1715 }else
1716
1717 /* pragma NAME VALUE...
1718 **
1719 ** The server can send pragmas to try to convey meta-information to
@@ -1736,20 +1738,22 @@
1736 */
1737 if( blob_eq(&xfer.aToken[0],"error") && xfer.nToken==2 ){
1738 if( (syncFlags & SYNC_CLONE)==0 || nCycle>0 ){
1739 char *zMsg = blob_terminate(&xfer.aToken[1]);
1740 defossilize(zMsg);
 
 
1741 if( fossil_strcmp(zMsg, "login failed")==0 ){
1742 if( nCycle<2 ){
1743 if( !g.dontKeepUrl ) db_unset("last-sync-pw", 0);
1744 go = 1;
 
1745 }
1746 }else{
1747 blob_appendf(&xfer.err, "\rserver says: %s", zMsg);
 
1748 }
1749 fossil_warning("\rError: %s", zMsg);
1750 nErr++;
1751 break;
1752 }
1753 }else
1754
1755 /* Unknown message */
@@ -1760,14 +1764,15 @@
1760 &recv
1761 );
1762 nErr++;
1763 break;
1764 }
1765 blob_appendf(&xfer.err, "unknown command: [%b]", &xfer.aToken[0]);
1766 }
1767
1768 if( blob_size(&xfer.err) ){
 
1769 fossil_warning("%b", &xfer.err);
1770 nErr++;
1771 break;
1772 }
1773 blobarray_reset(xfer.aToken, xfer.nToken);
1774
1775 DDED test/Greek-Lipsum-1.txt
1776 DDED test/Greek-Lipsum-2.txt
--- src/xfer.c
+++ src/xfer.c
@@ -1708,12 +1708,14 @@
1708 defossilize(zMsg);
1709 if( (syncFlags & SYNC_PUSH) && zMsg && strglob("pull only *", zMsg) ){
1710 syncFlags &= ~SYNC_PUSH;
1711 zMsg = 0;
1712 }
1713 if( zMsg && zMsg[0] ){
1714 fossil_force_newline();
1715 fossil_print("Server says: %s\n", zMsg);
1716 }
1717 }else
1718
1719 /* pragma NAME VALUE...
1720 **
1721 ** The server can send pragmas to try to convey meta-information to
@@ -1736,20 +1738,22 @@
1738 */
1739 if( blob_eq(&xfer.aToken[0],"error") && xfer.nToken==2 ){
1740 if( (syncFlags & SYNC_CLONE)==0 || nCycle>0 ){
1741 char *zMsg = blob_terminate(&xfer.aToken[1]);
1742 defossilize(zMsg);
1743 fossil_force_newline();
1744 fossil_print("Error: %s\n", zMsg);
1745 if( fossil_strcmp(zMsg, "login failed")==0 ){
1746 if( nCycle<2 ){
1747 g.urlPasswd = 0;
1748 go = 1;
1749 if( g.cgiOutput==0 ) url_prompt_for_password();
1750 }
1751 }else{
1752 blob_appendf(&xfer.err, "server says: %s\n", zMsg);
1753 nErr++;
1754 }
 
 
1755 break;
1756 }
1757 }else
1758
1759 /* Unknown message */
@@ -1760,14 +1764,15 @@
1764 &recv
1765 );
1766 nErr++;
1767 break;
1768 }
1769 blob_appendf(&xfer.err, "unknown command: [%b]\n", &xfer.aToken[0]);
1770 }
1771
1772 if( blob_size(&xfer.err) ){
1773 fossil_force_newline();
1774 fossil_warning("%b", &xfer.err);
1775 nErr++;
1776 break;
1777 }
1778 blobarray_reset(xfer.aToken, xfer.nToken);
1779
1780 DDED test/Greek-Lipsum-1.txt
1781 DDED test/Greek-Lipsum-2.txt
--- a/test/Greek-Lipsum-1.txt
+++ b/test/Greek-Lipsum-1.txt
@@ -0,0 +1,77 @@
1
+Κυο εξ υνυμ δισπυθανδο, ερος αλιενυμ κυι θε. Νες εξ ελωκυενθιαμ
2
+ινστρυσθιορ. Θεμπορ νοσθερ συ εως. Πυρθο μωφεθ μωδερατιυς ατ μελ. Συ δυο
3
+αμετ ειυς. Πρι δεσωρε ινθεγρε ασυμσαν αδ, πρω αν ρεβυμ εφφισιανθυρ
4
+νεσεσιταθιβυς.
5
+
6
+Νοσθρυμ συσιπιαντυρ ηας ει, ορναθυς ρεσυσαβο πρι ιδ, περ νολυισε οπωρθερε
7
+ιδ. Θε παρτιενδω περτινασια ινσωρρυπτε φις. Δισθας φαβυλας γυβεργρεν εως
8
+ιν, αλιι σολυμ ηις θε, ποσθυλανθ ασυσαμυς ετ ηας. Νο ινανι φαβυλας
9
+θχεωπηραστυς ναμ, ευμ διστα ηομερω εα. Μαγνα φυγιθ υθ περ, εσθ ατ νοσθρυμ
10
+δεσερυισε.
11
+
12
+Φις αυδιαμ λαβορες παθριοκυε εξ, ετ φευγιαθ δεφινιεβας σιθ. Αμετ εριπυιτ
13
+δελισατα υσυ ετ, σενσιβυς φολυπθατιβυς περ εξ. Κυωδ ιγνωθα τιβικυε ατ εαμ,
14
+νυλλα ηωνεσθαθις υθ νες. Φιξ αν μυτατ εξερσι λαβωρε. Σεδ νονυμυ κυοδσι
15
+δελενιτ νε, συμο φιδε εα κυι. Ποπυλω μαιορυμ περσεκυερις αν πρω.
16
+
17
+Σολυμ σωνφενιρε αδ ηας, αν ευμ σολυτα ρεγιονε προδεσεθ. Φερο λαβορες
18
+σαλυταθυς θε δυο, ηις νε φερο βλανδιτ πραεσενθ, ιδ φις σολεατ φιφενδυμ. Συ
19
+συμ μωδω συμμο δολορες. Θε ναμ πωσιθ φευγιαθ τινσιδυνθ.
20
+
21
+Υθ ιψυμ νεμωρε σαπιενθεμ μεα, ει εφερτι εφφισιενδι ηας. Ευμ αλβυσιυς
22
+πραεσενθ συ, δεσωρε σεθερο ινδοστυμ μει ει. Ηις υθ συμμο μαλορυμ μανδαμυς,
23
+κυι ιν συαφιθαθε περισυλις, ιισκυε οφφισιις κυο νο. Νε νονυμυ ηαβεμυς
24
+πχιλωσοπηια φις. Ετ ηας υταμυρ ρεφορμιδανς. Ινερμις δεθραξιθ νεγλεγενθυρ
25
+δυο υθ, τωρκυαθος δισεντιυνθ φιθυπερατοριβυς φιξ νε. Εα σεδ συας μελιυς,
26
+φιμ προβο ινδοστυμ ρεπριμικυε ευ.
27
+
28
+Πρι ιν λυδυς αυδιρε, συμμο περτινασια σωνσεθεθυρ φις ιν, σιθ εξ επισυρι
29
+μαλυισετ σωνσεπθαμ. Αν δετρασθο ελειφενδ εξπλισαρι πρω. Ιυδισο σομμοδο συμ
30
+αδ. Δισαμ δισυντ φυλπυτατε ιν πρω, εξ ηις δελενιτ μαιεσθατις. Ρεβυμ νονυμυ
31
+αππαρεατ σιθ εα, σιθ ιδ νυλλα σολεατ πεθενθιυμ, ει οπθιων περσεκυερις ευμ.
32
+Υθ νισλ ινσωλενς φιξ, εσθ φερι ιισκυε αργυμενθυμ συ, σεθερο μολεστιε
33
+αδιπισινγ ευ μεα.
34
+
35
+Ετ μεα μυσιυς λατινε, μει σεμπερ δεσερυντ περτινασια αν. Συ φενιαμ ποπυλω
36
+αθωμωρυμ κυο. Νο ιυς ρεβυμ φιθυπεραθα δισπυτατιονι, ατ αλθερυμ χενδρεριτ
37
+φιθυπεραθα συμ. Ευμ αυτεμ αππετερε αδιπισινγ ετ, νο κυο συας ελειφενδ. Εαμ
38
+θαλε δισαμ εξ.
39
+
40
+Ετ σομμοδο λεγενδως φελ, διαμ φωλυπθαρια νο μελ, δυο φελιτ νεμωρε αδ. Αν
41
+εξπετενδα συαφιθαθε φελ, ενιμ ασυμσαν περ αδ, εα φιμ μωδω υνυμ. Εα κυωδ
42
+προβο περσεσυτι φελ, ευ φερι πρωπριαε ινσιδεριντ νες. Εξ νες οδιο δελενιτ,
43
+ελιτ ιυδισο ινθεγρε δυο ιδ. Μελ αλικυιπ περισυλις ετ, ατ ηας αυγυε λαβορες
44
+ασεντιορ.
45
+
46
+Συ νυλλα δωσενδι δεφινιτιωνες φελ. Δωλορε δισερετ ρεφορμιδανς αδ πρω.
47
+Εφερτι πρωβατυς υρβανιθας νο μελ. Ιν φιξ φασεθε δεθραξιθ ομιθταντυρ, ζριλ
48
+υτιναμ παθριοκυε συ νες. Κυο ει δισενθιετ ασομμοδαρε.
49
+
50
+Ηας θε ομνεσκυε δελισαθισιμι. Εξερσι δελισατα ινιμισυς ευμ ευ, ιδ ελιτρ
51
+μελιορε αβχορρεανθ εσθ, εως οπθιων προδεσεθ σονσεσθεθυερ ιν. Ναμ διαμ ασυμ
52
+τεμποριβυς αν. Σομμυνε δεφινιθιονεμ κυο ιν, ηας νωμιναφι φιφενδυμ ατ.
53
+Ομνεσκυε δεφινιεβας μεα θε.
54
+
55
+Εαμ σανστυς αλβυσιυς ευ, φελ στετ επισυρι ιν, κυο αδ περτιναξ σενσεριτ
56
+τωρκυαθος. Λαβωρε νυσκυαμ ιν κυι, ερος σαεπε τιβικυε εσθ ατ. Φερο υτιναμ
57
+φελ νε, αδ απεριρι ομιθταντυρ δεφινιτιωνες δυο. Ινφενιρε ελειφενδ παθριοκυε
58
+εξ ναμ. Ιδ ναμ μινιμ υθροκυε. Αδ ναθυμ αππετερε σεα.
59
+
60
+Μολλις φολυμυς κυι νο, θε φιμ υβικυε αδιπισι διγνισιμ. Νοβις νοσθρω
61
+μενανδρι υσυ νο, πριμα ελιτρ κυαεκυε ιδ ηας. Πρω εα παρτεμ δομινγ. Θε
62
+φασεθε αυδιρε φολυπθατιβυς ιυς. Φις δεθραξιθ ινφενιρε ετ, αν ιυς πωσθεα
63
+μεδιοσριθαθεμ.
64
+
65
+Εα αδχυς υταμυρ φις. Σιβω λαυδεμ υσυ αδ, φις λεγιμυς πλασεραθ φερθερεμ συ.
66
+Φιμ ατ ειυς αλθερυμ φιθυπερατοριβυς, ατ λατινε ηαβεμυς φολυτπατ μεα. Γραεσω
67
+λυσιλιυς εα φελ.
68
+
69
+Θε φιξ βρυτε συμμο, φελ ωμιτθαμ ιμπερδιετ εξ. Μεα ιν μωδω νυμκυαμ, σεα
70
+τρασθατος εξπετενδα αδ. Γραεσε πλαθονεμ ρεπυδιανδαε φιξ εα, εα ετιαμ
71
+σωνσθιτυθο ασυεφεριθ σιθ. Ατ πυρθο ναθυμ σονγυε φιξ, κυι ετ δισαμ ινερμις
72
+ινιμισυς.
73
+
74
+Περ υθ διστα ινθεγρε, περ ρεκυε φιερενθ αδ. Νε δεσερυντ ινφενιρε σωνσεθεθυρ
75
+μει, αν ηομερω αργυμενθυμ ρεπυδιανδαε περ, ηις σωνσυλ μελιορε ινθελλεγαμ
76
+υθ. Νες εα λαβιθυρ δολορεμ υλλαμσορπερ. Μει εσεντ νεσεσιταθιβυς ιν, αφφερθ
77
+σαυσαε ινθερεσετ ηας αν.
--- a/test/Greek-Lipsum-1.txt
+++ b/test/Greek-Lipsum-1.txt
@@ -0,0 +1,77 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
--- a/test/Greek-Lipsum-1.txt
+++ b/test/Greek-Lipsum-1.txt
@@ -0,0 +1,77 @@
1 Κυο εξ υνυμ δισπυθανδο, ερος αλιενυμ κυι θε. Νες εξ ελωκυενθιαμ
2 ινστρυσθιορ. Θεμπορ νοσθερ συ εως. Πυρθο μωφεθ μωδερατιυς ατ μελ. Συ δυο
3 αμετ ειυς. Πρι δεσωρε ινθεγρε ασυμσαν αδ, πρω αν ρεβυμ εφφισιανθυρ
4 νεσεσιταθιβυς.
5
6 Νοσθρυμ συσιπιαντυρ ηας ει, ορναθυς ρεσυσαβο πρι ιδ, περ νολυισε οπωρθερε
7 ιδ. Θε παρτιενδω περτινασια ινσωρρυπτε φις. Δισθας φαβυλας γυβεργρεν εως
8 ιν, αλιι σολυμ ηις θε, ποσθυλανθ ασυσαμυς ετ ηας. Νο ινανι φαβυλας
9 θχεωπηραστυς ναμ, ευμ διστα ηομερω εα. Μαγνα φυγιθ υθ περ, εσθ ατ νοσθρυμ
10 δεσερυισε.
11
12 Φις αυδιαμ λαβορες παθριοκυε εξ, ετ φευγιαθ δεφινιεβας σιθ. Αμετ εριπυιτ
13 δελισατα υσυ ετ, σενσιβυς φολυπθατιβυς περ εξ. Κυωδ ιγνωθα τιβικυε ατ εαμ,
14 νυλλα ηωνεσθαθις υθ νες. Φιξ αν μυτατ εξερσι λαβωρε. Σεδ νονυμυ κυοδσι
15 δελενιτ νε, συμο φιδε εα κυι. Ποπυλω μαιορυμ περσεκυερις αν πρω.
16
17 Σολυμ σωνφενιρε αδ ηας, αν ευμ σολυτα ρεγιονε προδεσεθ. Φερο λαβορες
18 σαλυταθυς θε δυο, ηις νε φερο βλανδιτ πραεσενθ, ιδ φις σολεατ φιφενδυμ. Συ
19 συμ μωδω συμμο δολορες. Θε ναμ πωσιθ φευγιαθ τινσιδυνθ.
20
21 Υθ ιψυμ νεμωρε σαπιενθεμ μεα, ει εφερτι εφφισιενδι ηας. Ευμ αλβυσιυς
22 πραεσενθ συ, δεσωρε σεθερο ινδοστυμ μει ει. Ηις υθ συμμο μαλορυμ μανδαμυς,
23 κυι ιν συαφιθαθε περισυλις, ιισκυε οφφισιις κυο νο. Νε νονυμυ ηαβεμυς
24 πχιλωσοπηια φις. Ετ ηας υταμυρ ρεφορμιδανς. Ινερμις δεθραξιθ νεγλεγενθυρ
25 δυο υθ, τωρκυαθος δισεντιυνθ φιθυπερατοριβυς φιξ νε. Εα σεδ συας μελιυς,
26 φιμ προβο ινδοστυμ ρεπριμικυε ευ.
27
28 Πρι ιν λυδυς αυδιρε, συμμο περτινασια σωνσεθεθυρ φις ιν, σιθ εξ επισυρι
29 μαλυισετ σωνσεπθαμ. Αν δετρασθο ελειφενδ εξπλισαρι πρω. Ιυδισο σομμοδο συμ
30 αδ. Δισαμ δισυντ φυλπυτατε ιν πρω, εξ ηις δελενιτ μαιεσθατις. Ρεβυμ νονυμυ
31 αππαρεατ σιθ εα, σιθ ιδ νυλλα σολεατ πεθενθιυμ, ει οπθιων περσεκυερις ευμ.
32 Υθ νισλ ινσωλενς φιξ, εσθ φερι ιισκυε αργυμενθυμ συ, σεθερο μολεστιε
33 αδιπισινγ ευ μεα.
34
35 Ετ μεα μυσιυς λατινε, μει σεμπερ δεσερυντ περτινασια αν. Συ φενιαμ ποπυλω
36 αθωμωρυμ κυο. Νο ιυς ρεβυμ φιθυπεραθα δισπυτατιονι, ατ αλθερυμ χενδρεριτ
37 φιθυπεραθα συμ. Ευμ αυτεμ αππετερε αδιπισινγ ετ, νο κυο συας ελειφενδ. Εαμ
38 θαλε δισαμ εξ.
39
40 Ετ σομμοδο λεγενδως φελ, διαμ φωλυπθαρια νο μελ, δυο φελιτ νεμωρε αδ. Αν
41 εξπετενδα συαφιθαθε φελ, ενιμ ασυμσαν περ αδ, εα φιμ μωδω υνυμ. Εα κυωδ
42 προβο περσεσυτι φελ, ευ φερι πρωπριαε ινσιδεριντ νες. Εξ νες οδιο δελενιτ,
43 ελιτ ιυδισο ινθεγρε δυο ιδ. Μελ αλικυιπ περισυλις ετ, ατ ηας αυγυε λαβορες
44 ασεντιορ.
45
46 Συ νυλλα δωσενδι δεφινιτιωνες φελ. Δωλορε δισερετ ρεφορμιδανς αδ πρω.
47 Εφερτι πρωβατυς υρβανιθας νο μελ. Ιν φιξ φασεθε δεθραξιθ ομιθταντυρ, ζριλ
48 υτιναμ παθριοκυε συ νες. Κυο ει δισενθιετ ασομμοδαρε.
49
50 Ηας θε ομνεσκυε δελισαθισιμι. Εξερσι δελισατα ινιμισυς ευμ ευ, ιδ ελιτρ
51 μελιορε αβχορρεανθ εσθ, εως οπθιων προδεσεθ σονσεσθεθυερ ιν. Ναμ διαμ ασυμ
52 τεμποριβυς αν. Σομμυνε δεφινιθιονεμ κυο ιν, ηας νωμιναφι φιφενδυμ ατ.
53 Ομνεσκυε δεφινιεβας μεα θε.
54
55 Εαμ σανστυς αλβυσιυς ευ, φελ στετ επισυρι ιν, κυο αδ περτιναξ σενσεριτ
56 τωρκυαθος. Λαβωρε νυσκυαμ ιν κυι, ερος σαεπε τιβικυε εσθ ατ. Φερο υτιναμ
57 φελ νε, αδ απεριρι ομιθταντυρ δεφινιτιωνες δυο. Ινφενιρε ελειφενδ παθριοκυε
58 εξ ναμ. Ιδ ναμ μινιμ υθροκυε. Αδ ναθυμ αππετερε σεα.
59
60 Μολλις φολυμυς κυι νο, θε φιμ υβικυε αδιπισι διγνισιμ. Νοβις νοσθρω
61 μενανδρι υσυ νο, πριμα ελιτρ κυαεκυε ιδ ηας. Πρω εα παρτεμ δομινγ. Θε
62 φασεθε αυδιρε φολυπθατιβυς ιυς. Φις δεθραξιθ ινφενιρε ετ, αν ιυς πωσθεα
63 μεδιοσριθαθεμ.
64
65 Εα αδχυς υταμυρ φις. Σιβω λαυδεμ υσυ αδ, φις λεγιμυς πλασεραθ φερθερεμ συ.
66 Φιμ ατ ειυς αλθερυμ φιθυπερατοριβυς, ατ λατινε ηαβεμυς φολυτπατ μεα. Γραεσω
67 λυσιλιυς εα φελ.
68
69 Θε φιξ βρυτε συμμο, φελ ωμιτθαμ ιμπερδιετ εξ. Μεα ιν μωδω νυμκυαμ, σεα
70 τρασθατος εξπετενδα αδ. Γραεσε πλαθονεμ ρεπυδιανδαε φιξ εα, εα ετιαμ
71 σωνσθιτυθο ασυεφεριθ σιθ. Ατ πυρθο ναθυμ σονγυε φιξ, κυι ετ δισαμ ινερμις
72 ινιμισυς.
73
74 Περ υθ διστα ινθεγρε, περ ρεκυε φιερενθ αδ. Νε δεσερυντ ινφενιρε σωνσεθεθυρ
75 μει, αν ηομερω αργυμενθυμ ρεπυδιανδαε περ, ηις σωνσυλ μελιορε ινθελλεγαμ
76 υθ. Νες εα λαβιθυρ δολορεμ υλλαμσορπερ. Μει εσεντ νεσεσιταθιβυς ιν, αφφερθ
77 σαυσαε ινθερεσετ ηας αν.
--- a/test/Greek-Lipsum-2.txt
+++ b/test/Greek-Lipsum-2.txt
@@ -0,0 +1,77 @@
1
+Κυο εξ υνυμ δισπυθανδο, ερος αλιενυμ κυι θε. Νες εξ ελωκυενθιαμ
2
+ινστρυσθιορ. Θεμπορ νοσθερ συ εως. Πυρθο μωφεθ μωδερατιυς ατ μελ. Συ δυο
3
+αμετ ειυς. Πρι δεσωρε ινθεγρε ασυμσαν αδ, Φιξ αν ρεβυμ εφφισιανθυρ
4
+νεσεσιταθιβυς.
5
+
6
+Νοσθρυμ συσιπιαντυρ ηας ει, ορναθυς ρεσυσαβο πρι ιδ, περ νολυισε
7
+οπωρθερε ιδ. Θε παρτιενδω περτινασια ινσωρρυπτε φις. Δισθας φαβυλας
8
+γυβεργρεν εως ιν, αλιι σολυμ ηις θε, ποσθυλανθ ασυσαμυς ετ ηας. Νο ινανι
9
+φαβυλας θχεωπηραστυς ναμ, ευμ διστα ηομερω εα. Μαγνα φυγιθ υθ περ, εσθ
10
+ατ νοσθρυμ δεσερυισε.
11
+
12
+Φις αυδιαμ λαβορες παθριοκυε εξ, ετ φευγιαθ δεφινιεβας σιθ. Αμετ εριπυιτ
13
+δελισατα υσυ ετ, σενσιβυς φολυπθατιβυς περ εξ. Κυωδ ιγνωθα τιβικυε ατ
14
+εαμ, νυλλα ηωνεσθαθις υθ νες. Φιξ αν μυτατ εξερσι λαβωρε. Σεδ νονυμυ
15
+κυοδσι δελενιτ νε, συμο φιδε εα κυι. Ποπυλω μαιορυμ περσεκυερις αν πρω.
16
+
17
+Σολυμ σωνφενιρε αδ ηας, αν ευμ σολυτα ρεγιονε προδεσεθ. Φερο λαβορες
18
+σαλυταθυς θε δυο, ηις νε φερο βλανδιτ πραεσενθ, ιδ φις σολεατ φιφενδυμ.
19
+Συ συμ μωδω συμμο δολορες. Θε ναμ πωσιθ φευγιαθ τινσιδυνθ.
20
+
21
+Υθ ιψυμ νεμωρε σαπιενθεμ μεα, ει εφερτι εφφισιενδι ηας. Ευμ αλβυσιυς
22
+πραεσενθ συ, δεσωρε σεθερο ινδοστυμ μει ει. Ηις υθ συμμο μαλορυμ
23
+μανδαμυς, κυι ιν συαφιθαθε περισυλις, ιισκυε οφφισιις κυο νο. Νε νονυμυ
24
+ηαβεμυς πχιλωσοπηια φις. Ετ ηας υταμυρ ρεφορμιδανς. Ινερμις δεθραξιθ
25
+νεγλεγενθυρ δυο υθ, τωρκυαθος δισεντιυνθ φιθυπερατοριβυς φιξ νε. Εα σεδ
26
+συας μελιυς, φιμ προβο ινδοστυμ ρεπριμικυε ευ.
27
+
28
+Πρι ιν λυδυς αυδιρε, συμμο περτινασια σωνσεθεθυρ φις ιν, σιθ εξ επισυρι
29
+μαλυισετ σωνσεπθαμ. Αν δετρασθο ελειφενδ εξπλισαρι πρω. Ιυδισο σομμοδο
30
+συμ αδ. Δισαμ δισυντ φυλπυτατε ιν πρω, εξ ηις δελενιτ μαιεσθατις. Ρεβυμ
31
+νονυμυ αππαρεατ σιθ εα, σιθ ιδ νυλλα σολεατ πεθενθιυμ, ει οπθιων
32
+περσεκυερις ευμ. Υθ νισλ ινσωλενς φιξ, εσθ φερι ιισκυε αργυμενθυμ συ,
33
+σεθερο μολεστιε αδιπισινγ ευ μεα.
34
+
35
+Ετ μεα μυσιυς λατινε, μει σεμπερ δεσερυντ περτινασια αν. Συ φενιαμ
36
+ποπυλω αθωμωρυμ κυο. Νο ιυς ρεβυμ φιθυπεραθα δισπυτατιονι, ατ αλθερυμ
37
+χενδρεριτ φιθυπεραθα συμ. Ευμ αυτεμ αππετερε αδιπισινγ ετ, νο κυο συας
38
+ελειφενδ. Εαμ θαλε δισαμ εξ.
39
+
40
+Ετ σομμοδο λεγενδως φελ, διαμ φωλυπθαρια νο μελ, δυο φελιτ νεμωρε αδ. Αν
41
+εξπετενδα συαφιθαθε φελ, ενιμ ασυμσαν περ αδ, εα φιμ μωδω υνυμ. Εα κυωδ
42
+προβο περσεσυτι φελ, ευ φερι πρωπριαε ινσιδεριντ νες. Εξ νες οδιο
43
+δελενιτ, ελιτ ιυδισο ινθεγρε δυο ιδ. Μελ αλικυιπ περισυλις ετ, ατ ηας
44
+αυγυε λαβορες ασεντιορ.
45
+
46
+Συ νυλλα δωσενδι δεφινιτιωνες φελ. Δωλορε δισερετ ρεφορμιδανς αδ πρω.
47
+Εφερτι πρωβατυς υρβανιθας νο μελ. Ιν φιξ φασεθε δεθραξιθ ομιθταντυρ,
48
+ζριλ υτιναμ παθριοκυε συ νες. Κυο ει δισενθιετ ασομμοδαρε.
49
+
50
+Ηας θε ομνεσκυε δελισαθισιμι. Εξερσι δελισατα ινιμισυς ευμ ευ, ιδ ελιτρ
51
+μελιορε αβχορρεανθ εσθ, εως οπθιων προδεσεθ σονσεσθεθυερ ιν. Ναμ διαμ
52
+ασυμ τεμποριβυς αν. Σομμυνε δεφινιθιονεμ κυο ιν, ηας νωμιναφι φιφενδυμ
53
+ατ. Ομνεσκυε δεφινιεβας μεα θε.
54
+
55
+Εαμ σανστυς αλβυσιυς ευ, φελ στετ επισυρι ιν, κυο αδ περτιναξ σενσεριτ
56
+τωρκυαθος. Λαβωρε νυσκυαμ ιν κυι, ερος σαεπε τιβικυε εσθ ατ. Φερο υτιναμ
57
+φελ νε, αδ απεριρι ομιθταντυρ δεφινιτιωνες δυο. Ινφενιρε ελειφενδ
58
+παθριοκυε εξ ναμ. Ιδ ναμ μινιμ υθροκυε. Αδ ναθυμ αππετερε σεα.
59
+
60
+Μολλις φολυμυς κυι νο, θε φιμ υβικυε αδιπισι διγνισιμ. Νοβις νοσθρω
61
+μενανδρι υσυ νο, πριμα ελιτρ κυαεκυε ιδ ηας. Πρω εα παρτεμ δομινγ. Θε
62
+φασεθε αυδιρε φολυπθατιβυς ιυς. Φις δεθραξιθ ινφενιρε ετ, αν ιυς πωσθεα
63
+μεδιοσριθαθεμ.
64
+
65
+Εα αδχυς υταμυρ φις. Σιβω λαυδεμ υσυ αδ, φις λεγιμυς πλασεραθ φερθερεμ
66
+συ. Φιμ ατ ειυς αλθερυμ φιθυπερατοριβυς, ατ λατινε ηαβεμυς φολυτπατ
67
+μεα. Γραεσω λυσιλιυς εα φελ.
68
+
69
+Θε φιξ βρυτε συμμο, φελ ωμιτθαμ ιμπερδιετ εξ. Μεα ιν μωδω νυμκυαμ, σεα
70
+τρασθατος εξπετενδα αδ. Γραεσε πλαθονεμ ρεπυδιανδαε φιξ εα, εα ετιαμ
71
+σωνσθιτυθο ασυεφεριθ σιθ. Ατ πυρθο ναθυμ σονγυε φιξ, κυι ετ δισαμ
72
+ινερμις ινιμισυς.
73
+
74
+Περ υθ διστα ινθεγρε, περ ρεκυε φιερενθ αδ. Νε δεσερυντ ινφενιρε
75
+σωνσεθεθυρ μει, αν ηομερω αργυμενθυμ ρεπυδιανδαε περ, ηις σωνσυλ μελιορε
76
+ινθελλεγαμ υθ. Νες εα λαβιθυρ δολορεμ υλλαμσορπερ. Μει εσεντ
77
+νεσεσιταθιβυς ιν, αφφερθ σαυσαε ινθερεσετ ηας αν.
--- a/test/Greek-Lipsum-2.txt
+++ b/test/Greek-Lipsum-2.txt
@@ -0,0 +1,77 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
--- a/test/Greek-Lipsum-2.txt
+++ b/test/Greek-Lipsum-2.txt
@@ -0,0 +1,77 @@
1 Κυο εξ υνυμ δισπυθανδο, ερος αλιενυμ κυι θε. Νες εξ ελωκυενθιαμ
2 ινστρυσθιορ. Θεμπορ νοσθερ συ εως. Πυρθο μωφεθ μωδερατιυς ατ μελ. Συ δυο
3 αμετ ειυς. Πρι δεσωρε ινθεγρε ασυμσαν αδ, Φιξ αν ρεβυμ εφφισιανθυρ
4 νεσεσιταθιβυς.
5
6 Νοσθρυμ συσιπιαντυρ ηας ει, ορναθυς ρεσυσαβο πρι ιδ, περ νολυισε
7 οπωρθερε ιδ. Θε παρτιενδω περτινασια ινσωρρυπτε φις. Δισθας φαβυλας
8 γυβεργρεν εως ιν, αλιι σολυμ ηις θε, ποσθυλανθ ασυσαμυς ετ ηας. Νο ινανι
9 φαβυλας θχεωπηραστυς ναμ, ευμ διστα ηομερω εα. Μαγνα φυγιθ υθ περ, εσθ
10 ατ νοσθρυμ δεσερυισε.
11
12 Φις αυδιαμ λαβορες παθριοκυε εξ, ετ φευγιαθ δεφινιεβας σιθ. Αμετ εριπυιτ
13 δελισατα υσυ ετ, σενσιβυς φολυπθατιβυς περ εξ. Κυωδ ιγνωθα τιβικυε ατ
14 εαμ, νυλλα ηωνεσθαθις υθ νες. Φιξ αν μυτατ εξερσι λαβωρε. Σεδ νονυμυ
15 κυοδσι δελενιτ νε, συμο φιδε εα κυι. Ποπυλω μαιορυμ περσεκυερις αν πρω.
16
17 Σολυμ σωνφενιρε αδ ηας, αν ευμ σολυτα ρεγιονε προδεσεθ. Φερο λαβορες
18 σαλυταθυς θε δυο, ηις νε φερο βλανδιτ πραεσενθ, ιδ φις σολεατ φιφενδυμ.
19 Συ συμ μωδω συμμο δολορες. Θε ναμ πωσιθ φευγιαθ τινσιδυνθ.
20
21 Υθ ιψυμ νεμωρε σαπιενθεμ μεα, ει εφερτι εφφισιενδι ηας. Ευμ αλβυσιυς
22 πραεσενθ συ, δεσωρε σεθερο ινδοστυμ μει ει. Ηις υθ συμμο μαλορυμ
23 μανδαμυς, κυι ιν συαφιθαθε περισυλις, ιισκυε οφφισιις κυο νο. Νε νονυμυ
24 ηαβεμυς πχιλωσοπηια φις. Ετ ηας υταμυρ ρεφορμιδανς. Ινερμις δεθραξιθ
25 νεγλεγενθυρ δυο υθ, τωρκυαθος δισεντιυνθ φιθυπερατοριβυς φιξ νε. Εα σεδ
26 συας μελιυς, φιμ προβο ινδοστυμ ρεπριμικυε ευ.
27
28 Πρι ιν λυδυς αυδιρε, συμμο περτινασια σωνσεθεθυρ φις ιν, σιθ εξ επισυρι
29 μαλυισετ σωνσεπθαμ. Αν δετρασθο ελειφενδ εξπλισαρι πρω. Ιυδισο σομμοδο
30 συμ αδ. Δισαμ δισυντ φυλπυτατε ιν πρω, εξ ηις δελενιτ μαιεσθατις. Ρεβυμ
31 νονυμυ αππαρεατ σιθ εα, σιθ ιδ νυλλα σολεατ πεθενθιυμ, ει οπθιων
32 περσεκυερις ευμ. Υθ νισλ ινσωλενς φιξ, εσθ φερι ιισκυε αργυμενθυμ συ,
33 σεθερο μολεστιε αδιπισινγ ευ μεα.
34
35 Ετ μεα μυσιυς λατινε, μει σεμπερ δεσερυντ περτινασια αν. Συ φενιαμ
36 ποπυλω αθωμωρυμ κυο. Νο ιυς ρεβυμ φιθυπεραθα δισπυτατιονι, ατ αλθερυμ
37 χενδρεριτ φιθυπεραθα συμ. Ευμ αυτεμ αππετερε αδιπισινγ ετ, νο κυο συας
38 ελειφενδ. Εαμ θαλε δισαμ εξ.
39
40 Ετ σομμοδο λεγενδως φελ, διαμ φωλυπθαρια νο μελ, δυο φελιτ νεμωρε αδ. Αν
41 εξπετενδα συαφιθαθε φελ, ενιμ ασυμσαν περ αδ, εα φιμ μωδω υνυμ. Εα κυωδ
42 προβο περσεσυτι φελ, ευ φερι πρωπριαε ινσιδεριντ νες. Εξ νες οδιο
43 δελενιτ, ελιτ ιυδισο ινθεγρε δυο ιδ. Μελ αλικυιπ περισυλις ετ, ατ ηας
44 αυγυε λαβορες ασεντιορ.
45
46 Συ νυλλα δωσενδι δεφινιτιωνες φελ. Δωλορε δισερετ ρεφορμιδανς αδ πρω.
47 Εφερτι πρωβατυς υρβανιθας νο μελ. Ιν φιξ φασεθε δεθραξιθ ομιθταντυρ,
48 ζριλ υτιναμ παθριοκυε συ νες. Κυο ει δισενθιετ ασομμοδαρε.
49
50 Ηας θε ομνεσκυε δελισαθισιμι. Εξερσι δελισατα ινιμισυς ευμ ευ, ιδ ελιτρ
51 μελιορε αβχορρεανθ εσθ, εως οπθιων προδεσεθ σονσεσθεθυερ ιν. Ναμ διαμ
52 ασυμ τεμποριβυς αν. Σομμυνε δεφινιθιονεμ κυο ιν, ηας νωμιναφι φιφενδυμ
53 ατ. Ομνεσκυε δεφινιεβας μεα θε.
54
55 Εαμ σανστυς αλβυσιυς ευ, φελ στετ επισυρι ιν, κυο αδ περτιναξ σενσεριτ
56 τωρκυαθος. Λαβωρε νυσκυαμ ιν κυι, ερος σαεπε τιβικυε εσθ ατ. Φερο υτιναμ
57 φελ νε, αδ απεριρι ομιθταντυρ δεφινιτιωνες δυο. Ινφενιρε ελειφενδ
58 παθριοκυε εξ ναμ. Ιδ ναμ μινιμ υθροκυε. Αδ ναθυμ αππετερε σεα.
59
60 Μολλις φολυμυς κυι νο, θε φιμ υβικυε αδιπισι διγνισιμ. Νοβις νοσθρω
61 μενανδρι υσυ νο, πριμα ελιτρ κυαεκυε ιδ ηας. Πρω εα παρτεμ δομινγ. Θε
62 φασεθε αυδιρε φολυπθατιβυς ιυς. Φις δεθραξιθ ινφενιρε ετ, αν ιυς πωσθεα
63 μεδιοσριθαθεμ.
64
65 Εα αδχυς υταμυρ φις. Σιβω λαυδεμ υσυ αδ, φις λεγιμυς πλασεραθ φερθερεμ
66 συ. Φιμ ατ ειυς αλθερυμ φιθυπερατοριβυς, ατ λατινε ηαβεμυς φολυτπατ
67 μεα. Γραεσω λυσιλιυς εα φελ.
68
69 Θε φιξ βρυτε συμμο, φελ ωμιτθαμ ιμπερδιετ εξ. Μεα ιν μωδω νυμκυαμ, σεα
70 τρασθατος εξπετενδα αδ. Γραεσε πλαθονεμ ρεπυδιανδαε φιξ εα, εα ετιαμ
71 σωνσθιτυθο ασυεφεριθ σιθ. Ατ πυρθο ναθυμ σονγυε φιξ, κυι ετ δισαμ
72 ινερμις ινιμισυς.
73
74 Περ υθ διστα ινθεγρε, περ ρεκυε φιερενθ αδ. Νε δεσερυντ ινφενιρε
75 σωνσεθεθυρ μει, αν ηομερω αργυμενθυμ ρεπυδιανδαε περ, ηις σωνσυλ μελιορε
76 ινθελλεγαμ υθ. Νες εα λαβιθυρ δολορεμ υλλαμσορπερ. Μει εσεντ
77 νεσεσιταθιβυς ιν, αφφερθ σαυσαε ινθερεσετ ηας αν.
--- test/diff-test-1.wiki
+++ test/diff-test-1.wiki
@@ -33,10 +33,14 @@
3333
* <a href="../../../fdiff?v1=21f9a00fe2fa4a17&v2=d5c4ff0532bd89c3#chunk5"
3434
target="testwindow">sqlite3.c changes</a>
3535
that are difficult to align.
3636
* <a href="../../../fdiff?v2=21f9a00fe2fa4a17&v1=d5c4ff0532bd89c3#chunk5"
3737
target="testwindow">sqlite3.c changes inverted.</a>
38
+ * <a href="../../../fdiff?v1=4f70c682e44f&v2=55659c6e062994f"
39
+ target="testwindow">Lorem Ipsum in Greek.</a>
40
+ * <a href="../../../fdiff?v2=4f70c682e44f&v1=55659c6e062994f"
41
+ target="testwindow">Lorem Ipsum in Greek inverted.</a>
3842
3943
External:
4044
4145
* <a href="http://www.sqlite.org/src/fdiff?v1=aafcb21a74e41f9a&v2=a6d127dd05daf0f9#chunk3" target="testwindow">
4246
Code indentation change.</a>
4347
4448
ADDED test/glob.test
--- test/diff-test-1.wiki
+++ test/diff-test-1.wiki
@@ -33,10 +33,14 @@
33 * <a href="../../../fdiff?v1=21f9a00fe2fa4a17&v2=d5c4ff0532bd89c3#chunk5"
34 target="testwindow">sqlite3.c changes</a>
35 that are difficult to align.
36 * <a href="../../../fdiff?v2=21f9a00fe2fa4a17&v1=d5c4ff0532bd89c3#chunk5"
37 target="testwindow">sqlite3.c changes inverted.</a>
 
 
 
 
38
39 External:
40
41 * <a href="http://www.sqlite.org/src/fdiff?v1=aafcb21a74e41f9a&v2=a6d127dd05daf0f9#chunk3" target="testwindow">
42 Code indentation change.</a>
43
44 DDED test/glob.test
--- test/diff-test-1.wiki
+++ test/diff-test-1.wiki
@@ -33,10 +33,14 @@
33 * <a href="../../../fdiff?v1=21f9a00fe2fa4a17&v2=d5c4ff0532bd89c3#chunk5"
34 target="testwindow">sqlite3.c changes</a>
35 that are difficult to align.
36 * <a href="../../../fdiff?v2=21f9a00fe2fa4a17&v1=d5c4ff0532bd89c3#chunk5"
37 target="testwindow">sqlite3.c changes inverted.</a>
38 * <a href="../../../fdiff?v1=4f70c682e44f&v2=55659c6e062994f"
39 target="testwindow">Lorem Ipsum in Greek.</a>
40 * <a href="../../../fdiff?v2=4f70c682e44f&v1=55659c6e062994f"
41 target="testwindow">Lorem Ipsum in Greek inverted.</a>
42
43 External:
44
45 * <a href="http://www.sqlite.org/src/fdiff?v1=aafcb21a74e41f9a&v2=a6d127dd05daf0f9#chunk3" target="testwindow">
46 Code indentation change.</a>
47
48 DDED test/glob.test
--- a/test/glob.test
+++ b/test/glob.test
@@ -0,0 +1,118 @@
1
+#
2
+# Copyright (c) 2013 D. Richard Hipp
3
+#
4
+# This program is free software; you can redistribute it and/or
5
+# modify it under the terms of the Simplified BSD License (also
6
+# known as the "2-Clause License" or "FreeBSD License".)
7
+#
8
+# This program is distributed in the hope that it will be useful,
9
+# but without any warranty; without even the implied warranty of
10
+# merchantability or fitness for a particular purpose.
11
+#
12
+# Author contact information:
13
+# [email protected]
14
+# http://www.hwaci.com/drh/
15
+#
16
+############################################################################
17
+#
18
+# Test glob pattern parsing
19
+#
20
+
21
+ parsing
22
+#
23
+
24
+test_setup ""
25
+
26
+proc glob-parse {testname args} {
27
+ set i 1
28
+ foreach {pattern string result} $args {
29
+ fossil test-glob $pattern $string
30
+ test glob-parse-$testname.$i {$::RESULT eq $result}
31
+ incr i
32
+ }
33
+}
34
+
35
+glob-parse 100 test test [string map [list \r\n \n] \
36
+{SQL expression: (x GLOB 'test')
37
+pattern[0] = [test]
38
+1 t*')
39
+pattern[0] = [t*]
40
+1 1 test}]
41
+
42
+glob-parse 101 "one two" one [string map [list \r\n \n] \
43
+{SQL expression: (x GLOB 'one' OR x GLOB 'two')
44
+pattern[0] = 0 two one}]
45
+
46
+glob-p02 t* test-parse 108 "\"o*\rtwo\" \"thrt*#
47
+# Copyright (c)#
48
+# 1 test}]
49
+
50
+glob-parse 103 "o*test}]
51
+
52
+glob-parse 101 "one two" one [string map [list \r\n \n] \
53
+*' OR x GLOB 'two')
54
+pattern[0] =0 two one}]
55
+
56
+glob-p04 {"o* two" "three four"} "one two" [string map [list \r\n \n] \
57
+{SQL expression: (x GLOB 'o* two' OR x GLOB 'three four')
58
+pattern[0] = [o* two]
59
+pone two}]
60
+
61
+glob-parse 105 {"o* two" "three four"} "5 {"o* two" "three four"} "two one" [string map [list \r\n \n] \
62
+{SQL expression: (x GLOB 'o* two' OR x GLOB 'three four')
63
+pattern[0] = [o* two]
64
+p]
65
+0 0 two one}]
66
+
67
+glob-p0 0 two one}]
68
+
69
+glob-parse 106 "\"o*\ntwo\" \"three\nfour\"" "one\ntwo" \
70
+[string map [list \r\n \n] \
71
+{SQL expression: (x GLOB 'o*
72
+two' OR x GLOB 'three
73
+fou] = [one]
74
+pattern[1] = 1 1 one
75
+two}]
76
+
77
+glob-parse 107 "\"o*\ntwo\" \"three\nfour\"" "two\none" \
78
+[string map [list \r\n \n] \
79
+{SQL expression: (x GLOB 'o*
80
+two' OR x GLOB 'three
81
+foutwo
82
+0 two one}]
83
+
84
+glob-p08 "\"o*\rtwo\" \"three\rfour\"" "one\rtwo" \
85
+[string map [list \r\n \n] \
86
+{SQL expression: (x GLOB 'o*
87
+two' OR x GLOB 'three
88
+four')
89
+pattern[0] = [o*
90
+two]
91
+p] = [one]
92
+pattern[1] =
93
+ foreach {pattern string result} $args {
94
+ fossil test-glob $pattern $string
95
+ test glob-parse-$testname.$i {$::RESULT eq $result}
96
+ incr i
97
+ }
98
+}
99
+
100
+gtwo
101
+0 two one}]
102
+
103
+glob-patring map [list \r\n \n] \
104
+{SQL expression: (x GLOB 'test')
105
+pattern[0] = [test]
106
+1 1 test}]
107
+
108
+glob-parse 101 "one two" one [string map [list \r\n \n] \
109
+{] = [one]
110
+pattern[1] = [two]
111
+1 1 one}]
112
+
113
+glob-parse 102 t* test [string map [list \r\n \n] \
114
+{SQL expression: (x GLOB 't*')
115
+pattern[0] = [t*]
116
+1 1 test}]
117
+
118
+glob-parse 103 "o* two" one [st
--- a/test/glob.test
+++ b/test/glob.test
@@ -0,0 +1,118 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
--- a/test/glob.test
+++ b/test/glob.test
@@ -0,0 +1,118 @@
1 #
2 # Copyright (c) 2013 D. Richard Hipp
3 #
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the Simplified BSD License (also
6 # known as the "2-Clause License" or "FreeBSD License".)
7 #
8 # This program is distributed in the hope that it will be useful,
9 # but without any warranty; without even the implied warranty of
10 # merchantability or fitness for a particular purpose.
11 #
12 # Author contact information:
13 # [email protected]
14 # http://www.hwaci.com/drh/
15 #
16 ############################################################################
17 #
18 # Test glob pattern parsing
19 #
20
21 parsing
22 #
23
24 test_setup ""
25
26 proc glob-parse {testname args} {
27 set i 1
28 foreach {pattern string result} $args {
29 fossil test-glob $pattern $string
30 test glob-parse-$testname.$i {$::RESULT eq $result}
31 incr i
32 }
33 }
34
35 glob-parse 100 test test [string map [list \r\n \n] \
36 {SQL expression: (x GLOB 'test')
37 pattern[0] = [test]
38 1 t*')
39 pattern[0] = [t*]
40 1 1 test}]
41
42 glob-parse 101 "one two" one [string map [list \r\n \n] \
43 {SQL expression: (x GLOB 'one' OR x GLOB 'two')
44 pattern[0] = 0 two one}]
45
46 glob-p02 t* test-parse 108 "\"o*\rtwo\" \"thrt*#
47 # Copyright (c)#
48 # 1 test}]
49
50 glob-parse 103 "o*test}]
51
52 glob-parse 101 "one two" one [string map [list \r\n \n] \
53 *' OR x GLOB 'two')
54 pattern[0] =0 two one}]
55
56 glob-p04 {"o* two" "three four"} "one two" [string map [list \r\n \n] \
57 {SQL expression: (x GLOB 'o* two' OR x GLOB 'three four')
58 pattern[0] = [o* two]
59 pone two}]
60
61 glob-parse 105 {"o* two" "three four"} "5 {"o* two" "three four"} "two one" [string map [list \r\n \n] \
62 {SQL expression: (x GLOB 'o* two' OR x GLOB 'three four')
63 pattern[0] = [o* two]
64 p]
65 0 0 two one}]
66
67 glob-p0 0 two one}]
68
69 glob-parse 106 "\"o*\ntwo\" \"three\nfour\"" "one\ntwo" \
70 [string map [list \r\n \n] \
71 {SQL expression: (x GLOB 'o*
72 two' OR x GLOB 'three
73 fou] = [one]
74 pattern[1] = 1 1 one
75 two}]
76
77 glob-parse 107 "\"o*\ntwo\" \"three\nfour\"" "two\none" \
78 [string map [list \r\n \n] \
79 {SQL expression: (x GLOB 'o*
80 two' OR x GLOB 'three
81 foutwo
82 0 two one}]
83
84 glob-p08 "\"o*\rtwo\" \"three\rfour\"" "one\rtwo" \
85 [string map [list \r\n \n] \
86 {SQL expression: (x GLOB 'o*
87 two' OR x GLOB 'three
88 four')
89 pattern[0] = [o*
90 two]
91 p] = [one]
92 pattern[1] =
93 foreach {pattern string result} $args {
94 fossil test-glob $pattern $string
95 test glob-parse-$testname.$i {$::RESULT eq $result}
96 incr i
97 }
98 }
99
100 gtwo
101 0 two one}]
102
103 glob-patring map [list \r\n \n] \
104 {SQL expression: (x GLOB 'test')
105 pattern[0] = [test]
106 1 1 test}]
107
108 glob-parse 101 "one two" one [string map [list \r\n \n] \
109 {] = [one]
110 pattern[1] = [two]
111 1 1 one}]
112
113 glob-parse 102 t* test [string map [list \r\n \n] \
114 {SQL expression: (x GLOB 't*')
115 pattern[0] = [t*]
116 1 1 test}]
117
118 glob-parse 103 "o* two" one [st
--- test/th1-tcl.test
+++ test/th1-tcl.test
@@ -17,10 +17,18 @@
1717
#
1818
# TH1/Tcl integration
1919
#
2020
2121
set dir [file dirname [info script]]
22
+
23
+###############################################################################
24
+
25
+fossil test-th-eval "hasfeature tcl"
26
+
27
+if {$::RESULT ne "1"} then {
28
+ puts "Fossil was not compiled with Tcl support."; return
29
+}
2230
2331
###############################################################################
2432
2533
set env(TH1_ENABLE_TCL) 1; # Tcl integration must be enabled for this test.
2634
2735
2836
ADDED test/utf.test
--- test/th1-tcl.test
+++ test/th1-tcl.test
@@ -17,10 +17,18 @@
17 #
18 # TH1/Tcl integration
19 #
20
21 set dir [file dirname [info script]]
 
 
 
 
 
 
 
 
22
23 ###############################################################################
24
25 set env(TH1_ENABLE_TCL) 1; # Tcl integration must be enabled for this test.
26
27
28 DDED test/utf.test
--- test/th1-tcl.test
+++ test/th1-tcl.test
@@ -17,10 +17,18 @@
17 #
18 # TH1/Tcl integration
19 #
20
21 set dir [file dirname [info script]]
22
23 ###############################################################################
24
25 fossil test-th-eval "hasfeature tcl"
26
27 if {$::RESULT ne "1"} then {
28 puts "Fossil was not compiled with Tcl support."; return
29 }
30
31 ###############################################################################
32
33 set env(TH1_ENABLE_TCL) 1; # Tcl integration must be enabled for this test.
34
35
36 DDED test/utf.test
--- a/test/utf.test
+++ b/test/utf.test
@@ -0,0 +1,77 @@
1
+#
2
+0\x81\
3
+ 162 \xC0\x81\
4
+ 163 \xC0\x81\
5
+ 164 \xC0\x81\
6
+ 165 \xC1111E \
7
+ 170 \xE \
8
+ 171 \xE \
9
+ 172 \xE \
10
+ 1777777718#
11
+431-0-1#
12
+#
13
+#
14
+437-0437-0-168#
15
+438-04441 #
16
+44#
17
+#
18
+446-0446-0-1747448 49449-052 52-0-17454 454-0-1754-05 456#
19
+9459-0#
20
+461-0462-1-46463-1-4646446464-1-1465 465-1-465-1-166466-1-6467-1-468 utf-check-468-1-6469469-1-469-1-347070-1-70-1-471 471-1-47472 47472-1-473#
21
+7474474-1-4-1-6#
22
+#475-1-61-7477 477-1477-1-78#
23
+479 utf-check-479-1474808480-1-9481#
24
+848282-1-1482-1-10148484484-1-1484-1-11485485-1-481-16-1-487 utf-check-487-148488-1-13489 ut524524-1524-1-31#
25
+525-1-32265226-1-32#
26
+#
27
+32528-1-35295229-1-#
28
+5331
29
+31-1-3#
30
+532-1-3#
31
+#
32
+53#
33
+5334-1-335 535-15336-1-337 utf-check-537-1#
34
+38 utf-check-5338-1-3#
35
+#
36
+#
37
+40 5440-1-39#
38
+#
39
+342 4542-1-40543543-1-5444 544-1-4154545-1-441546 57-1-47558 #
40
+#
41
+560560-156enc [list \
42
+ 0 bk-155-6Z@Yyk,6:155-6-19@14LW,O@1~fl,Z:Line endings: NONE
43
+Other flags:\
44
+-01W@XtW,j:Line endings: AN_CR LONE_CR
45
+Other flag ANY_CR LONE_CR
46
+Other flags: NONEV@8dM,1:7Z@11kG,7:157-7-0h@z9W,p@WJ0,j:Line en\
47
+ 0 ""8jj,1:xEF\xBB\xBFOther \
48
+platform(byteOrder) eq "littleEndian" ? \
49
+ "\xFF\xFE" : "\FE\xFF"NONV@8wU,2:7-_@9LW,5:0-7-218@1AcW,R@17eW,j:Line endings: ANY_CR LONE_CR
50
+Other flas: NONED@H4W,K:161 utf-\
51
+ 0 ""\
52
+ 1 A8jj,1:xEF\\
53
+ 2 AB\
54
+ 3 ABCLine endings: A4 1-7-218@1iOG,P@1V\
55
+ 3 unicode \
56
+ 5 A#
57
+0\x81\
58
+ 162 \xC0\x81\
59
+ \xC0\x81\
60
+ 163#
61
+0\x81\
62
+ 162 \xC0\x81\
63
+ 163 \xC0\x81\
64
+ 164 \xC0\x81\
65
+ 165 \xC1111E \
66
+ 170 \xE \
67
+ 171 \xE \
68
+ 172 \xE \
69
+ 1777777718#
70
+431-0-1#
71
+#
72
+#
73
+437-0437-0-168#
74
+438-04441 #
75
+44#
76
+#
77
+446-0446-0-1747448 49449-052 52-0-17454 454-0-175
--- a/test/utf.test
+++ b/test/utf.test
@@ -0,0 +1,77 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
--- a/test/utf.test
+++ b/test/utf.test
@@ -0,0 +1,77 @@
1 #
2 0\x81\
3 162 \xC0\x81\
4 163 \xC0\x81\
5 164 \xC0\x81\
6 165 \xC1111E \
7 170 \xE \
8 171 \xE \
9 172 \xE \
10 1777777718#
11 431-0-1#
12 #
13 #
14 437-0437-0-168#
15 438-04441 #
16 44#
17 #
18 446-0446-0-1747448 49449-052 52-0-17454 454-0-1754-05 456#
19 9459-0#
20 461-0462-1-46463-1-4646446464-1-1465 465-1-465-1-166466-1-6467-1-468 utf-check-468-1-6469469-1-469-1-347070-1-70-1-471 471-1-47472 47472-1-473#
21 7474474-1-4-1-6#
22 #475-1-61-7477 477-1477-1-78#
23 479 utf-check-479-1474808480-1-9481#
24 848282-1-1482-1-10148484484-1-1484-1-11485485-1-481-16-1-487 utf-check-487-148488-1-13489 ut524524-1524-1-31#
25 525-1-32265226-1-32#
26 #
27 32528-1-35295229-1-#
28 5331
29 31-1-3#
30 532-1-3#
31 #
32 53#
33 5334-1-335 535-15336-1-337 utf-check-537-1#
34 38 utf-check-5338-1-3#
35 #
36 #
37 40 5440-1-39#
38 #
39 342 4542-1-40543543-1-5444 544-1-4154545-1-441546 57-1-47558 #
40 #
41 560560-156enc [list \
42 0 bk-155-6Z@Yyk,6:155-6-19@14LW,O@1~fl,Z:Line endings: NONE
43 Other flags:\
44 -01W@XtW,j:Line endings: AN_CR LONE_CR
45 Other flag ANY_CR LONE_CR
46 Other flags: NONEV@8dM,1:7Z@11kG,7:157-7-0h@z9W,p@WJ0,j:Line en\
47 0 ""8jj,1:xEF\xBB\xBFOther \
48 platform(byteOrder) eq "littleEndian" ? \
49 "\xFF\xFE" : "\FE\xFF"NONV@8wU,2:7-_@9LW,5:0-7-218@1AcW,R@17eW,j:Line endings: ANY_CR LONE_CR
50 Other flas: NONED@H4W,K:161 utf-\
51 0 ""\
52 1 A8jj,1:xEF\\
53 2 AB\
54 3 ABCLine endings: A4 1-7-218@1iOG,P@1V\
55 3 unicode \
56 5 A#
57 0\x81\
58 162 \xC0\x81\
59 \xC0\x81\
60 163#
61 0\x81\
62 162 \xC0\x81\
63 163 \xC0\x81\
64 164 \xC0\x81\
65 165 \xC1111E \
66 170 \xE \
67 171 \xE \
68 172 \xE \
69 1777777718#
70 431-0-1#
71 #
72 #
73 437-0437-0-168#
74 438-04441 #
75 44#
76 #
77 446-0446-0-1747448 49449-052 52-0-17454 454-0-175
+17 -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_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 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 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_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)\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)\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_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 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 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 >> $@
@@ -103,10 +103,11 @@
103103
$(OBJDIR)\json_dir$O : $(SRCDIR)\json_detail.h
104104
$(OBJDIR)\json_finfo$O : $(SRCDIR)\json_detail.h
105105
$(OBJDIR)\json_login$O : $(SRCDIR)\json_detail.h
106106
$(OBJDIR)\json_query$O : $(SRCDIR)\json_detail.h
107107
$(OBJDIR)\json_report$O : $(SRCDIR)\json_detail.h
108
+$(OBJDIR)\json_status$O : $(SRCDIR)\json_detail.h
108109
$(OBJDIR)\json_tag$O : $(SRCDIR)\json_detail.h
109110
$(OBJDIR)\json_timeline$O : $(SRCDIR)\json_detail.h
110111
$(OBJDIR)\json_user$O : $(SRCDIR)\json_detail.h
111112
$(OBJDIR)\json_wiki$O : $(SRCDIR)\json_detail.h
112113
@@ -397,10 +398,16 @@
397398
$(OBJDIR)\json_report$O : json_report_.c json_report.h
398399
$(TCC) -o$@ -c json_report_.c
399400
400401
json_report_.c : $(SRCDIR)\json_report.c
401402
+translate$E $** > $@
403
+
404
+$(OBJDIR)\json_status$O : json_status_.c json_status.h
405
+ $(TCC) -o$@ -c json_status_.c
406
+
407
+json_status_.c : $(SRCDIR)\json_status.c
408
+ +translate$E $** > $@
402409
403410
$(OBJDIR)\json_tag$O : json_tag_.c json_tag.h
404411
$(TCC) -o$@ -c json_tag_.c
405412
406413
json_tag_.c : $(SRCDIR)\json_tag.c
@@ -679,10 +686,16 @@
679686
$(OBJDIR)\utf8$O : utf8_.c utf8.h
680687
$(TCC) -o$@ -c utf8_.c
681688
682689
utf8_.c : $(SRCDIR)\utf8.c
683690
+translate$E $** > $@
691
+
692
+$(OBJDIR)\util$O : util_.c util.h
693
+ $(TCC) -o$@ -c util_.c
694
+
695
+util_.c : $(SRCDIR)\util.c
696
+ +translate$E $** > $@
684697
685698
$(OBJDIR)\verify$O : verify_.c verify.h
686699
$(TCC) -o$@ -c verify_.c
687700
688701
verify_.c : $(SRCDIR)\verify.c
@@ -735,7 +748,7 @@
735748
736749
zip_.c : $(SRCDIR)\zip.c
737750
+translate$E $** > $@
738751
739752
headers: makeheaders$E page_index.h VERSION.h
740
- +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_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 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
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
741754
@copy /Y nul: headers
742755
--- 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_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 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_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)\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_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 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 >> $@
@@ -103,10 +103,11 @@
103 $(OBJDIR)\json_dir$O : $(SRCDIR)\json_detail.h
104 $(OBJDIR)\json_finfo$O : $(SRCDIR)\json_detail.h
105 $(OBJDIR)\json_login$O : $(SRCDIR)\json_detail.h
106 $(OBJDIR)\json_query$O : $(SRCDIR)\json_detail.h
107 $(OBJDIR)\json_report$O : $(SRCDIR)\json_detail.h
 
108 $(OBJDIR)\json_tag$O : $(SRCDIR)\json_detail.h
109 $(OBJDIR)\json_timeline$O : $(SRCDIR)\json_detail.h
110 $(OBJDIR)\json_user$O : $(SRCDIR)\json_detail.h
111 $(OBJDIR)\json_wiki$O : $(SRCDIR)\json_detail.h
112
@@ -397,10 +398,16 @@
397 $(OBJDIR)\json_report$O : json_report_.c json_report.h
398 $(TCC) -o$@ -c json_report_.c
399
400 json_report_.c : $(SRCDIR)\json_report.c
401 +translate$E $** > $@
 
 
 
 
 
 
402
403 $(OBJDIR)\json_tag$O : json_tag_.c json_tag.h
404 $(TCC) -o$@ -c json_tag_.c
405
406 json_tag_.c : $(SRCDIR)\json_tag.c
@@ -679,10 +686,16 @@
679 $(OBJDIR)\utf8$O : utf8_.c utf8.h
680 $(TCC) -o$@ -c utf8_.c
681
682 utf8_.c : $(SRCDIR)\utf8.c
683 +translate$E $** > $@
 
 
 
 
 
 
684
685 $(OBJDIR)\verify$O : verify_.c verify.h
686 $(TCC) -o$@ -c verify_.c
687
688 verify_.c : $(SRCDIR)\verify.c
@@ -735,7 +748,7 @@
735
736 zip_.c : $(SRCDIR)\zip.c
737 +translate$E $** > $@
738
739 headers: makeheaders$E page_index.h VERSION.h
740 +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_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 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
741 @copy /Y nul: headers
742
--- 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 >> $@
@@ -103,10 +103,11 @@
103 $(OBJDIR)\json_dir$O : $(SRCDIR)\json_detail.h
104 $(OBJDIR)\json_finfo$O : $(SRCDIR)\json_detail.h
105 $(OBJDIR)\json_login$O : $(SRCDIR)\json_detail.h
106 $(OBJDIR)\json_query$O : $(SRCDIR)\json_detail.h
107 $(OBJDIR)\json_report$O : $(SRCDIR)\json_detail.h
108 $(OBJDIR)\json_status$O : $(SRCDIR)\json_detail.h
109 $(OBJDIR)\json_tag$O : $(SRCDIR)\json_detail.h
110 $(OBJDIR)\json_timeline$O : $(SRCDIR)\json_detail.h
111 $(OBJDIR)\json_user$O : $(SRCDIR)\json_detail.h
112 $(OBJDIR)\json_wiki$O : $(SRCDIR)\json_detail.h
113
@@ -397,10 +398,16 @@
398 $(OBJDIR)\json_report$O : json_report_.c json_report.h
399 $(TCC) -o$@ -c json_report_.c
400
401 json_report_.c : $(SRCDIR)\json_report.c
402 +translate$E $** > $@
403
404 $(OBJDIR)\json_status$O : json_status_.c json_status.h
405 $(TCC) -o$@ -c json_status_.c
406
407 json_status_.c : $(SRCDIR)\json_status.c
408 +translate$E $** > $@
409
410 $(OBJDIR)\json_tag$O : json_tag_.c json_tag.h
411 $(TCC) -o$@ -c json_tag_.c
412
413 json_tag_.c : $(SRCDIR)\json_tag.c
@@ -679,10 +686,16 @@
686 $(OBJDIR)\utf8$O : utf8_.c utf8.h
687 $(TCC) -o$@ -c utf8_.c
688
689 utf8_.c : $(SRCDIR)\utf8.c
690 +translate$E $** > $@
691
692 $(OBJDIR)\util$O : util_.c util.h
693 $(TCC) -o$@ -c util_.c
694
695 util_.c : $(SRCDIR)\util.c
696 +translate$E $** > $@
697
698 $(OBJDIR)\verify$O : verify_.c verify.h
699 $(TCC) -o$@ -c verify_.c
700
701 verify_.c : $(SRCDIR)\verify.c
@@ -735,7 +748,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.mingw
+++ win/Makefile.mingw
@@ -84,12 +84,12 @@
8484
#### The directories where the OpenSSL include and library files are located.
8585
# The recommended usage here is to use the Sysinternals junction tool
8686
# to create a hard link between an "openssl-1.x" sub-directory of the
8787
# Fossil source code directory and the target OpenSSL source directory.
8888
#
89
-OPENSSLINCDIR = $(SRCDIR)/../openssl-1.0.1c/include
90
-OPENSSLLIBDIR = $(SRCDIR)/../openssl-1.0.1c
89
+OPENSSLINCDIR = $(SRCDIR)/../openssl-1.0.1e/include
90
+OPENSSLLIBDIR = $(SRCDIR)/../openssl-1.0.1e
9191
9292
#### Either the directory where the Tcl library is installed or the Tcl
9393
# source code directory resides (depending on the value of the macro
9494
# FOSSIL_TCL_SOURCE). If this points to the Tcl install directory,
9595
# this directory must have "include" and "lib" sub-directories. If
@@ -301,10 +301,11 @@
301301
$(SRCDIR)/json_dir.c \
302302
$(SRCDIR)/json_finfo.c \
303303
$(SRCDIR)/json_login.c \
304304
$(SRCDIR)/json_query.c \
305305
$(SRCDIR)/json_report.c \
306
+ $(SRCDIR)/json_status.c \
306307
$(SRCDIR)/json_tag.c \
307308
$(SRCDIR)/json_timeline.c \
308309
$(SRCDIR)/json_user.c \
309310
$(SRCDIR)/json_wiki.c \
310311
$(SRCDIR)/leaf.c \
@@ -348,10 +349,11 @@
348349
$(SRCDIR)/unicode.c \
349350
$(SRCDIR)/update.c \
350351
$(SRCDIR)/url.c \
351352
$(SRCDIR)/user.c \
352353
$(SRCDIR)/utf8.c \
354
+ $(SRCDIR)/util.c \
353355
$(SRCDIR)/verify.c \
354356
$(SRCDIR)/vfile.c \
355357
$(SRCDIR)/wiki.c \
356358
$(SRCDIR)/wikiformat.c \
357359
$(SRCDIR)/winhttp.c \
@@ -407,10 +409,11 @@
407409
$(OBJDIR)/json_dir_.c \
408410
$(OBJDIR)/json_finfo_.c \
409411
$(OBJDIR)/json_login_.c \
410412
$(OBJDIR)/json_query_.c \
411413
$(OBJDIR)/json_report_.c \
414
+ $(OBJDIR)/json_status_.c \
412415
$(OBJDIR)/json_tag_.c \
413416
$(OBJDIR)/json_timeline_.c \
414417
$(OBJDIR)/json_user_.c \
415418
$(OBJDIR)/json_wiki_.c \
416419
$(OBJDIR)/leaf_.c \
@@ -454,10 +457,11 @@
454457
$(OBJDIR)/unicode_.c \
455458
$(OBJDIR)/update_.c \
456459
$(OBJDIR)/url_.c \
457460
$(OBJDIR)/user_.c \
458461
$(OBJDIR)/utf8_.c \
462
+ $(OBJDIR)/util_.c \
459463
$(OBJDIR)/verify_.c \
460464
$(OBJDIR)/vfile_.c \
461465
$(OBJDIR)/wiki_.c \
462466
$(OBJDIR)/wikiformat_.c \
463467
$(OBJDIR)/winhttp_.c \
@@ -513,10 +517,11 @@
513517
$(OBJDIR)/json_dir.o \
514518
$(OBJDIR)/json_finfo.o \
515519
$(OBJDIR)/json_login.o \
516520
$(OBJDIR)/json_query.o \
517521
$(OBJDIR)/json_report.o \
522
+ $(OBJDIR)/json_status.o \
518523
$(OBJDIR)/json_tag.o \
519524
$(OBJDIR)/json_timeline.o \
520525
$(OBJDIR)/json_user.o \
521526
$(OBJDIR)/json_wiki.o \
522527
$(OBJDIR)/leaf.o \
@@ -560,10 +565,11 @@
560565
$(OBJDIR)/unicode.o \
561566
$(OBJDIR)/update.o \
562567
$(OBJDIR)/url.o \
563568
$(OBJDIR)/user.o \
564569
$(OBJDIR)/utf8.o \
570
+ $(OBJDIR)/util.o \
565571
$(OBJDIR)/verify.o \
566572
$(OBJDIR)/vfile.o \
567573
$(OBJDIR)/wiki.o \
568574
$(OBJDIR)/wikiformat.o \
569575
$(OBJDIR)/winhttp.o \
@@ -732,10 +738,11 @@
732738
$(OBJDIR)/json_dir_.c:$(OBJDIR)/json_dir.h \
733739
$(OBJDIR)/json_finfo_.c:$(OBJDIR)/json_finfo.h \
734740
$(OBJDIR)/json_login_.c:$(OBJDIR)/json_login.h \
735741
$(OBJDIR)/json_query_.c:$(OBJDIR)/json_query.h \
736742
$(OBJDIR)/json_report_.c:$(OBJDIR)/json_report.h \
743
+ $(OBJDIR)/json_status_.c:$(OBJDIR)/json_status.h \
737744
$(OBJDIR)/json_tag_.c:$(OBJDIR)/json_tag.h \
738745
$(OBJDIR)/json_timeline_.c:$(OBJDIR)/json_timeline.h \
739746
$(OBJDIR)/json_user_.c:$(OBJDIR)/json_user.h \
740747
$(OBJDIR)/json_wiki_.c:$(OBJDIR)/json_wiki.h \
741748
$(OBJDIR)/leaf_.c:$(OBJDIR)/leaf.h \
@@ -779,10 +786,11 @@
779786
$(OBJDIR)/unicode_.c:$(OBJDIR)/unicode.h \
780787
$(OBJDIR)/update_.c:$(OBJDIR)/update.h \
781788
$(OBJDIR)/url_.c:$(OBJDIR)/url.h \
782789
$(OBJDIR)/user_.c:$(OBJDIR)/user.h \
783790
$(OBJDIR)/utf8_.c:$(OBJDIR)/utf8.h \
791
+ $(OBJDIR)/util_.c:$(OBJDIR)/util.h \
784792
$(OBJDIR)/verify_.c:$(OBJDIR)/verify.h \
785793
$(OBJDIR)/vfile_.c:$(OBJDIR)/vfile.h \
786794
$(OBJDIR)/wiki_.c:$(OBJDIR)/wiki.h \
787795
$(OBJDIR)/wikiformat_.c:$(OBJDIR)/wikiformat.h \
788796
$(OBJDIR)/winhttp_.c:$(OBJDIR)/winhttp.h \
@@ -1180,10 +1188,18 @@
11801188
11811189
$(OBJDIR)/json_report.o: $(OBJDIR)/json_report_.c $(OBJDIR)/json_report.h $(SRCDIR)/config.h
11821190
$(XTCC) -o $(OBJDIR)/json_report.o -c $(OBJDIR)/json_report_.c
11831191
11841192
$(OBJDIR)/json_report.h: $(OBJDIR)/headers
1193
+
1194
+$(OBJDIR)/json_status_.c: $(SRCDIR)/json_status.c $(OBJDIR)/translate
1195
+ $(TRANSLATE) $(SRCDIR)/json_status.c >$(OBJDIR)/json_status_.c
1196
+
1197
+$(OBJDIR)/json_status.o: $(OBJDIR)/json_status_.c $(OBJDIR)/json_status.h $(SRCDIR)/config.h
1198
+ $(XTCC) -o $(OBJDIR)/json_status.o -c $(OBJDIR)/json_status_.c
1199
+
1200
+$(OBJDIR)/json_status.h: $(OBJDIR)/headers
11851201
11861202
$(OBJDIR)/json_tag_.c: $(SRCDIR)/json_tag.c $(OBJDIR)/translate
11871203
$(TRANSLATE) $(SRCDIR)/json_tag.c >$(OBJDIR)/json_tag_.c
11881204
11891205
$(OBJDIR)/json_tag.o: $(OBJDIR)/json_tag_.c $(OBJDIR)/json_tag.h $(SRCDIR)/config.h
@@ -1556,10 +1572,18 @@
15561572
15571573
$(OBJDIR)/utf8.o: $(OBJDIR)/utf8_.c $(OBJDIR)/utf8.h $(SRCDIR)/config.h
15581574
$(XTCC) -o $(OBJDIR)/utf8.o -c $(OBJDIR)/utf8_.c
15591575
15601576
$(OBJDIR)/utf8.h: $(OBJDIR)/headers
1577
+
1578
+$(OBJDIR)/util_.c: $(SRCDIR)/util.c $(OBJDIR)/translate
1579
+ $(TRANSLATE) $(SRCDIR)/util.c >$(OBJDIR)/util_.c
1580
+
1581
+$(OBJDIR)/util.o: $(OBJDIR)/util_.c $(OBJDIR)/util.h $(SRCDIR)/config.h
1582
+ $(XTCC) -o $(OBJDIR)/util.o -c $(OBJDIR)/util_.c
1583
+
1584
+$(OBJDIR)/util.h: $(OBJDIR)/headers
15611585
15621586
$(OBJDIR)/verify_.c: $(SRCDIR)/verify.c $(OBJDIR)/translate
15631587
$(TRANSLATE) $(SRCDIR)/verify.c >$(OBJDIR)/verify_.c
15641588
15651589
$(OBJDIR)/verify.o: $(OBJDIR)/verify_.c $(OBJDIR)/verify.h $(SRCDIR)/config.h
@@ -1635,11 +1659,11 @@
16351659
$(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
16361660
16371661
$(OBJDIR)/cson_amalgamation.o: $(SRCDIR)/cson_amalgamation.c
16381662
$(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.o
16391663
1640
-$(OBJDIR)/json.o $(OBJDIR)/json_artifact.o $(OBJDIR)/json_branch.o $(OBJDIR)/json_config.o $(OBJDIR)/json_diff.o $(OBJDIR)/json_dir.o $(OBJDIR)/jsos_finfo.o $(OBJDIR)/json_login.o $(OBJDIR)/json_query.o $(OBJDIR)/json_report.o $(OBJDIR)/json_tag.o $(OBJDIR)/json_timeline.o $(OBJDIR)/json_user.o $(OBJDIR)/json_wiki.o : $(SRCDIR)/json_detail.h
1664
+$(OBJDIR)/json.o $(OBJDIR)/json_artifact.o $(OBJDIR)/json_branch.o $(OBJDIR)/json_config.o $(OBJDIR)/json_diff.o $(OBJDIR)/json_dir.o $(OBJDIR)/jsos_finfo.o $(OBJDIR)/json_login.o $(OBJDIR)/json_query.o $(OBJDIR)/json_report.o $(OBJDIR)/json_status.o $(OBJDIR)/json_tag.o $(OBJDIR)/json_timeline.o $(OBJDIR)/json_user.o $(OBJDIR)/json_wiki.o : $(SRCDIR)/json_detail.h
16411665
16421666
$(OBJDIR)/shell.o: $(SRCDIR)/shell.c $(SRCDIR)/sqlite3.h
16431667
$(XTCC) -Dmain=sqlite3_shell -DSQLITE_OMIT_LOAD_EXTENSION=1 -c $(SRCDIR)/shell.c -o $(OBJDIR)/shell.o
16441668
16451669
$(OBJDIR)/th.o: $(SRCDIR)/th.c
16461670
--- win/Makefile.mingw
+++ win/Makefile.mingw
@@ -84,12 +84,12 @@
84 #### The directories where the OpenSSL include and library files are located.
85 # The recommended usage here is to use the Sysinternals junction tool
86 # to create a hard link between an "openssl-1.x" sub-directory of the
87 # Fossil source code directory and the target OpenSSL source directory.
88 #
89 OPENSSLINCDIR = $(SRCDIR)/../openssl-1.0.1c/include
90 OPENSSLLIBDIR = $(SRCDIR)/../openssl-1.0.1c
91
92 #### Either the directory where the Tcl library is installed or the Tcl
93 # source code directory resides (depending on the value of the macro
94 # FOSSIL_TCL_SOURCE). If this points to the Tcl install directory,
95 # this directory must have "include" and "lib" sub-directories. If
@@ -301,10 +301,11 @@
301 $(SRCDIR)/json_dir.c \
302 $(SRCDIR)/json_finfo.c \
303 $(SRCDIR)/json_login.c \
304 $(SRCDIR)/json_query.c \
305 $(SRCDIR)/json_report.c \
 
306 $(SRCDIR)/json_tag.c \
307 $(SRCDIR)/json_timeline.c \
308 $(SRCDIR)/json_user.c \
309 $(SRCDIR)/json_wiki.c \
310 $(SRCDIR)/leaf.c \
@@ -348,10 +349,11 @@
348 $(SRCDIR)/unicode.c \
349 $(SRCDIR)/update.c \
350 $(SRCDIR)/url.c \
351 $(SRCDIR)/user.c \
352 $(SRCDIR)/utf8.c \
 
353 $(SRCDIR)/verify.c \
354 $(SRCDIR)/vfile.c \
355 $(SRCDIR)/wiki.c \
356 $(SRCDIR)/wikiformat.c \
357 $(SRCDIR)/winhttp.c \
@@ -407,10 +409,11 @@
407 $(OBJDIR)/json_dir_.c \
408 $(OBJDIR)/json_finfo_.c \
409 $(OBJDIR)/json_login_.c \
410 $(OBJDIR)/json_query_.c \
411 $(OBJDIR)/json_report_.c \
 
412 $(OBJDIR)/json_tag_.c \
413 $(OBJDIR)/json_timeline_.c \
414 $(OBJDIR)/json_user_.c \
415 $(OBJDIR)/json_wiki_.c \
416 $(OBJDIR)/leaf_.c \
@@ -454,10 +457,11 @@
454 $(OBJDIR)/unicode_.c \
455 $(OBJDIR)/update_.c \
456 $(OBJDIR)/url_.c \
457 $(OBJDIR)/user_.c \
458 $(OBJDIR)/utf8_.c \
 
459 $(OBJDIR)/verify_.c \
460 $(OBJDIR)/vfile_.c \
461 $(OBJDIR)/wiki_.c \
462 $(OBJDIR)/wikiformat_.c \
463 $(OBJDIR)/winhttp_.c \
@@ -513,10 +517,11 @@
513 $(OBJDIR)/json_dir.o \
514 $(OBJDIR)/json_finfo.o \
515 $(OBJDIR)/json_login.o \
516 $(OBJDIR)/json_query.o \
517 $(OBJDIR)/json_report.o \
 
518 $(OBJDIR)/json_tag.o \
519 $(OBJDIR)/json_timeline.o \
520 $(OBJDIR)/json_user.o \
521 $(OBJDIR)/json_wiki.o \
522 $(OBJDIR)/leaf.o \
@@ -560,10 +565,11 @@
560 $(OBJDIR)/unicode.o \
561 $(OBJDIR)/update.o \
562 $(OBJDIR)/url.o \
563 $(OBJDIR)/user.o \
564 $(OBJDIR)/utf8.o \
 
565 $(OBJDIR)/verify.o \
566 $(OBJDIR)/vfile.o \
567 $(OBJDIR)/wiki.o \
568 $(OBJDIR)/wikiformat.o \
569 $(OBJDIR)/winhttp.o \
@@ -732,10 +738,11 @@
732 $(OBJDIR)/json_dir_.c:$(OBJDIR)/json_dir.h \
733 $(OBJDIR)/json_finfo_.c:$(OBJDIR)/json_finfo.h \
734 $(OBJDIR)/json_login_.c:$(OBJDIR)/json_login.h \
735 $(OBJDIR)/json_query_.c:$(OBJDIR)/json_query.h \
736 $(OBJDIR)/json_report_.c:$(OBJDIR)/json_report.h \
 
737 $(OBJDIR)/json_tag_.c:$(OBJDIR)/json_tag.h \
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 \
@@ -779,10 +786,11 @@
779 $(OBJDIR)/unicode_.c:$(OBJDIR)/unicode.h \
780 $(OBJDIR)/update_.c:$(OBJDIR)/update.h \
781 $(OBJDIR)/url_.c:$(OBJDIR)/url.h \
782 $(OBJDIR)/user_.c:$(OBJDIR)/user.h \
783 $(OBJDIR)/utf8_.c:$(OBJDIR)/utf8.h \
 
784 $(OBJDIR)/verify_.c:$(OBJDIR)/verify.h \
785 $(OBJDIR)/vfile_.c:$(OBJDIR)/vfile.h \
786 $(OBJDIR)/wiki_.c:$(OBJDIR)/wiki.h \
787 $(OBJDIR)/wikiformat_.c:$(OBJDIR)/wikiformat.h \
788 $(OBJDIR)/winhttp_.c:$(OBJDIR)/winhttp.h \
@@ -1180,10 +1188,18 @@
1180
1181 $(OBJDIR)/json_report.o: $(OBJDIR)/json_report_.c $(OBJDIR)/json_report.h $(SRCDIR)/config.h
1182 $(XTCC) -o $(OBJDIR)/json_report.o -c $(OBJDIR)/json_report_.c
1183
1184 $(OBJDIR)/json_report.h: $(OBJDIR)/headers
 
 
 
 
 
 
 
 
1185
1186 $(OBJDIR)/json_tag_.c: $(SRCDIR)/json_tag.c $(OBJDIR)/translate
1187 $(TRANSLATE) $(SRCDIR)/json_tag.c >$(OBJDIR)/json_tag_.c
1188
1189 $(OBJDIR)/json_tag.o: $(OBJDIR)/json_tag_.c $(OBJDIR)/json_tag.h $(SRCDIR)/config.h
@@ -1556,10 +1572,18 @@
1556
1557 $(OBJDIR)/utf8.o: $(OBJDIR)/utf8_.c $(OBJDIR)/utf8.h $(SRCDIR)/config.h
1558 $(XTCC) -o $(OBJDIR)/utf8.o -c $(OBJDIR)/utf8_.c
1559
1560 $(OBJDIR)/utf8.h: $(OBJDIR)/headers
 
 
 
 
 
 
 
 
1561
1562 $(OBJDIR)/verify_.c: $(SRCDIR)/verify.c $(OBJDIR)/translate
1563 $(TRANSLATE) $(SRCDIR)/verify.c >$(OBJDIR)/verify_.c
1564
1565 $(OBJDIR)/verify.o: $(OBJDIR)/verify_.c $(OBJDIR)/verify.h $(SRCDIR)/config.h
@@ -1635,11 +1659,11 @@
1635 $(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
1636
1637 $(OBJDIR)/cson_amalgamation.o: $(SRCDIR)/cson_amalgamation.c
1638 $(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.o
1639
1640 $(OBJDIR)/json.o $(OBJDIR)/json_artifact.o $(OBJDIR)/json_branch.o $(OBJDIR)/json_config.o $(OBJDIR)/json_diff.o $(OBJDIR)/json_dir.o $(OBJDIR)/jsos_finfo.o $(OBJDIR)/json_login.o $(OBJDIR)/json_query.o $(OBJDIR)/json_report.o $(OBJDIR)/json_tag.o $(OBJDIR)/json_timeline.o $(OBJDIR)/json_user.o $(OBJDIR)/json_wiki.o : $(SRCDIR)/json_detail.h
1641
1642 $(OBJDIR)/shell.o: $(SRCDIR)/shell.c $(SRCDIR)/sqlite3.h
1643 $(XTCC) -Dmain=sqlite3_shell -DSQLITE_OMIT_LOAD_EXTENSION=1 -c $(SRCDIR)/shell.c -o $(OBJDIR)/shell.o
1644
1645 $(OBJDIR)/th.o: $(SRCDIR)/th.c
1646
--- win/Makefile.mingw
+++ win/Makefile.mingw
@@ -84,12 +84,12 @@
84 #### The directories where the OpenSSL include and library files are located.
85 # The recommended usage here is to use the Sysinternals junction tool
86 # to create a hard link between an "openssl-1.x" sub-directory of the
87 # Fossil source code directory and the target OpenSSL source directory.
88 #
89 OPENSSLINCDIR = $(SRCDIR)/../openssl-1.0.1e/include
90 OPENSSLLIBDIR = $(SRCDIR)/../openssl-1.0.1e
91
92 #### Either the directory where the Tcl library is installed or the Tcl
93 # source code directory resides (depending on the value of the macro
94 # FOSSIL_TCL_SOURCE). If this points to the Tcl install directory,
95 # this directory must have "include" and "lib" sub-directories. If
@@ -301,10 +301,11 @@
301 $(SRCDIR)/json_dir.c \
302 $(SRCDIR)/json_finfo.c \
303 $(SRCDIR)/json_login.c \
304 $(SRCDIR)/json_query.c \
305 $(SRCDIR)/json_report.c \
306 $(SRCDIR)/json_status.c \
307 $(SRCDIR)/json_tag.c \
308 $(SRCDIR)/json_timeline.c \
309 $(SRCDIR)/json_user.c \
310 $(SRCDIR)/json_wiki.c \
311 $(SRCDIR)/leaf.c \
@@ -348,10 +349,11 @@
349 $(SRCDIR)/unicode.c \
350 $(SRCDIR)/update.c \
351 $(SRCDIR)/url.c \
352 $(SRCDIR)/user.c \
353 $(SRCDIR)/utf8.c \
354 $(SRCDIR)/util.c \
355 $(SRCDIR)/verify.c \
356 $(SRCDIR)/vfile.c \
357 $(SRCDIR)/wiki.c \
358 $(SRCDIR)/wikiformat.c \
359 $(SRCDIR)/winhttp.c \
@@ -407,10 +409,11 @@
409 $(OBJDIR)/json_dir_.c \
410 $(OBJDIR)/json_finfo_.c \
411 $(OBJDIR)/json_login_.c \
412 $(OBJDIR)/json_query_.c \
413 $(OBJDIR)/json_report_.c \
414 $(OBJDIR)/json_status_.c \
415 $(OBJDIR)/json_tag_.c \
416 $(OBJDIR)/json_timeline_.c \
417 $(OBJDIR)/json_user_.c \
418 $(OBJDIR)/json_wiki_.c \
419 $(OBJDIR)/leaf_.c \
@@ -454,10 +457,11 @@
457 $(OBJDIR)/unicode_.c \
458 $(OBJDIR)/update_.c \
459 $(OBJDIR)/url_.c \
460 $(OBJDIR)/user_.c \
461 $(OBJDIR)/utf8_.c \
462 $(OBJDIR)/util_.c \
463 $(OBJDIR)/verify_.c \
464 $(OBJDIR)/vfile_.c \
465 $(OBJDIR)/wiki_.c \
466 $(OBJDIR)/wikiformat_.c \
467 $(OBJDIR)/winhttp_.c \
@@ -513,10 +517,11 @@
517 $(OBJDIR)/json_dir.o \
518 $(OBJDIR)/json_finfo.o \
519 $(OBJDIR)/json_login.o \
520 $(OBJDIR)/json_query.o \
521 $(OBJDIR)/json_report.o \
522 $(OBJDIR)/json_status.o \
523 $(OBJDIR)/json_tag.o \
524 $(OBJDIR)/json_timeline.o \
525 $(OBJDIR)/json_user.o \
526 $(OBJDIR)/json_wiki.o \
527 $(OBJDIR)/leaf.o \
@@ -560,10 +565,11 @@
565 $(OBJDIR)/unicode.o \
566 $(OBJDIR)/update.o \
567 $(OBJDIR)/url.o \
568 $(OBJDIR)/user.o \
569 $(OBJDIR)/utf8.o \
570 $(OBJDIR)/util.o \
571 $(OBJDIR)/verify.o \
572 $(OBJDIR)/vfile.o \
573 $(OBJDIR)/wiki.o \
574 $(OBJDIR)/wikiformat.o \
575 $(OBJDIR)/winhttp.o \
@@ -732,10 +738,11 @@
738 $(OBJDIR)/json_dir_.c:$(OBJDIR)/json_dir.h \
739 $(OBJDIR)/json_finfo_.c:$(OBJDIR)/json_finfo.h \
740 $(OBJDIR)/json_login_.c:$(OBJDIR)/json_login.h \
741 $(OBJDIR)/json_query_.c:$(OBJDIR)/json_query.h \
742 $(OBJDIR)/json_report_.c:$(OBJDIR)/json_report.h \
743 $(OBJDIR)/json_status_.c:$(OBJDIR)/json_status.h \
744 $(OBJDIR)/json_tag_.c:$(OBJDIR)/json_tag.h \
745 $(OBJDIR)/json_timeline_.c:$(OBJDIR)/json_timeline.h \
746 $(OBJDIR)/json_user_.c:$(OBJDIR)/json_user.h \
747 $(OBJDIR)/json_wiki_.c:$(OBJDIR)/json_wiki.h \
748 $(OBJDIR)/leaf_.c:$(OBJDIR)/leaf.h \
@@ -779,10 +786,11 @@
786 $(OBJDIR)/unicode_.c:$(OBJDIR)/unicode.h \
787 $(OBJDIR)/update_.c:$(OBJDIR)/update.h \
788 $(OBJDIR)/url_.c:$(OBJDIR)/url.h \
789 $(OBJDIR)/user_.c:$(OBJDIR)/user.h \
790 $(OBJDIR)/utf8_.c:$(OBJDIR)/utf8.h \
791 $(OBJDIR)/util_.c:$(OBJDIR)/util.h \
792 $(OBJDIR)/verify_.c:$(OBJDIR)/verify.h \
793 $(OBJDIR)/vfile_.c:$(OBJDIR)/vfile.h \
794 $(OBJDIR)/wiki_.c:$(OBJDIR)/wiki.h \
795 $(OBJDIR)/wikiformat_.c:$(OBJDIR)/wikiformat.h \
796 $(OBJDIR)/winhttp_.c:$(OBJDIR)/winhttp.h \
@@ -1180,10 +1188,18 @@
1188
1189 $(OBJDIR)/json_report.o: $(OBJDIR)/json_report_.c $(OBJDIR)/json_report.h $(SRCDIR)/config.h
1190 $(XTCC) -o $(OBJDIR)/json_report.o -c $(OBJDIR)/json_report_.c
1191
1192 $(OBJDIR)/json_report.h: $(OBJDIR)/headers
1193
1194 $(OBJDIR)/json_status_.c: $(SRCDIR)/json_status.c $(OBJDIR)/translate
1195 $(TRANSLATE) $(SRCDIR)/json_status.c >$(OBJDIR)/json_status_.c
1196
1197 $(OBJDIR)/json_status.o: $(OBJDIR)/json_status_.c $(OBJDIR)/json_status.h $(SRCDIR)/config.h
1198 $(XTCC) -o $(OBJDIR)/json_status.o -c $(OBJDIR)/json_status_.c
1199
1200 $(OBJDIR)/json_status.h: $(OBJDIR)/headers
1201
1202 $(OBJDIR)/json_tag_.c: $(SRCDIR)/json_tag.c $(OBJDIR)/translate
1203 $(TRANSLATE) $(SRCDIR)/json_tag.c >$(OBJDIR)/json_tag_.c
1204
1205 $(OBJDIR)/json_tag.o: $(OBJDIR)/json_tag_.c $(OBJDIR)/json_tag.h $(SRCDIR)/config.h
@@ -1556,10 +1572,18 @@
1572
1573 $(OBJDIR)/utf8.o: $(OBJDIR)/utf8_.c $(OBJDIR)/utf8.h $(SRCDIR)/config.h
1574 $(XTCC) -o $(OBJDIR)/utf8.o -c $(OBJDIR)/utf8_.c
1575
1576 $(OBJDIR)/utf8.h: $(OBJDIR)/headers
1577
1578 $(OBJDIR)/util_.c: $(SRCDIR)/util.c $(OBJDIR)/translate
1579 $(TRANSLATE) $(SRCDIR)/util.c >$(OBJDIR)/util_.c
1580
1581 $(OBJDIR)/util.o: $(OBJDIR)/util_.c $(OBJDIR)/util.h $(SRCDIR)/config.h
1582 $(XTCC) -o $(OBJDIR)/util.o -c $(OBJDIR)/util_.c
1583
1584 $(OBJDIR)/util.h: $(OBJDIR)/headers
1585
1586 $(OBJDIR)/verify_.c: $(SRCDIR)/verify.c $(OBJDIR)/translate
1587 $(TRANSLATE) $(SRCDIR)/verify.c >$(OBJDIR)/verify_.c
1588
1589 $(OBJDIR)/verify.o: $(OBJDIR)/verify_.c $(OBJDIR)/verify.h $(SRCDIR)/config.h
@@ -1635,11 +1659,11 @@
1659 $(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
1660
1661 $(OBJDIR)/cson_amalgamation.o: $(SRCDIR)/cson_amalgamation.c
1662 $(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.o
1663
1664 $(OBJDIR)/json.o $(OBJDIR)/json_artifact.o $(OBJDIR)/json_branch.o $(OBJDIR)/json_config.o $(OBJDIR)/json_diff.o $(OBJDIR)/json_dir.o $(OBJDIR)/jsos_finfo.o $(OBJDIR)/json_login.o $(OBJDIR)/json_query.o $(OBJDIR)/json_report.o $(OBJDIR)/json_status.o $(OBJDIR)/json_tag.o $(OBJDIR)/json_timeline.o $(OBJDIR)/json_user.o $(OBJDIR)/json_wiki.o : $(SRCDIR)/json_detail.h
1665
1666 $(OBJDIR)/shell.o: $(SRCDIR)/shell.c $(SRCDIR)/sqlite3.h
1667 $(XTCC) -Dmain=sqlite3_shell -DSQLITE_OMIT_LOAD_EXTENSION=1 -c $(SRCDIR)/shell.c -o $(OBJDIR)/shell.o
1668
1669 $(OBJDIR)/th.o: $(SRCDIR)/th.c
1670
--- win/Makefile.mingw.mistachkin
+++ win/Makefile.mingw.mistachkin
@@ -84,12 +84,12 @@
8484
#### The directories where the OpenSSL include and library files are located.
8585
# The recommended usage here is to use the Sysinternals junction tool
8686
# to create a hard link between an "openssl-1.x" sub-directory of the
8787
# Fossil source code directory and the target OpenSSL source directory.
8888
#
89
-OPENSSLINCDIR = $(SRCDIR)/../openssl-1.0.1c/include
90
-OPENSSLLIBDIR = $(SRCDIR)/../openssl-1.0.1c
89
+OPENSSLINCDIR = $(SRCDIR)/../openssl-1.0.1e/include
90
+OPENSSLLIBDIR = $(SRCDIR)/../openssl-1.0.1e
9191
9292
#### Either the directory where the Tcl library is installed or the Tcl
9393
# source code directory resides (depending on the value of the macro
9494
# FOSSIL_TCL_SOURCE). If this points to the Tcl install directory,
9595
# this directory must have "include" and "lib" sub-directories. If
@@ -301,10 +301,11 @@
301301
$(SRCDIR)/json_dir.c \
302302
$(SRCDIR)/json_finfo.c \
303303
$(SRCDIR)/json_login.c \
304304
$(SRCDIR)/json_query.c \
305305
$(SRCDIR)/json_report.c \
306
+ $(SRCDIR)/json_status.c \
306307
$(SRCDIR)/json_tag.c \
307308
$(SRCDIR)/json_timeline.c \
308309
$(SRCDIR)/json_user.c \
309310
$(SRCDIR)/json_wiki.c \
310311
$(SRCDIR)/leaf.c \
@@ -348,10 +349,11 @@
348349
$(SRCDIR)/unicode.c \
349350
$(SRCDIR)/update.c \
350351
$(SRCDIR)/url.c \
351352
$(SRCDIR)/user.c \
352353
$(SRCDIR)/utf8.c \
354
+ $(SRCDIR)/util.c \
353355
$(SRCDIR)/verify.c \
354356
$(SRCDIR)/vfile.c \
355357
$(SRCDIR)/wiki.c \
356358
$(SRCDIR)/wikiformat.c \
357359
$(SRCDIR)/winhttp.c \
@@ -407,10 +409,11 @@
407409
$(OBJDIR)/json_dir_.c \
408410
$(OBJDIR)/json_finfo_.c \
409411
$(OBJDIR)/json_login_.c \
410412
$(OBJDIR)/json_query_.c \
411413
$(OBJDIR)/json_report_.c \
414
+ $(OBJDIR)/json_status_.c \
412415
$(OBJDIR)/json_tag_.c \
413416
$(OBJDIR)/json_timeline_.c \
414417
$(OBJDIR)/json_user_.c \
415418
$(OBJDIR)/json_wiki_.c \
416419
$(OBJDIR)/leaf_.c \
@@ -454,10 +457,11 @@
454457
$(OBJDIR)/unicode_.c \
455458
$(OBJDIR)/update_.c \
456459
$(OBJDIR)/url_.c \
457460
$(OBJDIR)/user_.c \
458461
$(OBJDIR)/utf8_.c \
462
+ $(OBJDIR)/util_.c \
459463
$(OBJDIR)/verify_.c \
460464
$(OBJDIR)/vfile_.c \
461465
$(OBJDIR)/wiki_.c \
462466
$(OBJDIR)/wikiformat_.c \
463467
$(OBJDIR)/winhttp_.c \
@@ -513,10 +517,11 @@
513517
$(OBJDIR)/json_dir.o \
514518
$(OBJDIR)/json_finfo.o \
515519
$(OBJDIR)/json_login.o \
516520
$(OBJDIR)/json_query.o \
517521
$(OBJDIR)/json_report.o \
522
+ $(OBJDIR)/json_status.o \
518523
$(OBJDIR)/json_tag.o \
519524
$(OBJDIR)/json_timeline.o \
520525
$(OBJDIR)/json_user.o \
521526
$(OBJDIR)/json_wiki.o \
522527
$(OBJDIR)/leaf.o \
@@ -560,10 +565,11 @@
560565
$(OBJDIR)/unicode.o \
561566
$(OBJDIR)/update.o \
562567
$(OBJDIR)/url.o \
563568
$(OBJDIR)/user.o \
564569
$(OBJDIR)/utf8.o \
570
+ $(OBJDIR)/util.o \
565571
$(OBJDIR)/verify.o \
566572
$(OBJDIR)/vfile.o \
567573
$(OBJDIR)/wiki.o \
568574
$(OBJDIR)/wikiformat.o \
569575
$(OBJDIR)/winhttp.o \
@@ -732,10 +738,11 @@
732738
$(OBJDIR)/json_dir_.c:$(OBJDIR)/json_dir.h \
733739
$(OBJDIR)/json_finfo_.c:$(OBJDIR)/json_finfo.h \
734740
$(OBJDIR)/json_login_.c:$(OBJDIR)/json_login.h \
735741
$(OBJDIR)/json_query_.c:$(OBJDIR)/json_query.h \
736742
$(OBJDIR)/json_report_.c:$(OBJDIR)/json_report.h \
743
+ $(OBJDIR)/json_status_.c:$(OBJDIR)/json_status.h \
737744
$(OBJDIR)/json_tag_.c:$(OBJDIR)/json_tag.h \
738745
$(OBJDIR)/json_timeline_.c:$(OBJDIR)/json_timeline.h \
739746
$(OBJDIR)/json_user_.c:$(OBJDIR)/json_user.h \
740747
$(OBJDIR)/json_wiki_.c:$(OBJDIR)/json_wiki.h \
741748
$(OBJDIR)/leaf_.c:$(OBJDIR)/leaf.h \
@@ -779,10 +786,11 @@
779786
$(OBJDIR)/unicode_.c:$(OBJDIR)/unicode.h \
780787
$(OBJDIR)/update_.c:$(OBJDIR)/update.h \
781788
$(OBJDIR)/url_.c:$(OBJDIR)/url.h \
782789
$(OBJDIR)/user_.c:$(OBJDIR)/user.h \
783790
$(OBJDIR)/utf8_.c:$(OBJDIR)/utf8.h \
791
+ $(OBJDIR)/util_.c:$(OBJDIR)/util.h \
784792
$(OBJDIR)/verify_.c:$(OBJDIR)/verify.h \
785793
$(OBJDIR)/vfile_.c:$(OBJDIR)/vfile.h \
786794
$(OBJDIR)/wiki_.c:$(OBJDIR)/wiki.h \
787795
$(OBJDIR)/wikiformat_.c:$(OBJDIR)/wikiformat.h \
788796
$(OBJDIR)/winhttp_.c:$(OBJDIR)/winhttp.h \
@@ -1180,10 +1188,18 @@
11801188
11811189
$(OBJDIR)/json_report.o: $(OBJDIR)/json_report_.c $(OBJDIR)/json_report.h $(SRCDIR)/config.h
11821190
$(XTCC) -o $(OBJDIR)/json_report.o -c $(OBJDIR)/json_report_.c
11831191
11841192
$(OBJDIR)/json_report.h: $(OBJDIR)/headers
1193
+
1194
+$(OBJDIR)/json_status_.c: $(SRCDIR)/json_status.c $(OBJDIR)/translate
1195
+ $(TRANSLATE) $(SRCDIR)/json_status.c >$(OBJDIR)/json_status_.c
1196
+
1197
+$(OBJDIR)/json_status.o: $(OBJDIR)/json_status_.c $(OBJDIR)/json_status.h $(SRCDIR)/config.h
1198
+ $(XTCC) -o $(OBJDIR)/json_status.o -c $(OBJDIR)/json_status_.c
1199
+
1200
+$(OBJDIR)/json_status.h: $(OBJDIR)/headers
11851201
11861202
$(OBJDIR)/json_tag_.c: $(SRCDIR)/json_tag.c $(OBJDIR)/translate
11871203
$(TRANSLATE) $(SRCDIR)/json_tag.c >$(OBJDIR)/json_tag_.c
11881204
11891205
$(OBJDIR)/json_tag.o: $(OBJDIR)/json_tag_.c $(OBJDIR)/json_tag.h $(SRCDIR)/config.h
@@ -1556,10 +1572,18 @@
15561572
15571573
$(OBJDIR)/utf8.o: $(OBJDIR)/utf8_.c $(OBJDIR)/utf8.h $(SRCDIR)/config.h
15581574
$(XTCC) -o $(OBJDIR)/utf8.o -c $(OBJDIR)/utf8_.c
15591575
15601576
$(OBJDIR)/utf8.h: $(OBJDIR)/headers
1577
+
1578
+$(OBJDIR)/util_.c: $(SRCDIR)/util.c $(OBJDIR)/translate
1579
+ $(TRANSLATE) $(SRCDIR)/util.c >$(OBJDIR)/util_.c
1580
+
1581
+$(OBJDIR)/util.o: $(OBJDIR)/util_.c $(OBJDIR)/util.h $(SRCDIR)/config.h
1582
+ $(XTCC) -o $(OBJDIR)/util.o -c $(OBJDIR)/util_.c
1583
+
1584
+$(OBJDIR)/util.h: $(OBJDIR)/headers
15611585
15621586
$(OBJDIR)/verify_.c: $(SRCDIR)/verify.c $(OBJDIR)/translate
15631587
$(TRANSLATE) $(SRCDIR)/verify.c >$(OBJDIR)/verify_.c
15641588
15651589
$(OBJDIR)/verify.o: $(OBJDIR)/verify_.c $(OBJDIR)/verify.h $(SRCDIR)/config.h
@@ -1635,11 +1659,11 @@
16351659
$(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
16361660
16371661
$(OBJDIR)/cson_amalgamation.o: $(SRCDIR)/cson_amalgamation.c
16381662
$(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.o
16391663
1640
-$(OBJDIR)/json.o $(OBJDIR)/json_artifact.o $(OBJDIR)/json_branch.o $(OBJDIR)/json_config.o $(OBJDIR)/json_diff.o $(OBJDIR)/json_dir.o $(OBJDIR)/jsos_finfo.o $(OBJDIR)/json_login.o $(OBJDIR)/json_query.o $(OBJDIR)/json_report.o $(OBJDIR)/json_tag.o $(OBJDIR)/json_timeline.o $(OBJDIR)/json_user.o $(OBJDIR)/json_wiki.o : $(SRCDIR)/json_detail.h
1664
+$(OBJDIR)/json.o $(OBJDIR)/json_artifact.o $(OBJDIR)/json_branch.o $(OBJDIR)/json_config.o $(OBJDIR)/json_diff.o $(OBJDIR)/json_dir.o $(OBJDIR)/jsos_finfo.o $(OBJDIR)/json_login.o $(OBJDIR)/json_query.o $(OBJDIR)/json_report.o $(OBJDIR)/json_status.o $(OBJDIR)/json_tag.o $(OBJDIR)/json_timeline.o $(OBJDIR)/json_user.o $(OBJDIR)/json_wiki.o : $(SRCDIR)/json_detail.h
16411665
16421666
$(OBJDIR)/shell.o: $(SRCDIR)/shell.c $(SRCDIR)/sqlite3.h
16431667
$(XTCC) -Dmain=sqlite3_shell -DSQLITE_OMIT_LOAD_EXTENSION=1 -c $(SRCDIR)/shell.c -o $(OBJDIR)/shell.o
16441668
16451669
$(OBJDIR)/th.o: $(SRCDIR)/th.c
16461670
--- win/Makefile.mingw.mistachkin
+++ win/Makefile.mingw.mistachkin
@@ -84,12 +84,12 @@
84 #### The directories where the OpenSSL include and library files are located.
85 # The recommended usage here is to use the Sysinternals junction tool
86 # to create a hard link between an "openssl-1.x" sub-directory of the
87 # Fossil source code directory and the target OpenSSL source directory.
88 #
89 OPENSSLINCDIR = $(SRCDIR)/../openssl-1.0.1c/include
90 OPENSSLLIBDIR = $(SRCDIR)/../openssl-1.0.1c
91
92 #### Either the directory where the Tcl library is installed or the Tcl
93 # source code directory resides (depending on the value of the macro
94 # FOSSIL_TCL_SOURCE). If this points to the Tcl install directory,
95 # this directory must have "include" and "lib" sub-directories. If
@@ -301,10 +301,11 @@
301 $(SRCDIR)/json_dir.c \
302 $(SRCDIR)/json_finfo.c \
303 $(SRCDIR)/json_login.c \
304 $(SRCDIR)/json_query.c \
305 $(SRCDIR)/json_report.c \
 
306 $(SRCDIR)/json_tag.c \
307 $(SRCDIR)/json_timeline.c \
308 $(SRCDIR)/json_user.c \
309 $(SRCDIR)/json_wiki.c \
310 $(SRCDIR)/leaf.c \
@@ -348,10 +349,11 @@
348 $(SRCDIR)/unicode.c \
349 $(SRCDIR)/update.c \
350 $(SRCDIR)/url.c \
351 $(SRCDIR)/user.c \
352 $(SRCDIR)/utf8.c \
 
353 $(SRCDIR)/verify.c \
354 $(SRCDIR)/vfile.c \
355 $(SRCDIR)/wiki.c \
356 $(SRCDIR)/wikiformat.c \
357 $(SRCDIR)/winhttp.c \
@@ -407,10 +409,11 @@
407 $(OBJDIR)/json_dir_.c \
408 $(OBJDIR)/json_finfo_.c \
409 $(OBJDIR)/json_login_.c \
410 $(OBJDIR)/json_query_.c \
411 $(OBJDIR)/json_report_.c \
 
412 $(OBJDIR)/json_tag_.c \
413 $(OBJDIR)/json_timeline_.c \
414 $(OBJDIR)/json_user_.c \
415 $(OBJDIR)/json_wiki_.c \
416 $(OBJDIR)/leaf_.c \
@@ -454,10 +457,11 @@
454 $(OBJDIR)/unicode_.c \
455 $(OBJDIR)/update_.c \
456 $(OBJDIR)/url_.c \
457 $(OBJDIR)/user_.c \
458 $(OBJDIR)/utf8_.c \
 
459 $(OBJDIR)/verify_.c \
460 $(OBJDIR)/vfile_.c \
461 $(OBJDIR)/wiki_.c \
462 $(OBJDIR)/wikiformat_.c \
463 $(OBJDIR)/winhttp_.c \
@@ -513,10 +517,11 @@
513 $(OBJDIR)/json_dir.o \
514 $(OBJDIR)/json_finfo.o \
515 $(OBJDIR)/json_login.o \
516 $(OBJDIR)/json_query.o \
517 $(OBJDIR)/json_report.o \
 
518 $(OBJDIR)/json_tag.o \
519 $(OBJDIR)/json_timeline.o \
520 $(OBJDIR)/json_user.o \
521 $(OBJDIR)/json_wiki.o \
522 $(OBJDIR)/leaf.o \
@@ -560,10 +565,11 @@
560 $(OBJDIR)/unicode.o \
561 $(OBJDIR)/update.o \
562 $(OBJDIR)/url.o \
563 $(OBJDIR)/user.o \
564 $(OBJDIR)/utf8.o \
 
565 $(OBJDIR)/verify.o \
566 $(OBJDIR)/vfile.o \
567 $(OBJDIR)/wiki.o \
568 $(OBJDIR)/wikiformat.o \
569 $(OBJDIR)/winhttp.o \
@@ -732,10 +738,11 @@
732 $(OBJDIR)/json_dir_.c:$(OBJDIR)/json_dir.h \
733 $(OBJDIR)/json_finfo_.c:$(OBJDIR)/json_finfo.h \
734 $(OBJDIR)/json_login_.c:$(OBJDIR)/json_login.h \
735 $(OBJDIR)/json_query_.c:$(OBJDIR)/json_query.h \
736 $(OBJDIR)/json_report_.c:$(OBJDIR)/json_report.h \
 
737 $(OBJDIR)/json_tag_.c:$(OBJDIR)/json_tag.h \
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 \
@@ -779,10 +786,11 @@
779 $(OBJDIR)/unicode_.c:$(OBJDIR)/unicode.h \
780 $(OBJDIR)/update_.c:$(OBJDIR)/update.h \
781 $(OBJDIR)/url_.c:$(OBJDIR)/url.h \
782 $(OBJDIR)/user_.c:$(OBJDIR)/user.h \
783 $(OBJDIR)/utf8_.c:$(OBJDIR)/utf8.h \
 
784 $(OBJDIR)/verify_.c:$(OBJDIR)/verify.h \
785 $(OBJDIR)/vfile_.c:$(OBJDIR)/vfile.h \
786 $(OBJDIR)/wiki_.c:$(OBJDIR)/wiki.h \
787 $(OBJDIR)/wikiformat_.c:$(OBJDIR)/wikiformat.h \
788 $(OBJDIR)/winhttp_.c:$(OBJDIR)/winhttp.h \
@@ -1180,10 +1188,18 @@
1180
1181 $(OBJDIR)/json_report.o: $(OBJDIR)/json_report_.c $(OBJDIR)/json_report.h $(SRCDIR)/config.h
1182 $(XTCC) -o $(OBJDIR)/json_report.o -c $(OBJDIR)/json_report_.c
1183
1184 $(OBJDIR)/json_report.h: $(OBJDIR)/headers
 
 
 
 
 
 
 
 
1185
1186 $(OBJDIR)/json_tag_.c: $(SRCDIR)/json_tag.c $(OBJDIR)/translate
1187 $(TRANSLATE) $(SRCDIR)/json_tag.c >$(OBJDIR)/json_tag_.c
1188
1189 $(OBJDIR)/json_tag.o: $(OBJDIR)/json_tag_.c $(OBJDIR)/json_tag.h $(SRCDIR)/config.h
@@ -1556,10 +1572,18 @@
1556
1557 $(OBJDIR)/utf8.o: $(OBJDIR)/utf8_.c $(OBJDIR)/utf8.h $(SRCDIR)/config.h
1558 $(XTCC) -o $(OBJDIR)/utf8.o -c $(OBJDIR)/utf8_.c
1559
1560 $(OBJDIR)/utf8.h: $(OBJDIR)/headers
 
 
 
 
 
 
 
 
1561
1562 $(OBJDIR)/verify_.c: $(SRCDIR)/verify.c $(OBJDIR)/translate
1563 $(TRANSLATE) $(SRCDIR)/verify.c >$(OBJDIR)/verify_.c
1564
1565 $(OBJDIR)/verify.o: $(OBJDIR)/verify_.c $(OBJDIR)/verify.h $(SRCDIR)/config.h
@@ -1635,11 +1659,11 @@
1635 $(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
1636
1637 $(OBJDIR)/cson_amalgamation.o: $(SRCDIR)/cson_amalgamation.c
1638 $(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.o
1639
1640 $(OBJDIR)/json.o $(OBJDIR)/json_artifact.o $(OBJDIR)/json_branch.o $(OBJDIR)/json_config.o $(OBJDIR)/json_diff.o $(OBJDIR)/json_dir.o $(OBJDIR)/jsos_finfo.o $(OBJDIR)/json_login.o $(OBJDIR)/json_query.o $(OBJDIR)/json_report.o $(OBJDIR)/json_tag.o $(OBJDIR)/json_timeline.o $(OBJDIR)/json_user.o $(OBJDIR)/json_wiki.o : $(SRCDIR)/json_detail.h
1641
1642 $(OBJDIR)/shell.o: $(SRCDIR)/shell.c $(SRCDIR)/sqlite3.h
1643 $(XTCC) -Dmain=sqlite3_shell -DSQLITE_OMIT_LOAD_EXTENSION=1 -c $(SRCDIR)/shell.c -o $(OBJDIR)/shell.o
1644
1645 $(OBJDIR)/th.o: $(SRCDIR)/th.c
1646
--- win/Makefile.mingw.mistachkin
+++ win/Makefile.mingw.mistachkin
@@ -84,12 +84,12 @@
84 #### The directories where the OpenSSL include and library files are located.
85 # The recommended usage here is to use the Sysinternals junction tool
86 # to create a hard link between an "openssl-1.x" sub-directory of the
87 # Fossil source code directory and the target OpenSSL source directory.
88 #
89 OPENSSLINCDIR = $(SRCDIR)/../openssl-1.0.1e/include
90 OPENSSLLIBDIR = $(SRCDIR)/../openssl-1.0.1e
91
92 #### Either the directory where the Tcl library is installed or the Tcl
93 # source code directory resides (depending on the value of the macro
94 # FOSSIL_TCL_SOURCE). If this points to the Tcl install directory,
95 # this directory must have "include" and "lib" sub-directories. If
@@ -301,10 +301,11 @@
301 $(SRCDIR)/json_dir.c \
302 $(SRCDIR)/json_finfo.c \
303 $(SRCDIR)/json_login.c \
304 $(SRCDIR)/json_query.c \
305 $(SRCDIR)/json_report.c \
306 $(SRCDIR)/json_status.c \
307 $(SRCDIR)/json_tag.c \
308 $(SRCDIR)/json_timeline.c \
309 $(SRCDIR)/json_user.c \
310 $(SRCDIR)/json_wiki.c \
311 $(SRCDIR)/leaf.c \
@@ -348,10 +349,11 @@
349 $(SRCDIR)/unicode.c \
350 $(SRCDIR)/update.c \
351 $(SRCDIR)/url.c \
352 $(SRCDIR)/user.c \
353 $(SRCDIR)/utf8.c \
354 $(SRCDIR)/util.c \
355 $(SRCDIR)/verify.c \
356 $(SRCDIR)/vfile.c \
357 $(SRCDIR)/wiki.c \
358 $(SRCDIR)/wikiformat.c \
359 $(SRCDIR)/winhttp.c \
@@ -407,10 +409,11 @@
409 $(OBJDIR)/json_dir_.c \
410 $(OBJDIR)/json_finfo_.c \
411 $(OBJDIR)/json_login_.c \
412 $(OBJDIR)/json_query_.c \
413 $(OBJDIR)/json_report_.c \
414 $(OBJDIR)/json_status_.c \
415 $(OBJDIR)/json_tag_.c \
416 $(OBJDIR)/json_timeline_.c \
417 $(OBJDIR)/json_user_.c \
418 $(OBJDIR)/json_wiki_.c \
419 $(OBJDIR)/leaf_.c \
@@ -454,10 +457,11 @@
457 $(OBJDIR)/unicode_.c \
458 $(OBJDIR)/update_.c \
459 $(OBJDIR)/url_.c \
460 $(OBJDIR)/user_.c \
461 $(OBJDIR)/utf8_.c \
462 $(OBJDIR)/util_.c \
463 $(OBJDIR)/verify_.c \
464 $(OBJDIR)/vfile_.c \
465 $(OBJDIR)/wiki_.c \
466 $(OBJDIR)/wikiformat_.c \
467 $(OBJDIR)/winhttp_.c \
@@ -513,10 +517,11 @@
517 $(OBJDIR)/json_dir.o \
518 $(OBJDIR)/json_finfo.o \
519 $(OBJDIR)/json_login.o \
520 $(OBJDIR)/json_query.o \
521 $(OBJDIR)/json_report.o \
522 $(OBJDIR)/json_status.o \
523 $(OBJDIR)/json_tag.o \
524 $(OBJDIR)/json_timeline.o \
525 $(OBJDIR)/json_user.o \
526 $(OBJDIR)/json_wiki.o \
527 $(OBJDIR)/leaf.o \
@@ -560,10 +565,11 @@
565 $(OBJDIR)/unicode.o \
566 $(OBJDIR)/update.o \
567 $(OBJDIR)/url.o \
568 $(OBJDIR)/user.o \
569 $(OBJDIR)/utf8.o \
570 $(OBJDIR)/util.o \
571 $(OBJDIR)/verify.o \
572 $(OBJDIR)/vfile.o \
573 $(OBJDIR)/wiki.o \
574 $(OBJDIR)/wikiformat.o \
575 $(OBJDIR)/winhttp.o \
@@ -732,10 +738,11 @@
738 $(OBJDIR)/json_dir_.c:$(OBJDIR)/json_dir.h \
739 $(OBJDIR)/json_finfo_.c:$(OBJDIR)/json_finfo.h \
740 $(OBJDIR)/json_login_.c:$(OBJDIR)/json_login.h \
741 $(OBJDIR)/json_query_.c:$(OBJDIR)/json_query.h \
742 $(OBJDIR)/json_report_.c:$(OBJDIR)/json_report.h \
743 $(OBJDIR)/json_status_.c:$(OBJDIR)/json_status.h \
744 $(OBJDIR)/json_tag_.c:$(OBJDIR)/json_tag.h \
745 $(OBJDIR)/json_timeline_.c:$(OBJDIR)/json_timeline.h \
746 $(OBJDIR)/json_user_.c:$(OBJDIR)/json_user.h \
747 $(OBJDIR)/json_wiki_.c:$(OBJDIR)/json_wiki.h \
748 $(OBJDIR)/leaf_.c:$(OBJDIR)/leaf.h \
@@ -779,10 +786,11 @@
786 $(OBJDIR)/unicode_.c:$(OBJDIR)/unicode.h \
787 $(OBJDIR)/update_.c:$(OBJDIR)/update.h \
788 $(OBJDIR)/url_.c:$(OBJDIR)/url.h \
789 $(OBJDIR)/user_.c:$(OBJDIR)/user.h \
790 $(OBJDIR)/utf8_.c:$(OBJDIR)/utf8.h \
791 $(OBJDIR)/util_.c:$(OBJDIR)/util.h \
792 $(OBJDIR)/verify_.c:$(OBJDIR)/verify.h \
793 $(OBJDIR)/vfile_.c:$(OBJDIR)/vfile.h \
794 $(OBJDIR)/wiki_.c:$(OBJDIR)/wiki.h \
795 $(OBJDIR)/wikiformat_.c:$(OBJDIR)/wikiformat.h \
796 $(OBJDIR)/winhttp_.c:$(OBJDIR)/winhttp.h \
@@ -1180,10 +1188,18 @@
1188
1189 $(OBJDIR)/json_report.o: $(OBJDIR)/json_report_.c $(OBJDIR)/json_report.h $(SRCDIR)/config.h
1190 $(XTCC) -o $(OBJDIR)/json_report.o -c $(OBJDIR)/json_report_.c
1191
1192 $(OBJDIR)/json_report.h: $(OBJDIR)/headers
1193
1194 $(OBJDIR)/json_status_.c: $(SRCDIR)/json_status.c $(OBJDIR)/translate
1195 $(TRANSLATE) $(SRCDIR)/json_status.c >$(OBJDIR)/json_status_.c
1196
1197 $(OBJDIR)/json_status.o: $(OBJDIR)/json_status_.c $(OBJDIR)/json_status.h $(SRCDIR)/config.h
1198 $(XTCC) -o $(OBJDIR)/json_status.o -c $(OBJDIR)/json_status_.c
1199
1200 $(OBJDIR)/json_status.h: $(OBJDIR)/headers
1201
1202 $(OBJDIR)/json_tag_.c: $(SRCDIR)/json_tag.c $(OBJDIR)/translate
1203 $(TRANSLATE) $(SRCDIR)/json_tag.c >$(OBJDIR)/json_tag_.c
1204
1205 $(OBJDIR)/json_tag.o: $(OBJDIR)/json_tag_.c $(OBJDIR)/json_tag.h $(SRCDIR)/config.h
@@ -1556,10 +1572,18 @@
1572
1573 $(OBJDIR)/utf8.o: $(OBJDIR)/utf8_.c $(OBJDIR)/utf8.h $(SRCDIR)/config.h
1574 $(XTCC) -o $(OBJDIR)/utf8.o -c $(OBJDIR)/utf8_.c
1575
1576 $(OBJDIR)/utf8.h: $(OBJDIR)/headers
1577
1578 $(OBJDIR)/util_.c: $(SRCDIR)/util.c $(OBJDIR)/translate
1579 $(TRANSLATE) $(SRCDIR)/util.c >$(OBJDIR)/util_.c
1580
1581 $(OBJDIR)/util.o: $(OBJDIR)/util_.c $(OBJDIR)/util.h $(SRCDIR)/config.h
1582 $(XTCC) -o $(OBJDIR)/util.o -c $(OBJDIR)/util_.c
1583
1584 $(OBJDIR)/util.h: $(OBJDIR)/headers
1585
1586 $(OBJDIR)/verify_.c: $(SRCDIR)/verify.c $(OBJDIR)/translate
1587 $(TRANSLATE) $(SRCDIR)/verify.c >$(OBJDIR)/verify_.c
1588
1589 $(OBJDIR)/verify.o: $(OBJDIR)/verify_.c $(OBJDIR)/verify.h $(SRCDIR)/config.h
@@ -1635,11 +1659,11 @@
1659 $(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
1660
1661 $(OBJDIR)/cson_amalgamation.o: $(SRCDIR)/cson_amalgamation.c
1662 $(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.o
1663
1664 $(OBJDIR)/json.o $(OBJDIR)/json_artifact.o $(OBJDIR)/json_branch.o $(OBJDIR)/json_config.o $(OBJDIR)/json_diff.o $(OBJDIR)/json_dir.o $(OBJDIR)/jsos_finfo.o $(OBJDIR)/json_login.o $(OBJDIR)/json_query.o $(OBJDIR)/json_report.o $(OBJDIR)/json_status.o $(OBJDIR)/json_tag.o $(OBJDIR)/json_timeline.o $(OBJDIR)/json_user.o $(OBJDIR)/json_wiki.o : $(SRCDIR)/json_detail.h
1665
1666 $(OBJDIR)/shell.o: $(SRCDIR)/shell.c $(SRCDIR)/sqlite3.h
1667 $(XTCC) -Dmain=sqlite3_shell -DSQLITE_OMIT_LOAD_EXTENSION=1 -c $(SRCDIR)/shell.c -o $(OBJDIR)/shell.o
1668
1669 $(OBJDIR)/th.o: $(SRCDIR)/th.c
1670
--- win/Makefile.msc
+++ win/Makefile.msc
@@ -103,10 +103,11 @@
103103
json_dir_.c \
104104
json_finfo_.c \
105105
json_login_.c \
106106
json_query_.c \
107107
json_report_.c \
108
+ json_status_.c \
108109
json_tag_.c \
109110
json_timeline_.c \
110111
json_user_.c \
111112
json_wiki_.c \
112113
leaf_.c \
@@ -150,10 +151,11 @@
150151
unicode_.c \
151152
update_.c \
152153
url_.c \
153154
user_.c \
154155
utf8_.c \
156
+ util_.c \
155157
verify_.c \
156158
vfile_.c \
157159
wiki_.c \
158160
wikiformat_.c \
159161
winhttp_.c \
@@ -209,10 +211,11 @@
209211
$(OX)\json_dir$O \
210212
$(OX)\json_finfo$O \
211213
$(OX)\json_login$O \
212214
$(OX)\json_query$O \
213215
$(OX)\json_report$O \
216
+ $(OX)\json_status$O \
214217
$(OX)\json_tag$O \
215218
$(OX)\json_timeline$O \
216219
$(OX)\json_user$O \
217220
$(OX)\json_wiki$O \
218221
$(OX)\leaf$O \
@@ -260,10 +263,11 @@
260263
$(OX)\unicode$O \
261264
$(OX)\update$O \
262265
$(OX)\url$O \
263266
$(OX)\user$O \
264267
$(OX)\utf8$O \
268
+ $(OX)\util$O \
265269
$(OX)\verify$O \
266270
$(OX)\vfile$O \
267271
$(OX)\wiki$O \
268272
$(OX)\wikiformat$O \
269273
$(OX)\winhttp$O \
@@ -333,10 +337,11 @@
333337
echo $(OX)\json_dir.obj >> $@
334338
echo $(OX)\json_finfo.obj >> $@
335339
echo $(OX)\json_login.obj >> $@
336340
echo $(OX)\json_query.obj >> $@
337341
echo $(OX)\json_report.obj >> $@
342
+ echo $(OX)\json_status.obj >> $@
338343
echo $(OX)\json_tag.obj >> $@
339344
echo $(OX)\json_timeline.obj >> $@
340345
echo $(OX)\json_user.obj >> $@
341346
echo $(OX)\json_wiki.obj >> $@
342347
echo $(OX)\leaf.obj >> $@
@@ -384,10 +389,11 @@
384389
echo $(OX)\unicode.obj >> $@
385390
echo $(OX)\update.obj >> $@
386391
echo $(OX)\url.obj >> $@
387392
echo $(OX)\user.obj >> $@
388393
echo $(OX)\utf8.obj >> $@
394
+ echo $(OX)\util.obj >> $@
389395
echo $(OX)\verify.obj >> $@
390396
echo $(OX)\vfile.obj >> $@
391397
echo $(OX)\wiki.obj >> $@
392398
echo $(OX)\wikiformat.obj >> $@
393399
echo $(OX)\winhttp.obj >> $@
@@ -461,10 +467,11 @@
461467
$(OBJDIR)\json_dir$O : $(SRCDIR)\json_detail.h
462468
$(OBJDIR)\json_finfo$O : $(SRCDIR)\json_detail.h
463469
$(OBJDIR)\json_login$O : $(SRCDIR)\json_detail.h
464470
$(OBJDIR)\json_query$O : $(SRCDIR)\json_detail.h
465471
$(OBJDIR)\json_report$O : $(SRCDIR)\json_detail.h
472
+$(OBJDIR)\json_status$O : $(SRCDIR)\json_detail.h
466473
$(OBJDIR)\json_tag$O : $(SRCDIR)\json_detail.h
467474
$(OBJDIR)\json_timeline$O : $(SRCDIR)\json_detail.h
468475
$(OBJDIR)\json_user$O : $(SRCDIR)\json_detail.h
469476
$(OBJDIR)\json_wiki$O : $(SRCDIR)\json_detail.h
470477
@@ -754,10 +761,16 @@
754761
$(OX)\json_report$O : json_report_.c json_report.h
755762
$(TCC) /Fo$@ -c json_report_.c
756763
757764
json_report_.c : $(SRCDIR)\json_report.c
758765
translate$E $** > $@
766
+
767
+$(OX)\json_status$O : json_status_.c json_status.h
768
+ $(TCC) /Fo$@ -c json_status_.c
769
+
770
+json_status_.c : $(SRCDIR)\json_status.c
771
+ translate$E $** > $@
759772
760773
$(OX)\json_tag$O : json_tag_.c json_tag.h
761774
$(TCC) /Fo$@ -c json_tag_.c
762775
763776
json_tag_.c : $(SRCDIR)\json_tag.c
@@ -1036,10 +1049,16 @@
10361049
$(OX)\utf8$O : utf8_.c utf8.h
10371050
$(TCC) /Fo$@ -c utf8_.c
10381051
10391052
utf8_.c : $(SRCDIR)\utf8.c
10401053
translate$E $** > $@
1054
+
1055
+$(OX)\util$O : util_.c util.h
1056
+ $(TCC) /Fo$@ -c util_.c
1057
+
1058
+util_.c : $(SRCDIR)\util.c
1059
+ translate$E $** > $@
10411060
10421061
$(OX)\verify$O : verify_.c verify.h
10431062
$(TCC) /Fo$@ -c verify_.c
10441063
10451064
verify_.c : $(SRCDIR)\verify.c
@@ -1142,10 +1161,11 @@
11421161
json_dir_.c:json_dir.h \
11431162
json_finfo_.c:json_finfo.h \
11441163
json_login_.c:json_login.h \
11451164
json_query_.c:json_query.h \
11461165
json_report_.c:json_report.h \
1166
+ json_status_.c:json_status.h \
11471167
json_tag_.c:json_tag.h \
11481168
json_timeline_.c:json_timeline.h \
11491169
json_user_.c:json_user.h \
11501170
json_wiki_.c:json_wiki.h \
11511171
leaf_.c:leaf.h \
@@ -1189,10 +1209,11 @@
11891209
unicode_.c:unicode.h \
11901210
update_.c:update.h \
11911211
url_.c:url.h \
11921212
user_.c:user.h \
11931213
utf8_.c:utf8.h \
1214
+ util_.c:util.h \
11941215
verify_.c:verify.h \
11951216
vfile_.c:vfile.h \
11961217
wiki_.c:wiki.h \
11971218
wikiformat_.c:wikiformat.h \
11981219
winhttp_.c:winhttp.h \
11991220
--- win/Makefile.msc
+++ win/Makefile.msc
@@ -103,10 +103,11 @@
103 json_dir_.c \
104 json_finfo_.c \
105 json_login_.c \
106 json_query_.c \
107 json_report_.c \
 
108 json_tag_.c \
109 json_timeline_.c \
110 json_user_.c \
111 json_wiki_.c \
112 leaf_.c \
@@ -150,10 +151,11 @@
150 unicode_.c \
151 update_.c \
152 url_.c \
153 user_.c \
154 utf8_.c \
 
155 verify_.c \
156 vfile_.c \
157 wiki_.c \
158 wikiformat_.c \
159 winhttp_.c \
@@ -209,10 +211,11 @@
209 $(OX)\json_dir$O \
210 $(OX)\json_finfo$O \
211 $(OX)\json_login$O \
212 $(OX)\json_query$O \
213 $(OX)\json_report$O \
 
214 $(OX)\json_tag$O \
215 $(OX)\json_timeline$O \
216 $(OX)\json_user$O \
217 $(OX)\json_wiki$O \
218 $(OX)\leaf$O \
@@ -260,10 +263,11 @@
260 $(OX)\unicode$O \
261 $(OX)\update$O \
262 $(OX)\url$O \
263 $(OX)\user$O \
264 $(OX)\utf8$O \
 
265 $(OX)\verify$O \
266 $(OX)\vfile$O \
267 $(OX)\wiki$O \
268 $(OX)\wikiformat$O \
269 $(OX)\winhttp$O \
@@ -333,10 +337,11 @@
333 echo $(OX)\json_dir.obj >> $@
334 echo $(OX)\json_finfo.obj >> $@
335 echo $(OX)\json_login.obj >> $@
336 echo $(OX)\json_query.obj >> $@
337 echo $(OX)\json_report.obj >> $@
 
338 echo $(OX)\json_tag.obj >> $@
339 echo $(OX)\json_timeline.obj >> $@
340 echo $(OX)\json_user.obj >> $@
341 echo $(OX)\json_wiki.obj >> $@
342 echo $(OX)\leaf.obj >> $@
@@ -384,10 +389,11 @@
384 echo $(OX)\unicode.obj >> $@
385 echo $(OX)\update.obj >> $@
386 echo $(OX)\url.obj >> $@
387 echo $(OX)\user.obj >> $@
388 echo $(OX)\utf8.obj >> $@
 
389 echo $(OX)\verify.obj >> $@
390 echo $(OX)\vfile.obj >> $@
391 echo $(OX)\wiki.obj >> $@
392 echo $(OX)\wikiformat.obj >> $@
393 echo $(OX)\winhttp.obj >> $@
@@ -461,10 +467,11 @@
461 $(OBJDIR)\json_dir$O : $(SRCDIR)\json_detail.h
462 $(OBJDIR)\json_finfo$O : $(SRCDIR)\json_detail.h
463 $(OBJDIR)\json_login$O : $(SRCDIR)\json_detail.h
464 $(OBJDIR)\json_query$O : $(SRCDIR)\json_detail.h
465 $(OBJDIR)\json_report$O : $(SRCDIR)\json_detail.h
 
466 $(OBJDIR)\json_tag$O : $(SRCDIR)\json_detail.h
467 $(OBJDIR)\json_timeline$O : $(SRCDIR)\json_detail.h
468 $(OBJDIR)\json_user$O : $(SRCDIR)\json_detail.h
469 $(OBJDIR)\json_wiki$O : $(SRCDIR)\json_detail.h
470
@@ -754,10 +761,16 @@
754 $(OX)\json_report$O : json_report_.c json_report.h
755 $(TCC) /Fo$@ -c json_report_.c
756
757 json_report_.c : $(SRCDIR)\json_report.c
758 translate$E $** > $@
 
 
 
 
 
 
759
760 $(OX)\json_tag$O : json_tag_.c json_tag.h
761 $(TCC) /Fo$@ -c json_tag_.c
762
763 json_tag_.c : $(SRCDIR)\json_tag.c
@@ -1036,10 +1049,16 @@
1036 $(OX)\utf8$O : utf8_.c utf8.h
1037 $(TCC) /Fo$@ -c utf8_.c
1038
1039 utf8_.c : $(SRCDIR)\utf8.c
1040 translate$E $** > $@
 
 
 
 
 
 
1041
1042 $(OX)\verify$O : verify_.c verify.h
1043 $(TCC) /Fo$@ -c verify_.c
1044
1045 verify_.c : $(SRCDIR)\verify.c
@@ -1142,10 +1161,11 @@
1142 json_dir_.c:json_dir.h \
1143 json_finfo_.c:json_finfo.h \
1144 json_login_.c:json_login.h \
1145 json_query_.c:json_query.h \
1146 json_report_.c:json_report.h \
 
1147 json_tag_.c:json_tag.h \
1148 json_timeline_.c:json_timeline.h \
1149 json_user_.c:json_user.h \
1150 json_wiki_.c:json_wiki.h \
1151 leaf_.c:leaf.h \
@@ -1189,10 +1209,11 @@
1189 unicode_.c:unicode.h \
1190 update_.c:update.h \
1191 url_.c:url.h \
1192 user_.c:user.h \
1193 utf8_.c:utf8.h \
 
1194 verify_.c:verify.h \
1195 vfile_.c:vfile.h \
1196 wiki_.c:wiki.h \
1197 wikiformat_.c:wikiformat.h \
1198 winhttp_.c:winhttp.h \
1199
--- win/Makefile.msc
+++ win/Makefile.msc
@@ -103,10 +103,11 @@
103 json_dir_.c \
104 json_finfo_.c \
105 json_login_.c \
106 json_query_.c \
107 json_report_.c \
108 json_status_.c \
109 json_tag_.c \
110 json_timeline_.c \
111 json_user_.c \
112 json_wiki_.c \
113 leaf_.c \
@@ -150,10 +151,11 @@
151 unicode_.c \
152 update_.c \
153 url_.c \
154 user_.c \
155 utf8_.c \
156 util_.c \
157 verify_.c \
158 vfile_.c \
159 wiki_.c \
160 wikiformat_.c \
161 winhttp_.c \
@@ -209,10 +211,11 @@
211 $(OX)\json_dir$O \
212 $(OX)\json_finfo$O \
213 $(OX)\json_login$O \
214 $(OX)\json_query$O \
215 $(OX)\json_report$O \
216 $(OX)\json_status$O \
217 $(OX)\json_tag$O \
218 $(OX)\json_timeline$O \
219 $(OX)\json_user$O \
220 $(OX)\json_wiki$O \
221 $(OX)\leaf$O \
@@ -260,10 +263,11 @@
263 $(OX)\unicode$O \
264 $(OX)\update$O \
265 $(OX)\url$O \
266 $(OX)\user$O \
267 $(OX)\utf8$O \
268 $(OX)\util$O \
269 $(OX)\verify$O \
270 $(OX)\vfile$O \
271 $(OX)\wiki$O \
272 $(OX)\wikiformat$O \
273 $(OX)\winhttp$O \
@@ -333,10 +337,11 @@
337 echo $(OX)\json_dir.obj >> $@
338 echo $(OX)\json_finfo.obj >> $@
339 echo $(OX)\json_login.obj >> $@
340 echo $(OX)\json_query.obj >> $@
341 echo $(OX)\json_report.obj >> $@
342 echo $(OX)\json_status.obj >> $@
343 echo $(OX)\json_tag.obj >> $@
344 echo $(OX)\json_timeline.obj >> $@
345 echo $(OX)\json_user.obj >> $@
346 echo $(OX)\json_wiki.obj >> $@
347 echo $(OX)\leaf.obj >> $@
@@ -384,10 +389,11 @@
389 echo $(OX)\unicode.obj >> $@
390 echo $(OX)\update.obj >> $@
391 echo $(OX)\url.obj >> $@
392 echo $(OX)\user.obj >> $@
393 echo $(OX)\utf8.obj >> $@
394 echo $(OX)\util.obj >> $@
395 echo $(OX)\verify.obj >> $@
396 echo $(OX)\vfile.obj >> $@
397 echo $(OX)\wiki.obj >> $@
398 echo $(OX)\wikiformat.obj >> $@
399 echo $(OX)\winhttp.obj >> $@
@@ -461,10 +467,11 @@
467 $(OBJDIR)\json_dir$O : $(SRCDIR)\json_detail.h
468 $(OBJDIR)\json_finfo$O : $(SRCDIR)\json_detail.h
469 $(OBJDIR)\json_login$O : $(SRCDIR)\json_detail.h
470 $(OBJDIR)\json_query$O : $(SRCDIR)\json_detail.h
471 $(OBJDIR)\json_report$O : $(SRCDIR)\json_detail.h
472 $(OBJDIR)\json_status$O : $(SRCDIR)\json_detail.h
473 $(OBJDIR)\json_tag$O : $(SRCDIR)\json_detail.h
474 $(OBJDIR)\json_timeline$O : $(SRCDIR)\json_detail.h
475 $(OBJDIR)\json_user$O : $(SRCDIR)\json_detail.h
476 $(OBJDIR)\json_wiki$O : $(SRCDIR)\json_detail.h
477
@@ -754,10 +761,16 @@
761 $(OX)\json_report$O : json_report_.c json_report.h
762 $(TCC) /Fo$@ -c json_report_.c
763
764 json_report_.c : $(SRCDIR)\json_report.c
765 translate$E $** > $@
766
767 $(OX)\json_status$O : json_status_.c json_status.h
768 $(TCC) /Fo$@ -c json_status_.c
769
770 json_status_.c : $(SRCDIR)\json_status.c
771 translate$E $** > $@
772
773 $(OX)\json_tag$O : json_tag_.c json_tag.h
774 $(TCC) /Fo$@ -c json_tag_.c
775
776 json_tag_.c : $(SRCDIR)\json_tag.c
@@ -1036,10 +1049,16 @@
1049 $(OX)\utf8$O : utf8_.c utf8.h
1050 $(TCC) /Fo$@ -c utf8_.c
1051
1052 utf8_.c : $(SRCDIR)\utf8.c
1053 translate$E $** > $@
1054
1055 $(OX)\util$O : util_.c util.h
1056 $(TCC) /Fo$@ -c util_.c
1057
1058 util_.c : $(SRCDIR)\util.c
1059 translate$E $** > $@
1060
1061 $(OX)\verify$O : verify_.c verify.h
1062 $(TCC) /Fo$@ -c verify_.c
1063
1064 verify_.c : $(SRCDIR)\verify.c
@@ -1142,10 +1161,11 @@
1161 json_dir_.c:json_dir.h \
1162 json_finfo_.c:json_finfo.h \
1163 json_login_.c:json_login.h \
1164 json_query_.c:json_query.h \
1165 json_report_.c:json_report.h \
1166 json_status_.c:json_status.h \
1167 json_tag_.c:json_tag.h \
1168 json_timeline_.c:json_timeline.h \
1169 json_user_.c:json_user.h \
1170 json_wiki_.c:json_wiki.h \
1171 leaf_.c:leaf.h \
@@ -1189,10 +1209,11 @@
1209 unicode_.c:unicode.h \
1210 update_.c:update.h \
1211 url_.c:url.h \
1212 user_.c:user.h \
1213 utf8_.c:utf8.h \
1214 util_.c:util.h \
1215 verify_.c:verify.h \
1216 vfile_.c:vfile.h \
1217 wiki_.c:wiki.h \
1218 wikiformat_.c:wikiformat.h \
1219 winhttp_.c:winhttp.h \
1220
+14 -1
--- www/changes.wiki
+++ www/changes.wiki
@@ -1,8 +1,15 @@
11
<title>Change Log</title>
22
3
-<h2>Changes For Version 1.25 (2012-12-19)</h2>
3
+<h2>Changes For Version 1.26 (as yet unreleased)</h2>
4
+ * Enhancements to /timeline.rss, adding more flags for filtering
5
+ results, including the ability to subscribe to changes made
6
+ to individual tickets. For example: [/timeline.rss?y=t&tkt=12fceeec82].
7
+ * JSON API: added the 'status' command to report local checkout status.
8
+
9
+
10
+<h2>Changes For Version 1.25 (2013-02-16)</h2>
411
* Enhancements to ticket processing. There are now two tables: TICKET and
512
TICKETCHNG. There is one row in TICKETCHNG for each ticket artifact.
613
Fields from ticket artifacts go into either or both of TICKET and
714
TICKETCHNG, whichever contain matching column names. Default ticket
815
edit and viewing scripts are updated to use TICKETCHNG. The TH1
@@ -81,10 +88,16 @@
8188
use those sources when compiling on (windows) systems that do not have
8289
a zlib library installed by default.
8390
* Prompt the user with the option to convert non-UTF8 files into UTF8
8491
when committing.
8592
* Allow the characters <nowiki>*[]?</nowiki> in filenames.
93
+ * Allow the --context option on diff commands to have a value of 0.
94
+ * Added the "dbstat" command.
95
+ * Enhanced "fossil merge" so that if the VERSION argument is omitted, Fossil
96
+ tries to merge any forks of the current branch.
97
+ * Improved detection of forks in a commit race.
98
+ * Added the --analyze option to "fossil rebuild".
8699
87100
<h2>Changes For Version 1.24 (2012-10-22)</h2>
88101
* Added support for WYSIWYG editing of wiki pages. WYSIWYG is turned off
89102
by default and can be turned on by setting a configuration option.
90103
* Allow style= attribute to occur in HTML markup on wiki pages.
91104
92105
ADDED www/fossil_prompt.sh
93106
ADDED www/fossil_prompt.wiki
--- www/changes.wiki
+++ www/changes.wiki
@@ -1,8 +1,15 @@
1 <title>Change Log</title>
2
3 <h2>Changes For Version 1.25 (2012-12-19)</h2>
 
 
 
 
 
 
 
4 * Enhancements to ticket processing. There are now two tables: TICKET and
5 TICKETCHNG. There is one row in TICKETCHNG for each ticket artifact.
6 Fields from ticket artifacts go into either or both of TICKET and
7 TICKETCHNG, whichever contain matching column names. Default ticket
8 edit and viewing scripts are updated to use TICKETCHNG. The TH1
@@ -81,10 +88,16 @@
81 use those sources when compiling on (windows) systems that do not have
82 a zlib library installed by default.
83 * Prompt the user with the option to convert non-UTF8 files into UTF8
84 when committing.
85 * Allow the characters <nowiki>*[]?</nowiki> in filenames.
 
 
 
 
 
 
86
87 <h2>Changes For Version 1.24 (2012-10-22)</h2>
88 * Added support for WYSIWYG editing of wiki pages. WYSIWYG is turned off
89 by default and can be turned on by setting a configuration option.
90 * Allow style= attribute to occur in HTML markup on wiki pages.
91
92 DDED www/fossil_prompt.sh
93 DDED www/fossil_prompt.wiki
--- www/changes.wiki
+++ www/changes.wiki
@@ -1,8 +1,15 @@
1 <title>Change Log</title>
2
3 <h2>Changes For Version 1.26 (as yet unreleased)</h2>
4 * Enhancements to /timeline.rss, adding more flags for filtering
5 results, including the ability to subscribe to changes made
6 to individual tickets. For example: [/timeline.rss?y=t&tkt=12fceeec82].
7 * JSON API: added the 'status' command to report local checkout status.
8
9
10 <h2>Changes For Version 1.25 (2013-02-16)</h2>
11 * Enhancements to ticket processing. There are now two tables: TICKET and
12 TICKETCHNG. There is one row in TICKETCHNG for each ticket artifact.
13 Fields from ticket artifacts go into either or both of TICKET and
14 TICKETCHNG, whichever contain matching column names. Default ticket
15 edit and viewing scripts are updated to use TICKETCHNG. The TH1
@@ -81,10 +88,16 @@
88 use those sources when compiling on (windows) systems that do not have
89 a zlib library installed by default.
90 * Prompt the user with the option to convert non-UTF8 files into UTF8
91 when committing.
92 * Allow the characters <nowiki>*[]?</nowiki> in filenames.
93 * Allow the --context option on diff commands to have a value of 0.
94 * Added the "dbstat" command.
95 * Enhanced "fossil merge" so that if the VERSION argument is omitted, Fossil
96 tries to merge any forks of the current branch.
97 * Improved detection of forks in a commit race.
98 * Added the --analyze option to "fossil rebuild".
99
100 <h2>Changes For Version 1.24 (2012-10-22)</h2>
101 * Added support for WYSIWYG editing of wiki pages. WYSIWYG is turned off
102 by default and can be turned on by setting a configuration option.
103 * Allow style= attribute to occur in HTML markup on wiki pages.
104
105 DDED www/fossil_prompt.sh
106 DDED www/fossil_prompt.wiki
--- a/www/fossil_prompt.sh
+++ b/www/fossil_prompt.sh
@@ -0,0 +1,3 @@
1
+
2
+#--------------------------------- sed 's/"//g'|grep "^[^ ]*:" |
3
+
--- a/www/fossil_prompt.sh
+++ b/www/fossil_prompt.sh
@@ -0,0 +1,3 @@
 
 
 
--- a/www/fossil_prompt.sh
+++ b/www/fossil_prompt.sh
@@ -0,0 +1,3 @@
1
2 #--------------------------------- sed 's/"//g'|grep "^[^ ]*:" |
3
--- a/www/fossil_prompt.wiki
+++ b/www/fossil_prompt.wiki
@@ -0,0 +1 @@
1
+<title>Foss
--- a/www/fossil_prompt.wiki
+++ b/www/fossil_prompt.wiki
@@ -0,0 +1 @@
 
--- a/www/fossil_prompt.wiki
+++ b/www/fossil_prompt.wiki
@@ -0,0 +1 @@
1 <title>Foss
--- www/mkindex.tcl
+++ www/mkindex.tcl
@@ -49,10 +49,11 @@
4949
ssl.wiki {Using SSL with Fossil}
5050
sync.wiki {The Fossil Sync Protocol}
5151
tech_overview.wiki {A Technical Overview Of The Design And Implementation
5252
Of Fossil}
5353
tech_overview.wiki {SQLite Databases Used By Fossil}
54
+ tickets.wiki {The Fossil Ticket System}
5455
theory1.wiki {Thoughts On The Design Of The Fossil DVCS}
5556
webui.wiki {The Fossil Web Interface}
5657
wikitheory.wiki {Wiki In Fossil}
5758
}
5859
5960
--- www/mkindex.tcl
+++ www/mkindex.tcl
@@ -49,10 +49,11 @@
49 ssl.wiki {Using SSL with Fossil}
50 sync.wiki {The Fossil Sync Protocol}
51 tech_overview.wiki {A Technical Overview Of The Design And Implementation
52 Of Fossil}
53 tech_overview.wiki {SQLite Databases Used By Fossil}
 
54 theory1.wiki {Thoughts On The Design Of The Fossil DVCS}
55 webui.wiki {The Fossil Web Interface}
56 wikitheory.wiki {Wiki In Fossil}
57 }
58
59
--- www/mkindex.tcl
+++ www/mkindex.tcl
@@ -49,10 +49,11 @@
49 ssl.wiki {Using SSL with Fossil}
50 sync.wiki {The Fossil Sync Protocol}
51 tech_overview.wiki {A Technical Overview Of The Design And Implementation
52 Of Fossil}
53 tech_overview.wiki {SQLite Databases Used By Fossil}
54 tickets.wiki {The Fossil Ticket System}
55 theory1.wiki {Thoughts On The Design Of The Fossil DVCS}
56 webui.wiki {The Fossil Web Interface}
57 wikitheory.wiki {Wiki In Fossil}
58 }
59
60
--- www/permutedindex.wiki
+++ www/permutedindex.wiki
@@ -136,18 +136,21 @@
136136
<li><a href="style.wiki">Style Guidelines &mdash; Source Code</a></li>
137137
<li><a href="foss-cklist.wiki">Successful Open-Source Projects &mdash; Checklist For</a></li>
138138
<li><a href="sync.wiki">Sync Protocol &mdash; The Fossil</a></li>
139139
<li><a href="private.wiki">Syncing, and Deleting Private Branches &mdash; Creating,</a></li>
140140
<li><a href="custom_ticket.wiki">System &mdash; Customizing The Ticket</a></li>
141
+<li><a href="tickets.wiki">System &mdash; The Fossil Ticket</a></li>
141142
<li><a href="branching.wiki">Tagging &mdash; Branching, Forking, Merging, and</a></li>
142143
<li><a href="tech_overview.wiki">Technical Overview Of The Design And Implementation Of Fossil &mdash; A</a></li>
143144
<li><a href="../test/release-checklist.wiki">Testing Checklist &mdash; Pre-Release</a></li>
144145
<li><a href="makefile.wiki">The Fossil Build Process</a></li>
145146
<li><a href="sync.wiki">The Fossil Sync Protocol</a></li>
147
+<li><a href="tickets.wiki">The Fossil Ticket System</a></li>
146148
<li><a href="webui.wiki">The Fossil Web Interface</a></li>
147149
<li><a href="theory1.wiki">Thoughts On The Design Of The Fossil DVCS</a></li>
148150
<li><a href="custom_ticket.wiki">Ticket System &mdash; Customizing The</a></li>
151
+<li><a href="tickets.wiki">Ticket System &mdash; The Fossil</a></li>
149152
<li><a href="bugtheory.wiki">Tracking In Fossil &mdash; Bug</a></li>
150153
<li><a href="fiveminutes.wiki">Update and Running in 5 Minutes as a Single User</a></li>
151154
<li><a href="fiveminutes.wiki">User &mdash; Update and Running in 5 Minutes as a Single</a></li>
152155
<li><a href="ssl.wiki">Using SSL with Fossil</a></li>
153156
<li><a href="checkin_names.wiki">Version Names &mdash; Checkin And</a></li>
154157
155158
ADDED www/tickets.wiki
--- www/permutedindex.wiki
+++ www/permutedindex.wiki
@@ -136,18 +136,21 @@
136 <li><a href="style.wiki">Style Guidelines &mdash; Source Code</a></li>
137 <li><a href="foss-cklist.wiki">Successful Open-Source Projects &mdash; Checklist For</a></li>
138 <li><a href="sync.wiki">Sync Protocol &mdash; The Fossil</a></li>
139 <li><a href="private.wiki">Syncing, and Deleting Private Branches &mdash; Creating,</a></li>
140 <li><a href="custom_ticket.wiki">System &mdash; Customizing The Ticket</a></li>
 
141 <li><a href="branching.wiki">Tagging &mdash; Branching, Forking, Merging, and</a></li>
142 <li><a href="tech_overview.wiki">Technical Overview Of The Design And Implementation Of Fossil &mdash; A</a></li>
143 <li><a href="../test/release-checklist.wiki">Testing Checklist &mdash; Pre-Release</a></li>
144 <li><a href="makefile.wiki">The Fossil Build Process</a></li>
145 <li><a href="sync.wiki">The Fossil Sync Protocol</a></li>
 
146 <li><a href="webui.wiki">The Fossil Web Interface</a></li>
147 <li><a href="theory1.wiki">Thoughts On The Design Of The Fossil DVCS</a></li>
148 <li><a href="custom_ticket.wiki">Ticket System &mdash; Customizing The</a></li>
 
149 <li><a href="bugtheory.wiki">Tracking In Fossil &mdash; Bug</a></li>
150 <li><a href="fiveminutes.wiki">Update and Running in 5 Minutes as a Single User</a></li>
151 <li><a href="fiveminutes.wiki">User &mdash; Update and Running in 5 Minutes as a Single</a></li>
152 <li><a href="ssl.wiki">Using SSL with Fossil</a></li>
153 <li><a href="checkin_names.wiki">Version Names &mdash; Checkin And</a></li>
154
155 DDED www/tickets.wiki
--- www/permutedindex.wiki
+++ www/permutedindex.wiki
@@ -136,18 +136,21 @@
136 <li><a href="style.wiki">Style Guidelines &mdash; Source Code</a></li>
137 <li><a href="foss-cklist.wiki">Successful Open-Source Projects &mdash; Checklist For</a></li>
138 <li><a href="sync.wiki">Sync Protocol &mdash; The Fossil</a></li>
139 <li><a href="private.wiki">Syncing, and Deleting Private Branches &mdash; Creating,</a></li>
140 <li><a href="custom_ticket.wiki">System &mdash; Customizing The Ticket</a></li>
141 <li><a href="tickets.wiki">System &mdash; The Fossil Ticket</a></li>
142 <li><a href="branching.wiki">Tagging &mdash; Branching, Forking, Merging, and</a></li>
143 <li><a href="tech_overview.wiki">Technical Overview Of The Design And Implementation Of Fossil &mdash; A</a></li>
144 <li><a href="../test/release-checklist.wiki">Testing Checklist &mdash; Pre-Release</a></li>
145 <li><a href="makefile.wiki">The Fossil Build Process</a></li>
146 <li><a href="sync.wiki">The Fossil Sync Protocol</a></li>
147 <li><a href="tickets.wiki">The Fossil Ticket System</a></li>
148 <li><a href="webui.wiki">The Fossil Web Interface</a></li>
149 <li><a href="theory1.wiki">Thoughts On The Design Of The Fossil DVCS</a></li>
150 <li><a href="custom_ticket.wiki">Ticket System &mdash; Customizing The</a></li>
151 <li><a href="tickets.wiki">Ticket System &mdash; The Fossil</a></li>
152 <li><a href="bugtheory.wiki">Tracking In Fossil &mdash; Bug</a></li>
153 <li><a href="fiveminutes.wiki">Update and Running in 5 Minutes as a Single User</a></li>
154 <li><a href="fiveminutes.wiki">User &mdash; Update and Running in 5 Minutes as a Single</a></li>
155 <li><a href="ssl.wiki">Using SSL with Fossil</a></li>
156 <li><a href="checkin_names.wiki">Version Names &mdash; Checkin And</a></li>
157
158 DDED www/tickets.wiki
--- a/www/tickets.wiki
+++ b/www/tickets.wiki
@@ -0,0 +1,69 @@
1
+<title>The Fossil <title>The Fossil Ticket System</title>
2
+
3
+<h2>1.0 File Format</h2>
4
+
5
+At its lowest level, the tickets of Fossil consist solely of
6
+[./fileformi REFERENCES ticket,
7
+ tkt_rid INTEGER REFERENCES blob,
8
+ tkt_mtime DATE,
9
+ -- Add as many fields as required below this line
10
+ login TEXT,
11
+ username TEXT,
12
+ mimetype TEXT,
13
+ icomment TEXT
14
+);
15
+CREATE INDEX ticketchng_idx1 ON ticketchng(tkt_id, tkt_mtime);
16
+</verbatim>
17
+
18
+Generally speaking, there is one row in the TICKETCHNG table for each
19
+change to each ticket. In other words, there i
20
+<b>tkt_c
21
+Generally speaking, therow in the
22
+TICKETCHNG table for each low-level ticket change artifact. The
23
+TICKET table, on the other hand, contains a summary of the current
24
+status of each ticket.
25
+
26
+Fields of the TICKET and TICKETCHNG tables that begin with "tkt_" are
27
+used internally by Fossil. The logic inside of Fossil that converts
28
+ticket change artifacts into row data for the two ticket tables expects
29
+the "tkt_" fields to always be present. All of the other fields of the
30
+TICKET and TICKETCHNG tables are "user defined" in the sense that they
31
+can be anything the administrator of the system wants them to be. The
32
+user-defined fields should correspond to keys in the key/value pairs of
33
+the ticket change artifacts.
34
+
35
+The <b>tkt_id</b> fields of TICKET and TICKETCHNG are an integer key
36
+used to uniquely identify the ticket to which the row belongs. These
37
+keys are for internal use only and may change when doing a "fossil rebuild".
38
+
39
+The <b>tkt_uuid</b> field is the unique hexadecimal identifier for the ticket.
40
+Ticket identifiersy the hash of any identifjst et, Fossil uses
41
+a (high-quality) pseudo-random number generator to create the ticket
42
+number. The ticket numbers are large so that the chance of collision
43
+between any two tickets is vanishingly small.
44
+
45
+The <b>tkt_mtime</b> field of TICKET shows the time (as a Julian day number)
46
+of the most recent ticket change artifact for that ticket. The
47
+<b>tkt_mtime</b> field of TICKETCHNG shows the timestamp on the ticket
48
+change artifact that the TICKETCHNG row refers to. The
49
+<b>tkt_ctime</b> field of TICKET is the time of the oldest ticket ch+16:26:29 | 2012-11-27]) icket, thus holding the time that the ticket was
50
+created.
51
+
52
+The <b>tkt_rid</b> field of TICKETCHNG is the integer primary key in the
53
+BLOB table of the ticket change artifact that gave rise to the row in the
54
+TICKETCHNG table.
55
+
56
+All the other fields of the TICKET and TICKETCHNG tables are available
57
+for customization for individual projects. None of the remaining fields
58
+are required, but all of them are needed in order to use the default
59
+ticket creating, viewing, and editing scripts. It is recommended that
60
+the other fields be retained andhat customizations be restricted to
61
+adding new fields above and beyond the default.
62
+
63
+< s To Tables</h3>
64
+
65
+Each row in the TICKETCHNG table corresponds to a single ticket change
66
+artifact. The tkt_id field is the integer primary key of the TICKET
67
+table entry for the corresponding ticket. The tkt_rid field is the
68
+integer primary key for the BLOB table entry that contains the low-level
69
+artifact text. The tkt_mtime fieldstamp order.
--- a/www/tickets.wiki
+++ b/www/tickets.wiki
@@ -0,0 +1,69 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
--- a/www/tickets.wiki
+++ b/www/tickets.wiki
@@ -0,0 +1,69 @@
1 <title>The Fossil <title>The Fossil Ticket System</title>
2
3 <h2>1.0 File Format</h2>
4
5 At its lowest level, the tickets of Fossil consist solely of
6 [./fileformi REFERENCES ticket,
7 tkt_rid INTEGER REFERENCES blob,
8 tkt_mtime DATE,
9 -- Add as many fields as required below this line
10 login TEXT,
11 username TEXT,
12 mimetype TEXT,
13 icomment TEXT
14 );
15 CREATE INDEX ticketchng_idx1 ON ticketchng(tkt_id, tkt_mtime);
16 </verbatim>
17
18 Generally speaking, there is one row in the TICKETCHNG table for each
19 change to each ticket. In other words, there i
20 <b>tkt_c
21 Generally speaking, therow in the
22 TICKETCHNG table for each low-level ticket change artifact. The
23 TICKET table, on the other hand, contains a summary of the current
24 status of each ticket.
25
26 Fields of the TICKET and TICKETCHNG tables that begin with "tkt_" are
27 used internally by Fossil. The logic inside of Fossil that converts
28 ticket change artifacts into row data for the two ticket tables expects
29 the "tkt_" fields to always be present. All of the other fields of the
30 TICKET and TICKETCHNG tables are "user defined" in the sense that they
31 can be anything the administrator of the system wants them to be. The
32 user-defined fields should correspond to keys in the key/value pairs of
33 the ticket change artifacts.
34
35 The <b>tkt_id</b> fields of TICKET and TICKETCHNG are an integer key
36 used to uniquely identify the ticket to which the row belongs. These
37 keys are for internal use only and may change when doing a "fossil rebuild".
38
39 The <b>tkt_uuid</b> field is the unique hexadecimal identifier for the ticket.
40 Ticket identifiersy the hash of any identifjst et, Fossil uses
41 a (high-quality) pseudo-random number generator to create the ticket
42 number. The ticket numbers are large so that the chance of collision
43 between any two tickets is vanishingly small.
44
45 The <b>tkt_mtime</b> field of TICKET shows the time (as a Julian day number)
46 of the most recent ticket change artifact for that ticket. The
47 <b>tkt_mtime</b> field of TICKETCHNG shows the timestamp on the ticket
48 change artifact that the TICKETCHNG row refers to. The
49 <b>tkt_ctime</b> field of TICKET is the time of the oldest ticket ch+16:26:29 | 2012-11-27]) icket, thus holding the time that the ticket was
50 created.
51
52 The <b>tkt_rid</b> field of TICKETCHNG is the integer primary key in the
53 BLOB table of the ticket change artifact that gave rise to the row in the
54 TICKETCHNG table.
55
56 All the other fields of the TICKET and TICKETCHNG tables are available
57 for customization for individual projects. None of the remaining fields
58 are required, but all of them are needed in order to use the default
59 ticket creating, viewing, and editing scripts. It is recommended that
60 the other fields be retained andhat customizations be restricted to
61 adding new fields above and beyond the default.
62
63 < s To Tables</h3>
64
65 Each row in the TICKETCHNG table corresponds to a single ticket change
66 artifact. The tkt_id field is the integer primary key of the TICKET
67 table entry for the corresponding ticket. The tkt_rid field is the
68 integer primary key for the BLOB table entry that contains the low-level
69 artifact text. The tkt_mtime fieldstamp order.

Keyboard Shortcuts

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