aboutsummaryrefslogtreecommitdiff
path: root/ext/misc/sqlite3_stdio.c
diff options
context:
space:
mode:
authordrh <>2024-10-11 14:02:48 +0000
committerdrh <>2024-10-11 14:02:48 +0000
commit0b453b3b3379f34527c957c6e1f7631a887c7340 (patch)
tree3011b4b38bb018f35f4e212c26c11ef9617d9ba9 /ext/misc/sqlite3_stdio.c
parent64366ae114c69c61de03f5ccbfa2ee5956795d0c (diff)
downloadsqlite-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.c84
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);
}
}