--- /dev/null
--- /dev/null
- ** 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
++}
--- /dev/null
--- /dev/null
- ** 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.
++*/
- 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
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
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
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
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
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
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
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
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.
- d5e88fcde53ca7ba05bb164943a9f57bd92080bb7e5eebbbed64b9886ac97338
- 3978c084a509c3c739fbe87e20feec9ddf1325e35170329987af197ca9fd731a
-f1eae192315335d7e385b0a801a17700a9718d245bda6628518c5df9a1e9d3d6
+++14762a004cdf37d1e12f26aadff8ed3824893278f22ff141de86dd44d9b250f3
}
#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){
** 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
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);
}
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);
}
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) */
/*
** 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
# 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");