From 992902efa7d40f2bc52d5bda0e51da27a2a2dbcc Mon Sep 17 00:00:00 2001
From: Ron Yorston <rmy@pobox.com>
Date: Thu, 20 Mar 2014 11:22:40 +0000
Subject: Implement write replacement to handle OEM codepages

---
 win32/winansi.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 75 insertions(+), 1 deletion(-)

(limited to 'win32')

diff --git a/win32/winansi.c b/win32/winansi.c
index ba3167425..8f2bb72e4 100644
--- a/win32/winansi.c
+++ b/win32/winansi.c
@@ -15,7 +15,7 @@
 #undef putchar
 #undef fwrite
 #undef puts
-/* TODO: write */
+#undef write
 
 /*
  ANSI codes used by git: m, K
@@ -537,3 +537,77 @@ int winansi_get_terminal_width_height(struct winsize *win)
 
 	return ret ? 0 : -1;
 }
+
+static int ansi_emulate_write(int fd, const void *buf, size_t count)
+{
+	int rv = 0, i;
+	const char *s = (const char *)buf;
+	char *pos, *str;
+	size_t len, out_len;
+	static size_t max_len = 0;
+	static char *mem = NULL;
+
+	/* if no special treatment is required output the string as-is */
+	for ( i=0; i<count; ++i ) {
+		if ( s[i] == '\033' || s[i] > 0x7f ) {
+			break;
+		}
+	}
+
+	if ( i == count ) {
+		return write(fd, buf, count);
+	}
+
+	/* make a writable copy of the data and retain it for reuse */
+	if ( count > max_len ) {
+		free(mem);
+		mem = xmalloc(count+1);
+		max_len = count;
+	}
+	memcpy(mem, buf, count);
+	mem[count] = '\0';
+	pos = str = mem;
+
+	/* we're writing to the console so we assume the data isn't binary */
+	while (*pos) {
+		pos = strstr(str, "\033[");
+		if (pos) {
+			len = pos - str;
+
+			if (len) {
+				CharToOemBuff(str, str, len);
+				out_len = write(fd, buf, len);
+				rv += out_len;
+				if (out_len < len)
+					return rv;
+			}
+
+			str = pos + 2;
+			rv += 2;
+
+			pos = (char *)set_attr(str);
+			rv += pos - str;
+			str = pos;
+		} else {
+			len = strlen(str);
+			rv += len;
+			CharToOem(str, str);
+			write(fd, str, len);
+			return rv;
+		}
+	}
+	return rv;
+}
+
+int winansi_write(int fd, const void *buf, size_t count)
+{
+	if (!isatty(fd))
+		return write(fd, buf, count);
+
+	init();
+
+	if (!console)
+		return write(fd, buf, count);
+
+	return ansi_emulate_write(fd, buf, count);
+}
-- 
cgit v1.2.3-55-g6feb