@set PATH=$(LIBTCLPATH);$(PATH)
.\testfixture.exe $(TOP)\test\main.test $(TESTOPTS)
+TESTRUNS_SHX = \
+ $(TOP)/test/shell_x/shell9.test \
+ $(TOP)/test/shell_x/shell10.test
+
+shellxtest: $(TESTPROGS_SHX)
+ .\testfixture.exe $(TESTRUNS_SHX)
+
shelltest: $(TESTPROGS)
.\testfixture.exe $(TOP)\test\permutations.test shell
-C For\sTcl\sextension,\sget\sTk\soption\sinto\sMSVC\sbuild.
-D 2022-04-29T21:38:46.967
+C Get\ssqlite3x.exe\sand\sextensions\stested\swith\sMSVC\sbuild.
+D 2022-05-01T04:55:59.982
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
F Makefile.in 3a2d4e3a13c497b24b92fa36e93f80dc49844f1ca62e5a7848b899afe7105a37
F Makefile.linux-gcc f609543700659711fbd230eced1f01353117621dccae7b9fb70daa64236c5241
-F Makefile.msc f2fcd8771e903a5c59f2ea1afbc5410bc72c43fa5ac1b55f11544e60e8d26e24
+F Makefile.msc 9610cfe44d83d430ac7db9146678447940fb582a30a8f4b6902ae3c2be1c5119
F README.md 2dd87a5c1d108b224921f3dd47dea567973f706e1f6959386282a626f459a70c
F VERSION fa8e7d2d1cc962f9e14c6d410387cf75860ee139462763fda887c1be4261f824
F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
F src/resolve.c f72bb13359dd5a74d440df25f320dc2c1baff5cde4fc9f0d1bc3feba90b8932a
F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92
F src/select.c cc1a7581403fc074eee85283ba8d81de50a831ae175cb65a5751be00f621c0d5
-F src/shell.c.in e0064544eee8542d2f3dc9803c1ae08592a0d9d68cfa7cfb3054ad73f53d1d67
-F src/shext_linkage.h 0fe0dd831eb1e77b7ae8bc37e80811546531f82b17ef998e08960646cbaf5191
+F src/shell.c.in a298520dcb54d9d900e850b92c41e8fab461f2a536b0353c3da63b9aa9cfe1b0
+F src/shext_linkage.h 1d3567d5f141b84c4d895f015481abd1340ffc24206de81bd5512a4967d87c9f
F src/sqlite.h.in 2a35f62185eb5e7ecc64a2f68442b538ce9be74f80f28a00abc24837edcf1c17
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.c 966a97842ab65ffd64a62a9862073139652a4f772fd20f982583892e3c35b8c1
-F src/test_shellext_cpp.cpp 21410915d2985b5e82f63c5b3cb417bc17430c6336c92a0b86c25f3775776130
+F src/test_shellext_c.c 4e858a0f0618ccd62d845c16a3bb460c236177df3881555b6db3acebfcc5301b
+F src/test_shellext_cpp.cpp 791509064f6e3c08ecc101beed4cdab940c2ea89bdbffd7408790f751e417886
F src/test_sqllog.c 540feaea7280cd5f926168aee9deb1065ae136d0bbbe7361e2ef3541783e187a
F src/test_superlock.c 4839644b9201da822f181c5bc406c0b2385f672e
F src/test_syscall.c 1073306ba2e9bfc886771871a13d3de281ed3939
F test/shell6.test 1ceb51b2678c472ba6cf1e5da96679ce8347889fe2c3bf93a0e0fa73f00b00d3
F test/shell7.test 115132f66d0463417f408562cc2cf534f6bbc6d83a6d50f0072a9eb171bae97f
F test/shell8.test 388471d16e4de767333107e30653983f186232c0e863f4490bb230419e830aae
-F test/shell_x/shell10.test 80bf84e9d31ca4ec3db02dcecf9fb3febc4e76d717cd567141b2e2b64c816862
-F test/shell_x/shell9.test 22f15500ccdec5561cbedb3a4c28f0f2175a2b8eff1b837cc127de59c3bc0f73
+F test/shell_x/shell10.test 43c0b10cb4998c91b18861efef9466f6170e43c17a76e28600356a1cb6b41cf4
+F test/shell_x/shell9.test 867be89a86bc0c2fcf73e4759c85fd38d7e15fef71238e725ba4b6ca6897a0af
F test/shmlock.test 3dbf017d34ab0c60abe6a44e447d3552154bd0c87b41eaf5ceacd408dd13fda5
F test/shortread1.test bb591ef20f0fd9ed26d0d12e80eee6d7ac8897a3
F test/show_speedtest1_rtree.tcl 32e6c5f073d7426148a6936a0408f4b5b169aba5
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P cd5e57e0fe4ef2a59c1202b66f4e774f6642fa826cfe3840a786104841dde2f6
-R 037b3c4ffd48e706e2587b3f973fcce4
+P c3494fa75772077d3ef51bc4d9e7cd673050e6d60c78f1543bcaf9f1a2534915
+R 022d02304f18e854a14c2132bbc30385
U larrybr
-Z dbae7575bfac61c09fc21f4a48c444df
+Z 240e46def679b8cc9b945d4803ee9ff6
# Remove this line to create a well-formed Fossil manifest.
-c3494fa75772077d3ef51bc4d9e7cd673050e6d60c78f1543bcaf9f1a2534915
\ No newline at end of file
+d2b16c29fcbd73c2579aefcfb7042b22a2676e84e815c8ba4bf4b5570eca0d97
\ No newline at end of file
** output from UTF-8 into MBCS.
*/
#if defined(_WIN32) || defined(WIN32)
-void utf8_printf(FILE *out, const char *zFormat, ...){
- va_list ap;
- va_start(ap, zFormat);
+void vf_utf8_printf(FILE *out, const char *zFormat, va_list ap){
if( stdout_is_console && (out==STD_OUT || out==STD_ERR) ){
char *z1 = sqlite3_vmprintf(zFormat, ap);
char *z2 = sqlite3_win32_utf8_to_mbcs_v2(z1, 0);
}else{
vfprintf(out, zFormat, ap);
}
+}
+void utf8_printf(FILE *out, const char *zFormat, ...){
+ va_list ap;
+ va_start(ap, zFormat);
+ vf_utf8_printf(out, zFormat, ap);
va_end(ap);
}
#elif !defined(utf8_printf)
return 0;
}
+/*
+** Emit formatted output to shell's current output, possibly translated
+** for the legacy console on the Windows platform. This is exposed as
+** a helper for extensions so that they may share a common buffering
+** for FILE* output or share output capture when/if that is implemented.
+*/
+static void utf8_out_printf(ShellExState *p, const char *zFormat, ...){
+ va_list ap;
+ va_start(ap, zFormat);
+#if defined(_WIN32) || defined(WIN32)
+ vf_utf8_printf(ISS(p)->out, zFormat, ap);
+#else
+ vfprintf(ISS(p)->out, zFormat, ap);
+#endif
+ va_end(ap);
+}
+
/*
** SQL function: edit(VALUE)
** edit(VALUE,EDITOR)
static DotCmdRC runDotCommand(DotCommand*, char *[], int na, ShellExState*);
static ExtensionHelpers extHelpers = {
- 13,
+ 14,
{
failIfSafeMode,
currentOutputFile,
one_input_line,
free_input_line,
sqlite3_enable_load_extension,
+ utf8_out_printf,
0
}
};
int isContinuation, Prompts *pCue);
void (*freeInputLine)(char *zLine);
int (*enable_load_extension)(sqlite3 *db, int onoff);
+ void (*utf8CurrentOutPrintf)(ShellExState *p, const char *zFmt, ...);
void *pSentinel; /* Always set to 0, above never are. */
} helpers;
} AGGTYPE_END(ExtensionHelpers);
SHELL_EXTENSION_INIT1(pShExtApi, pExtHelpers, shextLinkFetcher);
#define SHX_API(entry) pShExtApi->entry
#define SHX_HELPER(entry) pExtHelpers->entry
+#define oprintf pExtHelpers->utf8CurrentOutPrintf
typedef struct BatBeing BatBeing;
-static void sayHowMany( BatBeing *pbb, FILE *out, ShellExState *psx );
+static void sayHowMany( BatBeing *pbb, ShellExState *psx );
/* These DERIVED_METHOD(...) macro calls' arguments were copied and
* pasted from the DotCommand interface declaration in shext_linkage.h ,
* but with "Interface,Derived" substituted for the interface typename.
* The function bodies are not so easily written, of course. */
-DERIVED_METHOD(void, destruct, DotCommand,BatBeing, 0, ()){
- (void)(pThis);
- fprintf(stdout, "BatBeing unbecoming.\n");
-}
+DERIVED_METHOD(void, destruct, DotCommand,BatBeing, 0, ());
DERIVED_METHOD(const char *, name, DotCommand,BatBeing, 0,()){
(void)(pThis);
int numCalls;
DotCommand * pPrint;
DotCommand * pPrior;
+ ShellExState *pSXS;
INSTANCE_END(BatBeing) batty = {
&batty_methods,
- 0, 0, 0
+ 0, 0, 0, 0
};
+DERIVED_METHOD(void, destruct, DotCommand,BatBeing, 0, ()){
+ BatBeing *pBB = (BatBeing*)(pThis);
+ if( pBB->pSXS ) oprintf(pBB->pSXS, "BatBeing unbecoming.\n");
+}
+
DERIVED_METHOD(DotCmdRC, execute, DotCommand,BatBeing, 4,
(ShellExState *psx, char **pzErrMsg, int nArgs, char *azArgs[])){
- FILE *out = pExtHelpers->currentOutputFile(psx);
BatBeing *pbb = (BatBeing*)pThis;
+ pbb->pSXS = psx;
switch( nArgs ){
default:
{
}else{
int cix;
SHX_HELPER(setColumnWidths)(psx, azArgs+1, nArgs-1);
- fprintf(out, "Column widths:");
+ oprintf(psx, "Column widths:");
for( cix=0; cix<psx->numWidths; ++cix ){
- fprintf(out, " %d", psx->pSpecWidths[cix]);
+ oprintf(psx, " %d", psx->pSpecWidths[cix]);
}
- fprintf(out, "\n");
+ oprintf(psx, "\n");
}
}
break;
case 3:
- fprintf(out, "The Penguin, Joker and Riddler have teamed up!\n");
- case 2: fprintf(out, "The Dynamic Duo arrives, and ... ");
- case 1: fprintf(out, "@#$ KaPow! $#@\n");
+ oprintf(psx, "The Penguin, Joker and Riddler have teamed up!\n");
+ case 2: oprintf(psx, "The Dynamic Duo arrives, and ... ");
+ case 1: oprintf(psx, "@#$ KaPow! $#@\n");
}
- sayHowMany((BatBeing *)pThis, out, psx);
+ sayHowMany((BatBeing *)pThis, psx);
return DCR_Ok;
}
-static void sayHowMany( BatBeing *pbb, FILE *out, ShellExState *psx ){
+static void sayHowMany( BatBeing *pbb, ShellExState *psx ){
if( pbb->pPrint ){
char *az[] = { "print", 0 };
char *zErr = 0;
rc = pdcPrint->pMethods->execute(pdcPrint, psx, &zErr, 2, az);
sqlite3_free(az[1]);
if( rc!= DCR_Ok ){
- fprintf(out, "print() failed: %d\n", rc);
+ oprintf(psx, "print() failed: %d\n", rc);
}
}
}
static int shellEventHandle(void *pv, NoticeKind nk,
void *pvSubject, ShellExState *psx){
- FILE *out = pExtHelpers->currentOutputFile(psx);
if( nk==NK_ShutdownImminent ){
BatBeing *pbb = (BatBeing *)pv;
- fprintf(out, "Bat cave meteor strike detected after %d calls.\n",
+ oprintf(psx, "Bat cave meteor strike detected after %d calls.\n",
pbb->numCalls);
}else if( nk==NK_Unsubscribe ){
- fprintf(out, "BatBeing incommunicado.\n");
+ oprintf(psx, "BatBeing incommunicado.\n");
}else if( nk==NK_DbUserAppeared || nk==NK_DbUserVanishing ){
const char *zWhat = (nk==NK_DbUserAppeared)? "appeared" : "vanishing";
int isDbu = pvSubject==psx->dbUser;
- fprintf(out, "db%s %s\n", isDbu? "User" : "?", zWhat);
- if( psx->dbUser != pvSubject ) fprintf(out, "not dbx(%p)\n", psx->dbUser);
+ oprintf(psx, "db%s %s\n", isDbu? "User" : "?", zWhat);
+ if( psx->dbUser != pvSubject ) oprintf(psx, "not dbx(%p)\n", psx->dbUser);
}else if( nk==NK_DbAboutToClose ){
const char *zdb = (pvSubject==psx->dbUser)? "User"
: (pvSubject==psx->dbShell)? "Shell" : "?";
- fprintf(out, "db%s closing\n", zdb);
+ oprintf(psx, "db%s closing\n", zdb);
}
return 0;
}
SHELL_EXTENSION_INIT2(pShExtLink, shextLinkFetcher, db);
SHELL_EXTENSION_INIT3(pShExtApi, pExtHelpers, pShExtLink);
- iLdErr = SHELL_EXTENSION_LOADFAIL_WHY(pShExtLink, 5, 5);
+ iLdErr = SHELL_EXTENSION_LOADFAIL_WHY(pShExtLink, 5, 14);
if( iLdErr!=EXLD_Ok ){
*pzErrMsg = sqlite3_mprintf("Load failed, cause %d\n", iLdErr);
return SQLITE_ERROR;
SHELL_EXTENSION_INIT1(pShExtApi, pExtHelpers, shextLinkFetcher);
#define SHX_API(entry) pShExtApi->entry
#define SHX_HELPER(entry) pExtHelpers->entry
+#define oprintf pExtHelpers->utf8CurrentOutPrintf
struct BatBeing : DotCommand {
~BatBeing() {
- fprintf(stdout, "BatBeing RIP.\n");
}; // No held resources; copy/assign is fine and dying is easy.
void destruct() {
- fprintf(stdout, "BatBeing unbecoming.\n");
+ if( pSXS ) oprintf(pSXS, "BatBeing unbecoming.\n");
}
const char *name() { return "bat_being"; };
numCalls = 0;
pPrint = pp;
pPrior = 0;
- fprintf(stdout, "BatBeing lives.\n");
+ pSXS = 0;
};
// Default copy/assign are fine; nothing held.
int numCalls;
DotCommand * pPrint;
DotCommand * pPrior;
+ ShellExState *pSXS;
};
-static void sayHowMany( BatBeing *pbb, FILE *out, ShellExState *psx ){
+static void sayHowMany( BatBeing *pbb, ShellExState *psx ){
if( pbb->pPrint ){
static char cmd[] = "print";
char *az[] = { cmd, 0 };
rc = pbb->pPrint->execute(psx, &zErr, 2, az);
sqlite3_free(az[1]);
if( rc!= DCR_Ok ){
- fprintf(out, "print() failed: %d\n", rc);
+ oprintf(psx, "print() failed: %d\n", rc);
}
}
}
DotCmdRC BatBeing::execute(ShellExState *psx, char **pzErrMsg,
int nArgs, char *azArgs[]) {
- FILE *out = SHX_HELPER(currentOutputFile)(psx);
+ pSXS = psx;
switch( nArgs ){
default:
{
return pPrior->execute(psx, pzErrMsg, nArgs, azArgs);
}else{
SHX_HELPER(setColumnWidths)(psx, azArgs+1, nArgs-1);
- fprintf(out, "Column widths:");
+ oprintf(psx, "Column widths:");
for( int cix=0; cix<psx->numWidths; ++cix ){
- fprintf(out, " %d", psx->pSpecWidths[cix]);
+ oprintf(psx, " %d", psx->pSpecWidths[cix]);
}
- fprintf(out, "\n");
+ oprintf(psx, "\n");
}
}
break;
case 3:
- fprintf(out, "The Penguin, Joker and Riddler have teamed up!\n");
- case 2: fprintf(out, "The Dynamic Duo arrives, and ... ");
- case 1: fprintf(out, "@#$ KaPow! $#@\n");
+ oprintf(psx, "The Penguin, Joker and Riddler have teamed up!\n");
+ case 2: oprintf(psx, "The Dynamic Duo arrives, and ... ");
+ case 1: oprintf(psx, "@#$ KaPow! $#@\n");
}
- sayHowMany(this, out, psx);
+ sayHowMany(this, psx);
return DCR_Ok;
}
static int shellEventHandle(void *pv, NoticeKind nk,
void *pvSubject, ShellExState *psx){
- FILE *out = SHX_HELPER(currentOutputFile)(psx);
if( nk==NK_ShutdownImminent ){
BatBeing *pbb = (BatBeing *)pv;
- fprintf(out, "Bat cave meteor strike detected after %d calls.\n",
+ oprintf(psx, "Bat cave meteor strike detected after %d calls.\n",
pbb->numCalls);
}else if( nk==NK_Unsubscribe ){
- fprintf(out, "BatBeing incommunicado.\n");
+ oprintf(psx, "BatBeing incommunicado.\n");
}else if( nk==NK_DbUserAppeared || nk==NK_DbUserVanishing ){
const char *zWhat = (nk==NK_DbUserAppeared)? "appeared" : "vanishing";
int isDbu = pvSubject==psx->dbUser;
- fprintf(out, "db%s %s\n", isDbu? "User" : "?", zWhat);
- if( psx->dbUser != pvSubject ) fprintf(out, "not dbx(%p)\n", psx->dbUser);
+ oprintf(psx, "db%s %s\n", isDbu? "User" : "?", zWhat);
+ if( psx->dbUser != pvSubject ) oprintf(psx, "not dbx(%p)\n", psx->dbUser);
}else if( nk==NK_DbAboutToClose ){
const char *zdb = (pvSubject==psx->dbUser)? "User"
: (pvSubject==psx->dbShell)? "Shell" : "?";
- fprintf(out, "db%s closing\n", zdb);
+ oprintf(psx, "db%s closing\n", zdb);
}
return 0;
}
SHELL_EXTENSION_INIT2(pShExtLink, shextLinkFetcher, db);
SHELL_EXTENSION_INIT3(pShExtApi, pExtHelpers, pShExtLink);
- iLdErr = SHELL_EXTENSION_LOADFAIL_WHY(pShExtLink, 5, 5);
+ iLdErr = SHELL_EXTENSION_LOADFAIL_WHY(pShExtLink, 5, 14);
if( iLdErr!=EXLD_Ok ){
*pzErrMsg = sqlite3_mprintf("Load failed, cause %d\n", iLdErr);
return SQLITE_ERROR;
"
do_test shell10-1.1 {
catch_mdb_cmd $cmds
-} {0 {BatBeing lives.
-Load arguments: C++
+} {0 {Load arguments: C++
dbUser appeared
dbUser closing
dbShell closing
-BatBeing incommunicado.
-BatBeing unbecoming.
-BatBeing RIP.}}
+BatBeing incommunicado.}}
set cmds ".
.shxload $blddir/test_shellext_c -- C
} {0 {Load arguments: C
Column widths: 10 20 30
This execute has been called 1 times.
-BatBeing lives.
Load arguments: C++
Column widths: 20 30 10
This execute has been called 2 times.
BatBeing incommunicado.
BatBeing incommunicado.
BatBeing unbecoming.
-BatBeing unbecoming.
-BatBeing RIP.}}
+BatBeing unbecoming.}}
#----------------------------------------------------------------------------
c 'c'}}
if {$::tcl_platform(platform)=="unix"} {
- proc set_ed {sayWhat} {
+ proc set_ed {what} {
global env
- set env(VISUAL) "echo SELECT $sayWhat ';' >"
+ set env(VISUAL) "cp $what"
return 1
}
} elseif {$::tcl_platform(platform)=="windows"} {
- proc set_ed {sayWhat} {
+ proc set_ed {what} {
global env
- set env(VISUAL) "echo SELECT $sayWhat ; >"
+ set env(VISUAL) "copy $what >nul"
return 1
}
} else { return 0 }
-if {[set_ed @name]} {
+if {[set_ed query.txt]} {
set cmds {
+.once query.txt
+.print SELECT @name ;
.pa set @name Fido
.var edit -t dog
-.var set mutt 'SELECT @name;'
-.x dog mutt
- }
+.x dog
+}
do_test shell9-3.4 {
set res [catchcmd ":memory: -quiet 1 -interactive" $cmds]
list [lindex $res 0] [string trimright [lindex $res 1]]
- } {0 {.pa set @name Fido
-.var edit -t dog
-.var set mutt 'SELECT @name;'
-.x dog mutt
-Fido
-Fido}}
+ } {0 Fido}
}
#----------------------------------------------------------------------------