".tcl ?FILES? Run a TCL REPL or interpret files as TCL\n";
case 1: return
" If FILES are provided, they name files to be read in as TCL.\n"
- " Otherwise, a read/evaluate/print loop is run until a lone \".\" is\n"
- " entered on an input line or end-of-stream is encountered.\n";
+ " Otherwise, a read/evaluate/print loop is run until a lone \".\"\n"
+ " is entered on an input line or end-of-stream is encountered.\n";
default: return 0;
}
}
static void copy_complaint(char **pzErr, Tcl_Interp *pi){
if( pzErr ){
Tcl_Obj *po = Tcl_GetObjResult(pi);
- *pzErr = sqlite3_mprintf("%s", Tcl_GetStringFromObj(po,0));
+ *pzErr = sqlite3_mprintf("%s\n", Tcl_GetStringFromObj(po,0));
}
}
"if {$line ne \".\"} {puts {}}\n"
"read stdin 0\n"
#else
- "set line {}\n"
- "set at_end 0\n"
- "set prompting [now_interactive]\n"
- "while {!$at_end} {\n"
- "if {$prompting} {\n"
- "if {$line!=\"\"} {\n"
- "puts -nonewline \"> \"\n"
+ "namespace eval ::REPL {\n"
+ "variable line {}\n"
+ "variable at_end 0\n"
+ "variable prompting [now_interactive]\n"
+ "}\n"
+ "while {!$::REPL::at_end} {\n"
+ "if {$::REPL::prompting} {\n"
+ "if {$::REPL::line!=\"\"} {\n"
+ "puts -nonewline \"...> \"\n"
"} else {\n"
- "puts -nonewline \"% \"\n"
+ "puts -nonewline \"tcl% \"\n"
"}\n"
"}\n"
"flush stdout\n"
- "set li [get_input_line]\n"
- "if {$li eq \"\"} {\n"
- "set at_end 1\n"
- "} elseif {[string trimright $li] eq \".\"} {\n"
- "if {$line ne \"\"} {\n"
+ "set ::REPL::li [get_input_line]\n"
+ "if {$::REPL::li eq \"\"} {\n"
+ "set ::REPL::at_end 1\n"
+ "} elseif {[string trimright $::REPL::li] eq \".\"} {\n"
+ "if {$::REPL::line ne \"\"} {\n"
"throw {NONE} {incomplete input at EOF}\n"
"}\n"
- "set at_end 1\n"
+ "set ::REPL::at_end 1\n"
"} else {\n"
- "append line $li\n"
- "if {[string trim $line] eq \"\"} {\n"
- "set line \"\"\n"
+ "append ::REPL::line $::REPL::li\n"
+ "if {[string trim $::REPL::line] eq \"\"} {\n"
+ "set ::REPL::line \"\"\n"
"continue\n"
"}\n"
- "if {[info complete $line]} {\n"
- "if {[catch {uplevel #0 $line} result]} {\n"
- "puts stderr \"Error: $result\"\n"
- "} elseif {$result!=\"\" && $prompting} {\n"
- "puts $result\n"
+ "if {[info complete $::REPL::line]} {\n"
+ "set ::REPL::rc [catch {uplevel #0 $::REPL::line} ::REPL::result]\n"
+ "if {$::REPL::rc == 0} {\n"
+ "if {$::REPL::result!=\"\" && $::REPL::prompting} {\n"
+ "puts $::REPL::result\n"
+ "}\n"
+ "} elseif {$::REPL::rc == 1} {\n"
+ "puts stderr \"Error: $::REPL::result\"\n"
+ "} elseif {$::REPL::rc == 2} {\n"
+ "set ::REPL::at_end 1\n"
"}\n"
- "set line {}\n"
+ "set ::REPL::line {}\n"
"}\n"
"}\n"
"}\n"
- "if {$prompting && $li ne \".\\n\"} {puts {}}\n"
- "unset li line prompting at_end\n"
+ "if {$::REPL::prompting && $::REPL::li ne \".\\n\"} {puts {}}\n"
+ "namespace delete ::REPL\n"
"read stdin 0\n"
#endif
;
#define UNKNOWN_RENAME "::_original_unknown"
/* C implementation of TCL ::unknown to delegate to dot commands */
-static int unknown_dot_delegate(void *pvSS, Tcl_Interp *interp,
+static int unknownDotDelegate(void *pvSS, Tcl_Interp *interp,
int nArgs, const char *azArgs[]){
const char *name = (nArgs>1 && *azArgs[1]=='.')? azArgs[1]+1 : 0;
ShellExState *psx = (ShellExState *)pvSS;
int ia, rc;
if( name ) pmc = pExtHelpers->findMetaCommand(name, psx, &nFound);
- if( pmc &&nFound==1 ){
+ if( pmc==(MetaCommand*)&tclcmd && nArgs==2 ){
+ /* Will not do a nested REPL, just silently semi-fake it. */
+ return TCL_OK;
+ }
+ if( pmc && nFound==1 ){
/* Run the dot command and interpret its returns. */
- char *zErr = 0;
- DotCmdRC drc = pmc->pMethods->argsCheck(pmc, &zErr, nArgs-1,
- (char **)azArgs+1);
- if( drc==DCR_Ok ){
- drc = pmc->pMethods->execute(pmc, psx, &zErr, nArgs-1,
- (char **)azArgs+1);
- }
- assert(!(drc==DCR_Ok && zErr!=0));
+ DotCmdRC drc = pExtHelpers->runMetaCommand(pmc, (char **)azArgs+1,
+ nArgs-1, psx);
if( drc==DCR_Ok ) return TCL_OK;
- else{
- /* ToDo: Try to indicate what went wrong as part of result.
- * This is deferred until some shell functionality helping
- * with this is factored out and exposed for extensions. */
- sqlite3_free(zErr);
+ else if( drc==DCR_Return ){
+ return TCL_RETURN;
+ }else{
+ Tcl_AppendResult(interp, "Execution of .", name, " failed.", 0);
return TCL_ERROR;
}
}else{
/* Defer to the TCL-default ::unknown command, or fail here. */
int haveUnkCmd = (0!=Tcl_FindCommand(interp, UNKNOWN_RENAME,
0, TCL_GLOBAL_ONLY));
- Tcl_Obj **ppo;
if( haveUnkCmd ){
- ppo = sqlite3_malloc((nArgs+1)*sizeof(Tcl_Obj*));
+ Tcl_Obj **ppo = sqlite3_malloc((nArgs+1)*sizeof(Tcl_Obj*));
if( ppo==0 ) return TCL_ERROR;
ppo[0] = Tcl_NewStringObj(UNKNOWN_RENAME, -1);
Tcl_IncrRefCount(ppo[0]);
"now_interactive", nowInteractive, psx, 0);
Tcl_Eval(tclcmd.interp, "rename unknown "UNKNOWN_RENAME);
Tcl_CreateCommand(tclcmd.interp,
- "unknown", unknown_dot_delegate, psx, 0);
+ "unknown", unknownDotDelegate, psx, 0);
pShExtLink->eid = sqlite3_tclshext_init;
}else{
TclCmd_Takedown(&tclcmd);
-C TCL\sshell\sextension\sdelegates\sto\sdot\scommands
-D 2022-03-24T12:49:05.311
+C Get\sshell\sTCL\sextension\smore\ssmoothly\sintegrated.
+D 2022-03-25T06:46:20.823
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
F ext/misc/spellfix.c 94df9bbfa514a563c1484f684a2df3d128a2f7209a84ca3ca100c68a0163e29f
F ext/misc/sqlar.c 0ace5d3c10fe736dc584bf1159a36b8e2e60fab309d310cd8a0eecd9036621b6
F ext/misc/stmt.c 35063044a388ead95557e4b84b89c1b93accc2f1c6ddea3f9710e8486a7af94a
-F ext/misc/tclshext.c.in 4c9e9c36877ea3a9bde62e4d4706e848fe0d56984e7ad36d5952de7f9d9cf308
+F ext/misc/tclshext.c.in d8f1a894edb7670341b8eb319686f4833f0d5545405c093d4d95b53966bbf5ff
F ext/misc/templatevtab.c 8a16a91a5ceaccfcbd6aaaa56d46828806e460dd194965b3f77bf38f14b942c4
F ext/misc/totype.c fa4aedeb07f66169005dffa8de3b0a2b621779fd44f85c103228a42afa71853b
F ext/misc/uint.c 053fed3bce2e89583afcd4bf804d75d659879bbcedac74d0fa9ed548839a030b
F src/resolve.c ea935b87d6fb36c78b70cdc7b28561dc8f33f2ef37048389549c7b5ef9b0ba5e
F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92
F src/select.c 4890a3cfee0bc60ff231c3a44db37968859ab0be156983dbcc0c096109832cdd
-F src/shell.c.in 840a4a72dcc39fafbcc82275babc77f928c3531cb5fe7217cb0a1596ef0a4555
-F src/shext_linkage.h 71b3600ba0e20f696fb226547e99413c67cfb27c5532701df16935e2a45c152a
+F src/shell.c.in 06593f6e93bbbcb5e58e29f1100ff1fa9e211642dc946d28ef1748be06383854
+F src/shext_linkage.h 511a218406b45240b3ad8a849a0898fac52ea64f7ad133548a9126d0f7d637cf
F src/sqlite.h.in 5845213799feca09cd69d18ff841a85fe0df31021f46aaa1797e703e80dc1d70
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/sqlite3ext.h f49e28c25bd941e79794db5415fdf7b202deb3bc072ed6f1ed273d578703684e
F src/test_rtree.c 671f3fae50ff116ef2e32a3bf1fe21b5615b4b7b
F src/test_schema.c f5d6067dfc2f2845c4dd56df63e66ee826fb23877855c785f75cc2ca83fd0c1b
F src/test_server.c a2615049954cbb9cfb4a62e18e2f0616e4dc38fe
-F src/test_shellext.c 0d07a78ac1487532f39ac93eafff0240e861f8f3430205af62b937136b6dbd49
+F src/test_shellext.c 6cbc7cbc4c1c55a747fcc8367fb9b45fe3d2d253e1b4235c8d4c4e6bd667b5ce
F src/test_sqllog.c 540feaea7280cd5f926168aee9deb1065ae136d0bbbe7361e2ef3541783e187a
F src/test_superlock.c 4839644b9201da822f181c5bc406c0b2385f672e
F src/test_syscall.c 1073306ba2e9bfc886771871a13d3de281ed3939
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P abf0316b3f58646974ab8e4d3e68896c9fc03bdd338eb7dc7b2f5d4de7365298
-R ce874ae1862d105669b12cd18d25e5bc
+P 353943108b36cabb3b9c745aa7f4d9a42cd100b7d0444373184b45cc1715837e
+R b9914f8d3b5384fdfccd2318410fb67e
U larrybr
-Z 4469eea4a17023c287722633d65da7c8
+Z 0021f50f48c3d55a3facb3cd03bb67af
# Remove this line to create a well-formed Fossil manifest.
#endif
/*
-** Do C-language style dequoting.
+** Do C-language style escape sequence translation.
**
** \a -> alarm
** \b -> backspace
static void setColumnWidths(ShellExState *p, char *azWidths[], int nWidths);
static MetaCommand * findMetaCommand(const char *, ShellExState *, int *);
+static DotCmdRC runMetaCommand(MetaCommand*, char *[], int na, ShellExState*);
static ExtensionHelpers extHelpers = {
- 10,
+ 11,
{
failIfSafeMode,
currentOutputFile,
currentInputSource,
strLineGet,
findMetaCommand,
+ runMetaCommand,
setColumnWidths,
nowInteractive,
shellInvokedAs,
/* This SQL function provides a way for a just-loaded shell extension to
* obtain a ShellExtensionLink pointer from the shell core while using
* the same sqlite3_load_extension API used for SQLite extensions.
- * This serves as an alternative to deriving the same pointer from
- * the pzErr argument passed into that API.
+ *
+ * (It is also useful for debugging a shell extension, as a breakpoint
+ * on it will be hit soon after loading and before real work is done.)
*/
static void shell_linkage(
sqlite3_context *context,
sqlite3_value **argv
){
int linkKind = 0;
+ void *pv;
if( argc>0 ){
linkKind = sqlite3_value_int(argv[0]);
}
switch (linkKind){
case 0:
- sqlite3_result_pointer(context, sqlite3_user_data(context),
- SHELLEXT_API_POINTERS, 0);
+ pv = sqlite3_user_data(context);
+ break;
+ case 1:
+ pv = &extHelpers;
+ break;
+ case 2:
+ pv = &shellExtAPI;
break;
default:
- sqlite3_result_null(context);
+ pv = 0;
}
+ if( pv==0 ) sqlite3_result_null(context);
+ else sqlite3_result_pointer(context, pv, SHELLEXT_API_POINTERS, 0);
}
#ifndef SHELL_DB_FILE
ScriptHooks shSave = psi->scripting;
ExtensionId siSave = psi->scriptXid;
int rc;
+
+ if( pzErr ) *pzErr = 0;
if( psx->dbShell==0 ){
rc = begin_db_dispatch(psx);
if( rc!=SQLITE_OK ) return rc;
psi->scriptXid = siSave;
}
psi->ixExtPending = 0;
- return rc!=SQLITE_OK;
+ if( rc!=SQLITE_OK ){
+ if( rc==SQLITE_MISUSE && pzErr!=0 ){
+ *pzErr = sqlite3_mprintf("extension id mismatch %z\n", *pzErr);
+ }
+ rc = SQLITE_ERROR;
+ }
+ return rc;
}
#endif
}
}
-/*****************
-** Command dispatcher
-** After successful command lookup and (simple) argument checking,
-** invoke the found MetaCommand with the input arguments (except
-** that azArg[0] is replaced with the properly spelled command name.)
-** The return is either a dispatch error or whatever the dispatched
-** MetaCommand returns.
-*/
-static DotCmdRC dispatchCommand(char *azArg[], int nArg,
- ShellExState *psx, char **pzErr){
- const char *cmdName = azArg[0];
- int nFound = 0;
- DotCmdRC argsCheck;
- MetaCommand *pMC = findMetaCommand(cmdName, psx, &nFound);
- if( 0==pMC || nFound>1 ) return (nFound>1)? DCR_Ambiguous: DCR_Unknown;
- argsCheck = pMC->pMethods->argsCheck(pMC, pzErr, nArg, azArg);
- if( argsCheck!=DCR_Ok ) return argsCheck;
- /* Replace any user-shortened command name with its whole name. */
- azArg[0] = (char *)(pMC->pMethods->name(pMC));
- return pMC->pMethods->execute(pMC, psx, pzErr, nArg, azArg);
-}
-
/*
** Output primary (single-line) help for a known command.
*/
return npm;
}
-/*
-** If an input line or line group begins with "." then invoke this routine
-** to process that line.
-**
-** Return sanitized DotCmdRC values, with invocation error codes
-** translated to DCR_Error, so that only these 8 returns are possible:
-** DCR_Ok, DCR_Return, DCR_Exit or DCR_Abort possibly or'ed with DCR_Error.
-*/
-static DotCmdRC do_meta_command(char *zLine, ShellExState *psx){
- int h = 1;
- int nArg = 0;
- char *azArg[52];
- char *zErr = 0;
- DotCmdRC dispatchResult;
-#if SHELL_VARIABLE_EXPANSION
- int ncLineIn = strlen30(zLine);
- u8 bExpVars = SHEXT_VAREXP(ISS(psx));
-#endif
-
+/* Perform preparation needed prior to actually running any dot command. */
+static void command_prep(ShellInState *psi){
+ clearTempFile(psi);
#ifndef SQLITE_OMIT_VIRTUALTABLE
- if( ISS(psx)->expert.pExpert ){
- expertFinish(ISS(psx), 1, 0);
+ if( psi->expert.pExpert ){
+ expertFinish(psi, 1, 0);
}
#endif
+}
- /* Parse the input line into tokens.
- */
- while( zLine[h] && nArg<ArraySize(azArg)-1 ){
- while( IsSpace(zLine[h]) ){ h++; }
- if( zLine[h]==0 ) break;
- if( zLine[h]=='\'' || zLine[h]=='"' ){
- int delim = zLine[h++];
- azArg[nArg++] = &zLine[h];
- while( zLine[h] && zLine[h]!=delim ){
- if( zLine[h]=='\\' && delim=='"' && zLine[h+1]!=0 ) h++;
- h++;
- }
- if( zLine[h]==delim ){
- zLine[h++] = 0;
- }
- if( delim=='"' ) resolve_backslashes(azArg[nArg-1]);
- }else{
- azArg[nArg++] = &zLine[h];
- while( zLine[h] && !IsSpace(zLine[h]) ){ h++; }
- if( zLine[h] ) zLine[h++] = 0;
- resolve_backslashes(azArg[nArg-1]);
- }
+/* Perform post-execution actions needed after running any dot command. */
+static void command_post(ShellInState *psi){
+ if( psi->outCount ){
+ psi->outCount--;
+ if( psi->outCount==0 ) output_reset(psi);
}
- azArg[nArg] = 0;
-
- /* Process the input line.
- */
- if( nArg==0 ) return DCR_Ok; /* no tokens, no error, done */
-
- clearTempFile(ISS(psx));
+ updateSafeMode(psi);
+}
- dispatchResult = dispatchCommand(azArg, nArg, psx, &zErr);
+/* Issue errors per returned DotCmdRC and error message, handle certain
+ * exceptional returns, and translate return to the sanitized first 8.
+ */
+static DotCmdRC meta_command_errors(char *zErr, char *azArg[], int nArg,
+ DotCmdRC dcr, ShellExState *psx){
if( psx->shellAbruptExit!=0 ){
- if( psx->shellAbruptExit>0x1ff ) dispatchResult = DCR_AbortError;
- else dispatchResult = DCR_Exit | (dispatchResult&DCR_Error);
+ if( psx->shellAbruptExit>0x1ff ) dcr = DCR_AbortError;
+ else dcr = DCR_Exit | (dcr & DCR_Error);
}
- if( dispatchResult==DCR_CmdErred ){
+ if( dcr==DCR_CmdErred ){
/* Error message(s) already emitted. Just translate to execute error. */
- dispatchResult = DCR_Error;
- }else if( dispatchResult==DCR_SayUsage ){
+ dcr = DCR_Error;
+ }else if( dcr==DCR_SayUsage ){
if( zErr ){
utf8_printf(STD_ERR, "%s", zErr);
}else{
utf8_printf(STD_ERR, "Usage:\n");
showPrimaryHelp(STD_ERR, azArg[0], psx);
}
- dispatchResult = DCR_Error;
- }else if( dispatchResult > DCR_AbortError ){
+ dcr = DCR_Error;
+ }else if( dcr > DCR_AbortError ){
/* Handle invocation errors. */
- int ia = dispatchResult & DCR_ArgIxMask;
+ int ia = dcr & DCR_ArgIxMask;
const char *pArg1st = (ia>=nArg)? "" : azArg[ia];
const char *pArg2nd = 0;
- int ec = dispatchResult & ~DCR_ArgIxMask;
+ int ec = dcr & ~DCR_ArgIxMask;
int unknownCmd = 0;
const char *z = 0;
switch( ec ){
z = "?";
break;
}
- if( zErr==0 ){
+ if( !zErr ){
if( z!=0 ){
- zErr = smprintf("Error: %z\n", smprintf(z, pArg1st, pArg2nd));
- utf8_printf(STD_ERR, "%s", zErr);
+ char *ze = smprintf("Error: %z\n", smprintf(z, pArg1st, pArg2nd));
+ utf8_printf(STD_ERR, "%s", ze);
+ sqlite3_free(ze);
}
}else{
const char *fmt
showPrimaryHelp(STD_ERR, azArg[0], psx);
}
}
- /* If the shell DB is messed up, at least .quit will be doable. */
+ /* If the shell DB becomes messed up, at least .quit will be doable. */
if( unknownCmd && psx->dbShell!=0
&& sqlite3_strnicmp(azArg[0],"quit",strlen30(azArg[0]))==0 ){
- dispatchResult = DCR_Return;
+ dcr = DCR_Return;
}else{
- dispatchResult = DCR_Error;
+ dcr = DCR_Error;
}
}else{
/* Handle execution errors. */
- if( dispatchResult==DCR_AbortError ){
- if( zErr!=0 ){
+ if( dcr==DCR_AbortError ){
+ if( zErr ){
utf8_printf(STD_ERR, "Error: \".%s\" may not %s in -safe mode\n",
azArg[0], zErr);
}else {
}
psx->shellAbruptExit = 0x203;
}else{
- int error = dispatchResult & DCR_Error;
- int action = dispatchResult & ~DCR_Error;
+ int error = dcr & DCR_Error;
+ int action = dcr & ~DCR_Error;
if( error ){
- if( zErr!=0 ){
+ if( zErr ){
const char *fmt
= (sqlite3_strnicmp(zErr, "Error", 5)==0)? "%s" : "Error: %s";
utf8_printf(STD_ERR, fmt, zErr);
}
}
}
- if( zErr ) sqlite3_free(zErr);
- if( ISS(psx)->outCount ){
- ISS(psx)->outCount--;
- if( ISS(psx)->outCount==0 ) output_reset(ISS(psx));
+ return dcr;
+}
+
+/* Argument-check and execute a found MetaCommand, wrapping execution
+ * with command_{prep,post}(...), and issue errors as made evident.
+ * Return one of the "Post-execute action and success/error status"
+ * codes from the DotCmdRC enum.
+ *
+ * Note that this function is exposed for shell extensions to use.
+ *
+ * This should be called for "top-level" dot command execution only.
+ * Should an extension wrap or use a MetaCommand object to effect its
+ * own functionality, that object's execute() method should be called
+ * directly, without going through this function.
+ */
+static DotCmdRC runMetaCommand(MetaCommand *pmc, char *azArg[], int nArg,
+ ShellExState *psx){
+ char *arg0 = azArg[0];
+ char *zErr = 0;
+ DotCmdRC dcr = pmc->pMethods->argsCheck(pmc, &zErr, nArg, azArg);
+
+ command_prep(ISS(psx));
+ azArg[0] = (char *)(pmc->pMethods->name(pmc));
+ if( dcr==DCR_Ok ){
+ dcr = pmc->pMethods->execute(pmc, psx, &zErr, nArg, azArg);
+ }
+ if( dcr!=DCR_Ok ){
+ dcr = meta_command_errors(zErr, azArg, nArg, dcr, psx);
+ }
+ azArg[0] = arg0;
+ sqlite3_free(zErr);
+ command_post(ISS(psx));
+ return dcr;
+}
+
+/*
+** If an input line or line group begins with "." then invoke this routine
+** to process that line.
+**
+** Returns sanitized DotCmdRC values, with invocation error codes
+** translated to DCR_Error, so that only these 8 returns are possible:
+** DCR_Ok, DCR_Return, DCR_Exit or DCR_Abort possibly or'ed with DCR_Error.
+**
+** Any applicable error messages are issued along with output messages.
+*/
+static DotCmdRC do_meta_command(char *zLine, ShellExState *psx){
+ int h = 1; /* Passing over leading '.' */
+ int nArg = 0;
+ char *azArg[52];
+ DotCmdRC dcr = DCR_Ok;
+#if SHELL_VARIABLE_EXPANSION
+ int ncLineIn = strlen30(zLine);
+ u8 bExpVars = SHEXT_VAREXP(ISS(psx));
+#endif
+
+ /* Parse the input line into tokens which are 0-terminated and left in-place.
+ */
+ while( zLine[h] && nArg<ArraySize(azArg)-1 ){
+ /* Future: Complain if this fixed argument count limit is hit. */
+ while( IsSpace(zLine[h]) ){ h++; }
+ if( zLine[h]==0 ) break;
+ if( zLine[h]=='\'' || zLine[h]=='"' ){
+ int delim = zLine[h++];
+ azArg[nArg++] = &zLine[h];
+ while( zLine[h] && zLine[h]!=delim ){
+ if( zLine[h]=='\\' && delim=='"' && zLine[h+1]!=0 ) h++;
+ h++;
+ }
+ if( zLine[h]==delim ){
+ zLine[h++] = 0;
+ }
+ if( delim=='"' ) resolve_backslashes(azArg[nArg-1]);
+ }else{
+ azArg[nArg++] = &zLine[h];
+ while( zLine[h] && !IsSpace(zLine[h]) ){ h++; }
+ if( zLine[h] ) zLine[h++] = 0;
+ resolve_backslashes(azArg[nArg-1]);
+ }
+ }
+ azArg[nArg] = 0; /* No code here relies on this, but some extension might. */
+
+ /* Process the input line. If it was empty, do nothing and declare success.
+ * Note that "empty" includes a leading '.' followed by nothing else.
+ */
+ if( nArg>0 ){
+ int nFound;
+ MetaCommand *pmc = findMetaCommand(azArg[0], psx, &nFound);
+ if( pmc==0 || nFound>1 ){
+ dcr = (nFound>1)? DCR_Ambiguous: DCR_Unknown;
+ /* Issue error for an unknown or inadequately specified dot command. */
+ dcr = meta_command_errors(0, azArg, nArg, dcr, psx);
+ }
+ else{
+ /* Run found command and issue or handle any errors it may report. */
+ dcr = runMetaCommand(pmc, azArg, nArg, psx);
+ }
}
- updateSafeMode(ISS(psx));
+
#if SHELL_VARIABLE_EXPANSION
if( bExpVars ){
/* Free any arguments that are allocated rather than tokenized in place. */
}
}
#endif
- return dispatchResult;
+ return dcr;
}
/* Line scan result and intermediate states (supporting scan resumption)