]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Merge console I/O changes for Windows CLI.
authorlarrybr <larrybr@noemail.net>
Tue, 21 Nov 2023 18:26:06 +0000 (18:26 +0000)
committerlarrybr <larrybr@noemail.net>
Tue, 21 Nov 2023 18:26:06 +0000 (18:26 +0000)
FossilOrigin-Name: 935a8a8ee76d0014df42c1480e044fd1c2dfc26e78abb587d99d861d2ae5eb27

1  2 
Makefile.msc
ext/consio/console_io.c
ext/consio/console_io.h
manifest
manifest.uuid
src/shell.c.in

diff --cc Makefile.msc
index 4339be891f89522bdacc7fc439b834a6a3fa781d,33a9746dd4ebbfbc95c6e68ea35fbf517ed83d93..3a4d46b01f048bd00cf634e029798aeb9807beae
@@@ -2261,8 -2261,12 +2261,10 @@@ keywordhash.h:        $(TOP)\tool\mkkeywordhas
  # Source files that go into making shell.c
  SHELL_SRC = \
        $(TOP)\src\shell.c.in \
+       $(TOP)\ext\consio\console_io.c \
+       $(TOP)\ext\consio\console_io.h \
        $(TOP)\ext\misc\appendvfs.c \
        $(TOP)\ext\misc\completion.c \
 -      $(TOP)\ext\consio\console_io.c \
 -      $(TOP)\ext\consio\console_io.h \
        $(TOP)\ext\misc\base64.c \
        $(TOP)\ext\misc\base85.c \
        $(TOP)\ext\misc\decimal.c \
index 0000000000000000000000000000000000000000,7ed06ccd31477188c49f2114871ec81a6ce68cff..781ae7fc7ec9c90a0fd91c05cbe70eee00bc1eef
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,677 +1,676 @@@
 -#undef CIO_WIN_WC_XLATE
