Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Some experimental command line shell input/output enhancements. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | expShell |
Files: | files | file ages | folders |
SHA1: |
25e99f3fe5e4c90e92554b8ac6cd6a83 |
User & Date: | mistachkin 2015-01-18 05:35:01.547 |
Context
2015-01-18
| ||
09:02 | Modify the new shell test case to work on non-Windows platforms as well. (check-in: f362c5d9d1 user: mistachkin tags: expShell) | |
05:35 | Some experimental command line shell input/output enhancements. (check-in: 25e99f3fe5 user: mistachkin tags: expShell) | |
01:50 | Set the command-line shell stdin to binary mode on windows. (check-in: 80541e8b94 user: drh tags: trunk) | |
Changes
Changes to src/shell.c.
︙ | ︙ | |||
742 743 744 745 746 747 748 749 750 751 752 753 754 755 | UNUSED_PARAMETER(NotUsed); seenInterrupt++; if( seenInterrupt>2 ) exit(1); if( db ) sqlite3_interrupt(db); } #endif /* ** This is the callback routine that the shell ** invokes for each row of a query result. */ static int shell_callback( void *pArg, int nArg, /* Number of result columns */ | > > > > > > > > > > > > > > > > | 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 | UNUSED_PARAMETER(NotUsed); seenInterrupt++; if( seenInterrupt>2 ) exit(1); if( db ) sqlite3_interrupt(db); } #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. */ static int shell_callback( void *pArg, int nArg, /* Number of result columns */ |
︙ | ︙ | |||
904 905 906 907 908 909 910 | output_c_string(p->out, azArg[i] ? azArg[i] : p->nullValue); if(i<nArg-1) fprintf(p->out, "%s", p->colSeparator); } fprintf(p->out, "%s", p->rowSeparator); break; } case MODE_Csv: { | < | < < < | < < | 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 | output_c_string(p->out, azArg[i] ? azArg[i] : p->nullValue); if(i<nArg-1) fprintf(p->out, "%s", p->colSeparator); } fprintf(p->out, "%s", p->rowSeparator); break; } case MODE_Csv: { enable_binary_output(p, 1); if( p->cnt++==0 && p->showHeader ){ for(i=0; i<nArg; i++){ output_csv(p, azCol[i] ? azCol[i] : "", i<nArg-1); } fprintf(p->out, "%s", p->rowSeparator); } if( nArg>0 ){ for(i=0; i<nArg; i++){ output_csv(p, azArg[i], i<nArg-1); } fprintf(p->out, "%s", p->rowSeparator); } enable_binary_output(p, 0); break; } case MODE_Insert: { p->cnt++; if( azArg==0 ) break; fprintf(p->out,"INSERT INTO %s VALUES(",p->zDestTable); for(i=0; i<nArg; i++){ |
︙ | ︙ | |||
1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 | /* ** Text of a help message */ static char zHelp[] = ".backup ?DB? FILE Backup DB (default \"main\") to FILE\n" ".bail on|off Stop after hitting an error. 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" " If TABLE specified, only dump tables matching\n" " LIKE pattern TABLE.\n" ".echo on|off Turn command echo on or off\n" ".eqp on|off Enable or disable automatic EXPLAIN QUERY PLAN\n" | > | 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 | /* ** Text of a help message */ 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" " If TABLE specified, only dump tables matching\n" " LIKE pattern TABLE.\n" ".echo on|off Turn command echo on or off\n" ".eqp on|off Enable or disable automatic EXPLAIN QUERY PLAN\n" |
︙ | ︙ | |||
1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 | writefileFunc, 0, 0); } } /* ** Do C-language style dequoting. ** ** \t -> tab ** \n -> newline ** \r -> carriage return ** \" -> " | > > > > > | > | | > > > > > > > > > > > > | 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 | writefileFunc, 0, 0); } } /* ** Do C-language style dequoting. ** ** \a -> alarm ** \b -> backspace ** \t -> tab ** \n -> newline ** \v -> vertical tab ** \f -> form feed ** \r -> carriage return ** \s -> space ** \" -> " ** \' -> ' ** \\ -> backslash ** \NNN -> ascii character NNN in octal */ static void resolve_backslashes(char *z){ int i, j; char c; while( *z && *z!='\\' ) z++; for(i=j=0; (c = z[i])!=0; i++, j++){ if( c=='\\' ){ c = z[++i]; 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' ){ c -= '0'; if( z[i+1]>='0' && z[i+1]<='7' ){ i++; c = (c<<3) + z[i] - '0'; |
︙ | ︙ | |||
2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 | if( nArg==2 ){ bail_on_error = booleanValue(azArg[1]); }else{ fprintf(stderr, "Usage: .bail on|off\n"); rc = 1; } }else /* The undocumented ".breakpoint" command causes a call to the no-op ** routine named test_breakpoint(). */ if( c=='b' && n>=3 && strncmp(azArg[0], "breakpoint", n)==0 ){ test_breakpoint(); }else | > > > > > > > > > | 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 | if( nArg==2 ){ bail_on_error = booleanValue(azArg[1]); }else{ fprintf(stderr, "Usage: .bail on|off\n"); rc = 1; } }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(). */ if( c=='b' && n>=3 && strncmp(azArg[0], "breakpoint", n)==0 ){ test_breakpoint(); }else |
︙ | ︙ | |||
4173 4174 4175 4176 4177 4178 4179 | if( strcmp(sqlite3_sourceid(),SQLITE_SOURCE_ID)!=0 ){ fprintf(stderr, "SQLite header and source version mismatch\n%s\n%s\n", sqlite3_sourceid(), SQLITE_SOURCE_ID); exit(1); } #endif #if defined(WIN32) || defined(_WIN32) | | | 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 | if( strcmp(sqlite3_sourceid(),SQLITE_SOURCE_ID)!=0 ){ fprintf(stderr, "SQLite header and source version mismatch\n%s\n%s\n", sqlite3_sourceid(), SQLITE_SOURCE_ID); exit(1); } #endif #if defined(WIN32) || defined(_WIN32) _setmode(_fileno(stdin), _O_BINARY); #endif Argv0 = argv[0]; main_init(&data); stdin_is_interactive = isatty(0); /* Make sure we have a valid signal handler early, before anything ** else is done. |
︙ | ︙ |
Changes to test/shell1.test.
︙ | ︙ | |||
810 811 812 813 814 815 816 817 818 | } {0 {"\"" "[" "]" "\\{" "\\}" ";" "$"} 7} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 | } {0 {"\"" "[" "]" "\\{" "\\}" ";" "$"} 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 |
Changes to test/tester.tcl.
︙ | ︙ | |||
661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 | } } else { puts " Omitted" omit_test $name "pattern mismatch" 0 } flush stdout } proc catchcmd {db {cmd ""}} { global CLI set out [open cmds.txt w] puts $out $cmd close $out set line "exec $CLI $db < cmds.txt" set rc [catch { eval $line } msg] list $rc $msg } proc filepath_normalize {p} { # test cases should be written to assume "unix"-like file paths if {$::tcl_platform(platform)!="unix"} { # lreverse*2 as a hack to remove any unneeded {} after the string map lreverse [lreverse [string map {\\ /} [regsub -nocase -all {[a-z]:[/\\]+} $p {/}]]] } { | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 | } } else { puts " Omitted" omit_test $name "pattern mismatch" 0 } 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] puts $out $cmd close $out set line "exec $CLI $db < cmds.txt" set rc [catch { eval $line } msg] 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"} { # lreverse*2 as a hack to remove any unneeded {} after the string map lreverse [lreverse [string map {\\ /} [regsub -nocase -all {[a-z]:[/\\]+} $p {/}]]] } { |
︙ | ︙ |