Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Changes In Branch StvPrivateHook2 Excluding Merge-Ins
This is equivalent to a diff from e6dce6a16a to a298a0e2f9
2010-11-09
| ||
01:17 | Cleanup of help_page() in preparation for merging with trunk. Leaf check-in: a298a0e2f9 user: drh tags: StvPrivateHook2 | |
2010-11-08
| ||
23:01 | remove hook command to be compatible with other hook designs check-in: a06121740a user: wolfgang tags: StvPrivateHook2 | |
2010-10-29
| ||
21:11 | merge from trunk and add sqlite shell to windows make check-in: 6d334ac9ed user: wolfgang tags: StvPrivateHook2 | |
2010-10-28
| ||
17:41 | merge from trunk Leaf check-in: e6dce6a16a user: wolfgang tags: StvPrivateHook2 | |
14:41 | Fix a few harmless compiler warnings. check-in: d03718ad5f user: drh tags: trunk | |
2010-10-27
| ||
20:39 | added missing dependency in dmc windows make for resource file check-in: 304c71a09c user: wolfgang tags: StvPrivateHook2 | |
Changes to src/allrepo.c.
58 58 ** be useful before or after a period of disconnected operation. 59 59 ** 60 60 ** On Win32 systems, the file is named "_fossil" and is located in 61 61 ** %LOCALAPPDATA%, %APPDATA% or %HOMEPATH%. 62 62 ** 63 63 ** Available operations are: 64 64 ** 65 +** ignore Arguments are repositories that should be ignored 66 +** by subsequent list, pull, push, rebuild, and sync. 67 +** 65 68 ** list | ls Display the location of all repositories 66 69 ** 67 70 ** pull Run a "pull" operation on all repositories 68 71 ** 69 72 ** push Run a "push" on all repositories 70 73 ** 71 74 ** rebuild Rebuild on all repositories 72 75 ** 73 76 ** sync Run a "sync" on all repositories 74 77 ** 75 78 ** Respositories are automatically added to the set of known repositories 76 79 ** when one of the following commands against the repository: 77 80 ** <a>clone</a>, <a>info</a>, <a>pull</a>, <a>push</a>, or <a>sync</a> 81 +** Even previously ignored repositories are added back 82 +** to the list of repositories by these commands. 78 83 */ 79 84 void all_cmd(void){ 80 85 int n; 81 86 Stmt q; 82 87 const char *zCmd; 83 88 char *zSyscmd; 84 89 char *zFossil; ................................................................................ 97 102 zCmd = "push -autourl -R"; 98 103 }else if( strncmp(zCmd, "pull", n)==0 ){ 99 104 zCmd = "pull -autourl -R"; 100 105 }else if( strncmp(zCmd, "rebuild", n)==0 ){ 101 106 zCmd = "rebuild"; 102 107 }else if( strncmp(zCmd, "sync", n)==0 ){ 103 108 zCmd = "sync -autourl -R"; 109 + }else if( strncmp(zCmd, "ignore", n)==0 ){ 110 + int j; 111 + db_begin_transaction(); 112 + for(j=3; j<g.argc; j++){ 113 + db_multi_exec("DELETE FROM global_config WHERE name GLOB 'repo:%q'", 114 + g.argv[j]); 115 + } 116 + db_end_transaction(0); 117 + return; 104 118 }else{ 105 119 fossil_fatal("\"all\" subcommand should be one of: " 106 - "list ls push pull rebuild sync"); 120 + "ignore list ls push pull rebuild sync"); 107 121 } 108 122 zFossil = quoteFilename(g.argv[0]); 109 123 nMissing = 0; 110 124 db_prepare(&q, 111 125 "SELECT DISTINCT substr(name, 6) COLLATE nocase" 112 126 " FROM global_config" 113 127 " WHERE substr(name, 1, 5)=='repo:' ORDER BY 1" ................................................................................ 123 137 printf("%s\n", zFilename); 124 138 continue; 125 139 } 126 140 zQFilename = quoteFilename(zFilename); 127 141 zSyscmd = mprintf("%s %s %s", zFossil, zCmd, zQFilename); 128 142 printf("%s\n", zSyscmd); 129 143 fflush(stdout); 130 - portable_system(zSyscmd); 144 + fossil_system(zSyscmd); 131 145 free(zSyscmd); 132 146 free(zQFilename); 133 147 } 134 148 135 149 /* If any repositories whose names appear in the ~/.fossil file could not 136 150 ** be found, remove those names from the ~/.fossil file. 137 151 */
Changes to src/checkin.c.
420 420 g.zLocalRoot); 421 421 #if defined(_WIN32) 422 422 blob_add_cr(&text); 423 423 #endif 424 424 blob_write_to_file(&text, zFile); 425 425 zCmd = mprintf("%s \"%s\"", zEditor, zFile); 426 426 printf("%s\n", zCmd); 427 - if( portable_system(zCmd) ){ 427 + if( fossil_system(zCmd) ){ 428 428 fossil_panic("editor aborted"); 429 429 } 430 430 blob_reset(&text); 431 431 blob_read_from_file(&text, zFile); 432 432 blob_remove_cr(&text); 433 433 unlink(zFile); 434 434 free(zFile); ................................................................................ 697 697 698 698 /* 699 699 ** COMMAND: ci 700 700 ** COMMAND: commit 701 701 ** 702 702 ** Usage: %fossil commit ?OPTIONS? ?FILE...? 703 703 ** 704 + 705 + 704 706 ** Create a new version containing all of the changes in the current 705 707 ** checkout. You will be prompted to enter a check-in comment unless 706 -** the comment has been specified on the command-line using "-m". The 707 -** editor defined in the "editor" fossil option (see %fossil help set) 708 -** will be used, or from the "VISUAL" or "EDITOR" environment variables 709 -** (in that order) if no editor is set. 708 +** the comment has been specified on the command-line using "-m" or a 709 +** file containing the comment using -M. The editor defined in the 710 +** "editor" fossil option (see %fossil <a>help</a> set) will be used, or from 711 +** the "VISUAL" or "EDITOR" environment variables (in that order) if 712 +** no editor is set. 713 +** 714 +** All files that have changed will be committed unless some subset of 715 +** files is specified on the command line. 710 716 ** 711 -** You will be prompted for your GPG passphrase in order to sign the 712 -** new manifest unless the "--nosign" option is used. All files that 713 -** have changed will be committed unless some subset of files is 714 -** specified on the command line. 715 -** 716 -** The --branch option followed by a branch name cases the new check-in 717 +** The --branch option followed by a branch name causes the new check-in 717 718 ** to be placed in the named branch. The --bgcolor option can be followed 718 719 ** by a color name (ex: '#ffc0c0') to specify the background color of 719 720 ** entries in the new branch when shown in the web timeline interface. 720 721 ** 721 722 ** A check-in is not permitted to fork unless the --force or -f option 722 723 ** appears. A check-in is not allowed against a closed check-in. 723 724 ** 724 725 ** The --private option creates a private check-in that is never synced. 725 726 ** Children of private check-ins are automatically private. 726 727 ** 727 728 ** Options: 728 729 ** 729 730 ** --comment|-m COMMENT-TEXT 731 +** --message-file|-M COMMENT-FILE 730 732 ** --branch NEW-BRANCH-NAME 731 733 ** --bgcolor COLOR 732 734 ** --nosign 733 735 ** --force|-f 734 736 ** --private 735 737 ** --baseline 736 738 ** --delta ................................................................................ 1063 1065 ** calculated before the checkin started (and stored as the R record 1064 1066 ** of the manifest file). 1065 1067 */ 1066 1068 vfile_aggregate_checksum_repository(nvid, &cksum2); 1067 1069 if( blob_compare(&cksum1, &cksum2) ){ 1068 1070 fossil_panic("tree checksum does not match repository after commit"); 1069 1071 } 1070 - 1072 + 1071 1073 /* Verify that the manifest checksum matches the expected checksum */ 1072 1074 vfile_aggregate_checksum_manifest(nvid, &cksum2, &cksum1b); 1073 1075 if( blob_compare(&cksum1, &cksum1b) ){ 1074 1076 fossil_panic("manifest checksum does not agree with manifest: " 1075 1077 "%b versus %b", &cksum1, &cksum1b); 1076 1078 } 1077 1079 if( blob_compare(&cksum1, &cksum2) ){ 1078 1080 fossil_panic("tree checksum does not match manifest after commit: " 1079 1081 "%b versus %b", &cksum1, &cksum2); 1080 1082 } 1081 - 1083 + 1082 1084 /* Verify that the commit did not modify any disk images. */ 1083 1085 vfile_aggregate_checksum_disk(nvid, &cksum2); 1084 1086 if( blob_compare(&cksum1, &cksum2) ){ 1085 1087 fossil_panic("tree checksums before and after commit do not match"); 1086 1088 } 1087 1089 } 1088 1090
Changes to src/clearsign.c.
37 37 return 0; 38 38 } 39 39 zRand = db_text(0, "SELECT hex(randomblob(10))"); 40 40 zOut = mprintf("out-%s", zRand); 41 41 zIn = mprintf("in-%z", zRand); 42 42 blob_write_to_file(pIn, zOut); 43 43 zCmd = mprintf("%s %s %s", zBase, zIn, zOut); 44 - rc = portable_system(zCmd); 44 + rc = fossil_system(zCmd); 45 45 free(zCmd); 46 46 if( rc==0 ){ 47 47 if( pOut==pIn ){ 48 48 blob_reset(pIn); 49 49 } 50 50 blob_zero(pOut); 51 51 blob_read_from_file(pOut, zIn);
Changes to src/db.c.
1521 1521 { "dont-push", 0, 0, "off" }, 1522 1522 { "editor", 0, 16, "" }, 1523 1523 { "gdiff-command", 0, 16, "gdiff" }, 1524 1524 { "ignore-glob", 0, 40, "" }, 1525 1525 { "http-port", 0, 16, "8080" }, 1526 1526 { "localauth", 0, 0, "off" }, 1527 1527 { "manifest", 0, 0, "off" }, 1528 - { "mtime-changes", 0, 0, "off" }, 1528 + { "mtime-changes", 0, 0, "on" }, 1529 1529 { "pgp-command", 0, 32, "gpg --clearsign -o " }, 1530 1530 { "proxy", 0, 32, "off" }, 1531 - { "push-hook-cmd", 0, 32, "" }, 1532 - { "push-hook-force", 1533 - 0, 0, "" }, 1534 - { "push-hook-pattern-client", 1535 - 0, 32, "" }, 1536 - { "push-hook-pattern-server", 1537 - 0, 32, "" }, 1538 - { "push-hook-privilege", 1539 - 0, 1, "" }, 1540 1531 { "repo-cksum", 0, 0, "on" }, 1541 1532 { "ssh-command", 0, 32, "" }, 1542 1533 { "web-browser", 0, 32, "" }, 1543 1534 { 0,0,0,0 } 1544 1535 }; 1545 1536 1546 1537 /* ................................................................................ 1610 1601 ** The default is "gpg --clearsign -o ". 1611 1602 ** 1612 1603 ** proxy URL of the HTTP proxy. If undefined or "off" then 1613 1604 ** the "http_proxy" environment variable is consulted. 1614 1605 ** If the http_proxy environment variable is undefined 1615 1606 ** then a direct HTTP connection is used. 1616 1607 ** 1617 -** push-hook-cmd this is the command line, that will be activated 1618 -** as push hook. Output redirects should be added to 1619 -** this command line. 1620 -** The complete command line looks like: 1621 -** command name: the configured value for push-hook-cmd 1622 -** argument 1: timestamp followed by random-number 1623 -** argument 2: pattern sent by client 1624 -** As fallback, stdin/stderr are redirected to files 1625 -** hook-log-<timestamp followed by random-number> 1626 -** 1627 -** push-hook-force 1628 -** if this is set on the client, it will request always 1629 -** the hook activation, even if no files where pushed on 1630 -** the sync. 1631 -** if this is set on the server, it will accept hook 1632 -** activiation, even if no files where pushed. 1633 -** Default: on 1634 -** 1635 -** push-hook-pattern-client 1636 -** if set, a client push will sent this message to the 1637 -** server, to activate the push hook command. 1638 -** Default: on 1639 -** 1640 -** push-hook-pattern-server 1641 -** if set, and a client send this pattern at the end of 1642 -** a push, the push hook command will be executed. This 1643 -** might be a prefix of the pattern, sent by the client. 1644 -** 1645 -** push-hook-privilege 1646 -** if set, the user doing the push needs this privilege 1647 -** to trigger the hook. Valid privileges are: 1648 -** s (setup), a (admin), i (checkin) or o (checkout) 1649 -** 1650 1608 ** repo-cksum Compute checksums over all files in each checkout 1651 1609 ** as a double-check of correctness. Defaults to "on". 1652 1610 ** Disable on large repositories for a performance 1653 1611 ** improvement. 1654 1612 ** 1655 1613 ** ssh-command Command used to talk to a remote machine with 1656 1614 ** the "ssh://" protocol.
Changes to src/diffcmd.c.
23 23 24 24 /* 25 25 ** Diff option flags 26 26 */ 27 27 #define DIFF_NEWFILE 0x01 /* Treat non-existing fails as empty files */ 28 28 #define DIFF_NOEOLWS 0x02 /* Ignore whitespace at the end of lines */ 29 29 30 -/* 31 -** This function implements a cross-platform "system()" interface. 32 -*/ 33 -int portable_system(const char *zOrigCmd){ 34 - int rc; 35 -#if defined(_WIN32) 36 - /* On windows, we have to put double-quotes around the entire command. 37 - ** Who knows why - this is just the way windows works. 38 - */ 39 - char *zNewCmd = mprintf("\"%s\"", zOrigCmd); 40 - fflush(0); 41 - rc = system(zNewCmd); 42 - free(zNewCmd); 43 -#else 44 - /* On unix, evaluate the command directly. 45 - */ 46 - rc = system(zOrigCmd); 47 -#endif 48 - return rc; 49 -} 50 - 51 30 /* 52 31 ** Show the difference between two files, one in memory and one on disk. 53 32 ** 54 33 ** The difference is the set of edits needed to transform pFile1 into 55 34 ** zFile2. The content of pFile1 is in memory. zFile2 exists on disk. 56 35 ** 57 36 ** Use the internal diff logic if zDiffCmd is NULL. Otherwise call the ................................................................................ 105 84 blob_zero(&cmd); 106 85 blob_appendf(&cmd, "%s ", zDiffCmd); 107 86 shell_escape(&cmd, blob_str(&nameFile1)); 108 87 blob_append(&cmd, " ", 1); 109 88 shell_escape(&cmd, zFile2); 110 89 111 90 /* Run the external diff command */ 112 - portable_system(blob_str(&cmd)); 91 + fossil_system(blob_str(&cmd)); 113 92 114 93 /* Delete the temporary file and clean up memory used */ 115 94 unlink(blob_str(&nameFile1)); 116 95 blob_reset(&nameFile1); 117 96 blob_reset(&cmd); 118 97 } 119 98 } ................................................................................ 159 138 blob_zero(&cmd); 160 139 blob_appendf(&cmd, "%s ", zDiffCmd); 161 140 shell_escape(&cmd, zTemp1); 162 141 blob_append(&cmd, " ", 1); 163 142 shell_escape(&cmd, zTemp2); 164 143 165 144 /* Run the external diff command */ 166 - portable_system(blob_str(&cmd)); 145 + fossil_system(blob_str(&cmd)); 167 146 168 147 /* Delete the temporary file and clean up memory used */ 169 148 unlink(zTemp1); 170 149 unlink(zTemp2); 171 150 blob_reset(&cmd); 172 151 } 173 152 } ................................................................................ 431 410 ** the <a>setting</a> command. If no external diff program is configured, then 432 411 ** the "-i" option is a no-op. The "-i" option converts "gdiff" into 433 412 ** "diff". 434 413 ** 435 414 ** The results of the internal diff command can also be seen in the gui: 436 415 ** 1. Go to the <a href="vdiff">vdiff</a> page 437 416 ** 2. use the "diff against another version" link on the Check-in detail view. 417 +** 418 +** The "-N" or "--new-file" option causes the complete text of added or 419 +** deleted files to be displayed. 438 420 */ 439 421 void diff_cmd(void){ 440 422 int isGDiff; /* True for gdiff. False for normal diff */ 441 423 int isInternDiff; /* True for internal diff */ 442 424 int hasNFlag; /* True if -N or --new-file flag is used */ 443 425 const char *zFrom; /* Source version number */ 444 426 const char *zTo; /* Target version number */
Changes to src/doc.c.
238 238 { "spl", 3, "application/x-futuresplash" }, 239 239 { "src", 3, "application/x-wais-source" }, 240 240 { "step", 4, "application/STEP" }, 241 241 { "stl", 3, "application/SLA" }, 242 242 { "stp", 3, "application/STEP" }, 243 243 { "sv4cpio", 7, "application/x-sv4cpio" }, 244 244 { "sv4crc", 6, "application/x-sv4crc" }, 245 + { "svg", 3, "image/svg+xml" }, 245 246 { "swf", 3, "application/x-shockwave-flash" }, 246 247 { "t", 1, "application/x-troff" }, 247 248 { "tar", 3, "application/x-tar" }, 248 249 { "tcl", 3, "application/x-tcl" }, 249 250 { "tex", 3, "application/x-tex" }, 250 251 { "texi", 4, "application/x-texinfo" }, 251 252 { "texinfo", 7, "application/x-texinfo" },
Changes to src/file.c.
307 307 ** Also test Fossil's ability to measure attributes of a file. 308 308 */ 309 309 void cmd_test_canonical_name(void){ 310 310 int i; 311 311 Blob x; 312 312 blob_zero(&x); 313 313 for(i=2; i<g.argc; i++){ 314 + char zBuf[100]; 314 315 const char *zName = g.argv[i]; 315 316 file_canonical_name(zName, &x); 316 317 printf("%s\n", blob_buffer(&x)); 317 318 blob_reset(&x); 318 - printf(" file_size = %lld\n", file_size(zName)); 319 - printf(" file_mtime = %lld\n", file_mtime(zName)); 319 + sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld", file_size(zName)); 320 + printf(" file_size = %s\n", zBuf); 321 + sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld", file_mtime(zName)); 322 + printf(" file_mtime = %s\n", zBuf); 320 323 printf(" file_isfile = %d\n", file_isfile(zName)); 321 324 printf(" file_isexe = %d\n", file_isexe(zName)); 322 325 printf(" file_isdir = %d\n", file_isdir(zName)); 323 326 } 324 327 } 325 328 326 329 /* ................................................................................ 424 427 ** false, then simply return 0. 425 428 ** 426 429 ** The root of the tree is defined by the g.zLocalRoot variable. 427 430 */ 428 431 int file_tree_name(const char *zOrigName, Blob *pOut, int errFatal){ 429 432 int n; 430 433 Blob full; 434 + int nFull; 435 + char *zFull; 436 + 437 + blob_zero(pOut); 431 438 db_must_be_within_tree(); 432 439 file_canonical_name(zOrigName, &full); 433 440 n = strlen(g.zLocalRoot); 434 - if( blob_size(&full)<=n || memcmp(g.zLocalRoot, blob_buffer(&full), n) ){ 441 + assert( n>0 && g.zLocalRoot[n-1]=='/' ); 442 + nFull = blob_size(&full); 443 + zFull = blob_buffer(&full); 444 + 445 + /* Special case. zOrigName refers to g.zLocalRoot directory. */ 446 + if( nFull==n-1 && memcmp(g.zLocalRoot, zFull, nFull)==0 ){ 447 + blob_append(pOut, ".", 1); 448 + return 1; 449 + } 450 + 451 + if( nFull<=n || memcmp(g.zLocalRoot, zFull, n) ){ 435 452 blob_reset(&full); 436 453 if( errFatal ){ 437 454 fossil_fatal("file outside of checkout tree: %s", zOrigName); 438 455 } 439 456 return 0; 440 457 } 441 - blob_zero(pOut); 442 - blob_append(pOut, blob_buffer(&full)+n, blob_size(&full)-n); 458 + blob_append(pOut, &zFull[n], nFull-n); 443 459 return 1; 444 460 } 445 461 446 462 /* 447 463 ** COMMAND: test-tree-name 448 464 ** 449 465 ** Test the operation of the tree name generator.
Changes to src/finfo.c.
19 19 */ 20 20 #include "config.h" 21 21 #include "finfo.h" 22 22 23 23 /* 24 24 ** COMMAND: finfo 25 25 ** 26 -** Usage: %fossil finfo FILENAME 26 +** Usage: %fossil finfo {?-l|--log? / -s|--status / --p|--print} FILENAME 27 +** 28 +** Print the complete change history for a single file going backwards 29 +** in time. The default is -l. 30 +** 31 +** For the -l|--log option: If "-b|--brief" is specified one line per revision 32 +** is printed, otherwise the full comment is printed. The "--limit N" 33 +** and "--offset P" options limits the output to the first N changes 34 +** after skipping P changes. 27 35 ** 28 -** Print the change history for a single file. 36 +** In the -s form prints the status as <status> <revision>. This is 37 +** a quick status and does not check for up-to-date-ness of the file. 29 38 ** 30 -** The "--limit N" and "--offset P" options limit the output to the first 31 -** N changes after skipping P changes. 39 +** The -p form, there's an optional flag "-r|--revision REVISION". The 40 +** specified version (or the latest checked out version) is printed to 41 +** stdout. 32 42 ** 33 43 ** The history of a file can also be viewed in the gui: 34 44 ** * Go to the <a href="dir">file browser</a> and drill down to the file 35 45 */ 36 46 void finfo_cmd(void){ 37 - Stmt q; 38 47 int vid; 39 - Blob dest; 40 - const char *zFilename; 41 - const char *zLimit; 42 - const char *zOffset; 43 - int iLimit, iOffset; 44 48 45 49 db_must_be_within_tree(); 46 50 vid = db_lget_int("checkout", 0); 47 51 if( vid==0 ){ 48 52 fossil_panic("no checkout to finfo files in"); 49 53 } 50 - zLimit = find_option("limit",0,1); 51 - iLimit = zLimit ? atoi(zLimit) : -1; 52 - zOffset = find_option("offset",0,1); 53 - iOffset = zOffset ? atoi(zOffset) : 0; 54 - if (g.argc<3) { 55 - usage("FILENAME"); 56 - } 57 - file_tree_name(g.argv[2], &dest, 1); 58 - zFilename = blob_str(&dest); 59 - db_prepare(&q, 60 - "SELECT " 61 - " (SELECT uuid FROM blob WHERE rid=mlink.fid)," /* New file */ 62 - " (SELECT uuid FROM blob WHERE rid=mlink.mid)," /* The check-in */ 63 - " date(event.mtime,'localtime')," 64 - " coalesce(event.ecomment, event.comment)," 65 - " coalesce(event.euser, event.user)" 66 - " FROM mlink, event" 67 - " WHERE mlink.fnid=(SELECT fnid FROM filename WHERE name=%Q)" 68 - " AND event.objid=mlink.mid" 69 - " ORDER BY event.mtime DESC LIMIT %d OFFSET %d /*sort*/", 70 - zFilename, iLimit, iOffset 71 - ); 54 + vfile_check_signature(vid, 1); 55 + if (find_option("status","s",0)) { 56 + Stmt q; 57 + Blob line; 58 + Blob fname; 59 + 60 + if( g.argc!=3 ) usage("-s|--status FILENAME"); 61 + file_tree_name(g.argv[2], &fname, 1); 62 + db_prepare(&q, 63 + "SELECT pathname, deleted, rid, chnged, coalesce(origname!=pathname,0)" 64 + " FROM vfile WHERE vfile.pathname=%B", &fname); 65 + blob_zero(&line); 66 + if ( db_step(&q)==SQLITE_ROW ) { 67 + Blob uuid; 68 + int isDeleted = db_column_int(&q, 1); 69 + int isNew = db_column_int(&q,2) == 0; 70 + int chnged = db_column_int(&q,3); 71 + int renamed = db_column_int(&q,4); 72 + 73 + blob_zero(&uuid); 74 + db_blob(&uuid, 75 + "SELECT uuid FROM blob, mlink, vfile WHERE " 76 + "blob.rid = mlink.mid AND mlink.fid = vfile.rid AND " 77 + "vfile.pathname=%B", 78 + &fname 79 + ); 80 + if( isNew ){ 81 + blob_appendf(&line, "new"); 82 + }else if( isDeleted ){ 83 + blob_appendf(&line, "deleted"); 84 + }else if( renamed ){ 85 + blob_appendf(&line, "renamed"); 86 + }else if( chnged ){ 87 + blob_appendf(&line, "edited"); 88 + }else{ 89 + blob_appendf(&line, "unchanged"); 90 + } 91 + blob_appendf(&line, " "); 92 + blob_appendf(&line, " %10.10s", blob_str(&uuid)); 93 + blob_reset(&uuid); 94 + }else{ 95 + blob_appendf(&line, "unknown 0000000000"); 96 + } 97 + db_finalize(&q); 98 + printf("%s\n", blob_str(&line)); 99 + blob_reset(&fname); 100 + blob_reset(&line); 101 + }else if( find_option("print","p",0) ){ 102 + Blob record; 103 + Blob fname; 104 + const char *zRevision = find_option("revision", "r", 1); 72 105 73 - printf("History of %s\n", zFilename); 74 - while( db_step(&q)==SQLITE_ROW ){ 75 - const char *zFileUuid = db_column_text(&q, 0); 76 - const char *zCiUuid = db_column_text(&q, 1); 77 - const char *zDate = db_column_text(&q, 2); 78 - const char *zCom = db_column_text(&q, 3); 79 - const char *zUser = db_column_text(&q, 4); 80 - char *zOut; 81 - printf("%s ", zDate); 82 - if( zFileUuid==0 ){ 83 - zOut = sqlite3_mprintf("[%.10s] DELETED %s (user: %s)", 84 - zCiUuid, zCom, zUser); 106 + file_tree_name(g.argv[2], &fname, 1); 107 + if( zRevision ){ 108 + historical_version_of_file(zRevision, blob_str(&fname), &record, 0); 85 109 }else{ 86 - zOut = sqlite3_mprintf("[%.10s] %s (user: %s, artifact: [%.10s])", 87 - zCiUuid, zCom, zUser, zFileUuid); 110 + int rid = db_int(0, "SELECT rid FROM vfile WHERE pathname=%B", &fname); 111 + if( rid==0 ){ 112 + fossil_fatal("no history for file: %b", &fname); 113 + } 114 + content_get(rid, &record); 115 + } 116 + blob_write_to_file(&record, "-"); 117 + blob_reset(&record); 118 + blob_reset(&fname); 119 + }else{ 120 + Blob line; 121 + Stmt q; 122 + Blob fname; 123 + int rid; 124 + const char *zFilename; 125 + const char *zLimit; 126 + const char *zOffset; 127 + int iLimit, iOffset, iBrief; 128 + 129 + if( find_option("log","l",0) ){ 130 + /* this is the default, no-op */ 131 + } 132 + zLimit = find_option("limit",0,1); 133 + iLimit = zLimit ? atoi(zLimit) : -1; 134 + zOffset = find_option("offset",0,1); 135 + iOffset = zOffset ? atoi(zOffset) : 0; 136 + iBrief = (find_option("brief","b",0) == 0); 137 + if( g.argc!=3 ){ 138 + usage("?-l|--log? ?-b|--brief? FILENAME"); 139 + } 140 + file_tree_name(g.argv[2], &fname, 1); 141 + rid = db_int(0, "SELECT rid FROM vfile WHERE pathname=%B", &fname); 142 + if( rid==0 ){ 143 + fossil_fatal("no history for file: %b", &fname); 144 + } 145 + zFilename = blob_str(&fname); 146 + db_prepare(&q, 147 + "SELECT b.uuid, ci.uuid, date(event.mtime,'localtime')," 148 + " coalesce(event.ecomment, event.comment)," 149 + " coalesce(event.euser, event.user)" 150 + " FROM mlink, blob b, event, blob ci" 151 + " WHERE mlink.fnid=(SELECT fnid FROM filename WHERE name=%Q)" 152 + " AND b.rid=mlink.fid" 153 + " AND event.objid=mlink.mid" 154 + " AND event.objid=ci.rid" 155 + " ORDER BY event.mtime DESC LIMIT %d OFFSET %d", 156 + zFilename, iLimit, iOffset 157 + ); 158 + blob_zero(&line); 159 + if( iBrief ){ 160 + printf("History of %s\n", blob_str(&fname)); 161 + } 162 + while( db_step(&q)==SQLITE_ROW ){ 163 + const char *zFileUuid = db_column_text(&q, 0); 164 + const char *zCiUuid = db_column_text(&q,1); 165 + const char *zDate = db_column_text(&q, 2); 166 + const char *zCom = db_column_text(&q, 3); 167 + const char *zUser = db_column_text(&q, 4); 168 + char *zOut; 169 + if( iBrief ){ 170 + printf("%s ", zDate); 171 + zOut = sqlite3_mprintf("[%.10s] %s (user: %s, artifact: [%.10s])", 172 + zCiUuid, zCom, zUser, zFileUuid); 173 + comment_print(zOut, 11, 79); 174 + sqlite3_free(zOut); 175 + }else{ 176 + blob_reset(&line); 177 + blob_appendf(&line, "%.10s ", zCiUuid); 178 + blob_appendf(&line, "%.10s ", zDate); 179 + blob_appendf(&line, "%8.8s ", zUser); 180 + blob_appendf(&line,"%-40.40s\n", zCom ); 181 + comment_print(blob_str(&line), 0, 79); 182 + } 88 183 } 89 - comment_print(zOut, 11, 79); 90 - sqlite3_free(zOut); 184 + db_finalize(&q); 185 + blob_reset(&fname); 91 186 } 92 - db_finalize(&q); 93 - blob_reset(&dest); 94 187 } 95 188 96 189 97 190 /* 98 191 ** WEBPAGE: finfo 99 192 ** URL: /finfo?name=FILENAME 100 193 **
Changes to src/http.c.
101 101 blob_zero(pHdr); 102 102 i = strlen(g.urlPath); 103 103 if( i>0 && g.urlPath[i-1]=='/' ){ 104 104 zSep = ""; 105 105 }else{ 106 106 zSep = "/"; 107 107 } 108 - blob_appendf(pHdr, "POST %s%sxfer HTTP/1.0\r\n", g.urlPath, zSep); 108 + blob_appendf(pHdr, "POST %s%sxfer/xfer HTTP/1.0\r\n", g.urlPath, zSep); 109 109 if( g.urlProxyAuth ){ 110 110 blob_appendf(pHdr, "Proxy-Authorization: %s\n", g.urlProxyAuth); 111 111 } 112 112 blob_appendf(pHdr, "Host: %s\r\n", g.urlHostname); 113 113 blob_appendf(pHdr, "User-Agent: Fossil/" MANIFEST_VERSION "\r\n"); 114 114 if( g.fHttpTrace ){ 115 115 blob_appendf(pHdr, "Content-Type: application/x-fossil-debug\r\n"); ................................................................................ 224 224 closeConnection = 0; 225 225 } 226 226 }else if( rc==302 && strncasecmp(zLine, "location:", 9)==0 ){ 227 227 int i, j; 228 228 for(i=9; zLine[i] && zLine[i]==' '; i++){} 229 229 if( zLine[i]==0 ) fossil_fatal("malformed redirect: %s", zLine); 230 230 j = strlen(zLine) - 1; 231 - if( j>4 && strcmp(&zLine[j-4],"/xfer")==0 ) zLine[j-4] = 0; 231 + while( j>4 && strcmp(&zLine[j-4],"/xfer")==0 ){ 232 + j -= 4; 233 + zLine[j] = 0; 234 + } 232 235 fossil_print("redirect to %s\n", &zLine[i]); 233 236 url_parse(&zLine[i]); 234 237 transport_close(); 235 238 http_exchange(pSend, pReply, useLogin); 236 239 return; 237 240 }else if( strncasecmp(zLine, "content-type: text/html", 23)==0 ){ 238 241 isError = 1;
Changes to src/http_transport.c.
294 294 fprintf(sshOut, "\n\n"); 295 295 }else if( g.urlIsFile ){ 296 296 char *zCmd; 297 297 fclose(transport.pFile); 298 298 zCmd = mprintf("\"%s\" http \"%s\" \"%s\" \"%s\" 127.0.0.1", 299 299 g.argv[0], g.urlName, transport.zOutFile, transport.zInFile 300 300 ); 301 - portable_system(zCmd); 301 + fossil_system(zCmd); 302 302 free(zCmd); 303 303 transport.pFile = fopen(transport.zInFile, "rb"); 304 304 } 305 305 } 306 306 307 307 /* 308 308 ** This routine is called when the inbound message has been received
Changes to src/login.c.
49 49 50 50 /* 51 51 ** Return the name of the login cookie 52 52 */ 53 53 static char *login_cookie_name(void){ 54 54 static char *zCookieName = 0; 55 55 if( zCookieName==0 ){ 56 - int n = strlen(g.zTop); 57 - zCookieName = fossil_malloc( n*2+16 ); 58 - /* 0123456789 12345 */ 59 - strcpy(zCookieName, "fossil_login_"); 60 - encode16((unsigned char*)g.zTop, (unsigned char*)&zCookieName[13], n); 56 + unsigned int h = 0; 57 + const char *z = g.zBaseURL; 58 + while( *z ){ h = (h<<3) ^ (h>>26) ^ *(z++); } 59 + zCookieName = mprintf("fossil_login_%08x", h); 61 60 } 62 61 return zCookieName; 63 62 } 64 63 65 64 /* 66 65 ** Redirect to the page specified by the "g" query parameter. 67 66 ** Or if there is no "g" query parameter, redirect to the homepage.
Changes to src/main.c.
221 221 /* 222 222 ** This procedure runs first. 223 223 */ 224 224 int main(int argc, char **argv){ 225 225 const char *zCmdName = "unknown"; 226 226 int idx; 227 227 int rc; 228 + int mightBeCgi; 228 229 229 230 sqlite3_config(SQLITE_CONFIG_LOG, fossil_sqlite_log, 0); 230 231 g.now = time(0); 231 232 g.argc = argc; 232 233 g.argv = argv; 233 - if( getenv("GATEWAY_INTERFACE")!=0 ){ 234 - zCmdName = "cgi"; 235 - }else if( argc<2 ){ 236 - fprintf(stderr, "Usage: %s COMMAND ...\n" 237 - "\"%s help\" for a list of available commands\n" 238 - "\"%s help COMMAND\" for specific details\n", 239 - argv[0], argv[0], argv[0]); 240 - fossil_exit(1); 234 + mightBeCgi = getenv("GATEWAY_INTERFACE")!=0; 235 + if( argc<2 ){ 236 + if( mightBeCgi ){ 237 + zCmdName = "cgi"; 238 + }else{ 239 + fprintf(stderr, "Usage: %s COMMAND ...\n" 240 + "\"%s help\" for a list of available commands\n" 241 + "\"%s help COMMAND\" for specific details\n", 242 + argv[0], argv[0], argv[0]); 243 + fossil_exit(1); 244 + } 241 245 }else{ 242 246 g.fQuiet = find_option("quiet", 0, 0)!=0; 243 247 g.fSqlTrace = find_option("sqltrace", 0, 0)!=0; 244 248 g.fSqlPrint = find_option("sqlprint", 0, 0)!=0; 245 249 g.fHttpTrace = find_option("httptrace", 0, 0)!=0; 246 250 g.zLogin = find_option("user", "U", 1); 247 251 zCmdName = argv[1]; 248 252 } 249 253 rc = name_search(zCmdName, aCommand, count(aCommand), &idx); 254 + if( rc==1 && mightBeCgi ){ 255 + rc = name_search("cgi", aCommand, count(aCommand), &idx); 256 + } 250 257 if( rc==1 ){ 251 258 fprintf(stderr,"%s: unknown command: %s\n" 252 259 "%s: use \"help\" for more information\n", 253 260 argv[0], zCmdName, argv[0]); 254 261 fossil_exit(1); 255 262 }else if( rc==2 ){ 256 263 fprintf(stderr,"%s: ambiguous command prefix: %s\n" ................................................................................ 374 381 free(p); 375 382 } 376 383 void *fossil_realloc(void *p, size_t n){ 377 384 p = realloc(p, n); 378 385 if( p==0 ) fossil_panic("out of memory"); 379 386 return p; 380 387 } 388 + 389 +/* 390 +** This function implements a cross-platform "system()" interface. 391 +*/ 392 +int fossil_system(const char *zOrigCmd){ 393 + int rc; 394 +#if defined(_WIN32) 395 + /* On windows, we have to put double-quotes around the entire command. 396 + ** Who knows why - this is just the way windows works. 397 + */ 398 + char *zNewCmd = mprintf("\"%s\"", zOrigCmd); 399 + rc = system(zNewCmd); 400 + free(zNewCmd); 401 +#else 402 + /* On unix, evaluate the command directly. 403 + */ 404 + rc = system(zOrigCmd); 405 +#endif 406 + return rc; 407 +} 408 + 381 409 382 410 383 411 /* 384 412 ** Return a name for an SQLite error code 385 413 */ 386 414 static const char *sqlite_error_code_name(int iCode){ 387 415 static char zCode[30]; ................................................................................ 627 655 } 628 656 629 657 /* 630 658 ** WEBPAGE: help 631 659 ** URL: /help?cmd=CMD 632 660 */ 633 661 void help_page(void){ 634 - const char * zCmd = P("cmd"); 635 - 636 - style_header("Command line help %s%s",zCmd?" - ":"",zCmd?zCmd:""); 637 - if( zCmd && zCmd[0] && strcmp(zCmd,"test") ){ 638 - int rc, idx; 662 + const char * zCmd = P("cmd"); 663 + 664 + style_header("Command line help %s%s",zCmd?" - ":"",zCmd?zCmd:""); 665 + if( zCmd && zCmd[0] && strcmp(zCmd,"test") ){ 666 + int rc, idx; 639 667 640 - rc = name_search(zCmd, aCommand, count(aCommand), &idx); 641 - if( rc==1 ){ 642 - @ <h1>unknown command: %s(zCmd)</h1> 643 - }else if( rc==2 ){ 644 - @ <h1>ambiguous command prefix: %s(zCmd)</h1> 668 + rc = name_search(zCmd, aCommand, count(aCommand), &idx); 669 + if( rc==1 ){ 670 + @ <h1>unknown command: %s(zCmd)</h1> 671 + }else if( rc==2 ){ 672 + @ <h1>ambiguous command prefix: %s(zCmd)</h1> 673 + }else{ 674 + const char *zHelp; 675 + int i; 676 + 677 + zHelp = aCmdHelp[idx]; 678 + @ <h1>%s(aCommand[idx].zName)</h1> 679 + if( zHelp==0 || zHelp[0]==0 ){ 680 + @ no help available for the %s(aCommand[idx].zName) command 645 681 }else{ 646 - char *zSrc, *zDest; 647 - int src,dest,len; 648 - 649 - @ <h1>%s(aCommand[idx].zName)</h1> 650 - zSrc = (char*)aCmdHelp[idx]; 651 - if( zSrc==0 || *zSrc==0 ){ 652 - @ no help available for the %s(aCommand[idx].zName) command 653 - }else{ 654 - len = strlen(zSrc); 655 - zDest = malloc(len+1); 656 - for(src=dest=0;zSrc[src];){ 657 - if( zSrc[src]=='%' && strncmp(zSrc+src, "%fossil", 7)==0 ){ 658 - src++; /* skip % for fossil argv[0] expansion */ 659 - }else if( zSrc[src]=='<' && strncmp(zSrc+src, "</a>", 3)==0 ){ 660 - src += 4; 661 - zDest[dest++]='<'; 662 - zDest[dest++]='/'; 663 - zDest[dest++]='a'; 664 - zDest[dest++]='>'; 665 - zDest[dest++]='"'; 666 - }else if( zSrc[src]=='<' && strncmp(zSrc+src, "<a ", 3)==0 ){ 667 - len += 2; 668 - zDest=realloc(zDest,len); 669 - zDest[dest++]='"'; 670 - while( zSrc[src] && zSrc[src]!='>' ){ 671 - zDest[dest++]=zSrc[src++]; 672 - } 673 - if( zSrc[src] ) zDest[dest++]=zSrc[src++]; 674 - }else if( zSrc[src]=='<' && strncmp(zSrc+src, "<a>", 3)==0 ){ 675 - /* found an internal command cross reference, 676 - ** create an additional link 677 - */ 678 - int start; 679 - 680 - len+=80; 681 - zDest=realloc(zDest,len); 682 - zDest[dest++]='"'; 683 - zDest[dest++]=zSrc[src++]; /* < */ 684 - zDest[dest++]=zSrc[src++]; /* a */ 685 - zDest[dest++]=' '; 686 - zDest[dest++]='h'; 687 - zDest[dest++]='r'; 688 - zDest[dest++]='e'; 689 - zDest[dest++]='f'; 690 - zDest[dest++]='='; 691 - zDest[dest++]='"'; 692 - zDest[dest++]='h'; 693 - zDest[dest++]='e'; 694 - zDest[dest++]='l'; 695 - zDest[dest++]='p'; 696 - zDest[dest++]='?'; 697 - zDest[dest++]='c'; 698 - zDest[dest++]='m'; 699 - zDest[dest++]='d'; 700 - zDest[dest++]='='; 701 - start = src+1; 702 - for( src=start; zSrc[src] && zSrc[src]!='<'; ){ 703 - zDest[dest++]=zSrc[src++]; /* command name */ 704 - } 705 - zDest[dest++]='"'; 706 - zDest[dest++]='>'; 707 - for( src=start; zSrc[src] && zSrc[src]!='<'; ){ 708 - zDest[dest++]=zSrc[src++]; /* command name */ 709 - } 710 - }else{ 711 - zDest[dest++] = zSrc[src++]; 682 + int c; 683 + @ <div class="cmdhelp"> 684 + for(i=0; (c = zHelp[i])!=0; i++){ 685 + if( c=='%' && memcmp(zHelp+i, "%fossil", 7)==0 ){ 686 + /* Skip over the "%" */ 687 + cgi_append_content(zHelp, i); 688 + i++; 689 + zHelp += i; 690 + i = 0; 691 + }else if( c=='<' && memcmp(zHelp+i, "</a>", 3)==0 ){ 692 + cgi_append_content(zHelp, i+4); 693 + zHelp += i+4; 694 + i = -1; 695 + cgi_append_content("\"", 1); 696 + }else if( c=='<' && memcmp(zHelp+i, "<a ", 3)==0 ){ 697 + cgi_append_content(zHelp, i); 698 + cgi_append_content("\"", 1); 699 + zHelp += i; 700 + i = 0; 701 + }else if( c=='<' && strncmp(zHelp+i, "<a>", 3)==0 ){ 702 + /* found an internal command cross reference, 703 + ** create an additional link 704 + */ 705 + cgi_append_content(zHelp, i); 706 + cgi_append_content("\"<a href=\"help?cmd=", -1); 707 + zHelp += i+3; 708 + i = 0; 709 + while( zHelp[i] && memcmp(zHelp+i,"</a>",4)!=0 ){ 710 + i++; 712 711 } 712 + cgi_append_content(zHelp, i); 713 + cgi_append_content("\">", -1); 714 + cgi_append_content(zHelp, i); 715 + cgi_append_content("</a>\"", -1); 716 + zHelp += i+4; 717 + i = -1; 713 718 } 714 - zDest[dest] = 0; 715 - @ <div class="cmdhelp">%s(zDest)</div> 716 - free(zDest); 717 - @ <hr/>additional information may be found in the web documentation: 718 - @ <a href="http://www.fossil-scm.org/fossil/doc/tip/www/cmd_%s(aCommand[idx].zName).wiki"> 719 - @ cmd_%s(aCommand[idx].zName)</a>, 720 719 } 720 + cgi_append_content(zHelp, i); 721 + @ </div> 722 + } 723 + } 724 + @ see also the list of 725 + @ <a href="help">available commands</a> in fossil 726 + @ version %s(MANIFEST_VERSION" "MANIFEST_DATE) UTC 727 + }else{ 728 + int nCol, nRow, i, ignored, cnt, showTest; 729 + 730 + /* detect, if we show normal or test commands */ 731 + showTest = ( zCmd && !strncmp(zCmd,"test",4) ); 732 + for( i=0,ignored=0; i<count(aCommand); i++){ 733 + if( (strncmp(aCommand[i].zName,"test",4)==0) ^ showTest ) ignored++; 734 + } 735 + nCol = 4; 736 + nRow = (count(aCommand)-ignored+nCol-1)/nCol; 737 + @ <h1>Available commands</h1> 738 + @ <table class="browser"><tr><td class="browser"><ul class="browser"> 739 + for( i=cnt=0; i<count(aCommand); i++ ){ 740 + if( cnt==nRow ){ 741 + @ </ul></td><td class="browser"><ul class="browser"> 742 + cnt=0; 721 743 } 722 - @ see also the list of 723 - @ <a href="help">available commands</a> in fossil 724 - @ version %s(MANIFEST_VERSION" "MANIFEST_DATE) UTC 744 + if( (strncmp(aCommand[i].zName,"test",4)==0) ^ showTest ) continue; 745 + @ <li><kbd><a href="help?cmd=%s(aCommand[i].zName)"> 746 + @ %s(aCommand[i].zName)</a></kbd></li> 747 + cnt++; 748 + } 749 + @ </ul></td></tr></table> 750 + if( showTest ){ 751 + @ <a href="help">show standard commands</a> 725 752 }else{ 726 - int nCol, nRow, i, ignored, cnt, showTest; 727 - 728 - /* detect, if we show normal or test commands */ 729 - showTest = ( zCmd && !strncmp(zCmd,"test",4) ); 730 - for( i=0,ignored=0; i<count(aCommand); i++){ 731 - if( (strncmp(aCommand[i].zName,"test",4)==0) ^ showTest ) ignored++; 732 - } 733 - nCol = 4; 734 - nRow = (count(aCommand)-ignored+nCol-1)/nCol; 735 - @ <h1>Available commands</h1> 736 - @ <table class="browser"><tr><td class="browser"><ul class="browser"> 737 - for( i=cnt=0; i<count(aCommand); i++ ){ 738 - if( cnt==nRow ){ 739 - @ </ul></td><td class="browser"><ul class="browser"> 740 - cnt=0; 741 - } 742 - if( (strncmp(aCommand[i].zName,"test",4)==0) ^ showTest ) continue; 743 - @ <li><kbd><a href="help?cmd=%s(aCommand[i].zName)"> 744 - @ %s(aCommand[i].zName)</a></kbd></li> 745 - cnt++; 746 - } 747 - @ </ul></td></tr></table> 748 - if( showTest ){ 749 - @ <a href="help">show standard commands</a> 750 - }else{ 751 - @ <a class="hidden" href="help?cmd=test">show test commands</a> 752 - } 753 - @ <hr/>fossil version %s(MANIFEST_VERSION" "MANIFEST_DATE) UTC 753 + @ <a class="hidden" href="help?cmd=test">show test commands</a> 754 754 } 755 - style_footer(); 755 + } 756 + style_footer(); 756 757 } 757 758 758 759 /* 759 760 ** Set the g.zBaseURL value to the full URL for the toplevel of 760 761 ** the fossil tree. Set g.zTop to g.zBaseURL without the 761 762 ** leading "http://" and the host and port. 762 763 */ ................................................................................ 1241 1242 zBrowser = db_get("web-browser", "start"); 1242 1243 zBrowserCmd = mprintf("%s http://127.0.0.1:%%d/", zBrowser); 1243 1244 } 1244 1245 db_close(); 1245 1246 win32_http_server(iPort, mxPort, zBrowserCmd, zStopperFile, zNotFound, flags); 1246 1247 #endif 1247 1248 } 1249 + 1250 +/* 1251 +** COMMAND: sqlite3 1252 +** 1253 +** Usage: %fossil sqlite3 ?DATABASE? ?OPTIONS? 1254 +** 1255 +** Run the standalone sqlite3 command-line shell on DATABASE with OPTIONS. 1256 +** If DATABASE is omitted, then the repository that serves the working 1257 +** directory is opened. 1258 +** 1259 +** WARNING: Careless use of this command can corrupt a Fossil repository 1260 +** in ways that are unrecoverable. Be sure you know what you are doing before 1261 +** running any SQL commands that modifies the repository database. 1262 +*/ 1263 +void sqlite3_cmd(void){ 1264 + extern int sqlite3_shell(int, char**); 1265 + sqlite3_shell(g.argc-1, g.argv+1); 1266 +} 1267 + 1268 +/* 1269 +** This routine is called by the patched sqlite3 command-line shell in order 1270 +** to load the name and database connection for the open Fossil database. 1271 +*/ 1272 +void fossil_open(sqlite3 **pDb, const char **pzRepoName){ 1273 + db_must_be_within_tree(); 1274 + *pDb = 0; 1275 + *pzRepoName = g.zRepositoryName; 1276 +}
Changes to src/main.mk.
262 262 $(TCLSH) test/tester.tcl $(APPNAME) 263 263 264 264 VERSION.h: $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest 265 265 awk '{ printf "#define MANIFEST_UUID \"%s\"\n", $$1}' $(SRCDIR)/../manifest.uuid >VERSION.h 266 266 awk '{ printf "#define MANIFEST_VERSION \"[%.10s]\"\n", $$1}' $(SRCDIR)/../manifest.uuid >>VERSION.h 267 267 awk '$$1=="D"{printf "#define MANIFEST_DATE \"%s %s\"\n", substr($$2,1,10),substr($$2,12)}' $(SRCDIR)/../manifest >>VERSION.h 268 268 269 -$(APPNAME): headers $(OBJ) $(OBJDIR)/sqlite3.o $(OBJDIR)/th.o $(OBJDIR)/th_lang.o 270 - $(TCC) -o $(APPNAME) $(OBJ) $(OBJDIR)/sqlite3.o $(OBJDIR)/th.o $(OBJDIR)/th_lang.o $(LIB) 269 +EXTRAOBJ = $(OBJDIR)/sqlite3.o $(OBJDIR)/shell.o $(OBJDIR)/th.o $(OBJDIR)/th_lang.o 270 + 271 +$(APPNAME): headers $(OBJ) $(EXTRAOBJ) 272 + $(TCC) -o $(APPNAME) $(OBJ) $(EXTRAOBJ) $(LIB) 271 273 272 274 # This rule prevents make from using its default rules to try build 273 275 # an executable named "manifest" out of the file named "manifest.c" 274 276 # 275 277 $(SRCDIR)/../manifest: 276 278 # noop 277 279 ................................................................................ 790 792 $(OBJDIR)/zip.o: zip_.c zip.h $(SRCDIR)/config.h 791 793 $(XTCC) -o $(OBJDIR)/zip.o -c zip_.c 792 794 793 795 zip.h: headers 794 796 $(OBJDIR)/sqlite3.o: $(SRCDIR)/sqlite3.c 795 797 $(XTCC) -DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -Dlocaltime=fossil_localtime -DSQLITE_ENABLE_LOCKING_STYLE=0 -c $(SRCDIR)/sqlite3.c -o $(OBJDIR)/sqlite3.o 796 798 799 +$(OBJDIR)/shell.o: $(SRCDIR)/shell.c 800 + $(XTCC) -Dmain=sqlite3_shell -DSQLITE_OMIT_LOAD_EXTENSION=1 -c $(SRCDIR)/shell.c -o $(OBJDIR)/shell.o 801 + 797 802 $(OBJDIR)/th.o: $(SRCDIR)/th.c 798 803 $(XTCC) -I$(SRCDIR) -c $(SRCDIR)/th.c -o $(OBJDIR)/th.o 799 804 800 805 $(OBJDIR)/th_lang.o: $(SRCDIR)/th_lang.c 801 806 $(XTCC) -I$(SRCDIR) -c $(SRCDIR)/th_lang.c -o $(OBJDIR)/th_lang.o 802 807
Changes to src/makemake.tcl.
146 146 $(SRCDIR)/../manifest.uuid >VERSION.h 147 147 awk '{ printf "#define MANIFEST_VERSION \"[%.10s]\"\n", $$1}' \ 148 148 $(SRCDIR)/../manifest.uuid >>VERSION.h 149 149 awk '$$1=="D"{printf "#define MANIFEST_DATE \"%s %s\"\n",\ 150 150 substr($$2,1,10),substr($$2,12)}' \ 151 151 $(SRCDIR)/../manifest >>VERSION.h 152 152 153 -$(APPNAME): headers $(OBJ) $(OBJDIR)/sqlite3.o $(OBJDIR)/th.o $(OBJDIR)/th_lang.o 154 - $(TCC) -o $(APPNAME) $(OBJ) $(OBJDIR)/sqlite3.o $(OBJDIR)/th.o $(OBJDIR)/th_lang.o $(LIB) 153 +EXTRAOBJ = \ 154 + $(OBJDIR)/sqlite3.o \ 155 + $(OBJDIR)/shell.o \ 156 + $(OBJDIR)/th.o \ 157 + $(OBJDIR)/th_lang.o 158 + 159 +$(APPNAME): headers $(OBJ) $(EXTRAOBJ) 160 + $(TCC) -o $(APPNAME) $(OBJ) $(EXTRAOBJ) $(LIB) 155 161 156 162 # This rule prevents make from using its default rules to try build 157 163 # an executable named "manifest" out of the file named "manifest.c" 158 164 # 159 165 $(SRCDIR)/../manifest: 160 166 # noop 161 167 ................................................................................ 199 205 set opt {-DSQLITE_OMIT_LOAD_EXTENSION=1} 200 206 append opt " -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4" 201 207 #append opt " -DSQLITE_ENABLE_FTS3=1" 202 208 append opt " -Dlocaltime=fossil_localtime" 203 209 append opt " -DSQLITE_ENABLE_LOCKING_STYLE=0" 204 210 puts "\t\$(XTCC) $opt -c \$(SRCDIR)/sqlite3.c -o \$(OBJDIR)/sqlite3.o\n" 205 211 212 +puts "\$(OBJDIR)/shell.o:\t\$(SRCDIR)/shell.c" 213 +set opt {-Dmain=sqlite3_shell} 214 +append opt " -DSQLITE_OMIT_LOAD_EXTENSION=1" 215 +puts "\t\$(XTCC) $opt -c \$(SRCDIR)/shell.c -o \$(OBJDIR)/shell.o\n" 216 + 206 217 puts "\$(OBJDIR)/th.o:\t\$(SRCDIR)/th.c" 207 218 puts "\t\$(XTCC) -I\$(SRCDIR) -c \$(SRCDIR)/th.c -o \$(OBJDIR)/th.o\n" 208 219 209 220 puts "\$(OBJDIR)/th_lang.o:\t\$(SRCDIR)/th_lang.c" 210 221 puts "\t\$(XTCC) -I\$(SRCDIR) -c \$(SRCDIR)/th_lang.c -o \$(OBJDIR)/th_lang.o\n" 211 222 exit 212 223 } ................................................................................ 245 256 puts -nonewline "${s}_.c " 246 257 } 247 258 puts "\n" 248 259 puts -nonewline "OBJ = " 249 260 foreach s [lsort $src] { 250 261 puts -nonewline "\$(OBJDIR)\\$s\$O " 251 262 } 252 -puts "\$(OBJDIR)\\sqlite3\$O \$(OBJDIR)\\th\$O \$(OBJDIR)\\th_lang\$O " 263 +puts "\$(OBJDIR)\\shell\$O \$(OBJDIR)\\sqlite3\$O \$(OBJDIR)\\th\$O \$(OBJDIR)\\th_lang\$O " 253 264 puts { 265 +RC=$(DMDIR)\bin\rcc 266 +RCFLAGS=-32 -w1 -I$(SRCDIR) /D__DMC__ 254 267 255 268 APPNAME = $(OBJDIR)\fossil$(E) 256 269 257 270 all: $(APPNAME) 258 271 259 -$(APPNAME) : translate$E mkindex$E headers $(OBJ) $(OBJDIR)\link 272 +$(APPNAME) : translate$E mkindex$E headers fossil.res $(OBJ) $(OBJDIR)\link 260 273 cd $(OBJDIR) 261 274 $(DMDIR)\bin\link @link 262 275 276 +fossil.res: $B\win\fossil.rc VERSION.h 277 + $(RC) $(RCFLAGS) -o$@ $B\win\fossil.rc 278 + 263 279 $(OBJDIR)\link: $B\win\Makefile.dmc} 264 280 puts -nonewline "\t+echo " 265 281 foreach s [lsort $src] { 266 282 puts -nonewline "$s " 267 283 } 268 -puts "sqlite3 th th_lang > \$@" 284 +puts "shell sqlite3 th th_lang > \$@" 269 285 puts "\t+echo fossil >> \$@" 270 286 puts "\t+echo fossil >> \$@" 271 -puts "\t+echo \$(LIBS) >> \$@\n\n" 287 +puts "\t+echo \$(LIBS) >> \$@" 288 +puts "\t+echo. >> \$@" 289 +puts "\t+echo fossil >> \$@\n\n" 272 290 273 291 puts { 274 292 translate$E: $(SRCDIR)\translate.c 275 293 $(BCC) -o$@ $** 276 294 277 295 makeheaders$E: $(SRCDIR)\makeheaders.c 278 296 $(BCC) -o$@ $** ................................................................................ 279 297 280 298 mkindex$E: $(SRCDIR)\mkindex.c 281 299 $(BCC) -o$@ $** 282 300 283 301 version$E: $B\win\version.c 284 302 $(BCC) -o$@ $** 285 303 304 +$(OBJDIR)\shell$O : $(SRCDIR)\shell.c 305 + $(TCC) -o$@ -c -Dmain=sqlite3_shell -DSQLITE_OMIT_LOAD_EXTENSION=1 $** 306 + 286 307 $(OBJDIR)\sqlite3$O : $(SRCDIR)\sqlite3.c 287 308 $(TCC) -o$@ -c -DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -Dlocaltime=fossil_localtime -DSQLITE_ENABLE_LOCKING_STYLE=0 $** 288 309 289 310 $(OBJDIR)\th$O : $(SRCDIR)\th.c 290 311 $(TCC) -o$@ -c $** 291 312 292 313 $(OBJDIR)\th_lang$O : $(SRCDIR)\th_lang.c ................................................................................ 300 321 301 322 clean: 302 323 -del $(OBJDIR)\*.obj 303 324 -del *.obj *_.c *.h *.map 304 325 305 326 realclean: 306 327 -del $(APPNAME) translate$E mkindex$E makeheaders$E version$E 328 + -del fossil.res headers link 307 329 308 330 } 309 331 foreach s [lsort $src] { 310 332 puts "\$(OBJDIR)\\$s\$O : ${s}_.c ${s}.h" 311 333 puts "\t\$(TCC) -o\$@ -c ${s}_.c\n" 312 334 puts "${s}_.c : \$(SRCDIR)\\$s.c" 313 335 puts "\t+translate\$E \$** > \$@\n"
Changes to src/merge.c.
71 71 if( vid==0 ){ 72 72 fossil_fatal("nothing is checked out"); 73 73 } 74 74 mid = name_to_rid(g.argv[2]); 75 75 if( mid==0 ){ 76 76 fossil_fatal("not a version: %s", g.argv[2]); 77 77 } 78 - if( mid>1 && !db_exists("SELECT 1 FROM plink WHERE cid=%d", mid) ){ 78 + if( !is_a_version(mid) ){ 79 79 fossil_fatal("not a version: %s", g.argv[2]); 80 80 } 81 81 if( pickFlag || backoutFlag ){ 82 82 pid = db_int(0, "SELECT pid FROM plink WHERE cid=%d AND isprim", mid); 83 83 if( pid<=0 ){ 84 84 fossil_fatal("cannot find an ancestor for %s", g.argv[2]); 85 85 } ................................................................................ 94 94 db_prepare(&q, "SELECT merge FROM vmerge WHERE id=0"); 95 95 while( db_step(&q)==SQLITE_ROW ){ 96 96 pivot_set_secondary(db_column_int(&q,0)); 97 97 } 98 98 db_finalize(&q); 99 99 pid = pivot_find(); 100 100 if( pid<=0 ){ 101 - fossil_fatal("cannot find a common ancestor between the current" 101 + fossil_fatal("cannot find a common ancestor between the current " 102 102 "checkout and %s", g.argv[2]); 103 103 } 104 104 } 105 - if( pid>1 && !db_exists("SELECT 1 FROM plink WHERE cid=%d", pid) ){ 106 - fossil_fatal("not a version: record #%d", mid); 105 + if( !is_a_version(pid) ){ 106 + fossil_fatal("not a version: record #%d", pid); 107 107 } 108 108 vfile_check_signature(vid, 1); 109 109 db_begin_transaction(); 110 110 undo_begin(); 111 111 load_vfile_from_rid(mid); 112 112 load_vfile_from_rid(pid); 113 113
Changes to src/pivot.c.
48 48 "DELETE FROM aqueue;" 49 49 "CREATE INDEX IF NOT EXISTS aqueue_idx1 ON aqueue(pending, mtime);" 50 50 ); 51 51 52 52 /* Insert the primary record */ 53 53 db_multi_exec( 54 54 "INSERT INTO aqueue(rid, mtime, pending, src)" 55 - " SELECT %d, mtime, 1, 1 FROM plink WHERE cid=%d LIMIT 1", 55 + " SELECT %d, mtime, 1, 1 FROM event WHERE objid=%d AND type='ci' LIMIT 1", 56 56 rid, rid 57 57 ); 58 58 } 59 59 60 60 /* 61 61 ** Set a secondary file. The primary file must be set first. There 62 62 ** must be at least one secondary but there can be more than one if 63 63 ** desired. 64 64 */ 65 65 void pivot_set_secondary(int rid){ 66 66 /* Insert the primary record */ 67 67 db_multi_exec( 68 68 "INSERT OR IGNORE INTO aqueue(rid, mtime, pending, src)" 69 - " SELECT %d, mtime, 1, 0 FROM plink WHERE cid=%d", 69 + " SELECT %d, mtime, 1, 0 FROM event WHERE objid=%d AND type='ci'", 70 70 rid, rid 71 71 ); 72 72 } 73 73 74 74 /* 75 75 ** Find the most recent common ancestor of the primary and one of 76 76 ** the secondaries. Return its rid. Return 0 if no common ancestor
Changes to src/rebuild.c.
104 104 ** Called after each artifact is processed 105 105 */ 106 106 static void rebuild_step_done(rid){ 107 107 /* assert( bag_find(&bagDone, rid)==0 ); */ 108 108 bag_insert(&bagDone, rid); 109 109 if( ttyOutput ){ 110 110 processCnt++; 111 - if (!g.fQuiet) { 111 + if (!g.fQuiet && totalSize>0) { 112 112 percent_complete((processCnt*1000)/totalSize); 113 113 } 114 114 } 115 115 } 116 116 117 117 /* 118 118 ** Rebuild cross-referencing information for the artifact ................................................................................ 322 322 db_multi_exec("INSERT OR IGNORE INTO phantom VALUES(%d)", rid); 323 323 rebuild_step_done(rid); 324 324 } 325 325 } 326 326 db_finalize(&s); 327 327 manifest_crosslink_end(); 328 328 rebuild_tag_trunk(); 329 - if (!g.fQuiet) { 329 + if( !g.fQuiet && totalSize>0 ){ 330 330 processCnt += incrSize; 331 331 percent_complete((processCnt*1000)/totalSize); 332 332 } 333 333 create_cluster(); 334 - if (!g.fQuiet) { 334 + if( !g.fQuiet && totalSize>0 ){ 335 335 processCnt += incrSize; 336 336 percent_complete((processCnt*1000)/totalSize); 337 337 } 338 338 if(!g.fQuiet && ttyOutput ){ 339 339 printf("\n"); 340 340 } 341 341 return errCnt; ................................................................................ 350 350 ** records. Run this command after updating the fossil 351 351 ** executable in a way that changes the database schema. 352 352 */ 353 353 void rebuild_database(void){ 354 354 int forceFlag; 355 355 int randomizeFlag; 356 356 int errCnt; 357 + int omitVerify; 357 358 359 + omitVerify = find_option("noverify",0,0)!=0; 358 360 forceFlag = find_option("force","f",0)!=0; 359 361 randomizeFlag = find_option("randomize", 0, 0)!=0; 360 362 if( g.argc==3 ){ 361 363 db_open_repository(g.argv[2]); 362 364 }else{ 363 365 db_find_and_open_repository(1); 364 366 if( g.argc!=2 ){ ................................................................................ 371 373 ttyOutput = 1; 372 374 errCnt = rebuild_db(randomizeFlag, 1); 373 375 if( errCnt && !forceFlag ){ 374 376 printf("%d errors. Rolling back changes. Use --force to force a commit.\n", 375 377 errCnt); 376 378 db_end_transaction(1); 377 379 }else{ 380 + if( omitVerify ) verify_cancel(); 378 381 db_end_transaction(0); 379 382 } 380 383 } 381 384 382 385 /* 383 386 ** COMMAND: test-detach 384 387 ** ................................................................................ 415 418 usage("?REPOSITORY-FILENAME?"); 416 419 } 417 420 db_close(); 418 421 db_open_repository(g.zRepositoryName); 419 422 } 420 423 db_begin_transaction(); 421 424 create_cluster(); 422 - db_end_transaction(0); 425 + db_end_transaction(0); 423 426 } 424 427 425 428 /* 426 429 ** COMMAND: scrub 427 430 ** %fossil scrub [--verily] [--force] [REPOSITORY] 428 431 ** 429 432 ** The command removes sensitive information (such as passwords) from a
Changes to src/setup.c.
692 692 iVal = iQ; 693 693 } 694 694 } 695 695 if( iVal ){ 696 696 @ <input type="checkbox" name="%s(zQParm)" checked="checked" /> 697 697 @ <b>%s(zLabel)</b> 698 698 }else{ 699 - @ <input type="checkbox" name="%s(zQParm)" /><b>%s(zLabel)</b> 699 + @ <input type="checkbox" name="%s(zQParm)" /> <b>%s(zLabel)</b> 700 700 } 701 701 } 702 702 703 703 /* 704 704 ** Generate an entry box for an attribute. 705 705 */ 706 706 void entry_attribute( ................................................................................ 875 875 @ <form action="%s(g.zBaseURL)/setup_settings" method="post"><div> 876 876 @ <table border="0"><tr><td valign="top"> 877 877 login_insert_csrf_secret(); 878 878 for(pSet=ctrlSettings; pSet->name!=0; pSet++){ 879 879 if( pSet->width==0 ){ 880 880 onoff_attribute(pSet->name, pSet->name, 881 881 pSet->var!=0 ? pSet->var : pSet->name, 882 - pSet->def[0]=='1'); 882 + is_truth(pSet->def)); 883 883 @ <br /> 884 884 } 885 885 } 886 886 @ </td><td style="width: 30;"></td><td valign="top"> 887 887 for(pSet=ctrlSettings; pSet->name!=0; pSet++){ 888 888 if( pSet->width!=0 ){ 889 889 entry_attribute(pSet->name, /*pSet->width*/ 40, pSet->name, ................................................................................ 1085 1085 db_end_transaction(0); 1086 1086 } 1087 1087 1088 1088 /* 1089 1089 ** WEBPAGE: setup_logo 1090 1090 */ 1091 1091 void setup_logo(void){ 1092 - const char *zMime = "image/gif"; 1092 + const char *zMime = db_get("logo-mimetype","image/gif"); 1093 1093 const char *aImg = P("im"); 1094 1094 int szImg = atoi(PD("im:bytes","0")); 1095 1095 if( szImg>0 ){ 1096 1096 zMime = PD("im:mimetype","image/gif"); 1097 1097 } 1098 1098 login_check_credentials(); 1099 1099 if( !g.okSetup ){
Added src/shell.c.
1 +/* 2 +** 2001 September 15 3 +** 4 +** The author disclaims copyright to this source code. In place of 5 +** a legal notice, here is a blessing: 6 +** 7 +** May you do good and not evil. 8 +** May you find forgiveness for yourself and forgive others. 9 +** May you share freely, never taking more than you give. 10 +** 11 +************************************************************************* 12 +** This file contains code to implement the "sqlite" command line 13 +** utility for accessing SQLite databases. 14 +*/ 15 +#if defined(_WIN32) || defined(WIN32) 16 +/* This needs to come before any includes for MSVC compiler */ 17 +#define _CRT_SECURE_NO_WARNINGS 18 +#endif 19 + 20 +#include <stdlib.h> 21 +#include <string.h> 22 +#include <stdio.h> 23 +#include <assert.h> 24 +#include "sqlite3.h" 25 +#include <ctype.h> 26 +#include <stdarg.h> 27 + 28 +#if !defined(_WIN32) && !defined(WIN32) && !defined(__OS2__) 29 +# include <signal.h> 30 +# if !defined(__RTP__) && !defined(_WRS_KERNEL) 31 +# include <pwd.h> 32 +# endif 33 +# include <unistd.h> 34 +# include <sys/types.h> 35 +#endif 36 + 37 +#ifdef __OS2__ 38 +# include <unistd.h> 39 +#endif 40 + 41 +#if defined(HAVE_READLINE) && HAVE_READLINE==1 42 +# include <readline/readline.h> 43 +# include <readline/history.h> 44 +#else 45 +# define readline(p) local_getline(p,stdin) 46 +# define add_history(X) 47 +# define read_history(X) 48 +# define write_history(X) 49 +# define stifle_history(X) 50 +#endif 51 + 52 +#if defined(_WIN32) || defined(WIN32) 53 +# include <io.h> 54 +#define isatty(h) _isatty(h) 55 +#define access(f,m) _access((f),(m)) 56 +#else 57 +/* Make sure isatty() has a prototype. 58 +*/ 59 +extern int isatty(); 60 +#endif 61 + 62 +#if defined(_WIN32_WCE) 63 +/* Windows CE (arm-wince-mingw32ce-gcc) does not provide isatty() 64 + * thus we always assume that we have a console. That can be 65 + * overridden with the -batch command line option. 66 + */ 67 +#define isatty(x) 1 68 +#endif 69 + 70 +#if !defined(_WIN32) && !defined(WIN32) && !defined(__OS2__) && !defined(__RTP__) && !defined(_WRS_KERNEL) 71 +#include <sys/time.h> 72 +#include <sys/resource.h> 73 + 74 +/* Saved resource information for the beginning of an operation */ 75 +static struct rusage sBegin; 76 + 77 +/* True if the timer is enabled */ 78 +static int enableTimer = 0; 79 + 80 +/* 81 +** Begin timing an operation 82 +*/ 83 +static void beginTimer(void){ 84 + if( enableTimer ){ 85 + getrusage(RUSAGE_SELF, &sBegin); 86 + } 87 +} 88 + 89 +/* Return the difference of two time_structs in seconds */ 90 +static double timeDiff(struct timeval *pStart, struct timeval *pEnd){ 91 + return (pEnd->tv_usec - pStart->tv_usec)*0.000001 + 92 + (double)(pEnd->tv_sec - pStart->tv_sec); 93 +} 94 + 95 +/* 96 +** Print the timing results. 97 +*/ 98 +static void endTimer(void){ 99 + if( enableTimer ){ 100 + struct rusage sEnd; 101 + getrusage(RUSAGE_SELF, &sEnd); 102 + printf("CPU Time: user %f sys %f\n", 103 + timeDiff(&sBegin.ru_utime, &sEnd.ru_utime), 104 + timeDiff(&sBegin.ru_stime, &sEnd.ru_stime)); 105 + } 106 +} 107 + 108 +#define BEGIN_TIMER beginTimer() 109 +#define END_TIMER endTimer() 110 +#define HAS_TIMER 1 111 + 112 +#elif (defined(_WIN32) || defined(WIN32)) 113 + 114 +#include <windows.h> 115 + 116 +/* Saved resource information for the beginning of an operation */ 117 +static HANDLE hProcess; 118 +static FILETIME ftKernelBegin; 119 +static FILETIME ftUserBegin; 120 +typedef BOOL (WINAPI *GETPROCTIMES)(HANDLE, LPFILETIME, LPFILETIME, LPFILETIME, LPFILETIME); 121 +static GETPROCTIMES getProcessTimesAddr = NULL; 122 + 123 +/* True if the timer is enabled */ 124 +static int enableTimer = 0; 125 + 126 +/* 127 +** Check to see if we have timer support. Return 1 if necessary 128 +** support found (or found previously). 129 +*/ 130 +static int hasTimer(void){ 131 + if( getProcessTimesAddr ){ 132 + return 1; 133 + } else { 134 + /* GetProcessTimes() isn't supported in WIN95 and some other Windows versions. 135 + ** See if the version we are running on has it, and if it does, save off 136 + ** a pointer to it and the current process handle. 137 + */ 138 + hProcess = GetCurrentProcess(); 139 + if( hProcess ){ 140 + HINSTANCE hinstLib = LoadLibrary(TEXT("Kernel32.dll")); 141 + if( NULL != hinstLib ){ 142 + getProcessTimesAddr = (GETPROCTIMES) GetProcAddress(hinstLib, "GetProcessTimes"); 143 + if( NULL != getProcessTimesAddr ){ 144 + return 1; 145 + } 146 + FreeLibrary(hinstLib); 147 + } 148 + } 149 + } 150 + return 0; 151 +} 152 + 153 +/* 154 +** Begin timing an operation 155 +*/ 156 +static void beginTimer(void){ 157 + if( enableTimer && getProcessTimesAddr ){ 158 + FILETIME ftCreation, ftExit; 159 + getProcessTimesAddr(hProcess, &ftCreation, &ftExit, &ftKernelBegin, &ftUserBegin); 160 + } 161 +} 162 + 163 +/* Return the difference of two FILETIME structs in seconds */ 164 +static double timeDiff(FILETIME *pStart, FILETIME *pEnd){ 165 + sqlite_int64 i64Start = *((sqlite_int64 *) pStart); 166 + sqlite_int64 i64End = *((sqlite_int64 *) pEnd); 167 + return (double) ((i64End - i64Start) / 10000000.0); 168 +} 169 + 170 +/* 171 +** Print the timing results. 172 +*/ 173 +static void endTimer(void){ 174 + if( enableTimer && getProcessTimesAddr){ 175 + FILETIME ftCreation, ftExit, ftKernelEnd, ftUserEnd; 176 + getProcessTimesAddr(hProcess, &ftCreation, &ftExit, &ftKernelEnd, &ftUserEnd); 177 + printf("CPU Time: user %f sys %f\n", 178 + timeDiff(&ftUserBegin, &ftUserEnd), 179 + timeDiff(&ftKernelBegin, &ftKernelEnd)); 180 + } 181 +} 182 + 183 +#define BEGIN_TIMER beginTimer() 184 +#define END_TIMER endTimer() 185 +#define HAS_TIMER hasTimer() 186 + 187 +#else 188 +#define BEGIN_TIMER 189 +#define END_TIMER 190 +#define HAS_TIMER 0 191 +#endif 192 + 193 +/* 194 +** Used to prevent warnings about unused parameters 195 +*/ 196 +#define UNUSED_PARAMETER(x) (void)(x) 197 + 198 +/* 199 +** If the following flag is set, then command execution stops 200 +** at an error if we are not interactive. 201 +*/ 202 +static int bail_on_error = 0; 203 + 204 +/* 205 +** Threat stdin as an interactive input if the following variable 206 +** is true. Otherwise, assume stdin is connected to a file or pipe. 207 +*/ 208 +static int stdin_is_interactive = 1; 209 + 210 +/* 211 +** The following is the open SQLite database. We make a pointer 212 +** to this database a static variable so that it can be accessed 213 +** by the SIGINT handler to interrupt database processing. 214 +*/ 215 +static sqlite3 *db = 0; 216 + 217 +/* 218 +** True if an interrupt (Control-C) has been received. 219 +*/ 220 +static volatile int seenInterrupt = 0; 221 + 222 +/* 223 +** This is the name of our program. It is set in main(), used 224 +** in a number of other places, mostly for error messages. 225 +*/ 226 +static char *Argv0; 227 + 228 +/* 229 +** Prompt strings. Initialized in main. Settable with 230 +** .prompt main continue 231 +*/ 232 +static char mainPrompt[20]; /* First line prompt. default: "sqlite> "*/ 233 +static char continuePrompt[20]; /* Continuation prompt. default: " ...> " */ 234 + 235 +/* 236 +** Write I/O traces to the following stream. 237 +*/ 238 +#ifdef SQLITE_ENABLE_IOTRACE 239 +static FILE *iotrace = 0; 240 +#endif 241 + 242 +/* 243 +** This routine works like printf in that its first argument is a 244 +** format string and subsequent arguments are values to be substituted 245 +** in place of % fields. The result of formatting this string 246 +** is written to iotrace. 247 +*/ 248 +#ifdef SQLITE_ENABLE_IOTRACE 249 +static void iotracePrintf(const char *zFormat, ...){ 250 + va_list ap; 251 + char *z; 252 + if( iotrace==0 ) return; 253 + va_start(ap, zFormat); 254 + z = sqlite3_vmprintf(zFormat, ap); 255 + va_end(ap); 256 + fprintf(iotrace, "%s", z); 257 + sqlite3_free(z); 258 +} 259 +#endif 260 + 261 + 262 +/* 263 +** Determines if a string is a number of not. 264 +*/ 265 +static int isNumber(const char *z, int *realnum){ 266 + if( *z=='-' || *z=='+' ) z++; 267 + if( !isdigit(*z) ){ 268 + return 0; 269 + } 270 + z++; 271 + if( realnum ) *realnum = 0; 272 + while( isdigit(*z) ){ z++; } 273 + if( *z=='.' ){ 274 + z++; 275 + if( !isdigit(*z) ) return 0; 276 + while( isdigit(*z) ){ z++; } 277 + if( realnum ) *realnum = 1; 278 + } 279 + if( *z=='e' || *z=='E' ){ 280 + z++; 281 + if( *z=='+' || *z=='-' ) z++; 282 + if( !isdigit(*z) ) return 0; 283 + while( isdigit(*z) ){ z++; } 284 + if( realnum ) *realnum = 1; 285 + } 286 + return *z==0; 287 +} 288 + 289 +/* 290 +** A global char* and an SQL function to access its current value 291 +** from within an SQL statement. This program used to use the 292 +** sqlite_exec_printf() API to substitue a string into an SQL statement. 293 +** The correct way to do this with sqlite3 is to use the bind API, but 294 +** since the shell is built around the callback paradigm it would be a lot 295 +** of work. Instead just use this hack, which is quite harmless. 296 +*/ 297 +static const char *zShellStatic = 0; 298 +static void shellstaticFunc( 299 + sqlite3_context *context, 300 + int argc, 301 + sqlite3_value **argv 302 +){ 303 + assert( 0==argc ); 304 + assert( zShellStatic ); 305 + UNUSED_PARAMETER(argc); 306 + UNUSED_PARAMETER(argv); 307 + sqlite3_result_text(context, zShellStatic, -1, SQLITE_STATIC); 308 +} 309 + 310 + 311 +/* 312 +** This routine reads a line of text from FILE in, stores 313 +** the text in memory obtained from malloc() and returns a pointer 314 +** to the text. NULL is returned at end of file, or if malloc() 315 +** fails. 316 +** 317 +** The interface is like "readline" but no command-line editing 318 +** is done. 319 +*/ 320 +static char *local_getline(char *zPrompt, FILE *in){ 321 + char *zLine; 322 + int nLine; 323 + int n; 324 + int eol; 325 + 326 + if( zPrompt && *zPrompt ){ 327 + printf("%s",zPrompt); 328 + fflush(stdout); 329 + } 330 + nLine = 100; 331 + zLine = malloc( nLine ); 332 + if( zLine==0 ) return 0; 333 + n = 0; 334 + eol = 0; 335 + while( !eol ){ 336 + if( n+100>nLine ){ 337 + nLine = nLine*2 + 100; 338 + zLine = realloc(zLine, nLine); 339 + if( zLine==0 ) return 0; 340 + } 341 + if( fgets(&zLine[n], nLine - n, in)==0 ){ 342 + if( n==0 ){ 343 + free(zLine); 344 + return 0; 345 + } 346 + zLine[n] = 0; 347 + eol = 1; 348 + break; 349 + } 350 + while( zLine[n] ){ n++; } 351 + if( n>0 && zLine[n-1]=='\n' ){ 352 + n--; 353 + if( n>0 && zLine[n-1]=='\r' ) n--; 354 + zLine[n] = 0; 355 + eol = 1; 356 + } 357 + } 358 + zLine = realloc( zLine, n+1 ); 359 + return zLine; 360 +} 361 + 362 +/* 363 +** Retrieve a single line of input text. 364 +** 365 +** zPrior is a string of prior text retrieved. If not the empty 366 +** string, then issue a continuation prompt. 367 +*/ 368 +static char *one_input_line(const char *zPrior, FILE *in){ 369 + char *zPrompt; 370 + char *zResult; 371 + if( in!=0 ){ 372 + return local_getline(0, in); 373 + } 374 + if( zPrior && zPrior[0] ){ 375 + zPrompt = continuePrompt; 376 + }else{ 377 + zPrompt = mainPrompt; 378 + } 379 + zResult = readline(zPrompt); 380 +#if defined(HAVE_READLINE) && HAVE_READLINE==1 381 + if( zResult && *zResult ) add_history(zResult); 382 +#endif 383 + return zResult; 384 +} 385 + 386 +struct previous_mode_data { 387 + int valid; /* Is there legit data in here? */ 388 + int mode; 389 + int showHeader; 390 + int colWidth[100]; 391 +}; 392 + 393 +/* 394 +** An pointer to an instance of this structure is passed from 395 +** the main program to the callback. This is used to communicate 396 +** state and mode information. 397 +*/ 398 +struct callback_data { 399 + sqlite3 *db; /* The database */ 400 + int echoOn; /* True to echo input commands */ 401 + int statsOn; /* True to display memory stats before each finalize */ 402 + int cnt; /* Number of records displayed so far */ 403 + FILE *out; /* Write results here */ 404 + int mode; /* An output mode setting */ 405 + int writableSchema; /* True if PRAGMA writable_schema=ON */ 406 + int showHeader; /* True to show column names in List or Column mode */ 407 + char *zDestTable; /* Name of destination table when MODE_Insert */ 408 + char separator[20]; /* Separator character for MODE_List */ 409 + int colWidth[100]; /* Requested width of each column when in column mode*/ 410 + int actualWidth[100]; /* Actual width of each column */ 411 + char nullvalue[20]; /* The text to print when a NULL comes back from 412 + ** the database */ 413 + struct previous_mode_data explainPrev; 414 + /* Holds the mode information just before 415 + ** .explain ON */ 416 + char outfile[FILENAME_MAX]; /* Filename for *out */ 417 + const char *zDbFilename; /* name of the database file */ 418 + sqlite3_stmt *pStmt; /* Current statement if any. */ 419 + FILE *pLog; /* Write log output here */ 420 +}; 421 + 422 +/* 423 +** These are the allowed modes. 424 +*/ 425 +#define MODE_Line 0 /* One column per line. Blank line between records */ 426 +#define MODE_Column 1 /* One record per line in neat columns */ 427 +#define MODE_List 2 /* One record per line with a separator */ 428 +#define MODE_Semi 3 /* Same as MODE_List but append ";" to each line */ 429 +#define MODE_Html 4 /* Generate an XHTML table */ 430 +#define MODE_Insert 5 /* Generate SQL "insert" statements */ 431 +#define MODE_Tcl 6 /* Generate ANSI-C or TCL quoted elements */ 432 +#define MODE_Csv 7 /* Quote strings, numbers are plain */ 433 +#define MODE_Explain 8 /* Like MODE_Column, but do not truncate data */ 434 + 435 +static const char *modeDescr[] = { 436 + "line", 437 + "column", 438 + "list", 439 + "semi", 440 + "html", 441 + "insert", 442 + "tcl", 443 + "csv", 444 + "explain", 445 +}; 446 + 447 +/* 448 +** Number of elements in an array 449 +*/ 450 +#define ArraySize(X) (int)(sizeof(X)/sizeof(X[0])) 451 + 452 +/* 453 +** Compute a string length that is limited to what can be stored in 454 +** lower 30 bits of a 32-bit signed integer. 455 +*/ 456 +static int strlen30(const char *z){ 457 + const char *z2 = z; 458 + while( *z2 ){ z2++; } 459 + return 0x3fffffff & (int)(z2 - z); 460 +} 461 + 462 +/* 463 +** A callback for the sqlite3_log() interface. 464 +*/ 465 +static void shellLog(void *pArg, int iErrCode, const char *zMsg){ 466 + struct callback_data *p = (struct callback_data*)pArg; 467 + if( p->pLog==0 ) return; 468 + fprintf(p->pLog, "(%d) %s\n", iErrCode, zMsg); 469 + fflush(p->pLog); 470 +} 471 + 472 +/* 473 +** Output the given string as a hex-encoded blob (eg. X'1234' ) 474 +*/ 475 +static void output_hex_blob(FILE *out, const void *pBlob, int nBlob){ 476 + int i; 477 + char *zBlob = (char *)pBlob; 478 + fprintf(out,"X'"); 479 + for(i=0; i<nBlob; i++){ fprintf(out,"%02x",zBlob[i]); } 480 + fprintf(out,"'"); 481 +} 482 + 483 +/* 484 +** Output the given string as a quoted string using SQL quoting conventions. 485 +*/ 486 +static void output_quoted_string(FILE *out, const char *z){ 487 + int i; 488 + int nSingle = 0; 489 + for(i=0; z[i]; i++){ 490 + if( z[i]=='\'' ) nSingle++; 491 + } 492 + if( nSingle==0 ){ 493 + fprintf(out,"'%s'",z); 494 + }else{ 495 + fprintf(out,"'"); 496 + while( *z ){ 497 + for(i=0; z[i] && z[i]!='\''; i++){} 498 + if( i==0 ){ 499 + fprintf(out,"''"); 500 + z++; 501 + }else if( z[i]=='\'' ){ 502 + fprintf(out,"%.*s''",i,z); 503 + z += i+1; 504 + }else{ 505 + fprintf(out,"%s",z); 506 + break; 507 + } 508 + } 509 + fprintf(out,"'"); 510 + } 511 +} 512 + 513 +/* 514 +** Output the given string as a quoted according to C or TCL quoting rules. 515 +*/ 516 +static void output_c_string(FILE *out, const char *z){ 517 + unsigned int c; 518 + fputc('"', out); 519 + while( (c = *(z++))!=0 ){ 520 + if( c=='\\' ){ 521 + fputc(c, out); 522 + fputc(c, out); 523 + }else if( c=='\t' ){ 524 + fputc('\\', out); 525 + fputc('t', out); 526 + }else if( c=='\n' ){ 527 + fputc('\\', out); 528 + fputc('n', out); 529 + }else if( c=='\r' ){ 530 + fputc('\\', out); 531 + fputc('r', out); 532 + }else if( !isprint(c) ){ 533 + fprintf(out, "\\%03o", c&0xff); 534 + }else{ 535 + fputc(c, out); 536 + } 537 + } 538 + fputc('"', out); 539 +} 540 + 541 +/* 542 +** Output the given string with characters that are special to 543 +** HTML escaped. 544 +*/ 545 +static void output_html_string(FILE *out, const char *z){ 546 + int i; 547 + while( *z ){ 548 + for(i=0; z[i] 549 + && z[i]!='<' 550 + && z[i]!='&' 551 + && z[i]!='>' 552 + && z[i]!='\"' 553 + && z[i]!='\''; 554 + i++){} 555 + if( i>0 ){ 556 + fprintf(out,"%.*s",i,z); 557 + } 558 + if( z[i]=='<' ){ 559 + fprintf(out,"<"); 560 + }else if( z[i]=='&' ){ 561 + fprintf(out,"&"); 562 + }else if( z[i]=='>' ){ 563 + fprintf(out,">"); 564 + }else if( z[i]=='\"' ){ 565 + fprintf(out,"""); 566 + }else if( z[i]=='\'' ){ 567 + fprintf(out,"'"); 568 + }else{ 569 + break; 570 + } 571 + z += i + 1; 572 + } 573 +} 574 + 575 +/* 576 +** If a field contains any character identified by a 1 in the following 577 +** array, then the string must be quoted for CSV. 578 +*/ 579 +static const char needCsvQuote[] = { 580 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 581 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 582 + 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 583 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 584 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 585 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 586 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 587 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 588 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 589 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 590 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 591 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 592 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 593 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 594 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 595 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 596 +}; 597 + 598 +/* 599 +** Output a single term of CSV. Actually, p->separator is used for 600 +** the separator, which may or may not be a comma. p->nullvalue is 601 +** the null value. Strings are quoted using ANSI-C rules. Numbers 602 +** appear outside of quotes. 603 +*/ 604 +static void output_csv(struct callback_data *p, const char *z, int bSep){ 605 + FILE *out = p->out; 606 + if( z==0 ){ 607 + fprintf(out,"%s",p->nullvalue); 608 + }else{ 609 + int i; 610 + int nSep = strlen30(p->separator); 611 + for(i=0; z[i]; i++){ 612 + if( needCsvQuote[((unsigned char*)z)[i]] 613 + || (z[i]==p->separator[0] && 614 + (nSep==1 || memcmp(z, p->separator, nSep)==0)) ){ 615 + i = 0; 616 + break; 617 + } 618 + } 619 + if( i==0 ){ 620 + putc('"', out); 621 + for(i=0; z[i]; i++){ 622 + if( z[i]=='"' ) putc('"', out); 623 + putc(z[i], out); 624 + } 625 + putc('"', out); 626 + }else{ 627 + fprintf(out, "%s", z); 628 + } 629 + } 630 + if( bSep ){ 631 + fprintf(p->out, "%s", p->separator); 632 + } 633 +} 634 + 635 +#ifdef SIGINT 636 +/* 637 +** This routine runs when the user presses Ctrl-C 638 +*/ 639 +static void interrupt_handler(int NotUsed){ 640 + UNUSED_PARAMETER(NotUsed); 641 + seenInterrupt = 1; 642 + if( db ) sqlite3_interrupt(db); 643 +} 644 +#endif 645 + 646 +/* 647 +** This is the callback routine that the shell 648 +** invokes for each row of a query result. 649 +*/ 650 +static int shell_callback(void *pArg, int nArg, char **azArg, char **azCol, int *aiType){ 651 + int i; 652 + struct callback_data *p = (struct callback_data*)pArg; 653 + 654 + switch( p->mode ){ 655 + case MODE_Line: { 656 + int w = 5; 657 + if( azArg==0 ) break; 658 + for(i=0; i<nArg; i++){ 659 + int len = strlen30(azCol[i] ? azCol[i] : ""); 660 + if( len>w ) w = len; 661 + } 662 + if( p->cnt++>0 ) fprintf(p->out,"\n"); 663 + for(i=0; i<nArg; i++){ 664 + fprintf(p->out,"%*s = %s\n", w, azCol[i], 665 + azArg[i] ? azArg[i] : p->nullvalue); 666 + } 667 + break; 668 + } 669 + case MODE_Explain: 670 + case MODE_Column: { 671 + if( p->cnt++==0 ){ 672 + for(i=0; i<nArg; i++){ 673 + int w, n; 674 + if( i<ArraySize(p->colWidth) ){ 675 + w = p->colWidth[i]; 676 + }else{ 677 + w = 0; 678 + } 679 + if( w<=0 ){ 680 + w = strlen30(azCol[i] ? azCol[i] : ""); 681 + if( w<10 ) w = 10; 682 + n = strlen30(azArg && azArg[i] ? azArg[i] : p->nullvalue); 683 + if( w<n ) w = n; 684 + } 685 + if( i<ArraySize(p->actualWidth) ){ 686 + p->actualWidth[i] = w; 687 + } 688 + if( p->showHeader ){ 689 + fprintf(p->out,"%-*.*s%s",w,w,azCol[i], i==nArg-1 ? "\n": " "); 690 + } 691 + } 692 + if( p->showHeader ){ 693 + for(i=0; i<nArg; i++){ 694 + int w; 695 + if( i<ArraySize(p->actualWidth) ){ 696 + w = p->actualWidth[i]; 697 + }else{ 698 + w = 10; 699 + } 700 + fprintf(p->out,"%-*.*s%s",w,w,"-----------------------------------" 701 + "----------------------------------------------------------", 702 + i==nArg-1 ? "\n": " "); 703 + } 704 + } 705 + } 706 + if( azArg==0 ) break; 707 + for(i=0; i<nArg; i++){ 708 + int w; 709 + if( i<ArraySize(p->actualWidth) ){ 710 + w = p->actualWidth[i]; 711 + }else{ 712 + w = 10; 713 + } 714 + if( p->mode==MODE_Explain && azArg[i] && 715 + strlen30(azArg[i])>w ){ 716 + w = strlen30(azArg[i]); 717 + } 718 + fprintf(p->out,"%-*.*s%s",w,w, 719 + azArg[i] ? azArg[i] : p->nullvalue, i==nArg-1 ? "\n": " "); 720 + } 721 + break; 722 + } 723 + case MODE_Semi: 724 + case MODE_List: { 725 + if( p->cnt++==0 && p->showHeader ){ 726 + for(i=0; i<nArg; i++){ 727 + fprintf(p->out,"%s%s",azCol[i], i==nArg-1 ? "\n" : p->separator); 728 + } 729 + } 730 + if( azArg==0 ) break; 731 + for(i=0; i<nArg; i++){ 732 + char *z = azArg[i]; 733 + if( z==0 ) z = p->nullvalue; 734 + fprintf(p->out, "%s", z); 735 + if( i<nArg-1 ){ 736 + fprintf(p->out, "%s", p->separator); 737 + }else if( p->mode==MODE_Semi ){ 738 + fprintf(p->out, ";\n"); 739 + }else{ 740 + fprintf(p->out, "\n"); 741 + } 742 + } 743 + break; 744 + } 745 + case MODE_Html: { 746 + if( p->cnt++==0 && p->showHeader ){ 747 + fprintf(p->out,"<TR>"); 748 + for(i=0; i<nArg; i++){ 749 + fprintf(p->out,"<TH>"); 750 + output_html_string(p->out, azCol[i]); 751 + fprintf(p->out,"</TH>\n"); 752 + } 753 + fprintf(p->out,"</TR>\n"); 754 + } 755 + if( azArg==0 ) break; 756 + fprintf(p->out,"<TR>"); 757 + for(i=0; i<nArg; i++){ 758 + fprintf(p->out,"<TD>"); 759 + output_html_string(p->out, azArg[i] ? azArg[i] : p->nullvalue); 760 + fprintf(p->out,"</TD>\n"); 761 + } 762 + fprintf(p->out,"</TR>\n"); 763 + break; 764 + } 765 + case MODE_Tcl: { 766 + if( p->cnt++==0 && p->showHeader ){ 767 + for(i=0; i<nArg; i++){ 768 + output_c_string(p->out,azCol[i] ? azCol[i] : ""); 769 + fprintf(p->out, "%s", p->separator); 770 + } 771 + fprintf(p->out,"\n"); 772 + } 773 + if( azArg==0 ) break; 774 + for(i=0; i<nArg; i++){ 775 + output_c_string(p->out, azArg[i] ? azArg[i] : p->nullvalue); 776 + fprintf(p->out, "%s", p->separator); 777 + } 778 + fprintf(p->out,"\n"); 779 + break; 780 + } 781 + case MODE_Csv: { 782 + if( p->cnt++==0 && p->showHeader ){ 783 + for(i=0; i<nArg; i++){ 784 + output_csv(p, azCol[i] ? azCol[i] : "", i<nArg-1); 785 + } 786 + fprintf(p->out,"\n"); 787 + } 788 + if( azArg==0 ) break; 789 + for(i=0; i<nArg; i++){ 790 + output_csv(p, azArg[i], i<nArg-1); 791 + } 792 + fprintf(p->out,"\n"); 793 + break; 794 + } 795 + case MODE_Insert: { 796 + p->cnt++; 797 + if( azArg==0 ) break; 798 + fprintf(p->out,"INSERT INTO %s VALUES(",p->zDestTable); 799 + for(i=0; i<nArg; i++){ 800 + char *zSep = i>0 ? ",": ""; 801 + if( (azArg[i]==0) || (aiType && aiType[i]==SQLITE_NULL) ){ 802 + fprintf(p->out,"%sNULL",zSep); 803 + }else if( aiType && aiType[i]==SQLITE_TEXT ){ 804 + if( zSep[0] ) fprintf(p->out,"%s",zSep); 805 + output_quoted_string(p->out, azArg[i]); 806 + }else if( aiType && (aiType[i]==SQLITE_INTEGER || aiType[i]==SQLITE_FLOAT) ){ 807 + fprintf(p->out,"%s%s",zSep, azArg[i]); 808 + }else if( aiType && aiType[i]==SQLITE_BLOB && p->pStmt ){ 809 + const void *pBlob = sqlite3_column_blob(p->pStmt, i); 810 + int nBlob = sqlite3_column_bytes(p->pStmt, i); 811 + if( zSep[0] ) fprintf(p->out,"%s",zSep); 812 + output_hex_blob(p->out, pBlob, nBlob); 813 + }else if( isNumber(azArg[i], 0) ){ 814 + fprintf(p->out,"%s%s",zSep, azArg[i]); 815 + }else{ 816 + if( zSep[0] ) fprintf(p->out,"%s",zSep); 817 + output_quoted_string(p->out, azArg[i]); 818 + } 819 + } 820 + fprintf(p->out,");\n"); 821 + break; 822 + } 823 + } 824 + return 0; 825 +} 826 + 827 +/* 828 +** This is the callback routine that the SQLite library 829 +** invokes for each row of a query result. 830 +*/ 831 +static int callback(void *pArg, int nArg, char **azArg, char **azCol){ 832 + /* since we don't have type info, call the shell_callback with a NULL value */ 833 + return shell_callback(pArg, nArg, azArg, azCol, NULL); 834 +} 835 + 836 +/* 837 +** Set the destination table field of the callback_data structure to 838 +** the name of the table given. Escape any quote characters in the 839 +** table name. 840 +*/ 841 +static void set_table_name(struct callback_data *p, const char *zName){ 842 + int i, n; 843 + int needQuote; 844 + char *z; 845 + 846 + if( p->zDestTable ){ 847 + free(p->zDestTable); 848 + p->zDestTable = 0; 849 + } 850 + if( zName==0 ) return; 851 + needQuote = !isalpha((unsigned char)*zName) && *zName!='_'; 852 + for(i=n=0; zName[i]; i++, n++){ 853 + if( !isalnum((unsigned char)zName[i]) && zName[i]!='_' ){ 854 + needQuote = 1; 855 + if( zName[i]=='\'' ) n++; 856 + } 857 + } 858 + if( needQuote ) n += 2; 859 + z = p->zDestTable = malloc( n+1 ); 860 + if( z==0 ){ 861 + fprintf(stderr,"Error: out of memory\n"); 862 + exit(1); 863 + } 864 + n = 0; 865 + if( needQuote ) z[n++] = '\''; 866 + for(i=0; zName[i]; i++){ 867 + z[n++] = zName[i]; 868 + if( zName[i]=='\'' ) z[n++] = '\''; 869 + } 870 + if( needQuote ) z[n++] = '\''; 871 + z[n] = 0; 872 +} 873 + 874 +/* zIn is either a pointer to a NULL-terminated string in memory obtained 875 +** from malloc(), or a NULL pointer. The string pointed to by zAppend is 876 +** added to zIn, and the result returned in memory obtained from malloc(). 877 +** zIn, if it was not NULL, is freed. 878 +** 879 +** If the third argument, quote, is not '\0', then it is used as a 880 +** quote character for zAppend. 881 +*/ 882 +static char *appendText(char *zIn, char const *zAppend, char quote){ 883 + int len; 884 + int i; 885 + int nAppend = strlen30(zAppend); 886 + int nIn = (zIn?strlen30(zIn):0); 887 + 888 + len = nAppend+nIn+1; 889 + if( quote ){ 890 + len += 2; 891 + for(i=0; i<nAppend; i++){ 892 + if( zAppend[i]==quote ) len++; 893 + } 894 + } 895 + 896 + zIn = (char *)realloc(zIn, len); 897 + if( !zIn ){ 898 + return 0; 899 + } 900 + 901 + if( quote ){ 902 + char *zCsr = &zIn[nIn]; 903 + *zCsr++ = quote; 904 + for(i=0; i<nAppend; i++){ 905 + *zCsr++ = zAppend[i]; 906 + if( zAppend[i]==quote ) *zCsr++ = quote; 907 + } 908 + *zCsr++ = quote; 909 + *zCsr++ = '\0'; 910 + assert( (zCsr-zIn)==len ); 911 + }else{ 912 + memcpy(&zIn[nIn], zAppend, nAppend); 913 + zIn[len-1] = '\0'; 914 + } 915 + 916 + return zIn; 917 +} 918 + 919 + 920 +/* 921 +** Execute a query statement that has a single result column. Print 922 +** that result column on a line by itself with a semicolon terminator. 923 +** 924 +** This is used, for example, to show the schema of the database by 925 +** querying the SQLITE_MASTER table. 926 +*/ 927 +static int run_table_dump_query( 928 + FILE *out, /* Send output here */ 929 + sqlite3 *db, /* Database to query */ 930 + const char *zSelect, /* SELECT statement to extract content */ 931 + const char *zFirstRow /* Print before first row, if not NULL */ 932 +){ 933 + sqlite3_stmt *pSelect; 934 + int rc; 935 + rc = sqlite3_prepare(db, zSelect, -1, &pSelect, 0); 936 + if( rc!=SQLITE_OK || !pSelect ){ 937 + return rc; 938 + } 939 + rc = sqlite3_step(pSelect); 940 + while( rc==SQLITE_ROW ){ 941 + if( zFirstRow ){ 942 + fprintf(out, "%s", zFirstRow); 943 + zFirstRow = 0; 944 + } 945 + fprintf(out, "%s;\n", sqlite3_column_text(pSelect, 0)); 946 + rc = sqlite3_step(pSelect); 947 + } 948 + return sqlite3_finalize(pSelect); 949 +} 950 + 951 +/* 952 +** Allocate space and save off current error string. 953 +*/ 954 +static char *save_err_msg( 955 + sqlite3 *db /* Database to query */ 956 +){ 957 + int nErrMsg = 1+strlen30(sqlite3_errmsg(db)); 958 + char *zErrMsg = sqlite3_malloc(nErrMsg); 959 + if( zErrMsg ){ 960 + memcpy(zErrMsg, sqlite3_errmsg(db), nErrMsg); 961 + } 962 + return zErrMsg; 963 +} 964 + 965 +/* 966 +** Display memory stats. 967 +*/ 968 +static int display_stats( 969 + sqlite3 *db, /* Database to query */ 970 + struct callback_data *pArg, /* Pointer to struct callback_data */ 971 + int bReset /* True to reset the stats */ 972 +){ 973 + int iCur; 974 + int iHiwtr; 975 + 976 + if( pArg && pArg->out ){ 977 + 978 + iHiwtr = iCur = -1; 979 + sqlite3_status(SQLITE_STATUS_MEMORY_USED, &iCur, &iHiwtr, bReset); 980 + fprintf(pArg->out, "Memory Used: %d (max %d) bytes\n", iCur, iHiwtr); 981 + iHiwtr = iCur = -1; 982 + sqlite3_status(SQLITE_STATUS_MALLOC_COUNT, &iCur, &iHiwtr, bReset); 983 + fprintf(pArg->out, "Number of Allocations: %d (max %d)\n", iCur, iHiwtr); 984 +/* 985 +** Not currently used by the CLI. 986 +** iHiwtr = iCur = -1; 987 +** sqlite3_status(SQLITE_STATUS_PAGECACHE_USED, &iCur, &iHiwtr, bReset); 988 +** fprintf(pArg->out, "Number of Pcache Pages Used: %d (max %d) pages\n", iCur, iHiwtr); 989 +*/ 990 + iHiwtr = iCur = -1; 991 + sqlite3_status(SQLITE_STATUS_PAGECACHE_OVERFLOW, &iCur, &iHiwtr, bReset); 992 + fprintf(pArg->out, "Number of Pcache Overflow Bytes: %d (max %d) bytes\n", iCur, iHiwtr); 993 +/* 994 +** Not currently used by the CLI. 995 +** iHiwtr = iCur = -1; 996 +** sqlite3_status(SQLITE_STATUS_SCRATCH_USED, &iCur, &iHiwtr, bReset); 997 +** fprintf(pArg->out, "Number of Scratch Allocations Used: %d (max %d)\n", iCur, iHiwtr); 998 +*/ 999 + iHiwtr = iCur = -1; 1000 + sqlite3_status(SQLITE_STATUS_SCRATCH_OVERFLOW, &iCur, &iHiwtr, bReset); 1001 + fprintf(pArg->out, "Number of Scratch Overflow Bytes: %d (max %d) bytes\n", iCur, iHiwtr); 1002 + iHiwtr = iCur = -1; 1003 + sqlite3_status(SQLITE_STATUS_MALLOC_SIZE, &iCur, &iHiwtr, bReset); 1004 + fprintf(pArg->out, "Largest Allocation: %d bytes\n", iHiwtr); 1005 + iHiwtr = iCur = -1; 1006 + sqlite3_status(SQLITE_STATUS_PAGECACHE_SIZE, &iCur, &iHiwtr, bReset); 1007 + fprintf(pArg->out, "Largest Pcache Allocation: %d bytes\n", iHiwtr); 1008 + iHiwtr = iCur = -1; 1009 + sqlite3_status(SQLITE_STATUS_SCRATCH_SIZE, &iCur, &iHiwtr, bReset); 1010 + fprintf(pArg->out, "Largest Scratch Allocation: %d bytes\n", iHiwtr); 1011 +#ifdef YYTRACKMAXSTACKDEPTH 1012 + iHiwtr = iCur = -1; 1013 + sqlite3_status(SQLITE_STATUS_PARSER_STACK, &iCur, &iHiwtr, bReset); 1014 + fprintf(pArg->out, "Deepest Parser Stack: %d (max %d)\n", iCur, iHiwtr); 1015 +#endif 1016 + } 1017 + 1018 + if( pArg && pArg->out && db ){ 1019 + iHiwtr = iCur = -1; 1020 + sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_USED, &iCur, &iHiwtr, bReset); 1021 + fprintf(pArg->out, "Lookaside Slots Used: %d (max %d)\n", iCur, iHiwtr); 1022 + iHiwtr = iCur = -1; 1023 + sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_USED, &iCur, &iHiwtr, bReset); 1024 + fprintf(pArg->out, "Pager Heap Usage: %d bytes\n", iCur); 1025 + iHiwtr = iCur = -1; 1026 + sqlite3_db_status(db, SQLITE_DBSTATUS_SCHEMA_USED, &iCur, &iHiwtr, bReset); 1027 + fprintf(pArg->out, "Schema Heap Usage: %d bytes\n", iCur); 1028 + iHiwtr = iCur = -1; 1029 + sqlite3_db_status(db, SQLITE_DBSTATUS_STMT_USED, &iCur, &iHiwtr, bReset); 1030 + fprintf(pArg->out, "Statement Heap/Lookaside Usage: %d bytes\n", iCur); 1031 + } 1032 + 1033 + if( pArg && pArg->out && db && pArg->pStmt ){ 1034 + iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_FULLSCAN_STEP, bReset); 1035 + fprintf(pArg->out, "Fullscan Steps: %d\n", iCur); 1036 + iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_SORT, bReset); 1037 + fprintf(pArg->out, "Sort Operations: %d\n", iCur); 1038 + iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_AUTOINDEX, bReset); 1039 + fprintf(pArg->out, "Autoindex Inserts: %d\n", iCur); 1040 + } 1041 + 1042 + return 0; 1043 +} 1044 + 1045 +/* 1046 +** Execute a statement or set of statements. Print 1047 +** any result rows/columns depending on the current mode 1048 +** set via the supplied callback. 1049 +** 1050 +** This is very similar to SQLite's built-in sqlite3_exec() 1051 +** function except it takes a slightly different callback 1052 +** and callback data argument. 1053 +*/ 1054 +static int shell_exec( 1055 + sqlite3 *db, /* An open database */ 1056 + const char *zSql, /* SQL to be evaluated */ 1057 + int (*xCallback)(void*,int,char**,char**,int*), /* Callback function */ 1058 + /* (not the same as sqlite3_exec) */ 1059 + struct callback_data *pArg, /* Pointer to struct callback_data */ 1060 + char **pzErrMsg /* Error msg written here */ 1061 +){ 1062 + sqlite3_stmt *pStmt = NULL; /* Statement to execute. */ 1063 + int rc = SQLITE_OK; /* Return Code */ 1064 + const char *zLeftover; /* Tail of unprocessed SQL */ 1065 + 1066 + if( pzErrMsg ){ 1067 + *pzErrMsg = NULL; 1068 + } 1069 + 1070 + while( zSql[0] && (SQLITE_OK == rc) ){ 1071 + rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zLeftover); 1072 + if( SQLITE_OK != rc ){ 1073 + if( pzErrMsg ){ 1074 + *pzErrMsg = save_err_msg(db); 1075 + } 1076 + }else{ 1077 + if( !pStmt ){ 1078 + /* this happens for a comment or white-space */ 1079 + zSql = zLeftover; 1080 + while( isspace(zSql[0]) ) zSql++; 1081 + continue; 1082 + } 1083 + 1084 + /* save off the prepared statment handle and reset row count */ 1085 + if( pArg ){ 1086 + pArg->pStmt = pStmt; 1087 + pArg->cnt = 0; 1088 + } 1089 + 1090 + /* echo the sql statement if echo on */ 1091 + if( pArg && pArg->echoOn ){ 1092 + const char *zStmtSql = sqlite3_sql(pStmt); 1093 + fprintf(pArg->out, "%s\n", zStmtSql ? zStmtSql : zSql); 1094 + } 1095 + 1096 + /* perform the first step. this will tell us if we 1097 + ** have a result set or not and how wide it is. 1098 + */ 1099 + rc = sqlite3_step(pStmt); 1100 + /* if we have a result set... */ 1101 + if( SQLITE_ROW == rc ){ 1102 + /* if we have a callback... */ 1103 + if( xCallback ){ 1104 + /* allocate space for col name ptr, value ptr, and type */ 1105 + int nCol = sqlite3_column_count(pStmt); 1106 + void *pData = sqlite3_malloc(3*nCol*sizeof(const char*) + 1); 1107 + if( !pData ){ 1108 + rc = SQLITE_NOMEM; 1109 + }else{ 1110 + char **azCols = (char **)pData; /* Names of result columns */ 1111 + char **azVals = &azCols[nCol]; /* Results */ 1112 + int *aiTypes = (int *)&azVals[nCol]; /* Result types */ 1113 + int i; 1114 + assert(sizeof(int) <= sizeof(char *)); 1115 + /* save off ptrs to column names */ 1116 + for(i=0; i<nCol; i++){ 1117 + azCols[i] = (char *)sqlite3_column_name(pStmt, i); 1118 + } 1119 + do{ 1120 + /* extract the data and data types */ 1121 + for(i=0; i<nCol; i++){ 1122 + azVals[i] = (char *)sqlite3_column_text(pStmt, i); 1123 + aiTypes[i] = sqlite3_column_type(pStmt, i); 1124 + if( !azVals[i] && (aiTypes[i]!=SQLITE_NULL) ){ 1125 + rc = SQLITE_NOMEM; 1126 + break; /* from for */ 1127 + } 1128 + } /* end for */ 1129 + 1130 + /* if data and types extracted successfully... */ 1131 + if( SQLITE_ROW == rc ){ 1132 + /* call the supplied callback with the result row data */ 1133 + if( xCallback(pArg, nCol, azVals, azCols, aiTypes) ){ 1134 + rc = SQLITE_ABORT; 1135 + }else{ 1136 + rc = sqlite3_step(pStmt); 1137 + } 1138 + } 1139 + } while( SQLITE_ROW == rc ); 1140 + sqlite3_free(pData); 1141 + } 1142 + }else{ 1143 + do{ 1144 + rc = sqlite3_step(pStmt); 1145 + } while( rc == SQLITE_ROW ); 1146 + } 1147 + } 1148 + 1149 + /* print usage stats if stats on */ 1150 + if( pArg && pArg->statsOn ){ 1151 + display_stats(db, pArg, 0); 1152 + } 1153 + 1154 + /* Finalize the statement just executed. If this fails, save a 1155 + ** copy of the error message. Otherwise, set zSql to point to the 1156 + ** next statement to execute. */ 1157 + rc = sqlite3_finalize(pStmt); 1158 + if( rc==SQLITE_OK ){ 1159 + zSql = zLeftover; 1160 + while( isspace(zSql[0]) ) zSql++; 1161 + }else if( pzErrMsg ){ 1162 + *pzErrMsg = save_err_msg(db); 1163 + } 1164 + 1165 + /* clear saved stmt handle */ 1166 + if( pArg ){ 1167 + pArg->pStmt = NULL; 1168 + } 1169 + } 1170 + } /* end while */ 1171 + 1172 + return rc; 1173 +} 1174 + 1175 + 1176 +/* 1177 +** This is a different callback routine used for dumping the database. 1178 +** Each row received by this callback consists of a table name, 1179 +** the table type ("index" or "table") and SQL to create the table. 1180 +** This routine should print text sufficient to recreate the table. 1181 +*/ 1182 +static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){ 1183 + int rc; 1184 + const char *zTable; 1185 + const char *zType; 1186 + const char *zSql; 1187 + const char *zPrepStmt = 0; 1188 + struct callback_data *p = (struct callback_data *)pArg; 1189 + 1190 + UNUSED_PARAMETER(azCol); 1191 + if( nArg!=3 ) return 1; 1192 + zTable = azArg[0]; 1193 + zType = azArg[1]; 1194 + zSql = azArg[2]; 1195 + 1196 + if( strcmp(zTable, "sqlite_sequence")==0 ){ 1197 + zPrepStmt = "DELETE FROM sqlite_sequence;\n"; 1198 + }else if( strcmp(zTable, "sqlite_stat1")==0 ){ 1199 + fprintf(p->out, "ANALYZE sqlite_master;\n"); 1200 + }else if( strncmp(zTable, "sqlite_", 7)==0 ){ 1201 + return 0; 1202 + }else if( strncmp(zSql, "CREATE VIRTUAL TABLE", 20)==0 ){ 1203 + char *zIns; 1204 + if( !p->writableSchema ){ 1205 + fprintf(p->out, "PRAGMA writable_schema=ON;\n"); 1206 + p->writableSchema = 1; 1207 + } 1208 + zIns = sqlite3_mprintf( 1209 + "INSERT INTO sqlite_master(type,name,tbl_name,rootpage,sql)" 1210 + "VALUES('table','%q','%q',0,'%q');", 1211 + zTable, zTable, zSql); 1212 + fprintf(p->out, "%s\n", zIns); 1213 + sqlite3_free(zIns); 1214 + return 0; 1215 + }else{ 1216 + fprintf(p->out, "%s;\n", zSql); 1217 + } 1218 + 1219 + if( strcmp(zType, "table")==0 ){ 1220 + sqlite3_stmt *pTableInfo = 0; 1221 + char *zSelect = 0; 1222 + char *zTableInfo = 0; 1223 + char *zTmp = 0; 1224 + int nRow = 0; 1225 + 1226 + zTableInfo = appendText(zTableInfo, "PRAGMA table_info(", 0); 1227 + zTableInfo = appendText(zTableInfo, zTable, '"'); 1228 + zTableInfo = appendText(zTableInfo, ");", 0); 1229 + 1230 + rc = sqlite3_prepare(p->db, zTableInfo, -1, &pTableInfo, 0); 1231 + free(zTableInfo); 1232 + if( rc!=SQLITE_OK || !pTableInfo ){ 1233 + return 1; 1234 + } 1235 + 1236 + zSelect = appendText(zSelect, "SELECT 'INSERT INTO ' || ", 0); 1237 + zTmp = appendText(zTmp, zTable, '"'); 1238 + if( zTmp ){ 1239 + zSelect = appendText(zSelect, zTmp, '\''); 1240 + } 1241 + zSelect = appendText(zSelect, " || ' VALUES(' || ", 0); 1242 + rc = sqlite3_step(pTableInfo); 1243 + while( rc==SQLITE_ROW ){ 1244 + const char *zText = (const char *)sqlite3_column_text(pTableInfo, 1); 1245 + zSelect = appendText(zSelect, "quote(", 0); 1246 + zSelect = appendText(zSelect, zText, '"'); 1247 + rc = sqlite3_step(pTableInfo); 1248 + if( rc==SQLITE_ROW ){ 1249 + zSelect = appendText(zSelect, ") || ',' || ", 0); 1250 + }else{ 1251 + zSelect = appendText(zSelect, ") ", 0); 1252 + } 1253 + nRow++; 1254 + } 1255 + rc = sqlite3_finalize(pTableInfo); 1256 + if( rc!=SQLITE_OK || nRow==0 ){ 1257 + free(zSelect); 1258 + return 1; 1259 + } 1260 + zSelect = appendText(zSelect, "|| ')' FROM ", 0); 1261 + zSelect = appendText(zSelect, zTable, '"'); 1262 + 1263 + rc = run_table_dump_query(p->out, p->db, zSelect, zPrepStmt); 1264 + if( rc==SQLITE_CORRUPT ){ 1265 + zSelect = appendText(zSelect, " ORDER BY rowid DESC", 0); 1266 + rc = run_table_dump_query(p->out, p->db, zSelect, 0); 1267 + } 1268 + if( zSelect ) free(zSelect); 1269 + } 1270 + return 0; 1271 +} 1272 + 1273 +/* 1274 +** Run zQuery. Use dump_callback() as the callback routine so that 1275 +** the contents of the query are output as SQL statements. 1276 +** 1277 +** If we get a SQLITE_CORRUPT error, rerun the query after appending 1278 +** "ORDER BY rowid DESC" to the end. 1279 +*/ 1280 +static int run_schema_dump_query( 1281 + struct callback_data *p, 1282 + const char *zQuery, 1283 + char **pzErrMsg 1284 +){ 1285 + int rc; 1286 + rc = sqlite3_exec(p->db, zQuery, dump_callback, p, pzErrMsg); 1287 + if( rc==SQLITE_CORRUPT ){ 1288 + char *zQ2; 1289 + int len = strlen30(zQuery); 1290 + if( pzErrMsg ) sqlite3_free(*pzErrMsg); 1291 + zQ2 = malloc( len+100 ); 1292 + if( zQ2==0 ) return rc; 1293 + sqlite3_snprintf(sizeof(zQ2), zQ2, "%s ORDER BY rowid DESC", zQuery); 1294 + rc = sqlite3_exec(p->db, zQ2, dump_callback, p, pzErrMsg); 1295 + free(zQ2); 1296 + } 1297 + return rc; 1298 +} 1299 + 1300 +/* 1301 +** Text of a help message 1302 +*/ 1303 +static char zHelp[] = 1304 + ".backup ?DB? FILE Backup DB (default \"main\") to FILE\n" 1305 + ".bail ON|OFF Stop after hitting an error. Default OFF\n" 1306 + ".databases List names and files of attached databases\n" 1307 + ".dump ?TABLE? ... Dump the database in an SQL text format\n" 1308 + " If TABLE specified, only dump tables matching\n" 1309 + " LIKE pattern TABLE.\n" 1310 + ".echo ON|OFF Turn command echo on or off\n" 1311 + ".exit Exit this program\n" 1312 + ".explain ?ON|OFF? Turn output mode suitable for EXPLAIN on or off.\n" 1313 + " With no args, it turns EXPLAIN on.\n" 1314 + ".header(s) ON|OFF Turn display of headers on or off\n" 1315 + ".help Show this message\n" 1316 + ".import FILE TABLE Import data from FILE into TABLE\n" 1317 + ".indices ?TABLE? Show names of all indices\n" 1318 + " If TABLE specified, only show indices for tables\n" 1319 + " matching LIKE pattern TABLE.\n" 1320 +#ifdef SQLITE_ENABLE_IOTRACE 1321 + ".iotrace FILE Enable I/O diagnostic logging to FILE\n" 1322 +#endif 1323 +#ifndef SQLITE_OMIT_LOAD_EXTENSION 1324 + ".load FILE ?ENTRY? Load an extension library\n" 1325 +#endif 1326 + ".log FILE|off Turn logging on or off. FILE can be stderr/stdout\n" 1327 + ".mode MODE ?TABLE? Set output mode where MODE is one of:\n" 1328 + " csv Comma-separated values\n" 1329 + " column Left-aligned columns. (See .width)\n" 1330 + " html HTML <table> code\n" 1331 + " insert SQL insert statements for TABLE\n" 1332 + " line One value per line\n" 1333 + " list Values delimited by .separator string\n" 1334 + " tabs Tab-separated values\n" 1335 + " tcl TCL list elements\n" 1336 + ".nullvalue STRING Print STRING in place of NULL values\n" 1337 + ".output FILENAME Send output to FILENAME\n" 1338 + ".output stdout Send output to the screen\n" 1339 + ".prompt MAIN CONTINUE Replace the standard prompts\n" 1340 + ".quit Exit this program\n" 1341 + ".read FILENAME Execute SQL in FILENAME\n" 1342 + ".restore ?DB? FILE Restore content of DB (default \"main\") from FILE\n" 1343 + ".schema ?TABLE? Show the CREATE statements\n" 1344 + " If TABLE specified, only show tables matching\n" 1345 + " LIKE pattern TABLE.\n" 1346 + ".separator STRING Change separator used by output mode and .import\n" 1347 + ".show Show the current values for various settings\n" 1348 + ".stats ON|OFF Turn stats on or off\n" 1349 + ".tables ?TABLE? List names of tables\n" 1350 + " If TABLE specified, only list tables matching\n" 1351 + " LIKE pattern TABLE.\n" 1352 + ".timeout MS Try opening locked tables for MS milliseconds\n" 1353 + ".width NUM1 NUM2 ... Set column widths for \"column\" mode\n" 1354 +; 1355 + 1356 +static char zTimerHelp[] = 1357 + ".timer ON|OFF Turn the CPU timer measurement on or off\n" 1358 +; 1359 + 1360 +/* Forward reference */ 1361 +static int process_input(struct callback_data *p, FILE *in); 1362 + 1363 +/* 1364 +** Make sure the database is open. If it is not, then open it. If 1365 +** the database fails to open, print an error message and exit. 1366 +*/ 1367 +static void open_db(struct callback_data *p){ 1368 + if( p->db==0 ){ 1369 + sqlite3_open(p->zDbFilename, &p->db); 1370 + db = p->db; 1371 + if( db && sqlite3_errcode(db)==SQLITE_OK ){ 1372 + sqlite3_create_function(db, "shellstatic", 0, SQLITE_UTF8, 0, 1373 + shellstaticFunc, 0, 0); 1374 + } 1375 + if( db==0 || SQLITE_OK!=sqlite3_errcode(db) ){ 1376 + fprintf(stderr,"Error: unable to open database \"%s\": %s\n", 1377 + p->zDbFilename, sqlite3_errmsg(db)); 1378 + exit(1); 1379 + } 1380 +#ifndef SQLITE_OMIT_LOAD_EXTENSION 1381 + sqlite3_enable_load_extension(p->db, 1); 1382 +#endif 1383 + } 1384 +} 1385 + 1386 +/* 1387 +** Do C-language style dequoting. 1388 +** 1389 +** \t -> tab 1390 +** \n -> newline 1391 +** \r -> carriage return 1392 +** \NNN -> ascii character NNN in octal 1393 +** \\ -> backslash 1394 +*/ 1395 +static void resolve_backslashes(char *z){ 1396 + int i, j; 1397 + char c; 1398 + for(i=j=0; (c = z[i])!=0; i++, j++){ 1399 + if( c=='\\' ){ 1400 + c = z[++i]; 1401 + if( c=='n' ){ 1402 + c = '\n'; 1403 + }else if( c=='t' ){ 1404 + c = '\t'; 1405 + }else if( c=='r' ){ 1406 + c = '\r'; 1407 + }else if( c>='0' && c<='7' ){ 1408 + c -= '0'; 1409 + if( z[i+1]>='0' && z[i+1]<='7' ){ 1410 + i++; 1411 + c = (c<<3) + z[i] - '0'; 1412 + if( z[i+1]>='0' && z[i+1]<='7' ){ 1413 + i++; 1414 + c = (c<<3) + z[i] - '0'; 1415 + } 1416 + } 1417 + } 1418 + } 1419 + z[j] = c; 1420 + } 1421 + z[j] = 0; 1422 +} 1423 + 1424 +/* 1425 +** Interpret zArg as a boolean value. Return either 0 or 1. 1426 +*/ 1427 +static int booleanValue(char *zArg){ 1428 + int val = atoi(zArg); 1429 + int j; 1430 + for(j=0; zArg[j]; j++){ 1431 + zArg[j] = (char)tolower(zArg[j]); 1432 + } 1433 + if( strcmp(zArg,"on")==0 ){ 1434 + val = 1; 1435 + }else if( strcmp(zArg,"yes")==0 ){ 1436 + val = 1; 1437 + } 1438 + return val; 1439 +} 1440 + 1441 +/* 1442 +** If an input line begins with "." then invoke this routine to 1443 +** process that line. 1444 +** 1445 +** Return 1 on error, 2 to exit, and 0 otherwise. 1446 +*/ 1447 +static int do_meta_command(char *zLine, struct callback_data *p){ 1448 + int i = 1; 1449 + int nArg = 0; 1450 + int n, c; 1451 + int rc = 0; 1452 + char *azArg[50]; 1453 + 1454 + /* Parse the input line into tokens. 1455 + */ 1456 + while( zLine[i] && nArg<ArraySize(azArg) ){ 1457 + while( isspace((unsigned char)zLine[i]) ){ i++; } 1458 + if( zLine[i]==0 ) break; 1459 + if( zLine[i]=='\'' || zLine[i]=='"' ){ 1460 + int delim = zLine[i++]; 1461 + azArg[nArg++] = &zLine[i]; 1462 + while( zLine[i] && zLine[i]!=delim ){ i++; } 1463 + if( zLine[i]==delim ){ 1464 + zLine[i++] = 0; 1465 + } 1466 + if( delim=='"' ) resolve_backslashes(azArg[nArg-1]); 1467 + }else{ 1468 + azArg[nArg++] = &zLine[i]; 1469 + while( zLine[i] && !isspace((unsigned char)zLine[i]) ){ i++; } 1470 + if( zLine[i] ) zLine[i++] = 0; 1471 + resolve_backslashes(azArg[nArg-1]); 1472 + } 1473 + } 1474 + 1475 + /* Process the input line. 1476 + */ 1477 + if( nArg==0 ) return 0; /* no tokens, no error */ 1478 + n = strlen30(azArg[0]); 1479 + c = azArg[0][0]; 1480 + if( c=='b' && n>=3 && strncmp(azArg[0], "backup", n)==0 && nArg>1 && nArg<4){ 1481 + const char *zDestFile; 1482 + const char *zDb; 1483 + sqlite3 *pDest; 1484 + sqlite3_backup *pBackup; 1485 + if( nArg==2 ){ 1486 + zDestFile = azArg[1]; 1487 + zDb = "main"; 1488 + }else{ 1489 + zDestFile = azArg[2]; 1490 + zDb = azArg[1]; 1491 + } 1492 + rc = sqlite3_open(zDestFile, &pDest); 1493 + if( rc!=SQLITE_OK ){ 1494 + fprintf(stderr, "Error: cannot open \"%s\"\n", zDestFile); 1495 + sqlite3_close(pDest); 1496 + return 1; 1497 + } 1498 + open_db(p); 1499 + pBackup = sqlite3_backup_init(pDest, "main", p->db, zDb); 1500 + if( pBackup==0 ){ 1501 + fprintf(stderr, "Error: %s\n", sqlite3_errmsg(pDest)); 1502 + sqlite3_close(pDest); 1503 + return 1; 1504 + } 1505 + while( (rc = sqlite3_backup_step(pBackup,100))==SQLITE_OK ){} 1506 + sqlite3_backup_finish(pBackup); 1507 + if( rc==SQLITE_DONE ){ 1508 + rc = 0; 1509 + }else{ 1510 + fprintf(stderr, "Error: %s\n", sqlite3_errmsg(pDest)); 1511 + rc = 1; 1512 + } 1513 + sqlite3_close(pDest); 1514 + }else 1515 + 1516 + if( c=='b' && n>=3 && strncmp(azArg[0], "bail", n)==0 && nArg>1 && nArg<3 ){ 1517 + bail_on_error = booleanValue(azArg[1]); 1518 + }else 1519 + 1520 + if( c=='d' && n>1 && strncmp(azArg[0], "databases", n)==0 && nArg==1 ){ 1521 + struct callback_data data; 1522 + char *zErrMsg = 0; 1523 + open_db(p); 1524 + memcpy(&data, p, sizeof(data)); 1525 + data.showHeader = 1; 1526 + data.mode = MODE_Column; 1527 + data.colWidth[0] = 3; 1528 + data.colWidth[1] = 15; 1529 + data.colWidth[2] = 58; 1530 + data.cnt = 0; 1531 + sqlite3_exec(p->db, "PRAGMA database_list; ", callback, &data, &zErrMsg); 1532 + if( zErrMsg ){ 1533 + fprintf(stderr,"Error: %s\n", zErrMsg); 1534 + sqlite3_free(zErrMsg); 1535 + rc = 1; 1536 + } 1537 + }else 1538 + 1539 + if( c=='d' && strncmp(azArg[0], "dump", n)==0 && nArg<3 ){ 1540 + char *zErrMsg = 0; 1541 + open_db(p); 1542 + /* When playing back a "dump", the content might appear in an order 1543 + ** which causes immediate foreign key constraints to be violated. 1544 + ** So disable foreign-key constraint enforcement to prevent problems. */ 1545 + fprintf(p->out, "PRAGMA foreign_keys=OFF;\n"); 1546 + fprintf(p->out, "BEGIN TRANSACTION;\n"); 1547 + p->writableSchema = 0; 1548 + sqlite3_exec(p->db, "PRAGMA writable_schema=ON", 0, 0, 0); 1549 + if( nArg==1 ){ 1550 + run_schema_dump_query(p, 1551 + "SELECT name, type, sql FROM sqlite_master " 1552 + "WHERE sql NOT NULL AND type=='table' AND name!='sqlite_sequence'", 0 1553 + ); 1554 + run_schema_dump_query(p, 1555 + "SELECT name, type, sql FROM sqlite_master " 1556 + "WHERE name=='sqlite_sequence'", 0 1557 + ); 1558 + run_table_dump_query(p->out, p->db, 1559 + "SELECT sql FROM sqlite_master " 1560 + "WHERE sql NOT NULL AND type IN ('index','trigger','view')", 0 1561 + ); 1562 + }else{ 1563 + int i; 1564 + for(i=1; i<nArg; i++){ 1565 + zShellStatic = azArg[i]; 1566 + run_schema_dump_query(p, 1567 + "SELECT name, type, sql FROM sqlite_master " 1568 + "WHERE tbl_name LIKE shellstatic() AND type=='table'" 1569 + " AND sql NOT NULL", 0); 1570 + run_table_dump_query(p->out, p->db, 1571 + "SELECT sql FROM sqlite_master " 1572 + "WHERE sql NOT NULL" 1573 + " AND type IN ('index','trigger','view')" 1574 + " AND tbl_name LIKE shellstatic()", 0 1575 + ); 1576 + zShellStatic = 0; 1577 + } 1578 + } 1579 + if( p->writableSchema ){ 1580 + fprintf(p->out, "PRAGMA writable_schema=OFF;\n"); 1581 + p->writableSchema = 0; 1582 + } 1583 + sqlite3_exec(p->db, "PRAGMA writable_schema=OFF", 0, 0, 0); 1584 + if( zErrMsg ){ 1585 + fprintf(stderr,"Error: %s\n", zErrMsg); 1586 + sqlite3_free(zErrMsg); 1587 + }else{ 1588 + fprintf(p->out, "COMMIT;\n"); 1589 + } 1590 + }else 1591 + 1592 + if( c=='e' && strncmp(azArg[0], "echo", n)==0 && nArg>1 && nArg<3 ){ 1593 + p->echoOn = booleanValue(azArg[1]); 1594 + }else 1595 + 1596 + if( c=='e' && strncmp(azArg[0], "exit", n)==0 && nArg==1 ){ 1597 + rc = 2; 1598 + }else 1599 + 1600 + if( c=='e' && strncmp(azArg[0], "explain", n)==0 && nArg<3 ){ 1601 + int val = nArg>=2 ? booleanValue(azArg[1]) : 1; 1602 + if(val == 1) { 1603 + if(!p->explainPrev.valid) { 1604 + p->explainPrev.valid = 1; 1605 + p->explainPrev.mode = p->mode; 1606 + p->explainPrev.showHeader = p->showHeader; 1607 + memcpy(p->explainPrev.colWidth,p->colWidth,sizeof(p->colWidth)); 1608 + } 1609 + /* We could put this code under the !p->explainValid 1610 + ** condition so that it does not execute if we are already in 1611 + ** explain mode. However, always executing it allows us an easy 1612 + ** was to reset to explain mode in case the user previously 1613 + ** did an .explain followed by a .width, .mode or .header 1614 + ** command. 1615 + */ 1616 + p->mode = MODE_Explain; 1617 + p->showHeader = 1; 1618 + memset(p->colWidth,0,ArraySize(p->colWidth)); 1619 + p->colWidth[0] = 4; /* addr */ 1620 + p->colWidth[1] = 13; /* opcode */ 1621 + p->colWidth[2] = 4; /* P1 */ 1622 + p->colWidth[3] = 4; /* P2 */ 1623 + p->colWidth[4] = 4; /* P3 */ 1624 + p->colWidth[5] = 13; /* P4 */ 1625 + p->colWidth[6] = 2; /* P5 */ 1626 + p->colWidth[7] = 13; /* Comment */ 1627 + }else if (p->explainPrev.valid) { 1628 + p->explainPrev.valid = 0; 1629 + p->mode = p->explainPrev.mode; 1630 + p->showHeader = p->explainPrev.showHeader; 1631 + memcpy(p->colWidth,p->explainPrev.colWidth,sizeof(p->colWidth)); 1632 + } 1633 + }else 1634 + 1635 + if( c=='h' && (strncmp(azArg[0], "header", n)==0 || 1636 + strncmp(azArg[0], "headers", n)==0) && nArg>1 && nArg<3 ){ 1637 + p->showHeader = booleanValue(azArg[1]); 1638 + }else 1639 + 1640 + if( c=='h' && strncmp(azArg[0], "help", n)==0 ){ 1641 + fprintf(stderr,"%s",zHelp); 1642 + if( HAS_TIMER ){ 1643 + fprintf(stderr,"%s",zTimerHelp); 1644 + } 1645 + }else 1646 + 1647 + if( c=='i' && strncmp(azArg[0], "import", n)==0 && nArg==3 ){ 1648 + char *zTable = azArg[2]; /* Insert data into this table */ 1649 + char *zFile = azArg[1]; /* The file from which to extract data */ 1650 + sqlite3_stmt *pStmt = NULL; /* A statement */ 1651 + int nCol; /* Number of columns in the table */ 1652 + int nByte; /* Number of bytes in an SQL string */ 1653 + int i, j; /* Loop counters */ 1654 + int nSep; /* Number of bytes in p->separator[] */ 1655 + char *zSql; /* An SQL statement */ 1656 + char *zLine; /* A single line of input from the file */ 1657 + char **azCol; /* zLine[] broken up into columns */ 1658 + char *zCommit; /* How to commit changes */ 1659 + FILE *in; /* The input file */ 1660 + int lineno = 0; /* Line number of input file */ 1661 + 1662 + open_db(p); 1663 + nSep = strlen30(p->separator); 1664 + if( nSep==0 ){ 1665 + fprintf(stderr, "Error: non-null separator required for import\n"); 1666 + return 1; 1667 + } 1668 + zSql = sqlite3_mprintf("SELECT * FROM '%q'", zTable); 1669 + if( zSql==0 ){ 1670 + fprintf(stderr, "Error: out of memory\n"); 1671 + return 1; 1672 + } 1673 + nByte = strlen30(zSql); 1674 + rc = sqlite3_prepare(p->db, zSql, -1, &pStmt, 0); 1675 + sqlite3_free(zSql); 1676 + if( rc ){ 1677 + if (pStmt) sqlite3_finalize(pStmt); 1678 + fprintf(stderr,"Error: %s\n", sqlite3_errmsg(db)); 1679 + return 1; 1680 + } 1681 + nCol = sqlite3_column_count(pStmt); 1682 + sqlite3_finalize(pStmt); 1683 + pStmt = 0; 1684 + if( nCol==0 ) return 0; /* no columns, no error */ 1685 + zSql = malloc( nByte + 20 + nCol*2 ); 1686 + if( zSql==0 ){ 1687 + fprintf(stderr, "Error: out of memory\n"); 1688 + return 1; 1689 + } 1690 + sqlite3_snprintf(nByte+20, zSql, "INSERT INTO '%q' VALUES(?", zTable); 1691 + j = strlen30(zSql); 1692 + for(i=1; i<nCol; i++){ 1693 + zSql[j++] = ','; 1694 + zSql[j++] = '?'; 1695 + } 1696 + zSql[j++] = ')'; 1697 + zSql[j] = 0; 1698 + rc = sqlite3_prepare(p->db, zSql, -1, &pStmt, 0); 1699 + free(zSql); 1700 + if( rc ){ 1701 + fprintf(stderr, "Error: %s\n", sqlite3_errmsg(db)); 1702 + if (pStmt) sqlite3_finalize(pStmt); 1703 + return 1; 1704 + } 1705 + in = fopen(zFile, "rb"); 1706 + if( in==0 ){ 1707 + fprintf(stderr, "Error: cannot open \"%s\"\n", zFile); 1708 + sqlite3_finalize(pStmt); 1709 + return 1; 1710 + } 1711 + azCol = malloc( sizeof(azCol[0])*(nCol+1) ); 1712 + if( azCol==0 ){ 1713 + fprintf(stderr, "Error: out of memory\n"); 1714 + fclose(in); 1715 + sqlite3_finalize(pStmt); 1716 + return 1; 1717 + } 1718 + sqlite3_exec(p->db, "BEGIN", 0, 0, 0); 1719 + zCommit = "COMMIT"; 1720 + while( (zLine = local_getline(0, in))!=0 ){ 1721 + char *z; 1722 + i = 0; 1723 + lineno++; 1724 + azCol[0] = zLine; 1725 + for(i=0, z=zLine; *z && *z!='\n' && *z!='\r'; z++){ 1726 + if( *z==p->separator[0] && strncmp(z, p->separator, nSep)==0 ){ 1727 + *z = 0; 1728 + i++; 1729 + if( i<nCol ){ 1730 + azCol[i] = &z[nSep]; 1731 + z += nSep-1; 1732 + } 1733 + } 1734 + } /* end for */ 1735 + *z = 0; 1736 + if( i+1!=nCol ){ 1737 + fprintf(stderr, 1738 + "Error: %s line %d: expected %d columns of data but found %d\n", 1739 + zFile, lineno, nCol, i+1); 1740 + zCommit = "ROLLBACK"; 1741 + free(zLine); 1742 + rc = 1; 1743 + break; /* from while */ 1744 + } 1745 + for(i=0; i<nCol; i++){ 1746 + sqlite3_bind_text(pStmt, i+1, azCol[i], -1, SQLITE_STATIC); 1747 + } 1748 + sqlite3_step(pStmt); 1749 + rc = sqlite3_reset(pStmt); 1750 + free(zLine); 1751 + if( rc!=SQLITE_OK ){ 1752 + fprintf(stderr,"Error: %s\n", sqlite3_errmsg(db)); 1753 + zCommit = "ROLLBACK"; 1754 + rc = 1; 1755 + break; /* from while */ 1756 + } 1757 + } /* end while */ 1758 + free(azCol); 1759 + fclose(in); 1760 + sqlite3_finalize(pStmt); 1761 + sqlite3_exec(p->db, zCommit, 0, 0, 0); 1762 + }else 1763 + 1764 + if( c=='i' && strncmp(azArg[0], "indices", n)==0 && nArg<3 ){ 1765 + struct callback_data data; 1766 + char *zErrMsg = 0; 1767 + open_db(p); 1768 + memcpy(&data, p, sizeof(data)); 1769 + data.showHeader = 0; 1770 + data.mode = MODE_List; 1771 + if( nArg==1 ){ 1772 + rc = sqlite3_exec(p->db, 1773 + "SELECT name FROM sqlite_master " 1774 + "WHERE type='index' AND name NOT LIKE 'sqlite_%' " 1775 + "UNION ALL " 1776 + "SELECT name FROM sqlite_temp_master " 1777 + "WHERE type='index' " 1778 + "ORDER BY 1", 1779 + callback, &data, &zErrMsg 1780 + ); 1781 + }else{ 1782 + zShellStatic = azArg[1]; 1783 + rc = sqlite3_exec(p->db, 1784 + "SELECT name FROM sqlite_master " 1785 + "WHERE type='index' AND tbl_name LIKE shellstatic() " 1786 + "UNION ALL " 1787 + "SELECT name FROM sqlite_temp_master " 1788 + "WHERE type='index' AND tbl_name LIKE shellstatic() " 1789 + "ORDER BY 1", 1790 + callback, &data, &zErrMsg 1791 + ); 1792 + zShellStatic = 0; 1793 + } 1794 + if( zErrMsg ){ 1795 + fprintf(stderr,"Error: %s\n", zErrMsg); 1796 + sqlite3_free(zErrMsg); 1797 + rc = 1; 1798 + }else if( rc != SQLITE_OK ){ 1799 + fprintf(stderr,"Error: querying sqlite_master and sqlite_temp_master\n"); 1800 + rc = 1; 1801 + } 1802 + }else 1803 + 1804 +#ifdef SQLITE_ENABLE_IOTRACE 1805 + if( c=='i' && strncmp(azArg[0], "iotrace", n)==0 ){ 1806 + extern void (*sqlite3IoTrace)(const char*, ...); 1807 + if( iotrace && iotrace!=stdout ) fclose(iotrace); 1808 + iotrace = 0; 1809 + if( nArg<2 ){ 1810 + sqlite3IoTrace = 0; 1811 + }else if( strcmp(azArg[1], "-")==0 ){ 1812 + sqlite3IoTrace = iotracePrintf; 1813 + iotrace = stdout; 1814 + }else{ 1815 + iotrace = fopen(azArg[1], "w"); 1816 + if( iotrace==0 ){ 1817 + fprintf(stderr, "Error: cannot open \"%s\"\n", azArg[1]); 1818 + sqlite3IoTrace = 0; 1819 + rc = 1; 1820 + }else{ 1821 + sqlite3IoTrace = iotracePrintf; 1822 + } 1823 + } 1824 + }else 1825 +#endif 1826 + 1827 +#ifndef SQLITE_OMIT_LOAD_EXTENSION 1828 + if( c=='l' && strncmp(azArg[0], "load", n)==0 && nArg>=2 ){ 1829 + const char *zFile, *zProc; 1830 + char *zErrMsg = 0; 1831 + zFile = azArg[1]; 1832 + zProc = nArg>=3 ? azArg[2] : 0; 1833 + open_db(p); 1834 + rc = sqlite3_load_extension(p->db, zFile, zProc, &zErrMsg); 1835 + if( rc!=SQLITE_OK ){ 1836 + fprintf(stderr, "Error: %s\n", zErrMsg); 1837 + sqlite3_free(zErrMsg); 1838 + rc = 1; 1839 + } 1840 + }else 1841 +#endif 1842 + 1843 + if( c=='l' && strncmp(azArg[0], "log", n)==0 && nArg>=1 ){ 1844 + const char *zFile = azArg[1]; 1845 + if( p->pLog && p->pLog!=stdout && p->pLog!=stderr ){ 1846 + fclose(p->pLog); 1847 + p->pLog = 0; 1848 + } 1849 + if( strcmp(zFile,"stdout")==0 ){ 1850 + p->pLog = stdout; 1851 + }else if( strcmp(zFile, "stderr")==0 ){ 1852 + p->pLog = stderr; 1853 + }else if( strcmp(zFile, "off")==0 ){ 1854 + p->pLog = 0; 1855 + }else{ 1856 + p->pLog = fopen(zFile, "w"); 1857 + if( p->pLog==0 ){ 1858 + fprintf(stderr, "Error: cannot open \"%s\"\n", zFile); 1859 + } 1860 + } 1861 + }else 1862 + 1863 + if( c=='m' && strncmp(azArg[0], "mode", n)==0 && nArg==2 ){ 1864 + int n2 = strlen30(azArg[1]); 1865 + if( (n2==4 && strncmp(azArg[1],"line",n2)==0) 1866 + || 1867 + (n2==5 && strncmp(azArg[1],"lines",n2)==0) ){ 1868 + p->mode = MODE_Line; 1869 + }else if( (n2==6 && strncmp(azArg[1],"column",n2)==0) 1870 + || 1871 + (n2==7 && strncmp(azArg[1],"columns",n2)==0) ){ 1872 + p->mode = MODE_Column; 1873 + }else if( n2==4 && strncmp(azArg[1],"list",n2)==0 ){ 1874 + p->mode = MODE_List; 1875 + }else if( n2==4 && strncmp(azArg[1],"html",n2)==0 ){ 1876 + p->mode = MODE_Html; 1877 + }else if( n2==3 && strncmp(azArg[1],"tcl",n2)==0 ){ 1878 + p->mode = MODE_Tcl; 1879 + }else if( n2==3 && strncmp(azArg[1],"csv",n2)==0 ){ 1880 + p->mode = MODE_Csv; 1881 + sqlite3_snprintf(sizeof(p->separator), p->separator, ","); 1882 + }else if( n2==4 && strncmp(azArg[1],"tabs",n2)==0 ){ 1883 + p->mode = MODE_List; 1884 + sqlite3_snprintf(sizeof(p->separator), p->separator, "\t"); 1885 + }else if( n2==6 && strncmp(azArg[1],"insert",n2)==0 ){ 1886 + p->mode = MODE_Insert; 1887 + set_table_name(p, "table"); 1888 + }else { 1889 + fprintf(stderr,"Error: mode should be one of: " 1890 + "column csv html insert line list tabs tcl\n"); 1891 + rc = 1; 1892 + } 1893 + }else 1894 + 1895 + if( c=='m' && strncmp(azArg[0], "mode", n)==0 && nArg==3 ){ 1896 + int n2 = strlen30(azArg[1]); 1897 + if( n2==6 && strncmp(azArg[1],"insert",n2)==0 ){ 1898 + p->mode = MODE_Insert; 1899 + set_table_name(p, azArg[2]); 1900 + }else { 1901 + fprintf(stderr, "Error: invalid arguments: " 1902 + " \"%s\". Enter \".help\" for help\n", azArg[2]); 1903 + rc = 1; 1904 + } 1905 + }else 1906 + 1907 + if( c=='n' && strncmp(azArg[0], "nullvalue", n)==0 && nArg==2 ) { 1908 + sqlite3_snprintf(sizeof(p->nullvalue), p->nullvalue, 1909 + "%.*s", (int)ArraySize(p->nullvalue)-1, azArg[1]); 1910 + }else 1911 + 1912 + if( c=='o' && strncmp(azArg[0], "output", n)==0 && nArg==2 ){ 1913 + if( p->out!=stdout ){ 1914 + fclose(p->out); 1915 + } 1916 + if( strcmp(azArg[1],"stdout")==0 ){ 1917 + p->out = stdout; 1918 + sqlite3_snprintf(sizeof(p->outfile), p->outfile, "stdout"); 1919 + }else{ 1920 + p->out = fopen(azArg[1], "wb"); 1921 + if( p->out==0 ){ 1922 + fprintf(stderr,"Error: cannot write to \"%s\"\n", azArg[1]); 1923 + p->out = stdout; 1924 + rc = 1; 1925 + } else { 1926 + sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", azArg[1]); 1927 + } 1928 + } 1929 + }else 1930 + 1931 + if( c=='p' && strncmp(azArg[0], "prompt", n)==0 && (nArg==2 || nArg==3)){ 1932 + if( nArg >= 2) { 1933 + strncpy(mainPrompt,azArg[1],(int)ArraySize(mainPrompt)-1); 1934 + } 1935 + if( nArg >= 3) { 1936 + strncpy(continuePrompt,azArg[2],(int)ArraySize(continuePrompt)-1); 1937 + } 1938 + }else 1939 + 1940 + if( c=='q' && strncmp(azArg[0], "quit", n)==0 && nArg==1 ){ 1941 + rc = 2; 1942 + }else 1943 + 1944 + if( c=='r' && n>=3 && strncmp(azArg[0], "read", n)==0 && nArg==2 ){ 1945 + FILE *alt = fopen(azArg[1], "rb"); 1946 + if( alt==0 ){ 1947 + fprintf(stderr,"Error: cannot open \"%s\"\n", azArg[1]); 1948 + rc = 1; 1949 + }else{ 1950 + rc = process_input(p, alt); 1951 + fclose(alt); 1952 + } 1953 + }else 1954 + 1955 + if( c=='r' && n>=3 && strncmp(azArg[0], "restore", n)==0 && nArg>1 && nArg<4){ 1956 + const char *zSrcFile; 1957 + const char *zDb; 1958 + sqlite3 *pSrc; 1959 + sqlite3_backup *pBackup; 1960 + int nTimeout = 0; 1961 + 1962 + if( nArg==2 ){ 1963 + zSrcFile = azArg[1]; 1964 + zDb = "main"; 1965 + }else{ 1966 + zSrcFile = azArg[2]; 1967 + zDb = azArg[1]; 1968 + } 1969 + rc = sqlite3_open(zSrcFile, &pSrc); 1970 + if( rc!=SQLITE_OK ){ 1971 + fprintf(stderr, "Error: cannot open \"%s\"\n", zSrcFile); 1972 + sqlite3_close(pSrc); 1973 + return 1; 1974 + } 1975 + open_db(p); 1976 + pBackup = sqlite3_backup_init(p->db, zDb, pSrc, "main"); 1977 + if( pBackup==0 ){ 1978 + fprintf(stderr, "Error: %s\n", sqlite3_errmsg(p->db)); 1979 + sqlite3_close(pSrc); 1980 + return 1; 1981 + } 1982 + while( (rc = sqlite3_backup_step(pBackup,100))==SQLITE_OK 1983 + || rc==SQLITE_BUSY ){ 1984 + if( rc==SQLITE_BUSY ){ 1985 + if( nTimeout++ >= 3 ) break; 1986 + sqlite3_sleep(100); 1987 + } 1988 + } 1989 + sqlite3_backup_finish(pBackup); 1990 + if( rc==SQLITE_DONE ){ 1991 + rc = 0; 1992 + }else if( rc==SQLITE_BUSY || rc==SQLITE_LOCKED ){ 1993 + fprintf(stderr, "Error: source database is busy\n"); 1994 + rc = 1; 1995 + }else{ 1996 + fprintf(stderr, "Error: %s\n", sqlite3_errmsg(p->db)); 1997 + rc = 1; 1998 + } 1999 + sqlite3_close(pSrc); 2000 + }else 2001 + 2002 + if( c=='s' && strncmp(azArg[0], "schema", n)==0 && nArg<3 ){ 2003 + struct callback_data data; 2004 + char *zErrMsg = 0; 2005 + open_db(p); 2006 + memcpy(&data, p, sizeof(data)); 2007 + data.showHeader = 0; 2008 + data.mode = MODE_Semi; 2009 + if( nArg>1 ){ 2010 + int i; 2011 + for(i=0; azArg[1][i]; i++) azArg[1][i] = (char)tolower(azArg[1][i]); 2012 + if( strcmp(azArg[1],"sqlite_master")==0 ){ 2013 + char *new_argv[2], *new_colv[2]; 2014 + new_argv[0] = "CREATE TABLE sqlite_master (\n" 2015 + " type text,\n" 2016 + " name text,\n" 2017 + " tbl_name text,\n" 2018 + " rootpage integer,\n" 2019 + " sql text\n" 2020 + ")"; 2021 + new_argv[1] = 0; 2022 + new_colv[0] = "sql"; 2023 + new_colv[1] = 0; 2024 + callback(&data, 1, new_argv, new_colv); 2025 + rc = SQLITE_OK; 2026 + }else if( strcmp(azArg[1],"sqlite_temp_master")==0 ){ 2027 + char *new_argv[2], *new_colv[2]; 2028 + new_argv[0] = "CREATE TEMP TABLE sqlite_temp_master (\n" 2029 + " type text,\n" 2030 + " name text,\n" 2031 + " tbl_name text,\n" 2032 + " rootpage integer,\n" 2033 + " sql text\n" 2034 + ")"; 2035 + new_argv[1] = 0; 2036 + new_colv[0] = "sql"; 2037 + new_colv[1] = 0; 2038 + callback(&data, 1, new_argv, new_colv); 2039 + rc = SQLITE_OK; 2040 + }else{ 2041 + zShellStatic = azArg[1]; 2042 + rc = sqlite3_exec(p->db, 2043 + "SELECT sql FROM " 2044 + " (SELECT sql sql, type type, tbl_name tbl_name, name name" 2045 + " FROM sqlite_master UNION ALL" 2046 + " SELECT sql, type, tbl_name, name FROM sqlite_temp_master) " 2047 + "WHERE tbl_name LIKE shellstatic() AND type!='meta' AND sql NOTNULL " 2048 + "ORDER BY substr(type,2,1), name", 2049 + callback, &data, &zErrMsg); 2050 + zShellStatic = 0; 2051 + } 2052 + }else{ 2053 + rc = sqlite3_exec(p->db, 2054 + "SELECT sql FROM " 2055 + " (SELECT sql sql, type type, tbl_name tbl_name, name name" 2056 + " FROM sqlite_master UNION ALL" 2057 + " SELECT sql, type, tbl_name, name FROM sqlite_temp_master) " 2058 + "WHERE type!='meta' AND sql NOTNULL AND name NOT LIKE 'sqlite_%'" 2059 + "ORDER BY substr(type,2,1), name", 2060 + callback, &data, &zErrMsg 2061 + ); 2062 + } 2063 + if( zErrMsg ){ 2064 + fprintf(stderr,"Error: %s\n", zErrMsg); 2065 + sqlite3_free(zErrMsg); 2066 + rc = 1; 2067 + }else if( rc != SQLITE_OK ){ 2068 + fprintf(stderr,"Error: querying schema information\n"); 2069 + rc = 1; 2070 + }else{ 2071 + rc = 0; 2072 + } 2073 + }else 2074 + 2075 + if( c=='s' && strncmp(azArg[0], "separator", n)==0 && nArg==2 ){ 2076 + sqlite3_snprintf(sizeof(p->separator), p->separator, 2077 + "%.*s", (int)sizeof(p->separator)-1, azArg[1]); 2078 + }else 2079 + 2080 + if( c=='s' && strncmp(azArg[0], "show", n)==0 && nArg==1 ){ 2081 + int i; 2082 + fprintf(p->out,"%9.9s: %s\n","echo", p->echoOn ? "on" : "off"); 2083 + fprintf(p->out,"%9.9s: %s\n","explain", p->explainPrev.valid ? "on" :"off"); 2084 + fprintf(p->out,"%9.9s: %s\n","headers", p->showHeader ? "on" : "off"); 2085 + fprintf(p->out,"%9.9s: %s\n","mode", modeDescr[p->mode]); 2086 + fprintf(p->out,"%9.9s: ", "nullvalue"); 2087 + output_c_string(p->out, p->nullvalue); 2088 + fprintf(p->out, "\n"); 2089 + fprintf(p->out,"%9.9s: %s\n","output", 2090 + strlen30(p->outfile) ? p->outfile : "stdout"); 2091 + fprintf(p->out,"%9.9s: ", "separator"); 2092 + output_c_string(p->out, p->separator); 2093 + fprintf(p->out, "\n"); 2094 + fprintf(p->out,"%9.9s: %s\n","stats", p->statsOn ? "on" : "off"); 2095 + fprintf(p->out,"%9.9s: ","width"); 2096 + for (i=0;i<(int)ArraySize(p->colWidth) && p->colWidth[i] != 0;i++) { 2097 + fprintf(p->out,"%d ",p->colWidth[i]); 2098 + } 2099 + fprintf(p->out,"\n"); 2100 + }else 2101 + 2102 + if( c=='s' && strncmp(azArg[0], "stats", n)==0 && nArg>1 && nArg<3 ){ 2103 + p->statsOn = booleanValue(azArg[1]); 2104 + }else 2105 + 2106 + if( c=='t' && n>1 && strncmp(azArg[0], "tables", n)==0 && nArg<3 ){ 2107 + char **azResult; 2108 + int nRow; 2109 + char *zErrMsg; 2110 + open_db(p); 2111 + if( nArg==1 ){ 2112 + rc = sqlite3_get_table(p->db, 2113 + "SELECT name FROM sqlite_master " 2114 + "WHERE type IN ('table','view') AND name NOT LIKE 'sqlite_%' " 2115 + "UNION ALL " 2116 + "SELECT name FROM sqlite_temp_master " 2117 + "WHERE type IN ('table','view') " 2118 + "ORDER BY 1", 2119 + &azResult, &nRow, 0, &zErrMsg 2120 + ); 2121 + }else{ 2122 + zShellStatic = azArg[1]; 2123 + rc = sqlite3_get_table(p->db, 2124 + "SELECT name FROM sqlite_master " 2125 + "WHERE type IN ('table','view') AND name LIKE shellstatic() " 2126 + "UNION ALL " 2127 + "SELECT name FROM sqlite_temp_master " 2128 + "WHERE type IN ('table','view') AND name LIKE shellstatic() " 2129 + "ORDER BY 1", 2130 + &azResult, &nRow, 0, &zErrMsg 2131 + ); 2132 + zShellStatic = 0; 2133 + } 2134 + if( zErrMsg ){ 2135 + fprintf(stderr,"Error: %s\n", zErrMsg); 2136 + sqlite3_free(zErrMsg); 2137 + rc = 1; 2138 + }else if( rc != SQLITE_OK ){ 2139 + fprintf(stderr,"Error: querying sqlite_master and sqlite_temp_master\n"); 2140 + rc = 1; 2141 + }else{ 2142 + int len, maxlen = 0; 2143 + int i, j; 2144 + int nPrintCol, nPrintRow; 2145 + for(i=1; i<=nRow; i++){ 2146 + if( azResult[i]==0 ) continue; 2147 + len = strlen30(azResult[i]); 2148 + if( len>maxlen ) maxlen = len; 2149 + } 2150 + nPrintCol = 80/(maxlen+2); 2151 + if( nPrintCol<1 ) nPrintCol = 1; 2152 + nPrintRow = (nRow + nPrintCol - 1)/nPrintCol; 2153 + for(i=0; i<nPrintRow; i++){ 2154 + for(j=i+1; j<=nRow; j+=nPrintRow){ 2155 + char *zSp = j<=nPrintRow ? "" : " "; 2156 + printf("%s%-*s", zSp, maxlen, azResult[j] ? azResult[j] : ""); 2157 + } 2158 + printf("\n"); 2159 + } 2160 + } 2161 + sqlite3_free_table(azResult); 2162 + }else 2163 + 2164 + if( c=='t' && n>4 && strncmp(azArg[0], "timeout", n)==0 && nArg==2 ){ 2165 + open_db(p); 2166 + sqlite3_busy_timeout(p->db, atoi(azArg[1])); 2167 + }else 2168 + 2169 + if( HAS_TIMER && c=='t' && n>=5 && strncmp(azArg[0], "timer", n)==0 && nArg==2 ){ 2170 + enableTimer = booleanValue(azArg[1]); 2171 + }else 2172 + 2173 + if( c=='w' && strncmp(azArg[0], "width", n)==0 && nArg>1 ){ 2174 + int j; 2175 + assert( nArg<=ArraySize(azArg) ); 2176 + for(j=1; j<nArg && j<ArraySize(p->colWidth); j++){ 2177 + p->colWidth[j-1] = atoi(azArg[j]); 2178 + } 2179 + }else 2180 + 2181 + { 2182 + fprintf(stderr, "Error: unknown command or invalid arguments: " 2183 + " \"%s\". Enter \".help\" for help\n", azArg[0]); 2184 + rc = 1; 2185 + } 2186 + 2187 + return rc; 2188 +} 2189 + 2190 +/* 2191 +** Return TRUE if a semicolon occurs anywhere in the first N characters 2192 +** of string z[]. 2193 +*/ 2194 +static int _contains_semicolon(const char *z, int N){ 2195 + int i; 2196 + for(i=0; i<N; i++){ if( z[i]==';' ) return 1; } 2197 + return 0; 2198 +} 2199 + 2200 +/* 2201 +** Test to see if a line consists entirely of whitespace. 2202 +*/ 2203 +static int _all_whitespace(const char *z){ 2204 + for(; *z; z++){ 2205 + if( isspace(*(unsigned char*)z) ) continue; 2206 + if( *z=='/' && z[1]=='*' ){ 2207 + z += 2; 2208 + while( *z && (*z!='*' || z[1]!='/') ){ z++; } 2209 + if( *z==0 ) return 0; 2210 + z++; 2211 + continue; 2212 + } 2213 + if( *z=='-' && z[1]=='-' ){ 2214 + z += 2; 2215 + while( *z && *z!='\n' ){ z++; } 2216 + if( *z==0 ) return 1; 2217 + continue; 2218 + } 2219 + return 0; 2220 + } 2221 + return 1; 2222 +} 2223 + 2224 +/* 2225 +** Return TRUE if the line typed in is an SQL command terminator other 2226 +** than a semi-colon. The SQL Server style "go" command is understood 2227 +** as is the Oracle "/". 2228 +*/ 2229 +static int _is_command_terminator(const char *zLine){ 2230 + while( isspace(*(unsigned char*)zLine) ){ zLine++; }; 2231 + if( zLine[0]=='/' && _all_whitespace(&zLine[1]) ){ 2232 + return 1; /* Oracle */ 2233 + } 2234 + if( tolower(zLine[0])=='g' && tolower(zLine[1])=='o' 2235 + && _all_whitespace(&zLine[2]) ){ 2236 + return 1; /* SQL Server */ 2237 + } 2238 + return 0; 2239 +} 2240 + 2241 +/* 2242 +** Return true if zSql is a complete SQL statement. Return false if it 2243 +** ends in the middle of a string literal or C-style comment. 2244 +*/ 2245 +static int _is_complete(char *zSql, int nSql){ 2246 + int rc; 2247 + if( zSql==0 ) return 1; 2248 + zSql[nSql] = ';'; 2249 + zSql[nSql+1] = 0; 2250 + rc = sqlite3_complete(zSql); 2251 + zSql[nSql] = 0; 2252 + return rc; 2253 +} 2254 + 2255 +/* 2256 +** Read input from *in and process it. If *in==0 then input 2257 +** is interactive - the user is typing it it. Otherwise, input 2258 +** is coming from a file or device. A prompt is issued and history 2259 +** is saved only if input is interactive. An interrupt signal will 2260 +** cause this routine to exit immediately, unless input is interactive. 2261 +** 2262 +** Return the number of errors. 2263 +*/ 2264 +static int process_input(struct callback_data *p, FILE *in){ 2265 + char *zLine = 0; 2266 + char *zSql = 0; 2267 + int nSql = 0; 2268 + int nSqlPrior = 0; 2269 + char *zErrMsg; 2270 + int rc; 2271 + int errCnt = 0; 2272 + int lineno = 0; 2273 + int startline = 0; 2274 + 2275 + while( errCnt==0 || !bail_on_error || (in==0 && stdin_is_interactive) ){ 2276 + fflush(p->out); 2277 + free(zLine); 2278 + zLine = one_input_line(zSql, in); 2279 + if( zLine==0 ){ 2280 + break; /* We have reached EOF */ 2281 + } 2282 + if( seenInterrupt ){ 2283 + if( in!=0 ) break; 2284 + seenInterrupt = 0; 2285 + } 2286 + lineno++; 2287 + if( (zSql==0 || zSql[0]==0) && _all_whitespace(zLine) ) continue; 2288 + if( zLine && zLine[0]=='.' && nSql==0 ){ 2289 + if( p->echoOn ) printf("%s\n", zLine); 2290 + rc = do_meta_command(zLine, p); 2291 + if( rc==2 ){ /* exit requested */ 2292 + break; 2293 + }else if( rc ){ 2294 + errCnt++; 2295 + } 2296 + continue; 2297 + } 2298 + if( _is_command_terminator(zLine) && _is_complete(zSql, nSql) ){ 2299 + memcpy(zLine,";",2); 2300 + } 2301 + nSqlPrior = nSql; 2302 + if( zSql==0 ){ 2303 + int i; 2304 + for(i=0; zLine[i] && isspace((unsigned char)zLine[i]); i++){} 2305 + if( zLine[i]!=0 ){ 2306 + nSql = strlen30(zLine); 2307 + zSql = malloc( nSql+3 ); 2308 + if( zSql==0 ){ 2309 + fprintf(stderr, "Error: out of memory\n"); 2310 + exit(1); 2311 + } 2312 + memcpy(zSql, zLine, nSql+1); 2313 + startline = lineno; 2314 + } 2315 + }else{ 2316 + int len = strlen30(zLine); 2317 + zSql = realloc( zSql, nSql + len + 4 ); 2318 + if( zSql==0 ){ 2319 + fprintf(stderr,"Error: out of memory\n"); 2320 + exit(1); 2321 + } 2322 + zSql[nSql++] = '\n'; 2323 + memcpy(&zSql[nSql], zLine, len+1); 2324 + nSql += len; 2325 + } 2326 + if( zSql && _contains_semicolon(&zSql[nSqlPrior], nSql-nSqlPrior) 2327 + && sqlite3_complete(zSql) ){ 2328 + p->cnt = 0; 2329 + open_db(p); 2330 + BEGIN_TIMER; 2331 + rc = shell_exec(p->db, zSql, shell_callback, p, &zErrMsg); 2332 + END_TIMER; 2333 + if( rc || zErrMsg ){ 2334 + char zPrefix[100]; 2335 + if( in!=0 || !stdin_is_interactive ){ 2336 + sqlite3_snprintf(sizeof(zPrefix), zPrefix, 2337 + "Error: near line %d:", startline); 2338 + }else{ 2339 + sqlite3_snprintf(sizeof(zPrefix), zPrefix, "Error:"); 2340 + } 2341 + if( zErrMsg!=0 ){ 2342 + fprintf(stderr, "%s %s\n", zPrefix, zErrMsg); 2343 + sqlite3_free(zErrMsg); 2344 + zErrMsg = 0; 2345 + }else{ 2346 + fprintf(stderr, "%s %s\n", zPrefix, sqlite3_errmsg(p->db)); 2347 + } 2348 + errCnt++; 2349 + } 2350 + free(zSql); 2351 + zSql = 0; 2352 + nSql = 0; 2353 + } 2354 + } 2355 + if( zSql ){ 2356 + if( !_all_whitespace(zSql) ) fprintf(stderr, "Error: incomplete SQL: %s\n", zSql); 2357 + free(zSql); 2358 + } 2359 + free(zLine); 2360 + return errCnt; 2361 +} 2362 + 2363 +/* 2364 +** Return a pathname which is the user's home directory. A 2365 +** 0 return indicates an error of some kind. Space to hold the 2366 +** resulting string is obtained from malloc(). The calling 2367 +** function should free the result. 2368 +*/ 2369 +static char *find_home_dir(void){ 2370 + char *home_dir = NULL; 2371 + 2372 +#if !defined(_WIN32) && !defined(WIN32) && !defined(__OS2__) && !defined(_WIN32_WCE) && !defined(__RTP__) && !defined(_WRS_KERNEL) 2373 + struct passwd *pwent; 2374 + uid_t uid = getuid(); 2375 + if( (pwent=getpwuid(uid)) != NULL) { 2376 + home_dir = pwent->pw_dir; 2377 + } 2378 +#endif 2379 + 2380 +#if defined(_WIN32_WCE) 2381 + /* Windows CE (arm-wince-mingw32ce-gcc) does not provide getenv() 2382 + */ 2383 + home_dir = strdup("/"); 2384 +#else 2385 + 2386 +#if defined(_WIN32) || defined(WIN32) || defined(__OS2__) 2387 + if (!home_dir) { 2388 + home_dir = getenv("USERPROFILE"); 2389 + } 2390 +#endif 2391 + 2392 + if (!home_dir) { 2393 + home_dir = getenv("HOME"); 2394 + } 2395 + 2396 +#if defined(_WIN32) || defined(WIN32) || defined(__OS2__) 2397 + if (!home_dir) { 2398 + char *zDrive, *zPath; 2399 + int n; 2400 + zDrive = getenv("HOMEDRIVE"); 2401 + zPath = getenv("HOMEPATH"); 2402 + if( zDrive && zPath ){ 2403 + n = strlen30(zDrive) + strlen30(zPath) + 1; 2404 + home_dir = malloc( n ); 2405 + if( home_dir==0 ) return 0; 2406 + sqlite3_snprintf(n, home_dir, "%s%s", zDrive, zPath); 2407 + return home_dir; 2408 + } 2409 + home_dir = "c:\\"; 2410 + } 2411 +#endif 2412 + 2413 +#endif /* !_WIN32_WCE */ 2414 + 2415 + if( home_dir ){ 2416 + int n = strlen30(home_dir) + 1; 2417 + char *z = malloc( n ); 2418 + if( z ) memcpy(z, home_dir, n); 2419 + home_dir = z; 2420 + } 2421 + 2422 + return home_dir; 2423 +} 2424 + 2425 +/* 2426 +** Read input from the file given by sqliterc_override. Or if that 2427 +** parameter is NULL, take input from ~/.sqliterc 2428 +** 2429 +** Returns the number of errors. 2430 +*/ 2431 +static int process_sqliterc( 2432 + struct callback_data *p, /* Configuration data */ 2433 + const char *sqliterc_override /* Name of config file. NULL to use default */ 2434 +){ 2435 + char *home_dir = NULL; 2436 + const char *sqliterc = sqliterc_override; 2437 + char *zBuf = 0; 2438 + FILE *in = NULL; 2439 + int nBuf; 2440 + int rc = 0; 2441 + 2442 + if (sqliterc == NULL) { 2443 + home_dir = find_home_dir(); 2444 + if( home_dir==0 ){ 2445 +#if !defined(__RTP__) && !defined(_WRS_KERNEL) 2446 + fprintf(stderr,"%s: Error: cannot locate your home directory\n", Argv0); 2447 +#endif 2448 + return 1; 2449 + } 2450 + nBuf = strlen30(home_dir) + 16; 2451 + zBuf = malloc( nBuf ); 2452 + if( zBuf==0 ){ 2453 + fprintf(stderr,"%s: Error: out of memory\n",Argv0); 2454 + return 1; 2455 + } 2456 + sqlite3_snprintf(nBuf, zBuf,"%s/.sqliterc",home_dir); 2457 + free(home_dir); 2458 + sqliterc = (const char*)zBuf; 2459 + } 2460 + in = fopen(sqliterc,"rb"); 2461 + if( in ){ 2462 + if( stdin_is_interactive ){ 2463 + fprintf(stderr,"-- Loading resources from %s\n",sqliterc); 2464 + } 2465 + rc = process_input(p,in); 2466 + fclose(in); 2467 + } 2468 + free(zBuf); 2469 + return rc; 2470 +} 2471 + 2472 +/* 2473 +** Show available command line options 2474 +*/ 2475 +static const char zOptions[] = 2476 + " -help show this message\n" 2477 + " -init filename read/process named file\n" 2478 + " -echo print commands before execution\n" 2479 + " -[no]header turn headers on or off\n" 2480 + " -bail stop after hitting an error\n" 2481 + " -interactive force interactive I/O\n" 2482 + " -batch force batch I/O\n" 2483 + " -column set output mode to 'column'\n" 2484 + " -csv set output mode to 'csv'\n" 2485 + " -html set output mode to HTML\n" 2486 + " -line set output mode to 'line'\n" 2487 + " -list set output mode to 'list'\n" 2488 + " -separator 'x' set output field separator (|)\n" 2489 + " -stats print memory stats before each finalize\n" 2490 + " -nullvalue 'text' set text string for NULL values\n" 2491 + " -version show SQLite version\n" 2492 +; 2493 +static void usage(int showDetail){ 2494 + fprintf(stderr, 2495 + "Usage: %s [OPTIONS] FILENAME [SQL]\n" 2496 + "FILENAME is the name of an SQLite database. A new database is created\n" 2497 + "if the file does not previously exist.\n", Argv0); 2498 + if( showDetail ){ 2499 + fprintf(stderr, "OPTIONS include:\n%s", zOptions); 2500 + }else{ 2501 + fprintf(stderr, "Use the -help option for additional information\n"); 2502 + } 2503 + exit(1); 2504 +} 2505 + 2506 +/* 2507 +** Initialize the state information in data 2508 +*/ 2509 +static void main_init(struct callback_data *data) { 2510 + memset(data, 0, sizeof(*data)); 2511 + data->mode = MODE_List; 2512 + memcpy(data->separator,"|", 2); 2513 + data->showHeader = 0; 2514 + sqlite3_config(SQLITE_CONFIG_LOG, shellLog, data); 2515 + sqlite3_snprintf(sizeof(mainPrompt), mainPrompt,"sqlite> "); 2516 + sqlite3_snprintf(sizeof(continuePrompt), continuePrompt," ...> "); 2517 + sqlite3_config(SQLITE_CONFIG_SINGLETHREAD); 2518 +} 2519 + 2520 +int main(int argc, char **argv){ 2521 + char *zErrMsg = 0; 2522 + struct callback_data data; 2523 + const char *zInitFile = 0; 2524 + char *zFirstCmd = 0; 2525 + int i; 2526 + int rc = 0; 2527 + 2528 + Argv0 = argv[0]; 2529 + main_init(&data); 2530 + stdin_is_interactive = isatty(0); 2531 + 2532 + /* Make sure we have a valid signal handler early, before anything 2533 + ** else is done. 2534 + */ 2535 +#ifdef SIGINT 2536 + signal(SIGINT, interrupt_handler); 2537 +#endif 2538 + 2539 + /* Do an initial pass through the command-line argument to locate 2540 + ** the name of the database file, the name of the initialization file, 2541 + ** and the first command to execute. 2542 + */ 2543 + for(i=1; i<argc-1; i++){ 2544 + char *z; 2545 + if( argv[i][0]!='-' ) break; 2546 + z = argv[i]; 2547 + if( z[0]=='-' && z[1]=='-' ) z++; 2548 + if( strcmp(argv[i],"-separator")==0 || strcmp(argv[i],"-nullvalue")==0 ){ 2549 + i++; 2550 + }else if( strcmp(argv[i],"-init")==0 ){ 2551 + i++; 2552 + zInitFile = argv[i]; 2553 + /* Need to check for batch mode here to so we can avoid printing 2554 + ** informational messages (like from process_sqliterc) before 2555 + ** we do the actual processing of arguments later in a second pass. 2556 + */ 2557 + }else if( strcmp(argv[i],"-batch")==0 ){ 2558 + stdin_is_interactive = 0; 2559 + } 2560 + } 2561 + if( i<argc ){ 2562 +#if defined(SQLITE_OS_OS2) && SQLITE_OS_OS2 2563 + data.zDbFilename = (const char *)convertCpPathToUtf8( argv[i++] ); 2564 +#else 2565 + data.zDbFilename = argv[i++]; 2566 +#endif 2567 + }else{ 2568 +#ifndef SQLITE_OMIT_MEMORYDB 2569 + data.zDbFilename = ":memory:"; 2570 +#else 2571 + data.zDbFilename = 0; 2572 +#endif 2573 + /***** Begin Fossil Patch *****/ 2574 + { 2575 + extern void fossil_open(sqlite3**, const char **); 2576 + fossil_open(&data.db, &data.zDbFilename); 2577 + } 2578 + /***** End Fossil Patch *****/ 2579 + } 2580 + if( i<argc ){ 2581 + zFirstCmd = argv[i++]; 2582 + } 2583 + if( i<argc ){ 2584 + fprintf(stderr,"%s: Error: too many options: \"%s\"\n", Argv0, argv[i]); 2585 + fprintf(stderr,"Use -help for a list of options.\n"); 2586 + return 1; 2587 + } 2588 + data.out = stdout; 2589 + 2590 +#ifdef SQLITE_OMIT_MEMORYDB 2591 + if( data.zDbFilename==0 ){ 2592 + fprintf(stderr,"%s: Error: no database filename specified\n", Argv0); 2593 + return 1; 2594 + } 2595 +#endif 2596 + 2597 + /* Go ahead and open the database file if it already exists. If the 2598 + ** file does not exist, delay opening it. This prevents empty database 2599 + ** files from being created if a user mistypes the database name argument 2600 + ** to the sqlite command-line tool. 2601 + */ 2602 + if( access(data.zDbFilename, 0)==0 ){ 2603 + open_db(&data); 2604 + } 2605 + 2606 + /* Process the initialization file if there is one. If no -init option 2607 + ** is given on the command line, look for a file named ~/.sqliterc and 2608 + ** try to process it. 2609 + */ 2610 + rc = process_sqliterc(&data,zInitFile); 2611 + if( rc>0 ){ 2612 + return rc; 2613 + } 2614 + 2615 + /* Make a second pass through the command-line argument and set 2616 + ** options. This second pass is delayed until after the initialization 2617 + ** file is processed so that the command-line arguments will override 2618 + ** settings in the initialization file. 2619 + */ 2620 + for(i=1; i<argc && argv[i][0]=='-'; i++){ 2621 + char *z = argv[i]; 2622 + if( z[1]=='-' ){ z++; } 2623 + if( strcmp(z,"-init")==0 ){ 2624 + i++; 2625 + }else if( strcmp(z,"-html")==0 ){ 2626 + data.mode = MODE_Html; 2627 + }else if( strcmp(z,"-list")==0 ){ 2628 + data.mode = MODE_List; 2629 + }else if( strcmp(z,"-line")==0 ){ 2630 + data.mode = MODE_Line; 2631 + }else if( strcmp(z,"-column")==0 ){ 2632 + data.mode = MODE_Column; 2633 + }else if( strcmp(z,"-csv")==0 ){ 2634 + data.mode = MODE_Csv; 2635 + memcpy(data.separator,",",2); 2636 + }else if( strcmp(z,"-separator")==0 ){ 2637 + i++; 2638 + if(i>=argc){ 2639 + fprintf(stderr,"%s: Error: missing argument for option: %s\n", Argv0, z); 2640 + fprintf(stderr,"Use -help for a list of options.\n"); 2641 + return 1; 2642 + } 2643 + sqlite3_snprintf(sizeof(data.separator), data.separator, 2644 + "%.*s",(int)sizeof(data.separator)-1,argv[i]); 2645 + }else if( strcmp(z,"-nullvalue")==0 ){ 2646 + i++; 2647 + if(i>=argc){ 2648 + fprintf(stderr,"%s: Error: missing argument for option: %s\n", Argv0, z); 2649 + fprintf(stderr,"Use -help for a list of options.\n"); 2650 + return 1; 2651 + } 2652 + sqlite3_snprintf(sizeof(data.nullvalue), data.nullvalue, 2653 + "%.*s",(int)sizeof(data.nullvalue)-1,argv[i]); 2654 + }else if( strcmp(z,"-header")==0 ){ 2655 + data.showHeader = 1; 2656 + }else if( strcmp(z,"-noheader")==0 ){ 2657 + data.showHeader = 0; 2658 + }else if( strcmp(z,"-echo")==0 ){ 2659 + data.echoOn = 1; 2660 + }else if( strcmp(z,"-stats")==0 ){ 2661 + data.statsOn = 1; 2662 + }else if( strcmp(z,"-bail")==0 ){ 2663 + bail_on_error = 1; 2664 + }else if( strcmp(z,"-version")==0 ){ 2665 + printf("%s\n", sqlite3_libversion()); 2666 + return 0; 2667 + }else if( strcmp(z,"-interactive")==0 ){ 2668 + stdin_is_interactive = 1; 2669 + }else if( strcmp(z,"-batch")==0 ){ 2670 + stdin_is_interactive = 0; 2671 + }else if( strcmp(z,"-help")==0 || strcmp(z, "--help")==0 ){ 2672 + usage(1); 2673 + }else{ 2674 + fprintf(stderr,"%s: Error: unknown option: %s\n", Argv0, z); 2675 + fprintf(stderr,"Use -help for a list of options.\n"); 2676 + return 1; 2677 + } 2678 + } 2679 + 2680 + if( zFirstCmd ){ 2681 + /* Run just the command that follows the database name 2682 + */ 2683 + if( zFirstCmd[0]=='.' ){ 2684 + rc = do_meta_command(zFirstCmd, &data); 2685 + }else{ 2686 + open_db(&data); 2687 + rc = shell_exec(data.db, zFirstCmd, shell_callback, &data, &zErrMsg); 2688 + if( zErrMsg!=0 ){ 2689 + fprintf(stderr,"Error: %s\n", zErrMsg); 2690 + return rc!=0 ? rc : 1; 2691 + }else if( rc!=0 ){ 2692 + fprintf(stderr,"Error: unable to process SQL \"%s\"\n", zFirstCmd); 2693 + return rc; 2694 + } 2695 + } 2696 + }else{ 2697 + /* Run commands received from standard input 2698 + */ 2699 + if( stdin_is_interactive ){ 2700 + char *zHome; 2701 + char *zHistory = 0; 2702 + int nHistory; 2703 + printf( 2704 + "SQLite version %s\n" 2705 + "Enter \".help\" for instructions\n" 2706 + "Enter SQL statements terminated with a \";\"\n", 2707 + sqlite3_libversion() 2708 + ); 2709 + zHome = find_home_dir(); 2710 + if( zHome ){ 2711 + nHistory = strlen30(zHome) + 20; 2712 + if( (zHistory = malloc(nHistory))!=0 ){ 2713 + sqlite3_snprintf(nHistory, zHistory,"%s/.sqlite_history", zHome); 2714 + } 2715 + } 2716 +#if defined(HAVE_READLINE) && HAVE_READLINE==1 2717 + if( zHistory ) read_history(zHistory); 2718 +#endif 2719 + rc = process_input(&data, 0); 2720 + if( zHistory ){ 2721 + stifle_history(100); 2722 + write_history(zHistory); 2723 + free(zHistory); 2724 + } 2725 + free(zHome); 2726 + }else{ 2727 + rc = process_input(&data, stdin); 2728 + } 2729 + } 2730 + set_table_name(&data, 0); 2731 + if( data.db ){ 2732 + if( sqlite3_close(data.db)!=SQLITE_OK ){ 2733 + fprintf(stderr,"Error: cannot close database \"%s\"\n", 2734 + sqlite3_errmsg(db)); 2735 + rc++; 2736 + } 2737 + } 2738 + return rc; 2739 +}
Changes to src/style.c.
87 87 va_start(ap, zTitleFormat); 88 88 zTitle = vmprintf(zTitleFormat, ap); 89 89 va_end(ap); 90 90 91 91 cgi_destination(CGI_HEADER); 92 92 cgi_printf("%s", 93 93 "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"" 94 - " \"http://www.x3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">"); 94 + " \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">"); 95 95 96 96 if( g.thTrace ) Th_Trace("BEGIN_HEADER<br />\n", -1); 97 97 98 98 /* Generate the header up through the main menu */ 99 99 Th_Store("project_name", db_get("project-name","Unnamed Fossil Project")); 100 100 Th_Store("title", zTitle); 101 101 Th_Store("baseurl", g.zBaseURL);
Changes to src/sync.c.
163 163 ** is used. 164 164 ** 165 165 ** The URL specified normally becomes the new "remote-url" used for 166 166 ** subsequent <a>push</a>, <a>pull</a>, and <a>sync</a> operations. However, 167 167 ** the "--once" command-line option makes the URL a one-time-use URL 168 168 ** that is not saved. 169 169 ** 170 -** If configured (<a>setting</a> push-hook-..), the push hook command will be 171 -** executed on the server after pushing files. 172 -** 173 -** See also: <a>callhook</a>, <a>clone</a>, <a>pull</a>, <a>sync</a>, <a>remote-url</a> 170 +** See also: <a>clone</a>, <a>pull</a>, <a>sync</a>, <a>remote-url</a> 174 171 */ 175 172 void push_cmd(void){ 176 173 process_sync_args(); 177 174 client_sync(1,0,0,0,0); 178 175 } 179 176 180 177 ................................................................................ 197 194 ** command is used. 198 195 ** 199 196 ** The URL specified normally becomes the new "remote-url" used for 200 197 ** subsequent <a>push</a>, <a>pull</a>, and <a>sync</a> operations. However, 201 198 ** the "--once" command-line option makes the URL a one-time-use URL 202 199 ** that is not saved. 203 200 ** 204 -** If configured (<a>setting</a> push-hook-..), the push hook command will be 205 -** executed on the server after pushing files. 206 -** 207 -** See also: <a>callhook</a>, <a>clone</a>, <a>push</a>, <a>pull</a>, <a>remote-url</a> 201 +** See also: <a>clone</a>, <a>push</a>, <a>pull</a>, <a>remote-url</a> 208 202 */ 209 203 void sync_cmd(void){ 210 204 int syncFlags = process_sync_args(); 211 205 client_sync(1,1,0,syncFlags,0); 212 206 } 213 207 214 208 /*
Changes to src/tkt.c.
843 843 ** Run various subcommands to control tickets 844 844 ** 845 845 ** %fossil ticket show (REPORTTITLE|REPORTNR) ?TICKETFILTER? ?options? 846 846 ** 847 847 ** options can be: 848 848 ** ?-l|--limit LIMITCHAR? 849 849 ** ?-q|--quote? 850 +** ?-R|--repository FILE? 850 851 ** 851 852 ** Run the ticket report, identified by the report format title 852 853 ** used in the gui. The data is written as flat file on stdout, 853 854 ** using "," as separator. The seperator "," can be changed using 854 855 ** the -l or --limit option. 855 856 ** If TICKETFILTER is given on the commandline, the query is 856 857 ** limited with a new WHERE-condition. ................................................................................ 901 902 ** All this stuff can also be done in the gui: 902 903 ** * Go the the <a href="reportlist">Tickets</a> page 903 904 */ 904 905 void ticket_cmd(void){ 905 906 int n; 906 907 907 908 /* do some ints, we want to be inside a checkout */ 908 - db_must_be_within_tree(); 909 909 db_find_and_open_repository(1); 910 910 user_select(); 911 911 /* 912 912 ** Check that the user exists. 913 913 */ 914 914 if( !db_exists("SELECT 1 FROM user WHERE login=%Q", g.zLogin) ){ 915 915 fossil_fatal("no such user: %s", g.zLogin);
Changes to src/update.c.
41 41 ** If the VERSION argument is omitted, then the leaf of the subtree 42 42 ** that begins at the current version is used, if there is only a single 43 43 ** leaf. VERSION can also be "current" to select the leaf of the current 44 44 ** version or "latest" to select the most recent check-in. 45 45 ** 46 46 ** If one or more FILES are listed after the VERSION then only the 47 47 ** named files are candidates to be updated. If FILES is omitted, all 48 -** files in the current checkout are subject to be updated. 48 +** files in the current checkout are subject to be updated. Using 49 +** a directory name for one of the FILES arguments is the same as 50 +** using every subdirectory and file beneath that directory. 49 51 ** 50 52 ** The -n or --nochange option causes this command to do a "dry run". It 51 53 ** prints out what would have happened but does not actually make any 52 54 ** changes to the current checkout or the repository. 53 55 ** 54 56 ** The -v or --verbose option prints status information about unchanged 55 57 ** files in addition to those file that actually do change. ................................................................................ 109 111 fossil_fatal("Multiple descendants"); 110 112 } 111 113 tid = db_int(0, "SELECT rid FROM leaves, event" 112 114 " WHERE event.objid=leaves.rid" 113 115 " ORDER BY event.mtime DESC"); 114 116 } 115 117 116 - if( tid==vid ) return; /* Nothing to update */ 118 + if( !verboseFlag && (tid==vid)) return; /* Nothing to update */ 117 119 db_begin_transaction(); 118 120 vfile_check_signature(vid, 1); 119 121 if( !nochangeFlag ) undo_begin(); 120 122 load_vfile_from_rid(tid); 121 123 122 124 /* 123 125 ** The record.fn field is used to match files against each other. The ................................................................................ 164 166 "UPDATE fv SET idv=%d, ridv=%d, chnged=%d WHERE fn=%Q", 165 167 id, rid, chnged, fn 166 168 ); 167 169 } 168 170 db_finalize(&q); 169 171 170 172 /* If FILES appear on the command-line, remove from the "fv" table 171 - ** every entry that is not named on the command-line. 173 + ** every entry that is not named on the command-line or which is not 174 + ** in a directory named on the command-line. 172 175 */ 173 176 if( g.argc>=4 ){ 174 177 Blob sql; /* SQL statement to purge unwanted entries */ 175 - char *zSep = "("; /* Separator in the list of filenames */ 176 178 Blob treename; /* Normalized filename */ 177 179 int i; /* Loop counter */ 180 + const char *zSep; /* Term separator */ 178 181 179 182 blob_zero(&sql); 180 - blob_append(&sql, "DELETE FROM fv WHERE fn NOT IN ", -1); 183 + blob_append(&sql, "DELETE FROM fv WHERE ", -1); 184 + zSep = ""; 181 185 for(i=3; i<g.argc; i++){ 182 186 file_tree_name(g.argv[i], &treename, 1); 183 - blob_appendf(&sql, "%s'%q'", zSep, blob_str(&treename)); 187 + if( file_isdir(g.argv[i])==1 ){ 188 + if( blob_size(&treename)>0 ){ 189 + blob_appendf(&sql, "%sfn NOT GLOB '%b/*' ", zSep, &treename); 190 + }else{ 191 + blob_reset(&sql); 192 + break; 193 + } 194 + }else{ 195 + blob_appendf(&sql, "%sfn<>%B ", zSep, &treename); 196 + } 197 + zSep = "AND "; 184 198 blob_reset(&treename); 185 - zSep = ","; 186 199 } 187 - blob_append(&sql, ")", -1); 188 200 db_multi_exec(blob_str(&sql)); 189 201 blob_reset(&sql); 190 202 } 191 203 192 204 db_prepare(&q, 193 205 "SELECT fn, idv, ridv, idt, ridt, chnged FROM fv ORDER BY 1" 194 206 ); ................................................................................ 262 274 printf("***** Cannot merge binary file %s\n", zName); 263 275 } 264 276 blob_reset(&v); 265 277 blob_reset(&e); 266 278 blob_reset(&t); 267 279 blob_reset(&r); 268 280 }else if( verboseFlag ){ 269 - printf("UNCHANGED %s\n", zName); 281 + if( chnged ){ 282 + printf("EDITED %s\n", zName); 283 + }else{ 284 + printf("UNCHANGED %s\n", zName); 285 + } 270 286 } 271 287 free(zFullPath); 272 288 } 273 289 db_finalize(&q); 274 290 275 291 /* 276 292 ** Clean up the mid and pid VFILE entries. Then commit the changes.
Changes to src/wiki.c.
84 84 char *zIndexPage = db_get("index-page",0); 85 85 login_check_credentials(); 86 86 if( !g.okRdWiki ){ 87 87 cgi_redirectf("%s/login?g=%s/home", g.zBaseURL, g.zBaseURL); 88 88 } 89 89 if( zIndexPage ){ 90 90 const char *zPathInfo = P("PATH_INFO"); 91 + while( zIndexPage[0]=='/' ) zIndexPage++; 91 92 if( strcmp(zIndexPage, zPathInfo)==0 ) zIndexPage = 0; 92 93 } 93 94 if( zIndexPage ){ 94 - while( zIndexPage[0]=='/' ) zIndexPage++; 95 95 cgi_redirectf("%s/%s", g.zBaseURL, zIndexPage); 96 96 } 97 97 if( zPageName ){ 98 98 login_check_credentials(); 99 99 g.zExtra = zPageName; 100 100 cgi_set_parameter_nocopy("name", g.zExtra); 101 101 g.isHome = 1;
Changes to src/winhttp.c.
113 113 sprintf(zCmd, "\"%s\" http \"%s\" %s %s %s%s", 114 114 _pgmptr, g.zRepositoryName, zRequestFName, zReplyFName, 115 115 inet_ntoa(p->addr.sin_addr), p->zNotFound 116 116 ); 117 117 if( g.fHttpTrace ){ 118 118 fprintf(stderr,"HTTPTRACE(%p): calling '%s'\n",pAppData,zCmd); 119 119 } 120 - portable_system(zCmd); 120 + fossil_system(zCmd); 121 121 in = fopen(zReplyFName, "rb"); 122 122 if( in ){ 123 123 if( g.fHttpTrace ){ 124 124 fprintf(stderr,"HTTPTRACE(%p): read reply '%s'\n",pAppData,zReplyFName); 125 125 } 126 126 while( (got = fread(zHdr, 1, sizeof(zHdr), in))>0 ){ 127 127 send(p->s, zHdr, got, 0); ................................................................................ 201 201 } 202 202 } 203 203 zTempPrefix = mprintf("fossil_server_P%d_", iPort); 204 204 printf("Listening for HTTP requests on TCP port %d\n", iPort); 205 205 if( zBrowser ){ 206 206 zBrowser = mprintf(zBrowser, iPort); 207 207 printf("Launch webbrowser: %s\n", zBrowser); 208 - portable_system(zBrowser); 208 + fossil_system(zBrowser); 209 209 } 210 210 printf("Type Ctrl-C to stop the HTTP server\n"); 211 211 for(;;){ 212 212 SOCKET client; 213 213 SOCKADDR_IN client_addr; 214 214 HttpRequest *p; 215 215 int len = sizeof(client_addr);
Changes to src/xfer.c.
38 38 int nDeltaSent; /* Number of deltas sent */ 39 39 int nFileRcvd; /* Number of files received */ 40 40 int nDeltaRcvd; /* Number of deltas received */ 41 41 int nDanglingFile; /* Number of dangling deltas received */ 42 42 int mxSend; /* Stop sending "file" with pOut reaches this size */ 43 43 }; 44 44 45 -/* 46 -** COMMAND: callhook 47 -** %fossil callhook PUSHHOOKPATTERN ?--force|-f? 48 -** 49 -** Call the push hook command on a server, which will normally be called 50 -** after a client push (<a>setting</a> push-hook-cmd). 51 -** 52 -** If --force is used, the given pattern is not checked against the 53 -** configuration (<a>setting</a> push-hook-pattern-server). 54 -** 55 -** This command only works on the server side, it does not send a message 56 -** from a client, but executes the hook directly on the server. 57 -** 58 -** See also <a>push</a>, <a>sync</a>, <a>setting</a> 59 -*/ 60 -void callhook_cmd(void){ 61 - int forceFlag = find_option("force","f",0)!=0; 62 - 63 - db_open_config(1); 64 - db_find_and_open_repository(0); 65 - if( (g.argc!=3) || (!g.argv[2]) || (!g.argv[2][0]) ){ 66 - usage("PUSHHOOKPATTERN ?--force?"); 67 - } 68 - if( !forceFlag ){ 69 - const char *zPushHookPattern = db_get("push-hook-pattern-server", ""); 70 - int lenPushHookPattern = (zPushHookPattern && zPushHookPattern[0]) 71 - ? strlen(zPushHookPattern) : 0; 72 - if( (!lenPushHookPattern) 73 - || memcmp(g.argv[2], zPushHookPattern, lenPushHookPattern) 74 - ){ 75 - fossil_fatal("push hook pattern '%s' doesn't match configuration '%s'\n", 76 - g.argv[2],zPushHookPattern); 77 - } 78 - } 79 - post_push_hook(g.argv[2],'C'); 80 -} 81 - 82 -/* 83 -** Let a server-side external agent know that a push has completed. /fatman 84 -** The second argument controls, how the command is called: 85 -** P - client request with pushed files 86 -** F - client request without pushed files(FORCE!) 87 -** C - server side command line activation 88 -*/ 89 -void post_push_hook(char const * const zPushHookLine, const char requestType){ 90 - /* 91 - ** TO DO: get the string cmd from a config file? Or the database local 92 - ** settings, as someone suggested? Ditto output and error logs. /fatman 93 - */ 94 - const char *zCmd = db_get("push-hook-cmd", ""); 95 - int allowForced = db_get_boolean("push-hook-force", 0); 96 - const char *zHookPriv = db_get("push-hook-privilege",""); 97 - int privOk = 0; 98 - 99 - if( zHookPriv && *zHookPriv ){ 100 - switch( *zHookPriv ){ 101 - 102 - case 's': 103 - if( g.okSetup ) privOk = 1; 104 - break; 105 - case 'a': 106 - if( g.okAdmin ) privOk = 1; 107 - break; 108 - case 'i': 109 - if( g.okWrite ) privOk = 1; 110 - break; 111 - case 'o': 112 - if( g.okRead ) privOk = 1; 113 - break; 114 - default: 115 - fossil_print("Push hook wrong privilege type '%s'\n", zHookPriv); 116 - } 117 - }else{ 118 - privOk = 1; 119 - } 120 - if( !privOk ){ 121 - fossil_print("No privilege to activate hook!\n"); 122 - }else if( requestType!='P' && requestType!='C' && requestType!='F' ){ 123 - fossil_print("Push hook wrong request type '%c'\n", requestType); 124 - }else if( requestType=='F' && !allowForced ){ 125 - fossil_print("Forced push call from client not allowed," 126 - " skipping call for '%s'\n", zPushHookLine); 127 - }else if( zCmd && zCmd[0] ){ 128 - int rc; 129 - char * zCalledCmd; 130 - char * zDate; 131 - const char *zRnd; 132 - 133 - 134 - zDate = db_text(0, "SELECT strftime('%%Y%%m%%d%%H%%M%%f','now')"); 135 - zRnd = db_text(0, "SELECT lower(hex(randomblob(6)))"); 136 - 137 - zCalledCmd = mprintf("%s %s-%s %s >hook-log-%s-%s 2>&1",zCmd,zDate,zRnd,zPushHookLine,zDate,zRnd); 138 - { /* remove newlines from command */ 139 - char *zSrc, *zDest; 140 - 141 - for (zSrc=zDest=zCalledCmd;;zSrc++){ 142 - switch( *zSrc ){ 143 - case '\0': 144 - *zDest=0; 145 - break; 146 - default: 147 - *zDest++ = *zSrc; 148 - /* fall through is intended! */ 149 - case '\n': 150 - continue; 151 - } 152 - break; 153 - } 154 - } 155 - rc = system(zCalledCmd); 156 - if (rc != 0) { 157 - fossil_print("The post-push-hook command '%s' failed.", zCalledCmd); 158 - } 159 - free(zCalledCmd); 160 - free(zDate); 161 - }else{ 162 - fossil_print("No push hook configured, skipping call for '%s'\n", zPushHookLine); 163 - } 164 -} 165 45 166 46 /* 167 47 ** The input blob contains a UUID. Convert it into a record ID. 168 48 ** Create a phantom record if no prior record exists and 169 49 ** phantomize is true. 170 50 ** 171 51 ** Compare to uuid_to_rid(). This routine takes a blob argument ................................................................................ 745 625 Xfer xfer; 746 626 int deltaFlag = 0; 747 627 int isClone = 0; 748 628 int nGimme = 0; 749 629 int size; 750 630 int recvConfig = 0; 751 631 char *zNow; 752 - const char *zPushHookPattern = db_get("push-hook-pattern-server", ""); 753 - int lenPushHookPattern = (zPushHookPattern && zPushHookPattern[0]) 754 - ? strlen(zPushHookPattern) : 0; 755 632 756 633 if( strcmp(PD("REQUEST_METHOD","POST"),"POST") ){ 757 634 fossil_redirect_home(); 758 635 } 759 636 memset(&xfer, 0, sizeof(xfer)); 760 637 blobarray_zero(xfer.aToken, count(xfer.aToken)); 761 638 cgi_set_content_type(g.zContentType); ................................................................................ 767 644 768 645 db_begin_transaction(); 769 646 db_multi_exec( 770 647 "CREATE TEMP TABLE onremote(rid INTEGER PRIMARY KEY);" 771 648 ); 772 649 manifest_crosslink_begin(); 773 650 while( blob_line(xfer.pIn, &xfer.line) ){ 774 - if( blob_buffer(&xfer.line)[0]=='#' ){ 775 - if( lenPushHookPattern 776 - && blob_buffer(&xfer.line)[1] 777 - && blob_buffer(&xfer.line)[2] 778 - && (0 == memcmp(blob_buffer(&xfer.line)+2, 779 - zPushHookPattern, lenPushHookPattern)) 780 - ){ 781 - post_push_hook(blob_buffer(&xfer.line)+2,blob_buffer(&xfer.line)[1]); 782 - } 783 - continue; 784 - } 651 + if( blob_buffer(&xfer.line)[0]=='#' ) continue; 785 652 xfer.nToken = blob_tokenize(&xfer.line, xfer.aToken, count(xfer.aToken)); 786 653 787 654 /* file UUID SIZE \n CONTENT 788 655 ** file UUID DELTASRC SIZE \n CONTENT 789 656 ** 790 657 ** Accept a file from the client. 791 658 */ ................................................................................ 1136 1003 Blob recv; /* Reply we got back from the server */ 1137 1004 Xfer xfer; /* Transfer data */ 1138 1005 int pctDone; /* Percentage done with a message */ 1139 1006 int lastPctDone = -1; /* Last displayed pctDone */ 1140 1007 double rArrivalTime; /* Time at which a message arrived */ 1141 1008 const char *zSCode = db_get("server-code", "x"); 1142 1009 const char *zPCode = db_get("project-code", 0); 1143 - const char *zPushHookPattern = db_get("push-hook-pattern-client", ""); 1144 - int allowForced = db_get_boolean("push-hook-force", 0); 1145 - 1146 1010 1147 1011 if( db_get_boolean("dont-push", 0) ) pushFlag = 0; 1148 1012 if( pushFlag + pullFlag + cloneFlag == 0 1149 1013 && configRcvMask==0 && configSendMask==0 ) return; 1150 1014 1151 1015 transport_stats(0, 0, 1); 1152 1016 socket_global_init(); ................................................................................ 1307 1171 g.clockSkewSeen = 1; 1308 1172 } 1309 1173 } 1310 1174 continue; 1311 1175 } 1312 1176 xfer.nToken = blob_tokenize(&xfer.line, xfer.aToken, count(xfer.aToken)); 1313 1177 nCardRcvd++; 1314 - if( !g.cgiOutput && !g.fQuiet ){ 1178 + if( !g.cgiOutput && !g.fQuiet && recv.nUsed>0 ){ 1315 1179 pctDone = (recv.iCursor*100)/recv.nUsed; 1316 1180 if( pctDone!=lastPctDone ){ 1317 1181 printf("\rprocessed: %d%% ", pctDone); 1318 1182 lastPctDone = pctDone; 1319 1183 fflush(stdout); 1320 1184 } 1321 1185 } ................................................................................ 1551 1415 1552 1416 /* If this is a clone, the go at least two rounds */ 1553 1417 if( cloneFlag && nCycle==1 ) go = 1; 1554 1418 1555 1419 /* Stop the cycle if the server sends a "clone_seqno 0" card */ 1556 1420 if( cloneSeqno<=0 ) go = 0; 1557 1421 }; 1558 - if( pushFlag && ( (nFileSend > 0) || allowForced ) ){ 1559 - if( zPushHookPattern && zPushHookPattern[0] ){ 1560 - blob_appendf(&send, "#%s%s\n", 1561 - ((nFileSend > 0)?"P":"F"), zPushHookPattern); 1562 - fossil_print("Triggering push hook %s '%s'\n",((nFileSend > 0)?"P":"F"),zPushHookPattern); 1563 - http_exchange(&send, &recv, cloneFlag==0 || nCycle>0); 1564 - blob_reset(&send); 1565 - nCardSent++; 1566 - } 1567 - int allowForced = db_get_boolean("push-hook-force", 0); 1568 - } 1569 1422 transport_stats(&nSent, &nRcvd, 1); 1570 1423 fossil_print("Total network traffic: %d bytes sent, %d bytes received\n", 1571 1424 nSent, nRcvd); 1572 1425 transport_close(); 1573 1426 transport_global_shutdown(); 1574 1427 db_multi_exec("DROP TABLE onremote"); 1575 1428 manifest_crosslink_end(); 1576 1429 content_enable_dephantomize(1); 1577 1430 db_end_transaction(0); 1578 1431 }
Changes to test/delta1.test.
30 30 # some random changes in "./t2". Then call test-delta on the 31 31 # two files to make sure that deltas between these two files 32 32 # work properly. 33 33 # 34 34 set filelist [glob $testdir/*] 35 35 foreach f $filelist { 36 36 set base [file root [file tail $f]] 37 -puts "base=$base f=$f" 37 +protOut "base=$base f=$f" 38 38 set f1 [read_file $f] 39 39 write_file t1 $f1 40 40 for {set i 0} {$i<100} {incr i} { 41 41 write_file t2 [random_changes $f1 1 1 0 0.1] 42 42 fossil test-delta t1 t2 43 43 test delta-$base-$i-1 {$RESULT=="ok"} 44 44 write_file t2 [random_changes $f1 1 1 0 0.2]
Changes to test/merge1.test.
75 75 111 - This is line one OF the demo program - 1111 76 76 222 - The second line program line in code - 2222 77 77 333 - This is a test of the merging algohm - 3333 78 78 444 - If all goes well, we will be pleased - 4444 79 79 555 - we think it well and other stuff too - 5555 80 80 } 81 81 write_file_indented t23 { 82 - >>>>>>> BEGIN MERGE CONFLICT 82 + <<<<<<< BEGIN MERGE CONFLICT 83 83 111 - This is line ONE of the demo program - 1111 84 84 ============================ 85 85 111 - This is line one OF the demo program - 1111 86 - <<<<<<< END MERGE CONFLICT 86 + >>>>>>> END MERGE CONFLICT 87 87 222 - The second line program line in code - 2222 88 88 333 - This is a test of the merging algohm - 3333 89 89 444 - If all goes well, we will be pleased - 4444 90 90 555 - we think it well and other stuff too - 5555 91 91 } 92 92 write_file_indented t32 { 93 - >>>>>>> BEGIN MERGE CONFLICT 93 + <<<<<<< BEGIN MERGE CONFLICT 94 94 111 - This is line one OF the demo program - 1111 95 95 ============================ 96 96 111 - This is line ONE of the demo program - 1111 97 - <<<<<<< END MERGE CONFLICT 97 + >>>>>>> END MERGE CONFLICT 98 98 222 - The second line program line in code - 2222 99 99 333 - This is a test of the merging algohm - 3333 100 100 444 - If all goes well, we will be pleased - 4444 101 101 555 - we think it well and other stuff too - 5555 102 102 } 103 103 fossil test-3 t1 t3 t2 a32 104 104 test merge1-2.1 {[same_file t32 a32]} ................................................................................ 156 156 write_file_indented t3 { 157 157 222 - The second line program line in code - 2222 158 158 333 - This is a test of the merging algohm - 3333 159 159 444 - If all goes well, we will be pleased - 4444 160 160 555 - we think it well and other stuff too - 5555 161 161 } 162 162 write_file_indented t32 { 163 - >>>>>>> BEGIN MERGE CONFLICT 163 + <<<<<<< BEGIN MERGE CONFLICT 164 164 ============================ 165 165 000 - Zero lines added to the beginning of - 0000 166 166 111 - This is line one of the demo program - 1111 167 - <<<<<<< END MERGE CONFLICT 167 + >>>>>>> END MERGE CONFLICT 168 168 222 - The second line program line in code - 2222 169 169 333 - This is a test of the merging algohm - 3333 170 170 444 - If all goes well, we will be pleased - 4444 171 171 555 - we think it well and other stuff too - 5555 172 172 } 173 173 write_file_indented t23 { 174 - >>>>>>> BEGIN MERGE CONFLICT 174 + <<<<<<< BEGIN MERGE CONFLICT 175 175 000 - Zero lines added to the beginning of - 0000 176 176 111 - This is line one of the demo program - 1111 177 177 ============================ 178 - <<<<<<< END MERGE CONFLICT 178 + >>>>>>> END MERGE CONFLICT 179 179 222 - The second line program line in code - 2222 180 180 333 - This is a test of the merging algohm - 3333 181 181 444 - If all goes well, we will be pleased - 4444 182 182 555 - we think it well and other stuff too - 5555 183 183 } 184 184 fossil test-3 t1 t3 t2 a32 185 185 test merge1-4.1 {[same_file t32 a32]} ................................................................................ 291 291 KLMN 292 292 OPQR 293 293 STUV 294 294 XYZ. 295 295 } 296 296 write_file_indented t23 { 297 297 abcd 298 - >>>>>>> BEGIN MERGE CONFLICT 298 + <<<<<<< BEGIN MERGE CONFLICT 299 299 efgh 2 300 300 ijkl 2 301 301 mnop 2 302 302 qrst 303 303 uvwx 304 304 yzAB 2 305 305 CDEF 2 ................................................................................ 309 309 ijkl 310 310 mnop 3 311 311 qrst 3 312 312 uvwx 3 313 313 yzAB 3 314 314 CDEF 315 315 GHIJ 316 - <<<<<<< END MERGE CONFLICT 316 + >>>>>>> END MERGE CONFLICT 317 317 KLMN 318 318 OPQR 319 319 STUV 320 320 XYZ. 321 321 } 322 322 fossil test-3 t1 t2 t3 a23 323 323 test merge1-7.1 {[same_file t23 a23]} ................................................................................ 352 352 STUV 353 353 XYZ. 354 354 } 355 355 write_file_indented t23 { 356 356 abcd 357 357 efgh 2 358 358 ijkl 2 359 - >>>>>>> BEGIN MERGE CONFLICT 359 + <<<<<<< BEGIN MERGE CONFLICT 360 360 mnop 361 361 qrst 362 362 uvwx 363 363 yzAB 2 364 364 CDEF 2 365 365 GHIJ 2 366 366 ============================ 367 367 mnop 3 368 368 qrst 3 369 369 uvwx 3 370 370 yzAB 3 371 371 CDEF 372 372 GHIJ 373 - <<<<<<< END MERGE CONFLICT 373 + >>>>>>> END MERGE CONFLICT 374 374 KLMN 375 375 OPQR 376 376 STUV 377 377 XYZ. 378 378 } 379 379 fossil test-3 t1 t2 t3 a23 380 380 test merge1-7.2 {[same_file t23 a23]}
Changes to test/merge3.test.
26 26 27 27 proc merge-test {testid basis v1 v2 result} { 28 28 write_file t1 [join [string trim $basis] \n]\n 29 29 write_file t2 [join [string trim $v1] \n]\n 30 30 write_file t3 [join [string trim $v2] \n]\n 31 31 fossil test-3-way-merge t1 t2 t3 t4 32 32 set x [read_file t4] 33 - regsub -all {>>>>>>> BEGIN MERGE CONFLICT} $x {>} x 33 + regsub -all {<<<<<<< BEGIN MERGE CONFLICT} $x {>} x 34 34 regsub -all {============================} $x {=} x 35 - regsub -all {<<<<<<< END MERGE CONFLICT} $x {<} x 35 + regsub -all {>>>>>>> END MERGE CONFLICT} $x {<} x 36 36 set x [split [string trim $x] \n] 37 37 set result [string trim $result] 38 38 if {$x!=$result} { 39 - puts " Expected \[$result\]" 40 - puts " Got \[$x\]" 39 + protOut " Expected \[$result\]" 40 + protOut " Got \[$x\]" 41 41 test merge3-$testid 0 42 42 } else { 43 43 test merge3-$testid 1 44 44 } 45 45 } 46 46 47 47 merge-test 1 {
Changes to test/merge4.test.
27 27 proc merge-test {testid basis v1 v2 result1 result2} { 28 28 write_file t1 [join [string trim $basis] \n]\n 29 29 write_file t2 [join [string trim $v1] \n]\n 30 30 write_file t3 [join [string trim $v2] \n]\n 31 31 fossil test-3-way-merge t1 t2 t3 t4 32 32 fossil test-3-way-merge t1 t3 t2 t5 33 33 set x [read_file t4] 34 - regsub -all {>>>>>>> BEGIN MERGE CONFLICT} $x {>} x 34 + regsub -all {<<<<<<< BEGIN MERGE CONFLICT} $x {>} x 35 35 regsub -all {============================} $x {=} x 36 - regsub -all {<<<<<<< END MERGE CONFLICT} $x {<} x 36 + regsub -all {>>>>>>> END MERGE CONFLICT} $x {<} x 37 37 set x [split [string trim $x] \n] 38 38 set y [read_file t5] 39 - regsub -all {>>>>>>> BEGIN MERGE CONFLICT} $y {>} y 39 + regsub -all {<<<<<<< BEGIN MERGE CONFLICT} $y {>} y 40 40 regsub -all {============================} $y {=} y 41 - regsub -all {<<<<<<< END MERGE CONFLICT} $y {<} y 41 + regsub -all {>>>>>>> END MERGE CONFLICT} $y {<} y 42 42 set y [split [string trim $y] \n] 43 43 set result1 [string trim $result1] 44 44 if {$x!=$result1} { 45 - puts " Expected \[$result1\]" 46 - puts " Got \[$x\]" 45 + protOut " Expected \[$result1\]" 46 + protOut " Got \[$x\]" 47 47 test merge3-$testid 0 48 48 } else { 49 49 set result2 [string trim $result2] 50 50 if {$y!=$result2} { 51 - puts " Expected \[$result2\]" 52 - puts " Got \[$y\]" 51 + protOut " Expected \[$result2\]" 52 + protOut " Got \[$y\]" 53 53 test merge3-$testid 0 54 54 } else { 55 55 test merge3-$testid 1 56 56 } 57 57 } 58 58 } 59 59
Changes to test/tester.tcl.
36 36 set i [lsearch $argv -halt] 37 37 if {$i>=0} { 38 38 set HALT 1 39 39 set argv [lreplace $argv $i $i] 40 40 } else { 41 41 set HALT 0 42 42 } 43 + 44 +set i [lsearch $argv -prot] 45 +if {$i>=0} { 46 + set PROT 1 47 + set argv [lreplace $argv $i $i] 48 +} else { 49 + set PROT 0 50 +} 43 51 44 52 if {[llength $argv]==0} { 45 53 foreach f [lsort [glob $testdir/*.test]] { 46 54 set base [file root [file tail $f]] 47 55 lappend argv $base 48 56 } 49 57 } 58 + 59 +# start protocol 60 +# 61 +proc protInit {cmd} { 62 + if {$::PROT} { 63 + set out [open "prot" w] 64 + fconfigure $out -translation platform 65 + puts $out "starting tests with:$cmd" 66 + close $out 67 + } 68 +} 69 + 70 +# write protocol 71 +# 72 +proc protOut {msg} { 73 + puts "$msg" 74 + if {$::PROT} { 75 + set out [open "prot" a] 76 + fconfigure $out -translation platform 77 + puts $out "$msg" 78 + close $out 79 + } 80 +} 50 81 51 82 # Run the fossil program 52 83 # 53 84 proc fossil {args} { 54 85 global fossilexe 55 86 set cmd $fossilexe 56 87 foreach a $args { 57 88 lappend cmd $a 58 89 } 59 - puts $cmd 90 + protOut $cmd 91 + 60 92 flush stdout 61 93 set rc [catch {eval exec $cmd} result] 62 94 global RESULT CODE 63 95 set CODE $rc 64 96 set RESULT $result 65 97 } 66 98 ................................................................................ 98 130 99 131 # Perform a test 100 132 # 101 133 proc test {name expr} { 102 134 global bad_test 103 135 set r [uplevel 1 [list expr $expr]] 104 136 if {$r} { 105 - puts "test $name OK" 137 + protOut "test $name OK" 106 138 } else { 107 - puts "test $name FAILED!" 139 + protOut "test $name FAILED!" 108 140 lappend bad_test $name 109 141 if {$::HALT} exit 110 142 } 111 143 } 112 144 set bad_test {} 113 145 114 146 # Return a random string N characters long. ................................................................................ 165 197 } 166 198 } 167 199 append out \n$line 168 200 } 169 201 return [string range $out 1 end] 170 202 } 171 203 204 +protInit $fossilexe 172 205 foreach testfile $argv { 173 - puts "***** $testfile ******" 206 + protOut "***** $testfile ******" 174 207 source $testdir/$testfile.test 175 208 } 176 -puts "[llength $bad_test] errors: $bad_test" 209 +protOut "[llength $bad_test] errors: $bad_test"
Changes to win/Makefile.PellesCGMake.
73 73 # define the special utilities files, needed to generate 74 74 # the automatically generated source files 75 75 UTILS=translate.exe mkindex.exe makeheaders.exe 76 76 UTILS_OBJ=$(UTILS:.exe=.obj) 77 77 UTILS_SRC=$(foreach uf,$(UTILS),$(SRCDIR)$(uf:.exe=.c)) 78 78 79 79 # define the sqlite files, which need special flags on compile 80 -SQLITESRC=sqlite3.c 81 -ORIGSQLITESRC=$(foreach sf,$(SQLITESRC),$(SRCDIR)$(sf)) 82 -SQLITEOBJ=$(foreach sf,$(SQLITESRC),$(sf:.c=.obj)) 83 -SQLITEDEFINES=-DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -Dlocaltime=fossil_localtime -DSQLITE_ENABLE_LOCKING_STYLE=0 80 +SQLITESRC1=sqlite3.c 81 +SQLITESRC2=shell.c 82 +ORIGSQLITESRC=$(foreach sf,$(SQLITESRC1) $(SQLITESRC2),$(SRCDIR)$(sf)) 83 +SQLITEOBJ1=$(foreach sf,$(SQLITESRC1),$(sf:.c=.obj)) 84 +SQLITEOBJ2=$(foreach sf,$(SQLITESRC2),$(sf:.c=.obj)) 85 +SQLITEOBJ=$(foreach sf,$(SQLITESRC1) $(SQLITESRC2),$(sf:.c=.obj)) 86 +SQLITEDEFINES1=-DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -Dlocaltime=fossil_localtime -DSQLITE_ENABLE_LOCKING_STYLE=0 87 +SQLITEDEFINES2=-Dmain=sqlite3_shell -DSQLITE_OMIT_LOAD_EXTENSION=1 84 88 85 89 # define the th scripting files, which need special flags on compile 86 90 THSRC=th.c th_lang.c 87 91 ORIGTHSRC=$(foreach sf,$(THSRC),$(SRCDIR)$(sf)) 88 92 THOBJ=$(foreach sf,$(THSRC),$(sf:.c=.obj)) 89 93 90 94 # define the zlib files, needed by this compile ................................................................................ 148 152 149 153 # ########################################################################### 150 154 # compile C sources with relevant options 151 155 152 156 $(TRANSLATEDOBJ): %_.obj: %_.c %.h 153 157 $(CC) $(CCFLAGS) $(INCLUDE) "$<" -Fo"$@" 154 158 155 -$(SQLITEOBJ): %.obj: $(SRCDIR)%.c $(SRCDIR)%.h 156 - $(CC) $(CCFLAGS) $(SQLITEDEFINES) $(INCLUDE) "$<" -Fo"$@" 159 +$(SQLITEOBJ1): %.obj: $(SRCDIR)%.c $(SRCDIR)%.h 160 + $(CC) $(CCFLAGS) $(SQLITEDEFINES1) $(INCLUDE) "$<" -Fo"$@" 161 + 162 +$(SQLITEOBJ2): %.obj: $(SRCDIR)%.c 163 + $(CC) $(CCFLAGS) $(SQLITEDEFINES2) $(INCLUDE) "$<" -Fo"$@" 157 164 158 165 $(THOBJ): %.obj: $(SRCDIR)%.c $(SRCDIR)th.h 159 166 $(CC) $(CCFLAGS) $(INCLUDE) "$<" -Fo"$@" 160 167 161 168 $(ZLIBOBJ): %.obj: $(ZLIBSRCDIR)%.c 162 169 $(CC) $(CCFLAGS) $(INCLUDE) "$<" -Fo"$@" 163 170
Changes to win/Makefile.dmc.
24 24 CFLAGS = -o 25 25 BCC = $(DMDIR)\bin\dmc $(CFLAGS) 26 26 TCC = $(DMDIR)\bin\dmc $(CFLAGS) $(DMCDEF) $(I18N) $(SSL) $(INCL) 27 27 LIBS = $(DMDIR)\extra\lib\ zlib wsock32 28 28 29 29 SRC = add_.c allrepo_.c attach_.c bag_.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 file_.c finfo_.c graph_.c http_.c http_socket_.c http_ssl_.c http_transport_.c info_.c login_.c main_.c manifest_.c md5_.c merge_.c merge3_.c name_.c pivot_.c popen_.c pqueue_.c printf_.c rebuild_.c report_.c rss_.c schema_.c search_.c setup_.c sha1_.c shun_.c skins_.c stat_.c style_.c sync_.c tag_.c th_main_.c timeline_.c tkt_.c tktsetup_.c undo_.c update_.c url_.c user_.c verify_.c vfile_.c wiki_.c wikiformat_.c winhttp_.c xfer_.c zip_.c 30 30 31 -OBJ = $(OBJDIR)\add$O $(OBJDIR)\allrepo$O $(OBJDIR)\attach$O $(OBJDIR)\bag$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)\file$O $(OBJDIR)\finfo$O $(OBJDIR)\graph$O $(OBJDIR)\http$O $(OBJDIR)\http_socket$O $(OBJDIR)\http_ssl$O $(OBJDIR)\http_transport$O $(OBJDIR)\info$O $(OBJDIR)\login$O $(OBJDIR)\main$O $(OBJDIR)\manifest$O $(OBJDIR)\md5$O $(OBJDIR)\merge$O $(OBJDIR)\merge3$O $(OBJDIR)\name$O $(OBJDIR)\pivot$O $(OBJDIR)\popen$O $(OBJDIR)\pqueue$O $(OBJDIR)\printf$O $(OBJDIR)\rebuild$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)\stat$O $(OBJDIR)\style$O $(OBJDIR)\sync$O $(OBJDIR)\tag$O $(OBJDIR)\th_main$O $(OBJDIR)\timeline$O $(OBJDIR)\tkt$O $(OBJDIR)\tktsetup$O $(OBJDIR)\undo$O $(OBJDIR)\update$O $(OBJDIR)\url$O $(OBJDIR)\user$O $(OBJDIR)\verify$O $(OBJDIR)\vfile$O $(OBJDIR)\wiki$O $(OBJDIR)\wikiformat$O $(OBJDIR)\winhttp$O $(OBJDIR)\xfer$O $(OBJDIR)\zip$O $(OBJDIR)\sqlite3$O $(OBJDIR)\th$O $(OBJDIR)\th_lang$O 31 +OBJ = $(OBJDIR)\add$O $(OBJDIR)\allrepo$O $(OBJDIR)\attach$O $(OBJDIR)\bag$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)\file$O $(OBJDIR)\finfo$O $(OBJDIR)\graph$O $(OBJDIR)\http$O $(OBJDIR)\http_socket$O $(OBJDIR)\http_ssl$O $(OBJDIR)\http_transport$O $(OBJDIR)\info$O $(OBJDIR)\login$O $(OBJDIR)\main$O $(OBJDIR)\manifest$O $(OBJDIR)\md5$O $(OBJDIR)\merge$O $(OBJDIR)\merge3$O $(OBJDIR)\name$O $(OBJDIR)\pivot$O $(OBJDIR)\popen$O $(OBJDIR)\pqueue$O $(OBJDIR)\printf$O $(OBJDIR)\rebuild$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)\stat$O $(OBJDIR)\style$O $(OBJDIR)\sync$O $(OBJDIR)\tag$O $(OBJDIR)\th_main$O $(OBJDIR)\timeline$O $(OBJDIR)\tkt$O $(OBJDIR)\tktsetup$O $(OBJDIR)\undo$O $(OBJDIR)\update$O $(OBJDIR)\url$O $(OBJDIR)\user$O $(OBJDIR)\verify$O $(OBJDIR)\vfile$O $(OBJDIR)\wiki$O $(OBJDIR)\wikiformat$O $(OBJDIR)\winhttp$O $(OBJDIR)\xfer$O $(OBJDIR)\zip$O $(OBJDIR)\shell$O $(OBJDIR)\sqlite3$O $(OBJDIR)\th$O $(OBJDIR)\th_lang$O 32 32 33 33 RC=$(DMDIR)\bin\rcc 34 34 RCFLAGS=-32 -w1 -I$(SRCDIR) /D__DMC__ 35 35 36 36 APPNAME = $(OBJDIR)\fossil$(E) 37 37 38 38 all: $(APPNAME) ................................................................................ 41 41 cd $(OBJDIR) 42 42 $(DMDIR)\bin\link @link 43 43 44 44 fossil.res: $B\win\fossil.rc VERSION.h 45 45 $(RC) $(RCFLAGS) -o$@ $B\win\fossil.rc 46 46 47 47 $(OBJDIR)\link: $B\win\Makefile.dmc 48 - +echo add allrepo attach bag blob branch browse captcha cgi checkin checkout clearsign clone comformat configure content db delta deltacmd descendants diff diffcmd doc encode event file finfo graph http http_socket http_ssl http_transport info login main manifest md5 merge merge3 name pivot popen pqueue printf rebuild report rss schema search setup sha1 shun skins stat style sync tag th_main timeline tkt tktsetup undo update url user verify vfile wiki wikiformat winhttp xfer zip sqlite3 th th_lang > $@ 48 + +echo add allrepo attach bag blob branch browse captcha cgi checkin checkout clearsign clone comformat configure content db delta deltacmd descendants diff diffcmd doc encode event file finfo graph http http_socket http_ssl http_transport info login main manifest md5 merge merge3 name pivot popen pqueue printf rebuild report rss schema search setup sha1 shun skins stat style sync tag th_main timeline tkt tktsetup undo update url user verify vfile wiki wikiformat winhttp xfer zip shell sqlite3 th th_lang > $@ 49 49 +echo fossil >> $@ 50 50 +echo fossil >> $@ 51 51 +echo $(LIBS) >> $@ 52 52 +echo. >> $@ 53 53 +echo fossil >> $@ 54 54 55 55 ................................................................................ 62 62 63 63 mkindex$E: $(SRCDIR)\mkindex.c 64 64 $(BCC) -o$@ $** 65 65 66 66 version$E: $B\win\version.c 67 67 $(BCC) -o$@ $** 68 68 69 +$(OBJDIR)\shell$O : $(SRCDIR)\shell.c 70 + $(TCC) -o$@ -c -Dmain=sqlite3_shell -DSQLITE_OMIT_LOAD_EXTENSION=1 $** 71 + 69 72 $(OBJDIR)\sqlite3$O : $(SRCDIR)\sqlite3.c 70 73 $(TCC) -o$@ -c -DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -Dlocaltime=fossil_localtime -DSQLITE_ENABLE_LOCKING_STYLE=0 $** 71 74 72 75 $(OBJDIR)\th$O : $(SRCDIR)\th.c 73 76 $(TCC) -o$@ -c $** 74 77 75 78 $(OBJDIR)\th_lang$O : $(SRCDIR)\th_lang.c ................................................................................ 83 86 84 87 clean: 85 88 -del $(OBJDIR)\*.obj 86 89 -del *.obj *_.c *.h *.map 87 90 88 91 realclean: 89 92 -del $(APPNAME) translate$E mkindex$E makeheaders$E version$E 93 + -del fossil.res headers link 90 94 91 95 92 96 $(OBJDIR)\add$O : add_.c add.h 93 97 $(TCC) -o$@ -c add_.c 94 98 95 99 add_.c : $(SRCDIR)\add.c 96 100 +translate$E $** > $@ ................................................................................ 223 227 224 228 $(OBJDIR)\doc$O : doc_.c doc.h 225 229 $(TCC) -o$@ -c doc_.c 226 230 227 231 doc_.c : $(SRCDIR)\doc.c 228 232 +translate$E $** > $@ 229 233 230 -$(OBJDIR)\event$O : event_.c event.h 231 - $(TCC) -o$@ -c event_.c 232 - 233 -event_.c : $(SRCDIR)\event.c 234 - +translate$E $** > $@ 235 - 236 234 $(OBJDIR)\encode$O : encode_.c encode.h 237 235 $(TCC) -o$@ -c encode_.c 238 236 239 237 encode_.c : $(SRCDIR)\encode.c 240 238 +translate$E $** > $@ 241 239 242 240 $(OBJDIR)\event$O : event_.c event.h ................................................................................ 524 522 $(OBJDIR)\zip$O : zip_.c zip.h 525 523 $(TCC) -o$@ -c zip_.c 526 524 527 525 zip_.c : $(SRCDIR)\zip.c 528 526 +translate$E $** > $@ 529 527 530 528 headers: makeheaders$E page_index.h VERSION.h 531 - +makeheaders$E add_.c:add.h allrepo_.c:allrepo.h attach_.c:attach.h bag_.c:bag.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 file_.c:file.h finfo_.c:finfo.h graph_.c:graph.h http_.c:http.h http_socket_.c:http_socket.h http_ssl_.c:http_ssl.h http_transport_.c:http_transport.h info_.c:info.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h name_.c:name.h pivot_.c:pivot.h popen_.c:popen.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.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 stat_.c:stat.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h winhttp_.c:winhttp.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)\sqlite3.h $(SRCDIR)\th.h VERSION.h 529 + +makeheaders$E add_.c:add.h allrepo_.c:allrepo.h attach_.c:attach.h bag_.c:bag.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 file_.c:file.h finfo_.c:finfo.h graph_.c:graph.h http_.c:http.h http_socket_.c:http_socket.h http_ssl_.c:http_ssl.h http_transport_.c:http_transport.h info_.c:info.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h name_.c:name.h pivot_.c:pivot.h popen_.c:popen.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.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 stat_.c:stat.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h winhttp_.c:winhttp.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)\sqlite3.h $(SRCDIR)\th.h VERSION.h 532 530 @copy /Y nul: headers
Changes to www/fileformat.wiki.
117 117 A delta-manifest records only changes from its baseline. 118 118 119 119 A manifest must have exactly one C-card. The sole argument to 120 120 the C-card is a check-in comment that describes the check-in that 121 121 the manifest defines. The check-in comment is text. The following 122 122 escape sequences are applied to the text: 123 123 A space (ASCII 0x20) is represented as "\s" (ASCII 0x5C, 0x73). A 124 -newline (ASCII 0x0a) is "\n" (ASCII 0x6C, x6E). A backslash 124 +newline (ASCII 0x0a) is "\n" (ASCII 0x5C, x6E). A backslash 125 125 (ASCII 0x5C) is represented as two backslashes "\\". Apart from 126 126 space and newline, no other whitespace characters are allowed in 127 127 the check-in comment. Nor are any unprintable characters allowed 128 128 in the comment. 129 129 130 130 A manifest must have exactly one D-card. The sole argument to 131 131 the D-card is a date-time stamp in the ISO8601 format. The