+ /*
+ ** 2023 November 4
+ **
+ ** The author disclaims copyright to this source code.  In place of
+ ** a legal notice, here is a blessing:
+ **
+ **    May you do good and not evil.
+ **    May you find forgiveness for yourself and forgive others.
+ **    May you share freely, never taking more than you give.
+ **
+ ********************************************************************************
+ ** This file implements various interfaces used for console and stream I/O
+ ** by the SQLite project command-line tools, as explained in console_io.h .
+ ** Functions prefixed by "SQLITE_INTERNAL_LINKAGE" behave as described there.
+ */
+ #ifndef SQLITE_CDECL
+ # define SQLITE_CDECL
+ #endif
+ #ifndef SHELL_NO_SYSINC
+ # include <stdarg.h>
+ # include <string.h>
+ # include <stdlib.h>
+ # include <limits.h>
+ # include <assert.h>
+ # include "console_io.h"
+ # include "sqlite3.h"
+ #endif
+ #ifndef SQLITE_CIO_NO_TRANSLATE
+ # if (defined(_WIN32) || defined(WIN32)) && !SQLITE_OS_WINRT
+ #  ifndef SHELL_NO_SYSINC
+ #   include <io.h>
+ #   include <fcntl.h>
+ #   undef WIN32_LEAN_AND_MEAN
+ #   define WIN32_LEAN_AND_MEAN
+ #   include <windows.h>
+ #  endif
+ #  define CIO_WIN_WC_XLATE 1 /* Use WCHAR Windows APIs for console I/O */
+ # else
+ #  ifndef SHELL_NO_SYSINC
+ #   include <unistd.h>
+ #  endif
+ #  define CIO_WIN_WC_XLATE 0 /* Use plain C library stream I/O at console */
+ # endif
+ #else
+ # define CIO_WIN_WC_XLATE 0 /* Not exposing translation routines at all */
+ #endif
+ #if CIO_WIN_WC_XLATE
+ /* Character used to represent a known-incomplete UTF-8 char group (�) */
+ static WCHAR cBadGroup = 0xfffd;
+ #endif
+ #if CIO_WIN_WC_XLATE
+ static HANDLE handleOfFile(FILE *pf){
+   int fileDesc = _fileno(pf);
+   union { intptr_t osfh; HANDLE fh; } fid = {
+     (fileDesc>=0)? _get_osfhandle(fileDesc) : (intptr_t)INVALID_HANDLE_VALUE
+   };
+   return fid.fh;
+ }
+ #endif
+ #ifndef SQLITE_CIO_NO_TRANSLATE
+ typedef struct PerStreamTags {
+ # if CIO_WIN_WC_XLATE
+   HANDLE hx;
+   DWORD consMode;
+   char acIncomplete[4];
+ # else
+   short reachesConsole;
+ # endif
+   FILE *pf;
+ } PerStreamTags;
+ /* Define NULL-like value for things which can validly be 0. */
+ # define SHELL_INVALID_FILE_PTR ((FILE *)~0)
+ # if CIO_WIN_WC_XLATE
+ #  define SHELL_INVALID_CONS_MODE 0xFFFF0000
+ # endif
+ # if CIO_WIN_WC_XLATE
+ #  define PST_INITIALIZER { INVALID_HANDLE_VALUE, SHELL_INVALID_CONS_MODE, \
+       {0,0,0,0}, SHELL_INVALID_FILE_PTR }
+ # else
+ #  define PST_INITIALIZER { 0, SHELL_INVALID_FILE_PTR }
+ # endif
+ /* Quickly say whether a known output is going to the console. */
+ # if CIO_WIN_WC_XLATE
+ static short pstReachesConsole(PerStreamTags *ppst){
+   return (ppst->hx != INVALID_HANDLE_VALUE);
+ }
+ # else
+ #  define pstReachesConsole(ppst) 0
+ # endif
+ # if CIO_WIN_WC_XLATE
+ static void restoreConsoleArb(PerStreamTags *ppst){
+   if( pstReachesConsole(ppst) ) SetConsoleMode(ppst->hx, ppst->consMode);
+ }
+ # else
+ #  define restoreConsoleArb(ppst)
+ # endif
+ /* Say whether FILE* appears to be a console, collect associated info. */
+ static short streamOfConsole(FILE *pf, /* out */ PerStreamTags *ppst){
+ # if CIO_WIN_WC_XLATE
+   short rv = 0;
+   DWORD dwCM = SHELL_INVALID_CONS_MODE;
+   HANDLE fh = handleOfFile(pf);
+   ppst->pf = pf;
+   if( INVALID_HANDLE_VALUE != fh ){
+     rv = (GetFileType(fh) == FILE_TYPE_CHAR && GetConsoleMode(fh,&dwCM));
+   }
+   ppst->hx = (rv)? fh : INVALID_HANDLE_VALUE;
+   ppst->consMode = dwCM;
+   return rv;
+ # else
+   ppst->pf = pf;
+   ppst->reachesConsole = ( (short)isatty(fileno(pf)) );
+   return ppst->reachesConsole;
+ # endif
+ }
+ # if CIO_WIN_WC_XLATE
+ /* Define console modes for use with the Windows Console API. */
+ #  define SHELL_CONI_MODE \
+   (ENABLE_ECHO_INPUT | ENABLE_INSERT_MODE | ENABLE_LINE_INPUT | 0x80 \
+   | ENABLE_QUICK_EDIT_MODE | ENABLE_EXTENDED_FLAGS | ENABLE_PROCESSED_INPUT)
+ #  define SHELL_CONO_MODE (ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT \
+   | ENABLE_VIRTUAL_TERMINAL_PROCESSING)
+ # endif
+ typedef struct ConsoleInfo {
+   PerStreamTags pstSetup[3];
+   PerStreamTags pstDesignated[3];
+   StreamsAreConsole sacSetup;
+ } ConsoleInfo;
+ static short isValidStreamInfo(PerStreamTags *ppst){
+   return (ppst->pf != SHELL_INVALID_FILE_PTR);
+ }
+ static ConsoleInfo consoleInfo = {
+   { /* pstSetup */ PST_INITIALIZER, PST_INITIALIZER, PST_INITIALIZER },
+   { /* pstDesignated[] */ PST_INITIALIZER, PST_INITIALIZER, PST_INITIALIZER },
+   SAC_NoConsole /* sacSetup */
+ };
+ SQLITE_INTERNAL_LINKAGE FILE* invalidFileStream = (FILE *)~0;
+ # if CIO_WIN_WC_XLATE
+ static void maybeSetupAsConsole(PerStreamTags *ppst, short odir){
+   if( pstReachesConsole(ppst) ){
+     DWORD cm = odir? SHELL_CONO_MODE : SHELL_CONI_MODE;
+     SetConsoleMode(ppst->hx, cm);
+   }
+ }
+ # else
+ #  define maybeSetupAsConsole(ppst,odir)
+ # endif
+ SQLITE_INTERNAL_LINKAGE void consoleRenewSetup(void){
+ # if CIO_WIN_WC_XLATE
+   int ix = 0;
+   while( ix < 6 ){
+     PerStreamTags *ppst = (ix<3)?
+       &consoleInfo.pstSetup[ix] : &consoleInfo.pstDesignated[ix-3];
+     maybeSetupAsConsole(ppst, (ix % 3)>0);
+     ++ix;
+   }
+ # endif
+ }
+ SQLITE_INTERNAL_LINKAGE StreamsAreConsole
+ consoleClassifySetup( FILE *pfIn, FILE *pfOut, FILE *pfErr ){
+   StreamsAreConsole rv = SAC_NoConsole;
+   FILE* apf[3] = { pfIn, pfOut, pfErr };
+   int ix;
+   for( ix = 2; ix >= 0; --ix ){
+     PerStreamTags *ppst = &consoleInfo.pstSetup[ix];
+     if( streamOfConsole(apf[ix], ppst) ){
+       rv |= (SAC_InConsole<<ix);
+     }
+     consoleInfo.pstDesignated[ix] = *ppst;
+     if( ix > 0 ) fflush(apf[ix]);
+   }
+   consoleInfo.sacSetup = rv;
+   consoleRenewSetup();
+   return rv;
+ }
+ SQLITE_INTERNAL_LINKAGE void SQLITE_CDECL consoleRestore( void ){
+ # if CIO_WIN_WC_XLATE
+   static ConsoleInfo *pci = &consoleInfo;
+   if( pci->sacSetup ){
+     int ix;
+     for( ix=0; ix<3; ++ix ){
+       if( pci->sacSetup & (SAC_InConsole<<ix) ){
+         PerStreamTags *ppst = &pci->pstSetup[ix];
+         SetConsoleMode(ppst->hx, ppst->consMode);
+       }
+     }
+   }
+ # endif
+ }
+ #endif /* !defined(SQLITE_CIO_NO_TRANSLATE) */
+ #ifdef SQLITE_CIO_INPUT_REDIR
+ /* Say whether given FILE* is among those known, via either
+ ** consoleClassifySetup() or set{Output,Error}Stream, as
+ ** readable, and return an associated PerStreamTags pointer
+ ** if so. Otherwise, return 0.
+ */
+ static PerStreamTags * isKnownReadable(FILE *pf){
+   static PerStreamTags *apst[] = {
+     &consoleInfo.pstDesignated[0], &consoleInfo.pstSetup[0], 0
+   };
+   int ix = 0;
+   do {
+     if( apst[ix]->pf == pf ) break;
+   } while( apst[++ix] != 0 );
+   return apst[ix];
+ }
+ #endif
+ #ifndef SQLITE_CIO_NO_TRANSLATE
+ /* Say whether given FILE* is among those known, via either
+ ** consoleClassifySetup() or set{Output,Error}Stream, as
+ ** writable, and return an associated PerStreamTags pointer
+ ** if so. Otherwise, return 0.
+ */
+ static PerStreamTags * isKnownWritable(FILE *pf){
+   static PerStreamTags *apst[] = {
+     &consoleInfo.pstDesignated[1], &consoleInfo.pstDesignated[2],
+     &consoleInfo.pstSetup[1], &consoleInfo.pstSetup[2], 0
+   };
+   int ix = 0;
+   do {
+     if( apst[ix]->pf == pf ) break;
+   } while( apst[++ix] != 0 );
+   return apst[ix];
+ }
+ static FILE *designateEmitStream(FILE *pf, unsigned chix){
+   FILE *rv = consoleInfo.pstDesignated[chix].pf;
+   if( pf == invalidFileStream ) return rv;
+   else{
+     /* Setting a possibly new output stream. */
+     PerStreamTags *ppst = isKnownWritable(pf);
+     if( ppst != 0 ){
+       PerStreamTags pst = *ppst;
+       consoleInfo.pstDesignated[chix] = pst;
+     }else streamOfConsole(pf, &consoleInfo.pstDesignated[chix]);
+   }
+   return rv;
+ }
+ SQLITE_INTERNAL_LINKAGE FILE *setOutputStream(FILE *pf){
+   return designateEmitStream(pf, 1);
+ }
+ # ifdef CONSIO_SET_ERROR_STREAM
+ SQLITE_INTERNAL_LINKAGE FILE *setErrorStream(FILE *pf){
+   return designateEmitStream(pf, 2);
+ }
+ # endif
+ #endif /* !defined(SQLITE_CIO_NO_TRANSLATE) */
+ #ifndef SQLITE_CIO_NO_SETMODE
+ # if CIO_WIN_WC_XLATE
+ static void setModeFlushQ(FILE *pf, short bFlush, int mode){
+   if( bFlush ) fflush(pf);
+   _setmode(_fileno(pf), mode);
+ }
+ # else
+ #  define setModeFlushQ(f, b, m) if(b) fflush(f)
+ # endif
+ SQLITE_INTERNAL_LINKAGE void setBinaryMode(FILE *pf, short bFlush){
+   setModeFlushQ(pf, bFlush, _O_BINARY);
+ }
+ SQLITE_INTERNAL_LINKAGE void setTextMode(FILE *pf, short bFlush){
+   setModeFlushQ(pf, bFlush, _O_TEXT);
+ }
+ # undef setModeFlushQ
+ #else /* defined(SQLITE_CIO_NO_SETMODE) */
+ # define setBinaryMode(f, bFlush) do{ if((bFlush)) fflush(f); }while(0)
+ # define setTextMode(f, bFlush) do{ if((bFlush)) fflush(f); }while(0)
+ #endif /* defined(SQLITE_CIO_NO_SETMODE) */
+ #ifndef SQLITE_CIO_NO_TRANSLATE
+ # if CIO_WIN_WC_XLATE
+ /* Write buffer cBuf as output to stream known to reach console,
+ ** limited to ncTake char's. Return ncTake on success, else 0. */
+ static int conZstrEmit(PerStreamTags *ppst, const char *z, int ncTake){
+   int rv = 0;
+   if( z!=NULL ){
+     int nwc = MultiByteToWideChar(CP_UTF8,0, z,ncTake, 0,0);
+     if( nwc > 0 ){
+       WCHAR *zw = sqlite3_malloc64(nwc*sizeof(WCHAR));
+       if( zw!=NULL ){
+         nwc = MultiByteToWideChar(CP_UTF8,0, z,ncTake, zw,nwc);
+         if( nwc > 0 ){
+           /* Translation from UTF-8 to UTF-16, then WCHARs out. */
+           if( WriteConsoleW(ppst->hx, zw,nwc, 0, NULL) ){
+             rv = ncTake;
+           }
+         }
+         sqlite3_free(zw);
+       }
+     }
+   }
+   return rv;
+ }
+ /* For {f,o,e}PrintfUtf8() when stream is known to reach console. */
+ static int conioVmPrintf(PerStreamTags *ppst, const char *zFormat, va_list ap){
+   char *z = sqlite3_vmprintf(zFormat, ap);
+   if( z ){
+     int rv = conZstrEmit(ppst, z, (int)strlen(z));
+     sqlite3_free(z);
+     return rv;
+   }else return 0;
+ }
+ # endif /* CIO_WIN_WC_XLATE */
+ # ifdef CONSIO_GET_EMIT_STREAM
+ static PerStreamTags * getDesignatedEmitStream(FILE *pf, unsigned chix,
+                                                PerStreamTags *ppst){
+   PerStreamTags *rv = isKnownWritable(pf);
+   short isValid = (rv!=0)? isValidStreamInfo(rv) : 0;
+   if( rv != 0 && isValid ) return rv;
+   streamOfConsole(pf, ppst);
+   return ppst;
+ }
+ # endif
+ /* Get stream info, either for designated output or error stream when
+ ** chix equals 1 or 2, or for an arbitrary stream when chix == 0.
+ ** In either case, ppst references a caller-owned PerStreamTags
+ ** struct which may be filled in if none of the known writable
+ ** streams is being held by consoleInfo. The ppf parameter is an
+ ** output when chix!=0 and an input when chix==0.
+  */
+ static PerStreamTags *
+ getEmitStreamInfo(unsigned chix, PerStreamTags *ppst,
+                   /* in/out */ FILE **ppf){
+   PerStreamTags *ppstTry;
+   FILE *pfEmit;
+   if( chix > 0 ){
+     ppstTry = &consoleInfo.pstDesignated[chix];
+     if( !isValidStreamInfo(ppstTry) ){
+       ppstTry = &consoleInfo.pstSetup[chix];
+       pfEmit = ppst->pf;
+     }else pfEmit = ppstTry->pf;
+     if( !isValidStreamInfo(ppst) ){
+       pfEmit = (chix > 1)? stderr : stdout;
+       ppstTry = ppst;
+       streamOfConsole(pfEmit, ppstTry);
+     }
+     *ppf = pfEmit;
+   }else{
+     ppstTry = isKnownWritable(*ppf);
+     if( ppstTry != 0 ) return ppstTry;
+     streamOfConsole(*ppf, ppst);
+     return ppst;
+   }
+   return ppstTry;
+ }
+ SQLITE_INTERNAL_LINKAGE int oPrintfUtf8(const char *zFormat, ...){
+   va_list ap;
+   int rv;
+   FILE *pfOut;
+   PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */
+ # if CIO_WIN_WC_XLATE
+   PerStreamTags *ppst = getEmitStreamInfo(1, &pst, &pfOut);
+ # else
+   getEmitStreamInfo(1, &pst, &pfOut);
+ # endif
+   assert(zFormat!=0);
+   va_start(ap, zFormat);
+ # if CIO_WIN_WC_XLATE
+   if( pstReachesConsole(ppst) ){
+     rv = conioVmPrintf(ppst, zFormat, ap);
+   }else{
+ # endif
+     rv = vfprintf(pfOut, zFormat, ap);
+ # if CIO_WIN_WC_XLATE
+   }
+ # endif
+   va_end(ap);
+   return rv;
+ }
+ SQLITE_INTERNAL_LINKAGE int ePrintfUtf8(const char *zFormat, ...){
+   va_list ap;
+   int rv;
+   FILE *pfErr;
+   PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */
+ # if CIO_WIN_WC_XLATE
+   PerStreamTags *ppst = getEmitStreamInfo(2, &pst, &pfErr);
+ # else
+   getEmitStreamInfo(2, &pst, &pfErr);
+ # endif
+   assert(zFormat!=0);
+   va_start(ap, zFormat);
+ # if CIO_WIN_WC_XLATE
+   if( pstReachesConsole(ppst) ){
+     rv = conioVmPrintf(ppst, zFormat, ap);
+   }else{
+ # endif
+     rv = vfprintf(pfErr, zFormat, ap);
+ # if CIO_WIN_WC_XLATE
+   }
+ # endif
+   va_end(ap);
+   return rv;
+ }
+ SQLITE_INTERNAL_LINKAGE int fPrintfUtf8(FILE *pfO, const char *zFormat, ...){
+   va_list ap;
+   int rv;
+   PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */
+ # if CIO_WIN_WC_XLATE
+   PerStreamTags *ppst = getEmitStreamInfo(0, &pst, &pfO);
+ # else
+   getEmitStreamInfo(0, &pst, &pfO);
+ # endif
+   assert(zFormat!=0);
+   va_start(ap, zFormat);
+ # if CIO_WIN_WC_XLATE
+   if( pstReachesConsole(ppst) ){
+     maybeSetupAsConsole(ppst, 1);
+     rv = conioVmPrintf(ppst, zFormat, ap);
+     if( 0 == isKnownWritable(ppst->pf) ) restoreConsoleArb(ppst);
+   }else{
+ # endif
+     rv = vfprintf(pfO, zFormat, ap);
+ # if CIO_WIN_WC_XLATE
+   }
+ # endif
+   va_end(ap);
+   return rv;
+ }
+ SQLITE_INTERNAL_LINKAGE int fPutsUtf8(const char *z, FILE *pfO){
+   PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */
+ # if CIO_WIN_WC_XLATE
+   PerStreamTags *ppst = getEmitStreamInfo(0, &pst, &pfO);
+ # else
+   getEmitStreamInfo(0, &pst, &pfO);
+ # endif
+   assert(z!=0);
+ # if CIO_WIN_WC_XLATE
+   if( pstReachesConsole(ppst) ){
+     int rv;
+     maybeSetupAsConsole(ppst, 1);
+     rv = conZstrEmit(ppst, z, (int)strlen(z));
+     if( 0 == isKnownWritable(ppst->pf) ) restoreConsoleArb(ppst);
+     return rv;
+   }else {
+ # endif
+     return (fputs(z, pfO)<0)? 0 : (int)strlen(z);
+ # if CIO_WIN_WC_XLATE
+   }
+ # endif
+ }
+ SQLITE_INTERNAL_LINKAGE int ePutsUtf8(const char *z){
+   FILE *pfErr;
+   PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */
+ # if CIO_WIN_WC_XLATE
+   PerStreamTags *ppst = getEmitStreamInfo(2, &pst, &pfErr);
+ # else
+   getEmitStreamInfo(2, &pst, &pfErr);
+ # endif
+   assert(z!=0);
+ # if CIO_WIN_WC_XLATE
+   if( pstReachesConsole(ppst) ) return conZstrEmit(ppst, z, (int)strlen(z));
+   else {
+ # endif
+     return (fputs(z, pfErr)<0)? 0 : (int)strlen(z);
+ # if CIO_WIN_WC_XLATE
+   }
+ # endif
+ }
+ SQLITE_INTERNAL_LINKAGE int oPutsUtf8(const char *z){
+   FILE *pfOut;
+   PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */
+ # if CIO_WIN_WC_XLATE
+   PerStreamTags *ppst = getEmitStreamInfo(1, &pst, &pfOut);
+ # else
+   getEmitStreamInfo(1, &pst, &pfOut);
+ # endif
+   assert(z!=0);
+ # if CIO_WIN_WC_XLATE
+   if( pstReachesConsole(ppst) ) return conZstrEmit(ppst, z, (int)strlen(z));
+   else {
+ # endif
+     return (fputs(z, pfOut)<0)? 0 : (int)strlen(z);
+ # if CIO_WIN_WC_XLATE
+   }
+ # endif
+ }
+ #endif /* !defined(SQLITE_CIO_NO_TRANSLATE) */
+ #if !(defined(SQLITE_CIO_NO_UTF8SCAN) && defined(SQLITE_CIO_NO_TRANSLATE))
+ /* Skip over as much z[] input char sequence as is valid UTF-8,
+ ** limited per nAccept char's or whole characters and containing
+ ** no char cn such that ((1<<cn) & ccm)!=0. On return, the
+ ** sequence z:return (inclusive:exclusive) is validated UTF-8.
+ ** Limit: nAccept>=0 => char count, nAccept<0 => character
+  */
+ SQLITE_INTERNAL_LINKAGE const char*
+ zSkipValidUtf8(const char *z, int nAccept, long ccm){
+   int ng = (nAccept<0)? -nAccept : 0;
+   const char *pcLimit = (nAccept>=0)? z+nAccept : 0;
+   assert(z!=0);
+   while( (pcLimit)? (z<pcLimit) : (ng-- != 0) ){
+     char c = *z;
+     if( (c & 0x80) == 0 ){
+       if( ccm != 0L && c < 0x20 && ((1L<<c) & ccm) != 0 ) return z;
+       ++z; /* ASCII */
+     }else if( (c & 0xC0) != 0xC0 ) return z; /* not a lead byte */
+     else{
+       const char *zt = z+1; /* Got lead byte, look at trail bytes.*/
+       do{
+         if( pcLimit && zt >= pcLimit ) return z;
+         else{
+           char ct = *zt++;
+           if( ct==0 || (zt-z)>4 || (ct & 0xC0)!=0x80 ){
+             /* Trailing bytes are too few, too many, or invalid. */
+             return z;
+           }
+         }
+       } while( ((c <<= 1) & 0x40) == 0x40 ); /* Eat lead byte's count. */
+       z = zt;
+     }
+   }
+   return z;
+ }
+ #endif /*!(defined(SQLITE_CIO_NO_UTF8SCAN)&&defined(SQLITE_CIO_NO_TRANSLATE))*/
+ #ifndef SQLITE_CIO_NO_TRANSLATE
+ SQLITE_INTERNAL_LINKAGE int
+ fPutbUtf8(FILE *pfO, const char *cBuf, int nAccept){
+   assert(pfO!=0);
+ # if CIO_WIN_WC_XLATE
+   PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */
+   PerStreamTags *ppst = getEmitStreamInfo(0, &pst, &pfO);
+   if( pstReachesConsole(ppst) ){
+     int rv;
+     maybeSetupAsConsole(ppst, 1);
+     rv = conZstrEmit(ppst, cBuf, nAccept);
+     if( 0 == isKnownWritable(ppst->pf) ) restoreConsoleArb(ppst);
+     return rv;
+   }else {
+ # endif
+     return (int)fwrite(cBuf, 1, nAccept, pfO);
+ # if CIO_WIN_WC_XLATE
+   }
+ # endif
+ }
+ SQLITE_INTERNAL_LINKAGE int
+ oPutbUtf8(const char *cBuf, int nAccept){
+   FILE *pfOut;
+   PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */
+ # if CIO_WIN_WC_XLATE
+   PerStreamTags *ppst = getEmitStreamInfo(1, &pst, &pfOut);
+ # else
+   getEmitStreamInfo(1, &pst, &pfOut);
+ # endif
+ # if CIO_WIN_WC_XLATE
+   if( pstReachesConsole(ppst) ){
+     return conZstrEmit(ppst, cBuf, nAccept);
+   }else {
+ # endif
+     return (int)fwrite(cBuf, 1, nAccept, pfOut);
+ # if CIO_WIN_WC_XLATE
+   }
+ # endif
+ }
+ # ifdef CONSIO_EPUTB
+ SQLITE_INTERNAL_LINKAGE int
+ ePutbUtf8(const char *cBuf, int nAccept){
+   FILE *pfErr;
+   PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */
+   PerStreamTags *ppst = getEmitStreamInfo(2, &pst, &pfErr);
+ #  if CIO_WIN_WC_XLATE
+   if( pstReachesConsole(ppst) ){
+     return conZstrEmit(ppst, cBuf, nAccept);
+   }else {
+ #  endif
+     return (int)fwrite(cBuf, 1, nAccept, pfErr);
+ #  if CIO_WIN_WC_XLATE
+   }
+ #  endif
+ }
+ # endif /* defined(CONSIO_EPUTB) */
+ SQLITE_INTERNAL_LINKAGE char* fGetsUtf8(char *cBuf, int ncMax, FILE *pfIn){
+   if( pfIn==0 ) pfIn = stdin;
+ # if CIO_WIN_WC_XLATE
+   if( pfIn == consoleInfo.pstSetup[0].pf
+       && (consoleInfo.sacSetup & SAC_InConsole)!=0 ){
+ #  if CIO_WIN_WC_XLATE==1
+ #   define SHELL_GULP 150 /* Count of WCHARS to be gulped at a time */
+     WCHAR wcBuf[SHELL_GULP+1];
+     int lend = 0, noc = 0;
+     if( ncMax > 0 ) cBuf[0] = 0;
+     while( noc < ncMax-8-1 && !lend ){
+       /* There is room for at least 2 more characters and a 0-terminator. */
+       int na = (ncMax > SHELL_GULP*4+1 + noc)? SHELL_GULP : (ncMax-1 - noc)/4;
+ #   undef SHELL_GULP
+       DWORD nbr = 0;
+       BOOL bRC = ReadConsoleW(consoleInfo.pstSetup[0].hx, wcBuf, na, &nbr, 0);
+       if( bRC && nbr>0 && (wcBuf[nbr-1]&0xF800)==0xD800 ){
+         /* Last WHAR read is first of a UTF-16 surrogate pair. Grab its mate. */
+         DWORD nbrx;
+         bRC &= ReadConsoleW(consoleInfo.pstSetup[0].hx, wcBuf+nbr, 1, &nbrx, 0);
+         if( bRC ) nbr += nbrx;
+       }
+       if( !bRC || (noc==0 && nbr==0) ) return 0;
+       if( nbr > 0 ){
+         int nmb = WideCharToMultiByte(CP_UTF8, 0, wcBuf,nbr,0,0,0,0);
+         if( nmb != 0 && noc+nmb <= ncMax ){
+           int iseg = noc;
+           nmb = WideCharToMultiByte(CP_UTF8, 0, wcBuf,nbr,cBuf+noc,nmb,0,0);
+           noc += nmb;
+           /* Fixup line-ends as coded by Windows for CR (or "Enter".)
+           ** This is done without regard for any setMode{Text,Binary}()
+           ** call that might have been done on the interactive input.
+           */
+           if( noc > 0 ){
+             if( cBuf[noc-1]=='\n' ){
+               lend = 1;
+               if( noc > 1 && cBuf[noc-2]=='\r' ) cBuf[--noc-1] = '\n';
+             }
+           }
+           /* Check for ^Z (anywhere in line) too, to act as EOF. */
+           while( iseg < noc ){
+             if( cBuf[iseg]=='\x1a' ){
+               noc = iseg; /* Chop ^Z and anything following. */
+               lend = 1; /* Counts as end of line too. */
+               break;
+             }
+             ++iseg;
+           }
+         }else break; /* Drop apparent garbage in. (Could assert.) */
+       }else break;
+     }
+     /* If got nothing, (after ^Z chop), must be at end-of-file. */
+     if( noc > 0 ){
+       cBuf[noc] = 0;
+       return cBuf;
+     }else return 0;
+ #  endif
+   }else{
+ # endif
+     return fgets(cBuf, ncMax, pfIn);
+ # if CIO_WIN_WC_XLATE
+   }
+ # endif
+ }
+ #endif /* !defined(SQLITE_CIO_NO_TRANSLATE) */
+ #undef SHELL_INVALID_FILE_PTR
index 0000000000000000000000000000000000000000,4fb51d24d8da0372641f492b8bf436c564888208..2c0e486cd10bf16a0de6a5e6e473207cb30d9598
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,273 +1,278 @@@
+ /*
+ ** 2023 November 1
+ **
+ ** The author disclaims copyright to this source code.  In place of
+ ** a legal notice, here is a blessing:
+ **
+ **    May you do good and not evil.
+ **    May you find forgiveness for yourself and forgive others.
+ **    May you share freely, never taking more than you give.
+ **
+ ********************************************************************************
+ ** This file exposes various interfaces used for console and other I/O
+ ** by the SQLite project command-line tools. These interfaces are used
+ ** at either source conglomeration time, compilation time, or run time.
+ ** This source provides for either inclusion into conglomerated,
+ ** "single-source" forms or separate compilation then linking.
+ **
+ ** Platform dependencies are "hidden" here by various stratagems so
+ ** that, provided certain conditions are met, the programs using this
+ ** source or object code compiled from it need no explicit conditional
+ ** compilation in their source for their console and stream I/O.
+ **
+ ** The symbols and functionality exposed here are not a public API.
+ ** This code may change in tandem with other project code as needed.
++**
++** When this .h file and its companion .c are directly incorporated into
++** a source conglomeration (such as shell.c), the preprocessor symbol
++** CIO_WIN_WC_XLATE is defined as 0 or 1, reflecting whether console I/O
++** translation for Windows is effected for the build.
+ */
+ #ifndef SQLITE_INTERNAL_LINKAGE
+ # define SQLITE_INTERNAL_LINKAGE extern /* external to translation unit */
+ # include <stdio.h>
+ #else
+ # define SHELL_NO_SYSINC /* Better yet, modify mkshellc.tcl for this. */
+ #endif
+ #ifndef SQLITE3_H
+ # include "sqlite3.h"
+ #endif
+ #ifndef SQLITE_CIO_NO_CLASSIFY
+ /* Define enum for use with following function. */
+ typedef enum StreamsAreConsole {
+   SAC_NoConsole = 0,
+   SAC_InConsole = 1, SAC_OutConsole = 2, SAC_ErrConsole = 4,
+   SAC_AnyConsole = 0x7
+ } StreamsAreConsole;
+ /*
+ ** Classify the three standard I/O streams according to whether
+ ** they are connected to a console attached to the process.
+ **
+ ** Returns the bit-wise OR of SAC_{In,Out,Err}Console values,
+ ** or SAC_NoConsole if none of the streams reaches a console.
+ **
+ ** This function should be called before any I/O is done with
+ ** the given streams. As a side-effect, the given inputs are
+ ** recorded so that later I/O operations on them may be done
+ ** differently than the C library FILE* I/O would be done,
+ ** iff the stream is used for the I/O functions that follow,
+ ** and to support the ones that use an implicit stream.
+ **
+ ** On some platforms, stream or console mode alteration (aka
+ ** "Setup") may be made which is undone by consoleRestore().
+ */
+ SQLITE_INTERNAL_LINKAGE StreamsAreConsole
+ consoleClassifySetup( FILE *pfIn, FILE *pfOut, FILE *pfErr );
+ /* A usual call for convenience: */
+ #define SQLITE_STD_CONSOLE_INIT() consoleClassifySetup(stdin,stdout,stderr)
+ /*
+ ** After an initial call to consoleClassifySetup(...), renew
+ ** the same setup it effected. (A call not after is an error.)
+ ** This will restore state altered by consoleRestore();
+ **
+ ** Applications which run an inferior (child) process which
+ ** inherits the same I/O streams may call this function after
+ ** such a process exits to guard against console mode changes.
+ */
+ SQLITE_INTERNAL_LINKAGE void consoleRenewSetup(void);
+ /*
+ ** Undo any side-effects left by consoleClassifySetup(...).
+ **
+ ** This should be called after consoleClassifySetup() and
+ ** before the process terminates normally. It is suitable
+ ** for use with the atexit() C library procedure. After
+ ** this call, no console I/O should be done until one of
+ ** console{Classify or Renew}Setup(...) is called again.
+ **
+ ** Applications which run an inferior (child) process that
+ ** inherits the same I/O streams might call this procedure
+ ** before so that said process will have a console setup
+ ** however users have configured it or come to expect.
+ */
+ SQLITE_INTERNAL_LINKAGE void SQLITE_CDECL consoleRestore( void );
+ #else /* defined(SQLITE_CIO_NO_CLASSIFY) */
+ # define consoleClassifySetup(i,o,e)
+ # define consoleRenewSetup()
+ # define consoleRestore()
+ #endif /* defined(SQLITE_CIO_NO_CLASSIFY) */
+ #ifndef SQLITE_CIO_NO_REDIRECT
+ /*
+ ** Set stream to be used for the functions below which write
+ ** to "the designated X stream", where X is Output or Error.
+ ** Returns the previous value.
+ **
+ ** Alternatively, pass the special value, invalidFileStream,
+ ** to get the designated stream value without setting it.
+ **
+ ** Before the designated streams are set, they default to
+ ** those passed to consoleClassifySetup(...), and before
+ ** that is called they default to stdout and stderr.
+ **
+ ** It is error to close a stream so designated, then, without
+ ** designating another, use the corresponding {o,e}Emit(...).
+ */
+ SQLITE_INTERNAL_LINKAGE FILE *invalidFileStream;
+ SQLITE_INTERNAL_LINKAGE FILE *setOutputStream(FILE *pf);
+ # ifdef CONSIO_SET_ERROR_STREAM
+ SQLITE_INTERNAL_LINKAGE FILE *setErrorStream(FILE *pf);
+ # endif
+ #else
+ # define setOutputStream(pf)
+ # define setErrorStream(pf)
+ #endif /* !defined(SQLITE_CIO_NO_REDIRECT) */
+ #ifndef SQLITE_CIO_NO_TRANSLATE
+ /*
+ ** Emit output like fprintf(). If the output is going to the
+ ** console and translation from UTF-8 is necessary, perform
+ ** the needed translation. Otherwise, write formatted output
+ ** to the provided stream almost as-is, possibly with newline
+ ** translation as specified by set{Binary,Text}Mode().
+ */
+ SQLITE_INTERNAL_LINKAGE int fPrintfUtf8(FILE *pfO, const char *zFormat, ...);
+ /* Like fPrintfUtf8 except stream is always the designated output. */
+ SQLITE_INTERNAL_LINKAGE int oPrintfUtf8(const char *zFormat, ...);
+ /* Like fPrintfUtf8 except stream is always the designated error. */
+ SQLITE_INTERNAL_LINKAGE int ePrintfUtf8(const char *zFormat, ...);
+ /*
+ ** Emit output like fputs(). If the output is going to the
+ ** console and translation from UTF-8 is necessary, perform
+ ** the needed translation. Otherwise, write given text to the
+ ** provided stream almost as-is, possibly with newline
+ ** translation as specified by set{Binary,Text}Mode().
+ */
+ SQLITE_INTERNAL_LINKAGE int fPutsUtf8(const char *z, FILE *pfO);
+ /* Like fPutsUtf8 except stream is always the designated output. */
+ SQLITE_INTERNAL_LINKAGE int oPutsUtf8(const char *z);
+ /* Like fPutsUtf8 except stream is always the designated error. */
+ SQLITE_INTERNAL_LINKAGE int ePutsUtf8(const char *z);
+ /*
+ ** Emit output like fPutsUtf8(), except that the length of the
+ ** accepted char or character sequence is limited by nAccept.
+ **
+ ** Returns the number of accepted char values.
+ */
+ SQLITE_INTERNAL_LINKAGE int
+ fPutbUtf8(FILE *pfOut, const char *cBuf, int nAccept);
+ /* Like fPutbUtf8 except stream is always the designated output. */
+ SQLITE_INTERNAL_LINKAGE int
+ oPutbUtf8(const char *cBuf, int nAccept);
+ /* Like fPutbUtf8 except stream is always the designated error. */
+ #ifdef CONSIO_EPUTB
+ SQLITE_INTERNAL_LINKAGE int
+ ePutbUtf8(const char *cBuf, int nAccept);
+ #endif
+ /*
+ ** Collect input like fgets(...) with special provisions for input
+ ** from the console on platforms that require same. Defers to the
+ ** C library fgets() when input is not from the console. Newline
+ ** translation may be done as set by set{Binary,Text}Mode(). As a
+ ** convenience, pfIn==NULL is treated as stdin.
+ */
+ SQLITE_INTERNAL_LINKAGE char* fGetsUtf8(char *cBuf, int ncMax, FILE *pfIn);
+ /* Like fGetsUtf8 except stream is always the designated input. */
+ /* SQLITE_INTERNAL_LINKAGE char* iGetsUtf8(char *cBuf, int ncMax); */
+ #endif /* !defined(SQLITE_CIO_NO_TRANSLATE) */
+ #ifndef SQLITE_CIO_NO_SETMODE
+ /*
+ ** Set given stream for binary mode, where newline translation is
+ ** not done, or for text mode where, for some platforms, newlines
+ ** are translated to the platform's conventional char sequence.
+ ** If bFlush true, flush the stream.
+ **
+ ** An additional side-effect is that if the stream is one passed
+ ** to consoleClassifySetup() as an output, it is flushed first.
+ **
+ ** Note that binary/text mode has no effect on console I/O
+ ** translation. On all platforms, newline to the console starts
+ ** a new line and CR,LF chars from the console become a newline.
+ */
+ SQLITE_INTERNAL_LINKAGE void setBinaryMode(FILE *, short bFlush);
+ SQLITE_INTERNAL_LINKAGE void setTextMode(FILE *, short bFlush);
+ #endif
+ #ifdef SQLITE_CIO_PROMPTED_IN
+ typedef struct Prompts {
+   int numPrompts;
+   const char **azPrompts;
+ } Prompts;
+ /*
+ ** Macros for use of a line editor.
+ **
+ ** The following macros define operations involving use of a
+ ** line-editing library or simple console interaction.
+ ** A "T" argument is a text (char *) buffer or filename.
+ ** A "N" argument is an integer.
+ **
+ ** SHELL_ADD_HISTORY(T) // Record text as line(s) of history.
+ ** SHELL_READ_HISTORY(T) // Read history from file named by T.
+ ** SHELL_WRITE_HISTORY(T) // Write history to file named by T.
+ ** SHELL_STIFLE_HISTORY(N) // Limit history to N entries.
+ **
+ ** A console program which does interactive console input is
+ ** expected to call:
+ ** SHELL_READ_HISTORY(T) before collecting such input;
+ ** SHELL_ADD_HISTORY(T) as record-worthy input is taken;
+ ** SHELL_STIFLE_HISTORY(N) after console input ceases; then
+ ** SHELL_WRITE_HISTORY(T) before the program exits.
+ */
+ /*
+ ** Retrieve a single line of input text from an input stream.
+ **
+ ** If pfIn is the input stream passed to consoleClassifySetup(),
+ ** and azPrompt is not NULL, then a prompt is issued before the
+ ** line is collected, as selected by the isContinuation flag.
+ ** Array azPrompt[{0,1}] holds the {main,continuation} prompt.
+ **
+ ** If zBufPrior is not NULL then it is a buffer from a prior
+ ** call to this routine that can be reused, or will be freed.
+ **
+ ** The result is stored in space obtained from malloc() and
+ ** must either be freed by the caller or else passed back to
+ ** this function as zBufPrior for reuse.
+ **
+ ** This function may call upon services of a line-editing
+ ** library to interactively collect line edited input.
+ */
+ SQLITE_INTERNAL_LINKAGE char *
+ shellGetLine(FILE *pfIn, char *zBufPrior, int nLen,
+              short isContinuation, Prompts azPrompt);
+ #endif /* defined(SQLITE_CIO_PROMPTED_IN) */
+ /*
+ ** TBD: Define an interface for application(s) to generate
+ ** completion candidates for use by the line-editor.
+ **
+ ** This may be premature; the CLI is the only application
+ ** that does this. Yet, getting line-editing melded into
+ ** console I/O is desirable because a line-editing library
+ ** may have to establish console operating mode, possibly
+ ** in a way that interferes with the above functionality.
+ */
+ #if !(defined(SQLITE_CIO_NO_UTF8SCAN)&&defined(SQLITE_CIO_NO_TRANSLATE))
+ /* Skip over as much z[] input char sequence as is valid UTF-8,
+ ** limited per nAccept char's or whole characters and containing
+ ** no char cn such that ((1<<cn) & ccm)!=0. On return, the
+ ** sequence z:return (inclusive:exclusive) is validated UTF-8.
+ ** Limit: nAccept>=0 => char count, nAccept<0 => character
+  */
+ SQLITE_INTERNAL_LINKAGE const char*
+ zSkipValidUtf8(const char *z, int nAccept, long ccm);
+ #endif
diff --cc manifest
index 721aac63bc3d845548cf4827cefff7d6799ff22b,049a2be3b35f66ceeb7c43eb86fec417ed3e1023..a6dac2dd9abbff29f79750211004434b5e1d1399
+++ b/manifest
@@@ -1,11 -1,11 +1,11 @@@
- C Fix\sthe\strace3-4.4\stest\sto\sbe\smore\srebust\sagainst\stiming\squirks.
- D 2023-11-21T12:02:04.720
 -C Sync\sw/trunk\sas\spre-merge-to-trunk\ssanity\scheck.
 -D 2023-11-21T15:55:31.480
