todo : chdir-long.c exclude.c

2014-03-20  Juan Manuel Guerrero <juan.guerrero@gmx.de>

	* lib/fchdir.c (_gl_register_fd) [__DJGPP__, __DJGPP_MINOR__]: Call
	access instead of stat when compiled for DJGPP 2.03.

	* lib/fdopendir.c (fdopendir_with_dup) [__DJGPP__,  __DJGPP_MINOR__]:
	DJGPP 2.04 has no method to get the file desscriptor of an directory
	open with opendir.  So do not close the file descriptor associated to
	the directory.

	* lib/fts.c: Include dosname.h for ISSLASH nor IS_ABSOLUTE_FILE_NAME
	definition.
	(link_count_optimize_ok): Use ISSLASH instead of '/'.
	(fts_children): Use IS_ABSOLUTE_FILE_NAME instead of '/'.

	* lib/openat-proc.c (openat_proc_name) [__DJGPP__]: DJGPP does not
	support openning of "/proc/self/fd".  Return always -1 even if
	"/proc/self/fd" is passed as filename to open; this may be a valid
	DOS file name in some application.

	* lib/chdir-long.c: Include dosname.h.
	(find_non_slash): Use OS specific DIR_SEPARATOR_CHARS instead of
	hardcoded posix slash.
	(chdir_long): Acount for possible drive letter prefix.  Use OS specific
	DIR_SEPARATOR_CHARS instead of hardcoded posix slash.

	* lib/dosname.h: New macro DIR_SEPARATOR_CHARS defines charactes to be
	used by strspn calls.

	* lib/iswctype-impl.h (iswctype) [__DJGPP__]:  DJGPP has no wide char
	support thus return always 0.

	* lib/open.c: Include dosname.h for ISSLASH definition.
	(open): Check with ISSLASH.
	(rpl_open) [__DJGPP__]: Use access to determinate if given path is
	an existing directory and ISSLASH to allow for mixed backslash and
        slash as directory separator.

	* lib/progname.c [MSDOS]: Define new macro GET_LAST_SLASH to find
	the last directory separator character.  On DOS-like systems these
	are slash, backslash or colon.  For POSIX this is simple a slash.

	* src/dfa.c [MBS_SUPPORT]:  For systems without wide char/multi byte
	support remove realloc_trans_if_necessary, transit_state_singlebyte,
	match_anychar, match_mb_charset, check_matching_with_multibyte_ops,
	transit_state, transit_state_consume_1char, prepare_wc_buf.
	(dfaexec) [MBS_SUPPORT]:  Remove all calls to unsupported multi byte
	functions.

	* src/dosbuf.c:  No longer include config.h.
	[__DJGPP__]: Include pc.h for ScreenGetCursor prototype.
	(restore_blink_bit, screen_puts, msdos_screen_write, djgpp_grep_startup)
	[__DJGPP__]: New functions to support colorization without requiring
	ANSI.SYS driver (or its work-alike) to be loaded.  
	(msdos_screen_write): Added support to decode and execute erase part
	of the line to the right escape sequence (ESC-[K), that is used to
	initialize and finish SGR escape sequences.

	* src/main.c [__DJGPP__]: New macro IS_TERMINAL defined.  If compiled
	with DJGPP do not check for the term environment variable to decided
	which value should color_option have.
	(main): Use CANONICALIZE_PATH, STRIP_FULL_PATH_AND_EXTENSION and
	IS_TERMINAL.

	* src/mbsupport.h [__DJGPP__]:  DJGPP has no wide char support thus
	set MBS_SUPPORT always to 0 and MB_CUR_MAX always to 1.

	* src/system.h [HAVE_DOS_FILE_NAMES]:  New macro CANONICALIZE_PATH.
	New macro STRIP_FULL_PATH_AND_EXTENSION to strip extension and full
	path from argv[0].  Are no-op for all other systems.










diff -aprNU5 grep-2.18.orig/lib/chdir-long.c grep-2.18/lib/chdir-long.c
--- grep-2.18.orig/lib/chdir-long.c	2014-01-02 02:32:04 +0100
+++ grep-2.18/lib/chdir-long.c	2014-03-20 21:09:28 +0100
@@ -26,10 +26,12 @@
 #include <stdlib.h>
 #include <stdbool.h>
 #include <string.h>
 #include <stdio.h>
 
+#include "dosname.h"
+
 #ifndef PATH_MAX
 # error "compile this file only if your system defines PATH_MAX"
 #endif
 
 /* The results of openat() in this file are not leaked to any
@@ -84,11 +86,11 @@ cdb_advance_fd (struct cd_buf *cdb, char
 
 /* Return a pointer to the first non-slash in S.  */
 static char * _GL_ATTRIBUTE_PURE
 find_non_slash (char const *s)
 {
-  size_t n_slash = strspn (s, "/");
+  size_t n_slash = strspn (s, DIR_SEPARATOR_CHARS);
   return (char *) s + n_slash;
 }
 
 /* This is a function much like chdir, but without the PATH_MAX limitation
    on the length of the directory name.  A significant difference is that
@@ -110,10 +112,11 @@ chdir_long (char *dir)
 {
   int e = chdir (dir);
   if (e == 0 || errno != ENAMETOOLONG)
     return e;
 
+  dir = dir + FILE_SYSTEM_PREFIX_LEN(dir);
   {
     size_t len = strlen (dir);
     char *dir_end = dir + len;
     struct cd_buf cdb;
     size_t n_leading_slash;
@@ -124,11 +127,11 @@ chdir_long (char *dir)
        must have failed and set errno to ENOENT.  */
     assert (0 < len);
     assert (PATH_MAX <= len);
 
     /* Count leading slashes.  */
-    n_leading_slash = strspn (dir, "/");
+    n_leading_slash = strspn (dir, DIR_SEPARATOR_CHARS);
 
     /* Handle any leading slashes as well as any name that matches
        the regular expression, m!^//hostname[/]*! .  Handling this
        prefix separately usually results in a single additional
        cdb_advance_fd call, but it's worthwhile, since it makes the
diff -aprNU5 grep-2.18.orig/lib/dosname.h grep-2.18/lib/dosname.h
--- grep-2.18.orig/lib/dosname.h	2014-01-02 02:32:04 +0100
+++ grep-2.18/lib/dosname.h	2014-03-20 21:09:28 +0100
@@ -31,13 +31,15 @@
           (_IS_DRIVE_LETTER ((Filename)[0]) && (Filename)[1] == ':' ? 2 : 0)
 # ifndef __CYGWIN__
 #  define FILE_SYSTEM_DRIVE_PREFIX_CAN_BE_RELATIVE 1
 # endif
 # define ISSLASH(C) ((C) == '/' || (C) == '\\')
+# define DIR_SEPARATOR_CHARS  "/\\"
 #else
 # define FILE_SYSTEM_PREFIX_LEN(Filename) 0
 # define ISSLASH(C) ((C) == '/')
+# define DIR_SEPARATOR_CHARS  "/"
 #endif
 
 #ifndef FILE_SYSTEM_DRIVE_PREFIX_CAN_BE_RELATIVE
 # define FILE_SYSTEM_DRIVE_PREFIX_CAN_BE_RELATIVE 0
 #endif
diff -aprNU5 grep-2.18.orig/lib/fchdir.c grep-2.18/lib/fchdir.c
--- grep-2.18.orig/lib/fchdir.c	2014-01-02 02:32:04 +0100
+++ grep-2.18/lib/fchdir.c	2014-03-20 21:10:42 +0100
@@ -132,11 +132,21 @@ _gl_register_fd (int fd, const char *fil
 {
   struct stat statbuf;
 
   assert (0 <= fd);
   if (REPLACE_OPEN_DIRECTORY
+#if defined(__DJGPP__) && __DJGPP__ == 2 && __DJGPP_MINOR__ < 4
+      /*
+       *  Computation of stat is very expensive.
+       *  To determinate if PATH is an existing
+       *  directory, access on DOS platforms is
+       *  mostly a fast system call.
+       */
+      || (access (filename, D_OK) == 0))
+#else
       || (fstat (fd, &statbuf) == 0 && S_ISDIR (statbuf.st_mode)))
