SQLite

Check-in [73a5f54231]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Cure CLI double-prompting (by ditching gcc fgetws()), general cleanup. Work remaining is to avoid effect of -utf8 when a line editor is linked/used as part of CLI.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | cli-utf8
Files: files | file ages | folders
SHA3-256: 73a5f54231e9f6ad8f013df3987ea48c516080f9193ed873b56f982ee75658c2
User & Date: larrybr 2023-04-14 19:56:32.111
Context
2023-04-14
21:23
Set CLI -utf8 option and build with line-editing package to be mutually exclusive. Integration of console-invasive UTF-8 handling with line-editing takeover of console may come later. (check-in: 047344a915 user: larrybr tags: cli-utf8)
19:56
Cure CLI double-prompting (by ditching gcc fgetws()), general cleanup. Work remaining is to avoid effect of -utf8 when a line editor is linked/used as part of CLI. (check-in: 73a5f54231 user: larrybr tags: cli-utf8)
2023-04-13
14:14
Get CLI utf8_fgets() to not consume more input than it returns. Get console setup restoration to happen for all non-crash exits. (check-in: b4fa233d3d user: larrybr tags: cli-utf8)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/shell.c.in.
585
586
587
588
589
590
591


592
593
594
595
596
597
598
599
600
601
602
603

604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642

643

644
645
646
647
648
649
650

651

652

653
654

655

656

657


658
















659
660
661

662

663
664
665
666
667
668
669
    }
  }
  return dynPrompt.dynamicPrompt;
}
#endif /* !defined(SQLITE_OMIT_DYNAPROMPT) */

#if (defined(_WIN32) || defined(WIN32)) && !defined(SQLITE_SHELL_FIDDLE)


static int infsMode;
static UINT codePage = 0;
static HANDLE hConsoleIn;
static DWORD consoleMode;

/*
** Prepare input stream, (if known to be a WIN32 console), for UTF-8
** input (from either typing or suitable paste operations) and for
** UTF-8 rendering. This may "fail" with a message to stderr, where
** the preparation is not done and common "code page" issues occur.
*/
static void instream_prepare(void){

  if( isatty(0) ){
    if( !IsValidCodePage(CP_UTF8) ){
      fprintf(stderr, "Cannot use UTF-8 code page.\n");
      console_utf8 = 0;
      return;
    }
    codePage = GetConsoleCP();
    SetConsoleCP(CP_UTF8);
    hConsoleIn = GetStdHandle(STD_INPUT_HANDLE);
    GetConsoleMode( hConsoleIn, &consoleMode);
    SetConsoleMode( hConsoleIn, consoleMode | ENABLE_LINE_INPUT );
    infsMode = _setmode(_fileno(stdin), _O_U16TEXT);
    console_utf8 = 1;
  }else{
    console_utf8 = 0;
  }
}

/*
** Undo the effects of instream_prepare(), if any.
*/
static void SQLITE_CDECL instream_restore(void){
  if( console_utf8 && codePage!=0 ){
    _setmode(_fileno(stdin), infsMode);
    SetConsoleCP(codePage);
    SetConsoleMode( hConsoleIn, consoleMode );
    console_utf8 = 0; /* Avoid multiple calls. */
  }
}

/*
** 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
** startup option, -utf8, has not been provided or taken effect.
*/
static char* utf8_fgets(char *buf, int ncmax, FILE *fin){
  #define SQLITE_IA_LINE_LEN 150
  if( fin==stdin && stdin_is_interactive && console_utf8 ){

    wchar_t wbuf[SQLITE_IA_LINE_LEN];

    int noc = 0;
    if( ncmax == 0 ) return 0;
    buf[0] = 0;
    while( noc < ncmax-7-1 ){
      /* There is room for at least 2 more characters and the 0-terminator. */
      int na = (ncmax-1 - noc)/4;
      wchar_t * wz;

      if( na > SQLITE_IA_LINE_LEN ) na = SQLITE_IA_LINE_LEN;

      wz = fgetws(wbuf, na, stdin);

      if( wz != 0 ){
        int nmb = WideCharToMultiByte(CP_UTF8, 0, wz, -1, 0, 0, 0, 0);

        if( nmb !=0 && noc+nmb <= ncmax ){

          WideCharToMultiByte(CP_UTF8, 0, wz, -1, buf+noc, nmb, 0, 0);

          noc += nmb-1; /* Strip 0-terminator added by above call. */


          if( buf[noc-1] == '\n' ) break;
















        }else break; /* Drop apparent garbage in. (Could assert.) */
      }else break;
    }

    if( noc == 0 ) return 0;

    return buf;
  }else{
    return fgets(buf, ncmax, fin);
  }
}