++C Merge\sconsole\sI/O\schanges\sfor\sWindows\sCLI.
++D 2023-11-21T18:26:06.197
  F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
  F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
  F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
- F Makefile.in a0cf17b2a456ae24959030b979bc6f1ec5efc74a240fb834c12e63dd1127cd72
+ F Makefile.in 890caf094636c308bc981032baf8f9208bf307755f9197ae4218a9fbcec2e449
  F Makefile.linux-gcc f3842a0b1efbfbb74ac0ef60e56b301836d05b4d867d014f714fa750048f1ab6
- F Makefile.msc f0cf219350d9af4fba411b4f6306dce2adc897484e8f446de1fb4f40de674d00
 -F Makefile.msc f90f75b3b62809e1d13e5362b84a5cce90bc9d6772e4092be52c2b9a6638a7ed
++F Makefile.msc 59bb36dba001f0b38212be0794fb838f25371008b180929bcf08aa799694c168
  F README.md 963d30019abf0cc06b263cd2824bce022893f3f93a531758f6f04ff2194a16a8
  F VERSION 73573d4545343f001bf5dc5461173a7c78c203dd046cabcf99153878cf25d3a6
  F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
@@@ -50,6 -50,8 +50,8 @@@ F ext/README.md fd5f78013b0a2bc6f0067af
  F ext/async/README.txt e12275968f6fde133a80e04387d0e839b0c51f91
  F ext/async/sqlite3async.c 6f247666b495c477628dd19364d279c78ea48cd90c72d9f9b98ad1aff3294f94
  F ext/async/sqlite3async.h 46b47c79357b97ad85d20d2795942c0020dc20c532114a49808287f04aa5309a
 -F ext/consio/console_io.c 48536ed2f2add0abd8be80f72cae46e19738fa671b69daa88197df53a55da7c4
 -F ext/consio/console_io.h b8dce7fa926b51f19b5d1c516219ac91b5c1ccddd467b2510e2557c900830f7d