+#endif
     {
       if (!ensure_dirs_slot (fd)
           || (dirs[fd].name = get_name (filename)) == NULL)
         {
           int saved_errno = errno;
diff -aprNU5 grep-2.18.orig/lib/fdopendir.c grep-2.18/lib/fdopendir.c
--- grep-2.18.orig/lib/fdopendir.c	2014-01-02 02:32:04 +0100
+++ grep-2.18/lib/fdopendir.c	2014-03-20 21:11:14 +0100
@@ -113,11 +113,21 @@ fdopendir_with_dup (int fd, int older_du
           dir = fdopendir_with_dup (fd, dupfd, cwd);
           saved_errno = errno;
         }
       else
         {
-          close (fd);
+#ifdef __DJGPP__
+          /*
+           *  DJGPP has no method to get the
+           *  the file descriptor of an open
+           *  directory, so do not close it.
+           *  If CWD != NULL we are doing
+           *  fchdir/opendir(".")/restore_cwd(CWD).
+           */
+          if (!cwd)
+#endif
+            close (fd);
           dir = fd_clone_opendir (dupfd, cwd);
           saved_errno = errno;
           if (! dir)
             {
               int fd1 = dup (dupfd);
diff -aprNU5 grep-2.18.orig/lib/fts.c grep-2.18/lib/fts.c
--- grep-2.18.orig/lib/fts.c	2014-01-02 02:32:04 +0100
+++ grep-2.18/lib/fts.c	2014-03-20 21:13:26 +0100
@@ -50,10 +50,14 @@
 static char sccsid[] = "@(#)fts.c       8.6 (Berkeley) 8/14/94";
 #endif /* LIBC_SCCS and not lint */
 
 #include "fts_.h"
 
+#if !defined(ISSLASH) || !defined(IS_ABSOLUTE_FILE_NAME)
+# include "dosname.h"
+#endif
+
 #if HAVE_SYS_PARAM_H || defined _LIBC
 # include <sys/param.h>
 #endif
 #ifdef _LIBC
 # include <include/sys/stat.h>
@@ -823,11 +827,11 @@ link_count_optimize_ok (FTSENT const *p)
 /*
  * Special case of "/" at the end of the file name so that slashes aren't
  * appended which would cause file names to be written as "....//foo".
  */
 #define NAPPEND(p)                                                      \
-        (p->fts_path[p->fts_pathlen - 1] == '/'                         \
+        (ISSLASH(p->fts_path[p->fts_pathlen - 1])                       \
             ? p->fts_pathlen - 1 : p->fts_pathlen)
 
 FTSENT *
 fts_read (register FTS *sp)
 {
@@ -1167,11 +1171,11 @@ fts_children (register FTS *sp, int inst
          * does its chdir to the root of a traversal, we can lose -- we need to
          * chdir into the subdirectory, and we don't know where the current
          * directory is, so we can't get back so that the upcoming chdir by
          * fts_read will work.
          */
-        if (p->fts_level != FTS_ROOTLEVEL || p->fts_accpath[0] == '/' ||
+        if (p->fts_level != FTS_ROOTLEVEL || IS_ABSOLUTE_FILE_NAME(p->fts_accpath) ||
             ISSET(FTS_NOCHDIR))
                 return (sp->fts_child = fts_build(sp, instr));
 
         if ((fd = diropen (sp, ".")) < 0)
                 return (sp->fts_child = NULL);
diff -aprNU5 grep-2.18.orig/lib/iswctype-impl.h grep-2.18/lib/iswctype-impl.h
--- grep-2.18.orig/lib/iswctype-impl.h	2014-01-02 02:32:06 +0100
+++ grep-2.18/lib/iswctype-impl.h	2014-03-20 21:14:20 +0100
@@ -16,7 +16,11 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 int
 iswctype (wint_t wc, wctype_t desc)
 {
+#ifdef __DJGPP__
+  return 0;
+#else
   return ((int (*) (wint_t)) desc) (wc);
+#endif
 }
diff -aprNU5 grep-2.18.orig/lib/open.c grep-2.18/lib/open.c
--- grep-2.18.orig/lib/open.c	2014-01-02 02:32:06 +0100
+++ grep-2.18/lib/open.c	2014-03-20 21:14:20 +0100
@@ -25,10 +25,14 @@
 /* Get the original definition of open.  It might be defined as a macro.  */
 #include <fcntl.h>
 #include <sys/types.h>
 #undef __need_system_fcntl_h
 
+#ifndef ISSLASH
+# include "dosname.h"
+#endif
+
 static int
 orig_open (const char *filename, int flags, mode_t mode)
 {
   return open (filename, flags, mode);
 }
@@ -105,11 +109,11 @@ open (const char *filename, int flags, .
        - if O_WRONLY or O_RDWR is specified, open() must fail because the
          file does not contain a '.' directory.  */
   if (flags & (O_CREAT | O_WRONLY | O_RDWR))
     {
       size_t len = strlen (filename);
-      if (len > 0 && filename[len - 1] == '/')
+      if (len > 0 && ISSLASH(filename[len - 1]))
         {
           errno = EISDIR;
           return -1;
         }
     }
@@ -126,12 +130,22 @@ open (const char *filename, int flags, .
      dummy.  */
   if (REPLACE_OPEN_DIRECTORY && fd < 0 && errno == EACCES
       && ((flags & O_ACCMODE) == O_RDONLY
           || (O_SEARCH != O_RDONLY && (flags & O_ACCMODE) == O_SEARCH)))
     {
+#if defined(__DJGPP__) && __DJGPP__ == 2 && __DJGPP_MINOR__ < 4
+      /*
+       *  Computation of stat is very expensive.
+       *  To determinate if PATH is an existing
+       *  directory, access on DOS platforms is
+       *  mostly a fast system call.
+       */
+      if (access (filename, D_OK) == 0)
+#else
       struct stat statbuf;
       if (stat (filename, &statbuf) == 0 && S_ISDIR (statbuf.st_mode))
+#endif
         {
           /* Maximum recursion depth of 1.  */
           fd = open ("/dev/null", flags, mode);
           if (0 <= fd)
             fd = _gl_register_fd (fd, filename);
@@ -156,15 +170,25 @@ open (const char *filename, int flags, .
      with ENOTDIR.  */
   if (fd >= 0)
     {
       /* We know len is positive, since open did not fail with ENOENT.  */
       size_t len = strlen (filename);
-      if (filename[len - 1] == '/')
+      if (ISSLASH(filename[len - 1]))
         {
+#ifdef __DJGPP__
+          /*
+           *  Computation of stat is very expensive.
+           *  To determinate if PATH is an existing
+           *  directory, access on DOS platforms is
+           *  mostly a fast system call.
+           */
+          if (access (filename, D_OK) == 0)
+#else
           struct stat statbuf;
 
           if (fstat (fd, &statbuf) >= 0 && !S_ISDIR (statbuf.st_mode))
+#endif
             {
               close (fd);
               errno = ENOTDIR;
               return -1;
             }
diff -aprNU5 grep-2.18.orig/lib/openat-proc.c grep-2.18/lib/openat-proc.c
--- grep-2.18.orig/lib/openat-proc.c	2014-01-02 02:32:06 +0100
+++ grep-2.18/lib/openat-proc.c	2014-03-20 21:15:00 +0100
@@ -64,20 +64,24 @@ openat_proc_name (char buf[OPENAT_BUFFER
       return buf;
     }
 
   if (! proc_status)
     {
+#ifdef __DJGPP__
+      int proc_self_fd = -1;
+#else
       /* Set PROC_STATUS to a positive value if /proc/self/fd is
          reliable, and a negative value otherwise.  Solaris 10
          /proc/self/fd mishandles "..", and any file name might expand
          to ".." after symbolic link expansion, so avoid /proc/self/fd
          if it mishandles "..".  Solaris 10 has openat, but this
          problem is exhibited on code that built on Solaris 8 and
          running on Solaris 10.  */
 
       int proc_self_fd = open ("/proc/self/fd",
                                O_SEARCH | O_DIRECTORY | O_NOCTTY | O_NONBLOCK);
+#endif
       if (proc_self_fd < 0)
         proc_status = -1;
       else
         {
           /* Detect whether /proc/self/fd/%i/../fd exists, where %i is the
diff -aprNU5 grep-2.18.orig/lib/progname.c grep-2.18/lib/progname.c
--- grep-2.18.orig/lib/progname.c	2014-01-02 02:32:06 +0100
+++ grep-2.18/lib/progname.c	2014-03-20 21:15:00 +0100
@@ -25,10 +25,39 @@
 #include <errno.h> /* get program_invocation_name declaration */
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
+/* MS-DOS and similar non-Posix systems have some peculiarities:
+    - they use both `/' and `\\' as directory separator in file names;
+    - they can have a drive letter X: prepended to a file name;
+   These are all parameterized here.  */
+
+#ifdef MSDOS
+# include <libc/unconst.h>
+# undef  IS_SLASH
+# define IS_SLASH(c)  ((c) == '/' || (c) == '\\' || (c) == ':')
+# define GET_LAST_SLASH(filename)              \
+  (__extension__                               \
+    ({                                         \
+      char *_slash = NULL;                     \
+      if ((filename))                          \
+      {                                        \
+        _slash = unconst((filename), char *);  \
+        while (*_slash++)                      \
+          ;                                    \
+        while ((--_slash - (filename)))        \
+          if (IS_SLASH(*_slash))               \
+            break;                             \
+      }                                        \
+      _slash;                                  \
+    })                                         \
+  )
+#else
+# define GET_LAST_SLASH(filename)  (strrchr((filename), '/'))
+#endif
+
 
 /* String containing name the program is called with.
    To be initialized by main().  */
 const char *program_name = NULL;
 
@@ -54,13 +83,21 @@ set_program_name (const char *argv0)
       fputs ("A NULL argv[0] was passed through an exec system call.\n",
              stderr);
       abort ();
     }
 
-  slash = strrchr (argv0, '/');
+  slash = GET_LAST_SLASH (argv0);
   base = (slash != NULL ? slash + 1 : argv0);
-  if (base - argv0 >= 7 && strncmp (base - 7, "/.libs/", 7) == 0)
+  if (base - argv0 >= 7 && (strncmp (base - 7, "/.libs/", 7) == 0
+#ifdef MSDOS
+     || strncmp (base - 7, "\\.libs/", 7) == 0
+     || strncmp (base - 7, "\\.libs\\", 7) == 0
+     || strncmp (base - 7, "/_libs/", 7) == 0
+     || strncmp (base - 7, "\\_libs/", 7) == 0
+     || strncmp (base - 7, "\\_libs\\", 7) == 0
+#endif
+     ))
     {
       argv0 = base;
       if (strncmp (base, "lt-", 3) == 0)
         {
           argv0 = base + 3;
diff -aprNU5 grep-2.18.orig/src/dfa.c grep-2.18/src/dfa.c
--- grep-2.18.orig/src/dfa.c	2014-02-21 07:23:40 +0100
+++ grep-2.18/src/dfa.c	2014-03-20 21:37:32 +0100
@@ -49,11 +49,11 @@
 /* gettext.h ensures that we don't use gettext if ENABLE_NLS is not defined */
 #include "gettext.h"
 #define _(str) gettext (str)
 
 #include "mbsupport.h" /* Define MBS_SUPPORT to 1 or 0, as appropriate.  */
-#if MBS_SUPPORT
+#if MBS_SUPPORT || defined(__DJGPP__)
 /* We can handle multibyte strings.  */
 # include <wchar.h>
 # include <wctype.h>
 #endif
 
@@ -630,11 +630,11 @@ static charclass letters;
 static charclass newline;
 
 /* Add this to the test for whether a byte is word-constituent, since on
    BSD-based systems, many values in the 128..255 range are classified as
    alphabetic, while on glibc-based systems, they are not.  */
-#ifdef __GLIBC__
+#if defined(__GLIBC__) || defined(MBS_SUPPORT) && MBS_SUPPORT == 0
 # define is_valid_unibyte_character(c) 1
 #else
 # define is_valid_unibyte_character(c) (! (MBS_SUPPORT && btowc (c) == WEOF))
 #endif
 
@@ -650,19 +650,21 @@ char_context (unsigned char c)
   if (IS_WORD_CONSTITUENT (c))
     return CTX_LETTER;
   return CTX_NONE;
 }
 
+#if MBS_SUPPORT
 static int
 wchar_context (wint_t wc)
 {
   if (wc == (wchar_t) eolbyte || wc == 0)
     return CTX_NEWLINE;
   if (wc == L'_' || iswalnum (wc))
     return CTX_LETTER;
   return CTX_NONE;
 }
+#endif /* MBS_SUPPORT */
 
 /* Entry point to set syntax options.  */
 void
 dfasyntax (reg_syntax_t bits, int fold, unsigned char eol)
 {
@@ -730,20 +732,22 @@ setbit_wc (wint_t wc, charclass c)
    and the caller takes care of setting the appropriate field of struct
    mb_char_classes.  */
 static void
 setbit_case_fold_c (int b, charclass c)
 {
+#if MBS_SUPPORT
   if (MB_CUR_MAX > 1)
     {
       wint_t wc = btowc (b);
       if (wc == WEOF)
         return;
       setbit (b, c);
       if (case_fold && iswalpha (wc))
         setbit_wc (iswupper (wc) ? towlower (wc) : towupper (wc), c);
     }
   else
+#endif /* MBS_SUPPORT */
     {
       setbit (b, c);
       if (case_fold && isalpha (b))
         setbit_c (isupper (b) ? tolower (b) : toupper (b), c);
     }
@@ -934,10 +938,11 @@ parse_bracket_exp (void)
     equivs_al, coll_elems_al;
 
   chars_al = 0;
   range_sts_al = range_ends_al = 0;
   ch_classes_al = equivs_al = coll_elems_al = 0;
+#if MBS_SUPPORT
   if (MB_CUR_MAX > 1)
     {
       REALLOC_IF_NECESSARY (dfa->mbcsets, dfa->mbcsets_alloc,
                             dfa->nmbcsets + 1);
 
@@ -948,10 +953,11 @@ parse_bracket_exp (void)
       /* Initialize work area.  */
       work_mbc = &(dfa->mbcsets[dfa->nmbcsets++]);
       memset (work_mbc, 0, sizeof *work_mbc);
     }
   else
+#endif /* MBS_SUPPORT */
     work_mbc = NULL;
 
   memset (ccl, 0, sizeof ccl);
   FETCH_WC (c, wc, _("unbalanced ["));
   if (c == '^')
@@ -1007,26 +1013,29 @@ parse_bracket_exp (void)
                                      || STREQ (str, "lower")) ? "alpha" : str);
                   const struct dfa_ctype *pred = find_pred (class);
                   if (!pred)
                     dfaerror (_("invalid character class"));
 
+#if MBS_SUPPORT
                   if (MB_CUR_MAX > 1 && !pred->single_byte_only)
                     {
                       /* Store the character class as wctype_t.  */
                       wctype_t wt = wctype (class);
 
                       REALLOC_IF_NECESSARY (work_mbc->ch_classes,
                                             ch_classes_al,
                                             work_mbc->nch_classes + 1);
                       work_mbc->ch_classes[work_mbc->nch_classes++] = wt;
                     }
+#endif /* MBS_SUPPORT */
 
                   for (c2 = 0; c2 < NOTCHAR; ++c2)
                     if (pred->func (c2))
                       setbit_case_fold_c (c2, ccl);
                 }
 
+#if MBS_SUPPORT
               else if (MBS_SUPPORT && (c1 == '=' || c1 == '.'))
                 {
                   char *elem = xmemdup (str, len + 1);
 
                   if (c1 == '=')
@@ -1044,10 +1053,11 @@ parse_bracket_exp (void)
                                             coll_elems_al,
                                             work_mbc->ncoll_elems + 1);
                       work_mbc->coll_elems[work_mbc->ncoll_elems++] = elem;
                     }
                 }
+#endif /* MBS_SUPPORT */
               colon_warning_state |= 8;
 
               /* Fetch new lookahead character.  */
               FETCH_WC (c1, wc1, _("unbalanced ["));
               continue;
@@ -1079,10 +1089,11 @@ parse_bracket_exp (void)
       if (c1 == '-' && c2 != ']')
         {
           if (c2 == '\\' && (syntax_bits & RE_BACKSLASH_ESCAPE_IN_LISTS))
             FETCH_WC (c2, wc2, _("unbalanced ["));
 
+#if MBS_SUPPORT
           if (MB_CUR_MAX > 1)
             {
               /* When case folding map a range, say [m-z] (or even [M-z])
                  to the pair of ranges, [m-z] [M-Z].  */
               REALLOC_IF_NECESSARY (work_mbc->range_sts,
@@ -1103,10 +1114,11 @@ parse_bracket_exp (void)
                                         range_ends_al, work_mbc->nranges + 1);
                   work_mbc->range_ends[work_mbc->nranges++] = towupper (wc2);
                 }
             }
           else
+#endif /* MBS_SUPPORT */
             {
               /* Defer to the system regex library about the meaning
                  of range expressions.  */
               struct re_pattern_buffer re = { 0 };
               char const *compile_msg;
@@ -1169,17 +1181,19 @@ parse_bracket_exp (void)
   while ((wc = wc1, (c = c1) != ']'));
 
   if (colon_warning_state == 7)
     dfawarn (_("character class syntax is [[:space:]], not [:space:]"));
 
+#if MBS_SUPPORT
   if (MB_CUR_MAX > 1)
     {
       static charclass zeroclass;
       work_mbc->invert = invert;
       work_mbc->cset = equal (ccl, zeroclass) ? -1 : charclass_index (ccl);
       return MBCSET;
     }
+#endif /* MBS_SUPPORT */
 
   if (invert)
     {
       assert (MB_CUR_MAX == 1);
       notset (ccl);
@@ -1204,17 +1218,19 @@ lex (void)
      main switch inside the backslash case.  On the minus side,
      it means that just about every case begins with
      "if (backslash) ...".  */
   for (i = 0; i < 2; ++i)
     {
+#if MBS_SUPPORT
       if (MB_CUR_MAX > 1)
         {
           FETCH_WC (c, wctok, NULL);
           if ((int) c == EOF)
             goto normal_char;
         }
       else
+#endif /* MBS_SUPPORT */
         FETCH (c, NULL);
 
       switch (c)
         {
         case '\\':
@@ -1410,17 +1426,19 @@ lex (void)
           return lasttok = RPAREN;
 
         case '.':
           if (backslash)
             goto normal_char;
+#if MBS_SUPPORT
           if (MB_CUR_MAX > 1)
             {
               /* In multibyte environment period must match with a single
                  character not a byte.  So we use ANYCHAR.  */
               laststart = 0;
               return lasttok = ANYCHAR;
             }
+#endif /* MBS_SUPPORT */
           zeroset (ccl);
           notset (ccl);
           if (!(syntax_bits & RE_DOT_NEWLINE))
             clrbit (eolbyte, ccl);
           if (syntax_bits & RE_DOT_NOT_NULL)
@@ -1493,14 +1511,16 @@ lex (void)
           return lasttok = parse_bracket_exp ();
 
         default:
         normal_char:
           laststart = 0;
+#if MBS_SUPPORT
           /* For multibyte character sets, folding is done in atom.  Always
              return WCHAR.  */
           if (MB_CUR_MAX > 1)
             return lasttok = WCHAR;
+#endif /* MBS_SUPPORT */
 
           if (case_fold && isalpha (c))
             {
               zeroset (ccl);
               setbit_case_fold_c (c, ccl);
@@ -1527,16 +1547,18 @@ static size_t depth;            /* Curre
                                    dfaanalyze.  */
 
 static void
 addtok_mb (token t, int mbprop)
 {
+#if MBS_SUPPORT
   if (MB_CUR_MAX > 1)
     {
       REALLOC_IF_NECESSARY (dfa->multibyte_prop, dfa->nmultibyte_prop,
                             dfa->tindex + 1);
       dfa->multibyte_prop[dfa->tindex] = mbprop;
     }
+#endif /* MBS_SUPPORT */
 
   REALLOC_IF_NECESSARY (dfa->tokens, dfa->talloc, dfa->tindex + 1);
   dfa->tokens[dfa->tindex++] = t;
 
   switch (t)
@@ -1566,10 +1588,11 @@ static void addtok_wc (wint_t wc);
 /* Add the given token to the parse tree, maintaining the depth count and
    updating the maximum depth if necessary.  */
 static void
 addtok (token t)
 {
+#if MBS_SUPPORT
   if (MB_CUR_MAX > 1 && t == MBCSET)
     {
       bool need_or = false;
       struct mb_char_classes *work_mbc = &dfa->mbcsets[dfa->nmbcsets - 1];
 
@@ -1612,10 +1635,11 @@ addtok (token t)
                 addtok (OR);
             }
         }
     }
   else
+#endif /* MBS_SUPPORT */
     {
       addtok_mb (t, 3);
     }
 }
 
@@ -1647,15 +1671,17 @@ addtok_wc (wint_t wc)
       addtok_mb (buf[i], i == cur_mb_len - 1 ? 2 : 0);
       addtok (CAT);
     }
 }
 #else
+#ifndef __DJGPP__
 static void
 addtok_wc (wint_t wc)
 {
 }
 #endif
+#endif
 
 static void
 add_utf8_anychar (void)
 {
 #if MBS_SUPPORT
@@ -1746,10 +1772,11 @@ atom (void)
 {
   if (0)
     {
       /* empty */
     }
+#if MBS_SUPPORT
   else if (MBS_SUPPORT && tok == WCHAR)
     {
       addtok_wc (case_fold ? towlower (wctok) : wctok);
       if (case_fold && iswalpha (wctok))
         {
@@ -1769,10 +1796,11 @@ atom (void)
          UTF-8: it is the most used, and the structure of the encoding
          makes the correctness more obvious.  */
       add_utf8_anychar ();
       tok = lex ();
     }
+#endif /* MBS_SUPPORT */
   else if ((tok >= 0 && tok < NOTCHAR) || tok >= CSET || tok == BACKREF
            || tok == BEGLINE || tok == ENDLINE || tok == BEGWORD
 #if MBS_SUPPORT
            || tok == ANYCHAR || tok == MBCSET
 #endif /* MBS_SUPPORT */
@@ -1818,14 +1846,16 @@ nsubtoks (size_t tindex)
 static void
 copytoks (size_t tindex, size_t ntokens)
 {
   size_t i;
 
+#if MBS_SUPPORT
   if (MB_CUR_MAX > 1)
     for (i = 0; i < ntokens; ++i)
       addtok_mb (dfa->tokens[tindex + i], dfa->multibyte_prop[tindex + i]);
   else
+#endif /* MBS_SUPPORT */
     for (i = 0; i < ntokens; ++i)
       addtok_mb (dfa->tokens[tindex + i], 3);
 }
 
 static void
@@ -1903,15 +1933,17 @@ dfaparse (char const *s, size_t len, str
   lexptr = s;
   lexleft = len;
   lasttok = END;
   laststart = 1;
   parens = 0;
+#if MBS_SUPPORT
   if (MB_CUR_MAX > 1)
     {
       cur_mb_len = 0;
       memset (&mbs, 0, sizeof mbs);
     }
+#endif /* MBS_SUPPORT */
 
   if (!syntax_bits_set)
     dfaerror (_("no syntax specified"));
 
   tok = lex ();
@@ -2056,15 +2088,19 @@ state_index (struct dfa *d, position_set
   copy (s, &d->states[i].elems);
   d->states[i].context = context;
   d->states[i].backref = 0;
   d->states[i].constraint = 0;
   d->states[i].first_end = 0;
+
+#if MBS_SUPPORT
   if (MBS_SUPPORT)
     {
       d->states[i].mbps.nelem = 0;
       d->states[i].mbps.elems = NULL;
     }
+#endif /* MBS_SUPPORT */
+
   for (j = 0; j < s->nelem; ++j)
     if (d->tokens[s->elems[j].index] < 0)
       {
         constraint = s->elems[j].constraint;
         if (SUCCEEDS_IN_CONTEXT (constraint, context, CTX_ANY))
@@ -2530,10 +2566,11 @@ dfastate (state_num s, struct dfa *d, st
       pos = d->states[s].elems.elems[i];
       if (d->tokens[pos.index] >= 0 && d->tokens[pos.index] < NOTCHAR)
         setbit (d->tokens[pos.index], matches);
       else if (d->tokens[pos.index] >= CSET)
         copyset (d->charclasses[d->tokens[pos.index] - CSET], matches);
+#if MBS_SUPPORT
       else if (MBS_SUPPORT
                && (d->tokens[pos.index] == ANYCHAR
                    || d->tokens[pos.index] == MBCSET))
         /* MB_CUR_MAX > 1  */
         {
@@ -2543,10 +2580,11 @@ dfastate (state_num s, struct dfa *d, st
           if (d->states[s].mbps.nelem == 0)
             alloc_position_set (&d->states[s].mbps, 1);
           insert (pos, &(d->states[s].mbps));
           continue;
         }
+#endif /* MBS_SUPPORT */
       else
         continue;
 
       /* Some characters may need to be eliminated from matches because
          they fail in the current context.  */
@@ -2672,10 +2710,11 @@ dfastate (state_num s, struct dfa *d, st
          This is a hideously inefficient loop.  Fix it someday.  */
       for (j = 0; j < grps[i].nelem; ++j)
         for (k = 0; k < d->follows[grps[i].elems[j]].nelem; ++k)
           insert (d->follows[grps[i].elems[j]].elems[k], &follows);
 
+#if MBS_SUPPORT
       if (d->mb_cur_max > 1)
         {
           /* If a token in follows.elems is not 1st byte of a multibyte
              character, or the states of follows must accept the bytes
              which are not 1st byte of the multibyte character.
@@ -2702,10 +2741,11 @@ dfastate (state_num s, struct dfa *d, st
                   next_isnt_1st_byte = 1;
                   break;
                 }
             }
         }
+#endif /* MBS_SUPPORT */
 
       /* If we are building a searching matcher, throw in the positions
          of state 0 as well.  */
       if (d->searchflag
           && (!MBS_SUPPORT || (d->mb_cur_max == 1 || !next_isnt_1st_byte)))
@@ -2840,10 +2880,11 @@ build_state_zero (struct dfa *d)
   MALLOC (d->success, d->tralloc);
   MALLOC (d->newlines, d->tralloc);
   build_state (0, d);
 }
 
+#if MBS_SUPPORT
 /* Multibyte character handling sub-routines for dfaexec.  */
 
 /* The initial state may encounter a byte which is not a single byte character
    nor the first byte of a multibyte character.  But it is incorrect for the
    initial state to accept such a byte.  For example, in Shift JIS the regular
@@ -3301,10 +3342,11 @@ prepare_wc_buf (const char *begin, const
   buf_end = (unsigned char *) (begin + i);
   mblen_buf[i] = 0;
   inputwcs[i] = 0;              /* sentinel */
 #endif /* MBS_SUPPORT */
 }
+#endif /* MBS_SUPPORT */
 
 /* Search through a buffer looking for a match to the given struct dfa.
    Find the first occurrence of a string matching the regexp in the
    buffer, and the shortest possible version thereof.  Return a pointer to
    the first character after the match, or NULL if none is found.  BEGIN
@@ -3334,20 +3376,23 @@ dfaexec (struct dfa *d, char const *begi
   p = (unsigned char const *) begin;
   trans = d->trans;
   saved_end = *(unsigned char *) end;
   *end = eol;
 
+#if MBS_SUPPORT
   if (d->mb_cur_max > 1)
     {
       MALLOC (mblen_buf, end - begin + 2);
       MALLOC (inputwcs, end - begin + 2);
       memset (&mbs, 0, sizeof (mbstate_t));
       prepare_wc_buf ((const char *) p, end);
     }
+#endif /* MBS_SUPPORT */
 
   for (;;)
     {
+#if MBS_SUPPORT
       if (d->mb_cur_max > 1)
         {
           while ((t = trans[s]) != NULL)
             {
               if (p > buf_end)
@@ -3379,10 +3424,11 @@ dfaexec (struct dfa *d, char const *begi
               s = transit_state (d, s, &p);
               trans = d->trans;
             }
         }
       else
+#endif /* MBS_SUPPORT */
         {
           while ((t = trans[s]) != NULL)
             {
               s1 = t[*p++];
               if ((t = trans[s1]) == NULL)
@@ -3410,40 +3456,46 @@ dfaexec (struct dfa *d, char const *begi
               *end = saved_end;
               return (char *) p;
             }
 
           s1 = s;
+#if MBS_SUPPORT
           if (d->mb_cur_max > 1)
             {
               /* Can match with a multibyte character (and multicharacter
                  collating element).  Transition table might be updated.  */
               s = transit_state (d, s, &p);
               trans = d->trans;
             }
           else
+#endif /* MBS_SUPPORT */
             s = d->fails[s][*p++];
           continue;
         }
 
       /* If the previous character was a newline, count it.  */
       if ((char *) p <= end && p[-1] == eol)
         {
           if (count)
             ++*count;
 
+#if MBS_SUPPORT
           if (d->mb_cur_max > 1)
             prepare_wc_buf ((const char *) p, end);
+#endif /* MBS_SUPPORT */
         }
 
       /* Check if we've run off the end of the buffer.  */
       if ((char *) p > end)
         {
+#if MBS_SUPPORT
           if (d->mb_cur_max > 1)
             {
               free (mblen_buf);
               free (inputwcs);
             }
+#endif /* MBS_SUPPORT */
           *end = saved_end;
           return NULL;
         }
 
       if (s >= 0)
@@ -3507,17 +3559,19 @@ dfainit (struct dfa *d)
   d->talloc = 1;
   MALLOC (d->tokens, d->talloc);
 
   d->mb_cur_max = MB_CUR_MAX;
 
+#if MBS_SUPPORT
   if (d->mb_cur_max > 1)
     {
       d->nmultibyte_prop = 1;
       MALLOC (d->multibyte_prop, d->nmultibyte_prop);
       d->mbcsets_alloc = 1;
       MALLOC (d->mbcsets, d->mbcsets_alloc);
     }
+#endif /* MBS_SUPPORT */
 }
 
 static void
 dfaoptimize (struct dfa *d)
 {
@@ -3564,12 +3618,14 @@ dfafree (struct dfa *d)
   struct dfamust *dm, *ndm;
 
   free (d->charclasses);
   free (d->tokens);
 
+#if MBS_SUPPORT
   if (d->mb_cur_max > 1)
     free_mbdata (d);
+#endif /* MBS_SUPPORT */
 
   for (i = 0; i < d->sindex; ++i)
     {
       free (d->states[i].elems.elems);
       if (MBS_SUPPORT)
diff -aprNU5 grep-2.18.orig/src/dosbuf.c grep-2.18/src/dosbuf.c
--- grep-2.18.orig/src/dosbuf.c	2014-01-02 02:31:50 +0100
+++ grep-2.18/src/dosbuf.c	2014-03-20 21:45:36 +0100
@@ -15,23 +15,24 @@
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
    02110-1301, USA.  */
 
 /* Messy DOS-specific code for correctly treating binary, Unix text
-   and DOS text files.
+   and DOS text files, and for emulating a Posix terminal driver
+   wrt SGR (a.k.a. ANSI) color escape sequences.
 
    This has several aspects:
 
      * Guessing the file type (unless the user tells us);
      * Stripping CR characters from DOS text files (otherwise regex
        functions won't work correctly);
      * Reporting correct byte count with -b for any kind of file.
+     * Redirecting output with ANSI color commands to direct screen
+       writes.
 
 */
 
-#include <config.h>
-
 typedef enum {
   UNKNOWN, DOS_BINARY, DOS_TEXT, UNIX_TEXT
 } File_type;
 
 struct dos_map {
@@ -196,5 +197,347 @@ dossified_pos (off_t byteno)
         out_map_idx--;
     }
 
   return byteno + dos_pos_map[out_map_idx].add;
 }
+
+#ifdef __DJGPP__
+/*  Screen write redirection.  We need this to support colorization
+    without requiring ANSI.SYS driver (or its work-alike) to be loaded.
+
+    This function uses the DJGPP filesystem extensions mechanism.  It is
+    installed as a handler for handle-based functions (read/write/close)
+    for the standard output (but actually only handles writes, only if
+    the standard output is connected to the terminal, and only if user
+    asked for colorization).  When a buffer is written to the screen by
+    low-level functions of the DJGPP C library, our handler will be
+    called.  For any request that doesn't require colored screen writes
+    we return a zero to the caller, in which case the caller will handle
+    the output in the usual way (by eventually calling DOS).
+
+    When colorization *is* required, the buffer is written directly to
+    the screen while converting the ANSI escape sequences into calls to
+    DJGPP conio functions which change text attributes.  A non-zero value is
+    then returned to the caller to signal that the output has been handled.
+*/
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <unistd.h>
+#include <conio.h>
+#include <sys/fsext.h>
+#include <go32.h> /* for `_dos_ds' */
+#include <sys/farptr.h>
+#include <pc.h> /* for `ScreenGetCursor' */
+
+static int norm_blink = -1, cur_blink = -1;
+static unsigned char norm_attr = 0, cur_attr = 0;
+static int isatty_stdout = -1;
+static size_t leftover = 0;
+
+/* Restore the BIOS blinking bit to its original value.  Called at exit.  */
+static void
+restore_blink_bit (void)
+{
+  if (cur_blink != norm_blink)
+    {
+      if (norm_blink > 0)
+        blinkvideo ();
+      else
+        intensevideo ();
+    }
+}
+
+/* Write a buffer to the screen video memory.  This expands the TAB
+   characters to the appropriate number of spaces, and also does TRT
+   with null characters and other non-printable characters, if
+   any.  */
+static void
+screen_puts (char *buf, char *buf_end)
+{
+  register char *p = buf, *q = p;
+  int row, col;
+  unsigned char c;
+
+  while (p < buf_end)
+    {
+      if (*p < ' ')
+        {
+          switch (*p)
+            {
+              case '\b':
+              case '\r':
+              case '\n':
+                /* nothing: cputs already does TRT with these */
+                break;
+              case '\t':
+                *p = '\0';
+                cputs (q);
+                ScreenGetCursor (&row, &col);
+                for (cputs (" "), col += 1; col % 8; col++)
+                  cputs (" ");
+                q = p + 1;
+                *p = '\t';
+                break;
+              default:
+                c = *p;
+                *p = '\0';
+                cputs (q);
+                cputs ("^");
+                putch (c | 0x40);
+                q = p + 1;
+                *p = c;
+                break;
+            }
+        }
+      p++;
+    }
+  /* Output whatever is left.  */
+  cputs (q);
+}
+
+#define ESC '\033'
+#define IS_SGR(s) (((s)[1] == '[') && ((s)[2] == 'm'))
+#define IS_EL(s)  (((s)[1] == '[') && ((s)[2] == 'K'))
+
+/* Screen writes redirector function.  */
+static int
+msdos_screen_write (__FSEXT_Fnumber func, int *retval, va_list rest_args)
+{
+  static char *cbuf = NULL;
+  static size_t cbuf_len = 0;
+  /* Only dark colors mentioned here, so that bold has visible effect.  */
+  static enum COLORS screen_color[] = {
+    BLACK,
+    RED,
+    GREEN,
+    BROWN,
+    BLUE,
+    MAGENTA,
+    CYAN,
+    LIGHTGRAY
+  };
+  char *anchor, *p_next;
+  unsigned char fg, bg;
+
+  int handle;
+  char *buf, *buf_end;
+  size_t buflen;
+
+  /* Avoid direct screen writes unless colorization was actually requested.
+     Otherwise, we will break programs that catch I/O from their children.  */
+  handle = va_arg (rest_args, int);
+  if (!color_option || func != __FSEXT_write ||
+       !(handle == STDOUT_FILENO ? isatty_stdout : isatty (handle)))
+    return 0;
+
+  buf = va_arg (rest_args, char *);
+  if (!buf)
+    {
+      errno = EINVAL;
+      *retval = -1;
+      return 1;
+    }
+
+  /* Allocate a sufficiently large buffer to hold the output.  */
+  buflen = va_arg (rest_args, size_t);
+  if (!cbuf)
+    {
+      struct text_info txtinfo;
+
+      cbuf_len = buflen + 1;
+      cbuf = (char *)xmalloc (cbuf_len);
+      gettextinfo (&txtinfo);
+      norm_attr = txtinfo.attribute; /* save the original text attribute */
+      cur_attr = norm_attr;
+      /* Does it normally blink when bg has its 3rd bit set?  */
+      norm_blink = (_farpeekb (_dos_ds, 0x465) & 0x20) ? 1 : 0;
+      cur_blink = norm_blink;
+    }
+  else if (buflen >= cbuf_len)
+    {
+      cbuf_len = buflen + 1 + leftover;
+      cbuf = (char *)xrealloc (cbuf, cbuf_len);
+    }
+  memcpy (cbuf + leftover, buf, buflen);
+  buf_end = cbuf + buflen + leftover;
+  *buf_end = '\0';
+
+  /* Current text attributes are used as baseline.  */
+  fg = cur_attr & 15;
+  bg = (cur_attr >> 4) & 15;
+
+  /* Walk the buffer, writing text directly to video RAM,
+     changing color attributes when an escape sequence is seen.  */
+  for (anchor = p_next = cbuf;
+       (p_next = memchr (p_next, ESC, buflen - (p_next - cbuf))) != 0; )
+    {
+      char *p = p_next;
+
+      /* If some chars seen since the last escape sequence,
+         write it out to the screen using current text attributes.  */
+      if (p > anchor)
+        {
+          *p = '\0'; /* `cputs' needs ASCIIZ string */
+          screen_puts (anchor, p);
+          *p = ESC; /* restore the ESC character */
+          anchor = p;
+        }
+
+      /* Handle the null escape sequence (ESC-[m), which is used to
+         restore the original color. */
+      if (IS_SGR(p))
+        {
+          textattr (norm_attr);
+          p += 3;
+          anchor = p_next = p;
+          continue;
+        }
+
+      /* Handle the erase in line to the right escape sequence (ESC-[K). */
+      if (IS_EL(p))
+        {
+          clreol();
+          p += 3;
+          anchor = p_next = p;
+          continue;
+        }
+
+      if (p[1] == '[') /* "Esc-[" sequence */
+        {
+          p += 2; /* get past "Esc-[" sequence */
+          p_next = p;
+          while (*p != 'm') /* `m' ends the escape sequence */
+            {
+              char *q;
+              long code = strtol (p, &q, 10);
+
+              if (!*q)
+                {
+                  /* Incomplete escape sequence.  Remember the part
+                     we've seen for the next time.  */
+                  leftover = q - anchor;
+                  if (leftover >= cbuf_len)
+                    {
+                      cbuf_len += 1 + leftover;
+                      cbuf = (char *)xrealloc (cbuf, cbuf_len);
+                    }
+                  strcpy (cbuf, anchor);
+                  *retval = buflen; /* that's a lie, but we have to! */
+                  return 1;
+                }
+
+              /* 
+                 Sanity checks:
+
+                 q > p unless p doesn't point to a number;
+                 SGR codes supported by ANSI.SYS are between 0 and 49;
+                 Each SGR code ends with a `;' or an `m'.
+
+                 If any of the above is violated, we just ignore the bogon.
+              */
+              if (q == p || code > 49 || code < 0 || (*q != 'm' && *q != ';'))
+                {
+                  p_next = q;
+                  break;
+                }
+              if (*q == ';') /* more codes to follow */
+                q++;
+
+              /* Convert ANSI codes to color fore- and background.  */
+              switch (code)
+                {
+                  case 0: /* all attributes off */
+                    fg = norm_attr & 15;
+                    bg = (norm_attr >> 4) & 15;
+                    break;
+                  case 1: /* intensity on */
+                    fg |= 8;
+                    break;
+                  case 4: /* underline on */
+                    fg |= 8; /* we can't, so make it bold instead */
+                    break;
+                  case 5: /* blink */
+                    if (cur_blink != 1)
+                      {
+                        blinkvideo (); /* ensure we are'nt in bright bg mode */
+                        cur_blink = 1;
+                      }
+                    bg |= 8;
+                    break;
+                  case 7: /* reverse video */
+                    {
+                      unsigned char t = fg;
+                      fg = bg;
+                      bg = t;
+
+                      /* If it was blinking before, let it blink after.  */
+                      if (fg & 8)
+                        bg |= 8;
+
+                      /* If the fg was bold, let the background be bold.  */
+                      if ((t & 8) && cur_blink != 0)
+                        {
+                          intensevideo ();
+                          cur_blink = 0;
+                        }
+                    }
+                    break;
+                  case 8: /* concealed on */
+                    fg = (bg & 7) | 8; /* make fg be like bg, only bright */
+                    break;
+                  case 30: case 31: case 32: case 33: /* foreground color */
+                  case 34: case 35: case 36: case 37:
+                    fg = (fg & 8) | (screen_color[code - 30] & 15);
+                    break;
+                  case 40: case 41: case 42: case 43: /* background color */
+                  case 44: case 45: case 46: case 47:
+                    bg = (bg & 8) | (screen_color[code - 40] & 15);
+                    break;
+                  case 39: /* default fg */
+                    fg = norm_attr & 15;
+                    break;
+                  case 49:
+                    bg = (norm_attr >> 4) & 15;
+                    break;
+                  default:
+                    p_next = q; /* ignore unknown codes */
+                    break;
+                }
+              p = q;
+            } /* while loop */
+
+          if (*p == 'm' && p > p_next)
+            {
+              /* They don't *really* want it invisible, do they?  */
+              if (fg == (bg & 7))
+                fg |= 8; /* make it concealed instead */
+
+              /* Construct the text attribute and set it.  */
+              cur_attr = (bg << 4) | fg;
+              textattr (cur_attr);
+              p_next = anchor = p + 1;
+            }
+          else
+            break;
+        }
+      else
+        p_next++;
+    }  /* for loop */
+
+  /* Output what's left in the buffer.  */
+  screen_puts (anchor, buf_end);
+  leftover = 0;
+  *retval = buflen;
+  return 1;
+}
+
+/* This is called before `main' to install our STDOUT redirector.  */
+static void __attribute__((constructor))
+djgpp_grep_startup (void)
+{
+  __FSEXT_set_function (STDOUT_FILENO, msdos_screen_write);
+  isatty_stdout = isatty (STDOUT_FILENO);
+  atexit (restore_blink_bit);
+}
+#endif  /* __DJGPP__ */
diff -aprNU5 grep-2.18.orig/src/main.c grep-2.18/src/main.c
--- grep-2.18.orig/src/main.c	2014-02-21 07:23:40 +0100
+++ grep-2.18/src/main.c	2014-03-20 21:46:26 +0100
@@ -54,10 +54,14 @@
 
 #define SEP_CHAR_SELECTED ':'
 #define SEP_CHAR_REJECTED '-'
 #define SEP_STR_GROUP    "--"
 
+#ifdef __DJGPP__
+# define IS_TERMINAL (isatty(STDOUT_FILENO))
+#endif
+
 #define AUTHORS \
   proper_name ("Mike Haertel"), \
   _("others, see <http://git.sv.gnu.org/cgit/grep.git/tree/AUTHORS>")
 
 /* When stdout is connected to a regular file, save its stat
@@ -1523,12 +1527,12 @@ grep_command_line_arg (char const *arg)
       filename = label ? label : _("(standard input)");
       return grepdesc (STDIN_FILENO, 1);
     }
   else
     {
-      filename = arg;
-      return grepfile (AT_FDCWD, arg, 1, 1);
+      filename = CANONICALIZE_PATH(arg);
+      return grepfile (AT_FDCWD, filename, 1, 1);
     }
 }
 
 _Noreturn void usage (int);
 void
@@ -1961,11 +1965,11 @@ main (int argc, char **argv)
   intmax_t default_context;
   FILE *fp;
   exit_failure = EXIT_TROUBLE;
   initialize_main (&argc, &argv);
   set_program_name (argv[0]);
-  program_name = argv[0];
+  program_name = STRIP_FULL_PATH_AND_EXTENSION(argv[0]);
 
   keys = NULL;
   keycc = 0;
   with_filenames = 0;
   eolbyte = '\n';
@@ -2098,11 +2102,11 @@ main (int argc, char **argv)
         keycc += cc;
         keys[keycc++] = '\n';
         break;
 
       case 'f':
-        fp = STREQ (optarg, "-") ? stdin : fopen (optarg, "r");
+        fp = STREQ (optarg, "-") ? stdin : fopen (CANONICALIZE_PATH(optarg), "r");
         if (!fp)
           error (EXIT_TROUBLE, errno, "%s", optarg);
         for (keyalloc = 1; keyalloc <= keycc + 1; keyalloc *= 2)
           ;
         keys = xrealloc (keys, keyalloc);
@@ -2275,11 +2279,15 @@ main (int argc, char **argv)
         break;
 
       }
 
   if (color_option == 2)
+#ifdef IS_TERMINAL
+    color_option = (IS_TERMINAL) ? 1 : 0;
+#else
     color_option = isatty (STDOUT_FILENO) && should_colorize ();
+#endif
   init_colorize ();
 
   /* POSIX says that -q overrides -l, which in turn overrides the
      other output options.  */
   if (exit_on_match)
diff -aprNU5 grep-2.18.orig/src/mbsupport.h grep-2.18/src/mbsupport.h
--- grep-2.18.orig/src/mbsupport.h	2014-01-02 02:31:50 +0100
+++ grep-2.18/src/mbsupport.h	2014-03-20 21:47:22 +0100
@@ -17,10 +17,14 @@
    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
    02110-1301, USA.  */
 
 #include <stdlib.h>
 
+#ifdef __DJGPP__
+# define MBS_SUPPORT 0
+#endif
+
 #ifndef MBS_SUPPORT
 # define MBS_SUPPORT 1
 #endif
 
 #if ! MBS_SUPPORT
diff -aprNU5 grep-2.18.orig/src/system.h grep-2.18/src/system.h
--- grep-2.18.orig/src/system.h	2014-02-08 19:04:28 +0100
+++ grep-2.18/src/system.h	2014-03-20 21:47:22 +0100
@@ -29,10 +29,74 @@
 #include "minmax.h"
 #include "same-inode.h"
 
 #if O_BINARY
 # define HAVE_DOS_FILE_CONTENTS 1
+# if __DJGPP__ == 2
+#  if __DJGPP_MINOR__ < 4
+/* Has dir eacces bug.  */
+#   ifdef EISDIR
+#    define is_EISDIR(e, f) \
+       ((e) == EISDIR \
+        || ((e) == EACCES && isdir(f) && ((e) = EISDIR, 1)))
+#   else
+#    define is_EISDIR(e, f)  ((e) == EACCES && isdir (f))
+#   endif
+#  endif  /* __DJGPP_MINOR__ < 4  */
+
+#  include <libc/unconst.h>
+#  define IS_DIR_SEPARATOR(c)  ((c) == '/' || (c) == '\\' || (c) == ':')
+#  define STRIP_FULL_PATH_AND_EXTENSION(file_name)     \
+   (__extension__                                      \
+     ({                                                \
+        char *_dst, *_src;                             \
+        _dst = _src = unconst((file_name), char *);    \
+        while (*_src++)                                \
+          ;                                            \
+        while ((_src - _dst) && (*--_src != '.'))      \
+          ;                                            \
+        for (*_src = '\0'; (_src - _dst); _src--)      \
+          if (IS_DIR_SEPARATOR(*_src))                 \
+            break;                                     \
+        if (_src - _dst)                               \
+          while ((*_dst++ = *++_src))                  \
+            ;                                          \
+        (file_name);                                   \
+     })                                                \
+   )
+#  define STRIP_EXTENSION(file_name)                   \
+   (__extension__                                      \
+     ({                                                \
+        char *_begin, *_end;                           \
+        _begin = _end = unconst((file_name), char *);  \
+        while (*_end++)                                \
+          ;                                            \
+        while ((_end - _begin) && (*--_end != '.'))    \
+          ;                                            \
+        if (*_end == '.')                              \
+          *_end = '\0';                                \
+        (file_name);                                   \
+     })                                                \
+   )
+#  define CANONICALIZE_PATH(path)                      \
+   (__extension__                                      \
+     ({                                                \
+        if ((path))                                    \
+        {                                              \
+          char *_p = unconst((path), char *);          \
+          for (; *_p; _p++)                            \
+            if (*_p == '\\')                           \
+              *_p = '/';                               \
+        }                                              \
+        (path);                                        \
+     })                                                \
+   )
+# else  /* !__DJGPP__  */
+#  define STRIP_FULL_PATH_AND_EXTENSION(file_name)  (file_name)
+#  define STRIP_EXTENSION(file_name)                (file_name)
+#  define CANONICALIZE_PATH(path)                   (path)
+# endif  /* !__DJGPP__  */
 #endif
 
 #include <stdlib.h>
 #include <stddef.h>
 #include <limits.h>
