]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Setup, takedown, mode set and output working. No input yet. (WIP)
authorlarrybr <larrybr@noemail.net>
Sun, 5 Nov 2023 01:21:14 +0000 (01:21 +0000)
committerlarrybr <larrybr@noemail.net>
Sun, 5 Nov 2023 01:21:14 +0000 (01:21 +0000)
FossilOrigin-Name: dfea85be1fb927ea446c9d98bae42ba1197bdab098aa6d95aa512a37d07a1e52

manifest
manifest.uuid
src/console_io.c [new file with mode: 0755]
src/console_io.h

index ea6e754aed7dfe29dcd0f8e748a71919492f896e..914526c556b23912b33aaff5b8a2e0e6386f6427 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Define\sinterface\sbetween\sproject\scommand-line\sapps\sand\sa\sconsole\sI/O\s"library".
-D 2023-11-04T02:22:04.015
+C Setup,\stakedown,\smode\sset\sand\soutput\sworking.\sNo\sinput\syet.\s(WIP)
+D 2023-11-05T01:21:14.743
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -669,7 +669,8 @@ F src/btreeInt.h ef12a72b708677e48d6bc8dcd66fed25434740568b89e2cfa368093cfc5b9d1
 F src/build.c 189e4517d67f09f0a3e0d8e1faa6e2ef0c2e95f6ac82e33c912cb7efa2a359cc
 F src/callback.c db3a45e376deff6a16c0058163fe0ae2b73a2945f3f408ca32cf74960b28d490
 F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
-F src/console_io.h 14057195f16cace1f669f723510190f90300ee6c1ef0a6f417a54344bc57bdd0
+F src/console_io.c 484a4ad56c18ddc62b845494f8ac6e06df9f9b0bc2fa60ac2dcba74635bdf8da x
+F src/console_io.h 6b7c86a5778445e507a089b9808803e4523e2989f33c04692e008eae3f0f4d8a
 F src/ctime.c 23331529e654be40ca97d171cbbffe9b3d4c71cc53b78fe5501230675952da8b
 F src/date.c eebc54a00e888d3c56147779e9f361b77d62fd69ff2008c5373946aa1ba1d574
 F src/dbpage.c 80e46e1df623ec40486da7a5086cb723b0275a6e2a7b01d9f9b5da0f04ba2782
@@ -2143,11 +2144,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
 F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 570635575cc5fbffe910ed992b58393e214117ef3b5370a66f115cd0ee202913
-R 44e2680e2cc755f86742bfd0211316ba
-T *branch * console-io-lib
-T *sym-console-io-lib *
-T -sym-trunk *
+P 64abef8314b8544fdc7b71317d61a4641dc607a1ae42b8ff21543226fd338ba2
+R 9aec452b903f28bc0cbf638b7c11370e
 U larrybr
-Z e3b2358cc83000c61d02936c7cb34f1b
+Z 37ecbe5d111f6f842b9b1e97c1e0e0d1
 # Remove this line to create a well-formed Fossil manifest.