++F ext/consio/console_io.c 0d9e79742930dadc13f4819fa0fe602676ac32c825304d498171c5922a3863ce
++F ext/consio/console_io.h d9ba2de923f11348919cccc2ba161ccbf2e417b866d2b7d072329e6c702eb242
  F ext/expert/README.md b321c2762bb93c18ea102d5a5f7753a4b8bac646cb392b3b437f633caf2020c3
  F ext/expert/expert.c d548d603a4cc9e61f446cc179c120c6713511c413f82a4a32b1e1e69d3f086a4
  F ext/expert/expert1.test 0dd5cb096d66bed593e33053a3b364f6ef52ed72064bf5cf298364636dbf3cd6
@@@ -726,7 -729,7 +729,7 @@@ F src/random.c 606b00941a1d7dd09c381d32
  F src/resolve.c d017bad7ba8e778617701a0e986fdeb393d67d6afa84fb28ef4e8b8ad2acf916
  F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97
  F src/select.c 85857bedd2913d888aa571755b48c54cd2e6e7fcb0087e19b226ee0368cfda1e
- F src/shell.c.in 297625a1ba6ea1c08bc2ea1b838b646cad309b62bf08df0e379355629404f140
 -F src/shell.c.in 9bfdb6faaea31e2ff0f940f1234e39f505f263b068ba6736838c7b6ad9d7d8ad
