return zLine;
}
+/*
+** Arrange for shell input from either a FILE or a string.
+** See getline_from(...) for applicable invariants. It is
+** the only modifier of data within this struct, except for
+** initialization which is either {0, zS, 0} or {pF, 0, 0},
+** left to whatever routine is switching input sources.
+*/
+typedef struct InSource {
+ FILE *inFile; /* Will be 0 when input is to be taken from string. */
+ char *zStrIn; /* Will be 0 when no input is available from string. */
+ int iReadOffset; /* Offset into ZStrIn where next "read" to be done. */
+} InSource;
+
+/*
+** Read single lines of input text from source selected by pInSource.
+** This function presents an interface similar to local_getline(...),
+** to which it defers for FILE input. (This function may be considered
+** to be an adapter except for the source parameter.)
+*/
+static char *getline_from( char *zPrior, InSource *pSource ){
+ char *zResult = 0;
+ if( pSource->inFile!=0 ){
+ zResult = local_getline(zPrior, pSource->inFile);
+ }
+ return zResult;
+}
+
/*
** Retrieve a single line of input text.
**
**
** 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.
+** zPrior argument for reuse (and eventual free by the caller.)
*/
-static char *one_input_line(FILE *in, char *zPrior, int isContinuation){
+static char *one_input_line(InSource *pInSrc, char *zPrior, int isContinuation){
char *zPrompt;
char *zResult;
- if( in!=0 ){
- zResult = local_getline(zPrior, in);
+ if( pInSrc!=0 ){
+ zResult = local_getline(zPrior, pInSrc->inFile);
}else{
zPrompt = isContinuation ? continuePrompt : mainPrompt;
#if SHELL_USE_LOCAL_GETLINE
char zPrefix[100]; /* Graph prefix */
};
+/* Input source switching is done through one of these (defined below) */
+typedef struct InSource InSource;
+
/*
** State information about the database connection is contained in an
** instance of the following structure.
int cnt; /* Number of records displayed so far */
int lineno; /* Line number of last line read from in */
int openFlags; /* Additional flags to open. (SQLITE_OPEN_NOFOLLOW) */
- FILE *in; /* Read commands from this stream */
+ InSource *pInSource; /* Read commands and SQL from this stream source */
FILE *out; /* Write results here */
FILE *traceOut; /* Output for sqlite3_trace() */
int nErr; /* Number of errors seen */
/*
** Reconstruct an in-memory database using the output from the "dbtotxt"
** program. Read content from the file in p->aAuxDb[].zDbFilename.
-** If p->aAuxDb[].zDbFilename is 0, then read from standard input.
+** If p->aAuxDb[].zDbFilename is 0, then read from either the present
+** input file, or standard input if there is no file open for input.
*/
static unsigned char *readHexDb(ShellState *p, int *pnData){
unsigned char *a = 0;
int iOffset = 0;
int j, k;
int rc;
- FILE *in;
+ FILE *in = 0;
const char *zDbFilename = p->pAuxDb->zDbFilename;
unsigned int x[16];
char zLine[1000];
}
nLine = 0;
}else{
- in = p->in;
+ if( p->pInSource!=0 ) in = p->pInSource->inFile;
nLine = p->lineno;
if( in==0 ) in = stdin;
}
}
}
*pnData = n;
- if( in!=p->in ){
- fclose(in);
- }else{
- p->lineno = nLine;
- }
+ if( zDbFilename ) fclose(in);
+ else p->lineno = nLine;
return a;
readHexDb_error:
- if( in!=p->in ){
+ if( zDbFilename ){
fclose(in);
}else{
- while( fgets(zLine, sizeof(zLine), p->in)!=0 ){
- nLine++;
+ int nLinePass = nLine;
+ while( fgets(zLine, sizeof(zLine), in)!=0 ){
+ nLinePass++;
if(strncmp(zLine, "| end ", 6)==0 ) break;
}
- p->lineno = nLine;
+ p->lineno = nLinePass;
}
sqlite3_free(a);
utf8_printf(stderr,"Error on line %d of --hexdb input\n", nLine);
}else
if( c=='r' && n>=3 && strncmp(azArg[0], "read", n)==0 ){
- FILE *inSaved = p->in;
- int savedLineno = p->lineno;
+ FILE *inUse = 0;
+ int (*fCloser)(FILE *) = 0;
failIfSafeMode(p, "cannot run .read in safe mode");
if( nArg!=2 ){
raw_printf(stderr, "Usage: .read FILE\n");
#ifdef SQLITE_OMIT_POPEN
raw_printf(stderr, "Error: pipes are not supported in this OS\n");
rc = 1;
- p->out = stdout;
+ p->out = stdout; /* This is likely not needed. To be investigated. */
#else
- p->in = popen(azArg[1]+1, "r");
- if( p->in==0 ){
+ inUse = popen(azArg[1]+1, "r");
+ if( inUse==0 ){
utf8_printf(stderr, "Error: cannot open \"%s\"\n", azArg[1]);
rc = 1;
}else{
- rc = process_input(p);
- pclose(p->in);
+ fCloser = pclose;
}
#endif
- }else if( (p->in = openChrSource(azArg[1]))==0 ){
+ }else if( (inUse = openChrSource(azArg[1]))==0 ){
utf8_printf(stderr,"Error: cannot open \"%s\"\n", azArg[1]);
rc = 1;
}else{
+ fCloser = fclose;
+ }
+ if( inUse!=0 ){
+ InSource *pInSrcSave = p->pInSource;
+ int savedLineno = p->lineno;
+ InSource inSourceDivert = {inUse, 0, 0};
+ p->pInSource = &inSourceDivert;
rc = process_input(p);
- fclose(p->in);
+ assert(fCloser!=0);
+ fCloser(inUse);
+ p->pInSource = pInSrcSave;
+ p->lineno = savedLineno;
}
- p->in = inSaved;
- p->lineno = savedLineno;
}else
if( c=='r' && n>=3 && strncmp(azArg[0], "restore", n)==0 ){
/*
** Run a single line of SQL. Return the number of errors.
+** bAltIn indicates that input has been redirected in some way.
*/
-static int runOneSqlLine(ShellState *p, char *zSql, FILE *in, int startline){
+static int runOneSqlLine(ShellState *p, char *zSql, int bAltIn, int startline){
int rc;
char *zErrMsg = 0;
END_TIMER;
if( rc || zErrMsg ){
char zPrefix[100];
- if( in!=0 || !stdin_is_interactive ){
+ if( bAltIn || !stdin_is_interactive ){
sqlite3_snprintf(sizeof(zPrefix), zPrefix,
"Error: near line %d:", startline);
}else{
QuickScanState qss = QSS_Start; /* Accumulated line status (so far) */
p->lineno = 0;
- while( errCnt==0 || !bail_on_error || (p->in==0 && stdin_is_interactive) ){
+ while( errCnt==0
+ || !bail_on_error
+ || (p->pInSource==0 && stdin_is_interactive) ){
fflush(p->out);
- zLine = one_input_line(p->in, zLine, nSql>0);
+ zLine = one_input_line(p->pInSource, zLine, nSql>0);
if( zLine==0 ){
/* End of input */
- if( p->in==0 && stdin_is_interactive ) printf("\n");
+ if( p->pInSource==0 && stdin_is_interactive ) printf("\n");
break;
}
if( seenInterrupt ){
- if( p->in!=0 ) break;
+ if( p->pInSource!=0 ) break;
seenInterrupt = 0;
}
p->lineno++;
nSql += nLine;
}
if( nSql && QSS_SEMITERM(qss) && sqlite3_complete(zSql) ){
- errCnt += runOneSqlLine(p, zSql, p->in, startline);
+ errCnt += runOneSqlLine(p, zSql, p->pInSource!=0, startline);
nSql = 0;
if( p->outCount ){
output_reset(p);
}
}
if( nSql && QSS_PLAINDARK(qss) ){
- errCnt += runOneSqlLine(p, zSql, p->in, startline);
+ errCnt += runOneSqlLine(p, zSql, p->pInSource!=0, startline);
}
free(zSql);
free(zLine);
char *home_dir = NULL;
const char *sqliterc = sqliterc_override;
char *zBuf = 0;
- FILE *inSaved = p->in;
- int savedLineno = p->lineno;
+ FILE *inUse;
if (sqliterc == NULL) {
home_dir = find_home_dir(0);
shell_check_oom(zBuf);
sqliterc = zBuf;
}
- p->in = fopen(sqliterc,"rb");
- if( p->in ){
+ inUse = fopen(sqliterc,"rb");
+ if( inUse!=0 ){
+ InSource *pInSrcSave = p->pInSource;
+ int savedLineno = p->lineno;
+ InSource inSourceDivert = {inUse, 0, 0};
+ int rc;
+ p->pInSource = &inSourceDivert;
if( stdin_is_interactive ){
utf8_printf(stderr,"-- Loading resources from %s\n",sqliterc);
}
- if( process_input(p) && bail_on_error ) exit(1);
- fclose(p->in);
+ rc = process_input(p);
+ fclose(inUse);
+ p->pInSource = pInSrcSave;
+ p->lineno = savedLineno;
+ if( rc!=0 && bail_on_error ) exit(1);
}else if( sqliterc_override!=0 ){
utf8_printf(stderr,"cannot open: \"%s\"\n", sqliterc);
if( bail_on_error ) exit(1);
}
- p->in = inSaved;
- p->lineno = savedLineno;
sqlite3_free(zBuf);
}
#endif
char *zErrMsg = 0;
ShellState data;
+ InSource inputSource = { stdin, 0, 0};
const char *zInitFile = 0;
int i;
int rc = 0;
#elif HAVE_LINENOISE
linenoiseSetCompletionCallback(linenoise_completion);
#endif
- data.in = 0;
+ data.pInSource = 0; /* read from stdin interactively */
rc = process_input(&data);
if( zHistory ){
shell_stifle_history(2000);
free(zHistory);
}
}else{
- data.in = stdin;
+ data.pInSource = &inputSource; /* read from stdin without prompts */
rc = process_input(&data);
}
}