diff options
author | drh <> | 2024-10-11 14:02:48 +0000 |
---|---|---|
committer | drh <> | 2024-10-11 14:02:48 +0000 |
commit | 0b453b3b3379f34527c957c6e1f7631a887c7340 (patch) | |
tree | 3011b4b38bb018f35f4e212c26c11ef9617d9ba9 /ext/misc/sqlite3_stdio.c | |
parent | 64366ae114c69c61de03f5ccbfa2ee5956795d0c (diff) | |
download | sqlite-0b453b3b3379f34527c957c6e1f7631a887c7340.tar.gz sqlite-0b453b3b3379f34527c957c6e1f7631a887c7340.zip |
Avoid undesirable NL to CRLF translation when doing binary output to the
Windows console.
FossilOrigin-Name: d25bdce36abed95524ad058a277aba7bb17270e7ff1476474713dbc29742c762
Diffstat (limited to 'ext/misc/sqlite3_stdio.c')
-rw-r--r-- | ext/misc/sqlite3_stdio.c | 84 |
1 files changed, 77 insertions, 7 deletions
diff --git a/ext/misc/sqlite3_stdio.c b/ext/misc/sqlite3_stdio.c index 46f12dff3..393815522 100644 --- a/ext/misc/sqlite3_stdio.c +++ b/ext/misc/sqlite3_stdio.c @@ -68,6 +68,31 @@ #endif /* +** Global variables determine if simulated O_BINARY mode is to be +** used for stdout or other, respectively. Simulated O_BINARY mode +** means the mode is usually O_BINARY, but switches to O_U8TEXT for +** unicode characters U+0080 or greater (any character that has a +** multi-byte representation in UTF-8). This is the only way we +** have found to render Unicode characters on a Windows console while +** at the same time avoiding undesirable \n to \r\n translation. +*/ +static int simBinaryStdout = 0; +static int simBinaryOther = 0; + + +/* +** Determine if simulated binary mode should be used for output to fd +*/ +static int UseBinaryWText(FILE *fd){ + if( fd==stdout || fd==stderr ){ + return simBinaryStdout; + }else{ + return simBinaryOther; + } +} + + +/* ** Work-alike for the fopen() routine from the standard C library. */ FILE *sqlite3_fopen(const char *zFilename, const char *zMode){ @@ -88,6 +113,7 @@ FILE *sqlite3_fopen(const char *zFilename, const char *zMode){ } free(b1); free(b2); + simBinaryOther = 0; return fp; } @@ -144,12 +170,52 @@ char *sqlite3_fgets(char *buf, int sz, FILE *in){ } /* +** Send ASCII text as O_BINARY. But for Unicode characters U+0080 and +** greater, switch to O_U8TEXT. +*/ +static void piecemealOutput(wchar_t *b1, int sz, FILE *out){ + int i; + wchar_t c; + while( sz>0 ){ + for(i=0; i<sz && b1[i]>=0x80; i++){} + if( i>0 ){ + c = b1[i]; + b1[i] = 0; + fflush(out); + _setmode(_fileno(out), _O_U8TEXT); + fputws(b1, out); + fflush(out); + b1 += i; + b1[0] = c; + sz -= i; + }else{ + fflush(out); + _setmode(_fileno(out), _O_TEXT); + _setmode(_fileno(out), _O_BINARY); + fwrite(&b1[0], 1, 1, out); + for(i=1; i<sz && b1[i]<0x80; i++){ + fwrite(&b1[i], 1, 1, out); + } + fflush(out); + _setmode(_fileno(out), _O_U8TEXT); + b1 += i; + sz -= i; + } + } +} + +/* ** Work-alike for fputs() from the standard C library. */ int sqlite3_fputs(const char *z, FILE *out){ - if( UseWtextForOutput(out) ){ + if( !UseWtextForOutput(out) ){ + /* Writing to a file or other destination, just write bytes without + ** any translation. */ + return fputs(z, out); + }else{ /* When writing to the command-prompt in Windows, it is necessary - ** to use _O_WTEXT input mode and write UTF-16 characters. + ** to use O_U8TEXT to render Unicode U+0080 and greater. Go ahead + ** use O_U8TEXT for everything in text mode. */ int sz = (int)strlen(z); wchar_t *b1 = malloc( (sz+1)*sizeof(wchar_t) ); @@ -157,13 +223,13 @@ int sqlite3_fputs(const char *z, FILE *out){ sz = MultiByteToWideChar(CP_UTF8, 0, z, sz, b1, sz); b1[sz] = 0; _setmode(_fileno(out), _O_U8TEXT); - fputws(b1, out); + if( UseBinaryWText(out) ){ + piecemealOutput(b1, sz, out); + }else{ + fputws(b1, out); + } sqlite3_free(b1); return 0; - }else{ - /* Writing to a file or other destination, just write bytes without - ** any translation. */ - return fputs(z, out); } } @@ -205,6 +271,10 @@ void sqlite3_fsetmode(FILE *fp, int mode){ if( !UseWtextForOutput(fp) ){ fflush(fp); _setmode(_fileno(fp), mode); + }else if( fp==stdout || fp==stderr ){ + simBinaryStdout = (mode==_O_BINARY); + }else{ + simBinaryOther = (mode==_O_BINARY); } } |