++F src/shell.c.in 345be14456aeadfaaeced4149563a4a6d70942d8a38a1cd27b75d4e491757028
  F src/sqlite.h.in d93a4821d2f792467a60f7dc81268d1bb8634f40c31694ef254cab4f9921f96a
  F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
  F src/sqlite3ext.h 3f046c04ea3595d6bfda99b781926b17e672fd6d27da2ba6d8d8fc39981dcb54
@@@ -2140,8 -2143,8 +2143,8 @@@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a9
  F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
  F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
  F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
- P f5b3eb0fc8936ba274a7654ff6dfa7d4654bd8dbca7f3a5ec1134b0b5260d59d
- R c3df342b9429d8c9fdce76751979c422
- U drh
- Z 57a5e144d820d25acd5cfb831cc09e5a
 -P 39e30c5f9cc6dcac003255734e3ce1ac5b05349ea1a25e1c108b5f6d1d97612b 8936daa08243729d8538bb7288bbefb43f3bd842a0d4b2e8019092f5701c2926
 -R 2d6da084016b6aec46129cec2ee38947
++P 8936daa08243729d8538bb7288bbefb43f3bd842a0d4b2e8019092f5701c2926 448d6a1182d29940d5d34be2ce67df5601b688cd902dbbe97e95073f982a49ce
++R 764d6a65ddcbf1b62de463cc42b71475
+ U larrybr
 -Z 345a9a9faa2545dfaaa7f274ef6f8330
