]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
CLI prepared for reading string input
authorlarrybr <larrybr@noemail.net>
Mon, 24 Jan 2022 00:22:06 +0000 (00:22 +0000)
committerlarrybr <larrybr@noemail.net>
Mon, 24 Jan 2022 00:22:06 +0000 (00:22 +0000)
FossilOrigin-Name: 073ded4d185d0133b07b4548dd78f4ad5eb17ce1f5c457d89fee23281420bbff

manifest
manifest.uuid
src/shell.c.in

index 792037e6b766bdf6d52568e81b880a43517049f2..ffc845b2cee600b336f0577ce67a7d9d72022329 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Factor\sout\sDB\sprotection\slift\sand\srestore\sin\sCLI
-D 2022-01-23T20:54:25.776
+C CLI\sprepared\sfor\sreading\sstring\sinput
+D 2022-01-24T00:22:06.344
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -553,7 +553,7 @@ F src/random.c 097dc8b31b8fba5a9aca1697aeb9fd82078ec91be734c16bffda620ced7ab83c
 F src/resolve.c 359bc0e445d427583d2ab6110433a5dc777f64a0ecdf8d24826d8b475233ead9
 F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92
 F src/select.c ab5717255420972e69b9b9ce4d1c4730fe82cfbdc14b7743e389a8bdb79ca027
-F src/shell.c.in 8c152178d813b1565d13e01a4e9f48a75185b11756dafc36c353aaff2fff68a8
+F src/shell.c.in e457581785607722cd12c79cbfe9e75b8385c194cf2705727b15c00b8870eb5a
 F src/sqlite.h.in 31c2c8d737814369bd3b71f3849c4a97ef7ede0aa3ce976ecb11632fa5f1f863
 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
 F src/sqlite3ext.h 5d54cf13d3406d8eb65d921a0d3c349de6126b732e695e79ecd4830ce86b4f8a
@@ -1941,8 +1941,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
 F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 8735caf13fc7e30da2fc5dc90921acbb3109f965c63dbf69fa70ef19c02308c0
-R 6253b464049656a2fb8c9361c4f1fbc9
+P 4462ed896459ee0312f1989d9a813c65150347ebdd15b59b2aa86bbce3abec1c
+R 4304075de837dc32a0991c68c10dfb6b
 U larrybr
-Z 54f5d49a44974e01c687a7b7befc32d9
+Z 3d97e11411e5c32cab39ea8a9a85a826
 # Remove this line to create a well-formed Fossil manifest.
index 5ff7000aa12ee61054f5deb8792934f9d82cb4ff..97851dc5f1be1bbbeb435e2b29790aad6f0c6a98 100644 (file)
@@ -1 +1 @@
-4462ed896459ee0312f1989d9a813c65150347ebdd15b59b2aa86bbce3abec1c
\ No newline at end of file
+073ded4d185d0133b07b4548dd78f4ad5eb17ce1f5c457d89fee23281420bbff
\ No newline at end of file
index d365a4ff80739707a702b72fa12caeafefd3f840..fbfb3c6a9d06e27453672db418f304907450ef5b 100644 (file)
@@ -677,6 +677,33 @@ static char *local_getline(char *zLine, FILE *in){
   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.
 **
@@ -689,13 +716,13 @@ static char *local_getline(char *zLine, FILE *in){
 **
 ** 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
@@ -1066,6 +1093,9 @@ struct EQPGraph {
   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.
@@ -1090,7 +1120,7 @@ struct ShellState {
   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 */
@@ -4491,7 +4521,8 @@ int deduceDatabaseType(const char *zName, int dfltZip){
 /*
 ** 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;
@@ -4501,7 +4532,7 @@ static unsigned char *readHexDb(ShellState *p, int *pnData){
   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];
@@ -4513,7 +4544,7 @@ static unsigned char *readHexDb(ShellState *p, int *pnData){
     }
     nLine = 0;
   }else{
-    in = p->in;
+    if( p->pInSource!=0 ) in = p->pInSource->inFile;
     nLine = p->lineno;
     if( in==0 ) in = stdin;
   }
@@ -4553,22 +4584,20 @@ static unsigned char *readHexDb(ShellState *p, int *pnData){
     }
   }
   *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);
@@ -9402,8 +9431,8 @@ static int do_meta_command(char *zLine, ShellState *p){
   }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");
@@ -9414,26 +9443,33 @@ static int do_meta_command(char *zLine, ShellState *p){
 #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 ){
@@ -10939,8 +10975,9 @@ static int line_is_complete(char *zSql, int nSql){
 
 /*
 ** 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;
 
@@ -10952,7 +10989,7 @@ static int runOneSqlLine(ShellState *p, char *zSql, FILE *in, int startline){
   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{
@@ -10998,16 +11035,18 @@ static int process_input(ShellState *p){
   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++;
@@ -11058,7 +11097,7 @@ static int process_input(ShellState *p){
       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);
@@ -11075,7 +11114,7 @@ static int process_input(ShellState *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);
@@ -11164,8 +11203,7 @@ static void process_sqliterc(
   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);
@@ -11178,19 +11216,25 @@ static void process_sqliterc(
     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);
 }
 
@@ -11356,6 +11400,7 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
 #endif
   char *zErrMsg = 0;
   ShellState data;
+  InSource inputSource = { stdin, 0, 0};
   const char *zInitFile = 0;
   int i;
   int rc = 0;
@@ -11882,7 +11927,7 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
 #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);
@@ -11890,7 +11935,7 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
         free(zHistory);
       }
     }else{
-      data.in = stdin;
+      data.pInSource = &inputSource; /* read from stdin without prompts */
       rc = process_input(&data);
     }
   }