| /* | 
 | ** 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 "sqlite3.h" | 
 | #endif | 
 | #ifndef HAVE_CONSOLE_IO_H | 
 | # include "console_io.h" | 
 | #endif | 
 | #if defined(_MSC_VER) | 
 | # pragma warning(disable : 4204) | 
 | #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 | 
 | 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 | 
 | } | 
 |  | 
 | # ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING | 
 | #  define ENABLE_VIRTUAL_TERMINAL_PROCESSING  (0x4) | 
 | # 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 a | 
 | ** byref output when chix!=0 and a byref 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(ppstTry) ){ | 
 |       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 | 
 | # ifdef CONSIO_SPUTB | 
 | 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 | 
 | } | 
 | # 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) */ | 
 |  | 
 | #if defined(_MSC_VER) | 
 | # pragma warning(default : 4204) | 
 | #endif | 
 |  | 
 | #undef SHELL_INVALID_FILE_PTR |