++Z 9d8c4f0e647c59f8c21d5587e8bd311b
  # Remove this line to create a well-formed Fossil manifest.
diff --cc manifest.uuid
index 73e608bdbe973a181b97a5217afc867a2c0e2d3a,79188a1745d3a7a2c115519fe3e2d760a7448d2c..094c6b93acf074bd02e9de9a1dd20d0062351daa
@@@ -1,1 -1,1 +1,1 @@@
- 8936daa08243729d8538bb7288bbefb43f3bd842a0d4b2e8019092f5701c2926
 -448d6a1182d29940d5d34be2ce67df5601b688cd902dbbe97e95073f982a49ce
++935a8a8ee76d0014df42c1480e044fd1c2dfc26e78abb587d99d861d2ae5eb27
diff --cc src/shell.c.in
index 0e0dbd36c76feeabb3e66d3879fb1f81de55b99d,91d99d336c07136409fe2d17fda8b272d5437399..62420741278282c3535f54be303eba97913424ad
@@@ -450,28 -479,9 +479,9 @@@ static int bail_on_error = 0
  static int stdin_is_interactive = 1;
  
  /*
- ** If build is for non-RT Windows, without 3rd-party line editing,
- ** console input and output may be done in a UTF-8 compatible way,
- ** if the OS is capable of it and the --no-utf8 option is not seen.
- */
- #if (defined(_WIN32) || defined(WIN32)) && SHELL_USE_LOCAL_GETLINE \
-   && !defined(SHELL_OMIT_WIN_UTF8) && !SQLITE_OS_WINRT
- # define SHELL_WIN_UTF8_OPT 1
- /* Record whether to do UTF-8 console I/O translation per stream. */
-   static int console_utf8_in = 0;
-   static int console_utf8_out = 0;
- /* Record whether can do UTF-8 or --no-utf8 seen in invocation. */
-   static int mbcs_opted = 1; /* Assume cannot do until shown otherwise. */
- #else
- # define console_utf8_in 0
- # define console_utf8_out 0
- # define SHELL_WIN_UTF8_OPT 0
- #endif
- /*
--** On Windows systems we have to know if standard output is a console
--** in order to translate UTF-8 into MBCS.  The following variable is
--** true if translation is required.
++** On Windows systems we need to know if standard output is a console
++** in order to show that UTF-16 translation is done in the sign-on
++** banner. The following variable is true if it is the console.
  */
  static int stdout_is_console = 1;
  
