diff --git a/manifest b/manifest index d122701d5e..0df4444317 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Set\sthe\scommand-line\sshell\sstdin\sto\sbinary\smode\son\swindows. -D 2015-01-18T01:50:54.333 +C Some\sexperimental\scommand\sline\sshell\sinput/output\senhancements. +D 2015-01-18T05:35:01.547 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5407a688f4d77a05c18a8142be8ae5a2829dd610 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -230,7 +230,7 @@ F src/random.c ba2679f80ec82c4190062d756f22d0c358180696 F src/resolve.c f6c46d3434439ab2084618d603e6d6dbeb0d6ada F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e F src/select.c e4c38c75e36f28aed80a69a725d888751bfd53df -F src/shell.c 96c40c85467552025d81505310efcf3679303d3a +F src/shell.c b976fd2b3dd3c097e7749f26b9cb8c6ca75985a8 F src/sqlite.h.in 9dfc99d6533d36d6a549c4f3f01cacc8be956ada F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad F src/sqlite3ext.h 17d487c3c91b0b8c584a32fbeb393f6f795eea7d @@ -855,7 +855,7 @@ F test/sharedA.test 0cdf1a76dfa00e6beee66af5b534b1e8df2720f5 F test/sharedB.test 16cc7178e20965d75278f410943109b77b2e645e F test/shared_err.test 2f2aee20db294b9924e81f6ccbe60f19e21e8506 F test/sharedlock.test 5ede3c37439067c43b0198f580fd374ebf15d304 -F test/shell1.test cdeb849acc2c37aada70d084564b0cc0a2c7df08 +F test/shell1.test 4c16272bc959443fe3848d1370e686694b10fdaf F test/shell2.test 12b8bf901b0e3a8ac58cf5c0c63a0a388d4d1862 F test/shell3.test 5e8545ec72c4413a0e8d4c6be56496e3c257ca29 F test/shell4.test 8a9c08976291e6c6c808b4d718f4a8b299f339f5 @@ -905,7 +905,7 @@ F test/tclsqlite.test 37a61c2da7e3bfe3b8c1a2867199f6b860df5d43 F test/tempdb.test 19d0f66e2e3eeffd68661a11c83ba5e6ace9128c F test/temptable.test d2c9b87a54147161bcd1822e30c1d1cd891e5b30 F test/temptrigger.test 8ec228b0db5d7ebc4ee9b458fc28cb9e7873f5e1 -F test/tester.tcl ed77454e6c7b40eb501db7e79d1c6fbfd3eebbff +F test/tester.tcl 51211254f2ee2340d3e4fa0a83bd5381b9e1a227 F test/thread001.test 9f22fd3525a307ff42a326b6bc7b0465be1745a5 F test/thread002.test e630504f8a06c00bf8bbe68528774dd96aeb2e58 F test/thread003.test ee4c9efc3b86a6a2767516a37bd64251272560a7 @@ -1236,7 +1236,10 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P ceac571f53bdbc02616b21a4404cb1250030dea8 -R af1132932e63d89318ed108ce444bb3a -U drh -Z 8c65f5a7bb0fabe2bc52b8a9296117bf +P 80541e8b94b713e8f9e588ae047ffc5ae804ef1c +R b03241b729782f3438422b692742f278 +T *branch * expShell +T *sym-expShell * +T -sym-trunk * +U mistachkin +Z 971bfa7ec1c0dafc699fba1587f31a66 diff --git a/manifest.uuid b/manifest.uuid index 2997f19ca0..9a4c0dbb06 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -80541e8b94b713e8f9e588ae047ffc5ae804ef1c \ No newline at end of file +25e99f3fe5e4c90e92554b8ac6cd6a83a8d01a6a \ No newline at end of file diff --git a/src/shell.c b/src/shell.c index 9e23734ae7..0b8eae2e4b 100644 --- a/src/shell.c +++ b/src/shell.c @@ -746,6 +746,22 @@ static void interrupt_handler(int NotUsed){ } #endif +#if defined(WIN32) || defined(_WIN32) +/* +** This routine is used to adjust the file translation mode for the output +** file. It is only used on Windows. +*/ +static void enable_binary_output( + ShellState *p, + int enable +){ + fflush(p->out); + _setmode(_fileno(p->out), enable ? _O_BINARY : _O_TEXT); +} +#else +#define enable_binary_output(p,e) +#endif + /* ** This is the callback routine that the shell ** invokes for each row of a query result. @@ -908,10 +924,7 @@ static int shell_callback( break; } case MODE_Csv: { -#if defined(WIN32) || defined(_WIN32) - fflush(p->out); - _setmode(_fileno(p->out), _O_BINARY); -#endif + enable_binary_output(p, 1); if( p->cnt++==0 && p->showHeader ){ for(i=0; iout, "%s", p->rowSeparator); } -#if defined(WIN32) || defined(_WIN32) - fflush(p->out); - _setmode(_fileno(p->out), _O_TEXT); -#endif + enable_binary_output(p, 0); break; } case MODE_Insert: { @@ -1715,6 +1725,7 @@ static int run_schema_dump_query( static char zHelp[] = ".backup ?DB? FILE Backup DB (default \"main\") to FILE\n" ".bail on|off Stop after hitting an error. Default OFF\n" + ".binary on|off Turn binary output on or off. Default OFF\n" ".clone NEWDB Clone data into NEWDB from the existing database\n" ".databases List names and files of attached databases\n" ".dump ?TABLE? ... Dump the database in an SQL text format\n" @@ -1875,12 +1886,18 @@ static void open_db(ShellState *p, int keepAlive){ /* ** Do C-language style dequoting. ** +** \a -> alarm +** \b -> backspace ** \t -> tab ** \n -> newline +** \v -> vertical tab +** \f -> form feed ** \r -> carriage return +** \s -> space ** \" -> " -** \NNN -> ascii character NNN in octal +** \' -> ' ** \\ -> backslash +** \NNN -> ascii character NNN in octal */ static void resolve_backslashes(char *z){ int i, j; @@ -1889,12 +1906,24 @@ static void resolve_backslashes(char *z){ for(i=j=0; (c = z[i])!=0; i++, j++){ if( c=='\\' ){ c = z[++i]; - if( c=='n' ){ - c = '\n'; + if( c=='a' ){ + c = '\a'; + }else if( c=='b' ){ + c = '\b'; }else if( c=='t' ){ c = '\t'; + }else if( c=='n' ){ + c = '\n'; + }else if( c=='v' ){ + c = '\v'; + }else if( c=='f' ){ + c = '\f'; }else if( c=='r' ){ c = '\r'; + }else if( c=='"' ){ + c = '"'; + }else if( c=='\'' ){ + c = '\''; }else if( c=='\\' ){ c = '\\'; }else if( c>='0' && c<='7' ){ @@ -2517,6 +2546,15 @@ static int do_meta_command(char *zLine, ShellState *p){ } }else + if( c=='b' && n>=3 && strncmp(azArg[0], "binary", n)==0 ){ + if( nArg==2 ){ + enable_binary_output(p, booleanValue(azArg[1])); + }else{ + fprintf(stderr, "Usage: .binary on|off\n"); + rc = 1; + } + }else + /* The undocumented ".breakpoint" command causes a call to the no-op ** routine named test_breakpoint(). */ @@ -4177,7 +4215,7 @@ int main(int argc, char **argv){ } #endif #if defined(WIN32) || defined(_WIN32) - _setmode(0, _O_BINARY); + _setmode(_fileno(stdin), _O_BINARY); #endif Argv0 = argv[0]; main_init(&data); diff --git a/test/shell1.test b/test/shell1.test index f24b00d494..22fd6ce16f 100644 --- a/test/shell1.test +++ b/test/shell1.test @@ -815,4 +815,37 @@ do_test shell1-4.6 { ";" "$"} 7} +# Test using arbitrary byte data with the shell via standard input/output. +# +do_test shell1-5.0 { + # + # NOTE: Skip NUL byte because it appears to be incompatible with command + # shell argument parsing. + # + for {set i 1} {$i < 256} {incr i} { + # + # NOTE: Due to how the Tcl [exec] command works on Windows (i.e. where + # it treats command channels opened for it as textual ones), the + # carriage-return and end-of-file characters cannot be used here. + # + if {$tcl_platform(platform)=="windows" && ($i == 0x0D || $i == 0x1A)} { + continue + } + set hex [format %02X $i] + set char [subst \\x$hex]; set oldChar $char + set char [string map [list \ + \a \\a \b \\b \t \\t \n \\n \v \\v \f \\f \r \\r \ + " " "\" \"" \" \\\" ' \"'\" \\ \\\\] $char] + set x [catchcmdex test.db ".print $char\r\n"] + set code [lindex $x 0] + set res [lindex $x 1] + if {$code ne "0"} { + error "failed with error: $res" + } + if {$res ne "$oldChar\n"} { + error "failed with byte $hex mismatch" + } + } +} {} + finish_test diff --git a/test/tester.tcl b/test/tester.tcl index dad22661bd..37ca69f497 100644 --- a/test/tester.tcl +++ b/test/tester.tcl @@ -666,6 +666,15 @@ proc do_test {name cmd expected} { flush stdout } +proc dumpbytes {s} { + set r "" + for {set i 0} {$i < [string length $s]} {incr i} { + if {$i > 0} {append r " "} + append r [format %02X [scan [string index $s $i] %c]] + } + return $r +} + proc catchcmd {db {cmd ""}} { global CLI set out [open cmds.txt w] @@ -676,6 +685,30 @@ proc catchcmd {db {cmd ""}} { list $rc $msg } +proc catchcmdex {db {cmd ""}} { + global CLI + set out [open cmds.txt w] + fconfigure $out -encoding binary -translation binary + puts -nonewline $out $cmd + close $out + set line "exec -keepnewline -- $CLI $db < cmds.txt" + set chans [list stdin stdout stderr] + foreach chan $chans { + catch { + set modes($chan) [fconfigure $chan] + fconfigure $chan -encoding binary -translation binary -buffering none + } + } + set rc [catch { eval $line } msg] + foreach chan $chans { + catch { + eval fconfigure [list $chan] $modes($chan) + } + } + # puts [dumpbytes $msg] + list $rc $msg +} + proc filepath_normalize {p} { # test cases should be written to assume "unix"-like file paths if {$::tcl_platform(platform)!="unix"} {