index 66b256945590f985c65180d498f8aac511b3f122..5e27b835d68d2fef91becee71579caf17493ae63 100644 (file)
@@ -1 +1 @@
-64abef8314b8544fdc7b71317d61a4641dc607a1ae42b8ff21543226fd338ba2
\ No newline at end of file
+dfea85be1fb927ea446c9d98bae42ba1197bdab098aa6d95aa512a37d07a1e52
\ No newline at end of file
diff --git a/src/console_io.c b/src/console_io.c
new file mode 100755 (executable)
index 0000000..8c4db84
--- /dev/null
@@ -0,0 +1,258 @@
+/*
+** 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 .
+*/
+
+#ifndef SQLITE_CDECL
+# define SQLITE_CDECL
+#endif
+
+#include <stdarg.h>
+#include <string.h>
+#include "console_io.h"
+#include "sqlite3.h"
+
+#if defined(_WIN32) || defined(WIN32)
+# include <io.h>
+# include <fcntl.h>
+# ifdef SHELL_LEGACY_CONSOLE_IO
+#  define SHELL_CON_TRANSLATE 2 /* Use UTF-8/MBCS translation for console I/O */
+# else
+#  define SHELL_CON_TRANSLATE 1 /* Use wchar APIs for console I/O */
+# endif
+#else
+# include <unistd.h>
+# 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
+  };
+  return fid.fh;
+}
+#endif
+
+static short fileOfConsole(FILE *pf){
+#if SHELL_CON_TRANSLATE
+  DWORD dwj;
+  HANDLE fh = handleOfFile(pf);
+  if( INVALID_HANDLE_VALUE != fh ){
+    return (GetFileType(fh) == FILE_TYPE_CHAR && GetConsoleMode(fh,&dwj));
+  }else return 0;
+#else
+  return (short)isatty(fileno(pf));
+#endif
+}
+
+#define SHELL_INVALID_FILE_PTR ((FILE *)sizeof(FILE*))
+
+typedef struct ConsoleInfo {
+  /* int iDefaultFmode; */
+  ConsoleStdConsStreams cscs;
+#if SHELL_CON_TRANSLATE
+  HANDLE hIn; HANDLE hOut; HANDLE hErr;
+  HANDLE hLowest;
+#endif
+  FILE *pfIn; FILE *pfOut; FILE *pfErr;
+} ConsoleInfo;
+
+static ConsoleInfo consoleInfo = {
+  /* 0, iDefaultFmode */
+  CSCS_NoConsole,
+#if SHELL_CON_TRANSLATE
+  INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE,
+  INVALID_HANDLE_VALUE,
+#endif
+  SHELL_INVALID_FILE_PTR, SHELL_INVALID_FILE_PTR, SHELL_INVALID_FILE_PTR
+};
+#undef SHELL_INVALID_FILE_PTR
+
+#if SHELL_CON_TRANSLATE == 1
+# define SHELL_CON_MODE_CSZ _O_U16TEXT
+#elif SHELL_CON_TRANSLATE == 2
+# define SHELL_CON_MODE_CSZ _O_U8TEXT
+#endif
+
+INT_LINKAGE ConsoleStdConsStreams
+consoleClassifySetup( FILE *pfIn, FILE *pfOut, FILE *pfErr ){
+  ConsoleStdConsStreams rv = CSCS_NoConsole;
+  if( fileOfConsole(pfErr) ){
+    rv |= CSCS_ErrConsole;
+    consoleInfo.pfErr = pfErr;
+#if SHELL_CON_TRANSLATE
+    fflush(pfErr);
+# if SHELL_CON_TRANSLATE == 1
+    _setmode(_fileno(pfErr), _O_U16TEXT);
+    _setmode(_fileno(pfErr), _O_BINARY);
+# elif SHELL_CON_TRANSLATE == 2
+    _setmode(_fileno(pfErr), _O_U8TEXT);
+    _setmode(_fileno(pfErr), _O_TEXT);
+# endif
+    consoleInfo.hLowest = consoleInfo.hErr = handleOfFile(pfErr);
+#endif
+  }
+  if( fileOfConsole(pfOut) ){
+    rv |= CSCS_OutConsole;
+    consoleInfo.pfOut = pfOut;
+#if SHELL_CON_TRANSLATE
+    fflush(pfOut);
+# if SHELL_CON_TRANSLATE == 1
+    _setmode(_fileno(pfOut), _O_U16TEXT);
+    _setmode(_fileno(pfOut), _O_BINARY);
+# elif SHELL_CON_TRANSLATE == 2
+    _setmode(_fileno(pfOut), _O_U8TEXT);
+    _setmode(_fileno(pfOut), _O_TEXT);
+# endif
+    consoleInfo.hLowest = consoleInfo.hOut = handleOfFile(pfOut);
+#endif
+  }
+  if( fileOfConsole(pfIn) ){
+    rv |= CSCS_InConsole;
+    consoleInfo.pfIn = pfIn;
+#if SHELL_CON_TRANSLATE == 1
+    _setmode(_fileno(pfIn), _O_U16TEXT);
+    _setmode(_fileno(pfIn), _O_BINARY);
+    consoleInfo.hLowest = consoleInfo.hIn = handleOfFile(pfIn);
+#elif SHELL_CON_TRANSLATE == 2
+    _setmode(_fileno(pfIn), _O_U8TEXT);
+    _setmode(_fileno(pfIn), _O_TEXT);
+    consoleInfo.hLowest = consoleInfo.hIn = handleOfFile(pfIn);
+#endif
+  }
+  consoleInfo.cscs = rv;
+  return rv;
+}
+
+INT_LINKAGE void SQLITE_CDECL consoleRestore( void ){
+#if SHELL_CON_TRANSLATE
+  if( consoleInfo.cscs ){
+    /* ToDo: Read these modes 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.
+    */
+    int tmode = _O_TEXT, xmode = _O_U8TEXT;
+    if( consoleInfo.cscs & CSCS_InConsole ){
+      _setmode(_fileno(consoleInfo.pfIn), tmode);
+      _setmode(_fileno(consoleInfo.pfIn), xmode);
+    }
+    if( consoleInfo.cscs & CSCS_OutConsole ){
+      _setmode(_fileno(consoleInfo.pfOut), tmode);
+      _setmode(_fileno(consoleInfo.pfOut), xmode);
+    }
+    if( consoleInfo.cscs & CSCS_ErrConsole ){
+      _setmode(_fileno(consoleInfo.pfErr), tmode);
+      _setmode(_fileno(consoleInfo.pfErr), xmode);
+    }
+  }
+#endif
+#ifdef TEST_CIO
+#endif
+}
+
+static short isConOut(FILE *pf){
+  if( pf==consoleInfo.pfOut ) return 1;
+  else if( pf==consoleInfo.pfErr ) return 2;
+  else return 0;
+}
+
+INT_LINKAGE void setBinaryMode(FILE *pf, short bFlush){
+  short ico = isConOut(pf);
+  if( ico || bFlush ) fflush(pf);
+#if SHELL_CON_TRANSLATE == 2
+  _setmode(_fileno(pf), _O_BINARY);
+#elif SHELL_CON_TRANSLATE == 1
+  /* Never change between text/binary on UTF-16 console streamss. */
+  if( !ico && !(consoleInfo.pfIn==pf)) _setmode(_fileno(pf), _O_BINARY);
+#endif
+}
+INT_LINKAGE void setTextMode(FILE *pf, short bFlush){
+  short ico = isConOut(pf);
+  if( ico || bFlush ) fflush(pf);
+#if SHELL_CON_TRANSLATE == 2
+  _setmode(_fileno(pf), _O_TEXT);
+#elif SHELL_CON_TRANSLATE == 1
+  /* Never change between text/binary on UTF-16 console streamss. */
+  if( !ico && !(consoleInfo.pfIn==pf)) _setmode(_fileno(pf), _O_TEXT);
+#endif
+}
+/* Later: Factor common code out of above 2 procs. */
+
+INT_LINKAGE int fprintfUtf8(FILE *pfO, const char *zFormat, ...){
+  va_list ap;
+  int rv = 0;
+  short on = isConOut(pfO);
+  va_start(ap, zFormat);
+  if( on > 0 ){
+#if SHELL_CON_TRANSLATE
+    char *z1 = sqlite3_vmprintf(zFormat, ap);
+# if SHELL_CON_TRANSLATE == 2
+    /* Legacy translation to active code page, then MBCS chars out. */
+    char *z2 = sqlite3_win32_utf8_to_mbcs_v2(z1, 0);
+    if( z2!=NULL ){
+      rv = strlen(z2);
+      vfprintf(pfO, "%s", z2);
+      sqlite3_free(z2);
+    }
+# else
+    /* Translation from UTF-8 to UTF-16, then WCHAR characters out. */
+    if( z1!=NULL ){
+      int nwc;
+      WCHAR *zw2 = 0;
+      rv = strlen(z1);
+      nwc = MultiByteToWideChar(CP_UTF8,0,z1,rv,0,0);
+      if( nwc>0 ){
+        zw2 = sqlite3_malloc64((nwc+1)*sizeof(WCHAR));
+        if( zw2!=NULL ){
+          HANDLE ho = (on==1)? consoleInfo.hOut : consoleInfo.hErr;
+          nwc = MultiByteToWideChar(CP_UTF8,0,z1,rv,zw2,nwc);
+          zw2[nwc] = 0;
+          WriteConsoleW(ho, zw2, nwc, 0, NULL);
+          sqlite3_free(zw2);
+        }else rv = 0;
+      }
+    }
+# endif
+    sqlite3_free(z1);
+#else
+#endif
+  }else{
+    rv = vfprintf(pfO, zFormat, ap);
+  }
+  va_end(ap);
+  return rv;
+}
+
+INT_LINKAGE int fgetsUtf8(char *buf, int ncMax, FILE *pfIn){
+  return 0;
+}
+
+#ifdef TEST_CIO
+// cl -Zi -I. -DWIN32 -DTEST_CIO sqlite3.c src/console_io.c -Fecio.exe
+// gcc -I. -DWIN32 -DTEST_CIO -o cio sqlite3.c src/console_io.c -o cio.exe
+const char *prompts[] = { "main", "cont" };
+Prompts goofy = { 2, prompts };
+
+int main(int na, char *av[]){
+  ConsoleStdConsStreams cc = consoleClassifySetup(stdin, stdout, stderr);
+  setTextMode(stdout, 1);
+  setTextMode(stderr, 1);
+  fprintfUtf8(stderr, "%d\n", cc);
+  fprintfUtf8(stdout, "%s=%d\n", "∑(1st 7 primes)", 42);
+  fprintfUtf8(stderr, "%s\n", "∫ (1/x) dx ≡ ln(x)");
+  consoleRestore();
+  return 0;
+}
+#endif /* defined(TEST_CIO) */
index b8c1ea982daf6561bfd66072d8596d0d83d05712..444c3e0e65bd2019e6d5bcb8eaf440d175e25716 100644 (file)
 ** This code may change in tandem with other project code as needed.
 */
 
