Changes On Branch StvPrivateHook2
Not logged in

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,"&lt;");
          560  +    }else if( z[i]=='&' ){
          561  +      fprintf(out,"&amp;");
          562  +    }else if( z[i]=='>' ){
          563  +      fprintf(out,"&gt;");
          564  +    }else if( z[i]=='\"' ){
          565  +      fprintf(out,"&quot;");
          566  +    }else if( z[i]=='\'' ){
          567  +      fprintf(out,"&#39;");
          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