** the caller of the shell's main, "do shell things" entry point.
**
** It is an error, (perhaps with only minor effect such as memory leak),
-** for a meta-command to call this function while it holds resources.
+** for a meta-command to call this function while it holds resources in
+** need of freeing. Instead, it should be called before acquiring them.
**
** The return is true if failing, 0 otherwise.
*/
/*
** Parse the command line for an ".ar" command. The results are written into
-** structure (*pAr). SQLITE_OK is returned if the command line is parsed
-** successfully, otherwise an error message is written to stderr and
-** SQLITE_ERROR returned.
+** structure (*pAr). DCR_Ok is returned if the command line is parsed
+** successfully, otherwise an error message is written to stderr and an
+** appropriate DCR_* argument error is returned.
*/
-static int arParseCommand(
+static DotCmdRC arParseCommand(
char **azArg, /* Array of arguments passed to dot command */
int nArg, /* Number of entries in azArg[] */
ArCommand *pAr /* Populate this object */
};
int nSwitch = sizeof(aSwitch) / sizeof(struct ArSwitch);
struct ArSwitch *pEnd = &aSwitch[nSwitch];
+ DotCmdRC rv = DCR_Ok;
if( nArg<=1 ){
utf8_printf(STD_ERR, "Error: Wrong number of arguments to \"%s\".\n",
azArg[0]);
if( stdin_is_interactive ){
utf8_printf(STD_ERR, "Usage:\n");
- return arUsage(STD_ERR, pAr);
+ arUsage(STD_ERR, pAr);
+ return DCR_TooFew;
}
}else{
char *z = azArg[1];
if( z[i]==pOpt->cShort ) break;
}
if( pOpt==pEnd ){
- return arErrorMsg(pAr, "unrecognized option: %c", z[i]);
+ arErrorMsg(pAr, "unrecognized option: %c", z[i]);
+ return DCR_Unknown|i;
}
if( pOpt->bArg ){
if( iArg>=nArg ){
- return arErrorMsg(pAr, "option requires an argument: %c",z[i]);
+ arErrorMsg(pAr, "option requires an argument: %c",z[i]);
+ return DCR_Unpaired|i;
}
zArg = azArg[iArg++];
}
- if( arProcessSwitch(pAr, pOpt->eSwitch, zArg) ) return SQLITE_ERROR;
+ rv = arProcessSwitch(pAr, pOpt->eSwitch, zArg);
+ if( rv!=DCR_Ok ) return rv;
}
pAr->nArg = nArg-iArg;
if( pAr->nArg>0 ){
if( z[i]==pOpt->cShort ) break;
}
if( pOpt==pEnd ){
- return arErrorMsg(pAr, "unrecognized option: %c", z[i]);
+ arErrorMsg(pAr, "unrecognized option: %c", z[i]);
+ return DCR_Unknown|iArg;
}
if( pOpt->bArg ){
if( i<(n-1) ){
i = n;
}else{
if( iArg>=(nArg-1) ){
- return arErrorMsg(pAr, "option requires an argument: %c",
- z[i]);
+ arErrorMsg(pAr, "option requires an argument: %c", z[i]);
+ return DCR_Unpaired|iArg;
}
zArg = azArg[++iArg];
}
}
- if( arProcessSwitch(pAr, pOpt->eSwitch, zArg) ) return SQLITE_ERROR;
+ rv = arProcessSwitch(pAr, pOpt->eSwitch, zArg);
+ if( rv!=DCR_Ok ) return rv;
}
}else if( z[2]=='\0' ){
/* A -- option, indicating that all remaining command line words
const char *zLong = pOpt->zLong;
if( (n-2)<=strlen30(zLong) && 0==memcmp(&z[2], zLong, n-2) ){
if( pMatch ){
- return arErrorMsg(pAr, "ambiguous option: %s",z);
+ arErrorMsg(pAr, "ambiguous option: %s",z);
+ return DCR_Ambiguous|iArg;
}else{
pMatch = pOpt;
}
}
if( pMatch==0 ){
- return arErrorMsg(pAr, "unrecognized option: %s", z);
+ arErrorMsg(pAr, "unrecognized option: %s", z);
+ return DCR_Unknown|iArg;
}
if( pMatch->bArg ){
if( iArg>=(nArg-1) ){
- return arErrorMsg(pAr, "option requires an argument: %s", z);
+ arErrorMsg(pAr, "option requires an argument: %s", z);
+ return DCR_Unpaired|iArg;
}
zArg = azArg[++iArg];
}
/*
** Implementation of ".ar" dot command.
*/
-static int arDotCommand(
+static DotCmdRC arDotCommand(
ShellExState *pState, /* Current shell tool state */
int fromCmdLine, /* True if -A command-line option, not .ar cmd */
char **azArg, /* Array of arguments passed to dot command */
int nArg /* Number of entries in azArg[] */
){
ArCommand cmd;
+ DotCmdRC rv;
int rc;
memset(&cmd, 0, sizeof(cmd));
cmd.fromCmdLine = fromCmdLine;
- rc = arParseCommand(azArg, nArg, &cmd);
+ rv = arParseCommand(azArg, nArg, &cmd);
cmd.out = currentOutputFile(pState);
- if( rc==SQLITE_OK ){
+ if( rv==DCR_Ok ){
int eDbType = SHELL_OPEN_UNSPEC;
cmd.p = pState;
cmd.db = DBX(pState);
}
sqlite3_free(cmd.zSrcTable);
- return rc;
+ return (rv!=DCR_Ok)? rv : (DCR_Ok|(rc!=0));
}
/* End of the ".archive" or ".ar" command logic
*******************************************************************************/
}
#endif /* !(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB) */
-static int writeDb( char *azArg[], int nArg, ShellExState *psx, char **pzErr ){
+static DotCmdRC
+writeDb( char *azArg[], int nArg, ShellExState *psx, char **pzErr ){
int rc = 0;
const char *zDestFile = 0;
const char *zDb = 0;
int j;
int bAsync = 0;
const char *zVfs = 0;
- if( ISS(psx)->bSafeMode ) return SHELL_FORBIDDEN_OP;
+ if( ISS(psx)->bSafeMode ) return DCR_AbortError;
for(j=1; j<nArg; j++){
const char *z = azArg[j];
if( z[0]=='-' ){
}else
{
utf8_printf(STD_ERR, "unknown option: %s\n", azArg[j]);
- return SHELL_INVALID_ARGS;
+ return DCR_Unknown|j;
}
}else if( zDestFile==0 ){
zDestFile = azArg[j];
zDb = zDestFile;
zDestFile = azArg[j];
}else{
- return SHELL_INVALID_ARGS;
+ return DCR_TooMany|j;
}
}
if( zDestFile==0 ){
- return SHELL_INVALID_ARGS;
+ return DCR_Missing;
}
if( zDb==0 ) zDb = "main";
rc = sqlite3_open_v2(zDestFile, &pDest,
if( rc!=SQLITE_OK ){
utf8_printf(STD_ERR, "Error: cannot open \"%s\"\n", zDestFile);
close_db(pDest);
- return 1;
+ return DCR_Error;
}
if( bAsync ){
sqlite3_exec(pDest, "PRAGMA synchronous=OFF; PRAGMA journal_mode=OFF;",
rc = 1;
}
close_db(pDest);
- return rc;
+ return DCR_Ok|rc;
}
/*
static int someCommand(char *azArg[], int nArg, ShellExState *p, char **pzErr);
*/
DISPATCH_CONFIG[
- RETURN_TYPE=int
+ RETURN_TYPE=DotCmdRC
STORAGE_CLASS=static
ARGS_SIGNATURE=char *$arg4\[\], int $arg5, ShellExState *$arg6, char **$arg7
DISPATCH_ENTRY={ "$cmd", ${cmd}Command, $arg1, $arg2, $arg3 },
",seeargs Echo arguments suffixed with |",
];
DISPATCHABLE_COMMAND( seeargs ? 0 0 azArg nArg p ){
- int rc = 0;
- for (rc=1; rc<nArg; ++rc)
- raw_printf(ISS(p)->out, "%s%s", azArg[rc], (rc==nArg-1)? "|\n" : "|");
- return 0;
+ int ia = 0;
+ for (ia=1; ia<nArg; ++ia)
+ raw_printf(ISS(p)->out, "%s%s", azArg[ia], (ia==nArg-1)? "|\n" : "|");
+ return DCR_Ok;
}
CONDITION_COMMAND(archive !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB));
];
DISPATCHABLE_COMMAND( archive ? 0 0 azArg nArg p ){
open_db(p, 0);
- if( ISS(p)->bSafeMode ) return SHELL_FORBIDDEN_OP;
+ if( ISS(p)->bSafeMode ) return DCR_AbortError;
return arDotCommand(p, 0, azArg, nArg);
}
".auth ON|OFF Show authorizer callbacks",
];
DISPATCHABLE_COMMAND( auth 3 2 2 azArg nArg p ){
- int rc = 0;
open_db(p, 0);
if( booleanValue(azArg[1]) ){
sqlite3_set_authorizer(DBX(p), shellAuth, p);
}else{
sqlite3_set_authorizer(DBX(p), 0, 0);
}
- return rc;
+ return DCR_Ok;
}
/*****************
];
DISPATCHABLE_COMMAND( bail 3 2 2 ){
bail_on_error = booleanValue(azArg[1]);
- return 0;
+ return DCR_Ok;
}
/*****************
}else{
setTextMode(ISS(p)->out, 1);
}
- return 0;
+ return DCR_Ok;
}
DISPATCHABLE_COMMAND( cd ? 2 2 ){
int rc=0;
- if( ISS(p)->bSafeMode ) return SHELL_FORBIDDEN_OP;
+ if( ISS(p)->bSafeMode ) return DCR_AbortError;
#if defined(_WIN32) || defined(WIN32)
wchar_t *z = sqlite3_win32_utf8_to_unicode(azArg[1]);
rc = !SetCurrentDirectoryW(z);
utf8_printf(STD_ERR, "Cannot change to directory \"%s\"\n", azArg[1]);
rc = 1;
}
- return rc;
+ return DCR_Ok|rc;
}
/* The undocumented ".breakpoint" command causes a call
*/
DISPATCHABLE_COMMAND( breakpoint 3 1 1 ){
test_breakpoint();
- return 0;
+ return DCR_Ok;
}
/*****************
];
DISPATCHABLE_COMMAND( changes 3 2 2 ){
setOrClearFlag(p, SHFLG_CountChanges, azArg[1]);
- return 0;
+ return DCR_Ok;
}
DISPATCHABLE_COMMAND( check 3 0 0 ){
/* Cancel output redirection, if it is currently set (by .testcase)
** azArg[1]. If there are differences, report an error and exit.
*/
char *zRes = 0;
- int rc=0;
+ int rc = 0;
+ DotCmdRC rv = DCR_Ok;
output_reset(ISS(p));
if( nArg!=2 ){
- return SHELL_INVALID_ARGS;
+ return DCR_ArgError;
}else if( (zRes = readFile("testcase-out.txt", 0))==0 ){
*pzErr = shellMPrintf(&rc, "Error: cannot read 'testcase-out.txt'");
- rc = 2;
+ rv = DCR_Return;
}else if( testcase_glob(azArg[1],zRes)==0 ){
*pzErr =
shellMPrintf(&rc,
"testcase-%s FAILED\n Expected: [%s]\n Got: [%s]\n",
ISS(p)->zTestcase, azArg[1], zRes);
- rc = 1;
+ rv = DCR_Error;
}else{
utf8_printf(STD_OUT, "testcase-%s ok\n", ISS(p)->zTestcase);
ISS(p)->nCheck++;
}
sqlite3_free(zRes);
- return rc;
+ return (rc==SQLITE_NOMEM)? DCR_Abort : rv;
}
DISPATCHABLE_COMMAND( clone ? 2 2 ){
- if( ISS(p)->bSafeMode ) return SHELL_FORBIDDEN_OP;
+ if( ISS(p)->bSafeMode ) return DCR_AbortError;
tryToClone(p, azArg[1]);
- return 0;
+ return DCR_Ok;
}
DISPATCHABLE_COMMAND( connection ? 1 4 ){
ShellInState *psi = ISS(p);
/* No-op */
}else if( psi->pAuxDb == &psi->aAuxDb[i] ){
raw_printf(STD_ERR, "cannot close the active database connection\n");
- return 1;
+ return DCR_Error;
}else if( psi->aAuxDb[i].db ){
session_close_all(psi, i);
close_db(psi->aAuxDb[i].db);
psi->aAuxDb[i].db = 0;
}
}else{
- return SHELL_INVALID_ARGS;
+ return DCR_ArgError;
}
- return 0;
+ return DCR_Ok;
}
/*****************
free(azName[i*2+1]);
}
sqlite3_free(azName);
- return rc;
+ return DCR_Ok|(rc!=0);
}
DISPATCHABLE_COMMAND( dbconfig 3 1 3 ){
static const struct DbConfigChoices {
("Error: unknown dbconfig \"%s\"\n"
"Enter \".dbconfig\" with no arguments for a list\n",
azArg[1]);
- return 1;
+ return DCR_ArgError;
}
- return 0;
+ return DCR_Ok;
}
DISPATCHABLE_COMMAND( dbinfo 3 1 2 ){
return shell_dbinfo_command(p, nArg, azArg);
("The --preserve-rowids option is not compatible"
" with SQLITE_OMIT_VIRTUALTABLE\n");
sqlite3_free(zLike);
- return 1;
+ return DCR_ArgError;
#else
ShellSetFlag(p, SHFLG_PreserveRowid);
#endif
*pzErr = sqlite3_mprintf
("Unknown option \"%s\" on \".dump\"\n", azArg[i]);
sqlite3_free(zLike);
- return 1;
+ return DCR_ArgError;
}
}
}else{
psi->showHeader = savedShowHeader;
psi->shellFlgs = savedShellFlags;
- return 0;
+ return DCR_Ok;
}
DISPATCHABLE_COMMAND( echo ? 2 2 ){
setOrClearFlag(p, SHFLG_Echo, azArg[1]);
- return 0;
+ return DCR_Ok;
}
DISPATCHABLE_COMMAND( eqp ? 0 0 ){
ShellInState *psi = ISS(p);
psi->autoEQP = (u8)booleanValue(azArg[1]);
}
}else{
- return SHELL_INVALID_ARGS;
+ return DCR_ArgError;
}
+ return DCR_Ok;
}
/*****************
int rc;
if( nArg>1 && (rc = (int)integerValue(azArg[1]))!=0 )
p->shellAbruptExit = rc;
- return 2;
+ return DCR_Return;
}
DISPATCHABLE_COMMAND( quit 1 1 0 ){
- return 2;
+ return DCR_Return;
}
/*****************
DISPATCHABLE_COMMAND( expert ? 1 1 ){
open_db(p, 0);
expertDotCommand(ISS(p), azArg, nArg);
- return 0;
+ return DCR_Ok;
}
DISPATCHABLE_COMMAND( explain ? 1 2 ){
/* The ".explain" command is automatic now. It is largely
if( psi->mode==MODE_Explain ) psi->mode = psi->normalMode;
psi->autoExplain = 1;
}
- return 0;
+ return DCR_Ok;
}
/*****************
" -e Send output to the system text editor",
" -x Send output as CSV to a spreadsheet (same as \".excel\")",
];
-static int outputRedirs(char *[], int, ShellInState *,
- char **pzErr, int bOnce, int eMode);
-DISPATCHABLE_COMMAND( excel ? 1 2 ){
- return outputRedirs(azArg, nArg, ISS(p), pzErr, 2, 'x');
-}
-DISPATCHABLE_COMMAND( once ? 1 6 ){
- return outputRedirs(azArg, nArg, ISS(p), pzErr, 1, 0);
-}
-DISPATCHABLE_COMMAND( output ? 1 6 ){
- return outputRedirs(azArg, nArg, ISS(p), pzErr, 0, 0);
-}
-
-static int outputRedirs(char *azArg[], int nArg, ShellInState *psi,
- char **pzErr, int bOnce, int eMode){
+/* Shared implementation of .excel, .once and .output */
+static DotCmdRC outputRedirs(char *azArg[], int nArg,
+ ShellInState *psi, char **pzErr,
+ int bOnce, int eMode){
/* bOnce => 0: .output, 1: .once, 2: .excel */
/* eMode => 'x' for excel, else 0 */
int rc = 0;
int bTxtMode = 0;
int i;
int bBOM = 0;
- if( psi->bSafeMode ) return SHELL_FORBIDDEN_OP;
+ if( psi->bSafeMode ) return DCR_AbortError;
for(i=1; i<nArg; i++){
char *z = azArg[i];
if( z[0]=='-' ){
eMode = 'e'; /* text editor */
}else{
*pzErr = shellMPrintf(0," unknown option: \"%s\"\n",azArg[i]);
- return SHELL_INVALID_ARGS;
+ return DCR_Unknown|i;
}
}else if( zFile==0 && eMode!='e' && eMode!='x' ){
zFile = sqlite3_mprintf("%s", z);
}else{
*pzErr = shellMPrintf(0," excess argument: \"%s\"\n", azArg[i]);
sqlite3_free(zFile);
- return SHELL_INVALID_ARGS;
+ return DCR_TooMany|i;
}
}
if( zFile==0 ){
}
}
sqlite3_free(zFile);
- return rc;
+ return DCR_Ok|rc;
+}
+DISPATCHABLE_COMMAND( excel ? 1 2 ){
+ return outputRedirs(azArg, nArg, ISS(p), pzErr, 2, 'x');
+}
+DISPATCHABLE_COMMAND( once ? 1 6 ){
+ return outputRedirs(azArg, nArg, ISS(p), pzErr, 1, 0);
+}
+DISPATCHABLE_COMMAND( output ? 1 6 ){
+ return outputRedirs(azArg, nArg, ISS(p), pzErr, 0, 0);
}
utf8_printf(psi->out, " .filectrl %s %s\n",
aCtrl[i].zCtrlName, aCtrl[i].zUsage);
}
- return 1;
+ return DCR_ArgError;
}
/* Convert filectrl text option to value. Allow any
}else{
utf8_printf(STD_ERR, "Error: ambiguous file-control: \"%s\"\n"
"Use \".filectrl --help\" for help\n", zCmd);
- return 1;
+ return DCR_ArgError;
}
}
}
}
if( isOk==0 && iCtrl>=0 ){
utf8_printf(psi->out, "Usage: .filectrl %s %s\n", zCmd,aCtrl[iCtrl].zUsage);
- return 1;
+ return DCR_ArgError;
}else if( isOk==1 ){
char zBuf[100];
sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld", iRes);
raw_printf(psi->out, "%s\n", zBuf);
}
- return 0;
+ return DCR_Ok;
}
DISPATCHABLE_COMMAND( fullschema ? 1 2 ){
nArg = 1;
}
if( nArg!=1 ){
- return SHELL_INVALID_ARGS;
+ return DCR_TooMany|1;
}
open_db(p, 0);
rc = sqlite3_exec(datax.dbUser,
DISPATCHABLE_COMMAND( headers 6 2 2 ){
ISS(p)->showHeader = booleanValue(azArg[1]);
ISS(p)->shellFlgs |= SHFLG_HeaderSet;
- return 0;
+ return DCR_Ok;
}
/*****************
utf8_printf(out, "Nothing matches '%s'\n", azArg[1]);
}
/* Help pleas never fail! */
- return 0;
+ return DCR_Ok;
}
/*****************
ShellInState *psi = ISS(p);
int rc = 0;
- if(psi->bSafeMode) return SHELL_FORBIDDEN_OP;
+ if(psi->bSafeMode) return DCR_AbortError;
memset(&sCtx, 0, sizeof(sCtx));
if( 0==(sCtx.z = sqlite3_malloc64(120)) ){
shell_out_of_memory();
zTable = z;
}else{
*pzErr = shellMPrintf(0," surplus argument: \"%s\"\n", z);
- return SHELL_INVALID_ARGS;
+ return DCR_TooMany|i;
}
}else if( strcmp(z,"-v")==0 ){
eVerbose++;
useOutputMode = 0;
}else{
*pzErr = shellMPrintf(0," unknown option: \"%s\"", z);
- return SHELL_INVALID_ARGS;
+ return DCR_Unknown|i;
}
}
if( zTable==0 ){
*pzErr = shellMPrintf(0," missing %s argument.\n",
zFile==0 ? "FILE" : "TABLE");
- return SHELL_INVALID_ARGS;
+ return DCR_Missing;
}
seenInterrupt = 0;
open_db(p, 0);
}
if( zYap!=0 ){
*pzErr = shellMPrintf(0,"%s\n", zYap);
- return 1;
+ return DCR_Error;
}
if( nSep==2 && psi->mode==MODE_Csv
&& strcmp(psi->rowSeparator,SEP_CrLf)==0 ){
if( nSep>1 ){
*pzErr = sqlite3_mprintf
("Error: multi-character row separators not allowed for import\n");
- return 1;
+ return DCR_Error;
}
sCtx.cColSep = psi->colSeparator[0];
sCtx.cRowSep = psi->rowSeparator[0];
if( sCtx.zFile[0]=='|' ){
#ifdef SQLITE_OMIT_POPEN
*pzErr = shellMPrintf(0,"Error: pipes are not supported in this OS\n");
- return 1;
+ return DCR_Error;
#else
sCtx.in = popen(sCtx.zFile+1, "r");
sCtx.zFile = "<pipe>";
if( sCtx.in==0 ){
*pzErr = shellMPrintf(0,"Error: cannot open \"%s\"\n", zFile);
import_cleanup(&sCtx);
- return 1;
+ return DCR_Error;
}
/* Here and below, resources must be freed before exit. */
if( eVerbose>=2 || (eVerbose>=1 && useOutputMode) ){
sqlite3_free(zSql);
sqlite3_free(zFullTabName);
import_cleanup(&sCtx);
- return 1;
+ return DCR_Error;
}
zCreate = sqlite3_mprintf("%z%z\n", zCreate, zColDefs);
if( eVerbose>=1 ){
nCol = sqlite3_column_count(pStmt);
sqlite3_finalize(pStmt);
pStmt = 0;
- if( nCol==0 ) return 0; /* no columns, no error */
+ if( nCol==0 ) return DCR_Ok; /* no columns, no error */
zSql = sqlite3_malloc64( nByte*2 + 20 + nCol*2 );
if( zSql==0 ){
import_cleanup(&sCtx);
"Added %d rows with %d errors using %d lines of input\n",
sCtx.nRow, sCtx.nErr, sCtx.nLine-1);
}
- return 0;
+ return DCR_Ok;
}
/*****************
utf8_printf(out, "%s is%s a keyword\n",
azArg[1], (isKeyword)? "" : " not");
}
- return 0;
+ return DCR_Ok;
}
/*****************
** where TABLE is a WITHOUT ROWID table. In that case, the
** imposter is another WITHOUT ROWID table with the columns in
** storage order. */
- return 1;
+ return DCR_ArgError;
}
open_db(p, 0);
db = DBX(p);
if( nArg==2 ){
sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, db, "main", 0, 1);
- return 0;
+ return DCR_Ok;
}
zSql = sqlite3_mprintf(
"SELECT rootpage, 0 FROM sqlite_schema"
if( i==0 || tnum==0 ){
*pzErr = shellMPrintf(0,"no such index: \"%s\"\n", azArg[1]);
sqlite3_free(zCollist);
- return 1;
+ return DCR_Error;
}
if( lenPK==0 ) lenPK = 100000;
zSql = sqlite3_mprintf("CREATE TABLE \"%w\"(%s,PRIMARY KEY(%.*s))"
if( iotrace==0 ){
*pzErr = shellMPrintf(0,"Error: cannot open \"%s\"\n", azArg[1]);
sqlite3IoTrace = 0;
- return 1;
+ return DCR_Error;
}else{
sqlite3IoTrace = iotracePrintf;
}
}
- return 0;
+ return DCR_Ok;
}
DISPATCHABLE_COMMAND( limits 5 1 3 ){
static const struct {
sqlite3_limit(DBX(p), aLimit[i].limitCode, -1));
}
}else if( nArg>3 ){
- return SHELL_INVALID_ARGS;
+ return DCR_TooMany;
}else{
int iLimit = -1;
n2 = strlen30(azArg[1]);
iLimit = i;
}else{
*pzErr = shellMPrintf(0,"ambiguous limit: \"%s\"\n", azArg[1]);
- return 1;
+ return DCR_Error;
}
}
}
("unknown limit: \"%s\"\n"
"enter \".limits\" with no arguments for a list.\n",
azArg[1]);
- return 1;
+ return DCR_ArgError;
}
if( nArg==3 ){
sqlite3_limit(DBX(p), aLimit[iLimit].limitCode,
fprintf(STD_OUT, "%20s %d\n", aLimit[iLimit].zLimitName,
sqlite3_limit(DBX(p), aLimit[iLimit].limitCode, -1));
}
- return 0;
+ return DCR_Ok;
}
DISPATCHABLE_COMMAND( lint 3 1 0 ){
("Usage %s sub-command ?switches...?\n"
"Where sub-commands are:\n"
" fkey-indexes\n", azArg[0]);
- return 1;
+ return DCR_ArgError;
}
open_db(p, 0);
db = DBX(p);
#if SHELL_DYNAMIC_EXTENSION
u8 bLoadExt = 0;
#endif
- if( ISS(p)->bSafeMode ) return SHELL_FORBIDDEN_OP;
+ if( ISS(p)->bSafeMode ) return DCR_AbortError;
while( ai<nArg ){
const char *zA = azArg[ai++];
#if SHELL_DYNAMIC_EXTENSION
#endif
if( zFile==0 ) zFile = zA;
else if( zProc==0 ) zProc = zA;
- else return SHELL_INVALID_ARGS;
+ else return DCR_TooMany;
}
+ open_db(p, 0);
#if SHELL_DYNAMIC_EXTENSION
if( bLoadExt ){
rc = load_shell_extension(p, zFile, zProc, pzErr);
}else
#endif
{
- open_db(p, 0);
rc = sqlite3_load_extension(DBX(p), zFile, zProc, pzErr);
}
- return rc!=SQLITE_OK;
+ return DCR_Ok|(rc!=SQLITE_OK);
}
DISPATCHABLE_COMMAND( log ? 2 2 ){
const char *zFile = azArg[1];
- if( ISS(p)->bSafeMode ) return SHELL_FORBIDDEN_OP;
+ if( ISS(p)->bSafeMode ) return DCR_AbortError;
output_file_close(ISS(p)->pLog);
ISS(p)->pLog = output_file_open(zFile, 0);
- return 0;
+ return DCR_Ok;
}
static void effectMode(ShellInState *psi, u8 modeRequest, u8 modeNominal){
}
}
psi->cMode = psi->mode;
- return 0;
+ return DCR_Ok;
flag_unknown:
utf8_printf(STD_ERR, "Error: Unknown .mode option: %s\nValid options:\n%s",
zArg,
" --wordwrap on/off\n"
" --wrap N\n"
" --ww\n");
- return 1;
+ return DCR_ArgError;
mode_unknown:
raw_printf(STD_ERR, "Error: Mode should be one of: "
"ascii box column csv html insert json line list markdown "
"qbox quote table tabs tcl\n");
- return 1;
+ return DCR_ArgError;
mode_badarg:
utf8_printf(STD_ERR, "Error: Invalid .mode argument: %s\n", zArg);
- return 1;
+ return DCR_ArgError;
}
/*****************
#endif /* SQLITE_OMIT_DESERIALIZE */
}else if( z[0]=='-' ){
*pzErr = shellMPrintf(0,"unknown option: %s\n", z);
- return SHELL_INVALID_ARGS;
+ return DCR_Unknown|iName;
}else if( zFN ){
*pzErr = shellMPrintf(0,"extra argument: \"%s\"\n", z);
- return SHELL_INVALID_ARGS;
+ return DCR_TooMany;
}else{
zFN = z;
}
&& strcmp(zFN,":memory:")!=0
){
*pzErr = shellMPrintf(0,"cannot open database files in safe mode");
- return SHELL_FORBIDDEN_OP;
+ return DCR_AbortError;
}
if( zFN ){
zNewFilename = sqlite3_mprintf("%s", zFN);
}
/* Suspend safe mode for 1 meta-command after this. */
psi->bSafeModeFuture = 2;
- return 0;
+ return DCR_Ok;
}
DISPATCHABLE_COMMAND( nullvalue ? 2 2 ){
sqlite3_snprintf(sizeof(ISS(p)->nullValue), ISS(p)->nullValue, "%.*s",
(int)ArraySize(ISS(p)->nullValue)-1, azArg[1]);
- return 0;
+ return DCR_Ok;
}
/* Helper functions for .parameter command
const char *zStore = params_store_path((nArg>1)? azArg[1] : 0);
if( zStore==0 ){
utf8_printf(STD_ERR, "Cannot form parameter load path. Nothing loaded.\n");
- return 1;
+ return DCR_Error;
}else{
const char **pzFirst = (nArg>2)? azArg+2 : 0;
int nNames = (nArg>2)? nArg-2 : 0;
const char *zStore = params_store_path((nArg>1)? azArg[1] : 0);
if( zStore==0 ){
utf8_printf(STD_ERR, "Cannot form parameter save path. Nothing saved.\n");
- return 1;
+ return DCR_Error;
}else{
const char **pzFirst = (nArg>2)? azArg+2 : 0;
int nNames = (nArg>2)? nArg-2 : 0;
if( !INSOURCE_IS_INTERACTIVE(psi->pInSource) ){
utf8_printf(STD_ERR, "Error: "
".parameter edit can only be used interactively.\n");
- return 1;
+ return DCR_Error;
}
param_table_init(db);
if( psi->zEditor==0 ){
" editor and restart, or rerun\n "
".parameter edit with an initial "
"edit option, --editor=EDITOR_COMMAND .\n");
- return 1;
+ return DCR_Error;
}
/* Future: Allow an option whereby new value can be evaluated
* the way that .parameter set ... does.
default:
utf8_printf(STD_ERR, "Error: bad .parameter name: %s\n",
azArg[--ia]);
- return 1;
+ return DCR_Error;
}
}
ptu = classify_param_name(azArg[ia]);
if( ptu==PTU_Nil ){
utf8_printf(STD_ERR, "Error: %s cannot be a binding or executable"
" parameter name.\n", azArg[ia]);
- return 1;
+ return DCR_Error;
}
rc = edit_one_param(db, azArg[ia], eval, ptu, psi->zEditor);
++ia;
{ /* If no command name and arg count matches, show a syntax error */
showHelp(ISS(p)->out, "parameter", p);
- return 1;
+ return DCR_ArgError;
}
return rc;
for(i=1; i<nArg; i++){
utf8_printf(ISS(p)->out, "%s%s", azArg[i], (i==nArg-1)? "\n" : " ");
}
- return 0;
+ return DCR_Ok;
}
DISPATCHABLE_COMMAND( progress 3 2 0 ){
ShellInState *psi = ISS(p);
if( strcmp(z,"limit")==0 ){
if( i+1>=nArg ){
*pzErr = shellMPrintf(0,"Error: missing argument on --limit\n");
- return SHELL_INVALID_ARGS;
+ return DCR_Unpaired|i;
}else{
psi->mxProgress = (int)integerValue(azArg[++i]);
}
continue;
}
*pzErr = shellMPrintf(0, "Error: unknown option: \"%s\"\n", azArg[i]);
- return SHELL_INVALID_ARGS;
+ return DCR_Unknown|i;
}else{
nn = (int)integerValue(z);
}
}
open_db(p, 0);
sqlite3_progress_handler(DBX(p), nn, progress_handler, psi);
- return 0;
+ return DCR_Ok;
}
/* Allow too few arguments by tradition, (a form of no-op.) */
DISPATCHABLE_COMMAND( prompt ? 1 3 ){
if( nArg >= 3) {
strncpy(continuePrompt,azArg[2],(int)ArraySize(continuePrompt)-1);
}
- return 0;
+ return DCR_Ok;
}
/*****************
int rc = 0;
FILE *inUse = 0;
int (*fCloser)(FILE *) = 0;
- if( ISS(p)->bSafeMode ) return SHELL_FORBIDDEN_OP;
+ if( ISS(p)->bSafeMode ) return DCR_AbortError;
if( azArg[1][0]=='|' ){
#ifdef SQLITE_OMIT_POPEN
*pzErr = shellMPrintf(0,"Error: pipes are not supported in this OS\n");
else{
*pzErr = shellMPrintf(0,"unexpected option: %s\n", azArg[i]);
showHelp(out, azArg[0], p);
- return 1;
+ return DCR_ArgError;
}
}
sqlite3_backup *pBackup;
int nTimeout = 0;
- if( ISS(p)->bSafeMode ) return SHELL_FORBIDDEN_OP;
+ if( ISS(p)->bSafeMode ) return DCR_AbortError;
if( nArg==2 ){
zSrcFile = azArg[1];
zDb = "main";
zSrcFile = azArg[2];
zDb = azArg[1];
}else{
- return SHELL_INVALID_ARGS;
+ return DCR_TooMany;
}
rc = sqlite3_open(zSrcFile, &pSrc);
if( rc!=SQLITE_OK ){
*pzErr = shellMPrintf(0,"Error: cannot open \"%s\"\n", zSrcFile);
close_db(pSrc);
- return 1;
+ return DCR_Error;
}
open_db(p, 0);
pBackup = sqlite3_backup_init(DBX(p), zDb, pSrc, "main");
if( pBackup==0 ){
*pzErr = shellMPrintf(0,"Error: %s\n", sqlite3_errmsg(DBX(p)));
close_db(pSrc);
- return 1;
+ return DCR_Error;
}
while( (rc = sqlite3_backup_step(pBackup,100))==SQLITE_OK
|| rc==SQLITE_BUSY ){
#ifndef SQLITE_ENABLE_STMT_SCANSTATUS
raw_printf(STD_ERR, "Warning: .scanstats not available in this build.\n");
#endif
- return 0;
+ return DCR_Ok;
}
DISPATCHABLE_COMMAND( schema ? 1 2 ){
int rc;
bNoSystemTabs = 1;
}else if( azArg[ii][0]=='-' ){
*pzErr = shellMPrintf(0,"Unknown option: \"%s\"\n", azArg[ii]);
- return SHELL_INVALID_ARGS;
+ return DCR_Unknown|ii;
}else if( zName==0 ){
zName = azArg[ii];
}else{
- return SHELL_INVALID_ARGS;
+ return DCR_TooMany;
}
}
if( zName!=0 ){
if( rc ){
*pzErr = shellMPrintf(0,"Error: %s\n", sqlite3_errmsg(datax.dbUser));
sqlite3_finalize(pStmt);
- return 1;
+ return DCR_Error;
}
appendText(&sSelect, "SELECT sql FROM", 0);
iSchema = 0;
}
if( zErrMsg ){
*pzErr = zErrMsg;
- return 1;
+ return DCR_Error;
}else if( rc != SQLITE_OK ){
*pzErr = shellMPrintf(0,"Error: querying schema information\n");
- return 1;
+ return DCR_Error;
}else{
- return 0;
+ return DCR_Ok;
}
}
DISPATCHABLE_COMMAND( selecttrace ? 1 0 ){
unsigned int x = nArg>=2 ? (unsigned int)integerValue(azArg[1]) : 0xffffffff;
sqlite3_test_control(SQLITE_TESTCTRL_TRACEFLAGS, 1, &x);
- return 0;
+ return DCR_Ok;
}
DISPATCHABLE_COMMAND( separator ? 2 3 ){
if( nArg>=2 ){
sqlite3_snprintf(sizeof(ISS(p)->rowSeparator), ISS(p)->rowSeparator,
"%.*s", (int)ArraySize(ISS(p)->rowSeparator)-1, azArg[2]);
}
- return 0;
+ return DCR_Ok;
}
DISPATCHABLE_COMMAND( session 3 2 0 ){
int rc = 0;
FILE *cs_out = 0;
if( failIfSafeMode
(p, "cannot run \".session %s\" in safe mode", azCmd[0]) ){
- rc = SHELL_FORBIDDEN_OP;
+ rc = DCR_AbortError;
}else{
if( nCmd!=2 ) goto session_syntax_error;
if( pSession->p==0 ) goto session_not_open;
/* If no command name matches, show a syntax error */
session_syntax_error:
showHelp(out, "session", p);
- return 1;
+ return DCR_ArgError;
}
return rc;
}
{
*pzErr = sqlite3_mprintf
("Unknown option \"%s\" on \"%s\"\n", azArg[i], azArg[0]);
- return SHELL_INVALID_ARGS;
+ return DCR_Unknown|i;
}
}else if( zLike ){
- return SHELL_INVALID_ARGS;
+ return DCR_TooMany;
}else{
zLike = z;
bSeparate = 1;
shell_exec(p, zSql, 0);
}
sqlite3_free(zSql);
- return 0;
+ return DCR_Ok;
}
/*****************
v = booleanValue(azArg[i]);
utf8_printf(ISS(p)->out, "%s: %d 0x%x\n", azArg[i], v, v);
}
- return 0;
+ return DCR_Ok;
}
DISPATCHABLE_COMMAND( selftest_int 10 0 0 ){
int i; sqlite3_int64 v;
sqlite3_snprintf(sizeof(zBuf),zBuf,"%s: %lld 0x%llx\n", azArg[i],v,v);
utf8_printf(ISS(p)->out, "%s", zBuf);
}
- return 0;
+ return DCR_Ok;
}
DISPATCHABLE_COMMAND( selftest 4 0 0 ){
*pzErr = sqlite3_mprintf
("Unknown option \"%s\" on \"%s\"\n"
"Should be one of: --init -v\n", azArg[i], azArg[0]);
- return 1;
+ return DCR_ArgError;
}
}
open_db(p,0);
if( rc ){
*pzErr = shellMPrintf(0,"Error querying the selftest table\n");
sqlite3_finalize(pStmt);
- return 1;
+ return DCR_Error;
}
for(i=1; sqlite3_step(pStmt)==SQLITE_ROW; i++){
int tno = sqlite3_column_int(pStmt, 0);
DISPATCHABLE_COMMAND( shell ? 2 0 ){
char *zCmd;
int i, x;
- if( ISS(p)->bSafeMode ) return SHELL_FORBIDDEN_OP;
+ if( ISS(p)->bSafeMode ) return DCR_AbortError;
zCmd = sqlite3_mprintf(strchr(azArg[1],' ')==0?"%s":"\"%s\"", azArg[1]);
shell_check_oom(zCmd);
for(i=2; i<nArg; i++){
x = system(zCmd);
sqlite3_free(zCmd);
if( x ) raw_printf(STD_ERR, "%s command returns %d\n", azArg[0], x);
- return 0;
+ return DCR_Ok;
}
DISPATCHABLE_COMMAND( shxopts 3 0 0 ){
static struct { const char *name; u8 mask; } shopts[] = {
shopts[io].name, v, m);
}
}
- return 0;
+ return DCR_Ok;
moan_error:
raw_printf(STD_ERR, "Error: %s %s\n", zAbout, zMoan);
- return 1;
+ return DCR_ArgError;
}
DISPATCHABLE_COMMAND( system ? 2 0 ){
return shellCommand(azArg, nArg, p, pzErr);
raw_printf(out, "\n");
utf8_printf(out, "%12.12s: %s\n", "filename",
psi->pAuxDb->zDbFilename ? psi->pAuxDb->zDbFilename : "");
- return 0;
+ return DCR_Ok;
}
DISPATCHABLE_COMMAND( stats ? 0 0 ){
ShellInState *psi = ISS(p);
display_stats(DBX(p), psi, 0);
}else{
*pzErr = shellMPrintf(0,"Usage: .stats ?on|off|stmt|vmstep?\n");
- return 1;
+ return DCR_ArgError;
}
- return 0;
+ return DCR_Ok;
}
/*****************
** command does not. */
*pzErr = shellMPrintf(0,"Usage: .indexes ?LIKE-PATTERN?\n");
sqlite3_finalize(pStmt);
- return 1;
+ return DCR_ArgError;
}
for(ii=0; sqlite3_step(pStmt)==SQLITE_ROW; ii++){
const char *zDbName = (const char*)sqlite3_column_text(pStmt, 1);
for(ii=0; ii<nRow; ii++) sqlite3_free(azResult[ii]);
sqlite3_free(azResult);
- return 0;
+ return DCR_Ok;
}
COLLECT_HELP_TEXT[
--nArg;
break;
default:
- return SHELL_INVALID_ARGS;
+ return DCR_Unknown|1;
}
}
#endif
}else{
sqlite3_snprintf(sizeof(psi->zTestcase), psi->zTestcase, "?");
}
- return 0;
+ return DCR_Ok;
}
DISPATCHABLE_COMMAND( testctrl ? 0 0 ){
FILE *out = ISS(p)->out;
utf8_printf(out, " .testctrl %s %s\n",
aCtrl[i].zCtrlName, aCtrl[i].zUsage);
}
- return 1;
+ return DCR_ArgError;
}
/* convert testctrl text option to value. allow any unique prefix
*pzErr = sqlite3_mprintf
("Error: ambiguous test-control: \"%s\"\n"
"Use \".testctrl --help\" for help\n", zCmd);
- return 1;
+ return DCR_ArgError;
}
}
}
}
if( isOk==0 && iCtrl>=0 ){
utf8_printf(out, "Usage: .testctrl %s %s\n", zCmd,aCtrl[iCtrl].zUsage);
- return 1;
+ return DCR_ArgError;
}else if( isOk==1 ){
raw_printf(out, "%d\n", rc2);
}else if( isOk==2 ){
raw_printf(out, "0x%08x\n", rc2);
}
- return 0;
+ return DCR_Ok;
}
DISPATCHABLE_COMMAND( timeout 4 1 2 ){
open_db(p, 0);
sqlite3_busy_timeout(DBX(p), nArg>=2 ? (int)integerValue(azArg[1]) : 0);
- return 0;
+ return DCR_Ok;
}
DISPATCHABLE_COMMAND( timer ? 2 2 ){
enableTimer = booleanValue(azArg[1]);
raw_printf(STD_ERR, "Error: timer not available on this system.\n");
enableTimer = 0;
}
- return 0;
+ return DCR_Ok;
}
DISPATCHABLE_COMMAND( trace ? 0 0 ){
ShellInState *psi = ISS(p);
}
else {
*pzErr = shellMPrintf(0,"Unknown option \"%s\" on \".trace\"\n", z);
- return 1;
+ return DCR_ArgError;
}
}else{
output_file_close(psi->traceOut);
if( mType==0 ) mType = SQLITE_TRACE_STMT;
sqlite3_trace_v2(DBX(p), mType, sql_trace_callback, psi);
}
- return 0;
+ return DCR_Ok;
}
/*****************
sqlite3_create_module(DBX(p), azArg[ii], 0, 0);
}
}
- return 0;
+ return DCR_Ok;
}
/*****************
if( nArg<2 ){
teach_fail:
*pzErr = shellMPrintf(0,usage);
- return 1;
+ return DCR_ArgError;
}
open_db(p, 0);
if( strcmp(azArg[1],"login")==0 ){
strlen30(azArg[3]));
if( rc ){
*pzErr = shellMPrintf(0,"Authentication failed for user %s\n", azArg[2]);
- return 1;
+ return DCR_Error;
}
}else if( strcmp(azArg[1],"add")==0 ){
if( nArg!=5 ){
booleanValue(azArg[4]));
if( rc ){
*pzErr = shellMPrintf(0,"User-Add failed: %d\n", rc);
- return 1;
+ return DCR_Error;
}
}else if( strcmp(azArg[1],"edit")==0 ){
if( nArg!=5 ){
booleanValue(azArg[4]));
if( rc ){
*pzErr = shellMPrintf(0,"User-Edit failed: %d\n", rc);
- return 1;
+ return DCR_Error;
}
}else if( strcmp(azArg[1],"delete")==0 ){
if( nArg!=3 ){
rc = sqlite3_user_delete(DBX(p), azArg[2]);
if( rc ){
*pzErr = shellMPrintf(0,"User-Delete failed: %d\n", rc);
- return 1;
+ return DCR_Error;
}
}else{
goto teach_fail;
}
- return 0;
+ return DCR_Ok;
}
/*****************
#elif defined(__GNUC__) && defined(__VERSION__)
utf8_printf(out, "gcc-" __VERSION__ "\n");
#endif
- return 0;
+ return DCR_Ok;
}
DISPATCHABLE_COMMAND( vfsinfo ? 1 2 ){
const char *zDbName = nArg==2 ? azArg[1] : "main";
raw_printf(out, "vfs.mxPathname = %d\n", pVfs->mxPathname);
}
}
- return 0;
+ return DCR_Ok;
}
DISPATCHABLE_COMMAND( vfslist ? 1 1 ){
sqlite3_vfs *pVfs;
raw_printf(out, "-----------------------------------\n");
}
}
- return 0;
+ return DCR_Ok;
}
DISPATCHABLE_COMMAND( vfsname ? 0 0 ){
const char *zDbName = nArg==2 ? azArg[1] : "main";
sqlite3_free(zVfsName);
}
}
- return 0;
+ return DCR_Ok;
}
/*****************
];
DISPATCHABLE_COMMAND( width ? 1 0 ){
setColumnWidths(p, azArg+1, nArg-1);
- return 0;
+ return DCR_Ok;
}
DISPATCHABLE_COMMAND( wheretrace ? 1 2 ){
unsigned int x = nArg>=2 ? (unsigned int)integerValue(azArg[1]) : 0xffffffff;
sqlite3_test_control(SQLITE_TESTCTRL_TRACEFLAGS, 3, &x);
- return 0;
+ return DCR_Ok;
}
/*****************
int ia, rc, nErrors = 0;
sqlite3_stmt *pStmt = 0;
sqlite3 *db;
+ DotCmdRC rv = DCR_Ok;
open_db(p, 0);
db = DBX(p);
if( db==0 ){
utf8_printf(STD_ERR, ".x can only be done with a database open.\n");
- return 1;
+ return DCR_Error;
}
if( sqlite3_table_column_metadata(db, PARAM_TABLE_SCHEMA,
PARAM_TABLE_NAME,
"key", 0, 0, 0, 0, 0)!=SQLITE_OK ){
utf8_printf(STD_ERR, "No "PARAM_TABLE_SNAME" table exists.\n");
- return 1;
+ return DCR_Error;
}
rc = sqlite3_prepare_v2(db, "SELECT value FROM "PARAM_TABLE_SNAME
" WHERE key=$1 AND uses=1", -1, &pStmt, 0);
if( rc!=SQLITE_OK ){
utf8_printf(STD_ERR, PARAM_TABLE_SNAME" is wrongly created.\n");
- return 1;
+ return DCR_Error;
}
for( ia=1; ia < nArg; ++ia ){
if( isalpha(azArg[ia][0]) ){
ShellInState *psi = ISS(p);
InSource inRedir
= INSOURCE_STR_REDIR(zSubmit, azArg[ia], psi->pInSource);
+ sqlite3_reset(pStmt); /* End the parameter read to unlock DB. */
shell_check_oom(zSubmit);
psi->pInSource = &inRedir;
- rc = process_input(psi);
+ rv = process_input(psi);
+ if( rv<DCR_ArgIxMask ){
+ nErrors += (rv & DCR_Error);
+ if( rv>=DCR_Exit ) break;
+ }
sqlite3_free(zSubmit);
psi->pInSource = inRedir.pFrom;
}else{
}
}
sqlite3_finalize(pStmt);
- return (rc==2)? 2 : nErrors>0;
+ return (rv==DCR_Return)? DCR_Return : DCR_Ok|(nErrors>0);
}
/* End of published, standard meta-command implementation functions
static void MetaCommand_dtor(MetaCommand *);
static const char * MetaCommand_name(MetaCommand *);
static const char * MetaCommand_help(MetaCommand *, int);
-static int MetaCommand_argsCheck(MetaCommand *, char **, int, char *azArgs[]);
-static int MetaCommand_execute(MetaCommand *, ShellExState *,
- char **, int, char *azArgs[]);
+static DotCmdRC
+ MetaCommand_argsCheck(MetaCommand *, char **, int nArgs, char *azArgs[]);
+static DotCmdRC
+ MetaCommand_execute(MetaCommand *, ShellExState *, char **, int, char *[]);
static VTABLE_NAME(MetaCommand) meta_cmd_VtabBuiltIn = {
MetaCommand_dtor,
static struct CommandInfo {
VTABLE_NAME(MetaCommand) *mcVtabBuiltIn;
const char * cmdName;
- int (*cmdDoer)(char *azArg[], int nArg, ShellExState *, char **pzErr);
+ DotCmdRC (*cmdDoer)(char *azArg[], int nArg,
+ ShellExState *, char **pzErr);
unsigned char minLen, minArgs, maxArgs;
const char *azHelp[2]; /* primary and secondary help text */
void * pCmdData;
else return 0;
}
-static int MetaCommand_argsCheck(MetaCommand *pMe,
- char **pzErrMsg, int nArgs, char *azArgs[]){
+static DotCmdRC
+ MetaCommand_argsCheck(MetaCommand *pMe,
+ char **pzErrMsg, int nArgs, char *azArgs[]){
struct CommandInfo *pci = (struct CommandInfo *)pMe;
- UNUSED_PARAMETER(pzErrMsg); /* Future: Make this more informative. */
- UNUSED_PARAMETER(nArgs);
UNUSED_PARAMETER(azArgs);
- if( pci->minArgs > nArgs||(pci->maxArgs > 0 && pci->maxArgs < nArgs) ){
- return SHELL_INVALID_ARGS;
- }else return 0;
+ if( pci->minArgs > nArgs ){
+ if( pzErrMsg ){
+ *pzErrMsg = sqlite3_mprintf("Too few arguments, need %d\n", pci->minArgs);
+ }
+ return DCR_TooFew;
+ }else if( pci->maxArgs > 0 && pci->maxArgs < nArgs ){
+ if( pzErrMsg ){
+ *pzErrMsg = sqlite3_mprintf("Too many arguments, over %d\n",
+ pci->maxArgs);
+ }
+ return DCR_TooMany;
+ }else return DCR_Ok;
}
-static int MetaCommand_execute(MetaCommand *pMe, ShellExState *pssx,
- char **pzErrMsg, int nArgs, char *azArgs[]){
+static DotCmdRC
+ MetaCommand_execute(MetaCommand *pMe, ShellExState *pssx,
+ char **pzErrMsg, int nArgs, char *azArgs[]){
return (((struct CommandInfo *)pMe)->cmdDoer)(azArgs, nArgs, pssx, pzErrMsg);
}
}
}
-#define NO_SUCH_COMMAND SQLITE_NOTFOUND
-/* SHELL_INVALID_ARGS defined as SQLITE_MISUSE in shext_linkage.h */
-
/*****************
** Command dispatcher
** After successful command lookup and (simple) argument checking,
** The return is either a dispatch error or whatever the dispatched
** MetaCommand returns.
*/
-int dispatchCommand(char *azArg[], int nArg, ShellExState *psx, char **pzErr){
+static DotCmdRC dispatchCommand(char *azArg[], int nArg,
+ ShellExState *psx, char **pzErr){
const char *cmdName = azArg[0];
- int nFound = 0, argsCheck;
+ int nFound = 0;
+ DotCmdRC argsCheck;
MetaCommand *pMC = findMetaCommand(cmdName, psx, &nFound);
- if( 0==pMC ) return NO_SUCH_COMMAND;
- /* Future: Distinguish not found from ambiguous (due to too-short name.) */
+ if( 0==pMC || nFound>1 ) return (nFound>1)? DCR_Ambiguous: DCR_Unknown;
argsCheck = pMC->pMethods->argsCheck(pMC, pzErr, nArg, azArg);
- if( argsCheck!=0 ) return SHELL_INVALID_ARGS;
+ 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);
}
/*
-** If an input line begins with "." then invoke this routine to
-** process that line.
+** If an input line or line group begins with "." then invoke this routine
+** to process that line.
**
-** Return 1 on error, 2 to exit, and 0 otherwise.
+** 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 int do_meta_command(char *zLine, ShellExState *psx){
+static DotCmdRC do_meta_command(char *zLine, ShellExState *psx){
int h = 1;
int nArg = 0;
int n, c;
- int rc = 0;
char *azArg[52];
char *zErr = 0;
- int dispatchResult;
+ DotCmdRC dispatchResult;
#if SHELL_VARIABLE_EXPANSION
int ncLineIn = strlen30(zLine);
u8 bExpVars = SHEXT_VAREXP(ISS(psx));
/* Process the input line.
*/
- if( nArg==0 ) return 0; /* no tokens, no error */
- n = strlen30(azArg[0]);
- c = azArg[0][0];
+ if( nArg==0 ) return DCR_Ok; /* no tokens, no error, done */
+
clearTempFile(ISS(psx));
dispatchResult = dispatchCommand(azArg, nArg, psx, &zErr);
if( psx->shellAbruptExit!=0 ){
- dispatchResult = SHELL_FORBIDDEN_OP;
- }
- switch( dispatchResult ){
- case NO_SUCH_COMMAND:
- utf8_printf(STD_ERR, "Error: unknown command: \"%s\"\n", azArg[0]);
- if( stdin_is_interactive )
- utf8_printf(STD_ERR, " Enter \".help\" for a list of commands.\n");
- if( psx->dbShell!=0 && sqlite3_strnicmp(azArg[0],"quit",n)==0 ) rc = 2;
- else rc = 1;
- break;
- case SHELL_INVALID_ARGS:
- utf8_printf(STD_ERR, "Error: invalid arguments for \".%s\"\n", azArg[0]);
- if( stdin_is_interactive ){
- if( zErr!=0 ){
- utf8_printf(STD_ERR, " %s\n", zErr);
+ dispatchResult = DCR_AbortError;
+ }
+ if( dispatchResult > DCR_AbortError ){
+ /* Handle invocation errors. */
+ int ia = dispatchResult & DCR_ArgIxMask;
+ int ec = dispatchResult & ~DCR_ArgIxMask;
+ int unknownCmd = 0;
+ const char *z = 0;
+ switch( ec ){
+ case DCR_Unknown:
+ unknownCmd = ia==0;
+ z = unknownCmd
+ ? "unknown dot command: \"%s\""
+ : "unknown option or subcommand: \"%s\"";
+ break;
+ case DCR_Ambiguous:
+ z = ia>0? "\"%s\" is ambiguous; it matches more than one subcommand"
+ : "\"%s\" is ambiguous; it matches multiple dot commands";
+ break;
+ case DCR_Unpaired:
+ z = "option %s must be paired with a value argument";
+ break;
+ case DCR_TooMany:
+ z = "excess arguments provided; try .help %s";
+ ia = 0;
+ break;
+ case DCR_TooFew:
+ z = "insufficient arguments; try .help %s";
+ ia = 0;
+ break;
+ case DCR_Missing:
+ z = "required arguments missing; try .help %s";
+ ia = 0;
+ break;
+ case DCR_ArgError:
+ z = "argument(s) are not right; try .help %s";
+ ia = 0;
+ break;
+ default:
+ assert(0);
+ z = "?";
+ break;
+ }
+ if( zErr==0 ){
+ zErr = sqlite3_mprintf(z, azArg[ia]);
+ zErr = sqlite3_mprintf("Error: %z\n", zErr);
+ }
+ utf8_printf(STD_ERR, "%s", zErr);
+ if( INSOURCE_IS_INTERACTIVE(ISS(psx)->pInSource) ){
+ if( unknownCmd ){
+ utf8_printf(STD_ERR, "Enter \".help\" for a list of commands.\n");
}else{
- utf8_printf(STD_ERR, "Usage: ");
+ utf8_printf(STD_ERR, "Usage:\n");
showPrimaryHelp(STD_ERR, azArg[0], psx);
}
}
- rc = 1;
- break;
- case SHELL_FORBIDDEN_OP:
- if( zErr!=0 ){
- utf8_printf
- (STD_ERR,
- "Error: \".%s\" may not %s in --safe mode\n", azArg[0], zErr);
- sqlite3_free(zErr);
- }else {
- utf8_printf(STD_ERR,
- "Error: \".%s\" forbidden in --safe mode\n", azArg[0]);
+ /* If the shell DB is messed up, at least .quit will be doable. */
+ if( unknownCmd && psx->dbShell!=0
+ && sqlite3_strnicmp(azArg[0],"quit",n)==0 ){
+ dispatchResult = DCR_Return;
+ }else{
+ dispatchResult = DCR_Error;
}
- psx->shellAbruptExit = 3;
- /* fall thru */
- case 2:
- rc = 2;
- /* fall thru */
- default:
- if( dispatchResult>2 ) rc = 1;
- if( zErr!=0 ){
- utf8_printf(STD_ERR, "%s", zErr);
- sqlite3_free(zErr);
+ }else{
+ /* Handle execution errors. */
+ if( dispatchResult==DCR_AbortError ){
+ if( zErr!=0 ){
+ utf8_printf(STD_ERR, "Error: \".%s\" may not %s in --safe mode\n",
+ azArg[0], zErr);
+ }else {
+ utf8_printf(STD_ERR, "Error: \".%s\" forbidden in --safe mode\n",
+ azArg[0]);
+ }
+ psx->shellAbruptExit = 3;
+ }else{
+ int error = dispatchResult & DCR_Error;
+ int action = dispatchResult & ~DCR_Error;
+ if( error ){
+ if( zErr!=0 ) utf8_printf(STD_ERR, "%s", zErr);
+ else utf8_printf(STD_ERR, "%s failed", azArg[0]);
+ }
}
}
-
+ if( zErr ) sqlite3_free(zErr);
if( ISS(psx)->outCount ){
ISS(psx)->outCount--;
if( ISS(psx)->outCount==0 ) output_reset(ISS(psx));
}
}
#endif
- return rc;
+ return dispatchResult;
}
/* Line scan result and intermediate states (supporting scan resumption)
iStartline);
if( bail_on_error && nErrors>0 ) bErrorBail = 1;
break;
- case Cmd:
+ case Cmd: {
+ DotCmdRC dcr;
echo_group_input(psi, *pzLineUse);
- switch( do_meta_command(*pzLineUse+ndcLeadWhite, XSS(psi)) ){
- default: ++nErrors; /* fall thru */
- case 0: break;
- case 2: bExitDemand = 1; break;
- }
+ dcr = do_meta_command(*pzLineUse+ndcLeadWhite, XSS(psi));
+ nErrors += (dcr & DCR_Error);
+ bExitDemand |= (dcr & ~DCR_Error)!= DCR_Ok;
break;
+ }
default:
assert(inKind!=Tbd);
break;