Snapshot of upstream SQLite 3.46.1
[sqlcipher.git] / ext / consio / console_io.c
blob3fa613ba9df96cb0b2b3b5b39c8da6273194c765
1 /*
2 ** 2023 November 4
3 **
4 ** The author disclaims copyright to this source code. In place of
5 ** a legal notice, here is a blessing:
6 **
7 ** May you do good and not evil.
8 ** May you find forgiveness for yourself and forgive others.
9 ** May you share freely, never taking more than you give.
11 ********************************************************************************
12 ** This file implements various interfaces used for console and stream I/O
13 ** by the SQLite project command-line tools, as explained in console_io.h .
14 ** Functions prefixed by "SQLITE_INTERNAL_LINKAGE" behave as described there.
17 #ifndef SQLITE_CDECL
18 # define SQLITE_CDECL
19 #endif
21 #ifndef SHELL_NO_SYSINC
22 # include <stdarg.h>
23 # include <string.h>
24 # include <stdlib.h>
25 # include <limits.h>
26 # include <assert.h>
27 # include "sqlite3.h"
28 #endif
29 #ifndef HAVE_CONSOLE_IO_H
30 # include "console_io.h"
31 #endif
32 #if defined(_MSC_VER)
33 # pragma warning(disable : 4204)
34 #endif
36 #ifndef SQLITE_CIO_NO_TRANSLATE
37 # if (defined(_WIN32) || defined(WIN32)) && !SQLITE_OS_WINRT
38 # ifndef SHELL_NO_SYSINC
39 # include <io.h>
40 # include <fcntl.h>
41 # undef WIN32_LEAN_AND_MEAN
42 # define WIN32_LEAN_AND_MEAN
43 # include <windows.h>
44 # endif
45 # define CIO_WIN_WC_XLATE 1 /* Use WCHAR Windows APIs for console I/O */
46 # else
47 # ifndef SHELL_NO_SYSINC
48 # include <unistd.h>
49 # endif
50 # define CIO_WIN_WC_XLATE 0 /* Use plain C library stream I/O at console */
51 # endif
52 #else
53 # define CIO_WIN_WC_XLATE 0 /* Not exposing translation routines at all */
54 #endif
56 #if CIO_WIN_WC_XLATE
57 static HANDLE handleOfFile(FILE *pf){
58 int fileDesc = _fileno(pf);
59 union { intptr_t osfh; HANDLE fh; } fid = {
60 (fileDesc>=0)? _get_osfhandle(fileDesc) : (intptr_t)INVALID_HANDLE_VALUE
62 return fid.fh;
64 #endif
66 #ifndef SQLITE_CIO_NO_TRANSLATE
67 typedef struct PerStreamTags {
68 # if CIO_WIN_WC_XLATE
69 HANDLE hx;
70 DWORD consMode;
71 char acIncomplete[4];
72 # else
73 short reachesConsole;
74 # endif
75 FILE *pf;
76 } PerStreamTags;
78 /* Define NULL-like value for things which can validly be 0. */
79 # define SHELL_INVALID_FILE_PTR ((FILE *)~0)
80 # if CIO_WIN_WC_XLATE
81 # define SHELL_INVALID_CONS_MODE 0xFFFF0000
82 # endif
84 # if CIO_WIN_WC_XLATE
85 # define PST_INITIALIZER { INVALID_HANDLE_VALUE, SHELL_INVALID_CONS_MODE, \
86 {0,0,0,0}, SHELL_INVALID_FILE_PTR }
87 # else
88 # define PST_INITIALIZER { 0, SHELL_INVALID_FILE_PTR }
89 # endif
91 /* Quickly say whether a known output is going to the console. */
92 # if CIO_WIN_WC_XLATE
93 static short pstReachesConsole(PerStreamTags *ppst){
94 return (ppst->hx != INVALID_HANDLE_VALUE);
96 # else
97 # define pstReachesConsole(ppst) 0
98 # endif
100 # if CIO_WIN_WC_XLATE
101 static void restoreConsoleArb(PerStreamTags *ppst){
102 if( pstReachesConsole(ppst) ) SetConsoleMode(ppst->hx, ppst->consMode);
104 # else
105 # define restoreConsoleArb(ppst)
106 # endif
108 /* Say whether FILE* appears to be a console, collect associated info. */
109 static short streamOfConsole(FILE *pf, /* out */ PerStreamTags *ppst){
110 # if CIO_WIN_WC_XLATE
111 short rv = 0;
112 DWORD dwCM = SHELL_INVALID_CONS_MODE;
113 HANDLE fh = handleOfFile(pf);
114 ppst->pf = pf;
115 if( INVALID_HANDLE_VALUE != fh ){
116 rv = (GetFileType(fh) == FILE_TYPE_CHAR && GetConsoleMode(fh,&dwCM));
118 ppst->hx = (rv)? fh : INVALID_HANDLE_VALUE;
119 ppst->consMode = dwCM;
120 return rv;
121 # else
122 ppst->pf = pf;
123 ppst->reachesConsole = ( (short)isatty(fileno(pf)) );
124 return ppst->reachesConsole;
125 # endif
128 # ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
129 # define ENABLE_VIRTUAL_TERMINAL_PROCESSING (0x4)
130 # endif
132 # if CIO_WIN_WC_XLATE
133 /* Define console modes for use with the Windows Console API. */
134 # define SHELL_CONI_MODE \
135 (ENABLE_ECHO_INPUT | ENABLE_INSERT_MODE | ENABLE_LINE_INPUT | 0x80 \
136 | ENABLE_QUICK_EDIT_MODE | ENABLE_EXTENDED_FLAGS | ENABLE_PROCESSED_INPUT)
137 # define SHELL_CONO_MODE (ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT \
138 | ENABLE_VIRTUAL_TERMINAL_PROCESSING)
139 # endif
141 typedef struct ConsoleInfo {
142 PerStreamTags pstSetup[3];
143 PerStreamTags pstDesignated[3];
144 StreamsAreConsole sacSetup;
145 } ConsoleInfo;
147 static short isValidStreamInfo(PerStreamTags *ppst){
148 return (ppst->pf != SHELL_INVALID_FILE_PTR);
151 static ConsoleInfo consoleInfo = {
152 { /* pstSetup */ PST_INITIALIZER, PST_INITIALIZER, PST_INITIALIZER },
153 { /* pstDesignated[] */ PST_INITIALIZER, PST_INITIALIZER, PST_INITIALIZER },
154 SAC_NoConsole /* sacSetup */
157 SQLITE_INTERNAL_LINKAGE FILE* invalidFileStream = (FILE *)~0;
159 # if CIO_WIN_WC_XLATE
160 static void maybeSetupAsConsole(PerStreamTags *ppst, short odir){
161 if( pstReachesConsole(ppst) ){
162 DWORD cm = odir? SHELL_CONO_MODE : SHELL_CONI_MODE;
163 SetConsoleMode(ppst->hx, cm);
166 # else
167 # define maybeSetupAsConsole(ppst,odir)
168 # endif
170 SQLITE_INTERNAL_LINKAGE void consoleRenewSetup(void){
171 # if CIO_WIN_WC_XLATE
172 int ix = 0;
173 while( ix < 6 ){
174 PerStreamTags *ppst = (ix<3)?
175 &consoleInfo.pstSetup[ix] : &consoleInfo.pstDesignated[ix-3];
176 maybeSetupAsConsole(ppst, (ix % 3)>0);
177 ++ix;
179 # endif
182 SQLITE_INTERNAL_LINKAGE StreamsAreConsole
183 consoleClassifySetup( FILE *pfIn, FILE *pfOut, FILE *pfErr ){
184 StreamsAreConsole rv = SAC_NoConsole;
185 FILE* apf[3] = { pfIn, pfOut, pfErr };
186 int ix;
187 for( ix = 2; ix >= 0; --ix ){
188 PerStreamTags *ppst = &consoleInfo.pstSetup[ix];
189 if( streamOfConsole(apf[ix], ppst) ){
190 rv |= (SAC_InConsole<<ix);
192 consoleInfo.pstDesignated[ix] = *ppst;
193 if( ix > 0 ) fflush(apf[ix]);
195 consoleInfo.sacSetup = rv;
196 consoleRenewSetup();
197 return rv;
200 SQLITE_INTERNAL_LINKAGE void SQLITE_CDECL consoleRestore( void ){
201 # if CIO_WIN_WC_XLATE
202 static ConsoleInfo *pci = &consoleInfo;
203 if( pci->sacSetup ){
204 int ix;
205 for( ix=0; ix<3; ++ix ){
206 if( pci->sacSetup & (SAC_InConsole<<ix) ){
207 PerStreamTags *ppst = &pci->pstSetup[ix];
208 SetConsoleMode(ppst->hx, ppst->consMode);
212 # endif
214 #endif /* !defined(SQLITE_CIO_NO_TRANSLATE) */
216 #ifdef SQLITE_CIO_INPUT_REDIR
217 /* Say whether given FILE* is among those known, via either
218 ** consoleClassifySetup() or set{Output,Error}Stream, as
219 ** readable, and return an associated PerStreamTags pointer
220 ** if so. Otherwise, return 0.
222 static PerStreamTags * isKnownReadable(FILE *pf){
223 static PerStreamTags *apst[] = {
224 &consoleInfo.pstDesignated[0], &consoleInfo.pstSetup[0], 0
226 int ix = 0;
227 do {
228 if( apst[ix]->pf == pf ) break;
229 } while( apst[++ix] != 0 );
230 return apst[ix];
232 #endif
234 #ifndef SQLITE_CIO_NO_TRANSLATE
235 /* Say whether given FILE* is among those known, via either
236 ** consoleClassifySetup() or set{Output,Error}Stream, as
237 ** writable, and return an associated PerStreamTags pointer
238 ** if so. Otherwise, return 0.
240 static PerStreamTags * isKnownWritable(FILE *pf){
241 static PerStreamTags *apst[] = {
242 &consoleInfo.pstDesignated[1], &consoleInfo.pstDesignated[2],
243 &consoleInfo.pstSetup[1], &consoleInfo.pstSetup[2], 0
245 int ix = 0;
246 do {
247 if( apst[ix]->pf == pf ) break;
248 } while( apst[++ix] != 0 );
249 return apst[ix];
252 static FILE *designateEmitStream(FILE *pf, unsigned chix){
253 FILE *rv = consoleInfo.pstDesignated[chix].pf;
254 if( pf == invalidFileStream ) return rv;
255 else{
256 /* Setting a possibly new output stream. */
257 PerStreamTags *ppst = isKnownWritable(pf);
258 if( ppst != 0 ){
259 PerStreamTags pst = *ppst;
260 consoleInfo.pstDesignated[chix] = pst;
261 }else streamOfConsole(pf, &consoleInfo.pstDesignated[chix]);
263 return rv;
266 SQLITE_INTERNAL_LINKAGE FILE *setOutputStream(FILE *pf){
267 return designateEmitStream(pf, 1);
269 # ifdef CONSIO_SET_ERROR_STREAM
270 SQLITE_INTERNAL_LINKAGE FILE *setErrorStream(FILE *pf){
271 return designateEmitStream(pf, 2);
273 # endif
274 #endif /* !defined(SQLITE_CIO_NO_TRANSLATE) */
276 #ifndef SQLITE_CIO_NO_SETMODE
277 # if CIO_WIN_WC_XLATE
278 static void setModeFlushQ(FILE *pf, short bFlush, int mode){
279 if( bFlush ) fflush(pf);
280 _setmode(_fileno(pf), mode);
282 # else
283 # define setModeFlushQ(f, b, m) if(b) fflush(f)
284 # endif
286 SQLITE_INTERNAL_LINKAGE void setBinaryMode(FILE *pf, short bFlush){
287 setModeFlushQ(pf, bFlush, _O_BINARY);
289 SQLITE_INTERNAL_LINKAGE void setTextMode(FILE *pf, short bFlush){
290 setModeFlushQ(pf, bFlush, _O_TEXT);
292 # undef setModeFlushQ
294 #else /* defined(SQLITE_CIO_NO_SETMODE) */
295 # define setBinaryMode(f, bFlush) do{ if((bFlush)) fflush(f); }while(0)
296 # define setTextMode(f, bFlush) do{ if((bFlush)) fflush(f); }while(0)
297 #endif /* defined(SQLITE_CIO_NO_SETMODE) */
299 #ifndef SQLITE_CIO_NO_TRANSLATE
300 # if CIO_WIN_WC_XLATE
301 /* Write buffer cBuf as output to stream known to reach console,
302 ** limited to ncTake char's. Return ncTake on success, else 0. */
303 static int conZstrEmit(PerStreamTags *ppst, const char *z, int ncTake){
304 int rv = 0;
305 if( z!=NULL ){
306 int nwc = MultiByteToWideChar(CP_UTF8,0, z,ncTake, 0,0);
307 if( nwc > 0 ){
308 WCHAR *zw = sqlite3_malloc64(nwc*sizeof(WCHAR));
309 if( zw!=NULL ){
310 nwc = MultiByteToWideChar(CP_UTF8,0, z,ncTake, zw,nwc);
311 if( nwc > 0 ){
312 /* Translation from UTF-8 to UTF-16, then WCHARs out. */
313 if( WriteConsoleW(ppst->hx, zw,nwc, 0, NULL) ){
314 rv = ncTake;
317 sqlite3_free(zw);
321 return rv;
324 /* For {f,o,e}PrintfUtf8() when stream is known to reach console. */
325 static int conioVmPrintf(PerStreamTags *ppst, const char *zFormat, va_list ap){
326 char *z = sqlite3_vmprintf(zFormat, ap);
327 if( z ){
328 int rv = conZstrEmit(ppst, z, (int)strlen(z));
329 sqlite3_free(z);
330 return rv;
331 }else return 0;
333 # endif /* CIO_WIN_WC_XLATE */
335 # ifdef CONSIO_GET_EMIT_STREAM
336 static PerStreamTags * getDesignatedEmitStream(FILE *pf, unsigned chix,
337 PerStreamTags *ppst){
338 PerStreamTags *rv = isKnownWritable(pf);
339 short isValid = (rv!=0)? isValidStreamInfo(rv) : 0;
340 if( rv != 0 && isValid ) return rv;
341 streamOfConsole(pf, ppst);
342 return ppst;
344 # endif
346 /* Get stream info, either for designated output or error stream when
347 ** chix equals 1 or 2, or for an arbitrary stream when chix == 0.
348 ** In either case, ppst references a caller-owned PerStreamTags
349 ** struct which may be filled in if none of the known writable
350 ** streams is being held by consoleInfo. The ppf parameter is a
351 ** byref output when chix!=0 and a byref input when chix==0.
353 static PerStreamTags *
354 getEmitStreamInfo(unsigned chix, PerStreamTags *ppst,
355 /* in/out */ FILE **ppf){
356 PerStreamTags *ppstTry;
357 FILE *pfEmit;
358 if( chix > 0 ){
359 ppstTry = &consoleInfo.pstDesignated[chix];
360 if( !isValidStreamInfo(ppstTry) ){
361 ppstTry = &consoleInfo.pstSetup[chix];
362 pfEmit = ppst->pf;
363 }else pfEmit = ppstTry->pf;
364 if( !isValidStreamInfo(ppstTry) ){
365 pfEmit = (chix > 1)? stderr : stdout;
366 ppstTry = ppst;
367 streamOfConsole(pfEmit, ppstTry);
369 *ppf = pfEmit;
370 }else{
371 ppstTry = isKnownWritable(*ppf);
372 if( ppstTry != 0 ) return ppstTry;
373 streamOfConsole(*ppf, ppst);
374 return ppst;
376 return ppstTry;
379 SQLITE_INTERNAL_LINKAGE int oPrintfUtf8(const char *zFormat, ...){
380 va_list ap;
381 int rv;
382 FILE *pfOut;
383 PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */
384 # if CIO_WIN_WC_XLATE
385 PerStreamTags *ppst = getEmitStreamInfo(1, &pst, &pfOut);
386 # else
387 getEmitStreamInfo(1, &pst, &pfOut);
388 # endif
389 assert(zFormat!=0);
390 va_start(ap, zFormat);
391 # if CIO_WIN_WC_XLATE
392 if( pstReachesConsole(ppst) ){
393 rv = conioVmPrintf(ppst, zFormat, ap);
394 }else{
395 # endif
396 rv = vfprintf(pfOut, zFormat, ap);
397 # if CIO_WIN_WC_XLATE
399 # endif
400 va_end(ap);
401 return rv;
404 SQLITE_INTERNAL_LINKAGE int ePrintfUtf8(const char *zFormat, ...){
405 va_list ap;
406 int rv;
407 FILE *pfErr;
408 PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */
409 # if CIO_WIN_WC_XLATE
410 PerStreamTags *ppst = getEmitStreamInfo(2, &pst, &pfErr);
411 # else
412 getEmitStreamInfo(2, &pst, &pfErr);
413 # endif
414 assert(zFormat!=0);
415 va_start(ap, zFormat);
416 # if CIO_WIN_WC_XLATE
417 if( pstReachesConsole(ppst) ){
418 rv = conioVmPrintf(ppst, zFormat, ap);
419 }else{
420 # endif
421 rv = vfprintf(pfErr, zFormat, ap);
422 # if CIO_WIN_WC_XLATE
424 # endif
425 va_end(ap);
426 return rv;
429 SQLITE_INTERNAL_LINKAGE int fPrintfUtf8(FILE *pfO, const char *zFormat, ...){
430 va_list ap;
431 int rv;
432 PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */
433 # if CIO_WIN_WC_XLATE
434 PerStreamTags *ppst = getEmitStreamInfo(0, &pst, &pfO);
435 # else
436 getEmitStreamInfo(0, &pst, &pfO);
437 # endif
438 assert(zFormat!=0);
439 va_start(ap, zFormat);
440 # if CIO_WIN_WC_XLATE
441 if( pstReachesConsole(ppst) ){
442 maybeSetupAsConsole(ppst, 1);
443 rv = conioVmPrintf(ppst, zFormat, ap);
444 if( 0 == isKnownWritable(ppst->pf) ) restoreConsoleArb(ppst);
445 }else{
446 # endif
447 rv = vfprintf(pfO, zFormat, ap);
448 # if CIO_WIN_WC_XLATE
450 # endif
451 va_end(ap);
452 return rv;
455 SQLITE_INTERNAL_LINKAGE int fPutsUtf8(const char *z, FILE *pfO){
456 PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */
457 # if CIO_WIN_WC_XLATE
458 PerStreamTags *ppst = getEmitStreamInfo(0, &pst, &pfO);
459 # else
460 getEmitStreamInfo(0, &pst, &pfO);
461 # endif
462 assert(z!=0);
463 # if CIO_WIN_WC_XLATE
464 if( pstReachesConsole(ppst) ){
465 int rv;
466 maybeSetupAsConsole(ppst, 1);
467 rv = conZstrEmit(ppst, z, (int)strlen(z));
468 if( 0 == isKnownWritable(ppst->pf) ) restoreConsoleArb(ppst);
469 return rv;
470 }else {
471 # endif
472 return (fputs(z, pfO)<0)? 0 : (int)strlen(z);
473 # if CIO_WIN_WC_XLATE
475 # endif
478 SQLITE_INTERNAL_LINKAGE int ePutsUtf8(const char *z){
479 FILE *pfErr;
480 PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */
481 # if CIO_WIN_WC_XLATE
482 PerStreamTags *ppst = getEmitStreamInfo(2, &pst, &pfErr);
483 # else
484 getEmitStreamInfo(2, &pst, &pfErr);
485 # endif
486 assert(z!=0);
487 # if CIO_WIN_WC_XLATE
488 if( pstReachesConsole(ppst) ) return conZstrEmit(ppst, z, (int)strlen(z));
489 else {
490 # endif
491 return (fputs(z, pfErr)<0)? 0 : (int)strlen(z);
492 # if CIO_WIN_WC_XLATE
494 # endif
497 SQLITE_INTERNAL_LINKAGE int oPutsUtf8(const char *z){
498 FILE *pfOut;
499 PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */
500 # if CIO_WIN_WC_XLATE
501 PerStreamTags *ppst = getEmitStreamInfo(1, &pst, &pfOut);
502 # else
503 getEmitStreamInfo(1, &pst, &pfOut);
504 # endif
505 assert(z!=0);
506 # if CIO_WIN_WC_XLATE
507 if( pstReachesConsole(ppst) ) return conZstrEmit(ppst, z, (int)strlen(z));
508 else {
509 # endif
510 return (fputs(z, pfOut)<0)? 0 : (int)strlen(z);
511 # if CIO_WIN_WC_XLATE
513 # endif
516 #endif /* !defined(SQLITE_CIO_NO_TRANSLATE) */
518 #if !(defined(SQLITE_CIO_NO_UTF8SCAN) && defined(SQLITE_CIO_NO_TRANSLATE))
519 /* Skip over as much z[] input char sequence as is valid UTF-8,
520 ** limited per nAccept char's or whole characters and containing
521 ** no char cn such that ((1<<cn) & ccm)!=0. On return, the
522 ** sequence z:return (inclusive:exclusive) is validated UTF-8.
523 ** Limit: nAccept>=0 => char count, nAccept<0 => character
525 SQLITE_INTERNAL_LINKAGE const char*
526 zSkipValidUtf8(const char *z, int nAccept, long ccm){
527 int ng = (nAccept<0)? -nAccept : 0;
528 const char *pcLimit = (nAccept>=0)? z+nAccept : 0;
529 assert(z!=0);
530 while( (pcLimit)? (z<pcLimit) : (ng-- != 0) ){
531 char c = *z;
532 if( (c & 0x80) == 0 ){
533 if( ccm != 0L && c < 0x20 && ((1L<<c) & ccm) != 0 ) return z;
534 ++z; /* ASCII */
535 }else if( (c & 0xC0) != 0xC0 ) return z; /* not a lead byte */
536 else{
537 const char *zt = z+1; /* Got lead byte, look at trail bytes.*/
539 if( pcLimit && zt >= pcLimit ) return z;
540 else{
541 char ct = *zt++;
542 if( ct==0 || (zt-z)>4 || (ct & 0xC0)!=0x80 ){
543 /* Trailing bytes are too few, too many, or invalid. */
544 return z;
547 } while( ((c <<= 1) & 0x40) == 0x40 ); /* Eat lead byte's count. */
548 z = zt;
551 return z;
553 #endif /*!(defined(SQLITE_CIO_NO_UTF8SCAN)&&defined(SQLITE_CIO_NO_TRANSLATE))*/
555 #ifndef SQLITE_CIO_NO_TRANSLATE
556 # ifdef CONSIO_SPUTB
557 SQLITE_INTERNAL_LINKAGE int
558 fPutbUtf8(FILE *pfO, const char *cBuf, int nAccept){
559 assert(pfO!=0);
560 # if CIO_WIN_WC_XLATE
561 PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */
562 PerStreamTags *ppst = getEmitStreamInfo(0, &pst, &pfO);
563 if( pstReachesConsole(ppst) ){
564 int rv;
565 maybeSetupAsConsole(ppst, 1);
566 rv = conZstrEmit(ppst, cBuf, nAccept);
567 if( 0 == isKnownWritable(ppst->pf) ) restoreConsoleArb(ppst);
568 return rv;
569 }else {
570 # endif
571 return (int)fwrite(cBuf, 1, nAccept, pfO);
572 # if CIO_WIN_WC_XLATE
574 # endif
576 # endif
578 SQLITE_INTERNAL_LINKAGE int
579 oPutbUtf8(const char *cBuf, int nAccept){
580 FILE *pfOut;
581 PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */
582 # if CIO_WIN_WC_XLATE
583 PerStreamTags *ppst = getEmitStreamInfo(1, &pst, &pfOut);
584 # else
585 getEmitStreamInfo(1, &pst, &pfOut);
586 # endif
587 # if CIO_WIN_WC_XLATE
588 if( pstReachesConsole(ppst) ){
589 return conZstrEmit(ppst, cBuf, nAccept);
590 }else {
591 # endif
592 return (int)fwrite(cBuf, 1, nAccept, pfOut);
593 # if CIO_WIN_WC_XLATE
595 # endif
598 # ifdef CONSIO_EPUTB
599 SQLITE_INTERNAL_LINKAGE int
600 ePutbUtf8(const char *cBuf, int nAccept){
601 FILE *pfErr;
602 PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */
603 PerStreamTags *ppst = getEmitStreamInfo(2, &pst, &pfErr);
604 # if CIO_WIN_WC_XLATE
605 if( pstReachesConsole(ppst) ){
606 return conZstrEmit(ppst, cBuf, nAccept);
607 }else {
608 # endif
609 return (int)fwrite(cBuf, 1, nAccept, pfErr);
610 # if CIO_WIN_WC_XLATE
612 # endif
614 # endif /* defined(CONSIO_EPUTB) */
616 SQLITE_INTERNAL_LINKAGE char* fGetsUtf8(char *cBuf, int ncMax, FILE *pfIn){
617 if( pfIn==0 ) pfIn = stdin;
618 # if CIO_WIN_WC_XLATE
619 if( pfIn == consoleInfo.pstSetup[0].pf
620 && (consoleInfo.sacSetup & SAC_InConsole)!=0 ){
621 # if CIO_WIN_WC_XLATE==1
622 # define SHELL_GULP 150 /* Count of WCHARS to be gulped at a time */
623 WCHAR wcBuf[SHELL_GULP+1];
624 int lend = 0, noc = 0;
625 if( ncMax > 0 ) cBuf[0] = 0;
626 while( noc < ncMax-8-1 && !lend ){
627 /* There is room for at least 2 more characters and a 0-terminator. */
628 int na = (ncMax > SHELL_GULP*4+1 + noc)? SHELL_GULP : (ncMax-1 - noc)/4;
629 # undef SHELL_GULP
630 DWORD nbr = 0;
631 BOOL bRC = ReadConsoleW(consoleInfo.pstSetup[0].hx, wcBuf, na, &nbr, 0);
632 if( bRC && nbr>0 && (wcBuf[nbr-1]&0xF800)==0xD800 ){
633 /* Last WHAR read is first of a UTF-16 surrogate pair. Grab its mate. */
634 DWORD nbrx;
635 bRC &= ReadConsoleW(consoleInfo.pstSetup[0].hx, wcBuf+nbr, 1, &nbrx, 0);
636 if( bRC ) nbr += nbrx;
638 if( !bRC || (noc==0 && nbr==0) ) return 0;
639 if( nbr > 0 ){
640 int nmb = WideCharToMultiByte(CP_UTF8, 0, wcBuf,nbr,0,0,0,0);
641 if( nmb != 0 && noc+nmb <= ncMax ){
642 int iseg = noc;
643 nmb = WideCharToMultiByte(CP_UTF8, 0, wcBuf,nbr,cBuf+noc,nmb,0,0);
644 noc += nmb;
645 /* Fixup line-ends as coded by Windows for CR (or "Enter".)
646 ** This is done without regard for any setMode{Text,Binary}()
647 ** call that might have been done on the interactive input.
649 if( noc > 0 ){
650 if( cBuf[noc-1]=='\n' ){
651 lend = 1;
652 if( noc > 1 && cBuf[noc-2]=='\r' ) cBuf[--noc-1] = '\n';
655 /* Check for ^Z (anywhere in line) too, to act as EOF. */
656 while( iseg < noc ){
657 if( cBuf[iseg]=='\x1a' ){
658 noc = iseg; /* Chop ^Z and anything following. */
659 lend = 1; /* Counts as end of line too. */
660 break;
662 ++iseg;
664 }else break; /* Drop apparent garbage in. (Could assert.) */
665 }else break;
667 /* If got nothing, (after ^Z chop), must be at end-of-file. */
668 if( noc > 0 ){
669 cBuf[noc] = 0;
670 return cBuf;
671 }else return 0;
672 # endif
673 }else{
674 # endif
675 return fgets(cBuf, ncMax, pfIn);
676 # if CIO_WIN_WC_XLATE
678 # endif
680 #endif /* !defined(SQLITE_CIO_NO_TRANSLATE) */
682 #if defined(_MSC_VER)
683 # pragma warning(default : 4204)
684 #endif
686 #undef SHELL_INVALID_FILE_PTR