diff --git a/src/util.c b/src/util.c
index bf9ed97..62adc0c 100644
--- a/src/util.c
+++ b/src/util.c
@@ -26,6 +26,9 @@
 #include <xalloc.h>
 #include "xvasprintf.h"
 #include <signal.h>
+#ifdef _WIN32
+#include <windows.h>
+#endif
 
 /* Use SA_NOCLDSTOP as a proxy for whether the sigaction machinery is
    present.  */
@@ -168,9 +171,11 @@ static sigset_t caught_signals;
 
 static sig_atomic_t volatile interrupt_signal;
 
+#ifndef _WIN32
 /* A count of the number of pending stop signals that have been received.  */
 
 static sig_atomic_t volatile stop_signal_count;
+#endif
 
 /* An ordinary signal was received; arrange for the program to exit.  */
 
@@ -183,6 +188,7 @@ sighandler (int sig)
     interrupt_signal = sig;
 }
 
+#ifndef _WIN32
 /* A SIGTSTP was received; arrange for the program to suspend itself.  */
 
 static void
@@ -193,6 +199,12 @@ stophandler (int sig)
   if (! interrupt_signal)
     stop_signal_count++;
 }
+#endif
+
+/* The internal set_color_context */
+
+void setcolorctx (enum color_context);
+
 /* Process any pending signals.  If signals are caught, this function
    should be called periodically.  Ideally there should never be an
    unbounded amount of time when signals are not being processed.
@@ -202,13 +214,19 @@ stophandler (int sig)
 static void
 process_signals (void)
 {
+#ifndef _WIN32
   while (interrupt_signal || stop_signal_count)
+#else
+  while (interrupt_signal)
+#endif
     {
       int sig;
+#ifndef _WIN32
       int stops;
+#endif
       sigset_t oldset;
 
-      set_color_context (RESET_CONTEXT);
+      setcolorctx (RESET_CONTEXT);
       fflush (stdout);
 
       sigprocmask (SIG_BLOCK, &caught_signals, &oldset);
@@ -216,6 +234,7 @@ process_signals (void)
       /* Reload interrupt_signal and stop_signal_count, in case a new
          signal was handled before sigprocmask took effect.  */
       sig = interrupt_signal;
+#ifndef _WIN32
       stops = stop_signal_count;
 
       /* SIGTSTP is special, since the application can receive that signal
@@ -227,6 +246,7 @@ process_signals (void)
           sig = SIGSTOP;
         }
       else
+#endif
         signal (sig, SIG_DFL);
 
       /* Exit or suspend the program.  */
@@ -244,11 +264,15 @@ install_signal_handlers (void)
   /* The signals that are trapped, and the number of such signals.  */
   static int const sig[] =
     {
+#ifndef _WIN32
       /* This one is handled specially.  */
       SIGTSTP,
 
       /* The usual suspects.  */
       SIGALRM, SIGHUP, SIGINT, SIGPIPE, SIGQUIT, SIGTERM,
+#else
+      SIGINT, SIGTERM,
+#endif
 #ifdef SIGPOLL
       SIGPOLL,
 #endif
@@ -267,9 +291,6 @@ install_signal_handlers (void)
     };
   enum { nsigs = sizeof (sig) / sizeof *(sig) };
 
-#if ! SA_NOCLDSTOP
-  bool caught_sig[nsigs];
-#endif
   {
     int j;
 #if SA_NOCLDSTOP
@@ -293,17 +314,23 @@ install_signal_handlers (void)
           sigaction (sig[j], &act, NULL);
         }
 #else
+    bool caught_sig[nsigs];
+
     for (j = 0; j < nsigs; j++)
       {
         caught_sig[j] = (signal (sig[j], SIG_IGN) != SIG_IGN);
         if (caught_sig[j])
           {
+#ifndef _WIN32
             signal (sig[j], sig[j] == SIGTSTP ? stophandler : sighandler);
+#else
+            signal (sig[j], sighandler);
+#endif
             siginterrupt (sig[j], 0);
           }
       }
 #endif
