> Seems I found 2 errors in .ar command of sqlite3 on Windows:
>

First, in shell.c the code that reads lines from console as input uses
> wrong codepage code CP_ACP or CP_OEMCP.
> This doesn't allow to pass proper filenames to your func runOneSqlLine() ,
> as my Windows 10 console uses codepage 1251.
> A made changes to shell.c:utf8_printf(), local_getline() and
> os_win.c:winMbcsToUnicode(), winUnicodeToMbcs().
>
> Second, on Windows we have wide chars filenames, and your code uses utf8
> for filenames.
>


This doesn't allow the .ar commands to work with non ASCII filenames
> (charcodes > 80).
>


I made changes to fileio.c:writeFile(), struct FsdirLevel, fsdirNext().
>
> Both errors make impossible to use archive command with files with
> nonASCII names.
> My fixes have comment //za++, you may search for it. I attached the patch.
>
>
> I compile with mingw gcc for Windows 10.
> Bellow is my gcc version.
>
> At the end of the this email there is a patch against your trunk branch
> .\sqlite3.exe --version 3.29.0 2019-05-03 02:41:36
> 9b5d943426c9273162ecb4c561eb3b25e843318dd438239c882c9db50f78alt2
>
> I use this compile command from powershell:
> (please pay attention that SQLITE_WIN32_HAS_WIDE must be defined
> explicitly because here we have shell.c and sqlite3.c compilation units.
> Shell.c doesn't define SQLITE_WIN32_HAS_WIDE by itself.)
>
>  gcc -municode -mwin32 -g3 -Og -DSQLITE_WIN32_HAS_WIDE
> -DSQLITE_OS_WINNT=1  -DSQLITE_DEBUG -DSQLITE_SHELL_IS
> _UTF8=0 -I. -I/f/Zavla_VB/sqlite_fossil/sqlite/src
> -I/f/Zavla_VB/sqlite_fossil/sqlite/ext/rtree -I/f/Zavla_VB/sqlite_fos
> sil/sqlite/ext/icu -I/f/Zavla_VB/sqlite_fossil/sqlite/ext/fts3
> -I/f/Zavla_VB/sqlite_fossil/sqlite/ext/async -I/f/Zavla_V
> B/sqlite_fossil/sqlite/ext/session
> -I/f/Zavla_VB/sqlite_fossil/sqlite/ext/userauth -D_HAVE_SQLITE_CONFIG_H
> -DBUILD_sqlit
> e -DNDEBUG '-I/mingw64/include/tcl8.6' -DSQLITE_THREADSAFE=1
> -DSQLITE_HAVE_ZLIB=1 -DHAVE_READLINE=0 -DHAVE_EDITLINE=0 -D
> SQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_RTREE
> -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_UNKNOWN_
> SQL_FUNCTION -DSQLITE_ENABLE_STMTVTAB -DSQLITE_ENABLE_DBPAGE_VTAB
> -DSQLITE_ENABLE_DBSTAT_VTAB -DSQLITE_ENABLE_OFFSET_SQL
> _FUNC -DSQLITE_ENABLE_DESERIALIZE -DSQLITE_INTROSPECTION_PRAGMAS
> -ID:\msys32\mingw32\include\ -o .libs/sqlite3.exe shel
> l.c sqlite3.c  -lz -L/mingw64/lib -LD:\msys32\mingw64\lib
>
>
> My versions:
>
> PS F:\Zavla_VB\sqlite_fossil\sqlite> cd .\.libs\
> PS F:\Zavla_VB\sqlite_fossil\sqlite\.libs> .\sqlite3.exe --version
> 3.29.0 2019-05-03 02:41:36
> 9b5d943426c9273162ecb4c561eb3b25e843318dd438239c882c9db50f78alt2
>
> PS F:\Zavla_VB\sqlite_fossil\sqlite\.libs> cd ..
> PS F:\Zavla_VB\sqlite_fossil\sqlite> fossil.exe status
> repository:   F:/Zavla_VB/sqlite_fossil/sqlite/..\sqlite.fossil
> local-root:   F:/Zavla_VB/sqlite_fossil/sqlite/
> config-db:    C:/Users/z.malinovskiy/AppData/Local/_fossil
> checkout:     9b5d943426c9273162ecb4c561eb3b25e843318d 2019-05-03 02:41:36
> UTC
> parent:       48889530a9de22fee536edfd1627be62396ed18d 2019-05-02 17:45:52
> UTC
> tags:         trunk
> comment:      Fix the ".open --hexdb" command in the CLI so that it works
> even with terminal input. (user: drh)
>
> PS F:\Zavla_VB\sqlite_fossil\sqlite> gcc --version
> gcc.exe (GCC) 8.2.0
> Copyright (C) 2018 Free Software Foundation, Inc.
>
> Next is a patch with my fixes:
> ============ HERE GOES THE PATCH ================
>
>
> Index: ext/misc/fileio.c
> ==================================================================
> --- ext/misc/fileio.c
> +++ ext/misc/fileio.c
> @@ -98,11 +98,48 @@
>  #  endif
>  #  ifndef stat
>  #    define stat _stat
>  #  endif
>  #  define mkdir(path,mode) _mkdir(path)
> -#  define lstat(path,buf) stat(path,buf)
> +//za++ wide Windows expects wchar_t filenames
> +#ifdef SQLITE_WIN32_HAS_WIDE
> +  #define closedir(X) _wclosedir((X))
> +  #define opendir(X) opendir_onWideWindows((X))
> +  _WDIR* opendir_onWideWindows(const char* utfFilename){
> +      LPWSTR tempws = sqlite3_win32_utf8_to_unicode(utfFilename);
> +      _WDIR* res = _wopendir(tempws);
> +      sqlite3_free(tempws);
> +      return res;
> +  }
> +
> +  #define fopen(X,Y) fopen_onWideWindows((X),(Y))
> +  FILE* fopen_onWideWindows(const char* utfFilename, const char* mode) {
> +
> +      LPWSTR tempws = sqlite3_win32_utf8_to_unicode(utfFilename);
> +      if (tempws == 0) return 0;
> +      wchar_t wmode[] = L"\0\0\0\0\0\0";
> +      int len = strlen(mode);
> +      int i;
> +      for (i = 0; i<len; i++) {
> +        wmode[i] = (wchar_t)mode[i];
> +      }
> +      FILE* res = _wfopen(tempws,wmode);
> +      sqlite3_free(tempws);
> +      return res;
> +  }
> +  #define lstat(X,Y) lstat_onWideWindows((X),(Y))
> +  int lstat_onWideWindows(const char* utfFilename, struct stat* pStatBuf){
> +    LPWSTR tempws = sqlite3_win32_utf8_to_unicode(utfFilename);
> +    if (tempws == 0) return 0;
> +    int res = _wstat64(tempws, pStatBuf);
> +    sqlite3_free(tempws);
> +    return res;
> +  }
> +#else
> +#  define lstat(path,buf) stat(path,buf)
> +#endif //SQLITE_WIN32_HAS_WIDE
> +
>  #endif
>  #include <time.h>
>  #include <errno.h>
>
>
> @@ -261,11 +298,12 @@
>  static int fileStat(
>    const char *zPath,
>    struct stat *pStatBuf
>  ){
>  #if defined(_WIN32)
> -  int rc = stat(zPath, pStatBuf);
> +  //za++
> +  int rc = lstat(zPath, pStatBuf);
>    if( rc==0 ) statTimesToUtc(zPath, pStatBuf);
>    return rc;
>  #else
>    return stat(zPath, pStatBuf);
>  #endif
> @@ -352,10 +390,19 @@
>      const char *zTo = (const char*)sqlite3_value_text(pData);
>      if( symlink(zTo, zFile)<0 ) return 1;
>    }else
>  #endif
>    {
> +    //za++ Windows expects wchar_t filenames
> +#ifdef SQLITE_WIN32_HAS_WIDE
> +    extern LPWSTR sqlite3_win32_utf8_to_unicode(const char*);
> +    LPWSTR tempws = sqlite3_win32_utf8_to_unicode(zFile);
> +    #pragma push_macro("mkdir")
> +    #pragma push_macro("chmode")
> +    #define mkdir(X,Y) _wmkdir((tempws))
> +    #define chmod(X,Y) _wchmod((tempws),(Y))
> +#endif
>      if( S_ISDIR(mode) ){
>        if( mkdir(zFile, mode) ){
>          /* The mkdir() call to create the directory failed. This might not
>          ** be an error though - if there is already a directory at the
> same
>          ** path and either the permissions already match or can be changed
> @@ -364,19 +411,31 @@
>          if( errno!=EEXIST
>           || 0!=fileStat(zFile, &sStat)
>           || !S_ISDIR(sStat.st_mode)
>           || ((sStat.st_mode&0777)!=(mode&0777) && 0!=chmod(zFile,
> mode&0777))
>          ){
> +          //za++ Windows expects wchar_t filenames
> +          #ifdef SQLITE_WIN32_HAS_WIDE
> +              sqlite3_free(tempws);
> +          #else
> +          #endif
>            return 1;
>          }
>        }
>      }else{
>        sqlite3_int64 nWrite = 0;
>        const char *z;
>        int rc = 0;
>        FILE *out = fopen(zFile, "wb");
> -      if( out==0 ) return 1;
> +      if( out==0 ) {
> +        //za++ Windows expects wchar_t filenames
> +        #ifdef SQLITE_WIN32_HAS_WIDE
> +            sqlite3_free(tempws);
> +        #else
> +        #endif
> +        return 1;
> +      }
>        z = (const char*)sqlite3_value_blob(pData);
>        if( z ){
>          sqlite3_int64 n = fwrite(z, 1, sqlite3_value_bytes(pData), out);
>          nWrite = sqlite3_value_bytes(pData);
>          if( nWrite!=n ){
> @@ -385,13 +444,30 @@
>        }
>        fclose(out);
>        if( rc==0 && mode && chmod(zFile, mode & 0777) ){
>          rc = 1;
>        }
> -      if( rc ) return 2;
> +      if( rc ) {
> +        //za++ Windows expects wchar_t filenames
> +        #ifdef SQLITE_WIN32_HAS_WIDE
> +            sqlite3_free(tempws);
> +        #else
> +        #endif
> +        return 2;
> +      }
>        sqlite3_result_int64(pCtx, nWrite);
>      }
> +    //za++ Windows expects wchar_t filenames
> +    #ifdef SQLITE_WIN32_HAS_WIDE
> +        sqlite3_free(tempws);
> +        //#undef fopen
> +        #undef mkdir
> +        #undef chmode
> +        //#pragma pop_macro("fopen")
> +        #pragma pop_macro("mkdir")
> +        #pragma pop_macro("chmode")
> +    #endif
>    }
>
>    if( mtime>=0 ){
>  #if defined(_WIN32)
>      /* Windows */
> @@ -538,11 +614,16 @@
>  */
>  typedef struct fsdir_cursor fsdir_cursor;
>  typedef struct FsdirLevel FsdirLevel;
>
>  struct FsdirLevel {
> +  //za++
> +  #ifdef SQLITE_WIN32_HAS_WIDE
> +    _WDIR *pDir;                 /* From opendir() */
> +  #else
>    DIR *pDir;                 /* From opendir() */
> +  #endif
>    char *zDir;                /* Name of directory (nul-terminated) */
>  };
>
>  struct fsdir_cursor {
>    sqlite3_vtab_cursor base;  /* Base class - must be first */
> @@ -683,25 +764,37 @@
>
>      pLvl->zDir = pCur->zPath;
>      pCur->zPath = 0;
>      pLvl->pDir = opendir(pLvl->zDir);
>      if( pLvl->pDir==0 ){
> -      fsdirSetErrmsg(pCur, "cannot read directory: %s", pCur->zPath);
> +      fsdirSetErrmsg(pCur, "cannot read directory: %s", pCur->zPath);
> //za++ may be pLvl->zDir
>        return SQLITE_ERROR;
>      }
>    }
>
>    while( pCur->iLvl>=0 ){
>      FsdirLevel *pLvl = &pCur->aLvl[pCur->iLvl];
> +    //za++
> +    #ifdef SQLITE_WIN32_HAS_WIDE
> +      struct _wdirent *pEntry = _wreaddir(pLvl->pDir);
> +    #else
>      struct dirent *pEntry = readdir(pLvl->pDir);
> +    #endif
>      if( pEntry ){
>        if( pEntry->d_name[0]=='.' ){
>         if( pEntry->d_name[1]=='.' && pEntry->d_name[2]=='\0' ) continue;
>         if( pEntry->d_name[1]=='\0' ) continue;
>        }
>        sqlite3_free(pCur->zPath);
> +      //za++
> +      #ifdef SQLITE_WIN32_HAS_WIDE
> +        char* temputf = sqlite3_win32_unicode_to_utf8(pEntry->d_name);
> +        pCur->zPath = sqlite3_mprintf("%s/%s", pLvl->zDir, temputf);
> +        sqlite3_free(temputf);
> +      #else
>        pCur->zPath = sqlite3_mprintf("%s/%s", pLvl->zDir, pEntry->d_name);
> +      #endif
>        if( pCur->zPath==0 ) return SQLITE_NOMEM;
>        if( fileLinkStat(pCur->zPath, &pCur->sStat) ){
>          fsdirSetErrmsg(pCur, "cannot stat file: %s", pCur->zPath);
>          return SQLITE_ERROR;
>        }
>
> Index: shell.c
> ==================================================================
> --- shell.c
> +++ shell.c
> @@ -2335,10 +2335,11 @@
>  static int fileStat(
>    const char *zPath,
>    struct stat *pStatBuf
>  ){
>  #if defined(_WIN32)
> +  //za++
>    int rc = lstat(zPath, pStatBuf);
>    if( rc==0 ) statTimesToUtc(zPath, pStatBuf);
>    return rc;
>  #else
>    return stat(zPath, pStatBuf);
> @@ -2816,14 +2817,12 @@
>    while( pCur->iLvl>=0 ){
>      FsdirLevel *pLvl = &pCur->aLvl[pCur->iLvl];
>      //za++
>      #ifdef SQLITE_WIN32_HAS_WIDE
>        struct _wdirent *pEntry = _wreaddir(pLvl->pDir);
> -      #define MAYBEWIDE L
>      #else
>        struct dirent *pEntry = readdir(pLvl->pDir);
> -      #define MAYBEWIDE
>      #endif
>      if( pEntry ){
>        if( pEntry->d_name[0]=='.' ){
>         if( pEntry->d_name[1]=='.' && pEntry->d_name[2]=='\0' ) continue;
>         if( pEntry->d_name[1]=='\0' ) continue;
>
> Index: src/os_win.c
> ==================================================================
> --- src/os_win.c
> +++ src/os_win.c
> @@ -1728,17 +1728,22 @@
>  */
>  static LPWSTR winMbcsToUnicode(const char *zText, int useAnsi){
>    int nByte;
>    LPWSTR zMbcsText;
>    int codepage = useAnsi ? CP_ACP : CP_OEMCP;
> +  //za++ wrongly determined current console codepage under win10 for
> example, my current codepage is 1251
> +  if (useAnsi > 3) { //default values CP_ACP=0, CP_OEMCP=3
> +    codepage = useAnsi; //we've passed a codepage
> +  }
> +  //za--
>
>    nByte = osMultiByteToWideChar(codepage, 0, zText, -1, NULL,
>                                  0)*sizeof(WCHAR);
>    if( nByte==0 ){
>      return 0;
>    }
> -  zMbcsText = sqlite3MallocZero( nByte*sizeof(WCHAR) );
> +  zMbcsText = sqlite3MallocZero( nByte*sizeof(WCHAR) ); //za *sizeof
> wchar seems redundant
>    if( zMbcsText==0 ){
>      return 0;
>    }
>    nByte = osMultiByteToWideChar(codepage, 0, zText, -1, zMbcsText,
>                                  nByte);
> @@ -1757,10 +1762,15 @@
>  */
>  static char *winUnicodeToMbcs(LPCWSTR zWideText, int useAnsi){
>    int nByte;
>    char *zText;
>    int codepage = useAnsi ? CP_ACP : CP_OEMCP;
> +  //za++ wrongly determined current console codepage under win10 for
> example, my current codepage is 1251
> +  if (useAnsi > 3) { //default values CP_ACP=0, CP_OEMCP=3
> +    codepage = useAnsi; //we've passed a codepage
> +  }
> +  //za--
>
>    nByte = osWideCharToMultiByte(codepage, 0, zWideText, -1, 0, 0, 0, 0);
>    if( nByte == 0 ){
>      return 0;
>    }
>
> Index: src/shell.c.in
> ==================================================================
> --- src/shell.c.in
> +++ src/shell.c.in
> @@ -418,12 +418,16 @@
>  #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) ){
> +    //za++
> +    int consoleHasCodePage = GetConsoleCP();
> +    //za--
> +
>      char *z1 = sqlite3_vmprintf(zFormat, ap);
> -    char *z2 = sqlite3_win32_utf8_to_mbcs_v2(z1, 0);
> +    char *z2 = sqlite3_win32_utf8_to_mbcs_v2(z1, consoleHasCodePage);
>      sqlite3_free(z1);
>      fputs(z2, out);
>      sqlite3_free(z2);
>    }else{
>      vfprintf(out, zFormat, ap);
> @@ -591,11 +595,14 @@
>    }
>  #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 ){
> -    char *zTrans = sqlite3_win32_mbcs_to_utf8_v2(zLine, 0);
> +    //za++
> +    int consoleHasCodePage = GetConsoleCP();
> +    //za--
> +    char *zTrans = sqlite3_win32_mbcs_to_utf8_v2(zLine,
> consoleHasCodePage);
>      if( zTrans ){
>        int nTrans = strlen30(zTrans)+1;
>        if( nTrans>nLine ){
>          zLine = realloc(zLine, nTrans);
>          if( zLine==0 ) shell_out_of_memory();
>
>
>
> =================================================================
> С Уважением,
> Захар Владимирович Малиновский,
> программист 1с, компания UBC.
>
>
>
>
_______________________________________________
sqlite-users mailing list
sqlite-users@mailinglists.sqlite.org
http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users

Reply via email to