issue #293: Check external diff error

* lib/vclib/__init__.py
  (): Don't import unused module 'io'

  (ExternalDiffError): New exception.
  (_diff_fp.__init__):
    - Specify str I/O explicitly in to communicate to subprocess and remove
      extra code for Python 2
    - Prepare to read from stderr

  (_diff_fp.read):
    Rename parameter, so as not to override global class name 'bytes'

  (_diff_fp.read, _diff_fp.readline):
    Check stderr and exit code at EOF on stdout to detect error and
    raise ExternalDifferror if it occurs.
diff --git a/lib/vclib/__init__.py b/lib/vclib/__init__.py
index fd81005..040f463 100644
--- a/lib/vclib/__init__.py
+++ b/lib/vclib/__init__.py
@@ -15,7 +15,6 @@
 """
 
 import sys
-import io
 import subprocess
 import os
 import time
@@ -376,6 +375,12 @@
     pass
 
 
+class ExternalDiffError(Error):
+    def __init__(self, returncode, mess):
+        self.returncode = returncode
+        Error.__init__(self, "Diff terminated with exit code {0:d}: {1}".format(returncode, mess))
+
+
 # ======================================================================
 # Implementation code used by multiple vclib modules
 
@@ -427,26 +432,41 @@
         if info1 and info2:
             args.extend(["-L", self._label(info1), "-L", self._label(info2)])
         args.extend([temp1, temp2])
+        # We assume pipe buffer for stderr is enough for diff utility,
+        # otherwise, it may cause deadlock.
         self.proc = subprocess.Popen(
-            args, stdout=subprocess.PIPE, bufsize=-1, close_fds=(sys.platform != "win32")
+            args, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
+            encoding="utf-8", errors="surrogateescape",
+            bufsize=-1, close_fds=(sys.platform != "win32")
         )
-        if not isinstance(self.proc.stdout, io.TextIOBase) and isinstance(
-            self.proc.stdout, io.BufferedIOBase
-        ):
-            self.fp = io.TextIOWrapper(self.proc.stdout, encoding="utf-8", errors="surrogateescape")
-        else:
-            self.fp = self.proc.stdout
 
-    def read(self, bytes):
-        return self.fp.read(bytes)
+    def read(self, buf_size):
+        buf = self.proc.stdout.read(buf_size)
+        if buf == "":
+            errs = self.proc.stderr.read()
+            ret = self.proc.poll()
+            if ret not in (None, 0, 1) or errs:
+                if ret is None:
+                    ret = -1
+                raise ExternalDiffError(ret, errs)
+        return buf
 
     def readline(self):
-        return self.fp.readline()
+        buf = self.proc.stdout.readline()
+        if buf == "":
+            errs = self.proc.stderr.read()
+            ret = self.proc.poll()
+            if ret not in (None, 0, 1) or errs:
+                if ret is None:
+                    ret = -1
+                raise ExternalDiffError(ret, errs)
+        return buf
 
     def close(self):
         try:
             if self.proc:
-                self.fp.close()
+                self.proc.stdout.close()
+                self.proc.stderr.close()
                 ret = self.proc.poll()
                 if ret is None:
                     # child process seems to be still running...