-    }
+  }
 }
 
 static char const *current_name0;
@@ -603,7 +630,7 @@ parse_diff_color (void)
           switch (*p)
             {
             case ':':
-              ++p;
+              *(buf++) = *(p++);
               break;
 
             case '*':
@@ -624,6 +651,7 @@ parse_diff_color (void)
               break;
 
             case '\0':
+              *(buf) = *(p);
               state = PS_DONE;	/* Done! */
               goto done;
 
@@ -702,6 +730,11 @@ parse_diff_color (void)
     }
 }
 
+#ifdef _WIN32
+static HANDLE hstdout = NULL;
+static SHORT attr_orig;
+#endif
+
 static void
 check_color_output (bool is_pipe)
 {
@@ -715,6 +748,19 @@ check_color_output (bool is_pipe)
   colors_enabled = (colors_style == ALWAYS
                     || (colors_style == AUTO && output_is_tty));
 
+#ifdef _WIN32
+  if (hstdout == NULL) {
+    CONSOLE_SCREEN_BUFFER_INFO csbi;
+
+    hstdout = GetStdHandle (STD_OUTPUT_HANDLE);
+    if (hstdout != INVALID_HANDLE_VALUE
+        && GetConsoleScreenBufferInfo (hstdout, &csbi))
+       attr_orig = csbi.wAttributes;
+    else
+      hstdout = INVALID_HANDLE_VALUE;
+  }
+#endif
+
   if (colors_enabled)
     parse_diff_color ();
 
@@ -1333,6 +1379,99 @@ output_1_line (char const *base, char const *limit, char const *flag_format,
     }
 }
 
+#ifdef _WIN32
+/* Convert a color spec, a semi-colon separated list of the form
+   "NN;MM;KK;...", where each number is a value of the SGR parameter,
+   into the corresponding Windows console text attribute.
+
+   This function supports a subset of the SGR rendition aspects that
+   the Windows console can display.  */
+static int
+w32_sgr2attr (const struct bin_str *sgr_seq)
+{
+  const char *p, *s = sgr_seq->string, *e = s + sgr_seq->len * sizeof *(s);
+  int code, fg = attr_orig & 15, bg = attr_orig & (15 << 4);
+  int bright = 0, inverse = 0;
+  static const int fg_color[] = {
+    0,          /* black */
+    FOREGROUND_RED, /* red */
+    FOREGROUND_GREEN,   /* green */
+    FOREGROUND_GREEN | FOREGROUND_RED, /* yellow */
+    FOREGROUND_BLUE,               /* blue */
+    FOREGROUND_BLUE | FOREGROUND_RED,  /* magenta */
+    FOREGROUND_BLUE | FOREGROUND_GREEN, /* cyan */
+    FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE /* gray */
+  };
+  static const int bg_color[] = {
+    0,          /* black */
+    BACKGROUND_RED, /* red */
+    BACKGROUND_GREEN,   /* green */
+    BACKGROUND_GREEN | BACKGROUND_RED, /* yellow */
+    BACKGROUND_BLUE,               /* blue */
+    BACKGROUND_BLUE | BACKGROUND_RED,  /* magenta */
+    BACKGROUND_BLUE | BACKGROUND_GREEN, /* cyan */
+    BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE /* gray */
+  };
+
+  for (p = s; *s && p <= e; p++)
+    {
+      if (*p == ';' || *p == '\0' || p == e)
+        {
+          code = strtol (s, NULL, 10);
+          s = p + (*p == ';');
+
+          switch (code)
+            {
+            case 0: /* all attributes off */
+              fg = attr_orig & 15;
+              bg = attr_orig & (15 << 4);
+              bright = 0;
+              inverse = 0;
+              break;
+            case 1: /* intensity on */
+              bright = 1;
+              break;
+            case 7: /* inverse video */
+              inverse = 1;
+              break;
+            case 22:    /* intensity off */
+              bright = 0;
+              break;
+            case 27:    /* inverse off */
+              inverse = 0;
+              break;
+            case 30: case 31: case 32: case 33: /* foreground color */
+            case 34: case 35: case 36: case 37:
+              fg = fg_color[code - 30];
+              break;
+            case 39:    /* default foreground */
+              fg = attr_orig & 15;
+              break;
+            case 40: case 41: case 42: case 43: /* background color */
+            case 44: case 45: case 46: case 47:
+              bg = bg_color[code - 40];
+              break;
+            case 49:    /* default background */
+              bg = attr_orig & (15 << 4);
+              break;
+            default:
+              break;
+            }
+        }
+    }
+  if (inverse)
+    {
+      int t = fg;
+      fg = (bg >> 4);
+      bg = (t << 4);
+    }
+  if (bright)
+    fg |= FOREGROUND_INTENSITY;
+
+  return (bg & (15 << 4)) | (fg & 15);
+}
+#endif
+
 enum indicator_no
   {
     C_LEFT, C_RIGHT, C_END, C_RESET, C_HEADER, C_ADD, C_DELETE, C_LINE
@@ -1344,46 +1483,88 @@ put_indicator (const struct bin_str *ind)
   fwrite (ind->string, ind->len, 1, outfile);
 }
 
