]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Pervasive changes to console_io.{c,h} in support of simplifying ubiquitous emit ops...
authorlarrybr <larrybr@noemail.net>
Sat, 11 Nov 2023 06:20:38 +0000 (06:20 +0000)
committerlarrybr <larrybr@noemail.net>
Sat, 11 Nov 2023 06:20:38 +0000 (06:20 +0000)
FossilOrigin-Name: 14762a004cdf37d1e12f26aadff8ed3824893278f22ff141de86dd44d9b250f3

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

index 35016b0c4a730d1cf2bda522ca8936c042455b71,0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..5d38feef3778c56d510625b03bee09ad77c37d6b
mode 100755,000000,000000..100755
--- /dev/null
--- /dev/null
@@@@ -1,449 -1,0 -1,0 +1,637 @@@@
-  ** This file implements various interfaces used for console I/O by the
-  ** SQLite project command-line tools, as explained in console_io.h .
 ++/*
 ++** 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.
 ++**
 ++********************************************************************************
-  #if defined(_WIN32) || defined(WIN32)
+++** 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
 ++
-  extern char *sqlite3_win32_utf8_to_mbcs_v2(const char *, int);
+++#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
 ++# ifdef SHELL_LEGACY_CONSOLE_IO
 ++#  define SHELL_CON_TRANSLATE 2 /* Use UTF-8/MBCS translation for console I/O */
-      (fileDesc!=-2)? _get_osfhandle(fileDesc) : (intptr_t)INVALID_HANDLE_VALUE
 ++# else
 ++#  define SHELL_CON_TRANSLATE 1 /* Use WCHAR Windows APIs for console I/O */
 ++# endif
 ++#else
 ++# ifndef SHELL_NO_SYSINC
 ++#  include <unistd.h>
 ++# endif
 ++# define SHELL_CON_TRANSLATE 0 /* Use plain C library stream I/O at console */
 ++#endif
 ++
 ++#if SHELL_CON_TRANSLATE
 ++static HANDLE handleOfFile(FILE *pf){
 ++  int fileDesc = _fileno(pf);
 ++  union { intptr_t osfh; HANDLE fh; } fid = {
-    DWORD consMode;
+++    (fileDesc>=0)? _get_osfhandle(fileDesc) : (intptr_t)INVALID_HANDLE_VALUE
 ++  };
 ++  return fid.fh;
 ++}
 ++#endif
 ++
 ++typedef struct PerStreamTags {
 ++#if SHELL_CON_TRANSLATE
-  static short fileOfConsole(FILE *pf, PerStreamTags *ppst){
 ++  HANDLE hx;
+++  DWORD consMode;
+++#else
+++  short reachesConsole;
 ++#endif
 ++  FILE *pf;
 ++} PerStreamTags;
 ++
-    DWORD dwj;
+++/* Define NULL-like value for things which can validly be 0. */
+++#define SHELL_INVALID_FILE_PTR ((FILE *)~0)
+++#if SHELL_CON_TRANSLATE
+++# define SHELL_INVALID_CONS_MODE 0xFFFF0000
+++#endif
+++
+++#if SHELL_CON_TRANSLATE
+++# define CI_INITIALIZER \
+++  { INVALID_HANDLE_VALUE, SHELL_INVALID_CONS_MODE, SHELL_INVALID_FILE_PTR }
+++#else
+++# define CI_INITIALIZER { 0, SHELL_INVALID_FILE_PTR }
+++#endif
+++
+++/* Quickly say whether a known output is going to the console. */
+++static short pstReachesConsole(PerStreamTags *ppst){
+++#if SHELL_CON_TRANSLATE
+++  return (ppst->hx != INVALID_HANDLE_VALUE);
+++#else
+++  return (ppst->reachesConsole != 0);
+++#endif
+++}
+++
+++#if SHELL_CON_TRANSLATE
+++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 SHELL_CON_TRANSLATE
 ++  short rv = 0;
-      rv = (GetFileType(fh) == FILE_TYPE_CHAR && GetConsoleMode(fh,&dwj));
-      if( rv ){
-        ppst->hx = fh;
-        ppst->pf = pf;
-        GetConsoleMode(fh, &ppst->consMode);
-      }
+++  DWORD dwCM = SHELL_INVALID_CONS_MODE;
 ++  HANDLE fh = handleOfFile(pf);
+++  ppst->pf = pf;
 ++  if( INVALID_HANDLE_VALUE != fh ){
-    return (short)isatty(fileno(pf));
+++    rv = (GetFileType(fh) == FILE_TYPE_CHAR && GetConsoleMode(fh,&dwCM));
 ++  }
+++  ppst->hx = (rv)? fh : INVALID_HANDLE_VALUE;
+++  ppst->consMode = dwCM;
 ++  return rv;
 ++#else
-  #define SHELL_INVALID_FILE_PTR ((FILE *)sizeof(FILE*))
-  #define SHELL_INVALID_CONS_MODE 0xFFFF0000
-  
+++  ppst->pf = pf;
+++  ppst->reachesConsole = ( (short)isatty(fileno(pf)) );
+++  return ppst->reachesConsole;
 ++#endif
 ++}
 ++
-    /* int iInitialFmode[3];
-    ** Above only needed for legacy console I/O for callable CLI.
-    ** Because that state cannot be obtained from each FILE *,
-    ** there will be no exact restoration of console state for
-    ** the CLI when built with SHELL_LEGACY_CONSOLE_IO defined.
-    */
-    PerStreamTags pst[3];
-  #if SHELL_CON_TRANSLATE
-    unsigned char haveInput;
-    unsigned char outputIx;
-    unsigned char stdinEof;
-  #endif
-    ConsoleStdConsStreams cscs;
 ++#if SHELL_CON_TRANSLATE
+++/* 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 {
-  # define CI_INITIALIZER \
-    {SHELL_INVALID_CONS_MODE, INVALID_HANDLE_VALUE, SHELL_INVALID_FILE_PTR }
+++  PerStreamTags pstSetup[3];
+++  PerStreamTags pstDesignated[3];
+++  StreamsAreConsole sacSetup;
+++  StreamsAreConsole sacDesignated;
 ++} ConsoleInfo;
 ++
+++static short isValidStreamInfo(PerStreamTags *ppst){
+++  return (ppst->pf != SHELL_INVALID_FILE_PTR);
+++}
+++
+++static ConsoleInfo consoleInfo = {
+++  { /* pstSetup */ CI_INITIALIZER, CI_INITIALIZER, CI_INITIALIZER },
+++  { /* pstDesignated[] */ CI_INITIALIZER, CI_INITIALIZER, CI_INITIALIZER },
+++  SAC_NoConsole, SAC_NoConsole /* sacSetup, sacDesignated */
+++};
+++#undef SHELL_INVALID_FILE_PTR
+++#undef CI_INITIALIZER
+++
+++SQLITE_INTERNAL_LINKAGE FILE* invalidFileStream = (FILE *)~0;
+++
+++static void maybeSetupAsConsole(PerStreamTags *ppst, short odir){
 ++#if SHELL_CON_TRANSLATE
-  # define CI_INITIALIZER { SHELL_INVALID_FILE_PTR }
+++  if( pstReachesConsole(ppst) ){
+++    DWORD cm = odir? SHELL_CONO_MODE : SHELL_CONI_MODE;
+++    SetConsoleMode(ppst->hx, cm);
+++# if SHELL_CON_TRANSLATE == 2
+++    _setmode(_fileno(ppst->pf), _O_TEXT);
+++# endif
+++  }
 ++#else
-  static ConsoleInfo consoleInfo = {
-    { /* pst */ CI_INITIALIZER, CI_INITIALIZER, CI_INITIALIZER },
+++  (void)ppst;
+++  (void)odir;
 ++#endif
+++}
 ++
-    0, 0, 1, /* haveInput, outputIx, stdinEof */
+++SQLITE_INTERNAL_LINKAGE void consoleRenewSetup(void){
 ++#if SHELL_CON_TRANSLATE
-    CSCS_NoConsole
-  };
-  #undef CI_INITIALIZER
+++  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 ConsoleStdConsStreams
+++}
 ++
