Improvements to the 'tcl' shell output mode.  Escape double quotes, set separator to space when mode is set, and skip separator after final column.

FossilOrigin-Name: 41fd9dd29034b2269e4b7f2626350124d37b5303
diff --git a/manifest b/manifest
index 60900d2..f459268 100644
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Remove\san\sunreachable\scondition.\s\sReplace\sit\swith\san\sassert().
-D 2012-12-03T19:42:39.167
+C Improvements\sto\sthe\s'tcl'\sshell\soutput\smode.\s\sEscape\sdouble\squotes,\sset\sseparator\sto\sspace\swhen\smode\sis\sset,\sand\sskip\sseparator\safter\sfinal\scolumn.
+D 2012-12-04T00:23:43.067
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in 82c41c0ed4cc94dd3cc7d498575b84c57c2c2384
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -175,7 +175,7 @@
 F src/resolve.c 7b986a715ac281643309c29257bb58cfae7aa810
 F src/rowset.c 64655f1a627c9c212d9ab497899e7424a34222e0
 F src/select.c 3a8baf4719f9723b4e0b43f2baa60692d0d921f8
-F src/shell.c 99091f9dcf2bca1e1ff342f3361388b57f804135
+F src/shell.c e392dd1ccbb77cc1d75a8367a89b473c24bea019
 F src/sqlite.h.in 4e71a210f383b6d060bd3fdf81d850f0f8c4eca3
 F src/sqlite3.rc fea433eb0a59f4c9393c8e6d76a6e2596b1fe0c0
 F src/sqlite3ext.h 6904f4aadf976f95241311fbffb00823075d9477
@@ -708,7 +708,7 @@
 F test/shared9.test 614a3ca431adc73c857632deb4eff75bcaee40ec
 F test/shared_err.test 91e26ec4f3fbe07951967955585137e2f18993de
 F test/sharedlock.test ffa0a3c4ac192145b310f1254f8afca4d553eabf
-F test/shell1.test 340125225cc96c7f48d59a869aaf82866e481007
+F test/shell1.test b7896eb84028f3bc8300caf1fc796a73728aad0b
 F test/shell2.test 037d6ad16e873354195d30bb2dc4b5321788154a
 F test/shell3.test 9196c42772d575685e722c92b4b39053c6ebba59
 F test/shell4.test aa4eef8118b412d1a01477a53426ece169ea86a9
@@ -1025,7 +1025,10 @@
 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381
 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac
-P b0c1ba655d69c0c46c16ea2aef4e6c9a3e6ce3fb
-R b849c716d2b2c058f619a22bc4f40fe8
-U drh
-Z 0f893cca86d4c59ca9756d8f8e113fff
+P 7d5fc1a339cf4f3597ab6a5f3e7101884d2d7673
+R 38c0a4b163ba004b3c0d2e19a002293a
+T *branch * tclMode
+T *sym-tclMode *
+T -sym-trunk *
+U mistachkin
+Z 962a729a6a99e4b42add9e81143f97fc
diff --git a/manifest.uuid b/manifest.uuid
index fd0b821..ce8ea06 100644
--- a/manifest.uuid
+++ b/manifest.uuid
@@ -1 +1 @@
-7d5fc1a339cf4f3597ab6a5f3e7101884d2d7673
\ No newline at end of file
+41fd9dd29034b2269e4b7f2626350124d37b5303
\ No newline at end of file
diff --git a/src/shell.c b/src/shell.c
index 0283c9e..7dd741b 100644
--- a/src/shell.c
+++ b/src/shell.c
@@ -541,6 +541,9 @@
     if( c=='\\' ){
       fputc(c, out);
       fputc(c, out);
+    }else if( c=='"' ){
+      fputc('\\', out);
+      fputc('"', out);
     }else if( c=='\t' ){
       fputc('\\', out);
       fputc('t', out);
@@ -796,14 +799,14 @@
       if( p->cnt++==0 && p->showHeader ){
         for(i=0; i<nArg; i++){
           output_c_string(p->out,azCol[i] ? azCol[i] : "");
-          fprintf(p->out, "%s", p->separator);
+          if(i<nArg-1) fprintf(p->out, "%s", p->separator);
         }
         fprintf(p->out,"\n");
       }
       if( azArg==0 ) break;
       for(i=0; i<nArg; i++){
         output_c_string(p->out, azArg[i] ? azArg[i] : p->nullvalue);
-        fprintf(p->out, "%s", p->separator);
+        if(i<nArg-1) fprintf(p->out, "%s", p->separator);
       }
       fprintf(p->out,"\n");
       break;
@@ -2018,6 +2021,7 @@
       p->mode = MODE_Html;
     }else if( n2==3 && strncmp(azArg[1],"tcl",n2)==0 ){
       p->mode = MODE_Tcl;
+      sqlite3_snprintf(sizeof(p->separator), p->separator, " ");
     }else if( n2==3 && strncmp(azArg[1],"csv",n2)==0 ){
       p->mode = MODE_Csv;
       sqlite3_snprintf(sizeof(p->separator), p->separator, ",");
diff --git a/test/shell1.test b/test/shell1.test
index e826b95..50e6c71 100644
--- a/test/shell1.test
+++ b/test/shell1.test
@@ -719,13 +719,14 @@
 do_test shell1-4.1 {
   db eval {
     CREATE TABLE t1(x);
-    INSERT INTO t1 VALUES(null), (1), (2.25), ('hello'), (x'807f');
+    INSERT INTO t1 VALUES(null), (''), (1), (2.25), ('hello'), (x'807f');
   }
   catchcmd test.db {.dump}
 } {0 {PRAGMA foreign_keys=OFF;
 BEGIN TRANSACTION;
 CREATE TABLE t1(x);
 INSERT INTO "t1" VALUES(NULL);
+INSERT INTO "t1" VALUES('');
 INSERT INTO "t1" VALUES(1);
 INSERT INTO "t1" VALUES(2.25);
 INSERT INTO "t1" VALUES('hello');
@@ -737,10 +738,58 @@
 do_test shell1-4.2 {
   catchcmd test.db ".mode insert t1\nselect * from t1;"
 } {0 {INSERT INTO t1 VALUES(NULL);
+INSERT INTO t1 VALUES('');
 INSERT INTO t1 VALUES(1);
 INSERT INTO t1 VALUES(2.25);
 INSERT INTO t1 VALUES('hello');
 INSERT INTO t1 VALUES(X'807f');}}
 
+# Test the output of ".mode tcl"
+#
+do_test shell1-4.3 {
+  catchcmd test.db ".mode tcl\nselect * from t1;"
+} {0 {""
+""
+"1"
+"2.25"
+"hello"
+"\200\177"}}
+
+# Test the output of ".mode tcl" with multiple columns
+#
+do_test shell1-4.4 {
+  db eval {
+    CREATE TABLE t2(x,y);
+    INSERT INTO t2 VALUES(null, ''), (1, 2.25), ('hello', x'807f');
+  }
+  catchcmd test.db ".mode tcl\nselect * from t2;"
+} {0 {"" ""
+"1" "2.25"
+"hello" "\200\177"}}
+
+# Test the output of ".mode tcl" with ".nullvalue"
+#
+do_test shell1-4.5 {
+  catchcmd test.db ".mode tcl\n.nullvalue NULL\nselect * from t2;"
+} {0 {"NULL" ""
+"1" "2.25"
+"hello" "\200\177"}}
+
+# Test the output of ".mode tcl" with Tcl reserved characters
+#
+do_test shell1-4.6 {
+  db eval {
+    CREATE TABLE tcl1(x);
+    INSERT INTO tcl1 VALUES('"'), ('['), (']'), ('\{'), ('\}'), (';'), ('$');
+  }
+  foreach {x y} [catchcmd test.db ".mode tcl\nselect * from tcl1;"] break
+  list $x $y [llength $y]
+} {0 {"\""
+"["
+"]"
+"\\{"
+"\\}"
+";"
+"$"} 7}
 
 finish_test