From:	MERC::"uunet!WKUVX1.BITNET!FILESERV-Mgr" 12-JUN-1992 15:22:35.34
To:	galaxy::gleeve
CC:	
Subj:	GREP.06_OF_12

-+-+-+-+-+-+-+-+ START OF PART 6 -+-+-+-+-+-+-+-+
X      if (!long_only `7C`7C argv`5Boptind`5D`5B1`5D == '-'
X#ifdef GETOPT_COMPAT
X`09  `7C`7C argv`5Boptind`5D`5B0`5D == '+'
X#endif`09`09`09`09/* GETOPT_COMPAT */
X`09  `7C`7C my_index (optstring, *nextchar) == NULL)
X`09`7B
X`09  if (opterr)
X`09    `7B
X`09      if (argv`5Boptind`5D`5B1`5D == '-')
X`09`09/* --option */
X`09`09fprintf (stderr, "%s: unrecognized option `60--%s'\n",
X`09`09`09 argv`5B0`5D, nextchar);
X`09      else
X`09`09/* +option or -option */
X`09`09fprintf (stderr, "%s: unrecognized option `60%c%s'\n",
X`09`09`09 argv`5B0`5D, argv`5Boptind`5D`5B0`5D, nextchar);
X`09    `7D
X`09  nextchar += strlen (nextchar);
X`09  optind++;
X`09  return '?';
X`09`7D
X    `7D
X
X  /* Look at and handle the next option-character.  */
X
X  `7B
X    char c = *nextchar++;
X    char *temp = my_index (optstring, c);
X
X    /* Increment `60optind' when we start to process its last character.  */
X    if (*nextchar == '\0')
X      optind++;
X
X    if (temp == NULL `7C`7C c == ':')
X      `7B
X`09if (opterr)
X`09  `7B
X`09    if (c < 040 `7C`7C c >= 0177)
X`09      fprintf (stderr, "%s: unrecognized option, character code 0%o\n",
X`09`09       argv`5B0`5D, c);
X`09    else
X`09      fprintf (stderr, "%s: unrecognized option `60-%c'\n", argv`5B0`5D,
V c);
X`09  `7D
X`09return '?';
X      `7D
X    if (temp`5B1`5D == ':')
X      `7B
X`09if (temp`5B2`5D == ':')
X`09  `7B
X`09    /* This is an option that accepts an argument optionally.  */
X`09    if (*nextchar != '\0')
X`09      `7B
X`09`09optarg = nextchar;
X`09`09optind++;
X`09      `7D
X`09    else
X`09      optarg = 0;
X`09    nextchar = NULL;
X`09  `7D
X`09else
X`09  `7B
X`09    /* This is an option that requires an argument.  */
X`09    if (*nextchar != 0)
X`09      `7B
X`09`09optarg = nextchar;
X`09`09/* If we end this ARGV-element by taking the rest as an arg,
X`09`09   we must advance to the next element now.  */
X`09`09optind++;
X`09      `7D
X`09    else if (optind == argc)
X`09      `7B
X`09`09if (opterr)
X`09`09  fprintf (stderr, "%s: option `60-%c' requires an argument\n",
X`09`09`09   argv`5B0`5D, c);
X`09`09c = '?';
X`09      `7D
X`09    else
X`09      /* We already incremented `60optind' once;
X`09`09 increment it again when taking next ARGV-elt as argument.  */
X`09      optarg = argv`5Boptind++`5D;
X`09    nextchar = NULL;
X`09  `7D
X      `7D
X    return c;
X  `7D
X`7D
X
Xint
Xgetopt (argc, argv, optstring)
X     int argc;
X     char *const *argv;
X     const char *optstring;
X`7B
X  return _getopt_internal (argc, argv, optstring,
X`09`09`09   (const struct option *) 0,
X`09`09`09   (int *) 0,
X`09`09`09   0);
X`7D
X`0C
X#ifdef TEST
X
X/* Compile with -DTEST to make an executable for use in testing
X   the above definition of `60getopt'.  */
X
Xint
Xmain (argc, argv)
X     int argc;
X     char **argv;
X`7B
X  int c;
X  int digit_optind = 0;
X
X  while (1)
X    `7B
X      int this_option_optind = optind ? optind : 1;
X
X      c = getopt (argc, argv, "abc:d:0123456789");
X      if (c == EOF)
X`09break;
X
X      switch (c)
X`09`7B
X`09case '0':
X`09case '1':
X`09case '2':
X`09case '3':
X`09case '4':
X`09case '5':
X`09case '6':
X`09case '7':
X`09case '8':
X`09case '9':
X`09  if (digit_optind != 0 && digit_optind != this_option_optind)
X`09    printf ("digits occur in two different argv-elements.\n");
X`09  digit_optind = this_option_optind;
X`09  printf ("option %c\n", c);
X`09  break;
X
X`09case 'a':
X`09  printf ("option a\n");
X`09  break;
X
X`09case 'b':
X`09  printf ("option b\n");
X`09  break;
X
X`09case 'c':
X`09  printf ("option c with value `60%s'\n", optarg);
X`09  break;
X
X`09case '?':
X`09  break;
X
X`09default:
X`09  printf ("?? getopt returned character code 0%o ??\n", c);
X`09`7D
X    `7D
X
X  if (optind < argc)
X    `7B
X      printf ("non-option ARGV-elements: ");
X      while (optind < argc)
X`09printf ("%s ", argv`5Boptind++`5D);
X      printf ("\n");
X    `7D
X
X  exit (0);
X`7D
X
X#endif /* TEST */
$ CALL UNPACK [.GREP016]GETOPT.C;1 1396174647
$ create 'f'
X/* Declarations for getopt.
X   Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
X
X   This program is free software; you can redistribute it and/or modify
X   it under the terms of the GNU General Public License as published by
X   the Free Software Foundation; either version 2, or (at your option)
X   any later version.
X
X   This program is distributed in the hope that it will be useful,
X   but WITHOUT ANY WARRANTY; without even the implied warranty of
X   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
X   GNU General Public License for more details.
X
X   You should have received a copy of the GNU General Public License
X   along with this program; if not, write to the Free Software
X   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
X
X#ifndef _GETOPT_H
X#define _GETOPT_H 1
X
X/* For communication from `60getopt' to the caller.
X   When `60getopt' finds an option that takes an argument,
X   the argument value is returned here.
X   Also, when `60ordering' is RETURN_IN_ORDER,
X   each non-option ARGV-element is returned here.  */
X
Xextern char *optarg;
X
X/* Index in ARGV of the next element to be scanned.
X   This is used for communication to and from the caller
X   and for communication between successive calls to `60getopt'.
X
X   On entry to `60getopt', zero means this is the first call; initialize.
X
X   When `60getopt' returns EOF, this is the index of the first of the
X   non-option elements that the caller should itself scan.
X
X   Otherwise, `60optind' communicates from one call to the next
X   how much of ARGV has been scanned so far.  */
X
Xextern int optind;
X
X/* Callers store zero here to inhibit the error message `60getopt' prints
X   for unrecognized options.  */
X
Xextern int opterr;
X
X/* Describe the long-named options requested by the application.
X   The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
X   of `60struct option' terminated by an element containing a name which is
X   zero.
X
X   The field `60has_arg' is:
X   no_argument`09`09(or 0) if the option does not take an argument,
X   required_argument`09(or 1) if the option requires an argument,
X   optional_argument `09(or 2) if the option takes an optional argument.
X
X   If the field `60flag' is not NULL, it points to a variable that is set
X   to the value given in the field `60val' when the option is found, but
X   left unchanged if the option is not found.
X
X   To have a long-named option do something other than set an `60int' to
X   a compiled-in constant, such as set a value from `60optarg', set the
X   option's `60flag' field to zero and its `60val' field to a nonzero
X   value (the equivalent single-letter option character, if there is
X   one).  For long options that have a zero `60flag' field, `60getopt'
X   returns the contents of the `60val' field.  */
X
Xstruct option
X`7B
X#if`09__STDC__
X  const char *name;
X#else
X  char *name;
X#endif
X  /* has_arg can't be an enum because some compilers complain about
X     type mismatches in all the code that assumes it is an int.  */
X  int has_arg;
X  int *flag;
X  int val;
X`7D;
X
X/* Names for the values of the `60has_arg' field of `60struct option'.  */
X
Xenum _argtype
X`7B
X  no_argument,
X  required_argument,
X  optional_argument
X`7D;
X
X#if __STDC__
Xextern int getopt (int argc, char *const *argv, const char *shortopts);
Xextern int getopt_long (int argc, char *const *argv, const char *shortopts,
X`09`09        const struct option *longopts, int *longind);
Xextern int getopt_long_only (int argc, char *const *argv,
X`09`09`09     const char *shortopts,
X`09`09             const struct option *longopts, int *longind);
X
X/* Internal only.  Users should not call this directly.  */
Xextern int _getopt_internal (int argc, char *const *argv,
X`09`09`09     const char *shortopts,
X`09`09             const struct option *longopts, int *longind,
X`09`09`09     int long_only);
X#else /* not __STDC__ */
Xextern int getopt ();
Xextern int getopt_long ();
Xextern int getopt_long_only ();
X
Xextern int _getopt_internal ();
X#endif /* not __STDC__ */
X
X#endif /* _GETOPT_H */
$ CALL UNPACK [.GREP016]GETOPT.H;1 86379725
$ create 'f'
X/* grep - print lines matching an extended regular expression
X   Copyright (C) 1988 Free Software Foundation, Inc.
X
X   This program is free software; you can redistribute it and/or modify
X   it under the terms of the GNU General Public License as published by
X   the Free Software Foundation; either version 2, or (at your option)
X   any later version.
X
X   This program is distributed in the hope that it will be useful,
X   but WITHOUT ANY WARRANTY; without even the implied warranty of
X   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
X   GNU General Public License for more details.
X
X   You should have received a copy of the GNU General Public License
X   along with this program; if not, write to the Free Software
X   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
X
X/* Written June, 1988 by Mike Haertel
X   BMG speedups added July, 1988 by James A. Woods and Arthur David Olson  *
V/
X
X/* June 11, 1992`09Hunter Goatley`09Modified to run under VMS
X`09`09`09`09`09(using #ifdef VMS)`09`09*/
X`0C
X#include <stdio.h>
X
X#if defined(USG) `7C`7C defined(STDC_HEADERS) `7C`7C defined(VMS)
X#include <string.h>
X#ifndef bcopy
X#define bcopy(s,d,n)`09memcpy((d),(s),(n))
X#endif
X#ifndef index
X#define index strchr
X#endif
X#else
X#include <strings.h>
X#endif
X
X#ifdef HAVE_UNISTD_H
X#include <unistd.h>
X#endif
X
X#ifndef STDC_HEADERS
Xextern char *getenv();
X#endif
X
X#ifdef VMS
X#include <errno.h>
X#else
Xextern int errno;
X
Xextern char *sys_errlist`5B`5D;
X#endif /* VMS */
X
X#include "dfa.h"
X#include "regex.h"
X#include "getopt.h"
X
X/* Used by -w */
X#define WCHAR(C) (ISALNUM(C) `7C`7C (C) == '_')
X
X#define MAX(a, b) ((a) > (b) ? (a) : (b))
X
X/* Exit status codes. */
X#ifdef VMS
X#include <ssdef.h>
X#define MATCHES_FOUND 1`09`09/* Matches were found */
X#define NO_MATCHES_FOUND 3`09/* No matches -- success */
X#define ERROR SS$_ABORT`09`09/* Abort */
X#else
X#define MATCHES_FOUND 0`09`09/* Exit 0 if no errors and matches found. */
X#define NO_MATCHES_FOUND 1`09/* Exit 1 if no matches were found. */
X#define ERROR 2`09`09`09/* Exit 2 if some error occurred. */
X#endif
X
X/* Error is set true if something awful happened. */
Xstatic int error;
X
X/* The program name for error messages. */
Xstatic char *prog;
X
X/* We do all our own buffering by hand for efficiency. */
Xstatic char *buffer;`09`09/* The buffer itself, grown as needed. */
Xstatic bufbytes;`09`09/* Number of bytes in the buffer. */
Xstatic size_t bufalloc;`09`09/* Number of bytes allocated to the buffer. */
Xstatic bufprev;`09`09`09/* Number of bytes that have been forgotten.
X`09`09`09`09   This is used to get byte offsets from the
X`09`09`09`09   beginning of the file. */
Xstatic bufread;`09`09`09/* Number of bytes to get with each read(). */
X
Xstatic void
Xinitialize_buffer()
X`7B
X  bufread = 8192;
X  bufalloc = bufread + bufread / 2;
X  buffer = malloc(bufalloc);
X  if (! buffer)
X    `7B
X      fprintf(stderr, "%s: Memory exhausted (%s)\n", prog,
X#ifdef VMS
X`09      strerror(errno,vaxc$errno));
X#else
X`09      sys_errlist`5Berrno`5D);
X#endif
X      exit(ERROR);
X    `7D
X`7D
X
X/* The current input file. */
Xstatic fd;
Xstatic char *filename;
Xstatic eof;
X
X/* Fill the buffer retaining the last n bytes at the beginning of the
X   newly filled buffer (for backward context).  Returns the number of new
X   bytes read from disk. */
Xstatic int
Xfill_buffer_retaining(n)
X     int n;
X`7B
X  char *p, *q;
X  int i;
X
X  /* See if we need to grow the buffer. */
X  if (bufalloc - n <= bufread)
X    `7B
X      while (bufalloc - n <= bufread)
X`09`7B
X`09  bufalloc *= 2;
X`09  bufread *= 2;
X`09`7D
X      buffer = realloc(buffer, bufalloc);
X      if (! buffer)
X`09`7B
X`09  fprintf(stderr, "%s: Memory exhausted (%s)\n", prog,
X#ifdef VMS
X`09`09  strerror(errno,vaxc$errno));
X#else
X`09`09  sys_errlist`5Berrno`5D);
X#endif
X`09  exit(ERROR);
X`09`7D
X    `7D
X
X  bufprev += bufbytes - n;
X
X  /* Shift stuff down. */
X  for (i = n, p = buffer, q = p + bufbytes - n; i--; )
X    *p++ = *q++;
X  bufbytes = n;
X
X  if (eof)
X    return 0;
X
X  /* Read in new stuff. */
X  i = read(fd, buffer + bufbytes, bufread);
X  if (i < 0)
X    `7B
X      fprintf(stderr, "%s: read on %s failed (%s)\n", prog,
X`09      filename ? filename : "<stdin>",
X#ifdef VMS
X`09      strerror(errno,vaxc$errno));
X#else
X`09      sys_errlist`5Berrno`5D);
X#endif
X      error = 1;
X    `7D
X
X  /* Kludge to pretend every nonempty file ends with a newline. */
X  if (i == 0 && bufbytes > 0 && buffer`5Bbufbytes - 1`5D != '\n')
X    `7B
X      eof = i = 1;
X      buffer`5Bbufbytes`5D = '\n';
X    `7D
X
X  bufbytes += i;
X  return i;
X`7D
X`0C
X/* Various flags set according to the argument switches. */
Xstatic trailing_context;`09/* Lines of context to show after matches. */
Xstatic leading_context;`09`09/* Lines of context to show before matches. */
Xstatic byte_count;`09`09/* Precede output lines the byte count of the
X`09`09`09`09   first character on the line. */
Xstatic no_filenames;`09`09/* Do not display filenames. */
Xstatic line_numbers;`09`09/* Precede output lines with line numbers. */
Xstatic silent;`09`09`09/* Produce no output at all.  This switch
X`09`09`09`09   is bogus, ever hear of /dev/null? */
Xstatic int whole_word;`09`09/* Match only whole words.  Note that if
X`09`09`09`09   backreferences are used this depends on
X`09`09`09`09   the regex routines getting leftmost-longest
X`09`09`09`09   right, which they don't right now if `7C
X`09`09`09`09   is also used. */
Xstatic int whole_line;`09`09/* Match only whole lines.  Backreference
X`09`09`09`09   caveat applies here too.  */
Xstatic nonmatching_lines;`09/* Print lines that don't match the regexp. */
X
Xstatic bmgexec;`09`09`09/* Invoke Boyer-Moore-Gosper routines */
X
X/* The compiled regular expression lives here. */
Xstatic struct regexp reg;
X
X/* The compiled regular expression for the backtracking matcher lives here.
V */
Xstatic struct re_pattern_buffer regex;
X
X/* Pointer in the buffer after the last character printed. */
Xstatic char *printed_limit;
X
X/* True when printed_limit has been artifically advanced without printing
X   anything. */
Xstatic int printed_limit_fake;
X
X/* Print a line at the given line number, returning the number of
X   characters actually printed.  Matching is true if the line is to
X   be considered a "matching line".  This is only meaningful if
X   surrounding context is turned on. */
Xstatic int
Xprint_line(p, number, matching)
X     char *p;
X     int number;
X     int matching;
X`7B
X  int count = 0;
X
X#ifdef VMS
X  printed_limit = p;
X  do
X    ++count;
X  while (*p++ != '\n');
X
X  if (silent)
X    `7B
X      printed_limit_fake = 0;
X      printed_limit = p;
X      return count;
X    `7D
X#else
X  if (silent)
X    `7B
X      do
X`09++count;
X      while (*p++ != '\n');
X      printed_limit_fake = 0;
X      printed_limit = p;
X      return count;
X    `7D
X#endif
X
X  if (filename && !no_filenames)
X    printf("%s%c", filename, matching ? ':' : '-');
X  if (byte_count)
X    printf("%d%c", p - buffer + bufprev, matching ? ':' : '-');
X  if (line_numbers)
X    printf("%d%c", number, matching ? ':' : '-');
X
X#ifdef VMS
X  printed_limit`5Bcount-1`5D = '\0';
X  printf("%s", printed_limit);`09`09/* printf is used because it's faster */
X  printed_limit`5Bcount-1`5D = '\n';`09/* than multiple putchar's.
V           */
X  putchar('\n');
X#else
X  do
X    `7B
X      ++count;
X      putchar(*p);
X    `7D
X  while (*p++ != '\n');
X#endif
X  printed_limit_fake = 0;
X  printed_limit = p;
X  return count;
X`7D
X
X/* Print matching or nonmatching lines from the current file.  Returns a
X   count of matching or nonmatching lines. */
Xstatic int
Xgrep()
X`7B
X  int retain = 0;`09`09/* Number of bytes to retain on next call
X`09`09`09`09   to fill_buffer_retaining(). */
X  char *search_limit;`09`09/* Pointer to the character after the last
X`09`09`09`09   newline in the buffer. */
X  char saved_char;`09`09/* Character after the last newline. */
X  char *resume;`09`09`09/* Pointer to where to resume search. */
X  int resume_index = 0;`09`09/* Count of characters to ignore after
X`09`09`09`09   refilling the buffer. */
X  int line_count = 1;`09`09/* Line number. */
X  int try_backref;`09`09/* Set to true if we need to verify the
X`09`09`09`09   match with a backtracking matcher. */
X  int initial_line_count;`09/* Line count at beginning of last search. */
X  char *match;`09`09`09/* Pointer to the first character after the
X`09`09`09`09   string matching the regexp. */
X  int match_count = 0;`09`09/* Count of matching lines. */
X  char *matching_line;`09`09/* Pointer to first character of the matching
X`09`09`09`09   line, or of the first line of context to
X`09`09`09`09   print if context is turned on. */
X  char *real_matching_line;`09/* Pointer to the first character of the
X`09`09`09`09   real matching line. */
X  char *next_line;`09`09/* Pointer to first character of the line
X`09`09`09`09   following the matching line. */
X  char *last_match_limit;`09/* Pointer after last matched line. */
X  int pending_lines = 0;`09/* Lines of context left over from last match
X`09`09`09`09   that we have to print. */
X  static first_match = 1;`09/* True when nothing has been printed. */
X  int i;
X  char *tmp;
X  char *execute();
X
X  printed_limit_fake = 0;
X `20
X  while (fill_buffer_retaining(retain) > 0)
X    `7B
X      /* Find the last newline in the buffer. */
X      search_limit = buffer + bufbytes;
X      while (search_limit > buffer && search_limit`5B-1`5D != '\n')
X`09--search_limit;
X      if (search_limit == buffer)
X`09`7B
X`09  retain = bufbytes;
X`09  continue;
X`09`7D
X
X      /* Save the character after the last newline so regexecute can write
X`09 its own sentinel newline. */
X      saved_char = *search_limit;
X
X      /* Search the buffer for a match. */
X      printed_limit = buffer;
X      resume = buffer + resume_index;
X      last_match_limit = resume;
X      initial_line_count = line_count;
X
X
X      /* In retrospect, I have to say that the following code sucks.
X`09 For an example of how to do this right, see the fgrep
X`09 driver program that I wrote around a year later.  I'm
X`09 too lazy to retrofit that to egrep right now (the
X`09 pattern matchers have different needs).  */
X
X
X      while (match = execute(&reg, resume, search_limit, 0, &line_count, &tr
Vy_backref))
X`09`7B
X`09  /* Find the beginning of the matching line. */
X`09  matching_line = match;
X`09  while (matching_line > resume && matching_line`5B-1`5D != '\n')
X`09    --matching_line;
X`09  real_matching_line = matching_line;
X
X`09  /* Find the beginning of the next line. */
X`09  next_line = match;
X`09  while (next_line < search_limit && *next_line++ != '\n')
X`09    ;
X
X`09  /* If a potential backreference is indicated, try it out with
X`09     a backtracking matcher to make sure the line is a match.
X`09     This is hairy because we need to handle whole_line and
X`09     whole_word matches specially.  The method was stolen from
X`09     GNU fgrep.  */
X`09  if (try_backref)
X`09    `7B
X`09      struct re_registers regs;
X`09      int beg, len, maxlen, ret;
X
X`09      beg = 0;
X`09      for (maxlen = next_line - matching_line - 1; beg <= maxlen; ++beg)
X`09`09`7B
X`09`09  /* See if the matching line matches when backreferences
X`09`09     are considered... */
X`09`09  ret = re_search (&regex, matching_line, maxlen,
X`09`09`09`09   beg, maxlen - beg, &regs);
X`09`09  if (ret == -1)
X`09`09    goto fail;
X`09`09  beg = ret;
X`09`09  len = regs.end`5B0`5D - beg;
X`09`09  /* Ok, now check if it subsumed the whole line if -x */
X`09`09  if (whole_line && (beg != 0 `7C`7C len != maxlen))
X`09`09    goto fail;
X`09`09  /* If -w then check if the match aligns with word
X`09`09     boundaries.  We have to do this iteratively, because
X`09`09     (a) The line may contain more than one occurence
X`09`09     of the pattern, and;
X`09`09     (b) Several alternatives in the pattern might
X`09`09     be valid at a given point, and we may need to
X`09`09     consider a shorter one in order to align with
X`09`09     word boundaries.  */
X`09`09  else if (whole_word)
X`09`09    while (len > 0)
X`09`09      `7B
X`09`09`09/* If it's preceeded by a word constituent, then no go.  */
X`09`09`09if (beg > 0
X`09`09`09    && WCHAR((unsigned char) matching_line`5Bbeg - 1`5D))
X`09`09`09  break;
X`09`09`09/* If it's followed by a word constituent, look for
X`09`09`09   a shorter match.  */
X`09`09`09else if (beg + len < maxlen
X`09`09`09    && WCHAR((unsigned char) matching_line`5Bbeg + len`5D))
X`09`09`09  /* This is sheer incest. */
X`09`09`09  len = re_match_2 (&regex, (unsigned char *) 0, 0,
X`09`09`09`09`09    matching_line, maxlen,
X`09`09`09`09`09    beg, &regs, beg + len - 1);
X`09`09`09else
X`09`09`09  goto succeed;
X`09`09      `7D
X`09`09  else
X`09`09    goto succeed;
X`09`09`7D
X`09    fail:
X`09      resume = next_line;
X`09      if (resume == search_limit)
X`09`09break;
X`09      else
X`09`09continue;
X`09    `7D
X
X`09succeed:
X`09  /* Print out the matching or nonmatching lines as necessary. */
X`09  if (! nonmatching_lines)
X`09    `7B
X`09      /* Not -v, so nothing hairy... */
X`09      ++match_count;
X
X`09      /* Print leftover trailing context from last time around.  */
X`09      while (pending_lines && last_match_limit < matching_line)
X`09`09`7B
X`09`09  last_match_limit += print_line(last_match_limit,
X`09`09`09`09`09`09 initial_line_count++,
X`09`09`09`09`09`09 0);
X`09`09  --pending_lines;
X`09`09`7D
X
X`09      /* Back up over leading context if necessary. */
X`09      for (i = leading_context;
X`09`09   i > 0 && matching_line > printed_limit;
X`09`09   --i)
X`09`09`7B
X`09`09  while (matching_line > printed_limit
X`09`09`09 && (--matching_line)`5B-1`5D != '\n')
X`09`09    ;
X`09`09  --line_count;
X`09`09`7D
X
X`09      /* If context is enabled, we may have to print a separator. */
X`09      if ((leading_context `7C`7C trailing_context) && !silent
X`09`09  && !first_match && (printed_limit_fake
X`09`09`09`09      `7C`7C matching_line > printed_limit))
X`09`09printf("----------\n");
X`09      first_match = 0;
X
X`09      /* Print the matching line and its leading context. */
X`09      while (matching_line < real_matching_line)
X`09`09matching_line += print_line(matching_line, line_count++, 0);
X`09      matching_line += print_line(matching_line, line_count++, 1);
X
X`09      /* If there's trailing context, leave some lines pending until
X`09`09 next time. */
X`09      pending_lines = trailing_context;
X`09    `7D
X`09  else if (matching_line == last_match_limit)
X`09    `7B
X`09      /* In the -v case, this is where we deal with leftover
X`09`09 trailing context from last time... */
X`09      if (pending_lines > 0)
X`09`09`7B
X`09`09  --pending_lines;
X`09`09  print_line(matching_line, line_count, 0);
X`09`09`7D
X`09      ++line_count;
X`09    `7D
X`09  else if (matching_line > last_match_limit)
X`09    `7B
X`09      char *start = last_match_limit;
X
X`09      /* Back up over leading context if necessary. */
X`09      for (i = leading_context; start > printed_limit && i; --i)
X`09`09`7B
X`09`09  while (start > printed_limit && (--start)`5B-1`5D != '\n')
X`09`09    ;
X`09`09  --initial_line_count;
X`09`09`7D
X
X`09      /* If context is enabled, we may have to print a separator. */
X`09      if ((leading_context `7C`7C trailing_context) && !silent
X`09`09  && !first_match && (printed_limit_fake
X`09`09`09`09      `7C`7C start > printed_limit))
X`09`09printf("----------\n");
X`09      first_match = 0;
X
X`09      /* Print out the presumably matching leading context. */
X`09      while (start < last_match_limit)
X`09`09start += print_line(start, initial_line_count++, 0);
X
X`09      /* Print out the nonmatching lines prior to the matching line. */
X`09      while (start < matching_line)
X`09`09`7B
X`09`09  /* This counts as a "matching line" in -v. */
X`09`09  ++match_count;
X`09`09  start += print_line(start, initial_line_count++, 1);
X`09`09`7D
X
X`09      /* Deal with trailing context.  In -v what this means is
X`09`09 we print the current (matching) line, marked as a non
X`09`09 matching line.  */
X`09      if (trailing_context)
X`09`09`7B
X`09`09  print_line(matching_line, line_count, 0);
X`09`09  pending_lines = trailing_context - 1;
X`09`09`7D
X
X`09      /* Count the current line. */
X`09      ++line_count;
X`09    `7D
X`09  else
X`09    /* Let us pray this never happens... */
X`09    abort();
X
X`09  /* Resume searching at the beginning of the next line. */
X`09  initial_line_count = line_count;
X`09  resume = next_line;
X`09  last_match_limit = next_line;
X
X`09  if (resume == search_limit)
X`09    break;
X`09`7D
X`20
X      /* Restore the saved character. */
X      *search_limit = saved_char;
X
X      if (! nonmatching_lines)
X`09`7B
X`09  while (last_match_limit < search_limit && pending_lines)
X`09    `7B
X`09      last_match_limit += print_line(last_match_limit,
X`09`09`09`09`09     initial_line_count++,
X`09`09`09`09`09     0);
X`09      --pending_lines;
X`09    `7D
X`09`7D
X      else if (search_limit > last_match_limit)
X`09`7B
X`09  char *start = last_match_limit;
X
X`09  /* Back up over leading context if necessary. */
X`09  for (i = leading_context; start > printed_limit && i; --i)
X`09    `7B
X`09      while (start > printed_limit && (--start)`5B-1`5D != '\n')
X`09`09;
X`09      --initial_line_count;
X`09    `7D
X
X`09  /* If context is enabled, we may have to print a separator. */
X`09  if ((leading_context `7C`7C trailing_context) && !silent
X`09      && !first_match && (printed_limit_fake
X`09`09`09`09  `7C`7C start > printed_limit))
X`09    printf("----------\n");
X`09  first_match = 0;
X
X`09  /* Print out all the nonmatching lines up to the search limit. */
X`09  while (start < last_match_limit)
X`09    start += print_line(start, initial_line_count++, 0);
X`09  while (start < search_limit)
X`09    `7B
X`09      ++match_count;
X`09      start += print_line(start, initial_line_count++, 1);
X`09    `7D
X
X`09  pending_lines = trailing_context;
X`09  resume_index = 0;
X`09  retain = bufbytes - (search_limit - buffer);
X`09  continue;
X`09`7D
X     `20
X      /* Save the trailing end of the buffer for possible use as leading
X`09 context in the future. */
X      i = leading_context;
X      tmp = search_limit;
X      while (tmp > printed_limit && i--)
X`09while (tmp > printed_limit && (--tmp)`5B-1`5D != '\n')
X`09  ;
X      resume_index = search_limit - tmp;
X      retain = bufbytes - (tmp - buffer);
X      if (tmp > printed_limit)
X`09printed_limit_fake = 1;
X    `7D
X
X  return match_count;
X`7D
X`0C
Xvoid
Xusage_and_die()
X`7B
X  fprintf(stderr, "\
XUsage: %s `5B-CVbchilnsvwx`5D `5B-num`5D `5B-A num`5D `5B-B num`5D `5B-f fil
Ve`5D\n\
X       `5B-e`5D expr `5Bfile...`5D\n", prog);
X  exit(ERROR);
X`7D
X
Xstatic char version`5B`5D = "GNU e?grep, version 1.6";
X
Xint
Xmain(argc, argv)
X     int argc;
X     char **argv;
X`7B
X  int c;
X  int ignore_case = 0;`09`09/* Compile the regexp to ignore case. */
X  char *the_regexp = 0;`09`09/* The regular expression. */
X  int regexp_len;`09`09/* Length of the regular expression. */
X  char *regexp_file = 0;`09/* File containing parallel regexps. */
X  int count_lines = 0;`09`09/* Display only a count of matching lines. */
X  int list_files = 0;`09`09/* Display only the names of matching files. */
X  int line_count = 0;`09`09/* Count of matching lines for a file. */
X  int matches_found = 0;`09/* True if matches were found. */
X  char *regex_errmesg;`09`09/* Error message from regex routines. */
X  char translate`5B_NOTCHAR`5D;`09/* Translate table for case conversion
X`09`09`09`09   (needed by the backtracking matcher). */
X
X#ifdef VMS
X  if (!shell$is_shell())
X      shell_mung(&argc,&argv,2,"A-B-e+-f+");
X#endif
X
X#ifdef VMS
X  if (prog = (char *) index(argv`5B0`5D, '/'))
X#else
X  if (prog = index(argv`5B0`5D, '/'))
X#endif
X    ++prog;
X  else
X    prog = argv`5B0`5D;
X
X  opterr = 0;
X  while ((c = getopt(argc, argv, "0123456789A:B:CVbce:f:hilnsvwx")) != EOF)
X    switch (c)
X      `7B
X      case '?':
X`09usage_and_die();
X`09break;
X
X      case '0':
X      case '1':
X      case '2':
X      case '3':
X      case '4':
X      case '5':
X      case '6':
X      case '7':
X      case '8':
X      case '9':
+-+-+-+-+-+-+-+-  END  OF PART 6 +-+-+-+-+-+-+-+-
