From: larrybr Date: Sat, 11 Nov 2023 06:20:38 +0000 (+0000) Subject: Pervasive changes to console_io.{c,h} in support of simplifying ubiquitous emit ops... X-Git-Tag: version-3.45.0~134^2~14 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=1229f8e6bde55d1bde34f74b95f76a02320c1c03;p=thirdparty%2Fsqlite.git Pervasive changes to console_io.{c,h} in support of simplifying ubiquitous emit ops in shell, and to get better control of console streams that might be opened only via .read or .output commands. Changes to shell to use {s,o,e}put{f,z}(...) calls for initial testing, but this check-in has few such conversions so that most will be in a separate check-in. Many renames to better follow recent coding convention. This code seems to be working, but has not been tested on difficult platforms or with multiple console hosts yet. So it is a WIP. FossilOrigin-Name: 14762a004cdf37d1e12f26aadff8ed3824893278f22ff141de86dd44d9b250f3 --- 1229f8e6bde55d1bde34f74b95f76a02320c1c03 diff --cc ext/consio/console_io.c index 35016b0c4a,0000000000,0000000000..5d38feef37 mode 100755,000000,000000..100755 --- a/ext/consio/console_io.c +++ b/ext/consio/console_io.c @@@@ -1,449 -1,0 -1,0 +1,637 @@@@ ++/* ++** 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 I/O by the - ** SQLite project command-line tools, as explained in console_io.h . +++** 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 ++# include ++# include ++# include +++# include ++# include "console_io.h" ++# include "sqlite3.h" ++#endif ++ - #if defined(_WIN32) || defined(WIN32) +++#if (defined(_WIN32) || defined(WIN32)) && !SQLITE_OS_WINRT ++# ifndef SHELL_NO_SYSINC ++# include ++# include ++# undef WIN32_LEAN_AND_MEAN ++# define WIN32_LEAN_AND_MEAN ++# include ++# endif ++# ifdef SHELL_LEGACY_CONSOLE_IO ++# define SHELL_CON_TRANSLATE 2 /* Use UTF-8/MBCS translation for console I/O */ - extern char *sqlite3_win32_utf8_to_mbcs_v2(const char *, int); ++# else ++# define SHELL_CON_TRANSLATE 1 /* Use WCHAR Windows APIs for console I/O */ ++# endif ++#else ++# ifndef SHELL_NO_SYSINC ++# include ++# 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 = { - (fileDesc!=-2)? _get_osfhandle(fileDesc) : (intptr_t)INVALID_HANDLE_VALUE +++ (fileDesc>=0)? _get_osfhandle(fileDesc) : (intptr_t)INVALID_HANDLE_VALUE ++ }; ++ return fid.fh; ++} ++#endif ++ ++typedef struct PerStreamTags { ++#if SHELL_CON_TRANSLATE - DWORD consMode; ++ HANDLE hx; +++ DWORD consMode; +++#else +++ short reachesConsole; ++#endif ++ FILE *pf; ++} PerStreamTags; ++ - static short fileOfConsole(FILE *pf, PerStreamTags *ppst){ +++/* 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; - DWORD dwj; +++ 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,&dwj)); - if( rv ){ - ppst->hx = fh; - ppst->pf = pf; - GetConsoleMode(fh, &ppst->consMode); - } +++ rv = (GetFileType(fh) == FILE_TYPE_CHAR && GetConsoleMode(fh,&dwCM)); ++ } +++ ppst->hx = (rv)? fh : INVALID_HANDLE_VALUE; +++ ppst->consMode = dwCM; ++ return rv; ++#else - return (short)isatty(fileno(pf)); +++ ppst->pf = pf; +++ ppst->reachesConsole = ( (short)isatty(fileno(pf)) ); +++ return ppst->reachesConsole; ++#endif ++} ++ - #define SHELL_INVALID_FILE_PTR ((FILE *)sizeof(FILE*)) - #define SHELL_INVALID_CONS_MODE 0xFFFF0000 - ++#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 { - /* 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; +++ 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_CONS_MODE, INVALID_HANDLE_VALUE, 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 - # define CI_INITIALIZER { SHELL_INVALID_FILE_PTR } +++ (void)ppst; +++ (void)odir; ++#endif +++} ++ - static ConsoleInfo consoleInfo = { - { /* pst */ CI_INITIALIZER, CI_INITIALIZER, CI_INITIALIZER }, +++SQLITE_INTERNAL_LINKAGE void consoleRenewSetup(void){ ++#if SHELL_CON_TRANSLATE - 0, 0, 1, /* haveInput, outputIx, stdinEof */ +++ int ix = 0; +++ while( ix < 6 ){ +++ PerStreamTags *ppst = (ix<3)? +++ &consoleInfo.pstSetup[ix] : &consoleInfo.pstDesignated[ix-3]; +++ maybeSetupAsConsole(ppst, (ix % 3)>0); +++ ++ix; +++ } ++#endif - CSCS_NoConsole - }; - #undef CI_INITIALIZER +++} ++ - SQLITE_INTERNAL_LINKAGE ConsoleStdConsStreams +++SQLITE_INTERNAL_LINKAGE StreamsAreConsole ++consoleClassifySetup( FILE *pfIn, FILE *pfOut, FILE *pfErr ){ - ConsoleStdConsStreams rv = CSCS_NoConsole; - FILE *apf[3] = { pfIn, pfOut, pfErr }; +++ StreamsAreConsole rv = SAC_NoConsole; +++ FILE* apf[3] = { pfIn, pfOut, pfErr }; ++ int ix; ++ for( ix = 2; ix >= 0; --ix ){ - 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< 0 ) fflush(apf[ix]); ++#if SHELL_CON_TRANSLATE == 2 ++ _setmode(_fileno(apf[ix]), _O_TEXT); ++#endif ++ } - consoleInfo.cscs = rv; +++ consoleInfo.sacSetup = rv; +++ consoleRenewSetup(); ++ return rv; ++} ++ ++SQLITE_INTERNAL_LINKAGE void SQLITE_CDECL consoleRestore( void ){ - if( consoleInfo.cscs ){ +++#if SHELL_CON_TRANSLATE +++ static ConsoleInfo *pci = &consoleInfo; +++ if( pci->sacSetup ){ ++ int ix; ++ for( ix=0; ix<3; ++ix ){ - if( consoleInfo.cscs & (CSCS_InConsole<sacSetup & (SAC_InConsole<pstSetup[ix]; +++# if SHELL_CON_TRANSLATE == 2 ++ static int tmode = _O_TEXT; - /* Consider: Read these modes in consoleClassifySetup somehow. +++ /* 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.) ++ */ - _setmode(_fileno(consoleInfo.pst[ix].pf), tmode); - #endif - #if SHELL_CON_TRANSLATE +++ _setmode(_fileno(pci->pstSetup[ix].pf), tmode); +++# endif ++ SetConsoleMode(ppst->hx, ppst->consMode); - ppst->hx = INVALID_HANDLE_VALUE; - #endif - ppst->pf = SHELL_INVALID_FILE_PTR; ++ } - consoleInfo.cscs = CSCS_NoConsole; - #if SHELL_CON_TRANSLATE - consoleInfo.stdinEof = consoleInfo.haveInput = consoleInfo.outputIx= 0; - #endif ++ } ++ } +++#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; +++/* 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){ - short ico = isConOut(pf); - if( ico>1 || bFlush ) fflush(pf); +++ if( bFlush ) fflush(pf); ++ _setmode(_fileno(pf), mode); ++} ++#else - # define setModeFlushQ(f, b, m) if(isConOut(f)>0||b) fflush(f) +++# 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 - /* Write plain 0-terminated output to stream known as console. */ - static int conioZstrOut(int rch, const char *z){ +++/* 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(); - FILE *pfO = consoleInfo.pst[rch].pf; +++ 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. */ - if( WriteConsoleW(consoleInfo.pst[rch].hx, zw,nwc, 0, NULL) ){ +++ if( WriteConsoleW(ppst->hx, zw,nwc, 0, NULL) ){ ++ rv = nc; ++ } ++# endif ++ } ++ sqlite3_free(zw); ++ } ++ } ++ } ++ return rv; ++} ++ - /* For fprintfUtf8() and printfUtf8() when stream is known as console. */ - static int conioVmPrintf(int rch, const char *zFormat, va_list ap){ +++/* 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); - int rv = conioZstrOut(rch, z); +++ 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; +++} ++ - SQLITE_INTERNAL_LINKAGE int printfUtf8(const char *zFormat, ...){ +++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 - if( SHELL_INVALID_FILE_PTR != consoleInfo.pst[1].pf ){ - rv = conioVmPrintf(1, zFormat, ap); +++ if( pstReachesConsole(ppst) ){ +++ rv = conioVmPrintf(ppst, zFormat, ap); ++ }else{ ++#endif - rv = vfprintf(stdout, zFormat, ap); +++ rv = vfprintf(pfErr, zFormat, ap); ++#if SHELL_CON_TRANSLATE ++ } ++#endif ++ va_end(ap); ++ return rv; ++} - #undef SHELL_INVALID_FILE_PTR ++ - SQLITE_INTERNAL_LINKAGE int fprintfUtf8(FILE *pfO, const char *zFormat, ...){ +++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 - short rch = isConOut(pfO); - if( rch > 0 ){ - rv = conioVmPrintf(rch, zFormat, ap); - }else { +++ 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; ++} ++ - SQLITE_INTERNAL_LINKAGE int fputsUtf8(const char *z, FILE *pfO){ +++SQLITE_INTERNAL_LINKAGE int fPutsUtf8(const char *z, FILE *pfO){ ++#if SHELL_CON_TRANSLATE - short rch = isConOut(pfO); - if( rch > 0 ){ - return conioZstrOut(rch, z); +++ 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 ++ - SQLITE_INTERNAL_LINKAGE char* fgetsUtf8(char *cBuf, int ncMax, FILE *pfIn){ +++SQLITE_INTERNAL_LINKAGE char* fGetsUtf8(char *cBuf, int ncMax, FILE *pfIn){ ++ if( pfIn==0 ) pfIn = stdin; ++#if SHELL_CON_TRANSLATE - if( pfIn == consoleInfo.pst[0].pf ){ +++ 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; - if( consoleInfo.stdinEof ) return 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.pst[0].hx, wcBuf, na, &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.pst[0].hx, wcBuf+nbr, 1, &nbrx, 0); +++ 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".) - ** Note that this is done without regard for any setModeText() +++ ** 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-2] = '\n'; - --noc; - } +++ 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]==0x1a ){ - consoleInfo.stdinEof = 1; +++ 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 ) return 0; - cBuf[noc] = 0; - return cBuf; +++ 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); - nco += nug; +++ 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 ++} diff --cc ext/consio/console_io.h index e799c71e74,0000000000,0000000000..2d6178fed3 mode 100644,000000,000000..100644 --- a/ext/consio/console_io.h +++ b/ext/consio/console_io.h @@@@ -1,187 -1,0 -1,0 +1,226 @@@@ ++/* ++** 2023 November 1 ++** ++** The author disclaims copyright to this source code. In place of ++** a legal notice, here is a blessing: ++** ++** May you do good and not evil. ++** May you find forgiveness for yourself and forgive others. ++** May you share freely, never taking more than you give. ++** ++******************************************************************************** - ** This file exposes various interfaces used for console I/O by the - ** SQLite project command-line tools. These interfaces are used at - ** either source conglomeration time, compilation time, or run time. +++** This file exposes various interfaces used for console and other I/O +++** by the SQLite project command-line tools. These interfaces are used +++** at either source conglomeration time, compilation time, or run time. ++** This source provides for either inclusion into conglomerated, - ** "single-source" forms or separate compilation then linking. (TBD) +++** "single-source" forms or separate compilation then linking. ++** ++** Platform dependencies are "hidden" here by various stratagems so - ** that, provided certain conditions are met, the programs using - ** this source or object code compiled from it need no explicit - ** conditional compilation in their source for their console I/O. +++** 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 ++#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. */ - typedef enum ConsoleStdConsStreams { - CSCS_NoConsole = 0, - CSCS_InConsole = 1, CSCS_OutConsole = 2, CSCS_ErrConsole = 4, - CSCS_AnyConsole = 0x7 - } ConsoleStdConsStreams; +++typedef enum StreamsAreConsole { +++ SAC_NoConsole = 0, +++ SAC_InConsole = 1, SAC_OutConsole = 2, SAC_ErrConsole = 4, +++ SAC_AnyConsole = 0x7 +++} StreamsAreConsole; ++ ++/* ++** Classify the three standard I/O streams according to whether ++** they are connected to a console attached to the process. ++** - ** Returns the bit-wise OR of CSCS_{In,Out,Err}Console values, - ** or CSCS_NoConsole if none of the streams reaches a console. +++** Returns the bit-wise OR of SAC_{In,Out,Err}Console values, +++** or SAC_NoConsole if none of the streams reaches a console. ++** ++** This function should be called before any I/O is done with ++** the given streams. As a side-effect, the given inputs are ++** recorded so that later I/O operations on them may be done ++** differently than the C library FILE* I/O would be done, - ** iff the stream is used for the I/O functions that follow. +++** iff the stream is used for the I/O functions that follow, +++** and to support the ones that use an implicit stream. ++** ++** On some platforms, stream or console mode alteration (aka ++** "Setup") may be made which is undone by consoleRestore(). +++*/ +++SQLITE_INTERNAL_LINKAGE StreamsAreConsole +++consoleClassifySetup( FILE *pfIn, FILE *pfOut, FILE *pfErr ); +++/* A usual call for convenience: */ +++#define SQLITE_STD_CONSOLE_INIT() consoleClassifySetup(stdin,stdout,stderr) +++ +++/* +++** After an initial call to consoleClassifySetup(...), renew +++** the same setup it effected. (A call not after is an error.) +++** This will restore state altered by consoleRestore(); ++** ++** Applications which run an inferior (child) process which ++** inherits the same I/O streams may call this function after ++** such a process exits to guard against console mode changes. ++*/ - SQLITE_INTERNAL_LINKAGE ConsoleStdConsStreams - consoleClassifySetup( FILE *pfIn, FILE *pfOut, FILE *pfErr ); +++SQLITE_INTERNAL_LINKAGE void consoleRenewSetup(void); ++ ++/* ++** Undo any side-effects left by consoleClassifySetup(...). ++** ++** This should be called after consoleClassifySetup() and ++** before the process terminates normally. It is suitable ++** for use with the atexit() C library procedure. After - ** this call, no I/O should be done with the console - ** until consoleClassifySetup(...) is called again. +++** 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 ); ++ ++/* - ** Render output like fprintf(). If the output is going to the +++** 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(). ++*/ - 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, ...); +++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, ...); ++ ++/* - ** Render output like fputs(). If the output is going to the +++** Emit output like fputs(). If the output is going to the ++** console and translation from UTF-8 is necessary, perform ++** the needed translation. Otherwise, write given text to the ++** provided stream almost as-is, possibly with newline ++** translation as specified by set{Binary,Text}Mode(). ++*/ - SQLITE_INTERNAL_LINKAGE int fputsUtf8(const char *z, FILE *pfO); +++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); +++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 98578565a7,ea62075a91,f1683dfa58..c56d84fa85 --- a/manifest +++ 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 4d85fa6de7,8a3f265a0b,873b025efc..340d950f96 --- a/manifest.uuid +++ b/manifest.uuid @@@@ -1,1 -1,1 -1,1 +1,1 @@@@ - d5e88fcde53ca7ba05bb164943a9f57bd92080bb7e5eebbbed64b9886ac97338 - 3978c084a509c3c739fbe87e20feec9ddf1325e35170329987af197ca9fd731a -f1eae192315335d7e385b0a801a17700a9718d245bda6628518c5df9a1e9d3d6 +++14762a004cdf37d1e12f26aadff8ed3824893278f22ff141de86dd44d9b250f3 diff --cc src/shell.c.in index a32c4f5d57,8d201bbbda,0e0dbd36c7..b3b97e1cec --- a/src/shell.c.in +++ b/src/shell.c.in @@@@ -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 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 @@@@ -10500,11 -10784,9 -10788,9 +10527,11 @@@@ 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); @@@@ -11825,14 -12113,14 -12117,14 +11852,14 @@@@ 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; @@@@ -11902,10 -12189,12 -12193,12 +11929,10 @@@@ 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 @@@@ -12174,7 -12470,7 -12474,7 +12201,7 @@@@ 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); } } @@@@ -12184,7 -12489,7 -12493,7 +12211,7 @@@@ 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 } @@@@ -12301,8 -12606,8 -12610,8 +12328,8 @@@@ }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 */ @@@@ -12358,18 -12663,18 -12667,18 +12385,18 @@@@ 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); @@@@ -12387,8 -12692,8 -12696,8 +12414,8 @@@@ }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; @@@@ -12412,9 -12717,9 -12721,9 +12439,9 @@@@ 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); @@@@ -12430,20 -12735,23 -12739,23 +12457,20 @@@@ 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");