+static void
+put_color_indicator (const enum indicator_no ind_no)
+{
+#ifdef _WIN32
+  if (hstdout != NULL && hstdout != INVALID_HANDLE_VALUE)
+    {
+      SHORT attr = w32_sgr2attr (&color_indicator[ind_no]);
+      SetConsoleTextAttribute (hstdout, attr);
+    }
+  else
+    {
+#endif
+      put_indicator (&color_indicator[C_LEFT]);
+      put_indicator (&color_indicator[ind_no]);
+      put_indicator (&color_indicator[C_RIGHT]);
+#ifdef _WIN32
+    }
+#endif
+}
+
+static void
+put_reset_indicator (void)
+{
+#ifdef _WIN32
+  if (hstdout != NULL && hstdout != INVALID_HANDLE_VALUE)
+    {
+      SetConsoleTextAttribute (hstdout, attr_orig);
+    }
+  else
+    {
+#endif
+      put_indicator (&color_indicator[C_LEFT]);
+      put_indicator (&color_indicator[C_RESET]);
+      put_indicator (&color_indicator[C_RIGHT]);
+#ifdef _WIN32
+    }
+#endif
+}
+
 static enum color_context last_context = RESET_CONTEXT;
 
 void
 set_color_context (enum color_context color_context)
 {
   process_signals ();
+  setcolorctx (color_context);
+}
+
+void
+setcolorctx (enum color_context color_context)
+{
   if (colors_enabled && last_context != color_context)
     {
-      put_indicator (&color_indicator[C_LEFT]);
       switch (color_context)
         {
         case HEADER_CONTEXT:
-          put_indicator (&color_indicator[C_HEADER]);
+          put_color_indicator (C_HEADER);
           break;
 
         case LINE_NUMBER_CONTEXT:
-          put_indicator (&color_indicator[C_LINE]);
+          put_color_indicator (C_LINE);
           break;
 
         case ADD_CONTEXT:
-          put_indicator (&color_indicator[C_ADD]);
+          put_color_indicator (C_ADD);
           break;
 
         case DELETE_CONTEXT:
-          put_indicator (&color_indicator[C_DELETE]);
+          put_color_indicator (C_DELETE);
           break;
 
         case RESET_CONTEXT:
-          put_indicator (&color_indicator[C_RESET]);
+          put_reset_indicator ();
           break;
 
         default:
           abort ();
         }
-      put_indicator (&color_indicator[C_RIGHT]);
       last_context = color_context;
     }
 }
 
-
 char const change_letter[] = { 0, 'd', 'a', 'c' };
 
 /* Translate an internal line number (an index into diff's table of lines)
