diff -Naurp grep/ChangeLog grep_new/ChangeLog
--- grep/ChangeLog	2005-02-26 16:25:57.000000000 +0100
+++ grep_new/ChangeLog	2005-03-07 14:49:26.000000000 +0100
@@ -1,3 +1,45 @@
+2005-03-02  Claudio Fontana  <sick_soul@users.sourceforge.net>
+	* src/grep.c :
+	  began code cleanup and restructure.
+	  - Big cut in main(), implemented grep actions with priority support,
+	    new functions to do what main did before.
+
+	  - Began restructuring the grep recursion;
+	    moved from [grepfile, grep, grepdir]
+	    to [action_grep, grep_parameter, grep_stdin, grep_fd, grep_dir]
+
+	    Implemented grep_result function to 
+	    convert a count return value into a grep status.
+
+	  - Removed everything about option parsing, and thus removed
+	    #include "getopt.h"
+
+	* src/grep.h : former static function setmatcher() has been exposed.
+
+	* src/grepopt.c (newfile) : does everything regarding option
+	  initialization and parsing.
+	* src/grepopt.h (newfile) : declares wrapper struct for all options.
+	  match_icase, match_words, match_lines and eolbyte, exposed by grep.h,
+	  are excluded.
+
+	* src/grep.c : removed direct include of dosbuf.c, which now gets
+	  compiled separately. Added params to undossify_input().
+	  undossify_input() and dossified_pos() have been made extern to
+	  realize interface.
+	* src/dosbuf.c : likewise.
+	* src/dosbuf.h : likewise.
+	
+	* src/grep.c : --exclude, --exclude-from and --include now concern
+	  directories too. Fixes bug #11017
+	* lib/savedir.c : likewise (waiting for gnulib update)
+
+	* src/grep.c : unblobbed prline(), added prline_part() function,
+	  removed special handling for match_icase. Includes ideas from
+	  patch #3770 (prline_head())
+
+	* src/Makefile.am: added entries for new files
+	* po/POTFILES.in: added entries for new files requiring translation
+	
 2005-02-26  Stepan Kasal  <kasal@ucw.cz>
 
 	* src/grep.c (get_nondigit_option): Don't give up too early.
diff -Naurp grep/lib/posix/regex.h grep_new/lib/posix/regex.h
--- grep/lib/posix/regex.h	2001-04-02 19:56:50.000000000 +0200
+++ grep_new/lib/posix/regex.h	2005-03-06 22:34:02.000000000 +0100
@@ -109,6 +109,10 @@ typedef unsigned long int reg_syntax_t;
    If not set, \{, \}, {, and } are literals.  */
 #define RE_INTERVALS (RE_HAT_LISTS_NOT_NEWLINE << 1)
 
+/* If this bit is set, then ignore case when matching.
+   If not set, then case is significant.  */
+#define RE_ICASE (RE_INVALID_INTERVAL_ORD << 1)
+
 /* If this bit is set, +, ? and | aren't recognized as operators.
    If not set, they are.  */
 #define RE_LIMITED_OPS (RE_INTERVALS << 1)
