aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOskari Timperi <oskari.timperi@iki.fi>2015-09-18 19:26:09 +0300
committerOskari Timperi <oskari.timperi@iki.fi>2015-09-18 19:26:09 +0300
commit8d7c62da8e05c177e3f79e2fd3ea0ade7ca1acb4 (patch)
treeca74819e574fc32eb3c95ac2a6975d477026730e
parent0996ffcd61bb03d820dac88ad42539dc1ab8c5e7 (diff)
downloaddiceware-8d7c62da8e05c177e3f79e2fd3ea0ade7ca1acb4.tar.gz
diceware-8d7c62da8e05c177e3f79e2fd3ea0ade7ca1acb4.zip
windows: do console output using WriteConsole
-rw-r--r--Makefile2
-rw-r--r--main.c4
-rw-r--r--winconsole.c104
-rw-r--r--winconsole.h19
4 files changed, 128 insertions, 1 deletions
diff --git a/Makefile b/Makefile
index 3862de1..7826677 100644
--- a/Makefile
+++ b/Makefile
@@ -23,7 +23,7 @@ endif
ifneq ($(BUILD_WIN32),)
E = .exe
-SOURCES += randgen_win32.c
+SOURCES += randgen_win32.c winconsole.c
else
E =
SOURCES += randgen_unix.c
diff --git a/main.c b/main.c
index cab4586..a565a05 100644
--- a/main.c
+++ b/main.c
@@ -6,6 +6,10 @@
#include <errno.h>
#include <string.h>
+#ifdef _WIN32
+#include "winconsole.h"
+#endif
+
/*
Generates a random id of length `size-1` consisting of characters in the set
[1-6] and places it in the buffer pointed to by `id`. The buffer is NULL
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;
+}
diff --git a/winconsole.h b/winconsole.h
new file mode 100644
index 0000000..195dac4
--- /dev/null
+++ b/winconsole.h
@@ -0,0 +1,19 @@
+#ifndef WINCONSOLE_H
+#define WINCONSOLE_H
+
+#include <stdio.h>
+
+#ifndef WINCONSOLE_NO_DEF
+#define vfprintf(FILE, FMT, AP) winconsole_vfprintf((FILE), (FMT), (AP))
+#define fprintf(FILE, FMT, ...) winconsole_fprintf((FILE), (FMT), ##__VA_ARGS__)
+#define vprintf(FMT, AP) winconsole_vprintf((FMT), (AP))
+#define printf(FMT, ...) winconsole_printf((FMT), ##__VA_ARGS__)
+#endif
+
+int winconsole_vfprintf(FILE *fp, const char *fmt, va_list ap);
+int winconsole_fprintf(FILE *fp, const char *fmt, ...);
+
+int winconsole_vprintf(const char *fmt, va_list ap);
+int winconsole_printf(const char *fmt, ...);
+
+#endif