# define fgets(b,n,f) utf8_fgets(b,n,f)







>
>
|
|
|
|








>
|







<













|














|

>
|
>

|

|
|
|
<
>
|
>
|
>
|
|
>

>
|
>
|
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>



>

>







585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614

615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653

654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
    }
  }
  return dynPrompt.dynamicPrompt;
}
#endif /* !defined(SQLITE_OMIT_DYNAPROMPT) */

#if (defined(_WIN32) || defined(WIN32)) && !defined(SQLITE_SHELL_FIDDLE)
/* Following variables are used for -utf8 operation. */
static int stdinEof = 0;  /* EOF seen on console input */
static int infsMode;      /* Input file stream mode upon shell start */
static UINT codePage = 0; /* Input code page upon shell start */
static HANDLE hConsoleIn = INVALID_HANDLE_VALUE; /* Console input handle */
static DWORD consoleMode; /* Console mode upon shell start */

/*
** Prepare input stream, (if known to be a WIN32 console), for UTF-8
** input (from either typing or suitable paste operations) and for
** UTF-8 rendering. This may "fail" with a message to stderr, where
** the preparation is not done and common "code page" issues occur.
*/
static void instream_prepare(void){
  hConsoleIn = GetStdHandle(STD_INPUT_HANDLE);
  if( isatty(0) && GetFileType(hConsoleIn)==FILE_TYPE_CHAR ){
    if( !IsValidCodePage(CP_UTF8) ){
      fprintf(stderr, "Cannot use UTF-8 code page.\n");
      console_utf8 = 0;
      return;
    }
    codePage = GetConsoleCP();
    SetConsoleCP(CP_UTF8);

    GetConsoleMode( hConsoleIn, &consoleMode);
    SetConsoleMode( hConsoleIn, consoleMode | ENABLE_LINE_INPUT );
    infsMode = _setmode(_fileno(stdin), _O_U16TEXT);
    console_utf8 = 1;
  }else{
    console_utf8 = 0;
  }
}

/*
** Undo the effects of instream_prepare(), if any.
*/
static void SQLITE_CDECL instream_restore(void){
  if( console_utf8 && codePage!=0 &&hConsoleIn != INVALID_HANDLE_VALUE ){
    _setmode(_fileno(stdin), infsMode);
    SetConsoleCP(codePage);
    SetConsoleMode( hConsoleIn, consoleMode );
    console_utf8 = 0; /* Avoid multiple calls. */
  }
}

/*
** 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
** startup option, -utf8, has not been provided or taken effect.
*/
static char* utf8_fgets(char *buf, int ncmax, FILE *fin){
  if( fin==0 ) fin = stdin;
  if( fin==stdin && stdin_is_interactive && console_utf8 ){
# define SQLITE_IALIM 150
    wchar_t wbuf[SQLITE_IALIM];
    int lend = 0;
    int noc = 0;
    if( ncmax == 0 || 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(hConsoleIn, 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 ){
              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)
885
886
887
888
889
890
891
892
893

894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
      n--;
      if( n>0 && zLine[n-1]=='\r' ) n--;
      zLine[n] = 0;
      break;
    }
  }
#if defined(_WIN32) || defined(WIN32)
  /* For interactive input on Windows systems, translate the
  ** multi-byte characterset characters into UTF-8. */

  if( stdin_is_interactive && in==stdin ){
    // FILE *cil = fopen("cin.log", "wa");
    // i64 nzl = strlen(zLine);
    char *zTrans = sqlite3_win32_mbcs_to_utf8_v2(zLine, 0);
    // fwrite(zLine, nzl, 1, cil);
    // fwrite("\n", 1,1, cil);
    if( zTrans ){
      i64 nTrans = strlen(zTrans)+1;
      if( nTrans>nLine ){
        zLine = realloc(zLine, nTrans);
        shell_check_oom(zLine);
      }
      memcpy(zLine, zTrans, nTrans);
      // fwrite(zLine, nTrans-1, 1, cil);
      // fwrite("\n", 1,1, cil);
      sqlite3_free(zTrans);
    }
    // fclose(cil);
  }
#endif /* defined(_WIN32) || defined(WIN32) */
  return zLine;
}

