- C Add\sCLI\s.x\scommand,\smake\sstring\sredirection\swork
- D 2022-01-24T04:21:20.922
-C Limit\sCLI\sinput\sredirect\snesting
-D 2022-01-24T06:36:16.156
++C Take\sCLI\sinput\sredirect\srecursion\slimit\sfrom\strunk
++D 2022-01-24T07:11:25.201
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
F src/resolve.c 359bc0e445d427583d2ab6110433a5dc777f64a0ecdf8d24826d8b475233ead9
F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92
F src/select.c ab5717255420972e69b9b9ce4d1c4730fe82cfbdc14b7743e389a8bdb79ca027
- F src/shell.c.in 3308232026d5b984fcbe6386915dae00d786de06013dfb398d25b1996eec2c0a
-F src/shell.c.in e80a140e92e342e2f92d405a77155c8e3a67c9b1d0bdbacb92885960cd4fc8f2
++F src/shell.c.in a97789adf08a352a98e8de2e225253e02b06535301c7e8c0d430fee15828ceaa
F src/sqlite.h.in 31c2c8d737814369bd3b71f3849c4a97ef7ede0aa3ce976ecb11632fa5f1f863
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/sqlite3ext.h 5d54cf13d3406d8eb65d921a0d3c349de6126b732e695e79ecd4830ce86b4f8a
F test/shell1.test 70f46b5d07776a107335c3c2c9cbd0431d44637bfeae1f6b9ded5e33b4c7c0bf
F test/shell2.test f00a0501c00583cbc46f7510e1d713366326b2b3e63d06d15937284171a8787c
F test/shell3.test cb4b835a901742c9719437a89171172ecc4a8823ad97349af8e4e841e6f82566
- F test/shell4.test 3ed6c4b42fd695efcbc25d69ef759dbb15855ca8e52ba6c5ee076f8b435f48be
-F test/shell4.test 8427e08751d4b16100fadb29f109cc1b8cce5c3858bdf34837c6e3b35fbbfee7
++F test/shell4.test d817597bb7f11f97ea86e4ccad0480c21183bcdc2083cd9de05a11303d9ee577
F test/shell5.test b85069bfcf3159b225228629ab2c3e69aa923d098fea8ea074b5dcd743522e2c
F test/shell6.test 1ceb51b2678c472ba6cf1e5da96679ce8347889fe2c3bf93a0e0fa73f00b00d3
F test/shell7.test 115132f66d0463417f408562cc2cf534f6bbc6d83a6d50f0072a9eb171bae97f
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
- P 073ded4d185d0133b07b4548dd78f4ad5eb17ce1f5c457d89fee23281420bbff
- R f62f785dd4d4b36cb5a7d1dd62c6a2c1
-P e4caf1e3932b1bd0dea072df7fc9458aed98c84ea397b6948b89292603949c41
-R 3ff059f17b79f35a7110343334a8c695
++P 2f2f1aaed691ba31ba70577012f785aae1f4a53ac7582bf30d26fbbec1eb3f3c 7a073931752d16ba71f1a606091461e427ca5ccf4d135d3c5141bfdd4e67e2d5
++R 2171c849337bd842c8b5ea7647d1f610
U larrybr
- Z c190fc10a0d856e1e83e9ea407a32719
-Z 22bca9d238f29be7cbeeb6418fbc3f83
++Z 86bfffa52bc0d70bd85c5a9f759d466b
# Remove this line to create a well-formed Fossil manifest.
return zLine;
}
- const char *zSourceSay; /* For complaints, keep a name for this source. */
+/*
+** 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} or {pF, 0}, (with
+** the iReadOffset always 0-initialized), 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. */
++ const char *zSourceSay; /* For complaints, keep a name for this source */
++ struct InSource *pFrom; /* and redirect tracking to aid unraveling. */
+} 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. With a rewrite,
+** it and local_getline can merge, saving most of 26 LOC. )
+*/
+static char *getline_from( char *zLine, InSource *pSource ){
+ if( pSource->inFile!=0 ){
+ return local_getline(zLine, pSource->inFile);
+ }else if( pSource->zStrIn!=0
+ && pSource->zStrIn[pSource->iReadOffset]!=0 ){
+ /* This code mostly copied from local_getline(); It begs for refactor. */
+ int nLine = zLine==0 ? 0 : 100;
+ int n = 0;
+
+ while( 1 ){
+ if( n+100>nLine ){
+ nLine = nLine*2 + 100;
+ zLine = realloc(zLine, nLine);
+ shell_check_oom(zLine);
+ }
+ {
+ /* This block is where fgets() became "read string". */
+ char *zBegin = pSource->zStrIn + pSource->iReadOffset;
+ int iTake = 0;
+ char c = zBegin[iTake];
+ if( c==0 ){
+ if( n==0 ){
+ free(zLine);
+ return 0;
+ }
+ zLine[n] = 0;
+ break;
+ }else{
+ while( iTake<nLine-n-1 && c!=0 ){
+ zLine[n+iTake++] = c;
+ if( c=='\n' ) break;
+ c = zBegin[iTake];
+ }
+ zLine[n+iTake] = 0;
+ pSource->iReadOffset += iTake;
+ }
+ }
+ /* Above block replaced this commented code: */
+ /* if( fgets(&zLine[n], nLine - n, in)==0 ){ */
+ /* if( n==0 ){ */
+ /* free(zLine); */
+ /* return 0; */
+ /* } */
+ /* zLine[n] = 0; */
+ /* break; */
+ /* } */
+ while( zLine[n] ) n++;
+ if( n>0 && zLine[n-1]=='\n' ){
+ n--;
+ if( n>0 && zLine[n-1]=='\r' ) n--;
+ zLine[n] = 0;
+ break;
+ }
+ }
+ return zLine;
+ }else{
+ return 0;
+ }
+}
+
/*
** Retrieve a single line of input text.
**
}
#endif /* !(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB) */
- InSource inSourceDivert = {0, zSubmit, 0, azArg[ia]};
+static int execute_variables(char *azArg[], int nArg, ShellState *p){
+ int ia, rc, nErrors = 0;
+ sqlite3_stmt *pStmt = 0;
+ open_db(p, 0);
+ if( p->db==0 ){
+ utf8_printf(stderr, ".x can only be done with a database open.\n");
+ return 1;
+ }
+ if( sqlite3_table_column_metadata(p->db, "TEMP", "sqlite_parameters",
+ "key", 0, 0, 0, 0, 0)!=SQLITE_OK ){
+ utf8_printf(stderr, "No temp.sqlite_parameters table exists.\n");
+ return 1;
+ }
+ rc = sqlite3_prepare_v2
+ (p->db, "SELECT value FROM temp.sqlite_parameters WHERE key=$1",
+ -1, &pStmt, 0);
+ if( rc!=SQLITE_OK ){
+ utf8_printf(stderr, "temp.sqlite_parameters is wrongly created.\n");
+ return 1;
+ }
+ for( ia=1; ia < nArg; ++ia ){
+ if( isalpha(azArg[ia][0]) ){
+ rc = sqlite3_reset(pStmt);
+ rc = sqlite3_bind_text(pStmt, 1, azArg[ia], -1, 0);
+ rc = sqlite3_step(pStmt);
+ if( rc==SQLITE_ROW ){
+ const unsigned char *zValue = sqlite3_column_text(pStmt, 0);
+ int nb = sqlite3_column_bytes(pStmt, 0);
+ /* If it's empty, just silently pretend to execute it. */
+ if( nb==0 ) continue;
+ while( IsSpace(zValue[nb-1]) ) --nb;
+ if( nb>0 ){
+ char *zSubmit = sqlite3_mprintf( "%.*s\n", nb, zValue );
++ InSource inSourceDivert =
++ {0, zSubmit, 0, azArg[ia], p->pInSource };
+ InSource *pInSrcSave = p->pInSource;
+ int savedLineno = p->lineno;
+ shell_check_oom(zSubmit);
+ p->pInSource = &inSourceDivert;
+ rc = process_input(p);
+ sqlite3_free(zSubmit);
+ p->pInSource = pInSrcSave;
+ p->lineno = savedLineno;
+ }else{
+ continue; /* All white, ignore. */
+ }
+ }else{
+ utf8_printf(stderr,
+ "Skipping parameter '%s' (not set.)\n", azArg[ia]);
+ ++nErrors;
+ }
+ }else{
+ utf8_printf(stderr,
+ "Skipping badly named %s. Run \".help x\"\n", azArg[ia]);
+ ++nErrors;
+ }
+ }
+ sqlite3_finalize(pStmt);
+ return nErrors>0;
+}
+
/*
** If an input line begins with "." then invoke this routine to
** process that line.
utf8_printf(stderr,"Error: cannot open \"%s\"\n", azArg[1]);
rc = 1;
}else{
- InSource inSourceDivert = {inUse, 0, 0, azArg[1]};
+ fCloser = fclose;
+ }
+ if( inUse!=0 ){
+ InSource *pInSrcSave = p->pInSource;
+ int savedLineno = p->lineno;
++ InSource inSourceDivert =
++ {inUse, 0, 0, azArg[1], p->pInSource};
+ 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 ){
int startline = 0; /* Line number for start of current input */
QuickScanState qss = QSS_Start; /* Accumulated line status (so far) */
- /* This will be more informative in a later version. */
- utf8_printf(stderr,"Input nesting limit (%d) reached at line %d."
- " Check recursion.\n", MAX_INPUT_NESTING, p->lineno);
+ if( p->inputNesting==MAX_INPUT_NESTING ){
++ InSource *pInSrc = p->pInSource;
++ utf8_printf
++ (stderr,
++ "Input nesting limit (%d) reached, from line %d of \"%s\",\n",
++ MAX_INPUT_NESTING, p->lineno-1, pInSrc->zSourceSay);
++ for( rc=0; rc<3 && (pInSrc=pInSrc->pFrom)!=0; ++rc )
++ utf8_printf(stderr, " from \"%s\"", pInSrc->zSourceSay);
++ utf8_printf(stderr, " ...\nCheck recursion.\n");
+ return 1;
+ }
+ ++p->inputNesting;
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 ){
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, sqliterc};
++ InSource inSourceDivert = {inUse, 0, 0, sqliterc, p->pInSource};
+ int rc;
+ p->pInSource = &inSourceDivert;
if( stdin_is_interactive ){
utf8_printf(stderr,"-- Loading resources from %s\n",sqliterc);
}