Fossil SCM
Merging from trunk to get the annotate fixes. Trivial conflict solved.
Commit
f14798e0e3d0fe9866b7ca82e1d08c0ea7323e2d
Parent
96c3133576e55f0…
64 files changed
+2
-2
+1
-1
+9
-6
+12
-2
+46
-28
+46
-28
+3
-13
+6
-14
+69
-37
+69
-37
+248
-107
+248
-107
+46
-38
+8
-8
+40
-24
+2
-2
+2
-2
+24
-76
+24
-76
+14
-8
+8
-5
+130
+199
-337
+22
-2
+8
-4
+1
-2
+22
-17
+166
-68
+4
-2
+3
-2
+56
+20
-20
+57
-22
+632
-351
+12
-2
+6
-6
+17
-43
+19
-3
+7
-10
+7
-10
+1
-1
+89
-8
+2
-7
+101
-31
+2
-2
+12
-5
+12
-7
+77
+77
+4
+118
+8
+77
+17
-4
+27
-3
+27
-3
+21
+14
-1
+3
+1
+1
+3
+69
~
src/add.c
~
src/attach.c
~
src/blob.c
~
src/cgi.c
~
src/checkin.c
~
src/checkin.c
~
src/clone.c
~
src/configure.c
~
src/db.c
~
src/db.c
~
src/diff.c
~
src/diff.c
~
src/file.c
~
src/finfo.c
~
src/glob.c
~
src/http.c
~
src/http_transport.c
~
src/info.c
~
src/info.c
~
src/json.c
~
src/json_detail.h
~
src/json_status.c
~
src/main.c
~
src/main.mk
~
src/makemake.tcl
~
src/md5.c
~
src/mkindex.c
~
src/printf.c
~
src/rebuild.c
~
src/regexp.c
~
src/rss.c
~
src/setup.c
~
src/shell.c
~
src/sqlite3.c
~
src/sqlite3.h
~
src/stat.c
~
src/sync.c
~
src/th_main.c
~
src/timeline.c
~
src/timeline.c
~
src/tkt.c
~
src/url.c
~
src/user.c
~
src/utf8.c
~
src/util.c
~
src/vfile.c
~
src/winhttp.c
~
src/xfer.c
~
test/Greek-Lipsum-1.txt
~
test/Greek-Lipsum-2.txt
~
test/diff-test-1.wiki
~
test/glob.test
~
test/th1-tcl.test
~
test/utf.test
~
win/Makefile.dmc
~
win/Makefile.mingw
~
win/Makefile.mingw.mistachkin
~
win/Makefile.msc
~
www/changes.wiki
~
www/fossil_prompt.sh
~
www/fossil_prompt.wiki
~
www/mkindex.tcl
~
www/permutedindex.wiki
~
www/tickets.wiki
+2
-2
| --- src/add.c | ||
| +++ src/add.c | ||
| @@ -262,11 +262,11 @@ | ||
| 262 | 262 | if( vid==0 ){ |
| 263 | 263 | fossil_panic("no checkout to add to"); |
| 264 | 264 | } |
| 265 | 265 | db_begin_transaction(); |
| 266 | 266 | db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)"); |
| 267 | -#if defined(_WIN32) | |
| 267 | +#if defined(_WIN32) || defined(__CYGWIN__) | |
| 268 | 268 | db_multi_exec( |
| 269 | 269 | "CREATE INDEX IF NOT EXISTS vfile_pathname " |
| 270 | 270 | " ON vfile(pathname COLLATE nocase)" |
| 271 | 271 | ); |
| 272 | 272 | #endif |
| @@ -388,11 +388,11 @@ | ||
| 388 | 388 | if( once ){ |
| 389 | 389 | once = 0; |
| 390 | 390 | if( zCaseSensitive ){ |
| 391 | 391 | caseSensitive = is_truth(zCaseSensitive); |
| 392 | 392 | }else{ |
| 393 | -#if !defined(_WIN32) && !defined(__DARWIN__) && !defined(__APPLE__) | |
| 393 | +#if !defined(_WIN32) && !defined(__CYGWIN__) && !defined(__DARWIN__) && !defined(__APPLE__) | |
| 394 | 394 | caseSensitive = 1; /* Unix */ |
| 395 | 395 | #else |
| 396 | 396 | caseSensitive = 0; /* Windows and Mac */ |
| 397 | 397 | #endif |
| 398 | 398 | caseSensitive = db_get_boolean("case-sensitive",caseSensitive); |
| 399 | 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) |
| 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 @@ | ||
| 94 | 94 | } |
| 95 | 95 | @ <br><a href="/attachview?%s(zUrlTail)">%h(zFilename)</a> |
| 96 | 96 | @ [<a href="/attachdownload/%t(zFilename)?%s(zUrlTail)">download</a>]<br /> |
| 97 | 97 | if( zComment ) while( fossil_isspace(zComment[0]) ) zComment++; |
| 98 | 98 | if( zComment && zComment[0] ){ |
| 99 | - @ %w(zComment)<br /> | |
| 99 | + @ %!w(zComment)<br /> | |
| 100 | 100 | } |
| 101 | 101 | if( zPage==0 && zTkt==0 ){ |
| 102 | 102 | if( zSrc==0 || zSrc[0]==0 ){ |
| 103 | 103 | zSrc = "Deleted from"; |
| 104 | 104 | }else { |
| 105 | 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 |
| --- 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 @@ | ||
| 792 | 792 | } |
| 793 | 793 | nName = file_simplify_name(zName, nName, 0); |
| 794 | 794 | for(i=1; i<nName; i++){ |
| 795 | 795 | if( zName[i]=='/' ){ |
| 796 | 796 | zName[i] = 0; |
| 797 | -#if defined(_WIN32) | |
| 797 | +#if defined(_WIN32) || defined(__CYGWIN__) | |
| 798 | 798 | /* |
| 799 | 799 | ** On Windows, local path looks like: C:/develop/project/file.txt |
| 800 | 800 | ** The if stops us from trying to create a directory of a drive letter |
| 801 | 801 | ** C: in this example. |
| 802 | 802 | */ |
| @@ -804,11 +804,11 @@ | ||
| 804 | 804 | #endif |
| 805 | 805 | if( file_mkdir(zName, 1) && file_isdir(zName)!=1 ){ |
| 806 | 806 | fossil_fatal_recursive("unable to create directory %s", zName); |
| 807 | 807 | return 0; |
| 808 | 808 | } |
| 809 | -#if defined(_WIN32) | |
| 809 | +#if defined(_WIN32) || defined(__CYGWIN__) | |
| 810 | 810 | } |
| 811 | 811 | #endif |
| 812 | 812 | zName[i] = '/'; |
| 813 | 813 | } |
| 814 | 814 | } |
| @@ -1096,24 +1096,25 @@ | ||
| 1096 | 1096 | ** to be UTF-8 already, so no conversion is done. |
| 1097 | 1097 | */ |
| 1098 | 1098 | void blob_to_utf8_no_bom(Blob *pBlob, int useMbcs){ |
| 1099 | 1099 | char *zUtf8; |
| 1100 | 1100 | int bomSize = 0; |
| 1101 | + int bomReverse = 0; | |
| 1101 | 1102 | if( starts_with_utf8_bom(pBlob, &bomSize) ){ |
| 1102 | 1103 | struct Blob temp; |
| 1103 | 1104 | zUtf8 = blob_str(pBlob) + bomSize; |
| 1104 | 1105 | blob_zero(&temp); |
| 1105 | 1106 | blob_append(&temp, zUtf8, -1); |
| 1106 | 1107 | blob_swap(pBlob, &temp); |
| 1107 | 1108 | 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) ){ | |
| 1110 | 1111 | zUtf8 = blob_buffer(pBlob); |
| 1111 | - if (*((unsigned short *)zUtf8) == 0xfffe) { | |
| 1112 | + if( bomReverse ){ | |
| 1112 | 1113 | /* Found BOM, but with reversed bytes */ |
| 1113 | 1114 | unsigned int i = blob_size(pBlob); |
| 1114 | - while( i > 0 ){ | |
| 1115 | + while( i>0 ){ | |
| 1115 | 1116 | /* swap bytes of unicode representation */ |
| 1116 | 1117 | char zTemp = zUtf8[--i]; |
| 1117 | 1118 | zUtf8[i] = zUtf8[i-1]; |
| 1118 | 1119 | zUtf8[--i] = zTemp; |
| 1119 | 1120 | } |
| @@ -1123,13 +1124,15 @@ | ||
| 1123 | 1124 | zUtf8 = blob_str(pBlob) + bomSize; |
| 1124 | 1125 | zUtf8 = fossil_unicode_to_utf8(zUtf8); |
| 1125 | 1126 | blob_zero(pBlob); |
| 1126 | 1127 | blob_append(pBlob, zUtf8, -1); |
| 1127 | 1128 | fossil_unicode_free(zUtf8); |
| 1129 | +#endif /* _WIN32 || __CYGWIN__ */ | |
| 1130 | +#if defined(_WIN32) | |
| 1128 | 1131 | }else if( useMbcs ){ |
| 1129 | 1132 | zUtf8 = fossil_mbcs_to_utf8(blob_str(pBlob)); |
| 1130 | 1133 | blob_reset(pBlob); |
| 1131 | 1134 | blob_append(pBlob, zUtf8, -1); |
| 1132 | 1135 | fossil_mbcs_free(zUtf8); |
| 1133 | 1136 | #endif /* _WIN32 */ |
| 1134 | 1137 | } |
| 1135 | 1138 | } |
| 1136 | 1139 |
| --- 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 @@ | ||
| 1272 | 1272 | ** The parent never returns from this procedure. |
| 1273 | 1273 | ** |
| 1274 | 1274 | ** Return 0 to each child as it runs. If unable to establish a |
| 1275 | 1275 | ** listening socket, return non-zero. |
| 1276 | 1276 | */ |
| 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 | +){ | |
| 1278 | 1283 | #if defined(_WIN32) |
| 1279 | 1284 | /* Use win32_http_server() instead */ |
| 1280 | 1285 | fossil_exit(1); |
| 1281 | 1286 | #else |
| 1282 | 1287 | int listener = -1; /* The server socket */ |
| @@ -1291,11 +1296,16 @@ | ||
| 1291 | 1296 | int iPort = mnPort; |
| 1292 | 1297 | |
| 1293 | 1298 | while( iPort<=mxPort ){ |
| 1294 | 1299 | memset(&inaddr, 0, sizeof(inaddr)); |
| 1295 | 1300 | 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 ){ | |
| 1297 | 1307 | inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); |
| 1298 | 1308 | }else{ |
| 1299 | 1309 | inaddr.sin_addr.s_addr = htonl(INADDR_ANY); |
| 1300 | 1310 | } |
| 1301 | 1311 | inaddr.sin_port = htons(iPort); |
| 1302 | 1312 |
| --- 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 @@ | ||
| 177 | 177 | if( showHdr && blob_size(&report)>0 ){ |
| 178 | 178 | fossil_print("Changes for %s at %s:\n", db_get("project-name","???"), |
| 179 | 179 | g.zLocalRoot); |
| 180 | 180 | } |
| 181 | 181 | blob_write_to_file(&report, "-"); |
| 182 | + blob_reset(&report); | |
| 182 | 183 | } |
| 183 | 184 | |
| 184 | 185 | /* |
| 185 | 186 | ** COMMAND: status |
| 186 | 187 | ** |
| @@ -205,22 +206,20 @@ | ||
| 205 | 206 | int vid; |
| 206 | 207 | db_must_be_within_tree(); |
| 207 | 208 | /* 012345678901234 */ |
| 208 | 209 | fossil_print("repository: %s\n", db_repository_filename()); |
| 209 | 210 | fossil_print("local-root: %s\n", g.zLocalRoot); |
| 211 | + if( g.zConfigDbName ){ | |
| 212 | + fossil_print("config-db: %s\n", g.zConfigDbName); | |
| 213 | + } | |
| 210 | 214 | vid = db_lget_int("checkout", 0); |
| 211 | 215 | if( vid ){ |
| 212 | 216 | show_common_info(vid, "checkout:", 1, 1); |
| 213 | 217 | } |
| 214 | 218 | db_record_repository_filename(0); |
| 215 | 219 | changes_cmd(); |
| 216 | 220 | } |
| 217 | - | |
| 218 | -/* | |
| 219 | -** Implementation of the checkin_mtime SQL function | |
| 220 | -*/ | |
| 221 | - | |
| 222 | 221 | |
| 223 | 222 | /* |
| 224 | 223 | ** COMMAND: ls |
| 225 | 224 | ** |
| 226 | 225 | ** Usage: %fossil ls ?OPTIONS? ?VERSION? |
| @@ -442,24 +441,26 @@ | ||
| 442 | 441 | } |
| 443 | 442 | db_multi_exec("DELETE FROM sfile WHERE x IN (SELECT pathname FROM vfile)"); |
| 444 | 443 | while( db_step(&q)==SQLITE_ROW ){ |
| 445 | 444 | if( testFlag ){ |
| 446 | 445 | 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 ){ | |
| 450 | 448 | Blob ans; |
| 451 | 449 | char cReply; |
| 452 | - char *prompt = mprintf("remove unmanaged file \"%s\" (y/N)? ", | |
| 450 | + char *prompt = mprintf("remove unmanaged file \"%s\" (a=all/y/N)? ", | |
| 453 | 451 | db_column_text(&q, 0)); |
| 454 | 452 | blob_zero(&ans); |
| 455 | 453 | prompt_user(prompt, &ans); |
| 456 | 454 | 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; | |
| 459 | 459 | } |
| 460 | 460 | } |
| 461 | + file_delete(db_column_text(&q, 0)); | |
| 461 | 462 | } |
| 462 | 463 | db_finalize(&q); |
| 463 | 464 | } |
| 464 | 465 | |
| 465 | 466 | /* |
| @@ -909,58 +910,75 @@ | ||
| 909 | 910 | int encodingOk, /* Non-zero if encoding warnings should be disabled. */ |
| 910 | 911 | const char *zFilename /* The full name of the file being committed. */ |
| 911 | 912 | ){ |
| 912 | 913 | int eType; /* return value of looks_like_utf8/utf16() */ |
| 913 | 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 */ | |
| 914 | 917 | char *zMsg; /* Warning message */ |
| 915 | 918 | Blob fname; /* Relative pathname of the file */ |
| 916 | 919 | static int allOk = 0; /* Set to true to disable this routine */ |
| 917 | 920 | |
| 918 | 921 | 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 ){ | |
| 922 | 936 | const char *zWarning; |
| 923 | 937 | const char *zDisable; |
| 924 | 938 | const char *zConvert = "c=convert/"; |
| 925 | 939 | Blob ans; |
| 926 | 940 | char cReply; |
| 927 | 941 | |
| 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 ){ | |
| 930 | 955 | return 0; /* We don't want CR/NL and Unicode warnings for this file. */ |
| 931 | 956 | } |
| 932 | 957 | zWarning = "CR/NL line endings and Unicode"; |
| 933 | 958 | zDisable = "\"crnl-glob\" and \"encoding-glob\" settings"; |
| 934 | - }else if( eType==-1 ){ | |
| 959 | + }else if( fHasCrLf ){ | |
| 935 | 960 | if( crnlOk ){ |
| 936 | 961 | return 0; /* We don't want CR/NL warnings for this file. */ |
| 937 | 962 | } |
| 938 | 963 | zWarning = "CR/NL line endings"; |
| 939 | 964 | 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 | 965 | }else{ |
| 948 | - if ( encodingOk ){ | |
| 966 | + if( encodingOk ){ | |
| 949 | 967 | return 0; /* We don't want encoding warnings for this file. */ |
| 950 | 968 | } |
| 951 | 969 | zWarning = "Unicode"; |
| 952 | 970 | zDisable = "\"encoding-glob\" setting"; |
| 953 | -#ifndef _WIN32 | |
| 971 | +#if !defined(_WIN32) && !defined(__CYGWIN__) | |
| 954 | 972 | zConvert = ""; /* On Unix, we cannot easily convert Unicode files. */ |
| 955 | 973 | #endif |
| 956 | 974 | } |
| 957 | 975 | file_relative_name(zFilename, &fname, 0); |
| 958 | 976 | blob_zero(&ans); |
| 959 | 977 | zMsg = mprintf( |
| 960 | 978 | "%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)? ", | |
| 962 | 980 | blob_str(&fname), zWarning, zDisable, zConvert); |
| 963 | 981 | prompt_user(zMsg, &ans); |
| 964 | 982 | fossil_free(zMsg); |
| 965 | 983 | cReply = blob_str(&ans)[0]; |
| 966 | 984 | if( cReply=='a' || cReply=='A' ){ |
| @@ -1208,11 +1226,11 @@ | ||
| 1208 | 1226 | ** After the following function call has returned, the Global.aCommitFile[] |
| 1209 | 1227 | ** array is allocated to contain the "id" field from the vfile table |
| 1210 | 1228 | ** for each file to be committed. Or, if aCommitFile is NULL, all files |
| 1211 | 1229 | ** should be committed. |
| 1212 | 1230 | */ |
| 1213 | - if ( select_commit_files() ){ | |
| 1231 | + if( select_commit_files() ){ | |
| 1214 | 1232 | blob_zero(&ans); |
| 1215 | 1233 | prompt_user("continue (y/N)? ", &ans); |
| 1216 | 1234 | cReply = blob_str(&ans)[0]; |
| 1217 | 1235 | if( cReply!='y' && cReply!='Y' ) fossil_exit(1);; |
| 1218 | 1236 | } |
| 1219 | 1237 |
| --- 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 @@ | ||
| 177 | 177 | if( showHdr && blob_size(&report)>0 ){ |
| 178 | 178 | fossil_print("Changes for %s at %s:\n", db_get("project-name","???"), |
| 179 | 179 | g.zLocalRoot); |
| 180 | 180 | } |
| 181 | 181 | blob_write_to_file(&report, "-"); |
| 182 | + blob_reset(&report); | |
| 182 | 183 | } |
| 183 | 184 | |
| 184 | 185 | /* |
| 185 | 186 | ** COMMAND: status |
| 186 | 187 | ** |
| @@ -205,22 +206,20 @@ | ||
| 205 | 206 | int vid; |
| 206 | 207 | db_must_be_within_tree(); |
| 207 | 208 | /* 012345678901234 */ |
| 208 | 209 | fossil_print("repository: %s\n", db_repository_filename()); |
| 209 | 210 | fossil_print("local-root: %s\n", g.zLocalRoot); |
| 211 | + if( g.zConfigDbName ){ | |
| 212 | + fossil_print("config-db: %s\n", g.zConfigDbName); | |
| 213 | + } | |
| 210 | 214 | vid = db_lget_int("checkout", 0); |
| 211 | 215 | if( vid ){ |
| 212 | 216 | show_common_info(vid, "checkout:", 1, 1); |
| 213 | 217 | } |
| 214 | 218 | db_record_repository_filename(0); |
| 215 | 219 | changes_cmd(); |
| 216 | 220 | } |
| 217 | - | |
| 218 | -/* | |
| 219 | -** Implementation of the checkin_mtime SQL function | |
| 220 | -*/ | |
| 221 | - | |
| 222 | 221 | |
| 223 | 222 | /* |
| 224 | 223 | ** COMMAND: ls |
| 225 | 224 | ** |
| 226 | 225 | ** Usage: %fossil ls ?OPTIONS? ?VERSION? |
| @@ -442,24 +441,26 @@ | ||
| 442 | 441 | } |
| 443 | 442 | db_multi_exec("DELETE FROM sfile WHERE x IN (SELECT pathname FROM vfile)"); |
| 444 | 443 | while( db_step(&q)==SQLITE_ROW ){ |
| 445 | 444 | if( testFlag ){ |
| 446 | 445 | 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 ){ | |
| 450 | 448 | Blob ans; |
| 451 | 449 | char cReply; |
| 452 | - char *prompt = mprintf("remove unmanaged file \"%s\" (y/N)? ", | |
| 450 | + char *prompt = mprintf("remove unmanaged file \"%s\" (a=all/y/N)? ", | |
| 453 | 451 | db_column_text(&q, 0)); |
| 454 | 452 | blob_zero(&ans); |
| 455 | 453 | prompt_user(prompt, &ans); |
| 456 | 454 | 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; | |
| 459 | 459 | } |
| 460 | 460 | } |
| 461 | + file_delete(db_column_text(&q, 0)); | |
| 461 | 462 | } |
| 462 | 463 | db_finalize(&q); |
| 463 | 464 | } |
| 464 | 465 | |
| 465 | 466 | /* |
| @@ -909,58 +910,75 @@ | ||
| 909 | 910 | int encodingOk, /* Non-zero if encoding warnings should be disabled. */ |
| 910 | 911 | const char *zFilename /* The full name of the file being committed. */ |
| 911 | 912 | ){ |
| 912 | 913 | int eType; /* return value of looks_like_utf8/utf16() */ |
| 913 | 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 */ | |
| 914 | 917 | char *zMsg; /* Warning message */ |
| 915 | 918 | Blob fname; /* Relative pathname of the file */ |
| 916 | 919 | static int allOk = 0; /* Set to true to disable this routine */ |
| 917 | 920 | |
| 918 | 921 | 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 ){ | |
| 922 | 936 | const char *zWarning; |
| 923 | 937 | const char *zDisable; |
| 924 | 938 | const char *zConvert = "c=convert/"; |
| 925 | 939 | Blob ans; |
| 926 | 940 | char cReply; |
| 927 | 941 | |
| 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 ){ | |
| 930 | 955 | return 0; /* We don't want CR/NL and Unicode warnings for this file. */ |
| 931 | 956 | } |
| 932 | 957 | zWarning = "CR/NL line endings and Unicode"; |
| 933 | 958 | zDisable = "\"crnl-glob\" and \"encoding-glob\" settings"; |
| 934 | - }else if( eType==-1 ){ | |
| 959 | + }else if( fHasCrLf ){ | |
| 935 | 960 | if( crnlOk ){ |
| 936 | 961 | return 0; /* We don't want CR/NL warnings for this file. */ |
| 937 | 962 | } |
| 938 | 963 | zWarning = "CR/NL line endings"; |
| 939 | 964 | 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 | 965 | }else{ |
| 948 | - if ( encodingOk ){ | |
| 966 | + if( encodingOk ){ | |
| 949 | 967 | return 0; /* We don't want encoding warnings for this file. */ |
| 950 | 968 | } |
| 951 | 969 | zWarning = "Unicode"; |
| 952 | 970 | zDisable = "\"encoding-glob\" setting"; |
| 953 | -#ifndef _WIN32 | |
| 971 | +#if !defined(_WIN32) && !defined(__CYGWIN__) | |
| 954 | 972 | zConvert = ""; /* On Unix, we cannot easily convert Unicode files. */ |
| 955 | 973 | #endif |
| 956 | 974 | } |
| 957 | 975 | file_relative_name(zFilename, &fname, 0); |
| 958 | 976 | blob_zero(&ans); |
| 959 | 977 | zMsg = mprintf( |
| 960 | 978 | "%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)? ", | |
| 962 | 980 | blob_str(&fname), zWarning, zDisable, zConvert); |
| 963 | 981 | prompt_user(zMsg, &ans); |
| 964 | 982 | fossil_free(zMsg); |
| 965 | 983 | cReply = blob_str(&ans)[0]; |
| 966 | 984 | if( cReply=='a' || cReply=='A' ){ |
| @@ -1208,11 +1226,11 @@ | ||
| 1208 | 1226 | ** After the following function call has returned, the Global.aCommitFile[] |
| 1209 | 1227 | ** array is allocated to contain the "id" field from the vfile table |
| 1210 | 1228 | ** for each file to be committed. Or, if aCommitFile is NULL, all files |
| 1211 | 1229 | ** should be committed. |
| 1212 | 1230 | */ |
| 1213 | - if ( select_commit_files() ){ | |
| 1231 | + if( select_commit_files() ){ | |
| 1214 | 1232 | blob_zero(&ans); |
| 1215 | 1233 | prompt_user("continue (y/N)? ", &ans); |
| 1216 | 1234 | cReply = blob_str(&ans)[0]; |
| 1217 | 1235 | if( cReply!='y' && cReply!='Y' ) fossil_exit(1);; |
| 1218 | 1236 | } |
| 1219 | 1237 |
| --- 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 @@ | ||
| 99 | 99 | ** See also: init |
| 100 | 100 | */ |
| 101 | 101 | void clone_cmd(void){ |
| 102 | 102 | char *zPassword; |
| 103 | 103 | const char *zDefaultUser; /* Optional name of the default user */ |
| 104 | - const char *zPw; /* The user clone password */ | |
| 105 | 104 | int nErr = 0; |
| 106 | 105 | int bPrivate = 0; /* Also clone private branches */ |
| 107 | 106 | |
| 108 | 107 | if( find_option("private",0,0)!=0 ) bPrivate = SYNC_PRIVATE; |
| 109 | 108 | url_proxy_options(); |
| @@ -115,23 +114,17 @@ | ||
| 115 | 114 | fossil_panic("file already exists: %s", g.argv[3]); |
| 116 | 115 | } |
| 117 | 116 | |
| 118 | 117 | zDefaultUser = find_option("admin-user","A",1); |
| 119 | 118 | |
| 120 | - url_parse(g.argv[2]); | |
| 119 | + url_parse(g.argv[2], URL_PROMPT_PW|URL_ASK_REMEMBER_PW); | |
| 121 | 120 | if( g.urlIsFile ){ |
| 122 | 121 | file_copy(g.urlName, g.argv[3]); |
| 123 | 122 | db_close(1); |
| 124 | 123 | db_open_repository(g.argv[3]); |
| 125 | 124 | 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(); | |
| 133 | 126 | if( !bPrivate ) delete_private_content(); |
| 134 | 127 | shun_artifacts(); |
| 135 | 128 | db_create_default_users(1, zDefaultUser); |
| 136 | 129 | if( zDefaultUser ){ |
| 137 | 130 | g.zLogin = zDefaultUser; |
| @@ -146,11 +139,11 @@ | ||
| 146 | 139 | db_record_repository_filename(g.argv[3]); |
| 147 | 140 | db_initial_setup(0, 0, zDefaultUser, 0); |
| 148 | 141 | user_select(); |
| 149 | 142 | db_set("content-schema", CONTENT_SCHEMA, 0); |
| 150 | 143 | db_set("aux-schema", AUX_SCHEMA, 0); |
| 151 | - db_set("last-sync-url", g.argv[2], 0); | |
| 144 | + url_remember(); | |
| 152 | 145 | if( g.zSSLIdentity!=0 ){ |
| 153 | 146 | /* If the --ssl-identity option was specified, store it as a setting */ |
| 154 | 147 | Blob fn; |
| 155 | 148 | blob_zero(&fn); |
| 156 | 149 | file_canonical_name(g.zSSLIdentity, &fn, 0); |
| @@ -177,12 +170,9 @@ | ||
| 177 | 170 | } |
| 178 | 171 | db_begin_transaction(); |
| 179 | 172 | fossil_print("Rebuilding repository meta-data...\n"); |
| 180 | 173 | rebuild_db(0, 1, 0); |
| 181 | 174 | fossil_print("project-id: %s\n", db_get("project-code", 0)); |
| 182 | - fossil_print("server-id: %s\n", db_get("server-code", 0)); | |
| 183 | 175 | zPassword = db_text(0, "SELECT pw FROM user WHERE login=%Q", g.zLogin); |
| 184 | 176 | 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 | 177 | db_end_transaction(0); |
| 188 | 178 | } |
| 189 | 179 |
| --- 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 @@ | ||
| 878 | 878 | if( strncmp(zMethod, "pull", n)==0 |
| 879 | 879 | || strncmp(zMethod, "push", n)==0 |
| 880 | 880 | || strncmp(zMethod, "sync", n)==0 |
| 881 | 881 | ){ |
| 882 | 882 | int mask; |
| 883 | - const char *zServer; | |
| 884 | - const char *zPw; | |
| 883 | + const char *zServer = 0; | |
| 885 | 884 | int legacyFlag = 0; |
| 886 | 885 | int overwriteFlag = 0; |
| 886 | + | |
| 887 | 887 | if( zMethod[0]!='s' ) legacyFlag = find_option("legacy",0,0)!=0; |
| 888 | 888 | if( strncmp(zMethod,"pull",n)==0 ){ |
| 889 | 889 | overwriteFlag = find_option("overwrite",0,0)!=0; |
| 890 | 890 | } |
| 891 | 891 | url_proxy_options(); |
| 892 | 892 | if( g.argc!=4 && g.argc!=5 ){ |
| 893 | - usage("pull AREA ?URL?"); | |
| 893 | + usage(mprintf("%s AREA ?URL?", zMethod)); | |
| 894 | 894 | } |
| 895 | 895 | mask = configure_name_to_mask(g.argv[3], 1); |
| 896 | 896 | if( g.argc==5 ){ |
| 897 | 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); | |
| 898 | + } | |
| 899 | + url_parse(zServer, URL_PROMPT_PW); | |
| 900 | + if( g.urlProtocol==0 ) fossil_fatal("no server URL specified"); | |
| 909 | 901 | user_select(); |
| 910 | 902 | url_enable_proxy("via proxy: "); |
| 911 | 903 | if( legacyFlag ) mask |= CONFIGSET_OLDFORMAT; |
| 912 | 904 | if( overwriteFlag ) mask |= CONFIGSET_OVERWRITE; |
| 913 | 905 | if( strncmp(zMethod, "push", n)==0 ){ |
| 914 | 906 |
| --- 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 |
M
src/db.c
+69
-37
| --- src/db.c | ||
| +++ src/db.c | ||
| @@ -221,11 +221,11 @@ | ||
| 221 | 221 | ** rolls back rather than commit. It is the responsibility of the |
| 222 | 222 | ** hooks themselves to issue any error messages. |
| 223 | 223 | */ |
| 224 | 224 | void db_commit_hook(int (*x)(void), int sequence){ |
| 225 | 225 | int i; |
| 226 | - assert( db.nCommitHook < sizeof(db.aHook)/sizeof(db.aHook[1]) ); | |
| 226 | + assert( db.nCommitHook < count(db.aHook) ); | |
| 227 | 227 | for(i=0; i<db.nCommitHook; i++){ |
| 228 | 228 | assert( x!=db.aHook[i].xHook ); |
| 229 | 229 | if( db.aHook[i].sequence>sequence ){ |
| 230 | 230 | int s = sequence; |
| 231 | 231 | int (*xS)(void) = x; |
| @@ -769,15 +769,15 @@ | ||
| 769 | 769 | ){ |
| 770 | 770 | if( !g.db ){ |
| 771 | 771 | assert( g.zMainDbType==0 ); |
| 772 | 772 | g.db = db_open(zDbName); |
| 773 | 773 | g.zMainDbType = zLabel; |
| 774 | - if ( pWasAttached ) *pWasAttached = 0; | |
| 774 | + if( pWasAttached ) *pWasAttached = 0; | |
| 775 | 775 | }else{ |
| 776 | 776 | assert( g.zMainDbType!=0 ); |
| 777 | 777 | db_attach(zDbName, zLabel); |
| 778 | - if ( pWasAttached ) *pWasAttached = 1; | |
| 778 | + if( pWasAttached ) *pWasAttached = 1; | |
| 779 | 779 | } |
| 780 | 780 | } |
| 781 | 781 | |
| 782 | 782 | /* |
| 783 | 783 | ** Open the user database in "~/.fossil". Create the database anew if |
| @@ -791,13 +791,13 @@ | ||
| 791 | 791 | ** connection so that we can join between the various databases. In that |
| 792 | 792 | ** case, invoke this routine with useAttach as 1. |
| 793 | 793 | */ |
| 794 | 794 | void db_open_config(int useAttach){ |
| 795 | 795 | 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__) | |
| 799 | 799 | zHome = fossil_getenv("LOCALAPPDATA"); |
| 800 | 800 | if( zHome==0 ){ |
| 801 | 801 | zHome = fossil_getenv("APPDATA"); |
| 802 | 802 | if( zHome==0 ){ |
| 803 | 803 | char *zDrive = fossil_getenv("HOMEDRIVE"); |
| @@ -818,36 +818,37 @@ | ||
| 818 | 818 | } |
| 819 | 819 | #endif |
| 820 | 820 | if( file_isdir(zHome)!=1 ){ |
| 821 | 821 | fossil_fatal("invalid home directory: %s", zHome); |
| 822 | 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) | |
| 823 | +#if defined(_WIN32) || defined(__CYGWIN__) | |
| 830 | 824 | /* . filenames give some window systems problems and many apps problems */ |
| 831 | 825 | zDbName = mprintf("%//_fossil", zHome); |
| 832 | 826 | #else |
| 827 | + if( file_access(zHome, W_OK) ){ | |
| 828 | + fossil_fatal("home directory %s must be writeable", zHome); | |
| 829 | + } | |
| 833 | 830 | zDbName = mprintf("%s/.fossil", zHome); |
| 834 | 831 | #endif |
| 835 | 832 | if( file_size(zDbName)<1024*3 ){ |
| 836 | 833 | db_init_database(zDbName, zConfigSchema, (char*)0); |
| 837 | 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 | |
| 838 | 840 | if( useAttach ){ |
| 839 | 841 | db_open_or_attach(zDbName, "configdb", &g.useAttach); |
| 840 | 842 | g.dbConfig = 0; |
| 841 | 843 | g.zConfigDbType = 0; |
| 842 | 844 | }else{ |
| 843 | 845 | g.useAttach = 0; |
| 844 | 846 | g.dbConfig = db_open(zDbName); |
| 845 | 847 | g.zConfigDbType = "configdb"; |
| 846 | 848 | } |
| 847 | - g.configOpen = 1; | |
| 848 | - free(zDbName); | |
| 849 | + g.zConfigDbName = zDbName; | |
| 849 | 850 | } |
| 850 | 851 | |
| 851 | 852 | |
| 852 | 853 | /* |
| 853 | 854 | ** Returns TRUE if zTable exists in the local database but lacks column |
| @@ -882,10 +883,11 @@ | ||
| 882 | 883 | lsize = file_size(zDbName); |
| 883 | 884 | if( lsize%1024!=0 || lsize<4096 ) return 0; |
| 884 | 885 | db_open_or_attach(zDbName, "localdb", 0); |
| 885 | 886 | zVFileDef = db_text(0, "SELECT sql FROM %s.sqlite_master" |
| 886 | 887 | " WHERE name=='vfile'", db_name("localdb")); |
| 888 | + if( zVFileDef==0 ) return 0; | |
| 887 | 889 | |
| 888 | 890 | /* If the "isexe" column is missing from the vfile table, then |
| 889 | 891 | ** add it now. This code added on 2010-03-06. After all users have |
| 890 | 892 | ** upgraded, this code can be safely deleted. |
| 891 | 893 | */ |
| @@ -918,32 +920,31 @@ | ||
| 918 | 920 | ** that contains a valid repository database. |
| 919 | 921 | ** |
| 920 | 922 | ** For legacy, also look for ".fos". The use of ".fos" is deprecated |
| 921 | 923 | ** since "fos" has negative connotations in Hungarian, we are told. |
| 922 | 924 | ** |
| 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 | |
| 924 | 926 | ** try again. Once the file is found, the g.zLocalRoot variable is set |
| 925 | 927 | ** to the root of the repository tree and this routine returns 1. If |
| 926 | 928 | ** no database is found, then this routine return 0. |
| 927 | 929 | ** |
| 928 | 930 | ** 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 | |
| 930 | 932 | ** is found, it is attached to the open database connection too. |
| 931 | 933 | */ |
| 932 | 934 | int db_open_local(void){ |
| 933 | 935 | int i, n; |
| 934 | 936 | char zPwd[2000]; |
| 935 | - static const char *const aDbName[] = { "/_FOSSIL_", "/.fslckout", "/.fos" }; | |
| 937 | + static const char aDbName[][10] = { "_FOSSIL_", ".fslckout", ".fos" }; | |
| 936 | 938 | |
| 937 | 939 | if( g.localOpen) return 1; |
| 938 | 940 | file_getcwd(zPwd, sizeof(zPwd)-20); |
| 939 | 941 | n = strlen(zPwd); |
| 940 | 942 | if( n==1 && zPwd[0]=='/' ) zPwd[0] = '.'; |
| 941 | 943 | 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]); | |
| 945 | 946 | if( isValidLocalDb(zPwd) ){ |
| 946 | 947 | /* Found a valid checkout database file */ |
| 947 | 948 | zPwd[n] = 0; |
| 948 | 949 | while( n>1 && zPwd[n-1]=='/' ){ |
| 949 | 950 | n--; |
| @@ -1202,11 +1203,11 @@ | ||
| 1202 | 1203 | fossil_warning("unfinalized SQL statement: [%s]", sqlite3_sql(pStmt)); |
| 1203 | 1204 | } |
| 1204 | 1205 | } |
| 1205 | 1206 | g.repositoryOpen = 0; |
| 1206 | 1207 | g.localOpen = 0; |
| 1207 | - g.configOpen = 0; | |
| 1208 | + g.zConfigDbName = NULL; | |
| 1208 | 1209 | sqlite3_wal_checkpoint(g.db, 0); |
| 1209 | 1210 | sqlite3_close(g.db); |
| 1210 | 1211 | g.db = 0; |
| 1211 | 1212 | g.zMainDbType = 0; |
| 1212 | 1213 | if( g.dbConfig ){ |
| @@ -1262,17 +1263,17 @@ | ||
| 1262 | 1263 | "UPDATE user SET cap='s', pw=lower(hex(randomblob(3)))" |
| 1263 | 1264 | " WHERE login=%Q", zUser |
| 1264 | 1265 | ); |
| 1265 | 1266 | if( !setupUserOnly ){ |
| 1266 | 1267 | db_multi_exec( |
| 1267 | - "INSERT INTO user(login,pw,cap,info)" | |
| 1268 | + "INSERT OR IGNORE INTO user(login,pw,cap,info)" | |
| 1268 | 1269 | " 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)" | |
| 1270 | 1271 | " VALUES('nobody','','gjor','Nobody');" |
| 1271 | - "INSERT INTO user(login,pw,cap,info)" | |
| 1272 | + "INSERT OR IGNORE INTO user(login,pw,cap,info)" | |
| 1272 | 1273 | " VALUES('developer','','dei','Dev');" |
| 1273 | - "INSERT INTO user(login,pw,cap,info)" | |
| 1274 | + "INSERT OR IGNORE INTO user(login,pw,cap,info)" | |
| 1274 | 1275 | " VALUES('reader','','kptw','Reader');" |
| 1275 | 1276 | ); |
| 1276 | 1277 | } |
| 1277 | 1278 | } |
| 1278 | 1279 | |
| @@ -1626,19 +1627,19 @@ | ||
| 1626 | 1627 | ** Return true if the string zVal represents "true" (or "false"). |
| 1627 | 1628 | */ |
| 1628 | 1629 | int is_truth(const char *zVal){ |
| 1629 | 1630 | static const char *const azOn[] = { "on", "yes", "true", "1" }; |
| 1630 | 1631 | int i; |
| 1631 | - for(i=0; i<sizeof(azOn)/sizeof(azOn[0]); i++){ | |
| 1632 | + for(i=0; i<count(azOn); i++){ | |
| 1632 | 1633 | if( fossil_stricmp(zVal,azOn[i])==0 ) return 1; |
| 1633 | 1634 | } |
| 1634 | 1635 | return 0; |
| 1635 | 1636 | } |
| 1636 | 1637 | int is_false(const char *zVal){ |
| 1637 | 1638 | static const char *const azOff[] = { "off", "no", "false", "0" }; |
| 1638 | 1639 | int i; |
| 1639 | - for(i=0; i<sizeof(azOff)/sizeof(azOff[0]); i++){ | |
| 1640 | + for(i=0; i<count(azOff); i++){ | |
| 1640 | 1641 | if( fossil_stricmp(zVal,azOff[i])==0 ) return 1; |
| 1641 | 1642 | } |
| 1642 | 1643 | return 0; |
| 1643 | 1644 | } |
| 1644 | 1645 | |
| @@ -1765,17 +1766,18 @@ | ||
| 1765 | 1766 | } |
| 1766 | 1767 | } |
| 1767 | 1768 | if( g.repositoryOpen ){ |
| 1768 | 1769 | z = db_text(0, "SELECT value FROM config WHERE name=%Q", zName); |
| 1769 | 1770 | } |
| 1770 | - if( z==0 && g.configOpen ){ | |
| 1771 | + if( z==0 && g.zConfigDbName ){ | |
| 1771 | 1772 | db_swap_connections(); |
| 1772 | 1773 | z = db_text(0, "SELECT value FROM global_config WHERE name=%Q", zName); |
| 1773 | 1774 | db_swap_connections(); |
| 1774 | 1775 | } |
| 1775 | 1776 | 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 */ | |
| 1777 | 1779 | z = db_get_do_versionable(zName, z); |
| 1778 | 1780 | } |
| 1779 | 1781 | if( z==0 ){ |
| 1780 | 1782 | z = zDefault; |
| 1781 | 1783 | } |
| @@ -1811,11 +1813,11 @@ | ||
| 1811 | 1813 | } |
| 1812 | 1814 | db_end_transaction(0); |
| 1813 | 1815 | } |
| 1814 | 1816 | int db_is_global(const char *zName){ |
| 1815 | 1817 | int rc = 0; |
| 1816 | - if( g.configOpen ){ | |
| 1818 | + if( g.zConfigDbName ){ | |
| 1817 | 1819 | db_swap_connections(); |
| 1818 | 1820 | rc = db_exists("SELECT 1 FROM global_config WHERE name=%Q", zName); |
| 1819 | 1821 | db_swap_connections(); |
| 1820 | 1822 | } |
| 1821 | 1823 | return rc; |
| @@ -1832,11 +1834,11 @@ | ||
| 1832 | 1834 | } |
| 1833 | 1835 | db_finalize(&q); |
| 1834 | 1836 | }else{ |
| 1835 | 1837 | rc = SQLITE_DONE; |
| 1836 | 1838 | } |
| 1837 | - if( rc==SQLITE_DONE && g.configOpen ){ | |
| 1839 | + if( rc==SQLITE_DONE && g.zConfigDbName ){ | |
| 1838 | 1840 | db_swap_connections(); |
| 1839 | 1841 | v = db_int(dflt, "SELECT value FROM global_config WHERE name=%Q", zName); |
| 1840 | 1842 | db_swap_connections(); |
| 1841 | 1843 | } |
| 1842 | 1844 | return v; |
| @@ -1872,10 +1874,31 @@ | ||
| 1872 | 1874 | return db_int(dflt, "SELECT value FROM vvar WHERE name=%Q", zName); |
| 1873 | 1875 | } |
| 1874 | 1876 | void db_lset_int(const char *zName, int value){ |
| 1875 | 1877 | db_multi_exec("REPLACE INTO vvar(name,value) VALUES(%Q,%d)", zName, value); |
| 1876 | 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 | +} | |
| 1877 | 1900 | |
| 1878 | 1901 | /* |
| 1879 | 1902 | ** Record the name of a local repository in the global_config() database. |
| 1880 | 1903 | ** The repository filename %s is recorded as an entry with a "name" field |
| 1881 | 1904 | ** of the following form: |
| @@ -1958,16 +1981,20 @@ | ||
| 1958 | 1981 | if( !allowNested && db_open_local() ){ |
| 1959 | 1982 | fossil_panic("already within an open tree rooted at %s", g.zLocalRoot); |
| 1960 | 1983 | } |
| 1961 | 1984 | file_canonical_name(g.argv[2], &path, 0); |
| 1962 | 1985 | db_open_repository(blob_str(&path)); |
| 1963 | -#if defined(_WIN32) | |
| 1986 | +#if defined(_WIN32) || defined(__CYGWIN__) | |
| 1964 | 1987 | # define LOCALDB_NAME "./_FOSSIL_" |
| 1965 | 1988 | #else |
| 1966 | 1989 | # define LOCALDB_NAME "./.fslckout" |
| 1967 | 1990 | #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); | |
| 1969 | 1996 | db_delete_on_failure(LOCALDB_NAME); |
| 1970 | 1997 | db_open_local(); |
| 1971 | 1998 | db_lset("repository", g.argv[2]); |
| 1972 | 1999 | db_record_repository_filename(blob_str(&path)); |
| 1973 | 2000 | vid = db_int(0, "SELECT pid FROM plink y" |
| @@ -1996,11 +2023,14 @@ | ||
| 1996 | 2023 | } |
| 1997 | 2024 | |
| 1998 | 2025 | /* |
| 1999 | 2026 | ** Print the value of a setting named zName |
| 2000 | 2027 | */ |
| 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 | +){ | |
| 2002 | 2032 | Stmt q; |
| 2003 | 2033 | if( g.repositoryOpen ){ |
| 2004 | 2034 | db_prepare(&q, |
| 2005 | 2035 | "SELECT '(local)', value FROM config WHERE name=%Q" |
| 2006 | 2036 | " UNION ALL " |
| @@ -2021,13 +2051,15 @@ | ||
| 2021 | 2051 | } |
| 2022 | 2052 | if( ctrlSetting->versionable && localOpen ){ |
| 2023 | 2053 | /* Check to see if this is overridden by a versionable settings file */ |
| 2024 | 2054 | Blob versionedPathname; |
| 2025 | 2055 | 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); | |
| 2027 | 2058 | 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); | |
| 2029 | 2061 | } |
| 2030 | 2062 | } |
| 2031 | 2063 | db_finalize(&q); |
| 2032 | 2064 | } |
| 2033 | 2065 | |
| 2034 | 2066 |
| --- 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 |
M
src/db.c
+69
-37
| --- src/db.c | ||
| +++ src/db.c | ||
| @@ -221,11 +221,11 @@ | ||
| 221 | 221 | ** rolls back rather than commit. It is the responsibility of the |
| 222 | 222 | ** hooks themselves to issue any error messages. |
| 223 | 223 | */ |
| 224 | 224 | void db_commit_hook(int (*x)(void), int sequence){ |
| 225 | 225 | int i; |
| 226 | - assert( db.nCommitHook < sizeof(db.aHook)/sizeof(db.aHook[1]) ); | |
| 226 | + assert( db.nCommitHook < count(db.aHook) ); | |
| 227 | 227 | for(i=0; i<db.nCommitHook; i++){ |
| 228 | 228 | assert( x!=db.aHook[i].xHook ); |
| 229 | 229 | if( db.aHook[i].sequence>sequence ){ |
| 230 | 230 | int s = sequence; |
| 231 | 231 | int (*xS)(void) = x; |
| @@ -769,15 +769,15 @@ | ||
| 769 | 769 | ){ |
| 770 | 770 | if( !g.db ){ |
| 771 | 771 | assert( g.zMainDbType==0 ); |
| 772 | 772 | g.db = db_open(zDbName); |
| 773 | 773 | g.zMainDbType = zLabel; |
| 774 | - if ( pWasAttached ) *pWasAttached = 0; | |
| 774 | + if( pWasAttached ) *pWasAttached = 0; | |
| 775 | 775 | }else{ |
| 776 | 776 | assert( g.zMainDbType!=0 ); |
| 777 | 777 | db_attach(zDbName, zLabel); |
| 778 | - if ( pWasAttached ) *pWasAttached = 1; | |
| 778 | + if( pWasAttached ) *pWasAttached = 1; | |
| 779 | 779 | } |
| 780 | 780 | } |
| 781 | 781 | |
| 782 | 782 | /* |
| 783 | 783 | ** Open the user database in "~/.fossil". Create the database anew if |
| @@ -791,13 +791,13 @@ | ||
| 791 | 791 | ** connection so that we can join between the various databases. In that |
| 792 | 792 | ** case, invoke this routine with useAttach as 1. |
| 793 | 793 | */ |
| 794 | 794 | void db_open_config(int useAttach){ |
| 795 | 795 | 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__) | |
| 799 | 799 | zHome = fossil_getenv("LOCALAPPDATA"); |
| 800 | 800 | if( zHome==0 ){ |
| 801 | 801 | zHome = fossil_getenv("APPDATA"); |
| 802 | 802 | if( zHome==0 ){ |
| 803 | 803 | char *zDrive = fossil_getenv("HOMEDRIVE"); |
| @@ -818,36 +818,37 @@ | ||
| 818 | 818 | } |
| 819 | 819 | #endif |
| 820 | 820 | if( file_isdir(zHome)!=1 ){ |
| 821 | 821 | fossil_fatal("invalid home directory: %s", zHome); |
| 822 | 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) | |
| 823 | +#if defined(_WIN32) || defined(__CYGWIN__) | |
| 830 | 824 | /* . filenames give some window systems problems and many apps problems */ |
| 831 | 825 | zDbName = mprintf("%//_fossil", zHome); |
| 832 | 826 | #else |
| 827 | + if( file_access(zHome, W_OK) ){ | |
| 828 | + fossil_fatal("home directory %s must be writeable", zHome); | |
| 829 | + } | |
| 833 | 830 | zDbName = mprintf("%s/.fossil", zHome); |
| 834 | 831 | #endif |
| 835 | 832 | if( file_size(zDbName)<1024*3 ){ |
| 836 | 833 | db_init_database(zDbName, zConfigSchema, (char*)0); |
| 837 | 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 | |
| 838 | 840 | if( useAttach ){ |
| 839 | 841 | db_open_or_attach(zDbName, "configdb", &g.useAttach); |
| 840 | 842 | g.dbConfig = 0; |
| 841 | 843 | g.zConfigDbType = 0; |
| 842 | 844 | }else{ |
| 843 | 845 | g.useAttach = 0; |
| 844 | 846 | g.dbConfig = db_open(zDbName); |
| 845 | 847 | g.zConfigDbType = "configdb"; |
| 846 | 848 | } |
| 847 | - g.configOpen = 1; | |
| 848 | - free(zDbName); | |
| 849 | + g.zConfigDbName = zDbName; | |
| 849 | 850 | } |
| 850 | 851 | |
| 851 | 852 | |
| 852 | 853 | /* |
| 853 | 854 | ** Returns TRUE if zTable exists in the local database but lacks column |
| @@ -882,10 +883,11 @@ | ||
| 882 | 883 | lsize = file_size(zDbName); |
| 883 | 884 | if( lsize%1024!=0 || lsize<4096 ) return 0; |
| 884 | 885 | db_open_or_attach(zDbName, "localdb", 0); |
| 885 | 886 | zVFileDef = db_text(0, "SELECT sql FROM %s.sqlite_master" |
| 886 | 887 | " WHERE name=='vfile'", db_name("localdb")); |
| 888 | + if( zVFileDef==0 ) return 0; | |
| 887 | 889 | |
| 888 | 890 | /* If the "isexe" column is missing from the vfile table, then |
| 889 | 891 | ** add it now. This code added on 2010-03-06. After all users have |
| 890 | 892 | ** upgraded, this code can be safely deleted. |
| 891 | 893 | */ |
| @@ -918,32 +920,31 @@ | ||
| 918 | 920 | ** that contains a valid repository database. |
| 919 | 921 | ** |
| 920 | 922 | ** For legacy, also look for ".fos". The use of ".fos" is deprecated |
| 921 | 923 | ** since "fos" has negative connotations in Hungarian, we are told. |
| 922 | 924 | ** |
| 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 | |
| 924 | 926 | ** try again. Once the file is found, the g.zLocalRoot variable is set |
| 925 | 927 | ** to the root of the repository tree and this routine returns 1. If |
| 926 | 928 | ** no database is found, then this routine return 0. |
| 927 | 929 | ** |
| 928 | 930 | ** 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 | |
| 930 | 932 | ** is found, it is attached to the open database connection too. |
| 931 | 933 | */ |
| 932 | 934 | int db_open_local(void){ |
| 933 | 935 | int i, n; |
| 934 | 936 | char zPwd[2000]; |
| 935 | - static const char *const aDbName[] = { "/_FOSSIL_", "/.fslckout", "/.fos" }; | |
| 937 | + static const char aDbName[][10] = { "_FOSSIL_", ".fslckout", ".fos" }; | |
| 936 | 938 | |
| 937 | 939 | if( g.localOpen) return 1; |
| 938 | 940 | file_getcwd(zPwd, sizeof(zPwd)-20); |
| 939 | 941 | n = strlen(zPwd); |
| 940 | 942 | if( n==1 && zPwd[0]=='/' ) zPwd[0] = '.'; |
| 941 | 943 | 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]); | |
| 945 | 946 | if( isValidLocalDb(zPwd) ){ |
| 946 | 947 | /* Found a valid checkout database file */ |
| 947 | 948 | zPwd[n] = 0; |
| 948 | 949 | while( n>1 && zPwd[n-1]=='/' ){ |
| 949 | 950 | n--; |
| @@ -1202,11 +1203,11 @@ | ||
| 1202 | 1203 | fossil_warning("unfinalized SQL statement: [%s]", sqlite3_sql(pStmt)); |
| 1203 | 1204 | } |
| 1204 | 1205 | } |
| 1205 | 1206 | g.repositoryOpen = 0; |
| 1206 | 1207 | g.localOpen = 0; |
| 1207 | - g.configOpen = 0; | |
| 1208 | + g.zConfigDbName = NULL; | |
| 1208 | 1209 | sqlite3_wal_checkpoint(g.db, 0); |
| 1209 | 1210 | sqlite3_close(g.db); |
| 1210 | 1211 | g.db = 0; |
| 1211 | 1212 | g.zMainDbType = 0; |
| 1212 | 1213 | if( g.dbConfig ){ |
| @@ -1262,17 +1263,17 @@ | ||
| 1262 | 1263 | "UPDATE user SET cap='s', pw=lower(hex(randomblob(3)))" |
| 1263 | 1264 | " WHERE login=%Q", zUser |
| 1264 | 1265 | ); |
| 1265 | 1266 | if( !setupUserOnly ){ |
| 1266 | 1267 | db_multi_exec( |
| 1267 | - "INSERT INTO user(login,pw,cap,info)" | |
| 1268 | + "INSERT OR IGNORE INTO user(login,pw,cap,info)" | |
| 1268 | 1269 | " 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)" | |
| 1270 | 1271 | " VALUES('nobody','','gjor','Nobody');" |
| 1271 | - "INSERT INTO user(login,pw,cap,info)" | |
| 1272 | + "INSERT OR IGNORE INTO user(login,pw,cap,info)" | |
| 1272 | 1273 | " VALUES('developer','','dei','Dev');" |
| 1273 | - "INSERT INTO user(login,pw,cap,info)" | |
| 1274 | + "INSERT OR IGNORE INTO user(login,pw,cap,info)" | |
| 1274 | 1275 | " VALUES('reader','','kptw','Reader');" |
| 1275 | 1276 | ); |
| 1276 | 1277 | } |
| 1277 | 1278 | } |
| 1278 | 1279 | |
| @@ -1626,19 +1627,19 @@ | ||
| 1626 | 1627 | ** Return true if the string zVal represents "true" (or "false"). |
| 1627 | 1628 | */ |
| 1628 | 1629 | int is_truth(const char *zVal){ |
| 1629 | 1630 | static const char *const azOn[] = { "on", "yes", "true", "1" }; |
| 1630 | 1631 | int i; |
| 1631 | - for(i=0; i<sizeof(azOn)/sizeof(azOn[0]); i++){ | |
| 1632 | + for(i=0; i<count(azOn); i++){ | |
| 1632 | 1633 | if( fossil_stricmp(zVal,azOn[i])==0 ) return 1; |
| 1633 | 1634 | } |
| 1634 | 1635 | return 0; |
| 1635 | 1636 | } |
| 1636 | 1637 | int is_false(const char *zVal){ |
| 1637 | 1638 | static const char *const azOff[] = { "off", "no", "false", "0" }; |
| 1638 | 1639 | int i; |
| 1639 | - for(i=0; i<sizeof(azOff)/sizeof(azOff[0]); i++){ | |
| 1640 | + for(i=0; i<count(azOff); i++){ | |
| 1640 | 1641 | if( fossil_stricmp(zVal,azOff[i])==0 ) return 1; |
| 1641 | 1642 | } |
| 1642 | 1643 | return 0; |
| 1643 | 1644 | } |
| 1644 | 1645 | |
| @@ -1765,17 +1766,18 @@ | ||
| 1765 | 1766 | } |
| 1766 | 1767 | } |
| 1767 | 1768 | if( g.repositoryOpen ){ |
| 1768 | 1769 | z = db_text(0, "SELECT value FROM config WHERE name=%Q", zName); |
| 1769 | 1770 | } |
| 1770 | - if( z==0 && g.configOpen ){ | |
| 1771 | + if( z==0 && g.zConfigDbName ){ | |
| 1771 | 1772 | db_swap_connections(); |
| 1772 | 1773 | z = db_text(0, "SELECT value FROM global_config WHERE name=%Q", zName); |
| 1773 | 1774 | db_swap_connections(); |
| 1774 | 1775 | } |
| 1775 | 1776 | 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 */ | |
| 1777 | 1779 | z = db_get_do_versionable(zName, z); |
| 1778 | 1780 | } |
| 1779 | 1781 | if( z==0 ){ |
| 1780 | 1782 | z = zDefault; |
| 1781 | 1783 | } |
| @@ -1811,11 +1813,11 @@ | ||
| 1811 | 1813 | } |
| 1812 | 1814 | db_end_transaction(0); |
| 1813 | 1815 | } |
| 1814 | 1816 | int db_is_global(const char *zName){ |
| 1815 | 1817 | int rc = 0; |
| 1816 | - if( g.configOpen ){ | |
| 1818 | + if( g.zConfigDbName ){ | |
| 1817 | 1819 | db_swap_connections(); |
| 1818 | 1820 | rc = db_exists("SELECT 1 FROM global_config WHERE name=%Q", zName); |
| 1819 | 1821 | db_swap_connections(); |
| 1820 | 1822 | } |
| 1821 | 1823 | return rc; |
| @@ -1832,11 +1834,11 @@ | ||
| 1832 | 1834 | } |
| 1833 | 1835 | db_finalize(&q); |
| 1834 | 1836 | }else{ |
| 1835 | 1837 | rc = SQLITE_DONE; |
| 1836 | 1838 | } |
| 1837 | - if( rc==SQLITE_DONE && g.configOpen ){ | |
| 1839 | + if( rc==SQLITE_DONE && g.zConfigDbName ){ | |
| 1838 | 1840 | db_swap_connections(); |
| 1839 | 1841 | v = db_int(dflt, "SELECT value FROM global_config WHERE name=%Q", zName); |
| 1840 | 1842 | db_swap_connections(); |
| 1841 | 1843 | } |
| 1842 | 1844 | return v; |
| @@ -1872,10 +1874,31 @@ | ||
| 1872 | 1874 | return db_int(dflt, "SELECT value FROM vvar WHERE name=%Q", zName); |
| 1873 | 1875 | } |
| 1874 | 1876 | void db_lset_int(const char *zName, int value){ |
| 1875 | 1877 | db_multi_exec("REPLACE INTO vvar(name,value) VALUES(%Q,%d)", zName, value); |
| 1876 | 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 | +} | |
| 1877 | 1900 | |
| 1878 | 1901 | /* |
| 1879 | 1902 | ** Record the name of a local repository in the global_config() database. |
| 1880 | 1903 | ** The repository filename %s is recorded as an entry with a "name" field |
| 1881 | 1904 | ** of the following form: |
| @@ -1958,16 +1981,20 @@ | ||
| 1958 | 1981 | if( !allowNested && db_open_local() ){ |
| 1959 | 1982 | fossil_panic("already within an open tree rooted at %s", g.zLocalRoot); |
| 1960 | 1983 | } |
| 1961 | 1984 | file_canonical_name(g.argv[2], &path, 0); |
| 1962 | 1985 | db_open_repository(blob_str(&path)); |
| 1963 | -#if defined(_WIN32) | |
| 1986 | +#if defined(_WIN32) || defined(__CYGWIN__) | |
| 1964 | 1987 | # define LOCALDB_NAME "./_FOSSIL_" |
| 1965 | 1988 | #else |
| 1966 | 1989 | # define LOCALDB_NAME "./.fslckout" |
| 1967 | 1990 | #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); | |
| 1969 | 1996 | db_delete_on_failure(LOCALDB_NAME); |
| 1970 | 1997 | db_open_local(); |
| 1971 | 1998 | db_lset("repository", g.argv[2]); |
| 1972 | 1999 | db_record_repository_filename(blob_str(&path)); |
| 1973 | 2000 | vid = db_int(0, "SELECT pid FROM plink y" |
| @@ -1996,11 +2023,14 @@ | ||
| 1996 | 2023 | } |
| 1997 | 2024 | |
| 1998 | 2025 | /* |
| 1999 | 2026 | ** Print the value of a setting named zName |
| 2000 | 2027 | */ |
| 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 | +){ | |
| 2002 | 2032 | Stmt q; |
| 2003 | 2033 | if( g.repositoryOpen ){ |
| 2004 | 2034 | db_prepare(&q, |
| 2005 | 2035 | "SELECT '(local)', value FROM config WHERE name=%Q" |
| 2006 | 2036 | " UNION ALL " |
| @@ -2021,13 +2051,15 @@ | ||
| 2021 | 2051 | } |
| 2022 | 2052 | if( ctrlSetting->versionable && localOpen ){ |
| 2023 | 2053 | /* Check to see if this is overridden by a versionable settings file */ |
| 2024 | 2054 | Blob versionedPathname; |
| 2025 | 2055 | 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); | |
| 2027 | 2058 | 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); | |
| 2029 | 2061 | } |
| 2030 | 2062 | } |
| 2031 | 2063 | db_finalize(&q); |
| 2032 | 2064 | } |
| 2033 | 2065 | |
| 2034 | 2066 |
| --- 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 @@ | ||
| 39 | 39 | #define DIFF_LINENO ((u64)0x20000000) /* Show line numbers */ |
| 40 | 40 | #define DIFF_WS_WARNING ((u64)0x40000000) /* Warn about whitespace */ |
| 41 | 41 | #define DIFF_NOOPT (((u64)0x01)<<32) /* Suppress optimizations (debug) */ |
| 42 | 42 | #define DIFF_INVERT (((u64)0x02)<<32) /* Invert the diff (debug) */ |
| 43 | 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 */ | |
| 44 | 45 | |
| 45 | 46 | /* |
| 46 | 47 | ** These error messages are shared in multiple locations. They are defined |
| 47 | 48 | ** here for consistency. |
| 48 | 49 | */ |
| @@ -50,11 +51,35 @@ | ||
| 50 | 51 | "cannot compute difference between binary files\n" |
| 51 | 52 | |
| 52 | 53 | #define DIFF_CANNOT_COMPUTE_SYMLINK \ |
| 53 | 54 | "cannot compute difference between symlink and regular file\n" |
| 54 | 55 | |
| 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. */ | |
| 56 | 81 | #endif /* INTERFACE */ |
| 57 | 82 | |
| 58 | 83 | /* |
| 59 | 84 | ** Maximum length of a line in a text file, in bytes. (2**13 = 8192 bytes) |
| 60 | 85 | */ |
| @@ -180,63 +205,73 @@ | ||
| 180 | 205 | /* |
| 181 | 206 | ** This function attempts to scan each logical line within the blob to |
| 182 | 207 | ** determine the type of content it appears to contain. Possible return |
| 183 | 208 | ** values are: |
| 184 | 209 | ** |
| 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. | |
| 188 | 212 | ** |
| 189 | 213 | ** (0) -- The content appears to be binary because it contains embedded |
| 190 | 214 | ** NUL characters or an extremely long line. Since this function |
| 191 | 215 | ** does not understand UTF-16, it may falsely consider UTF-16 text |
| 192 | 216 | ** to be binary. |
| 193 | 217 | ** |
| 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 | 218 | ************************************ WARNING ********************************** |
| 199 | 219 | ** |
| 200 | 220 | ** This function does not validate that the blob content is properly formed |
| 201 | 221 | ** UTF-8. It assumes that all code points are the same size. It does not |
| 202 | 222 | ** validate any code points. It makes no attempt to detect if any [invalid] |
| 203 | 223 | ** switches between UTF-8 and other encodings occur. |
| 204 | 224 | ** |
| 205 | 225 | ** The only code points that this function cares about are the NUL character, |
| 206 | 226 | ** carriage-return, and line-feed. |
| 227 | +** | |
| 228 | +** Whether or not this function examines the entire contents of the blob is | |
| 229 | +** officially unspecified. | |
| 207 | 230 | ** |
| 208 | 231 | ************************************ WARNING ********************************** |
| 209 | 232 | */ |
| 210 | -int looks_like_utf8(const Blob *pContent){ | |
| 233 | +int looks_like_utf8(const Blob *pContent, int *pFlags){ | |
| 211 | 234 | const char *z = blob_buffer(pContent); |
| 212 | 235 | 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 */ | |
| 215 | 237 | |
| 216 | - /* Check individual lines. | |
| 217 | - */ | |
| 238 | + if( pFlags ) *pFlags = LOOK_NONE; | |
| 218 | 239 | if( n==0 ) return result; /* Empty file -> text */ |
| 219 | 240 | 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 */ | |
| 238 | 273 | } |
| 239 | 274 | return result; /* No problems seen -> not binary */ |
| 240 | 275 | } |
| 241 | 276 | |
| 242 | 277 | /* |
| @@ -270,64 +305,80 @@ | ||
| 270 | 305 | /* |
| 271 | 306 | ** This function attempts to scan each logical line within the blob to |
| 272 | 307 | ** determine the type of content it appears to contain. Possible return |
| 273 | 308 | ** values are: |
| 274 | 309 | ** |
| 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. | |
| 278 | 312 | ** |
| 279 | 313 | ** (0) -- The content appears to be binary because it contains embedded |
| 280 | 314 | ** NUL characters or an extremely long line. Since this function |
| 281 | 315 | ** does not understand UTF-8, it may falsely consider UTF-8 text |
| 282 | 316 | ** to be binary. |
| 283 | 317 | ** |
| 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 | 318 | ************************************ WARNING ********************************** |
| 289 | 319 | ** |
| 290 | 320 | ** This function does not validate that the blob content is properly formed |
| 291 | 321 | ** UTF-16. It assumes that all code points are the same size. It does not |
| 292 | 322 | ** validate any code points. It makes no attempt to detect if any [invalid] |
| 293 | 323 | ** switches between the UTF-16be and UTF-16le encodings occur. |
| 294 | 324 | ** |
| 295 | 325 | ** The only code points that this function cares about are the NUL character, |
| 296 | 326 | ** carriage-return, and line-feed. |
| 327 | +** | |
| 328 | +** Whether or not this function examines the entire contents of the blob is | |
| 329 | +** officially unspecified. | |
| 297 | 330 | ** |
| 298 | 331 | ************************************ WARNING ********************************** |
| 299 | 332 | */ |
| 300 | -int looks_like_utf16(const Blob *pContent){ | |
| 333 | +int looks_like_utf16(const Blob *pContent, int *pFlags){ | |
| 301 | 334 | const WCHAR_T *z = (WCHAR_T *)blob_buffer(pContent); |
| 302 | 335 | 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 */ | |
| 329 | 380 | } |
| 330 | 381 | return result; /* No problems seen -> not binary */ |
| 331 | 382 | } |
| 332 | 383 | |
| 333 | 384 | /* |
| @@ -355,26 +406,36 @@ | ||
| 355 | 406 | if( blob_size(pContent)<bomSize ) return 0; |
| 356 | 407 | return memcmp(z, bom, bomSize)==0; |
| 357 | 408 | } |
| 358 | 409 | |
| 359 | 410 | /* |
| 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. | |
| 362 | 416 | */ |
| 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. */ | |
| 376 | 437 | } |
| 377 | 438 | |
| 378 | 439 | /* |
| 379 | 440 | ** Return true if two DLine elements are identical. |
| 380 | 441 | */ |
| @@ -516,11 +577,11 @@ | ||
| 516 | 577 | a = xa; |
| 517 | 578 | b = xb; |
| 518 | 579 | continue; |
| 519 | 580 | } |
| 520 | 581 | } |
| 521 | - | |
| 582 | + | |
| 522 | 583 | /* For the current block comprising nr triples, figure out |
| 523 | 584 | ** how many lines of A and B are to be displayed |
| 524 | 585 | */ |
| 525 | 586 | if( R[r]>nContext ){ |
| 526 | 587 | na = nb = nContext; |
| @@ -871,21 +932,33 @@ | ||
| 871 | 932 | /* |
| 872 | 933 | ** Simplify iStart and iStart2: |
| 873 | 934 | ** |
| 874 | 935 | ** * If iStart is a null-change then move iStart2 into iStart |
| 875 | 936 | ** * Make sure any null-changes are in canonoical form. |
| 937 | +** * Make sure all changes are at character boundaries for | |
| 938 | +** multi-byte characters. | |
| 876 | 939 | */ |
| 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 | + } | |
| 879 | 947 | if( p->iStart==p->iEnd ){ |
| 880 | 948 | p->iStart = p->iStart2; |
| 881 | 949 | p->iEnd = p->iEnd2; |
| 882 | 950 | p->zStart = p->zStart2; |
| 883 | 951 | p->iStart2 = 0; |
| 884 | 952 | p->iEnd2 = 0; |
| 885 | 953 | } |
| 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 | + } | |
| 887 | 960 | } |
| 888 | 961 | |
| 889 | 962 | /* |
| 890 | 963 | ** Write out lines that have been edited. Adjust the highlight to cover |
| 891 | 964 | ** only those parts of the line that actually changed. |
| @@ -897,10 +970,11 @@ | ||
| 897 | 970 | DLine *pRight, /* Right line of the change */ |
| 898 | 971 | int lnRight /* Line number of the right line */ |
| 899 | 972 | ){ |
| 900 | 973 | int nLeft; /* Length of left line in bytes */ |
| 901 | 974 | int nRight; /* Length of right line in bytes */ |
| 975 | + int nShort; /* Shortest of left and right */ | |
| 902 | 976 | int nPrefix; /* Length of common prefix */ |
| 903 | 977 | int nSuffix; /* Length of common suffix */ |
| 904 | 978 | const char *zLeft; /* Text of the left line */ |
| 905 | 979 | const char *zRight; /* Text of the right line */ |
| 906 | 980 | int nLeftDiff; /* nLeft - nPrefix - nSuffix */ |
| @@ -912,25 +986,31 @@ | ||
| 912 | 986 | |
| 913 | 987 | nLeft = pLeft->h & LENGTH_MASK; |
| 914 | 988 | zLeft = pLeft->z; |
| 915 | 989 | nRight = pRight->h & LENGTH_MASK; |
| 916 | 990 | zRight = pRight->z; |
| 991 | + nShort = nLeft<nRight ? nLeft : nRight; | |
| 917 | 992 | |
| 918 | 993 | nPrefix = 0; |
| 919 | - while( nPrefix<nLeft && nPrefix<nRight && zLeft[nPrefix]==zRight[nPrefix] ){ | |
| 994 | + while( nPrefix<nShort && zLeft[nPrefix]==zRight[nPrefix] ){ | |
| 920 | 995 | nPrefix++; |
| 921 | 996 | } |
| 997 | + if( nPrefix<nShort ){ | |
| 998 | + while( nPrefix>0 && (zLeft[nPrefix]&0xc0)==0x80 ) nPrefix--; | |
| 999 | + } | |
| 922 | 1000 | 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] ){ | |
| 926 | 1003 | nSuffix++; |
| 927 | 1004 | } |
| 1005 | + if( nSuffix<nShort ){ | |
| 1006 | + while( nSuffix>0 && (zLeft[nLeft-nSuffix]&0xc0)==0x80 ) nSuffix--; | |
| 1007 | + } | |
| 928 | 1008 | if( nSuffix==nLeft || nSuffix==nRight ) nPrefix = 0; |
| 929 | 1009 | } |
| 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 | + | |
| 932 | 1012 | |
| 933 | 1013 | /* A single chunk of text inserted on the right */ |
| 934 | 1014 | if( nPrefix+nSuffix==nLeft ){ |
| 935 | 1015 | sbsWriteLineno(p, lnLeft); |
| 936 | 1016 | p->iStart2 = p->iEnd2 = 0; |
| @@ -986,11 +1066,11 @@ | ||
| 986 | 1066 | p->zStart = zClassChng; |
| 987 | 1067 | } |
| 988 | 1068 | p->iStart2 = nPrefix + aLCS[1]; |
| 989 | 1069 | p->iEnd2 = nLeft - nSuffix; |
| 990 | 1070 | p->zStart2 = aLCS[3]==nRightDiff ? zClassRm : zClassChng; |
| 991 | - sbsSimplifyLine(p); | |
| 1071 | + sbsSimplifyLine(p, zLeft+nPrefix); | |
| 992 | 1072 | sbsWriteText(p, pLeft, SBS_PAD); |
| 993 | 1073 | sbsWrite(p, " | ", 3); |
| 994 | 1074 | sbsWriteLineno(p, lnRight); |
| 995 | 1075 | p->iStart = nPrefix; |
| 996 | 1076 | p->iEnd = nPrefix + aLCS[2]; |
| @@ -1001,11 +1081,11 @@ | ||
| 1001 | 1081 | p->zStart = zClassChng; |
| 1002 | 1082 | } |
| 1003 | 1083 | p->iStart2 = nPrefix + aLCS[3]; |
| 1004 | 1084 | p->iEnd2 = nRight - nSuffix; |
| 1005 | 1085 | p->zStart2 = aLCS[1]==nLeftDiff ? zClassAdd : zClassChng; |
| 1006 | - sbsSimplifyLine(p); | |
| 1086 | + sbsSimplifyLine(p, zRight+nPrefix); | |
| 1007 | 1087 | sbsWriteText(p, pRight, SBS_NEWLINE); |
| 1008 | 1088 | return; |
| 1009 | 1089 | } |
| 1010 | 1090 | |
| 1011 | 1091 | /* If all else fails, show a single big change between left and right */ |
| @@ -1220,11 +1300,11 @@ | ||
| 1220 | 1300 | ** Then this is probably an alignment that will be difficult for humans |
| 1221 | 1301 | ** to read. So instead, just show all of the right side inserted followed |
| 1222 | 1302 | ** by all of the left side deleted. |
| 1223 | 1303 | ** |
| 1224 | 1304 | ** The coefficients for conditions (1) and (2) above are determined by |
| 1225 | - ** experimentation. | |
| 1305 | + ** experimentation. | |
| 1226 | 1306 | */ |
| 1227 | 1307 | mxLen = nLeft>nRight ? nLeft : nRight; |
| 1228 | 1308 | if( i*4>mxLen*5 && (nMatch==0 || iMatch/nMatch>15) ){ |
| 1229 | 1309 | memset(aM, 4, mnLen); |
| 1230 | 1310 | if( nLeft>mnLen ) memset(aM+mnLen, 1, nLeft-mnLen); |
| @@ -1406,11 +1486,11 @@ | ||
| 1406 | 1486 | /* Delete one line from the left */ |
| 1407 | 1487 | s.n = 0; |
| 1408 | 1488 | sbsWriteLineno(&s, a); |
| 1409 | 1489 | s.iStart = 0; |
| 1410 | 1490 | s.zStart = "<span class=\"diffrm\">"; |
| 1411 | - s.iEnd = s.width; | |
| 1491 | + s.iEnd = LENGTH(&A[a]); | |
| 1412 | 1492 | sbsWriteText(&s, &A[a], SBS_PAD); |
| 1413 | 1493 | if( s.escHtml ){ |
| 1414 | 1494 | sbsWrite(&s, " <\n", 6); |
| 1415 | 1495 | }else{ |
| 1416 | 1496 | sbsWrite(&s, " <\n", 3); |
| @@ -1439,11 +1519,11 @@ | ||
| 1439 | 1519 | sbsWrite(&s, " > ", 3); |
| 1440 | 1520 | } |
| 1441 | 1521 | sbsWriteLineno(&s, b); |
| 1442 | 1522 | s.iStart = 0; |
| 1443 | 1523 | s.zStart = "<span class=\"diffadd\">"; |
| 1444 | - s.iEnd = s.width; | |
| 1524 | + s.iEnd = LENGTH(&B[b]); | |
| 1445 | 1525 | sbsWriteText(&s, &B[b], SBS_NEWLINE); |
| 1446 | 1526 | blob_append(pOut, s.zLine, s.n); |
| 1447 | 1527 | assert( mb>0 ); |
| 1448 | 1528 | mb--; |
| 1449 | 1529 | b++; |
| @@ -1451,25 +1531,25 @@ | ||
| 1451 | 1531 | /* Delete from the left and insert on the right */ |
| 1452 | 1532 | s.n = 0; |
| 1453 | 1533 | sbsWriteLineno(&s, a); |
| 1454 | 1534 | s.iStart = 0; |
| 1455 | 1535 | s.zStart = "<span class=\"diffrm\">"; |
| 1456 | - s.iEnd = s.width; | |
| 1536 | + s.iEnd = LENGTH(&A[a]); | |
| 1457 | 1537 | sbsWriteText(&s, &A[a], SBS_PAD); |
| 1458 | 1538 | sbsWrite(&s, " | ", 3); |
| 1459 | 1539 | sbsWriteLineno(&s, b); |
| 1460 | 1540 | s.iStart = 0; |
| 1461 | 1541 | s.zStart = "<span class=\"diffadd\">"; |
| 1462 | - s.iEnd = s.width; | |
| 1542 | + s.iEnd = LENGTH(&B[b]); | |
| 1463 | 1543 | sbsWriteText(&s, &B[b], SBS_NEWLINE); |
| 1464 | 1544 | blob_append(pOut, s.zLine, s.n); |
| 1465 | 1545 | ma--; |
| 1466 | 1546 | mb--; |
| 1467 | 1547 | a++; |
| 1468 | 1548 | b++; |
| 1469 | 1549 | } |
| 1470 | - | |
| 1550 | + | |
| 1471 | 1551 | } |
| 1472 | 1552 | fossil_free(alignment); |
| 1473 | 1553 | if( i<nr-1 ){ |
| 1474 | 1554 | m = R[r+i*3+3]; |
| 1475 | 1555 | for(j=0; j<m; j++){ |
| @@ -1954,11 +2034,30 @@ | ||
| 1954 | 2034 | return 0; |
| 1955 | 2035 | } |
| 1956 | 2036 | |
| 1957 | 2037 | /* Compute the difference */ |
| 1958 | 2038 | 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 | + } | |
| 1960 | 2059 | |
| 1961 | 2060 | if( pOut ){ |
| 1962 | 2061 | /* Compute a context or side-by-side diff into pOut */ |
| 1963 | 2062 | if( diffFlags & DIFF_SIDEBYSIDE ){ |
| 1964 | 2063 | sbsDiff(&c, pOut, pRe, diffFlags); |
| @@ -2205,11 +2304,12 @@ | ||
| 2205 | 2304 | fossil_print("%10s: %.*s\n", zSrc, x.aOrig[i].n, x.aOrig[i].z); |
| 2206 | 2305 | } |
| 2207 | 2306 | } |
| 2208 | 2307 | |
| 2209 | 2308 | /* 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 */ | |
| 2211 | 2311 | |
| 2212 | 2312 | /* |
| 2213 | 2313 | ** Compute a complete annotation on a file. The file is identified |
| 2214 | 2314 | ** by its filename number (filename.fnid) and the baseline in which |
| 2215 | 2315 | ** it was checked in (mlink.mid). |
| @@ -2243,11 +2343,11 @@ | ||
| 2243 | 2343 | if( !content_get(rid, &toAnnotate) ){ |
| 2244 | 2344 | fossil_panic("unable to retrieve content of artifact #%d", rid); |
| 2245 | 2345 | } |
| 2246 | 2346 | if( iLimit<=0 ) iLimit = 1000000000; |
| 2247 | 2347 | annotation_start(p, &toAnnotate); |
| 2248 | - | |
| 2348 | + | |
| 2249 | 2349 | db_prepare(&q, |
| 2250 | 2350 | "SELECT (SELECT uuid FROM blob WHERE rid=mlink.%s)," |
| 2251 | 2351 | " (SELECT uuid FROM blob WHERE rid=mlink.fid)," |
| 2252 | 2352 | " (SELECT uuid FROM blob WHERE rid=mlink.pid)," |
| 2253 | 2353 | " date(event.mtime)," |
| @@ -2254,14 +2354,16 @@ | ||
| 2254 | 2354 | " coalesce(event.euser,event.user)," |
| 2255 | 2355 | " mlink.pid" |
| 2256 | 2356 | " FROM mlink, event" |
| 2257 | 2357 | " WHERE mlink.fid=:rid" |
| 2258 | 2358 | " 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,":"" | |
| 2261 | 2363 | ); |
| 2262 | - | |
| 2364 | + | |
| 2263 | 2365 | db_bind_int(&q, ":rid", rid); |
| 2264 | 2366 | if( iLimit==0 ) iLimit = 1000000000; |
| 2265 | 2367 | while( rid && iLimit>cnt && db_step(&q)==SQLITE_ROW ){ |
| 2266 | 2368 | const char *zUuid = db_column_text(&q, 0); |
| 2267 | 2369 | const char *zUuidFile = db_column_text(&q, 1); |
| @@ -2313,11 +2415,11 @@ | ||
| 2313 | 2415 | void annotation_page(void){ |
| 2314 | 2416 | int mid; |
| 2315 | 2417 | int fnid; |
| 2316 | 2418 | int i; |
| 2317 | 2419 | int iLimit; |
| 2318 | - int annFlags = 0; | |
| 2420 | + int annFlags = ANN_FILE_ANCEST; | |
| 2319 | 2421 | int showLn = 0; /* True if line numbers should be shown */ |
| 2320 | 2422 | char zLn[10]; /* Line number buffer */ |
| 2321 | 2423 | char zFormat[10]; /* Format string for line numbers */ |
| 2322 | 2424 | Annotator ann; |
| 2323 | 2425 | |
| @@ -2329,10 +2431,11 @@ | ||
| 2329 | 2431 | if( mid==0 || fnid==0 ){ fossil_redirect_home(); } |
| 2330 | 2432 | iLimit = atoi(PD("limit","-1")); |
| 2331 | 2433 | if( !db_exists("SELECT 1 FROM mlink WHERE mid=%d AND fnid=%d",mid,fnid) ){ |
| 2332 | 2434 | fossil_redirect_home(); |
| 2333 | 2435 | } |
| 2436 | + compute_direct_ancestors(mid, 10000000); | |
| 2334 | 2437 | style_header("File Annotation"); |
| 2335 | 2438 | if( P("filevers") ) annFlags |= ANN_FILE_VERS; |
| 2336 | 2439 | annotate_file(&ann, P("filename"), fnid, mid, g.perm.Hyperlink, iLimit, annFlags); |
| 2337 | 2440 | if( P("log") ){ |
| 2338 | 2441 | int i; |
| @@ -2395,11 +2498,11 @@ | ||
| 2395 | 2498 | if( zLimit==0 || zLimit[0]==0 ) zLimit = "-1"; |
| 2396 | 2499 | iLimit = atoi(zLimit); |
| 2397 | 2500 | showLog = find_option("log",0,0)!=0; |
| 2398 | 2501 | fileVers = find_option("filevers",0,0)!=0; |
| 2399 | 2502 | db_must_be_within_tree(); |
| 2400 | - if (g.argc<3) { | |
| 2503 | + if( g.argc<3 ) { | |
| 2401 | 2504 | usage("FILENAME"); |
| 2402 | 2505 | } |
| 2403 | 2506 | file_tree_name(g.argv[2], &treename, 1); |
| 2404 | 2507 | zFilename = blob_str(&treename); |
| 2405 | 2508 | fnid = db_int(0, "SELECT fnid FROM filename WHERE name=%Q", zFilename); |
| @@ -2409,11 +2512,11 @@ | ||
| 2409 | 2512 | fid = db_int(0, "SELECT rid FROM vfile WHERE pathname=%Q", zFilename); |
| 2410 | 2513 | if( fid==0 ){ |
| 2411 | 2514 | fossil_fatal("not part of current checkout: %s", zFilename); |
| 2412 | 2515 | } |
| 2413 | 2516 | cid = db_lget_int("checkout", 0); |
| 2414 | - if (cid == 0){ | |
| 2517 | + if( cid == 0 ){ | |
| 2415 | 2518 | fossil_fatal("Not in a checkout"); |
| 2416 | 2519 | } |
| 2417 | 2520 | if( iLimit<=0 ) iLimit = 1000000000; |
| 2418 | 2521 | compute_direct_ancestors(cid, iLimit); |
| 2419 | 2522 | mid = db_int(0, "SELECT mlink.mid FROM mlink, ancestor " |
| @@ -2422,10 +2525,11 @@ | ||
| 2422 | 2525 | fid, fnid); |
| 2423 | 2526 | if( mid==0 ){ |
| 2424 | 2527 | fossil_panic("unable to find manifest"); |
| 2425 | 2528 | } |
| 2426 | 2529 | if( fileVers ) annFlags |= ANN_FILE_VERS; |
| 2530 | + annFlags |= ANN_FILE_ANCEST; | |
| 2427 | 2531 | annotate_file(&ann, zFilename, fnid, mid, 0, iLimit, annFlags); |
| 2428 | 2532 | if( showLog ){ |
| 2429 | 2533 | for(i=0; i<ann.nVers; i++){ |
| 2430 | 2534 | printf("version %3d: %s\n", i+1, ann.azVers[i]); |
| 2431 | 2535 | } |
| @@ -2434,5 +2538,42 @@ | ||
| 2434 | 2538 | for(i=0; i<ann.nOrig; i++){ |
| 2435 | 2539 | fossil_print("%s: %.*s\n", |
| 2436 | 2540 | ann.aOrig[i].zSrc, ann.aOrig[i].n, ann.aOrig[i].z); |
| 2437 | 2541 | } |
| 2438 | 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 | +} | |
| 2439 | 2580 |
| --- 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, " <\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, " <\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 @@ | ||
| 39 | 39 | #define DIFF_LINENO ((u64)0x20000000) /* Show line numbers */ |
| 40 | 40 | #define DIFF_WS_WARNING ((u64)0x40000000) /* Warn about whitespace */ |
| 41 | 41 | #define DIFF_NOOPT (((u64)0x01)<<32) /* Suppress optimizations (debug) */ |
| 42 | 42 | #define DIFF_INVERT (((u64)0x02)<<32) /* Invert the diff (debug) */ |
| 43 | 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 */ | |
| 44 | 45 | |
| 45 | 46 | /* |
| 46 | 47 | ** These error messages are shared in multiple locations. They are defined |
| 47 | 48 | ** here for consistency. |
| 48 | 49 | */ |
| @@ -50,11 +51,35 @@ | ||
| 50 | 51 | "cannot compute difference between binary files\n" |
| 51 | 52 | |
| 52 | 53 | #define DIFF_CANNOT_COMPUTE_SYMLINK \ |
| 53 | 54 | "cannot compute difference between symlink and regular file\n" |
| 54 | 55 | |
| 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. */ | |
| 56 | 81 | #endif /* INTERFACE */ |
| 57 | 82 | |
| 58 | 83 | /* |
| 59 | 84 | ** Maximum length of a line in a text file, in bytes. (2**13 = 8192 bytes) |
| 60 | 85 | */ |
| @@ -180,63 +205,73 @@ | ||
| 180 | 205 | /* |
| 181 | 206 | ** This function attempts to scan each logical line within the blob to |
| 182 | 207 | ** determine the type of content it appears to contain. Possible return |
| 183 | 208 | ** values are: |
| 184 | 209 | ** |
| 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. | |
| 188 | 212 | ** |
| 189 | 213 | ** (0) -- The content appears to be binary because it contains embedded |
| 190 | 214 | ** NUL characters or an extremely long line. Since this function |
| 191 | 215 | ** does not understand UTF-16, it may falsely consider UTF-16 text |
| 192 | 216 | ** to be binary. |
| 193 | 217 | ** |
| 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 | 218 | ************************************ WARNING ********************************** |
| 199 | 219 | ** |
| 200 | 220 | ** This function does not validate that the blob content is properly formed |
| 201 | 221 | ** UTF-8. It assumes that all code points are the same size. It does not |
| 202 | 222 | ** validate any code points. It makes no attempt to detect if any [invalid] |
| 203 | 223 | ** switches between UTF-8 and other encodings occur. |
| 204 | 224 | ** |
| 205 | 225 | ** The only code points that this function cares about are the NUL character, |
| 206 | 226 | ** carriage-return, and line-feed. |
| 227 | +** | |
| 228 | +** Whether or not this function examines the entire contents of the blob is | |
| 229 | +** officially unspecified. | |
| 207 | 230 | ** |
| 208 | 231 | ************************************ WARNING ********************************** |
| 209 | 232 | */ |
| 210 | -int looks_like_utf8(const Blob *pContent){ | |
| 233 | +int looks_like_utf8(const Blob *pContent, int *pFlags){ | |
| 211 | 234 | const char *z = blob_buffer(pContent); |
| 212 | 235 | 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 */ | |
| 215 | 237 | |
| 216 | - /* Check individual lines. | |
| 217 | - */ | |
| 238 | + if( pFlags ) *pFlags = LOOK_NONE; | |
| 218 | 239 | if( n==0 ) return result; /* Empty file -> text */ |
| 219 | 240 | 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 */ | |
| 238 | 273 | } |
| 239 | 274 | return result; /* No problems seen -> not binary */ |
| 240 | 275 | } |
| 241 | 276 | |
| 242 | 277 | /* |
| @@ -270,64 +305,80 @@ | ||
| 270 | 305 | /* |
| 271 | 306 | ** This function attempts to scan each logical line within the blob to |
| 272 | 307 | ** determine the type of content it appears to contain. Possible return |
| 273 | 308 | ** values are: |
| 274 | 309 | ** |
| 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. | |
| 278 | 312 | ** |
| 279 | 313 | ** (0) -- The content appears to be binary because it contains embedded |
| 280 | 314 | ** NUL characters or an extremely long line. Since this function |
| 281 | 315 | ** does not understand UTF-8, it may falsely consider UTF-8 text |
| 282 | 316 | ** to be binary. |
| 283 | 317 | ** |
| 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 | 318 | ************************************ WARNING ********************************** |
| 289 | 319 | ** |
| 290 | 320 | ** This function does not validate that the blob content is properly formed |
| 291 | 321 | ** UTF-16. It assumes that all code points are the same size. It does not |
| 292 | 322 | ** validate any code points. It makes no attempt to detect if any [invalid] |
| 293 | 323 | ** switches between the UTF-16be and UTF-16le encodings occur. |
| 294 | 324 | ** |
| 295 | 325 | ** The only code points that this function cares about are the NUL character, |
| 296 | 326 | ** carriage-return, and line-feed. |
| 327 | +** | |
| 328 | +** Whether or not this function examines the entire contents of the blob is | |
| 329 | +** officially unspecified. | |
| 297 | 330 | ** |
| 298 | 331 | ************************************ WARNING ********************************** |
| 299 | 332 | */ |
| 300 | -int looks_like_utf16(const Blob *pContent){ | |
| 333 | +int looks_like_utf16(const Blob *pContent, int *pFlags){ | |
| 301 | 334 | const WCHAR_T *z = (WCHAR_T *)blob_buffer(pContent); |
| 302 | 335 | 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 */ | |
| 329 | 380 | } |
| 330 | 381 | return result; /* No problems seen -> not binary */ |
| 331 | 382 | } |
| 332 | 383 | |
| 333 | 384 | /* |
| @@ -355,26 +406,36 @@ | ||
| 355 | 406 | if( blob_size(pContent)<bomSize ) return 0; |
| 356 | 407 | return memcmp(z, bom, bomSize)==0; |
| 357 | 408 | } |
| 358 | 409 | |
| 359 | 410 | /* |
| 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. | |
| 362 | 416 | */ |
| 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. */ | |
| 376 | 437 | } |
| 377 | 438 | |
| 378 | 439 | /* |
| 379 | 440 | ** Return true if two DLine elements are identical. |
| 380 | 441 | */ |
| @@ -516,11 +577,11 @@ | ||
| 516 | 577 | a = xa; |
| 517 | 578 | b = xb; |
| 518 | 579 | continue; |
| 519 | 580 | } |
| 520 | 581 | } |
| 521 | - | |
| 582 | + | |
| 522 | 583 | /* For the current block comprising nr triples, figure out |
| 523 | 584 | ** how many lines of A and B are to be displayed |
| 524 | 585 | */ |
| 525 | 586 | if( R[r]>nContext ){ |
| 526 | 587 | na = nb = nContext; |
| @@ -871,21 +932,33 @@ | ||
| 871 | 932 | /* |
| 872 | 933 | ** Simplify iStart and iStart2: |
| 873 | 934 | ** |
| 874 | 935 | ** * If iStart is a null-change then move iStart2 into iStart |
| 875 | 936 | ** * Make sure any null-changes are in canonoical form. |
| 937 | +** * Make sure all changes are at character boundaries for | |
| 938 | +** multi-byte characters. | |
| 876 | 939 | */ |
| 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 | + } | |
| 879 | 947 | if( p->iStart==p->iEnd ){ |
| 880 | 948 | p->iStart = p->iStart2; |
| 881 | 949 | p->iEnd = p->iEnd2; |
| 882 | 950 | p->zStart = p->zStart2; |
| 883 | 951 | p->iStart2 = 0; |
| 884 | 952 | p->iEnd2 = 0; |
| 885 | 953 | } |
| 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 | + } | |
| 887 | 960 | } |
| 888 | 961 | |
| 889 | 962 | /* |
| 890 | 963 | ** Write out lines that have been edited. Adjust the highlight to cover |
| 891 | 964 | ** only those parts of the line that actually changed. |
| @@ -897,10 +970,11 @@ | ||
| 897 | 970 | DLine *pRight, /* Right line of the change */ |
| 898 | 971 | int lnRight /* Line number of the right line */ |
| 899 | 972 | ){ |
| 900 | 973 | int nLeft; /* Length of left line in bytes */ |
| 901 | 974 | int nRight; /* Length of right line in bytes */ |
| 975 | + int nShort; /* Shortest of left and right */ | |
| 902 | 976 | int nPrefix; /* Length of common prefix */ |
| 903 | 977 | int nSuffix; /* Length of common suffix */ |
| 904 | 978 | const char *zLeft; /* Text of the left line */ |
| 905 | 979 | const char *zRight; /* Text of the right line */ |
| 906 | 980 | int nLeftDiff; /* nLeft - nPrefix - nSuffix */ |
| @@ -912,25 +986,31 @@ | ||
| 912 | 986 | |
| 913 | 987 | nLeft = pLeft->h & LENGTH_MASK; |
| 914 | 988 | zLeft = pLeft->z; |
| 915 | 989 | nRight = pRight->h & LENGTH_MASK; |
| 916 | 990 | zRight = pRight->z; |
| 991 | + nShort = nLeft<nRight ? nLeft : nRight; | |
| 917 | 992 | |
| 918 | 993 | nPrefix = 0; |
| 919 | - while( nPrefix<nLeft && nPrefix<nRight && zLeft[nPrefix]==zRight[nPrefix] ){ | |
| 994 | + while( nPrefix<nShort && zLeft[nPrefix]==zRight[nPrefix] ){ | |
| 920 | 995 | nPrefix++; |
| 921 | 996 | } |
| 997 | + if( nPrefix<nShort ){ | |
| 998 | + while( nPrefix>0 && (zLeft[nPrefix]&0xc0)==0x80 ) nPrefix--; | |
| 999 | + } | |
| 922 | 1000 | 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] ){ | |
| 926 | 1003 | nSuffix++; |
| 927 | 1004 | } |
| 1005 | + if( nSuffix<nShort ){ | |
| 1006 | + while( nSuffix>0 && (zLeft[nLeft-nSuffix]&0xc0)==0x80 ) nSuffix--; | |
| 1007 | + } | |
| 928 | 1008 | if( nSuffix==nLeft || nSuffix==nRight ) nPrefix = 0; |
| 929 | 1009 | } |
| 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 | + | |
| 932 | 1012 | |
| 933 | 1013 | /* A single chunk of text inserted on the right */ |
| 934 | 1014 | if( nPrefix+nSuffix==nLeft ){ |
| 935 | 1015 | sbsWriteLineno(p, lnLeft); |
| 936 | 1016 | p->iStart2 = p->iEnd2 = 0; |
| @@ -986,11 +1066,11 @@ | ||
| 986 | 1066 | p->zStart = zClassChng; |
| 987 | 1067 | } |
| 988 | 1068 | p->iStart2 = nPrefix + aLCS[1]; |
| 989 | 1069 | p->iEnd2 = nLeft - nSuffix; |
| 990 | 1070 | p->zStart2 = aLCS[3]==nRightDiff ? zClassRm : zClassChng; |
| 991 | - sbsSimplifyLine(p); | |
| 1071 | + sbsSimplifyLine(p, zLeft+nPrefix); | |
| 992 | 1072 | sbsWriteText(p, pLeft, SBS_PAD); |
| 993 | 1073 | sbsWrite(p, " | ", 3); |
| 994 | 1074 | sbsWriteLineno(p, lnRight); |
| 995 | 1075 | p->iStart = nPrefix; |
| 996 | 1076 | p->iEnd = nPrefix + aLCS[2]; |
| @@ -1001,11 +1081,11 @@ | ||
| 1001 | 1081 | p->zStart = zClassChng; |
| 1002 | 1082 | } |
| 1003 | 1083 | p->iStart2 = nPrefix + aLCS[3]; |
| 1004 | 1084 | p->iEnd2 = nRight - nSuffix; |
| 1005 | 1085 | p->zStart2 = aLCS[1]==nLeftDiff ? zClassAdd : zClassChng; |
| 1006 | - sbsSimplifyLine(p); | |
| 1086 | + sbsSimplifyLine(p, zRight+nPrefix); | |
| 1007 | 1087 | sbsWriteText(p, pRight, SBS_NEWLINE); |
| 1008 | 1088 | return; |
| 1009 | 1089 | } |
| 1010 | 1090 | |
| 1011 | 1091 | /* If all else fails, show a single big change between left and right */ |
| @@ -1220,11 +1300,11 @@ | ||
| 1220 | 1300 | ** Then this is probably an alignment that will be difficult for humans |
| 1221 | 1301 | ** to read. So instead, just show all of the right side inserted followed |
| 1222 | 1302 | ** by all of the left side deleted. |
| 1223 | 1303 | ** |
| 1224 | 1304 | ** The coefficients for conditions (1) and (2) above are determined by |
| 1225 | - ** experimentation. | |
| 1305 | + ** experimentation. | |
| 1226 | 1306 | */ |
| 1227 | 1307 | mxLen = nLeft>nRight ? nLeft : nRight; |
| 1228 | 1308 | if( i*4>mxLen*5 && (nMatch==0 || iMatch/nMatch>15) ){ |
| 1229 | 1309 | memset(aM, 4, mnLen); |
| 1230 | 1310 | if( nLeft>mnLen ) memset(aM+mnLen, 1, nLeft-mnLen); |
| @@ -1406,11 +1486,11 @@ | ||
| 1406 | 1486 | /* Delete one line from the left */ |
| 1407 | 1487 | s.n = 0; |
| 1408 | 1488 | sbsWriteLineno(&s, a); |
| 1409 | 1489 | s.iStart = 0; |
| 1410 | 1490 | s.zStart = "<span class=\"diffrm\">"; |
| 1411 | - s.iEnd = s.width; | |
| 1491 | + s.iEnd = LENGTH(&A[a]); | |
| 1412 | 1492 | sbsWriteText(&s, &A[a], SBS_PAD); |
| 1413 | 1493 | if( s.escHtml ){ |
| 1414 | 1494 | sbsWrite(&s, " <\n", 6); |
| 1415 | 1495 | }else{ |
| 1416 | 1496 | sbsWrite(&s, " <\n", 3); |
| @@ -1439,11 +1519,11 @@ | ||
| 1439 | 1519 | sbsWrite(&s, " > ", 3); |
| 1440 | 1520 | } |
| 1441 | 1521 | sbsWriteLineno(&s, b); |
| 1442 | 1522 | s.iStart = 0; |
| 1443 | 1523 | s.zStart = "<span class=\"diffadd\">"; |
| 1444 | - s.iEnd = s.width; | |
| 1524 | + s.iEnd = LENGTH(&B[b]); | |
| 1445 | 1525 | sbsWriteText(&s, &B[b], SBS_NEWLINE); |
| 1446 | 1526 | blob_append(pOut, s.zLine, s.n); |
| 1447 | 1527 | assert( mb>0 ); |
| 1448 | 1528 | mb--; |
| 1449 | 1529 | b++; |
| @@ -1451,25 +1531,25 @@ | ||
| 1451 | 1531 | /* Delete from the left and insert on the right */ |
| 1452 | 1532 | s.n = 0; |
| 1453 | 1533 | sbsWriteLineno(&s, a); |
| 1454 | 1534 | s.iStart = 0; |
| 1455 | 1535 | s.zStart = "<span class=\"diffrm\">"; |
| 1456 | - s.iEnd = s.width; | |
| 1536 | + s.iEnd = LENGTH(&A[a]); | |
| 1457 | 1537 | sbsWriteText(&s, &A[a], SBS_PAD); |
| 1458 | 1538 | sbsWrite(&s, " | ", 3); |
| 1459 | 1539 | sbsWriteLineno(&s, b); |
| 1460 | 1540 | s.iStart = 0; |
| 1461 | 1541 | s.zStart = "<span class=\"diffadd\">"; |
| 1462 | - s.iEnd = s.width; | |
| 1542 | + s.iEnd = LENGTH(&B[b]); | |
| 1463 | 1543 | sbsWriteText(&s, &B[b], SBS_NEWLINE); |
| 1464 | 1544 | blob_append(pOut, s.zLine, s.n); |
| 1465 | 1545 | ma--; |
| 1466 | 1546 | mb--; |
| 1467 | 1547 | a++; |
| 1468 | 1548 | b++; |
| 1469 | 1549 | } |
| 1470 | - | |
| 1550 | + | |
| 1471 | 1551 | } |
| 1472 | 1552 | fossil_free(alignment); |
| 1473 | 1553 | if( i<nr-1 ){ |
| 1474 | 1554 | m = R[r+i*3+3]; |
| 1475 | 1555 | for(j=0; j<m; j++){ |
| @@ -1954,11 +2034,30 @@ | ||
| 1954 | 2034 | return 0; |
| 1955 | 2035 | } |
| 1956 | 2036 | |
| 1957 | 2037 | /* Compute the difference */ |
| 1958 | 2038 | 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 | + } | |
| 1960 | 2059 | |
| 1961 | 2060 | if( pOut ){ |
| 1962 | 2061 | /* Compute a context or side-by-side diff into pOut */ |
| 1963 | 2062 | if( diffFlags & DIFF_SIDEBYSIDE ){ |
| 1964 | 2063 | sbsDiff(&c, pOut, pRe, diffFlags); |
| @@ -2205,11 +2304,12 @@ | ||
| 2205 | 2304 | fossil_print("%10s: %.*s\n", zSrc, x.aOrig[i].n, x.aOrig[i].z); |
| 2206 | 2305 | } |
| 2207 | 2306 | } |
| 2208 | 2307 | |
| 2209 | 2308 | /* 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 */ | |
| 2211 | 2311 | |
| 2212 | 2312 | /* |
| 2213 | 2313 | ** Compute a complete annotation on a file. The file is identified |
| 2214 | 2314 | ** by its filename number (filename.fnid) and the baseline in which |
| 2215 | 2315 | ** it was checked in (mlink.mid). |
| @@ -2243,11 +2343,11 @@ | ||
| 2243 | 2343 | if( !content_get(rid, &toAnnotate) ){ |
| 2244 | 2344 | fossil_panic("unable to retrieve content of artifact #%d", rid); |
| 2245 | 2345 | } |
| 2246 | 2346 | if( iLimit<=0 ) iLimit = 1000000000; |
| 2247 | 2347 | annotation_start(p, &toAnnotate); |
| 2248 | - | |
| 2348 | + | |
| 2249 | 2349 | db_prepare(&q, |
| 2250 | 2350 | "SELECT (SELECT uuid FROM blob WHERE rid=mlink.%s)," |
| 2251 | 2351 | " (SELECT uuid FROM blob WHERE rid=mlink.fid)," |
| 2252 | 2352 | " (SELECT uuid FROM blob WHERE rid=mlink.pid)," |
| 2253 | 2353 | " date(event.mtime)," |
| @@ -2254,14 +2354,16 @@ | ||
| 2254 | 2354 | " coalesce(event.euser,event.user)," |
| 2255 | 2355 | " mlink.pid" |
| 2256 | 2356 | " FROM mlink, event" |
| 2257 | 2357 | " WHERE mlink.fid=:rid" |
| 2258 | 2358 | " 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,":"" | |
| 2261 | 2363 | ); |
| 2262 | - | |
| 2364 | + | |
| 2263 | 2365 | db_bind_int(&q, ":rid", rid); |
| 2264 | 2366 | if( iLimit==0 ) iLimit = 1000000000; |
| 2265 | 2367 | while( rid && iLimit>cnt && db_step(&q)==SQLITE_ROW ){ |
| 2266 | 2368 | const char *zUuid = db_column_text(&q, 0); |
| 2267 | 2369 | const char *zUuidFile = db_column_text(&q, 1); |
| @@ -2313,11 +2415,11 @@ | ||
| 2313 | 2415 | void annotation_page(void){ |
| 2314 | 2416 | int mid; |
| 2315 | 2417 | int fnid; |
| 2316 | 2418 | int i; |
| 2317 | 2419 | int iLimit; |
| 2318 | - int annFlags = 0; | |
| 2420 | + int annFlags = ANN_FILE_ANCEST; | |
| 2319 | 2421 | int showLn = 0; /* True if line numbers should be shown */ |
| 2320 | 2422 | char zLn[10]; /* Line number buffer */ |
| 2321 | 2423 | char zFormat[10]; /* Format string for line numbers */ |
| 2322 | 2424 | Annotator ann; |
| 2323 | 2425 | |
| @@ -2329,10 +2431,11 @@ | ||
| 2329 | 2431 | if( mid==0 || fnid==0 ){ fossil_redirect_home(); } |
| 2330 | 2432 | iLimit = atoi(PD("limit","-1")); |
| 2331 | 2433 | if( !db_exists("SELECT 1 FROM mlink WHERE mid=%d AND fnid=%d",mid,fnid) ){ |
| 2332 | 2434 | fossil_redirect_home(); |
| 2333 | 2435 | } |
| 2436 | + compute_direct_ancestors(mid, 10000000); | |
| 2334 | 2437 | style_header("File Annotation"); |
| 2335 | 2438 | if( P("filevers") ) annFlags |= ANN_FILE_VERS; |
| 2336 | 2439 | annotate_file(&ann, P("filename"), fnid, mid, g.perm.Hyperlink, iLimit, annFlags); |
| 2337 | 2440 | if( P("log") ){ |
| 2338 | 2441 | int i; |
| @@ -2395,11 +2498,11 @@ | ||
| 2395 | 2498 | if( zLimit==0 || zLimit[0]==0 ) zLimit = "-1"; |
| 2396 | 2499 | iLimit = atoi(zLimit); |
| 2397 | 2500 | showLog = find_option("log",0,0)!=0; |
| 2398 | 2501 | fileVers = find_option("filevers",0,0)!=0; |
| 2399 | 2502 | db_must_be_within_tree(); |
| 2400 | - if (g.argc<3) { | |
| 2503 | + if( g.argc<3 ) { | |
| 2401 | 2504 | usage("FILENAME"); |
| 2402 | 2505 | } |
| 2403 | 2506 | file_tree_name(g.argv[2], &treename, 1); |
| 2404 | 2507 | zFilename = blob_str(&treename); |
| 2405 | 2508 | fnid = db_int(0, "SELECT fnid FROM filename WHERE name=%Q", zFilename); |
| @@ -2409,11 +2512,11 @@ | ||
| 2409 | 2512 | fid = db_int(0, "SELECT rid FROM vfile WHERE pathname=%Q", zFilename); |
| 2410 | 2513 | if( fid==0 ){ |
| 2411 | 2514 | fossil_fatal("not part of current checkout: %s", zFilename); |
| 2412 | 2515 | } |
| 2413 | 2516 | cid = db_lget_int("checkout", 0); |
| 2414 | - if (cid == 0){ | |
| 2517 | + if( cid == 0 ){ | |
| 2415 | 2518 | fossil_fatal("Not in a checkout"); |
| 2416 | 2519 | } |
| 2417 | 2520 | if( iLimit<=0 ) iLimit = 1000000000; |
| 2418 | 2521 | compute_direct_ancestors(cid, iLimit); |
| 2419 | 2522 | mid = db_int(0, "SELECT mlink.mid FROM mlink, ancestor " |
| @@ -2422,10 +2525,11 @@ | ||
| 2422 | 2525 | fid, fnid); |
| 2423 | 2526 | if( mid==0 ){ |
| 2424 | 2527 | fossil_panic("unable to find manifest"); |
| 2425 | 2528 | } |
| 2426 | 2529 | if( fileVers ) annFlags |= ANN_FILE_VERS; |
| 2530 | + annFlags |= ANN_FILE_ANCEST; | |
| 2427 | 2531 | annotate_file(&ann, zFilename, fnid, mid, 0, iLimit, annFlags); |
| 2428 | 2532 | if( showLog ){ |
| 2429 | 2533 | for(i=0; i<ann.nVers; i++){ |
| 2430 | 2534 | printf("version %3d: %s\n", i+1, ann.azVers[i]); |
| 2431 | 2535 | } |
| @@ -2434,5 +2538,42 @@ | ||
| 2434 | 2538 | for(i=0; i<ann.nOrig; i++){ |
| 2435 | 2539 | fossil_print("%s: %.*s\n", |
| 2436 | 2540 | ann.aOrig[i].zSrc, ann.aOrig[i].n, ann.aOrig[i].z); |
| 2437 | 2541 | } |
| 2438 | 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 | +} | |
| 2439 | 2580 |
| --- 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, " <\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, " <\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 @@ | ||
| 64 | 64 | ** Fill stat buf with information received from stat() or lstat(). |
| 65 | 65 | ** lstat() is called on Unix if isWd is TRUE and allow-symlinks setting is on. |
| 66 | 66 | ** |
| 67 | 67 | */ |
| 68 | 68 | static int fossil_stat(const char *zFilename, struct stat *buf, int isWd){ |
| 69 | + int rc; | |
| 69 | 70 | #if !defined(_WIN32) |
| 71 | + char *zMbcs = fossil_utf8_to_filename(zFilename); | |
| 70 | 72 | if( isWd && g.allowSymlinks ){ |
| 71 | - return lstat(zFilename, buf); | |
| 73 | + rc = lstat(zMbcs, buf); | |
| 72 | 74 | }else{ |
| 73 | - return stat(zFilename, buf); | |
| 75 | + rc = stat(zMbcs, buf); | |
| 74 | 76 | } |
| 75 | 77 | #else |
| 76 | - int rc = 0; | |
| 77 | - wchar_t *zMbcs = fossil_utf8_to_unicode(zFilename); | |
| 78 | + wchar_t *zMbcs = fossil_utf8_to_filename(zFilename); | |
| 78 | 79 | rc = _wstati64(zMbcs, buf); |
| 79 | - fossil_unicode_free(zMbcs); | |
| 80 | - return rc; | |
| 81 | 80 | #endif |
| 81 | + fossil_filename_free(zMbcs); | |
| 82 | + return rc; | |
| 82 | 83 | } |
| 83 | 84 | |
| 84 | 85 | /* |
| 85 | 86 | ** Fill in the fileStat variable for the file named zFilename. |
| 86 | 87 | ** If zFilename==0, then use the previous value of fileStat if |
| @@ -303,16 +304,17 @@ | ||
| 303 | 304 | /* |
| 304 | 305 | ** Wrapper around the access() system call. |
| 305 | 306 | */ |
| 306 | 307 | int file_access(const char *zFilename, int flags){ |
| 307 | 308 | #ifdef _WIN32 |
| 308 | - wchar_t *zMbcs = fossil_utf8_to_unicode(zFilename); | |
| 309 | + wchar_t *zMbcs = fossil_utf8_to_filename(zFilename); | |
| 309 | 310 | int rc = _waccess(zMbcs, flags); |
| 310 | - fossil_unicode_free(zMbcs); | |
| 311 | 311 | #else |
| 312 | - int rc = access(zFilename, flags); | |
| 312 | + char *zMbcs = fossil_utf8_to_filename(zFilename); | |
| 313 | + int rc = access(zMbcs, flags); | |
| 313 | 314 | #endif |
| 315 | + fossil_filename_free(zMbcs); | |
| 314 | 316 | return rc; |
| 315 | 317 | } |
| 316 | 318 | |
| 317 | 319 | /* |
| 318 | 320 | ** Find an unused filename similar to zBase with zSuffix appended. |
| @@ -402,19 +404,20 @@ | ||
| 402 | 404 | #if !defined(_WIN32) |
| 403 | 405 | struct timeval tv[2]; |
| 404 | 406 | memset(tv, 0, sizeof(tv[0])*2); |
| 405 | 407 | tv[0].tv_sec = newMTime; |
| 406 | 408 | tv[1].tv_sec = newMTime; |
| 407 | - utimes(zFilename, tv); | |
| 409 | + char *zMbcs = fossil_utf8_to_filename(zFilename); | |
| 410 | + utimes(zMbcs, tv); | |
| 408 | 411 | #else |
| 409 | 412 | struct _utimbuf tb; |
| 410 | - wchar_t *zMbcs = fossil_utf8_to_unicode(zFilename); | |
| 413 | + wchar_t *zMbcs = fossil_utf8_to_filename(zFilename); | |
| 411 | 414 | tb.actime = newMTime; |
| 412 | 415 | tb.modtime = newMTime; |
| 413 | 416 | _wutime(zMbcs, &tb); |
| 414 | - fossil_unicode_free(zMbcs); | |
| 415 | 417 | #endif |
| 418 | + fossil_filename_free(zMbcs); | |
| 416 | 419 | } |
| 417 | 420 | |
| 418 | 421 | /* |
| 419 | 422 | ** COMMAND: test-set-mtime |
| 420 | 423 | ** |
| @@ -441,16 +444,17 @@ | ||
| 441 | 444 | /* |
| 442 | 445 | ** Delete a file. |
| 443 | 446 | */ |
| 444 | 447 | void file_delete(const char *zFilename){ |
| 445 | 448 | #ifdef _WIN32 |
| 446 | - wchar_t *z = fossil_utf8_to_unicode(zFilename); | |
| 449 | + wchar_t *z = fossil_utf8_to_filename(zFilename); | |
| 447 | 450 | _wunlink(z); |
| 448 | - fossil_unicode_free(z); | |
| 449 | 451 | #else |
| 452 | + char *z = fossil_utf8_to_filename(zFilename); | |
| 450 | 453 | unlink(zFilename); |
| 451 | 454 | #endif |
| 455 | + fossil_filename_free(z); | |
| 452 | 456 | } |
| 453 | 457 | |
| 454 | 458 | /* |
| 455 | 459 | ** Create the directory named in the argument, if it does not already |
| 456 | 460 | ** exist. If forceFlag is 1, delete any prior non-directory object |
| @@ -464,18 +468,18 @@ | ||
| 464 | 468 | if( !forceFlag ) return 1; |
| 465 | 469 | file_delete(zName); |
| 466 | 470 | } |
| 467 | 471 | if( rc!=1 ){ |
| 468 | 472 | #if defined(_WIN32) |
| 469 | - int rc; | |
| 470 | - wchar_t *zMbcs = fossil_utf8_to_unicode(zName); | |
| 473 | + wchar_t *zMbcs = fossil_utf8_to_filename(zName); | |
| 471 | 474 | rc = _wmkdir(zMbcs); |
| 472 | - fossil_unicode_free(zMbcs); | |
| 473 | - return rc; | |
| 474 | 475 | #else |
| 475 | - return mkdir(zName, 0755); | |
| 476 | + char *zMbcs = fossil_utf8_to_filename(zName); | |
| 477 | + rc = mkdir(zName, 0755); | |
| 476 | 478 | #endif |
| 479 | + fossil_filename_free(zMbcs); | |
| 480 | + return rc; | |
| 477 | 481 | } |
| 478 | 482 | return 0; |
| 479 | 483 | } |
| 480 | 484 | |
| 481 | 485 | /* |
| @@ -580,11 +584,11 @@ | ||
| 580 | 584 | } |
| 581 | 585 | |
| 582 | 586 | /* |
| 583 | 587 | ** Simplify a filename by |
| 584 | 588 | ** |
| 585 | -** * Convert all \ into / on windows | |
| 589 | +** * Convert all \ into / on windows and cygwin | |
| 586 | 590 | ** * removing any trailing and duplicate / |
| 587 | 591 | ** * removing /./ |
| 588 | 592 | ** * removing /A/../ |
| 589 | 593 | ** |
| 590 | 594 | ** Changes are made in-place. Return the new name length. |
| @@ -593,12 +597,12 @@ | ||
| 593 | 597 | */ |
| 594 | 598 | int file_simplify_name(char *z, int n, int slash){ |
| 595 | 599 | int i, j; |
| 596 | 600 | if( n<0 ) n = strlen(z); |
| 597 | 601 | |
| 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__) | |
| 600 | 604 | for(i=0; i<n; i++){ |
| 601 | 605 | if( z[i]=='\\' ) z[i] = '/'; |
| 602 | 606 | } |
| 603 | 607 | #endif |
| 604 | 608 | |
| @@ -705,13 +709,13 @@ | ||
| 705 | 709 | ** Return true if zPath is an absolute pathname. Return false |
| 706 | 710 | ** if it is relative. |
| 707 | 711 | */ |
| 708 | 712 | int file_is_absolute_path(const char *zPath){ |
| 709 | 713 | if( zPath[0]=='/' |
| 710 | -#if defined(_WIN32) | |
| 714 | +#if defined(_WIN32) || defined(__CYGWIN__) | |
| 711 | 715 | || zPath[0]=='\\' |
| 712 | - || (strlen(zPath)>3 && zPath[1]==':' | |
| 716 | + || (fossil_isalpha(zPath[0]) && zPath[1]==':' | |
| 713 | 717 | && (zPath[2]=='\\' || zPath[2]=='/')) |
| 714 | 718 | #endif |
| 715 | 719 | ){ |
| 716 | 720 | return 1; |
| 717 | 721 | }else{ |
| @@ -728,21 +732,21 @@ | ||
| 728 | 732 | ** If the slash parameter is non-zero, the trailing slash, if any, |
| 729 | 733 | ** is retained. |
| 730 | 734 | */ |
| 731 | 735 | void file_canonical_name(const char *zOrigName, Blob *pOut, int slash){ |
| 732 | 736 | if( file_is_absolute_path(zOrigName) ){ |
| 733 | -#if defined(_WIN32) | |
| 737 | +#if defined(_WIN32) || defined(__CYGWIN__) | |
| 734 | 738 | char *zOut; |
| 735 | 739 | #endif |
| 736 | 740 | blob_set(pOut, zOrigName); |
| 737 | 741 | blob_materialize(pOut); |
| 738 | -#if defined(_WIN32) | |
| 742 | +#if defined(_WIN32) || defined(__CYGWIN__) | |
| 739 | 743 | /* |
| 740 | - ** On Windows, normalize the drive letter to upper case. | |
| 744 | + ** On Windows/cygwin, normalize the drive letter to upper case. | |
| 741 | 745 | */ |
| 742 | 746 | zOut = blob_str(pOut); |
| 743 | - if( fossil_isalpha(zOut[0]) && zOut[1]==':' ){ | |
| 747 | + if( fossil_islower(zOut[0]) && zOut[1]==':' ){ | |
| 744 | 748 | zOut[0] = fossil_toupper(zOut[0]); |
| 745 | 749 | } |
| 746 | 750 | #endif |
| 747 | 751 | }else{ |
| 748 | 752 | char zPwd[2000]; |
| @@ -749,11 +753,11 @@ | ||
| 749 | 753 | file_getcwd(zPwd, sizeof(zPwd)-strlen(zOrigName)); |
| 750 | 754 | #if defined(_WIN32) |
| 751 | 755 | /* |
| 752 | 756 | ** On Windows, normalize the drive letter to upper case. |
| 753 | 757 | */ |
| 754 | - if( fossil_isalpha(zPwd[0]) && zPwd[1]==':' ){ | |
| 758 | + if( fossil_islower(zPwd[0]) && zPwd[1]==':' ){ | |
| 755 | 759 | zPwd[0] = fossil_toupper(zPwd[0]); |
| 756 | 760 | } |
| 757 | 761 | #endif |
| 758 | 762 | blob_zero(pOut); |
| 759 | 763 | blob_appendf(pOut, "%//%/", zPwd, zOrigName); |
| @@ -798,12 +802,12 @@ | ||
| 798 | 802 | ** contain no "/./" or "/../" terms. |
| 799 | 803 | */ |
| 800 | 804 | int file_is_canonical(const char *z){ |
| 801 | 805 | int i; |
| 802 | 806 | 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]!='/') | |
| 805 | 809 | #endif |
| 806 | 810 | ) return 0; |
| 807 | 811 | |
| 808 | 812 | for(i=0; z[i]; i++){ |
| 809 | 813 | if( z[i]=='\\' ) return 0; |
| @@ -846,11 +850,11 @@ | ||
| 846 | 850 | char zBuf[2000]; |
| 847 | 851 | zPwd = zBuf; |
| 848 | 852 | file_getcwd(zBuf, sizeof(zBuf)-20); |
| 849 | 853 | zPwd = file_without_drive_letter(zBuf); |
| 850 | 854 | i = 1; |
| 851 | -#ifdef _WIN32 | |
| 855 | +#if defined(_WIN32) || defined(__CYGWIN__) | |
| 852 | 856 | while( zPath[i] && fossil_tolower(zPwd[i])==fossil_tolower(zPath[i]) ) i++; |
| 853 | 857 | #else |
| 854 | 858 | while( zPath[i] && zPwd[i]==zPath[i] ) i++; |
| 855 | 859 | #endif |
| 856 | 860 | if( zPath[i]==0 ){ |
| @@ -1011,23 +1015,26 @@ | ||
| 1011 | 1015 | |
| 1012 | 1016 | /* |
| 1013 | 1017 | ** Construct a random temporary filename into zBuf[]. |
| 1014 | 1018 | */ |
| 1015 | 1019 | void file_tempname(int nBuf, char *zBuf){ |
| 1016 | - static const char *azDirs[] = { | |
| 1017 | 1020 | #if defined(_WIN32) |
| 1021 | + const char *azDirs[] = { | |
| 1018 | 1022 | 0, /* GetTempPath */ |
| 1019 | 1023 | 0, /* TEMP */ |
| 1020 | 1024 | 0, /* TMP */ |
| 1025 | + ".", | |
| 1026 | + }; | |
| 1021 | 1027 | #else |
| 1028 | + static const char *const azDirs[] = { | |
| 1022 | 1029 | "/var/tmp", |
| 1023 | 1030 | "/usr/tmp", |
| 1024 | 1031 | "/tmp", |
| 1025 | 1032 | "/temp", |
| 1026 | -#endif | |
| 1027 | 1033 | ".", |
| 1028 | 1034 | }; |
| 1035 | +#endif | |
| 1029 | 1036 | static const unsigned char zChars[] = |
| 1030 | 1037 | "abcdefghijklmnopqrstuvwxyz" |
| 1031 | 1038 | "ABCDEFGHIJKLMNOPQRSTUVWXYZ" |
| 1032 | 1039 | "0123456789"; |
| 1033 | 1040 | unsigned int i, j; |
| @@ -1070,12 +1077,13 @@ | ||
| 1070 | 1077 | } |
| 1071 | 1078 | zBuf[j] = 0; |
| 1072 | 1079 | }while( file_size(zBuf)>=0 ); |
| 1073 | 1080 | |
| 1074 | 1081 | #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]); | |
| 1077 | 1085 | #endif |
| 1078 | 1086 | } |
| 1079 | 1087 | |
| 1080 | 1088 | |
| 1081 | 1089 | /* |
| @@ -1137,14 +1145,14 @@ | ||
| 1137 | 1145 | ** Like fopen() but always takes a UTF8 argument. |
| 1138 | 1146 | */ |
| 1139 | 1147 | FILE *fossil_fopen(const char *zName, const char *zMode){ |
| 1140 | 1148 | #ifdef _WIN32 |
| 1141 | 1149 | 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); | |
| 1143 | 1151 | FILE *f = _wfopen(uName, uMode); |
| 1144 | - fossil_unicode_free(uName); | |
| 1152 | + fossil_filename_free(uName); | |
| 1145 | 1153 | fossil_unicode_free(uMode); |
| 1146 | 1154 | #else |
| 1147 | 1155 | FILE *f = fopen(zName, zMode); |
| 1148 | 1156 | #endif |
| 1149 | 1157 | return f; |
| 1150 | 1158 | } |
| 1151 | 1159 |
| --- 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 @@ | ||
| 20 | 20 | #include "config.h" |
| 21 | 21 | #include "finfo.h" |
| 22 | 22 | |
| 23 | 23 | /* |
| 24 | 24 | ** COMMAND: finfo |
| 25 | -** | |
| 25 | +** | |
| 26 | 26 | ** Usage: %fossil finfo ?OPTIONS? FILENAME |
| 27 | 27 | ** |
| 28 | 28 | ** Print the complete change history for a single file going backwards |
| 29 | 29 | ** in time. The default mode is -l. |
| 30 | 30 | ** |
| @@ -55,11 +55,11 @@ | ||
| 55 | 55 | ** See also: artifact, cat, descendants, info, leaves |
| 56 | 56 | */ |
| 57 | 57 | void finfo_cmd(void){ |
| 58 | 58 | capture_case_sensitive_option(); |
| 59 | 59 | db_must_be_within_tree(); |
| 60 | - if (find_option("status","s",0)) { | |
| 60 | + if( find_option("status","s",0) ){ | |
| 61 | 61 | Stmt q; |
| 62 | 62 | Blob line; |
| 63 | 63 | Blob fname; |
| 64 | 64 | int vid; |
| 65 | 65 | |
| @@ -73,11 +73,11 @@ | ||
| 73 | 73 | db_prepare(&q, |
| 74 | 74 | "SELECT pathname, deleted, rid, chnged, coalesce(origname!=pathname,0)" |
| 75 | 75 | " FROM vfile WHERE vfile.pathname=%B %s", |
| 76 | 76 | &fname, filename_collation()); |
| 77 | 77 | blob_zero(&line); |
| 78 | - if ( db_step(&q)==SQLITE_ROW ) { | |
| 78 | + if( db_step(&q)==SQLITE_ROW ) { | |
| 79 | 79 | Blob uuid; |
| 80 | 80 | int isDeleted = db_column_int(&q, 1); |
| 81 | 81 | int isNew = db_column_int(&q,2) == 0; |
| 82 | 82 | int chnged = db_column_int(&q,3); |
| 83 | 83 | int renamed = db_column_int(&q,4); |
| @@ -247,11 +247,11 @@ | ||
| 247 | 247 | |
| 248 | 248 | /* |
| 249 | 249 | ** WEBPAGE: finfo |
| 250 | 250 | ** URL: /finfo?name=FILENAME |
| 251 | 251 | ** |
| 252 | -** Show the change history for a single file. | |
| 252 | +** Show the change history for a single file. | |
| 253 | 253 | ** |
| 254 | 254 | ** Additional query parameters: |
| 255 | 255 | ** |
| 256 | 256 | ** a=DATE Only show changes after DATE |
| 257 | 257 | ** b=DATE Only show changes before DATE |
| @@ -265,11 +265,11 @@ | ||
| 265 | 265 | const char *zFilename; |
| 266 | 266 | char zPrevDate[20]; |
| 267 | 267 | const char *zA; |
| 268 | 268 | const char *zB; |
| 269 | 269 | int n; |
| 270 | - | |
| 270 | + | |
| 271 | 271 | Blob title; |
| 272 | 272 | Blob sql; |
| 273 | 273 | HQuery url; |
| 274 | 274 | GraphContext *pGraph; |
| 275 | 275 | int brBg = P("brbg")!=0; |
| @@ -288,11 +288,11 @@ | ||
| 288 | 288 | |
| 289 | 289 | zPrevDate[0] = 0; |
| 290 | 290 | zFilename = PD("name",""); |
| 291 | 291 | url_add_parameter(&url, "name", zFilename); |
| 292 | 292 | blob_zero(&sql); |
| 293 | - blob_appendf(&sql, | |
| 293 | + blob_appendf(&sql, | |
| 294 | 294 | "SELECT" |
| 295 | 295 | " datetime(event.mtime,'localtime')," /* Date of change */ |
| 296 | 296 | " coalesce(event.ecomment, event.comment)," /* Check-in comment */ |
| 297 | 297 | " coalesce(event.euser, event.user)," /* User who made chng */ |
| 298 | 298 | " mlink.pid," /* Parent rid */ |
| @@ -403,11 +403,11 @@ | ||
| 403 | 403 | @ %z(href("%R/finfo?name=%t", zPrevName))%h(zPrevName)</a> |
| 404 | 404 | } |
| 405 | 405 | @ %z(href("%R/artifact/%s",zUuid))[%S(zUuid)]</a> part of check-in |
| 406 | 406 | }else{ |
| 407 | 407 | char *zNewName; |
| 408 | - zNewName = db_text(0, | |
| 408 | + zNewName = db_text(0, | |
| 409 | 409 | "SELECT name FROM filename WHERE fnid = " |
| 410 | 410 | " (SELECT fnid FROM mlink" |
| 411 | 411 | " WHERE mid=%d" |
| 412 | 412 | " AND pfnid IN (SELECT fnid FROM filename WHERE name=%Q %s))", |
| 413 | 413 | fmid, zFilename, filename_collation()); |
| @@ -418,11 +418,11 @@ | ||
| 418 | 418 | }else{ |
| 419 | 419 | @ <b>Deleted</b> by check-in |
| 420 | 420 | } |
| 421 | 421 | } |
| 422 | 422 | hyperlink_to_uuid(zShortCkin); |
| 423 | - @ %h(zCom) (user: | |
| 423 | + @ %w(zCom) (user: | |
| 424 | 424 | hyperlink_to_user(zUser, zDate, ""); |
| 425 | 425 | @ branch: %h(zBr)) |
| 426 | 426 | if( g.perm.Hyperlink && zUuid ){ |
| 427 | 427 | const char *z = zFilename; |
| 428 | 428 | if( fpid ){ |
| 429 | 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 | @ %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 @@ | ||
| 29 | 29 | ** zVal: "x" |
| 30 | 30 | ** zGlobList: "*.o,*.obj" |
| 31 | 31 | ** |
| 32 | 32 | ** Result: "(x GLOB '*.o' OR x GLOB '*.obj')" |
| 33 | 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 "...". | |
| 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 | 38 | ** |
| 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. | |
| 40 | 41 | */ |
| 41 | 42 | char *glob_expr(const char *zVal, const char *zGlobList){ |
| 42 | 43 | Blob expr; |
| 43 | 44 | char *zSep = "("; |
| 44 | 45 | int nTerm = 0; |
| @@ -46,21 +47,24 @@ | ||
| 46 | 47 | int cTerm; |
| 47 | 48 | |
| 48 | 49 | if( zGlobList==0 || zGlobList[0]==0 ) return "0"; |
| 49 | 50 | blob_zero(&expr); |
| 50 | 51 | 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 | + } | |
| 52 | 55 | if( zGlobList[0]==0 ) break; |
| 53 | 56 | if( zGlobList[0]=='\'' || zGlobList[0]=='"' ){ |
| 54 | 57 | cTerm = zGlobList[0]; |
| 55 | 58 | zGlobList++; |
| 56 | 59 | }else{ |
| 57 | 60 | cTerm = ','; |
| 58 | 61 | } |
| 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. */ | |
| 62 | 66 | } |
| 63 | 67 | blob_appendf(&expr, "%s%s GLOB '%#q'", zSep, zVal, i, zGlobList); |
| 64 | 68 | zSep = " OR "; |
| 65 | 69 | if( cTerm!=',' && zGlobList[i] ) i++; |
| 66 | 70 | zGlobList += i; |
| @@ -85,24 +89,24 @@ | ||
| 85 | 89 | char **azPattern; /* Array of pointers to patterns */ |
| 86 | 90 | }; |
| 87 | 91 | #endif /* INTERFACE */ |
| 88 | 92 | |
| 89 | 93 | /* |
| 90 | -** zPatternList is a comma-separate list of glob patterns. Parse up | |
| 94 | +** zPatternList is a comma-separated list of glob patterns. Parse up | |
| 91 | 95 | ** that list and use it to create a new Glob object. |
| 92 | 96 | ** |
| 93 | 97 | ** 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. | |
| 95 | 99 | ** |
| 96 | 100 | ** Leading and trailing spaces on unquoted glob patterns are ignored. |
| 97 | 101 | ** |
| 98 | 102 | ** An empty or null pattern list results in a null glob, which will |
| 99 | 103 | ** match nothing. |
| 100 | 104 | */ |
| 101 | 105 | Glob *glob_create(const char *zPatternList){ |
| 102 | 106 | int nList; /* Size of zPatternList in bytes */ |
| 103 | - int i, j; /* Loop counters */ | |
| 107 | + int i; /* Loop counters */ | |
| 104 | 108 | Glob *p; /* The glob being created */ |
| 105 | 109 | char *z; /* Copy of the pattern list */ |
| 106 | 110 | char delimiter; /* '\'' or '\"' or 0 */ |
| 107 | 111 | |
| 108 | 112 | if( zPatternList==0 || zPatternList[0]==0 ) return 0; |
| @@ -110,27 +114,26 @@ | ||
| 110 | 114 | p = fossil_malloc( sizeof(*p) + nList+1 ); |
| 111 | 115 | memset(p, 0, sizeof(*p)); |
| 112 | 116 | z = (char*)&p[1]; |
| 113 | 117 | memcpy(z, zPatternList, nList+1); |
| 114 | 118 | 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 */ | |
| 117 | 121 | } |
| 122 | + if( z[0]==0 ) break; | |
| 118 | 123 | if( z[0]=='\'' || z[0]=='"' ){ |
| 119 | 124 | delimiter = z[0]; |
| 120 | 125 | z++; |
| 121 | 126 | }else{ |
| 122 | 127 | delimiter = ','; |
| 123 | 128 | } |
| 124 | - if( z[0]==0 ) break; | |
| 125 | 129 | p->azPattern = fossil_realloc(p->azPattern, (p->nPattern+1)*sizeof(char*) ); |
| 126 | 130 | 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. */ | |
| 132 | 135 | } |
| 133 | 136 | if( z[i]==0 ) break; |
| 134 | 137 | z[i] = 0; |
| 135 | 138 | z += i+1; |
| 136 | 139 | } |
| @@ -245,22 +248,35 @@ | ||
| 245 | 248 | /* |
| 246 | 249 | ** COMMAND: test-glob |
| 247 | 250 | ** |
| 248 | 251 | ** Usage: %fossil test-glob PATTERN STRING... |
| 249 | 252 | ** |
| 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. | |
| 252 | 260 | */ |
| 253 | 261 | void glob_test_cmd(void){ |
| 254 | 262 | Glob *pGlob; |
| 255 | 263 | int i; |
| 264 | + char *zPattern; | |
| 256 | 265 | 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); | |
| 259 | 275 | for(i=0; i<pGlob->nPattern; i++){ |
| 260 | 276 | fossil_print("pattern[%d] = [%s]\n", i, pGlob->azPattern[i]); |
| 261 | 277 | } |
| 262 | 278 | for(i=3; i<g.argc; i++){ |
| 263 | 279 | fossil_print("%d %s\n", glob_match(pGlob, g.argv[i]), g.argv[i]); |
| 264 | 280 | } |
| 265 | 281 | glob_free(pGlob); |
| 266 | 282 | } |
| 267 | 283 |
| --- 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 @@ | ||
| 60 | 60 | zPw = 0; |
| 61 | 61 | }else{ |
| 62 | 62 | /* Password failure while doing a sync from the command-line interface */ |
| 63 | 63 | url_prompt_for_password(); |
| 64 | 64 | zPw = g.urlPasswd; |
| 65 | - if( !g.dontKeepUrl ) db_set("last-sync-pw", obscure(zPw), 0); | |
| 66 | 65 | } |
| 67 | 66 | |
| 68 | 67 | /* If the first character of the password is "#", then that character is |
| 69 | 68 | ** not really part of the password - it is an indicator that we should |
| 70 | 69 | ** use Basic Authentication. So skip that character. |
| @@ -72,10 +71,11 @@ | ||
| 72 | 71 | if( zPw && zPw[0]=='#' ) zPw++; |
| 73 | 72 | |
| 74 | 73 | /* The login card wants the SHA1 hash of the password, so convert the |
| 75 | 74 | ** password to its SHA1 hash it it isn't already a SHA1 hash. |
| 76 | 75 | */ |
| 76 | + /* fossil_print("\nzPw=[%s]\n", zPw); // TESTING ONLY */ | |
| 77 | 77 | if( zPw && zPw[0] ) zPw = sha1_shared_secret(zPw, zLogin, 0); |
| 78 | 78 | |
| 79 | 79 | blob_append(&pw, zPw, -1); |
| 80 | 80 | sha1sum_blob(&pw, &sig); |
| 81 | 81 | blob_appendf(pLogin, "login %F %b %b\n", zLogin, &nonce, &sig); |
| @@ -243,11 +243,11 @@ | ||
| 243 | 243 | while( j>4 && fossil_strcmp(&zLine[j-4],"/xfer")==0 ){ |
| 244 | 244 | j -= 4; |
| 245 | 245 | zLine[j] = 0; |
| 246 | 246 | } |
| 247 | 247 | fossil_print("redirect to %s\n", &zLine[i]); |
| 248 | - url_parse(&zLine[i]); | |
| 248 | + url_parse(&zLine[i], 0); | |
| 249 | 249 | transport_close(); |
| 250 | 250 | return http_exchange(pSend, pReply, useLogin, maxRedirect); |
| 251 | 251 | }else if( fossil_strnicmp(zLine, "content-type: ", 14)==0 ){ |
| 252 | 252 | if( fossil_strnicmp(&zLine[14], "application/x-fossil-debug", -1)==0 ){ |
| 253 | 253 | isCompressed = 0; |
| 254 | 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 | 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 |
+2
-2
| --- src/http_transport.c | ||
| +++ src/http_transport.c | ||
| @@ -312,11 +312,11 @@ | ||
| 312 | 312 | sqlite3_randomness(sizeof(iRandId), &iRandId); |
| 313 | 313 | transport.zOutFile = mprintf("%s-%llu-out.http", |
| 314 | 314 | g.zRepositoryName, iRandId); |
| 315 | 315 | transport.zInFile = mprintf("%s-%llu-in.http", |
| 316 | 316 | g.zRepositoryName, iRandId); |
| 317 | - transport.pFile = fopen(transport.zOutFile, "wb"); | |
| 317 | + transport.pFile = fossil_fopen(transport.zOutFile, "wb"); | |
| 318 | 318 | if( transport.pFile==0 ){ |
| 319 | 319 | fossil_fatal("cannot output temporary file: %s", transport.zOutFile); |
| 320 | 320 | } |
| 321 | 321 | transport.isOpen = 1; |
| 322 | 322 | }else{ |
| @@ -409,11 +409,11 @@ | ||
| 409 | 409 | zCmd = mprintf("\"%s\" http \"%s\" \"%s\" \"%s\" 127.0.0.1 --localauth", |
| 410 | 410 | g.nameOfExe, g.urlName, transport.zOutFile, transport.zInFile |
| 411 | 411 | ); |
| 412 | 412 | fossil_system(zCmd); |
| 413 | 413 | free(zCmd); |
| 414 | - transport.pFile = fopen(transport.zInFile, "rb"); | |
| 414 | + transport.pFile = fossil_fopen(transport.zInFile, "rb"); | |
| 415 | 415 | } |
| 416 | 416 | } |
| 417 | 417 | |
| 418 | 418 | /* |
| 419 | 419 | ** Log all input to a file. The transport layer will take responsibility |
| 420 | 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 = 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 @@ | ||
| 198 | 198 | if( g.localOpen ){ |
| 199 | 199 | fossil_print("repository: %s\n", db_repository_filename()); |
| 200 | 200 | fossil_print("local-root: %s\n", g.zLocalRoot); |
| 201 | 201 | } |
| 202 | 202 | 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); | |
| 206 | 205 | } |
| 207 | -#endif | |
| 208 | 206 | fossil_print("project-code: %s\n", db_get("project-code", "")); |
| 209 | 207 | vid = g.localOpen ? db_lget_int("checkout", 0) : 0; |
| 210 | 208 | if( vid ){ |
| 211 | 209 | show_common_info(vid, "checkout:", 1, 1); |
| 212 | 210 | } |
| 213 | 211 | 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*/")); | |
| 215 | 213 | }else{ |
| 216 | 214 | int rid; |
| 217 | 215 | rid = name_to_rid(g.argv[2]); |
| 218 | 216 | if( rid==0 ){ |
| 219 | 217 | fossil_panic("no such object: %s\n", g.argv[2]); |
| @@ -314,16 +312,17 @@ | ||
| 314 | 312 | }else{ |
| 315 | 313 | blob_zero(&to); |
| 316 | 314 | } |
| 317 | 315 | blob_zero(&out); |
| 318 | 316 | 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); | |
| 320 | 318 | @ <div class="sbsdiff"> |
| 321 | 319 | @ %s(blob_str(&out)) |
| 322 | 320 | @ </div> |
| 323 | 321 | }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); | |
| 325 | 324 | @ <div class="udiff"> |
| 326 | 325 | @ %s(blob_str(&out)) |
| 327 | 326 | @ </div> |
| 328 | 327 | } |
| 329 | 328 | blob_reset(&from); |
| @@ -492,15 +491,10 @@ | ||
| 492 | 491 | char *zEUser, *zEComment; |
| 493 | 492 | const char *zUser; |
| 494 | 493 | const char *zComment; |
| 495 | 494 | const char *zDate; |
| 496 | 495 | const char *zOrigDate; |
| 497 | -#if 0 | |
| 498 | - char *zThisBranch; | |
| 499 | - double thisMtime; | |
| 500 | - int seenDiffTitle = 0; | |
| 501 | -#endif | |
| 502 | 496 | |
| 503 | 497 | style_header(zTitle); |
| 504 | 498 | login_anonymous_available(); |
| 505 | 499 | free(zTitle); |
| 506 | 500 | zEUser = db_text(0, |
| @@ -511,13 +505,10 @@ | ||
| 511 | 505 | TAG_COMMENT, rid); |
| 512 | 506 | zUser = db_column_text(&q, 2); |
| 513 | 507 | zComment = db_column_text(&q, 3); |
| 514 | 508 | zDate = db_column_text(&q,1); |
| 515 | 509 | zOrigDate = db_column_text(&q, 4); |
| 516 | -#if 0 | |
| 517 | - thisMtime = db_column_double(&q, 5); | |
| 518 | -#endif | |
| 519 | 510 | @ <div class="section">Overview</div> |
| 520 | 511 | @ <table class="label-value"> |
| 521 | 512 | @ <tr><th>SHA1 Hash:</th><td>%s(zUuid) |
| 522 | 513 | if( g.perm.Setup ){ |
| 523 | 514 | @ (Record ID: %d(rid)) |
| @@ -537,14 +528,14 @@ | ||
| 537 | 528 | }else{ |
| 538 | 529 | @ <tr><th>User:</th><td> |
| 539 | 530 | hyperlink_to_user(zUser,zDate,"</td></tr>"); |
| 540 | 531 | } |
| 541 | 532 | if( zEComment ){ |
| 542 | - @ <tr><th>Edited Comment:</th><td>%w(zEComment)</td></tr> | |
| 543 | - @ <tr><th>Original Comment:</th><td>%w(zComment)</td></tr> | |
| 533 | + @ <tr><th>Edited Comment:</th><td>%!w(zEComment)</td></tr> | |
| 534 | + @ <tr><th>Original Comment:</th><td>%!w(zComment)</td></tr> | |
| 544 | 535 | }else{ |
| 545 | - @ <tr><th>Comment:</th><td>%w(zComment)</td></tr> | |
| 536 | + @ <tr><th>Comment:</th><td>%!w(zComment)</td></tr> | |
| 546 | 537 | } |
| 547 | 538 | if( g.perm.Admin ){ |
| 548 | 539 | db_prepare(&q, |
| 549 | 540 | "SELECT rcvfrom.ipaddr, user.login, datetime(rcvfrom.mtime)" |
| 550 | 541 | " FROM blob JOIN rcvfrom USING(rcvid) LEFT JOIN user USING(uid)" |
| @@ -582,61 +573,10 @@ | ||
| 582 | 573 | const char *zTagName = db_column_text(&q, 0); |
| 583 | 574 | @ | %z(href("%R/timeline?r=%T",zTagName))%h(zTagName)</a> |
| 584 | 575 | } |
| 585 | 576 | db_finalize(&q); |
| 586 | 577 | |
| 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 | 578 | |
| 639 | 579 | /* The Download: line */ |
| 640 | 580 | if( g.perm.Zip ){ |
| 641 | 581 | char *zUrl = mprintf("%R/tarball/%t-%S.tar.gz?uuid=%s", |
| 642 | 582 | zProjName, zUuid, zUuid); |
| @@ -1150,11 +1090,11 @@ | ||
| 1150 | 1090 | @ - part of checkin |
| 1151 | 1091 | hyperlink_to_uuid(zVers); |
| 1152 | 1092 | if( zBr && zBr[0] ){ |
| 1153 | 1093 | @ on branch %z(href("%R/timeline?r=%T",zBr))%h(zBr)</a> |
| 1154 | 1094 | } |
| 1155 | - @ - %w(zCom) (user: | |
| 1095 | + @ - %!w(zCom) (user: | |
| 1156 | 1096 | hyperlink_to_user(zUser,zDate,")"); |
| 1157 | 1097 | if( g.perm.Hyperlink ){ |
| 1158 | 1098 | @ %z(href("%R/annotate?checkin=%S&filename=%T",zVers,zName)) |
| 1159 | 1099 | @ [annotate]</a> |
| 1160 | 1100 | } |
| @@ -1233,11 +1173,11 @@ | ||
| 1233 | 1173 | @ Control file referencing |
| 1234 | 1174 | } |
| 1235 | 1175 | if( zType[0]!='e' ){ |
| 1236 | 1176 | hyperlink_to_uuid(zUuid); |
| 1237 | 1177 | } |
| 1238 | - @ - %w(zCom) by | |
| 1178 | + @ - %!w(zCom) by | |
| 1239 | 1179 | hyperlink_to_user(zUser,zDate," on"); |
| 1240 | 1180 | hyperlink_to_date(zDate, "."); |
| 1241 | 1181 | if( pDownloadName && blob_size(pDownloadName)==0 ){ |
| 1242 | 1182 | blob_appendf(pDownloadName, "%.10s.txt", zUuid); |
| 1243 | 1183 | } |
| @@ -1740,11 +1680,11 @@ | ||
| 1740 | 1680 | const char *zUuid; |
| 1741 | 1681 | char zTktName[UUID_SIZE+1]; |
| 1742 | 1682 | Manifest *pTktChng; |
| 1743 | 1683 | int modPending; |
| 1744 | 1684 | const char *zModAction; |
| 1745 | - | |
| 1685 | + char *zTktTitle; | |
| 1746 | 1686 | login_check_credentials(); |
| 1747 | 1687 | if( !g.perm.RdTkt ){ login_needed(); return; } |
| 1748 | 1688 | rid = name_to_rid_www("name"); |
| 1749 | 1689 | if( rid==0 ){ fossil_redirect_home(); } |
| 1750 | 1690 | zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid); |
| @@ -1769,10 +1709,13 @@ | ||
| 1769 | 1709 | } |
| 1770 | 1710 | if( strcmp(zModAction,"approve")==0 ){ |
| 1771 | 1711 | moderation_approve(rid); |
| 1772 | 1712 | } |
| 1773 | 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; | |
| 1774 | 1717 | style_header("Ticket Change Details"); |
| 1775 | 1718 | style_submenu_element("Raw", "Raw", "%R/artifact/%S", zUuid); |
| 1776 | 1719 | style_submenu_element("History", "History", "%R/tkthistory/%s", zTktName); |
| 1777 | 1720 | style_submenu_element("Page", "Page", "%R/tktview/%t", zTktName); |
| 1778 | 1721 | style_submenu_element("Timeline", "Timeline", "%R/tkttimeline/%t", zTktName); |
| @@ -1793,18 +1736,23 @@ | ||
| 1793 | 1736 | modPending = moderation_pending(rid); |
| 1794 | 1737 | if( modPending ){ |
| 1795 | 1738 | @ <span class="modpending">*** Awaiting Moderator Approval ***</span> |
| 1796 | 1739 | } |
| 1797 | 1740 | @ <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> | |
| 1799 | 1746 | @ <tr><th>Date:</th><td> |
| 1800 | 1747 | hyperlink_to_date(zDate, "</td></tr>"); |
| 1801 | 1748 | @ <tr><th>User:</th><td> |
| 1802 | 1749 | hyperlink_to_user(pTktChng->zUser, zDate, "</td></tr>"); |
| 1803 | 1750 | @ </table> |
| 1804 | 1751 | free(zDate); |
| 1805 | - | |
| 1752 | + free(zTktTitle); | |
| 1753 | + | |
| 1806 | 1754 | if( g.perm.ModTkt && modPending ){ |
| 1807 | 1755 | @ <div class="section">Moderation</div> |
| 1808 | 1756 | @ <blockquote> |
| 1809 | 1757 | @ <form method="POST" action="%R/tinfo/%s(zUuid)"> |
| 1810 | 1758 | @ <label><input type="radio" name="modaction" value="delete"> |
| @@ -1993,11 +1941,11 @@ | ||
| 1993 | 1941 | if( (i%8)==7 && i+1<nColor ){ |
| 1994 | 1942 | @ </tr><tr> |
| 1995 | 1943 | } |
| 1996 | 1944 | } |
| 1997 | 1945 | @ </tr><tr> |
| 1998 | - if (stdClrFound){ | |
| 1946 | + if( stdClrFound ){ | |
| 1999 | 1947 | @ <td colspan="6"> |
| 2000 | 1948 | @ <input type="radio" name="%s(zId)" value="%h(aColor[nColor].zColor)" /> |
| 2001 | 1949 | }else{ |
| 2002 | 1950 | @ <td style="background-color: %h(zDefaultColor);" colspan="6"> |
| 2003 | 1951 | @ <input type="radio" name="%s(zId)" value="%h(aColor[nColor].zColor)" |
| @@ -2222,11 +2170,11 @@ | ||
| 2222 | 2170 | if( zNewColor && zNewColor[0] ){ |
| 2223 | 2171 | @ <tr><td style="background-color: %h(zNewColor);"> |
| 2224 | 2172 | }else{ |
| 2225 | 2173 | @ <tr><td> |
| 2226 | 2174 | } |
| 2227 | - @ %w(blob_str(&comment)) | |
| 2175 | + @ %!w(blob_str(&comment)) | |
| 2228 | 2176 | blob_zero(&suffix); |
| 2229 | 2177 | blob_appendf(&suffix, "(user: %h", zNewUser); |
| 2230 | 2178 | db_prepare(&q, "SELECT substr(tagname,5) FROM tagxref, tag" |
| 2231 | 2179 | " WHERE tagname GLOB 'sym-*' AND tagxref.rid=%d" |
| 2232 | 2180 | " AND tagtype>1 AND tag.tagid=tagxref.tagid", |
| 2233 | 2181 |
| --- 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 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 Comment:</th><td>%w(zEComment)</td></tr> |
| 543 | @ <tr><th>Original 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 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 Comment:</th><td>%!w(zEComment)</td></tr> |
| 534 | @ <tr><th>Original 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 @@ | ||
| 198 | 198 | if( g.localOpen ){ |
| 199 | 199 | fossil_print("repository: %s\n", db_repository_filename()); |
| 200 | 200 | fossil_print("local-root: %s\n", g.zLocalRoot); |
| 201 | 201 | } |
| 202 | 202 | 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); | |
| 206 | 205 | } |
| 207 | -#endif | |
| 208 | 206 | fossil_print("project-code: %s\n", db_get("project-code", "")); |
| 209 | 207 | vid = g.localOpen ? db_lget_int("checkout", 0) : 0; |
| 210 | 208 | if( vid ){ |
| 211 | 209 | show_common_info(vid, "checkout:", 1, 1); |
| 212 | 210 | } |
| 213 | 211 | 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*/")); | |
| 215 | 213 | }else{ |
| 216 | 214 | int rid; |
| 217 | 215 | rid = name_to_rid(g.argv[2]); |
| 218 | 216 | if( rid==0 ){ |
| 219 | 217 | fossil_panic("no such object: %s\n", g.argv[2]); |
| @@ -314,16 +312,17 @@ | ||
| 314 | 312 | }else{ |
| 315 | 313 | blob_zero(&to); |
| 316 | 314 | } |
| 317 | 315 | blob_zero(&out); |
| 318 | 316 | 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); | |
| 320 | 318 | @ <div class="sbsdiff"> |
| 321 | 319 | @ %s(blob_str(&out)) |
| 322 | 320 | @ </div> |
| 323 | 321 | }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); | |
| 325 | 324 | @ <div class="udiff"> |
| 326 | 325 | @ %s(blob_str(&out)) |
| 327 | 326 | @ </div> |
| 328 | 327 | } |
| 329 | 328 | blob_reset(&from); |
| @@ -492,15 +491,10 @@ | ||
| 492 | 491 | char *zEUser, *zEComment; |
| 493 | 492 | const char *zUser; |
| 494 | 493 | const char *zComment; |
| 495 | 494 | const char *zDate; |
| 496 | 495 | const char *zOrigDate; |
| 497 | -#if 0 | |
| 498 | - char *zThisBranch; | |
| 499 | - double thisMtime; | |
| 500 | - int seenDiffTitle = 0; | |
| 501 | -#endif | |
| 502 | 496 | |
| 503 | 497 | style_header(zTitle); |
| 504 | 498 | login_anonymous_available(); |
| 505 | 499 | free(zTitle); |
| 506 | 500 | zEUser = db_text(0, |
| @@ -511,13 +505,10 @@ | ||
| 511 | 505 | TAG_COMMENT, rid); |
| 512 | 506 | zUser = db_column_text(&q, 2); |
| 513 | 507 | zComment = db_column_text(&q, 3); |
| 514 | 508 | zDate = db_column_text(&q,1); |
| 515 | 509 | zOrigDate = db_column_text(&q, 4); |
| 516 | -#if 0 | |
| 517 | - thisMtime = db_column_double(&q, 5); | |
| 518 | -#endif | |
| 519 | 510 | @ <div class="section">Overview</div> |
| 520 | 511 | @ <table class="label-value"> |
| 521 | 512 | @ <tr><th>SHA1 Hash:</th><td>%s(zUuid) |
| 522 | 513 | if( g.perm.Setup ){ |
| 523 | 514 | @ (Record ID: %d(rid)) |
| @@ -537,14 +528,14 @@ | ||
| 537 | 528 | }else{ |
| 538 | 529 | @ <tr><th>User:</th><td> |
| 539 | 530 | hyperlink_to_user(zUser,zDate,"</td></tr>"); |
| 540 | 531 | } |
| 541 | 532 | if( zEComment ){ |
| 542 | - @ <tr><th>Edited Comment:</th><td>%w(zEComment)</td></tr> | |
| 543 | - @ <tr><th>Original Comment:</th><td>%w(zComment)</td></tr> | |
| 533 | + @ <tr><th>Edited Comment:</th><td>%!w(zEComment)</td></tr> | |
| 534 | + @ <tr><th>Original Comment:</th><td>%!w(zComment)</td></tr> | |
| 544 | 535 | }else{ |
| 545 | - @ <tr><th>Comment:</th><td>%w(zComment)</td></tr> | |
| 536 | + @ <tr><th>Comment:</th><td>%!w(zComment)</td></tr> | |
| 546 | 537 | } |
| 547 | 538 | if( g.perm.Admin ){ |
| 548 | 539 | db_prepare(&q, |
| 549 | 540 | "SELECT rcvfrom.ipaddr, user.login, datetime(rcvfrom.mtime)" |
| 550 | 541 | " FROM blob JOIN rcvfrom USING(rcvid) LEFT JOIN user USING(uid)" |
| @@ -582,61 +573,10 @@ | ||
| 582 | 573 | const char *zTagName = db_column_text(&q, 0); |
| 583 | 574 | @ | %z(href("%R/timeline?r=%T",zTagName))%h(zTagName)</a> |
| 584 | 575 | } |
| 585 | 576 | db_finalize(&q); |
| 586 | 577 | |
| 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 | 578 | |
| 639 | 579 | /* The Download: line */ |
| 640 | 580 | if( g.perm.Zip ){ |
| 641 | 581 | char *zUrl = mprintf("%R/tarball/%t-%S.tar.gz?uuid=%s", |
| 642 | 582 | zProjName, zUuid, zUuid); |
| @@ -1150,11 +1090,11 @@ | ||
| 1150 | 1090 | @ - part of checkin |
| 1151 | 1091 | hyperlink_to_uuid(zVers); |
| 1152 | 1092 | if( zBr && zBr[0] ){ |
| 1153 | 1093 | @ on branch %z(href("%R/timeline?r=%T",zBr))%h(zBr)</a> |
| 1154 | 1094 | } |
| 1155 | - @ - %w(zCom) (user: | |
| 1095 | + @ - %!w(zCom) (user: | |
| 1156 | 1096 | hyperlink_to_user(zUser,zDate,")"); |
| 1157 | 1097 | if( g.perm.Hyperlink ){ |
| 1158 | 1098 | @ %z(href("%R/annotate?checkin=%S&filename=%T",zVers,zName)) |
| 1159 | 1099 | @ [annotate]</a> |
| 1160 | 1100 | } |
| @@ -1233,11 +1173,11 @@ | ||
| 1233 | 1173 | @ Control file referencing |
| 1234 | 1174 | } |
| 1235 | 1175 | if( zType[0]!='e' ){ |
| 1236 | 1176 | hyperlink_to_uuid(zUuid); |
| 1237 | 1177 | } |
| 1238 | - @ - %w(zCom) by | |
| 1178 | + @ - %!w(zCom) by | |
| 1239 | 1179 | hyperlink_to_user(zUser,zDate," on"); |
| 1240 | 1180 | hyperlink_to_date(zDate, "."); |
| 1241 | 1181 | if( pDownloadName && blob_size(pDownloadName)==0 ){ |
| 1242 | 1182 | blob_appendf(pDownloadName, "%.10s.txt", zUuid); |
| 1243 | 1183 | } |
| @@ -1740,11 +1680,11 @@ | ||
| 1740 | 1680 | const char *zUuid; |
| 1741 | 1681 | char zTktName[UUID_SIZE+1]; |
| 1742 | 1682 | Manifest *pTktChng; |
| 1743 | 1683 | int modPending; |
| 1744 | 1684 | const char *zModAction; |
| 1745 | - | |
| 1685 | + char *zTktTitle; | |
| 1746 | 1686 | login_check_credentials(); |
| 1747 | 1687 | if( !g.perm.RdTkt ){ login_needed(); return; } |
| 1748 | 1688 | rid = name_to_rid_www("name"); |
| 1749 | 1689 | if( rid==0 ){ fossil_redirect_home(); } |
| 1750 | 1690 | zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid); |
| @@ -1769,10 +1709,13 @@ | ||
| 1769 | 1709 | } |
| 1770 | 1710 | if( strcmp(zModAction,"approve")==0 ){ |
| 1771 | 1711 | moderation_approve(rid); |
| 1772 | 1712 | } |
| 1773 | 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; | |
| 1774 | 1717 | style_header("Ticket Change Details"); |
| 1775 | 1718 | style_submenu_element("Raw", "Raw", "%R/artifact/%S", zUuid); |
| 1776 | 1719 | style_submenu_element("History", "History", "%R/tkthistory/%s", zTktName); |
| 1777 | 1720 | style_submenu_element("Page", "Page", "%R/tktview/%t", zTktName); |
| 1778 | 1721 | style_submenu_element("Timeline", "Timeline", "%R/tkttimeline/%t", zTktName); |
| @@ -1793,18 +1736,23 @@ | ||
| 1793 | 1736 | modPending = moderation_pending(rid); |
| 1794 | 1737 | if( modPending ){ |
| 1795 | 1738 | @ <span class="modpending">*** Awaiting Moderator Approval ***</span> |
| 1796 | 1739 | } |
| 1797 | 1740 | @ <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> | |
| 1799 | 1746 | @ <tr><th>Date:</th><td> |
| 1800 | 1747 | hyperlink_to_date(zDate, "</td></tr>"); |
| 1801 | 1748 | @ <tr><th>User:</th><td> |
| 1802 | 1749 | hyperlink_to_user(pTktChng->zUser, zDate, "</td></tr>"); |
| 1803 | 1750 | @ </table> |
| 1804 | 1751 | free(zDate); |
| 1805 | - | |
| 1752 | + free(zTktTitle); | |
| 1753 | + | |
| 1806 | 1754 | if( g.perm.ModTkt && modPending ){ |
| 1807 | 1755 | @ <div class="section">Moderation</div> |
| 1808 | 1756 | @ <blockquote> |
| 1809 | 1757 | @ <form method="POST" action="%R/tinfo/%s(zUuid)"> |
| 1810 | 1758 | @ <label><input type="radio" name="modaction" value="delete"> |
| @@ -1993,11 +1941,11 @@ | ||
| 1993 | 1941 | if( (i%8)==7 && i+1<nColor ){ |
| 1994 | 1942 | @ </tr><tr> |
| 1995 | 1943 | } |
| 1996 | 1944 | } |
| 1997 | 1945 | @ </tr><tr> |
| 1998 | - if (stdClrFound){ | |
| 1946 | + if( stdClrFound ){ | |
| 1999 | 1947 | @ <td colspan="6"> |
| 2000 | 1948 | @ <input type="radio" name="%s(zId)" value="%h(aColor[nColor].zColor)" /> |
| 2001 | 1949 | }else{ |
| 2002 | 1950 | @ <td style="background-color: %h(zDefaultColor);" colspan="6"> |
| 2003 | 1951 | @ <input type="radio" name="%s(zId)" value="%h(aColor[nColor].zColor)" |
| @@ -2222,11 +2170,11 @@ | ||
| 2222 | 2170 | if( zNewColor && zNewColor[0] ){ |
| 2223 | 2171 | @ <tr><td style="background-color: %h(zNewColor);"> |
| 2224 | 2172 | }else{ |
| 2225 | 2173 | @ <tr><td> |
| 2226 | 2174 | } |
| 2227 | - @ %w(blob_str(&comment)) | |
| 2175 | + @ %!w(blob_str(&comment)) | |
| 2228 | 2176 | blob_zero(&suffix); |
| 2229 | 2177 | blob_appendf(&suffix, "(user: %h", zNewUser); |
| 2230 | 2178 | db_prepare(&q, "SELECT substr(tagname,5) FROM tagxref, tag" |
| 2231 | 2179 | " WHERE tagname GLOB 'sym-*' AND tagxref.rid=%d" |
| 2232 | 2180 | " AND tagtype>1 AND tag.tagid=tagxref.tagid", |
| 2233 | 2181 |
| --- 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 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 Comment:</th><td>%w(zEComment)</td></tr> |
| 543 | @ <tr><th>Original 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 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 Comment:</th><td>%!w(zEComment)</td></tr> |
| 534 | @ <tr><th>Original 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 @@ | ||
| 239 | 239 | C(STMT_EXEC,"Statement execution/stepping failed"); |
| 240 | 240 | C(DB_LOCKED,"Database is locked"); |
| 241 | 241 | C(DB_NEEDS_REBUILD,"Fossil repository needs to be rebuilt"); |
| 242 | 242 | C(DB_NOT_FOUND,"Fossil repository db file could not be found."); |
| 243 | 243 | C(DB_NOT_VALID, "Fossil repository db file is not valid."); |
| 244 | + C(DB_NEEDS_CHECKOUT, "Command requires a local checkout."); | |
| 244 | 245 | #undef C |
| 245 | 246 | default: |
| 246 | 247 | return "Unknown Error"; |
| 247 | 248 | } |
| 248 | 249 | } |
| @@ -1371,11 +1372,11 @@ | ||
| 1371 | 1372 | #define VAL(K,V) cson_object_set(o, #K, (V) ? (V) : cson_value_null()) |
| 1372 | 1373 | VAL(capabilities, json_cap_value()); |
| 1373 | 1374 | INT(g, argc); |
| 1374 | 1375 | INT(g, isConst); |
| 1375 | 1376 | INT(g, useAttach); |
| 1376 | - INT(g, configOpen); | |
| 1377 | + CSTR(g, zConfigDbName); | |
| 1377 | 1378 | INT(g, repositoryOpen); |
| 1378 | 1379 | INT(g, localOpen); |
| 1379 | 1380 | INT(g, minPrefix); |
| 1380 | 1381 | INT(g, fSqlTrace); |
| 1381 | 1382 | INT(g, fSqlStats); |
| @@ -1397,11 +1398,10 @@ | ||
| 1397 | 1398 | INT(g, urlIsFile); |
| 1398 | 1399 | INT(g, urlIsHttps); |
| 1399 | 1400 | INT(g, urlIsSsh); |
| 1400 | 1401 | INT(g, urlPort); |
| 1401 | 1402 | INT(g, urlDfltPort); |
| 1402 | - INT(g, dontKeepUrl); | |
| 1403 | 1403 | INT(g, useLocalauth); |
| 1404 | 1404 | INT(g, noPswd); |
| 1405 | 1405 | INT(g, userUid); |
| 1406 | 1406 | INT(g, rcvid); |
| 1407 | 1407 | INT(g, okCsrf); |
| @@ -1410,11 +1410,10 @@ | ||
| 1410 | 1410 | INT(g, nAux); |
| 1411 | 1411 | INT(g, allowSymlinks); |
| 1412 | 1412 | |
| 1413 | 1413 | CSTR(g, zMainDbType); |
| 1414 | 1414 | CSTR(g, zConfigDbType); |
| 1415 | - CSTR(g, zHome); | |
| 1416 | 1415 | CSTR(g, zLocalRoot); |
| 1417 | 1416 | CSTR(g, zPath); |
| 1418 | 1417 | CSTR(g, zExtra); |
| 1419 | 1418 | CSTR(g, zBaseURL); |
| 1420 | 1419 | CSTR(g, zTop); |
| @@ -2118,18 +2117,22 @@ | ||
| 2118 | 2117 | ** taken from zPages. zPages must be an array of objects |
| 2119 | 2118 | ** whose final entry MUST have a NULL name value or results |
| 2120 | 2119 | ** are undefined. |
| 2121 | 2120 | ** |
| 2122 | 2121 | ** 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). | |
| 2124 | 2125 | */ |
| 2125 | 2126 | static int json_pagedefs_to_string(JsonPageDef const * zPages, |
| 2126 | - Blob * pOut){ | |
| 2127 | + Blob * pOut, int filterByMode){ | |
| 2127 | 2128 | int i = 0; |
| 2128 | 2129 | 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 | + } | |
| 2131 | 2134 | blob_appendf(pOut, zPages->name, -1); |
| 2132 | 2135 | if((zPages+1)->name){ |
| 2133 | 2136 | blob_append(pOut, ", ",2); |
| 2134 | 2137 | } |
| 2135 | 2138 | } |
| @@ -2153,11 +2156,11 @@ | ||
| 2153 | 2156 | blob_init(&cmdNames,NULL,0); |
| 2154 | 2157 | if( !zErrPrefix ) { |
| 2155 | 2158 | zErrPrefix = "Try one of: "; |
| 2156 | 2159 | } |
| 2157 | 2160 | blob_append( &cmdNames, zErrPrefix, strlen(zErrPrefix) ); |
| 2158 | - json_pagedefs_to_string(pCommands, &cmdNames); | |
| 2161 | + json_pagedefs_to_string(pCommands, &cmdNames, 1); | |
| 2159 | 2162 | json_set_err(FSL_JSON_E_MISSING_ARGS, "%s", |
| 2160 | 2163 | blob_str(&cmdNames)); |
| 2161 | 2164 | blob_reset(&cmdNames); |
| 2162 | 2165 | } |
| 2163 | 2166 | |
| @@ -2246,10 +2249,12 @@ | ||
| 2246 | 2249 | cson_value * json_page_user(); |
| 2247 | 2250 | /* Impl in json_config.c. */ |
| 2248 | 2251 | cson_value * json_page_config(); |
| 2249 | 2252 | /* Impl in json_finfo.c. */ |
| 2250 | 2253 | cson_value * json_page_finfo(); |
| 2254 | +/* Impl in json_status.c. */ | |
| 2255 | +cson_value * json_page_status(); | |
| 2251 | 2256 | |
| 2252 | 2257 | /* |
| 2253 | 2258 | ** Mapping of names to JSON pages/commands. Each name is a subpath of |
| 2254 | 2259 | ** /json (in CGI mode) or a subcommand of the json command in CLI mode |
| 2255 | 2260 | */ |
| @@ -2270,10 +2275,11 @@ | ||
| 2270 | 2275 | {"query",json_page_query,0}, |
| 2271 | 2276 | {"rebuild",json_page_rebuild,0}, |
| 2272 | 2277 | {"report", json_page_report, 0}, |
| 2273 | 2278 | {"resultCodes", json_page_resultCodes,0}, |
| 2274 | 2279 | {"stat",json_page_stat,0}, |
| 2280 | +{"status", json_page_status, 0}, | |
| 2275 | 2281 | {"tag", json_page_tag,0}, |
| 2276 | 2282 | /*{"ticket", json_page_nyi,0},*/ |
| 2277 | 2283 | {"timeline", json_page_timeline,0}, |
| 2278 | 2284 | {"user",json_page_user,0}, |
| 2279 | 2285 | {"version",json_page_version,0}, |
| 2280 | 2286 |
| --- 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 |
+8
-5
| --- src/json_detail.h | ||
| +++ src/json_detail.h | ||
| @@ -103,12 +103,18 @@ | ||
| 103 | 103 | FSL_JSON_E_STMT_EXEC /*+3*/, |
| 104 | 104 | FSL_JSON_E_DB_LOCKED /*+4*/, |
| 105 | 105 | |
| 106 | 106 | FSL_JSON_E_DB_NEEDS_REBUILD = FSL_JSON_E_DB + 101, |
| 107 | 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 | - | |
| 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 | |
| 110 | 116 | }; |
| 111 | 117 | |
| 112 | 118 | |
| 113 | 119 | /* |
| 114 | 120 | ** Signature for JSON page/command callbacks. Each callback is |
| @@ -177,13 +183,10 @@ | ||
| 177 | 183 | ** <0 = CLI only, >0 = HTTP only, 0==both |
| 178 | 184 | ** |
| 179 | 185 | ** Now that we can simulate POST in CLI mode, the distinction |
| 180 | 186 | ** between them has disappeared in most (or all) cases, so 0 is |
| 181 | 187 | ** 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 | 188 | */ |
| 186 | 189 | char runMode; |
| 187 | 190 | } JsonPageDef; |
| 188 | 191 | |
| 189 | 192 | /* |
| 190 | 193 | |
| 191 | 194 | 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 |
+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 |
| --- 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 @@ | ||
| 31 | 31 | #else |
| 32 | 32 | # include <errno.h> /* errno global */ |
| 33 | 33 | #endif |
| 34 | 34 | #if INTERFACE |
| 35 | 35 | #ifdef FOSSIL_ENABLE_JSON |
| 36 | -# include "cson_amalgamation.h" /* JSON API. Needed inside the INTERFACE block! */ | |
| 36 | +# include "cson_amalgamation.h" /* JSON API. */ | |
| 37 | 37 | # include "json_detail.h" |
| 38 | 38 | #endif |
| 39 | 39 | #ifdef FOSSIL_ENABLE_TCL |
| 40 | 40 | #include "tcl.h" |
| 41 | 41 | #endif |
| @@ -114,17 +114,16 @@ | ||
| 114 | 114 | char *nameOfExe; /* Full path of executable. */ |
| 115 | 115 | int isConst; /* True if the output is unchanging */ |
| 116 | 116 | sqlite3 *db; /* The connection to the databases */ |
| 117 | 117 | sqlite3 *dbConfig; /* Separate connection for global_config table */ |
| 118 | 118 | 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 */ | |
| 120 | 120 | sqlite3_int64 now; /* Seconds since 1970 */ |
| 121 | 121 | int repositoryOpen; /* True if the main repository database is open */ |
| 122 | 122 | char *zRepositoryName; /* Name of the repository database */ |
| 123 | 123 | const char *zMainDbType;/* "configdb", "localdb", or "repository" */ |
| 124 | 124 | const char *zConfigDbType; /* "configdb", "localdb", or "repository" */ |
| 125 | - const char *zHome; /* Name of user home directory */ | |
| 126 | 125 | int localOpen; /* True if the local database is open */ |
| 127 | 126 | char *zLocalRoot; /* The directory holding the local database */ |
| 128 | 127 | int minPrefix; /* Number of digits needed for a distinct UUID */ |
| 129 | 128 | int fSqlTrace; /* True if --sqltrace flag is present */ |
| 130 | 129 | int fSqlStats; /* True if --sqltrace or --sqlstats are present */ |
| @@ -172,14 +171,15 @@ | ||
| 172 | 171 | char *urlPasswd; /* Password for http: */ |
| 173 | 172 | char *urlCanonical; /* Canonical representation of the URL */ |
| 174 | 173 | char *urlProxyAuth; /* Proxy-Authorizer: string */ |
| 175 | 174 | char *urlFossil; /* The fossil query parameter on ssh: */ |
| 176 | 175 | char *urlShell; /* The shell query parameter on ssh: */ |
| 177 | - int dontKeepUrl; /* Do not persist the URL */ | |
| 176 | + unsigned urlFlags; /* Boolean flags controlling URL processing */ | |
| 178 | 177 | |
| 179 | 178 | 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 */ | |
| 181 | 181 | int useLocalauth; /* No login required if from 127.0.0.1 */ |
| 182 | 182 | int noPswd; /* Logged in without password (on 127.0.0.1) */ |
| 183 | 183 | int userUid; /* Integer user id */ |
| 184 | 184 | |
| 185 | 185 | /* Information used to populate the RCVFROM table */ |
| @@ -223,11 +223,12 @@ | ||
| 223 | 223 | reported. In JSON mode we try to |
| 224 | 224 | always output JSON-form error |
| 225 | 225 | responses and always exit() with |
| 226 | 226 | code 0 to avoid an HTTP 500 error. |
| 227 | 227 | */ |
| 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. */ | |
| 229 | 230 | int errorDetailParanoia; /* 0=full error codes, 1=%10, 2=%100, 3=%1000 */ |
| 230 | 231 | cson_output_opt outOpt; /* formatting options for JSON mode. */ |
| 231 | 232 | cson_value * authToken; /* authentication token */ |
| 232 | 233 | char const * jsonp; /* Name of JSONP function wrapper. */ |
| 233 | 234 | unsigned char dispatchDepth /* Tells JSON command dispatching |
| @@ -252,14 +253,11 @@ | ||
| 252 | 253 | } cmd; |
| 253 | 254 | struct { /* JSON POST data. */ |
| 254 | 255 | cson_value * v; |
| 255 | 256 | cson_object * o; |
| 256 | 257 | } 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. */ | |
| 261 | 259 | cson_value * v; |
| 262 | 260 | cson_object * o; |
| 263 | 261 | } param; |
| 264 | 262 | struct { |
| 265 | 263 | cson_value * v; |
| @@ -335,11 +333,11 @@ | ||
| 335 | 333 | |
| 336 | 334 | /* |
| 337 | 335 | ** atexit() handler which frees up "some" of the resources |
| 338 | 336 | ** used by fossil. |
| 339 | 337 | */ |
| 340 | -void fossil_atexit(void) { | |
| 338 | +static void fossil_atexit(void) { | |
| 341 | 339 | #ifdef FOSSIL_ENABLE_JSON |
| 342 | 340 | cson_value_free(g.json.gc.v); |
| 343 | 341 | memset(&g.json, 0, sizeof(g.json)); |
| 344 | 342 | #endif |
| 345 | 343 | free(g.zErrMsg); |
| @@ -368,11 +366,11 @@ | ||
| 368 | 366 | char *z; /* General use string pointer */ |
| 369 | 367 | char **newArgv; /* New expanded g.argv under construction */ |
| 370 | 368 | char const * zFileName; /* input file name */ |
| 371 | 369 | FILE * zInFile; /* input FILE */ |
| 372 | 370 | #if defined(_WIN32) |
| 373 | - WCHAR buf[MAX_PATH]; | |
| 371 | + wchar_t buf[MAX_PATH]; | |
| 374 | 372 | #endif |
| 375 | 373 | |
| 376 | 374 | g.argc = argc; |
| 377 | 375 | g.argv = argv; |
| 378 | 376 | sqlite3_initialize(); |
| @@ -456,10 +454,49 @@ | ||
| 456 | 454 | } |
| 457 | 455 | return zNewArgv; |
| 458 | 456 | } |
| 459 | 457 | #endif |
| 460 | 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 | +} | |
| 461 | 498 | |
| 462 | 499 | /* |
| 463 | 500 | ** This procedure runs first. |
| 464 | 501 | */ |
| 465 | 502 | #if defined(_WIN32) && !defined(BROKEN_MINGW_CMDLINE) |
| @@ -563,263 +600,21 @@ | ||
| 563 | 600 | fossil_exit(0); |
| 564 | 601 | /*NOT_REACHED*/ |
| 565 | 602 | return 0; |
| 566 | 603 | } |
| 567 | 604 | |
| 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 | 605 | /* |
| 811 | 606 | ** Print a usage comment and quit |
| 812 | 607 | */ |
| 813 | 608 | 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); | |
| 815 | 610 | } |
| 816 | 611 | |
| 817 | 612 | /* |
| 818 | 613 | ** Remove n elements from g.argv beginning with the i-th element. |
| 819 | 614 | */ |
| 820 | -void remove_from_argv(int i, int n){ | |
| 615 | +static void remove_from_argv(int i, int n){ | |
| 821 | 616 | int j; |
| 822 | 617 | for(j=i+n; j<g.argc; i++, j++){ |
| 823 | 618 | g.argv[i] = g.argv[j]; |
| 824 | 619 | } |
| 825 | 620 | g.argc = i; |
| @@ -840,11 +635,11 @@ | ||
| 840 | 635 | const char *zReturn = 0; |
| 841 | 636 | assert( hasArg==0 || hasArg==1 ); |
| 842 | 637 | nLong = strlen(zLong); |
| 843 | 638 | for(i=1; i<g.argc; i++){ |
| 844 | 639 | char *z; |
| 845 | - if (i+hasArg >= g.argc) break; | |
| 640 | + if( i+hasArg >= g.argc ) break; | |
| 846 | 641 | z = g.argv[i]; |
| 847 | 642 | if( z[0]!='-' ) continue; |
| 848 | 643 | z++; |
| 849 | 644 | if( z[0]=='-' ){ |
| 850 | 645 | if( z[1]==0 ){ |
| @@ -934,14 +729,17 @@ | ||
| 934 | 729 | ** |
| 935 | 730 | ** List all web pages |
| 936 | 731 | */ |
| 937 | 732 | void cmd_test_webpage_list(void){ |
| 938 | 733 | 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 | + } | |
| 942 | 739 | } |
| 740 | + assert(nCmd && "page list is empty?"); | |
| 943 | 741 | multi_column_list(aCmd, nCmd); |
| 944 | 742 | } |
| 945 | 743 | |
| 946 | 744 | /* |
| 947 | 745 | ** COMMAND: version |
| @@ -967,14 +765,17 @@ | ||
| 967 | 765 | ** |
| 968 | 766 | ** %fossil help Show common commands |
| 969 | 767 | ** %fossil help --all Show both common and auxiliary commands |
| 970 | 768 | ** %fossil help --test Show test commands only |
| 971 | 769 | ** %fossil help --aux Show auxiliary commands only |
| 770 | +** %fossil help --www Show list of WWW pages | |
| 972 | 771 | */ |
| 973 | 772 | void help_cmd(void){ |
| 974 | - int rc, idx; | |
| 773 | + int rc, idx, isPage = 0; | |
| 975 | 774 | const char *z; |
| 775 | + char const * zCmdOrPage; | |
| 776 | + char const * zCmdOrPagePlural; | |
| 976 | 777 | if( g.argc<3 ){ |
| 977 | 778 | z = g.argv[0]; |
| 978 | 779 | fossil_print( |
| 979 | 780 | "Usage: %s help COMMAND\n" |
| 980 | 781 | "Common COMMANDs: (use \"%s help --all\" for a complete list)\n", |
| @@ -985,33 +786,46 @@ | ||
| 985 | 786 | } |
| 986 | 787 | if( find_option("all",0,0) ){ |
| 987 | 788 | command_list(0, CMDFLAG_1ST_TIER | CMDFLAG_2ND_TIER); |
| 988 | 789 | return; |
| 989 | 790 | } |
| 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) ){ | |
| 991 | 796 | command_list(0, CMDFLAG_2ND_TIER); |
| 992 | 797 | return; |
| 993 | 798 | } |
| 994 | - if( find_option("test",0,0) ){ | |
| 799 | + else if( find_option("test",0,0) ){ | |
| 995 | 800 | command_list(0, CMDFLAG_TEST); |
| 996 | 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"; | |
| 997 | 810 | } |
| 998 | 811 | rc = name_search(g.argv[2], aCommand, count(aCommand), &idx); |
| 999 | 812 | 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)); | |
| 1002 | 816 | fossil_exit(1); |
| 1003 | 817 | }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); | |
| 1006 | 820 | command_list(g.argv[2], 0xff); |
| 1007 | 821 | fossil_exit(1); |
| 1008 | 822 | } |
| 1009 | - z = aCmdHelp[idx]; | |
| 823 | + z = aCmdHelp[idx].zText; | |
| 1010 | 824 | 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); | |
| 1013 | 827 | } |
| 1014 | 828 | while( *z ){ |
| 1015 | 829 | if( *z=='%' && strncmp(z, "%fossil", 7)==0 ){ |
| 1016 | 830 | fossil_print("%s", g.argv[0]); |
| 1017 | 831 | z += 7; |
| @@ -1033,20 +847,20 @@ | ||
| 1033 | 847 | if( zCmd==0 ) zCmd = P("name"); |
| 1034 | 848 | style_header("Command-line Help"); |
| 1035 | 849 | if( zCmd ){ |
| 1036 | 850 | int rc, idx; |
| 1037 | 851 | char *z, *s, *d; |
| 1038 | - | |
| 852 | + char const * zCmdOrPage = ('/'==*zCmd) ? "page" : "command"; | |
| 1039 | 853 | 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> | |
| 1041 | 855 | rc = name_search(zCmd, aCommand, count(aCommand), &idx); |
| 1042 | 856 | if( rc==1 ){ |
| 1043 | 857 | @ unknown command: %s(zCmd) |
| 1044 | 858 | }else if( rc==2 ){ |
| 1045 | 859 | @ ambiguous command prefix: %s(zCmd) |
| 1046 | 860 | }else{ |
| 1047 | - z = (char*)aCmdHelp[idx]; | |
| 861 | + z = (char*)aCmdHelp[idx].zText; | |
| 1048 | 862 | if( z==0 ){ |
| 1049 | 863 | @ no help available for the %s(aCommand[idx].zName) command |
| 1050 | 864 | }else{ |
| 1051 | 865 | z=s=d=mprintf("%s",z); |
| 1052 | 866 | while( *s ){ |
| @@ -1068,21 +882,52 @@ | ||
| 1068 | 882 | |
| 1069 | 883 | @ <h1>Available commands:</h1> |
| 1070 | 884 | @ <table border="0"><tr> |
| 1071 | 885 | for(i=j=0; i<count(aCommand); i++){ |
| 1072 | 886 | const char *z = aCommand[i].zName; |
| 1073 | - if( strncmp(z,"test",4)==0 ) continue; | |
| 887 | + if( '/'==*z || strncmp(z,"test",4)==0 ) continue; | |
| 1074 | 888 | j++; |
| 1075 | 889 | } |
| 1076 | 890 | n = (j+6)/7; |
| 1077 | 891 | for(i=j=0; i<count(aCommand); i++){ |
| 1078 | 892 | 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; | |
| 1080 | 921 | if( j==0 ){ |
| 1081 | 922 | @ <td valign="top"><ul> |
| 1082 | 923 | } |
| 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 | + } | |
| 1084 | 929 | j++; |
| 1085 | 930 | if( j>=n ){ |
| 1086 | 931 | @ </ul></td> |
| 1087 | 932 | j = 0; |
| 1088 | 933 | } |
| @@ -1089,10 +934,11 @@ | ||
| 1089 | 934 | } |
| 1090 | 935 | if( j>0 ){ |
| 1091 | 936 | @ </ul></td> |
| 1092 | 937 | } |
| 1093 | 938 | @ </tr></table> |
| 939 | + | |
| 1094 | 940 | } |
| 1095 | 941 | style_footer(); |
| 1096 | 942 | } |
| 1097 | 943 | |
| 1098 | 944 | /* |
| @@ -1105,11 +951,11 @@ | ||
| 1105 | 951 | style_header("Testpage: All Help Text"); |
| 1106 | 952 | for(i=0; i<count(aCommand); i++){ |
| 1107 | 953 | if( memcmp(aCommand[i].zName, "test", 4)==0 ) continue; |
| 1108 | 954 | @ <h2>%s(aCommand[i].zName):</h2> |
| 1109 | 955 | @ <blockquote><pre> |
| 1110 | - @ %h(aCmdHelp[i]) | |
| 956 | + @ %h(aCmdHelp[i].zText) | |
| 1111 | 957 | @ </pre></blockquote> |
| 1112 | 958 | } |
| 1113 | 959 | style_footer(); |
| 1114 | 960 | } |
| 1115 | 961 | |
| @@ -1285,11 +1131,11 @@ | ||
| 1285 | 1131 | zRepo = zToFree = mprintf("%s%.*s.fossil",g.zRepositoryName,i,zPathInfo); |
| 1286 | 1132 | |
| 1287 | 1133 | /* To avoid mischief, make sure the repository basename contains no |
| 1288 | 1134 | ** characters other than alphanumerics, "/", "_", "-", and ".", and |
| 1289 | 1135 | ** 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 | |
| 1291 | 1137 | ** satisfy these constraints is converted into "_". |
| 1292 | 1138 | */ |
| 1293 | 1139 | szFile = 0; |
| 1294 | 1140 | for(j=strlen(g.zRepositoryName)+1, k=0; zRepo[j] && k<i-1; j++, k++){ |
| 1295 | 1141 | char c = zRepo[j]; |
| @@ -1504,10 +1350,61 @@ | ||
| 1504 | 1350 | |
| 1505 | 1351 | /* Return the result. |
| 1506 | 1352 | */ |
| 1507 | 1353 | cgi_reply(); |
| 1508 | 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 | +} | |
| 1509 | 1406 | |
| 1510 | 1407 | /* |
| 1511 | 1408 | ** COMMAND: cgi* |
| 1512 | 1409 | ** |
| 1513 | 1410 | ** Usage: %fossil ?cgi? SCRIPT |
| @@ -1604,61 +1501,10 @@ | ||
| 1604 | 1501 | }else{ |
| 1605 | 1502 | process_one_web_page(zNotFound, pFileGlob); |
| 1606 | 1503 | } |
| 1607 | 1504 | } |
| 1608 | 1505 | |
| 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 | 1506 | /* |
| 1661 | 1507 | ** If g.argv[2] exists then it is either the name of a repository |
| 1662 | 1508 | ** that will be used by a server, or else it is a directory that |
| 1663 | 1509 | ** contains multiple repositories that can be served. If g.argv[2] |
| 1664 | 1510 | ** is a directory, the repositories it contains must be named |
| @@ -1745,11 +1591,11 @@ | ||
| 1745 | 1591 | const char *zHost; |
| 1746 | 1592 | const char *zAltBase; |
| 1747 | 1593 | const char *zFileGlob; |
| 1748 | 1594 | |
| 1749 | 1595 | /* 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 | |
| 1751 | 1597 | ** shell. This option is for internal use and is undocumented. |
| 1752 | 1598 | */ |
| 1753 | 1599 | zFileGlob = find_option("files-urlenc",0,1); |
| 1754 | 1600 | if( zFileGlob ){ |
| 1755 | 1601 | char *z = mprintf("%s", zFileGlob); |
| @@ -1849,12 +1695,12 @@ | ||
| 1849 | 1695 | ** |
| 1850 | 1696 | ** The "ui" command automatically starts a web browser after initializing |
| 1851 | 1697 | ** the web server. The "ui" command also binds to 127.0.0.1 and so will |
| 1852 | 1698 | ** only process HTTP traffic from the local machine. |
| 1853 | 1699 | ** |
| 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 | |
| 1856 | 1702 | ** a prefix of the URL pathname is used to search the directory for an |
| 1857 | 1703 | ** appropriate repository. To thwart mischief, the pathname in the URL must |
| 1858 | 1704 | ** contain only alphanumerics, "_", "/", "-", and ".", and no "-" may |
| 1859 | 1705 | ** occur after "/", and every "." must be surrounded on both sides by |
| 1860 | 1706 | ** alphanumerics. Any pathname that does not satisfy these constraints |
| @@ -1891,10 +1737,11 @@ | ||
| 1891 | 1737 | int isUiCmd; /* True if command is "ui", not "server' */ |
| 1892 | 1738 | const char *zNotFound; /* The --notfound option or NULL */ |
| 1893 | 1739 | int flags = 0; /* Server flags */ |
| 1894 | 1740 | const char *zAltBase; /* Argument to the --baseurl option */ |
| 1895 | 1741 | const char *zFileGlob; /* Static content must match this */ |
| 1742 | + char *zIpAddr = 0; /* Bind to this IP address */ | |
| 1896 | 1743 | |
| 1897 | 1744 | #if defined(_WIN32) |
| 1898 | 1745 | const char *zStopperFile; /* Name of file used to terminate server */ |
| 1899 | 1746 | zStopperFile = find_option("stopper", 0, 1); |
| 1900 | 1747 | #endif |
| @@ -1917,10 +1764,16 @@ | ||
| 1917 | 1764 | flags |= HTTP_SERVER_LOCALHOST; |
| 1918 | 1765 | g.useLocalauth = 1; |
| 1919 | 1766 | } |
| 1920 | 1767 | find_server_repository(isUiCmd && zNotFound==0); |
| 1921 | 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 | + } | |
| 1922 | 1775 | iPort = mxPort = atoi(zPort); |
| 1923 | 1776 | }else{ |
| 1924 | 1777 | iPort = db_get_int("http-port", 8080); |
| 1925 | 1778 | mxPort = iPort+100; |
| 1926 | 1779 | } |
| @@ -1928,11 +1781,12 @@ | ||
| 1928 | 1781 | /* Unix implementation */ |
| 1929 | 1782 | if( isUiCmd ){ |
| 1930 | 1783 | #if !defined(__DARWIN__) && !defined(__APPLE__) && !defined(__HAIKU__) |
| 1931 | 1784 | zBrowser = db_get("web-browser", 0); |
| 1932 | 1785 | 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" }; | |
| 1934 | 1788 | int i; |
| 1935 | 1789 | zBrowser = "echo"; |
| 1936 | 1790 | for(i=0; i<sizeof(azBrowserProg)/sizeof(azBrowserProg[0]); i++){ |
| 1937 | 1791 | if( binaryOnPath(azBrowserProg[i]) ){ |
| 1938 | 1792 | zBrowser = azBrowserProg[i]; |
| @@ -1941,14 +1795,18 @@ | ||
| 1941 | 1795 | } |
| 1942 | 1796 | } |
| 1943 | 1797 | #else |
| 1944 | 1798 | zBrowser = db_get("web-browser", "open"); |
| 1945 | 1799 | #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 | + } | |
| 1947 | 1805 | } |
| 1948 | 1806 | db_close(1); |
| 1949 | - if( cgi_http_server(iPort, mxPort, zBrowserCmd, flags) ){ | |
| 1807 | + if( cgi_http_server(iPort, mxPort, zBrowserCmd, zIpAddr, flags) ){ | |
| 1950 | 1808 | fossil_fatal("unable to listen on TCP socket %d", iPort); |
| 1951 | 1809 | } |
| 1952 | 1810 | g.sslNotAvailable = 1; |
| 1953 | 1811 | g.httpIn = stdin; |
| 1954 | 1812 | g.httpOut = stdout; |
| @@ -1962,16 +1820,20 @@ | ||
| 1962 | 1820 | process_one_web_page(zNotFound, glob_create(zFileGlob)); |
| 1963 | 1821 | #else |
| 1964 | 1822 | /* Win32 implementation */ |
| 1965 | 1823 | if( isUiCmd ){ |
| 1966 | 1824 | 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 | + } | |
| 1968 | 1830 | } |
| 1969 | 1831 | db_close(1); |
| 1970 | 1832 | if( win32_http_service(iPort, zNotFound, zFileGlob, flags) ){ |
| 1971 | 1833 | win32_http_server(iPort, mxPort, zBrowserCmd, |
| 1972 | - zStopperFile, zNotFound, zFileGlob, flags); | |
| 1834 | + zStopperFile, zNotFound, zFileGlob, zIpAddr, flags); | |
| 1973 | 1835 | } |
| 1974 | 1836 | #endif |
| 1975 | 1837 | } |
| 1976 | 1838 | |
| 1977 | 1839 | /* |
| 1978 | 1840 |
| --- 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 @@ | ||
| 60 | 60 | $(SRCDIR)/json_dir.c \ |
| 61 | 61 | $(SRCDIR)/json_finfo.c \ |
| 62 | 62 | $(SRCDIR)/json_login.c \ |
| 63 | 63 | $(SRCDIR)/json_query.c \ |
| 64 | 64 | $(SRCDIR)/json_report.c \ |
| 65 | + $(SRCDIR)/json_status.c \ | |
| 65 | 66 | $(SRCDIR)/json_tag.c \ |
| 66 | 67 | $(SRCDIR)/json_timeline.c \ |
| 67 | 68 | $(SRCDIR)/json_user.c \ |
| 68 | 69 | $(SRCDIR)/json_wiki.c \ |
| 69 | 70 | $(SRCDIR)/leaf.c \ |
| @@ -107,10 +108,11 @@ | ||
| 107 | 108 | $(SRCDIR)/unicode.c \ |
| 108 | 109 | $(SRCDIR)/update.c \ |
| 109 | 110 | $(SRCDIR)/url.c \ |
| 110 | 111 | $(SRCDIR)/user.c \ |
| 111 | 112 | $(SRCDIR)/utf8.c \ |
| 113 | + $(SRCDIR)/util.c \ | |
| 112 | 114 | $(SRCDIR)/verify.c \ |
| 113 | 115 | $(SRCDIR)/vfile.c \ |
| 114 | 116 | $(SRCDIR)/wiki.c \ |
| 115 | 117 | $(SRCDIR)/wikiformat.c \ |
| 116 | 118 | $(SRCDIR)/winhttp.c \ |
| @@ -166,10 +168,11 @@ | ||
| 166 | 168 | $(OBJDIR)/json_dir_.c \ |
| 167 | 169 | $(OBJDIR)/json_finfo_.c \ |
| 168 | 170 | $(OBJDIR)/json_login_.c \ |
| 169 | 171 | $(OBJDIR)/json_query_.c \ |
| 170 | 172 | $(OBJDIR)/json_report_.c \ |
| 173 | + $(OBJDIR)/json_status_.c \ | |
| 171 | 174 | $(OBJDIR)/json_tag_.c \ |
| 172 | 175 | $(OBJDIR)/json_timeline_.c \ |
| 173 | 176 | $(OBJDIR)/json_user_.c \ |
| 174 | 177 | $(OBJDIR)/json_wiki_.c \ |
| 175 | 178 | $(OBJDIR)/leaf_.c \ |
| @@ -213,10 +216,11 @@ | ||
| 213 | 216 | $(OBJDIR)/unicode_.c \ |
| 214 | 217 | $(OBJDIR)/update_.c \ |
| 215 | 218 | $(OBJDIR)/url_.c \ |
| 216 | 219 | $(OBJDIR)/user_.c \ |
| 217 | 220 | $(OBJDIR)/utf8_.c \ |
| 221 | + $(OBJDIR)/util_.c \ | |
| 218 | 222 | $(OBJDIR)/verify_.c \ |
| 219 | 223 | $(OBJDIR)/vfile_.c \ |
| 220 | 224 | $(OBJDIR)/wiki_.c \ |
| 221 | 225 | $(OBJDIR)/wikiformat_.c \ |
| 222 | 226 | $(OBJDIR)/winhttp_.c \ |
| @@ -272,10 +276,11 @@ | ||
| 272 | 276 | $(OBJDIR)/json_dir.o \ |
| 273 | 277 | $(OBJDIR)/json_finfo.o \ |
| 274 | 278 | $(OBJDIR)/json_login.o \ |
| 275 | 279 | $(OBJDIR)/json_query.o \ |
| 276 | 280 | $(OBJDIR)/json_report.o \ |
| 281 | + $(OBJDIR)/json_status.o \ | |
| 277 | 282 | $(OBJDIR)/json_tag.o \ |
| 278 | 283 | $(OBJDIR)/json_timeline.o \ |
| 279 | 284 | $(OBJDIR)/json_user.o \ |
| 280 | 285 | $(OBJDIR)/json_wiki.o \ |
| 281 | 286 | $(OBJDIR)/leaf.o \ |
| @@ -319,10 +324,11 @@ | ||
| 319 | 324 | $(OBJDIR)/unicode.o \ |
| 320 | 325 | $(OBJDIR)/update.o \ |
| 321 | 326 | $(OBJDIR)/url.o \ |
| 322 | 327 | $(OBJDIR)/user.o \ |
| 323 | 328 | $(OBJDIR)/utf8.o \ |
| 329 | + $(OBJDIR)/util.o \ | |
| 324 | 330 | $(OBJDIR)/verify.o \ |
| 325 | 331 | $(OBJDIR)/vfile.o \ |
| 326 | 332 | $(OBJDIR)/wiki.o \ |
| 327 | 333 | $(OBJDIR)/wikiformat.o \ |
| 328 | 334 | $(OBJDIR)/winhttp.o \ |
| @@ -396,14 +402,14 @@ | ||
| 396 | 402 | |
| 397 | 403 | |
| 398 | 404 | $(OBJDIR)/page_index.h: $(TRANS_SRC) $(OBJDIR)/mkindex |
| 399 | 405 | $(OBJDIR)/mkindex $(TRANS_SRC) >$@ |
| 400 | 406 | $(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 | |
| 402 | 408 | touch $(OBJDIR)/headers |
| 403 | 409 | $(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 | |
| 405 | 411 | Makefile: |
| 406 | 412 | $(OBJDIR)/add_.c: $(SRCDIR)/add.c $(OBJDIR)/translate |
| 407 | 413 | $(OBJDIR)/translate $(SRCDIR)/add.c >$(OBJDIR)/add_.c |
| 408 | 414 | |
| 409 | 415 | $(OBJDIR)/add.o: $(OBJDIR)/add_.c $(OBJDIR)/add.h $(SRCDIR)/config.h |
| @@ -737,10 +743,17 @@ | ||
| 737 | 743 | |
| 738 | 744 | $(OBJDIR)/json_report.o: $(OBJDIR)/json_report_.c $(OBJDIR)/json_report.h $(SRCDIR)/config.h |
| 739 | 745 | $(XTCC) -o $(OBJDIR)/json_report.o -c $(OBJDIR)/json_report_.c |
| 740 | 746 | |
| 741 | 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 | |
| 742 | 755 | $(OBJDIR)/json_tag_.c: $(SRCDIR)/json_tag.c $(OBJDIR)/translate |
| 743 | 756 | $(OBJDIR)/translate $(SRCDIR)/json_tag.c >$(OBJDIR)/json_tag_.c |
| 744 | 757 | |
| 745 | 758 | $(OBJDIR)/json_tag.o: $(OBJDIR)/json_tag_.c $(OBJDIR)/json_tag.h $(SRCDIR)/config.h |
| 746 | 759 | $(XTCC) -o $(OBJDIR)/json_tag.o -c $(OBJDIR)/json_tag_.c |
| @@ -1066,10 +1079,17 @@ | ||
| 1066 | 1079 | |
| 1067 | 1080 | $(OBJDIR)/utf8.o: $(OBJDIR)/utf8_.c $(OBJDIR)/utf8.h $(SRCDIR)/config.h |
| 1068 | 1081 | $(XTCC) -o $(OBJDIR)/utf8.o -c $(OBJDIR)/utf8_.c |
| 1069 | 1082 | |
| 1070 | 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 | |
| 1071 | 1091 | $(OBJDIR)/verify_.c: $(SRCDIR)/verify.c $(OBJDIR)/translate |
| 1072 | 1092 | $(OBJDIR)/translate $(SRCDIR)/verify.c >$(OBJDIR)/verify_.c |
| 1073 | 1093 | |
| 1074 | 1094 | $(OBJDIR)/verify.o: $(OBJDIR)/verify_.c $(OBJDIR)/verify.h $(SRCDIR)/config.h |
| 1075 | 1095 | $(XTCC) -o $(OBJDIR)/verify.o -c $(OBJDIR)/verify_.c |
| 1076 | 1096 |
| --- 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 |
+8
-4
| --- src/makemake.tcl | ||
| +++ src/makemake.tcl | ||
| @@ -63,10 +63,11 @@ | ||
| 63 | 63 | json_dir |
| 64 | 64 | json_finfo |
| 65 | 65 | json_login |
| 66 | 66 | json_query |
| 67 | 67 | json_report |
| 68 | + json_status | |
| 68 | 69 | json_tag |
| 69 | 70 | json_timeline |
| 70 | 71 | json_user |
| 71 | 72 | json_wiki |
| 72 | 73 | leaf |
| @@ -110,10 +111,11 @@ | ||
| 110 | 111 | unicode |
| 111 | 112 | update |
| 112 | 113 | url |
| 113 | 114 | user |
| 114 | 115 | utf8 |
| 116 | + util | |
| 115 | 117 | verify |
| 116 | 118 | vfile |
| 117 | 119 | wiki |
| 118 | 120 | wikiformat |
| 119 | 121 | winhttp |
| @@ -268,11 +270,11 @@ | ||
| 268 | 270 | writeln "\t\$(OBJDIR)/mkindex \$(TRANS_SRC) >$@" |
| 269 | 271 | writeln "\$(OBJDIR)/headers:\t\$(OBJDIR)/page_index.h \$(OBJDIR)/makeheaders \$(OBJDIR)/VERSION.h" |
| 270 | 272 | writeln "\t\$(OBJDIR)/makeheaders $mhargs" |
| 271 | 273 | writeln "\ttouch \$(OBJDIR)/headers" |
| 272 | 274 | 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" | |
| 274 | 276 | writeln "Makefile:" |
| 275 | 277 | set extra_h(main) \$(OBJDIR)/page_index.h |
| 276 | 278 | |
| 277 | 279 | foreach s [lsort $src] { |
| 278 | 280 | writeln "\$(OBJDIR)/${s}_.c:\t\$(SRCDIR)/$s.c \$(OBJDIR)/translate" |
| @@ -418,12 +420,12 @@ | ||
| 418 | 420 | #### The directories where the OpenSSL include and library files are located. |
| 419 | 421 | # The recommended usage here is to use the Sysinternals junction tool |
| 420 | 422 | # to create a hard link between an "openssl-1.x" sub-directory of the |
| 421 | 423 | # Fossil source code directory and the target OpenSSL source directory. |
| 422 | 424 | # |
| 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 | |
| 425 | 427 | |
| 426 | 428 | #### Either the directory where the Tcl library is installed or the Tcl |
| 427 | 429 | # source code directory resides (depending on the value of the macro |
| 428 | 430 | # FOSSIL_TCL_SOURCE). If this points to the Tcl install directory, |
| 429 | 431 | # this directory must have "include" and "lib" sub-directories. If |
| @@ -752,11 +754,11 @@ | ||
| 752 | 754 | writeln "\t\$(XTCC) $opt -c \$(SRCDIR)/sqlite3.c -o \$(OBJDIR)/sqlite3.o\n" |
| 753 | 755 | |
| 754 | 756 | set opt {} |
| 755 | 757 | writeln "\$(OBJDIR)/cson_amalgamation.o:\t\$(SRCDIR)/cson_amalgamation.c" |
| 756 | 758 | 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" | |
| 758 | 760 | |
| 759 | 761 | writeln "\$(OBJDIR)/shell.o:\t\$(SRCDIR)/shell.c \$(SRCDIR)/sqlite3.h" |
| 760 | 762 | set opt {-Dmain=sqlite3_shell} |
| 761 | 763 | append opt " -DSQLITE_OMIT_LOAD_EXTENSION=1" |
| 762 | 764 | writeln "\t\$(XTCC) $opt -c \$(SRCDIR)/shell.c -o \$(OBJDIR)/shell.o\n" |
| @@ -900,10 +902,11 @@ | ||
| 900 | 902 | $(OBJDIR)\json_dir$O : $(SRCDIR)\json_detail.h |
| 901 | 903 | $(OBJDIR)\json_finfo$O : $(SRCDIR)\json_detail.h |
| 902 | 904 | $(OBJDIR)\json_login$O : $(SRCDIR)\json_detail.h |
| 903 | 905 | $(OBJDIR)\json_query$O : $(SRCDIR)\json_detail.h |
| 904 | 906 | $(OBJDIR)\json_report$O : $(SRCDIR)\json_detail.h |
| 907 | +$(OBJDIR)\json_status$O : $(SRCDIR)\json_detail.h | |
| 905 | 908 | $(OBJDIR)\json_tag$O : $(SRCDIR)\json_detail.h |
| 906 | 909 | $(OBJDIR)\json_timeline$O : $(SRCDIR)\json_detail.h |
| 907 | 910 | $(OBJDIR)\json_user$O : $(SRCDIR)\json_detail.h |
| 908 | 911 | $(OBJDIR)\json_wiki$O : $(SRCDIR)\json_detail.h |
| 909 | 912 | |
| @@ -1096,10 +1099,11 @@ | ||
| 1096 | 1099 | $(OBJDIR)\json_dir$O : $(SRCDIR)\json_detail.h |
| 1097 | 1100 | $(OBJDIR)\json_finfo$O : $(SRCDIR)\json_detail.h |
| 1098 | 1101 | $(OBJDIR)\json_login$O : $(SRCDIR)\json_detail.h |
| 1099 | 1102 | $(OBJDIR)\json_query$O : $(SRCDIR)\json_detail.h |
| 1100 | 1103 | $(OBJDIR)\json_report$O : $(SRCDIR)\json_detail.h |
| 1104 | +$(OBJDIR)\json_status$O : $(SRCDIR)\json_detail.h | |
| 1101 | 1105 | $(OBJDIR)\json_tag$O : $(SRCDIR)\json_detail.h |
| 1102 | 1106 | $(OBJDIR)\json_timeline$O : $(SRCDIR)\json_detail.h |
| 1103 | 1107 | $(OBJDIR)\json_user$O : $(SRCDIR)\json_detail.h |
| 1104 | 1108 | $(OBJDIR)\json_wiki$O : $(SRCDIR)\json_detail.h |
| 1105 | 1109 | |
| 1106 | 1110 |
| --- 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 @@ | ||
| 258 | 258 | memset(p, 0, count-8); |
| 259 | 259 | } |
| 260 | 260 | byteReverse(ctx->in, 14); |
| 261 | 261 | |
| 262 | 262 | /* 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)); | |
| 265 | 264 | |
| 266 | 265 | MD5Transform(ctx->buf, (uint32 *)ctx->in); |
| 267 | 266 | byteReverse((unsigned char *)ctx->buf, 4); |
| 268 | 267 | memcpy(digest, ctx->buf, 16); |
| 269 | 268 | memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */ |
| 270 | 269 |
| --- 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 @@ | ||
| 174 | 174 | if( strncmp(zLine, "**", 2)==0 |
| 175 | 175 | && isspace(zLine[2]) |
| 176 | 176 | && strlen(zLine)<sizeof(zHelp)-nHelp-1 |
| 177 | 177 | && nUsed>nFixed |
| 178 | 178 | && memcmp(zLine,"** COMMAND:",11)!=0 |
| 179 | + && memcmp(zLine,"** WEBPAGE:",11)!=0 | |
| 179 | 180 | ){ |
| 180 | 181 | if( zLine[2]=='\n' ){ |
| 181 | 182 | zHelp[nHelp++] = '\n'; |
| 182 | 183 | }else{ |
| 183 | 184 | if( strncmp(&zLine[3], "Usage: ", 6)==0 ) nHelp = 0; |
| @@ -242,11 +243,10 @@ | ||
| 242 | 243 | /* |
| 243 | 244 | ** Build the binary search table. |
| 244 | 245 | */ |
| 245 | 246 | void build_table(void){ |
| 246 | 247 | int i; |
| 247 | - int nType0; | |
| 248 | 248 | |
| 249 | 249 | qsort(aEntry, nFixed, sizeof(aEntry[0]), e_compare); |
| 250 | 250 | for(i=0; i<nFixed; i++){ |
| 251 | 251 | if( aEntry[i].zIf ) printf("%s", aEntry[i].zIf); |
| 252 | 252 | printf("extern void %s(void);\n", aEntry[i].zFunc); |
| @@ -260,10 +260,11 @@ | ||
| 260 | 260 | " char cmdFlags;\n" |
| 261 | 261 | "};\n" |
| 262 | 262 | "#define CMDFLAG_1ST_TIER 0x01\n" |
| 263 | 263 | "#define CMDFLAG_2ND_TIER 0x02\n" |
| 264 | 264 | "#define CMDFLAG_TEST 0x04\n" |
| 265 | + "#define CMDFLAG_WEBPAGE 0x08\n" | |
| 265 | 266 | "static const NameMap aWebpage[] = {\n" |
| 266 | 267 | ); |
| 267 | 268 | for(i=0; i<nFixed && aEntry[i].eType==0; i++){ |
| 268 | 269 | const char *z = aEntry[i].zPath; |
| 269 | 270 | int n = strlen(z); |
| @@ -275,36 +276,38 @@ | ||
| 275 | 276 | (int)(35-strlen(aEntry[i].zFunc)), "" |
| 276 | 277 | ); |
| 277 | 278 | if( aEntry[i].zIf ) printf("#endif\n"); |
| 278 | 279 | } |
| 279 | 280 | printf("};\n"); |
| 280 | - nType0 = i; | |
| 281 | 281 | printf( |
| 282 | 282 | "static const NameMap aCommand[] = {\n" |
| 283 | 283 | ); |
| 284 | - for(i=nType0; i<nFixed && aEntry[i].eType==1; i++){ | |
| 284 | + for(i=0; i<nFixed /*&& aEntry[i].eType==1*/; i++){ | |
| 285 | 285 | const char *z = aEntry[i].zPath; |
| 286 | 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; | |
| 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 | + } | |
| 293 | 295 | } |
| 294 | 296 | 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) ? "/" : "", | |
| 296 | 299 | n, z, |
| 297 | 300 | 25-n, "", |
| 298 | 301 | aEntry[i].zFunc, |
| 299 | 302 | (int)(35-strlen(aEntry[i].zFunc)), "", |
| 300 | 303 | cmdFlags |
| 301 | 304 | ); |
| 302 | 305 | if( aEntry[i].zIf ) printf("#endif\n"); |
| 303 | 306 | } |
| 304 | 307 | printf("};\n"); |
| 305 | - for(i=nType0; i<nFixed; i++){ | |
| 308 | + for(i=0; i<nFixed; i++){ | |
| 306 | 309 | char *z = aEntry[i].zHelp; |
| 307 | 310 | if( z && z[0] ){ |
| 308 | 311 | if( aEntry[i].zIf ) printf("%s", aEntry[i].zIf); |
| 309 | 312 | printf("static const char zHelp_%s[] = \n", aEntry[i].zFunc); |
| 310 | 313 | printf(" \""); |
| @@ -321,19 +324,21 @@ | ||
| 321 | 324 | printf("\";\n"); |
| 322 | 325 | if( aEntry[i].zIf ) printf("#endif\n"); |
| 323 | 326 | aEntry[i].zHelp[0] = 0; |
| 324 | 327 | } |
| 325 | 328 | } |
| 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++){ | |
| 330 | 335 | if( aEntry[i].zIf ) printf("%s", aEntry[i].zIf); |
| 331 | 336 | if( aEntry[i].zHelp==0 ){ |
| 332 | - printf(" 0,\n"); | |
| 337 | + printf("{%d, 0},\n", aEntry[i].eType); | |
| 333 | 338 | }else{ |
| 334 | - printf(" zHelp_%s,\n", aEntry[i].zFunc); | |
| 339 | + printf("{%d, zHelp_%s},\n", aEntry[i].eType, aEntry[i].zFunc); | |
| 335 | 340 | } |
| 336 | 341 | if( aEntry[i].zIf ) printf("#endif\n"); |
| 337 | 342 | } |
| 338 | 343 | printf("};\n"); |
| 339 | 344 | } |
| 340 | 345 |
| --- 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 @@ | ||
| 13 | 13 | ** [email protected] |
| 14 | 14 | ** http://www.hwaci.com/drh/ |
| 15 | 15 | ** |
| 16 | 16 | ******************************************************************************* |
| 17 | 17 | ** |
| 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. | |
| 19 | 20 | */ |
| 20 | 21 | #include "config.h" |
| 21 | 22 | #include "printf.h" |
| 23 | +#if defined(_WIN32) | |
| 24 | +# include <io.h> | |
| 25 | +# include <fcntl.h> | |
| 26 | +#endif | |
| 22 | 27 | |
| 23 | 28 | /* |
| 24 | 29 | ** Conversion types fall into various categories as defined by the |
| 25 | 30 | ** following enumeration. |
| 26 | 31 | */ |
| @@ -159,15 +164,20 @@ | ||
| 159 | 164 | |
| 160 | 165 | /* |
| 161 | 166 | ** Return an appropriate set of flags for wiki_convert() for displaying |
| 162 | 167 | ** comments on a timeline. These flag settings are determined by |
| 163 | 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. | |
| 164 | 174 | */ |
| 165 | -static int wiki_convert_flags(void){ | |
| 175 | +static int wiki_convert_flags(int altForm2){ | |
| 166 | 176 | static int wikiFlags = 0; |
| 167 | 177 | if( wikiFlags==0 ){ |
| 168 | - if( db_get_boolean("timeline-block-markup", 0) ){ | |
| 178 | + if( altForm2 || db_get_boolean("timeline-block-markup", 0) ){ | |
| 169 | 179 | wikiFlags = WIKI_INLINE | WIKI_NOBADLINKS; |
| 170 | 180 | }else{ |
| 171 | 181 | wikiFlags = WIKI_INLINE | WIKI_NOBLOCK | WIKI_NOBADLINKS; |
| 172 | 182 | } |
| 173 | 183 | if( db_get_boolean("timeline-plaintext", 0) ){ |
| @@ -717,11 +727,11 @@ | ||
| 717 | 727 | case etWIKISTR: { |
| 718 | 728 | int limit = flag_alternateform ? va_arg(ap,int) : -1; |
| 719 | 729 | char *zWiki = va_arg(ap, char*); |
| 720 | 730 | Blob wiki; |
| 721 | 731 | blob_init(&wiki, zWiki, limit); |
| 722 | - wiki_convert(&wiki, pBlob, wiki_convert_flags()); | |
| 732 | + wiki_convert(&wiki, pBlob, wiki_convert_flags(flag_altform2)); | |
| 723 | 733 | blob_reset(&wiki); |
| 724 | 734 | length = width = 0; |
| 725 | 735 | break; |
| 726 | 736 | } |
| 727 | 737 | case etERROR: |
| @@ -888,70 +898,158 @@ | ||
| 888 | 898 | fossil_puts(blob_str(&b), 1); |
| 889 | 899 | blob_reset(&b); |
| 890 | 900 | va_end(ap); |
| 891 | 901 | } |
| 892 | 902 | |
| 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 | |
| 957 | 1055 | } |
| 958 | 1056 |
| --- 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 @@ | ||
| 785 | 785 | int bVerily = find_option("verily",0,0)!=0; |
| 786 | 786 | int bForce = find_option("force", "f", 0)!=0; |
| 787 | 787 | int privateOnly = find_option("private",0,0)!=0; |
| 788 | 788 | int bNeedRebuild = 0; |
| 789 | 789 | db_find_and_open_repository(OPEN_ANY_SCHEMA, 2); |
| 790 | + db_close(1); | |
| 791 | + db_open_repository(g.zRepositoryName); | |
| 790 | 792 | if( !bForce ){ |
| 791 | 793 | Blob ans; |
| 792 | 794 | char cReply; |
| 793 | 795 | blob_zero(&ans); |
| 794 | 796 | prompt_user( |
| @@ -841,11 +843,11 @@ | ||
| 841 | 843 | Blob aContent; /* content of the just read artifact */ |
| 842 | 844 | static int nFileRead = 0; |
| 843 | 845 | void *zUnicodePath; |
| 844 | 846 | char *zUtf8Name; |
| 845 | 847 | |
| 846 | - zUnicodePath = fossil_utf8_to_unicode(zPath); | |
| 848 | + zUnicodePath = fossil_utf8_to_filename(zPath); | |
| 847 | 849 | d = opendir(zUnicodePath); |
| 848 | 850 | if( d ){ |
| 849 | 851 | while( (pEntry=readdir(d))!=0 ){ |
| 850 | 852 | Blob path; |
| 851 | 853 | char *zSubpath; |
| @@ -875,11 +877,11 @@ | ||
| 875 | 877 | closedir(d); |
| 876 | 878 | }else { |
| 877 | 879 | fossil_panic("encountered error %d while trying to open \"%s\".", |
| 878 | 880 | errno, g.argv[3]); |
| 879 | 881 | } |
| 880 | - fossil_unicode_free(zUnicodePath); | |
| 882 | + fossil_filename_free(zUnicodePath); | |
| 881 | 883 | } |
| 882 | 884 | |
| 883 | 885 | /* |
| 884 | 886 | ** COMMAND: reconstruct* |
| 885 | 887 | ** |
| 886 | 888 |
| --- 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 @@ | ||
| 111 | 111 | ReInput sIn; /* Regular expression text */ |
| 112 | 112 | const char *zErr; /* Error message to return */ |
| 113 | 113 | char *aOp; /* Operators for the virtual machine */ |
| 114 | 114 | int *aArg; /* Arguments to each operator */ |
| 115 | 115 | unsigned (*xNextChar)(ReInput*); /* Next character function */ |
| 116 | - char zInit[12]; /* Initial text to match */ | |
| 116 | + unsigned char zInit[12]; /* Initial text to match */ | |
| 117 | 117 | int nInit; /* Number of characters in zInit */ |
| 118 | 118 | unsigned nState; /* Number of entries in aOp[] and aArg[] */ |
| 119 | 119 | unsigned nAlloc; /* Slots allocated for aOp[] and aArg[] */ |
| 120 | 120 | }; |
| 121 | 121 | #endif |
| @@ -197,11 +197,12 @@ | ||
| 197 | 197 | |
| 198 | 198 | /* Look for the initial prefix match, if there is one. */ |
| 199 | 199 | if( pRe->nInit ){ |
| 200 | 200 | unsigned char x = pRe->zInit[0]; |
| 201 | 201 | 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) | |
| 203 | 204 | ){ |
| 204 | 205 | in.i++; |
| 205 | 206 | } |
| 206 | 207 | if( in.i+pRe->nInit>in.mx ) return 0; |
| 207 | 208 | } |
| 208 | 209 |
| --- 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 @@ | ||
| 22 | 22 | #include "rss.h" |
| 23 | 23 | #include <assert.h> |
| 24 | 24 | |
| 25 | 25 | /* |
| 26 | 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). | |
| 27 | 40 | */ |
| 41 | + | |
| 28 | 42 | void page_timeline_rss(void){ |
| 29 | 43 | Stmt q; |
| 30 | 44 | int nLine=0; |
| 31 | 45 | char *zPubDate, *zProjectName, *zProjectDescr, *zFreeProjectName=0; |
| 32 | 46 | Blob bSQL; |
| 33 | 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); | |
| 34 | 52 | int nLimit = atoi(PD("n","20")); |
| 53 | + int nTagId; | |
| 35 | 54 | const char zSQL1[] = |
| 36 | 55 | @ SELECT |
| 37 | 56 | @ blob.rid, |
| 38 | 57 | @ uuid, |
| 39 | 58 | @ event.mtime, |
| @@ -62,10 +81,11 @@ | ||
| 62 | 81 | if( !g.perm.Read ){ |
| 63 | 82 | if( g.perm.RdTkt && g.perm.RdWiki ){ |
| 64 | 83 | blob_append(&bSQL, " AND event.type!='ci'", -1); |
| 65 | 84 | }else if( g.perm.RdTkt ){ |
| 66 | 85 | blob_append(&bSQL, " AND event.type=='t'", -1); |
| 86 | + | |
| 67 | 87 | }else{ |
| 68 | 88 | blob_append(&bSQL, " AND event.type=='w'", -1); |
| 69 | 89 | } |
| 70 | 90 | }else if( !g.perm.RdWiki ){ |
| 71 | 91 | if( g.perm.RdTkt ){ |
| @@ -76,10 +96,46 @@ | ||
| 76 | 96 | }else if( !g.perm.RdTkt ){ |
| 77 | 97 | assert( !g.perm.RdTkt &&& g.perm.Read && g.perm.RdWiki ); |
| 78 | 98 | blob_append(&bSQL, " AND event.type!='t'", -1); |
| 79 | 99 | } |
| 80 | 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 | + } | |
| 81 | 137 | |
| 82 | 138 | blob_append( &bSQL, " ORDER BY event.mtime DESC", -1 ); |
| 83 | 139 | |
| 84 | 140 | cgi_set_content_type("application/rss+xml"); |
| 85 | 141 | |
| 86 | 142 |
| --- 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 @@ | ||
| 139 | 139 | @ <table class="usetupLayoutTable"> |
| 140 | 140 | @ <tr><td class="usetupColumnLayout"> |
| 141 | 141 | @ <span class="note">Users:</span> |
| 142 | 142 | @ <table class="usetupUserList"> |
| 143 | 143 | prevLevel = 0; |
| 144 | - db_prepare(&s, | |
| 144 | + db_prepare(&s, | |
| 145 | 145 | "SELECT uid, login, cap, info, 1 FROM user" |
| 146 | 146 | " WHERE login IN ('anonymous','nobody','developer','reader') " |
| 147 | 147 | " UNION ALL " |
| 148 | 148 | "SELECT uid, login, cap, info, 2 FROM user" |
| 149 | 149 | " WHERE login NOT IN ('anonymous','nobody','developer','reader') " |
| @@ -250,11 +250,11 @@ | ||
| 250 | 250 | @ <td><i>Write-Tkt:</i> Edit tickets</td></tr> |
| 251 | 251 | @ <tr><td valign="top"><b>x</b></td> |
| 252 | 252 | @ <td><i>Private:</i> Push and/or pull private branches</td></tr> |
| 253 | 253 | @ <tr><td valign="top"><b>z</b></td> |
| 254 | 254 | @ <td><i>Zip download:</i> Download a baseline via the |
| 255 | - @ <tt>/zip</tt> URL even without | |
| 255 | + @ <tt>/zip</tt> URL even without | |
| 256 | 256 | @ check<span class="capability">o</span>ut |
| 257 | 257 | @ and <span class="capability">h</span>istory permissions</td></tr> |
| 258 | 258 | @ </table> |
| 259 | 259 | @ </li> |
| 260 | 260 | @ |
| @@ -357,11 +357,11 @@ | ||
| 357 | 357 | style_header("User Creation Error"); |
| 358 | 358 | @ <span class="loginError">Empty login not allowed.</span> |
| 359 | 359 | @ |
| 360 | 360 | @ <p><a href="setup_uedit?id=%d(uid)">[Bummer]</a></p> |
| 361 | 361 | style_footer(); |
| 362 | - return; | |
| 362 | + return; | |
| 363 | 363 | } |
| 364 | 364 | if( isValidPwString(zPw) ){ |
| 365 | 365 | zPw = sha1_shared_secret(zPw, zLogin, 0); |
| 366 | 366 | }else{ |
| 367 | 367 | zPw = db_text(0, "SELECT pw FROM user WHERE uid=%d", uid); |
| @@ -394,11 +394,11 @@ | ||
| 394 | 394 | " SELECT %Q WHERE NOT EXISTS(SELECT 1 FROM user WHERE login=%Q);", |
| 395 | 395 | zLogin, zLogin |
| 396 | 396 | ); |
| 397 | 397 | zOldLogin = zLogin; |
| 398 | 398 | } |
| 399 | - blob_appendf(&sql, | |
| 399 | + blob_appendf(&sql, | |
| 400 | 400 | "UPDATE user SET login=%Q," |
| 401 | 401 | " pw=coalesce(shared_secret(%Q,%Q," |
| 402 | 402 | "(SELECT value FROM config WHERE name='project-code')),pw)," |
| 403 | 403 | " info=%Q," |
| 404 | 404 | " cap=%Q," |
| @@ -643,11 +643,11 @@ | ||
| 643 | 643 | @ </p></li> |
| 644 | 644 | @ |
| 645 | 645 | @ <li><p> |
| 646 | 646 | @ The <span class="capability">Delete</span> privilege give the user the |
| 647 | 647 | @ 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. | |
| 649 | 649 | @ The delete capability is only in effect for 24 hours after the item |
| 650 | 650 | @ is first posted. The <span class="usertype">Setup</span> user can |
| 651 | 651 | @ delete anything at any time. |
| 652 | 652 | @ </p></li> |
| 653 | 653 | @ |
| @@ -700,11 +700,11 @@ | ||
| 700 | 700 | @ </p></li> |
| 701 | 701 | @ |
| 702 | 702 | @ <li><p> |
| 703 | 703 | @ The <span class="capability">EMail</span> privilege allows the display of |
| 704 | 704 | @ 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 | |
| 706 | 706 | @ <span class="usertype">anonymous</span> and for |
| 707 | 707 | @ <span class="usertype">nobody</span> but ON for |
| 708 | 708 | @ <span class="usertype">developer</span>. |
| 709 | 709 | @ </p></li> |
| 710 | 710 | @ |
| @@ -724,11 +724,11 @@ | ||
| 724 | 724 | @ <ul> |
| 725 | 725 | @ <li><p> |
| 726 | 726 | @ No login is required for user <span class="usertype">nobody</span>. The |
| 727 | 727 | @ capabilities of the <span class="usertype">nobody</span> user are |
| 728 | 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 | |
| 729 | + @ To disable universal access to the repository, make sure no user named | |
| 730 | 730 | @ <span class="usertype">nobody</span> exists or that the |
| 731 | 731 | @ <span class="usertype">nobody</span> user has no capabilities |
| 732 | 732 | @ enabled. The password for <span class="usertype">nobody</span> is ignore. |
| 733 | 733 | @ To avoid problems with spiders overloading the server, it is recommended |
| 734 | 734 | @ that the <span class="capability">h</span> (Hyperlinks) capability be |
| @@ -749,13 +749,13 @@ | ||
| 749 | 749 | @ |
| 750 | 750 | @ <li><p> |
| 751 | 751 | @ The <span class="usertype">developer</span> user is intended as a template |
| 752 | 752 | @ for trusted users with check-in privileges. When adding new trusted users, |
| 753 | 753 | @ 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 | |
| 755 | 755 | @ <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 | |
| 757 | 757 | @ template for users who are allowed more access than |
| 758 | 758 | @ <span class="usertype">anonymous</span>, |
| 759 | 759 | @ but less than a <span class="usertype">developer</span>. |
| 760 | 760 | @ </p></li> |
| 761 | 761 | @ </ul> |
| @@ -833,11 +833,11 @@ | ||
| 833 | 833 | z = zQ; |
| 834 | 834 | } |
| 835 | 835 | if( rows>0 && cols>0 ){ |
| 836 | 836 | @ <textarea id="id%s(zQP)" name="%s(zQP)" rows="%d(rows)" |
| 837 | 837 | @ cols="%d(cols)">%h(z)</textarea> |
| 838 | - if (zLabel && *zLabel){ | |
| 838 | + if( zLabel && *zLabel ){ | |
| 839 | 839 | @ <span class="textareaLabel">%s(zLabel)</span> |
| 840 | 840 | } |
| 841 | 841 | } |
| 842 | 842 | } |
| 843 | 843 | |
| @@ -895,11 +895,11 @@ | ||
| 895 | 895 | @ login name of a valid user and no other login credentials are available, |
| 896 | 896 | @ then the REMOTE_USER is accepted as an authenticated user. |
| 897 | 897 | @ </p> |
| 898 | 898 | @ |
| 899 | 899 | @ <hr /> |
| 900 | - entry_attribute("IP address terms used in login cookie", 3, | |
| 900 | + entry_attribute("IP address terms used in login cookie", 3, | |
| 901 | 901 | "ip-prefix-terms", "ipt", "2"); |
| 902 | 902 | @ <p>The number of octets of of the IP address used in the login cookie. |
| 903 | 903 | @ Set to zero to omit the IP address from the login cookie. A value of |
| 904 | 904 | @ 2 is recommended. |
| 905 | 905 | @ </p> |
| @@ -958,23 +958,23 @@ | ||
| 958 | 958 | entry_attribute("Public pages", 30, "public-pages", |
| 959 | 959 | "pubpage", ""); |
| 960 | 960 | @ <p>A comma-separated list of glob patterns for pages that are accessible |
| 961 | 961 | @ without needing a login and using the privileges given by the |
| 962 | 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 | |
| 963 | + @ to "/doc/trunk/www/*" to give anonymous users read-only permission to the | |
| 964 | 964 | @ latest version of the embedded documentation in the www/ folder without |
| 965 | 965 | @ allowing them to see the rest of the source code. |
| 966 | 966 | @ </p> |
| 967 | 967 | |
| 968 | 968 | @ <hr /> |
| 969 | 969 | onoff_attribute("Allow users to register themselves", |
| 970 | 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 | |
| 971 | + @ <p>Allow users to register themselves through the HTTP UI. | |
| 972 | + @ The registration form always requires filling in a CAPTCHA | |
| 973 | 973 | @ (<em>auto-captcha</em> setting is ignored). Still, bear in mind that anyone |
| 974 | 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 | |
| 975 | + @ where you do not want everyone in any ticket discussion to be named | |
| 976 | 976 | @ "Anonymous".</p> |
| 977 | 977 | |
| 978 | 978 | @ <hr /> |
| 979 | 979 | entry_attribute("Default privileges", 10, "default-perms", |
| 980 | 980 | "defaultperms", "u"); |
| @@ -1128,11 +1128,11 @@ | ||
| 1128 | 1128 | "timeline-utc", "utc", 1); |
| 1129 | 1129 | @ <p>Show times as UTC (also sometimes called Greenwich Mean Time (GMT) or |
| 1130 | 1130 | @ Zulu) instead of in local time. On this server, local time is currently |
| 1131 | 1131 | g.fTimeFormat = 2; |
| 1132 | 1132 | tmDiff = db_double(0.0, "SELECT julianday('now')"); |
| 1133 | - tmDiff = db_double(0.0, | |
| 1133 | + tmDiff = db_double(0.0, | |
| 1134 | 1134 | "SELECT (julianday(%.17g,'localtime')-julianday(%.17g))*24.0", |
| 1135 | 1135 | tmDiff, tmDiff); |
| 1136 | 1136 | sqlite3_snprintf(sizeof(zTmDiff), zTmDiff, "%.1f", tmDiff); |
| 1137 | 1137 | if( strcmp(zTmDiff, "0.0")==0 ){ |
| 1138 | 1138 | @ the same as UTC and so this setting will make no difference in |
| @@ -1450,11 +1450,11 @@ | ||
| 1450 | 1450 | onoff_attribute("Moderate ticket changes", |
| 1451 | 1451 | "modreq-tkt", "modreq-tkt", 0); |
| 1452 | 1452 | @ <p>When enabled, any change to tickets is subject to the approval |
| 1453 | 1453 | @ a ticket moderator - a user with the "q" or Mod-Tkt privilege. |
| 1454 | 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 | |
| 1455 | + @ synced until they are approved. The moderator has the option to | |
| 1456 | 1456 | @ delete the change rather than approve it. Ticket changes made by |
| 1457 | 1457 | @ a user who hwas the Mod-Tkt privilege are never subject to |
| 1458 | 1458 | @ moderation. |
| 1459 | 1459 | @ |
| 1460 | 1460 | @ <hr /> |
| @@ -1461,16 +1461,16 @@ | ||
| 1461 | 1461 | onoff_attribute("Moderate wiki changes", |
| 1462 | 1462 | "modreq-wiki", "modreq-wiki", 0); |
| 1463 | 1463 | @ <p>When enabled, any change to wiki is subject to the approval |
| 1464 | 1464 | @ a ticket moderator - a user with the "l" or Mod-Wiki privilege. |
| 1465 | 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 | |
| 1466 | + @ synced until they are approved. The moderator has the option to | |
| 1467 | 1467 | @ delete the change rather than approve it. Wiki changes made by |
| 1468 | 1468 | @ a user who has the Mod-Wiki privilege are never subject to |
| 1469 | 1469 | @ moderation. |
| 1470 | 1470 | @ </p> |
| 1471 | - | |
| 1471 | + | |
| 1472 | 1472 | @ <hr /> |
| 1473 | 1473 | @ <p><input type="submit" name="submit" value="Apply Changes" /></p> |
| 1474 | 1474 | @ </div></form> |
| 1475 | 1475 | db_end_transaction(0); |
| 1476 | 1476 | style_footer(); |
| @@ -1678,11 +1678,11 @@ | ||
| 1678 | 1678 | @ |
| 1679 | 1679 | @ <p>Only a the first statement in the entry box will be run. |
| 1680 | 1680 | @ Any subsequent statements will be silently ignored.</p> |
| 1681 | 1681 | @ |
| 1682 | 1682 | @ <p>Database names:<ul><li>repository → %s(db_name("repository")) |
| 1683 | - if( g.configOpen ){ | |
| 1683 | + if( g.zConfigDbName ){ | |
| 1684 | 1684 | @ <li>config → %s(db_name("configdb")) |
| 1685 | 1685 | } |
| 1686 | 1686 | if( g.localOpen ){ |
| 1687 | 1687 | @ <li>local-checkout → %s(db_name("localdb")) |
| 1688 | 1688 | } |
| 1689 | 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 → %s(db_name("repository")) |
| 1683 | if( g.configOpen ){ |
| 1684 | @ <li>config → %s(db_name("configdb")) |
| 1685 | } |
| 1686 | if( g.localOpen ){ |
| 1687 | @ <li>local-checkout → %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 → %s(db_name("repository")) |
| 1683 | if( g.zConfigDbName ){ |
| 1684 | @ <li>config → %s(db_name("configdb")) |
| 1685 | } |
| 1686 | if( g.localOpen ){ |
| 1687 | @ <li>local-checkout → %s(db_name("localdb")) |
| 1688 | } |
| 1689 |
+57
-22
| --- src/shell.c | ||
| +++ src/shell.c | ||
| @@ -88,11 +88,12 @@ | ||
| 88 | 88 | /* ctype macros that work with signed characters */ |
| 89 | 89 | #define IsSpace(X) isspace((unsigned char)X) |
| 90 | 90 | #define IsDigit(X) isdigit((unsigned char)X) |
| 91 | 91 | #define ToLower(X) (char)tolower((unsigned char)X) |
| 92 | 92 | |
| 93 | -#if !defined(_WIN32) && !defined(WIN32) && !defined(_WRS_KERNEL) | |
| 93 | +#if !defined(_WIN32) && !defined(WIN32) && !defined(_WRS_KERNEL) \ | |
| 94 | + && !defined(__minux) | |
| 94 | 95 | #include <sys/time.h> |
| 95 | 96 | #include <sys/resource.h> |
| 96 | 97 | |
| 97 | 98 | /* Saved resource information for the beginning of an operation */ |
| 98 | 99 | static struct rusage sBegin; |
| @@ -1484,10 +1485,16 @@ | ||
| 1484 | 1485 | { |
| 1485 | 1486 | extern int sqlite3_add_regexp_func(sqlite3*); |
| 1486 | 1487 | sqlite3_add_regexp_func(db); |
| 1487 | 1488 | } |
| 1488 | 1489 | #endif |
| 1490 | +#ifdef SQLITE_ENABLE_SPELLFIX | |
| 1491 | + { | |
| 1492 | + extern int sqlite3_spellfix1_register(sqlite3*); | |
| 1493 | + sqlite3_spellfix1_register(db); | |
| 1494 | + } | |
| 1495 | +#endif | |
| 1489 | 1496 | } |
| 1490 | 1497 | } |
| 1491 | 1498 | |
| 1492 | 1499 | /* |
| 1493 | 1500 | ** Do C-language style dequoting. |
| @@ -1529,21 +1536,22 @@ | ||
| 1529 | 1536 | |
| 1530 | 1537 | /* |
| 1531 | 1538 | ** Interpret zArg as a boolean value. Return either 0 or 1. |
| 1532 | 1539 | */ |
| 1533 | 1540 | 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; | |
| 1545 | 1553 | } |
| 1546 | 1554 | |
| 1547 | 1555 | /* |
| 1548 | 1556 | ** Close an output file, assuming it is not stderr or stdout |
| 1549 | 1557 | */ |
| @@ -1627,28 +1635,54 @@ | ||
| 1627 | 1635 | /* Process the input line. |
| 1628 | 1636 | */ |
| 1629 | 1637 | if( nArg==0 ) return 0; /* no tokens, no error */ |
| 1630 | 1638 | n = strlen30(azArg[0]); |
| 1631 | 1639 | 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; | |
| 1635 | 1644 | sqlite3 *pDest; |
| 1636 | 1645 | 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; | |
| 1643 | 1671 | } |
| 1672 | + if( zDb==0 ) zDb = "main"; | |
| 1644 | 1673 | rc = sqlite3_open(zDestFile, &pDest); |
| 1645 | 1674 | if( rc!=SQLITE_OK ){ |
| 1646 | 1675 | fprintf(stderr, "Error: cannot open \"%s\"\n", zDestFile); |
| 1647 | 1676 | sqlite3_close(pDest); |
| 1648 | 1677 | return 1; |
| 1649 | 1678 | } |
| 1679 | +#ifdef SQLITE_HAS_CODEC | |
| 1680 | + sqlite3_key(pDest, zKey, (int)strlen(zKey)); | |
| 1681 | +#else | |
| 1682 | + (void)zKey; | |
| 1683 | +#endif | |
| 1650 | 1684 | open_db(p); |
| 1651 | 1685 | pBackup = sqlite3_backup_init(pDest, "main", p->db, zDb); |
| 1652 | 1686 | if( pBackup==0 ){ |
| 1653 | 1687 | fprintf(stderr, "Error: %s\n", sqlite3_errmsg(pDest)); |
| 1654 | 1688 | sqlite3_close(pDest); |
| @@ -1746,11 +1780,12 @@ | ||
| 1746 | 1780 | |
| 1747 | 1781 | if( c=='e' && strncmp(azArg[0], "echo", n)==0 && nArg>1 && nArg<3 ){ |
| 1748 | 1782 | p->echoOn = booleanValue(azArg[1]); |
| 1749 | 1783 | }else |
| 1750 | 1784 | |
| 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); | |
| 1752 | 1787 | rc = 2; |
| 1753 | 1788 | }else |
| 1754 | 1789 | |
| 1755 | 1790 | if( c=='e' && strncmp(azArg[0], "explain", n)==0 && nArg<3 ){ |
| 1756 | 1791 | int val = nArg>=2 ? booleanValue(azArg[1]) : 1; |
| 1757 | 1792 |
| --- 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 @@ | ||
| 304 | 304 | /* Needed for various definitions... */ |
| 305 | 305 | #ifndef _GNU_SOURCE |
| 306 | 306 | # define _GNU_SOURCE |
| 307 | 307 | #endif |
| 308 | 308 | |
| 309 | +#if defined(__OpenBSD__) && !defined(_BSD_SOURCE) | |
| 310 | +# define _BSD_SOURCE | |
| 311 | +#endif | |
| 312 | + | |
| 309 | 313 | /* |
| 310 | 314 | ** Include standard header files as necessary |
| 311 | 315 | */ |
| 312 | 316 | #ifdef HAVE_STDINT_H |
| 313 | 317 | #include <stdint.h> |
| @@ -438,11 +442,12 @@ | ||
| 438 | 442 | ** if it is already defined or if it is unneeded because we are |
| 439 | 443 | ** not doing a threadsafe build. Ticket #2681. |
| 440 | 444 | ** |
| 441 | 445 | ** See also ticket #2741. |
| 442 | 446 | */ |
| 443 | -#if !defined(_XOPEN_SOURCE) && !defined(__DARWIN__) && !defined(__APPLE__) && SQLITE_THREADSAFE | |
| 447 | +#if !defined(_XOPEN_SOURCE) && !defined(__DARWIN__) \ | |
| 448 | + && !defined(__APPLE__) && SQLITE_THREADSAFE | |
| 444 | 449 | # define _XOPEN_SOURCE 500 /* Needed to enable pthread recursive mutexes */ |
| 445 | 450 | #endif |
| 446 | 451 | |
| 447 | 452 | /* |
| 448 | 453 | ** The TCL headers are only needed when compiling the TCL bindings. |
| @@ -673,11 +678,11 @@ | ||
| 673 | 678 | ** [sqlite3_libversion_number()], [sqlite3_sourceid()], |
| 674 | 679 | ** [sqlite_version()] and [sqlite_source_id()]. |
| 675 | 680 | */ |
| 676 | 681 | #define SQLITE_VERSION "3.7.16" |
| 677 | 682 | #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" | |
| 679 | 684 | |
| 680 | 685 | /* |
| 681 | 686 | ** CAPI3REF: Run-Time Library Version Numbers |
| 682 | 687 | ** KEYWORDS: sqlite3_version, sqlite3_sourceid |
| 683 | 688 | ** |
| @@ -852,11 +857,11 @@ | ||
| 852 | 857 | ** |
| 853 | 858 | ** Applications should [sqlite3_finalize | finalize] all [prepared statements], |
| 854 | 859 | ** [sqlite3_blob_close | close] all [BLOB handles], and |
| 855 | 860 | ** [sqlite3_backup_finish | finish] all [sqlite3_backup] objects associated |
| 856 | 861 | ** 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 | |
| 858 | 863 | ** outstanding [prepared statements], [BLOB handles], and/or |
| 859 | 864 | ** [sqlite3_backup] objects then it returns SQLITE_OK but the deallocation |
| 860 | 865 | ** of resources is deferred until all [prepared statements], [BLOB handles], |
| 861 | 866 | ** and [sqlite3_backup] objects are also destroyed. |
| 862 | 867 | ** |
| @@ -1047,11 +1052,21 @@ | ||
| 1047 | 1052 | #define SQLITE_CANTOPEN_ISDIR (SQLITE_CANTOPEN | (2<<8)) |
| 1048 | 1053 | #define SQLITE_CANTOPEN_FULLPATH (SQLITE_CANTOPEN | (3<<8)) |
| 1049 | 1054 | #define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1<<8)) |
| 1050 | 1055 | #define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1<<8)) |
| 1051 | 1056 | #define SQLITE_READONLY_CANTLOCK (SQLITE_READONLY | (2<<8)) |
| 1057 | +#define SQLITE_READONLY_ROLLBACK (SQLITE_READONLY | (3<<8)) | |
| 1052 | 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)) | |
| 1053 | 1068 | |
| 1054 | 1069 | /* |
| 1055 | 1070 | ** CAPI3REF: Flags For File Open Operations |
| 1056 | 1071 | ** |
| 1057 | 1072 | ** These bit values are intended for use in the |
| @@ -10018,11 +10033,11 @@ | ||
| 10018 | 10033 | #define SQLITE_NullCallback 0x00000020 /* Invoke the callback once if the */ |
| 10019 | 10034 | /* result set is empty */ |
| 10020 | 10035 | #define SQLITE_SqlTrace 0x00000040 /* Debug print SQL as it executes */ |
| 10021 | 10036 | #define SQLITE_VdbeListing 0x00000080 /* Debug listings of VDBE programs */ |
| 10022 | 10037 | #define SQLITE_WriteSchema 0x00000100 /* OK to update SQLITE_MASTER */ |
| 10023 | - /* 0x00000200 Unused */ | |
| 10038 | +#define SQLITE_VdbeAddopTrace 0x00000200 /* Trace sqlite3VdbeAddOp() calls */ | |
| 10024 | 10039 | #define SQLITE_IgnoreChecks 0x00000400 /* Do not enforce check constraints */ |
| 10025 | 10040 | #define SQLITE_ReadUncommitted 0x0000800 /* For shared-cache mode */ |
| 10026 | 10041 | #define SQLITE_LegacyFileFmt 0x00001000 /* Create new databases in format 1 */ |
| 10027 | 10042 | #define SQLITE_FullFSync 0x00002000 /* Use full fsync on the backend */ |
| 10028 | 10043 | #define SQLITE_CkptFullFSync 0x00004000 /* Use full fsync for checkpoint */ |
| @@ -11034,10 +11049,11 @@ | ||
| 11034 | 11049 | struct { |
| 11035 | 11050 | int nIn; /* Number of entries in aInLoop[] */ |
| 11036 | 11051 | struct InLoop { |
| 11037 | 11052 | int iCur; /* The VDBE cursor used by this IN operator */ |
| 11038 | 11053 | int addrInTop; /* Top of the IN loop */ |
| 11054 | + u8 eEndLoopOp; /* IN Loop terminator. OP_Next or OP_Prev */ | |
| 11039 | 11055 | } *aInLoop; /* Information about each nested IN operator */ |
| 11040 | 11056 | } in; /* Used when plan.wsFlags&WHERE_IN_ABLE */ |
| 11041 | 11057 | Index *pCovidx; /* Possible covering index for WHERE_MULTI_OR */ |
| 11042 | 11058 | } u; |
| 11043 | 11059 | double rOptCost; /* "Optimal" cost for this level */ |
| @@ -11905,11 +11921,11 @@ | ||
| 11905 | 11921 | SQLITE_PRIVATE void sqlite3SelectDelete(sqlite3*, Select*); |
| 11906 | 11922 | SQLITE_PRIVATE Table *sqlite3SrcListLookup(Parse*, SrcList*); |
| 11907 | 11923 | SQLITE_PRIVATE int sqlite3IsReadOnly(Parse*, Table*, int); |
| 11908 | 11924 | SQLITE_PRIVATE void sqlite3OpenTable(Parse*, int iCur, int iDb, Table*, int); |
| 11909 | 11925 | #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*); | |
| 11911 | 11927 | #endif |
| 11912 | 11928 | SQLITE_PRIVATE void sqlite3DeleteFrom(Parse*, SrcList*, Expr*); |
| 11913 | 11929 | SQLITE_PRIVATE void sqlite3Update(Parse*, SrcList*, ExprList*, Expr*, int); |
| 11914 | 11930 | SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(Parse*,SrcList*,Expr*,ExprList*,ExprList*,u16,int); |
| 11915 | 11931 | SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo*); |
| @@ -11973,11 +11989,11 @@ | ||
| 11973 | 11989 | SQLITE_PRIVATE void sqlite3CompleteInsertion(Parse*, Table*, int, int, int*, int, int, int); |
| 11974 | 11990 | SQLITE_PRIVATE int sqlite3OpenTableAndIndices(Parse*, Table*, int, int); |
| 11975 | 11991 | SQLITE_PRIVATE void sqlite3BeginWriteOperation(Parse*, int, int); |
| 11976 | 11992 | SQLITE_PRIVATE void sqlite3MultiWrite(Parse*); |
| 11977 | 11993 | SQLITE_PRIVATE void sqlite3MayAbort(Parse*); |
| 11978 | -SQLITE_PRIVATE void sqlite3HaltConstraint(Parse*, int, char*, int); | |
| 11994 | +SQLITE_PRIVATE void sqlite3HaltConstraint(Parse*, int, int, char*, int); | |
| 11979 | 11995 | SQLITE_PRIVATE Expr *sqlite3ExprDup(sqlite3*,Expr*,int); |
| 11980 | 11996 | SQLITE_PRIVATE ExprList *sqlite3ExprListDup(sqlite3*,ExprList*,int); |
| 11981 | 11997 | SQLITE_PRIVATE SrcList *sqlite3SrcListDup(sqlite3*,SrcList*,int); |
| 11982 | 11998 | SQLITE_PRIVATE IdList *sqlite3IdListDup(sqlite3*,IdList*); |
| 11983 | 11999 | SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3*,Select*,int); |
| @@ -12086,12 +12102,15 @@ | ||
| 12086 | 12102 | ** |
| 12087 | 12103 | ** x = getVarint32( A, B ); |
| 12088 | 12104 | ** x = putVarint32( A, B ); |
| 12089 | 12105 | ** |
| 12090 | 12106 | */ |
| 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))) | |
| 12093 | 12112 | #define getVarint sqlite3GetVarint |
| 12094 | 12113 | #define putVarint sqlite3PutVarint |
| 12095 | 12114 | |
| 12096 | 12115 | |
| 12097 | 12116 | SQLITE_PRIVATE const char *sqlite3IndexAffinityStr(Vdbe *, Index *); |
| @@ -12323,11 +12342,12 @@ | ||
| 12323 | 12342 | #define sqlite3EndBenignMalloc() |
| 12324 | 12343 | #endif |
| 12325 | 12344 | |
| 12326 | 12345 | #define IN_INDEX_ROWID 1 |
| 12327 | 12346 | #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 | |
| 12329 | 12349 | SQLITE_PRIVATE int sqlite3FindInIndex(Parse *, Expr *, int*); |
| 12330 | 12350 | |
| 12331 | 12351 | #ifdef SQLITE_ENABLE_ATOMIC_WRITE |
| 12332 | 12352 | SQLITE_PRIVATE int sqlite3JournalOpen(sqlite3_vfs *, const char *, sqlite3_file *, int, int); |
| 12333 | 12353 | SQLITE_PRIVATE int sqlite3JournalSize(sqlite3_vfs *); |
| @@ -13208,11 +13228,11 @@ | ||
| 13208 | 13228 | Mem *aMem; /* Array of memory cells for parent frame */ |
| 13209 | 13229 | u8 *aOnceFlag; /* Array of OP_Once flags for parent frame */ |
| 13210 | 13230 | VdbeCursor **apCsr; /* Array of Vdbe cursors for parent frame */ |
| 13211 | 13231 | void *token; /* Copy of SubProgram.token */ |
| 13212 | 13232 | i64 lastRowid; /* Last insert rowid (sqlite3.lastRowid) */ |
| 13213 | - u16 nCursor; /* Number of entries in apCsr */ | |
| 13233 | + int nCursor; /* Number of entries in apCsr */ | |
| 13214 | 13234 | int pc; /* Program Counter in parent (calling) frame */ |
| 13215 | 13235 | int nOp; /* Size of aOp array */ |
| 13216 | 13236 | int nMem; /* Number of entries in aMem */ |
| 13217 | 13237 | int nOnceFlag; /* Number of entries in aOnceFlag */ |
| 13218 | 13238 | int nChildMem; /* Number of memory cells for child frame */ |
| @@ -13394,11 +13414,11 @@ | ||
| 13394 | 13414 | int nOp; /* Number of instructions in the program */ |
| 13395 | 13415 | int nOpAlloc; /* Number of slots allocated for aOp[] */ |
| 13396 | 13416 | int nLabel; /* Number of labels used */ |
| 13397 | 13417 | int *aLabel; /* Space to hold the labels */ |
| 13398 | 13418 | 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[] */ | |
| 13400 | 13420 | u32 magic; /* Magic number for sanity checking */ |
| 13401 | 13421 | char *zErrMsg; /* Error message written here */ |
| 13402 | 13422 | Vdbe *pPrev,*pNext; /* Linked list of VDBEs with the same Vdbe.db */ |
| 13403 | 13423 | VdbeCursor **apCsr; /* One element of this array for each open cursor */ |
| 13404 | 13424 | Mem *aVar; /* Values for the OP_Variable opcode. */ |
| @@ -23445,11 +23465,14 @@ | ||
| 23445 | 23465 | #endif |
| 23446 | 23466 | }while( fd<0 && errno==EINTR ); |
| 23447 | 23467 | if( fd>=0 ){ |
| 23448 | 23468 | if( m!=0 ){ |
| 23449 | 23469 | 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 | + ){ | |
| 23451 | 23474 | osFchmod(fd, m); |
| 23452 | 23475 | } |
| 23453 | 23476 | } |
| 23454 | 23477 | #if defined(FD_CLOEXEC) && (!defined(O_CLOEXEC) || O_CLOEXEC==0) |
| 23455 | 23478 | osFcntl(fd, F_SETFD, osFcntl(fd, F_GETFD, 0) | FD_CLOEXEC); |
| @@ -27645,11 +27668,11 @@ | ||
| 27645 | 27668 | pNew->ctrlFlags = (u8)ctrlFlags; |
| 27646 | 27669 | if( sqlite3_uri_boolean(((ctrlFlags & UNIXFILE_URI) ? zFilename : 0), |
| 27647 | 27670 | "psow", SQLITE_POWERSAFE_OVERWRITE) ){ |
| 27648 | 27671 | pNew->ctrlFlags |= UNIXFILE_PSOW; |
| 27649 | 27672 | } |
| 27650 | - if( memcmp(pVfs->zName,"unix-excl",10)==0 ){ | |
| 27673 | + if( strcmp(pVfs->zName,"unix-excl")==0 ){ | |
| 27651 | 27674 | pNew->ctrlFlags |= UNIXFILE_EXCL; |
| 27652 | 27675 | } |
| 27653 | 27676 | |
| 27654 | 27677 | #if OS_VXWORKS |
| 27655 | 27678 | pNew->pId = vxworksFindFileId(zFilename); |
| @@ -31099,11 +31122,11 @@ | ||
| 31099 | 31122 | /* |
| 31100 | 31123 | ** This function outputs the specified (ANSI) string to the Win32 debugger |
| 31101 | 31124 | ** (if available). |
| 31102 | 31125 | */ |
| 31103 | 31126 | |
| 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){ | |
| 31105 | 31128 | char zDbgBuf[SQLITE_WIN32_DBG_BUF_SIZE]; |
| 31106 | 31129 | int nMin = MIN(nBuf, (SQLITE_WIN32_DBG_BUF_SIZE - 1)); /* may be negative. */ |
| 31107 | 31130 | if( nMin<-1 ) nMin = -1; /* all negative values become -1. */ |
| 31108 | 31131 | assert( nMin==-1 || nMin==0 || nMin<SQLITE_WIN32_DBG_BUF_SIZE ); |
| 31109 | 31132 | #if defined(SQLITE_WIN32_HAS_ANSI) |
| @@ -31732,13 +31755,14 @@ | ||
| 31732 | 31755 | |
| 31733 | 31756 | #if SQLITE_OS_WINCE |
| 31734 | 31757 | /************************************************************************* |
| 31735 | 31758 | ** This section contains code for WinCE only. |
| 31736 | 31759 | */ |
| 31760 | +#if !defined(SQLITE_MSVC_LOCALTIME_API) || !SQLITE_MSVC_LOCALTIME_API | |
| 31737 | 31761 | /* |
| 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. | |
| 31740 | 31764 | */ |
| 31741 | 31765 | /* #include <time.h> */ |
| 31742 | 31766 | struct tm *__cdecl localtime(const time_t *t) |
| 31743 | 31767 | { |
| 31744 | 31768 | static struct tm y; |
| @@ -31758,10 +31782,11 @@ | ||
| 31758 | 31782 | y.tm_hour = pTm.wHour; |
| 31759 | 31783 | y.tm_min = pTm.wMinute; |
| 31760 | 31784 | y.tm_sec = pTm.wSecond; |
| 31761 | 31785 | return &y; |
| 31762 | 31786 | } |
| 31787 | +#endif | |
| 31763 | 31788 | |
| 31764 | 31789 | #define HANDLE_TO_WINFILE(a) (winFile*)&((char*)a)[-(int)offsetof(winFile,h)] |
| 31765 | 31790 | |
| 31766 | 31791 | /* |
| 31767 | 31792 | ** Acquire a lock on the handle h |
| @@ -31779,19 +31804,21 @@ | ||
| 31779 | 31804 | |
| 31780 | 31805 | /* |
| 31781 | 31806 | ** Create the mutex and shared memory used for locking in the file |
| 31782 | 31807 | ** descriptor pFile |
| 31783 | 31808 | */ |
| 31784 | -static BOOL winceCreateLock(const char *zFilename, winFile *pFile){ | |
| 31809 | +static int winceCreateLock(const char *zFilename, winFile *pFile){ | |
| 31785 | 31810 | LPWSTR zTok; |
| 31786 | 31811 | LPWSTR zName; |
| 31812 | + DWORD lastErrno; | |
| 31813 | + BOOL bLogged = FALSE; | |
| 31787 | 31814 | BOOL bInit = TRUE; |
| 31788 | 31815 | |
| 31789 | 31816 | zName = utf8ToUnicode(zFilename); |
| 31790 | 31817 | if( zName==0 ){ |
| 31791 | 31818 | /* out of memory */ |
| 31792 | - return FALSE; | |
| 31819 | + return SQLITE_IOERR_NOMEM; | |
| 31793 | 31820 | } |
| 31794 | 31821 | |
| 31795 | 31822 | /* Initialize the local lockdata */ |
| 31796 | 31823 | memset(&pFile->local, 0, sizeof(pFile->local)); |
| 31797 | 31824 | |
| @@ -31804,13 +31831,14 @@ | ||
| 31804 | 31831 | |
| 31805 | 31832 | /* Create/open the named mutex */ |
| 31806 | 31833 | pFile->hMutex = osCreateMutexW(NULL, FALSE, zName); |
| 31807 | 31834 | if (!pFile->hMutex){ |
| 31808 | 31835 | pFile->lastErrno = osGetLastError(); |
| 31809 | - winLogError(SQLITE_ERROR, pFile->lastErrno, "winceCreateLock1", zFilename); | |
| 31836 | + winLogError(SQLITE_IOERR, pFile->lastErrno, | |
| 31837 | + "winceCreateLock1", zFilename); | |
| 31810 | 31838 | sqlite3_free(zName); |
| 31811 | - return FALSE; | |
| 31839 | + return SQLITE_IOERR; | |
| 31812 | 31840 | } |
| 31813 | 31841 | |
| 31814 | 31842 | /* Acquire the mutex before continuing */ |
| 31815 | 31843 | winceMutexAcquire(pFile->hMutex); |
| 31816 | 31844 | |
| @@ -31823,45 +31851,53 @@ | ||
| 31823 | 31851 | PAGE_READWRITE, 0, sizeof(winceLock), |
| 31824 | 31852 | zName); |
| 31825 | 31853 | |
| 31826 | 31854 | /* Set a flag that indicates we're the first to create the memory so it |
| 31827 | 31855 | ** must be zero-initialized */ |
| 31828 | - if (osGetLastError() == ERROR_ALREADY_EXISTS){ | |
| 31856 | + lastErrno = osGetLastError(); | |
| 31857 | + if (lastErrno == ERROR_ALREADY_EXISTS){ | |
| 31829 | 31858 | bInit = FALSE; |
| 31830 | 31859 | } |
| 31831 | 31860 | |
| 31832 | 31861 | sqlite3_free(zName); |
| 31833 | 31862 | |
| 31834 | 31863 | /* If we succeeded in making the shared memory handle, map it. */ |
| 31835 | - if (pFile->hShared){ | |
| 31864 | + if( pFile->hShared ){ | |
| 31836 | 31865 | pFile->shared = (winceLock*)osMapViewOfFile(pFile->hShared, |
| 31837 | 31866 | FILE_MAP_READ|FILE_MAP_WRITE, 0, 0, sizeof(winceLock)); |
| 31838 | 31867 | /* If mapping failed, close the shared memory handle and erase it */ |
| 31839 | - if (!pFile->shared){ | |
| 31868 | + if( !pFile->shared ){ | |
| 31840 | 31869 | pFile->lastErrno = osGetLastError(); |
| 31841 | - winLogError(SQLITE_ERROR, pFile->lastErrno, | |
| 31842 | - "winceCreateLock2", zFilename); | |
| 31870 | + winLogError(SQLITE_IOERR, pFile->lastErrno, | |
| 31871 | + "winceCreateLock2", zFilename); | |
| 31872 | + bLogged = TRUE; | |
| 31843 | 31873 | osCloseHandle(pFile->hShared); |
| 31844 | 31874 | pFile->hShared = NULL; |
| 31845 | 31875 | } |
| 31846 | 31876 | } |
| 31847 | 31877 | |
| 31848 | 31878 | /* 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 | + } | |
| 31850 | 31886 | winceMutexRelease(pFile->hMutex); |
| 31851 | 31887 | osCloseHandle(pFile->hMutex); |
| 31852 | 31888 | pFile->hMutex = NULL; |
| 31853 | - return FALSE; | |
| 31889 | + return SQLITE_IOERR; | |
| 31854 | 31890 | } |
| 31855 | 31891 | |
| 31856 | 31892 | /* Initialize the shared memory if we're supposed to */ |
| 31857 | - if (bInit) { | |
| 31893 | + if( bInit ){ | |
| 31858 | 31894 | memset(pFile->shared, 0, sizeof(winceLock)); |
| 31859 | 31895 | } |
| 31860 | 31896 | |
| 31861 | 31897 | winceMutexRelease(pFile->hMutex); |
| 31862 | - return TRUE; | |
| 31898 | + return SQLITE_OK; | |
| 31863 | 31899 | } |
| 31864 | 31900 | |
| 31865 | 31901 | /* |
| 31866 | 31902 | ** Destroy the part of winFile that deals with wince locks |
| 31867 | 31903 | */ |
| @@ -31936,21 +31972,23 @@ | ||
| 31936 | 31972 | bReturn = TRUE; |
| 31937 | 31973 | } |
| 31938 | 31974 | } |
| 31939 | 31975 | |
| 31940 | 31976 | /* Want a pending lock? */ |
| 31941 | - else if (dwFileOffsetLow == (DWORD)PENDING_BYTE && nNumberOfBytesToLockLow == 1){ | |
| 31977 | + else if (dwFileOffsetLow == (DWORD)PENDING_BYTE | |
| 31978 | + && nNumberOfBytesToLockLow == 1){ | |
| 31942 | 31979 | /* If no pending lock has been acquired, then acquire it */ |
| 31943 | 31980 | if (pFile->shared->bPending == 0) { |
| 31944 | 31981 | pFile->shared->bPending = TRUE; |
| 31945 | 31982 | pFile->local.bPending = TRUE; |
| 31946 | 31983 | bReturn = TRUE; |
| 31947 | 31984 | } |
| 31948 | 31985 | } |
| 31949 | 31986 | |
| 31950 | 31987 | /* Want a reserved lock? */ |
| 31951 | - else if (dwFileOffsetLow == (DWORD)RESERVED_BYTE && nNumberOfBytesToLockLow == 1){ | |
| 31988 | + else if (dwFileOffsetLow == (DWORD)RESERVED_BYTE | |
| 31989 | + && nNumberOfBytesToLockLow == 1){ | |
| 31952 | 31990 | if (pFile->shared->bReserved == 0) { |
| 31953 | 31991 | pFile->shared->bReserved = TRUE; |
| 31954 | 31992 | pFile->local.bReserved = TRUE; |
| 31955 | 31993 | bReturn = TRUE; |
| 31956 | 31994 | } |
| @@ -31989,11 +32027,12 @@ | ||
| 31989 | 32027 | bReturn = TRUE; |
| 31990 | 32028 | } |
| 31991 | 32029 | |
| 31992 | 32030 | /* Did we just have a reader lock? */ |
| 31993 | 32031 | else if (pFile->local.nReaders){ |
| 31994 | - assert(nNumberOfBytesToUnlockLow == (DWORD)SHARED_SIZE || nNumberOfBytesToUnlockLow == 1); | |
| 32032 | + assert(nNumberOfBytesToUnlockLow == (DWORD)SHARED_SIZE | |
| 32033 | + || nNumberOfBytesToUnlockLow == 1); | |
| 31995 | 32034 | pFile->local.nReaders --; |
| 31996 | 32035 | if (pFile->local.nReaders == 0) |
| 31997 | 32036 | { |
| 31998 | 32037 | pFile->shared->nReaders --; |
| 31999 | 32038 | } |
| @@ -32000,19 +32039,21 @@ | ||
| 32000 | 32039 | bReturn = TRUE; |
| 32001 | 32040 | } |
| 32002 | 32041 | } |
| 32003 | 32042 | |
| 32004 | 32043 | /* Releasing a pending lock */ |
| 32005 | - else if (dwFileOffsetLow == (DWORD)PENDING_BYTE && nNumberOfBytesToUnlockLow == 1){ | |
| 32044 | + else if (dwFileOffsetLow == (DWORD)PENDING_BYTE | |
| 32045 | + && nNumberOfBytesToUnlockLow == 1){ | |
| 32006 | 32046 | if (pFile->local.bPending){ |
| 32007 | 32047 | pFile->local.bPending = FALSE; |
| 32008 | 32048 | pFile->shared->bPending = FALSE; |
| 32009 | 32049 | bReturn = TRUE; |
| 32010 | 32050 | } |
| 32011 | 32051 | } |
| 32012 | 32052 | /* Releasing a reserved lock */ |
| 32013 | - else if (dwFileOffsetLow == (DWORD)RESERVED_BYTE && nNumberOfBytesToUnlockLow == 1){ | |
| 32053 | + else if (dwFileOffsetLow == (DWORD)RESERVED_BYTE | |
| 32054 | + && nNumberOfBytesToUnlockLow == 1){ | |
| 32014 | 32055 | if (pFile->local.bReserved) { |
| 32015 | 32056 | pFile->local.bReserved = FALSE; |
| 32016 | 32057 | pFile->shared->bReserved = FALSE; |
| 32017 | 32058 | bReturn = TRUE; |
| 32018 | 32059 | } |
| @@ -32174,10 +32215,11 @@ | ||
| 32174 | 32215 | assert( id!=0 ); |
| 32175 | 32216 | #ifndef SQLITE_OMIT_WAL |
| 32176 | 32217 | assert( pFile->pShm==0 ); |
| 32177 | 32218 | #endif |
| 32178 | 32219 | OSTRACE(("CLOSE %d\n", pFile->h)); |
| 32220 | + assert( pFile->h!=NULL && pFile->h!=INVALID_HANDLE_VALUE ); | |
| 32179 | 32221 | do{ |
| 32180 | 32222 | rc = osCloseHandle(pFile->h); |
| 32181 | 32223 | /* SimulateIOError( rc=0; cnt=MX_CLOSE_ATTEMPT; ); */ |
| 32182 | 32224 | }while( rc==0 && ++cnt < MX_CLOSE_ATTEMPT && (sqlite3_win32_sleep(100), 1) ); |
| 32183 | 32225 | #if SQLITE_OS_WINCE |
| @@ -32866,11 +32908,11 @@ | ||
| 32866 | 32908 | a[1] = win32IoerrRetryDelay; |
| 32867 | 32909 | } |
| 32868 | 32910 | return SQLITE_OK; |
| 32869 | 32911 | } |
| 32870 | 32912 | case SQLITE_FCNTL_TEMPFILENAME: { |
| 32871 | - char *zTFile = sqlite3_malloc( pFile->pVfs->mxPathname ); | |
| 32913 | + char *zTFile = sqlite3MallocZero( pFile->pVfs->mxPathname ); | |
| 32872 | 32914 | if( zTFile ){ |
| 32873 | 32915 | getTempname(pFile->pVfs->mxPathname, zTFile); |
| 32874 | 32916 | *(char**)pArg = zTFile; |
| 32875 | 32917 | } |
| 32876 | 32918 | return SQLITE_OK; |
| @@ -33090,11 +33132,11 @@ | ||
| 33090 | 33132 | bRc = osCloseHandle(p->aRegion[i].hMap); |
| 33091 | 33133 | OSTRACE(("SHM-PURGE pid-%d close region=%d %s\n", |
| 33092 | 33134 | (int)osGetCurrentProcessId(), i, |
| 33093 | 33135 | bRc ? "ok" : "failed")); |
| 33094 | 33136 | } |
| 33095 | - if( p->hFile.h != INVALID_HANDLE_VALUE ){ | |
| 33137 | + if( p->hFile.h!=NULL && p->hFile.h!=INVALID_HANDLE_VALUE ){ | |
| 33096 | 33138 | SimulateIOErrorBenign(1); |
| 33097 | 33139 | winClose((sqlite3_file *)&p->hFile); |
| 33098 | 33140 | SimulateIOErrorBenign(0); |
| 33099 | 33141 | } |
| 33100 | 33142 | if( deleteFlag ){ |
| @@ -33170,11 +33212,11 @@ | ||
| 33170 | 33212 | } |
| 33171 | 33213 | |
| 33172 | 33214 | rc = winOpen(pDbFd->pVfs, |
| 33173 | 33215 | pShmNode->zFilename, /* Name of the file (UTF-8) */ |
| 33174 | 33216 | (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, | |
| 33176 | 33218 | 0); |
| 33177 | 33219 | if( SQLITE_OK!=rc ){ |
| 33178 | 33220 | goto shm_open_err; |
| 33179 | 33221 | } |
| 33180 | 33222 | |
| @@ -33785,27 +33827,27 @@ | ||
| 33785 | 33827 | || eType==SQLITE_OPEN_MAIN_JOURNAL || eType==SQLITE_OPEN_TEMP_JOURNAL |
| 33786 | 33828 | || eType==SQLITE_OPEN_SUBJOURNAL || eType==SQLITE_OPEN_MASTER_JOURNAL |
| 33787 | 33829 | || eType==SQLITE_OPEN_TRANSIENT_DB || eType==SQLITE_OPEN_WAL |
| 33788 | 33830 | ); |
| 33789 | 33831 | |
| 33790 | - assert( id!=0 ); | |
| 33791 | - UNUSED_PARAMETER(pVfs); | |
| 33832 | + assert( pFile!=0 ); | |
| 33833 | + memset(pFile, 0, sizeof(winFile)); | |
| 33834 | + pFile->h = INVALID_HANDLE_VALUE; | |
| 33792 | 33835 | |
| 33793 | 33836 | #if SQLITE_OS_WINRT |
| 33794 | 33837 | if( !sqlite3_temp_directory ){ |
| 33795 | 33838 | sqlite3_log(SQLITE_ERROR, |
| 33796 | 33839 | "sqlite3_temp_directory variable should be set for WinRT"); |
| 33797 | 33840 | } |
| 33798 | 33841 | #endif |
| 33799 | 33842 | |
| 33800 | - pFile->h = INVALID_HANDLE_VALUE; | |
| 33801 | - | |
| 33802 | 33843 | /* If the second argument to this function is NULL, generate a |
| 33803 | 33844 | ** temporary file name to use |
| 33804 | 33845 | */ |
| 33805 | 33846 | if( !zUtf8Name ){ |
| 33806 | 33847 | assert(isDelete && !isOpenJournal); |
| 33848 | + memset(zTmpname, 0, MAX_PATH+2); | |
| 33807 | 33849 | rc = getTempname(MAX_PATH+2, zTmpname); |
| 33808 | 33850 | if( rc!=SQLITE_OK ){ |
| 33809 | 33851 | return rc; |
| 33810 | 33852 | } |
| 33811 | 33853 | zUtf8Name = zTmpname; |
| @@ -33924,11 +33966,13 @@ | ||
| 33924 | 33966 | pFile->lastErrno = lastErrno; |
| 33925 | 33967 | winLogError(SQLITE_CANTOPEN, pFile->lastErrno, "winOpen", zUtf8Name); |
| 33926 | 33968 | sqlite3_free(zConverted); |
| 33927 | 33969 | if( isReadWrite && !isExclusive ){ |
| 33928 | 33970 | 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); | |
| 33930 | 33974 | }else{ |
| 33931 | 33975 | return SQLITE_CANTOPEN_BKPT; |
| 33932 | 33976 | } |
| 33933 | 33977 | } |
| 33934 | 33978 | |
| @@ -33938,38 +33982,34 @@ | ||
| 33938 | 33982 | }else{ |
| 33939 | 33983 | *pOutFlags = SQLITE_OPEN_READONLY; |
| 33940 | 33984 | } |
| 33941 | 33985 | } |
| 33942 | 33986 | |
| 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 | 33987 | #if SQLITE_OS_WINCE |
| 33957 | 33988 | if( isReadWrite && eType==SQLITE_OPEN_MAIN_DB |
| 33958 | - && !winceCreateLock(zName, pFile) | |
| 33989 | + && (rc = winceCreateLock(zName, pFile))!=SQLITE_OK | |
| 33959 | 33990 | ){ |
| 33960 | 33991 | osCloseHandle(h); |
| 33961 | 33992 | sqlite3_free(zConverted); |
| 33962 | - return SQLITE_CANTOPEN_BKPT; | |
| 33993 | + return rc; | |
| 33963 | 33994 | } |
| 33964 | 33995 | if( isTemp ){ |
| 33965 | 33996 | pFile->zDeleteOnClose = zConverted; |
| 33966 | 33997 | }else |
| 33967 | 33998 | #endif |
| 33968 | 33999 | { |
| 33969 | 34000 | sqlite3_free(zConverted); |
| 33970 | 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; | |
| 33971 | 34011 | |
| 33972 | 34012 | OpenCounter(+1); |
| 33973 | 34013 | return rc; |
| 33974 | 34014 | } |
| 33975 | 34015 | |
| @@ -34011,11 +34051,12 @@ | ||
| 34011 | 34051 | if ( osGetFileAttributesExW(zConverted, GetFileExInfoStandard, |
| 34012 | 34052 | &sAttrData) ){ |
| 34013 | 34053 | attr = sAttrData.dwFileAttributes; |
| 34014 | 34054 | }else{ |
| 34015 | 34055 | 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 ){ | |
| 34017 | 34058 | rc = SQLITE_IOERR_DELETE_NOENT; /* Already gone? */ |
| 34018 | 34059 | }else{ |
| 34019 | 34060 | rc = SQLITE_ERROR; |
| 34020 | 34061 | } |
| 34021 | 34062 | break; |
| @@ -34023,11 +34064,12 @@ | ||
| 34023 | 34064 | #else |
| 34024 | 34065 | attr = osGetFileAttributesW(zConverted); |
| 34025 | 34066 | #endif |
| 34026 | 34067 | if ( attr==INVALID_FILE_ATTRIBUTES ){ |
| 34027 | 34068 | 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 ){ | |
| 34029 | 34071 | rc = SQLITE_IOERR_DELETE_NOENT; /* Already gone? */ |
| 34030 | 34072 | }else{ |
| 34031 | 34073 | rc = SQLITE_ERROR; |
| 34032 | 34074 | } |
| 34033 | 34075 | break; |
| @@ -34050,11 +34092,12 @@ | ||
| 34050 | 34092 | else{ |
| 34051 | 34093 | do { |
| 34052 | 34094 | attr = osGetFileAttributesA(zConverted); |
| 34053 | 34095 | if ( attr==INVALID_FILE_ATTRIBUTES ){ |
| 34054 | 34096 | 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 ){ | |
| 34056 | 34099 | rc = SQLITE_IOERR_DELETE_NOENT; /* Already gone? */ |
| 34057 | 34100 | }else{ |
| 34058 | 34101 | rc = SQLITE_ERROR; |
| 34059 | 34102 | } |
| 34060 | 34103 | break; |
| @@ -34218,20 +34261,16 @@ | ||
| 34218 | 34261 | ** for converting the relative path name to an absolute |
| 34219 | 34262 | ** one by prepending the data directory and a slash. |
| 34220 | 34263 | */ |
| 34221 | 34264 | char zOut[MAX_PATH+1]; |
| 34222 | 34265 | 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); | |
| 34224 | 34268 | sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s\\%s", |
| 34225 | 34269 | sqlite3_data_directory, zOut); |
| 34226 | 34270 | }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); | |
| 34233 | 34272 | } |
| 34234 | 34273 | return SQLITE_OK; |
| 34235 | 34274 | #endif |
| 34236 | 34275 | |
| 34237 | 34276 | #if (SQLITE_OS_WINCE || SQLITE_OS_WINRT) && !defined(__CYGWIN__) |
| @@ -34385,13 +34424,13 @@ | ||
| 34385 | 34424 | } |
| 34386 | 34425 | static void winDlError(sqlite3_vfs *pVfs, int nBuf, char *zBufOut){ |
| 34387 | 34426 | UNUSED_PARAMETER(pVfs); |
| 34388 | 34427 | getLastErrorMsg(osGetLastError(), nBuf, zBufOut); |
| 34389 | 34428 | } |
| 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){ | |
| 34391 | 34430 | UNUSED_PARAMETER(pVfs); |
| 34392 | - return (void(*)(void))osGetProcAddressA((HANDLE)pHandle, zSymbol); | |
| 34431 | + return (void(*)(void))osGetProcAddressA((HANDLE)pH, zSym); | |
| 34393 | 34432 | } |
| 34394 | 34433 | static void winDlClose(sqlite3_vfs *pVfs, void *pHandle){ |
| 34395 | 34434 | UNUSED_PARAMETER(pVfs); |
| 34396 | 34435 | osFreeLibrary((HANDLE)pHandle); |
| 34397 | 34436 | } |
| @@ -34485,11 +34524,12 @@ | ||
| 34485 | 34524 | #ifdef SQLITE_TEST |
| 34486 | 34525 | static const sqlite3_int64 unixEpoch = 24405875*(sqlite3_int64)8640000; |
| 34487 | 34526 | #endif |
| 34488 | 34527 | /* 2^32 - to avoid use of LL and warnings in gcc */ |
| 34489 | 34528 | 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; | |
| 34491 | 34531 | |
| 34492 | 34532 | #if SQLITE_OS_WINCE |
| 34493 | 34533 | SYSTEMTIME time; |
| 34494 | 34534 | osGetSystemTime(&time); |
| 34495 | 34535 | /* if SystemTimeToFileTime() fails, it returns zero. */ |
| @@ -39163,10 +39203,12 @@ | ||
| 39163 | 39203 | pPager->eState = PAGER_ERROR; |
| 39164 | 39204 | } |
| 39165 | 39205 | return rc; |
| 39166 | 39206 | } |
| 39167 | 39207 | |
| 39208 | +static int pager_truncate(Pager *pPager, Pgno nPage); | |
| 39209 | + | |
| 39168 | 39210 | /* |
| 39169 | 39211 | ** This routine ends a transaction. A transaction is usually ended by |
| 39170 | 39212 | ** either a COMMIT or a ROLLBACK operation. This routine may be called |
| 39171 | 39213 | ** after rollback of a hot-journal, or if an error occurs while opening |
| 39172 | 39214 | ** the journal file or writing the very first journal-header of a |
| @@ -39216,11 +39258,11 @@ | ||
| 39216 | 39258 | ** tries to unlock the database file if not in exclusive mode. If the |
| 39217 | 39259 | ** unlock operation fails as well, then the first error code related |
| 39218 | 39260 | ** to the first error encountered (the journal finalization one) is |
| 39219 | 39261 | ** returned. |
| 39220 | 39262 | */ |
| 39221 | -static int pager_end_transaction(Pager *pPager, int hasMaster){ | |
| 39263 | +static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){ | |
| 39222 | 39264 | int rc = SQLITE_OK; /* Error code from journal finalization operation */ |
| 39223 | 39265 | int rc2 = SQLITE_OK; /* Error code from db file unlock operation */ |
| 39224 | 39266 | |
| 39225 | 39267 | /* Do nothing if the pager does not have an open write transaction |
| 39226 | 39268 | ** or at least a RESERVED lock. This function may be called when there |
| @@ -39302,11 +39344,21 @@ | ||
| 39302 | 39344 | ** locking_mode=exclusive mode but is no longer, drop the EXCLUSIVE |
| 39303 | 39345 | ** lock held on the database file. |
| 39304 | 39346 | */ |
| 39305 | 39347 | rc2 = sqlite3WalEndWriteTransaction(pPager->pWal); |
| 39306 | 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); | |
| 39307 | 39358 | } |
| 39359 | + | |
| 39308 | 39360 | if( !pPager->exclusiveMode |
| 39309 | 39361 | && (!pagerUseWal(pPager) || sqlite3WalExclusiveMode(pPager->pWal, 0)) |
| 39310 | 39362 | ){ |
| 39311 | 39363 | rc2 = pagerUnlockDb(pPager, SHARED_LOCK); |
| 39312 | 39364 | pPager->changeCountDone = 0; |
| @@ -39341,11 +39393,11 @@ | ||
| 39341 | 39393 | sqlite3BeginBenignMalloc(); |
| 39342 | 39394 | sqlite3PagerRollback(pPager); |
| 39343 | 39395 | sqlite3EndBenignMalloc(); |
| 39344 | 39396 | }else if( !pPager->exclusiveMode ){ |
| 39345 | 39397 | assert( pPager->eState==PAGER_READER ); |
| 39346 | - pager_end_transaction(pPager, 0); | |
| 39398 | + pager_end_transaction(pPager, 0, 0); | |
| 39347 | 39399 | } |
| 39348 | 39400 | } |
| 39349 | 39401 | pager_unlock(pPager); |
| 39350 | 39402 | } |
| 39351 | 39403 | |
| @@ -40116,11 +40168,11 @@ | ||
| 40116 | 40168 | && (pPager->eState>=PAGER_WRITER_DBMOD || pPager->eState==PAGER_OPEN) |
| 40117 | 40169 | ){ |
| 40118 | 40170 | rc = sqlite3PagerSync(pPager); |
| 40119 | 40171 | } |
| 40120 | 40172 | if( rc==SQLITE_OK ){ |
| 40121 | - rc = pager_end_transaction(pPager, zMaster[0]!='\0'); | |
| 40173 | + rc = pager_end_transaction(pPager, zMaster[0]!='\0', 0); | |
| 40122 | 40174 | testcase( rc!=SQLITE_OK ); |
| 40123 | 40175 | } |
| 40124 | 40176 | if( rc==SQLITE_OK && zMaster[0] && res ){ |
| 40125 | 40177 | /* If there was a master journal and this routine will return success, |
| 40126 | 40178 | ** see if it is possible to delete the master journal. |
| @@ -41068,16 +41120,30 @@ | ||
| 41068 | 41120 | /* |
| 41069 | 41121 | ** Truncate the in-memory database file image to nPage pages. This |
| 41070 | 41122 | ** function does not actually modify the database file on disk. It |
| 41071 | 41123 | ** just sets the internal state of the pager object so that the |
| 41072 | 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. | |
| 41073 | 41130 | */ |
| 41074 | 41131 | SQLITE_PRIVATE void sqlite3PagerTruncateImage(Pager *pPager, Pgno nPage){ |
| 41075 | 41132 | assert( pPager->dbSize>=nPage ); |
| 41076 | 41133 | assert( pPager->eState>=PAGER_WRITER_CACHEMOD ); |
| 41077 | 41134 | 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. */ | |
| 41079 | 41145 | } |
| 41080 | 41146 | |
| 41081 | 41147 | |
| 41082 | 41148 | /* |
| 41083 | 41149 | ** This function is called before attempting a hot-journal rollback. It |
| @@ -42126,10 +42192,15 @@ | ||
| 42126 | 42192 | } |
| 42127 | 42193 | if( rc!=SQLITE_OK ){ |
| 42128 | 42194 | goto failed; |
| 42129 | 42195 | } |
| 42130 | 42196 | if( bHotJournal ){ |
| 42197 | + if( pPager->readOnly ){ | |
| 42198 | + rc = SQLITE_READONLY_ROLLBACK; | |
| 42199 | + goto failed; | |
| 42200 | + } | |
| 42201 | + | |
| 42131 | 42202 | /* Get an EXCLUSIVE lock on the database file. At this point it is |
| 42132 | 42203 | ** important that a RESERVED lock is not obtained on the way to the |
| 42133 | 42204 | ** EXCLUSIVE lock. If it were, another process might open the |
| 42134 | 42205 | ** database file, detect the RESERVED lock, and conclude that the |
| 42135 | 42206 | ** database is safe to read while this process is still rolling the |
| @@ -43210,40 +43281,10 @@ | ||
| 43210 | 43281 | #else |
| 43211 | 43282 | rc = pager_incr_changecounter(pPager, 0); |
| 43212 | 43283 | #endif |
| 43213 | 43284 | if( rc!=SQLITE_OK ) goto commit_phase_one_exit; |
| 43214 | 43285 | |
| 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 | 43286 | /* Write the master journal name into the journal file. If a master |
| 43246 | 43287 | ** journal file name has already been written to the journal file, |
| 43247 | 43288 | ** or if zMaster is NULL (no master journal), then this call is a no-op. |
| 43248 | 43289 | */ |
| 43249 | 43290 | rc = writeMasterJournal(pPager, zMaster); |
| @@ -43267,15 +43308,18 @@ | ||
| 43267 | 43308 | if( rc!=SQLITE_OK ){ |
| 43268 | 43309 | assert( rc!=SQLITE_IOERR_BLOCKED ); |
| 43269 | 43310 | goto commit_phase_one_exit; |
| 43270 | 43311 | } |
| 43271 | 43312 | 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 ){ | |
| 43277 | 43321 | Pgno nNew = pPager->dbSize - (pPager->dbSize==PAGER_MJ_PGNO(pPager)); |
| 43278 | 43322 | assert( pPager->eState==PAGER_WRITER_DBMOD ); |
| 43279 | 43323 | rc = pager_truncate(pPager, nNew); |
| 43280 | 43324 | if( rc!=SQLITE_OK ) goto commit_phase_one_exit; |
| 43281 | 43325 | } |
| @@ -43344,11 +43388,11 @@ | ||
| 43344 | 43388 | pPager->eState = PAGER_READER; |
| 43345 | 43389 | return SQLITE_OK; |
| 43346 | 43390 | } |
| 43347 | 43391 | |
| 43348 | 43392 | PAGERTRACE(("COMMIT %d\n", PAGERID(pPager))); |
| 43349 | - rc = pager_end_transaction(pPager, pPager->setMaster); | |
| 43393 | + rc = pager_end_transaction(pPager, pPager->setMaster, 1); | |
| 43350 | 43394 | return pager_error(pPager, rc); |
| 43351 | 43395 | } |
| 43352 | 43396 | |
| 43353 | 43397 | /* |
| 43354 | 43398 | ** If a write transaction is open, then all changes made within the |
| @@ -43389,15 +43433,15 @@ | ||
| 43389 | 43433 | if( pPager->eState<=PAGER_READER ) return SQLITE_OK; |
| 43390 | 43434 | |
| 43391 | 43435 | if( pagerUseWal(pPager) ){ |
| 43392 | 43436 | int rc2; |
| 43393 | 43437 | rc = sqlite3PagerSavepoint(pPager, SAVEPOINT_ROLLBACK, -1); |
| 43394 | - rc2 = pager_end_transaction(pPager, pPager->setMaster); | |
| 43438 | + rc2 = pager_end_transaction(pPager, pPager->setMaster, 0); | |
| 43395 | 43439 | if( rc==SQLITE_OK ) rc = rc2; |
| 43396 | 43440 | }else if( !isOpen(pPager->jfd) || pPager->eState==PAGER_WRITER_LOCKED ){ |
| 43397 | 43441 | int eState = pPager->eState; |
| 43398 | - rc = pager_end_transaction(pPager, 0); | |
| 43442 | + rc = pager_end_transaction(pPager, 0, 0); | |
| 43399 | 43443 | if( !MEMDB && eState>PAGER_WRITER_LOCKED ){ |
| 43400 | 43444 | /* This can happen using journal_mode=off. Move the pager to the error |
| 43401 | 43445 | ** state to indicate that the contents of the cache may not be trusted. |
| 43402 | 43446 | ** Any active readers will get SQLITE_ABORT. |
| 43403 | 43447 | */ |
| @@ -43791,11 +43835,12 @@ | ||
| 43791 | 43835 | ** the journal needs to be sync()ed before database page pPg->pgno |
| 43792 | 43836 | ** can be written to. The caller has already promised not to write to it. |
| 43793 | 43837 | */ |
| 43794 | 43838 | if( (pPg->flags&PGHDR_NEED_SYNC) && !isCommit ){ |
| 43795 | 43839 | 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 ); | |
| 43797 | 43842 | assert( pPg->flags&PGHDR_DIRTY ); |
| 43798 | 43843 | } |
| 43799 | 43844 | |
| 43800 | 43845 | /* If the cache contains a page with page-number pgno, remove it |
| 43801 | 43846 | ** from its hash chain. Also, if the PGHDR_NEED_SYNC flag was set for |
| @@ -47795,10 +47840,11 @@ | ||
| 47795 | 47840 | MemPage *pPage1; /* First page of the database */ |
| 47796 | 47841 | u8 openFlags; /* Flags to sqlite3BtreeOpen() */ |
| 47797 | 47842 | #ifndef SQLITE_OMIT_AUTOVACUUM |
| 47798 | 47843 | u8 autoVacuum; /* True if auto-vacuum is enabled */ |
| 47799 | 47844 | u8 incrVacuum; /* True if incr-vacuum is enabled */ |
| 47845 | + u8 bDoTruncate; /* True to truncate db on commit */ | |
| 47800 | 47846 | #endif |
| 47801 | 47847 | u8 inTransaction; /* Transaction state */ |
| 47802 | 47848 | u8 max1bytePayload; /* Maximum first byte of cell for a 1-byte payload */ |
| 47803 | 47849 | u16 btsFlags; /* Boolean parameters. See BTS_* macros below */ |
| 47804 | 47850 | u16 maxLocal; /* Maximum local payload in non-LEAFDATA tables */ |
| @@ -48361,10 +48407,29 @@ | ||
| 48361 | 48407 | ** is empty, the offset should be 65536, but the 2-byte value stores zero. |
| 48362 | 48408 | ** This routine makes the necessary adjustment to 65536. |
| 48363 | 48409 | */ |
| 48364 | 48410 | #define get2byteNotZero(X) (((((int)get2byte(X))-1)&0xffff)+1) |
| 48365 | 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 | + | |
| 48366 | 48431 | #ifndef SQLITE_OMIT_SHARED_CACHE |
| 48367 | 48432 | /* |
| 48368 | 48433 | ** A list of BtShared objects that are eligible for participation |
| 48369 | 48434 | ** in shared cache. This variable has file scope during normal builds, |
| 48370 | 48435 | ** but the test harness needs to access it so we make it global for |
| @@ -50913,10 +50978,11 @@ | ||
| 50913 | 50978 | ** is requested, this is a no-op. |
| 50914 | 50979 | */ |
| 50915 | 50980 | if( p->inTrans==TRANS_WRITE || (p->inTrans==TRANS_READ && !wrflag) ){ |
| 50916 | 50981 | goto trans_begun; |
| 50917 | 50982 | } |
| 50983 | + assert( IfNotOmitAV(pBt->bDoTruncate)==0 ); | |
| 50918 | 50984 | |
| 50919 | 50985 | /* Write transactions are not possible on a read-only database */ |
| 50920 | 50986 | if( (pBt->btsFlags & BTS_READ_ONLY)!=0 && wrflag ){ |
| 50921 | 50987 | rc = SQLITE_READONLY; |
| 50922 | 50988 | goto trans_begun; |
| @@ -51229,28 +51295,27 @@ | ||
| 51229 | 51295 | |
| 51230 | 51296 | /* Forward declaration required by incrVacuumStep(). */ |
| 51231 | 51297 | static int allocateBtreePage(BtShared *, MemPage **, Pgno *, Pgno, u8); |
| 51232 | 51298 | |
| 51233 | 51299 | /* |
| 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){ | |
| 51252 | 51317 | Pgno nFreeList; /* Number of pages still on the free-list */ |
| 51253 | 51318 | int rc; |
| 51254 | 51319 | |
| 51255 | 51320 | assert( sqlite3_mutex_held(pBt->mutex) ); |
| 51256 | 51321 | assert( iLastPg>nFin ); |
| @@ -51271,85 +51336,98 @@ | ||
| 51271 | 51336 | if( eType==PTRMAP_ROOTPAGE ){ |
| 51272 | 51337 | return SQLITE_CORRUPT_BKPT; |
| 51273 | 51338 | } |
| 51274 | 51339 | |
| 51275 | 51340 | if( eType==PTRMAP_FREEPAGE ){ |
| 51276 | - if( nFin==0 ){ | |
| 51341 | + if( bCommit==0 ){ | |
| 51277 | 51342 | /* 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 | |
| 51279 | 51344 | ** truncated to zero after this function returns, so it doesn't |
| 51280 | 51345 | ** matter if it still contains some garbage entries. |
| 51281 | 51346 | */ |
| 51282 | 51347 | Pgno iFreePg; |
| 51283 | 51348 | MemPage *pFreePg; |
| 51284 | - rc = allocateBtreePage(pBt, &pFreePg, &iFreePg, iLastPg, 1); | |
| 51349 | + rc = allocateBtreePage(pBt, &pFreePg, &iFreePg, iLastPg, BTALLOC_EXACT); | |
| 51285 | 51350 | if( rc!=SQLITE_OK ){ |
| 51286 | 51351 | return rc; |
| 51287 | 51352 | } |
| 51288 | 51353 | assert( iFreePg==iLastPg ); |
| 51289 | 51354 | releasePage(pFreePg); |
| 51290 | 51355 | } |
| 51291 | 51356 | } else { |
| 51292 | 51357 | Pgno iFreePg; /* Index of free page to move pLastPg to */ |
| 51293 | 51358 | MemPage *pLastPg; |
| 51359 | + u8 eMode = BTALLOC_ANY; /* Mode parameter for allocateBtreePage() */ | |
| 51360 | + Pgno iNear = 0; /* nearby parameter for allocateBtreePage() */ | |
| 51294 | 51361 | |
| 51295 | 51362 | rc = btreeGetPage(pBt, iLastPg, &pLastPg, 0); |
| 51296 | 51363 | if( rc!=SQLITE_OK ){ |
| 51297 | 51364 | return rc; |
| 51298 | 51365 | } |
| 51299 | 51366 | |
| 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 | |
| 51301 | 51368 | ** is swapped with the first free page pulled off the free list. |
| 51302 | 51369 | ** |
| 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 | |
| 51304 | 51371 | ** looping until a free-page located within the first nFin pages |
| 51305 | 51372 | ** of the file is found. |
| 51306 | 51373 | */ |
| 51374 | + if( bCommit==0 ){ | |
| 51375 | + eMode = BTALLOC_LE; | |
| 51376 | + iNear = nFin; | |
| 51377 | + } | |
| 51307 | 51378 | do { |
| 51308 | 51379 | MemPage *pFreePg; |
| 51309 | - rc = allocateBtreePage(pBt, &pFreePg, &iFreePg, 0, 0); | |
| 51380 | + rc = allocateBtreePage(pBt, &pFreePg, &iFreePg, iNear, eMode); | |
| 51310 | 51381 | if( rc!=SQLITE_OK ){ |
| 51311 | 51382 | releasePage(pLastPg); |
| 51312 | 51383 | return rc; |
| 51313 | 51384 | } |
| 51314 | 51385 | releasePage(pFreePg); |
| 51315 | - }while( nFin!=0 && iFreePg>nFin ); | |
| 51386 | + }while( bCommit && iFreePg>nFin ); | |
| 51316 | 51387 | assert( iFreePg<iLastPg ); |
| 51317 | 51388 | |
| 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); | |
| 51322 | 51390 | releasePage(pLastPg); |
| 51323 | 51391 | if( rc!=SQLITE_OK ){ |
| 51324 | 51392 | return rc; |
| 51325 | 51393 | } |
| 51326 | 51394 | } |
| 51327 | 51395 | } |
| 51328 | 51396 | |
| 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; | |
| 51347 | 51402 | pBt->nPage = iLastPg; |
| 51348 | 51403 | } |
| 51349 | 51404 | return SQLITE_OK; |
| 51350 | 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 | +} | |
| 51351 | 51429 | |
| 51352 | 51430 | /* |
| 51353 | 51431 | ** A write-transaction must be opened before calling this function. |
| 51354 | 51432 | ** It performs a single unit of work towards an incremental vacuum. |
| 51355 | 51433 | ** |
| @@ -51364,15 +51442,25 @@ | ||
| 51364 | 51442 | sqlite3BtreeEnter(p); |
| 51365 | 51443 | assert( pBt->inTransaction==TRANS_WRITE && p->inTrans==TRANS_WRITE ); |
| 51366 | 51444 | if( !pBt->autoVacuum ){ |
| 51367 | 51445 | rc = SQLITE_DONE; |
| 51368 | 51446 | }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; | |
| 51374 | 51462 | } |
| 51375 | 51463 | } |
| 51376 | 51464 | sqlite3BtreeLeave(p); |
| 51377 | 51465 | return rc; |
| 51378 | 51466 | } |
| @@ -51395,13 +51483,11 @@ | ||
| 51395 | 51483 | invalidateAllOverflowCache(pBt); |
| 51396 | 51484 | assert(pBt->autoVacuum); |
| 51397 | 51485 | if( !pBt->incrVacuum ){ |
| 51398 | 51486 | Pgno nFin; /* Number of pages in database after autovacuuming */ |
| 51399 | 51487 | Pgno nFree; /* Number of pages on the freelist initially */ |
| 51400 | - Pgno nPtrmap; /* Number of PtrMap pages to be freed */ | |
| 51401 | 51488 | Pgno iFree; /* The next page to be freed */ |
| 51402 | - int nEntry; /* Number of entries on one ptrmap page */ | |
| 51403 | 51489 | Pgno nOrig; /* Database size before freeing */ |
| 51404 | 51490 | |
| 51405 | 51491 | nOrig = btreePagecount(pBt); |
| 51406 | 51492 | if( PTRMAP_ISPAGE(pBt, nOrig) || nOrig==PENDING_BYTE_PAGE(pBt) ){ |
| 51407 | 51493 | /* It is not possible to create a database for which the final page |
| @@ -51410,30 +51496,22 @@ | ||
| 51410 | 51496 | */ |
| 51411 | 51497 | return SQLITE_CORRUPT_BKPT; |
| 51412 | 51498 | } |
| 51413 | 51499 | |
| 51414 | 51500 | 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); | |
| 51424 | 51502 | if( nFin>nOrig ) return SQLITE_CORRUPT_BKPT; |
| 51425 | 51503 | |
| 51426 | 51504 | for(iFree=nOrig; iFree>nFin && rc==SQLITE_OK; iFree--){ |
| 51427 | - rc = incrVacuumStep(pBt, nFin, iFree); | |
| 51505 | + rc = incrVacuumStep(pBt, nFin, iFree, 1); | |
| 51428 | 51506 | } |
| 51429 | 51507 | if( (rc==SQLITE_DONE || rc==SQLITE_OK) && nFree>0 ){ |
| 51430 | 51508 | rc = sqlite3PagerWrite(pBt->pPage1->pDbPage); |
| 51431 | 51509 | put4byte(&pBt->pPage1->aData[32], 0); |
| 51432 | 51510 | put4byte(&pBt->pPage1->aData[36], 0); |
| 51433 | 51511 | put4byte(&pBt->pPage1->aData[28], nFin); |
| 51434 | - sqlite3PagerTruncateImage(pBt->pPager, nFin); | |
| 51512 | + pBt->bDoTruncate = 1; | |
| 51435 | 51513 | pBt->nPage = nFin; |
| 51436 | 51514 | } |
| 51437 | 51515 | if( rc!=SQLITE_OK ){ |
| 51438 | 51516 | sqlite3PagerRollback(pPager); |
| 51439 | 51517 | } |
| @@ -51484,10 +51562,13 @@ | ||
| 51484 | 51562 | if( rc!=SQLITE_OK ){ |
| 51485 | 51563 | sqlite3BtreeLeave(p); |
| 51486 | 51564 | return rc; |
| 51487 | 51565 | } |
| 51488 | 51566 | } |
| 51567 | + if( pBt->bDoTruncate ){ | |
| 51568 | + sqlite3PagerTruncateImage(pBt->pPager, pBt->nPage); | |
| 51569 | + } | |
| 51489 | 51570 | #endif |
| 51490 | 51571 | rc = sqlite3PagerCommitPhaseOne(pBt->pPager, zMaster, 0); |
| 51491 | 51572 | sqlite3BtreeLeave(p); |
| 51492 | 51573 | } |
| 51493 | 51574 | return rc; |
| @@ -51499,10 +51580,13 @@ | ||
| 51499 | 51580 | */ |
| 51500 | 51581 | static void btreeEndTransaction(Btree *p){ |
| 51501 | 51582 | BtShared *pBt = p->pBt; |
| 51502 | 51583 | assert( sqlite3BtreeHoldsMutex(p) ); |
| 51503 | 51584 | |
| 51585 | +#ifndef SQLITE_OMIT_AUTOVACUUM | |
| 51586 | + pBt->bDoTruncate = 0; | |
| 51587 | +#endif | |
| 51504 | 51588 | btreeClearHasContent(pBt); |
| 51505 | 51589 | if( p->inTrans>TRANS_NONE && p->db->activeVdbeCnt>1 ){ |
| 51506 | 51590 | /* If there are other active statements that belong to this database |
| 51507 | 51591 | ** handle, downgrade to a read-only transaction. The other statements |
| 51508 | 51592 | ** may still be reading from the database. */ |
| @@ -53171,25 +53255,27 @@ | ||
| 53171 | 53255 | ** |
| 53172 | 53256 | ** SQLITE_OK is returned on success. Any other return value indicates |
| 53173 | 53257 | ** an error. *ppPage and *pPgno are undefined in the event of an error. |
| 53174 | 53258 | ** Do not invoke sqlite3PagerUnref() on *ppPage if an error is returned. |
| 53175 | 53259 | ** |
| 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 | |
| 53177 | 53261 | ** locate a page close to the page number "nearby". This can be used in an |
| 53178 | 53262 | ** attempt to keep related pages close to each other in the database file, |
| 53179 | 53263 | ** which in turn can make database access faster. |
| 53180 | 53264 | ** |
| 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. | |
| 53184 | 53270 | */ |
| 53185 | 53271 | 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 */ | |
| 53191 | 53277 | ){ |
| 53192 | 53278 | MemPage *pPage1; |
| 53193 | 53279 | int rc; |
| 53194 | 53280 | u32 n; /* Number of pages on the freelist */ |
| 53195 | 53281 | u32 k; /* Number of leaves on the trunk of the freelist */ |
| @@ -53196,10 +53282,11 @@ | ||
| 53196 | 53282 | MemPage *pTrunk = 0; |
| 53197 | 53283 | MemPage *pPrevTrunk = 0; |
| 53198 | 53284 | Pgno mxPage; /* Total size of the database file */ |
| 53199 | 53285 | |
| 53200 | 53286 | assert( sqlite3_mutex_held(pBt->mutex) ); |
| 53287 | + assert( eMode==BTALLOC_ANY || (nearby>0 && IfNotOmitAV(pBt->autoVacuum)) ); | |
| 53201 | 53288 | pPage1 = pBt->pPage1; |
| 53202 | 53289 | mxPage = btreePagecount(pBt); |
| 53203 | 53290 | n = get4byte(&pPage1->aData[36]); |
| 53204 | 53291 | testcase( n==mxPage-1 ); |
| 53205 | 53292 | if( n>=mxPage ){ |
| @@ -53208,25 +53295,28 @@ | ||
| 53208 | 53295 | if( n>0 ){ |
| 53209 | 53296 | /* There are pages on the freelist. Reuse one of those pages. */ |
| 53210 | 53297 | Pgno iTrunk; |
| 53211 | 53298 | u8 searchList = 0; /* If the free-list must be searched for 'nearby' */ |
| 53212 | 53299 | |
| 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 | |
| 53214 | 53301 | ** shows that the page 'nearby' is somewhere on the free-list, then |
| 53215 | 53302 | ** the entire-list will be searched for that page. |
| 53216 | 53303 | */ |
| 53217 | 53304 | #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; | |
| 53228 | 53318 | } |
| 53229 | 53319 | #endif |
| 53230 | 53320 | |
| 53231 | 53321 | /* Decrement the free-list count by 1. Set iTrunk to the index of the |
| 53232 | 53322 | ** first free-list trunk page. iPrevTrunk is initially 1. |
| @@ -53235,11 +53325,12 @@ | ||
| 53235 | 53325 | if( rc ) return rc; |
| 53236 | 53326 | put4byte(&pPage1->aData[36], n-1); |
| 53237 | 53327 | |
| 53238 | 53328 | /* The code within this loop is run only once if the 'searchList' variable |
| 53239 | 53329 | ** 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) | |
| 53241 | 53332 | */ |
| 53242 | 53333 | do { |
| 53243 | 53334 | pPrevTrunk = pTrunk; |
| 53244 | 53335 | if( pPrevTrunk ){ |
| 53245 | 53336 | iTrunk = get4byte(&pPrevTrunk->aData[0]); |
| @@ -53277,15 +53368,17 @@ | ||
| 53277 | 53368 | }else if( k>(u32)(pBt->usableSize/4 - 2) ){ |
| 53278 | 53369 | /* Value of k is out of range. Database corruption */ |
| 53279 | 53370 | rc = SQLITE_CORRUPT_BKPT; |
| 53280 | 53371 | goto end_allocate_page; |
| 53281 | 53372 | #ifndef SQLITE_OMIT_AUTOVACUUM |
| 53282 | - }else if( searchList && nearby==iTrunk ){ | |
| 53373 | + }else if( searchList | |
| 53374 | + && (nearby==iTrunk || (iTrunk<nearby && eMode==BTALLOC_LE)) | |
| 53375 | + ){ | |
| 53283 | 53376 | /* The list is being searched and this trunk page is the page |
| 53284 | 53377 | ** to allocate, regardless of whether it has leaves. |
| 53285 | 53378 | */ |
| 53286 | - assert( *pPgno==iTrunk ); | |
| 53379 | + *pPgno = iTrunk; | |
| 53287 | 53380 | *ppPage = pTrunk; |
| 53288 | 53381 | searchList = 0; |
| 53289 | 53382 | rc = sqlite3PagerWrite(pTrunk->pDbPage); |
| 53290 | 53383 | if( rc ){ |
| 53291 | 53384 | goto end_allocate_page; |
| @@ -53344,18 +53437,28 @@ | ||
| 53344 | 53437 | u32 closest; |
| 53345 | 53438 | Pgno iPage; |
| 53346 | 53439 | unsigned char *aData = pTrunk->aData; |
| 53347 | 53440 | if( nearby>0 ){ |
| 53348 | 53441 | u32 i; |
| 53349 | - int dist; | |
| 53350 | 53442 | 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 | + } | |
| 53357 | 53460 | } |
| 53358 | 53461 | } |
| 53359 | 53462 | }else{ |
| 53360 | 53463 | closest = 0; |
| 53361 | 53464 | } |
| @@ -53365,11 +53468,13 @@ | ||
| 53365 | 53468 | if( iPage>mxPage ){ |
| 53366 | 53469 | rc = SQLITE_CORRUPT_BKPT; |
| 53367 | 53470 | goto end_allocate_page; |
| 53368 | 53471 | } |
| 53369 | 53472 | testcase( iPage==mxPage ); |
| 53370 | - if( !searchList || iPage==nearby ){ | |
| 53473 | + if( !searchList | |
| 53474 | + || (iPage==nearby || (iPage<nearby && eMode==BTALLOC_LE)) | |
| 53475 | + ){ | |
| 53371 | 53476 | int noContent; |
| 53372 | 53477 | *pPgno = iPage; |
| 53373 | 53478 | TRACE(("ALLOCATE: %d was leaf %d of %d on trunk %d" |
| 53374 | 53479 | ": %d more free pages\n", |
| 53375 | 53480 | *pPgno, closest+1, k, pTrunk->pgno, n-1)); |
| @@ -53392,12 +53497,30 @@ | ||
| 53392 | 53497 | } |
| 53393 | 53498 | releasePage(pPrevTrunk); |
| 53394 | 53499 | pPrevTrunk = 0; |
| 53395 | 53500 | }while( searchList ); |
| 53396 | 53501 | }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 | + | |
| 53399 | 53522 | rc = sqlite3PagerWrite(pBt->pPage1->pDbPage); |
| 53400 | 53523 | if( rc ) return rc; |
| 53401 | 53524 | pBt->nPage++; |
| 53402 | 53525 | if( pBt->nPage==PENDING_BYTE_PAGE(pBt) ) pBt->nPage++; |
| 53403 | 53526 | |
| @@ -53408,11 +53531,11 @@ | ||
| 53408 | 53531 | ** becomes a new pointer-map page, the second is used by the caller. |
| 53409 | 53532 | */ |
| 53410 | 53533 | MemPage *pPg = 0; |
| 53411 | 53534 | TRACE(("ALLOCATE: %d from end of file (pointer-map page)\n", pBt->nPage)); |
| 53412 | 53535 | assert( pBt->nPage!=PENDING_BYTE_PAGE(pBt) ); |
| 53413 | - rc = btreeGetPage(pBt, pBt->nPage, &pPg, 1); | |
| 53536 | + rc = btreeGetPage(pBt, pBt->nPage, &pPg, bNoContent); | |
| 53414 | 53537 | if( rc==SQLITE_OK ){ |
| 53415 | 53538 | rc = sqlite3PagerWrite(pPg->pDbPage); |
| 53416 | 53539 | releasePage(pPg); |
| 53417 | 53540 | } |
| 53418 | 53541 | if( rc ) return rc; |
| @@ -53422,11 +53545,11 @@ | ||
| 53422 | 53545 | #endif |
| 53423 | 53546 | put4byte(28 + (u8*)pBt->pPage1->aData, pBt->nPage); |
| 53424 | 53547 | *pPgno = pBt->nPage; |
| 53425 | 53548 | |
| 53426 | 53549 | assert( *pPgno!=PENDING_BYTE_PAGE(pBt) ); |
| 53427 | - rc = btreeGetPage(pBt, *pPgno, ppPage, 1); | |
| 53550 | + rc = btreeGetPage(pBt, *pPgno, ppPage, bNoContent); | |
| 53428 | 53551 | if( rc ) return rc; |
| 53429 | 53552 | rc = sqlite3PagerWrite((*ppPage)->pDbPage); |
| 53430 | 53553 | if( rc!=SQLITE_OK ){ |
| 53431 | 53554 | releasePage(*ppPage); |
| 53432 | 53555 | } |
| @@ -55437,11 +55560,11 @@ | ||
| 55437 | 55560 | |
| 55438 | 55561 | /* Allocate a page. The page that currently resides at pgnoRoot will |
| 55439 | 55562 | ** be moved to the allocated page (unless the allocated page happens |
| 55440 | 55563 | ** to reside at pgnoRoot). |
| 55441 | 55564 | */ |
| 55442 | - rc = allocateBtreePage(pBt, &pPageMove, &pgnoMove, pgnoRoot, 1); | |
| 55565 | + rc = allocateBtreePage(pBt, &pPageMove, &pgnoMove, pgnoRoot, BTALLOC_EXACT); | |
| 55443 | 55566 | if( rc!=SQLITE_OK ){ |
| 55444 | 55567 | return rc; |
| 55445 | 55568 | } |
| 55446 | 55569 | |
| 55447 | 55570 | if( pgnoMove!=pgnoRoot ){ |
| @@ -57129,11 +57252,10 @@ | ||
| 57129 | 57252 | } |
| 57130 | 57253 | }else{ |
| 57131 | 57254 | nDestTruncate = nSrcPage * (pgszSrc/pgszDest); |
| 57132 | 57255 | } |
| 57133 | 57256 | assert( nDestTruncate>0 ); |
| 57134 | - sqlite3PagerTruncateImage(pDestPager, nDestTruncate); | |
| 57135 | 57257 | |
| 57136 | 57258 | if( pgszSrc<pgszDest ){ |
| 57137 | 57259 | /* If the source page-size is smaller than the destination page-size, |
| 57138 | 57260 | ** two extra things may need to happen: |
| 57139 | 57261 | ** |
| @@ -57143,10 +57265,12 @@ | ||
| 57143 | 57265 | ** pending-byte page in the source database may need to be |
| 57144 | 57266 | ** copied into the destination database. |
| 57145 | 57267 | */ |
| 57146 | 57268 | const i64 iSize = (i64)pgszSrc * (i64)nSrcPage; |
| 57147 | 57269 | sqlite3_file * const pFile = sqlite3PagerFile(pDestPager); |
| 57270 | + Pgno iPg; | |
| 57271 | + int nDstPage; | |
| 57148 | 57272 | i64 iOff; |
| 57149 | 57273 | i64 iEnd; |
| 57150 | 57274 | |
| 57151 | 57275 | assert( pFile ); |
| 57152 | 57276 | assert( nDestTruncate==0 |
| @@ -57153,17 +57277,30 @@ | ||
| 57153 | 57277 | || (i64)nDestTruncate*(i64)pgszDest >= iSize || ( |
| 57154 | 57278 | nDestTruncate==(int)(PENDING_BYTE_PAGE(p->pDest->pBt)-1) |
| 57155 | 57279 | && iSize>=PENDING_BYTE && iSize<=PENDING_BYTE+pgszDest |
| 57156 | 57280 | )); |
| 57157 | 57281 | |
| 57158 | - /* This call ensures that all data required to recreate the original | |
| 57282 | + /* This block ensures that all data required to recreate the original | |
| 57159 | 57283 | ** database has been stored in the journal for pDestPager and the |
| 57160 | 57284 | ** journal synced to disk. So at this point we may safely modify |
| 57161 | 57285 | ** the database file in any way, knowing that if a power failure |
| 57162 | 57286 | ** occurs, the original database will be reconstructed from the |
| 57163 | 57287 | ** 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 | + } | |
| 57165 | 57302 | |
| 57166 | 57303 | /* Write the extra pages and truncate the database file as required */ |
| 57167 | 57304 | iEnd = MIN(PENDING_BYTE + pgszDest, iSize); |
| 57168 | 57305 | for( |
| 57169 | 57306 | iOff=PENDING_BYTE+pgszSrc; |
| @@ -57186,10 +57323,11 @@ | ||
| 57186 | 57323 | /* Sync the database file to disk. */ |
| 57187 | 57324 | if( rc==SQLITE_OK ){ |
| 57188 | 57325 | rc = sqlite3PagerSync(pDestPager); |
| 57189 | 57326 | } |
| 57190 | 57327 | }else{ |
| 57328 | + sqlite3PagerTruncateImage(pDestPager, nDestTruncate); | |
| 57191 | 57329 | rc = sqlite3PagerCommitPhaseOne(pDestPager, 0, 0); |
| 57192 | 57330 | } |
| 57193 | 57331 | |
| 57194 | 57332 | /* Finish committing the transaction to the destination database. */ |
| 57195 | 57333 | if( SQLITE_OK==rc |
| @@ -57437,11 +57575,13 @@ | ||
| 57437 | 57575 | ** SQLITE_OK is returned if the conversion is successful (or not required). |
| 57438 | 57576 | ** SQLITE_NOMEM may be returned if a malloc() fails during conversion |
| 57439 | 57577 | ** between formats. |
| 57440 | 57578 | */ |
| 57441 | 57579 | SQLITE_PRIVATE int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){ |
| 57580 | +#ifndef SQLITE_OMIT_UTF16 | |
| 57442 | 57581 | int rc; |
| 57582 | +#endif | |
| 57443 | 57583 | assert( (pMem->flags&MEM_RowSet)==0 ); |
| 57444 | 57584 | assert( desiredEnc==SQLITE_UTF8 || desiredEnc==SQLITE_UTF16LE |
| 57445 | 57585 | || desiredEnc==SQLITE_UTF16BE ); |
| 57446 | 57586 | if( !(pMem->flags&MEM_Str) || pMem->enc==desiredEnc ){ |
| 57447 | 57587 | return SQLITE_OK; |
| @@ -58582,22 +58722,10 @@ | ||
| 58582 | 58722 | ** a VDBE (or an "sqlite3_stmt" as it is known to the outside world.) Prior |
| 58583 | 58723 | ** to version 2.8.7, all this code was combined into the vdbe.c source file. |
| 58584 | 58724 | ** But that file was getting too big so this subroutines were split out. |
| 58585 | 58725 | */ |
| 58586 | 58726 | |
| 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 | 58727 | /* |
| 58600 | 58728 | ** Create a new virtual database engine. |
| 58601 | 58729 | */ |
| 58602 | 58730 | SQLITE_PRIVATE Vdbe *sqlite3VdbeCreate(sqlite3 *db){ |
| 58603 | 58731 | Vdbe *p; |
| @@ -58723,11 +58851,13 @@ | ||
| 58723 | 58851 | pOp->p3 = p3; |
| 58724 | 58852 | pOp->p4.p = 0; |
| 58725 | 58853 | pOp->p4type = P4_NOTUSED; |
| 58726 | 58854 | #ifdef SQLITE_DEBUG |
| 58727 | 58855 | 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 | + } | |
| 58729 | 58859 | #endif |
| 58730 | 58860 | #ifdef VDBE_PROFILE |
| 58731 | 58861 | pOp->cycles = 0; |
| 58732 | 58862 | pOp->cnt = 0; |
| 58733 | 58863 | #endif |
| @@ -58942,11 +59072,11 @@ | ||
| 58942 | 59072 | if( opcode==OP_Destroy || opcode==OP_VUpdate || opcode==OP_VRename |
| 58943 | 59073 | #ifndef SQLITE_OMIT_FOREIGN_KEY |
| 58944 | 59074 | || (opcode==OP_FkCounter && pOp->p1==0 && pOp->p2==1) |
| 58945 | 59075 | #endif |
| 58946 | 59076 | || ((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)) | |
| 58948 | 59078 | ){ |
| 58949 | 59079 | hasAbort = 1; |
| 58950 | 59080 | break; |
| 58951 | 59081 | } |
| 58952 | 59082 | } |
| @@ -59077,11 +59207,11 @@ | ||
| 59077 | 59207 | pOut->p4type = P4_NOTUSED; |
| 59078 | 59208 | pOut->p4.p = 0; |
| 59079 | 59209 | pOut->p5 = 0; |
| 59080 | 59210 | #ifdef SQLITE_DEBUG |
| 59081 | 59211 | pOut->zComment = 0; |
| 59082 | - if( sqlite3VdbeAddopTrace ){ | |
| 59212 | + if( p->db->flags & SQLITE_VdbeAddopTrace ){ | |
| 59083 | 59213 | sqlite3VdbePrintOp(0, i+addr, &p->aOp[i+addr]); |
| 59084 | 59214 | } |
| 59085 | 59215 | #endif |
| 59086 | 59216 | } |
| 59087 | 59217 | p->nOp += nOp; |
| @@ -60103,11 +60233,11 @@ | ||
| 60103 | 60233 | } |
| 60104 | 60234 | zCsr = p->pFree; |
| 60105 | 60235 | zEnd = &zCsr[nByte]; |
| 60106 | 60236 | }while( nByte && !db->mallocFailed ); |
| 60107 | 60237 | |
| 60108 | - p->nCursor = (u16)nCursor; | |
| 60238 | + p->nCursor = nCursor; | |
| 60109 | 60239 | p->nOnceFlag = nOnce; |
| 60110 | 60240 | if( p->aVar ){ |
| 60111 | 60241 | p->nVar = (ynVar)nVar; |
| 60112 | 60242 | for(n=0; n<nVar; n++){ |
| 60113 | 60243 | p->aVar[n].flags = MEM_Null; |
| @@ -60345,11 +60475,11 @@ | ||
| 60345 | 60475 | |
| 60346 | 60476 | /* If there are any write-transactions at all, invoke the commit hook */ |
| 60347 | 60477 | if( needXcommit && db->xCommitCallback ){ |
| 60348 | 60478 | rc = db->xCommitCallback(db->pCommitArg); |
| 60349 | 60479 | if( rc ){ |
| 60350 | - return SQLITE_CONSTRAINT; | |
| 60480 | + return SQLITE_CONSTRAINT_COMMITHOOK; | |
| 60351 | 60481 | } |
| 60352 | 60482 | } |
| 60353 | 60483 | |
| 60354 | 60484 | /* The simple case - no more than one database file (not counting the |
| 60355 | 60485 | ** TEMP database) has a transaction active. There is no need for the |
| @@ -60637,18 +60767,18 @@ | ||
| 60637 | 60767 | ** handle associated with the VM passed as an argument is about to be |
| 60638 | 60768 | ** committed. If there are outstanding deferred foreign key constraint |
| 60639 | 60769 | ** violations, return SQLITE_ERROR. Otherwise, SQLITE_OK. |
| 60640 | 60770 | ** |
| 60641 | 60771 | ** 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. | |
| 60644 | 60774 | */ |
| 60645 | 60775 | #ifndef SQLITE_OMIT_FOREIGN_KEY |
| 60646 | 60776 | SQLITE_PRIVATE int sqlite3VdbeCheckFk(Vdbe *p, int deferred){ |
| 60647 | 60777 | sqlite3 *db = p->db; |
| 60648 | 60778 | if( (deferred && db->nDeferredCons>0) || (!deferred && p->nFkConstraint>0) ){ |
| 60649 | - p->rc = SQLITE_CONSTRAINT; | |
| 60779 | + p->rc = SQLITE_CONSTRAINT_FOREIGNKEY; | |
| 60650 | 60780 | p->errorAction = OE_Abort; |
| 60651 | 60781 | sqlite3SetString(&p->zErrMsg, db, "foreign key constraint failed"); |
| 60652 | 60782 | return SQLITE_ERROR; |
| 60653 | 60783 | } |
| 60654 | 60784 | return SQLITE_OK; |
| @@ -60759,11 +60889,11 @@ | ||
| 60759 | 60889 | if( rc!=SQLITE_OK ){ |
| 60760 | 60890 | if( NEVER(p->readOnly) ){ |
| 60761 | 60891 | sqlite3VdbeLeave(p); |
| 60762 | 60892 | return SQLITE_ERROR; |
| 60763 | 60893 | } |
| 60764 | - rc = SQLITE_CONSTRAINT; | |
| 60894 | + rc = SQLITE_CONSTRAINT_FOREIGNKEY; | |
| 60765 | 60895 | }else{ |
| 60766 | 60896 | /* The auto-commit flag is true, the vdbe program was successful |
| 60767 | 60897 | ** or hit an 'OR FAIL' constraint and there are no deferred foreign |
| 60768 | 60898 | ** key constraints to hold up the transaction. This means a commit |
| 60769 | 60899 | ** is required. */ |
| @@ -60802,11 +60932,11 @@ | ||
| 60802 | 60932 | ** current statement error code. |
| 60803 | 60933 | */ |
| 60804 | 60934 | if( eStatementOp ){ |
| 60805 | 60935 | rc = sqlite3VdbeCloseStatement(p, eStatementOp); |
| 60806 | 60936 | if( rc ){ |
| 60807 | - if( p->rc==SQLITE_OK || p->rc==SQLITE_CONSTRAINT ){ | |
| 60937 | + if( p->rc==SQLITE_OK || (p->rc&0xff)==SQLITE_CONSTRAINT ){ | |
| 60808 | 60938 | p->rc = rc; |
| 60809 | 60939 | sqlite3DbFree(db, p->zErrMsg); |
| 60810 | 60940 | p->zErrMsg = 0; |
| 60811 | 60941 | } |
| 60812 | 60942 | sqlite3RollbackAll(db, SQLITE_ABORT_ROLLBACK); |
| @@ -61043,11 +61173,11 @@ | ||
| 61043 | 61173 | sqlite3DbFree(db, p->aLabel); |
| 61044 | 61174 | sqlite3DbFree(db, p->aColName); |
| 61045 | 61175 | sqlite3DbFree(db, p->zSql); |
| 61046 | 61176 | sqlite3DbFree(db, p->pFree); |
| 61047 | 61177 | #if defined(SQLITE_ENABLE_TREE_EXPLAIN) |
| 61048 | - sqlite3_free(p->zExplain); | |
| 61178 | + sqlite3DbFree(db, p->zExplain); | |
| 61049 | 61179 | sqlite3DbFree(db, p->pExplain); |
| 61050 | 61180 | #endif |
| 61051 | 61181 | } |
| 61052 | 61182 | |
| 61053 | 61183 | /* |
| @@ -63025,11 +63155,11 @@ | ||
| 63025 | 63155 | return 0; |
| 63026 | 63156 | } |
| 63027 | 63157 | if( zName ){ |
| 63028 | 63158 | for(i=0; i<p->nzVar; i++){ |
| 63029 | 63159 | 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 ){ | |
| 63031 | 63161 | return i+1; |
| 63032 | 63162 | } |
| 63033 | 63163 | } |
| 63034 | 63164 | } |
| 63035 | 63165 | return 0; |
| @@ -64799,11 +64929,11 @@ | ||
| 64799 | 64929 | rc = sqlite3VdbeHalt(p); |
| 64800 | 64930 | assert( rc==SQLITE_BUSY || rc==SQLITE_OK || rc==SQLITE_ERROR ); |
| 64801 | 64931 | if( rc==SQLITE_BUSY ){ |
| 64802 | 64932 | p->rc = rc = SQLITE_BUSY; |
| 64803 | 64933 | }else{ |
| 64804 | - assert( rc==SQLITE_OK || p->rc==SQLITE_CONSTRAINT ); | |
| 64934 | + assert( rc==SQLITE_OK || (p->rc&0xff)==SQLITE_CONSTRAINT ); | |
| 64805 | 64935 | assert( rc==SQLITE_OK || db->nDeferredCons>0 ); |
| 64806 | 64936 | rc = p->rc ? SQLITE_ERROR : SQLITE_DONE; |
| 64807 | 64937 | } |
| 64808 | 64938 | goto vdbe_return; |
| 64809 | 64939 | } |
| @@ -70131,11 +70261,11 @@ | ||
| 70131 | 70261 | importVtabErrMsg(p, u.cr.pVtab); |
| 70132 | 70262 | if( rc==SQLITE_OK && pOp->p1 ){ |
| 70133 | 70263 | assert( u.cr.nArg>1 && u.cr.apArg[0] && (u.cr.apArg[0]->flags&MEM_Null) ); |
| 70134 | 70264 | db->lastRowid = lastRowid = u.cr.rowid; |
| 70135 | 70265 | } |
| 70136 | - if( rc==SQLITE_CONSTRAINT && pOp->p4.pVtab->bConstraint ){ | |
| 70266 | + if( (rc&0xff)==SQLITE_CONSTRAINT && pOp->p4.pVtab->bConstraint ){ | |
| 70137 | 70267 | if( pOp->p5==OE_Ignore ){ |
| 70138 | 70268 | rc = SQLITE_OK; |
| 70139 | 70269 | }else{ |
| 70140 | 70270 | p->errorAction = ((pOp->p5==OE_Replace) ? OE_Abort : pOp->p5); |
| 70141 | 70271 | } |
| @@ -72677,16 +72807,16 @@ | ||
| 72677 | 72807 | const char *zTab, |
| 72678 | 72808 | const char *zDb |
| 72679 | 72809 | ){ |
| 72680 | 72810 | int n; |
| 72681 | 72811 | 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) ){ | |
| 72683 | 72813 | return 0; |
| 72684 | 72814 | } |
| 72685 | 72815 | zSpan += n+1; |
| 72686 | 72816 | 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) ){ | |
| 72688 | 72818 | return 0; |
| 72689 | 72819 | } |
| 72690 | 72820 | zSpan += n+1; |
| 72691 | 72821 | if( zCol && sqlite3StrICmp(zSpan, zCol)!=0 ){ |
| 72692 | 72822 | return 0; |
| @@ -72775,12 +72905,12 @@ | ||
| 72775 | 72905 | |
| 72776 | 72906 | pTab = pItem->pTab; |
| 72777 | 72907 | assert( pTab!=0 && pTab->zName!=0 ); |
| 72778 | 72908 | assert( pTab->nCol>0 ); |
| 72779 | 72909 | if( pItem->pSelect && (pItem->pSelect->selFlags & SF_NestedFrom)!=0 ){ |
| 72780 | - ExprList *pEList = pItem->pSelect->pEList; | |
| 72781 | 72910 | int hit = 0; |
| 72911 | + pEList = pItem->pSelect->pEList; | |
| 72782 | 72912 | for(j=0; j<pEList->nExpr; j++){ |
| 72783 | 72913 | if( sqlite3MatchSpanName(pEList->a[j].zSpan, zCol, zTab, zDb) ){ |
| 72784 | 72914 | cnt++; |
| 72785 | 72915 | cntTab = 2; |
| 72786 | 72916 | pMatch = pItem; |
| @@ -74479,11 +74609,11 @@ | ||
| 74479 | 74609 | ** number as the prior appearance of the same name, or if the name |
| 74480 | 74610 | ** has never appeared before, reuse the same variable number |
| 74481 | 74611 | */ |
| 74482 | 74612 | ynVar i; |
| 74483 | 74613 | 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 ){ | |
| 74485 | 74615 | pExpr->iColumn = x = (ynVar)i+1; |
| 74486 | 74616 | break; |
| 74487 | 74617 | } |
| 74488 | 74618 | } |
| 74489 | 74619 | if( x==0 ) x = pExpr->iColumn = (ynVar)(++pParse->nVar); |
| @@ -75297,14 +75427,15 @@ | ||
| 75297 | 75427 | ** A cursor is opened on the b-tree object that the RHS of the IN operator |
| 75298 | 75428 | ** and pX->iTable is set to the index of that cursor. |
| 75299 | 75429 | ** |
| 75300 | 75430 | ** The returned value of this function indicates the b-tree type, as follows: |
| 75301 | 75431 | ** |
| 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. | |
| 75306 | 75437 | ** |
| 75307 | 75438 | ** An existing b-tree might be used if the RHS expression pX is a simple |
| 75308 | 75439 | ** subquery such as: |
| 75309 | 75440 | ** |
| 75310 | 75441 | ** SELECT <column> FROM <table> |
| @@ -75423,11 +75554,12 @@ | ||
| 75423 | 75554 | iAddr = sqlite3CodeOnce(pParse); |
| 75424 | 75555 | |
| 75425 | 75556 | sqlite3VdbeAddOp4(v, OP_OpenRead, iTab, pIdx->tnum, iDb, |
| 75426 | 75557 | pKey,P4_KEYINFO_HANDOFF); |
| 75427 | 75558 | 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]; | |
| 75429 | 75561 | |
| 75430 | 75562 | sqlite3VdbeJumpHere(v, iAddr); |
| 75431 | 75563 | if( prNotFound && !pTab->aCol[iCol].notNull ){ |
| 75432 | 75564 | *prNotFound = ++pParse->nMem; |
| 75433 | 75565 | sqlite3VdbeAddOp2(v, OP_Null, 0, *prNotFound); |
| @@ -76776,11 +76908,12 @@ | ||
| 76776 | 76908 | assert( !ExprHasProperty(pExpr, EP_IntValue) ); |
| 76777 | 76909 | if( pExpr->affinity==OE_Ignore ){ |
| 76778 | 76910 | sqlite3VdbeAddOp4( |
| 76779 | 76911 | v, OP_Halt, SQLITE_OK, OE_Ignore, 0, pExpr->u.zToken,0); |
| 76780 | 76912 | }else{ |
| 76781 | - sqlite3HaltConstraint(pParse, pExpr->affinity, pExpr->u.zToken, 0); | |
| 76913 | + sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_TRIGGER, | |
| 76914 | + pExpr->affinity, pExpr->u.zToken, 0); | |
| 76782 | 76915 | } |
| 76783 | 76916 | |
| 76784 | 76917 | break; |
| 76785 | 76918 | } |
| 76786 | 76919 | #endif |
| @@ -79335,11 +79468,11 @@ | ||
| 79335 | 79468 | } |
| 79336 | 79469 | if( pTab->tnum==0 ){ |
| 79337 | 79470 | /* Do not gather statistics on views or virtual tables */ |
| 79338 | 79471 | return; |
| 79339 | 79472 | } |
| 79340 | - if( memcmp(pTab->zName, "sqlite_", 7)==0 ){ | |
| 79473 | + if( sqlite3_strnicmp(pTab->zName, "sqlite_", 7)==0 ){ | |
| 79341 | 79474 | /* Do not gather statistics on system tables */ |
| 79342 | 79475 | return; |
| 79343 | 79476 | } |
| 79344 | 79477 | assert( sqlite3BtreeHoldsAllMutexes(db) ); |
| 79345 | 79478 | iDb = sqlite3SchemaToIndex(db, pTab->pSchema); |
| @@ -79745,11 +79878,11 @@ | ||
| 79745 | 79878 | } |
| 79746 | 79879 | if( i==0 ) pTable->nRowEst = v; |
| 79747 | 79880 | if( pIndex==0 ) break; |
| 79748 | 79881 | pIndex->aiRowEst[i] = v; |
| 79749 | 79882 | if( *z==' ' ) z++; |
| 79750 | - if( memcmp(z, "unordered", 10)==0 ){ | |
| 79883 | + if( strcmp(z, "unordered")==0 ){ | |
| 79751 | 79884 | pIndex->bUnordered = 1; |
| 79752 | 79885 | break; |
| 79753 | 79886 | } |
| 79754 | 79887 | } |
| 79755 | 79888 | return 0; |
| @@ -83247,12 +83380,12 @@ | ||
| 83247 | 83380 | if( pIndex->onError!=OE_None ){ |
| 83248 | 83381 | int j2 = sqlite3VdbeCurrentAddr(v) + 3; |
| 83249 | 83382 | sqlite3VdbeAddOp2(v, OP_Goto, 0, j2); |
| 83250 | 83383 | addr2 = sqlite3VdbeCurrentAddr(v); |
| 83251 | 83384 | 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 | |
| 83254 | 83387 | ); |
| 83255 | 83388 | }else{ |
| 83256 | 83389 | addr2 = sqlite3VdbeCurrentAddr(v); |
| 83257 | 83390 | } |
| 83258 | 83391 | sqlite3VdbeAddOp2(v, OP_SorterData, iSorter, regRecord); |
| @@ -83274,12 +83407,12 @@ | ||
| 83274 | 83407 | ** opcode use the values stored within seems dangerous. However, since |
| 83275 | 83408 | ** we can be sure that no other temp registers have been allocated |
| 83276 | 83409 | ** since sqlite3ReleaseTempRange() was called, it is safe to do so. |
| 83277 | 83410 | */ |
| 83278 | 83411 | 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); | |
| 83281 | 83414 | } |
| 83282 | 83415 | sqlite3VdbeAddOp3(v, OP_IdxInsert, iIdx, regRecord, 0); |
| 83283 | 83416 | sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT); |
| 83284 | 83417 | #endif |
| 83285 | 83418 | sqlite3ReleaseTempReg(pParse, regRecord); |
| @@ -83394,11 +83527,11 @@ | ||
| 83394 | 83527 | pDb = &db->aDb[iDb]; |
| 83395 | 83528 | |
| 83396 | 83529 | assert( pTab!=0 ); |
| 83397 | 83530 | assert( pParse->nErr==0 ); |
| 83398 | 83531 | if( sqlite3StrNICmp(pTab->zName, "sqlite_", 7)==0 |
| 83399 | - && memcmp(&pTab->zName[7],"altertab_",9)!=0 ){ | |
| 83532 | + && sqlite3StrNICmp(&pTab->zName[7],"altertab_",9)!=0 ){ | |
| 83400 | 83533 | sqlite3ErrorMsg(pParse, "table %s may not be indexed", pTab->zName); |
| 83401 | 83534 | goto exit_create_index; |
| 83402 | 83535 | } |
| 83403 | 83536 | #ifndef SQLITE_OMIT_VIEW |
| 83404 | 83537 | if( pTab->pSelect ){ |
| @@ -84492,16 +84625,23 @@ | ||
| 84492 | 84625 | /* |
| 84493 | 84626 | ** Code an OP_Halt that causes the vdbe to return an SQLITE_CONSTRAINT |
| 84494 | 84627 | ** error. The onError parameter determines which (if any) of the statement |
| 84495 | 84628 | ** and/or current transaction is rolled back. |
| 84496 | 84629 | */ |
| 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 | +){ | |
| 84498 | 84637 | Vdbe *v = sqlite3GetVdbe(pParse); |
| 84638 | + assert( (errCode&0xff)==SQLITE_CONSTRAINT ); | |
| 84499 | 84639 | if( onError==OE_Abort ){ |
| 84500 | 84640 | sqlite3MayAbort(pParse); |
| 84501 | 84641 | } |
| 84502 | - sqlite3VdbeAddOp4(v, OP_Halt, SQLITE_CONSTRAINT, onError, 0, p4, p4type); | |
| 84642 | + sqlite3VdbeAddOp4(v, OP_Halt, errCode, onError, 0, p4, p4type); | |
| 84503 | 84643 | } |
| 84504 | 84644 | |
| 84505 | 84645 | /* |
| 84506 | 84646 | ** Check to see if pIndex uses the collating sequence pColl. Return |
| 84507 | 84647 | ** true if it does and false if it does not. |
| @@ -85242,34 +85382,32 @@ | ||
| 85242 | 85382 | Table *pView, /* View definition */ |
| 85243 | 85383 | Expr *pWhere, /* Optional WHERE clause to be added */ |
| 85244 | 85384 | int iCur /* Cursor number for ephemerial table */ |
| 85245 | 85385 | ){ |
| 85246 | 85386 | SelectDest dest; |
| 85247 | - Select *pDup; | |
| 85387 | + Select *pSel; | |
| 85388 | + SrcList *pFrom; | |
| 85248 | 85389 | 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 | + | |
| 85268 | 85406 | sqlite3SelectDestInit(&dest, SRT_EphemTab, iCur); |
| 85269 | - sqlite3Select(pParse, pDup, &dest); | |
| 85270 | - sqlite3SelectDelete(db, pDup); | |
| 85407 | + sqlite3Select(pParse, pSel, &dest); | |
| 85408 | + sqlite3SelectDelete(db, pSel); | |
| 85271 | 85409 | } |
| 85272 | 85410 | #endif /* !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER) */ |
| 85273 | 85411 | |
| 85274 | 85412 | #if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) && !defined(SQLITE_OMIT_SUBQUERY) |
| 85275 | 85413 | /* |
| @@ -86765,10 +86903,66 @@ | ||
| 86765 | 86903 | sqlite3_result_text(context, "NULL", 4, SQLITE_STATIC); |
| 86766 | 86904 | break; |
| 86767 | 86905 | } |
| 86768 | 86906 | } |
| 86769 | 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 | +} | |
| 86770 | 86964 | |
| 86771 | 86965 | /* |
| 86772 | 86966 | ** The hex() function. Interpret the argument as a blob. Return |
| 86773 | 86967 | ** a hexadecimal rendering as text. |
| 86774 | 86968 | */ |
| @@ -87393,10 +87587,12 @@ | ||
| 87393 | 87587 | FUNCTION2(typeof, 1, 0, 0, typeofFunc, SQLITE_FUNC_TYPEOF), |
| 87394 | 87588 | FUNCTION2(length, 1, 0, 0, lengthFunc, SQLITE_FUNC_LENGTH), |
| 87395 | 87589 | FUNCTION(instr, 2, 0, 0, instrFunc ), |
| 87396 | 87590 | FUNCTION(substr, 2, 0, 0, substrFunc ), |
| 87397 | 87591 | FUNCTION(substr, 3, 0, 0, substrFunc ), |
| 87592 | + FUNCTION(unicode, 1, 0, 0, unicodeFunc ), | |
| 87593 | + FUNCTION(char, -1, 0, 0, charFunc ), | |
| 87398 | 87594 | FUNCTION(abs, 1, 0, 0, absFunc ), |
| 87399 | 87595 | #ifndef SQLITE_OMIT_FLOATING_POINT |
| 87400 | 87596 | FUNCTION(round, 1, 0, 0, roundFunc ), |
| 87401 | 87597 | FUNCTION(round, 2, 0, 0, roundFunc ), |
| 87402 | 87598 | #endif |
| @@ -87484,12 +87680,13 @@ | ||
| 87484 | 87680 | /* |
| 87485 | 87681 | ** Deferred and Immediate FKs |
| 87486 | 87682 | ** -------------------------- |
| 87487 | 87683 | ** |
| 87488 | 87684 | ** 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 | |
| 87491 | 87688 | ** deferred foreign key constraint is violated, no action is taken |
| 87492 | 87689 | ** immediately. However if the application attempts to commit the |
| 87493 | 87690 | ** transaction before fixing the constraint violation, the attempt fails. |
| 87494 | 87691 | ** |
| 87495 | 87692 | ** Deferred constraints are implemented using a simple counter associated |
| @@ -87549,11 +87746,12 @@ | ||
| 87549 | 87746 | ** row is inserted. |
| 87550 | 87747 | ** |
| 87551 | 87748 | ** Immediate constraints are usually handled similarly. The only difference |
| 87552 | 87749 | ** is that the counter used is stored as part of each individual statement |
| 87553 | 87750 | ** 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 | |
| 87555 | 87753 | ** and the statement transaction is rolled back. An exception is an INSERT |
| 87556 | 87754 | ** statement that inserts a single row only (no triggers). In this case, |
| 87557 | 87755 | ** instead of using a counter, an exception is thrown immediately if the |
| 87558 | 87756 | ** INSERT violates a foreign key constraint. This is necessary as such |
| 87559 | 87757 | ** an INSERT does not open a statement transaction. |
| @@ -87889,12 +88087,12 @@ | ||
| 87889 | 88087 | /* Special case: If this is an INSERT statement that will insert exactly |
| 87890 | 88088 | ** one row into the table, raise a constraint immediately instead of |
| 87891 | 88089 | ** incrementing a counter. This is necessary as the VM code is being |
| 87892 | 88090 | ** generated for will not open a statement transaction. */ |
| 87893 | 88091 | 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 | |
| 87896 | 88094 | ); |
| 87897 | 88095 | }else{ |
| 87898 | 88096 | if( nIncr>0 && pFKey->isDeferred==0 ){ |
| 87899 | 88097 | sqlite3ParseToplevel(pParse)->mayAbort = 1; |
| 87900 | 88098 | } |
| @@ -88130,12 +88328,12 @@ | ||
| 88130 | 88328 | /* If the DELETE has generated immediate foreign key constraint |
| 88131 | 88329 | ** violations, halt the VDBE and return an error at this point, before |
| 88132 | 88330 | ** any modifications to the schema are made. This is because statement |
| 88133 | 88331 | ** transactions are not able to rollback schema changes. */ |
| 88134 | 88332 | 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 | |
| 88137 | 88335 | ); |
| 88138 | 88336 | |
| 88139 | 88337 | if( iSkip ){ |
| 88140 | 88338 | sqlite3VdbeResolveLabel(v, iSkip); |
| 88141 | 88339 | } |
| @@ -89935,11 +90133,11 @@ | ||
| 89935 | 90133 | sqlite3MayAbort(pParse); |
| 89936 | 90134 | case OE_Rollback: |
| 89937 | 90135 | case OE_Fail: { |
| 89938 | 90136 | char *zMsg; |
| 89939 | 90137 | sqlite3VdbeAddOp3(v, OP_HaltIfNull, |
| 89940 | - SQLITE_CONSTRAINT, onError, regData+i); | |
| 90138 | + SQLITE_CONSTRAINT_NOTNULL, onError, regData+i); | |
| 89941 | 90139 | zMsg = sqlite3MPrintf(db, "%s.%s may not be NULL", |
| 89942 | 90140 | pTab->zName, pTab->aCol[i].zName); |
| 89943 | 90141 | sqlite3VdbeChangeP4(v, -1, zMsg, P4_DYNAMIC); |
| 89944 | 90142 | break; |
| 89945 | 90143 | } |
| @@ -89975,11 +90173,12 @@ | ||
| 89975 | 90173 | if( zConsName ){ |
| 89976 | 90174 | zConsName = sqlite3MPrintf(db, "constraint %s failed", zConsName); |
| 89977 | 90175 | }else{ |
| 89978 | 90176 | zConsName = 0; |
| 89979 | 90177 | } |
| 89980 | - sqlite3HaltConstraint(pParse, onError, zConsName, P4_DYNAMIC); | |
| 90178 | + sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_CHECK, | |
| 90179 | + onError, zConsName, P4_DYNAMIC); | |
| 89981 | 90180 | } |
| 89982 | 90181 | sqlite3VdbeResolveLabel(v, allOk); |
| 89983 | 90182 | } |
| 89984 | 90183 | } |
| 89985 | 90184 | #endif /* !defined(SQLITE_OMIT_CHECK) */ |
| @@ -90006,12 +90205,12 @@ | ||
| 90006 | 90205 | /* Fall thru into the next case */ |
| 90007 | 90206 | } |
| 90008 | 90207 | case OE_Rollback: |
| 90009 | 90208 | case OE_Abort: |
| 90010 | 90209 | 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); | |
| 90013 | 90212 | break; |
| 90014 | 90213 | } |
| 90015 | 90214 | case OE_Replace: { |
| 90016 | 90215 | /* If there are DELETE triggers on this table and the |
| 90017 | 90216 | ** recursive-triggers flag is set, call GenerateRowDelete() to |
| @@ -90134,11 +90333,12 @@ | ||
| 90134 | 90333 | sqlite3StrAccumAppend(&errMsg, zCol, -1); |
| 90135 | 90334 | } |
| 90136 | 90335 | sqlite3StrAccumAppend(&errMsg, |
| 90137 | 90336 | pIdx->nColumn>1 ? " are not unique" : " is not unique", -1); |
| 90138 | 90337 | zErr = sqlite3StrAccumFinish(&errMsg); |
| 90139 | - sqlite3HaltConstraint(pParse, onError, zErr, 0); | |
| 90338 | + sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_UNIQUE, | |
| 90339 | + onError, zErr, 0); | |
| 90140 | 90340 | sqlite3DbFree(errMsg.db, zErr); |
| 90141 | 90341 | break; |
| 90142 | 90342 | } |
| 90143 | 90343 | case OE_Ignore: { |
| 90144 | 90344 | assert( seenReplace==0 ); |
| @@ -90542,12 +90742,12 @@ | ||
| 90542 | 90742 | regData = sqlite3GetTempReg(pParse); |
| 90543 | 90743 | regRowid = sqlite3GetTempReg(pParse); |
| 90544 | 90744 | if( pDest->iPKey>=0 ){ |
| 90545 | 90745 | addr1 = sqlite3VdbeAddOp2(v, OP_Rowid, iSrc, regRowid); |
| 90546 | 90746 | 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); | |
| 90549 | 90749 | sqlite3VdbeJumpHere(v, addr2); |
| 90550 | 90750 | autoIncStep(pParse, regAutoinc, regRowid); |
| 90551 | 90751 | }else if( pDest->pIndex==0 ){ |
| 90552 | 90752 | addr1 = sqlite3VdbeAddOp2(v, OP_NewRowid, iDest, regRowid); |
| 90553 | 90753 | }else{ |
| @@ -91000,10 +91200,24 @@ | ||
| 91000 | 91200 | int (*wal_checkpoint)(sqlite3*,const char*); |
| 91001 | 91201 | void *(*wal_hook)(sqlite3*,int(*)(void*,sqlite3*,const char*,int),void*); |
| 91002 | 91202 | int (*blob_reopen)(sqlite3_blob*,sqlite3_int64); |
| 91003 | 91203 | int (*vtab_config)(sqlite3*,int op,...); |
| 91004 | 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*); | |
| 91005 | 91219 | }; |
| 91006 | 91220 | |
| 91007 | 91221 | /* |
| 91008 | 91222 | ** The following macros redefine the API routines so that they are |
| 91009 | 91223 | ** redirected throught the global sqlite3_api structure. |
| @@ -91203,10 +91417,24 @@ | ||
| 91203 | 91417 | #define sqlite3_wal_checkpoint sqlite3_api->wal_checkpoint |
| 91204 | 91418 | #define sqlite3_wal_hook sqlite3_api->wal_hook |
| 91205 | 91419 | #define sqlite3_blob_reopen sqlite3_api->blob_reopen |
| 91206 | 91420 | #define sqlite3_vtab_config sqlite3_api->vtab_config |
| 91207 | 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 | |
| 91208 | 91436 | #endif /* SQLITE_CORE */ |
| 91209 | 91437 | |
| 91210 | 91438 | #define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api = 0; |
| 91211 | 91439 | #define SQLITE_EXTENSION_INIT2(v) sqlite3_api = v; |
| 91212 | 91440 | |
| @@ -91572,10 +91800,23 @@ | ||
| 91572 | 91800 | 0, |
| 91573 | 91801 | #endif |
| 91574 | 91802 | sqlite3_blob_reopen, |
| 91575 | 91803 | sqlite3_vtab_config, |
| 91576 | 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 | |
| 91577 | 91818 | }; |
| 91578 | 91819 | |
| 91579 | 91820 | /* |
| 91580 | 91821 | ** Attempt to load an SQLite extension library contained in the file |
| 91581 | 91822 | ** zFile. The entry point is zProc. zProc may be 0 in which case a |
| @@ -92038,10 +92279,13 @@ | ||
| 92038 | 92279 | #endif |
| 92039 | 92280 | #ifdef SQLITE_DEBUG |
| 92040 | 92281 | { "sql_trace", SQLITE_SqlTrace }, |
| 92041 | 92282 | { "vdbe_listing", SQLITE_VdbeListing }, |
| 92042 | 92283 | { "vdbe_trace", SQLITE_VdbeTrace }, |
| 92284 | + { "vdbe_addoptrace", SQLITE_VdbeAddopTrace}, | |
| 92285 | + { "vdbe_debug", SQLITE_SqlTrace | SQLITE_VdbeListing | |
| 92286 | + | SQLITE_VdbeTrace }, | |
| 92043 | 92287 | #endif |
| 92044 | 92288 | #ifndef SQLITE_OMIT_CHECK |
| 92045 | 92289 | { "ignore_check_constraints", SQLITE_IgnoreChecks }, |
| 92046 | 92290 | #endif |
| 92047 | 92291 | /* The following is VERY experimental */ |
| @@ -92809,10 +93053,11 @@ | ||
| 92809 | 93053 | Column *pCol; |
| 92810 | 93054 | Index *pPk; |
| 92811 | 93055 | for(pPk=pTab->pIndex; pPk && pPk->autoIndex!=2; pPk=pPk->pNext){} |
| 92812 | 93056 | sqlite3VdbeSetNumCols(v, 6); |
| 92813 | 93057 | pParse->nMem = 6; |
| 93058 | + sqlite3CodeVerifySchema(pParse, iDb); | |
| 92814 | 93059 | sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "cid", SQLITE_STATIC); |
| 92815 | 93060 | sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", SQLITE_STATIC); |
| 92816 | 93061 | sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "type", SQLITE_STATIC); |
| 92817 | 93062 | sqlite3VdbeSetColName(v, 3, COLNAME_NAME, "notnull", SQLITE_STATIC); |
| 92818 | 93063 | sqlite3VdbeSetColName(v, 4, COLNAME_NAME, "dflt_value", SQLITE_STATIC); |
| @@ -92854,10 +93099,11 @@ | ||
| 92854 | 93099 | if( pIdx ){ |
| 92855 | 93100 | int i; |
| 92856 | 93101 | pTab = pIdx->pTable; |
| 92857 | 93102 | sqlite3VdbeSetNumCols(v, 3); |
| 92858 | 93103 | pParse->nMem = 3; |
| 93104 | + sqlite3CodeVerifySchema(pParse, iDb); | |
| 92859 | 93105 | sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seqno", SQLITE_STATIC); |
| 92860 | 93106 | sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "cid", SQLITE_STATIC); |
| 92861 | 93107 | sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "name", SQLITE_STATIC); |
| 92862 | 93108 | for(i=0; i<pIdx->nColumn; i++){ |
| 92863 | 93109 | int cnum = pIdx->aiColumn[i]; |
| @@ -92880,10 +93126,11 @@ | ||
| 92880 | 93126 | pIdx = pTab->pIndex; |
| 92881 | 93127 | if( pIdx ){ |
| 92882 | 93128 | int i = 0; |
| 92883 | 93129 | sqlite3VdbeSetNumCols(v, 3); |
| 92884 | 93130 | pParse->nMem = 3; |
| 93131 | + sqlite3CodeVerifySchema(pParse, iDb); | |
| 92885 | 93132 | sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seq", SQLITE_STATIC); |
| 92886 | 93133 | sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", SQLITE_STATIC); |
| 92887 | 93134 | sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "unique", SQLITE_STATIC); |
| 92888 | 93135 | while(pIdx){ |
| 92889 | 93136 | sqlite3VdbeAddOp2(v, OP_Integer, i, 1); |
| @@ -92943,10 +93190,11 @@ | ||
| 92943 | 93190 | pFK = pTab->pFKey; |
| 92944 | 93191 | if( pFK ){ |
| 92945 | 93192 | int i = 0; |
| 92946 | 93193 | sqlite3VdbeSetNumCols(v, 8); |
| 92947 | 93194 | pParse->nMem = 8; |
| 93195 | + sqlite3CodeVerifySchema(pParse, iDb); | |
| 92948 | 93196 | sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "id", SQLITE_STATIC); |
| 92949 | 93197 | sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "seq", SQLITE_STATIC); |
| 92950 | 93198 | sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "table", SQLITE_STATIC); |
| 92951 | 93199 | sqlite3VdbeSetColName(v, 3, COLNAME_NAME, "from", SQLITE_STATIC); |
| 92952 | 93200 | sqlite3VdbeSetColName(v, 4, COLNAME_NAME, "to", SQLITE_STATIC); |
| @@ -92977,10 +93225,11 @@ | ||
| 92977 | 93225 | } |
| 92978 | 93226 | }else |
| 92979 | 93227 | #endif /* !defined(SQLITE_OMIT_FOREIGN_KEY) */ |
| 92980 | 93228 | |
| 92981 | 93229 | #ifndef SQLITE_OMIT_FOREIGN_KEY |
| 93230 | +#ifndef SQLITE_OMIT_TRIGGER | |
| 92982 | 93231 | if( sqlite3StrICmp(zLeft, "foreign_key_check")==0 ){ |
| 92983 | 93232 | FKey *pFK; /* A foreign key constraint */ |
| 92984 | 93233 | Table *pTab; /* Child table contain "REFERENCES" keyword */ |
| 92985 | 93234 | Table *pParent; /* Parent table that child points to */ |
| 92986 | 93235 | Index *pIdx; /* Index in the parent table */ |
| @@ -93088,10 +93337,11 @@ | ||
| 93088 | 93337 | } |
| 93089 | 93338 | sqlite3VdbeAddOp2(v, OP_Next, 0, addrTop+1); |
| 93090 | 93339 | sqlite3VdbeJumpHere(v, addrTop); |
| 93091 | 93340 | } |
| 93092 | 93341 | }else |
| 93342 | +#endif /* !defined(SQLITE_OMIT_TRIGGER) */ | |
| 93093 | 93343 | #endif /* !defined(SQLITE_OMIT_FOREIGN_KEY) */ |
| 93094 | 93344 | |
| 93095 | 93345 | #ifndef NDEBUG |
| 93096 | 93346 | if( sqlite3StrICmp(zLeft, "parser_trace")==0 ){ |
| 93097 | 93347 | if( zRight ){ |
| @@ -93884,15 +94134,19 @@ | ||
| 93884 | 94134 | ** For an attached db, it is an error if the encoding is not the same |
| 93885 | 94135 | ** as sqlite3.enc. |
| 93886 | 94136 | */ |
| 93887 | 94137 | if( meta[BTREE_TEXT_ENCODING-1] ){ /* text encoding */ |
| 93888 | 94138 | if( iDb==0 ){ |
| 94139 | +#ifndef SQLITE_OMIT_UTF16 | |
| 93889 | 94140 | u8 encoding; |
| 93890 | 94141 | /* If opening the main database, set ENC(db). */ |
| 93891 | 94142 | encoding = (u8)meta[BTREE_TEXT_ENCODING-1] & 3; |
| 93892 | 94143 | if( encoding==0 ) encoding = SQLITE_UTF8; |
| 93893 | 94144 | ENC(db) = encoding; |
| 94145 | +#else | |
| 94146 | + ENC(db) = SQLITE_UTF8; | |
| 94147 | +#endif | |
| 93894 | 94148 | }else{ |
| 93895 | 94149 | /* If opening an attached database, the encoding much match ENC(db) */ |
| 93896 | 94150 | if( meta[BTREE_TEXT_ENCODING-1]!=ENC(db) ){ |
| 93897 | 94151 | sqlite3SetString(pzErrMsg, db, "attached databases must use the same" |
| 93898 | 94152 | " text encoding as main database"); |
| @@ -96198,10 +96452,12 @@ | ||
| 96198 | 96452 | switch( p->op ){ |
| 96199 | 96453 | case TK_ALL: { |
| 96200 | 96454 | int addr = 0; |
| 96201 | 96455 | int nLimit; |
| 96202 | 96456 | assert( !pPrior->pLimit ); |
| 96457 | + pPrior->iLimit = p->iLimit; | |
| 96458 | + pPrior->iOffset = p->iOffset; | |
| 96203 | 96459 | pPrior->pLimit = p->pLimit; |
| 96204 | 96460 | pPrior->pOffset = p->pOffset; |
| 96205 | 96461 | explainSetInteger(iSub1, pParse->iNextSelectId); |
| 96206 | 96462 | rc = sqlite3Select(pParse, pPrior, &dest); |
| 96207 | 96463 | p->pLimit = 0; |
| @@ -96855,11 +97111,12 @@ | ||
| 96855 | 97111 | if( op==TK_ALL ){ |
| 96856 | 97112 | regPrev = 0; |
| 96857 | 97113 | }else{ |
| 96858 | 97114 | int nExpr = p->pEList->nExpr; |
| 96859 | 97115 | assert( nOrderBy>=nExpr || db->mallocFailed ); |
| 96860 | - regPrev = sqlite3GetTempRange(pParse, nExpr+1); | |
| 97116 | + regPrev = pParse->nMem+1; | |
| 97117 | + pParse->nMem += nExpr+1; | |
| 96861 | 97118 | sqlite3VdbeAddOp2(v, OP_Integer, 0, regPrev); |
| 96862 | 97119 | pKeyDup = sqlite3DbMallocZero(db, |
| 96863 | 97120 | sizeof(*pKeyDup) + nExpr*(sizeof(CollSeq*)+1) ); |
| 96864 | 97121 | if( pKeyDup ){ |
| 96865 | 97122 | pKeyDup->aSortOrder = (u8*)&pKeyDup->aColl[nExpr]; |
| @@ -97037,16 +97294,10 @@ | ||
| 97037 | 97294 | sqlite3VdbeAddOp4(v, OP_Compare, destA.iSdst, destB.iSdst, nOrderBy, |
| 97038 | 97295 | (char*)pKeyMerge, P4_KEYINFO_HANDOFF); |
| 97039 | 97296 | sqlite3VdbeChangeP5(v, OPFLAG_PERMUTE); |
| 97040 | 97297 | sqlite3VdbeAddOp3(v, OP_Jump, addrAltB, addrAeqB, addrAgtB); |
| 97041 | 97298 | |
| 97042 | - /* Release temporary registers | |
| 97043 | - */ | |
| 97044 | - if( regPrev ){ | |
| 97045 | - sqlite3ReleaseTempRange(pParse, regPrev, nOrderBy+1); | |
| 97046 | - } | |
| 97047 | - | |
| 97048 | 97299 | /* Jump to the this point in order to terminate the query. |
| 97049 | 97300 | */ |
| 97050 | 97301 | sqlite3VdbeResolveLabel(v, labelEnd); |
| 97051 | 97302 | |
| 97052 | 97303 | /* Set the number of output columns |
| @@ -97454,16 +97705,19 @@ | ||
| 97454 | 97705 | */ |
| 97455 | 97706 | for(pSub=pSub->pPrior; pSub; pSub=pSub->pPrior){ |
| 97456 | 97707 | Select *pNew; |
| 97457 | 97708 | ExprList *pOrderBy = p->pOrderBy; |
| 97458 | 97709 | Expr *pLimit = p->pLimit; |
| 97710 | + Expr *pOffset = p->pOffset; | |
| 97459 | 97711 | Select *pPrior = p->pPrior; |
| 97460 | 97712 | p->pOrderBy = 0; |
| 97461 | 97713 | p->pSrc = 0; |
| 97462 | 97714 | p->pPrior = 0; |
| 97463 | 97715 | p->pLimit = 0; |
| 97716 | + p->pOffset = 0; | |
| 97464 | 97717 | pNew = sqlite3SelectDup(db, p, 0); |
| 97718 | + p->pOffset = pOffset; | |
| 97465 | 97719 | p->pLimit = pLimit; |
| 97466 | 97720 | p->pOrderBy = pOrderBy; |
| 97467 | 97721 | p->pSrc = pSrc; |
| 97468 | 97722 | p->op = TK_ALL; |
| 97469 | 97723 | p->pRightmost = 0; |
| @@ -97784,18 +98038,19 @@ | ||
| 97784 | 98038 | SrcList *pTabList; |
| 97785 | 98039 | ExprList *pEList; |
| 97786 | 98040 | struct SrcList_item *pFrom; |
| 97787 | 98041 | sqlite3 *db = pParse->db; |
| 97788 | 98042 | Expr *pE, *pRight, *pExpr; |
| 98043 | + u16 selFlags = p->selFlags; | |
| 97789 | 98044 | |
| 98045 | + p->selFlags |= SF_Expanded; | |
| 97790 | 98046 | if( db->mallocFailed ){ |
| 97791 | 98047 | return WRC_Abort; |
| 97792 | 98048 | } |
| 97793 | - if( NEVER(p->pSrc==0) || (p->selFlags & SF_Expanded)!=0 ){ | |
| 98049 | + if( NEVER(p->pSrc==0) || (selFlags & SF_Expanded)!=0 ){ | |
| 97794 | 98050 | return WRC_Prune; |
| 97795 | 98051 | } |
| 97796 | - p->selFlags |= SF_Expanded; | |
| 97797 | 98052 | pTabList = p->pSrc; |
| 97798 | 98053 | pEList = p->pEList; |
| 97799 | 98054 | |
| 97800 | 98055 | /* Make sure cursor numbers have been assigned to all entries in |
| 97801 | 98056 | ** the FROM clause of the SELECT statement. |
| @@ -97834,10 +98089,16 @@ | ||
| 97834 | 98089 | }else{ |
| 97835 | 98090 | /* An ordinary table or view name in the FROM clause */ |
| 97836 | 98091 | assert( pFrom->pTab==0 ); |
| 97837 | 98092 | pFrom->pTab = pTab = sqlite3LocateTableItem(pParse, 0, pFrom); |
| 97838 | 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 | + } | |
| 97839 | 98100 | pTab->nRef++; |
| 97840 | 98101 | #if !defined(SQLITE_OMIT_VIEW) || !defined (SQLITE_OMIT_VIRTUALTABLE) |
| 97841 | 98102 | if( pTab->pSelect || IsVirtual(pTab) ){ |
| 97842 | 98103 | /* We reach here if the named table is a really a view */ |
| 97843 | 98104 | if( sqlite3ViewGetColumnNames(pParse, pTab) ) return WRC_Abort; |
| @@ -98146,10 +98407,11 @@ | ||
| 98146 | 98407 | NameContext *pOuterNC /* Name context for container */ |
| 98147 | 98408 | ){ |
| 98148 | 98409 | sqlite3 *db; |
| 98149 | 98410 | if( NEVER(p==0) ) return; |
| 98150 | 98411 | db = pParse->db; |
| 98412 | + if( db->mallocFailed ) return; | |
| 98151 | 98413 | if( p->selFlags & SF_HasTypeInfo ) return; |
| 98152 | 98414 | sqlite3SelectExpand(pParse, p); |
| 98153 | 98415 | if( pParse->nErr || db->mallocFailed ) return; |
| 98154 | 98416 | sqlite3ResolveSelectNames(pParse, p, pOuterNC); |
| 98155 | 98417 | if( pParse->nErr || db->mallocFailed ) return; |
| @@ -99231,11 +99493,14 @@ | ||
| 99231 | 99493 | SQLITE_PRIVATE void sqlite3ExplainSelect(Vdbe *pVdbe, Select *p){ |
| 99232 | 99494 | if( p==0 ){ |
| 99233 | 99495 | sqlite3ExplainPrintf(pVdbe, "(null-select)"); |
| 99234 | 99496 | return; |
| 99235 | 99497 | } |
| 99236 | - while( p->pPrior ) p = p->pPrior; | |
| 99498 | + while( p->pPrior ){ | |
| 99499 | + p->pPrior->pNext = p; | |
| 99500 | + p = p->pPrior; | |
| 99501 | + } | |
| 99237 | 99502 | sqlite3ExplainPush(pVdbe); |
| 99238 | 99503 | while( p ){ |
| 99239 | 99504 | explainOneSelect(pVdbe, p); |
| 99240 | 99505 | p = p->pNext; |
| 99241 | 99506 | if( p==0 ) break; |
| @@ -102850,11 +103115,10 @@ | ||
| 102850 | 103115 | ** subclauses points to the WhereClause object for the whole clause. |
| 102851 | 103116 | */ |
| 102852 | 103117 | struct WhereClause { |
| 102853 | 103118 | Parse *pParse; /* The parser context */ |
| 102854 | 103119 | WhereMaskSet *pMaskSet; /* Mapping of table cursor numbers to bitmasks */ |
| 102855 | - Bitmask vmask; /* Bitmask identifying virtual table cursors */ | |
| 102856 | 103120 | WhereClause *pOuter; /* Outer conjunction */ |
| 102857 | 103121 | u8 op; /* Split operator. TK_AND or TK_OR */ |
| 102858 | 103122 | u16 wctrlFlags; /* Might include WHERE_AND_ONLY */ |
| 102859 | 103123 | int nTerm; /* Number of terms */ |
| 102860 | 103124 | int nSlot; /* Number of entries in a[] */ |
| @@ -103027,11 +103291,10 @@ | ||
| 103027 | 103291 | pWC->pMaskSet = pMaskSet; |
| 103028 | 103292 | pWC->pOuter = 0; |
| 103029 | 103293 | pWC->nTerm = 0; |
| 103030 | 103294 | pWC->nSlot = ArraySize(pWC->aStatic); |
| 103031 | 103295 | pWC->a = pWC->aStatic; |
| 103032 | - pWC->vmask = 0; | |
| 103033 | 103296 | pWC->wctrlFlags = wctrlFlags; |
| 103034 | 103297 | } |
| 103035 | 103298 | |
| 103036 | 103299 | /* Forward reference */ |
| 103037 | 103300 | static void whereClauseClear(WhereClause*); |
| @@ -103355,13 +103618,12 @@ | ||
| 103355 | 103618 | ** |
| 103356 | 103619 | ** If there are multiple terms in the WHERE clause of the form "X <op> <expr>" |
| 103357 | 103620 | ** then try for the one with no dependencies on <expr> - in other words where |
| 103358 | 103621 | ** <expr> is a constant expression of some kind. Only return entries of |
| 103359 | 103622 | ** 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. | |
| 103363 | 103625 | */ |
| 103364 | 103626 | static WhereTerm *findTerm( |
| 103365 | 103627 | WhereClause *pWC, /* The WHERE clause to be searched */ |
| 103366 | 103628 | int iCur, /* Cursor number of LHS */ |
| 103367 | 103629 | int iColumn, /* Column number of LHS */ |
| @@ -103416,12 +103678,16 @@ | ||
| 103416 | 103678 | } |
| 103417 | 103679 | if( sqlite3StrICmp(pColl->zName, pIdx->azColl[j]) ){ |
| 103418 | 103680 | continue; |
| 103419 | 103681 | } |
| 103420 | 103682 | } |
| 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 | + } | |
| 103423 | 103689 | } |
| 103424 | 103690 | if( (pTerm->eOperator & WO_EQUIV)!=0 |
| 103425 | 103691 | && nEquiv<ArraySize(aEquiv) |
| 103426 | 103692 | ){ |
| 103427 | 103693 | pX = sqlite3ExprSkipCollate(pTerm->pExpr->pRight); |
| @@ -103627,11 +103893,11 @@ | ||
| 103627 | 103893 | ** (D) x=expr1 OR (y>11 AND y<22 AND z LIKE '*hello*') |
| 103628 | 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) |
| 103629 | 103895 | ** |
| 103630 | 103896 | ** CASE 1: |
| 103631 | 103897 | ** |
| 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 | |
| 103633 | 103899 | ** a single table T (as shown in example B above) then create a new virtual |
| 103634 | 103900 | ** term that is an equivalent IN expression. In other words, if the term |
| 103635 | 103901 | ** being analyzed is: |
| 103636 | 103902 | ** |
| 103637 | 103903 | ** x = expr1 OR expr2 = x OR x = expr3 |
| @@ -103715,11 +103981,11 @@ | ||
| 103715 | 103981 | |
| 103716 | 103982 | /* |
| 103717 | 103983 | ** Compute the set of tables that might satisfy cases 1 or 2. |
| 103718 | 103984 | */ |
| 103719 | 103985 | indexable = ~(Bitmask)0; |
| 103720 | - chngToIN = ~(pWC->vmask); | |
| 103986 | + chngToIN = ~(Bitmask)0; | |
| 103721 | 103987 | for(i=pOrWc->nTerm-1, pOrTerm=pOrWc->a; i>=0 && indexable; i--, pOrTerm++){ |
| 103722 | 103988 | if( (pOrTerm->eOperator & WO_SINGLE)==0 ){ |
| 103723 | 103989 | WhereAndInfo *pAndInfo; |
| 103724 | 103990 | assert( (pOrTerm->wtFlags & (TERM_ANDINFO|TERM_ORINFO))==0 ); |
| 103725 | 103991 | chngToIN = 0; |
| @@ -104982,12 +105248,13 @@ | ||
| 104982 | 105248 | Table *pTab = pSrc->pTab; |
| 104983 | 105249 | sqlite3_index_info *pIdxInfo; |
| 104984 | 105250 | struct sqlite3_index_constraint *pIdxCons; |
| 104985 | 105251 | struct sqlite3_index_constraint_usage *pUsage; |
| 104986 | 105252 | WhereTerm *pTerm; |
| 104987 | - int i, j; | |
| 105253 | + int i, j, k; | |
| 104988 | 105254 | int nOrderBy; |
| 105255 | + int sortOrder; /* Sort order for IN clauses */ | |
| 104989 | 105256 | int bAllowIN; /* Allow IN optimizations */ |
| 104990 | 105257 | double rCost; |
| 104991 | 105258 | |
| 104992 | 105259 | /* Make sure wsFlags is initialized to some sane value. Otherwise, if the |
| 104993 | 105260 | ** malloc in allocateIndexInfo() fails and this function returns leaving |
| @@ -105082,22 +105349,31 @@ | ||
| 105082 | 105349 | |
| 105083 | 105350 | if( vtabBestIndex(pParse, pTab, pIdxInfo) ){ |
| 105084 | 105351 | return; |
| 105085 | 105352 | } |
| 105086 | 105353 | |
| 105354 | + sortOrder = SQLITE_SO_ASC; | |
| 105087 | 105355 | pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint; |
| 105088 | 105356 | for(i=0; i<pIdxInfo->nConstraint; i++, pIdxCons++){ |
| 105089 | 105357 | if( pUsage[i].argvIndex>0 ){ |
| 105090 | 105358 | j = pIdxCons->iTermOffset; |
| 105091 | 105359 | pTerm = &pWC->a[j]; |
| 105092 | 105360 | 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 | + } | |
| 105099 | 105375 | } |
| 105100 | 105376 | } |
| 105101 | 105377 | } |
| 105102 | 105378 | if( i>=pIdxInfo->nConstraint ) break; |
| 105103 | 105379 | } |
| @@ -105123,11 +105399,12 @@ | ||
| 105123 | 105399 | }else{ |
| 105124 | 105400 | p->cost.rCost = rCost; |
| 105125 | 105401 | } |
| 105126 | 105402 | p->cost.plan.u.pVtabIdx = pIdxInfo; |
| 105127 | 105403 | 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; | |
| 105129 | 105406 | p->cost.plan.nOBSat = nOrderBy; |
| 105130 | 105407 | }else{ |
| 105131 | 105408 | p->cost.plan.nOBSat = p->i ? p->aLevel[p->i-1].plan.nOBSat : 0; |
| 105132 | 105409 | } |
| 105133 | 105410 | p->cost.plan.nEq = 0; |
| @@ -105720,14 +105997,11 @@ | ||
| 105720 | 105997 | pConstraint = findTerm(p->pWC, base, iColumn, p->notReady, |
| 105721 | 105998 | WO_EQ|WO_ISNULL|WO_IN, pIdx); |
| 105722 | 105999 | if( pConstraint==0 ){ |
| 105723 | 106000 | isEq = 0; |
| 105724 | 106001 | }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; | |
| 105729 | 106003 | }else if( (pConstraint->eOperator & WO_ISNULL)!=0 ){ |
| 105730 | 106004 | uniqueNotNull = 0; |
| 105731 | 106005 | isEq = 1; /* "X IS NULL" means X has only a single value */ |
| 105732 | 106006 | }else if( pConstraint->prereqRight==0 ){ |
| 105733 | 106007 | isEq = 1; /* Constraint "X=constant" means X has only a single value */ |
| @@ -106027,12 +106301,12 @@ | ||
| 106027 | 106301 | ** constraint for all columns in the index, then this search will find |
| 106028 | 106302 | ** at most a single row. In this case set the WHERE_UNIQUE flag to |
| 106029 | 106303 | ** indicate this to the caller. |
| 106030 | 106304 | ** |
| 106031 | 106305 | ** 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. | |
| 106034 | 106308 | */ |
| 106035 | 106309 | if( pc.plan.nEq==pProbe->nColumn && pProbe->onError!=OE_None ){ |
| 106036 | 106310 | testcase( pc.plan.wsFlags & WHERE_COLUMN_IN ); |
| 106037 | 106311 | testcase( pc.plan.wsFlags & WHERE_COLUMN_NULL ); |
| 106038 | 106312 | if( (pc.plan.wsFlags & (WHERE_COLUMN_IN|WHERE_COLUMN_NULL))==0 ){ |
| @@ -106369,11 +106643,12 @@ | ||
| 106369 | 106643 | #ifndef SQLITE_OMIT_VIRTUALTABLE |
| 106370 | 106644 | if( IsVirtual(p->pSrc->pTab) ){ |
| 106371 | 106645 | sqlite3_index_info *pIdxInfo = 0; |
| 106372 | 106646 | p->ppIdxInfo = &pIdxInfo; |
| 106373 | 106647 | bestVirtualIndex(p); |
| 106374 | - if( pIdxInfo->needToFreeIdxStr ){ | |
| 106648 | + assert( pIdxInfo!=0 || p->pParse->db->mallocFailed ); | |
| 106649 | + if( pIdxInfo && pIdxInfo->needToFreeIdxStr ){ | |
| 106375 | 106650 | sqlite3_free(pIdxInfo->idxStr); |
| 106376 | 106651 | } |
| 106377 | 106652 | sqlite3DbFree(p->pParse->db, pIdxInfo); |
| 106378 | 106653 | }else |
| 106379 | 106654 | #endif |
| @@ -106475,11 +106750,12 @@ | ||
| 106475 | 106750 | ** this routine sets up a loop that will iterate over all values of X. |
| 106476 | 106751 | */ |
| 106477 | 106752 | static int codeEqualityTerm( |
| 106478 | 106753 | Parse *pParse, /* The parsing context */ |
| 106479 | 106754 | 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 */ | |
| 106481 | 106757 | int iTarget /* Attempt to leave results in this register */ |
| 106482 | 106758 | ){ |
| 106483 | 106759 | Expr *pX = pTerm->pExpr; |
| 106484 | 106760 | Vdbe *v = pParse->pVdbe; |
| 106485 | 106761 | int iReg; /* Register holding results */ |
| @@ -106493,16 +106769,30 @@ | ||
| 106493 | 106769 | #ifndef SQLITE_OMIT_SUBQUERY |
| 106494 | 106770 | }else{ |
| 106495 | 106771 | int eType; |
| 106496 | 106772 | int iTab; |
| 106497 | 106773 | struct InLoop *pIn; |
| 106774 | + u8 bRev = (pLevel->plan.wsFlags & WHERE_REVERSE)!=0; | |
| 106498 | 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 | + } | |
| 106499 | 106785 | assert( pX->op==TK_IN ); |
| 106500 | 106786 | iReg = iTarget; |
| 106501 | 106787 | eType = sqlite3FindInIndex(pParse, pX, 0); |
| 106788 | + if( eType==IN_INDEX_INDEX_DESC ){ | |
| 106789 | + testcase( bRev ); | |
| 106790 | + bRev = !bRev; | |
| 106791 | + } | |
| 106502 | 106792 | iTab = pX->iTable; |
| 106503 | - sqlite3VdbeAddOp2(v, OP_Rewind, iTab, 0); | |
| 106793 | + sqlite3VdbeAddOp2(v, bRev ? OP_Last : OP_Rewind, iTab, 0); | |
| 106504 | 106794 | assert( pLevel->plan.wsFlags & WHERE_IN_ABLE ); |
| 106505 | 106795 | if( pLevel->u.in.nIn==0 ){ |
| 106506 | 106796 | pLevel->addrNxt = sqlite3VdbeMakeLabel(v); |
| 106507 | 106797 | } |
| 106508 | 106798 | pLevel->u.in.nIn++; |
| @@ -106516,10 +106806,11 @@ | ||
| 106516 | 106806 | if( eType==IN_INDEX_ROWID ){ |
| 106517 | 106807 | pIn->addrInTop = sqlite3VdbeAddOp2(v, OP_Rowid, iTab, iReg); |
| 106518 | 106808 | }else{ |
| 106519 | 106809 | pIn->addrInTop = sqlite3VdbeAddOp3(v, OP_Column, iTab, 0, iReg); |
| 106520 | 106810 | } |
| 106811 | + pIn->eEndLoopOp = bRev ? OP_Prev : OP_Next; | |
| 106521 | 106812 | sqlite3VdbeAddOp1(v, OP_IsNull, iReg); |
| 106522 | 106813 | }else{ |
| 106523 | 106814 | pLevel->u.in.nIn = 0; |
| 106524 | 106815 | } |
| 106525 | 106816 | #endif |
| @@ -106610,11 +106901,11 @@ | ||
| 106610 | 106901 | if( pTerm==0 ) break; |
| 106611 | 106902 | /* The following true for indices with redundant columns. |
| 106612 | 106903 | ** Ex: CREATE INDEX i1 ON t1(a,b,a); SELECT * FROM t1 WHERE a=0 AND b=0; */ |
| 106613 | 106904 | testcase( (pTerm->wtFlags & TERM_CODED)!=0 ); |
| 106614 | 106905 | 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); | |
| 106616 | 106907 | if( r1!=regBase+j ){ |
| 106617 | 106908 | if( nReg==1 ){ |
| 106618 | 106909 | sqlite3ReleaseTempReg(pParse, regBase); |
| 106619 | 106910 | regBase = r1; |
| 106620 | 106911 | }else{ |
| @@ -106884,14 +107175,14 @@ | ||
| 106884 | 107175 | iReg = sqlite3GetTempRange(pParse, nConstraint+2); |
| 106885 | 107176 | addrNotFound = pLevel->addrBrk; |
| 106886 | 107177 | for(j=1; j<=nConstraint; j++){ |
| 106887 | 107178 | for(k=0; k<nConstraint; k++){ |
| 106888 | 107179 | if( aUsage[k].argvIndex==j ){ |
| 106889 | - WhereTerm *pTerm = &pWC->a[aConstraint[k].iTermOffset]; | |
| 106890 | 107180 | int iTarget = iReg+j+1; |
| 107181 | + pTerm = &pWC->a[aConstraint[k].iTermOffset]; | |
| 106891 | 107182 | if( pTerm->eOperator & WO_IN ){ |
| 106892 | - codeEqualityTerm(pParse, pTerm, pLevel, iTarget); | |
| 107183 | + codeEqualityTerm(pParse, pTerm, pLevel, k, iTarget); | |
| 106893 | 107184 | addrNotFound = pLevel->addrNxt; |
| 106894 | 107185 | }else{ |
| 106895 | 107186 | sqlite3ExprCode(pParse, pTerm->pExpr->pRight, iTarget); |
| 106896 | 107187 | } |
| 106897 | 107188 | break; |
| @@ -106928,14 +107219,15 @@ | ||
| 106928 | 107219 | pTerm = findTerm(pWC, iCur, -1, notReady, WO_EQ|WO_IN, 0); |
| 106929 | 107220 | assert( pTerm!=0 ); |
| 106930 | 107221 | assert( pTerm->pExpr!=0 ); |
| 106931 | 107222 | assert( omitTable==0 ); |
| 106932 | 107223 | testcase( pTerm->wtFlags & TERM_VIRTUAL ); /* EV: R-30575-11662 */ |
| 106933 | - iRowidReg = codeEqualityTerm(pParse, pTerm, pLevel, iReleaseReg); | |
| 107224 | + iRowidReg = codeEqualityTerm(pParse, pTerm, pLevel, 0, iReleaseReg); | |
| 106934 | 107225 | addrNxt = pLevel->addrNxt; |
| 106935 | 107226 | sqlite3VdbeAddOp2(v, OP_MustBeInt, iRowidReg, addrNxt); |
| 106936 | 107227 | sqlite3VdbeAddOp3(v, OP_NotExists, iCur, addrNxt, iRowidReg); |
| 107228 | + sqlite3ExprCacheAffinityChange(pParse, iRowidReg, 1); | |
| 106937 | 107229 | sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg); |
| 106938 | 107230 | VdbeComment((v, "pk")); |
| 106939 | 107231 | pLevel->op = OP_Noop; |
| 106940 | 107232 | }else if( pLevel->plan.wsFlags & WHERE_ROWID_RANGE ){ |
| 106941 | 107233 | /* Case 2: We have an inequality comparison against the ROWID field. |
| @@ -107767,28 +108059,17 @@ | ||
| 107767 | 108059 | ** its Expr.iRightJoinTable value to find the bitmask of the right table |
| 107768 | 108060 | ** of the join. Subtracting one from the right table bitmask gives a |
| 107769 | 108061 | ** bitmask for all tables to the left of the join. Knowing the bitmask |
| 107770 | 108062 | ** for all tables to the left of a left join is important. Ticket #3015. |
| 107771 | 108063 | ** |
| 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 | 108064 | ** Note that bitmasks are created for all pTabList->nSrc tables in |
| 107778 | 108065 | ** pTabList, not just the first nTabList tables. nTabList is normally |
| 107779 | 108066 | ** equal to pTabList->nSrc but might be shortened to 1 if the |
| 107780 | 108067 | ** WHERE_ONETABLE_ONLY flag is set. |
| 107781 | 108068 | */ |
| 107782 | - assert( sWBI.pWC->vmask==0 && pMaskSet->n==0 ); | |
| 107783 | 108069 | for(ii=0; ii<pTabList->nSrc; ii++){ |
| 107784 | 108070 | 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 | 108071 | } |
| 107791 | 108072 | #ifndef NDEBUG |
| 107792 | 108073 | { |
| 107793 | 108074 | Bitmask toTheLeft = 0; |
| 107794 | 108075 | for(ii=0; ii<pTabList->nSrc; ii++){ |
| @@ -108268,11 +108549,11 @@ | ||
| 108268 | 108549 | struct InLoop *pIn; |
| 108269 | 108550 | int j; |
| 108270 | 108551 | sqlite3VdbeResolveLabel(v, pLevel->addrNxt); |
| 108271 | 108552 | for(j=pLevel->u.in.nIn, pIn=&pLevel->u.in.aInLoop[j-1]; j>0; j--, pIn--){ |
| 108272 | 108553 | sqlite3VdbeJumpHere(v, pIn->addrInTop+1); |
| 108273 | - sqlite3VdbeAddOp2(v, OP_Next, pIn->iCur, pIn->addrInTop); | |
| 108554 | + sqlite3VdbeAddOp2(v, pIn->eEndLoopOp, pIn->iCur, pIn->addrInTop); | |
| 108274 | 108555 | sqlite3VdbeJumpHere(v, pIn->addrInTop-1); |
| 108275 | 108556 | } |
| 108276 | 108557 | sqlite3DbFree(db, pLevel->u.in.aInLoop); |
| 108277 | 108558 | } |
| 108278 | 108559 | sqlite3VdbeResolveLabel(v, pLevel->addrBrk); |
| @@ -114034,11 +114315,11 @@ | ||
| 114034 | 114315 | } |
| 114035 | 114316 | } |
| 114036 | 114317 | sqlite3VtabRollback(db); |
| 114037 | 114318 | sqlite3EndBenignMalloc(); |
| 114038 | 114319 | |
| 114039 | - if( db->flags&SQLITE_InternChanges ){ | |
| 114320 | + if( (db->flags&SQLITE_InternChanges)!=0 && db->init.busy==0 ){ | |
| 114040 | 114321 | sqlite3ExpirePreparedStatements(db); |
| 114041 | 114322 | sqlite3ResetAllSchemasOfConnection(db); |
| 114042 | 114323 | } |
| 114043 | 114324 | |
| 114044 | 114325 | /* Any deferred constraint violations have now been resolved. */ |
| 114045 | 114326 |
| --- 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 @@ | ||
| 107 | 107 | ** [sqlite3_libversion_number()], [sqlite3_sourceid()], |
| 108 | 108 | ** [sqlite_version()] and [sqlite_source_id()]. |
| 109 | 109 | */ |
| 110 | 110 | #define SQLITE_VERSION "3.7.16" |
| 111 | 111 | #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" | |
| 113 | 113 | |
| 114 | 114 | /* |
| 115 | 115 | ** CAPI3REF: Run-Time Library Version Numbers |
| 116 | 116 | ** KEYWORDS: sqlite3_version, sqlite3_sourceid |
| 117 | 117 | ** |
| @@ -286,11 +286,11 @@ | ||
| 286 | 286 | ** |
| 287 | 287 | ** Applications should [sqlite3_finalize | finalize] all [prepared statements], |
| 288 | 288 | ** [sqlite3_blob_close | close] all [BLOB handles], and |
| 289 | 289 | ** [sqlite3_backup_finish | finish] all [sqlite3_backup] objects associated |
| 290 | 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 | |
| 291 | +** sqlite3_close_v2() is called on a [database connection] that still has | |
| 292 | 292 | ** outstanding [prepared statements], [BLOB handles], and/or |
| 293 | 293 | ** [sqlite3_backup] objects then it returns SQLITE_OK but the deallocation |
| 294 | 294 | ** of resources is deferred until all [prepared statements], [BLOB handles], |
| 295 | 295 | ** and [sqlite3_backup] objects are also destroyed. |
| 296 | 296 | ** |
| @@ -481,11 +481,21 @@ | ||
| 481 | 481 | #define SQLITE_CANTOPEN_ISDIR (SQLITE_CANTOPEN | (2<<8)) |
| 482 | 482 | #define SQLITE_CANTOPEN_FULLPATH (SQLITE_CANTOPEN | (3<<8)) |
| 483 | 483 | #define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1<<8)) |
| 484 | 484 | #define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1<<8)) |
| 485 | 485 | #define SQLITE_READONLY_CANTLOCK (SQLITE_READONLY | (2<<8)) |
| 486 | +#define SQLITE_READONLY_ROLLBACK (SQLITE_READONLY | (3<<8)) | |
| 486 | 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)) | |
| 487 | 497 | |
| 488 | 498 | /* |
| 489 | 499 | ** CAPI3REF: Flags For File Open Operations |
| 490 | 500 | ** |
| 491 | 501 | ** These bit values are intended for use in the |
| 492 | 502 |
| --- 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 @@ | ||
| 156 | 156 | int n, m; |
| 157 | 157 | int szMax, szAvg; |
| 158 | 158 | const char *zDb; |
| 159 | 159 | int brief; |
| 160 | 160 | 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 */; | |
| 162 | 162 | brief = find_option("brief", "b",0)!=0; |
| 163 | 163 | db_find_and_open_repository(0,0); |
| 164 | 164 | fsize = file_size(g.zRepositoryName); |
| 165 | 165 | bigSizeName(sizeof(zBuf), zBuf, fsize); |
| 166 | 166 | fossil_print( "%*s%s\n", colWidth, "repository-size:", zBuf ); |
| @@ -179,12 +179,12 @@ | ||
| 179 | 179 | t = db_column_int64(&q, 0); |
| 180 | 180 | szAvg = db_column_int(&q, 1); |
| 181 | 181 | szMax = db_column_int(&q, 2); |
| 182 | 182 | db_finalize(&q); |
| 183 | 183 | 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", | |
| 186 | 186 | colWidth, "artifact-sizes:", |
| 187 | 187 | szAvg, szMax, zBuf); |
| 188 | 188 | if( t/fsize < 5 ){ |
| 189 | 189 | b = 10; |
| 190 | 190 | fsize /= 10; |
| @@ -214,20 +214,20 @@ | ||
| 214 | 214 | n = db_int(0, "SELECT julianday('now') - (SELECT min(mtime) FROM event)" |
| 215 | 215 | " + 0.99"); |
| 216 | 216 | fossil_print("%*s%d days or approximately %.2f years.\n", |
| 217 | 217 | colWidth, "project-age:", n, n/365.2425); |
| 218 | 218 | 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", | |
| 220 | 220 | colWidth, "fossil-version:", |
| 221 | - RELEASE_VERSION, MANIFEST_DATE, MANIFEST_VERSION, | |
| 221 | + MANIFEST_DATE, MANIFEST_VERSION, RELEASE_VERSION, | |
| 222 | 222 | COMPILER_NAME); |
| 223 | 223 | fossil_print("%*s%.19s [%.10s] (%s)\n", |
| 224 | 224 | colWidth, "sqlite-version:", |
| 225 | 225 | SQLITE_SOURCE_ID, &SQLITE_SOURCE_ID[20], |
| 226 | 226 | SQLITE_VERSION); |
| 227 | 227 | 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, " | |
| 229 | 229 | "%s, %s mode\n", |
| 230 | 230 | colWidth, "database-stats:", |
| 231 | 231 | db_int(0, "PRAGMA %s.page_count", zDb), |
| 232 | 232 | db_int(0, "PRAGMA %s.page_size", zDb), |
| 233 | 233 | db_int(0, "PRAGMA %s.freelist_count", zDb), |
| 234 | 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 = -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 @@ | ||
| 27 | 27 | ** if the argument is false. |
| 28 | 28 | ** |
| 29 | 29 | ** Return the number of errors. |
| 30 | 30 | */ |
| 31 | 31 | int autosync(int flags){ |
| 32 | - const char *zUrl; | |
| 33 | 32 | const char *zAutosync; |
| 34 | - const char *zPw; | |
| 35 | 33 | int rc; |
| 36 | 34 | int configSync = 0; /* configuration changes transferred */ |
| 37 | 35 | if( g.fNoSync ){ |
| 38 | 36 | return 0; |
| 39 | 37 | } |
| @@ -49,18 +47,14 @@ | ||
| 49 | 47 | return 0; /* Autosync is completely off */ |
| 50 | 48 | } |
| 51 | 49 | }else{ |
| 52 | 50 | /* Autosync defaults on. To make it default off, "return" here. */ |
| 53 | 51 | } |
| 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; | |
| 60 | 54 | if( g.urlUser!=0 && g.urlPasswd==0 ){ |
| 61 | - g.urlPasswd = mprintf("%s", zPw); | |
| 55 | + g.urlPasswd = unobscure(db_get("last-sync-pw", 0)); | |
| 62 | 56 | } |
| 63 | 57 | #if 0 /* Disabled for now */ |
| 64 | 58 | if( (flags & AUTOSYNC_PULL)!=0 && db_get_boolean("auto-shun",1) ){ |
| 65 | 59 | /* When doing an automatic pull, also automatically pull shuns from |
| 66 | 60 | ** the server if pull_shuns is enabled. |
| @@ -86,14 +80,18 @@ | ||
| 86 | 80 | ** of a server to sync against. If no argument is given, use the |
| 87 | 81 | ** most recently synced URL. Remember the current URL for next time. |
| 88 | 82 | */ |
| 89 | 83 | static void process_sync_args(unsigned *pConfigFlags, unsigned *pSyncFlags){ |
| 90 | 84 | const char *zUrl = 0; |
| 91 | - const char *zPw = 0; | |
| 92 | 85 | 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; | |
| 95 | 93 | if( find_option("private",0,0)!=0 ){ |
| 96 | 94 | *pSyncFlags |= SYNC_PRIVATE; |
| 97 | 95 | } |
| 98 | 96 | if( find_option("verbose","v",0)!=0 ){ |
| 99 | 97 | *pSyncFlags |= SYNC_VERBOSE; |
| @@ -100,32 +98,19 @@ | ||
| 100 | 98 | } |
| 101 | 99 | url_proxy_options(); |
| 102 | 100 | db_find_and_open_repository(0, 0); |
| 103 | 101 | db_open_config(0); |
| 104 | 102 | if( g.argc==2 ){ |
| 105 | - zUrl = db_get("last-sync-url", 0); | |
| 106 | - zPw = unobscure(db_get("last-sync-pw", 0)); | |
| 107 | 103 | if( db_get_boolean("auto-shun",1) ) configSync = CONFIGSET_SHUN; |
| 108 | 104 | }else if( g.argc==3 ){ |
| 109 | 105 | zUrl = g.argv[2]; |
| 110 | 106 | } |
| 111 | - if( zUrl==0 ){ | |
| 107 | + url_parse(zUrl, urlFlags); | |
| 108 | + if( g.urlProtocol==0 ){ | |
| 112 | 109 | if( urlOptional ) fossil_exit(0); |
| 113 | 110 | usage("URL"); |
| 114 | 111 | } |
| 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 | 112 | user_select(); |
| 128 | 113 | if( g.argc==2 ){ |
| 129 | 114 | if( ((*pSyncFlags) & (SYNC_PUSH|SYNC_PULL))==(SYNC_PUSH|SYNC_PULL) ){ |
| 130 | 115 | fossil_print("Sync with %s\n", g.urlCanonical); |
| 131 | 116 | }else if( (*pSyncFlags) & SYNC_PUSH ){ |
| @@ -258,30 +243,19 @@ | ||
| 258 | 243 | db_find_and_open_repository(0, 0); |
| 259 | 244 | if( g.argc!=2 && g.argc!=3 ){ |
| 260 | 245 | usage("remote-url ?URL|off?"); |
| 261 | 246 | } |
| 262 | 247 | 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); | |
| 278 | 252 | } |
| 279 | 253 | zUrl = db_get("last-sync-url", 0); |
| 280 | 254 | if( zUrl==0 ){ |
| 281 | 255 | fossil_print("off\n"); |
| 282 | 256 | return; |
| 283 | 257 | }else{ |
| 284 | - url_parse(zUrl); | |
| 258 | + url_parse(zUrl, 0); | |
| 285 | 259 | fossil_print("%s\n", g.urlCanonical); |
| 286 | 260 | } |
| 287 | 261 | } |
| 288 | 262 |
| --- 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 @@ | ||
| 87 | 87 | } |
| 88 | 88 | |
| 89 | 89 | /* |
| 90 | 90 | ** Return a name for a TH1 return code. |
| 91 | 91 | */ |
| 92 | -const char *Th_ReturnCodeName(int rc){ | |
| 92 | +const char *Th_ReturnCodeName(int rc, int nullIfOk){ | |
| 93 | 93 | static char zRc[32]; |
| 94 | 94 | switch( rc ){ |
| 95 | - case TH_OK: return "TH_OK"; | |
| 95 | + case TH_OK: return nullIfOk ? 0 : "TH_OK"; | |
| 96 | 96 | case TH_ERROR: return "TH_ERROR"; |
| 97 | 97 | case TH_BREAK: return "TH_BREAK"; |
| 98 | 98 | case TH_RETURN: return "TH_RETURN"; |
| 99 | 99 | case TH_CONTINUE: return "TH_CONTINUE"; |
| 100 | 100 | default: { |
| @@ -742,11 +742,11 @@ | ||
| 742 | 742 | sendError(zResult, nResult, 0); |
| 743 | 743 | } |
| 744 | 744 | } |
| 745 | 745 | if( g.thTrace ){ |
| 746 | 746 | Th_Trace("th1-setup {%h} => %h<br />\n", g.th1Setup, |
| 747 | - Th_ReturnCodeName(rc)); | |
| 747 | + Th_ReturnCodeName(rc, 0)); | |
| 748 | 748 | } |
| 749 | 749 | } |
| 750 | 750 | } |
| 751 | 751 | |
| 752 | 752 | /* |
| @@ -932,5 +932,21 @@ | ||
| 932 | 932 | db_open_config(0); /* Needed for global "tcl" setting. */ |
| 933 | 933 | blob_zero(&in); |
| 934 | 934 | blob_read_from_file(&in, g.argv[2]); |
| 935 | 935 | Th_Render(blob_str(&in)); |
| 936 | 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 | +} | |
| 937 | 953 |
| --- 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 @@ | ||
| 593 | 593 | cgi_printf("],h:\"%s\"}%s", pRow->zUuid, pRow->pNext ? ",\n" : "];\n"); |
| 594 | 594 | } |
| 595 | 595 | cgi_printf("var nrail = %d\n", pGraph->mxRail+1); |
| 596 | 596 | graph_free(pGraph); |
| 597 | 597 | @ var canvasDiv = gebi("canvas"); |
| 598 | -#if 0 | |
| 599 | - @ var realCanvas = null; | |
| 600 | -#endif | |
| 601 | 598 | @ function drawBox(color,x0,y0,x1,y1){ |
| 602 | 599 | @ var n = document.createElement("div"); |
| 603 | 600 | @ if( x0>x1 ){ var t=x0; x0=x1; x1=t; } |
| 604 | 601 | @ if( y0>y1 ){ var t=y0; y0=y1; y1=t; } |
| 605 | 602 | @ var w = x1-x0+1; |
| @@ -636,11 +633,11 @@ | ||
| 636 | 633 | @ } |
| 637 | 634 | @ return left; |
| 638 | 635 | @ } |
| 639 | 636 | @ function drawUpArrow(x,y0,y1){ |
| 640 | 637 | @ drawBox("black",x,y0,x+1,y1); |
| 641 | - @ if( y0+8>=y1 ){ | |
| 638 | + @ if( y0+10>=y1 ){ | |
| 642 | 639 | @ drawBox("black",x-1,y0+1,x+2,y0+2); |
| 643 | 640 | @ drawBox("black",x-2,y0+3,x+3,y0+4); |
| 644 | 641 | @ }else{ |
| 645 | 642 | @ drawBox("black",x-1,y0+2,x+2,y0+4); |
| 646 | 643 | @ drawBox("black",x-2,y0+5,x+3,y0+7); |
| @@ -647,28 +644,28 @@ | ||
| 647 | 644 | @ } |
| 648 | 645 | @ } |
| 649 | 646 | @ function drawThinArrow(y,xFrom,xTo){ |
| 650 | 647 | @ if( xFrom<xTo ){ |
| 651 | 648 | @ 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); | |
| 654 | 651 | @ }else{ |
| 655 | 652 | @ 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); | |
| 658 | 655 | @ } |
| 659 | 656 | @ } |
| 660 | 657 | @ function drawThinLine(x0,y0,x1,y1){ |
| 661 | 658 | @ drawBox("black",x0,y0,x1,y1); |
| 662 | 659 | @ } |
| 663 | 660 | @ function drawNode(p, left, btm){ |
| 664 | 661 | @ drawBox("black",p.x-5,p.y-5,p.x+6,p.y+6); |
| 665 | 662 | @ drawBox(p.bg,p.x-4,p.y-4,p.x+5,p.y+5); |
| 666 | 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); | |
| 667 | 665 | if( !omitDescenders ){ |
| 668 | 666 | @ 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 | 667 | @ if( p.d ) drawUpArrow(p.x, p.y+6, btm); |
| 671 | 668 | } |
| 672 | 669 | @ if( p.mo>0 ){ |
| 673 | 670 | @ var x1 = p.mo + left - 1; |
| 674 | 671 | @ var y1 = p.y-3; |
| @@ -721,11 +718,10 @@ | ||
| 721 | 718 | @ while( canvasDiv.hasChildNodes() ){ |
| 722 | 719 | @ canvasDiv.removeChild(canvasDiv.firstChild); |
| 723 | 720 | @ } |
| 724 | 721 | @ var canvasY = absoluteY("timelineTable"); |
| 725 | 722 | @ var left = absoluteX("m"+rowinfo[0].id) - absoluteX("canvas") + 15; |
| 726 | - @ var width = nrail*railPitch; | |
| 727 | 723 | @ for(var i in rowinfo){ |
| 728 | 724 | @ rowinfo[i].y = absoluteY("m"+rowinfo[i].id) + 10 - canvasY; |
| 729 | 725 | @ rowinfo[i].x = left + rowinfo[i].r*railPitch; |
| 730 | 726 | @ } |
| 731 | 727 | @ var btm = absoluteY("grbtm") + 10 - canvasY; |
| @@ -1143,10 +1139,11 @@ | ||
| 1143 | 1139 | db_multi_exec("%s", blob_str(&sql)); |
| 1144 | 1140 | if( useDividers ) timeline_add_dividers(0, f_rid); |
| 1145 | 1141 | blob_appendf(&desc, "Parents and children of check-in "); |
| 1146 | 1142 | zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", f_rid); |
| 1147 | 1143 | blob_appendf(&desc, "%z[%.10s]</a>", href("%R/info/%s", zUuid), zUuid); |
| 1144 | + tmFlags |= TIMELINE_DISJOINT; | |
| 1148 | 1145 | }else{ |
| 1149 | 1146 | /* Otherwise, a timeline based on a span of time */ |
| 1150 | 1147 | int n; |
| 1151 | 1148 | const char *zEType = "timeline item"; |
| 1152 | 1149 | char *zDate; |
| 1153 | 1150 |
| --- 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 @@ | ||
| 593 | 593 | cgi_printf("],h:\"%s\"}%s", pRow->zUuid, pRow->pNext ? ",\n" : "];\n"); |
| 594 | 594 | } |
| 595 | 595 | cgi_printf("var nrail = %d\n", pGraph->mxRail+1); |
| 596 | 596 | graph_free(pGraph); |
| 597 | 597 | @ var canvasDiv = gebi("canvas"); |
| 598 | -#if 0 | |
| 599 | - @ var realCanvas = null; | |
| 600 | -#endif | |
| 601 | 598 | @ function drawBox(color,x0,y0,x1,y1){ |
| 602 | 599 | @ var n = document.createElement("div"); |
| 603 | 600 | @ if( x0>x1 ){ var t=x0; x0=x1; x1=t; } |
| 604 | 601 | @ if( y0>y1 ){ var t=y0; y0=y1; y1=t; } |
| 605 | 602 | @ var w = x1-x0+1; |
| @@ -636,11 +633,11 @@ | ||
| 636 | 633 | @ } |
| 637 | 634 | @ return left; |
| 638 | 635 | @ } |
| 639 | 636 | @ function drawUpArrow(x,y0,y1){ |
| 640 | 637 | @ drawBox("black",x,y0,x+1,y1); |
| 641 | - @ if( y0+8>=y1 ){ | |
| 638 | + @ if( y0+10>=y1 ){ | |
| 642 | 639 | @ drawBox("black",x-1,y0+1,x+2,y0+2); |
| 643 | 640 | @ drawBox("black",x-2,y0+3,x+3,y0+4); |
| 644 | 641 | @ }else{ |
| 645 | 642 | @ drawBox("black",x-1,y0+2,x+2,y0+4); |
| 646 | 643 | @ drawBox("black",x-2,y0+5,x+3,y0+7); |
| @@ -647,28 +644,28 @@ | ||
| 647 | 644 | @ } |
| 648 | 645 | @ } |
| 649 | 646 | @ function drawThinArrow(y,xFrom,xTo){ |
| 650 | 647 | @ if( xFrom<xTo ){ |
| 651 | 648 | @ 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); | |
| 654 | 651 | @ }else{ |
| 655 | 652 | @ 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); | |
| 658 | 655 | @ } |
| 659 | 656 | @ } |
| 660 | 657 | @ function drawThinLine(x0,y0,x1,y1){ |
| 661 | 658 | @ drawBox("black",x0,y0,x1,y1); |
| 662 | 659 | @ } |
| 663 | 660 | @ function drawNode(p, left, btm){ |
| 664 | 661 | @ drawBox("black",p.x-5,p.y-5,p.x+6,p.y+6); |
| 665 | 662 | @ drawBox(p.bg,p.x-4,p.y-4,p.x+5,p.y+5); |
| 666 | 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); | |
| 667 | 665 | if( !omitDescenders ){ |
| 668 | 666 | @ 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 | 667 | @ if( p.d ) drawUpArrow(p.x, p.y+6, btm); |
| 671 | 668 | } |
| 672 | 669 | @ if( p.mo>0 ){ |
| 673 | 670 | @ var x1 = p.mo + left - 1; |
| 674 | 671 | @ var y1 = p.y-3; |
| @@ -721,11 +718,10 @@ | ||
| 721 | 718 | @ while( canvasDiv.hasChildNodes() ){ |
| 722 | 719 | @ canvasDiv.removeChild(canvasDiv.firstChild); |
| 723 | 720 | @ } |
| 724 | 721 | @ var canvasY = absoluteY("timelineTable"); |
| 725 | 722 | @ var left = absoluteX("m"+rowinfo[0].id) - absoluteX("canvas") + 15; |
| 726 | - @ var width = nrail*railPitch; | |
| 727 | 723 | @ for(var i in rowinfo){ |
| 728 | 724 | @ rowinfo[i].y = absoluteY("m"+rowinfo[i].id) + 10 - canvasY; |
| 729 | 725 | @ rowinfo[i].x = left + rowinfo[i].r*railPitch; |
| 730 | 726 | @ } |
| 731 | 727 | @ var btm = absoluteY("grbtm") + 10 - canvasY; |
| @@ -1143,10 +1139,11 @@ | ||
| 1143 | 1139 | db_multi_exec("%s", blob_str(&sql)); |
| 1144 | 1140 | if( useDividers ) timeline_add_dividers(0, f_rid); |
| 1145 | 1141 | blob_appendf(&desc, "Parents and children of check-in "); |
| 1146 | 1142 | zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", f_rid); |
| 1147 | 1143 | blob_appendf(&desc, "%z[%.10s]</a>", href("%R/info/%s", zUuid), zUuid); |
| 1144 | + tmFlags |= TIMELINE_DISJOINT; | |
| 1148 | 1145 | }else{ |
| 1149 | 1146 | /* Otherwise, a timeline based on a span of time */ |
| 1150 | 1147 | int n; |
| 1151 | 1148 | const char *zEType = "timeline item"; |
| 1152 | 1149 | char *zDate; |
| 1153 | 1150 |
| --- 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 @@ | ||
| 934 | 934 | @ |
| 935 | 935 | @ <li><p>Delete attachment "%h(zFile)" |
| 936 | 936 | }else{ |
| 937 | 937 | @ |
| 938 | 938 | @ <li><p>Add attachment |
| 939 | - @ "%z(href("%R/artifact/%S",zSrc))%h(zFile)</a>" | |
| 939 | + @ "%z(href("%R/artifact/%S",zSrc))%s(zFile)</a>" | |
| 940 | 940 | } |
| 941 | 941 | @ [%z(href("%R/artifact/%T",zChngUuid))%s(zShort)</a>] |
| 942 | 942 | @ (rid %d(rid)) by |
| 943 | 943 | hyperlink_to_user(zUser,zDate," on"); |
| 944 | 944 | hyperlink_to_date(zDate, ".</p>"); |
| 945 | 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))%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 @@ | ||
| 17 | 17 | ** |
| 18 | 18 | ** This file contains code for parsing URLs that appear on the command-line |
| 19 | 19 | */ |
| 20 | 20 | #include "config.h" |
| 21 | 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 | + | |
| 22 | 35 | |
| 23 | 36 | /* |
| 24 | 37 | ** Convert a string to lower-case. |
| 25 | 38 | */ |
| 26 | 39 | static void url_tolower(char *z){ |
| @@ -29,11 +42,12 @@ | ||
| 29 | 42 | z++; |
| 30 | 43 | } |
| 31 | 44 | } |
| 32 | 45 | |
| 33 | 46 | /* |
| 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: | |
| 35 | 49 | ** |
| 36 | 50 | ** g.urlIsFile True if FILE: |
| 37 | 51 | ** g.urlIsHttps True if HTTPS: |
| 38 | 52 | ** g.urlIsSsh True if SSH: |
| 39 | 53 | ** g.urlProtocol "http" or "https" or "file" |
| @@ -44,22 +58,32 @@ | ||
| 44 | 58 | ** g.urlUser Userid. |
| 45 | 59 | ** g.urlPasswd Password. |
| 46 | 60 | ** g.urlHostname HOST:PORT or just HOST if port is the default. |
| 47 | 61 | ** g.urlCanonical The URL in canonical form, omitting the password |
| 48 | 62 | ** |
| 49 | -** HTTP url format is: | |
| 63 | +** HTTP url format as follows (HTTPS is the same with a different scheme): | |
| 50 | 64 | ** |
| 51 | 65 | ** http://userid:password@host:port/path |
| 52 | 66 | ** |
| 53 | 67 | ** SSH url format is: |
| 54 | 68 | ** |
| 55 | 69 | ** ssh://userid:password@host:port/path?fossil=path/to/fossil.exe |
| 56 | 70 | ** |
| 57 | 71 | */ |
| 58 | -void url_parse(const char *zUrl){ | |
| 72 | +void url_parse(const char *zUrl, unsigned int urlFlags){ | |
| 59 | 73 | int i, j, c; |
| 60 | 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 | + | |
| 61 | 85 | if( strncmp(zUrl, "http://", 7)==0 |
| 62 | 86 | || strncmp(zUrl, "https://", 8)==0 |
| 63 | 87 | || strncmp(zUrl, "ssh://", 6)==0 |
| 64 | 88 | ){ |
| 65 | 89 | int iStart; |
| @@ -188,15 +212,16 @@ | ||
| 188 | 212 | zFile = mprintf("%s/FOSSIL", zUrl); |
| 189 | 213 | if( file_isfile(zFile) ){ |
| 190 | 214 | g.urlIsFile = 1; |
| 191 | 215 | }else{ |
| 192 | 216 | free(zFile); |
| 193 | - fossil_panic("unknown repository: %s", zUrl); | |
| 217 | + fossil_fatal("unknown repository: %s", zUrl); | |
| 194 | 218 | } |
| 195 | 219 | }else{ |
| 196 | - fossil_panic("unknown repository: %s", zUrl); | |
| 220 | + fossil_fatal("unknown repository: %s", zUrl); | |
| 197 | 221 | } |
| 222 | + g.urlFlags = urlFlags; | |
| 198 | 223 | if( g.urlIsFile ){ |
| 199 | 224 | Blob cfile; |
| 200 | 225 | dehttpize(zFile); |
| 201 | 226 | file_canonical_name(zFile, &cfile, 0); |
| 202 | 227 | free(zFile); |
| @@ -203,23 +228,45 @@ | ||
| 203 | 228 | g.urlProtocol = "file"; |
| 204 | 229 | g.urlPath = ""; |
| 205 | 230 | g.urlName = mprintf("%b", &cfile); |
| 206 | 231 | g.urlCanonical = mprintf("file://%T", g.urlName); |
| 207 | 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 | + } | |
| 208 | 244 | } |
| 209 | 245 | } |
| 210 | 246 | |
| 211 | 247 | /* |
| 212 | 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 | |
| 213 | 254 | */ |
| 214 | 255 | void cmd_test_urlparser(void){ |
| 215 | 256 | int i; |
| 257 | + unsigned fg = 0; | |
| 216 | 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; | |
| 217 | 264 | if( g.argc!=3 && g.argc!=4 ){ |
| 218 | 265 | usage("URL"); |
| 219 | 266 | } |
| 220 | - url_parse(g.argv[2]); | |
| 267 | + url_parse(g.argv[2], fg); | |
| 221 | 268 | for(i=0; i<2; i++){ |
| 222 | 269 | fossil_print("g.urlIsFile = %d\n", g.urlIsFile); |
| 223 | 270 | fossil_print("g.urlIsHttps = %d\n", g.urlIsHttps); |
| 224 | 271 | fossil_print("g.urlIsSsh = %d\n", g.urlIsSsh); |
| 225 | 272 | fossil_print("g.urlProtocol = %s\n", g.urlProtocol); |
| @@ -230,10 +277,11 @@ | ||
| 230 | 277 | fossil_print("g.urlPath = %s\n", g.urlPath); |
| 231 | 278 | fossil_print("g.urlUser = %s\n", g.urlUser); |
| 232 | 279 | fossil_print("g.urlPasswd = %s\n", g.urlPasswd); |
| 233 | 280 | fossil_print("g.urlCanonical = %s\n", g.urlCanonical); |
| 234 | 281 | fossil_print("g.urlFossil = %s\n", g.urlFossil); |
| 282 | + fossil_print("g.urlFlags = 0x%02x\n", g.urlFlags); | |
| 235 | 283 | if( g.urlIsFile || g.urlIsSsh ) break; |
| 236 | 284 | if( i==0 ){ |
| 237 | 285 | fossil_print("********\n"); |
| 238 | 286 | url_enable_proxy("Using proxy: "); |
| 239 | 287 | } |
| @@ -282,13 +330,14 @@ | ||
| 282 | 330 | if( zProxy && zProxy[0] && !is_false(zProxy) ){ |
| 283 | 331 | char *zOriginalUrl = g.urlCanonical; |
| 284 | 332 | char *zOriginalHost = g.urlHostname; |
| 285 | 333 | char *zOriginalUser = g.urlUser; |
| 286 | 334 | char *zOriginalPasswd = g.urlPasswd; |
| 335 | + unsigned uOriginalFlags = g.urlFlags; | |
| 287 | 336 | g.urlUser = 0; |
| 288 | 337 | g.urlPasswd = ""; |
| 289 | - url_parse(zProxy); | |
| 338 | + url_parse(zProxy, 0); | |
| 290 | 339 | if( zMsg ) fossil_print("%s%s\n", zMsg, g.urlCanonical); |
| 291 | 340 | g.urlPath = zOriginalUrl; |
| 292 | 341 | g.urlHostname = zOriginalHost; |
| 293 | 342 | if( g.urlUser ){ |
| 294 | 343 | char *zCredentials1 = mprintf("%s:%s", g.urlUser, g.urlPasswd); |
| @@ -296,10 +345,11 @@ | ||
| 296 | 345 | g.urlProxyAuth = mprintf("Basic %z", zCredentials2); |
| 297 | 346 | free(zCredentials1); |
| 298 | 347 | } |
| 299 | 348 | g.urlUser = zOriginalUser; |
| 300 | 349 | g.urlPasswd = zOriginalPasswd; |
| 350 | + g.urlFlags = uOriginalFlags; | |
| 301 | 351 | } |
| 302 | 352 | } |
| 303 | 353 | |
| 304 | 354 | #if INTERFACE |
| 305 | 355 | /* |
| @@ -379,22 +429,53 @@ | ||
| 379 | 429 | /* |
| 380 | 430 | ** Prompt the user for the password for g.urlUser. Store the result |
| 381 | 431 | ** in g.urlPasswd. |
| 382 | 432 | */ |
| 383 | 433 | 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 | + ){ | |
| 385 | 439 | char *zPrompt = mprintf("\rpassword for %s: ", g.urlUser); |
| 386 | 440 | Blob x; |
| 441 | + fossil_force_newline(); | |
| 387 | 442 | prompt_for_password(zPrompt, &x, 0); |
| 388 | 443 | free(zPrompt); |
| 389 | 444 | g.urlPasswd = mprintf("%b", &x); |
| 390 | 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 | + } | |
| 391 | 461 | }else{ |
| 392 | 462 | fossil_fatal("missing or incorrect password for user \"%s\"", |
| 393 | 463 | g.urlUser); |
| 394 | 464 | } |
| 395 | 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 | +} | |
| 396 | 477 | |
| 397 | 478 | /* Preemptively prompt for a password if a username is given in the |
| 398 | 479 | ** URL but no password. |
| 399 | 480 | */ |
| 400 | 481 | void url_get_password_if_needed(void){ |
| 401 | 482 |
| --- 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 @@ | ||
| 314 | 314 | ** (7) Check if the user can be extracted from the remote URL. |
| 315 | 315 | ** |
| 316 | 316 | ** The user name is stored in g.zLogin. The uid is in g.userUid. |
| 317 | 317 | */ |
| 318 | 318 | void user_select(void){ |
| 319 | - char *zUrl; | |
| 320 | - | |
| 321 | 319 | if( g.userUid ) return; |
| 322 | 320 | if( g.zLogin ){ |
| 323 | 321 | if( attempt_user(g.zLogin)==0 ){ |
| 324 | 322 | fossil_fatal("no such user: %s", g.zLogin); |
| 325 | 323 | }else{ |
| @@ -335,15 +333,12 @@ | ||
| 335 | 333 | |
| 336 | 334 | if( attempt_user(fossil_getenv("USER")) ) return; |
| 337 | 335 | |
| 338 | 336 | if( attempt_user(fossil_getenv("USERNAME")) ) return; |
| 339 | 337 | |
| 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; | |
| 345 | 340 | |
| 346 | 341 | fossil_print( |
| 347 | 342 | "Cannot figure out who you are! Consider using the --user\n" |
| 348 | 343 | "command line option, setting your USER environment variable,\n" |
| 349 | 344 | "or setting a default user with \"fossil user default USER\".\n" |
| 350 | 345 |
| --- 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 @@ | ||
| 23 | 23 | #include "utf8.h" |
| 24 | 24 | #include <sqlite3.h> |
| 25 | 25 | #ifdef _WIN32 |
| 26 | 26 | # include <windows.h> |
| 27 | 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 | |
| 28 | 36 | |
| 37 | +#ifdef _WIN32 | |
| 29 | 38 | /* |
| 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. | |
| 31 | 40 | ** Call fossil_mbcs_free() to deallocate any memory used to store the |
| 32 | 41 | ** returned pointer when done. |
| 33 | 42 | */ |
| 34 | 43 | char *fossil_mbcs_to_utf8(const char *zMbcs){ |
| 35 | -#ifdef _WIN32 | |
| 36 | 44 | extern char *sqlite3_win32_mbcs_to_utf8(const char*); |
| 37 | 45 | return sqlite3_win32_mbcs_to_utf8(zMbcs); |
| 38 | -#else | |
| 39 | - return (char*)zMbcs; /* No-op on unix */ | |
| 40 | -#endif | |
| 41 | 46 | } |
| 42 | 47 | |
| 43 | 48 | /* |
| 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 | |
| 45 | 50 | ** any memory used to hold the translation |
| 46 | 51 | */ |
| 47 | 52 | void fossil_mbcs_free(char *zOld){ |
| 48 | -#ifdef _WIN32 | |
| 49 | 53 | sqlite3_free(zOld); |
| 50 | -#else | |
| 51 | - /* No-op on unix */ | |
| 52 | -#endif | |
| 53 | 54 | } |
| 55 | +#endif /* _WIN32 */ | |
| 54 | 56 | |
| 55 | 57 | /* |
| 56 | -** Translate Unicode text into UTF8. | |
| 58 | +** Translate Unicode text into UTF-8. | |
| 57 | 59 | ** Return a pointer to the translated text. |
| 58 | 60 | ** Call fossil_unicode_free() to deallocate any memory used to store the |
| 59 | 61 | ** returned pointer when done. |
| 60 | 62 | */ |
| 61 | 63 | char *fossil_unicode_to_utf8(const void *zUnicode){ |
| 62 | -#ifdef _WIN32 | |
| 64 | +#if defined(_WIN32) || defined(__CYGWIN__) | |
| 63 | 65 | int nByte = WideCharToMultiByte(CP_UTF8, 0, zUnicode, -1, 0, 0, 0, 0); |
| 64 | 66 | char *zUtf = sqlite3_malloc( nByte ); |
| 65 | 67 | if( zUtf==0 ){ |
| 66 | 68 | return 0; |
| 67 | 69 | } |
| 68 | 70 | WideCharToMultiByte(CP_UTF8, 0, zUnicode, -1, zUtf, nByte, 0, 0); |
| 69 | 71 | return zUtf; |
| 70 | 72 | #else |
| 71 | - return (char *)zUnicode; /* No-op on unix */ | |
| 73 | + return fossil_strdup(zUnicode); /* TODO: implement for unix */ | |
| 72 | 74 | #endif |
| 73 | 75 | } |
| 74 | 76 | |
| 75 | 77 | /* |
| 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 | |
| 77 | 79 | ** translated text.. Call fossil_unicode_free() to deallocate any memory |
| 78 | 80 | ** used to store the returned pointer when done. |
| 79 | 81 | */ |
| 80 | 82 | void *fossil_utf8_to_unicode(const char *zUtf8){ |
| 81 | -#ifdef _WIN32 | |
| 83 | +#if defined(_WIN32) || defined(__CYGWIN__) | |
| 82 | 84 | int nByte = MultiByteToWideChar(CP_UTF8, 0, zUtf8, -1, 0, 0); |
| 83 | 85 | wchar_t *zUnicode = sqlite3_malloc( nByte * 2 ); |
| 84 | 86 | if( zUnicode==0 ){ |
| 85 | 87 | return 0; |
| 86 | 88 | } |
| 87 | 89 | MultiByteToWideChar(CP_UTF8, 0, zUtf8, -1, zUnicode, nByte); |
| 88 | 90 | return zUnicode; |
| 89 | 91 | #else |
| 90 | - return (void *)zUtf8; /* No-op on unix */ | |
| 92 | + return fossil_strdup(zUtf8); /* TODO: implement for unix */ | |
| 91 | 93 | #endif |
| 92 | 94 | } |
| 93 | 95 | |
| 94 | 96 | /* |
| 95 | 97 | ** Deallocate any memory that was previously allocated by |
| 96 | 98 | ** fossil_unicode_to_utf8(). |
| 97 | 99 | */ |
| 98 | 100 | void fossil_unicode_free(void *pOld){ |
| 99 | -#ifdef _WIN32 | |
| 101 | +#if defined(_WIN32) || defined(__CYGWIN__) | |
| 100 | 102 | sqlite3_free(pOld); |
| 101 | 103 | #else |
| 102 | - /* No-op on unix */ | |
| 104 | + fossil_free(pOld); | |
| 103 | 105 | #endif |
| 104 | 106 | } |
| 105 | 107 | |
| 106 | 108 | #if defined(__APPLE__) && !defined(WITHOUT_ICONV) |
| 107 | 109 | # include <iconv.h> |
| 108 | 110 | #endif |
| 109 | 111 | |
| 110 | 112 | /* |
| 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. | |
| 113 | 115 | ** Call fossil_filename_free() to deallocate any memory used to store the |
| 114 | 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(). | |
| 115 | 121 | */ |
| 116 | 122 | char *fossil_filename_to_utf8(const void *zFilename){ |
| 117 | 123 | #if defined(_WIN32) |
| 118 | 124 | int nByte = WideCharToMultiByte(CP_UTF8, 0, zFilename, -1, 0, 0, 0, 0); |
| 119 | 125 | char *zUtf = sqlite3_malloc( nByte ); |
| @@ -120,10 +126,14 @@ | ||
| 120 | 126 | if( zUtf==0 ){ |
| 121 | 127 | return 0; |
| 122 | 128 | } |
| 123 | 129 | WideCharToMultiByte(CP_UTF8, 0, zFilename, -1, zUtf, nByte, 0, 0); |
| 124 | 130 | return zUtf; |
| 131 | +#elif defined(__CYGWIN__) | |
| 132 | + char *zOut; | |
| 133 | + zOut = fossil_strdup(zFilename); | |
| 134 | + return zOut; | |
| 125 | 135 | #elif defined(__APPLE__) && !defined(WITHOUT_ICONV) |
| 126 | 136 | char *zIn = (char*)zFilename; |
| 127 | 137 | char *zOut; |
| 128 | 138 | iconv_t cd; |
| 129 | 139 | size_t n, x; |
| @@ -149,34 +159,91 @@ | ||
| 149 | 159 | return zOut; |
| 150 | 160 | #else |
| 151 | 161 | return (char *)zFilename; /* No-op on non-mac unix */ |
| 152 | 162 | #endif |
| 153 | 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 | +} | |
| 154 | 221 | |
| 155 | 222 | /* |
| 156 | 223 | ** Deallocate any memory that was previously allocated by |
| 157 | -** fossil_filename_to_utf8(). | |
| 224 | +** fossil_filename_to_utf8() or fossil_utf8_to_filename(). | |
| 158 | 225 | */ |
| 159 | -void fossil_filename_free(char *pOld){ | |
| 226 | +void fossil_filename_free(void *pOld){ | |
| 160 | 227 | #if defined(_WIN32) |
| 161 | 228 | sqlite3_free(pOld); |
| 162 | -#elif defined(__APPLE__) && !defined(WITHOUT_ICONV) | |
| 229 | +#elif (defined(__APPLE__) && !defined(WITHOUT_ICONV)) || defined(__CYGWIN__) | |
| 163 | 230 | fossil_free(pOld); |
| 164 | 231 | #else |
| 165 | 232 | /* No-op on all other unix */ |
| 166 | 233 | #endif |
| 167 | 234 | } |
| 168 | 235 | |
| 169 | 236 | /* |
| 170 | -** Display UTF8 on the console. Return the number of | |
| 237 | +** Display UTF-8 on the console. Return the number of | |
| 171 | 238 | ** Characters written. If stdout or stderr is redirected |
| 172 | 239 | ** to a file, -1 is returned and nothing is written |
| 173 | 240 | ** to the console. |
| 174 | 241 | */ |
| 175 | 242 | int fossil_utf8_to_console(const char *zUtf8, int nByte, int toStdErr){ |
| 176 | 243 | #ifdef _WIN32 |
| 177 | - int nChar; | |
| 244 | + int nChar, written = 0; | |
| 178 | 245 | wchar_t *zUnicode; /* Unicode version of zUtf8 */ |
| 179 | 246 | DWORD dummy; |
| 180 | 247 | |
| 181 | 248 | static int istty[2] = { -1, -1 }; |
| 182 | 249 | if( istty[toStdErr] == -1 ){ |
| @@ -191,17 +258,20 @@ | ||
| 191 | 258 | zUnicode = malloc( (nChar + 1) *sizeof(zUnicode[0]) ); |
| 192 | 259 | if( zUnicode==0 ){ |
| 193 | 260 | return 0; |
| 194 | 261 | } |
| 195 | 262 | 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; | |
| 199 | 271 | } |
| 200 | - zUnicode[nChar] = '\0'; | |
| 201 | - WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE - toStdErr), zUnicode, nChar, | |
| 202 | - &dummy, 0); | |
| 272 | + free(zUnicode); | |
| 203 | 273 | return nChar; |
| 204 | 274 | #else |
| 205 | 275 | return -1; /* No-op on unix */ |
| 206 | 276 | #endif |
| 207 | 277 | } |
| 208 | 278 | |
| 209 | 279 | 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 @@ | ||
| 459 | 459 | ); |
| 460 | 460 | } |
| 461 | 461 | depth++; |
| 462 | 462 | |
| 463 | 463 | zDir = blob_str(pPath); |
| 464 | - zNative = fossil_utf8_to_unicode(zDir); | |
| 464 | + zNative = fossil_utf8_to_filename(zDir); | |
| 465 | 465 | d = opendir(zNative); |
| 466 | 466 | if( d ){ |
| 467 | 467 | while( (pEntry=readdir(d))!=0 ){ |
| 468 | 468 | char *zPath; |
| 469 | 469 | char *zUtf8; |
| @@ -491,11 +491,11 @@ | ||
| 491 | 491 | fossil_filename_free(zUtf8); |
| 492 | 492 | blob_resize(pPath, origSize); |
| 493 | 493 | } |
| 494 | 494 | closedir(d); |
| 495 | 495 | } |
| 496 | - fossil_unicode_free(zNative); | |
| 496 | + fossil_filename_free(zNative); | |
| 497 | 497 | |
| 498 | 498 | depth--; |
| 499 | 499 | if( depth==0 ){ |
| 500 | 500 | db_finalize(&ins); |
| 501 | 501 | } |
| 502 | 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_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 @@ | ||
| 139 | 139 | int mnPort, int mxPort, /* Range of allowed TCP port numbers */ |
| 140 | 140 | const char *zBrowser, /* Command to launch browser. (Or NULL) */ |
| 141 | 141 | const char *zStopper, /* Stop server when this file is exists (Or NULL) */ |
| 142 | 142 | const char *zNotFound, /* The --notfound option, or NULL */ |
| 143 | 143 | const char *zFileGlob, /* The --fileglob option, or NULL */ |
| 144 | + const char *zIpAddr, /* Bind to this IP address, if not NULL */ | |
| 144 | 145 | int flags /* One or more HTTP_SERVER_ flags */ |
| 145 | 146 | ){ |
| 146 | 147 | WSADATA wd; |
| 147 | 148 | SOCKET s = INVALID_SOCKET; |
| 148 | 149 | SOCKADDR_IN addr; |
| 149 | 150 | int idCnt = 0; |
| 150 | 151 | int iPort = mnPort; |
| 151 | 152 | Blob options; |
| 152 | - WCHAR zTmpPath[MAX_PATH]; | |
| 153 | + wchar_t zTmpPath[MAX_PATH]; | |
| 153 | 154 | |
| 154 | 155 | if( zStopper ) file_delete(zStopper); |
| 155 | 156 | blob_zero(&options); |
| 156 | 157 | if( zNotFound ){ |
| 157 | 158 | blob_appendf(&options, " --notfound %s", zNotFound); |
| @@ -170,11 +171,16 @@ | ||
| 170 | 171 | if( s==INVALID_SOCKET ){ |
| 171 | 172 | fossil_fatal("unable to create a socket"); |
| 172 | 173 | } |
| 173 | 174 | addr.sin_family = AF_INET; |
| 174 | 175 | 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 ){ | |
| 176 | 182 | addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); |
| 177 | 183 | }else{ |
| 178 | 184 | addr.sin_addr.s_addr = htonl(INADDR_ANY); |
| 179 | 185 | } |
| 180 | 186 | if( bind(s, (struct sockaddr*)&addr, sizeof(addr))==SOCKET_ERROR ){ |
| @@ -198,11 +204,12 @@ | ||
| 198 | 204 | } |
| 199 | 205 | } |
| 200 | 206 | if( !GetTempPathW(MAX_PATH, zTmpPath) ){ |
| 201 | 207 | fossil_fatal("unable to get path to the temporary directory."); |
| 202 | 208 | } |
| 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); | |
| 204 | 211 | fossil_print("Listening for HTTP requests on TCP port %d\n", iPort); |
| 205 | 212 | if( zBrowser ){ |
| 206 | 213 | zBrowser = mprintf(zBrowser, iPort); |
| 207 | 214 | fossil_print("Launch webbrowser: %s\n", zBrowser); |
| 208 | 215 | fossil_system(zBrowser); |
| @@ -254,11 +261,11 @@ | ||
| 254 | 261 | int port; /* Port on which the http server should run */ |
| 255 | 262 | const char *zNotFound; /* The --notfound option, or NULL */ |
| 256 | 263 | const char *zFileGlob; /* The --files option, or NULL */ |
| 257 | 264 | int flags; /* One or more HTTP_SERVER_ flags */ |
| 258 | 265 | 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 */ | |
| 260 | 267 | SOCKET s; /* Socket on which the http server listens */ |
| 261 | 268 | }; |
| 262 | 269 | |
| 263 | 270 | /* |
| 264 | 271 | ** Variables used for running as windows service. |
| @@ -402,11 +409,11 @@ | ||
| 402 | 409 | ssStatus.dwServiceSpecificExitCode = 0; |
| 403 | 410 | win32_report_service_status(SERVICE_START_PENDING, NO_ERROR, 3000); |
| 404 | 411 | |
| 405 | 412 | /* Execute the http server */ |
| 406 | 413 | win32_http_server(hsData.port, hsData.port, |
| 407 | - NULL, NULL, hsData.zNotFound, hsData.zFileGlob, | |
| 414 | + NULL, NULL, hsData.zNotFound, hsData.zFileGlob, 0, | |
| 408 | 415 | hsData.flags); |
| 409 | 416 | |
| 410 | 417 | /* Service has stopped now. */ |
| 411 | 418 | win32_report_service_status(SERVICE_STOPPED, NO_ERROR, 0); |
| 412 | 419 | return; |
| 413 | 420 |
| --- 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 @@ | ||
| 1708 | 1708 | defossilize(zMsg); |
| 1709 | 1709 | if( (syncFlags & SYNC_PUSH) && zMsg && strglob("pull only *", zMsg) ){ |
| 1710 | 1710 | syncFlags &= ~SYNC_PUSH; |
| 1711 | 1711 | zMsg = 0; |
| 1712 | 1712 | } |
| 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 | + } | |
| 1715 | 1717 | }else |
| 1716 | 1718 | |
| 1717 | 1719 | /* pragma NAME VALUE... |
| 1718 | 1720 | ** |
| 1719 | 1721 | ** The server can send pragmas to try to convey meta-information to |
| @@ -1736,20 +1738,22 @@ | ||
| 1736 | 1738 | */ |
| 1737 | 1739 | if( blob_eq(&xfer.aToken[0],"error") && xfer.nToken==2 ){ |
| 1738 | 1740 | if( (syncFlags & SYNC_CLONE)==0 || nCycle>0 ){ |
| 1739 | 1741 | char *zMsg = blob_terminate(&xfer.aToken[1]); |
| 1740 | 1742 | defossilize(zMsg); |
| 1743 | + fossil_force_newline(); | |
| 1744 | + fossil_print("Error: %s\n", zMsg); | |
| 1741 | 1745 | if( fossil_strcmp(zMsg, "login failed")==0 ){ |
| 1742 | 1746 | if( nCycle<2 ){ |
| 1743 | - if( !g.dontKeepUrl ) db_unset("last-sync-pw", 0); | |
| 1747 | + g.urlPasswd = 0; | |
| 1744 | 1748 | go = 1; |
| 1749 | + if( g.cgiOutput==0 ) url_prompt_for_password(); | |
| 1745 | 1750 | } |
| 1746 | 1751 | }else{ |
| 1747 | - blob_appendf(&xfer.err, "\rserver says: %s", zMsg); | |
| 1752 | + blob_appendf(&xfer.err, "server says: %s\n", zMsg); | |
| 1753 | + nErr++; | |
| 1748 | 1754 | } |
| 1749 | - fossil_warning("\rError: %s", zMsg); | |
| 1750 | - nErr++; | |
| 1751 | 1755 | break; |
| 1752 | 1756 | } |
| 1753 | 1757 | }else |
| 1754 | 1758 | |
| 1755 | 1759 | /* Unknown message */ |
| @@ -1760,14 +1764,15 @@ | ||
| 1760 | 1764 | &recv |
| 1761 | 1765 | ); |
| 1762 | 1766 | nErr++; |
| 1763 | 1767 | break; |
| 1764 | 1768 | } |
| 1765 | - blob_appendf(&xfer.err, "unknown command: [%b]", &xfer.aToken[0]); | |
| 1769 | + blob_appendf(&xfer.err, "unknown command: [%b]\n", &xfer.aToken[0]); | |
| 1766 | 1770 | } |
| 1767 | 1771 | |
| 1768 | 1772 | if( blob_size(&xfer.err) ){ |
| 1773 | + fossil_force_newline(); | |
| 1769 | 1774 | fossil_warning("%b", &xfer.err); |
| 1770 | 1775 | nErr++; |
| 1771 | 1776 | break; |
| 1772 | 1777 | } |
| 1773 | 1778 | blobarray_reset(xfer.aToken, xfer.nToken); |
| 1774 | 1779 | |
| 1775 | 1780 | ADDED test/Greek-Lipsum-1.txt |
| 1776 | 1781 | 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 |
+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-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 | σαυσαε ινθερεσετ ηας αν. |
+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 @@ | ||
| 33 | 33 | * <a href="../../../fdiff?v1=21f9a00fe2fa4a17&v2=d5c4ff0532bd89c3#chunk5" |
| 34 | 34 | target="testwindow">sqlite3.c changes</a> |
| 35 | 35 | that are difficult to align. |
| 36 | 36 | * <a href="../../../fdiff?v2=21f9a00fe2fa4a17&v1=d5c4ff0532bd89c3#chunk5" |
| 37 | 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> | |
| 38 | 42 | |
| 39 | 43 | External: |
| 40 | 44 | |
| 41 | 45 | * <a href="http://www.sqlite.org/src/fdiff?v1=aafcb21a74e41f9a&v2=a6d127dd05daf0f9#chunk3" target="testwindow"> |
| 42 | 46 | Code indentation change.</a> |
| 43 | 47 | |
| 44 | 48 | 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 |
+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 |
| --- 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 |
+8
| --- test/th1-tcl.test | ||
| +++ test/th1-tcl.test | ||
| @@ -17,10 +17,18 @@ | ||
| 17 | 17 | # |
| 18 | 18 | # TH1/Tcl integration |
| 19 | 19 | # |
| 20 | 20 | |
| 21 | 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 | +} | |
| 22 | 30 | |
| 23 | 31 | ############################################################################### |
| 24 | 32 | |
| 25 | 33 | set env(TH1_ENABLE_TCL) 1; # Tcl integration must be enabled for this test. |
| 26 | 34 | |
| 27 | 35 | |
| 28 | 36 | 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 |
+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 |
| --- 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 @@ | ||
| 26 | 26 | TCC = $(DMDIR)\bin\dmc $(CFLAGS) $(DMCDEF) $(SSL) $(INCL) |
| 27 | 27 | LIBS = $(DMDIR)\extra\lib\ zlib wsock32 advapi32 |
| 28 | 28 | |
| 29 | 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 | 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 | |
| 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 | 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 | |
| 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 | 34 | |
| 35 | 35 | |
| 36 | 36 | RC=$(DMDIR)\bin\rcc |
| 37 | 37 | RCFLAGS=-32 -w1 -I$(SRCDIR) /D__DMC__ |
| 38 | 38 | |
| @@ -46,11 +46,11 @@ | ||
| 46 | 46 | |
| 47 | 47 | $(OBJDIR)\fossil.res: $B\win\fossil.rc |
| 48 | 48 | $(RC) $(RCFLAGS) -o$@ $** |
| 49 | 49 | |
| 50 | 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 > $@ | |
| 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 | 52 | +echo fossil >> $@ |
| 53 | 53 | +echo fossil >> $@ |
| 54 | 54 | +echo $(LIBS) >> $@ |
| 55 | 55 | +echo. >> $@ |
| 56 | 56 | +echo fossil >> $@ |
| @@ -103,10 +103,11 @@ | ||
| 103 | 103 | $(OBJDIR)\json_dir$O : $(SRCDIR)\json_detail.h |
| 104 | 104 | $(OBJDIR)\json_finfo$O : $(SRCDIR)\json_detail.h |
| 105 | 105 | $(OBJDIR)\json_login$O : $(SRCDIR)\json_detail.h |
| 106 | 106 | $(OBJDIR)\json_query$O : $(SRCDIR)\json_detail.h |
| 107 | 107 | $(OBJDIR)\json_report$O : $(SRCDIR)\json_detail.h |
| 108 | +$(OBJDIR)\json_status$O : $(SRCDIR)\json_detail.h | |
| 108 | 109 | $(OBJDIR)\json_tag$O : $(SRCDIR)\json_detail.h |
| 109 | 110 | $(OBJDIR)\json_timeline$O : $(SRCDIR)\json_detail.h |
| 110 | 111 | $(OBJDIR)\json_user$O : $(SRCDIR)\json_detail.h |
| 111 | 112 | $(OBJDIR)\json_wiki$O : $(SRCDIR)\json_detail.h |
| 112 | 113 | |
| @@ -397,10 +398,16 @@ | ||
| 397 | 398 | $(OBJDIR)\json_report$O : json_report_.c json_report.h |
| 398 | 399 | $(TCC) -o$@ -c json_report_.c |
| 399 | 400 | |
| 400 | 401 | json_report_.c : $(SRCDIR)\json_report.c |
| 401 | 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 $** > $@ | |
| 402 | 409 | |
| 403 | 410 | $(OBJDIR)\json_tag$O : json_tag_.c json_tag.h |
| 404 | 411 | $(TCC) -o$@ -c json_tag_.c |
| 405 | 412 | |
| 406 | 413 | json_tag_.c : $(SRCDIR)\json_tag.c |
| @@ -679,10 +686,16 @@ | ||
| 679 | 686 | $(OBJDIR)\utf8$O : utf8_.c utf8.h |
| 680 | 687 | $(TCC) -o$@ -c utf8_.c |
| 681 | 688 | |
| 682 | 689 | utf8_.c : $(SRCDIR)\utf8.c |
| 683 | 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 $** > $@ | |
| 684 | 697 | |
| 685 | 698 | $(OBJDIR)\verify$O : verify_.c verify.h |
| 686 | 699 | $(TCC) -o$@ -c verify_.c |
| 687 | 700 | |
| 688 | 701 | verify_.c : $(SRCDIR)\verify.c |
| @@ -735,7 +748,7 @@ | ||
| 735 | 748 | |
| 736 | 749 | zip_.c : $(SRCDIR)\zip.c |
| 737 | 750 | +translate$E $** > $@ |
| 738 | 751 | |
| 739 | 752 | 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 | |
| 741 | 754 | @copy /Y nul: headers |
| 742 | 755 |
| --- win/Makefile.dmc | |
| +++ win/Makefile.dmc | |
| @@ -26,13 +26,13 @@ | |
| 26 | TCC = $(DMDIR)\bin\dmc $(CFLAGS) $(DMCDEF) $(SSL) $(INCL) |
| 27 | LIBS = $(DMDIR)\extra\lib\ zlib wsock32 advapi32 |
| 28 | |
| 29 | SQLITE_OPTIONS = -DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_STAT3 -Dlocaltime=fossil_localtime -DSQLITE_ENABLE_LOCKING_STYLE=0 |
| 30 | |
| 31 | SRC = add_.c allrepo_.c attach_.c bag_.c bisect_.c blob_.c branch_.c browse_.c captcha_.c cgi_.c checkin_.c checkout_.c clearsign_.c clone_.c comformat_.c configure_.c content_.c db_.c delta_.c deltacmd_.c descendants_.c diff_.c diffcmd_.c doc_.c encode_.c event_.c export_.c file_.c finfo_.c glob_.c graph_.c gzip_.c http_.c http_socket_.c http_ssl_.c http_transport_.c import_.c info_.c json_.c json_artifact_.c json_branch_.c json_config_.c json_diff_.c json_dir_.c json_finfo_.c json_login_.c json_query_.c json_report_.c json_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 |
+27
-3
| --- win/Makefile.mingw | ||
| +++ win/Makefile.mingw | ||
| @@ -84,12 +84,12 @@ | ||
| 84 | 84 | #### The directories where the OpenSSL include and library files are located. |
| 85 | 85 | # The recommended usage here is to use the Sysinternals junction tool |
| 86 | 86 | # to create a hard link between an "openssl-1.x" sub-directory of the |
| 87 | 87 | # Fossil source code directory and the target OpenSSL source directory. |
| 88 | 88 | # |
| 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 | |
| 91 | 91 | |
| 92 | 92 | #### Either the directory where the Tcl library is installed or the Tcl |
| 93 | 93 | # source code directory resides (depending on the value of the macro |
| 94 | 94 | # FOSSIL_TCL_SOURCE). If this points to the Tcl install directory, |
| 95 | 95 | # this directory must have "include" and "lib" sub-directories. If |
| @@ -301,10 +301,11 @@ | ||
| 301 | 301 | $(SRCDIR)/json_dir.c \ |
| 302 | 302 | $(SRCDIR)/json_finfo.c \ |
| 303 | 303 | $(SRCDIR)/json_login.c \ |
| 304 | 304 | $(SRCDIR)/json_query.c \ |
| 305 | 305 | $(SRCDIR)/json_report.c \ |
| 306 | + $(SRCDIR)/json_status.c \ | |
| 306 | 307 | $(SRCDIR)/json_tag.c \ |
| 307 | 308 | $(SRCDIR)/json_timeline.c \ |
| 308 | 309 | $(SRCDIR)/json_user.c \ |
| 309 | 310 | $(SRCDIR)/json_wiki.c \ |
| 310 | 311 | $(SRCDIR)/leaf.c \ |
| @@ -348,10 +349,11 @@ | ||
| 348 | 349 | $(SRCDIR)/unicode.c \ |
| 349 | 350 | $(SRCDIR)/update.c \ |
| 350 | 351 | $(SRCDIR)/url.c \ |
| 351 | 352 | $(SRCDIR)/user.c \ |
| 352 | 353 | $(SRCDIR)/utf8.c \ |
| 354 | + $(SRCDIR)/util.c \ | |
| 353 | 355 | $(SRCDIR)/verify.c \ |
| 354 | 356 | $(SRCDIR)/vfile.c \ |
| 355 | 357 | $(SRCDIR)/wiki.c \ |
| 356 | 358 | $(SRCDIR)/wikiformat.c \ |
| 357 | 359 | $(SRCDIR)/winhttp.c \ |
| @@ -407,10 +409,11 @@ | ||
| 407 | 409 | $(OBJDIR)/json_dir_.c \ |
| 408 | 410 | $(OBJDIR)/json_finfo_.c \ |
| 409 | 411 | $(OBJDIR)/json_login_.c \ |
| 410 | 412 | $(OBJDIR)/json_query_.c \ |
| 411 | 413 | $(OBJDIR)/json_report_.c \ |
| 414 | + $(OBJDIR)/json_status_.c \ | |
| 412 | 415 | $(OBJDIR)/json_tag_.c \ |
| 413 | 416 | $(OBJDIR)/json_timeline_.c \ |
| 414 | 417 | $(OBJDIR)/json_user_.c \ |
| 415 | 418 | $(OBJDIR)/json_wiki_.c \ |
| 416 | 419 | $(OBJDIR)/leaf_.c \ |
| @@ -454,10 +457,11 @@ | ||
| 454 | 457 | $(OBJDIR)/unicode_.c \ |
| 455 | 458 | $(OBJDIR)/update_.c \ |
| 456 | 459 | $(OBJDIR)/url_.c \ |
| 457 | 460 | $(OBJDIR)/user_.c \ |
| 458 | 461 | $(OBJDIR)/utf8_.c \ |
| 462 | + $(OBJDIR)/util_.c \ | |
| 459 | 463 | $(OBJDIR)/verify_.c \ |
| 460 | 464 | $(OBJDIR)/vfile_.c \ |
| 461 | 465 | $(OBJDIR)/wiki_.c \ |
| 462 | 466 | $(OBJDIR)/wikiformat_.c \ |
| 463 | 467 | $(OBJDIR)/winhttp_.c \ |
| @@ -513,10 +517,11 @@ | ||
| 513 | 517 | $(OBJDIR)/json_dir.o \ |
| 514 | 518 | $(OBJDIR)/json_finfo.o \ |
| 515 | 519 | $(OBJDIR)/json_login.o \ |
| 516 | 520 | $(OBJDIR)/json_query.o \ |
| 517 | 521 | $(OBJDIR)/json_report.o \ |
| 522 | + $(OBJDIR)/json_status.o \ | |
| 518 | 523 | $(OBJDIR)/json_tag.o \ |
| 519 | 524 | $(OBJDIR)/json_timeline.o \ |
| 520 | 525 | $(OBJDIR)/json_user.o \ |
| 521 | 526 | $(OBJDIR)/json_wiki.o \ |
| 522 | 527 | $(OBJDIR)/leaf.o \ |
| @@ -560,10 +565,11 @@ | ||
| 560 | 565 | $(OBJDIR)/unicode.o \ |
| 561 | 566 | $(OBJDIR)/update.o \ |
| 562 | 567 | $(OBJDIR)/url.o \ |
| 563 | 568 | $(OBJDIR)/user.o \ |
| 564 | 569 | $(OBJDIR)/utf8.o \ |
| 570 | + $(OBJDIR)/util.o \ | |
| 565 | 571 | $(OBJDIR)/verify.o \ |
| 566 | 572 | $(OBJDIR)/vfile.o \ |
| 567 | 573 | $(OBJDIR)/wiki.o \ |
| 568 | 574 | $(OBJDIR)/wikiformat.o \ |
| 569 | 575 | $(OBJDIR)/winhttp.o \ |
| @@ -732,10 +738,11 @@ | ||
| 732 | 738 | $(OBJDIR)/json_dir_.c:$(OBJDIR)/json_dir.h \ |
| 733 | 739 | $(OBJDIR)/json_finfo_.c:$(OBJDIR)/json_finfo.h \ |
| 734 | 740 | $(OBJDIR)/json_login_.c:$(OBJDIR)/json_login.h \ |
| 735 | 741 | $(OBJDIR)/json_query_.c:$(OBJDIR)/json_query.h \ |
| 736 | 742 | $(OBJDIR)/json_report_.c:$(OBJDIR)/json_report.h \ |
| 743 | + $(OBJDIR)/json_status_.c:$(OBJDIR)/json_status.h \ | |
| 737 | 744 | $(OBJDIR)/json_tag_.c:$(OBJDIR)/json_tag.h \ |
| 738 | 745 | $(OBJDIR)/json_timeline_.c:$(OBJDIR)/json_timeline.h \ |
| 739 | 746 | $(OBJDIR)/json_user_.c:$(OBJDIR)/json_user.h \ |
| 740 | 747 | $(OBJDIR)/json_wiki_.c:$(OBJDIR)/json_wiki.h \ |
| 741 | 748 | $(OBJDIR)/leaf_.c:$(OBJDIR)/leaf.h \ |
| @@ -779,10 +786,11 @@ | ||
| 779 | 786 | $(OBJDIR)/unicode_.c:$(OBJDIR)/unicode.h \ |
| 780 | 787 | $(OBJDIR)/update_.c:$(OBJDIR)/update.h \ |
| 781 | 788 | $(OBJDIR)/url_.c:$(OBJDIR)/url.h \ |
| 782 | 789 | $(OBJDIR)/user_.c:$(OBJDIR)/user.h \ |
| 783 | 790 | $(OBJDIR)/utf8_.c:$(OBJDIR)/utf8.h \ |
| 791 | + $(OBJDIR)/util_.c:$(OBJDIR)/util.h \ | |
| 784 | 792 | $(OBJDIR)/verify_.c:$(OBJDIR)/verify.h \ |
| 785 | 793 | $(OBJDIR)/vfile_.c:$(OBJDIR)/vfile.h \ |
| 786 | 794 | $(OBJDIR)/wiki_.c:$(OBJDIR)/wiki.h \ |
| 787 | 795 | $(OBJDIR)/wikiformat_.c:$(OBJDIR)/wikiformat.h \ |
| 788 | 796 | $(OBJDIR)/winhttp_.c:$(OBJDIR)/winhttp.h \ |
| @@ -1180,10 +1188,18 @@ | ||
| 1180 | 1188 | |
| 1181 | 1189 | $(OBJDIR)/json_report.o: $(OBJDIR)/json_report_.c $(OBJDIR)/json_report.h $(SRCDIR)/config.h |
| 1182 | 1190 | $(XTCC) -o $(OBJDIR)/json_report.o -c $(OBJDIR)/json_report_.c |
| 1183 | 1191 | |
| 1184 | 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 | |
| 1185 | 1201 | |
| 1186 | 1202 | $(OBJDIR)/json_tag_.c: $(SRCDIR)/json_tag.c $(OBJDIR)/translate |
| 1187 | 1203 | $(TRANSLATE) $(SRCDIR)/json_tag.c >$(OBJDIR)/json_tag_.c |
| 1188 | 1204 | |
| 1189 | 1205 | $(OBJDIR)/json_tag.o: $(OBJDIR)/json_tag_.c $(OBJDIR)/json_tag.h $(SRCDIR)/config.h |
| @@ -1556,10 +1572,18 @@ | ||
| 1556 | 1572 | |
| 1557 | 1573 | $(OBJDIR)/utf8.o: $(OBJDIR)/utf8_.c $(OBJDIR)/utf8.h $(SRCDIR)/config.h |
| 1558 | 1574 | $(XTCC) -o $(OBJDIR)/utf8.o -c $(OBJDIR)/utf8_.c |
| 1559 | 1575 | |
| 1560 | 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 | |
| 1561 | 1585 | |
| 1562 | 1586 | $(OBJDIR)/verify_.c: $(SRCDIR)/verify.c $(OBJDIR)/translate |
| 1563 | 1587 | $(TRANSLATE) $(SRCDIR)/verify.c >$(OBJDIR)/verify_.c |
| 1564 | 1588 | |
| 1565 | 1589 | $(OBJDIR)/verify.o: $(OBJDIR)/verify_.c $(OBJDIR)/verify.h $(SRCDIR)/config.h |
| @@ -1635,11 +1659,11 @@ | ||
| 1635 | 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 |
| 1636 | 1660 | |
| 1637 | 1661 | $(OBJDIR)/cson_amalgamation.o: $(SRCDIR)/cson_amalgamation.c |
| 1638 | 1662 | $(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.o |
| 1639 | 1663 | |
| 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 | |
| 1641 | 1665 | |
| 1642 | 1666 | $(OBJDIR)/shell.o: $(SRCDIR)/shell.c $(SRCDIR)/sqlite3.h |
| 1643 | 1667 | $(XTCC) -Dmain=sqlite3_shell -DSQLITE_OMIT_LOAD_EXTENSION=1 -c $(SRCDIR)/shell.c -o $(OBJDIR)/shell.o |
| 1644 | 1668 | |
| 1645 | 1669 | $(OBJDIR)/th.o: $(SRCDIR)/th.c |
| 1646 | 1670 |
| --- 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 |
+27
-3
| --- win/Makefile.mingw.mistachkin | ||
| +++ win/Makefile.mingw.mistachkin | ||
| @@ -84,12 +84,12 @@ | ||
| 84 | 84 | #### The directories where the OpenSSL include and library files are located. |
| 85 | 85 | # The recommended usage here is to use the Sysinternals junction tool |
| 86 | 86 | # to create a hard link between an "openssl-1.x" sub-directory of the |
| 87 | 87 | # Fossil source code directory and the target OpenSSL source directory. |
| 88 | 88 | # |
| 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 | |
| 91 | 91 | |
| 92 | 92 | #### Either the directory where the Tcl library is installed or the Tcl |
| 93 | 93 | # source code directory resides (depending on the value of the macro |
| 94 | 94 | # FOSSIL_TCL_SOURCE). If this points to the Tcl install directory, |
| 95 | 95 | # this directory must have "include" and "lib" sub-directories. If |
| @@ -301,10 +301,11 @@ | ||
| 301 | 301 | $(SRCDIR)/json_dir.c \ |
| 302 | 302 | $(SRCDIR)/json_finfo.c \ |
| 303 | 303 | $(SRCDIR)/json_login.c \ |
| 304 | 304 | $(SRCDIR)/json_query.c \ |
| 305 | 305 | $(SRCDIR)/json_report.c \ |
| 306 | + $(SRCDIR)/json_status.c \ | |
| 306 | 307 | $(SRCDIR)/json_tag.c \ |
| 307 | 308 | $(SRCDIR)/json_timeline.c \ |
| 308 | 309 | $(SRCDIR)/json_user.c \ |
| 309 | 310 | $(SRCDIR)/json_wiki.c \ |
| 310 | 311 | $(SRCDIR)/leaf.c \ |
| @@ -348,10 +349,11 @@ | ||
| 348 | 349 | $(SRCDIR)/unicode.c \ |
| 349 | 350 | $(SRCDIR)/update.c \ |
| 350 | 351 | $(SRCDIR)/url.c \ |
| 351 | 352 | $(SRCDIR)/user.c \ |
| 352 | 353 | $(SRCDIR)/utf8.c \ |
| 354 | + $(SRCDIR)/util.c \ | |
| 353 | 355 | $(SRCDIR)/verify.c \ |
| 354 | 356 | $(SRCDIR)/vfile.c \ |
| 355 | 357 | $(SRCDIR)/wiki.c \ |
| 356 | 358 | $(SRCDIR)/wikiformat.c \ |
| 357 | 359 | $(SRCDIR)/winhttp.c \ |
| @@ -407,10 +409,11 @@ | ||
| 407 | 409 | $(OBJDIR)/json_dir_.c \ |
| 408 | 410 | $(OBJDIR)/json_finfo_.c \ |
| 409 | 411 | $(OBJDIR)/json_login_.c \ |
| 410 | 412 | $(OBJDIR)/json_query_.c \ |
| 411 | 413 | $(OBJDIR)/json_report_.c \ |
| 414 | + $(OBJDIR)/json_status_.c \ | |
| 412 | 415 | $(OBJDIR)/json_tag_.c \ |
| 413 | 416 | $(OBJDIR)/json_timeline_.c \ |
| 414 | 417 | $(OBJDIR)/json_user_.c \ |
| 415 | 418 | $(OBJDIR)/json_wiki_.c \ |
| 416 | 419 | $(OBJDIR)/leaf_.c \ |
| @@ -454,10 +457,11 @@ | ||
| 454 | 457 | $(OBJDIR)/unicode_.c \ |
| 455 | 458 | $(OBJDIR)/update_.c \ |
| 456 | 459 | $(OBJDIR)/url_.c \ |
| 457 | 460 | $(OBJDIR)/user_.c \ |
| 458 | 461 | $(OBJDIR)/utf8_.c \ |
| 462 | + $(OBJDIR)/util_.c \ | |
| 459 | 463 | $(OBJDIR)/verify_.c \ |
| 460 | 464 | $(OBJDIR)/vfile_.c \ |
| 461 | 465 | $(OBJDIR)/wiki_.c \ |
| 462 | 466 | $(OBJDIR)/wikiformat_.c \ |
| 463 | 467 | $(OBJDIR)/winhttp_.c \ |
| @@ -513,10 +517,11 @@ | ||
| 513 | 517 | $(OBJDIR)/json_dir.o \ |
| 514 | 518 | $(OBJDIR)/json_finfo.o \ |
| 515 | 519 | $(OBJDIR)/json_login.o \ |
| 516 | 520 | $(OBJDIR)/json_query.o \ |
| 517 | 521 | $(OBJDIR)/json_report.o \ |
| 522 | + $(OBJDIR)/json_status.o \ | |
| 518 | 523 | $(OBJDIR)/json_tag.o \ |
| 519 | 524 | $(OBJDIR)/json_timeline.o \ |
| 520 | 525 | $(OBJDIR)/json_user.o \ |
| 521 | 526 | $(OBJDIR)/json_wiki.o \ |
| 522 | 527 | $(OBJDIR)/leaf.o \ |
| @@ -560,10 +565,11 @@ | ||
| 560 | 565 | $(OBJDIR)/unicode.o \ |
| 561 | 566 | $(OBJDIR)/update.o \ |
| 562 | 567 | $(OBJDIR)/url.o \ |
| 563 | 568 | $(OBJDIR)/user.o \ |
| 564 | 569 | $(OBJDIR)/utf8.o \ |
| 570 | + $(OBJDIR)/util.o \ | |
| 565 | 571 | $(OBJDIR)/verify.o \ |
| 566 | 572 | $(OBJDIR)/vfile.o \ |
| 567 | 573 | $(OBJDIR)/wiki.o \ |
| 568 | 574 | $(OBJDIR)/wikiformat.o \ |
| 569 | 575 | $(OBJDIR)/winhttp.o \ |
| @@ -732,10 +738,11 @@ | ||
| 732 | 738 | $(OBJDIR)/json_dir_.c:$(OBJDIR)/json_dir.h \ |
| 733 | 739 | $(OBJDIR)/json_finfo_.c:$(OBJDIR)/json_finfo.h \ |
| 734 | 740 | $(OBJDIR)/json_login_.c:$(OBJDIR)/json_login.h \ |
| 735 | 741 | $(OBJDIR)/json_query_.c:$(OBJDIR)/json_query.h \ |
| 736 | 742 | $(OBJDIR)/json_report_.c:$(OBJDIR)/json_report.h \ |
| 743 | + $(OBJDIR)/json_status_.c:$(OBJDIR)/json_status.h \ | |
| 737 | 744 | $(OBJDIR)/json_tag_.c:$(OBJDIR)/json_tag.h \ |
| 738 | 745 | $(OBJDIR)/json_timeline_.c:$(OBJDIR)/json_timeline.h \ |
| 739 | 746 | $(OBJDIR)/json_user_.c:$(OBJDIR)/json_user.h \ |
| 740 | 747 | $(OBJDIR)/json_wiki_.c:$(OBJDIR)/json_wiki.h \ |
| 741 | 748 | $(OBJDIR)/leaf_.c:$(OBJDIR)/leaf.h \ |
| @@ -779,10 +786,11 @@ | ||
| 779 | 786 | $(OBJDIR)/unicode_.c:$(OBJDIR)/unicode.h \ |
| 780 | 787 | $(OBJDIR)/update_.c:$(OBJDIR)/update.h \ |
| 781 | 788 | $(OBJDIR)/url_.c:$(OBJDIR)/url.h \ |
| 782 | 789 | $(OBJDIR)/user_.c:$(OBJDIR)/user.h \ |
| 783 | 790 | $(OBJDIR)/utf8_.c:$(OBJDIR)/utf8.h \ |
| 791 | + $(OBJDIR)/util_.c:$(OBJDIR)/util.h \ | |
| 784 | 792 | $(OBJDIR)/verify_.c:$(OBJDIR)/verify.h \ |
| 785 | 793 | $(OBJDIR)/vfile_.c:$(OBJDIR)/vfile.h \ |
| 786 | 794 | $(OBJDIR)/wiki_.c:$(OBJDIR)/wiki.h \ |
| 787 | 795 | $(OBJDIR)/wikiformat_.c:$(OBJDIR)/wikiformat.h \ |
| 788 | 796 | $(OBJDIR)/winhttp_.c:$(OBJDIR)/winhttp.h \ |
| @@ -1180,10 +1188,18 @@ | ||
| 1180 | 1188 | |
| 1181 | 1189 | $(OBJDIR)/json_report.o: $(OBJDIR)/json_report_.c $(OBJDIR)/json_report.h $(SRCDIR)/config.h |
| 1182 | 1190 | $(XTCC) -o $(OBJDIR)/json_report.o -c $(OBJDIR)/json_report_.c |
| 1183 | 1191 | |
| 1184 | 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 | |
| 1185 | 1201 | |
| 1186 | 1202 | $(OBJDIR)/json_tag_.c: $(SRCDIR)/json_tag.c $(OBJDIR)/translate |
| 1187 | 1203 | $(TRANSLATE) $(SRCDIR)/json_tag.c >$(OBJDIR)/json_tag_.c |
| 1188 | 1204 | |
| 1189 | 1205 | $(OBJDIR)/json_tag.o: $(OBJDIR)/json_tag_.c $(OBJDIR)/json_tag.h $(SRCDIR)/config.h |
| @@ -1556,10 +1572,18 @@ | ||
| 1556 | 1572 | |
| 1557 | 1573 | $(OBJDIR)/utf8.o: $(OBJDIR)/utf8_.c $(OBJDIR)/utf8.h $(SRCDIR)/config.h |
| 1558 | 1574 | $(XTCC) -o $(OBJDIR)/utf8.o -c $(OBJDIR)/utf8_.c |
| 1559 | 1575 | |
| 1560 | 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 | |
| 1561 | 1585 | |
| 1562 | 1586 | $(OBJDIR)/verify_.c: $(SRCDIR)/verify.c $(OBJDIR)/translate |
| 1563 | 1587 | $(TRANSLATE) $(SRCDIR)/verify.c >$(OBJDIR)/verify_.c |
| 1564 | 1588 | |
| 1565 | 1589 | $(OBJDIR)/verify.o: $(OBJDIR)/verify_.c $(OBJDIR)/verify.h $(SRCDIR)/config.h |
| @@ -1635,11 +1659,11 @@ | ||
| 1635 | 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 |
| 1636 | 1660 | |
| 1637 | 1661 | $(OBJDIR)/cson_amalgamation.o: $(SRCDIR)/cson_amalgamation.c |
| 1638 | 1662 | $(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.o |
| 1639 | 1663 | |
| 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 | |
| 1641 | 1665 | |
| 1642 | 1666 | $(OBJDIR)/shell.o: $(SRCDIR)/shell.c $(SRCDIR)/sqlite3.h |
| 1643 | 1667 | $(XTCC) -Dmain=sqlite3_shell -DSQLITE_OMIT_LOAD_EXTENSION=1 -c $(SRCDIR)/shell.c -o $(OBJDIR)/shell.o |
| 1644 | 1668 | |
| 1645 | 1669 | $(OBJDIR)/th.o: $(SRCDIR)/th.c |
| 1646 | 1670 |
| --- 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 |
+21
| --- win/Makefile.msc | ||
| +++ win/Makefile.msc | ||
| @@ -103,10 +103,11 @@ | ||
| 103 | 103 | json_dir_.c \ |
| 104 | 104 | json_finfo_.c \ |
| 105 | 105 | json_login_.c \ |
| 106 | 106 | json_query_.c \ |
| 107 | 107 | json_report_.c \ |
| 108 | + json_status_.c \ | |
| 108 | 109 | json_tag_.c \ |
| 109 | 110 | json_timeline_.c \ |
| 110 | 111 | json_user_.c \ |
| 111 | 112 | json_wiki_.c \ |
| 112 | 113 | leaf_.c \ |
| @@ -150,10 +151,11 @@ | ||
| 150 | 151 | unicode_.c \ |
| 151 | 152 | update_.c \ |
| 152 | 153 | url_.c \ |
| 153 | 154 | user_.c \ |
| 154 | 155 | utf8_.c \ |
| 156 | + util_.c \ | |
| 155 | 157 | verify_.c \ |
| 156 | 158 | vfile_.c \ |
| 157 | 159 | wiki_.c \ |
| 158 | 160 | wikiformat_.c \ |
| 159 | 161 | winhttp_.c \ |
| @@ -209,10 +211,11 @@ | ||
| 209 | 211 | $(OX)\json_dir$O \ |
| 210 | 212 | $(OX)\json_finfo$O \ |
| 211 | 213 | $(OX)\json_login$O \ |
| 212 | 214 | $(OX)\json_query$O \ |
| 213 | 215 | $(OX)\json_report$O \ |
| 216 | + $(OX)\json_status$O \ | |
| 214 | 217 | $(OX)\json_tag$O \ |
| 215 | 218 | $(OX)\json_timeline$O \ |
| 216 | 219 | $(OX)\json_user$O \ |
| 217 | 220 | $(OX)\json_wiki$O \ |
| 218 | 221 | $(OX)\leaf$O \ |
| @@ -260,10 +263,11 @@ | ||
| 260 | 263 | $(OX)\unicode$O \ |
| 261 | 264 | $(OX)\update$O \ |
| 262 | 265 | $(OX)\url$O \ |
| 263 | 266 | $(OX)\user$O \ |
| 264 | 267 | $(OX)\utf8$O \ |
| 268 | + $(OX)\util$O \ | |
| 265 | 269 | $(OX)\verify$O \ |
| 266 | 270 | $(OX)\vfile$O \ |
| 267 | 271 | $(OX)\wiki$O \ |
| 268 | 272 | $(OX)\wikiformat$O \ |
| 269 | 273 | $(OX)\winhttp$O \ |
| @@ -333,10 +337,11 @@ | ||
| 333 | 337 | echo $(OX)\json_dir.obj >> $@ |
| 334 | 338 | echo $(OX)\json_finfo.obj >> $@ |
| 335 | 339 | echo $(OX)\json_login.obj >> $@ |
| 336 | 340 | echo $(OX)\json_query.obj >> $@ |
| 337 | 341 | echo $(OX)\json_report.obj >> $@ |
| 342 | + echo $(OX)\json_status.obj >> $@ | |
| 338 | 343 | echo $(OX)\json_tag.obj >> $@ |
| 339 | 344 | echo $(OX)\json_timeline.obj >> $@ |
| 340 | 345 | echo $(OX)\json_user.obj >> $@ |
| 341 | 346 | echo $(OX)\json_wiki.obj >> $@ |
| 342 | 347 | echo $(OX)\leaf.obj >> $@ |
| @@ -384,10 +389,11 @@ | ||
| 384 | 389 | echo $(OX)\unicode.obj >> $@ |
| 385 | 390 | echo $(OX)\update.obj >> $@ |
| 386 | 391 | echo $(OX)\url.obj >> $@ |
| 387 | 392 | echo $(OX)\user.obj >> $@ |
| 388 | 393 | echo $(OX)\utf8.obj >> $@ |
| 394 | + echo $(OX)\util.obj >> $@ | |
| 389 | 395 | echo $(OX)\verify.obj >> $@ |
| 390 | 396 | echo $(OX)\vfile.obj >> $@ |
| 391 | 397 | echo $(OX)\wiki.obj >> $@ |
| 392 | 398 | echo $(OX)\wikiformat.obj >> $@ |
| 393 | 399 | echo $(OX)\winhttp.obj >> $@ |
| @@ -461,10 +467,11 @@ | ||
| 461 | 467 | $(OBJDIR)\json_dir$O : $(SRCDIR)\json_detail.h |
| 462 | 468 | $(OBJDIR)\json_finfo$O : $(SRCDIR)\json_detail.h |
| 463 | 469 | $(OBJDIR)\json_login$O : $(SRCDIR)\json_detail.h |
| 464 | 470 | $(OBJDIR)\json_query$O : $(SRCDIR)\json_detail.h |
| 465 | 471 | $(OBJDIR)\json_report$O : $(SRCDIR)\json_detail.h |
| 472 | +$(OBJDIR)\json_status$O : $(SRCDIR)\json_detail.h | |
| 466 | 473 | $(OBJDIR)\json_tag$O : $(SRCDIR)\json_detail.h |
| 467 | 474 | $(OBJDIR)\json_timeline$O : $(SRCDIR)\json_detail.h |
| 468 | 475 | $(OBJDIR)\json_user$O : $(SRCDIR)\json_detail.h |
| 469 | 476 | $(OBJDIR)\json_wiki$O : $(SRCDIR)\json_detail.h |
| 470 | 477 | |
| @@ -754,10 +761,16 @@ | ||
| 754 | 761 | $(OX)\json_report$O : json_report_.c json_report.h |
| 755 | 762 | $(TCC) /Fo$@ -c json_report_.c |
| 756 | 763 | |
| 757 | 764 | json_report_.c : $(SRCDIR)\json_report.c |
| 758 | 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 $** > $@ | |
| 759 | 772 | |
| 760 | 773 | $(OX)\json_tag$O : json_tag_.c json_tag.h |
| 761 | 774 | $(TCC) /Fo$@ -c json_tag_.c |
| 762 | 775 | |
| 763 | 776 | json_tag_.c : $(SRCDIR)\json_tag.c |
| @@ -1036,10 +1049,16 @@ | ||
| 1036 | 1049 | $(OX)\utf8$O : utf8_.c utf8.h |
| 1037 | 1050 | $(TCC) /Fo$@ -c utf8_.c |
| 1038 | 1051 | |
| 1039 | 1052 | utf8_.c : $(SRCDIR)\utf8.c |
| 1040 | 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 $** > $@ | |
| 1041 | 1060 | |
| 1042 | 1061 | $(OX)\verify$O : verify_.c verify.h |
| 1043 | 1062 | $(TCC) /Fo$@ -c verify_.c |
| 1044 | 1063 | |
| 1045 | 1064 | verify_.c : $(SRCDIR)\verify.c |
| @@ -1142,10 +1161,11 @@ | ||
| 1142 | 1161 | json_dir_.c:json_dir.h \ |
| 1143 | 1162 | json_finfo_.c:json_finfo.h \ |
| 1144 | 1163 | json_login_.c:json_login.h \ |
| 1145 | 1164 | json_query_.c:json_query.h \ |
| 1146 | 1165 | json_report_.c:json_report.h \ |
| 1166 | + json_status_.c:json_status.h \ | |
| 1147 | 1167 | json_tag_.c:json_tag.h \ |
| 1148 | 1168 | json_timeline_.c:json_timeline.h \ |
| 1149 | 1169 | json_user_.c:json_user.h \ |
| 1150 | 1170 | json_wiki_.c:json_wiki.h \ |
| 1151 | 1171 | leaf_.c:leaf.h \ |
| @@ -1189,10 +1209,11 @@ | ||
| 1189 | 1209 | unicode_.c:unicode.h \ |
| 1190 | 1210 | update_.c:update.h \ |
| 1191 | 1211 | url_.c:url.h \ |
| 1192 | 1212 | user_.c:user.h \ |
| 1193 | 1213 | utf8_.c:utf8.h \ |
| 1214 | + util_.c:util.h \ | |
| 1194 | 1215 | verify_.c:verify.h \ |
| 1195 | 1216 | vfile_.c:vfile.h \ |
| 1196 | 1217 | wiki_.c:wiki.h \ |
| 1197 | 1218 | wikiformat_.c:wikiformat.h \ |
| 1198 | 1219 | winhttp_.c:winhttp.h \ |
| 1199 | 1220 |
| --- 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 @@ | ||
| 1 | 1 | <title>Change Log</title> |
| 2 | 2 | |
| 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> | |
| 4 | 11 | * Enhancements to ticket processing. There are now two tables: TICKET and |
| 5 | 12 | TICKETCHNG. There is one row in TICKETCHNG for each ticket artifact. |
| 6 | 13 | Fields from ticket artifacts go into either or both of TICKET and |
| 7 | 14 | TICKETCHNG, whichever contain matching column names. Default ticket |
| 8 | 15 | edit and viewing scripts are updated to use TICKETCHNG. The TH1 |
| @@ -81,10 +88,16 @@ | ||
| 81 | 88 | use those sources when compiling on (windows) systems that do not have |
| 82 | 89 | a zlib library installed by default. |
| 83 | 90 | * Prompt the user with the option to convert non-UTF8 files into UTF8 |
| 84 | 91 | when committing. |
| 85 | 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". | |
| 86 | 99 | |
| 87 | 100 | <h2>Changes For Version 1.24 (2012-10-22)</h2> |
| 88 | 101 | * Added support for WYSIWYG editing of wiki pages. WYSIWYG is turned off |
| 89 | 102 | by default and can be turned on by setting a configuration option. |
| 90 | 103 | * Allow style= attribute to occur in HTML markup on wiki pages. |
| 91 | 104 | |
| 92 | 105 | ADDED www/fossil_prompt.sh |
| 93 | 106 | 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 |
+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.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 |
+1
| --- www/mkindex.tcl | ||
| +++ www/mkindex.tcl | ||
| @@ -49,10 +49,11 @@ | ||
| 49 | 49 | ssl.wiki {Using SSL with Fossil} |
| 50 | 50 | sync.wiki {The Fossil Sync Protocol} |
| 51 | 51 | tech_overview.wiki {A Technical Overview Of The Design And Implementation |
| 52 | 52 | Of Fossil} |
| 53 | 53 | tech_overview.wiki {SQLite Databases Used By Fossil} |
| 54 | + tickets.wiki {The Fossil Ticket System} | |
| 54 | 55 | theory1.wiki {Thoughts On The Design Of The Fossil DVCS} |
| 55 | 56 | webui.wiki {The Fossil Web Interface} |
| 56 | 57 | wikitheory.wiki {Wiki In Fossil} |
| 57 | 58 | } |
| 58 | 59 | |
| 59 | 60 |
| --- 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 @@ | ||
| 136 | 136 | <li><a href="style.wiki">Style Guidelines — Source Code</a></li> |
| 137 | 137 | <li><a href="foss-cklist.wiki">Successful Open-Source Projects — Checklist For</a></li> |
| 138 | 138 | <li><a href="sync.wiki">Sync Protocol — The Fossil</a></li> |
| 139 | 139 | <li><a href="private.wiki">Syncing, and Deleting Private Branches — Creating,</a></li> |
| 140 | 140 | <li><a href="custom_ticket.wiki">System — Customizing The Ticket</a></li> |
| 141 | +<li><a href="tickets.wiki">System — The Fossil Ticket</a></li> | |
| 141 | 142 | <li><a href="branching.wiki">Tagging — Branching, Forking, Merging, and</a></li> |
| 142 | 143 | <li><a href="tech_overview.wiki">Technical Overview Of The Design And Implementation Of Fossil — A</a></li> |
| 143 | 144 | <li><a href="../test/release-checklist.wiki">Testing Checklist — Pre-Release</a></li> |
| 144 | 145 | <li><a href="makefile.wiki">The Fossil Build Process</a></li> |
| 145 | 146 | <li><a href="sync.wiki">The Fossil Sync Protocol</a></li> |
| 147 | +<li><a href="tickets.wiki">The Fossil Ticket System</a></li> | |
| 146 | 148 | <li><a href="webui.wiki">The Fossil Web Interface</a></li> |
| 147 | 149 | <li><a href="theory1.wiki">Thoughts On The Design Of The Fossil DVCS</a></li> |
| 148 | 150 | <li><a href="custom_ticket.wiki">Ticket System — Customizing The</a></li> |
| 151 | +<li><a href="tickets.wiki">Ticket System — The Fossil</a></li> | |
| 149 | 152 | <li><a href="bugtheory.wiki">Tracking In Fossil — Bug</a></li> |
| 150 | 153 | <li><a href="fiveminutes.wiki">Update and Running in 5 Minutes as a Single User</a></li> |
| 151 | 154 | <li><a href="fiveminutes.wiki">User — Update and Running in 5 Minutes as a Single</a></li> |
| 152 | 155 | <li><a href="ssl.wiki">Using SSL with Fossil</a></li> |
| 153 | 156 | <li><a href="checkin_names.wiki">Version Names — Checkin And</a></li> |
| 154 | 157 | |
| 155 | 158 | ADDED www/tickets.wiki |
| --- www/permutedindex.wiki | |
| +++ www/permutedindex.wiki | |
| @@ -136,18 +136,21 @@ | |
| 136 | <li><a href="style.wiki">Style Guidelines — Source Code</a></li> |
| 137 | <li><a href="foss-cklist.wiki">Successful Open-Source Projects — Checklist For</a></li> |
| 138 | <li><a href="sync.wiki">Sync Protocol — The Fossil</a></li> |
| 139 | <li><a href="private.wiki">Syncing, and Deleting Private Branches — Creating,</a></li> |
| 140 | <li><a href="custom_ticket.wiki">System — Customizing The Ticket</a></li> |
| 141 | <li><a href="branching.wiki">Tagging — Branching, Forking, Merging, and</a></li> |
| 142 | <li><a href="tech_overview.wiki">Technical Overview Of The Design And Implementation Of Fossil — A</a></li> |
| 143 | <li><a href="../test/release-checklist.wiki">Testing Checklist — 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 — Customizing The</a></li> |
| 149 | <li><a href="bugtheory.wiki">Tracking In Fossil — 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 — 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 — 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 — Source Code</a></li> |
| 137 | <li><a href="foss-cklist.wiki">Successful Open-Source Projects — Checklist For</a></li> |
| 138 | <li><a href="sync.wiki">Sync Protocol — The Fossil</a></li> |
| 139 | <li><a href="private.wiki">Syncing, and Deleting Private Branches — Creating,</a></li> |
| 140 | <li><a href="custom_ticket.wiki">System — Customizing The Ticket</a></li> |
| 141 | <li><a href="tickets.wiki">System — The Fossil Ticket</a></li> |
| 142 | <li><a href="branching.wiki">Tagging — Branching, Forking, Merging, and</a></li> |
| 143 | <li><a href="tech_overview.wiki">Technical Overview Of The Design And Implementation Of Fossil — A</a></li> |
| 144 | <li><a href="../test/release-checklist.wiki">Testing Checklist — 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 — Customizing The</a></li> |
| 151 | <li><a href="tickets.wiki">Ticket System — The Fossil</a></li> |
| 152 | <li><a href="bugtheory.wiki">Tracking In Fossil — 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 — 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 — Checkin And</a></li> |
| 157 | |
| 158 | DDED www/tickets.wiki |
+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. |
| --- 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. |