diff options
| author | Oskari Timperi <oskari.timperi@iki.fi> | 2015-09-18 19:26:09 +0300 |
|---|---|---|
| committer | Oskari Timperi <oskari.timperi@iki.fi> | 2015-09-18 19:26:09 +0300 |
| commit | 8d7c62da8e05c177e3f79e2fd3ea0ade7ca1acb4 (patch) | |
| tree | ca74819e574fc32eb3c95ac2a6975d477026730e | |
| parent | 0996ffcd61bb03d820dac88ad42539dc1ab8c5e7 (diff) | |
| download | diceware-8d7c62da8e05c177e3f79e2fd3ea0ade7ca1acb4.tar.gz diceware-8d7c62da8e05c177e3f79e2fd3ea0ade7ca1acb4.zip | |
windows: do console output using WriteConsole
| -rw-r--r-- | Makefile | 2 | ||||
| -rw-r--r-- | main.c | 4 | ||||
| -rw-r--r-- | winconsole.c | 104 | ||||
| -rw-r--r-- | winconsole.h | 19 |
4 files changed, 128 insertions, 1 deletions
@@ -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 @@ -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 |
