-C CLI\sprepared\sfor\sreading\sstring\sinput
-D 2022-01-24T00:22:06.344
+C Add\sCLI\s.x\scommand,\smake\sstring\sredirection\swork
+D 2022-01-24T04:21:20.922
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 e457581785607722cd12c79cbfe9e75b8385c194cf2705727b15c00b8870eb5a
+F src/shell.c.in 3308232026d5b984fcbe6386915dae00d786de06013dfb398d25b1996eec2c0a
F src/sqlite.h.in 31c2c8d737814369bd3b71f3849c4a97ef7ede0aa3ce976ecb11632fa5f1f863
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/sqlite3ext.h 5d54cf13d3406d8eb65d921a0d3c349de6126b732e695e79ecd4830ce86b4f8a
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 4462ed896459ee0312f1989d9a813c65150347ebdd15b59b2aa86bbce3abec1c
-R 4304075de837dc32a0991c68c10dfb6b
+P 073ded4d185d0133b07b4548dd78f4ad5eb17ce1f5c457d89fee23281420bbff
+R f62f785dd4d4b36cb5a7d1dd62c6a2c1
U larrybr
-Z 3d97e11411e5c32cab39ea8a9a85a826
+Z c190fc10a0d856e1e83e9ea407a32719
# Remove this line to create a well-formed Fossil manifest.
** 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.
+** 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. */
+ 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. */
} 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.)
+** 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 *zPrior, InSource *pSource ){
- char *zResult = 0;
+static char *getline_from( char *zLine, InSource *pSource ){
if( pSource->inFile!=0 ){
- zResult = local_getline(zPrior, pSource->inFile);
+ 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;
}
- return zResult;
}
/*
char *zPrompt;
char *zResult;
if( pInSrc!=0 ){
- zResult = local_getline(zPrior, pInSrc->inFile);
+ zResult = getline_from(zPrior, pInSrc);
}else{
zPrompt = isContinuation ? continuePrompt : mainPrompt;
#if SHELL_USE_LOCAL_GETLINE
".vfslist List all available VFSes",
".vfsname ?AUX? Print the name of the VFS stack",
".width NUM1 NUM2 ... Set minimum column widths for columnar output",
- " Negative values right-justify",
+ " Negative values right-justify",
+ ".x NAME ... Excecute content of some .param set variable(s)",
+ " Only variables whose name begins with a letter are eligible for this."
};
/* Like azHelp[], but for undocumented commands. */
}
#endif /* !(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB) */
+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]};
+ 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.
if( inUse!=0 ){
InSource *pInSrcSave = p->pInSource;
int savedLineno = p->lineno;
- InSource inSourceDivert = {inUse, 0, 0};
+ InSource inSourceDivert = {inUse, 0, 0, azArg[1]};
p->pInSource = &inSourceDivert;
rc = process_input(p);
assert(fCloser!=0);
}
}else
+ if( c=='x' && n==1 ){ /* "x" */
+ rc = execute_variables(azArg, nArg, p);
+ }else
+
{
utf8_printf(stderr, "Error: unknown command or invalid arguments: "
" \"%s\". Enter \".help\" for help\n", azArg[0]);
if( inUse!=0 ){
InSource *pInSrcSave = p->pInSource;
int savedLineno = p->lineno;
- InSource inSourceDivert = {inUse, 0, 0};
+ InSource inSourceDivert = {inUse, 0, 0, sqliterc};
int rc;
p->pInSource = &inSourceDivert;
if( stdin_is_interactive ){
#endif
char *zErrMsg = 0;
ShellState data;
- InSource inputSource = { stdin, 0, 0};
+ InSource inputSource = { stdin, 0, 0, "stdin"};
const char *zInitFile = 0;
int i;
int rc = 0;