+#ifndef INT_LINKAGE
+# define INT_LINKAGE /* Linkage will be external to translation unit. */
+# include <stdio.h>
+# include <stdlib.h>
+# include <limits.h>
+# if defined(_WIN32) || defined(WIN32)
+#  undef WIN32_LEAN_AND_MEAN
+#  define WIN32_LEAN_AND_MEAN
+#  include <windows.h>
+#  include <io.h>
+#  include <fcntl.h>
+# endif
+#endif
+
 /* Define enum for use with following function. */
-enum ConsoleStdStreams {
-  CSC_NoConsole = 0,
-  CSC_InConsole = 1, CSC_OutConsole = 2, CSC_ErrConsole = 4,
-  CSC_AnyConsole = 0x7
-};
+typedef enum ConsoleStdConsStreams {
+  CSCS_NoConsole = 0,
+  CSCS_InConsole = 1, CSCS_OutConsole = 2, CSCS_ErrConsole = 4,
+  CSCS_AnyConsole = 0x7
+} ConsoleStdConsStreams;
 
 /*
 ** 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 CSC_{In,Out,Err}Console values,
-** or CSC_NoConsole if none of the streams reaches a console.
+** Returns the bit-wise OR of CSCS_{In,Out,Err}Console values,
+** or CSCS_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
@@ -47,8 +61,8 @@ enum ConsoleStdStreams {
 ** On some platforms, stream or console mode alteration (aka
 ** "Setup") may be made which is undone by consoleRestore().
 */