-    ConsoleStdConsStreams rv = CSCS_NoConsole;
-    FILE *apf[3] = { pfIn, pfOut, pfErr };
+++SQLITE_INTERNAL_LINKAGE StreamsAreConsole
 ++consoleClassifySetup( FILE *pfIn, FILE *pfOut, FILE *pfErr ){
-      PerStreamTags *ppst = &consoleInfo.pst[ix];
-      if( fileOfConsole(apf[ix], ppst) ){
-  #if SHELL_CON_TRANSLATE
-        DWORD cm = (ix==0)? SHELL_CONI_MODE : SHELL_CONO_MODE;
-        if( ix==0 ){
-          consoleInfo.haveInput = 1;
-          consoleInfo.stdinEof = 0;
-        }else{
-          consoleInfo.outputIx |= ix;
-        }
-        SetConsoleMode(ppst->hx, cm);
-  #endif
-        rv |= (CSCS_InConsole<<ix);
+++  StreamsAreConsole rv = SAC_NoConsole;
+++  FILE* apf[3] = { pfIn, pfOut, pfErr };
 ++  int ix;
 ++  for( ix = 2; ix >= 0; --ix ){
-    consoleInfo.cscs = rv;
+++    PerStreamTags *ppst = &consoleInfo.pstSetup[ix];
+++    if( streamOfConsole(apf[ix], ppst) ){
+++      rv |= (SAC_InConsole<<ix);
 ++    }
+++    consoleInfo.pstDesignated[ix] = *ppst;
 ++    if( ix > 0 ) fflush(apf[ix]);
 ++#if SHELL_CON_TRANSLATE == 2
 ++    _setmode(_fileno(apf[ix]), _O_TEXT);
 ++#endif
 ++  }
-    if( consoleInfo.cscs ){
+++  consoleInfo.sacSetup = rv;
+++  consoleRenewSetup();
 ++  return rv;
 ++}
 ++
 ++SQLITE_INTERNAL_LINKAGE void SQLITE_CDECL consoleRestore( void ){
-        if( consoleInfo.cscs & (CSCS_InConsole<<ix) ){
-          PerStreamTags *ppst = &consoleInfo.pst[ix];
-  #if SHELL_CON_TRANSLATE == 2
+++#if SHELL_CON_TRANSLATE
+++  static ConsoleInfo *pci = &consoleInfo;
+++  if( pci->sacSetup ){
 ++    int ix;
 ++    for( ix=0; ix<3; ++ix ){
-          /* Consider: Read these modes in consoleClassifySetup somehow.
+++      if( pci->sacSetup & (SAC_InConsole<<ix) ){
+++        PerStreamTags *ppst = &pci->pstSetup[ix];
+++# if SHELL_CON_TRANSLATE == 2
 ++        static int tmode = _O_TEXT;
-          _setmode(_fileno(consoleInfo.pst[ix].pf), tmode);
-  #endif
-  #if SHELL_CON_TRANSLATE
+++        /* Consider: Read this mode in consoleClassifySetup somehow.
 ++        ** A _get_fmode() call almost works. But not with gcc, yet.
 ++        ** This has to be done to make the CLI a callable function
 ++        ** when legacy console I/O is done. (This may never happen.)
 ++        */
-          ppst->hx = INVALID_HANDLE_VALUE;
-  #endif
-          ppst->pf = SHELL_INVALID_FILE_PTR;
+++        _setmode(_fileno(pci->pstSetup[ix].pf), tmode);
+++# endif
 ++        SetConsoleMode(ppst->hx, ppst->consMode);
-        consoleInfo.cscs = CSCS_NoConsole;
-  #if SHELL_CON_TRANSLATE
-        consoleInfo.stdinEof = consoleInfo.haveInput = consoleInfo.outputIx= 0;
-  #endif
 ++      }
-  static short isConOut(FILE *pf){
-    if( pf==consoleInfo.pst[1].pf ) return 1;
-    else if( pf==consoleInfo.pst[2].pf ) return 2;
-    else return 0;
 ++    }
 ++  }
+++#endif
 ++}
 ++
-    short ico = isConOut(pf);
-    if( ico>1 || bFlush ) fflush(pf);
+++/* 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];
+++}
+++
+++/* 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);
+++}
+++SQLITE_INTERNAL_LINKAGE FILE *setErrorStream(FILE *pf){
+++  return designateEmitStream(pf, 2);
 ++}
 ++
 ++#if SHELL_CON_TRANSLATE
 ++static void setModeFlushQ(FILE *pf, short bFlush, int mode){
-  # define setModeFlushQ(f, b, m) if(isConOut(f)>0||b) fflush(f)
+++  if( bFlush ) fflush(pf);
 ++  _setmode(_fileno(pf), mode);
 ++}
 ++#else
-  /* Write plain 0-terminated output to stream known as console. */
-  static int conioZstrOut(int rch, const char *z){
+++# 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
 ++
 ++#if SHELL_CON_TRANSLATE
-      FILE *pfO = consoleInfo.pst[rch].pf;
+++/* Write plain 0-terminated output to stream known as reaching console. */
+++static int conioZstrOut(PerStreamTags *ppst, const char *z){
 ++  int rv = 0;
 ++  if( z!=NULL && *z!=0 ){
 ++    int nc;
 ++    int nwc;
 ++# if SHELL_CON_TRANSLATE == 2
 ++    UINT cocp = GetConsoleOutputCP();
-            if( WriteConsoleW(consoleInfo.pst[rch].hx, zw,nwc, 0, NULL) ){
+++    FILE *pfO = ppst->pf;
 ++    if( cocp == CP_UTF8 ){
 ++      /* This is not legacy action. But it can work better,
 ++      ** when the console putatively can handle UTF-8. */
 ++      return fputs(z, pfO)<0 ? 0 : (int)strlen(z);
 ++    }
 ++# endif
 ++    nc = (int)strlen(z);
 ++    nwc = MultiByteToWideChar(CP_UTF8,0, z,nc, 0,0);
 ++    if( nwc > 0 ){
 ++      WCHAR *zw = sqlite3_malloc64(nwc*sizeof(WCHAR));
 ++      if( zw!=NULL ){
 ++        nwc = MultiByteToWideChar(CP_UTF8,0, z,nc, zw,nwc);
 ++        if( nwc > 0 ){
 ++# if SHELL_CON_TRANSLATE == 2
 ++          /* Legacy translation to active code page, then MBCS out. */
 ++          rv = WideCharToMultiByte(cocp,0, zw,nwc, 0,0, 0,0);
 ++          if( rv != 0 ){
 ++            char *zmb = sqlite3_malloc64(rv+1);
 ++            if( zmb != NULL ){
 ++              rv = WideCharToMultiByte(cocp,0, zw,nwc, zmb,rv, 0,0);
 ++              zmb[rv] = 0;
 ++              if( fputs(zmb, pfO)<0 ) rv = 0;
 ++              sqlite3_free(zmb);
 ++            }
 ++          }
 ++# elif SHELL_CON_TRANSLATE == 1
 ++          /* Translation from UTF-8 to UTF-16, then WCHARs out. */
-  /* For fprintfUtf8() and printfUtf8() when stream is known as console. */
-  static int conioVmPrintf(int rch, const char *zFormat, va_list ap){
+++          if( WriteConsoleW(ppst->hx, zw,nwc, 0, NULL) ){
 ++            rv = nc;
 ++          }
 ++# endif
 ++        }
 ++        sqlite3_free(zw);
 ++      }
 ++    }
 ++  }
 ++  return rv;
 ++}
 ++
-    int rv = conioZstrOut(rch, z);
+++/* 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);
-  SQLITE_INTERNAL_LINKAGE int printfUtf8(const char *zFormat, ...){
+++  int rv = conioZstrOut(ppst, z);
 ++  sqlite3_free(z);
 ++  return rv;
 ++}
+++#endif /* SHELL_CON_TRANSLATE */
+++
+++
+++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;
+++}
+++
+++/* 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; /* Needed only for heretofore unknown streams. */
+++  PerStreamTags *ppst = getEmitStreamInfo(1, &pst, &pfOut);
+++
+++  va_start(ap, zFormat);
+++#if SHELL_CON_TRANSLATE
+++  if( pstReachesConsole(ppst) ){
+++    rv = conioVmPrintf(ppst, zFormat, ap);
+++  }else{
 ++#endif
+++    rv = vfprintf(pfOut, zFormat, ap);
+++#if SHELL_CON_TRANSLATE
+++  }
+++#endif
+++  va_end(ap);
+++  return rv;
+++}
 ++
-    if( SHELL_INVALID_FILE_PTR != consoleInfo.pst[1].pf ){
-      rv = conioVmPrintf(1, zFormat, ap);
+++SQLITE_INTERNAL_LINKAGE int ePrintfUtf8(const char *zFormat, ...){
 ++  va_list ap;
 ++  int rv;
+++  FILE *pfErr;
+++  PerStreamTags pst; /* Needed only for heretofore unknown streams. */
+++  PerStreamTags *ppst = getEmitStreamInfo(2, &pst, &pfErr);
+++
 ++  va_start(ap, zFormat);
 ++#if SHELL_CON_TRANSLATE
-      rv = vfprintf(stdout, zFormat, ap);
+++  if( pstReachesConsole(ppst) ){
+++    rv = conioVmPrintf(ppst, zFormat, ap);
 ++  }else{
 ++#endif
-  #undef SHELL_INVALID_FILE_PTR
+++    rv = vfprintf(pfErr, zFormat, ap);
 ++#if SHELL_CON_TRANSLATE
 ++  }
 ++#endif
 ++  va_end(ap);
 ++  return rv;
 ++}
-  SQLITE_INTERNAL_LINKAGE int fprintfUtf8(FILE *pfO, const char *zFormat, ...){
 ++
-    short rch = isConOut(pfO);
-    if( rch > 0 ){
-      rv = conioVmPrintf(rch, zFormat, ap);
-    }else {
+++SQLITE_INTERNAL_LINKAGE int fPrintfUtf8(FILE *pfO, const char *zFormat, ...){
 ++  va_list ap;
 ++  int rv;
+++#if SHELL_CON_TRANSLATE
+++  PerStreamTags pst; /* Needed only for heretofore unknown streams. */
+++  PerStreamTags *ppst = getEmitStreamInfo(0, &pst, &pfO);
+++#endif
+++
 ++  va_start(ap, zFormat);
 ++#if SHELL_CON_TRANSLATE
-  SQLITE_INTERNAL_LINKAGE int fputsUtf8(const char *z, FILE *pfO){
+++  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 SHELL_CON_TRANSLATE
 ++  }
 ++#endif
 ++  va_end(ap);
 ++  return rv;
 ++}
 ++
-    short rch = isConOut(pfO);
-    if( rch > 0 ){
-      return conioZstrOut(rch, z);
+++SQLITE_INTERNAL_LINKAGE int fPutsUtf8(const char *z, FILE *pfO){
 ++#if SHELL_CON_TRANSLATE
-  SQLITE_INTERNAL_LINKAGE char* fgetsUtf8(char *cBuf, int ncMax, FILE *pfIn){
+++  PerStreamTags pst; /* Needed only for heretofore unknown streams. */
+++  PerStreamTags *ppst = getEmitStreamInfo(0, &pst, &pfO);
+++  if( pstReachesConsole(ppst) ){
+++    int rv;
+++    maybeSetupAsConsole(ppst, 1);
+++    rv = conioZstrOut(ppst, z);
+++    if( 0 == isKnownWritable(ppst->pf) ) restoreConsoleArb(ppst);
+++    return rv;
 ++  }else {
 ++#endif
 ++    return (fputs(z, pfO)<0)? 0 : (int)strlen(z);
 ++#if SHELL_CON_TRANSLATE
 ++  }
 ++#endif
 ++}
 ++
+++SQLITE_INTERNAL_LINKAGE int ePutsUtf8(const char *z){
+++  FILE *pfErr;
+++  PerStreamTags pst; /* Needed only for heretofore unknown streams. */
+++  PerStreamTags *ppst = getEmitStreamInfo(2, &pst, &pfErr);
+++#if SHELL_CON_TRANSLATE
+++  if( pstReachesConsole(ppst) ) return conioZstrOut(ppst, z);
+++  else {
+++#endif
+++    return (fputs(z, pfErr)<0)? 0 : (int)strlen(z);
+++#if SHELL_CON_TRANSLATE
+++  }
+++#endif
+++}
+++
+++SQLITE_INTERNAL_LINKAGE int oPutsUtf8(const char *z){
+++  FILE *pfOut;
+++  PerStreamTags pst; /* Needed only for heretofore unknown streams. */
+++  PerStreamTags *ppst = getEmitStreamInfo(1, &pst, &pfOut);
+++#if SHELL_CON_TRANSLATE
+++  if( pstReachesConsole(ppst) ) return conioZstrOut(ppst, z);
+++  else {
+++#endif
+++    return (fputs(z, pfOut)<0)? 0 : (int)strlen(z);
+++#if SHELL_CON_TRANSLATE
+++  }
+++#endif
+++}
+++
 ++#if SHELL_CON_TRANSLATE==2
 ++static int mbcsToUtf8InPlaceIfValid(char *pc, int nci, int nco, UINT codePage){
 ++  WCHAR wcOneCode[2];
 ++  int nuo = 0;
 ++  int nwConvert = MultiByteToWideChar(codePage, MB_ERR_INVALID_CHARS,
 ++                                      pc, nci, wcOneCode, 2);
 ++  if( nwConvert > 0 ){
 ++    nuo = WideCharToMultiByte(CP_UTF8, 0, wcOneCode, nwConvert, pc, nco, 0,0);
 ++  }
 ++  return nuo;
 ++}
 ++#endif
 ++
-    if( pfIn == consoleInfo.pst[0].pf ){
+++SQLITE_INTERNAL_LINKAGE char* fGetsUtf8(char *cBuf, int ncMax, FILE *pfIn){
 ++  if( pfIn==0 ) pfIn = stdin;
 ++#if SHELL_CON_TRANSLATE
-      if( consoleInfo.stdinEof ) return 0;
+++  if( pfIn == consoleInfo.pstSetup[0].pf ){
 ++# if SHELL_CON_TRANSLATE==1
 ++#  define SHELL_GULP 150 /* Count of WCHARS to be gulped at a time */
 ++    WCHAR wcBuf[SHELL_GULP+1];
 ++    int lend = 0, noc = 0;
-        BOOL bRC = ReadConsoleW(consoleInfo.pst[0].hx, wcBuf, na, &nbr, 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;
-          bRC &= ReadConsoleW(consoleInfo.pst[0].hx, wcBuf+nbr, 1, &nbrx, 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;
-            ** Note that this is done without regard for any setModeText()
+++        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".)
-                if( noc > 1 && cBuf[noc-2]=='\r' ){
-                  cBuf[noc-2] = '\n';
-                  --noc;
-                }
+++          ** 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( cBuf[iseg]==0x1a ){
-                consoleInfo.stdinEof = 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( noc == 0 ) return 0;
-      cBuf[noc] = 0;
-      return cBuf;
+++            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. */
-            nco += nug;
+++    if( noc > 0 ){
+++      cBuf[noc] = 0;
+++      return cBuf;
+++    }else return 0;
 ++# elif SHELL_CON_TRANSLATE==2
 ++    /* This is not done efficiently because it may never be used.
 ++    ** Also, it is interactive input so it need not be fast.  */
 ++    int nco = 0;
 ++    /* For converstion to WCHAR, or pre-test of same. */
 ++    UINT cicp = GetConsoleCP(); /* For translation from mbcs. */
 ++    /* If input code page is CP_UTF8, must bypass MBCS input
 ++    ** collection because getc() returns 0 for non-ASCII byte
 ++    ** Instead, use fgets() which repects character boundaries. */
 ++    if( cicp == CP_UTF8 ) return fgets(cBuf, ncMax, pfIn);
 ++    while( ncMax-nco >= 5 ){
 ++      /* Have space for max UTF-8 group and 0-term. */
 ++      int nug = 0;
 ++      int c = getc(pfIn);
 ++      if( c < 0 ){
 ++        if( nco > 0 ) break;
 ++        else return 0;
 ++      }
 ++      cBuf[nco] = (char)c;
 ++      if( c < 0x80 ){
 ++        ++nco;
 ++        if( c == '\n' ) break;
 ++        continue;
 ++      }
 ++      /* Deal with possible mbcs lead byte. */
 ++      nug = mbcsToUtf8InPlaceIfValid(cBuf+nco, 1, ncMax-nco-1, cicp);
 ++      if( nug > 0 ){
 ++        nco += nug;
 ++      }else{
 ++        /* Must have just mbcs lead byte; get the trail byte(s). */
 ++        int ntb = 1, ct;
 ++        while( ntb <= 3 ){ /* No more under any multi-byte code. */
 ++          ct = getc(pfIn);
 ++          if( ct < 0 || ct == '\n' ){
 ++            /* Just drop whatever garbage preceded the newline or.
 ++            ** EOF. It's not valid, should not happen, and there
 ++            ** is no good way to deal with it, short of bailing. */
 ++            if( ct > 0 ){
 ++              cBuf[nco++] = (int)ct;
 ++            }
 ++            break;
 ++          }
 ++          /* Treat ct as bona fide MBCS trailing byte, if valid. */
 ++          cBuf[nco+ntb] = ct;
 ++          nug = mbcsToUtf8InPlaceIfValid(cBuf+nco, 1+ntb, ncMax-nco-1, cicp);
+++          if( nug > 0 ){
+++            nco += nug;
+++            break;
+++          }
 ++        }
 ++        if( ct < 0 ) break;
 ++      }
 ++    }
 ++    cBuf[nco] = 0;
 ++    return cBuf;
 ++# endif
 ++  }else{
 ++#endif
 ++    return fgets(cBuf, ncMax, pfIn);
 ++#if SHELL_CON_TRANSLATE
 ++  }
 ++#endif
 ++}
index e799c71e747f6fbb08d144887184976fc5d20933,0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..2d6178fed3e0afa11e8f17cda288ee9599547848
mode 100644,000000,000000..100644
--- /dev/null
--- /dev/null
@@@@ -1,187 -1,0 -1,0 +1,226 @@@@
-  ** This file exposes various interfaces used for console I/O by the
-  ** SQLite project command-line tools. These interfaces are used at
-  ** either source conglomeration time, compilation time, or run time.
 ++/*
 ++** 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.
 ++**
 ++********************************************************************************
-  ** "single-source" forms or separate compilation then linking. (TBD)
+++** 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,
-  ** 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 I/O.
+++** "single-source" forms or separate compilation then linking.
 ++**
 ++** Platform dependencies are "hidden" here by various stratagems so
-  typedef enum ConsoleStdConsStreams {
-    CSCS_NoConsole = 0,
-    CSCS_InConsole = 1, CSCS_OutConsole = 2, CSCS_ErrConsole = 4,
-    CSCS_AnyConsole = 0x7
-  } ConsoleStdConsStreams;
+++** 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.
 ++*/
 ++
 ++#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
 ++
 ++/* Define enum for use with following function. */
-  ** Returns the bit-wise OR of CSCS_{In,Out,Err}Console values,
-  ** or CSCS_NoConsole if none of the streams reaches a console.
+++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.
 ++**
-  ** iff the stream is used for the I/O functions that follow.
+++** 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,
-  SQLITE_INTERNAL_LINKAGE ConsoleStdConsStreams
-  consoleClassifySetup( FILE *pfIn, FILE *pfOut, FILE *pfErr );
+++** 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.
 ++*/
-  ** this call, no I/O should be done with the console
-  ** until consoleClassifySetup(...) is called again.
+++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
-  ** Render output like fprintf(). If the output is going to the
+++** 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 );
 ++
 ++/*
-  SQLITE_INTERNAL_LINKAGE int fprintfUtf8(FILE *pfO, const char *zFormat, ...);
-  /* Like fprintfUtf8 except stream is always the recorded output. */
-  SQLITE_INTERNAL_LINKAGE int printfUtf8(const char *zFormat, ...);
+++** 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);
+++SQLITE_INTERNAL_LINKAGE FILE *setErrorStream(FILE *pf);
+++
+++/*
+++** 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().
 ++*/
-  ** Render output like fputs(). If the output is going to the
+++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, ...);
 ++
 ++/*
-  SQLITE_INTERNAL_LINKAGE int fputsUtf8(const char *z, FILE *pfO);
+++** 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 char* fgetsUtf8(char *cBuf, int ncMax, FILE *pfIn);
+++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);
 ++
 ++/*
 ++** 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);
 ++
 ++/*
 ++** 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);
 ++
+++#if 0 /* For use with line editor. (not yet used) */
 ++typedef struct Prompts {
 ++  int numPrompts;
 ++  const char **azPrompts;
 ++} Prompts;
+++#endif
 ++
 ++/*
 ++** 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.
 ++*/
 ++#if 0 /* not yet implemented */
 ++SQLITE_INTERNAL_LINKAGE char *
 ++shellGetLine(FILE *pfIn, char *zBufPrior, int nLen,
 ++             short isContinuation, Prompts azPrompt);
 ++#endif
 ++/*
 ++** 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.
 ++*/
diff --cc manifest
index 98578565a7c1b8fa26be01c5f7adfa1b848bd093,ea62075a913480c71e3b518d874733565ba29797,f1683dfa587ad5f79db4772a1b01822c1ee78620..c56d84fa858e4bdf25bb5269e57e7e1cdb67df61
+++ b/manifest
@@@@ -1,5 -1,5 -1,5 +1,5 @@@@
-  C Refactor\sMBCS/UTF-8\stranslation\sto\savoid\sextra\sallocations,\ssupporting\snon-formatted\s(faster)\soutput.\sSome\scode\scleanup.\sWrap\s.system/.shell\scommand\sexection\swith\srestoration\sof\sstartup\sconsole\smode\sand\srenewing\smode\ssetup.\sChanges\sto\smake\slegacy\sMBCS\sbuild\swork\sbetter\s(than\slegacy\sdid,\seven\swith\s--no-utf8.)
-  D 2023-11-07T19:30:14.998
 - C Have\sthe\sshell\stool\semit\sa\swarning\sif\sthe\suser\sattempts\sto\suse\s".scanstats\svm"\sin\sa\snon-SQLITE_ENABLE_BYTECODE_VTAB\sbuild.
 - D 2023-11-08T15:56:41.847
  -C Fix\sanother\sproblem\swith\smixed\sjoin\stypes\sand\sthe\sRIGHT\sJOIN\sstrength-reduction\soptimization.\s[forum:/forumpost/befdab472d\s|\sForum\spost\sbefdab472d].
  -D 2023-11-10T20:55:20.957
+++C Pervasive\schanges\sto\sconsole_io.{c,h}\sin\ssupport\sof\ssimplifying\subiquitous\semit\sops\sin\sshell,\sand\sto\sget\sbetter\scontrol\sof\sconsole\sstreams\sthat\smight\sbe\sopened\sonly\svia\s.read\sor\s.output\scommands.\sChanges\sto\sshell\sto\suse\s{s,o,e}put{f,z}(...)\scalls\sfor\sinitial\stesting,\sbut\sthis\scheck-in\shas\sfew\ssuch\sconversions\sso\sthat\smost\swill\sbe\sin\sa\sseparate\scheck-in.\sMany\srenames\sto\sbetter\sfollow\srecent\scoding\sconvention.\sThis\scode\sseems\sto\sbe\sworking,\sbut\shas\snot\sbeen\stested\son\sdifficult\splatforms\sor\swith\smultiple\sconsole\shosts\syet.\sSo\sit\sis\sa\sWIP.
+++D 2023-11-11T06:20:38.614
   F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
   F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
   F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@@@ -50,8 -50,6 -50,6 +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 adb7da4947a5dc661f0106a7a6962c7528653bf95709bcddae22f3422cde25f7 x
-  F ext/consio/console_io.h e6055b6a13a2a9f237e1672f9ef861126a37a61db0e6218a137832557f10ea25
+++F ext/consio/console_io.c 19344e149e5c939c3c421823033abd4179d276ec1dae5f99e37d5bcd68ddbd59 x
+++F ext/consio/console_io.h c64d51d9f4e387679027d3b0977893390652f40c2e50a3c797506a9abb4856dc
   F ext/expert/README.md b321c2762bb93c18ea102d5a5f7753a4b8bac646cb392b3b437f633caf2020c3
   F ext/expert/expert.c d548d603a4cc9e61f446cc179c120c6713511c413f82a4a32b1e1e69d3f086a4
   F ext/expert/expert1.test 0dd5cb096d66bed593e33053a3b364f6ef52ed72064bf5cf298364636dbf3cd6
@@@@ -240,24 -238,24 -238,24 +240,24 @@@@ F ext/fts5/tool/showfts5.tcl d54da0e067
   F ext/icu/README.txt 7ab7ced8ae78e3a645b57e78570ff589d4c672b71370f5aa9e1cd7024f400fc9
   F ext/icu/icu.c c074519b46baa484bb5396c7e01e051034da8884bad1a1cb7f09bbe6be3f0282
   F ext/icu/sqliteicu.h fa373836ed5a1ee7478bdf8a1650689294e41d0c89c1daab26e9ae78a32075a8
-  F ext/jni/GNUmakefile 36919b7c4fb8447da4330df9996c7b064b766957f8b7be214a30eab55a8b8072
 - F ext/jni/GNUmakefile df91212d772011e3d39712a0e38586856c42528b6ee3d507a5bb3b3248c0ecbc
++ F ext/jni/GNUmakefile f2f3a31923293659b95225e932a286af1f2287d75bf88ad6c0fd1b9d9cd020d4
   F ext/jni/README.md ef9ac115e97704ea995d743b4a8334e23c659e5534c3b64065a5405256d5f2f4
   F ext/jni/jar-dist.make 030aaa4ae71dd86e4ec5e7c1e6cd86f9dfa47c4592c070d2e35157e42498e1fa
-  F ext/jni/src/c/sqlite3-jni.c afe9c25b82279a28fe2c81f869070fa0d434b0a8ccd7f8aca0e8173db410d14a
-  F ext/jni/src/c/sqlite3-jni.h 1c45fd4689cec42f3d84d2fee41bb494016a12fcb5fd80291095590666a14015
 - F ext/jni/src/c/sqlite3-jni.c 6b95974189d7cc394afbe15507050f1d174170a65be5a4dad201ab11f0a9777a
 - F ext/jni/src/c/sqlite3-jni.h 18925c56d6664fdec081c56daf3b2ffa0e0ff6b9b128b9f39b84862f34ba0601
-- F ext/jni/src/org/sqlite/jni/annotation/NotNull.java a99341e88154e70447596b1af6a27c586317df41a7e0f246fd41370cd7b723b2
++ F ext/jni/src/c/sqlite3-jni.c 3774703e5865e7ff776b762de5386af8aa703e569bbb3a85c423c3f8473a3c26
++ F ext/jni/src/c/sqlite3-jni.h 891444578550a7aa69fe5e0dedb3e6dedad752501ba99801f17797be51796934
++ F ext/jni/src/org/sqlite/jni/annotation/NotNull.java 02091a8112e33389f1c160f506cd413168c8dfacbeda608a4946c6e3557b7d5a
   F ext/jni/src/org/sqlite/jni/annotation/Nullable.java 0b1879852707f752512d4db9d7edd0d8db2f0c2612316ce1c832715e012ff6ba
   F ext/jni/src/org/sqlite/jni/annotation/package-info.java 977b374aed9d5853cbf3438ba3b0940abfa2ea4574f702a2448ee143b98ac3ca
   F ext/jni/src/org/sqlite/jni/capi/AbstractCollationCallback.java 1afa90d3f236f79cc7fcd2497e111992644f7596fbc8e8bcf7f1908ae00acd6c
   F ext/jni/src/org/sqlite/jni/capi/AggregateFunction.java 0b72cdff61533b564d65b63418129656daa9a9f30e7e7be982bd5ab394b1dbd0
-  F ext/jni/src/org/sqlite/jni/capi/AuthorizerCallback.java 7ed409d5449684616cc924534e22ff6b07d361f12ad904b69ecb10e0568a8013
+  F ext/jni/src/org/sqlite/jni/capi/AuthorizerCallback.java c045a5b47e02bb5f1af91973814a905f12048c428a3504fbc5266d1c1be3de5a
   F ext/jni/src/org/sqlite/jni/capi/AutoExtensionCallback.java 74cc4998a73d6563542ecb90804a3c4f4e828cb4bd69e61226d1a51f4646e759
   F ext/jni/src/org/sqlite/jni/capi/BusyHandlerCallback.java 7b8e19810c42b0ad21a04b5d8c804b32ee5905d137148703f16a75b612c380ca
-  F ext/jni/src/org/sqlite/jni/capi/CApi.java 24aba7b14b11da52cd47083608d37c186122c2e2072e75b2ff923d1f15bfb9e5
 - F ext/jni/src/org/sqlite/jni/capi/CApi.java 16a28138c3c25f33356193970644389ff8ebc0720499549653934b2529c8d1dd
++ F ext/jni/src/org/sqlite/jni/capi/CApi.java 92d443b08175c798e132a312f71b1a42140c60d473d35c149e3d95a45b6550f3
   F ext/jni/src/org/sqlite/jni/capi/CallbackProxy.java 57e2d275dcebe690b1fc1f3d34eb96879b2d7039bce30b563aee547bf45d8a8b
   F ext/jni/src/org/sqlite/jni/capi/CollationCallback.java e29bcfc540fdd343e2f5cca4d27235113f2886acb13380686756d5cabdfd065a
-  F ext/jni/src/org/sqlite/jni/capi/CollationNeededCallback.java f81cf10b79c52f9b2e9247d523d29ae48863935f60420eae35f257c38c80ce95
-  F ext/jni/src/org/sqlite/jni/capi/CommitHookCallback.java 29c002f3c638cc80f7db1594564a262d1beb32637824c3dca2d60a224d1f71d7
+  F ext/jni/src/org/sqlite/jni/capi/CollationNeededCallback.java 5bfa226a8e7a92e804fd52d6e42b4c7b875fa7a94f8e2c330af8cc244a8920ab
+  F ext/jni/src/org/sqlite/jni/capi/CommitHookCallback.java 482f53dfec9e3ac2a9070d3fceebd56250932aaaf7c4f5bc8de29fc011416e0c
   F ext/jni/src/org/sqlite/jni/capi/ConfigLogCallback.java b995ca412f59b631803b93aa5b3684fce62e335d1e123207084c054abfd488d4
   F ext/jni/src/org/sqlite/jni/capi/ConfigSqllogCallback.java 701f2e4d8bdeb27cfbeeb56315d15b13d8752b0fdbca705f31bd4366c58d8a33
   F ext/jni/src/org/sqlite/jni/capi/NativePointerHolder.java b7036dcb1ef1b39f1f36ac605dde0ff1a24a9a01ade6aa1a605039443e089a61
@@@@ -278,11 -276,11 -276,11 +278,11 @@@@ F ext/jni/src/org/sqlite/jni/capi/Value
   F ext/jni/src/org/sqlite/jni/capi/WindowFunction.java caf4396f91b2567904cf94bc538a069fd62260d975bd037d15a02a890ed1ef9e
   F ext/jni/src/org/sqlite/jni/capi/XDestroyCallback.java f3abb8dd7381f53ebba909437090caf68200f06717b8a7d6aa96fa3e8133117d
   F ext/jni/src/org/sqlite/jni/capi/package-info.java 08ff986a65d2be9162442c82d28a65ce431d826f188520717c2ecb1484d0a50e
-  F ext/jni/src/org/sqlite/jni/capi/sqlite3.java 4010bbebc5bf44e2044e610786088cdee7dc155da2b333c0551492ff1cedf33b
+  F ext/jni/src/org/sqlite/jni/capi/sqlite3.java c6a5c555d163d76663534f2b2cce7cab15325b9852d0f58c6688a85e73ae52f0
   F ext/jni/src/org/sqlite/jni/capi/sqlite3_backup.java 6742b431cd4d77e8000c1f92ec66265a58414c86bf3b0b5fbcb1164e08477227
-- F ext/jni/src/org/sqlite/jni/capi/sqlite3_blob.java f204ab6ab1263e119fe43730141a00662d80972129a5351dfb11aae5d282df36
++ F ext/jni/src/org/sqlite/jni/capi/sqlite3_blob.java 59e26ca5254cd4771f467237bcfe2d8deed30a77152fabcd4574fd406c301d63
   F ext/jni/src/org/sqlite/jni/capi/sqlite3_context.java f0ef982009c335c4393ffcb68051809ca1711e4f47bcb8d1d46952f22c01bc22
-  F ext/jni/src/org/sqlite/jni/capi/sqlite3_stmt.java ff579621e9bd5ffbc6b2ef9f996c12db4df6e0c8cc5697c91273e5fca279fcf8
+  F ext/jni/src/org/sqlite/jni/capi/sqlite3_stmt.java 293b5fa7d5b5724c87de544654aca1103d76f3092bc2c8f4360102a65ba25dff
   F ext/jni/src/org/sqlite/jni/capi/sqlite3_value.java e1d62a257c13504b46d39d5c21c49cf157ad73fda00cc5f34c931aa008c37049
   F ext/jni/src/org/sqlite/jni/fts5/Fts5.java e94681023785f1eff5399f0ddc82f46b035977d350f14838db659236ebdf6b41
   F ext/jni/src/org/sqlite/jni/fts5/Fts5Context.java 338637e6e5a2cc385d962b220f3c1f475cc371d12ae43d18ef27327b6e6225f7
@@@@ -295,14 -293,14 -293,14 +295,14 @@@@ F ext/jni/src/org/sqlite/jni/fts5/fts5_
   F ext/jni/src/org/sqlite/jni/fts5/fts5_extension_function.java 9e2b954d210d572552b28aca523b272fae14bd41e318921b22f65b728d5bf978
   F ext/jni/src/org/sqlite/jni/fts5/fts5_tokenizer.java 92bdaa3893bd684533004d64ade23d329843f809cd0d0f4f1a2856da6e6b4d90
   F ext/jni/src/org/sqlite/jni/test-script-interpreter.md f9f25126127045d051e918fe59004a1485311c50a13edbf18c79a6ff9160030e
-  F ext/jni/src/org/sqlite/jni/wrapper1/AggregateFunction.java bbe60ac7fd8718edb215a23dc901771bcedb1df3b46d9cf6caff6f419828587f
+  F ext/jni/src/org/sqlite/jni/wrapper1/AggregateFunction.java d5c108b02afd3c63c9e5e53f71f85273c1bfdc461ae526e0a0bb2b25e4df6483
   F ext/jni/src/org/sqlite/jni/wrapper1/ScalarFunction.java 43c43adfb7866098aadaaca1620028a6ec82d5193149970019b1cce9eb59fb03
-  F ext/jni/src/org/sqlite/jni/wrapper1/SqlFunction.java 0b01b9058ef6737c85b505c6aa2490fb1dc1d974fb39d88a93269fed09553f9f
-  F ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java 1c95f5e0f872aeb9cdd174cbb2e254d158df1f8b2fee9f0e6ec82c348602a7bd
-  F ext/jni/src/org/sqlite/jni/wrapper1/SqliteException.java aa85b4b05fae240b14f3d332f9524a2f80c619fb03856be72b4adda866b63b72
-  F ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java 9ab7e38e6741842f8e3b74cd3ecb4953e2f1957f5229bd32663df7331245ce95
 - F ext/jni/src/org/sqlite/jni/wrapper1/SqlFunction.java 2833afdb9af5c1949bb35f4c926a5351fba9d1cdf0996864caa7b47827a346c7
++ F ext/jni/src/org/sqlite/jni/wrapper1/SqlFunction.java 27b141f5914c7cb0e40e90a301d5e05b77f3bd42236834a68031b7086381fafd
+  F ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java 0ef62b43b1d6a9f044e106b56c9ea42bc7150b82ebeb79cff58f5be08cb9a435
+  F ext/jni/src/org/sqlite/jni/wrapper1/SqliteException.java 982538ddb4c0719ef87dfa664cd137b09890b546029a7477810bd64d4c47ee35
+  F ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java 40806dbbf8e120f115e33255d1813db13b40f0a598869e299a947a580429939b
   F ext/jni/src/org/sqlite/jni/wrapper1/ValueHolder.java 7b89a7391f771692c5b83b0a5b86266abe8d59f1c77d7a0eccc9b79f259d79af
-  F ext/jni/src/org/sqlite/jni/wrapper1/WindowFunction.java 1a1afbafbd7406ff67e7d6405541c6347517c731de535a97d7a3df1d4db835b4
+  F ext/jni/src/org/sqlite/jni/wrapper1/WindowFunction.java c7d1452f9ff26175b3c19bbf273116cc2846610af68e01756d755f037fe7319f
   F ext/jni/src/tests/000-000-sanity.test c3427a0e0ac84d7cbe4c95fdc1cd4b61f9ddcf43443408f3000139478c4dc745
   F ext/jni/src/tests/000-001-ignored.test e17e874c6ab3c437f1293d88093cf06286083b65bf162317f91bbfd92f961b70
   F ext/jni/src/tests/900-001-fts.test bf0ce17a8d082773450e91f2388f5bbb2dfa316d0b676c313c637a91198090f0
@@@@ -710,10 -708,10 -708,10 +710,10 @@@@ F src/os.h 1ff5ae51d339d0e30d8a9d814f4b
   F src/os_common.h 6c0eb8dd40ef3e12fe585a13e709710267a258e2c8dd1c40b1948a1d14582e06
   F src/os_kv.c 4d39e1f1c180b11162c6dc4aa8ad34053873a639bac6baae23272fc03349986a
   F src/os_setup.h 6011ad7af5db4e05155f385eb3a9b4470688de6f65d6166b8956e58a3d872107
-  F src/os_unix.c cb116fde9e3ca3c1bbfdf89d6928f776a2a34da168e2667426523a4db353b271
+  F src/os_unix.c 0a33005e6426702c7e76f3d451f296c088693a95b2be28ba9ef59c8d8529ce6b
   F src/os_win.c 4a50a154aeebc66a1f8fb79c1ff6dd5fe3d005556533361e0d460d41cb6a45a8
   F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
-- F src/pager.c 699aab8dfc88056d796b03b40c0ab979040d58dfc3ae9db207f1be91e4880bbf
++ F src/pager.c 987ab3a2cd9065d62e9955474470ff733445e2357432a67e3d0f5a8f9313e334
   F src/pager.h f4d33fec8052603758792045493423b8871a996da2d0973927b7d36cd6070473
   F src/parse.y 020d80386eb216ec9520549106353c517d2bbc89be28752ffdca649a9eaf56ec
   F src/pcache.c 040b165f30622a21b7a9a77c6f2e4877a32fb7f22d4c7f0d2a6fa6833a156a75
@@@@ -726,12 -724,12 -724,12 +726,12 @@@@ F src/printf.c 9da63b9ae1c14789bcae1284
   F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c
   F src/resolve.c d017bad7ba8e778617701a0e986fdeb393d67d6afa84fb28ef4e8b8ad2acf916
   F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97
-- F src/select.c a19daa26e95f7245106a31f288b2f50c72d1f2cc156703f04c8c91450e111515
-  F src/shell.c.in 5afd6ba7c0144e2a55df1c24732d88e4ae860459970b25ee2b4a3812af53c358
-  F src/sqlite.h.in ef0e41e83ad1ac0dcc9ec9939bf541a44b1c5de821bee2d6c61754c3252f3276
 - F src/shell.c.in 7312c571ebf518fc8927bbb5aeb4fa67e5b0dfb2adae4258dcd1ccae42c11e1f
 - F src/sqlite.h.in a0fce680a40fe81b13eae3749d001134d9fe0a43aecc09a8986520d5119acfcd
++ F src/select.c 503331aca8785254a7bf3d74ab338a99118fa297e1184a4dde33b3cdf7a9d341
  -F src/shell.c.in 297625a1ba6ea1c08bc2ea1b838b646cad309b62bf08df0e379355629404f140
+++F src/shell.c.in 2bbff1e18baafccf312c622ce966792f6a70ec77b642d92b0c0df4885df76722
++ F src/sqlite.h.in 4f841d3d117b830ee5ee45e8d89ceff1195f3ebb72d041ace8d116ba4c103b35
   F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
   F src/sqlite3ext.h 3f046c04ea3595d6bfda99b781926b17e672fd6d27da2ba6d8d8fc39981dcb54
-  F src/sqliteInt.h 707095a0591e02f4866ed9798cbdd97a8ae8cf4d98f061808944c2cd1c95d1a9
 - F src/sqliteInt.h b9f6cfac999b60def4d3523897dc1f5453ab9c24195e462fd346476541cf659a
++ F src/sqliteInt.h cd171cba32c7a553e7623fbd82b68b36a1b6c81079ab963260777ea9b3abe4d9
   F src/sqliteLimit.h 33b1c9baba578d34efe7dfdb43193b366111cdf41476b1e82699e14c11ee1fb6
   F src/status.c 160c445d7d28c984a0eae38c144f6419311ed3eace59b44ac6dafc20db4af749
   F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
@@@@ -796,22 -794,22 -794,22 +796,22 @@@@ F src/upsert.c fa125a8d3410ce9a97b02cb5
   F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0
   F src/util.c b22cc9f203a8c0b9ee5338a67f8860347d14845864c10248bebe84518a781677
   F src/vacuum.c 604fcdaebe76f3497c855afcbf91b8fa5046b32de3045bab89cc008d68e40104
-  F src/vdbe.c 14479441337135eed8e290fb1d4abb7db657d93217a3b1ea8a2f031d3895536a
+  F src/vdbe.c 7034cf3eec0c905df753368efbcdd96377fca0245584e66766ec47a29fe468c8
   F src/vdbe.h 41485521f68e9437fdb7ec4a90f9d86ab294e9bb8281e33b235915e29122cfc0
   F src/vdbeInt.h 949669dfd8a41550d27dcb905b494f2ccde9a2e6c1b0b04daa1227e2e74c2b2c
-- F src/vdbeapi.c db190d007bdf5b9165edeb12369f4c59a459f88fd652c1671c1238862e662cc3
-  F src/vdbeaux.c dffcf79e7e415fcd6e4c8ac1ec7124cae5257018443adf09551c807655b04993
++ F src/vdbeapi.c b07df805110dc6e81f2a3f9cd4e83f56ea523277a59bcec489a12b740c1079e7
+  F src/vdbeaux.c f3997b5956c8d97bd2fc3392db42caecddfa6549e9df82e0a7e5804653ca475a
   F src/vdbeblob.c 13f9287b55b6356b4b1845410382d6bede203ceb29ef69388a4a3d007ffacbe5
-  F src/vdbemem.c c936e9002af4993b84c4eb7133d6b1190efe46d391cc86117ecd67ba17b1a04b
+  F src/vdbemem.c 0012d5f01cc866833847c2f3ae4c318ac53a1cb3d28acad9c35e688039464cf0
   F src/vdbesort.c 237840ca1947511fa59bd4e18b9eeae93f2af2468c34d2427b059f896230a547
   F src/vdbetrace.c fe0bc29ebd4e02c8bc5c1945f1d2e6be5927ec12c06d89b03ef2a4def34bf823
   F src/vdbevtab.c 2143db7db0ceed69b21422581f434baffc507a08d831565193a7a02882a1b6a7
   F src/vtab.c 154725ebecd3bc02f7fbd7ad3974334f73fff76e02a964e828e48a7c5fb7efff
   F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
-  F src/wal.c 01e051a1e713d9eabdb25df38602837cec8f4c2cae448ce2cf6accc87af903e9
+  F src/wal.c bba7db5dae3ffe2c6b9c173fc10be4b570b125e985cb5b95a6c22716213adde4
   F src/wal.h ba252daaa94f889f4b2c17c027e823d9be47ce39da1d3799886bbd51f0490452
   F src/walker.c 7c7ea0115345851c3da4e04e2e239a29983b61fb5b038b94eede6aba462640e2
-- F src/where.c 313ce81270d2a414672370e1ee74e65949ad620519193d4cac2986d073cbc8a0
++ F src/where.c 45b2239e127beaaae2367e503ca4c82868d8fef707c7f7f4a6c0528e7d5f65ff
   F src/whereInt.h 4b38c5889514e3aead3f27d0ee9a26e47c3f150efc59e2a8b4e3bc8835e4d7a1
   F src/wherecode.c 5d77db30a2a3dd532492ae882de114edba2fae672622056b1c7fd61f5917a8f1
   F src/whereexpr.c dc5096eca5ed503999be3bdee8a90c51361289a678d396a220912e9cb73b3c00
@@@@ -2144,8 -2139,8 -2139,8 +2141,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 1721dc6a434361c4e2b87c6e677b6dc223432b3cdd5b9eecabaa258889fb2d2a
-  R c19fe6cbae4ae273f253c34b1a4e1156
 - P dd3e7b5bcad122ac1e7e19ec547f4486ce90a6a2aa89a64e36bea13a216492fe
 - R 6732486a2aaa0526e06e22748aa04499
  -P aca31e49d1d25043769544ccf2a07980c5f162a8eb2486e393bf9d9d1a394a60
  -R 97cf5703d60c0dd519713f02ba70db03
 --U dan
 - Z 4a970381aa1757bde9016fd89b987339
  -Z e3c451988b970e006792a61910aa1f15
+++P d5e88fcde53ca7ba05bb164943a9f57bd92080bb7e5eebbbed64b9886ac97338 3978c084a509c3c739fbe87e20feec9ddf1325e35170329987af197ca9fd731a f1eae192315335d7e385b0a801a17700a9718d245bda6628518c5df9a1e9d3d6
+++R 13fdfe04f23cf8d5bcfae91b277b730e
 ++U larrybr
-  Z 24f475e52cde2b6dcf8641f1d924498c
+++Z 7767a4710aecdf1826b87f96aec24468
   # Remove this line to create a well-formed Fossil manifest.
diff --cc manifest.uuid
index 4d85fa6de75598fdc12b6d18979378395a369b9b,8a3f265a0bafdc6ca2fbfe5cc0292435d27417c1,873b025efcd965886d89eb335b937d28748d5a6f..340d950f96a618da9080a906704e2b4c8f1390a6
@@@@ -1,1 -1,1 -1,1 +1,1 @@@@
-  d5e88fcde53ca7ba05bb164943a9f57bd92080bb7e5eebbbed64b9886ac97338
 - 3978c084a509c3c739fbe87e20feec9ddf1325e35170329987af197ca9fd731a
  -f1eae192315335d7e385b0a801a17700a9718d245bda6628518c5df9a1e9d3d6
+++14762a004cdf37d1e12f26aadff8ed3824893278f22ff141de86dd44d9b250f3
diff --cc src/shell.c.in
index a32c4f5d572ce27578467880b80d8af4488b9ff9,8d201bbbdaed28649a8dd1fa69785eaaf6b45a30,0e0dbd36c76feeabb3e66d3879fb1f81de55b99d..b3b97e1ceca4fd1d97b794aa25969d05d4ec2bb1
@@@@ -565,13 -600,239 -600,239 +565,33 @@@@ static char *dynamicContinuePrompt(void
   }
   #endif /* !defined(SQLITE_OMIT_DYNAPROMPT) */
   
 --#if SHELL_WIN_UTF8_OPT
 --/* Following struct is used for UTF-8 console I/O. */
 --static struct ConsoleState {
 --  int stdinEof;      /* EOF has been seen on console input */
 --  int infsMode;      /* Input file stream mode upon shell start */
 --  UINT inCodePage;   /* Input code page upon shell start */
 --  UINT outCodePage;  /* Output code page upon shell start */
 --  HANDLE hConsole;   /* Console input or output handle */
 --  DWORD consoleMode; /* Console mode upon shell start */
 --} conState = { 0, 0, 0, 0, INVALID_HANDLE_VALUE, 0 };
 --
 --#ifndef _O_U16TEXT /* For build environments lacking this constant: */
 --# define _O_U16TEXT 0x20000
 --#endif
 --
 --/*
 --** If given stream number is a console, return 1 and get some attributes,
 --** else return 0 and set the output attributes to invalid values.
 --*/
 --static short console_attrs(unsigned stnum, HANDLE *pH, DWORD *pConsMode){
 --  static int stid[3] = { STD_INPUT_HANDLE,STD_OUTPUT_HANDLE,STD_ERROR_HANDLE };
 --  HANDLE h;
 --  *pH = INVALID_HANDLE_VALUE;
 --  *pConsMode = 0;
 --  if( stnum > 2 ) return 0;
 --  h = GetStdHandle(stid[stnum]);
 --  if( h!=*pH && GetFileType(h)==FILE_TYPE_CHAR && GetConsoleMode(h,pConsMode) ){
 --    *pH = h;
 --    return 1;
 --  }
 --  return 0;
 --}
 --
 --/*
 --** Perform a runtime test of Windows console to determine if it can
 --** do char-stream I/O correctly when the code page is set to CP_UTF8.
 --** Returns are: 1 => yes it can, 0 => no it cannot
 --**
 --** The console's output code page is momentarily set, then restored.
 --** So this should only be run when the process is given use of the
 --** console for either input or output.
 --*/
 --static short ConsoleDoesUTF8(void){
 --  UINT ocp = GetConsoleOutputCP();
 --  const char TrialUtf8[] = { '\xC8', '\xAB' }; /* "ȫ" or 2 MBCS characters */
 --  WCHAR aReadBack[1] = { 0 }; /* Read back as 0x022B when decoded as UTF-8. */
 --  CONSOLE_SCREEN_BUFFER_INFO csbInfo = {0};
 --  /* Create an inactive screen buffer with which to do the experiment. */
 --  HANDLE hCSB = CreateConsoleScreenBuffer(GENERIC_READ|GENERIC_WRITE, 0, 0,
 --                                          CONSOLE_TEXTMODE_BUFFER, NULL);
 --  if( hCSB!=INVALID_HANDLE_VALUE ){
 --    COORD cpos = {0,0};
 --    DWORD rbc;
 --    SetConsoleCursorPosition(hCSB, cpos);
 --    SetConsoleOutputCP(CP_UTF8);
 --    /* Write 2 chars which are a single character in UTF-8 but more in MBCS. */
 --    WriteConsoleA(hCSB, TrialUtf8, sizeof(TrialUtf8), NULL, NULL);
 --    ReadConsoleOutputCharacterW(hCSB, &aReadBack[0], 1, cpos, &rbc);
 --    GetConsoleScreenBufferInfo(hCSB, &csbInfo);
 --    SetConsoleOutputCP(ocp);
 --    CloseHandle(hCSB);
 --  }
 --  /* Return 1 if cursor advanced by 1 position, else 0. */
 --  return (short)(csbInfo.dwCursorPosition.X == 1 && aReadBack[0] == 0x022B);
 --}
 --
 --static short in_console = 0;
 --static short out_console = 0;
 --
 --/*
 --** Determine whether either normal I/O stream is the console,
 --** and whether it can do UTF-8 translation, setting globals
 --** in_console, out_console and mbcs_opted accordingly.
 --*/
 --static void probe_console(void){
 --  HANDLE h;
 --  DWORD cMode;
 --  in_console = console_attrs(0, &h, &cMode);
 --  out_console = console_attrs(1, &h, &cMode);
 --  if( in_console || out_console ) mbcs_opted = !ConsoleDoesUTF8();
 --}
 --
 --/*
 --** If console is used for normal I/O, absent a --no-utf8 option,
 --** prepare console for UTF-8 input (from either typing or suitable
 --** paste operations) and/or for UTF-8 output rendering.
 --**
 --** The console state upon entry is preserved, in conState, so that
 --** console_restore() can later restore the same console state.
 --**
 --** The globals console_utf8_in and console_utf8_out are set, for
 --** later use in selecting UTF-8 or MBCS console I/O translations.
 --** This routine depends upon globals set by probe_console().
 --*/
 --static void console_prepare_utf8(void){
 --  struct ConsoleState csWork = { 0, 0, 0, 0, INVALID_HANDLE_VALUE, 0 };
 --
 --  console_utf8_in = console_utf8_out = 0;
 --  if( (!in_console && !out_console) || mbcs_opted ) return;
 --  console_attrs((in_console)? 0 : 1, &conState.hConsole, &conState.consoleMode);
 --  conState.inCodePage = GetConsoleCP();
 --  conState.outCodePage = GetConsoleOutputCP();
 --  if( in_console ){
 --    SetConsoleCP(CP_UTF8);
 --    SetConsoleMode(conState.hConsole, conState.consoleMode
 --                   | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT);
 --    conState.infsMode = _setmode(_fileno(stdin), _O_U16TEXT);
 --    console_utf8_in = 1;
 --  }
 --  if( out_console ){
 --    SetConsoleOutputCP(CP_UTF8);
 --    console_utf8_out = 1;
 --  }
 --}
 --
 --/*
 --** Undo the effects of console_prepare_utf8(), if any.
 --*/
 --static void SQLITE_CDECL console_restore(void){
 --  if( (console_utf8_in||console_utf8_out)
 --      && conState.hConsole!=INVALID_HANDLE_VALUE ){
 --    if( console_utf8_in ){
 --      SetConsoleCP(conState.inCodePage);
 --      _setmode(_fileno(stdin), conState.infsMode);
 --    }
 --    if( console_utf8_out ) SetConsoleOutputCP(conState.outCodePage);
 --    SetConsoleMode(conState.hConsole, conState.consoleMode);
 --    /* Avoid multiple calls. */
 --    conState.hConsole = INVALID_HANDLE_VALUE;
 --    conState.consoleMode = 0;
 --    console_utf8_in = 0;
 --    console_utf8_out = 0;
 --  }
 --}
 --
 --/*
 --** Collect input like fgets(...) with special provisions for input
 --** from the Windows console to get around its strange coding issues.
 --** Defers to plain fgets() when input is not interactive or when the
 --** UTF-8 input is unavailable or opted out.
 --*/
 --static char* utf8_fgets(char *buf, int ncmax, FILE *fin){
 --  if( fin==0 ) fin = stdin;
 --  if( fin==stdin && stdin_is_interactive && console_utf8_in ){
 --# define SQLITE_IALIM 150
 --    wchar_t wbuf[SQLITE_IALIM];
 --    int lend = 0;
 --    int noc = 0;
 --    if( ncmax==0 || conState.stdinEof ) return 0;
 --    buf[0] = 0;
 --    while( noc<ncmax-7-1 && !lend ){
 --      /* There is room for at least 2 more characters and a 0-terminator. */
 --      int na = (ncmax > SQLITE_IALIM*4+1 + noc)
 --        ? SQLITE_IALIM : (ncmax-1 - noc)/4;
 --# undef SQLITE_IALIM
 --      DWORD nbr = 0;
 --      BOOL bRC = ReadConsoleW(conState.hConsole, wbuf, na, &nbr, 0);
 --      if( !bRC || (noc==0 && nbr==0) ) return 0;
 --      if( nbr > 0 ){
 --        int nmb = WideCharToMultiByte(CP_UTF8,WC_COMPOSITECHECK|WC_DEFAULTCHAR,
 --                                      wbuf,nbr,0,0,0,0);
 --        if( nmb !=0 && noc+nmb <= ncmax ){
 --          int iseg = noc;
 --          nmb = WideCharToMultiByte(CP_UTF8,WC_COMPOSITECHECK|WC_DEFAULTCHAR,
 --                                    wbuf,nbr,buf+noc,nmb,0,0);
 --          noc += nmb;
 --          /* Fixup line-ends as coded by Windows for CR (or "Enter".)*/
 --          if( noc > 0 ){
 --            if( buf[noc-1]=='\n' ){
 --              lend = 1;
 --              if( noc > 1 && buf[noc-2]=='\r' ){
 --                buf[noc-2] = '\n';
 --                --noc;
 --              }
 --            }
 --          }
 --          /* Check for ^Z (anywhere in line) too. */
 --          while( iseg < noc ){
 --            if( buf[iseg]==0x1a ){
 --              conState.stdinEof = 1;
 --              noc = iseg; /* Chop ^Z and anything following. */
 --              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 ) return 0;
 --    buf[noc] = 0;
 --    return buf;
 --  }else{
 --    return fgets(buf, ncmax, fin);
 --  }
 --}
 --
 --# define fgets(b,n,f) utf8_fgets(b,n,f)
 --#endif /* SHELL_WIN_UTF8_OPT */
 --
 --/*
 --** Render output like fprintf().  Except, if the output is going to the
 --** console and if this is running on a Windows machine, and if UTF-8
 --** output unavailable (or available but opted out), translate the
 --** output from UTF-8 into MBCS for output through 8-bit stdout stream.
 --** (Without -no-utf8, no translation is needed and must not be done.)
 --*/
 --#if defined(_WIN32) || defined(WIN32)
 --void utf8_printf(FILE *out, const char *zFormat, ...){
 --  va_list ap;
 --  va_start(ap, zFormat);
 --  if( stdout_is_console && (out==stdout || out==stderr) && !console_utf8_out ){
 --    char *z1 = sqlite3_vmprintf(zFormat, ap);
 --    char *z2 = sqlite3_win32_utf8_to_mbcs_v2(z1, 0);
 --    sqlite3_free(z1);
 --    fputs(z2, out);
 --    sqlite3_free(z2);
 --  }else{
 --    vfprintf(out, zFormat, ap);
 --  }
 --  va_end(ap);
 --}
 --#elif !defined(utf8_printf)
 --# define utf8_printf fprintf
 --#endif
 --
 --/*
 --** Render output like fprintf().  This should not be used on anything that
 --** includes string formatting (e.g. "%s").
 --*/
 --#if !defined(raw_printf)
 --# define raw_printf fprintf
 --#endif
 ++/* From here onward, fgets() is redirected to the console_io library. */
-  #define fgets(b,n,f) fgetsUtf8(b,n,f)
+++#define fgets(b,n,f) fGetsUtf8(b,n,f)
 ++/* Also, (varargs) utf8_printf(f,z,...),printf(z,...) so redirected. */
-  #define utf8_printf fprintfUtf8
-  #define printf printfUtf8
+++#define utf8_printf fPrintfUtf8
+++#define printf oPrintfUtf8
 ++/* And, utf8_print(f,z) is redirected to fputsUtf8(z,f) in the library. */
-  #define utf8_print(f,z) fputsUtf8(z,f)
+++#define utf8_print(f,z) fPutsUtf8(z,f)
+++/*
+++ * Define macros for writing output text in various ways:
+++ *  sputz(s, z)      => emit 0-terminated string z to given stream s
+++ *  sputf(s, f, ...) => emit varargs per format f to given stream s
+++ *  oputz(z)         => emit 0-terminated string z to default stream
+++ *  oputf(f, ...)    => emit varargs per format f to default stream
+++ *  eputz(z)         => emit 0-terminated string z to error stream
+++ *  eputf(f, ...)    => emit varargs per format f to error stream
+++ *
+++ * Note that the default stream is whatever has been last set via:
+++ *   setDefaultOutputStream(FILE *pf)
+++ * This is normally the stream that CLI normal output goes to.
+++ * For the stand-alone CLI, it is stdout with no .output redirect.
+++ */
+++#define sputz(s,z) fPutsUtf8(z,s)
+++#define sputf fPrintfUtf8
+++#define oputz(z) oPutsUtf8(z)
+++#define oputf oPrintfUtf8
+++#define eputz(z) ePutsUtf8(z)
+++#define eputf ePrintfUtf8
   
   /* Indicate out-of-memory and exit. */
   static void shell_out_of_memory(void){
@@@@ -697,7 -958,7 -958,7 +717,7 @@@@ static int strlenChar(const char *z)
   ** Otherwise return 0.
   */
   static FILE * openChrSource(const char *zFile){
---#ifdef _WIN32
+++#if defined(_WIN32) || defined(WIN32)
     struct _stat x = {0};
   # define STAT_CHR_SRC(mode) ((mode & (_S_IFCHR|_S_IFIFO|_S_IFREG))!=0)
     /* On Windows, open first, then check the stream nature. This order
@@@@ -1033,7 -1311,7 -1311,11 +1053,7 @@@@ static void shellDtostr
     char z[400];
     if( n<1 ) n = 1;
     if( n>350 ) n = 350;
  -#if defined(_MSC_VER)
  -  _snprintf(z, sizeof(z)-2, "%#+.*e", n, r);
  -#else
---  snprintf(z, sizeof(z)-1, "%#+.*e", n, r);
  -#endif
+++  sqlite3_snprintf(sizeof(z), z, "%#+.*e", n, r);
     sqlite3_result_text(pCtx, z, -1, SQLITE_TRANSIENT);
   }
   
@@@@ -7739,6 -8017,6 -8021,6 +7759,7 @@@@ FROM (
           sqlite3_exec(*pDb,"drop table if exists ColNames;"
                        "drop view if exists RepeatedNames;",0,0,0);
   #endif
+++#undef SHELL_COLFIX_DB
         rc = sqlite3_exec(*pDb, zTabMake, 0, 0, 0);
         rc_err_oom_die(rc);
       }
@@@@ -9796,11 -10074,17 -10078,17 +9817,17 @@@@ static int do_meta_command(char *zLine
         sqlite3_db_config(
             p->db, SQLITE_DBCONFIG_STMT_SCANSTATUS, p->scanstatsOn, (int*)0
         );
-  #ifndef SQLITE_ENABLE_STMT_SCANSTATUS
+  #if !defined(SQLITE_ENABLE_STMT_SCANSTATUS)
 --      raw_printf(stderr, "Warning: .scanstats not available in this build.\n");
 ++      utf8_print(stderr, "Warning: .scanstats not available in this build.\n");
+  #elif !defined(SQLITE_ENABLE_BYTECODE_VTAB)
+        if( p->scanstatsOn==3 ){
+          raw_printf(stderr, 
+              "Warning: \".scanstats vm\" not available in this build.\n"
+          );
+        }
   #endif
       }else{
 --      raw_printf(stderr, "Usage: .scanstats on|off|est\n");
 ++      utf8_print(stderr, "Usage: .scanstats on|off|est\n");
         rc = 1;
       }
     }else
         zCmd = sqlite3_mprintf(strchr(azArg[i],' ')==0?"%z %s":"%z \"%s\"",
                                zCmd, azArg[i]);
       }
 ++    consoleRestore();
       x = zCmd!=0 ? system(zCmd) : 1;
-      consoleClassifySetup(stdin, stdout, stderr);
+++    consoleRenewSetup();
       sqlite3_free(zCmd);
 --    if( x ) raw_printf(stderr, "System command returns %d\n", x);
 ++    if( x ) utf8_printf(stderr, "System command returns %d\n", x);
     }else
   #endif /* !defined(SQLITE_NOHAVE_SYSTEM) && !defined(SQLITE_SHELL_FIDDLE) */
   
@@@@ -11815,7 -12103,7 -12107,7 +11842,7 @@@@ static void main_init(ShellState *data
   /*
   ** Output text to the console in a font that attracts extra attention.
   */
---#ifdef _WIN32
+++#if defined(_WIN32) || defined(WIN32)
   static void printBold(const char *zText){
   #if !SQLITE_OS_WINRT
     HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE);
            FOREGROUND_RED|FOREGROUND_INTENSITY
     );
   #endif
---  printf("%s", zText);
+++  oputf("%s", zText);
   #if !SQLITE_OS_WINRT
     SetConsoleTextAttribute(out, defaultScreenInfo.wAttributes);
   #endif
   }
   #else
   static void printBold(const char *zText){
---  printf("\033[1m%s\033[0m", zText);
+++  oputf("\033[1m%s\033[0m", zText);
   }
   #endif
   
@@@@ -11880,7 -12168,6 -12172,6 +11907,7 @@@@ int SQLITE_CDECL wmain(int argc, wchar_
   #  define data shellState
   #else
     ShellState data;
-    ConsoleStdConsStreams csStreams = CSCS_NoConsole;
+++  StreamsAreConsole consStreams = SAC_NoConsole;
   #endif
     const char *zInitFile = 0;
     int i;
     stdout_is_console = 1;
     data.wasm.zDefaultDbName = "/fiddle.sqlite3";
   #else
-    csStreams = consoleClassifySetup(stdin, stdout, stderr);
-    stdin_is_interactive = (csStreams & CSCS_InConsole)!=0;
-    stdout_is_console = (csStreams & CSCS_OutConsole)!=0;
 --  stdin_is_interactive = isatty(0);
 --  stdout_is_console = isatty(1);
 --#endif
 --#if SHELL_WIN_UTF8_OPT
 --  probe_console(); /* Check for console I/O and UTF-8 capability. */
 --  if( !mbcs_opted ) atexit(console_restore);
+++  consStreams = consoleClassifySetup(stdin, stdout, stderr);
+++  stdin_is_interactive = (consStreams & SAC_InConsole)!=0;
+++  stdout_is_console = (consStreams & SAC_OutConsole)!=0;
 ++  atexit(consoleRestore);
   #endif
     atexit(sayAbnormalExit);
   #ifdef SQLITE_DEBUG
       if( pVfs ){
         sqlite3_vfs_register(pVfs, 1);
       }else{
---      utf8_printf(stderr, "no such VFS: \"%s\"\n", zVfs);
+++      eputf("no such VFS: \"%s\"\n", zVfs);
         exit(1);
       }
     }
       data.pAuxDb->zDbFilename = ":memory:";
       warnInmemoryDb = argc==1;
   #else
---    utf8_printf(stderr,"%s: Error: no database filename specified\n", Argv0);
+++    eputf("%s: Error: no database filename specified\n", Argv0);
       return 1;
   #endif
     }
       }else if( cli_strcmp(z,"-bail")==0 ){
         /* No-op.  The bail_on_error flag should already be set. */
       }else if( cli_strcmp(z,"-version")==0 ){
---      printf("%s %s (%d-bit)\n", sqlite3_libversion(), sqlite3_sourceid(),
---             8*(int)sizeof(char*));
+++      oputf("%s %s (%d-bit)\n", sqlite3_libversion(), sqlite3_sourceid(),
+++            8*(int)sizeof(char*));
         return 0;
       }else if( cli_strcmp(z,"-interactive")==0 ){
         /* already handled */
           open_db(&data, 0);
           rc = shell_exec(&data, z, &zErrMsg);
           if( zErrMsg!=0 ){
---          utf8_printf(stderr,"Error: %s\n", zErrMsg);
+++          eputf("Error: %s\n", zErrMsg);
             if( bail_on_error ) return rc!=0 ? rc : 1;
           }else if( rc!=0 ){
---          utf8_printf(stderr,"Error: unable to process SQL \"%s\"\n", z);
+++          eputf("Error: unable to process SQL \"%s\"\n", z);
             if( bail_on_error ) return rc;
           }
         }
   #if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB)
       }else if( cli_strncmp(z, "-A", 2)==0 ){
         if( nCmd>0 ){
---        utf8_printf(stderr, "Error: cannot mix regular SQL or dot-commands"
---                            " with \"%s\"\n", z);
+++        eputf("Error: cannot mix regular SQL or dot-commands"
+++              " with \"%s\"\n", z);
           return 1;
         }
         open_db(&data, OPEN_DB_ZIPFILE);
       }else if( cli_strcmp(z,"-unsafe-testing")==0 ){
         /* Acted upon in first pass. */
       }else{
---      utf8_printf(stderr,"%s: Error: unknown option: %s\n", Argv0, z);
-        utf8_print(stderr,"Use -help for a list of options.\n");
 --      raw_printf(stderr,"Use -help for a list of options.\n");
+++      eputf("%s: Error: unknown option: %s\n", Argv0, z);
+++      eputz("Use -help for a list of options.\n");
         return 1;
       }
       data.cMode = data.mode;
           rc = shell_exec(&data, azCmd[i], &zErrMsg);
           if( zErrMsg || rc ){
             if( zErrMsg!=0 ){
---            utf8_printf(stderr,"Error: %s\n", zErrMsg);
+++            eputf("Error: %s\n", zErrMsg);
             }else{
---            utf8_printf(stderr,"Error: unable to process SQL: %s\n", azCmd[i]);
+++            eputf("Error: unable to process SQL: %s\n", azCmd[i]);
             }
             sqlite3_free(zErrMsg);
             free(azCmd);
         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;
 --      }
 ++#if SHELL_CON_TRANSLATE==1
 ++      zCharset = " (UTF-16 console I/O)";
 ++#elif SHELL_CON_TRANSLATE==2
 ++      zCharset = " (MBCS console I/O)";
   #endif
---      printf(
+++      oputf(
           "SQLite version %s %.19s%s\n" /*extra-version-info*/
           "Enter \".help\" for usage hints.\n",
           sqlite3_libversion(), sqlite3_sourceid(), zCharset
         );
         if( warnInmemoryDb ){
---        printf("Connected to a ");
+++        oputz("Connected to a ");
           printBold("transient in-memory database");
---        printf(".\nUse \".open FILENAME\" to reopen on a "
+++        oputz(".\nUse \".open FILENAME\" to reopen on a "
                  "persistent database.\n");
         }
         zHistory = getenv("SQLITE_HISTORY");