diff -Naurp grep/lib/savedir.c grep_new/lib/savedir.c
--- grep/lib/savedir.c	2001-03-04 06:33:12.000000000 +0100
+++ grep_new/lib/savedir.c	2005-03-02 03:24:37.000000000 +0100
@@ -133,8 +133,7 @@ savedir (const char *dir, off_t name_siz
 	{
 	  off_t size_needed = (namep - name_space) + NAMLEN (dp) + 2;
 
-	  if ((included_patterns || excluded_patterns)
-	      && !isdir1 (dir, dp->d_name))
+	  if (included_patterns || excluded_patterns)
 	    {
 	      if (included_patterns
 		  && !excluded_filename (included_patterns, dp->d_name, 0))
diff -Naurp grep/po/POTFILES.in grep_new/po/POTFILES.in
--- grep/po/POTFILES.in	2001-03-04 06:42:36.000000000 +0100
+++ grep_new/po/POTFILES.in	2005-03-02 13:56:31.000000000 +0100
@@ -3,6 +3,7 @@
 src/dfa.c
 src/kwset.c
 src/grep.c
+src/grepopt.c
 src/search.c
 
 # Library files
diff -Naurp grep/src/Makefile.am grep_new/src/Makefile.am
--- grep/src/Makefile.am	2004-11-23 13:49:36.000000000 +0100
+++ grep_new/src/Makefile.am	2005-03-03 11:11:41.000000000 +0100
@@ -7,8 +7,9 @@ bin_PROGRAMS = grep
 bin_SCRIPTS = egrep fgrep
 CLEANFILES = egrep fgrep
 grep_SOURCES = grep.c dfa.c kwset.c search.c \
-               grepmat.c
-noinst_HEADERS = grep.h dfa.h kwset.h getpagesize.h system.h mbsupport.h
+               grepmat.c grepopt.c dosbuf.c
+noinst_HEADERS = grep.h dfa.h kwset.h getpagesize.h system.h mbsupport.h \
+                 grepopt.h dosbuf.h
 
 LDADD = @INTLLIBS@ ../lib/libgreputils.a
 datadir = $(prefix)/@DATADIRNAME@
@@ -16,7 +17,6 @@ localedir = $(datadir)/locale
 INCLUDES = -I../intl -I$(top_srcdir)/lib -DLOCALEDIR=\"$(localedir)\"
 
 EXTRA_DIST = \
-             dosbuf.c \
              vms_fab.c vms_fab.h
 
 OPTION_for_egrep = -E
diff -Naurp grep/src/dfa.c grep_new/src/dfa.c
--- grep/src/dfa.c	2005-01-13 14:32:42.000000000 +0100
+++ grep_new/src/dfa.c	2005-03-06 23:52:45.000000000 +0100
@@ -118,7 +118,7 @@ extern void free();
 # include <wctype.h>
 #endif
 
-#include "regex.h"
+#include <regex.h>
 #include "dfa.h"
 #include "hard-locale.h"
 
diff -Naurp grep/src/dosbuf.c grep_new/src/dosbuf.c
--- grep/src/dosbuf.c	2000-01-20 05:43:03.000000000 +0100
+++ grep_new/src/dosbuf.c	2005-03-03 11:11:51.000000000 +0100
@@ -10,19 +10,28 @@
 
 */
 
-typedef enum {
-  UNKNOWN, DOS_BINARY, DOS_TEXT, UNIX_TEXT
-} File_type;
+#if defined(HAVE_DOS_FILE_CONTENTS)
+
+# ifdef HAVE_CONFIG_H
+# include <config.h>
+# endif
+
+# include <sys/types.h>
+# include <sys/stat.h>
+
+# include <stdio.h>
+# include "system.h"
+# include "xalloc.h"
+# include "xstrtol.h"
+# include "dosbuf.h"
+# include "grepopt.h"
 
 struct dos_map {
   off_t pos;	/* position in buffer passed to matcher */
   off_t add;	/* how much to add when reporting char position */
 };
 
-static int       dos_report_unix_offset = 0;
-
 static File_type dos_file_type     = UNKNOWN;
-static File_type dos_use_file_type = UNKNOWN;
 static off_t     dos_stripped_crs  = 0;
 static struct dos_map *dos_pos_map;
 static int       dos_pos_map_size  = 0;
@@ -56,8 +65,8 @@ guess_type (char *buf, register size_t b
 /* Convert external DOS file representation to internal.
    Return the count of characters left in the buffer.
    Build table to map character positions when reporting byte counts.  */
-static inline int
-undossify_input (register char *buf, size_t buflen)
+inline int
+undossify_input (register char *buf, size_t buflen, char *bufbeg, uintmax_t totalcc)
 {
   int chars_left = 0;
 
@@ -69,7 +78,7 @@ undossify_input (register char *buf, siz
       out_map_idx = 1;
       dos_pos_map_used = 0;
       dos_stripped_crs = 0;
-      dos_file_type = dos_use_file_type;
+      dos_file_type = o.dos_use_file_type;
     }
 
   /* Guess if this file is binary, unless we already know that.  */
@@ -92,7 +101,7 @@ undossify_input (register char *buf, siz
           else
             {
               buf++;
-              if (out_byte && !dos_report_unix_offset)
+              if (o.out_lines_byte_offset && !o.dos_report_unix_offset)
                 {
                   dos_stripped_crs++;
                   while (buflen && *buf == '\r')
@@ -145,13 +154,13 @@ undossify_input (register char *buf, siz
 }
 
 /* Convert internal byte count into external.  */
-static inline off_t
+inline off_t
 dossified_pos (off_t byteno)
 {
   off_t pos_lo;
   off_t pos_hi;
 
-  if (dos_file_type != DOS_TEXT || dos_report_unix_offset)
+  if (dos_file_type != DOS_TEXT || o.dos_report_unix_offset)
     return byteno;
 
   /* Optimization: usually the file will be scanned sequentially.
@@ -179,3 +188,5 @@ dossified_pos (off_t byteno)
 
   return byteno + dos_pos_map[out_map_idx].add;
 }
+
+#endif
diff -Naurp grep/src/dosbuf.h grep_new/src/dosbuf.h
--- grep/src/dosbuf.h	1970-01-01 01:00:00.000000000 +0100
+++ grep_new/src/dosbuf.h	2005-03-03 11:11:55.000000000 +0100
@@ -0,0 +1,15 @@
+#ifndef DOSBUF_H
+#define DOSBUF_H
+
+typedef enum {
+  UNKNOWN, DOS_BINARY, DOS_TEXT, UNIX_TEXT
+} File_type;
+
+inline int
+undossify_input PARAMS ((register char *buf, size_t buflen,
+			 char *bufbeg, uintmax_t totalcc));
+
+inline off_t
+dossified_pos PARAMS ((off_t byteno));
+
+#endif
diff -Naurp grep/src/grep.c grep_new/src/grep.c
--- grep/src/grep.c	2005-02-26 16:20:00.000000000 +0100
+++ grep_new/src/grep.c	2005-03-07 13:57:36.000000000 +0100
@@ -38,15 +38,20 @@
 #endif
 #include <stdio.h>
 #include "system.h"
-#include "getopt.h"
 #include "getpagesize.h"
-#include "grep.h"
 #include "savedir.h"
 #include "xstrtol.h"
 #include "xalloc.h"
 #include "error.h"
 #include "exclude.h"
 #include "closeout.h"
+#include "grep.h"
+
+#if defined(HAVE_DOS_FILE_CONTENTS)
+#include "dosbuf.h"
+#endif
+
+#include "grepopt.h"
 
 #undef MAX
 #define MAX(A,B) ((A) > (B) ? (A) : (B))
@@ -60,102 +65,10 @@ struct stats
 /* base of chain of stat buffers, used to detect directory loops */
 static struct stats stats_base;
 
-/* if non-zero, display usage information and exit */
-static int show_help;
-
-/* If non-zero, print the version on standard output and exit.  */
-static int show_version;
-
-/* If nonzero, suppress diagnostics for nonexistent or unreadable files.  */
-static int suppress_errors;
-
-/* If nonzero, use mmap if possible.  */
-static int mmap_option;
-
-/* If nonzero, use grep_color marker.  */
-static int color_option;
-
-/* If nonzero, show only the part of a line matching the expression. */
-static int only_matching;
-
-/* The color string used.  The user can overwrite it using the environment
-   variable GREP_COLOR.  The default is to print red.  */
-static const char *grep_color = "01;31";
-
-static struct exclude *excluded_patterns;
-static struct exclude *included_patterns;
-/* Short options.  */
-static char const short_options[] =
-"0123456789A:B:C:D:EFGHIPUVX:abcd:e:f:hiKLlm:noqRrsuvwxyZz";
-
-/* Non-boolean long options that have no corresponding short equivalents.  */
-enum
-{
-  BINARY_FILES_OPTION = CHAR_MAX + 1,
-  COLOR_OPTION,
-  INCLUDE_OPTION,
-  EXCLUDE_OPTION,
-  EXCLUDE_FROM_OPTION,
-  LINE_BUFFERED_OPTION,
-  LABEL_OPTION
-};
-
-/* Long options equivalences. */
-static struct option const long_options[] =
-{
-  {"after-context", required_argument, NULL, 'A'},
-  {"basic-regexp", no_argument, NULL, 'G'},
-  {"before-context", required_argument, NULL, 'B'},
-  {"binary-files", required_argument, NULL, BINARY_FILES_OPTION},
-  {"byte-offset", no_argument, NULL, 'b'},
-  {"context", required_argument, NULL, 'C'},
-  {"color", optional_argument, NULL, COLOR_OPTION},
-  {"colour", optional_argument, NULL, COLOR_OPTION},
-  {"count", no_argument, NULL, 'c'},
-  {"devices", required_argument, NULL, 'D'},
-  {"directories", required_argument, NULL, 'd'},
-  {"extended-regexp", no_argument, NULL, 'E'},
-  {"exclude", required_argument, NULL, EXCLUDE_OPTION},
-  {"exclude-from", required_argument, NULL, EXCLUDE_FROM_OPTION},
-  {"file", required_argument, NULL, 'f'},
-  {"files-with-matches", no_argument, NULL, 'l'},
-  {"files-without-match", no_argument, NULL, 'L'},
-  {"fixed-regexp", no_argument, NULL, 'F'},
-  {"fixed-strings", no_argument, NULL, 'F'},
-  {"help", no_argument, &show_help, 1},
-  {"include", required_argument, NULL, INCLUDE_OPTION},
-  {"ignore-case", no_argument, NULL, 'i'},
-  {"label", required_argument, NULL, LABEL_OPTION},
-  {"line-buffered", no_argument, NULL, LINE_BUFFERED_OPTION},
-  {"line-number", no_argument, NULL, 'n'},
-  {"line-regexp", no_argument, NULL, 'x'},
-  {"max-count", required_argument, NULL, 'm'},
-  {"mmap", no_argument, &mmap_option, 1},
-  {"no-filename", no_argument, NULL, 'h'},
-  {"no-messages", no_argument, NULL, 's'},
-  {"null", no_argument, NULL, 'Z'},
-  {"null-data", no_argument, NULL, 'z'},
-  {"only-matching", no_argument, NULL, 'o'},
-  {"perl-regexp", no_argument, NULL, 'P'},
-  {"quiet", no_argument, NULL, 'q'},
-  {"recursive", no_argument, NULL, 'r'},
-  {"recursive", no_argument, NULL, 'R'},
-  {"regexp", required_argument, NULL, 'e'},
-  {"invert-match", no_argument, NULL, 'v'},
-  {"silent", no_argument, NULL, 'q'},
-  {"text", no_argument, NULL, 'a'},
-  {"binary", no_argument, NULL, 'U'},
-  {"unix-byte-offsets", no_argument, NULL, 'u'},
-  {"version", no_argument, NULL, 'V'},
-  {"with-filename", no_argument, NULL, 'H'},
-  {"word-regexp", no_argument, NULL, 'w'},
-  {0, 0, 0, 0}
-};
-
-/* Define flags declared in grep.h. */
-int match_icase;
-int match_words;
-int match_lines;
+/* Define flags declared in grep.h.              */
+char match_icase;
+char match_words;
+char match_lines;
 unsigned char eolbyte;
 
 /* For error messages. */
@@ -164,27 +77,14 @@ char *program_name;
 static char const *filename;
 static int errseen;
 
-/* How to handle directories.  */
-static enum
-  {
-    READ_DIRECTORIES,
-    RECURSE_DIRECTORIES,
-    SKIP_DIRECTORIES
-  } directories = READ_DIRECTORIES;
-
-/* How to handle devices. */
-static enum
-  {
-    READ_DEVICES,
-    SKIP_DEVICES
-  } devices = READ_DEVICES;
-
-static int grepdir PARAMS ((char const *, struct stats const *));
-#if defined(HAVE_DOS_FILE_CONTENTS)
-static inline int undossify_input PARAMS ((register char *, size_t));
-#endif
+static int grep_parameter PARAMS ((char const *file, struct stats *stats));
+static int grep_dir PARAMS ((char const *, struct stats const *));
+static int grep_fd PARAMS ((int fd, char const *file, struct stats *stats));
+static int grep_stdin PARAMS ((void));
+static int grep_result PARAMS ((int count));
 
 /* Functions we'll use to search. */
+
 static void (*compile) PARAMS ((char const *, size_t));
 static size_t (*execute) PARAMS ((char const *, size_t, size_t *, int));
 
@@ -192,27 +92,11 @@ static size_t (*execute) PARAMS ((char c
 static void
 suppressible_error (char const *mesg, int errnum)
 {
-  if (! suppress_errors)
+  if (!o.suppress_errors)
     error (0, errnum, "%s", mesg);
   errseen = 1;
 }
 
-/* Convert STR to a positive integer, storing the result in *OUT.
-   STR must be a valid context length argument; report an error if it
-   isn't.  */
-static void
-context_length_arg (char const *str, int *out)
-{
-  uintmax_t value;
-  if (! (xstrtoumax (str, 0, 10, &value, "") == LONGINT_OK
-	 && 0 <= (*out = value)
-	 && *out == value))
-    {
-      error (2, 0, "%s: %s\n", str, _("invalid context length argument"));
-    }
-}
-
-
 /* Hairy buffering mechanism for grep.  The intent is to keep
    all reads aligned on a page boundary and multiples of the
    page size, unless a read yields a partial page.  */
@@ -244,11 +128,13 @@ static off_t initial_bufoffset;	/* Initi
    : (val) + ((alignment) - (size_t) (val) % (alignment)))
 
 /* Reset the buffer for a new file, returning zero if we should skip it.
-   Initialize on the first time through. */
+   Initialize on the first time through.
+   Sets bufdesc = fd
+*/
 static int
-reset (int fd, char const *file, struct stats *stats)
+reset (int fd, struct stats *stats)
 {
-  if (! pagesize)
+  if (!pagesize)
     {
       pagesize = getpagesize ();
       if (pagesize == 0 || 2 * pagesize + 1 <= pagesize)
@@ -256,14 +142,14 @@ reset (int fd, char const *file, struct 
       bufalloc = ALIGN_TO (INITIAL_BUFSIZE, pagesize) + pagesize + 1;
       buffer = xmalloc (bufalloc);
     }
-
+  
   bufbeg = buflim = ALIGN_TO (buffer + 1, pagesize);
   bufbeg[-1] = eolbyte;
   bufdesc = fd;
-
+  
   if (S_ISREG (stats->stat.st_mode))
     {
-      if (file)
+      if (fd != STDIN_FILENO)
 	bufoffset = 0;
       else
 	{
@@ -276,7 +162,7 @@ reset (int fd, char const *file, struct 
 	}
 #if defined(HAVE_MMAP)
       initial_bufoffset = bufoffset;
-      bufmapped = mmap_option && bufoffset % pagesize == 0;
+      bufmapped = o.use_mmap && bufoffset % pagesize == 0;
 #endif
     }
   else
@@ -311,21 +197,21 @@ fillbuf (size_t save, struct stats const
     }
   else
     {
-      size_t minsize = save + pagesize;
-      size_t newsize;
-      size_t newalloc;
+      size_t minsize, newsize, newalloc;
       char *newbuf;
 
+      minsize = save + pagesize;
+
       /* Grow newsize until it is at least as great as minsize.  */
       for (newsize = bufalloc - pagesize - 1; newsize < minsize; newsize *= 2)
 	if (newsize * 2 < newsize || newsize * 2 + pagesize + 1 < newsize * 2)
 	  xalloc_die ();
 
       /* Try not to allocate more memory than the file size indicates,
-	 as that might cause unnecessary memory exhaustion if the file
-	 is large.  However, do not use the original file size as a
-	 heuristic if we've already read past the file end, as most
-	 likely the file is growing.  */
+         as that might cause unnecessary memory exhaustion if the file
+         is large.  However, do not use the original file size as a
+         heuristic if we've already read past the file end, as most
+         likely the file is growing.  */
       if (S_ISREG (stats->stat.st_mode))
 	{
 	  off_t to_be_read = stats->stat.st_size - bufoffset;
@@ -338,7 +224,7 @@ fillbuf (size_t save, struct stats const
 	}
 
       /* Add enough room so that the buffer is aligned and has room
-	 for byte sentinels fore and aft.  */
+         for byte sentinels fore and aft.  */
       newalloc = newsize + pagesize + 1;
 
       newbuf = bufalloc < newalloc ? xmalloc (bufalloc = newalloc) : buffer;
@@ -362,7 +248,7 @@ fillbuf (size_t save, struct stats const
       size_t mmapsize = readsize;
 
       /* Don't mmap past the end of the file; some hosts don't allow this.
-	 Use `read' on the last page.  */
+         Use `read' on the last page.  */
       if (stats->stat.st_size - bufoffset < mmapsize)
 	{
 	  mmapsize = stats->stat.st_size - bufoffset;
@@ -372,8 +258,7 @@ fillbuf (size_t save, struct stats const
       if (mmapsize
 	  && (mmap ((caddr_t) readbuf, mmapsize,
 		    PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_FIXED,
-		    bufdesc, bufoffset)
-	      != (caddr_t) -1))
+		    bufdesc, bufoffset) != (caddr_t) -1))
 	{
 	  /* Do not bother to use madvise with MADV_SEQUENTIAL or
 	     MADV_WILLNEED on the mmapped memory.  One might think it
@@ -396,9 +281,9 @@ fillbuf (size_t save, struct stats const
 	    }
 	}
     }
-#endif /*HAVE_MMAP*/
+#endif /*HAVE_MMAP */
 
-  if (! fillsize)
+  if (!fillsize)
     {
       ssize_t bytesread;
       while ((bytesread = read (bufdesc, readbuf, readsize)) < 0
@@ -413,38 +298,12 @@ fillbuf (size_t save, struct stats const
   bufoffset += fillsize;
 #if defined(HAVE_DOS_FILE_CONTENTS)
   if (fillsize)
-    fillsize = undossify_input (readbuf, fillsize);
+    fillsize = undossify_input (readbuf, fillsize, bufbeg, totalcc);
 #endif
   buflim = readbuf + fillsize;
   return cc;
 }
 
-/* Flags controlling the style of output. */
-static enum
-{
-  BINARY_BINARY_FILES,
-  TEXT_BINARY_FILES,
-  WITHOUT_MATCH_BINARY_FILES
-} binary_files;		/* How to handle binary files.  */
-
-static int filename_mask;	/* If zero, output nulls after filenames.  */
-static int out_quiet;		/* Suppress all normal output. */
-static int out_invert;		/* Print nonmatching stuff. */
-static int out_file;		/* Print filenames. */
-static int out_line;		/* Print line numbers. */
-static int out_byte;		/* Print byte offsets. */
-static int out_before;		/* Lines of leading context. */
-static int out_after;		/* Lines of trailing context. */
-static int count_matches;	/* Count matching lines.  */
-static int list_files;		/* List matching files.  */
-static int no_filenames;	/* Suppress file names.  */
-static off_t max_count;		/* Stop after outputting this many
-				   lines from an input file.  */
-static int line_buffered;       /* If nonzero, use line buffering, i.e.
-				   fflush everyline out.  */
-static char *label = NULL;      /* Fake filename for stdin */
-
-
 /* Internal variables to keep track of byte count, context, etc. */
 static uintmax_t totalcc;	/* Total character count before bufbeg. */
 static char const *lastnl;	/* Pointer after last newline counted. */
@@ -454,13 +313,7 @@ static char const *lastout;	/* Pointer a
 static uintmax_t totalnl;	/* Total newline count before lastnl. */
 static off_t outleft;		/* Maximum number of lines to be output.  */
 static int pending;		/* Pending lines of output.
-				   Always kept 0 if out_quiet is true.  */
-static int done_on_match;	/* Stop scanning file on first match.  */
-static int exit_on_match;	/* Exit on first match.  */
-
-#if defined(HAVE_DOS_FILE_CONTENTS)
-# include "dosbuf.c"
-#endif
+				   Always kept 0 if o.out_quiet is true.  */
 
 /* Add two numbers that count input bytes or lines, and report an
    error if the addition overflows.  */
@@ -478,7 +331,8 @@ nlscan (char const *lim)
 {
   size_t newlines = 0;
   char const *beg;
-  for (beg = lastnl; beg != lim; beg = memchr (beg, eolbyte, lim - beg), beg++)
+  for (beg = lastnl; beg != lim;
+       beg = memchr (beg, eolbyte, lim - beg), beg++)
     newlines++;
   totalnl = add_count (totalnl, newlines);
   lastnl = lim;
@@ -502,19 +356,23 @@ print_offset_sep (uintmax_t pos, char se
   fwrite (p, 1, buf + sizeof buf - p, stdout);
 }
 
-static void
-prline (char const *beg, char const *lim, int sep)
+void
+prline_head (char const *beg, char const *lim, int sep)
 {
-  if (out_file)
-    printf ("%s%c", filename, sep & filename_mask);
-  if (out_line)
-    {
-      nlscan (beg);
-      totalnl = add_count (totalnl, 1);
+  if (o.out_filename == OUT_FILENAME_YES)
+    printf ("%s%c", filename, o.out_filename_null ? 0 : sep);
+  
+  if (o.out_lines_lineno)
+    {
+      if (lastnl < lim)
+	{
+	  nlscan (beg);
+	  totalnl = add_count (totalnl, 1);
+	  lastnl = lim;
+	}
       print_offset_sep (totalnl, sep);
-      lastnl = lim;
     }
-  if (out_byte)
+  if (o.out_lines_byte_offset)
     {
       uintmax_t pos = add_count (totalcc, beg - bufbeg);
 #if defined(HAVE_DOS_FILE_CONTENTS)
@@ -522,120 +380,71 @@ prline (char const *beg, char const *lim
 #endif
       print_offset_sep (pos, sep);
     }
-  if (only_matching)
-    {
-      size_t match_size;
-      size_t match_offset;
-      if(match_icase)
-        {
-          char *buf = (char*) xmalloc (lim - beg);
-	  char *ibeg = buf;
-	  char *ilim = ibeg + (lim - beg);
-	  int i;
-	  for (i = 0; i < lim - beg; i++)
-	    ibeg[i] = tolower (beg[i]);
+}
 
-	  while ((match_offset = (*execute) (ibeg, lim - beg, &match_size, 1))
-		 != (size_t) -1)
-	    {
-	      char const *b = ibeg + match_offset;
-	      if (b == lim)
-		break;
-	      if (match_size == 0)
-		break;
-	      if(color_option)
-		printf("\33[%sm", grep_color);
-	      fwrite(b, sizeof (char), match_size, stdout);
-	      if(color_option)
-		fputs("\33[00m", stdout);
-	      fputs("\n", stdout);
-	      ibeg = b + match_size;
-	    }
-	  free (buf);
-	  lastout = lim;
-	  if(line_buffered)
-	    fflush(stdout);
-	  return;
-	}
-      while ((match_offset = (*execute) (beg, lim - beg, &match_size, 1))
-	  != (size_t) -1)
-        {
-	  char const *b = beg + match_offset;
-	  if (b == lim)
-	    break;
-	  if (match_size == 0)
-	    break;
-	  if(color_option)
-	    printf("\33[%sm", grep_color);
-	  fwrite(b, sizeof (char), match_size, stdout);
-	  if(color_option)
-	    fputs("\33[00m", stdout);
-	  fputs("\n", stdout);
-	  beg = b + match_size;
-        }
-      lastout = lim;
-      if(line_buffered)
-	fflush(stdout);
-      return;
-    }
-  if (color_option)
-    {
-      size_t match_size;
-      size_t match_offset;
-      if(match_icase)
-        {
-	  /* Yuck, this is tricky */
-          char *buf = (char*) xmalloc (lim - beg);
-	  char *ibeg = buf;
-	  char *ilim = ibeg + (lim - beg);
-	  int i;
-	  for (i = 0; i < lim - beg; i++)
-	    ibeg[i] = tolower (beg[i]);
-	  while ((match_offset = (*execute) (ibeg, ilim-ibeg, &match_size, 1))
-		 != (size_t) -1)
-	    {
-	      char const *b = beg + match_offset;
-	      if (b == lim)
-		break;
-	      if (match_size == 0)
-	        break;
-	      fwrite (beg, sizeof (char), match_offset, stdout);
-	      printf ("\33[%sm", grep_color);
-	      fwrite (b, sizeof (char), match_size, stdout);
-	      fputs ("\33[00m", stdout);
-	      beg = b + match_size;
-	      ibeg = ibeg + match_offset + match_size;
-	    }
-	  fwrite (beg, 1, lim - beg, stdout);
-	  free (buf);
-	  lastout = lim;
-	  return;
-	}
-      while (lim-beg && (match_offset = (*execute) (beg, lim - beg, &match_size, 1))
-	     != (size_t) -1)
-	{
-	  char const *b = beg + match_offset;
-	  /* Avoid matching the empty line at the end of the buffer. */
-	  if (b == lim)
-	    break;
-	  /* Avoid hanging on grep --color "" foo */
-	  if (match_size == 0)
-	    break;
-	  fwrite (beg, sizeof (char), match_offset, stdout);
-	  printf ("\33[%sm", grep_color);
-	  fwrite (b, sizeof (char), match_size, stdout);
-	  fputs ("\33[00m", stdout);
-	  beg = b + match_size;
-	}
+/* print part of the line separately and then return a pointer to the last
+   part still to be printed so prline can finish its job.
+*/
+
+static char const*
+prline_part (char const *beg, char const *lim) {
+  size_t match_size;
+  size_t match_offset;
+
+  while (lim > beg && 
+	 (match_offset = (*execute) (beg, lim - beg, &match_size, 1))
+	 != (size_t) -1)
+    {
+      char const *b = beg + match_offset;
+      if (b == lim || match_size == 0)
+	break;
+      
+      if (o.out_lines_matchonly)
+	prline_head(beg, lim, ':');
+      else
+	fwrite (beg, sizeof (char), match_offset, stdout);
+
+      if (o.color) {
+	printf ("\33[%sm", o.colorstr);
+      }
+      
+      fwrite (b, sizeof (char), match_size, stdout);
+      
+      if (o.color)
+	fputs ("\33[00m", stdout);
+      
+      if (o.out_lines_matchonly)
+	fputs ("\n", stdout);
+      
+      beg = b + match_size;
     }
+
+  if (o.out_lines_matchonly)	/* we are done */
+    beg = lim;
+
+  return beg;
+}
+
+static void
+prline (char const *beg, char const *lim, int sep)
+{
+  if (!o.out_lines_matchonly)
+    prline_head(beg, lim, sep);
+
+  if (o.out_lines_matchonly || o.color && *o.colorstr && sep == ':')
+    beg = prline_part (beg, lim);
+
   fwrite (beg, 1, lim - beg, stdout);
+
   if (ferror (stdout))
     error (0, errno, _("writing output"));
+
   lastout = lim;
-  if (line_buffered)
+  if (o.line_buffered)
     fflush (stdout);
 }
 
+
 /* Print pending lines of trailing context prior to LIM. Trailing context ends
    at the next matching line when OUTLEFT is 0.  */
 static void
@@ -648,9 +457,9 @@ prpending (char const *lim)
       char const *nl = memchr (lastout, eolbyte, lim - lastout);
       size_t match_size;
       --pending;
-      if (outleft
-	  || (((*execute) (lastout, nl - lastout, &match_size, 0) == (size_t) -1)
-	      == !out_invert))
+      if (outleft ||
+	  (((*execute) (lastout, nl - lastout, &match_size, 0) ==
+	    (size_t) -1) == !o.out_invert))
 	prline (lastout, nl + 1, '-');
       else
 	pending = 0;
@@ -667,25 +476,25 @@ prtext (char const *beg, char const *lim
   char eol = eolbyte;
   int i, n;
 
-  if (!out_quiet && pending > 0)
+  if (!o.out_quiet && pending > 0)
     prpending (beg);
 
   p = beg;
 
-  if (!out_quiet)
+  if (!o.out_quiet)
     {
       /* Deal with leading context crap. */
 
       bp = lastout ? lastout : bufbeg;
-      for (i = 0; i < out_before; ++i)
+      for (i = 0; i < o.out_lines_before; ++i)
 	if (p > bp)
 	  do
 	    --p;
 	  while (p[-1] != eol);
 
       /* We print the "--" separator only if our output is
-	 discontiguous from the last output in the file. */
-      if ((out_before || out_after) && used && p != lastout)
+         discontiguous from the last output in the file. */
+      if ((o.out_lines_before || o.out_lines_after) && used && p != lastout)
 	puts ("--");
 
       while (p < beg)
@@ -704,7 +513,7 @@ prtext (char const *beg, char const *lim
 	{
 	  char const *nl = memchr (p, eol, lim - p);
 	  nl++;
-	  if (!out_quiet)
+	  if (!o.out_quiet)
 	    prline (p, nl, ':');
 	  p = nl;
 	}
@@ -713,11 +522,10 @@ prtext (char const *beg, char const *lim
       /* relying on it that this function is never called when outleft = 0.  */
       after_last_match = bufoffset - (buflim - p);
     }
-  else
-    if (!out_quiet)
-      prline (beg, lim, ':');
+  else if (!o.out_quiet)
+    prline (beg, lim, ':');
 
-  pending = out_quiet ? 0 : out_after;
+  pending = o.out_quiet ? 0 : o.out_lines_after;
   used = 1;
 }
 
@@ -734,21 +542,22 @@ grepbuf (char const *beg, char const *li
 
   nlines = 0;
   p = beg;
-  while ((match_offset = (*execute) (p, lim - p, &match_size, 0)) != (size_t) -1)
+  while ((match_offset =
+	  (*execute) (p, lim - p, &match_size, 0)) != (size_t) -1)
     {
       char const *b = p + match_offset;
       char const *endp = b + match_size;
       /* Avoid matching the empty line at the end of the buffer. */
       if (b == lim)
 	break;
-      if (!out_invert)
+      if (!o.out_invert)
 	{
 	  prtext (b, endp, (int *) 0);
 	  nlines++;
-          outleft--;
-	  if (!outleft || done_on_match)
+	  outleft--;
+	  if (!outleft || o.done_on_match)
 	    {
-	      if (exit_on_match)
+	      if (o.action == ACTION_EXIT_ON_MATCH)
 		exit (0);
 	      after_last_match = bufoffset - (buflim - endp);
 	      return nlines;
@@ -758,13 +567,13 @@ grepbuf (char const *beg, char const *li
 	{
 	  prtext (p, b, &n);
 	  nlines += n;
-          outleft -= n;
+	  outleft -= n;
 	  if (!outleft)
 	    return nlines;
 	}
       p = endp;
     }
-  if (out_invert && p < lim)
+  if (o.out_invert && p < lim)
     {
       prtext (p, lim, &n);
       nlines += n;
@@ -777,7 +586,7 @@ grepbuf (char const *beg, char const *li
    but if the file is a directory and we search it recursively, then
    return -2 if there was a match, and -1 otherwise.  */
 static int
-grep (int fd, char const *file, struct stats *stats)
+grep_fd (int fd, char const *file, struct stats *stats)
 {
   int nlines, i;
   int not_text;
@@ -787,23 +596,22 @@ grep (int fd, char const *file, struct s
   char *lim;
   char eol = eolbyte;
 
-  if (!reset (fd, file, stats))
+  if (!reset (fd, stats))
     return 0;
 
-  if (file && directories == RECURSE_DIRECTORIES
-      && S_ISDIR (stats->stat.st_mode))
+  if (o.directories == DIRECTORIES_RECURSE && S_ISDIR (stats->stat.st_mode))
     {
       /* Close fd now, so that we don't open a lot of file descriptors
-	 when we recurse deeply.  */
+         when we recurse deeply.  */
       if (close (fd) != 0)
 	error (0, errno, "%s", file);
-      return grepdir (file, stats) - 2;
+      return grep_dir (file, stats) - 2;
     }
 
   totalcc = 0;
   lastout = 0;
   totalnl = 0;
-  outleft = max_count;
+  outleft = o.out_lines_max;
   after_last_match = 0;
   pending = 0;
 
@@ -811,21 +619,20 @@ grep (int fd, char const *file, struct s
   residue = 0;
   save = 0;
 
-  if (! fillbuf (save, stats))
+  if (!fillbuf (save, stats))
     {
-      if (! is_EISDIR (errno, file))
-	suppressible_error (filename, errno);
+      suppressible_error (file, errno);
       return 0;
     }
 
-  not_text = (((binary_files == BINARY_BINARY_FILES && !out_quiet)
-	       || binary_files == WITHOUT_MATCH_BINARY_FILES)
+  not_text = (((o.binary_files == BINARY_FILES_BINARY && !o.out_quiet)
+	       || o.binary_files == BINARY_FILES_NOMATCH)
 	      && memchr (bufbeg, eol ? '\0' : '\200', buflim - bufbeg));
-  if (not_text && binary_files == WITHOUT_MATCH_BINARY_FILES)
+  if (not_text && o.binary_files == BINARY_FILES_NOMATCH)
     return 0;
-  done_on_match += not_text;
-  out_quiet += not_text;
-
+  o.done_on_match += not_text;
+  o.out_quiet += not_text;
+  
   for (;;)
     {
       lastnl = bufbeg;
@@ -856,16 +663,17 @@ grep (int fd, char const *file, struct s
 	    nlines += grepbuf (beg, lim);
 	  if (pending)
 	    prpending (lim);
-	  if((!outleft && !pending) || (nlines && done_on_match && !out_invert))
+	  if ((!outleft && !pending) ||
+	      (nlines && o.done_on_match && !o.out_invert))
 	    goto finish_grep;
 	}
 
       /* The last OUT_BEFORE lines at the end of the buffer will be needed as
-	 leading context if there is a matching line at the begin of the
-	 next data. Make beg point to their begin.  */
+         leading context if there is a matching line at the begin of the
+         next data. Make beg point to their begin.  */
       i = 0;
       beg = lim;
-      while (i < out_before && beg > bufbeg && beg != lastout)
+      while (i < o.out_lines_before && beg > bufbeg && beg != lastout)
 	{
 	  ++i;
 	  do
@@ -879,14 +687,13 @@ grep (int fd, char const *file, struct s
 
       /* Handle some details and read more data to scan.  */
       save = residue + lim - beg;
-      if (out_byte)
+      if (o.out_lines_byte_offset)
 	totalcc = add_count (totalcc, buflim - bufbeg - save);
-      if (out_line)
+      if (o.out_lines_lineno)
 	nlscan (beg);
-      if (! fillbuf (save, stats))
+      if (!fillbuf (save, stats))
 	{
-	  if (! is_EISDIR (errno, file))
-	    suppressible_error (filename, errno);
+	  suppressible_error (file, errno);
 	  goto finish_grep;
 	}
     }
@@ -896,87 +703,83 @@ grep (int fd, char const *file, struct s
       if (outleft)
 	nlines += grepbuf (bufbeg + save - residue, buflim);
       if (pending)
-        prpending (buflim);
+	prpending (buflim);
     }
 
- finish_grep:
-  done_on_match -= not_text;
-  out_quiet -= not_text;
-  if ((not_text & ~out_quiet) && nlines != 0)
+finish_grep:
+  o.done_on_match -= not_text;
+  o.out_quiet -= not_text;
+  if ((not_text & ~o.out_quiet) && nlines != 0)
     printf (_("Binary file %s matches\n"), filename);
   return nlines;
 }
 
+/* scan one filename and return a grep status */
 static int
-grepfile (char const *file, struct stats *stats)
+grep_parameter (char const *file, struct stats *stats)
 {
-  int desc;
-  int count;
-  int status;
+  int desc, count;
 
-  if (! file)
+  if (stat (file, &stats->stat) != 0)
     {
-      desc = 0;
-      filename = label ? label : _("(standard input)");
+      suppressible_error (file, errno);
+      return 1;
     }
-  else
-    {
-      if (stat (file, &stats->stat) != 0)
-        {
-          suppressible_error (file, errno);
-          return 1;
-        }
-      if (directories == SKIP_DIRECTORIES && S_ISDIR (stats->stat.st_mode))
-        return 1;
+  
+  if (o.directories == DIRECTORIES_SKIP && S_ISDIR (stats->stat.st_mode))
+    return 1;
 #ifndef DJGPP
-      if (devices == SKIP_DEVICES && (S_ISCHR(stats->stat.st_mode) || S_ISBLK(stats->stat.st_mode) || S_ISSOCK(stats->stat.st_mode) || S_ISFIFO(stats->stat.st_mode)))
+  if (o.devices == DEVICES_SKIP
+      && (S_ISCHR (stats->stat.st_mode) || S_ISBLK (stats->stat.st_mode)
+	  || S_ISSOCK (stats->stat.st_mode)
+	  || S_ISFIFO (stats->stat.st_mode)))
 #else
-      if (devices == SKIP_DEVICES && (S_ISCHR(stats->stat.st_mode) || S_ISBLK(stats->stat.st_mode)))
+    if (o.devices == DEVICES_SKIP
+	&& (S_ISCHR (stats->stat.st_mode) || S_ISBLK (stats->stat.st_mode)))
 #endif
-        return 1;
-      while ((desc = open (file, O_RDONLY)) < 0 && errno == EINTR)
-	continue;
+      return 1;
+  while ((desc = open (file, O_RDONLY)) < 0 && errno == EINTR)
+    continue;
 
-      if (desc < 0)
-	{
-	  int e = errno;
+  if (desc < 0)
+    {
+      int e = errno;
 
-	  if (is_EISDIR (e, file) && directories == RECURSE_DIRECTORIES)
+      if (is_EISDIR (e, file) && o.directories == DIRECTORIES_RECURSE)
+	{
+	  if (stat (file, &stats->stat) != 0)
 	    {
-	      if (stat (file, &stats->stat) != 0)
-		{
-		  error (0, errno, "%s", file);
-		  return 1;
-		}
-
-	      return grepdir (file, stats);
+	      error (0, errno, "%s", file);
+	      return 1;
 	    }
+	  
+	  return grep_dir (file, stats);
+	}
 
-	  if (!suppress_errors)
-	    {
-	      if (directories == SKIP_DIRECTORIES)
-		switch (e)
-		  {
+      if (!o.suppress_errors)
+	{
+	  if (o.directories == DIRECTORIES_SKIP)
+	    switch (e)
+	      {
 #if defined(EISDIR)
-		  case EISDIR:
-		    return 1;
+	      case EISDIR:
+		return 1;
 #endif
-		  case EACCES:
-		    /* When skipping directories, don't worry about
-		       directories that can't be opened.  */
-		    if (isdir (file))
-		      return 1;
-		    break;
-		  }
-	    }
-
-	  suppressible_error (file, e);
-	  return 1;
+	      case EACCES:
+		/* When skipping directories, don't worry about
+		   directories that can't be opened.  */
+		if (isdir (file))
+		  return 1;
+		break;
+	      }
 	}
 
-      filename = file;
+      suppressible_error (file, e);
+      return 1;
     }
 
+  filename = file;
+  
 #if defined(SET_BINARY)
   /* Set input to binary mode.  Pipes are simulated with files
      on DOS, so this includes the case of "foo | grep bar".  */
@@ -984,66 +787,45 @@ grepfile (char const *file, struct stats
     SET_BINARY (desc);
 #endif
 
-  count = grep (desc, file, stats);
-  if (count < 0)
-    status = count + 2;
-  else
-    {
-      if (count_matches)
-	{
-	  if (out_file)
-	    printf ("%s%c", filename, ':' & filename_mask);
-	  printf ("%d\n", count);
-	}
-
-      status = !count;
-      if (list_files == 1 - 2 * status)
-	printf ("%s%c", filename, '\n' & filename_mask);
+  count = grep_fd (desc, file, stats);
 
-      if (! file)
+  if (count >= 0) {
+    while (close (desc) != 0) {
+      if (errno != EINTR)
 	{
-	  off_t required_offset = outleft ? bufoffset : after_last_match;
-	  if ((bufmapped || required_offset != bufoffset)
-	      && lseek (desc, required_offset, SEEK_SET) < 0
-	      && S_ISREG (stats->stat.st_mode))
-	    error (0, errno, "%s", filename);
+	  error (0, errno, "%s", file);
+	  break;
 	}
-      else
-	while (close (desc) != 0)
-	  if (errno != EINTR)
-	    {
-	      error (0, errno, "%s", file);
-	      break;
-	    }
     }
-
-  return status;
+  }
+  
+  return grep_result (count);
 }
 
 static int
-grepdir (char const *dir, struct stats const *stats)
+grep_dir (char const *dir, struct stats const *stats)
 {
   int status = 1;
   struct stats const *ancestor;
   char *name_space;
-
+  
   /* Mingw32 does not support st_ino.  No known working hosts use zero
      for st_ino, so assume that the Mingw32 bug applies if it's zero.  */
   if (stats->stat.st_ino)
-    for (ancestor = stats;  (ancestor = ancestor->parent) != 0;  )
+    for (ancestor = stats; (ancestor = ancestor->parent) != 0;)
       if (ancestor->stat.st_ino == stats->stat.st_ino
 	  && ancestor->stat.st_dev == stats->stat.st_dev)
 	{
-	  if (!suppress_errors)
+	  if (!o.suppress_errors)
 	    error (0, 0, _("warning: %s: %s\n"), dir,
 		   _("recursive directory loop"));
 	  return 1;
 	}
-
-  name_space = savedir (dir, stats->stat.st_size, included_patterns,
-			excluded_patterns);
-
-  if (! name_space)
+  
+  name_space = savedir (dir, stats->stat.st_size, o.included_patterns,
+			o.excluded_patterns);
+  
+  if (!name_space)
     {
       if (errno)
 	suppressible_error (dir, errno);
@@ -1053,13 +835,16 @@ grepdir (char const *dir, struct stats c
   else
     {
       size_t dirlen = strlen (dir);
-      int needs_slash = ! (dirlen == FILESYSTEM_PREFIX_LEN (dir)
-			   || IS_SLASH (dir[dirlen - 1]));
+      int needs_slash = !(dirlen == FILESYSTEM_PREFIX_LEN (dir)
+			  || IS_SLASH (dir[dirlen - 1]));
       char *file = NULL;
       char const *namep = name_space;
-      struct stats child;
+      struct stats child; int old_out_filename;
       child.parent = stats;
-      out_file += !no_filenames;
+      
+      if ((old_out_filename = o.out_filename) == OUT_FILENAME_AUTO)
+	o.out_filename = OUT_FILENAME_YES;
+      
       while (*namep)
 	{
 	  size_t namelen = strlen (namep);
@@ -1068,49 +853,150 @@ grepdir (char const *dir, struct stats c
 	  file[dirlen] = '/';
 	  strcpy (file + dirlen + needs_slash, namep);
 	  namep += namelen + 1;
-	  status &= grepfile (file, &child);
+	  status &= grep_parameter (file, &child);
 	}
-      out_file -= !no_filenames;
+      o.out_filename = old_out_filename;
       if (file)
-        free (file);
+	free (file);
       free (name_space);
     }
-
+  
   return status;
 }
 
-static void
-usage (int status)
+/* Set the matcher to M, reporting any conflicts.  */
+void
+setmatcher (char const *m)
 {
-  if (status != 0)
-    {
-      fprintf (stderr, _("Usage: %s [OPTION]... PATTERN [FILE]...\n"),
-	       program_name);
-      fprintf (stderr, _("Try `%s --help' for more information.\n"),
-	       program_name);
-    }
-  else
-    {
-      printf (_("Usage: %s [OPTION]... PATTERN [FILE]...\n"), program_name);
-      printf (_("\
+  if (matcher && strcmp (matcher, m) != 0)
+    error (2, 0, _("conflicting matchers specified"));
+  matcher = m;
+}
+
+/* Go through the matchers vector and look for the specified matcher.
+   If we find it, install it in compile and execute, and return 1.  */
+static int
+install_matcher (char const *name)
+{
+  int i;
+#if defined(HAVE_SETRLIMIT)
+  struct rlimit rlim;
+#endif
+
+  for (i = 0; matchers[i].compile; i++)
+    if (strcmp (name, matchers[i].name) == 0)
+      {
+	compile = matchers[i].compile;
+	execute = matchers[i].execute;
+#if defined(HAVE_SETRLIMIT) && defined(RLIMIT_STACK)
+	/* I think every platform needs to do this, so that regex.c
+	   doesn't oveflow the stack.  The default value of
+	   `re_max_failures' is too large for some platforms: it needs
+	   more than 3MB-large stack.
+
+	   The test for HAVE_SETRLIMIT should go into `configure'.  */
+	if (!getrlimit (RLIMIT_STACK, &rlim))
+	  {
+	    long newlim;
+	    extern long int re_max_failures;	/* from regex.c */
+
+	    /* Approximate the amount regex.c needs, plus some more.  */
+	    newlim = re_max_failures * 2 * 20 * sizeof (char *);
+	    if (newlim > rlim.rlim_max)
+	      {
+		newlim = rlim.rlim_max;
+		re_max_failures = newlim / (2 * 20 * sizeof (char *));
+	      }
+	    if (rlim.rlim_cur < newlim)
+	      {
+		rlim.rlim_cur = newlim;
+		setrlimit (RLIMIT_STACK, &rlim);
+	      }
+	  }
+#endif
+	return 1;
+      }
+  return 0;
+}
+
+static char *
+get_program_name (char *full)
+{
+  char *program_name, *p, *q;
+
+  if (!full)
+    return 0;
+
+  program_name = (p = strrchr (full, '/')) ? p + 1 : full;
+
+#if defined(__MSDOS__) || defined(_WIN32)
+  /* DOS and MS-Windows use backslashes as directory separators, and usually
+     have an .exe suffix.  They also have case-insensitive filesystems.  */
+
+  if (q = strrchr (program_name, '\\'))
+    program_name = q + 1;
+  else if (program_name == full && full[0][0] && full[0][1] == ':')
+    program_name += 2;		/* handle c:program */
+
+  /* Collapse the letter-case, so `strcmp' could be used hence.  */
+  for (p = program_name; *p; p++)
+    if (*p >= 'A' && *p <= 'Z')
+      *p += 'a' - 'A';
+
+  /* Remove the .exe extension, if any.  */
+  if ((p = strrchr (program_name, '.')) && strcmp (p, ".exe") == 0)
+    *p = '\0';
+#endif
+
+  return program_name;
+}
+
+static int
+action_version (void)
+{
+  printf ("%s\n\n", PACKAGE_STRING);
+  printf (_("\
+Copyright (C) 1988, 1992-1999, 2000, 2001, 2002, 2004 Free Software Foundation, Inc.\n"));
+  printf (_("\
+This is free software; see the source for copying conditions. There is NO\n\
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"));
+  printf ("\n");
+  return 0;
+}
+
+static int
+action_usage (void)
+{
+  fprintf (stderr, _("Usage: %s [OPTION]... PATTERN [FILE]...\n"),
+	   program_name);
+  fprintf (stderr, _("Try `%s --help' for more information.\n"),
+	   program_name);
+  return 2;
+}
+
+static int
+action_help (void)
+{
+  printf (_("Usage: %s [OPTION]... PATTERN [FILE]...\n"), program_name);
+  printf (_("\
 Search for PATTERN in each FILE or standard input.\n\
 Example: %s -i 'hello world' menu.h main.c\n\
 \n\
 Regexp selection and interpretation:\n"), program_name);
-      printf (_("\
+  printf (_("\
   -E, --extended-regexp     PATTERN is an extended regular expression\n\
   -F, --fixed-strings       PATTERN is a set of newline-separated strings\n\
   -G, --basic-regexp        PATTERN is a basic regular expression\n\
   -P, --perl-regexp         PATTERN is a Perl regular expression\n"));
   /* -X is undocumented on purpose. */
-      printf (_("\
+  printf (_("\
   -e, --regexp=PATTERN      use PATTERN as a regular expression\n\
   -f, --file=FILE           obtain PATTERN from FILE\n\
   -i, --ignore-case         ignore case distinctions\n\
   -w, --word-regexp         force PATTERN to match only whole words\n\
   -x, --line-regexp         force PATTERN to match only whole lines\n\
   -z, --null-data           a data line ends in 0 byte, not newline\n"));
-      printf (_("\
+  printf (_("\
 \n\
 Miscellaneous:\n\
   -s, --no-messages         suppress error messages\n\
@@ -1118,7 +1004,7 @@ Miscellaneous:\n\
   -V, --version             print version information and exit\n\
       --help                display this help and exit\n\
       --mmap                use memory-mapped input if possible\n"));
-      printf (_("\
+  printf (_("\
 \n\
 Output control:\n\
   -m, --max-count=NUM       stop after NUM matches\n\
@@ -1146,7 +1032,7 @@ Output control:\n\
   -l, --files-with-matches  print only names of FILEs containing matches\n\
   -c, --count               print only a count of matching lines per FILE\n\
   -Z, --null                print 0 byte after FILE name\n"));
-      printf (_("\
+  printf (_("\
 \n\
 Context control:\n\
   -B, --before-context=NUM  print NUM lines of leading context\n\
@@ -1163,650 +1049,160 @@ Context control:\n\
 With no FILE, or when FILE is -, read standard input.  If less than two FILEs\n\
 are given, assume -h.  Exit status is 0 if any line was selected, 1 otherwise;\n\
 if any error occurs and -q was not given, the exit status is 2.\n"));
-      printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
-    }
-  exit (status);
-}
+  printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
 
-/* Set the matcher to M, reporting any conflicts.  */
-static void
-setmatcher (char const *m)
-{
-  if (matcher && strcmp (matcher, m) != 0)
-    error (2, 0, _("conflicting matchers specified"));
-  matcher = m;
+  return 0;
 }
 
-/* Go through the matchers vector and look for the specified matcher.
-   If we find it, install it in compile and execute, and return 1.  */
 static int
-install_matcher (char const *name)
+action_grep (void)
 {
-  int i;
-#if defined(HAVE_SETRLIMIT)
-  struct rlimit rlim;
+  int i, status;
+
+#ifdef SET_BINARY
+  /* Output is set to binary mode because we shouldn't convert
+     NL to CR-LF pairs, especially when grepping binary files.  */
+  if (!isatty (1))
+    SET_BINARY (1);
 #endif
 
-  for (i = 0; matchers[i].compile; i++)
-    if (strcmp (name, matchers[i].name) == 0)
-      {
-	compile = matchers[i].compile;
-	execute = matchers[i].execute;
-#if defined(HAVE_SETRLIMIT) && defined(RLIMIT_STACK)
-	/* I think every platform needs to do this, so that regex.c
-	   doesn't oveflow the stack.  The default value of
-	   `re_max_failures' is too large for some platforms: it needs
-	   more than 3MB-large stack.
+  if (o.out_lines_max == 0)
+    return 1;
 
-	   The test for HAVE_SETRLIMIT should go into `configure'.  */
-	if (!getrlimit (RLIMIT_STACK, &rlim))
-	  {
-	    long newlim;
-	    extern long int re_max_failures; /* from regex.c */
+  if (!install_matcher (matcher) && !install_matcher ("default"))
+    abort ();
 
-	    /* Approximate the amount regex.c needs, plus some more.  */
-	    newlim = re_max_failures * 2 * 20 * sizeof (char *);
-	    if (newlim > rlim.rlim_max)
-	      {
-		newlim = rlim.rlim_max;
-		re_max_failures = newlim / (2 * 20 * sizeof (char *));
-	      }
-	    if (rlim.rlim_cur < newlim)
+  (*compile) (o.keys, o.keycc);
+
+  status = 1;			/* nothing found yet */
+
+  if (!o.filenames)
+    status &= grep_stdin();
+  else
+    {
+      for (i = 0; i < o.n_filenames; i++)
+	{
+	  char *file = o.filenames[i];
+	  
+	  if (strcmp (file, "-") == 0)
+	    status &= grep_stdin ();
+	  else {
+	    if ((o.included_patterns || o.excluded_patterns))
 	      {
-		rlim.rlim_cur = newlim;
-		setrlimit (RLIMIT_STACK, &rlim);
+		if (o.included_patterns &&
+		    !excluded_filename (o.included_patterns, file, 0))
+		  continue;
+		if (o.excluded_patterns &&
+		    excluded_filename (o.excluded_patterns, file, 0))
+		  continue;
 	      }
+	    status &= grep_parameter (file, &stats_base);
 	  }
-#endif
-	return 1;
-      }
-  return 0;
+	}
+    }
+  return (errseen ? 2 : status);
 }
 
-/* Find the white-space-separated options specified by OPTIONS, and
-   using BUF to store copies of these options, set ARGV[0], ARGV[1],
-   etc. to the option copies.  Return the number N of options found.
-   Do not set ARGV[N] to NULL.  If ARGV is NULL, do not store ARGV[0]
-   etc.  Backslash can be used to escape whitespace (and backslashes).  */
+  /* takes a count and return a grep status result */
 static int
-prepend_args (char const *options, char *buf, char **argv)
-{
-  char const *o = options;
-  char *b = buf;
-  int n = 0;
+grep_result (int count) {
+  int status;
 
-  for (;;)
+  if (count < 0)
+    status = count + 2;
+  else
     {
-      while (ISSPACE ((unsigned char) *o))
-	o++;
-      if (!*o)
-	return n;
-      if (argv)
-	argv[n] = b;
-      n++;
-
-      do
-	if ((*b++ = *o++) == '\\' && *o)
-	  b[-1] = *o++;
-      while (*o && ! ISSPACE ((unsigned char) *o));
-
-      *b++ = '\0';
+      if (o.action == ACTION_COUNT)
+	{
+	  if (o.out_filename == OUT_FILENAME_YES)
+	    printf ("%s%c", filename, o.out_filename_null ? 0 : ':');
+	  printf ("%d\n", count);
+	}
+
+      status = !count;
+
+      if (o.action == ACTION_LIST_FILES && !status ||
+	  o.action == ACTION_LIST_NEG_FILES && status)
+	printf ("%s%c", filename, o.out_filename_null ? 0 : '\n');
     }
+
+  return status;
 }
 
-/* Prepend the whitespace-separated options in OPTIONS to the argument
-   vector of a main program with argument count *PARGC and argument
-   vector *PARGV.  */
-static void
-prepend_default_options (char const *options, int *pargc, char ***pargv)
-{
-  if (options)
+static int
+grep_stdin (void) {
+  struct stats s; int count;
+  s.parent = 0;
+
+  if (fstat (STDIN_FILENO, &s.stat) != 0)
     {
-      char *buf = xmalloc (strlen (options) + 1);
-      int prepended = prepend_args (options, buf, (char **) NULL);
-      int argc = *pargc;
-      char * const *argv = *pargv;
-      char **pp = (char **) xmalloc ((prepended + argc + 1) * sizeof *pp);
-      *pargc = prepended + argc;
-      *pargv = pp;
-      *pp++ = *argv++;
-      pp += prepend_args (options, buf, pp);
-      while ((*pp++ = *argv++))
-	continue;
+      suppressible_error (o.label_stdin, errno);
+      return 0;
     }
+  
+  count = grep_fd(STDIN_FILENO, o.label_stdin, &s);
+
+  if (1) {
+    /* I have no idea what this code is for. I think it fits here.
+       Maybe someone will explain me. Claudio */
+
+    off_t required_offset = outleft ? bufoffset : after_last_match;
+    if ((bufmapped || required_offset != bufoffset)
+	&& lseek (STDIN_FILENO, required_offset, SEEK_SET) < 0
+	&& S_ISREG (s.stat.st_mode))
+      error (0, errno, "%s", filename);
+  }
+
+  return grep_result (count);
 }
 
-/* Get the next non-digit option from ARGC and ARGV.
-   Return -1 if there are no more options.
-   Process any digit options that were encountered on the way,
-   and store the resulting integer into *DEFAULT_CONTEXT.  */
 static int
-get_nondigit_option (int argc, char *const *argv, int *default_context)
+dispatch_action (unsigned int a)
 {
-  int opt;
-  char buf[sizeof (uintmax_t) * CHAR_BIT + 4];
-  char *p = buf;
-
-  /* Set buf[0] to anything but '0', for the leading-zero test below.  */
-  buf[0] = '\0';
 
-  while (opt = getopt_long (argc, argv, short_options, long_options, NULL),
-	 '0' <= opt && opt <= '9')
+  switch (a)
     {
-      /* Suppress trivial leading zeros, to avoid incorrect
-	 diagnostic on strings like 00000000000.  */
-      p -= buf[0] == '0';
+    case ACTION_VERSION:
+      return action_version ();
 
-      if (p == buf + sizeof buf - 4)
-	{
-	  /* Too many digits.  Append "..." to make context_length_arg
-	     complain about "X...", where X contains the digits seen
-	     so far.  */
-	  strcpy (p, "...");
-	  p += 3;
-	  break;
-	}
-      *p++ = opt;
-    }
-  if (p != buf)
-    {
-      *p = '\0';
-      context_length_arg (buf, default_context);
-    }
+    case ACTION_USAGE:
+      return action_usage ();
+
+    case ACTION_HELP:
+      return action_help ();
 
-  return opt;
+    default:
+      return action_grep ();
+    }
 }
 
 int
 main (int argc, char **argv)
 {
-  char *keys;
-  size_t keycc, oldcc, keyalloc;
-  int with_filenames;
-  int opt, cc, status;
-  int default_context;
-  FILE *fp;
-  extern char *optarg;
-  extern int optind;
-
   initialize_main (&argc, &argv);
-  program_name = argv[0];
-  if (program_name && strrchr (program_name, '/'))
-    program_name = strrchr (program_name, '/') + 1;
-
-  if (!strcmp(program_name, "egrep"))
-    setmatcher ("egrep");
-  if (!strcmp(program_name, "fgrep"))
-    setmatcher ("fgrep");
+  program_name = get_program_name (argv[0]);
 
-#if defined(__MSDOS__) || defined(_WIN32)
-  /* DOS and MS-Windows use backslashes as directory separators, and usually
-     have an .exe suffix.  They also have case-insensitive filesystems.  */
-  if (program_name)
-    {
-      char *p = program_name;
-      char *bslash = strrchr (argv[0], '\\');
-
-      if (bslash && bslash >= program_name) /* for mixed forward/backslash case */
-	program_name = bslash + 1;
-      else if (program_name == argv[0]
-	       && argv[0][0] && argv[0][1] == ':') /* "c:progname" */
-	program_name = argv[0] + 2;
-
-      /* Collapse the letter-case, so `strcmp' could be used hence.  */
-      for ( ; *p; p++)
-	if (*p >= 'A' && *p <= 'Z')
-	  *p += 'a' - 'A';
-
-      /* Remove the .exe extension, if any.  */
-      if ((p = strrchr (program_name, '.')) && strcmp (p, ".exe") == 0)
-	*p = '\0';
-    }
-#endif
+  atexit (close_stdout);
 
-  keys = NULL;
-  keycc = 0;
-  with_filenames = 0;
-  eolbyte = '\n';
-  filename_mask = ~0;
-
-  max_count = TYPE_MAXIMUM (off_t);
-
-  /* The value -1 means to use DEFAULT_CONTEXT. */
-  out_after = out_before = -1;
-  /* Default before/after context: chaged by -C/-NUM options */
-  default_context = 0;
-  /* Changed by -o option */
-  only_matching = 0;
+  init_options (&argc, &argv);
 
-  /* Internationalization. */
+  /* l10n and i18n */
 #if defined(HAVE_SETLOCALE)
   setlocale (LC_ALL, "");
 #endif
+
 #if defined(ENABLE_NLS)
   bindtextdomain (PACKAGE, LOCALEDIR);
   textdomain (PACKAGE);
 #endif
 
-  atexit (close_stdout);
-
-  prepend_default_options (getenv ("GREP_OPTIONS"), &argc, &argv);
-
-  while ((opt = get_nondigit_option (argc, argv, &default_context)) != -1)
-    switch (opt)
-      {
-      case 'A':
-	context_length_arg (optarg, &out_after);
-	break;
-
-      case 'B':
-	context_length_arg (optarg, &out_before);
-	break;
-
-      case 'C':
-	/* Set output match context, but let any explicit leading or
-	   trailing amount specified with -A or -B stand. */
-	context_length_arg (optarg, &default_context);
-	break;
-
-      case 'D':
-	if (strcmp (optarg, "read") == 0)
-	  devices = READ_DEVICES;
-	else if (strcmp (optarg, "skip") == 0)
-	  devices = SKIP_DEVICES;
-	else
-	  error (2, 0, _("unknown devices method"));
-	break;
-
-      case 'E':
-	setmatcher ("egrep");
-	break;
-
-      case 'F':
-	setmatcher ("fgrep");
-	break;
-
-      case 'P':
-	setmatcher ("perl");
-	break;
-
-      case 'G':
-	setmatcher ("grep");
-	break;
-
-      case 'H':
-	with_filenames = 1;
-	break;
-
-      case 'I':
-	binary_files = WITHOUT_MATCH_BINARY_FILES;
-	break;
-
-      case 'U':
-#if defined(HAVE_DOS_FILE_CONTENTS)
-	dos_use_file_type = DOS_BINARY;
-#endif
-	break;
-
-      case 'u':
-#if defined(HAVE_DOS_FILE_CONTENTS)
-	dos_report_unix_offset = 1;
-#endif
-	break;
-
-      case 'V':
-	show_version = 1;
-	break;
-
-      case 'X': /* undocumented on purpose */
-	setmatcher (optarg);
-	break;
-
-      case 'a':
-	binary_files = TEXT_BINARY_FILES;
-	break;
-
-      case 'b':
-	out_byte = 1;
-	break;
-
-      case 'c':
-	count_matches = 1;
-	break;
-
-      case 'd':
-	if (strcmp (optarg, "read") == 0)
-	  directories = READ_DIRECTORIES;
-	else if (strcmp (optarg, "skip") == 0)
-	  directories = SKIP_DIRECTORIES;
-	else if (strcmp (optarg, "recurse") == 0)
-	  directories = RECURSE_DIRECTORIES;
-	else
-	  error (2, 0, _("unknown directories method"));
-	break;
-
-      case 'e':
-	cc = strlen (optarg);
-	keys = xrealloc (keys, keycc + cc + 1);
-	strcpy (&keys[keycc], optarg);
-	keycc += cc;
-	keys[keycc++] = '\n';
-	break;
-
-      case 'f':
-	fp = strcmp (optarg, "-") != 0 ? fopen (optarg, "r") : stdin;
-	if (!fp)
-	  error (2, errno, "%s", optarg);
-	for (keyalloc = 1; keyalloc <= keycc + 1; keyalloc *= 2)
-	  ;
-	keys = xrealloc (keys, keyalloc);
-	oldcc = keycc;
-	while (!feof (fp)
-	       && (cc = fread (keys + keycc, 1, keyalloc - 1 - keycc, fp)) > 0)
-	  {
-	    keycc += cc;
-	    if (keycc == keyalloc - 1)
-	      keys = xrealloc (keys, keyalloc *= 2);
-	  }
-	if (fp != stdin)
-	  fclose(fp);
-	/* Append final newline if file ended in non-newline. */
-	if (oldcc != keycc && keys[keycc - 1] != '\n')
-	  keys[keycc++] = '\n';
-	break;
-
-      case 'h':
-	no_filenames = 1;
-	break;
-
-      case 'i':
-      case 'y':			/* For old-timers . . . */
-	match_icase = 1;
-	break;
-
-      case 'L':
-	/* Like -l, except list files that don't contain matches.
-	   Inspired by the same option in Hume's gre. */
-	list_files = -1;
-	break;
-
-      case 'l':
-	list_files = 1;
-	break;
-
-      case 'm':
-	{
-	  uintmax_t value;
-	  switch (xstrtoumax (optarg, 0, 10, &value, ""))
-	    {
-	    case LONGINT_OK:
-	      max_count = value;
-	      if (0 <= max_count && max_count == value)
-		break;
-	      /* Fall through.  */
-	    case LONGINT_OVERFLOW:
-	      max_count = TYPE_MAXIMUM (off_t);
-	      break;
-
-	    default:
-	      error (2, 0, _("invalid max count"));
-	    }
-	}
-	break;
-
-      case 'n':
-	out_line = 1;
-	break;
-
-      case 'o':
-	only_matching = 1;
-	break;
-
-      case 'q':
-	exit_on_match = 1;
-	close_stdout_set_status(0);
-	break;
-
-      case 'R':
-      case 'r':
-	directories = RECURSE_DIRECTORIES;
-	break;
-
-      case 's':
-	suppress_errors = 1;
-	break;
-
-      case 'v':
-	out_invert = 1;
-	break;
-
-      case 'w':
-	match_words = 1;
-	break;
-
-      case 'x':
-	match_lines = 1;
-	break;
-
-      case 'Z':
-	filename_mask = 0;
-	break;
-
-      case 'z':
-	eolbyte = '\0';
-	break;
-
-      case BINARY_FILES_OPTION:
-	if (strcmp (optarg, "binary") == 0)
-	  binary_files = BINARY_BINARY_FILES;
-	else if (strcmp (optarg, "text") == 0)
-	  binary_files = TEXT_BINARY_FILES;
-	else if (strcmp (optarg, "without-match") == 0)
-	  binary_files = WITHOUT_MATCH_BINARY_FILES;
-	else
-	  error (2, 0, _("unknown binary-files type"));
-	break;
-
-      case COLOR_OPTION:
-        if(optarg) {
-          if(!strcasecmp(optarg, "always") || !strcasecmp(optarg, "yes") ||
-             !strcasecmp(optarg, "force"))
-            color_option = 1;
-          else if(!strcasecmp(optarg, "never") || !strcasecmp(optarg, "no") ||
-                  !strcasecmp(optarg, "none"))
-            color_option = 0;
-          else if(!strcasecmp(optarg, "auto") || !strcasecmp(optarg, "tty") ||
-                  !strcasecmp(optarg, "if-tty"))
-            color_option = 2;
-          else
-            show_help = 1;
-        } else
-          color_option = 2;
-        if(color_option == 2) {
-          if(isatty(STDOUT_FILENO) && getenv("TERM") &&
-	     strcmp(getenv("TERM"), "dumb"))
-                  color_option = 1;
-          else
-            color_option = 0;
-        }
-	break;
-
-      case EXCLUDE_OPTION:
-	if (!excluded_patterns)
-	  excluded_patterns = new_exclude ();
-	add_exclude (excluded_patterns, optarg);
-	break;
-
-      case EXCLUDE_FROM_OPTION:
-	if (!excluded_patterns)
-	  excluded_patterns = new_exclude ();
-        if (add_exclude_file (add_exclude, excluded_patterns, optarg, '\n')
-	    != 0)
-          {
-            error (2, errno, "%s", optarg);
-          }
-        break;
-
-      case INCLUDE_OPTION:
-	if (!included_patterns)
-	  included_patterns = new_exclude ();
-	add_exclude (included_patterns, optarg);
-	break;
-
-      case LINE_BUFFERED_OPTION:
-	line_buffered = 1;
-	break;
-
-      case LABEL_OPTION:
-	label = optarg;
-	break;
-
-      case 0:
-	/* long options */
-	break;
-
-      default:
-	usage (2);
-	break;
-
-      }
-
-  /* POSIX.2 says that -q overrides -l, which in turn overrides the
-     other output options.  */
-  if (exit_on_match)
-    list_files = 0;
-  if (exit_on_match | list_files)
-    {
-      count_matches = 0;
-      done_on_match = 1;
-    }
-  out_quiet = count_matches | done_on_match;
-
-  if (out_after < 0)
-    out_after = default_context;
-  if (out_before < 0)
-    out_before = default_context;
-
-  if (color_option)
-    {
-      char *userval = getenv ("GREP_COLOR");
-      if (userval != NULL && *userval != '\0')
-	grep_color = userval;
-    }
-
-  if (! matcher)
-    matcher = "grep";
-
-  if (show_version)
-    {
-      printf ("%s\n\n", PACKAGE_STRING);
-      printf (_("\
-Copyright (C) 1988, 1992-1999, 2000, 2001, 2002, 2004 Free Software Foundation, Inc.\n"));
-      printf (_("\
-This is free software; see the source for copying conditions. There is NO\n\
-warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"));
-      printf ("\n");
-      exit (0);
-    }
-
-  if (show_help)
-    usage (0);
-
-  if (keys)
-    {
-      if (keycc == 0)
-	{
-	  /* No keys were specified (e.g. -f /dev/null).  Match nothing.  */
-	  out_invert ^= 1;
-	  match_lines = match_words = 0;
-	}
-      else
-	/* Strip trailing newline. */
-        --keycc;
-    }
-  else
-    if (optind < argc)
-      {
-	keys = argv[optind++];
-	keycc = strlen (keys);
-      }
-    else
-      usage (2);
-
-  if (!install_matcher (matcher) && !install_matcher ("default"))
-    abort ();
-
-#ifdef MBS_SUPPORT
-  if (MB_CUR_MAX != 1 && match_icase)
-    {
-      wchar_t wc;
-      mbstate_t cur_state, prev_state;
-      int i, len = strlen(keys);
-
-      memset(&cur_state, 0, sizeof(mbstate_t));
-      for (i = 0; i <= len ;)
-	{
-	  size_t mbclen;
-	  mbclen = mbrtowc(&wc, keys + i, len - i, &cur_state);
-	  if (mbclen == (size_t) -1 || mbclen == (size_t) -2 || mbclen == 0)
-	    {
-	      /* An invalid sequence, or a truncated multibyte character.
-		 We treat it as a single byte character.  */
-	      mbclen = 1;
-	    }
-	  else
-	    {
-	      if (iswupper((wint_t)wc))
-		{
-		  wc = towlower((wint_t)wc);
-		  wcrtomb(keys + i, wc, &cur_state);
-		}
-	    }
-	  i += mbclen;
-	}
-    }
-#endif /* MBS_SUPPORT */
-
-  (*compile)(keys, keycc);
-
-  if ((argc - optind > 1 && !no_filenames) || with_filenames)
-    out_file = 1;
-
-#ifdef SET_BINARY
-  /* Output is set to binary mode because we shouldn't convert
-     NL to CR-LF pairs, especially when grepping binary files.  */
-  if (!isatty (1))
-    SET_BINARY (1);
-#endif
-
-  if (max_count == 0)
-    exit (1);
-
-  if (optind < argc)
-    {
-	status = 1;
-	do
-	{
-	  char *file = argv[optind];
-	  if ((included_patterns || excluded_patterns)
-	      && !isdir (file))
-	    {
-	      if (included_patterns &&
-		  ! excluded_filename (included_patterns, file, 0))
-		continue;
-	      if (excluded_patterns &&
-		  excluded_filename (excluded_patterns, file, 0))
-		continue;
-	    }
-	  status &= grepfile (strcmp (file, "-") == 0 ? (char *) NULL : file,
-			      &stats_base);
-	}
-	while ( ++optind < argc);
-    }
-  else
-    status = grepfile ((char *) NULL, &stats_base);
+  if (strcmp (program_name, "egrep") == 0)
+    setmatcher ("egrep");
+  else if (strcmp (program_name, "fgrep") == 0)
+    setmatcher ("fgrep");
 
-  /* We register via atexit() to test stdout.  */
-  exit (errseen ? 2 : status);
+  parse_options (argc, argv);
+  return dispatch_action (o.action);
 }
+
 /* vim:set shiftwidth=2: */
diff -Naurp grep/src/grep.h grep_new/src/grep.h
--- grep/src/grep.h	2001-03-04 06:39:41.000000000 +0100
+++ grep_new/src/grep.h	2005-03-03 11:12:29.000000000 +0100
@@ -36,7 +36,9 @@ extern char const *matcher;
 
 /* The following flags are exported from grep for the matchers
    to look at. */
-extern int match_icase;		/* -i */
-extern int match_words;		/* -w */
-extern int match_lines;		/* -x */
-extern unsigned char eolbyte;	/* -z */
+extern char match_icase;		/* -i */
+extern char match_words;		/* -w */
+extern char match_lines;		/* -x */
+extern unsigned char eolbyte;    	/* -z */
+
+void setmatcher PARAMS ((char const *m));
diff -Naurp grep/src/grepopt.c grep_new/src/grepopt.c
--- grep/src/grepopt.c	1970-01-01 01:00:00.000000000 +0100
+++ grep_new/src/grepopt.c	2005-03-03 16:25:52.000000000 +0100
@@ -0,0 +1,604 @@
+/*  grepopt.c -- option related data and functions
+    GNU grep,
+    Copyright (C) 1992, 1997, 1998, 1999, 2000, 2001, 2002, 2004, 
+    Free Software Foundation, Inc.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program (look for the file called COPYING);
+    if not, write to the Free Software Foundation, Inc.,
+    59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+	                                                                     */
+
+/*  Written 2005 by Claudio Fontana <sick_soul@users.sourceforge.net>        */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "mbsupport.h"
+#ifdef MBS_SUPPORT
+# include <wchar.h>
+# include <wctype.h>
+#endif
+#include <stdio.h>
+#include "system.h"
+#include "getopt.h"
+#include "grep.h"
+#include "xstrtol.h"
+#include "xalloc.h"
+#include "error.h"
+#include "exclude.h"
+
+#if defined(HAVE_DOS_FILE_CONTENTS)
+#include "dosbuf.h"
+#endif
+
+#include "grepopt.h"
+
+enum
+{
+  LONG_OPTION_BINARY_FILES = CHAR_MAX + 1,
+  LONG_OPTION_COLOR,
+  LONG_OPTION_EXCLUDE,
+  LONG_OPTION_EXCLUDE_FROM,
+  LONG_OPTION_HELP,
+  LONG_OPTION_INCLUDE,
+  LONG_OPTION_LABEL,
+  LONG_OPTION_LINE_BUFFERED,
+  LONG_OPTION_MMAP
+};
+
+static struct option const long_options[] = {
+  {"after-context", required_argument, NULL, 'A'},
+  {"basic-regexp", no_argument, NULL, 'G'},
+  {"before-context", required_argument, NULL, 'B'},
+  {"binary-files", required_argument, NULL, LONG_OPTION_BINARY_FILES},
+  {"byte-offset", no_argument, NULL, 'b'},
+  {"context", required_argument, NULL, 'C'},
+  {"color", optional_argument, NULL, LONG_OPTION_COLOR},
+  {"colour", optional_argument, NULL, LONG_OPTION_COLOR},
+  {"count", no_argument, NULL, 'c'},
+  {"devices", required_argument, NULL, 'D'},
+  {"directories", required_argument, NULL, 'd'},
+  {"extended-regexp", no_argument, NULL, 'E'},
+  {"exclude", required_argument, NULL, LONG_OPTION_EXCLUDE},
+  {"exclude-from", required_argument, NULL, LONG_OPTION_EXCLUDE_FROM},
+  {"file", required_argument, NULL, 'f'},
+  {"files-with-matches", no_argument, NULL, 'l'},
+  {"files-without-match", no_argument, NULL, 'L'},
+  {"fixed-regexp", no_argument, NULL, 'F'},
+  {"fixed-strings", no_argument, NULL, 'F'},
+  {"help", no_argument, NULL, LONG_OPTION_HELP},
+  {"include", required_argument, NULL, LONG_OPTION_INCLUDE},
+  {"ignore-case", no_argument, NULL, 'i'},
+  {"label", required_argument, NULL, LONG_OPTION_LABEL},
+  {"line-buffered", no_argument, NULL, LONG_OPTION_LINE_BUFFERED},
+  {"line-number", no_argument, NULL, 'n'},
+  {"line-regexp", no_argument, NULL, 'x'},
+  {"max-count", required_argument, NULL, 'm'},
+  {"mmap", no_argument, NULL, LONG_OPTION_MMAP},
+  {"no-filename", no_argument, NULL, 'h'},
+  {"no-messages", no_argument, NULL, 's'},
+  {"null", no_argument, NULL, 'Z'},
+  {"null-data", no_argument, NULL, 'z'},
+  {"only-matching", no_argument, NULL, 'o'},
+  {"perl-regexp", no_argument, NULL, 'P'},
+  {"quiet", no_argument, NULL, 'q'},
+  {"recursive", no_argument, NULL, 'r'},
+  {"recursive", no_argument, NULL, 'R'},
+  {"regexp", required_argument, NULL, 'e'},
+  {"invert-match", no_argument, NULL, 'v'},
+  {"silent", no_argument, NULL, 'q'},
+  {"text", no_argument, NULL, 'a'},
+  {"binary", no_argument, NULL, 'U'},
+  {"unix-byte-offsets", no_argument, NULL, 'u'},
+  {"version", no_argument, NULL, 'V'},
+  {"with-filename", no_argument, NULL, 'H'},
+  {"word-regexp", no_argument, NULL, 'w'},
+  {0, 0, 0, 0}
+};
+
+static char *short_options =
+  "0123456789A:B:C:D:EFGHIPUVX:abcd:e:f:hiLlm:noqRrsuvwxyZz";
+
+struct grepopt o;		/* all grep options reachable here */
+
+static char *choices_color[] = {
+  "never", "no", "none",	/* these will map to COLOR_NEVER   */
+  "auto", "if-tty", "tty",	/* these will map to COLOR_AUTO    */
+  "always", "yes", "force",	/* these will map to COLOR_ALWAYS  */
+  0
+};
+
+static char *choices_directories[] = { "skip", "read", "recurse", 0 };
+static char *choices_devices[] = { "skip", "read", 0 };
+static char *choices_binary_files[] =
+  { "without-match", "text", "binary", 0 };
+
+/* prepend_options adds options in raw string pointed by newp, and replaces
+ * argv and argc in the caller with the new resulting vector and count.
+ */
+
+static void
+prepend_options (char *newp, int *argc, char ***argv)
+{
+  int new_argc, i;
+  char *buf, *bufp, **new_argv;
+
+  if (!newp || !*newp)
+    return;
+  bufp = (buf = xmalloc (strlen (newp) + 1));
+
+  new_argc = 0;
+
+  while (*newp)
+    {
+      while (ISSPACE (*newp))
+	newp++;
+      if (!*newp)
+	break;
+      new_argc++;
+
+      do
+	{
+	  *bufp++ = *newp++;
+	}
+      while (*newp && !ISSPACE (*newp));
+
+      *bufp++ = 0;		/* null terminate new option */
+    }
+
+  new_argv = xmalloc (sizeof (char *) * (new_argc + *argc + 1));
+  new_argv[0] = (*argv)[0];	/* program name */
+
+  for (i = 0; i < new_argc; i++)
+    {
+      new_argv[i + 1] = buf;
+      if (i == new_argc - 1)
+	break;
+      buf = ((char*)memchr (buf, '\0', bufp - buf)) + 1;
+    }
+
+  for (i = 1; i < *argc; i++)
+    new_argv[new_argc + i] = (*argv)[i];
+
+  *argc = new_argc + *argc;
+  new_argv[*argc] = 0;
+  *argv = new_argv;
+}
+
+void
+init_options (int *argc, char ***argv)
+{
+  memset (&o, 0, sizeof (o));	/* turn off all options */
+
+  o.out_lines_max = TYPE_MAXIMUM (off_t);
+  /* The value -1 means to use o.out_lines_context */
+  o.out_lines_after = o.out_lines_before = -1;
+  /* Default before/after context */
+  o.out_lines_context = 0;
+  /* Whether to put filenames in output */
+  o.out_filename = OUT_FILENAME_AUTO;
+
+  if (!(o.colorstr = getenv ("GREP_COLOR")) || o.colorstr[0] == 0)
+    o.colorstr = "01;31";	/* red */
+
+  eolbyte = '\n';		/* o.eolbyte = '\n' */
+  match_icase = match_words = match_lines = 0;	/* o.match_icase ... */
+
+  o.label_stdin = _("(standard input)");
+  o.action = ACTION_LINES;
+
+  o.directories = DIRECTORIES_READ;
+  o.binary_files = BINARY_FILES_BINARY;
+
+#if defined(HAVE_DOS_FILE_CONTENTS)
+  o.dos_use_file_type = UNKNOWN;
+  o.dos_report_unix_offset = 0;
+#endif
+
+  prepend_options (getenv ("GREP_OPTIONS"), argc, argv);
+}
+
+static void
+set_off_t_option (char *s, off_t * v)
+{
+  uintmax_t value;
+  switch (xstrtoumax (s, 0, 10, &value, ""))
+    {
+    case LONGINT_OK:
+      *v = value;
+      if (0 <= *v && *v == value)
+	break;
+      /* vvv fall through vvv  */
+    case LONGINT_OVERFLOW:
+      *v = TYPE_MAXIMUM (off_t);
+      break;
+
+    default:
+      error (2, 0, _("invalid max count"));
+    }
+}
+
+static void
+set_int_option (char *s, int *v)
+{
+  uintmax_t value;
+  if (!(xstrtoumax (s, 0, 10, &value, "") == LONGINT_OK
+	&& 0 <= (*v = value) && *v == value))
+    error (2, 0, "%s: %s\n", s, _("invalid context length argument"));
+}
+
+static int
+set_choice_option (char *s, char* choices_set[])
+{
+  int i;
+  
+  for (i = 0; *choices_set; i++, choices_set++)
+    {
+      if (strcmp (s, *choices_set) == 0)
+	return i;
+    }
+
+  error (2, 0, "%s: %s\n", s, _("invalid choice argument"));
+  return -1;			/* never reached */
+}
+
+static int
+set_color_auto (void)
+{
+  return (isatty (STDOUT_FILENO) && getenv ("TERM") &&
+	  strcmp (getenv ("TERM"), "dumb") != 0) ? COLOR_YES : COLOR_NO;
+}
+
+static void
+add_key (char *s)
+{
+  size_t cc;
+  cc = strlen (s);
+  o.keys = xrealloc (o.keys, o.keycc + cc + 1);
+  strcpy (o.keys + o.keycc, s);
+  o.keycc += cc;
+  o.keys[o.keycc++] = '\n';
+}
+
+static void
+add_keys_from_file (char *s)
+{
+  FILE *f;
+  size_t keyalloc;
+  size_t cc, oldcc;
+
+  f = (strcmp (s, "-") != 0) ? fopen (s, "r") : stdin;
+  if (!f)
+    error (2, errno, "%s", s);
+
+  for (keyalloc = 1; keyalloc <= o.keycc + 1; keyalloc *= 2)
+    ;
+
+  o.keys = xrealloc (o.keys, keyalloc);
+  oldcc = o.keycc;
+
+  while (!feof (f)
+	 && (cc = fread (o.keys + o.keycc, 1, keyalloc - 1 - o.keycc, f)) > 0)
+    {
+      o.keycc += cc;
+      if (o.keycc == keyalloc - 1)
+	o.keys = xrealloc (o.keys, keyalloc *= 2);
+    }
+
+  if (f != stdin)
+    fclose (f);
+
+  /* Append final newline if file ended in non-newline. */
+  if (oldcc != o.keycc && o.keys[o.keycc - 1] != '\n')
+    o.keys[o.keycc++] = '\n';
+}
+
+
+static int
+finalize_keys(int argc, char *argv[], int *optind) {
+  if (o.keys)
+    {
+      if (o.keycc == 0)
+	{
+	  /* No keys were specified (e.g. -f /dev/null).  Match nothing.  */
+	  o.out_invert ^= 1;	/* invert invert */
+	  match_lines = match_words = 0;
+	}
+      else
+	/* Strip trailing newline. */
+	o.keycc--;
+    }
+  else if (*optind < argc)
+    {
+      o.keys = argv[(*optind)++];
+      o.keycc = strlen (o.keys);
+    }
+  else
+    return 0;			/* failure */
+
+#ifdef MBS_SUPPORT
+  if (MB_CUR_MAX != 1 && match_icase)
+    {
+      wchar_t wc;
+      mbstate_t cur_state;
+      int i, len = strlen (o.keys);
+
+      memset(&cur_state, 0, sizeof(mbstate_t));
+      for (i = 0; i <= len ;)
+	{
+	  size_t mbclen;
+	  mbclen = mbrtowc(&wc, o.keys + i, len - i, &cur_state);
+	  if (mbclen == (size_t) -1 || mbclen == (size_t) -2 || mbclen == 0)
+	    {
+	      /* An invalid sequence, or a truncated multibyte character.
+		 We treat it as a single byte character.  */
+	      mbclen = 1;
+	    }
+	  else
+	    {
+	      if (iswupper((wint_t)wc))
+		{
+		  wc = towlower((wint_t)wc);
+		  wcrtomb(o.keys + i, wc, &cur_state);
+		}
+	    }
+	  i += mbclen;
+	}
+    }
+#endif /* MBS_SUPPORT */
+  return 1;			/* success */
+}
+
+void
+parse_options (int argc, char *argv[])
+{
+  extern char *optarg;
+  extern int optind;
+  int i;
+  unsigned int c;
+
+  c = 0;
+
+  while ((i = getopt_long (argc, argv, short_options, long_options, 0)) != -1)
+    {
+
+      if (ISDIGIT (i))
+	{
+	  /* deprecated alternate form for -C option. Do not use. */
+	  /* Following code is a temp hack that relies on getopt internal use
+	     of optind. */
+	  if (!c)
+	    {
+	      if (ISDIGIT (argv[optind][1]))
+		set_int_option (argv[optind] + 1, &o.out_lines_context);
+	      else o.out_lines_context = i - '0';
+	      c = 1;
+	    }
+	  continue;
+	}
+
+      switch (i)
+	{
+	  /* the following actions take place as soon as they are found,
+	     because there is no restriction on which action should be
+	     prioritized on these. */
+	case ':':
+	  o.action = ACTION_USAGE;
+	  return;
+	case '?':
+	  o.action = ACTION_USAGE;
+	  return;
+	case LONG_OPTION_HELP:
+	  o.action = ACTION_HELP;
+	  return;
+	case 'V':
+	  o.action = ACTION_VERSION;
+	  return;
+	case 'A':
+	  set_int_option (optarg, &o.out_lines_after);
+	  break;
+	case 'B':
+	  set_int_option (optarg, &o.out_lines_before);
+	  break;
+	case 'C':
+	  /* Set output match context, but let any explicit leading or
+	     trailing amount specified with -A or -B stand. */
+	  set_int_option (optarg, &o.out_lines_context);
+	  break;
+	case 'D':
+	  o.devices = set_choice_option (optarg, choices_devices);
+	  break;
+	case 'E':
+	  setmatcher ("egrep");
+	  break;
+	case 'F':
+	  setmatcher ("fgrep");
+	  break;
+	case 'P':
+	  setmatcher ("perl");
+	  break;
+	case 'G':
+	  setmatcher ("grep");
+	  break;
+	case 'X':		/* undocumented on purpose */
+	  setmatcher (optarg);
+	  break;
+	case 'H':
+	  o.out_filename = OUT_FILENAME_YES;
+	  break;
+	case 'I':
+	  o.binary_files = BINARY_FILES_NOMATCH;
+	  break;
+	case 'U':
+#if defined(HAVE_DOS_FILE_CONTENTS)
+	  o.dos_use_file_type = DOS_BINARY;
+#endif
+	  break;
+	case 'u':
+#if defined(HAVE_DOS_FILE_CONTENTS)
+	  o.dos_report_unix_offset = 1;
+#endif
+	  break;
+	case 'a':
+	  o.binary_files = BINARY_FILES_TEXT;
+	  break;
+	case 'b':
+	  o.out_lines_byte_offset = 1;
+	  break;
+	case 'c':
+	  o.action |= ACTION_COUNT;
+	  break;
+	case 'd':
+	  o.directories = set_choice_option (optarg, choices_directories);
+	  break;
+	case 'e':
+	  add_key (optarg);
+	  break;
+	case 'f':
+	  add_keys_from_file (optarg);
+	  break;
+	case 'h':
+	  o.out_filename = OUT_FILENAME_NO;
+	  break;
+	case 'i':
+	case 'y':
+	  match_icase = 1;	/* o.match_icase = 1; */
+	  break;
+	case 'L':
+	  /* why have separate L option and not use l + v ? */
+	  o.action |= ACTION_LIST_NEG_FILES;
+	  break;
+	case 'l':
+	  o.action |= ACTION_LIST_FILES;
+	  break;
+	case 'm':
+	  set_off_t_option (optarg, &o.out_lines_max);
+	  break;
+	case 'n':
+	  o.out_lines_lineno = 1;
+	  break;
+	case 'o':
+	  o.out_lines_matchonly = 1;
+	  break;
+	case 'q':
+	  o.action |= ACTION_EXIT_ON_MATCH;
+	  break;
+	case 'R':
+	case 'r':
+	  o.directories = DIRECTORIES_RECURSE;
+	  break;
+	case 's':
+	  o.suppress_errors = 1;
+	  break;
+	case 'v':
+	  o.out_invert = 1;	/* invert should apply to l too IMO */
+	  break;
+	case 'w':
+	  match_words = 1;	/* o.match_words = 1; */
+	  break;
+	case 'x':
+	  match_lines = 1;	/* o.match_lines = 1; */
+	  break;
+	case 'Z':
+	  o.out_filename_null = 1;
+	  break;
+	case 'z':
+	  eolbyte = '\0';	/* o.eolbyte = '\0'; */
+	  break;
+	case LONG_OPTION_COLOR:
+	  o.color = (!optarg) ? COLOR_AUTO :
+	    set_choice_option (optarg, choices_color) / 3;
+
+	  if (o.color == COLOR_AUTO)
+	    o.color = set_color_auto ();	/* test term and set to YES or NO */
+	  break;
+	case LONG_OPTION_EXCLUDE:
+	  if (!o.excluded_patterns)
+	    o.excluded_patterns = new_exclude ();
+	  add_exclude (o.excluded_patterns, optarg);
+	  break;
+	case LONG_OPTION_EXCLUDE_FROM:
+	  if (!o.excluded_patterns)
+	    o.excluded_patterns = new_exclude ();
+	  if (add_exclude_file (add_exclude, o.excluded_patterns,
+				optarg, '\n') != 0)
+	    error (2, errno, "%s", optarg);
+	  break;
+	case LONG_OPTION_INCLUDE:
+	  if (!o.included_patterns)
+	    o.included_patterns = new_exclude ();
+	  add_exclude (o.included_patterns, optarg);
+	  break;
+	case LONG_OPTION_LINE_BUFFERED:
+	  o.line_buffered = 1;
+	  break;
+	case LONG_OPTION_LABEL:
+	  o.label_stdin = optarg;
+	  break;
+	case LONG_OPTION_MMAP:
+	  o.use_mmap = 1;
+	  break;
+	case LONG_OPTION_BINARY_FILES:
+	  o.binary_files = 
+	    set_choice_option (optarg, choices_binary_files);
+	  break;
+
+	default:
+	  abort ();		/* code must not reach here */
+	  break;
+	}
+    }
+
+  /* check action priorities following POSIX.2 */
+
+  for (c = 0x01; /* c <= ACTION_LIMIT */ ; c <<= 1)
+    {
+      if (o.action & c)
+	break;
+      if (c == ACTION_LIMIT)
+	abort ();		/* must not reach here (no action) */
+    }
+
+  o.action = c;			/* set definitive action */
+
+  /* finalize keys */
+
+  if (!finalize_keys (argc, argv, &optind))
+    { o.action = ACTION_USAGE; return; }
+
+  o.filenames = (optind < argc) ? argv + optind : 0;
+  o.n_filenames = argc - optind;
+
+  /* initialize option-derived values */
+
+  if (o.out_filename == OUT_FILENAME_AUTO && o.n_filenames > 1)
+    o.out_filename = OUT_FILENAME_YES;
+    
+  o.done_on_match =
+    !!(o.action &
+       (ACTION_EXIT_ON_MATCH | ACTION_LIST_FILES | ACTION_LIST_NEG_FILES));
+
+  o.out_quiet = (o.done_on_match || o.action == ACTION_COUNT);
+
+  if (o.out_lines_after < 0)
+    o.out_lines_after = o.out_lines_context;
+  if (o.out_lines_before < 0)
+    o.out_lines_before = o.out_lines_context;
+
+  if (!matcher)
+    matcher = "grep";
+}
diff -Naurp grep/src/grepopt.h grep_new/src/grepopt.h
--- grep/src/grepopt.h	1970-01-01 01:00:00.000000000 +0100
+++ grep_new/src/grepopt.h	2005-03-07 01:40:49.000000000 +0100
@@ -0,0 +1,120 @@
+/*  grepopt.h -- option related data and functions
+    GNU grep,
+    Copyright (C) 1992, 1997, 1998, 1999, 2000, 2001, 2002, 2004, 
+    Free Software Foundation, Inc.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program (look for the file called COPYING);
+    if not, write to the Free Software Foundation, Inc.,
+    59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+	                                                                     */
+
+/* Written 2005 by Claudio Fontana <sick_soul@users.sourceforge.net>         */
+
+#ifndef GREPOPT_H
+#define GREPOPT_H
+
+struct grepopt {
+
+  /* general options */
+
+  char suppress_errors;
+  char use_mmap;
+
+  enum { COLOR_NO, COLOR_AUTO, COLOR_YES } color;
+  char *colorstr;
+
+  enum { DIRECTORIES_SKIP, DIRECTORIES_READ, DIRECTORIES_RECURSE } directories;
+  enum { DEVICES_SKIP, DEVICES_READ } devices;
+  enum {
+    BINARY_FILES_NOMATCH, BINARY_FILES_TEXT, BINARY_FILES_BINARY
+  } binary_files;
+
+  struct exclude *excluded_patterns;
+  struct exclude *included_patterns;
+
+  /* Should be here too, but we let them in the globals to make
+     less drastic change */
+
+  /*
+    char match_icase;
+    char match_words;
+    char match_lines;
+    unsigned char eolbyte;
+  */
+
+  char *keys;			/* the keys provided by the user */
+  size_t keycc;			/* key count */
+
+  char **filenames;	        /* the filenames provided by the user      */
+                                /* NULL EQU stdin                          */
+                                /* filenames[i] = "-" also refers to stdin */
+
+  int n_filenames;		/* number of filename parameters      */
+
+  char *label_stdin;		/* the string to indicate standard input */
+
+  /* During option parsing these values may combine (OR), however at the */
+  /* end of the story, only one of those bits will be set.               */
+  /* Low values mean high priority.                                      */
+
+#define ACTION_LIMIT            0x80
+
+#define ACTION_LINES            0x80
+#define ACTION_COUNT            0x40
+#define ACTION_LIST_FILES       0x20
+#define ACTION_LIST_NEG_FILES   0x10
+#define ACTION_EXIT_ON_MATCH    0x08
+#define ACTION_VERSION          0x04
+#define ACTION_HELP             0x02
+#define ACTION_USAGE            0x01
+
+  unsigned int action;
+
+  char done_on_match;		/* set for EXIT_ON_MATCH and LIST*FILES   */
+  char out_quiet;		/* set for COUNT and EXIT_ON_MATCH        */
+
+  /* output options: general (apply to many actions) */
+  char line_buffered;            /* fflush(3) every output line.    */
+  enum {
+    OUT_FILENAME_NO, OUT_FILENAME_YES, OUT_FILENAME_AUTO
+  } out_filename;		 /* When to include filename in output.     */
+
+  char out_filename_null;	 /* Output nulls after filenames.   */
+  char out_invert;		 /* Invert match output             */
+
+  /* output options: lines (apply to lines action) */
+
+  char out_lines_lineno;	 /* Print line numbers.                     */
+  char out_lines_byte_offset;	 /* Print byte offsets.                     */
+  int out_lines_before;		 /* Lines of leading context                */
+  int out_lines_after;		 /* Lines of trailing context               */
+  int out_lines_context;	 /* Default context                         */
+  off_t out_lines_max;		 /* Max lines printed for each input file   */
+  int out_lines_matchonly;	 /* Do not print whole line, only the match */
+
+#if defined(HAVE_DOS_FILE_CONTENTS)
+  File_type dos_use_file_type;
+  char dos_report_unix_offset;
+#endif
+
+};
+
+extern struct grepopt o;
+
+void init_options PARAMS ((int *argc, char ***argv));
+void parse_options PARAMS ((int argc, char *argv[]));
+
+#endif
+
