Clean up the input reader in the command-line shell for improved legibility
and performance. FossilOrigin-Name: 2b1743d60171635c1e5a6ede6b4928f4671f948d
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
C More\sthan\sdouble\sthe\sspeed\sof\sthe\sresolveP2Values()\sroutine\sin\svdbeaux.c\sby\nmoving\sfrom\san\sextended\sif-else\son\severy\sopcode\sto\sa\sswitch.\s\sOpcodes\sare\nreordered\sin\smkopcodesh.awk\sto\sput\sthe\sswitched\sopcodes\sclose\stogether,\nfor\sadditional\sperformance\sand\sto\sreduce\scode\sfootprint.
|
||||
D 2013-08-06T07:45:08.160
|
||||
C Clean\sup\sthe\sinput\sreader\sin\sthe\scommand-line\sshell\sfor\simproved\slegibility\nand\sperformance.
|
||||
D 2013-08-06T14:01:46.052
|
||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||
F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e
|
||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||
@@ -217,7 +217,7 @@ F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50
|
||||
F src/resolve.c 17e670996729ac41aadf6a31f57b4e6f29b3d819
|
||||
F src/rowset.c 64655f1a627c9c212d9ab497899e7424a34222e0
|
||||
F src/select.c 8b148eb851f384412aea57091659d14b369918ca
|
||||
F src/shell.c 52f975eae87c8338c4dfbf4c2842d2a0971f01fd
|
||||
F src/shell.c 18be30ad43044f1d84441667c8b50df0b4996db9
|
||||
F src/sqlite.h.in 442c109e0c3447c34b1794971ecdb673ce08a843
|
||||
F src/sqlite3.rc fea433eb0a59f4c9393c8e6d76a6e2596b1fe0c0
|
||||
F src/sqlite3ext.h 886f5a34de171002ad46fae8c36a7d8051c190fc
|
||||
@@ -1105,7 +1105,7 @@ F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
|
||||
F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381
|
||||
F tool/wherecosttest.c f407dc4c79786982a475261866a161cd007947ae
|
||||
F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac
|
||||
P c589b2fed7beabc2337d701094c22635914d9c23
|
||||
R 63c66722ef11a129368dbe6ccc84108b
|
||||
P 924f7e4d7a8fa2fe9100836663f3733b6e1a9084
|
||||
R a0a003b94645637a781f18f2495d5c36
|
||||
U drh
|
||||
Z db760ef775aca796d7a23f90b9b7ee9e
|
||||
Z 390282ae711b439a5d58cc71aa5c9578
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
924f7e4d7a8fa2fe9100836663f3733b6e1a9084
|
||||
2b1743d60171635c1e5a6ede6b4928f4671f948d
|
||||
+65
-77
@@ -53,7 +53,6 @@
|
||||
# include <readline/history.h>
|
||||
#endif
|
||||
#if !defined(HAVE_EDITLINE) && (!defined(HAVE_READLINE) || HAVE_READLINE!=1)
|
||||
# define readline(p) local_getline(p,stdin,0)
|
||||
# define add_history(X)
|
||||
# define read_history(X)
|
||||
# define write_history(X)
|
||||
@@ -337,23 +336,13 @@ static void shellstaticFunc(
|
||||
** to the text. NULL is returned at end of file, or if malloc()
|
||||
** fails.
|
||||
**
|
||||
** The interface is like "readline" but no command-line editing
|
||||
** is done.
|
||||
** If zLine is not NULL then it is a malloced buffer returned from
|
||||
** a previous call to this routine that may be reused.
|
||||
*/
|
||||
static char *local_getline(char *zPrompt, FILE *in, int csvFlag){
|
||||
char *zLine;
|
||||
int nLine;
|
||||
int n;
|
||||
int inQuote = 0;
|
||||
static char *local_getline(char *zLine, FILE *in){
|
||||
int nLine = zLine==0 ? 0 : 100;
|
||||
int n = 0;
|
||||
|
||||
if( zPrompt && *zPrompt ){
|
||||
printf("%s",zPrompt);
|
||||
fflush(stdout);
|
||||
}
|
||||
nLine = 100;
|
||||
zLine = malloc( nLine );
|
||||
if( zLine==0 ) return 0;
|
||||
n = 0;
|
||||
while( 1 ){
|
||||
if( n+100>nLine ){
|
||||
nLine = nLine*2 + 100;
|
||||
@@ -368,42 +357,48 @@ static char *local_getline(char *zPrompt, FILE *in, int csvFlag){
|
||||
zLine[n] = 0;
|
||||
break;
|
||||
}
|
||||
while( zLine[n] ){
|
||||
if( zLine[n]=='"' ) inQuote = !inQuote;
|
||||
n++;
|
||||
}
|
||||
if( n>0 && zLine[n-1]=='\n' && (!inQuote || !csvFlag) ){
|
||||
while( zLine[n] ) n++;
|
||||
if( n>0 && zLine[n-1]=='\n' ){
|
||||
n--;
|
||||
if( n>0 && zLine[n-1]=='\r' ) n--;
|
||||
zLine[n] = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
zLine = realloc( zLine, n+1 );
|
||||
return zLine;
|
||||
}
|
||||
|
||||
/*
|
||||
** Retrieve a single line of input text.
|
||||
**
|
||||
** zPrior is a string of prior text retrieved. If not the empty
|
||||
** string, then issue a continuation prompt.
|
||||
** If in==0 then read from standard input and prompt before each line.
|
||||
** If isContinuation is true, then a continuation prompt is appropriate.
|
||||
** If isContinuation is zero, then the main prompt should be used.
|
||||
**
|
||||
** If zPrior is not NULL then it is a buffer from a prior call to this
|
||||
** routine that can be reused.
|
||||
**
|
||||
** The result is stored in space obtained from malloc() and must either
|
||||
** be freed by the caller or else passed back into this routine via the
|
||||
** zPrior argument for reuse.
|
||||
*/
|
||||
static char *one_input_line(const char *zPrior, FILE *in){
|
||||
static char *one_input_line(FILE *in, char *zPrior, int isContinuation){
|
||||
char *zPrompt;
|
||||
char *zResult;
|
||||
if( in!=0 ){
|
||||
return local_getline(0, in, 0);
|
||||
}
|
||||
if( zPrior && zPrior[0] ){
|
||||
zPrompt = continuePrompt;
|
||||
zResult = local_getline(zPrior, in);
|
||||
}else{
|
||||
zPrompt = mainPrompt;
|
||||
}
|
||||
zResult = readline(zPrompt);
|
||||
zPrompt = isContinuation ? continuePrompt : mainPrompt;
|
||||
#if defined(HAVE_READLINE) && HAVE_READLINE==1
|
||||
if( zResult && *zResult ) add_history(zResult);
|
||||
free(zPrior);
|
||||
zResult = readline(zPrompt);
|
||||
if( zResult && *zResult ) add_history(zResult);
|
||||
#else
|
||||
printf("%s", zPrompt);
|
||||
fflush(stdout);
|
||||
zResult = local_getline(zPrior, stdin);
|
||||
#endif
|
||||
}
|
||||
return zResult;
|
||||
}
|
||||
|
||||
@@ -2781,7 +2776,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
||||
** Return TRUE if a semicolon occurs anywhere in the first N characters
|
||||
** of string z[].
|
||||
*/
|
||||
static int _contains_semicolon(const char *z, int N){
|
||||
static int line_contains_semicolon(const char *z, int N){
|
||||
int i;
|
||||
for(i=0; i<N; i++){ if( z[i]==';' ) return 1; }
|
||||
return 0;
|
||||
@@ -2816,7 +2811,7 @@ static int _all_whitespace(const char *z){
|
||||
** than a semi-colon. The SQL Server style "go" command is understood
|
||||
** as is the Oracle "/".
|
||||
*/
|
||||
static int _is_command_terminator(const char *zLine){
|
||||
static int line_is_command_terminator(const char *zLine){
|
||||
while( IsSpace(zLine[0]) ){ zLine++; };
|
||||
if( zLine[0]=='/' && _all_whitespace(&zLine[1]) ){
|
||||
return 1; /* Oracle */
|
||||
@@ -2832,7 +2827,7 @@ static int _is_command_terminator(const char *zLine){
|
||||
** Return true if zSql is a complete SQL statement. Return false if it
|
||||
** ends in the middle of a string literal or C-style comment.
|
||||
*/
|
||||
static int _is_complete(char *zSql, int nSql){
|
||||
static int line_is_complete(char *zSql, int nSql){
|
||||
int rc;
|
||||
if( zSql==0 ) return 1;
|
||||
zSql[nSql] = ';';
|
||||
@@ -2852,20 +2847,21 @@ static int _is_complete(char *zSql, int nSql){
|
||||
** Return the number of errors.
|
||||
*/
|
||||
static int process_input(struct callback_data *p, FILE *in){
|
||||
char *zLine = 0;
|
||||
char *zSql = 0;
|
||||
int nSql = 0;
|
||||
int nSqlPrior = 0;
|
||||
char *zErrMsg;
|
||||
int rc;
|
||||
int errCnt = 0;
|
||||
int lineno = 0;
|
||||
int startline = 0;
|
||||
char *zLine = 0; /* A single input line */
|
||||
char *zSql = 0; /* Accumulated SQL text */
|
||||
int nLine; /* Length of current line */
|
||||
int nSql = 0; /* Bytes of zSql[] used */
|
||||
int nAlloc = 0; /* Allocated zSql[] space */
|
||||
int nSqlPrior = 0; /* Bytes of zSql[] used by prior line */
|
||||
char *zErrMsg; /* Error message returned */
|
||||
int rc; /* Error code */
|
||||
int errCnt = 0; /* Number of errors seen */
|
||||
int lineno = 0; /* Current line number */
|
||||
int startline = 0; /* Line number for start of current input */
|
||||
|
||||
while( errCnt==0 || !bail_on_error || (in==0 && stdin_is_interactive) ){
|
||||
fflush(p->out);
|
||||
free(zLine);
|
||||
zLine = one_input_line(zSql, in);
|
||||
zLine = one_input_line(in, zLine, nSql>0);
|
||||
if( zLine==0 ){
|
||||
/* End of input */
|
||||
if( stdin_is_interactive ) printf("\n");
|
||||
@@ -2876,7 +2872,7 @@ static int process_input(struct callback_data *p, FILE *in){
|
||||
seenInterrupt = 0;
|
||||
}
|
||||
lineno++;
|
||||
if( (zSql==0 || zSql[0]==0) && _all_whitespace(zLine) ) continue;
|
||||
if( nSql==0 && _all_whitespace(zLine) ) continue;
|
||||
if( zLine && zLine[0]=='.' && nSql==0 ){
|
||||
if( p->echoOn ) printf("%s\n", zLine);
|
||||
rc = do_meta_command(zLine, p);
|
||||
@@ -2887,35 +2883,31 @@ static int process_input(struct callback_data *p, FILE *in){
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if( _is_command_terminator(zLine) && _is_complete(zSql, nSql) ){
|
||||
if( line_is_command_terminator(zLine) && line_is_complete(zSql, nSql) ){
|
||||
memcpy(zLine,";",2);
|
||||
}
|
||||
nSqlPrior = nSql;
|
||||
if( zSql==0 ){
|
||||
int i;
|
||||
for(i=0; zLine[i] && IsSpace(zLine[i]); i++){}
|
||||
if( zLine[i]!=0 ){
|
||||
nSql = strlen30(zLine);
|
||||
zSql = malloc( nSql+3 );
|
||||
if( zSql==0 ){
|
||||
fprintf(stderr, "Error: out of memory\n");
|
||||
exit(1);
|
||||
}
|
||||
memcpy(zSql, zLine, nSql+1);
|
||||
startline = lineno;
|
||||
}
|
||||
}else{
|
||||
int len = strlen30(zLine);
|
||||
zSql = realloc( zSql, nSql + len + 4 );
|
||||
nLine = strlen30(zLine);
|
||||
if( nSql+nLine+2>=nAlloc ){
|
||||
nAlloc = nSql+nLine+100;
|
||||
zSql = realloc(zSql, nAlloc);
|
||||
if( zSql==0 ){
|
||||
fprintf(stderr,"Error: out of memory\n");
|
||||
fprintf(stderr, "Error: out of memory\n");
|
||||
exit(1);
|
||||
}
|
||||
zSql[nSql++] = '\n';
|
||||
memcpy(&zSql[nSql], zLine, len+1);
|
||||
nSql += len;
|
||||
}
|
||||
if( zSql && _contains_semicolon(&zSql[nSqlPrior], nSql-nSqlPrior)
|
||||
nSqlPrior = nSql;
|
||||
if( nSql==0 ){
|
||||
int i;
|
||||
for(i=0; zLine[i] && IsSpace(zLine[i]); i++){}
|
||||
memcpy(zSql, zLine+i, nLine+1-i);
|
||||
startline = lineno;
|
||||
nSql = nLine-i;
|
||||
}else{
|
||||
zSql[nSql++] = '\n';
|
||||
memcpy(zSql+nSql, zLine, nLine+1);
|
||||
nSql += nLine;
|
||||
}
|
||||
if( nSql && line_contains_semicolon(&zSql[nSqlPrior], nSql-nSqlPrior)
|
||||
&& sqlite3_complete(zSql) ){
|
||||
p->cnt = 0;
|
||||
open_db(p);
|
||||
@@ -2939,16 +2931,12 @@ static int process_input(struct callback_data *p, FILE *in){
|
||||
}
|
||||
errCnt++;
|
||||
}
|
||||
free(zSql);
|
||||
zSql = 0;
|
||||
nSql = 0;
|
||||
}else if( zSql && _all_whitespace(zSql) ){
|
||||
free(zSql);
|
||||
zSql = 0;
|
||||
}else if( nSql && _all_whitespace(zSql) ){
|
||||
nSql = 0;
|
||||
}
|
||||
}
|
||||
if( zSql ){
|
||||
if( nSql ){
|
||||
if( !_all_whitespace(zSql) ){
|
||||
fprintf(stderr, "Error: incomplete SQL: %s\n", zSql);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user