-INT_LINKAGE ConsoleStdStreams
-consoleClassifySetup( FILE *pfIn, FILE *pfOut,FILE *pfErr );
+INT_LINKAGE ConsoleStdConsStreams
+consoleClassifySetup( FILE *pfIn, FILE *pfOut, FILE *pfErr );
 
 /*
 ** Undo any side-effects left by consoleClassifySetup(...).
@@ -64,10 +78,10 @@ INT_LINKAGE void SQLITE_CDECL consoleRestore( void );
 ** Render 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, with possibly with
-** newline translation as set by set{Binary,Text}Mode().
+** to the provided stream almost as-is, possibly with newline
+** translation as specified by set{Binary,Text}Mode().
 */
-INT_LINKAGE int fprintfUtf8(FILE *, const char *zFmt, ...);
+INT_LINKAGE int fprintfUtf8(FILE *pfO, const char *zFormat, ...);
 
 /*
 ** Collect input like fgets(...) with special provisions for input
@@ -79,14 +93,23 @@ INT_LINKAGE int fgetsUtf8(char *buf, int ncMax, FILE *pfIn);
 
 /*
 ** Set given stream for binary mode, where newline translation is
-** not done, or to text mode where, for some platforms, newlines
+** 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.
+** to consoleClassifySetup() as an output, it is flushed first.
+**
+** Note that binary/text mode has no effect on console output
+** translation. Newline chars start a new line on all platforms.
 */
-INT_LINKAGE void setBinaryMode(File *);
-INT_LINKAGE void setTextMode(File *);
+INT_LINKAGE void setBinaryMode(FILE *, short bFlush);
+INT_LINKAGE void setTextMode(FILE *, short bFlush);
+
+typedef struct Prompts {
+  int numPrompts;
+  const char **azPrompts;
+} Prompts;
 
 /*
 ** Macros for use of a line editor.
@@ -128,8 +151,8 @@ INT_LINKAGE void setTextMode(File *);
 ** library to interactively collect line edited input.
 */
 INT_LINKAGE char *
-shellGetLine(File *pfIn, char *zBufPrior, int nLen,
-             short isContinuation, const char *azPrompt[2]);
+shellGetLine(FILE *pfIn, char *zBufPrior, int nLen,
+             short isContinuation, Prompts azPrompt);
 
 /*
 ** TBD: Define an interface for application(s) to generate