@@@ -10315,8 -10077,8 +10077,7 @@@ static int do_meta_command(char *zLine
          }
          if( pChng
            && fwrite(pChng, szChng, 1, out)!=1 ){
-           raw_printf(stderr, "ERROR: Failed to write entire %d-byte output\n",
-                   szChng);
 -          eputf("ERROR: Failed to write entire %d-byte output\n",
 -                szChng);
++          eputf("ERROR: Failed to write entire %d-byte output\n", szChng);
          }
          sqlite3_free(pChng);
          fclose(out);
@@@ -12117,7 -11861,7 +11860,7 @@@ static void printBold(const char *zText
           FOREGROUND_RED|FOREGROUND_INTENSITY
    );
  #endif
-   printf("%s", zText);
 -  oputf("%s", zText);
++  oputz(zText);
  #if !SQLITE_OS_WINRT
    SetConsoleTextAttribute(out, defaultScreenInfo.wAttributes);
  #endif
@@@ -12134,8 -11878,8 +11877,7 @@@ static void printBold(const char *zText
  */
  static char *cmdline_option_value(int argc, char **argv, int i){
    if( i==argc ){
-     utf8_printf(stderr, "%s: Error: missing argument to %s\n",
-             argv[0], argv[argc-1]);
 -    eputf("%s: Error: missing argument to %s\n",
 -          argv[0], argv[argc-1]);
++    eputf("%s: Error: missing argument to %s\n", argv[0], argv[argc-1]);
      exit(1);
    }
    return argv[i];
@@@ -12229,7 -11971,7 +11969,7 @@@ int SQLITE_CDECL wmain(int argc, wchar_
    signal(SIGINT, interrupt_handler);
  #elif (defined(_WIN32) || defined(WIN32)) && !defined(_WIN32_WCE)
    if( !SetConsoleCtrlHandler(ConsoleCtrlHandler, TRUE) ){
-     fprintf(stderr, "No ^C handler.\n");
 -    eputf("No ^C handler.\n");
++    eputz("No ^C handler.\n");
    }
  #endif
  
      if( stdin_is_interactive ){
        char *zHome;
        char *zHistory;
--      const char *zCharset = "";
        int nHistory;
- #if SHELL_WIN_UTF8_OPT
-       switch( console_utf8_in+2*console_utf8_out ){
-       default: case 0: break;
-       case 1: zCharset = " (utf8 in)"; break;
-       case 2: zCharset = " (utf8 out)"; break;
-       case 3: zCharset = " (utf8 I/O)"; break;
-       }
- #endif
-       printf(
-         "SQLite version %s %.19s%s\n" /*extra-version-info*/
-         "Enter \".help\" for usage hints.\n",
-         sqlite3_libversion(), sqlite3_sourceid(), zCharset
-       );
 -#if SHELL_CON_TRANSLATE==1
 -      zCharset = " (UTF-16 console I/O)";
 -#elif SHELL_CON_TRANSLATE==2
 -      zCharset = " (MBCS console I/O)";
++#if CIO_WIN_WC_XLATE
++# define SHELL_CIO_CHAR_SET (stdout_is_console? " (UTF-16 console I/O)" : "")
++#else
++# define SHELL_CIO_CHAR_SET ""
+ #endif
+       oputf("SQLite version %s %.19s%s\n" /*extra-version-info*/
+             "Enter \".help\" for usage hints.\n",
 -            sqlite3_libversion(), sqlite3_sourceid(), zCharset);
++            sqlite3_libversion(), sqlite3_sourceid(), SHELL_CIO_CHAR_SET);
        if( warnInmemoryDb ){
-         printf("Connected to a ");
+         oputz("Connected to a ");
          printBold("transient in-memory database");
-         printf(".\nUse \".open FILENAME\" to reopen on a "
-                "persistent database.\n");
+         oputz(".\nUse \".open FILENAME\" to reopen on a"
+               persistent database.\n");
        }
        zHistory = getenv("SQLITE_HISTORY");
        if( zHistory ){