From 0b453b3b3379f34527c957c6e1f7631a887c7340 Mon Sep 17 00:00:00 2001 From: drh <> Date: Fri, 11 Oct 2024 14:02:48 +0000 Subject: [PATCH] Avoid undesirable NL to CRLF translation when doing binary output to the Windows console. FossilOrigin-Name: d25bdce36abed95524ad058a277aba7bb17270e7ff1476474713dbc29742c762 --- ext/misc/sqlite3_stdio.c | 84 ++++++++++++++++++++++++++++++++++++---- manifest | 15 ++++--- manifest.uuid | 2 +- src/shell.c.in | 17 ++++---- 4 files changed, 92 insertions(+), 26 deletions(-) diff --git a/ext/misc/sqlite3_stdio.c b/ext/misc/sqlite3_stdio.c index 46f12dff36..393815522b 100644 --- a/ext/misc/sqlite3_stdio.c +++ b/ext/misc/sqlite3_stdio.c @@ -67,6 +67,31 @@ # define IsConsole(fd) 1 #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. */ @@ -88,6 +113,7 @@ FILE *sqlite3_fopen(const char *zFilename, const char *zMode){ } free(b1); free(b2); + simBinaryOther = 0; return fp; } @@ -143,13 +169,53 @@ 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=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; ipLog); if( cli_strcmp(zFile,"on")==0 ) zFile = "stdout"; - p->pLog = output_file_open(zFile, 0); + p->pLog = output_file_open(zFile); } }else @@ -9918,7 +9918,6 @@ static int do_meta_command(char *zLine, ShellState *p){ || (c=='w' && n==3 && cli_strcmp(azArg[0],"www")==0) ){ char *zFile = 0; - int bTxtMode = 0; int i; int eMode = 0; int bOnce = 0; /* 0: .output, 1: .once, 2: .excel/.www */ @@ -10000,11 +9999,9 @@ static int do_meta_command(char *zLine, ShellState *p){ /* web-browser mode. */ newTempFile(p, "html"); if( !bPlain ) p->mode = MODE_Www; - bTxtMode = 1; }else{ /* text editor mode */ newTempFile(p, "txt"); - bTxtMode = 1; } sqlite3_free(zFile); zFile = sqlite3_mprintf("%s", p->zTempFile); @@ -10028,7 +10025,7 @@ static int do_meta_command(char *zLine, ShellState *p){ } #endif }else{ - FILE *pfFile = output_file_open(zFile, bTxtMode); + FILE *pfFile = output_file_open(zFile); if( pfFile==0 ){ if( cli_strcmp(zFile,"off")!=0 ){ sqlite3_fprintf(stderr,"Error: cannot write to \"%s\"\n", zFile); @@ -10036,13 +10033,13 @@ static int do_meta_command(char *zLine, ShellState *p){ rc = 1; } else { output_redir(p, pfFile); + if( zBom ) sqlite3_fputs(zBom, pfFile); if( bPlain && eMode=='w' ){ sqlite3_fputs( "\n\n\n", pfFile ); } - if( zBom ) sqlite3_fputs(zBom, pfFile); sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", zFile); } } @@ -11225,7 +11222,7 @@ static int do_meta_command(char *zLine, ShellState *p){ /* Begin redirecting output to the file "testcase-out.txt" */ if( c=='t' && cli_strcmp(azArg[0],"testcase")==0 ){ output_reset(p); - p->out = output_file_open("testcase-out.txt", 0); + p->out = output_file_open("testcase-out.txt"); if( p->out==0 ){ eputz("Error: cannot open 'testcase-out.txt'\n"); } @@ -11729,7 +11726,7 @@ static int do_meta_command(char *zLine, ShellState *p){ } }else{ output_file_close(p->traceOut); - p->traceOut = output_file_open(z, 0); + p->traceOut = output_file_open(z); } } if( p->traceOut==0 ){