1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
|
#define WINCONSOLE_NO_DEF
#include "winconsole.h"
#include <windows.h>
#include <io.h>
/*
To correctly make console output on Windows, we need to check if the
output stream we are writing to is a console. If it is, we use
WriteConsoleW() to directly write to the console. Otherwise we use the
fprintf() function. This dance makes us correctly output whatever codepage
the console is in (we assume that our internal strings and dictionary are
UTF-8).
*/
static int is_console(HANDLE h)
{
DWORD mode;
if (h == INVALID_HANDLE_VALUE)
return 0;
return !!(GetConsoleMode(h, &mode));
}
int winconsole_vfprintf(FILE *fp, const char *fmt, va_list ap)
{
wchar_t *wbuf;
va_list aq;
DWORD nwritten;
char *buf;
int bufsz, wbufsz;
HANDLE h = (HANDLE) _get_osfhandle(_fileno(fp));
/* WriteConsoleW works only with the console */
if (!is_console(h))
return vfprintf(fp, fmt, ap);
/* get the length of the buffer */
va_copy(aq, ap);
bufsz = vsnprintf(NULL, 0, fmt, aq);
if (bufsz < 0)
return bufsz;
va_end(aq);
if (bufsz == 0)
return 0;
buf = malloc(bufsz+1);
if (!buf)
return -1;
/* now really print to the buffer */
bufsz = vsnprintf(buf, bufsz+1, fmt, ap);
if (bufsz < 0)
return bufsz;
/* get the length of the wide buf */
wbufsz = MultiByteToWideChar(CP_UTF8, 0, buf, bufsz+1, NULL, 0);
if (wbufsz == 0xFFFD || wbufsz == 0)
{
free(buf);
return -1;
}
wbuf = malloc(sizeof(wchar_t) * wbufsz);
if (!wbuf)
{
free(buf);
return -1;
}
MultiByteToWideChar(CP_UTF8, 0, buf, bufsz+1, wbuf, wbufsz);
if (!WriteConsoleW(h, wbuf, wbufsz-1, &nwritten, NULL))
return -1;
return nwritten;
}
int winconsole_fprintf(FILE *fp, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
int ret = winconsole_vfprintf(fp, fmt, ap);
va_end(ap);
return ret;
}
int winconsole_vprintf(const char *fmt, va_list ap)
{
return winconsole_vfprintf(stdout, fmt, ap);
}
int winconsole_printf(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
int ret = winconsole_vprintf(fmt, ap);
va_end(ap);
return ret;
}
|