Fossil SCM
Merge enhancements and fixes from trunk.
Commit
23c86b503f0f0336703270b47a07b19240aa0859
Parent
837d9b5b18d9852…
14 files changed
+2
-2
+1
-1
+2
-2
+3
-3
+4
+18
-6
+1
-1
+2
-2
+33
-10
+1
-1
+1
-1
+2
-2
+120
-5
+1
-1
+2
-2
| --- src/attach.c | ||
| +++ src/attach.c | ||
| @@ -443,11 +443,11 @@ | ||
| 443 | 443 | } |
| 444 | 444 | |
| 445 | 445 | if( P("del") |
| 446 | 446 | && ((zTktUuid && g.perm.WrTkt) || (zWikiName && g.perm.WrWiki)) |
| 447 | 447 | ){ |
| 448 | - form_begin(0, "%R/ainfo/%s", zUuid); | |
| 448 | + form_begin(0, "%R/ainfo/%!S", zUuid); | |
| 449 | 449 | @ <p>Confirm you want to delete the attachment shown below. |
| 450 | 450 | @ <input type="submit" name="confirm" value="Confirm"> |
| 451 | 451 | @ </form> |
| 452 | 452 | } |
| 453 | 453 | |
| @@ -456,11 +456,11 @@ | ||
| 456 | 456 | (zWikiName && g.perm.ModWiki); |
| 457 | 457 | if( isModerator && (zModAction = P("modaction"))!=0 ){ |
| 458 | 458 | if( strcmp(zModAction,"delete")==0 ){ |
| 459 | 459 | moderation_disapprove(rid); |
| 460 | 460 | if( zTktUuid ){ |
| 461 | - cgi_redirectf("%R/tktview/%s", zTktUuid); | |
| 461 | + cgi_redirectf("%R/tktview/%!S", zTktUuid); | |
| 462 | 462 | }else{ |
| 463 | 463 | cgi_redirectf("%R/wiki?name=%t", zWikiName); |
| 464 | 464 | } |
| 465 | 465 | return; |
| 466 | 466 | } |
| 467 | 467 |
| --- src/attach.c | |
| +++ src/attach.c | |
| @@ -443,11 +443,11 @@ | |
| 443 | } |
| 444 | |
| 445 | if( P("del") |
| 446 | && ((zTktUuid && g.perm.WrTkt) || (zWikiName && g.perm.WrWiki)) |
| 447 | ){ |
| 448 | form_begin(0, "%R/ainfo/%s", zUuid); |
| 449 | @ <p>Confirm you want to delete the attachment shown below. |
| 450 | @ <input type="submit" name="confirm" value="Confirm"> |
| 451 | @ </form> |
| 452 | } |
| 453 | |
| @@ -456,11 +456,11 @@ | |
| 456 | (zWikiName && g.perm.ModWiki); |
| 457 | if( isModerator && (zModAction = P("modaction"))!=0 ){ |
| 458 | if( strcmp(zModAction,"delete")==0 ){ |
| 459 | moderation_disapprove(rid); |
| 460 | if( zTktUuid ){ |
| 461 | cgi_redirectf("%R/tktview/%s", zTktUuid); |
| 462 | }else{ |
| 463 | cgi_redirectf("%R/wiki?name=%t", zWikiName); |
| 464 | } |
| 465 | return; |
| 466 | } |
| 467 |
| --- src/attach.c | |
| +++ src/attach.c | |
| @@ -443,11 +443,11 @@ | |
| 443 | } |
| 444 | |
| 445 | if( P("del") |
| 446 | && ((zTktUuid && g.perm.WrTkt) || (zWikiName && g.perm.WrWiki)) |
| 447 | ){ |
| 448 | form_begin(0, "%R/ainfo/%!S", zUuid); |
| 449 | @ <p>Confirm you want to delete the attachment shown below. |
| 450 | @ <input type="submit" name="confirm" value="Confirm"> |
| 451 | @ </form> |
| 452 | } |
| 453 | |
| @@ -456,11 +456,11 @@ | |
| 456 | (zWikiName && g.perm.ModWiki); |
| 457 | if( isModerator && (zModAction = P("modaction"))!=0 ){ |
| 458 | if( strcmp(zModAction,"delete")==0 ){ |
| 459 | moderation_disapprove(rid); |
| 460 | if( zTktUuid ){ |
| 461 | cgi_redirectf("%R/tktview/%!S", zTktUuid); |
| 462 | }else{ |
| 463 | cgi_redirectf("%R/wiki?name=%t", zWikiName); |
| 464 | } |
| 465 | return; |
| 466 | } |
| 467 |
+1
-1
| --- src/branch.c | ||
| +++ src/branch.c | ||
| @@ -159,11 +159,11 @@ | ||
| 159 | 159 | fossil_fatal("%s\n", g.zErrMsg); |
| 160 | 160 | } |
| 161 | 161 | assert( blob_is_reset(&branch) ); |
| 162 | 162 | content_deltify(rootid, brid, 0); |
| 163 | 163 | zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", brid); |
| 164 | - fossil_print("New branch: %s\n", zUuid); | |
| 164 | + fossil_print("New branch: %S\n", zUuid); | |
| 165 | 165 | if( g.argc==3 ){ |
| 166 | 166 | fossil_print( |
| 167 | 167 | "\n" |
| 168 | 168 | "Note: the local check-out has not been updated to the new\n" |
| 169 | 169 | " branch. To begin working on the new branch, do this:\n" |
| 170 | 170 |
| --- src/branch.c | |
| +++ src/branch.c | |
| @@ -159,11 +159,11 @@ | |
| 159 | fossil_fatal("%s\n", g.zErrMsg); |
| 160 | } |
| 161 | assert( blob_is_reset(&branch) ); |
| 162 | content_deltify(rootid, brid, 0); |
| 163 | zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", brid); |
| 164 | fossil_print("New branch: %s\n", zUuid); |
| 165 | if( g.argc==3 ){ |
| 166 | fossil_print( |
| 167 | "\n" |
| 168 | "Note: the local check-out has not been updated to the new\n" |
| 169 | " branch. To begin working on the new branch, do this:\n" |
| 170 |
| --- src/branch.c | |
| +++ src/branch.c | |
| @@ -159,11 +159,11 @@ | |
| 159 | fossil_fatal("%s\n", g.zErrMsg); |
| 160 | } |
| 161 | assert( blob_is_reset(&branch) ); |
| 162 | content_deltify(rootid, brid, 0); |
| 163 | zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", brid); |
| 164 | fossil_print("New branch: %S\n", zUuid); |
| 165 | if( g.argc==3 ){ |
| 166 | fossil_print( |
| 167 | "\n" |
| 168 | "Note: the local check-out has not been updated to the new\n" |
| 169 | " branch. To begin working on the new branch, do this:\n" |
| 170 |
+2
-2
| --- src/browse.c | ||
| +++ src/browse.c | ||
| @@ -181,13 +181,13 @@ | ||
| 181 | 181 | url_render(&sURI, "ci", "tip", 0, 0)); |
| 182 | 182 | } |
| 183 | 183 | if( zCI ){ |
| 184 | 184 | @ <h2>Files of check-in [%z(href("vinfo?name=%!S",zUuid))%S(zUuid)</a>] |
| 185 | 185 | @ %s(blob_str(&dirname))</h2> |
| 186 | - zSubdirLink = mprintf("%R/dir?ci=%s&name=%T", zUuid, zPrefix); | |
| 186 | + zSubdirLink = mprintf("%R/dir?name=%T&ci=%!S", zPrefix, zUuid); | |
| 187 | 187 | if( nD==0 ){ |
| 188 | - style_submenu_element("File Ages", "File Ages", "%R/fileage?name=%s", | |
| 188 | + style_submenu_element("File Ages", "File Ages", "%R/fileage?name=%!S", | |
| 189 | 189 | zUuid); |
| 190 | 190 | } |
| 191 | 191 | }else{ |
| 192 | 192 | @ <h2>The union of all files from all check-ins |
| 193 | 193 | @ %s(blob_str(&dirname))</h2> |
| 194 | 194 |
| --- src/browse.c | |
| +++ src/browse.c | |
| @@ -181,13 +181,13 @@ | |
| 181 | url_render(&sURI, "ci", "tip", 0, 0)); |
| 182 | } |
| 183 | if( zCI ){ |
| 184 | @ <h2>Files of check-in [%z(href("vinfo?name=%!S",zUuid))%S(zUuid)</a>] |
| 185 | @ %s(blob_str(&dirname))</h2> |
| 186 | zSubdirLink = mprintf("%R/dir?ci=%s&name=%T", zUuid, zPrefix); |
| 187 | if( nD==0 ){ |
| 188 | style_submenu_element("File Ages", "File Ages", "%R/fileage?name=%s", |
| 189 | zUuid); |
| 190 | } |
| 191 | }else{ |
| 192 | @ <h2>The union of all files from all check-ins |
| 193 | @ %s(blob_str(&dirname))</h2> |
| 194 |
| --- src/browse.c | |
| +++ src/browse.c | |
| @@ -181,13 +181,13 @@ | |
| 181 | url_render(&sURI, "ci", "tip", 0, 0)); |
| 182 | } |
| 183 | if( zCI ){ |
| 184 | @ <h2>Files of check-in [%z(href("vinfo?name=%!S",zUuid))%S(zUuid)</a>] |
| 185 | @ %s(blob_str(&dirname))</h2> |
| 186 | zSubdirLink = mprintf("%R/dir?name=%T&ci=%!S", zPrefix, zUuid); |
| 187 | if( nD==0 ){ |
| 188 | style_submenu_element("File Ages", "File Ages", "%R/fileage?name=%!S", |
| 189 | zUuid); |
| 190 | } |
| 191 | }else{ |
| 192 | @ <h2>The union of all files from all check-ins |
| 193 | @ %s(blob_str(&dirname))</h2> |
| 194 |
+3
-3
| --- src/checkin.c | ||
| +++ src/checkin.c | ||
| @@ -1936,18 +1936,18 @@ | ||
| 1936 | 1936 | db_prepare(&q, "SELECT uuid,merge FROM vmerge JOIN blob ON merge=rid" |
| 1937 | 1937 | " WHERE id=-4"); |
| 1938 | 1938 | while( db_step(&q)==SQLITE_ROW ){ |
| 1939 | 1939 | const char *zIntegrateUuid = db_column_text(&q, 0); |
| 1940 | 1940 | if( is_a_leaf(db_column_int(&q, 1)) ){ |
| 1941 | - fossil_print("Closed: %s\n", zIntegrateUuid); | |
| 1941 | + fossil_print("Closed: %S\n", zIntegrateUuid); | |
| 1942 | 1942 | }else{ |
| 1943 | - fossil_print("Not_Closed: %s (not a leaf any more)\n", zIntegrateUuid); | |
| 1943 | + fossil_print("Not_Closed: %S (not a leaf any more)\n", zIntegrateUuid); | |
| 1944 | 1944 | } |
| 1945 | 1945 | } |
| 1946 | 1946 | db_finalize(&q); |
| 1947 | 1947 | |
| 1948 | - fossil_print("New_Version: %s\n", zUuid); | |
| 1948 | + fossil_print("New_Version: %S\n", zUuid); | |
| 1949 | 1949 | if( outputManifest ){ |
| 1950 | 1950 | zManifestFile = mprintf("%smanifest.uuid", g.zLocalRoot); |
| 1951 | 1951 | blob_zero(&muuid); |
| 1952 | 1952 | blob_appendf(&muuid, "%s\n", zUuid); |
| 1953 | 1953 | blob_write_to_file(&muuid, zManifestFile); |
| 1954 | 1954 |
| --- src/checkin.c | |
| +++ src/checkin.c | |
| @@ -1936,18 +1936,18 @@ | |
| 1936 | db_prepare(&q, "SELECT uuid,merge FROM vmerge JOIN blob ON merge=rid" |
| 1937 | " WHERE id=-4"); |
| 1938 | while( db_step(&q)==SQLITE_ROW ){ |
| 1939 | const char *zIntegrateUuid = db_column_text(&q, 0); |
| 1940 | if( is_a_leaf(db_column_int(&q, 1)) ){ |
| 1941 | fossil_print("Closed: %s\n", zIntegrateUuid); |
| 1942 | }else{ |
| 1943 | fossil_print("Not_Closed: %s (not a leaf any more)\n", zIntegrateUuid); |
| 1944 | } |
| 1945 | } |
| 1946 | db_finalize(&q); |
| 1947 | |
| 1948 | fossil_print("New_Version: %s\n", zUuid); |
| 1949 | if( outputManifest ){ |
| 1950 | zManifestFile = mprintf("%smanifest.uuid", g.zLocalRoot); |
| 1951 | blob_zero(&muuid); |
| 1952 | blob_appendf(&muuid, "%s\n", zUuid); |
| 1953 | blob_write_to_file(&muuid, zManifestFile); |
| 1954 |
| --- src/checkin.c | |
| +++ src/checkin.c | |
| @@ -1936,18 +1936,18 @@ | |
| 1936 | db_prepare(&q, "SELECT uuid,merge FROM vmerge JOIN blob ON merge=rid" |
| 1937 | " WHERE id=-4"); |
| 1938 | while( db_step(&q)==SQLITE_ROW ){ |
| 1939 | const char *zIntegrateUuid = db_column_text(&q, 0); |
| 1940 | if( is_a_leaf(db_column_int(&q, 1)) ){ |
| 1941 | fossil_print("Closed: %S\n", zIntegrateUuid); |
| 1942 | }else{ |
| 1943 | fossil_print("Not_Closed: %S (not a leaf any more)\n", zIntegrateUuid); |
| 1944 | } |
| 1945 | } |
| 1946 | db_finalize(&q); |
| 1947 | |
| 1948 | fossil_print("New_Version: %S\n", zUuid); |
| 1949 | if( outputManifest ){ |
| 1950 | zManifestFile = mprintf("%smanifest.uuid", g.zLocalRoot); |
| 1951 | blob_zero(&muuid); |
| 1952 | blob_appendf(&muuid, "%s\n", zUuid); |
| 1953 | blob_write_to_file(&muuid, zManifestFile); |
| 1954 |
M
src/db.c
+4
| --- src/db.c | ||
| +++ src/db.c | ||
| @@ -2389,10 +2389,11 @@ | ||
| 2389 | 2389 | { "editor", 0, 32, 0, 0, "" }, |
| 2390 | 2390 | { "empty-dirs", 0, 40, 1, 0, "" }, |
| 2391 | 2391 | { "encoding-glob", 0, 40, 1, 0, "" }, |
| 2392 | 2392 | { "gdiff-command", 0, 40, 0, 0, "gdiff" }, |
| 2393 | 2393 | { "gmerge-command", 0, 40, 0, 0, "" }, |
| 2394 | + { "hash-digits", 0, 5, 0, 0, "10" }, | |
| 2394 | 2395 | { "http-port", 0, 16, 0, 0, "8080" }, |
| 2395 | 2396 | { "https-login", 0, 0, 0, 0, "off" }, |
| 2396 | 2397 | { "ignore-glob", 0, 40, 1, 0, "" }, |
| 2397 | 2398 | { "keep-glob", 0, 40, 1, 0, "" }, |
| 2398 | 2399 | { "localauth", 0, 0, 0, 0, "off" }, |
| @@ -2565,10 +2566,13 @@ | ||
| 2565 | 2566 | ** gmerge-command A graphical merge conflict resolver command operating |
| 2566 | 2567 | ** on four files. |
| 2567 | 2568 | ** Ex: kdiff3 "%baseline" "%original" "%merge" -o "%output" |
| 2568 | 2569 | ** Ex: xxdiff "%original" "%baseline" "%merge" -M "%output" |
| 2569 | 2570 | ** Ex: meld "%baseline" "%original" "%merge" "%output" |
| 2571 | +** | |
| 2572 | +** hash-digits The number of hexadecimal digits of the SHA1 hash to | |
| 2573 | +** display. (Default: 10; Minimum: 6) | |
| 2570 | 2574 | ** |
| 2571 | 2575 | ** http-port The TCP/IP port number to use by the "server" |
| 2572 | 2576 | ** and "ui" commands. Default: 8080 |
| 2573 | 2577 | ** |
| 2574 | 2578 | ** https-login Send login credentials using HTTPS instead of HTTP |
| 2575 | 2579 |
| --- src/db.c | |
| +++ src/db.c | |
| @@ -2389,10 +2389,11 @@ | |
| 2389 | { "editor", 0, 32, 0, 0, "" }, |
| 2390 | { "empty-dirs", 0, 40, 1, 0, "" }, |
| 2391 | { "encoding-glob", 0, 40, 1, 0, "" }, |
| 2392 | { "gdiff-command", 0, 40, 0, 0, "gdiff" }, |
| 2393 | { "gmerge-command", 0, 40, 0, 0, "" }, |
| 2394 | { "http-port", 0, 16, 0, 0, "8080" }, |
| 2395 | { "https-login", 0, 0, 0, 0, "off" }, |
| 2396 | { "ignore-glob", 0, 40, 1, 0, "" }, |
| 2397 | { "keep-glob", 0, 40, 1, 0, "" }, |
| 2398 | { "localauth", 0, 0, 0, 0, "off" }, |
| @@ -2565,10 +2566,13 @@ | |
| 2565 | ** gmerge-command A graphical merge conflict resolver command operating |
| 2566 | ** on four files. |
| 2567 | ** Ex: kdiff3 "%baseline" "%original" "%merge" -o "%output" |
| 2568 | ** Ex: xxdiff "%original" "%baseline" "%merge" -M "%output" |
| 2569 | ** Ex: meld "%baseline" "%original" "%merge" "%output" |
| 2570 | ** |
| 2571 | ** http-port The TCP/IP port number to use by the "server" |
| 2572 | ** and "ui" commands. Default: 8080 |
| 2573 | ** |
| 2574 | ** https-login Send login credentials using HTTPS instead of HTTP |
| 2575 |
| --- src/db.c | |
| +++ src/db.c | |
| @@ -2389,10 +2389,11 @@ | |
| 2389 | { "editor", 0, 32, 0, 0, "" }, |
| 2390 | { "empty-dirs", 0, 40, 1, 0, "" }, |
| 2391 | { "encoding-glob", 0, 40, 1, 0, "" }, |
| 2392 | { "gdiff-command", 0, 40, 0, 0, "gdiff" }, |
| 2393 | { "gmerge-command", 0, 40, 0, 0, "" }, |
| 2394 | { "hash-digits", 0, 5, 0, 0, "10" }, |
| 2395 | { "http-port", 0, 16, 0, 0, "8080" }, |
| 2396 | { "https-login", 0, 0, 0, 0, "off" }, |
| 2397 | { "ignore-glob", 0, 40, 1, 0, "" }, |
| 2398 | { "keep-glob", 0, 40, 1, 0, "" }, |
| 2399 | { "localauth", 0, 0, 0, 0, "off" }, |
| @@ -2565,10 +2566,13 @@ | |
| 2566 | ** gmerge-command A graphical merge conflict resolver command operating |
| 2567 | ** on four files. |
| 2568 | ** Ex: kdiff3 "%baseline" "%original" "%merge" -o "%output" |
| 2569 | ** Ex: xxdiff "%original" "%baseline" "%merge" -M "%output" |
| 2570 | ** Ex: meld "%baseline" "%original" "%merge" "%output" |
| 2571 | ** |
| 2572 | ** hash-digits The number of hexadecimal digits of the SHA1 hash to |
| 2573 | ** display. (Default: 10; Minimum: 6) |
| 2574 | ** |
| 2575 | ** http-port The TCP/IP port number to use by the "server" |
| 2576 | ** and "ui" commands. Default: 8080 |
| 2577 | ** |
| 2578 | ** https-login Send login credentials using HTTPS instead of HTTP |
| 2579 |
+18
-6
| --- src/doc.c | ||
| +++ src/doc.c | ||
| @@ -106,10 +106,11 @@ | ||
| 106 | 106 | { "com", 3, "application/x-msdos-program" }, |
| 107 | 107 | { "cpio", 4, "application/x-cpio" }, |
| 108 | 108 | { "cpt", 3, "application/mac-compactpro" }, |
| 109 | 109 | { "csh", 3, "application/x-csh" }, |
| 110 | 110 | { "css", 3, "text/css" }, |
| 111 | + { "csv", 3, "text/csv" }, | |
| 111 | 112 | { "dcr", 3, "application/x-director" }, |
| 112 | 113 | { "deb", 3, "application/x-debian-package" }, |
| 113 | 114 | { "dir", 3, "application/x-director" }, |
| 114 | 115 | { "dl", 2, "video/dl" }, |
| 115 | 116 | { "dms", 3, "application/octet-stream" }, |
| @@ -291,10 +292,24 @@ | ||
| 291 | 292 | { "xpm", 3, "image/x-xpixmap" }, |
| 292 | 293 | { "xwd", 3, "image/x-xwindowdump" }, |
| 293 | 294 | { "xyz", 3, "chemical/x-pdb" }, |
| 294 | 295 | { "zip", 3, "application/zip" }, |
| 295 | 296 | }; |
| 297 | + | |
| 298 | +/* | |
| 299 | +** Verify that all entries in the aMime[] table are in sorted order. | |
| 300 | +** Abort with a fatal error if any is out-of-order. | |
| 301 | +*/ | |
| 302 | +static void mimetype_verify(void){ | |
| 303 | + int i; | |
| 304 | + for(i=1; i<ArraySize(aMime); i++){ | |
| 305 | + if( fossil_strcmp(aMime[i-1].zSuffix,aMime[i].zSuffix)>=0 ){ | |
| 306 | + fossil_fatal("mimetypes out of sequence: %s before %s", | |
| 307 | + aMime[i-1].zSuffix, aMime[i].zSuffix); | |
| 308 | + } | |
| 309 | + } | |
| 310 | +} | |
| 296 | 311 | |
| 297 | 312 | /* |
| 298 | 313 | ** Guess the mime-type of a document based on its name. |
| 299 | 314 | */ |
| 300 | 315 | const char *mimetype_from_name(const char *zName){ |
| @@ -308,16 +323,11 @@ | ||
| 308 | 323 | #ifdef FOSSIL_DEBUG |
| 309 | 324 | /* This is test code to make sure the table above is in the correct |
| 310 | 325 | ** order |
| 311 | 326 | */ |
| 312 | 327 | if( fossil_strcmp(zName, "mimetype-test")==0 ){ |
| 313 | - for(i=1; i<ArraySize(aMime); i++){ | |
| 314 | - if( fossil_strcmp(aMime[i-1].zSuffix,aMime[i].zSuffix)>=0 ){ | |
| 315 | - fossil_fatal("mimetypes out of sequence: %s before %s", | |
| 316 | - aMime[i-1].zSuffix, aMime[i].zSuffix); | |
| 317 | - } | |
| 318 | - } | |
| 328 | + mimetype_verify(); | |
| 319 | 329 | return "ok"; |
| 320 | 330 | } |
| 321 | 331 | #endif |
| 322 | 332 | |
| 323 | 333 | z = zName; |
| @@ -356,10 +366,11 @@ | ||
| 356 | 366 | ** filename is special and verifies the integrity of the mimetype table. |
| 357 | 367 | ** It should return "ok". |
| 358 | 368 | */ |
| 359 | 369 | void mimetype_test_cmd(void){ |
| 360 | 370 | int i; |
| 371 | + mimetype_verify(); | |
| 361 | 372 | for(i=2; i<g.argc; i++){ |
| 362 | 373 | fossil_print("%-20s -> %s\n", g.argv[i], mimetype_from_name(g.argv[i])); |
| 363 | 374 | } |
| 364 | 375 | } |
| 365 | 376 | |
| @@ -369,10 +380,11 @@ | ||
| 369 | 380 | ** Show the built-in table used to guess embedded document mimetypes |
| 370 | 381 | ** from file suffixes. |
| 371 | 382 | */ |
| 372 | 383 | void mimetype_list_page(void){ |
| 373 | 384 | int i; |
| 385 | + mimetype_verify(); | |
| 374 | 386 | style_header("Mimetype List"); |
| 375 | 387 | @ <p>The Fossil <a href="%R/help?cmd=/doc">/doc</a> page uses filename |
| 376 | 388 | @ suffixes and the following table to guess at the appropriate mimetype |
| 377 | 389 | @ for each document.</p> |
| 378 | 390 | @ <table id='mimeTable' border=1 cellpadding=0 class='mimetypetable'> |
| 379 | 391 |
| --- src/doc.c | |
| +++ src/doc.c | |
| @@ -106,10 +106,11 @@ | |
| 106 | { "com", 3, "application/x-msdos-program" }, |
| 107 | { "cpio", 4, "application/x-cpio" }, |
| 108 | { "cpt", 3, "application/mac-compactpro" }, |
| 109 | { "csh", 3, "application/x-csh" }, |
| 110 | { "css", 3, "text/css" }, |
| 111 | { "dcr", 3, "application/x-director" }, |
| 112 | { "deb", 3, "application/x-debian-package" }, |
| 113 | { "dir", 3, "application/x-director" }, |
| 114 | { "dl", 2, "video/dl" }, |
| 115 | { "dms", 3, "application/octet-stream" }, |
| @@ -291,10 +292,24 @@ | |
| 291 | { "xpm", 3, "image/x-xpixmap" }, |
| 292 | { "xwd", 3, "image/x-xwindowdump" }, |
| 293 | { "xyz", 3, "chemical/x-pdb" }, |
| 294 | { "zip", 3, "application/zip" }, |
| 295 | }; |
| 296 | |
| 297 | /* |
| 298 | ** Guess the mime-type of a document based on its name. |
| 299 | */ |
| 300 | const char *mimetype_from_name(const char *zName){ |
| @@ -308,16 +323,11 @@ | |
| 308 | #ifdef FOSSIL_DEBUG |
| 309 | /* This is test code to make sure the table above is in the correct |
| 310 | ** order |
| 311 | */ |
| 312 | if( fossil_strcmp(zName, "mimetype-test")==0 ){ |
| 313 | for(i=1; i<ArraySize(aMime); i++){ |
| 314 | if( fossil_strcmp(aMime[i-1].zSuffix,aMime[i].zSuffix)>=0 ){ |
| 315 | fossil_fatal("mimetypes out of sequence: %s before %s", |
| 316 | aMime[i-1].zSuffix, aMime[i].zSuffix); |
| 317 | } |
| 318 | } |
| 319 | return "ok"; |
| 320 | } |
| 321 | #endif |
| 322 | |
| 323 | z = zName; |
| @@ -356,10 +366,11 @@ | |
| 356 | ** filename is special and verifies the integrity of the mimetype table. |
| 357 | ** It should return "ok". |
| 358 | */ |
| 359 | void mimetype_test_cmd(void){ |
| 360 | int i; |
| 361 | for(i=2; i<g.argc; i++){ |
| 362 | fossil_print("%-20s -> %s\n", g.argv[i], mimetype_from_name(g.argv[i])); |
| 363 | } |
| 364 | } |
| 365 | |
| @@ -369,10 +380,11 @@ | |
| 369 | ** Show the built-in table used to guess embedded document mimetypes |
| 370 | ** from file suffixes. |
| 371 | */ |
| 372 | void mimetype_list_page(void){ |
| 373 | int i; |
| 374 | style_header("Mimetype List"); |
| 375 | @ <p>The Fossil <a href="%R/help?cmd=/doc">/doc</a> page uses filename |
| 376 | @ suffixes and the following table to guess at the appropriate mimetype |
| 377 | @ for each document.</p> |
| 378 | @ <table id='mimeTable' border=1 cellpadding=0 class='mimetypetable'> |
| 379 |
| --- src/doc.c | |
| +++ src/doc.c | |
| @@ -106,10 +106,11 @@ | |
| 106 | { "com", 3, "application/x-msdos-program" }, |
| 107 | { "cpio", 4, "application/x-cpio" }, |
| 108 | { "cpt", 3, "application/mac-compactpro" }, |
| 109 | { "csh", 3, "application/x-csh" }, |
| 110 | { "css", 3, "text/css" }, |
| 111 | { "csv", 3, "text/csv" }, |
| 112 | { "dcr", 3, "application/x-director" }, |
| 113 | { "deb", 3, "application/x-debian-package" }, |
| 114 | { "dir", 3, "application/x-director" }, |
| 115 | { "dl", 2, "video/dl" }, |
| 116 | { "dms", 3, "application/octet-stream" }, |
| @@ -291,10 +292,24 @@ | |
| 292 | { "xpm", 3, "image/x-xpixmap" }, |
| 293 | { "xwd", 3, "image/x-xwindowdump" }, |
| 294 | { "xyz", 3, "chemical/x-pdb" }, |
| 295 | { "zip", 3, "application/zip" }, |
| 296 | }; |
| 297 | |
| 298 | /* |
| 299 | ** Verify that all entries in the aMime[] table are in sorted order. |
| 300 | ** Abort with a fatal error if any is out-of-order. |
| 301 | */ |
| 302 | static void mimetype_verify(void){ |
| 303 | int i; |
| 304 | for(i=1; i<ArraySize(aMime); i++){ |
| 305 | if( fossil_strcmp(aMime[i-1].zSuffix,aMime[i].zSuffix)>=0 ){ |
| 306 | fossil_fatal("mimetypes out of sequence: %s before %s", |
| 307 | aMime[i-1].zSuffix, aMime[i].zSuffix); |
| 308 | } |
| 309 | } |
| 310 | } |
| 311 | |
| 312 | /* |
| 313 | ** Guess the mime-type of a document based on its name. |
| 314 | */ |
| 315 | const char *mimetype_from_name(const char *zName){ |
| @@ -308,16 +323,11 @@ | |
| 323 | #ifdef FOSSIL_DEBUG |
| 324 | /* This is test code to make sure the table above is in the correct |
| 325 | ** order |
| 326 | */ |
| 327 | if( fossil_strcmp(zName, "mimetype-test")==0 ){ |
| 328 | mimetype_verify(); |
| 329 | return "ok"; |
| 330 | } |
| 331 | #endif |
| 332 | |
| 333 | z = zName; |
| @@ -356,10 +366,11 @@ | |
| 366 | ** filename is special and verifies the integrity of the mimetype table. |
| 367 | ** It should return "ok". |
| 368 | */ |
| 369 | void mimetype_test_cmd(void){ |
| 370 | int i; |
| 371 | mimetype_verify(); |
| 372 | for(i=2; i<g.argc; i++){ |
| 373 | fossil_print("%-20s -> %s\n", g.argv[i], mimetype_from_name(g.argv[i])); |
| 374 | } |
| 375 | } |
| 376 | |
| @@ -369,10 +380,11 @@ | |
| 380 | ** Show the built-in table used to guess embedded document mimetypes |
| 381 | ** from file suffixes. |
| 382 | */ |
| 383 | void mimetype_list_page(void){ |
| 384 | int i; |
| 385 | mimetype_verify(); |
| 386 | style_header("Mimetype List"); |
| 387 | @ <p>The Fossil <a href="%R/help?cmd=/doc">/doc</a> page uses filename |
| 388 | @ suffixes and the following table to guess at the appropriate mimetype |
| 389 | @ for each document.</p> |
| 390 | @ <table id='mimeTable' border=1 cellpadding=0 class='mimetypetable'> |
| 391 |
+1
-1
| --- src/finfo.c | ||
| +++ src/finfo.c | ||
| @@ -215,11 +215,11 @@ | ||
| 215 | 215 | zCiUuid, zCom, zUser, zFileUuid, zBr); |
| 216 | 216 | comment_print(zOut, zCom, 11, iWidth, g.comFmtFlags); |
| 217 | 217 | fossil_free(zOut); |
| 218 | 218 | }else{ |
| 219 | 219 | blob_reset(&line); |
| 220 | - blob_appendf(&line, "%.10s ", zCiUuid); | |
| 220 | + blob_appendf(&line, "%S ", zCiUuid); | |
| 221 | 221 | blob_appendf(&line, "%.10s ", zDate); |
| 222 | 222 | blob_appendf(&line, "%8.8s ", zUser); |
| 223 | 223 | blob_appendf(&line, "%8.8s ", zBr); |
| 224 | 224 | blob_appendf(&line,"%-39.39s", zCom ); |
| 225 | 225 | comment_print(blob_str(&line), zCom, 0, iWidth, g.comFmtFlags); |
| 226 | 226 |
| --- src/finfo.c | |
| +++ src/finfo.c | |
| @@ -215,11 +215,11 @@ | |
| 215 | zCiUuid, zCom, zUser, zFileUuid, zBr); |
| 216 | comment_print(zOut, zCom, 11, iWidth, g.comFmtFlags); |
| 217 | fossil_free(zOut); |
| 218 | }else{ |
| 219 | blob_reset(&line); |
| 220 | blob_appendf(&line, "%.10s ", zCiUuid); |
| 221 | blob_appendf(&line, "%.10s ", zDate); |
| 222 | blob_appendf(&line, "%8.8s ", zUser); |
| 223 | blob_appendf(&line, "%8.8s ", zBr); |
| 224 | blob_appendf(&line,"%-39.39s", zCom ); |
| 225 | comment_print(blob_str(&line), zCom, 0, iWidth, g.comFmtFlags); |
| 226 |
| --- src/finfo.c | |
| +++ src/finfo.c | |
| @@ -215,11 +215,11 @@ | |
| 215 | zCiUuid, zCom, zUser, zFileUuid, zBr); |
| 216 | comment_print(zOut, zCom, 11, iWidth, g.comFmtFlags); |
| 217 | fossil_free(zOut); |
| 218 | }else{ |
| 219 | blob_reset(&line); |
| 220 | blob_appendf(&line, "%S ", zCiUuid); |
| 221 | blob_appendf(&line, "%.10s ", zDate); |
| 222 | blob_appendf(&line, "%8.8s ", zUser); |
| 223 | blob_appendf(&line, "%8.8s ", zBr); |
| 224 | blob_appendf(&line,"%-39.39s", zCom ); |
| 225 | comment_print(blob_str(&line), zCom, 0, iWidth, g.comFmtFlags); |
| 226 |
+2
-2
| --- src/info.c | ||
| +++ src/info.c | ||
| @@ -1336,11 +1336,11 @@ | ||
| 1336 | 1336 | } |
| 1337 | 1337 | @ - %!w(zCom) by |
| 1338 | 1338 | hyperlink_to_user(zUser,zDate," on"); |
| 1339 | 1339 | hyperlink_to_date(zDate, "."); |
| 1340 | 1340 | if( pDownloadName && blob_size(pDownloadName)==0 ){ |
| 1341 | - blob_appendf(pDownloadName, "%.10s.txt", zUuid); | |
| 1341 | + blob_appendf(pDownloadName, "%S.txt", zUuid); | |
| 1342 | 1342 | } |
| 1343 | 1343 | tag_private_status(rid); |
| 1344 | 1344 | cnt++; |
| 1345 | 1345 | } |
| 1346 | 1346 | db_finalize(&q); |
| @@ -1388,11 +1388,11 @@ | ||
| 1388 | 1388 | } |
| 1389 | 1389 | db_finalize(&q); |
| 1390 | 1390 | if( cnt==0 ){ |
| 1391 | 1391 | @ Control artifact. |
| 1392 | 1392 | if( pDownloadName && blob_size(pDownloadName)==0 ){ |
| 1393 | - blob_appendf(pDownloadName, "%.10s.txt", zUuid); | |
| 1393 | + blob_appendf(pDownloadName, "%S.txt", zUuid); | |
| 1394 | 1394 | } |
| 1395 | 1395 | tag_private_status(rid); |
| 1396 | 1396 | } |
| 1397 | 1397 | return objType; |
| 1398 | 1398 | } |
| 1399 | 1399 |
| --- src/info.c | |
| +++ src/info.c | |
| @@ -1336,11 +1336,11 @@ | |
| 1336 | } |
| 1337 | @ - %!w(zCom) by |
| 1338 | hyperlink_to_user(zUser,zDate," on"); |
| 1339 | hyperlink_to_date(zDate, "."); |
| 1340 | if( pDownloadName && blob_size(pDownloadName)==0 ){ |
| 1341 | blob_appendf(pDownloadName, "%.10s.txt", zUuid); |
| 1342 | } |
| 1343 | tag_private_status(rid); |
| 1344 | cnt++; |
| 1345 | } |
| 1346 | db_finalize(&q); |
| @@ -1388,11 +1388,11 @@ | |
| 1388 | } |
| 1389 | db_finalize(&q); |
| 1390 | if( cnt==0 ){ |
| 1391 | @ Control artifact. |
| 1392 | if( pDownloadName && blob_size(pDownloadName)==0 ){ |
| 1393 | blob_appendf(pDownloadName, "%.10s.txt", zUuid); |
| 1394 | } |
| 1395 | tag_private_status(rid); |
| 1396 | } |
| 1397 | return objType; |
| 1398 | } |
| 1399 |
| --- src/info.c | |
| +++ src/info.c | |
| @@ -1336,11 +1336,11 @@ | |
| 1336 | } |
| 1337 | @ - %!w(zCom) by |
| 1338 | hyperlink_to_user(zUser,zDate," on"); |
| 1339 | hyperlink_to_date(zDate, "."); |
| 1340 | if( pDownloadName && blob_size(pDownloadName)==0 ){ |
| 1341 | blob_appendf(pDownloadName, "%S.txt", zUuid); |
| 1342 | } |
| 1343 | tag_private_status(rid); |
| 1344 | cnt++; |
| 1345 | } |
| 1346 | db_finalize(&q); |
| @@ -1388,11 +1388,11 @@ | |
| 1388 | } |
| 1389 | db_finalize(&q); |
| 1390 | if( cnt==0 ){ |
| 1391 | @ Control artifact. |
| 1392 | if( pDownloadName && blob_size(pDownloadName)==0 ){ |
| 1393 | blob_appendf(pDownloadName, "%S.txt", zUuid); |
| 1394 | } |
| 1395 | tag_private_status(rid); |
| 1396 | } |
| 1397 | return objType; |
| 1398 | } |
| 1399 |
+33
-10
| --- src/printf.c | ||
| +++ src/printf.c | ||
| @@ -29,18 +29,42 @@ | ||
| 29 | 29 | /* Two custom conversions are used to show a prefix of SHA1 hashes: |
| 30 | 30 | ** |
| 31 | 31 | ** %!S Prefix of a length appropriate for URLs |
| 32 | 32 | ** %S Prefix of a length appropriate for human display |
| 33 | 33 | ** |
| 34 | -** The following macros determine those lengths. | |
| 35 | -*/ | |
| 36 | -#ifndef FOSSIL_SHA1_PREFIX_LEN | |
| 37 | -# define FOSSIL_SHA1_PREFIX_LEN 10 /* For %S (human display) */ | |
| 38 | -#endif | |
| 39 | -#ifndef FOSSIL_SHA1_URLPREFIX_LEN | |
| 40 | -# define FOSSIL_SHA1_URLPREFIX_LEN 16 /* For %!S (embedded in URLs) */ | |
| 41 | -#endif | |
| 34 | +** The following macros help determine those lengths. FOSSIL_HASH_DIGITS | |
| 35 | +** is the default number of digits to display to humans. This value can | |
| 36 | +** be overridden using the hash-digits setting. FOSSIL_HASH_DIGITS_URL | |
| 37 | +** is the minimum number of digits to be used in URLs. The number used | |
| 38 | +** will always be at least 6 more than the number used for human output, | |
| 39 | +** or 40 if the number of digits in human output is 34 or more. | |
| 40 | +*/ | |
| 41 | +#ifndef FOSSIL_HASH_DIGITS | |
| 42 | +# define FOSSIL_HASH_DIGITS 10 /* For %S (human display) */ | |
| 43 | +#endif | |
| 44 | +#ifndef FOSSIL_HASH_DIGITS_URL | |
| 45 | +# define FOSSIL_HASH_DIGITS_URL 16 /* For %!S (embedded in URLs) */ | |
| 46 | +#endif | |
| 47 | + | |
| 48 | +/* | |
| 49 | +** Return the number of SHA1 hash digits to display. The number is for | |
| 50 | +** human output if the bForUrl is false and is destined for a URL if | |
| 51 | +** bForUrl is false. | |
| 52 | +*/ | |
| 53 | +static int hashDigits(int bForUrl){ | |
| 54 | + static int nDigitHuman = 0; | |
| 55 | + static int nDigitUrl = 0; | |
| 56 | + if( nDigitHuman==0 ){ | |
| 57 | + nDigitHuman = db_get_int("hash-digits", FOSSIL_HASH_DIGITS); | |
| 58 | + if( nDigitHuman < 6 ) nDigitHuman = 6; | |
| 59 | + if( nDigitHuman > 40 ) nDigitHuman = 40; | |
| 60 | + nDigitUrl = nDigitHuman + 6; | |
| 61 | + if( nDigitUrl < FOSSIL_HASH_DIGITS_URL ) nDigitUrl = FOSSIL_HASH_DIGITS_URL; | |
| 62 | + if( nDigitUrl > 40 ) nDigitUrl = 40; | |
| 63 | + } | |
| 64 | + return bForUrl ? nDigitUrl : nDigitHuman; | |
| 65 | +} | |
| 42 | 66 | |
| 43 | 67 | /* |
| 44 | 68 | ** Conversion types fall into various categories as defined by the |
| 45 | 69 | ** following enumeration. |
| 46 | 70 | */ |
| @@ -634,12 +658,11 @@ | ||
| 634 | 658 | if( bufpt==0 ){ |
| 635 | 659 | bufpt = ""; |
| 636 | 660 | }else if( xtype==etDYNSTRING ){ |
| 637 | 661 | zExtra = bufpt; |
| 638 | 662 | }else if( xtype==etSTRINGID ){ |
| 639 | - precision = flag_altform2 ? FOSSIL_SHA1_URLPREFIX_LEN : | |
| 640 | - FOSSIL_SHA1_PREFIX_LEN; | |
| 663 | + precision = hashDigits(flag_altform2); | |
| 641 | 664 | } |
| 642 | 665 | length = StrNLen32(bufpt, limit); |
| 643 | 666 | if( precision>=0 && precision<length ) length = precision; |
| 644 | 667 | break; |
| 645 | 668 | } |
| 646 | 669 |
| --- src/printf.c | |
| +++ src/printf.c | |
| @@ -29,18 +29,42 @@ | |
| 29 | /* Two custom conversions are used to show a prefix of SHA1 hashes: |
| 30 | ** |
| 31 | ** %!S Prefix of a length appropriate for URLs |
| 32 | ** %S Prefix of a length appropriate for human display |
| 33 | ** |
| 34 | ** The following macros determine those lengths. |
| 35 | */ |
| 36 | #ifndef FOSSIL_SHA1_PREFIX_LEN |
| 37 | # define FOSSIL_SHA1_PREFIX_LEN 10 /* For %S (human display) */ |
| 38 | #endif |
| 39 | #ifndef FOSSIL_SHA1_URLPREFIX_LEN |
| 40 | # define FOSSIL_SHA1_URLPREFIX_LEN 16 /* For %!S (embedded in URLs) */ |
| 41 | #endif |
| 42 | |
| 43 | /* |
| 44 | ** Conversion types fall into various categories as defined by the |
| 45 | ** following enumeration. |
| 46 | */ |
| @@ -634,12 +658,11 @@ | |
| 634 | if( bufpt==0 ){ |
| 635 | bufpt = ""; |
| 636 | }else if( xtype==etDYNSTRING ){ |
| 637 | zExtra = bufpt; |
| 638 | }else if( xtype==etSTRINGID ){ |
| 639 | precision = flag_altform2 ? FOSSIL_SHA1_URLPREFIX_LEN : |
| 640 | FOSSIL_SHA1_PREFIX_LEN; |
| 641 | } |
| 642 | length = StrNLen32(bufpt, limit); |
| 643 | if( precision>=0 && precision<length ) length = precision; |
| 644 | break; |
| 645 | } |
| 646 |
| --- src/printf.c | |
| +++ src/printf.c | |
| @@ -29,18 +29,42 @@ | |
| 29 | /* Two custom conversions are used to show a prefix of SHA1 hashes: |
| 30 | ** |
| 31 | ** %!S Prefix of a length appropriate for URLs |
| 32 | ** %S Prefix of a length appropriate for human display |
| 33 | ** |
| 34 | ** The following macros help determine those lengths. FOSSIL_HASH_DIGITS |
| 35 | ** is the default number of digits to display to humans. This value can |
| 36 | ** be overridden using the hash-digits setting. FOSSIL_HASH_DIGITS_URL |
| 37 | ** is the minimum number of digits to be used in URLs. The number used |
| 38 | ** will always be at least 6 more than the number used for human output, |
| 39 | ** or 40 if the number of digits in human output is 34 or more. |
| 40 | */ |
| 41 | #ifndef FOSSIL_HASH_DIGITS |
| 42 | # define FOSSIL_HASH_DIGITS 10 /* For %S (human display) */ |
| 43 | #endif |
| 44 | #ifndef FOSSIL_HASH_DIGITS_URL |
| 45 | # define FOSSIL_HASH_DIGITS_URL 16 /* For %!S (embedded in URLs) */ |
| 46 | #endif |
| 47 | |
| 48 | /* |
| 49 | ** Return the number of SHA1 hash digits to display. The number is for |
| 50 | ** human output if the bForUrl is false and is destined for a URL if |
| 51 | ** bForUrl is false. |
| 52 | */ |
| 53 | static int hashDigits(int bForUrl){ |
| 54 | static int nDigitHuman = 0; |
| 55 | static int nDigitUrl = 0; |
| 56 | if( nDigitHuman==0 ){ |
| 57 | nDigitHuman = db_get_int("hash-digits", FOSSIL_HASH_DIGITS); |
| 58 | if( nDigitHuman < 6 ) nDigitHuman = 6; |
| 59 | if( nDigitHuman > 40 ) nDigitHuman = 40; |
| 60 | nDigitUrl = nDigitHuman + 6; |
| 61 | if( nDigitUrl < FOSSIL_HASH_DIGITS_URL ) nDigitUrl = FOSSIL_HASH_DIGITS_URL; |
| 62 | if( nDigitUrl > 40 ) nDigitUrl = 40; |
| 63 | } |
| 64 | return bForUrl ? nDigitUrl : nDigitHuman; |
| 65 | } |
| 66 | |
| 67 | /* |
| 68 | ** Conversion types fall into various categories as defined by the |
| 69 | ** following enumeration. |
| 70 | */ |
| @@ -634,12 +658,11 @@ | |
| 658 | if( bufpt==0 ){ |
| 659 | bufpt = ""; |
| 660 | }else if( xtype==etDYNSTRING ){ |
| 661 | zExtra = bufpt; |
| 662 | }else if( xtype==etSTRINGID ){ |
| 663 | precision = hashDigits(flag_altform2); |
| 664 | } |
| 665 | length = StrNLen32(bufpt, limit); |
| 666 | if( precision>=0 && precision<length ) length = precision; |
| 667 | break; |
| 668 | } |
| 669 |
+1
-1
| --- src/search.c | ||
| +++ src/search.c | ||
| @@ -993,11 +993,11 @@ | ||
| 993 | 993 | static void get_stext_by_mimetype( |
| 994 | 994 | Blob *pIn, |
| 995 | 995 | const char *zMimetype, |
| 996 | 996 | Blob *pOut |
| 997 | 997 | ){ |
| 998 | - Blob html, title, tail; | |
| 998 | + Blob html, title; | |
| 999 | 999 | blob_init(&html, 0, 0); |
| 1000 | 1000 | blob_init(&title, 0, 0); |
| 1001 | 1001 | if( zMimetype==0 ) zMimetype = "text/plain"; |
| 1002 | 1002 | if( fossil_strcmp(zMimetype,"text/x-fossil-wiki")==0 ){ |
| 1003 | 1003 | Blob tail; |
| 1004 | 1004 |
| --- src/search.c | |
| +++ src/search.c | |
| @@ -993,11 +993,11 @@ | |
| 993 | static void get_stext_by_mimetype( |
| 994 | Blob *pIn, |
| 995 | const char *zMimetype, |
| 996 | Blob *pOut |
| 997 | ){ |
| 998 | Blob html, title, tail; |
| 999 | blob_init(&html, 0, 0); |
| 1000 | blob_init(&title, 0, 0); |
| 1001 | if( zMimetype==0 ) zMimetype = "text/plain"; |
| 1002 | if( fossil_strcmp(zMimetype,"text/x-fossil-wiki")==0 ){ |
| 1003 | Blob tail; |
| 1004 |
| --- src/search.c | |
| +++ src/search.c | |
| @@ -993,11 +993,11 @@ | |
| 993 | static void get_stext_by_mimetype( |
| 994 | Blob *pIn, |
| 995 | const char *zMimetype, |
| 996 | Blob *pOut |
| 997 | ){ |
| 998 | Blob html, title; |
| 999 | blob_init(&html, 0, 0); |
| 1000 | blob_init(&title, 0, 0); |
| 1001 | if( zMimetype==0 ) zMimetype = "text/plain"; |
| 1002 | if( fossil_strcmp(zMimetype,"text/x-fossil-wiki")==0 ){ |
| 1003 | Blob tail; |
| 1004 |
+1
-1
| --- src/search.c | ||
| +++ src/search.c | ||
| @@ -993,11 +993,11 @@ | ||
| 993 | 993 | static void get_stext_by_mimetype( |
| 994 | 994 | Blob *pIn, |
| 995 | 995 | const char *zMimetype, |
| 996 | 996 | Blob *pOut |
| 997 | 997 | ){ |
| 998 | - Blob html, title, tail; | |
| 998 | + Blob html, title; | |
| 999 | 999 | blob_init(&html, 0, 0); |
| 1000 | 1000 | blob_init(&title, 0, 0); |
| 1001 | 1001 | if( zMimetype==0 ) zMimetype = "text/plain"; |
| 1002 | 1002 | if( fossil_strcmp(zMimetype,"text/x-fossil-wiki")==0 ){ |
| 1003 | 1003 | Blob tail; |
| 1004 | 1004 |
| --- src/search.c | |
| +++ src/search.c | |
| @@ -993,11 +993,11 @@ | |
| 993 | static void get_stext_by_mimetype( |
| 994 | Blob *pIn, |
| 995 | const char *zMimetype, |
| 996 | Blob *pOut |
| 997 | ){ |
| 998 | Blob html, title, tail; |
| 999 | blob_init(&html, 0, 0); |
| 1000 | blob_init(&title, 0, 0); |
| 1001 | if( zMimetype==0 ) zMimetype = "text/plain"; |
| 1002 | if( fossil_strcmp(zMimetype,"text/x-fossil-wiki")==0 ){ |
| 1003 | Blob tail; |
| 1004 |
| --- src/search.c | |
| +++ src/search.c | |
| @@ -993,11 +993,11 @@ | |
| 993 | static void get_stext_by_mimetype( |
| 994 | Blob *pIn, |
| 995 | const char *zMimetype, |
| 996 | Blob *pOut |
| 997 | ){ |
| 998 | Blob html, title; |
| 999 | blob_init(&html, 0, 0); |
| 1000 | blob_init(&title, 0, 0); |
| 1001 | if( zMimetype==0 ) zMimetype = "text/plain"; |
| 1002 | if( fossil_strcmp(zMimetype,"text/x-fossil-wiki")==0 ){ |
| 1003 | Blob tail; |
| 1004 |
+2
-2
| --- src/setup.c | ||
| +++ src/setup.c | ||
| @@ -1708,11 +1708,11 @@ | ||
| 1708 | 1708 | login_insert_csrf_secret(); |
| 1709 | 1709 | @ <hr /> |
| 1710 | 1710 | onoff_attribute("Moderate ticket changes", |
| 1711 | 1711 | "modreq-tkt", "modreq-tkt", 0, 0); |
| 1712 | 1712 | @ <p>When enabled, any change to tickets is subject to the approval |
| 1713 | - @ a ticket moderator - a user with the "q" or Mod-Tkt privilege. | |
| 1713 | + @ by a ticket moderator - a user with the "q" or Mod-Tkt privilege. | |
| 1714 | 1714 | @ Ticket changes enter the system and are shown locally, but are not |
| 1715 | 1715 | @ synced until they are approved. The moderator has the option to |
| 1716 | 1716 | @ delete the change rather than approve it. Ticket changes made by |
| 1717 | 1717 | @ a user who has the Mod-Tkt privilege are never subject to |
| 1718 | 1718 | @ moderation. |
| @@ -1719,11 +1719,11 @@ | ||
| 1719 | 1719 | @ |
| 1720 | 1720 | @ <hr /> |
| 1721 | 1721 | onoff_attribute("Moderate wiki changes", |
| 1722 | 1722 | "modreq-wiki", "modreq-wiki", 0, 0); |
| 1723 | 1723 | @ <p>When enabled, any change to wiki is subject to the approval |
| 1724 | - @ a ticket moderator - a user with the "l" or Mod-Wiki privilege. | |
| 1724 | + @ by a wiki moderator - a user with the "l" or Mod-Wiki privilege. | |
| 1725 | 1725 | @ Wiki changes enter the system and are shown locally, but are not |
| 1726 | 1726 | @ synced until they are approved. The moderator has the option to |
| 1727 | 1727 | @ delete the change rather than approve it. Wiki changes made by |
| 1728 | 1728 | @ a user who has the Mod-Wiki privilege are never subject to |
| 1729 | 1729 | @ moderation. |
| 1730 | 1730 |
| --- src/setup.c | |
| +++ src/setup.c | |
| @@ -1708,11 +1708,11 @@ | |
| 1708 | login_insert_csrf_secret(); |
| 1709 | @ <hr /> |
| 1710 | onoff_attribute("Moderate ticket changes", |
| 1711 | "modreq-tkt", "modreq-tkt", 0, 0); |
| 1712 | @ <p>When enabled, any change to tickets is subject to the approval |
| 1713 | @ a ticket moderator - a user with the "q" or Mod-Tkt privilege. |
| 1714 | @ Ticket changes enter the system and are shown locally, but are not |
| 1715 | @ synced until they are approved. The moderator has the option to |
| 1716 | @ delete the change rather than approve it. Ticket changes made by |
| 1717 | @ a user who has the Mod-Tkt privilege are never subject to |
| 1718 | @ moderation. |
| @@ -1719,11 +1719,11 @@ | |
| 1719 | @ |
| 1720 | @ <hr /> |
| 1721 | onoff_attribute("Moderate wiki changes", |
| 1722 | "modreq-wiki", "modreq-wiki", 0, 0); |
| 1723 | @ <p>When enabled, any change to wiki is subject to the approval |
| 1724 | @ a ticket moderator - a user with the "l" or Mod-Wiki privilege. |
| 1725 | @ Wiki changes enter the system and are shown locally, but are not |
| 1726 | @ synced until they are approved. The moderator has the option to |
| 1727 | @ delete the change rather than approve it. Wiki changes made by |
| 1728 | @ a user who has the Mod-Wiki privilege are never subject to |
| 1729 | @ moderation. |
| 1730 |
| --- src/setup.c | |
| +++ src/setup.c | |
| @@ -1708,11 +1708,11 @@ | |
| 1708 | login_insert_csrf_secret(); |
| 1709 | @ <hr /> |
| 1710 | onoff_attribute("Moderate ticket changes", |
| 1711 | "modreq-tkt", "modreq-tkt", 0, 0); |
| 1712 | @ <p>When enabled, any change to tickets is subject to the approval |
| 1713 | @ by a ticket moderator - a user with the "q" or Mod-Tkt privilege. |
| 1714 | @ Ticket changes enter the system and are shown locally, but are not |
| 1715 | @ synced until they are approved. The moderator has the option to |
| 1716 | @ delete the change rather than approve it. Ticket changes made by |
| 1717 | @ a user who has the Mod-Tkt privilege are never subject to |
| 1718 | @ moderation. |
| @@ -1719,11 +1719,11 @@ | |
| 1719 | @ |
| 1720 | @ <hr /> |
| 1721 | onoff_attribute("Moderate wiki changes", |
| 1722 | "modreq-wiki", "modreq-wiki", 0, 0); |
| 1723 | @ <p>When enabled, any change to wiki is subject to the approval |
| 1724 | @ by a wiki moderator - a user with the "l" or Mod-Wiki privilege. |
| 1725 | @ Wiki changes enter the system and are shown locally, but are not |
| 1726 | @ synced until they are approved. The moderator has the option to |
| 1727 | @ delete the change rather than approve it. Wiki changes made by |
| 1728 | @ a user who has the Mod-Wiki privilege are never subject to |
| 1729 | @ moderation. |
| 1730 |
+120
-5
| --- src/shell.c | ||
| +++ src/shell.c | ||
| @@ -1742,10 +1742,11 @@ | ||
| 1742 | 1742 | static char zHelp[] = |
| 1743 | 1743 | ".backup ?DB? FILE Backup DB (default \"main\") to FILE\n" |
| 1744 | 1744 | ".bail on|off Stop after hitting an error. Default OFF\n" |
| 1745 | 1745 | ".clone NEWDB Clone data into NEWDB from the existing database\n" |
| 1746 | 1746 | ".databases List names and files of attached databases\n" |
| 1747 | + ".dbinfo ?DB? Show status information about the database\n" | |
| 1747 | 1748 | ".dump ?TABLE? ... Dump the database in an SQL text format\n" |
| 1748 | 1749 | " If TABLE specified, only dump tables matching\n" |
| 1749 | 1750 | " LIKE pattern TABLE.\n" |
| 1750 | 1751 | ".echo on|off Turn command echo on or off\n" |
| 1751 | 1752 | ".eqp on|off Enable or disable automatic EXPLAIN QUERY PLAN\n" |
| @@ -1754,12 +1755,12 @@ | ||
| 1754 | 1755 | " With no args, it turns EXPLAIN on.\n" |
| 1755 | 1756 | ".fullschema Show schema and the content of sqlite_stat tables\n" |
| 1756 | 1757 | ".headers on|off Turn display of headers on or off\n" |
| 1757 | 1758 | ".help Show this message\n" |
| 1758 | 1759 | ".import FILE TABLE Import data from FILE into TABLE\n" |
| 1759 | - ".indices ?TABLE? Show names of all indices\n" | |
| 1760 | - " If TABLE specified, only show indices for tables\n" | |
| 1760 | + ".indexes ?TABLE? Show names of all indexes\n" | |
| 1761 | + " If TABLE specified, only show indexes for tables\n" | |
| 1761 | 1762 | " matching LIKE pattern TABLE.\n" |
| 1762 | 1763 | #ifdef SQLITE_ENABLE_IOTRACE |
| 1763 | 1764 | ".iotrace FILE Enable I/O diagnostic logging to FILE\n" |
| 1764 | 1765 | #endif |
| 1765 | 1766 | #ifndef SQLITE_OMIT_LOAD_EXTENSION |
| @@ -2434,10 +2435,119 @@ | ||
| 2434 | 2435 | output_file_close(p->out); |
| 2435 | 2436 | } |
| 2436 | 2437 | p->outfile[0] = 0; |
| 2437 | 2438 | p->out = stdout; |
| 2438 | 2439 | } |
| 2440 | + | |
| 2441 | +/* | |
| 2442 | +** Run an SQL command and return the single integer result. | |
| 2443 | +*/ | |
| 2444 | +static int db_int(ShellState *p, const char *zSql){ | |
| 2445 | + sqlite3_stmt *pStmt; | |
| 2446 | + int res = 0; | |
| 2447 | + sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); | |
| 2448 | + if( pStmt && sqlite3_step(pStmt)==SQLITE_ROW ){ | |
| 2449 | + res = sqlite3_column_int(pStmt,0); | |
| 2450 | + } | |
| 2451 | + sqlite3_finalize(pStmt); | |
| 2452 | + return res; | |
| 2453 | +} | |
| 2454 | + | |
| 2455 | +/* | |
| 2456 | +** Convert a 2-byte or 4-byte big-endian integer into a native integer | |
| 2457 | +*/ | |
| 2458 | +unsigned int get2byteInt(unsigned char *a){ | |
| 2459 | + return (a[0]<<8) + a[1]; | |
| 2460 | +} | |
| 2461 | +unsigned int get4byteInt(unsigned char *a){ | |
| 2462 | + return (a[0]<<24) + (a[1]<<16) + (a[2]<<8) + a[3]; | |
| 2463 | +} | |
| 2464 | + | |
| 2465 | +/* | |
| 2466 | +** Implementation of the ".info" command. | |
| 2467 | +** | |
| 2468 | +** Return 1 on error, 2 to exit, and 0 otherwise. | |
| 2469 | +*/ | |
| 2470 | +static int shell_dbinfo_command(ShellState *p, int nArg, char **azArg){ | |
| 2471 | + static const struct { const char *zName; int ofst; } aField[] = { | |
| 2472 | + { "file change counter:", 24 }, | |
| 2473 | + { "database page count:", 28 }, | |
| 2474 | + { "freelist page count:", 36 }, | |
| 2475 | + { "schema cookie:", 40 }, | |
| 2476 | + { "schema format:", 44 }, | |
| 2477 | + { "default cache size:", 48 }, | |
| 2478 | + { "autovacuum top root:", 52 }, | |
| 2479 | + { "incremental vacuum:", 64 }, | |
| 2480 | + { "text encoding:", 56 }, | |
| 2481 | + { "user version:", 60 }, | |
| 2482 | + { "application id:", 68 }, | |
| 2483 | + { "software version:", 96 }, | |
| 2484 | + }; | |
| 2485 | + static const struct { const char *zName; const char *zSql; } aQuery[] = { | |
| 2486 | + { "number of tables:", | |
| 2487 | + "SELECT count(*) FROM %s WHERE type='table'" }, | |
| 2488 | + { "number of indexes:", | |
| 2489 | + "SELECT count(*) FROM %s WHERE type='index'" }, | |
| 2490 | + { "number of triggers:", | |
| 2491 | + "SELECT count(*) FROM %s WHERE type='trigger'" }, | |
| 2492 | + { "number of views:", | |
| 2493 | + "SELECT count(*) FROM %s WHERE type='view'" }, | |
| 2494 | + { "schema size:", | |
| 2495 | + "SELECT total(length(sql)) FROM %s" }, | |
| 2496 | + }; | |
| 2497 | + sqlite3_file *pFile; | |
| 2498 | + int i; | |
| 2499 | + char *zSchemaTab; | |
| 2500 | + char *zDb = nArg>=2 ? azArg[1] : "main"; | |
| 2501 | + unsigned char aHdr[100]; | |
| 2502 | + open_db(p, 0); | |
| 2503 | + if( p->db==0 ) return 1; | |
| 2504 | + sqlite3_file_control(p->db, zDb, SQLITE_FCNTL_FILE_POINTER, &pFile); | |
| 2505 | + if( pFile==0 || pFile->pMethods==0 || pFile->pMethods->xRead==0 ){ | |
| 2506 | + return 1; | |
| 2507 | + } | |
| 2508 | + i = pFile->pMethods->xRead(pFile, aHdr, 100, 0); | |
| 2509 | + if( i!=SQLITE_OK ){ | |
| 2510 | + fprintf(stderr, "unable to read database header\n"); | |
| 2511 | + return 1; | |
| 2512 | + } | |
| 2513 | + i = get2byteInt(aHdr+16); | |
| 2514 | + if( i==1 ) i = 65536; | |
| 2515 | + fprintf(p->out, "%-20s %d\n", "database page size:", i); | |
| 2516 | + fprintf(p->out, "%-20s %d\n", "write format:", aHdr[18]); | |
| 2517 | + fprintf(p->out, "%-20s %d\n", "read format:", aHdr[19]); | |
| 2518 | + fprintf(p->out, "%-20s %d\n", "reserved bytes:", aHdr[20]); | |
| 2519 | + for(i=0; i<sizeof(aField)/sizeof(aField[0]); i++){ | |
| 2520 | + int ofst = aField[i].ofst; | |
| 2521 | + unsigned int val = get4byteInt(aHdr + ofst); | |
| 2522 | + fprintf(p->out, "%-20s %u", aField[i].zName, val); | |
| 2523 | + switch( ofst ){ | |
| 2524 | + case 56: { | |
| 2525 | + if( val==1 ) fprintf(p->out, " (utf8)"); | |
| 2526 | + if( val==2 ) fprintf(p->out, " (utf16le)"); | |
| 2527 | + if( val==3 ) fprintf(p->out, " (utf16be)"); | |
| 2528 | + } | |
| 2529 | + } | |
| 2530 | + fprintf(p->out, "\n"); | |
| 2531 | + } | |
| 2532 | + if( zDb==0 ){ | |
| 2533 | + zSchemaTab = sqlite3_mprintf("main.sqlite_master"); | |
| 2534 | + }else if( strcmp(zDb,"temp")==0 ){ | |
| 2535 | + zSchemaTab = sqlite3_mprintf("%s", "sqlite_temp_master"); | |
| 2536 | + }else{ | |
| 2537 | + zSchemaTab = sqlite3_mprintf("\"%w\".sqlite_master", zDb); | |
| 2538 | + } | |
| 2539 | + for(i=0; i<sizeof(aQuery)/sizeof(aQuery[0]); i++){ | |
| 2540 | + char *zSql = sqlite3_mprintf(aQuery[i].zSql, zSchemaTab); | |
| 2541 | + int val = db_int(p, zSql); | |
| 2542 | + sqlite3_free(zSql); | |
| 2543 | + fprintf(p->out, "%-20s %d\n", aQuery[i].zName, val); | |
| 2544 | + } | |
| 2545 | + sqlite3_free(zSchemaTab); | |
| 2546 | + return 0; | |
| 2547 | +} | |
| 2548 | + | |
| 2439 | 2549 | |
| 2440 | 2550 | /* |
| 2441 | 2551 | ** If an input line begins with "." then invoke this routine to |
| 2442 | 2552 | ** process that line. |
| 2443 | 2553 | ** |
| @@ -2576,10 +2686,14 @@ | ||
| 2576 | 2686 | fprintf(stderr,"Error: %s\n", zErrMsg); |
| 2577 | 2687 | sqlite3_free(zErrMsg); |
| 2578 | 2688 | rc = 1; |
| 2579 | 2689 | } |
| 2580 | 2690 | }else |
| 2691 | + | |
| 2692 | + if( c=='d' && strncmp(azArg[0], "dbinfo", n)==0 ){ | |
| 2693 | + rc = shell_dbinfo_command(p, nArg, azArg); | |
| 2694 | + }else | |
| 2581 | 2695 | |
| 2582 | 2696 | if( c=='d' && strncmp(azArg[0], "dump", n)==0 ){ |
| 2583 | 2697 | open_db(p, 0); |
| 2584 | 2698 | /* When playing back a "dump", the content might appear in an order |
| 2585 | 2699 | ** which causes immediate foreign key constraints to be violated. |
| @@ -2916,11 +3030,11 @@ | ||
| 2916 | 3030 | sqlite3_bind_text(pStmt, i+1, z, -1, SQLITE_TRANSIENT); |
| 2917 | 3031 | if( i<nCol-1 && sCtx.cTerm!=sCtx.cColSep ){ |
| 2918 | 3032 | fprintf(stderr, "%s:%d: expected %d columns but found %d - " |
| 2919 | 3033 | "filling the rest with NULL\n", |
| 2920 | 3034 | sCtx.zFile, startLine, nCol, i+1); |
| 2921 | - i++; | |
| 3035 | + i += 2; | |
| 2922 | 3036 | while( i<=nCol ){ sqlite3_bind_null(pStmt, i); i++; } |
| 2923 | 3037 | } |
| 2924 | 3038 | } |
| 2925 | 3039 | if( sCtx.cTerm==sCtx.cColSep ){ |
| 2926 | 3040 | do{ |
| @@ -2945,11 +3059,12 @@ | ||
| 2945 | 3059 | sqlite3_free(sCtx.z); |
| 2946 | 3060 | sqlite3_finalize(pStmt); |
| 2947 | 3061 | if( needCommit ) sqlite3_exec(db, "COMMIT", 0, 0, 0); |
| 2948 | 3062 | }else |
| 2949 | 3063 | |
| 2950 | - if( c=='i' && strncmp(azArg[0], "indices", n)==0 ){ | |
| 3064 | + if( c=='i' && (strncmp(azArg[0], "indices", n)==0 | |
| 3065 | + || strncmp(azArg[0], "indexes", n)==0) ){ | |
| 2951 | 3066 | ShellState data; |
| 2952 | 3067 | char *zErrMsg = 0; |
| 2953 | 3068 | open_db(p, 0); |
| 2954 | 3069 | memcpy(&data, p, sizeof(data)); |
| 2955 | 3070 | data.showHeader = 0; |
| @@ -2975,11 +3090,11 @@ | ||
| 2975 | 3090 | "ORDER BY 1", |
| 2976 | 3091 | callback, &data, &zErrMsg |
| 2977 | 3092 | ); |
| 2978 | 3093 | zShellStatic = 0; |
| 2979 | 3094 | }else{ |
| 2980 | - fprintf(stderr, "Usage: .indices ?LIKE-PATTERN?\n"); | |
| 3095 | + fprintf(stderr, "Usage: .indexes ?LIKE-PATTERN?\n"); | |
| 2981 | 3096 | rc = 1; |
| 2982 | 3097 | goto meta_command_exit; |
| 2983 | 3098 | } |
| 2984 | 3099 | if( zErrMsg ){ |
| 2985 | 3100 | fprintf(stderr,"Error: %s\n", zErrMsg); |
| 2986 | 3101 |
| --- src/shell.c | |
| +++ src/shell.c | |
| @@ -1742,10 +1742,11 @@ | |
| 1742 | static char zHelp[] = |
| 1743 | ".backup ?DB? FILE Backup DB (default \"main\") to FILE\n" |
| 1744 | ".bail on|off Stop after hitting an error. Default OFF\n" |
| 1745 | ".clone NEWDB Clone data into NEWDB from the existing database\n" |
| 1746 | ".databases List names and files of attached databases\n" |
| 1747 | ".dump ?TABLE? ... Dump the database in an SQL text format\n" |
| 1748 | " If TABLE specified, only dump tables matching\n" |
| 1749 | " LIKE pattern TABLE.\n" |
| 1750 | ".echo on|off Turn command echo on or off\n" |
| 1751 | ".eqp on|off Enable or disable automatic EXPLAIN QUERY PLAN\n" |
| @@ -1754,12 +1755,12 @@ | |
| 1754 | " With no args, it turns EXPLAIN on.\n" |
| 1755 | ".fullschema Show schema and the content of sqlite_stat tables\n" |
| 1756 | ".headers on|off Turn display of headers on or off\n" |
| 1757 | ".help Show this message\n" |
| 1758 | ".import FILE TABLE Import data from FILE into TABLE\n" |
| 1759 | ".indices ?TABLE? Show names of all indices\n" |
| 1760 | " If TABLE specified, only show indices for tables\n" |
| 1761 | " matching LIKE pattern TABLE.\n" |
| 1762 | #ifdef SQLITE_ENABLE_IOTRACE |
| 1763 | ".iotrace FILE Enable I/O diagnostic logging to FILE\n" |
| 1764 | #endif |
| 1765 | #ifndef SQLITE_OMIT_LOAD_EXTENSION |
| @@ -2434,10 +2435,119 @@ | |
| 2434 | output_file_close(p->out); |
| 2435 | } |
| 2436 | p->outfile[0] = 0; |
| 2437 | p->out = stdout; |
| 2438 | } |
| 2439 | |
| 2440 | /* |
| 2441 | ** If an input line begins with "." then invoke this routine to |
| 2442 | ** process that line. |
| 2443 | ** |
| @@ -2576,10 +2686,14 @@ | |
| 2576 | fprintf(stderr,"Error: %s\n", zErrMsg); |
| 2577 | sqlite3_free(zErrMsg); |
| 2578 | rc = 1; |
| 2579 | } |
| 2580 | }else |
| 2581 | |
| 2582 | if( c=='d' && strncmp(azArg[0], "dump", n)==0 ){ |
| 2583 | open_db(p, 0); |
| 2584 | /* When playing back a "dump", the content might appear in an order |
| 2585 | ** which causes immediate foreign key constraints to be violated. |
| @@ -2916,11 +3030,11 @@ | |
| 2916 | sqlite3_bind_text(pStmt, i+1, z, -1, SQLITE_TRANSIENT); |
| 2917 | if( i<nCol-1 && sCtx.cTerm!=sCtx.cColSep ){ |
| 2918 | fprintf(stderr, "%s:%d: expected %d columns but found %d - " |
| 2919 | "filling the rest with NULL\n", |
| 2920 | sCtx.zFile, startLine, nCol, i+1); |
| 2921 | i++; |
| 2922 | while( i<=nCol ){ sqlite3_bind_null(pStmt, i); i++; } |
| 2923 | } |
| 2924 | } |
| 2925 | if( sCtx.cTerm==sCtx.cColSep ){ |
| 2926 | do{ |
| @@ -2945,11 +3059,12 @@ | |
| 2945 | sqlite3_free(sCtx.z); |
| 2946 | sqlite3_finalize(pStmt); |
| 2947 | if( needCommit ) sqlite3_exec(db, "COMMIT", 0, 0, 0); |
| 2948 | }else |
| 2949 | |
| 2950 | if( c=='i' && strncmp(azArg[0], "indices", n)==0 ){ |
| 2951 | ShellState data; |
| 2952 | char *zErrMsg = 0; |
| 2953 | open_db(p, 0); |
| 2954 | memcpy(&data, p, sizeof(data)); |
| 2955 | data.showHeader = 0; |
| @@ -2975,11 +3090,11 @@ | |
| 2975 | "ORDER BY 1", |
| 2976 | callback, &data, &zErrMsg |
| 2977 | ); |
| 2978 | zShellStatic = 0; |
| 2979 | }else{ |
| 2980 | fprintf(stderr, "Usage: .indices ?LIKE-PATTERN?\n"); |
| 2981 | rc = 1; |
| 2982 | goto meta_command_exit; |
| 2983 | } |
| 2984 | if( zErrMsg ){ |
| 2985 | fprintf(stderr,"Error: %s\n", zErrMsg); |
| 2986 |
| --- src/shell.c | |
| +++ src/shell.c | |
| @@ -1742,10 +1742,11 @@ | |
| 1742 | static char zHelp[] = |
| 1743 | ".backup ?DB? FILE Backup DB (default \"main\") to FILE\n" |
| 1744 | ".bail on|off Stop after hitting an error. Default OFF\n" |
| 1745 | ".clone NEWDB Clone data into NEWDB from the existing database\n" |
| 1746 | ".databases List names and files of attached databases\n" |
| 1747 | ".dbinfo ?DB? Show status information about the database\n" |
| 1748 | ".dump ?TABLE? ... Dump the database in an SQL text format\n" |
| 1749 | " If TABLE specified, only dump tables matching\n" |
| 1750 | " LIKE pattern TABLE.\n" |
| 1751 | ".echo on|off Turn command echo on or off\n" |
| 1752 | ".eqp on|off Enable or disable automatic EXPLAIN QUERY PLAN\n" |
| @@ -1754,12 +1755,12 @@ | |
| 1755 | " With no args, it turns EXPLAIN on.\n" |
| 1756 | ".fullschema Show schema and the content of sqlite_stat tables\n" |
| 1757 | ".headers on|off Turn display of headers on or off\n" |
| 1758 | ".help Show this message\n" |
| 1759 | ".import FILE TABLE Import data from FILE into TABLE\n" |
| 1760 | ".indexes ?TABLE? Show names of all indexes\n" |
| 1761 | " If TABLE specified, only show indexes for tables\n" |
| 1762 | " matching LIKE pattern TABLE.\n" |
| 1763 | #ifdef SQLITE_ENABLE_IOTRACE |
| 1764 | ".iotrace FILE Enable I/O diagnostic logging to FILE\n" |
| 1765 | #endif |
| 1766 | #ifndef SQLITE_OMIT_LOAD_EXTENSION |
| @@ -2434,10 +2435,119 @@ | |
| 2435 | output_file_close(p->out); |
| 2436 | } |
| 2437 | p->outfile[0] = 0; |
| 2438 | p->out = stdout; |
| 2439 | } |
| 2440 | |
| 2441 | /* |
| 2442 | ** Run an SQL command and return the single integer result. |
| 2443 | */ |
| 2444 | static int db_int(ShellState *p, const char *zSql){ |
| 2445 | sqlite3_stmt *pStmt; |
| 2446 | int res = 0; |
| 2447 | sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); |
| 2448 | if( pStmt && sqlite3_step(pStmt)==SQLITE_ROW ){ |
| 2449 | res = sqlite3_column_int(pStmt,0); |
| 2450 | } |
| 2451 | sqlite3_finalize(pStmt); |
| 2452 | return res; |
| 2453 | } |
| 2454 | |
| 2455 | /* |
| 2456 | ** Convert a 2-byte or 4-byte big-endian integer into a native integer |
| 2457 | */ |
| 2458 | unsigned int get2byteInt(unsigned char *a){ |
| 2459 | return (a[0]<<8) + a[1]; |
| 2460 | } |
| 2461 | unsigned int get4byteInt(unsigned char *a){ |
| 2462 | return (a[0]<<24) + (a[1]<<16) + (a[2]<<8) + a[3]; |
| 2463 | } |
| 2464 | |
| 2465 | /* |
| 2466 | ** Implementation of the ".info" command. |
| 2467 | ** |
| 2468 | ** Return 1 on error, 2 to exit, and 0 otherwise. |
| 2469 | */ |
| 2470 | static int shell_dbinfo_command(ShellState *p, int nArg, char **azArg){ |
| 2471 | static const struct { const char *zName; int ofst; } aField[] = { |
| 2472 | { "file change counter:", 24 }, |
| 2473 | { "database page count:", 28 }, |
| 2474 | { "freelist page count:", 36 }, |
| 2475 | { "schema cookie:", 40 }, |
| 2476 | { "schema format:", 44 }, |
| 2477 | { "default cache size:", 48 }, |
| 2478 | { "autovacuum top root:", 52 }, |
| 2479 | { "incremental vacuum:", 64 }, |
| 2480 | { "text encoding:", 56 }, |
| 2481 | { "user version:", 60 }, |
| 2482 | { "application id:", 68 }, |
| 2483 | { "software version:", 96 }, |
| 2484 | }; |
| 2485 | static const struct { const char *zName; const char *zSql; } aQuery[] = { |
| 2486 | { "number of tables:", |
| 2487 | "SELECT count(*) FROM %s WHERE type='table'" }, |
| 2488 | { "number of indexes:", |
| 2489 | "SELECT count(*) FROM %s WHERE type='index'" }, |
| 2490 | { "number of triggers:", |
| 2491 | "SELECT count(*) FROM %s WHERE type='trigger'" }, |
| 2492 | { "number of views:", |
| 2493 | "SELECT count(*) FROM %s WHERE type='view'" }, |
| 2494 | { "schema size:", |
| 2495 | "SELECT total(length(sql)) FROM %s" }, |
| 2496 | }; |
| 2497 | sqlite3_file *pFile; |
| 2498 | int i; |
| 2499 | char *zSchemaTab; |
| 2500 | char *zDb = nArg>=2 ? azArg[1] : "main"; |
| 2501 | unsigned char aHdr[100]; |
| 2502 | open_db(p, 0); |
| 2503 | if( p->db==0 ) return 1; |
| 2504 | sqlite3_file_control(p->db, zDb, SQLITE_FCNTL_FILE_POINTER, &pFile); |
| 2505 | if( pFile==0 || pFile->pMethods==0 || pFile->pMethods->xRead==0 ){ |
| 2506 | return 1; |
| 2507 | } |
| 2508 | i = pFile->pMethods->xRead(pFile, aHdr, 100, 0); |
| 2509 | if( i!=SQLITE_OK ){ |
| 2510 | fprintf(stderr, "unable to read database header\n"); |
| 2511 | return 1; |
| 2512 | } |
| 2513 | i = get2byteInt(aHdr+16); |
| 2514 | if( i==1 ) i = 65536; |
| 2515 | fprintf(p->out, "%-20s %d\n", "database page size:", i); |
| 2516 | fprintf(p->out, "%-20s %d\n", "write format:", aHdr[18]); |
| 2517 | fprintf(p->out, "%-20s %d\n", "read format:", aHdr[19]); |
| 2518 | fprintf(p->out, "%-20s %d\n", "reserved bytes:", aHdr[20]); |
| 2519 | for(i=0; i<sizeof(aField)/sizeof(aField[0]); i++){ |
| 2520 | int ofst = aField[i].ofst; |
| 2521 | unsigned int val = get4byteInt(aHdr + ofst); |
| 2522 | fprintf(p->out, "%-20s %u", aField[i].zName, val); |
| 2523 | switch( ofst ){ |
| 2524 | case 56: { |
| 2525 | if( val==1 ) fprintf(p->out, " (utf8)"); |
| 2526 | if( val==2 ) fprintf(p->out, " (utf16le)"); |
| 2527 | if( val==3 ) fprintf(p->out, " (utf16be)"); |
| 2528 | } |
| 2529 | } |
| 2530 | fprintf(p->out, "\n"); |
| 2531 | } |
| 2532 | if( zDb==0 ){ |
| 2533 | zSchemaTab = sqlite3_mprintf("main.sqlite_master"); |
| 2534 | }else if( strcmp(zDb,"temp")==0 ){ |
| 2535 | zSchemaTab = sqlite3_mprintf("%s", "sqlite_temp_master"); |
| 2536 | }else{ |
| 2537 | zSchemaTab = sqlite3_mprintf("\"%w\".sqlite_master", zDb); |
| 2538 | } |
| 2539 | for(i=0; i<sizeof(aQuery)/sizeof(aQuery[0]); i++){ |
| 2540 | char *zSql = sqlite3_mprintf(aQuery[i].zSql, zSchemaTab); |
| 2541 | int val = db_int(p, zSql); |
| 2542 | sqlite3_free(zSql); |
| 2543 | fprintf(p->out, "%-20s %d\n", aQuery[i].zName, val); |
| 2544 | } |
| 2545 | sqlite3_free(zSchemaTab); |
| 2546 | return 0; |
| 2547 | } |
| 2548 | |
| 2549 | |
| 2550 | /* |
| 2551 | ** If an input line begins with "." then invoke this routine to |
| 2552 | ** process that line. |
| 2553 | ** |
| @@ -2576,10 +2686,14 @@ | |
| 2686 | fprintf(stderr,"Error: %s\n", zErrMsg); |
| 2687 | sqlite3_free(zErrMsg); |
| 2688 | rc = 1; |
| 2689 | } |
| 2690 | }else |
| 2691 | |
| 2692 | if( c=='d' && strncmp(azArg[0], "dbinfo", n)==0 ){ |
| 2693 | rc = shell_dbinfo_command(p, nArg, azArg); |
| 2694 | }else |
| 2695 | |
| 2696 | if( c=='d' && strncmp(azArg[0], "dump", n)==0 ){ |
| 2697 | open_db(p, 0); |
| 2698 | /* When playing back a "dump", the content might appear in an order |
| 2699 | ** which causes immediate foreign key constraints to be violated. |
| @@ -2916,11 +3030,11 @@ | |
| 3030 | sqlite3_bind_text(pStmt, i+1, z, -1, SQLITE_TRANSIENT); |
| 3031 | if( i<nCol-1 && sCtx.cTerm!=sCtx.cColSep ){ |
| 3032 | fprintf(stderr, "%s:%d: expected %d columns but found %d - " |
| 3033 | "filling the rest with NULL\n", |
| 3034 | sCtx.zFile, startLine, nCol, i+1); |
| 3035 | i += 2; |
| 3036 | while( i<=nCol ){ sqlite3_bind_null(pStmt, i); i++; } |
| 3037 | } |
| 3038 | } |
| 3039 | if( sCtx.cTerm==sCtx.cColSep ){ |
| 3040 | do{ |
| @@ -2945,11 +3059,12 @@ | |
| 3059 | sqlite3_free(sCtx.z); |
| 3060 | sqlite3_finalize(pStmt); |
| 3061 | if( needCommit ) sqlite3_exec(db, "COMMIT", 0, 0, 0); |
| 3062 | }else |
| 3063 | |
| 3064 | if( c=='i' && (strncmp(azArg[0], "indices", n)==0 |
| 3065 | || strncmp(azArg[0], "indexes", n)==0) ){ |
| 3066 | ShellState data; |
| 3067 | char *zErrMsg = 0; |
| 3068 | open_db(p, 0); |
| 3069 | memcpy(&data, p, sizeof(data)); |
| 3070 | data.showHeader = 0; |
| @@ -2975,11 +3090,11 @@ | |
| 3090 | "ORDER BY 1", |
| 3091 | callback, &data, &zErrMsg |
| 3092 | ); |
| 3093 | zShellStatic = 0; |
| 3094 | }else{ |
| 3095 | fprintf(stderr, "Usage: .indexes ?LIKE-PATTERN?\n"); |
| 3096 | rc = 1; |
| 3097 | goto meta_command_exit; |
| 3098 | } |
| 3099 | if( zErrMsg ){ |
| 3100 | fprintf(stderr,"Error: %s\n", zErrMsg); |
| 3101 |
+1
-1
| --- src/tkt.c | ||
| +++ src/tkt.c | ||
| @@ -428,11 +428,11 @@ | ||
| 428 | 428 | @ <font color="blue"> |
| 429 | 429 | @ <p>Database fields:</p><ul> |
| 430 | 430 | for(i=0; i<nField; i++){ |
| 431 | 431 | @ <li>aField[%d(i)].zName = "%h(aField[i].zName)"; |
| 432 | 432 | @ originally = "%h(aField[i].zValue)"; |
| 433 | - @ currently = "%h(PD(aField[i].zName,""))""; | |
| 433 | + @ currently = "%h(PD(aField[i].zName,""))"; | |
| 434 | 434 | if( aField[i].zAppend ){ |
| 435 | 435 | @ zAppend = "%h(aField[i].zAppend)"; |
| 436 | 436 | } |
| 437 | 437 | @ mUsed = %d(aField[i].mUsed); |
| 438 | 438 | } |
| 439 | 439 |
| --- src/tkt.c | |
| +++ src/tkt.c | |
| @@ -428,11 +428,11 @@ | |
| 428 | @ <font color="blue"> |
| 429 | @ <p>Database fields:</p><ul> |
| 430 | for(i=0; i<nField; i++){ |
| 431 | @ <li>aField[%d(i)].zName = "%h(aField[i].zName)"; |
| 432 | @ originally = "%h(aField[i].zValue)"; |
| 433 | @ currently = "%h(PD(aField[i].zName,""))""; |
| 434 | if( aField[i].zAppend ){ |
| 435 | @ zAppend = "%h(aField[i].zAppend)"; |
| 436 | } |
| 437 | @ mUsed = %d(aField[i].mUsed); |
| 438 | } |
| 439 |
| --- src/tkt.c | |
| +++ src/tkt.c | |
| @@ -428,11 +428,11 @@ | |
| 428 | @ <font color="blue"> |
| 429 | @ <p>Database fields:</p><ul> |
| 430 | for(i=0; i<nField; i++){ |
| 431 | @ <li>aField[%d(i)].zName = "%h(aField[i].zName)"; |
| 432 | @ originally = "%h(aField[i].zValue)"; |
| 433 | @ currently = "%h(PD(aField[i].zName,""))"; |
| 434 | if( aField[i].zAppend ){ |
| 435 | @ zAppend = "%h(aField[i].zAppend)"; |
| 436 | } |
| 437 | @ mUsed = %d(aField[i].mUsed); |
| 438 | } |
| 439 |