-C Further\smigration\sto\scentralized\serror\sreporting
-D 2022-03-18T16:00:07.658
+C macro-ize\sextension\sboiler-plate,\simprove\sexit\sprocessing
+D 2022-03-19T14:27:57.463
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
F src/resolve.c ea935b87d6fb36c78b70cdc7b28561dc8f33f2ef37048389549c7b5ef9b0ba5e
F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92
F src/select.c 4890a3cfee0bc60ff231c3a44db37968859ab0be156983dbcc0c096109832cdd
-F src/shell.c.in e1214665c269fad77b3cb6cb679939337a7259fecf189276b398a88d4653d4d6
-F src/shext_linkage.h 7c8ac3970d81c20c752e58860cc1a0f4521889152766a6cbcbd2734fcba6232d
+F src/shell.c.in acb97f8ad071498a35748d31b86d5797745ba236e042d54ae31adb8c23a27581
+F src/shext_linkage.h 6c75ac9690965ae6968b5b246f83bde6bac9f13a248e5ac0f5775d2ad8a35496
F src/sqlite.h.in 5845213799feca09cd69d18ff841a85fe0df31021f46aaa1797e703e80dc1d70
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/sqlite3ext.h a95cb9ed106e3d39e2118e4dcc15a14faec3fa50d0093425083d340d9dfd96e6
F src/test_rtree.c 671f3fae50ff116ef2e32a3bf1fe21b5615b4b7b
F src/test_schema.c f5d6067dfc2f2845c4dd56df63e66ee826fb23877855c785f75cc2ca83fd0c1b
F src/test_server.c a2615049954cbb9cfb4a62e18e2f0616e4dc38fe
-F src/test_shellext.c 049533eae21ff0c041ff97d2681f3005e612fc33b3824ef7b6525a719180115e
+F src/test_shellext.c 0d07a78ac1487532f39ac93eafff0240e861f8f3430205af62b937136b6dbd49
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 3457f87c5db7a28eb6a47223f7853cd066245edfe1882feabbdb8ce9555f872e 72029cf7cdb266703cc8716102dbba8e6f2666e1f47409f42c39528795757b73
-R e4977d7e43e565456c0cd3ce58d731ce
+P 898088008e2d15f89941db433f743594aea1351f353c12ce3932a39902dfb161
+R 129774c9c2e8cac58d8036d38701569e
U larrybr
-Z 7cb1fae332b9ca509f4fbb346c55037d
+Z 76b79faefcf881b072c961370ce1a08d
# Remove this line to create a well-formed Fossil manifest.
-898088008e2d15f89941db433f743594aea1351f353c12ce3932a39902dfb161
\ No newline at end of file
+7996d3a359ab90ef9f42f501e0ddb2efa964a906739116836cb1eafe2a96a0ed
\ No newline at end of file
va_end(ap);
raw_printf(STD_ERR, "line %d: ", ISS(psx)->pInSource->lineno);
utf8_printf(STD_ERR, "%s\n", zMsg);
- psx->shellAbruptExit = 3;
+ psx->shellAbruptExit = 0x202;
return 1;
}
return 0;
}
/*****************
- * The .exit and .quit commands
- * These are together so that their subtle differences are apparent.
+ * The .cease, .exit and .quit commands
+ * These are together so that their differing effects are apparent.
*/
+CONDITION_COMMAND(cease defined(SHELL_CEASE));
COLLECT_HELP_TEXT[
- ".exit ?CODE? Exit this program with return-code CODE",
- ".quit Exit this program or script",
+ ".cease ?CODE? Cease shell operation, with optional return code",
+ " Return code defaults to 0, otherwise is limited to non-signal values",
+ ".exit ?CODE? Exit shell program, maybe with return-code CODE",
+ " Exit immediately if CODE != 0, else functions as \"quit this input\"",
+ ".quit Quit processing this input or script",
];
+DISPATCHABLE_COMMAND( cease 4 1 2 ){
+ /* .cease effects an exit, always. Only the exit code is variable. */
+ int rc = 0;
+ if( nArg>1 ){
+ rc = (int)integerValue(azArg[1]);
+ if( rc>0x7f ) rc = 0x7f;
+ }
+ p->shellAbruptExit = 0x100|rc;
+ return DCR_Exit;
+}
DISPATCHABLE_COMMAND( exit 3 1 0 ){
+ /* .exit acts like .quit with no argument or a zero argument,
+ * only returning. With a non-zero argument, it effects an exit. */
int rc;
- if( nArg>1 && (rc = (int)integerValue(azArg[1]))!=0 )
- p->shellAbruptExit = rc;
+ if( nArg>1 && (rc = (int)integerValue(azArg[1]))!=0 ){
+ rc &= 0xff; /* Mimic effect of legacy call to exit(). */
+ p->shellAbruptExit = 0x100|rc;
+ }
return DCR_Return;
}
DISPATCHABLE_COMMAND( quit 1 1 0 ){
+ /* .quit would be more aptly named .return, as it does nothing more. */
return DCR_Return;
}
dispatchResult = dispatchCommand(azArg, nArg, psx, &zErr);
if( psx->shellAbruptExit!=0 ){
- dispatchResult = DCR_AbortError;
+ if( psx->shellAbruptExit>0x1ff ) dispatchResult = DCR_AbortError;
+ else dispatchResult = DCR_Exit | (dispatchResult&DCR_Error);
}
if( dispatchResult==DCR_CmdErred ){
/* Error message(s) already emitted. Just translate to execute error. */
/* Handle execution errors. */
if( dispatchResult==DCR_AbortError ){
if( zErr!=0 ){
- utf8_printf(STD_ERR, "Error: \".%s\" may not %s in --safe mode\n",
+ 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",
+ utf8_printf(STD_ERR, "Error: \".%s\" forbidden in -safe mode\n",
azArg[0]);
}
- psx->shellAbruptExit = 3;
+ psx->shellAbruptExit = 0x203;
}else{
int error = dispatchResult & DCR_Error;
int action = dispatchResult & ~DCR_Error;
break;
}
if( XSS(psi)->shellAbruptExit!=0 ){
- termKind = XSS(psi)->shellAbruptExit;
+ termKind = DCR_Exit;
}
break;
case Erroneous:
}else{
utf8_printf(STD_ERR,"Error: unable to process SQL \"%s\"\n", zSql);
}
- psx->shellAbruptExit = (rc==0)? 1 : rc;
+ psx->shellAbruptExit = (rc==0)? 0x100 : 0x102;
rc = 2;
}
return rc;
rc = process_input(psi);
fclose(inUse);
psi->pInSource = inSourceRedir.pFrom;
- if( rc>DCR_Ok && bail_on_error ) XSS(psi)->shellAbruptExit = rc;
+ if( rc>DCR_Ok && bail_on_error ){
+ XSS(psi)->shellAbruptExit = 0x100|((rc>>1)&0x3);
+ }
}else if( sqliterc_override!=0 ){
utf8_printf(STD_ERR,"cannot open: \"%s\"\n", sqliterc);
if( bail_on_error ) exit(1); /* Future: Exit shell rather than process. */
* exit code or an abnormal exit code. Its abnormal values take priority.
*/
/* Check for an abnormal exit, and issue error if so. */
- if( rc>2 || aec>1 ){
- rc = (rc<aec)? aec : rc;
- if( rc>255 ) rc = 255; /* Clamp to valid error exit range. */
- raw_printf(STD_ERR, "Abnormal exit (%d)\n", rc);
+ if( aec!=0 ){
+ rc = aec & 0xff;
+ if( aec>0x1ff ) raw_printf(STD_ERR, "Abnormal exit (%d)\n", rc);
}else{
/* rc is one of 0,1,2, mapping to 0,1,0 shellexit codes. */
rc &= ~2;
/* Output stream to which shell's text output to be written (reference) */
FILE **ppCurrentOutput;
- /* Whether to exit as command completes.
+ /* Shell abrupt exit indicator with return code in LS-byte
* 0 => no exit
- * ~0 => a non-error (0) exit
- * other => exit with process exit code other
+ * 0x100 => a non-error (0) exit
+ * 0x100|other => exit with process exit code other
+ * Any value greater than 0x1ff indicates an abnormal exit.
* For embedded shell, "exit" means "return from REPL function".
*/
int shellAbruptExit;
2,( ShellExState *pSES, char **pzErr ));
INTERFACE_END( ImportHandlerVtable );
+/* Define an implementation's v-table matching the MetaCommand interface.
+ * Method signatures are copied and pasted from above interface declaration.
+ */
+#define MetaCommand_IMPLEMENT_VTABLE(Derived, vtname) \
+CONCRETE_BEGIN(MetaCommand, Derived); \
+CONCRETE_METHOD(const char *, name, MetaCommand, 0,()); \
+CONCRETE_METHOD(const char *, help, MetaCommand, 1,(int more)); \
+CONCRETE_METHOD(DotCmdRC, argsCheck, MetaCommand, 3, \
+ (char **pzErrMsg, int nArgs, char *azArgs[])); \
+CONCRETE_METHOD(DotCmdRC, execute, MetaCommand, 4, \
+ (ShellExState *, char **pzErrMsg, int nArgs, char *azArgs[])); \
+CONCRETE_END(Derived) vtname = { \
+ DECORATE_METHOD(Derived,destruct), \
+ DECORATE_METHOD(Derived,name), \
+ DECORATE_METHOD(Derived,help), \
+ DECORATE_METHOD(Derived,argsCheck), \
+ DECORATE_METHOD(Derived,execute) \
+}
+
/* This function pointer has the same signature as the sqlite3_X_init()
* function that is called as SQLite3 completes loading an extension.
*/
static struct ShExtAPI *pShExtApi = 0;
static struct ExtHelpers *pExtHelpers = 0;
+typedef struct BatBeing BatBeing;
+static void sayHowMany( BatBeing *pbb, FILE *out, ShellExState *psx );
+
/* These DERIVED_METHOD(...) macro calls' arguments were copied and
* pasted from the MetaCommand interface declaration in shext_linkage.h ,
- * but with Interface,Derived substituted for the interface typename.
+ * but with "Interface,Derived" substituted for the interface typename.
* The function bodies are not so easily written, of course. */
DERIVED_METHOD(void, destruct, MetaCommand,BatBeing, 0, ()){
return DCR_Ok;
}
-typedef struct BatBeing BatBeing;
-static void sayHowMany( struct BatBeing *pbb, FILE *out, ShellExState *psx );
-
DERIVED_METHOD(DotCmdRC, execute, MetaCommand,BatBeing, 4,
(ShellExState *psx, char **pzErrMsg, int nArgs, char *azArgs[])){
FILE *out = pExtHelpers->currentOutputFile(psx);
case 2: fprintf(out, "The Dynamic Duo arrives, and ... ");
case 1: fprintf(out, "@#$ KaPow! $#@\n");
}
- sayHowMany((struct BatBeing *)pThis, out, psx);
+ sayHowMany((BatBeing *)pThis, out, psx);
return DCR_Ok;
}
-/* Note that these CONCRETE_METHOD... macro calls' arguments were copied and
- * pasted from the MetaCommand interface declaration in shext_linkage.h .
- * In a future version of shext_linkage.h, this will all be a mondo maco. */
-CONCRETE_BEGIN(MetaCommand, BatBeing);
-CONCRETE_METHOD(const char *, name, MetaCommand, 0,());
-CONCRETE_METHOD(const char *, help, MetaCommand, 1,(int more));
-CONCRETE_METHOD(DotCmdRC, argsCheck, MetaCommand, 3,
- (char **pzErrMsg, int nArgs, char *azArgs[]));
-CONCRETE_METHOD(DotCmdRC, execute, MetaCommand, 4,
- (ShellExState *, char **pzErrMsg, int nArgs, char *azArgs[]));
-CONCRETE_END(BatBeing) batty_methods = {
- DECORATE_METHOD(BatBeing,destruct),
- DECORATE_METHOD(BatBeing,name),
- DECORATE_METHOD(BatBeing,help),
- DECORATE_METHOD(BatBeing,argsCheck),
- DECORATE_METHOD(BatBeing,execute)
-};
+/* Define a MetaCommand v-table initialized to reference above methods. */
+MetaCommand_IMPLEMENT_VTABLE(BatBeing, batty_methods);
+/* Define/initialize BatBeing as a MetaCommand subclass using above v-table.
+ * This compiles in a type-safe manner because the batty_methods v-table
+ * and methods it incorporates strictly match the MetaCommand interface.
+ */
INSTANCE_BEGIN(BatBeing);
int numCalls;
- MetaCommand * pShow;
+ MetaCommand * pPrint;
INSTANCE_END(BatBeing) batty = {
&batty_methods,
0, 0
};
-static void sayHowMany( struct BatBeing *pbb, FILE *out, ShellExState *psx ){
- fprintf(out, "This execute has been called %d times.\n", ++pbb->numCalls);
- if( pbb->pShow ){
- char *az[] = { "show" };
+static void sayHowMany( BatBeing *pbb, FILE *out, ShellExState *psx ){
+ if( pbb->pPrint ){
+ char *az[] = { "print", 0 };
char *zErr = 0;
- MetaCommand * pmcShow = (MetaCommand *)pbb->pShow;
- DotCmdRC rc = pmc->pMethods->execute(pmc, psx, &zErr, 1, az);
+ MetaCommand * pmcPrint = pbb->pPrint;
+ DotCmdRC rc;
+ az[1] = sqlite3_mprintf("This execute has been called %d times.\n",
+ ++pbb->numCalls);
+ rc = pmcPrint->pMethods->execute(pmcPrint, psx, &zErr, 2, az);
+ sqlite3_free(az[1]);
if( rc!= DCR_Ok ){
- fprintf(out, "show() failed: %d\n", rc);
+ fprintf(out, "print() failed: %d\n", rc);
}
}
}
pShExtApi = & pShExtLink->pShellExtensionAPI->api.named;
pExtHelpers = & pShExtLink->pShellExtensionAPI->pExtHelpers->helpers.named;
- batty.pShow = pExtHelpers->findMetaCommand("show", psx, &rc);
+ batty.pPrint = pExtHelpers->findMetaCommand("print", psx, &rc);
rc = pShExtApi->registerMetaCommand(psx, sqlite3_testshellext_init,pmc);
if( rc!=0 ) ++nErr;
}