aboutsummaryrefslogtreecommitdiff
path: root/winconsole.c
diff options
context:
space:
mode:
Diffstat (limited to 'winconsole.c')
-rw-r--r--winconsole.c104
1 files changed, 104 insertions, 0 deletions
diff --git a/winconsole.c b/winconsole.c
new file mode 100644
index 0000000..4eded13
--- /dev/null
+++ b/winconsole.c
@@ -0,0 +1,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;
+}