/*
** Retrieve a single line of input text.







|
|
>
|
<
<

<
<







<
<


<







914
915
916
917
918
919
920
921
922
923
924


925


926
927
928
929
930
931
932


933
934

935
936
937
938
939
940
941
      n--;
      if( n>0 && zLine[n-1]=='\r' ) n--;
      zLine[n] = 0;
      break;
    }
  }
#if defined(_WIN32) || defined(WIN32)
  /* For interactive input on Windows systems, without -utf8,
  ** translate the multi-byte characterset characters into UTF-8.
  ** This is the translation that predates the -utf8 option. */
  if( stdin_is_interactive && in==stdin && !console_utf8 ){


    char *zTrans = sqlite3_win32_mbcs_to_utf8_v2(zLine, 0);


    if( zTrans ){
      i64 nTrans = strlen(zTrans)+1;
      if( nTrans>nLine ){
        zLine = realloc(zLine, nTrans);
        shell_check_oom(zLine);
      }
      memcpy(zLine, zTrans, nTrans);


      sqlite3_free(zTrans);
    }

  }
#endif /* defined(_WIN32) || defined(WIN32) */
  return zLine;
}

/*
** Retrieve a single line of input text.
11815
11816
11817
11818
11819
11820
11821
11822
11823
11824
11825
11826
11827
11828
11829
  char **azCmd = 0;
  const char *zVfs = 0;           /* Value of -vfs command-line option */
#if !SQLITE_SHELL_IS_UTF8
  char **argvToFree = 0;
  int argcToFree = 0;
#endif

  setBinaryMode(stdin, 0);
  setvbuf(stderr, 0, _IONBF, 0); /* Make sure stderr is unbuffered */
#ifdef SQLITE_SHELL_FIDDLE
  stdin_is_interactive = 0;
  stdout_is_console = 1;
  data.wasm.zDefaultDbName = "/fiddle.sqlite3";
#else
  stdin_is_interactive = isatty(0);







<







11838
11839
11840
11841
11842
11843
11844

11845
11846
11847
11848
11849
11850
11851
  char **azCmd = 0;
  const char *zVfs = 0;           /* Value of -vfs command-line option */
#if !SQLITE_SHELL_IS_UTF8
  char **argvToFree = 0;
  int argcToFree = 0;
#endif


  setvbuf(stderr, 0, _IONBF, 0); /* Make sure stderr is unbuffered */
#ifdef SQLITE_SHELL_FIDDLE
  stdin_is_interactive = 0;
  stdout_is_console = 1;
  data.wasm.zDefaultDbName = "/fiddle.sqlite3";
#else
  stdin_is_interactive = isatty(0);
12302
12303
12304
12305
12306
12307
12308

12309
12310
12311
12312
12313
12314
12315
    }
    data.cMode = data.mode;
  }
#if (defined(_WIN32) || defined(WIN32)) && !defined(SQLITE_SHELL_FIDDLE)
  if( console_utf8 && stdin_is_interactive ){
    instream_prepare();
  }else{

    console_utf8 = 0;
  }
#endif

  if( !readStdin ){
    /* Run all arguments that do not begin with '-' as if they were separate
    ** command-line inputs, except for the argToSkip argument which contains







>







12324
12325
12326
12327
12328
12329
12330
12331
12332
12333
12334
12335
12336
12337
12338
    }
    data.cMode = data.mode;
  }
#if (defined(_WIN32) || defined(WIN32)) && !defined(SQLITE_SHELL_FIDDLE)
  if( console_utf8 && stdin_is_interactive ){
    instream_prepare();
  }else{
    setBinaryMode(stdin, 0);
    console_utf8 = 0;
  }
#endif

  if( !readStdin ){
    /* Run all arguments that do not begin with '-' as if they were separate
    ** command-line inputs, except for the argToSkip argument which contains