[comp.sources.amiga] v89i218: rcs - revision control system, Part03/14

page%swap@Sun.COM (Bob Page) (11/19/89)

Submitted-by: rsbx@cbmvax.commodore.com (Raymond S. Brand)
Posting-number: Volume 89, Issue 218
Archive-name: unix/rcs.03

# This is a shell archive.
# Remove anything above and including the cut line.
# Then run the rest of the file through 'sh'.
# Unpacked files will be owned by you and have default permissions.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# shar: SHell ARchive
# Run the following text through 'sh' to create:
#	diff/dir.c
#	diff/ed.c
#	diff/io.c
#	diff/normal.c
#	diff/regex.c
# This is archive 3 of a 14-part kit.
# This archive created: Sun Nov 19 01:12:05 1989
if `test ! -d diff`
then
  mkdir diff
  echo "mkdir diff"
fi
echo "extracting diff/dir.c"
sed 's/^X//' << \SHAR_EOF > diff/dir.c
X/* Read, sort and compare two directories.  Used for GNU DIFF.
X   Copyright (C) 1988, 1989 Free Software Foundation, Inc.
X
XThis file is part of GNU DIFF.
X
XGNU DIFF is free software; you can redistribute it and/or modify
Xit under the terms of the GNU General Public License as published by
Xthe Free Software Foundation; either version 1, or (at your option)
Xany later version.
X
XGNU DIFF is distributed in the hope that it will be useful,
Xbut WITHOUT ANY WARRANTY; without even the implied warranty of
XMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
XGNU General Public License for more details.
X
XYou should have received a copy of the GNU General Public License
Xalong with GNU DIFF; see the file COPYING.  If not, write to
Xthe Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
X
X#include "diff.h"
X
Xstatic int compare_names ();
X
X/* Read the directory named DIRNAME and return a sorted vector
X   of filenames for its contents.  NONEX nonzero means this directory is
X   known to be nonexistent, so return zero files.  */
X
Xstruct dirdata
X{
X  int length;			/* # elements in `files' */
X  char **files;			/* Sorted names of files in the dir */
X};
X
Xstatic struct dirdata
Xdir_sort (dirname, nonex)
X     char *dirname;
X     int nonex;
X{
X  register DIR *reading;
X  register struct direct *next;
X  struct dirdata dirdata;
X  int compare_names ();
X
X  /* Address of block containing the files that are described.  */
X  char **files;
X
X  /* Length of block that `files' points to, measured in files.  */
X  int nfiles;
X
X  /* Index of first unused in `files'.  */
X  int files_index;
X
X  if (nonex)
X    {
X      dirdata.length = 0;
X      dirdata.files = 0;
X      return dirdata;
X    }
X
X  /* Open the directory and check for errors.  */
X  reading = opendir (dirname);
X  if (!reading)
X    {
X      perror_with_name (dirname);
X      dirdata.length = -1;
X      return dirdata;
X    }
X
X  /* Initialize the table of filenames.  */
X
X  nfiles = 100;
X  files = (char **) xmalloc (nfiles * sizeof (char *));
X  files_index = 0;
X
X  /* Read the directory entries, and insert the subfiles
X     into the `files' table.  */
X
X  while (next = readdir (reading))
X    {
X      /* Ignore the files `.' and `..' */
X      if (next->d_name[0] == '.'
X	  && (next->d_name[1] == 0
X	      || (next->d_name[1] == '.'
X		  && next->d_name[2] == 0)))
X	continue;
X
X      if (files_index == nfiles)
X	{
X	  nfiles *= 2;
X	  files
X	    = (char **) xrealloc (files, sizeof (char *) * nfiles);
X	}
X      files[files_index++] = concat (next->d_name, "", "");
X    }
X
X  closedir (reading);
X
X  /* Sort the table.  */
X  qsort (files, files_index, sizeof (char *), compare_names);
X
X  /* Return a description of location and length of the table.  */
X  dirdata.files = files;
X  dirdata.length = files_index;
X
X  return dirdata;
X}
X
X/* Sort the files now in the table.  */
X
Xstatic int
Xcompare_names (file1, file2)
X     char **file1, **file2;
X{
X  return strcmp (*file1, *file2);
X}
X
X/* Compare the contents of two directories named NAME1 and NAME2.
X   This is a top-level routine; it does everything necessary for diff
X   on two directories.
X
X   NONEX1 nonzero says directory NAME1 doesn't exist, but pretend it is
X   empty.  Likewise NONEX2.
X
X   HANDLE_FILE is a caller-provided subroutine called to handle each file.
X   It gets five operands: dir and name (rel to original working dir) of file
X   in dir 1, dir and name pathname of file in dir 2, and the recursion depth.
X
X   For a file that appears in only one of the dirs, one of the name-args
X   to HANDLE_FILE is zero.
X
X   DEPTH is the current depth in recursion.
X
X   Returns the maximum of all the values returned by HANDLE_FILE,
X   or 2 if trouble is encountered in opening files.  */
X
Xint
Xdiff_dirs (name1, name2, handle_file, depth, nonex1, nonex2)
X     char *name1, *name2;
X     int (*handle_file) ();
X     int nonex1, nonex2;
X{
X  struct dirdata data1, data2;
X  register int i1, i2;
X  int val = 0;
X  int v1;
X
X  /* Get sorted contents of both dirs.  */
X  data1 = dir_sort (name1, nonex1);
X  data2 = dir_sort (name2, nonex2);
X  if (data1.length == -1 || data2.length == -1)
X    {
X      if (data1.length >= 0)
X	free (data1.files);
X      if (data2.length >= 0)
X	free (data2.files);
X      return 2;
X    }
X
X  i1 = 0;
X  i2 = 0;
X
X  /* If -Sname was specified, and this is the topmost level of comparison,
X     ignore all file names less than the specified starting name.  */
X
X  if (dir_start_file && depth == 0)
X    {
X      while (i1 < data1.length && strcmp (data1.files[i1], dir_start_file) < 0)
X	i1++;
X      while (i2 < data2.length && strcmp (data2.files[i2], dir_start_file) < 0)
X	i2++;
X    }
X
X  /* Loop while files remain in one or both dirs.  */
X  while (i1 < data1.length || i2 < data2.length)
X    {
X      int nameorder;
X
X      /* Compare next name in dir 1 with next name in dir 2.
X	 At the end of a dir,
X	 pretend the "next name" in that dir is very large.  */
X
X      if (i1 == data1.length)
X	nameorder = 1;
X      else if (i2 == data2.length)
X	nameorder = -1;
X      else
X	nameorder = strcmp (data1.files[i1], data2.files[i2]);
X
X      if (nameorder == 0)
X	{
X	  /* We have found a file (or subdir) in common between both dirs.
X	     Compare the two files.  */
X	  v1 = (*handle_file) (name1, data1.files[i1], name2, data2.files[i2],
X			       depth + 1);
X	  i1++, i2++;
X	}
X      if (nameorder < 0)
X	{
X	  /* Next filename in dir 1 is less; that is a file in dir 1 only.  */
X	  v1 = (*handle_file) (name1, data1.files[i1], name2, 0, depth + 1);
X	  i1++;
X	}
X      if (nameorder > 0)
X	{
X	  /* Next filename in dir 2 is less; that is a file in dir 2 only.  */
X	  v1 = (*handle_file) (name1, 0, name2, data2.files[i2], depth + 1);
X	  i2++;
X	}
X      if (v1 > val)
X	val = v1;
X    }
X  free (data1.files);
X  free (data2.files);
X
X  return val;
X}
SHAR_EOF
echo "extracting diff/ed.c"
sed 's/^X//' << \SHAR_EOF > diff/ed.c
X/* Output routines for ed-script format.
X   Copyright (C) 1988, 1989 Free Software Foundation, Inc.
X
XThis file is part of GNU DIFF.
X
XGNU DIFF is free software; you can redistribute it and/or modify
Xit under the terms of the GNU General Public License as published by
Xthe Free Software Foundation; either version 1, or (at your option)
Xany later version.
X
XGNU DIFF is distributed in the hope that it will be useful,
Xbut WITHOUT ANY WARRANTY; without even the implied warranty of
XMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
XGNU General Public License for more details.
X
XYou should have received a copy of the GNU General Public License
Xalong with GNU DIFF; see the file COPYING.  If not, write to
Xthe Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
X
X#include "diff.h"
X
Xstatic void print_rcs_hunk ();
Xstatic void print_ed_hunk ();
Xstatic void pr_forward_ed_hunk ();
Xstatic void print_range_length ();
Xvoid translate_range ();
Xstruct change *find_change ();
Xstruct change *find_reverse_change ();
X
X/* Print our script as ed commands.  */
X
Xvoid
Xprint_ed_script (script)
X    struct change *script;
X{
X  print_script (script, find_reverse_change, print_ed_hunk);
X}
X
X/* Print a hunk of an ed diff */
X
Xstatic void
Xprint_ed_hunk (hunk)
X     struct change *hunk; 
X{
X  int f0, l0, f1, l1;
X  int deletes, inserts;
X
X#if 0
X  hunk = flip_script (hunk);
X#endif
X#ifdef MYDEBUG
X  debug_script (hunk);
X#endif
X
X  /* Determine range of line numbers involved in each file.  */
X  analyze_hunk (hunk, &f0, &l0, &f1, &l1, &deletes, &inserts);
X  if (!deletes && !inserts)
X    return;
X
X  /* Print out the line number header for this hunk */
X  print_number_range (',', &files[0], f0, l0);
X  fprintf (outfile, "%c\n", change_letter (inserts, deletes));
X
X  /* Print new/changed lines from second file, if needed */
X  if (inserts)
X    {
X      int i;
X      int inserting = 1;
X      for (i = f1; i <= l1; i++)
X	{
X	  /* Resume the insert, if we stopped.  */
X	  if (! inserting)
X	    fprintf (outfile, "%da\n",
X		     i - f1 + translate_line_number (&files[0], f0) - 1);
X	  inserting = 1;
X
X	  /* If the file's line is just a dot, it would confuse `ed'.
X	     So output it with a double dot, and set the flag LEADING_DOT
X	     so that we will output another ed-command later
X	     to change the double dot into a single dot.  */
X
X	  if (files[1].linbuf[i].text[0] == '.'
X	      && files[1].linbuf[i].text[1] == '\n')
X	    {
X	      fprintf (outfile, "..\n");
X	      fprintf (outfile, ".\n");
X	      /* Now change that double dot to the desired single dot.  */
X	      fprintf (outfile, "%ds/^\\.\\././\n",
X		       i - f1 + translate_line_number (&files[0], f0));
X	      inserting = 0;
X	    }
X	  else
X	    /* Line is not `.', so output it unmodified.  */
X	    print_1_line ("", &files[1].linbuf[i]);
X	}
X
X      /* End insert mode, if we are still in it.  */
X      if (inserting)
X	fprintf (outfile, ".\n");
X    }
X}
X
X/* Print change script in the style of ed commands,
X   but print the changes in the order they appear in the input files,
X   which means that the commands are not truly useful with ed.  */
X
Xvoid
Xpr_forward_ed_script (script)
X     struct change *script;
X{
X  print_script (script, find_change, pr_forward_ed_hunk);
X}
X
Xstatic void
Xpr_forward_ed_hunk (hunk)
X     struct change *hunk;
X{
X  int i;
X  int f0, l0, f1, l1;
X  int deletes, inserts;
X
X  /* Determine range of line numbers involved in each file.  */
X  analyze_hunk (hunk, &f0, &l0, &f1, &l1, &deletes, &inserts);
X  if (!deletes && !inserts)
X    return;
X
X  fprintf (outfile, "%c", change_letter (inserts, deletes));
X  print_number_range (' ', files, f0, l0);
X  fprintf (outfile, "\n");
X
X  /* If deletion only, print just the number range.  */
X
X  if (!inserts)
X    return;
X
X  /* For insertion (with or without deletion), print the number range
X     and the lines from file 2.  */
X
X  for (i = f1; i <= l1; i++)
X    print_1_line ("", &files[1].linbuf[i]);
X
X  fprintf (outfile, ".\n");
X}
X
X/* Print in a format somewhat like ed commands
X   except that each insert command states the number of lines it inserts.
X   This format is used for RCS.  */
X
Xvoid
Xprint_rcs_script (script)
X     struct change *script;
X{
X  print_script (script, find_change, print_rcs_hunk);
X}
X
X/* Print a hunk of an RCS diff */
X
Xstatic void
Xprint_rcs_hunk (hunk)
X     struct change *hunk;
X{
X  int i;
X  int f0, l0, f1, l1;
X  int deletes, inserts;
X  int tf0, tl0, tf1, tl1;
X
X  /* Determine range of line numbers involved in each file.  */
X  analyze_hunk (hunk, &f0, &l0, &f1, &l1, &deletes, &inserts);
X  if (!deletes && !inserts)
X    return;
X
X  translate_range (&files[0], f0, l0, &tf0, &tl0);
X
X  if (deletes)
X    {
X      fprintf (outfile, "d");
X      /* For deletion, print just the starting line number from file 0
X	 and the number of lines deleted.  */
X      fprintf (outfile, "%d %d\n",
X	       tf0,
X	       (tl0 >= tf0 ? tl0 - tf0 + 1 : 1));	     
X    }
X
X  if (inserts)
X    {
X      fprintf (outfile, "a");
X
X      /* Take last-line-number from file 0 and # lines from file 1.  */
X      translate_range (&files[1], f1, l1, &tf1, &tl1);
X      fprintf (outfile, "%d %d\n",
X	       tl0,
X	       (tl1 >= tf1 ? tl1 - tf1 + 1 : 1));	     
X
X      /* Print the inserted lines.  */
X      for (i = f1; i <= l1; i++)
X	print_1_line ("", &files[1].linbuf[i]);
X    }
X}
SHAR_EOF
echo "extracting diff/io.c"
sed 's/^X//' << \SHAR_EOF > diff/io.c
X/* File I/O for GNU DIFF.
X   Copyright (C) 1988, 1989 Free Software Foundation, Inc.
X
XThis file is part of GNU DIFF.
X
XGNU DIFF is free software; you can redistribute it and/or modify
Xit under the terms of the GNU General Public License as published by
Xthe Free Software Foundation; either version 1, or (at your option)
Xany later version.
X
XGNU DIFF is distributed in the hope that it will be useful,
Xbut WITHOUT ANY WARRANTY; without even the implied warranty of
XMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
XGNU General Public License for more details.
X
XYou should have received a copy of the GNU General Public License
Xalong with GNU DIFF; see the file COPYING.  If not, write to
Xthe Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
X
X#include "diff.h"
X
X/* Rotate a value n bits to the left. */
X#define UINT_BIT (sizeof (unsigned) * CHAR_BIT)
X#define ROL(v, n) ((v) << (n) | (v) >> UINT_BIT - (n))
X
X/* Given a hash value and a new character, return a new hash value. */
X#define HASH(h, c) ((c) + ROL (h, 7))
X
X/* Current file under consideration. */
Xstruct file_data *current;
X
X/* Check for binary files and compare them for exact identity.  */
X
X/* Return 1 if BUF contains a character with the 0200 bit set.
X   SIZE is the number of characters in BUF.  */
X
Xstatic int
Xbinary_file_p (buf, size)
X     char *buf;
X     int size;
X{
X  while (--size >= 0)
X    if (*buf++ & 0200)
X      return 1;
X  return 0;
X}
X
Xint binary_file_threshold = 512;
X
X/* Slurp the current file completely into core.
X   Return nonzero if it appears to be a binary file.  */
X
Xstatic int
Xslurp ()
X{
X  /* If we have a nonexistent file at this stage, treat it as empty.  */
X  if (current->desc < 0)
X    {
X      current->bufsize = 0;
X      current->buffered_chars = 0;
X      current->buffer = 0;
X    }
X  /* If it's a regular file, we can just get the size out of the stat
X     block and slurp it in all at once. */
X  /* In all cases, we leave room in the buffer for 2 extra chars
X     beyond those that current->bufsize describes:
X     one for a newline (in case the text does not end with one)
X     and one for a sentinel in find_identical_ends.  */
X#ifdef AMIGA
X  else if (current->stat.st_type < 0)
X#else
X  else if ((current->stat.st_mode & S_IFMT) == S_IFREG)
X#endif
X    {
X      current->bufsize = current->stat.st_size;
X      current->buffer = (char *) xmalloc (current->bufsize + 2);
X      current->buffered_chars
X	= read (current->desc, current->buffer, current->bufsize);
X      if (current->buffered_chars < 0)
X	pfatal_with_name (current->name);
X    }
X  else
X    {
X      int cc;
X
X      current->bufsize = 4096;
X      current->buffer = (char *) xmalloc (current->bufsize + 2);
X      current->buffered_chars = 0;
X      
X      /* Not a regular file; read it in a little at a time, growing the
X	 buffer as necessary. */
X      while ((cc = read (current->desc,
X			 current->buffer + current->buffered_chars,
X			 current->bufsize - current->buffered_chars))
X	     > 0)
X	{
X	  current->buffered_chars += cc;
X	  if (current->buffered_chars == current->bufsize)
X	    {
X	      current->bufsize = current->bufsize * 2;
X	      current->buffer = (char *) xrealloc (current->buffer,
X						   current->bufsize + 2);
X	    }
X	}
X      if (cc < 0)
X	pfatal_with_name (current->name);
X    }
X  
X  /* Check first part of file to see if it's a binary file.  */
X  if (! always_text_flag
X      && binary_file_p (current->buffer,
X			min (current->buffered_chars, binary_file_threshold)))
X    return 1;
X
X  /* If not binary, make sure text ends in a newline,
X     but remember that we had to add one.  */
X  if (current->buffered_chars > 0
X      && current->buffer[current->buffered_chars - 1] != '\n')
X    {
X      current->missing_newline = 1;
X      current->buffer[current->buffered_chars++] = '\n';
X    }
X  else
X    current->missing_newline = 0;
X
X  return 0;
X}
X
X/* Split the file into lines, simultaneously computing the hash codes for
X   each line. */
X
Xvoid
Xfind_and_hash_each_line ()
X{
X  unsigned h;
X  int i;
X  unsigned char *p = (unsigned char *) current->prefix_end, *ip, c;
X
X  /* Attempt to get a good initial guess as to the number of lines. */
X  current->linbufsize = current->buffered_chars / 50 + 5;
X  current->linbuf
X    = (struct line_def *) xmalloc (current->linbufsize * sizeof (struct line_def));
X
X  if (function_regexp)
X    {
X      /* If the -C or -F option is used, we need to find the lines
X	 of the matching prefix.  At least we will need to find the last few,
X	 but since we don't know how many, it's easiest to find them all.  */
X      current->buffered_lines = 0;
X      p = (unsigned char *) current->buffer;
X    }
X  else
X    {
X      /* Skip the identical prefixes, except be prepared to handle context.
X	 In fact, handle 1 more preceding line than the context says,
X	 in case shift_boundaries moves things backwards in this file.  */
X      current->buffered_lines = current->prefix_lines - context - 1;
X      if (current->buffered_lines < 0)
X	current->buffered_lines = 0;
X      for (i = 0; i < context + 1; ++i)
X	/* Unless we are at the beginning, */
X	if ((char *) p != current->buffer)
X	  /* Back up at least 1 char until at the start of a line.  */
X	  while ((char *) --p != current->buffer && p[-1] != '\n')
X	    ;
X    }
X
X  while ((char *) p < current->suffix_begin)
X    {
X      h = 0;
X      ip = p;
X
X      if (current->prefix_end <= (char *) p)
X	{
X	  /* Hash this line until we find a newline. */
X	  if (ignore_case_flag)
X	    {
X	      if (ignore_all_space_flag)
X		while ((c = *p) != '\n')
X		  {
X		    if (! isspace (c))
X		      if (isupper (c))
X			h = HASH (h, tolower (c));
X		      else
X			h = HASH (h, c);
X		    ++p;
X		  }
X	      else if (ignore_space_change_flag)
X
X		while ((c = *p) != '\n')
X		  {
X		    if (c == ' ' || c == '\t')
X		      {
X			while ((c = *p) == ' ' || c == '\t')
X			  ++p;
X			if (c == '\n')
X			  break;
X			h = HASH (h, ' ');
X		      }
X		    else if (isupper (c))
X		      h = HASH (h, tolower (c));
X		    else
X		      h = HASH (h, c);
X		    ++p;
X		  }
X	      else
X		while ((c = *p) != '\n')
X		  {
X		    if (isupper (c))
X		      h = HASH (h, tolower (c));
X		    else
X		      h = HASH (h, c);
X		    ++p;
X		  }
X	    }
X	  else
X	    {
X	      if (ignore_all_space_flag)
X		while ((c = *p) != '\n')
X		  {
X		    if (! isspace (c))
X		      h = HASH (h, c);
X		    ++p;
X		  }
X	      else if (ignore_space_change_flag)
X		while ((c = *p) != '\n')
X		  {
X		    if (c == ' ' || c == '\t')
X		      {
X			while ((c = *p) == ' ' || c == '\t')
X			  ++p;
X			if (c == '\n')
X			  break;
X			h = HASH (h, ' ');
X		      }
X		    else
X		      h = HASH (h, c);
X		    ++p;
X		  }
X	      else
X		while ((c = *p) != '\n')
X		  {
X		    h = HASH (h, c);
X		    ++p;
X		  }
X	    }
X	}
X      else
X	/* This line is part of the matching prefix,
X	   so we don't need to hash it.  */
X	while (*p != '\n')
X	  ++p;
X      
X      /* Maybe increase the size of the line table. */
X      if (current->buffered_lines >= current->linbufsize)
X	{
X	  while (current->buffered_lines >= current->linbufsize)
X	    current->linbufsize *= 2;
X	  current->linbuf
X	    = (struct line_def *) xrealloc (current->linbuf,
X					    current->linbufsize
X					    * sizeof (struct line_def));
X	}
X      current->linbuf[current->buffered_lines].text = (char *) ip;
X      current->linbuf[current->buffered_lines].length = p - ip;
X      current->linbuf[current->buffered_lines].hash = h;
X      ++current->buffered_lines;
X      ++p;
X    }
X
X  i = 0;
X  while (i < context && (char *) p < current->buffer + current->buffered_chars)
X    {
X      ip = p;
X      while (*p++ != '\n')
X	;
X      /* Maybe increase the size of the line table. */
X      if (current->buffered_lines >= current->linbufsize)
X	{
X	  while (current->buffered_lines >= current->linbufsize)
X	    current->linbufsize *= 2;
X	  current->linbuf
X	    = (struct line_def *) xrealloc (current->linbuf,
X					    current->linbufsize
X					    * sizeof (struct line_def));
X	}
X      current->linbuf[current->buffered_lines].text = (char *) ip;
X      current->linbuf[current->buffered_lines].length = p - ip - 1;
X      current->linbuf[current->buffered_lines].hash = 0;
X      ++current->buffered_lines;
X      ++i;
X    }
X}
X
X/* Given a vector of two file_data objects, find the identical
X   prefixes and suffixes of each object. */
X
Xstatic void
Xfind_identical_ends (filevec)
X     struct file_data filevec[];
X{
X  char *p0, *p1, *end0, *beg0;
X  int lines;
X
X  if (filevec[0].buffered_chars == 0 || filevec[1].buffered_chars == 0)
X    {
X      filevec[0].prefix_end = filevec[0].buffer;
X      filevec[1].prefix_end = filevec[1].buffer;
X      filevec[0].prefix_lines = filevec[1].prefix_lines = 0;
X      filevec[0].suffix_begin = filevec[0].buffer + filevec[0].buffered_chars;
X      filevec[1].suffix_begin = filevec[1].buffer + filevec[1].buffered_chars;
X      filevec[0].suffix_lines = filevec[1].suffix_lines = 0;
X      return;
X    }
X
X  /* Find identical prefix.  */
X
X  p0 = filevec[0].buffer;
X  p1 = filevec[1].buffer;
X  lines = 0;
X
X  /* Insert end "sentinels", in this case characters that are guarranteed
X     to make the equality test false, and thus terminate the loop.  */
X
X  if (filevec[0].buffered_chars < filevec[1].buffered_chars)
X    p0[filevec[0].buffered_chars] = ~p1[filevec[0].buffered_chars];
X  else
X    p1[filevec[1].buffered_chars] = ~p0[filevec[1].buffered_chars];
X
X  /* Loop until first mismatch, or to the sentinel characters.  */
X  while (1)
X    {
X      char c = *p0++;
X      if (c != *p1++)
X	break;
X      if (c == '\n')
X	++lines;
X    }
X
X  /* If the sentinel was passed, and lengths are equal, the
X     files are identical.  */
X  if (p0 - filevec[0].buffer > filevec[0].buffered_chars
X      && filevec[0].buffered_chars == filevec[1].buffered_chars)
X    {
X      filevec[0].prefix_end = p0 - 1;
X      filevec[1].prefix_end = p1 - 1;
X      filevec[0].prefix_lines = filevec[1].prefix_lines = lines;
X      filevec[0].suffix_begin = filevec[0].buffer;
X      filevec[1].suffix_begin = filevec[1].buffer;
X      filevec[0].suffix_lines = filevec[1].suffix_lines = lines;
X      return;
X    }
X
X  /* Point at first nonmatching characters.  */
X  --p0, --p1;
X
X  /* Skip back to last line-beginning in the prefix.  */
X  while (p0 != filevec[0].buffer && p0[-1] != '\n')
X    --p0, --p1;
X
X  /* Record the prefix.  */
X  filevec[0].prefix_end = p0;
X  filevec[1].prefix_end = p1;
X  filevec[0].prefix_lines = filevec[1].prefix_lines = lines;
X  
X  /* Find identical suffix.  */
X
X  /* P0 and P1 point beyond the last chars not yet compared.  */
X  p0 = filevec[0].buffer + filevec[0].buffered_chars;
X  p1 = filevec[1].buffer + filevec[1].buffered_chars;
X  lines = 0;
X  end0 = p0;		/* Addr of last char in file 0.  */
X
X  /* Get value of P0 at which we should stop scanning backward:
X     this is when either P0 or P1 points at the last char
X     of the identical prefix.  */
X  if (filevec[0].buffered_chars < filevec[1].buffered_chars)
X    beg0 = filevec[0].prefix_end - 1;
X  else
X    beg0 = (filevec[0].prefix_end - 1
X	    + filevec[1].buffered_chars - filevec[0].buffered_chars);
X
X  /* Scan back until chars don't match or we reach that point.  */
X  while (p0 != beg0)
X    {
X      char c = *--p0;
X      if (c != *--p1)
X	break;
X      if (c == '\n')
X	++lines;
X    }
X
X  /* Make P0 and P1 point at the first char of the matching suffix.  */
X  ++p0, ++p1;
X
X  /* Advance to next place that is a line-beginning in both files.  */
X  while (p0 != end0
X	 && !((p0 == filevec[0].buffer || p0[-1] == '\n')
X	      &&
X	      (p1 == filevec[1].buffer || p1[-1] == '\n')))
X    ++p0, ++p1;
X
X  /* Subtract one, since the last newline isn't followed by a line.  */
X  --lines;
X  
X  /* Record the suffix.  */
X  filevec[0].suffix_begin = p0;
X  filevec[1].suffix_begin = p1;
X  filevec[0].suffix_lines = filevec[1].suffix_lines = lines;
X}
X
X/* Lines are put into equivalence classes (of lines that match in line_cmp).
X   Each equivalence class is represented by one of these structures,
X   but only while the classes are being computed.
X   Afterward, each class is represented by a number.  */
Xstruct equivclass
X{
X  struct equivclass *next;	/* Next item in this bucket. */
X  struct line_def line;	/* A line that fits this class. */
X};
X
X/* Hash-table: array of buckets, each being a chain of equivalence classes.  */
Xstatic struct equivclass **buckets;
X  
X/* Size of the bucket array. */
Xstatic int nbuckets;
X
X/* Array in which the equivalence classes are allocated.
X   The bucket-chains go through the elements in this array.
X   The number of an equivalence class is its index in this array.  */
Xstatic struct equivclass *equivs;
X
X/* Index of first free element in the array `equivs'.  */
Xstatic int equivs_index;
X
X/* Size allocated to the array `equivs'.  */
Xstatic int equivs_alloc;
X
X/* Largest primes less than some power of two, for nbuckets.  Values range
X   from useful to preposterous.  If one of these numbers isn't prime
X   after all, don't blame it on me, blame it on primes (6) . . . */
Xstatic int primes[] =
X{
X  509,
X  1021,
X  2039,
X  4093,
X  8191,
X  16381,
X  32749,
X  65521,
X  131071,
X  262139,
X  524287,
X  1048573,
X  2097143,
X  4194301,
X  8388593,
X  16777213,
X  33554393,
X  67108859,			/* Preposterously large . . . */
X  -1
X};
X
X/* Index of current nbuckets in primes. */
Xstatic int primes_index;
X
X/* Find the equiv class associated with line N of the current file.  */
X
Xstatic int
Xfind_equiv_class (n)
X     int n;
X{
X  int bucket = current->linbuf[n].hash % nbuckets;
X  struct equivclass *b = buckets[bucket], *p = NULL;
X
X  /* Equivalence class 0 is permanently allocated to lines that were
X     not hashed because they were parts of identical prefixes or
X     suffixes. */
X  if (n < current->prefix_lines
X      || current->linbuf[n].text >= current->suffix_begin)
X    return 0;
X
X  /* Check through the appropriate bucket to see if there isn't already
X     an equivalence class for this line. */
X  while (b)
X    {
X      if (b->line.hash == current->linbuf[n].hash
X	  && (b->line.length == current->linbuf[n].length
X	      /* Lines of different lengths can match with certain options.  */
X	      || length_varies)
X	  && !line_cmp (&b->line, &current->linbuf[n]))
X	return b - equivs;
X      p = b, b = b->next;
X    }
X
X  /* Create a new equivalence class in this bucket. */
X
X  p = &equivs[equivs_index++];
X  p->next = buckets[bucket];
X  buckets[bucket] = p;
X  p->line = current->linbuf[n];
X
X  return equivs_index - 1;
X}
X
X/* Given a vector of two file_data objects, read the file associated
X   with each one, and build the table of equivalence classes.
X   Return nonzero if either file appears to be a binary file.  */
X
Xint
Xread_files (filevec)
X     struct file_data filevec[];
X{
X  int i, j;
X  int binary = 0;
X  int this_binary;
X
X  current = &filevec[0];
X  binary = this_binary = slurp ();
X
X  current = &filevec[1];
X  this_binary = slurp ();
X  if (binary || this_binary)
X    return 1;
X
X  find_identical_ends (filevec);
X
X  for (i = 0; i < 2; ++i)
X    {
X      current = &filevec[i];
X      find_and_hash_each_line ();
X    }
X
X  /* This is guaranteed to be enough space.  */
X  equivs_alloc = filevec[0].buffered_lines + filevec[1].buffered_lines + 1;
X  equivs = (struct equivclass *) xmalloc (equivs_alloc * sizeof (struct equivclass));
X  /* Equivalence class 0 is permanently safe for lines that were not
X     hashed.  Real equivalence classes start at 1. */
X  equivs_index = 1;
X  
X  primes_index = 0;
X  while (primes[primes_index] < equivs_alloc / 3)
X    primes_index++;
X
X  buckets = (struct equivclass **) xmalloc (primes[primes_index] * sizeof (struct equivclass *));
X  bzero (buckets, primes[primes_index] * sizeof (struct equivclass *));
X  nbuckets = primes[primes_index];
X
X  for (i = 0; i < 2; ++i)
X    {
X      current = &filevec[i];
X      current->equivs
X	= (int *) xmalloc (current->buffered_lines * sizeof (int));
X      for (j = 0; j < current->buffered_lines; ++j)
X	current->equivs[j] = find_equiv_class (j);
X    }
X
X  filevec[0].equiv_max = filevec[1].equiv_max = equivs_index;
X
X  free (equivs);
X  free (buckets);
X
X  return 0;
X}
SHAR_EOF
echo "extracting diff/normal.c"
sed 's/^X//' << \SHAR_EOF > diff/normal.c
X/* Normal-format output routines for GNU DIFF.
X   Copyright (C) 1988, 1989 Free Software Foundation, Inc.
X
XThis file is part of GNU DIFF.
X
XGNU DIFF is free software; you can redistribute it and/or modify
Xit under the terms of the GNU General Public License as published by
Xthe Free Software Foundation; either version 1, or (at your option)
Xany later version.
X
XGNU DIFF is distributed in the hope that it will be useful,
Xbut WITHOUT ANY WARRANTY; without even the implied warranty of
XMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
XGNU General Public License for more details.
X
XYou should have received a copy of the GNU General Public License
Xalong with GNU DIFF; see the file COPYING.  If not, write to
Xthe Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
X
X
X#include "diff.h"
X
Xvoid print_normal_hunk ();
Xvoid print_number_range ();
Xstruct change *find_change ();
X
X/* Print the edit-script SCRIPT as a normal diff.
X   INF points to an array of descriptions of the two files.  */
X
Xvoid
Xprint_normal_script (script)
X     struct change *script;
X{
X  print_script (script, find_change, print_normal_hunk);
X}
X
X/* Print a hunk of a normal diff.
X   This is a contiguous portion of a complete edit script,
X   describing changes in consecutive lines.  */
X
Xvoid
Xprint_normal_hunk (hunk)
X     struct change *hunk;
X{
X  int first0, last0, first1, last1, deletes, inserts;
X  register int i;
X
X  /* Determine range of line numbers involved in each file.  */
X  analyze_hunk (hunk, &first0, &last0, &first1, &last1, &deletes, &inserts);
X  if (!deletes && !inserts)
X    return;
X
X  /* Print out the line number header for this hunk */
X  print_number_range (',', &files[0], first0, last0);
X  fprintf (outfile, "%c", change_letter (inserts, deletes));
X  print_number_range (',', &files[1], first1, last1);
X  fprintf (outfile, "\n");
X
X  /* Print the lines that the first file has.  */
X  if (deletes)
X    for (i = first0; i <= last0; i++)
X      print_1_line ("<", &files[0].linbuf[i]);
X
X  if (inserts && deletes)
X    fprintf (outfile, "---\n");
X
X  /* Print the lines that the second file has.  */
X  if (inserts)
X    for (i = first1; i <= last1; i++)
X      print_1_line (">", &files[1].linbuf[i]);
X}
SHAR_EOF
echo "extracting diff/regex.c"
sed 's/^X//' << \SHAR_EOF > diff/regex.c
X/* Extended regular expression matching and search library.
X   Copyright (C) 1985, 1989 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 1, 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
X   In other words, you are welcome to use, share and improve this program.
X   You are forbidden to forbid anyone else to use, share and improve
X   what you give them.   Help stamp out software-hoarding!  */
X
X
X/* To test, compile with -Dtest.
X This Dtestable feature turns this into a self-contained program
X which reads a pattern, describes how it compiles,
X then reads a string and searches for it.  */
X
X#ifdef AMIGA
X#define bcmp(a,b,l) memcmp(a,b,l)
X#define bcopy(f,t,l) movmem(f,t,l)
X#define bzero(a,l) memset(a,'0',l)
X#define alloca(n) malloc(n)
X#endif
X
X#ifdef emacs
X
X/* The `emacs' switch turns on certain special matching commands
X that make sense only in emacs. */
X
X#include "config.h"
X#include "lisp.h"
X#include "buffer.h"
X#include "syntax.h"
X
X#else  /* not emacs */
X
X#ifdef USG
X#ifndef BSTRING
X#define bcopy(s,d,n)	memcpy((d),(s),(n))
X#define bcmp(s1,s2,n)	memcmp((s1),(s2),(n))
X#define bzero(s,n)	memset((s),0,(n))
X#endif
X#endif
X
X/* Make alloca work the best possible way.  */
X#ifdef __GNUC__
X#define alloca __builtin_alloca
X#else
X#ifdef sparc
X#include <alloca.h>
X#endif
X#endif
X
X/*
X * Define the syntax stuff, so we can do the \<...\> things.
X */
X
X#ifndef Sword /* must be non-zero in some of the tests below... */
X#define Sword 1
X#endif
X
X#define SYNTAX(c) re_syntax_table[c]
X
X#ifdef SYNTAX_TABLE
X
Xchar *re_syntax_table;
X
X#else
X
Xstatic char re_syntax_table[256];
X
Xstatic void
Xinit_syntax_once ()
X{
X   register int c;
X   static int done = 0;
X
X   if (done)
X     return;
X
X   bzero (re_syntax_table, sizeof re_syntax_table);
X
X   for (c = 'a'; c <= 'z'; c++)
X     re_syntax_table[c] = Sword;
X
X   for (c = 'A'; c <= 'Z'; c++)
X     re_syntax_table[c] = Sword;
X
X   for (c = '0'; c <= '9'; c++)
X     re_syntax_table[c] = Sword;
X
X   done = 1;
X}
X
X#endif /* SYNTAX_TABLE */
X#endif /* not emacs */
X
X#include "regex.h"
X
X/* Number of failure points to allocate space for initially,
X when matching.  If this number is exceeded, more space is allocated,
X so it is not a hard limit.  */
X
X#ifndef NFAILURES
X#define NFAILURES 80
X#endif /* NFAILURES */
X
X/* width of a byte in bits */
X
X#define BYTEWIDTH 8
X
X#ifndef SIGN_EXTEND_CHAR
X#define SIGN_EXTEND_CHAR(x) (x)
X#endif
X
Xstatic int obscure_syntax = 0;
X
X/* Specify the precise syntax of regexp for compilation.
X   This provides for compatibility for various utilities
X   which historically have different, incompatible syntaxes.
X
X   The argument SYNTAX is a bit-mask containing the two bits
X   RE_NO_BK_PARENS and RE_NO_BK_VBAR.  */
X
Xint
Xre_set_syntax (syntax)
X{
X  int ret;
X
X  ret = obscure_syntax;
X  obscure_syntax = syntax;
X  return ret;
X}
X
X/* re_compile_pattern takes a regular-expression string
X   and converts it into a buffer full of byte commands for matching.
X
X  PATTERN   is the address of the pattern string
X  SIZE      is the length of it.
X  BUFP	    is a  struct re_pattern_buffer *  which points to the info
X	    on where to store the byte commands.
X	    This structure contains a  char *  which points to the
X	    actual space, which should have been obtained with malloc.
X	    re_compile_pattern may use  realloc  to grow the buffer space.
X
X  The number of bytes of commands can be found out by looking in
X  the  struct re_pattern_buffer  that bufp pointed to,
X  after re_compile_pattern returns.
X*/
X
X#define PATPUSH(ch) (*b++ = (char) (ch))
X
X#define PATFETCH(c) \
X {if (p == pend) goto end_of_pattern; \
X  c = * (unsigned char *) p++; \
X  if (translate) c = translate[c]; }
X
X#define PATFETCH_RAW(c) \
X {if (p == pend) goto end_of_pattern; \
X  c = * (unsigned char *) p++; }
X
X#define PATUNFETCH p--
X
X#define EXTEND_BUFFER \
X  { char *old_buffer = bufp->buffer; \
X    if (bufp->allocated == (1<<16)) goto too_big; \
X    bufp->allocated *= 2; \
X    if (bufp->allocated > (1<<16)) bufp->allocated = (1<<16); \
X    if (!(bufp->buffer = (char *) realloc (bufp->buffer, bufp->allocated))) \
X      goto memory_exhausted; \
X    c = bufp->buffer - old_buffer; \
X    b += c; \
X    if (fixup_jump) \
X      fixup_jump += c; \
X    if (laststart) \
X      laststart += c; \
X    begalt += c; \
X    if (pending_exact) \
X      pending_exact += c; \
X  }
X
Xstatic int store_jump (), insert_jump ();
X
Xchar *
Xre_compile_pattern (pattern, size, bufp)
X     char *pattern;
X     int size;
X     struct re_pattern_buffer *bufp;
X{
X  register char *b = bufp->buffer;
X  register char *p = pattern;
X  char *pend = pattern + size;
X  register unsigned c, c1;
X  char *p1;
X  unsigned char *translate = (unsigned char *) bufp->translate;
X
X  /* address of the count-byte of the most recently inserted "exactn" command.
X    This makes it possible to tell whether a new exact-match character
X    can be added to that command or requires a new "exactn" command. */
X     
X  char *pending_exact = 0;
X
X  /* address of the place where a forward-jump should go
X    to the end of the containing expression.
X    Each alternative of an "or", except the last, ends with a forward-jump
X    of this sort. */
X
X  char *fixup_jump = 0;
X
X  /* address of start of the most recently finished expression.
X    This tells postfix * where to find the start of its operand. */
X
X  char *laststart = 0;
X
X  /* In processing a repeat, 1 means zero matches is allowed */
X
X  char zero_times_ok;
X
X  /* In processing a repeat, 1 means many matches is allowed */
X
X  char many_times_ok;
X
X  /* address of beginning of regexp, or inside of last \( */
X
X  char *begalt = b;
X
X  /* Stack of information saved by \( and restored by \).
X     Four stack elements are pushed by each \(:
X       First, the value of b.
X       Second, the value of fixup_jump.
X       Third, the value of regnum.
X       Fourth, the value of begalt.  */
X
X  int stackb[40];
X  int *stackp = stackb;
X  int *stacke = stackb + 40;
X  int *stackt;
X
X  /* Counts \('s as they are encountered.  Remembered for the matching \),
X     where it becomes the "register number" to put in the stop_memory command */
X
X  int regnum = 1;
X
X  bufp->fastmap_accurate = 0;
X
X#ifndef emacs
X#ifndef SYNTAX_TABLE
X  /*
X   * Initialize the syntax table.
X   */
X   init_syntax_once();
X#endif
X#endif
X
X  if (bufp->allocated == 0)
X    {
X      bufp->allocated = 28;
X      if (bufp->buffer)
X	/* EXTEND_BUFFER loses when bufp->allocated is 0 */
X	bufp->buffer = (char *) realloc (bufp->buffer, 28);
X      else
X	/* Caller did not allocate a buffer.  Do it for him */
X	bufp->buffer = (char *) malloc (28);
X      if (!bufp->buffer) goto memory_exhausted;
X      begalt = b = bufp->buffer;
X    }
X
X  while (p != pend)
X    {
X      if (b - bufp->buffer > bufp->allocated - 10)
X	/* Note that EXTEND_BUFFER clobbers c */
X	EXTEND_BUFFER;
X
X      PATFETCH (c);
X
X      switch (c)
X	{
X	case '$':
X	  if (obscure_syntax & RE_TIGHT_VBAR)
X	    {
X	      if (! (obscure_syntax & RE_CONTEXT_INDEP_OPS) && p != pend)
X		goto normal_char;
X	      /* Make operand of last vbar end before this `$'.  */
X	      if (fixup_jump)
X		store_jump (fixup_jump, jump, b);
X	      fixup_jump = 0;
X	      PATPUSH (endline);
X	      break;
X	    }
X
X	  /* $ means succeed if at end of line, but only in special contexts.
X	    If randomly in the middle of a pattern, it is a normal character. */
X	  if (p == pend || *p == '\n'
X	      || (obscure_syntax & RE_CONTEXT_INDEP_OPS)
X	      || (obscure_syntax & RE_NO_BK_PARENS
X		  ? *p == ')'
X		  : *p == '\\' && p[1] == ')')
X	      || (obscure_syntax & RE_NO_BK_VBAR
X		  ? *p == '|'
X		  : *p == '\\' && p[1] == '|'))
X	    {
X	      PATPUSH (endline);
X	      break;
X	    }
X	  goto normal_char;
X
X	case '^':
X	  /* ^ means succeed if at beg of line, but only if no preceding pattern. */
X
X	  if (laststart && p[-2] != '\n'
X	      && ! (obscure_syntax & RE_CONTEXT_INDEP_OPS))
X	    goto normal_char;
X	  if (obscure_syntax & RE_TIGHT_VBAR)
X	    {
X	      if (p != pattern + 1
X		  && ! (obscure_syntax & RE_CONTEXT_INDEP_OPS))
X		goto normal_char;
X	      PATPUSH (begline);
X	      begalt = b;
X	    }
X	  else
X	    PATPUSH (begline);
X	  break;
X
X	case '+':
X	case '?':
X	  if (obscure_syntax & RE_BK_PLUS_QM)
X	    goto normal_char;
X	handle_plus:
X	case '*':
X	  /* If there is no previous pattern, char not special. */
X	  if (!laststart && ! (obscure_syntax & RE_CONTEXT_INDEP_OPS))
X	    goto normal_char;
X	  /* If there is a sequence of repetition chars,
X	     collapse it down to equivalent to just one.  */
X	  zero_times_ok = 0;
X	  many_times_ok = 0;
X	  while (1)
X	    {
X	      zero_times_ok |= c != '+';
X	      many_times_ok |= c != '?';
X	      if (p == pend)
X		break;
X	      PATFETCH (c);
X	      if (c == '*')
X		;
X	      else if (!(obscure_syntax & RE_BK_PLUS_QM)
X		       && (c == '+' || c == '?'))
X		;
X	      else if ((obscure_syntax & RE_BK_PLUS_QM)
X		       && c == '\\')
X		{
X		  int c1;
X		  PATFETCH (c1);
X		  if (!(c1 == '+' || c1 == '?'))
X		    {
X		      PATUNFETCH;
X		      PATUNFETCH;
X		      break;
X		    }
X		  c = c1;
X		}
X	      else
X		{
X		  PATUNFETCH;
X		  break;
X		}
X	    }
X
X	  /* Star, etc. applied to an empty pattern is equivalent
X	     to an empty pattern.  */
X	  if (!laststart)
X	    break;
X
X	  /* Now we know whether 0 matches is allowed,
X	     and whether 2 or more matches is allowed.  */
X	  if (many_times_ok)
X	    {
X	      /* If more than one repetition is allowed,
X		 put in a backward jump at the end.  */
X	      store_jump (b, maybe_finalize_jump, laststart - 3);
X	      b += 3;
X	    }
X	  insert_jump (on_failure_jump, laststart, b + 3, b);
X	  pending_exact = 0;
X	  b += 3;
X	  if (!zero_times_ok)
X	    {
X	      /* At least one repetition required: insert before the loop
X		 a skip over the initial on-failure-jump instruction */
X	      insert_jump (dummy_failure_jump, laststart, laststart + 6, b);
X	      b += 3;
X	    }
X	  break;
X
X	case '.':
X	  laststart = b;
X	  PATPUSH (anychar);
X	  break;
X
X	case '[':
X	  while (b - bufp->buffer
X		 > bufp->allocated - 3 - (1 << BYTEWIDTH) / BYTEWIDTH)
X	    /* Note that EXTEND_BUFFER clobbers c */
X	    EXTEND_BUFFER;
X
X	  laststart = b;
X	  if (*p == '^')
X	    PATPUSH (charset_not), p++;
X	  else
X	    PATPUSH (charset);
X	  p1 = p;
X
X	  PATPUSH ((1 << BYTEWIDTH) / BYTEWIDTH);
X	  /* Clear the whole map */
X	  bzero (b, (1 << BYTEWIDTH) / BYTEWIDTH);
X	  /* Read in characters and ranges, setting map bits */
X	  while (1)
X	    {
X	      PATFETCH (c);
X	      if (c == ']' && p != p1 + 1) break;
X	      if (*p == '-' && p[1] != ']')
X		{
X		  PATFETCH (c1);
X		  PATFETCH (c1);
X		  while (c <= c1)
X		    b[c / BYTEWIDTH] |= 1 << (c % BYTEWIDTH), c++;
X		}
X	      else
X		{
X		  b[c / BYTEWIDTH] |= 1 << (c % BYTEWIDTH);
X		}
X	    }
X	  /* Discard any bitmap bytes that are all 0 at the end of the map.
X	     Decrement the map-length byte too. */
X	  while ((int) b[-1] > 0 && b[b[-1] - 1] == 0)
X	    b[-1]--;
X	  b += b[-1];
X	  break;
X
X	case '(':
X	  if (! (obscure_syntax & RE_NO_BK_PARENS))
X	    goto normal_char;
X	  else
X	    goto handle_open;
X
X	case ')':
X	  if (! (obscure_syntax & RE_NO_BK_PARENS))
X	    goto normal_char;
X	  else
X	    goto handle_close;
X
X	case '\n':
X	  if (! (obscure_syntax & RE_NEWLINE_OR))
X	    goto normal_char;
X	  else
X	    goto handle_bar;
X
X	case '|':
X	  if (! (obscure_syntax & RE_NO_BK_VBAR))
X	    goto normal_char;
X	  else
X	    goto handle_bar;
X
X        case '\\':
X	  if (p == pend) goto invalid_pattern;
X	  PATFETCH_RAW (c);
X	  switch (c)
X	    {
X	    case '(':
X	      if (obscure_syntax & RE_NO_BK_PARENS)
X		goto normal_backsl;
X	    handle_open:
X	      if (stackp == stacke) goto nesting_too_deep;
X	      if (regnum < RE_NREGS)
X	        {
X		  PATPUSH (start_memory);
X		  PATPUSH (regnum);
X	        }
X	      *stackp++ = b - bufp->buffer;
X	      *stackp++ = fixup_jump ? fixup_jump - bufp->buffer + 1 : 0;
X	      *stackp++ = regnum++;
X	      *stackp++ = begalt - bufp->buffer;
X	      fixup_jump = 0;
X	      laststart = 0;
X	      begalt = b;
X	      break;
X
X	    case ')':
X	      if (obscure_syntax & RE_NO_BK_PARENS)
X		goto normal_backsl;
X	    handle_close:
X	      if (stackp == stackb) goto unmatched_close;
X	      begalt = *--stackp + bufp->buffer;
X	      if (fixup_jump)
X		store_jump (fixup_jump, jump, b);
X	      if (stackp[-1] < RE_NREGS)
X		{
X		  PATPUSH (stop_memory);
X		  PATPUSH (stackp[-1]);
X		}
X	      stackp -= 2;
X	      fixup_jump = 0;
X	      if (*stackp)
X		fixup_jump = *stackp + bufp->buffer - 1;
X	      laststart = *--stackp + bufp->buffer;
X	      break;
X
X	    case '|':
X	      if (obscure_syntax & RE_NO_BK_VBAR)
X		goto normal_backsl;
X	    handle_bar:
X	      insert_jump (on_failure_jump, begalt, b + 6, b);
X	      pending_exact = 0;
X	      b += 3;
X	      if (fixup_jump)
X		store_jump (fixup_jump, jump, b);
X	      fixup_jump = b;
X	      b += 3;
X	      laststart = 0;
X	      begalt = b;
X	      break;
X
X#ifdef emacs
X	    case '=':
X	      PATPUSH (at_dot);
X	      break;
X
X	    case 's':	
X	      laststart = b;
X	      PATPUSH (syntaxspec);
X	      PATFETCH (c);
X	      PATPUSH (syntax_spec_code[c]);
X	      break;
X
X	    case 'S':
X	      laststart = b;
X	      PATPUSH (notsyntaxspec);
X	      PATFETCH (c);
X	      PATPUSH (syntax_spec_code[c]);
X	      break;
X#endif /* emacs */
X
X	    case 'w':
X	      laststart = b;
X	      PATPUSH (wordchar);
X	      break;
X
X	    case 'W':
X	      laststart = b;
X	      PATPUSH (notwordchar);
X	      break;
X
X	    case '<':
X	      PATPUSH (wordbeg);
X	      break;
X
X	    case '>':
X	      PATPUSH (wordend);
X	      break;
X
X	    case 'b':
X	      PATPUSH (wordbound);
X	      break;
X
X	    case 'B':
X	      PATPUSH (notwordbound);
X	      break;
X
X	    case '`':
X	      PATPUSH (begbuf);
X	      break;
X
X	    case '\'':
X	      PATPUSH (endbuf);
X	      break;
X
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':
X	      c1 = c - '0';
X	      if (c1 >= regnum)
X		goto normal_char;
X	      for (stackt = stackp - 2;  stackt > stackb;  stackt -= 4)
X 		if (*stackt == c1)
X		  goto normal_char;
X	      laststart = b;
X	      PATPUSH (duplicate);
X	      PATPUSH (c1);
X	      break;
X
X	    case '+':
X	    case '?':
X	      if (obscure_syntax & RE_BK_PLUS_QM)
X		goto handle_plus;
X
X	    default:
X	    normal_backsl:
X	      /* You might think it would be useful for \ to mean
X		 not to translate; but if we don't translate it
X		 it will never match anything.  */
X	      if (translate) c = translate[c];
X	      goto normal_char;
X	    }
X	  break;
X
X	default:
X	normal_char:
X	  if (!pending_exact || pending_exact + *pending_exact + 1 != b
X	      || *pending_exact == 0177 || *p == '*' || *p == '^'
X	      || ((obscure_syntax & RE_BK_PLUS_QM)
X		  ? *p == '\\' && (p[1] == '+' || p[1] == '?')
X		  : (*p == '+' || *p == '?')))
X	    {
X	      laststart = b;
X	      PATPUSH (exactn);
X	      pending_exact = b;
X	      PATPUSH (0);
X	    }
X	  PATPUSH (c);
X	  (*pending_exact)++;
X	}
X    }
X
X  if (fixup_jump)
X    store_jump (fixup_jump, jump, b);
X
X  if (stackp != stackb) goto unmatched_open;
X
X  bufp->used = b - bufp->buffer;
X  return 0;
X
X invalid_pattern:
X  return "Invalid regular expression";
X
X unmatched_open:
X  return "Unmatched \\(";
X
X unmatched_close:
X  return "Unmatched \\)";
X
X end_of_pattern:
X  return "Premature end of regular expression";
X
X nesting_too_deep:
X  return "Nesting too deep";
X
X too_big:
X  return "Regular expression too big";
X
X memory_exhausted:
X  return "Memory exhausted";
X}
X
X/* Store where `from' points a jump operation to jump to where `to' points.
X  `opcode' is the opcode to store. */
X
Xstatic int
Xstore_jump (from, opcode, to)
X     char *from, *to;
X     char opcode;
X{
X  from[0] = opcode;
X  from[1] = (to - (from + 3)) & 0377;
X  from[2] = (to - (from + 3)) >> 8;
X  return(0);
X}
X
X/* Open up space at char FROM, and insert there a jump to TO.
X   CURRENT_END gives te end of the storage no in use,
X   so we know how much data to copy up.
X   OP is the opcode of the jump to insert.
X
X   If you call this function, you must zero out pending_exact.  */
X
Xstatic int
Xinsert_jump (op, from, to, current_end)
X     char op;
X     char *from, *to, *current_end;
X{
X  register char *pto = current_end + 3;
X  register char *pfrom = current_end;
X  while (pfrom != from)
X    *--pto = *--pfrom;
X  store_jump (from, op, to);
X  return(0);
X}
X
X/* Given a pattern, compute a fastmap from it.
X The fastmap records which of the (1 << BYTEWIDTH) possible characters
X can start a string that matches the pattern.
X This fastmap is used by re_search to skip quickly over totally implausible text.
X
X The caller must supply the address of a (1 << BYTEWIDTH)-byte data area
X as bufp->fastmap.
X The other components of bufp describe the pattern to be used.  */
X
Xvoid
Xre_compile_fastmap (bufp)
X     struct re_pattern_buffer *bufp;
X{
X  unsigned char *pattern = (unsigned char *) bufp->buffer;
X  int size = bufp->used;
X  register char *fastmap = bufp->fastmap;
X  register unsigned char *p = pattern;
X  register unsigned char *pend = pattern + size;
X  register int j;
X  unsigned char *translate = (unsigned char *) bufp->translate;
X
X  unsigned char *stackb[NFAILURES];
X  unsigned char **stackp = stackb;
X
X  bzero (fastmap, (1 << BYTEWIDTH));
X  bufp->fastmap_accurate = 1;
X  bufp->can_be_null = 0;
X      
X  while (p)
X    {
X      if (p == pend)
X	{
X	  bufp->can_be_null = 1;
X	  break;
X	}
X#ifdef SWITCH_ENUM_BUG
X      switch ((int) ((enum regexpcode) *p++))
X#else
X      switch ((enum regexpcode) *p++)
X#endif
X	{
X	case exactn:
X	  if (translate)
X	    fastmap[translate[p[1]]] = 1;
X	  else
X	    fastmap[p[1]] = 1;
X	  break;
X
X        case begline:
X        case before_dot:
X	case at_dot:
X	case after_dot:
X	case begbuf:
X	case endbuf:
X	case wordbound:
X	case notwordbound:
X	case wordbeg:
X	case wordend:
X	  continue;
X
X	case endline:
X	  if (translate)
X	    fastmap[translate['\n']] = 1;
X	  else
X	    fastmap['\n'] = 1;
X	  if (bufp->can_be_null != 1)
X	    bufp->can_be_null = 2;
X	  break;
X
X	case finalize_jump:
X	case maybe_finalize_jump:
X	case jump:
X	case dummy_failure_jump:
X	  bufp->can_be_null = 1;
X	  j = *p++ & 0377;
X	  j += SIGN_EXTEND_CHAR (*(char *)p) << 8;
X	  p += j + 1;		/* The 1 compensates for missing ++ above */
X	  if (j > 0)
X	    continue;
X	  /* Jump backward reached implies we just went through
X	     the body of a loop and matched nothing.
X	     Opcode jumped to should be an on_failure_jump.
X	     Just treat it like an ordinary jump.
X	     For a * loop, it has pushed its failure point already;
X	     if so, discard that as redundant.  */
X	  if ((enum regexpcode) *p != on_failure_jump)
X	    continue;
X	  p++;
X	  j = *p++ & 0377;
X	  j += SIGN_EXTEND_CHAR (*(char *)p) << 8;
X	  p += j + 1;		/* The 1 compensates for missing ++ above */
X	  if (stackp != stackb && *stackp == p)
X	    stackp--;
X	  continue;
X	  
X	case on_failure_jump:
X	  j = *p++ & 0377;
X	  j += SIGN_EXTEND_CHAR (*(char *)p) << 8;
X	  p++;
X	  *++stackp = p + j;
X	  continue;
X
X	case start_memory:
X	case stop_memory:
X	  p++;
X	  continue;
X
X	case duplicate:
X	  bufp->can_be_null = 1;
X	  fastmap['\n'] = 1;
X	case anychar:
X	  for (j = 0; j < (1 << BYTEWIDTH); j++)
X	    if (j != '\n')
X	      fastmap[j] = 1;
X	  if (bufp->can_be_null)
X	    return;
X	  /* Don't return; check the alternative paths
X	     so we can set can_be_null if appropriate.  */
X	  break;
X
X	case wordchar:
X	  for (j = 0; j < (1 << BYTEWIDTH); j++)
X	    if (SYNTAX (j) == Sword)
X	      fastmap[j] = 1;
X	  break;
X
X	case notwordchar:
X	  for (j = 0; j < (1 << BYTEWIDTH); j++)
X	    if (SYNTAX (j) != Sword)
X	      fastmap[j] = 1;
X	  break;
X
X#ifdef emacs
X	case syntaxspec:
X	  k = *p++;
X	  for (j = 0; j < (1 << BYTEWIDTH); j++)
X	    if (SYNTAX (j) == (enum syntaxcode) k)
X	      fastmap[j] = 1;
X	  break;
X
X	case notsyntaxspec:
X	  k = *p++;
X	  for (j = 0; j < (1 << BYTEWIDTH); j++)
X	    if (SYNTAX (j) != (enum syntaxcode) k)
X	      fastmap[j] = 1;
X	  break;
X#endif /* emacs */
X
X	case charset:
X	  for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--)
X	    if (p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH)))
X	      {
X		if (translate)
X		  fastmap[translate[j]] = 1;
X		else
X		  fastmap[j] = 1;
X	      }
X	  break;
X
X	case charset_not:
X	  /* Chars beyond end of map must be allowed */
X	  for (j = *p * BYTEWIDTH; j < (1 << BYTEWIDTH); j++)
X	    if (translate)
X	      fastmap[translate[j]] = 1;
X	    else
X	      fastmap[j] = 1;
X
X	  for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--)
X	    if (!(p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH))))
X	      {
X		if (translate)
X		  fastmap[translate[j]] = 1;
X		else
X		  fastmap[j] = 1;
X	      }
X	  break;
X	}
X
X      /* Get here means we have successfully found the possible starting characters
X	 of one path of the pattern.  We need not follow this path any farther.
X	 Instead, look at the next alternative remembered in the stack. */
X      if (stackp != stackb)
X	p = *stackp--;
X      else
X	break;
X    }
X}
X
X/* Like re_search_2, below, but only one string is specified. */
X
Xint
Xre_search (pbufp, string, size, startpos, range, regs)
X     struct re_pattern_buffer *pbufp;
X     char *string;
X     int size, startpos, range;
X     struct re_registers *regs;
X{
X  return re_search_2 (pbufp, 0, 0, string, size, startpos, range, regs, size);
X}
X
X/* Like re_match_2 but tries first a match starting at index STARTPOS,
X   then at STARTPOS + 1, and so on.
X   RANGE is the number of places to try before giving up.
X   If RANGE is negative, the starting positions tried are
X    STARTPOS, STARTPOS - 1, etc.
X   It is up to the caller to make sure that range is not so large
X   as to take the starting position outside of the input strings.
X
XThe value returned is the position at which the match was found,
X or -1 if no match was found,
X or -2 if error (such as failure stack overflow).  */
X
Xint
Xre_search_2 (pbufp, string1, size1, string2, size2, startpos, range, regs, mstop)
X     struct re_pattern_buffer *pbufp;
X     char *string1, *string2;
X     int size1, size2;
X     int startpos;
X     register int range;
X     struct re_registers *regs;
X     int mstop;
X{
X  register char *fastmap = pbufp->fastmap;
X  register unsigned char *translate = (unsigned char *) pbufp->translate;
X  int total = size1 + size2;
X  int val;
X
X  /* Update the fastmap now if not correct already */
X  if (fastmap && !pbufp->fastmap_accurate)
X    re_compile_fastmap (pbufp);
X  
X  /* Don't waste time in a long search for a pattern
X     that says it is anchored.  */
X  if (pbufp->used > 0 && (enum regexpcode) pbufp->buffer[0] == begbuf
X      && range > 0)
X    {
X      if (startpos > 0)
X	return -1;
X      else
X	range = 1;
X    }
X
X  while (1)
X    {
X      /* If a fastmap is supplied, skip quickly over characters
X	 that cannot possibly be the start of a match.
X	 Note, however, that if the pattern can possibly match
X	 the null string, we must test it at each starting point
X	 so that we take the first null string we get.  */
X
X      if (fastmap && startpos < total && pbufp->can_be_null != 1)
X	{
X	  if (range > 0)
X	    {
X	      register int lim = 0;
X	      register unsigned char *p;
X	      int irange = range;
X	      if (startpos < size1 && startpos + range >= size1)
X		lim = range - (size1 - startpos);
X
X	      p = ((unsigned char *)
X		   &(startpos >= size1 ? string2 - size1 : string1)[startpos]);
X
X	      if (translate)
X		{
X		  while (range > lim && !fastmap[translate[*p++]])
X		    range--;
X		}
X	      else
X		{
X		  while (range > lim && !fastmap[*p++])
X		    range--;
X		}
X	      startpos += irange - range;
X	    }
X	  else
X	    {
X	      register unsigned char c;
X	      if (startpos >= size1)
X		c = string2[startpos - size1];
X	      else
X		c = string1[startpos];
X	      c &= 0xff;
X	      if (translate ? !fastmap[translate[c]] : !fastmap[c])
X		goto advance;
X	    }
X	}
X
X      if (range >= 0 && startpos == total
X	  && fastmap && pbufp->can_be_null == 0)
X	return -1;
X
X      val = re_match_2 (pbufp, string1, size1, string2, size2, startpos, regs, mstop);
X      if (0 <= val)
X	{
X	  if (val == -2)
X	    return -2;
X	  return startpos;
X	}
X
X#ifdef C_ALLOCA
X      alloca (0);
X#endif /* C_ALLOCA */
X
X    advance:
X      if (!range) break;
X      if (range > 0) range--, startpos++; else range++, startpos--;
X    }
X  return -1;
X}
X
X#ifndef emacs   /* emacs never uses this */
Xint
Xre_match (pbufp, string, size, pos, regs)
X     struct re_pattern_buffer *pbufp;
X     char *string;
X     int size, pos;
X     struct re_registers *regs;
X{
X  return re_match_2 (pbufp, 0, 0, string, size, pos, regs, size);
X}
X#endif /* emacs */
X
X/* Maximum size of failure stack.  Beyond this, overflow is an error.  */
X
Xint re_max_failures = 2000;
X
Xstatic int bcmp_translate();
X/* Match the pattern described by PBUFP
X   against data which is the virtual concatenation of STRING1 and STRING2.
X   SIZE1 and SIZE2 are the sizes of the two data strings.
X   Start the match at position POS.
X   Do not consider matching past the position MSTOP.
X
X   If pbufp->fastmap is nonzero, then it had better be up to date.
X
X   The reason that the data to match are specified as two components
X   which are to be regarded as concatenated
X   is so this function can be used directly on the contents of an Emacs buffer.
X
X   -1 is returned if there is no match.  -2 is returned if there is
X   an error (such as match stack overflow).  Otherwise the value is the length
X   of the substring which was matched.  */
X
Xint
Xre_match_2 (pbufp, string1, size1, string2, size2, pos, regs, mstop)
X     struct re_pattern_buffer *pbufp;
X     unsigned char *string1, *string2;
X     int size1, size2;
X     int pos;
X     struct re_registers *regs;
X     int mstop;
X{
X  register unsigned char *p = (unsigned char *) pbufp->buffer;
X  register unsigned char *pend = p + pbufp->used;
X  /* End of first string */
X  unsigned char *end1;
X  /* End of second string */
X  unsigned char *end2;
X  /* Pointer just past last char to consider matching */
X  unsigned char *end_match_1, *end_match_2;
X  register unsigned char *d, *dend;
X  register int mcnt;
X  unsigned char *translate = (unsigned char *) pbufp->translate;
X
X /* Failure point stack.  Each place that can handle a failure further down the line
X    pushes a failure point on this stack.  It consists of two char *'s.
X    The first one pushed is where to resume scanning the pattern;
X    the second pushed is where to resume scanning the strings.
X    If the latter is zero, the failure point is a "dummy".
X    If a failure happens and the innermost failure point is dormant,
X    it discards that failure point and tries the next one. */
X
X  unsigned char *initial_stack[2 * NFAILURES];
X  unsigned char **stackb = initial_stack;
X  unsigned char **stackp = stackb, **stacke = &stackb[2 * NFAILURES];
X
X  /* Information on the "contents" of registers.
X     These are pointers into the input strings; they record
X     just what was matched (on this attempt) by some part of the pattern.
X     The start_memory command stores the start of a register's contents
X     and the stop_memory command stores the end.
X
X     At that point, regstart[regnum] points to the first character in the register,
X     regend[regnum] points to the first character beyond the end of the register,
X     regstart_seg1[regnum] is true iff regstart[regnum] points into string1,
X     and regend_seg1[regnum] is true iff regend[regnum] points into string1.  */
X
X  unsigned char *regstart[RE_NREGS];
X  unsigned char *regend[RE_NREGS];
X  unsigned char regstart_seg1[RE_NREGS], regend_seg1[RE_NREGS];
X
X  /* Set up pointers to ends of strings.
X     Don't allow the second string to be empty unless both are empty.  */
X  if (!size2)
X    {
X      string2 = string1;
X      size2 = size1;
X      string1 = 0;
X      size1 = 0;
X    }
X  end1 = string1 + size1;
X  end2 = string2 + size2;
X
X  /* Compute where to stop matching, within the two strings */
X  if (mstop <= size1)
X    {
X      end_match_1 = string1 + mstop;
X      end_match_2 = string2;
X    }
X  else
X    {
X      end_match_1 = end1;
X      end_match_2 = string2 + mstop - size1;
X    }
X
X  /* Initialize \) text positions to -1
X     to mark ones that no \( or \) has been seen for.  */
X
X  for (mcnt = 0; mcnt < sizeof (regend) / sizeof (*regend); mcnt++)
X    regend[mcnt] = (unsigned char *) -1;
X
X  /* `p' scans through the pattern as `d' scans through the data.
X     `dend' is the end of the input string that `d' points within.
X     `d' is advanced into the following input string whenever necessary,
X     but this happens before fetching;
X     therefore, at the beginning of the loop,
X     `d' can be pointing at the end of a string,
X     but it cannot equal string2.  */
X
X  if (pos <= size1)
X    d = string1 + pos, dend = end_match_1;
X  else
X    d = string2 + pos - size1, dend = end_match_2;
X
X/* Write PREFETCH; just before fetching a character with *d.  */
X#define PREFETCH \
X while (d == dend)						    \
X  { if (dend == end_match_2) goto fail;  /* end of string2 => failure */   \
X    d = string2;  /* end of string1 => advance to string2. */       \
X    dend = end_match_2; }
X
X  /* This loop loops over pattern commands.
X     It exits by returning from the function if match is complete,
X     or it drops through if match fails at this starting point in the input data. */
X
X  while (1)
X    {
X      if (p == pend)
X	/* End of pattern means we have succeeded! */
X	{
X	  /* If caller wants register contents data back, convert it to indices */
X	  if (regs)
X	    {
X 	      regs->start[0] = pos;
X 	      if (dend == end_match_1)
X 		regs->end[0] = d - string1;
X 	      else
X 		regs->end[0] = d - string2 + size1;
X 	      for (mcnt = 1; mcnt < RE_NREGS; mcnt++)
X		{
X		  if (regend[mcnt] == (unsigned char *) -1)
X		    {
X		      regs->start[mcnt] = -1;
X		      regs->end[mcnt] = -1;
X		      continue;
X		    }
X 		  if (regstart_seg1[mcnt])
X		    regs->start[mcnt] = regstart[mcnt] - string1;
X		  else
X		    regs->start[mcnt] = regstart[mcnt] - string2 + size1;
X 		  if (regend_seg1[mcnt])
X		    regs->end[mcnt] = regend[mcnt] - string1;
X		  else
X		    regs->end[mcnt] = regend[mcnt] - string2 + size1;
X		}
X	    }
X 	  if (dend == end_match_1)
X	    return (d - string1 - pos);
X	  else
X	    return d - string2 + size1 - pos;
X	}
X
X      /* Otherwise match next pattern command */
X#ifdef SWITCH_ENUM_BUG
X      switch ((int) ((enum regexpcode) *p++))
X#else
X      switch ((enum regexpcode) *p++)
X#endif
X	{
X
X	/* \( is represented by a start_memory, \) by a stop_memory.
X	    Both of those commands contain a "register number" argument.
X	    The text matched within the \( and \) is recorded under that number.
X	    Then, \<digit> turns into a `duplicate' command which
X	    is followed by the numeric value of <digit> as the register number. */
X
X	case start_memory:
X	  regstart[*p] = d;
X 	  regstart_seg1[*p++] = (dend == end_match_1);
X	  break;
X
X	case stop_memory:
X	  regend[*p] = d;
X 	  regend_seg1[*p++] = (dend == end_match_1);
X	  break;
X
X	case duplicate:
X	  {
X	    int regno = *p++;   /* Get which register to match against */
X	    register unsigned char *d2, *dend2;
X
X	    d2 = regstart[regno];
X 	    dend2 = ((regstart_seg1[regno] == regend_seg1[regno])
X		     ? regend[regno] : end_match_1);
X	    while (1)
X	      {
X		/* Advance to next segment in register contents, if necessary */
X		while (d2 == dend2)
X		  {
X		    if (dend2 == end_match_2) break;
X		    if (dend2 == regend[regno]) break;
X		    d2 = string2, dend2 = regend[regno];  /* end of string1 => advance to string2. */
X		  }
X		/* At end of register contents => success */
X		if (d2 == dend2) break;
X
X		/* Advance to next segment in data being matched, if necessary */
X		PREFETCH;
X
X		/* mcnt gets # consecutive chars to compare */
X		mcnt = dend - d;
X		if (mcnt > dend2 - d2)
X		  mcnt = dend2 - d2;
X		/* Compare that many; failure if mismatch, else skip them. */
X		if (translate ? bcmp_translate (d, d2, mcnt, translate) : bcmp (d, d2, mcnt))
X		  goto fail;
X		d += mcnt, d2 += mcnt;
X	      }
X	  }
X	  break;
X
X	case anychar:
X	  /* fetch a data character */
X	  PREFETCH;
X	  /* Match anything but a newline.  */
X	  if ((translate ? translate[*d++] : *d++) == '\n')
X	    goto fail;
X	  break;
X
X	case charset:
X	case charset_not:
X	  {
X	    /* Nonzero for charset_not */
X	    int not = 0;
X	    register int c;
X	    if (*(p - 1) == (unsigned char) charset_not)
X	      not = 1;
X
X	    /* fetch a data character */
X	    PREFETCH;
X
X	    if (translate)
X	      c = translate [*d];
X	    else
X	      c = *d;
X
X	    if (c < *p * BYTEWIDTH
X		&& p[1 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH)))
X	      not = !not;
X
X	    p += 1 + *p;
X
X	    if (!not) goto fail;
X	    d++;
X	    break;
X	  }
X
X	case begline:
X	  if (d == string1 || d[-1] == '\n')
X	    break;
X	  goto fail;
X
X	case endline:
X	  if (d == end2
X	      || (d == end1 ? (size2 == 0 || *string2 == '\n') : *d == '\n'))
X	    break;
X	  goto fail;
X
X	/* "or" constructs ("|") are handled by starting each alternative
X	    with an on_failure_jump that points to the start of the next alternative.
X	    Each alternative except the last ends with a jump to the joining point.
X	    (Actually, each jump except for the last one really jumps
X	     to the following jump, because tensioning the jumps is a hassle.) */
X
X	/* The start of a stupid repeat has an on_failure_jump that points
X	   past the end of the repeat text.
X	   This makes a failure point so that, on failure to match a repetition,
X	   matching restarts past as many repetitions have been found
X	   with no way to fail and look for another one.  */
X
X	/* A smart repeat is similar but loops back to the on_failure_jump
X	   so that each repetition makes another failure point. */
X
X	case on_failure_jump:
X	  if (stackp == stacke)
X	    {
X	      unsigned char **stackx;
X	      if (stacke - stackb > re_max_failures * 2)
X		return -2;
X	      stackx = (unsigned char **) alloca (2 * (stacke - stackb)
X					 * sizeof (char *));
X	      bcopy (stackb, stackx, (stacke - stackb) * sizeof (char *));
X	      stackp = stackx + (stackp - stackb);
X	      stacke = stackx + 2 * (stacke - stackb);
X	      stackb = stackx;
X	    }
X	  mcnt = *p++ & 0377;
X	  mcnt += SIGN_EXTEND_CHAR (*(char *)p) << 8;
X	  p++;
X	  *stackp++ = mcnt + p;
X	  *stackp++ = d;
X	  break;
X
X	/* The end of a smart repeat has an maybe_finalize_jump back.
X	   Change it either to a finalize_jump or an ordinary jump. */
X
X	case maybe_finalize_jump:
X	  mcnt = *p++ & 0377;
X	  mcnt += SIGN_EXTEND_CHAR (*(char *)p) << 8;
X	  p++;
X	  {
X	    register unsigned char *p2 = p;
X	    /* Compare what follows with the begining of the repeat.
X	       If we can establish that there is nothing that they would
X	       both match, we can change to finalize_jump */
X	    while (p2 != pend
X		   && (*p2 == (unsigned char) stop_memory
X		       || *p2 == (unsigned char) start_memory))
X	      p2++;
X	    if (p2 == pend)
X	      p[-3] = (unsigned char) finalize_jump;
X	    else if (*p2 == (unsigned char) exactn
X		     || *p2 == (unsigned char) endline)
X	      {
X		register int c = *p2 == (unsigned char) endline ? '\n' : p2[2];
X		register unsigned char *p1 = p + mcnt;
X		/* p1[0] ... p1[2] are an on_failure_jump.
X		   Examine what follows that */
X		if (p1[3] == (unsigned char) exactn && p1[5] != c)
X		  p[-3] = (unsigned char) finalize_jump;
X		else if (p1[3] == (unsigned char) charset
X			 || p1[3] == (unsigned char) charset_not)
X		  {
X		    int not = p1[3] == (unsigned char) charset_not;
X		    if (c < p1[4] * BYTEWIDTH
X			&& p1[5 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH)))
X		      not = !not;
X		    /* not is 1 if c would match */
X		    /* That means it is not safe to finalize */
X		    if (!not)
X		      p[-3] = (unsigned char) finalize_jump;
X		  }
X	      }
X	  }
X	  p -= 2;
X	  if (p[-1] != (unsigned char) finalize_jump)
X	    {
X	      p[-1] = (unsigned char) jump;
X	      goto nofinalize;
X	    }
X
X	/* The end of a stupid repeat has a finalize-jump
X	   back to the start, where another failure point will be made
X	   which will point after all the repetitions found so far. */
X
X	case finalize_jump:
X	  stackp -= 2;
X
X	case jump:
X	nofinalize:
X	  mcnt = *p++ & 0377;
X	  mcnt += SIGN_EXTEND_CHAR (*(char *)p) << 8;
X	  p += mcnt + 1;	/* The 1 compensates for missing ++ above */
X	  break;
X
X	case dummy_failure_jump:
X	  if (stackp == stacke)
X	    {
X	      unsigned char **stackx
X		= (unsigned char **) alloca (2 * (stacke - stackb)
X					     * sizeof (char *));
X	      bcopy (stackb, stackx, (stacke - stackb) * sizeof (char *));
X	      stackp = stackx + (stackp - stackb);
X	      stacke = stackx + 2 * (stacke - stackb);
X	      stackb = stackx;
X	    }
X	  *stackp++ = 0;
X	  *stackp++ = 0;
X	  goto nofinalize;
X
X	case wordbound:
X	  if (d == string1  /* Points to first char */
X	      || d == end2  /* Points to end */
X	      || (d == end1 && size2 == 0)) /* Points to end */
X	    break;
X	  if ((SYNTAX (d[-1]) == Sword)
X	      != (SYNTAX (d == end1 ? *string2 : *d) == Sword))
X	    break;
X	  goto fail;
X
X	case notwordbound:
X	  if (d == string1  /* Points to first char */
X	      || d == end2  /* Points to end */
X	      || (d == end1 && size2 == 0)) /* Points to end */
X	    goto fail;
X	  if ((SYNTAX (d[-1]) == Sword)
X	      != (SYNTAX (d == end1 ? *string2 : *d) == Sword))
X	    goto fail;
X	  break;
X
X	case wordbeg:
X	  if (d == end2  /* Points to end */
X	      || (d == end1 && size2 == 0) /* Points to end */
X	      || SYNTAX (* (d == end1 ? string2 : d)) != Sword) /* Next char not a letter */
X	    goto fail;
X	  if (d == string1  /* Points to first char */
X	      || SYNTAX (d[-1]) != Sword)  /* prev char not letter */
X	    break;
X	  goto fail;
X
X	case wordend:
X	  if (d == string1  /* Points to first char */
X	      || SYNTAX (d[-1]) != Sword)  /* prev char not letter */
X	    goto fail;
X	  if (d == end2  /* Points to end */
X	      || (d == end1 && size2 == 0) /* Points to end */
X	      || SYNTAX (d == end1 ? *string2 : *d) != Sword) /* Next char not a letter */
X	    break;
X	  goto fail;
X
X#ifdef emacs
X	case before_dot:
X	  if (((d - string2 <= (unsigned) size2)
X	       ? d - bf_p2 : d - bf_p1)
X	      <= point)
X	    goto fail;
X	  break;
X
X	case at_dot:
X	  if (((d - string2 <= (unsigned) size2)
X	       ? d - bf_p2 : d - bf_p1)
X	      == point)
X	    goto fail;
X	  break;
X
X	case after_dot:
X	  if (((d - string2 <= (unsigned) size2)
X	       ? d - bf_p2 : d - bf_p1)
X	      >= point)
X	    goto fail;
X	  break;
X
X	case wordchar:
X	  mcnt = (int) Sword;
X	  goto matchsyntax;
X
X	case syntaxspec:
X	  mcnt = *p++;
X	matchsyntax:
X	  PREFETCH;
X	  if (SYNTAX (*d++) != (enum syntaxcode) mcnt) goto fail;
X	  break;
X	  
X	case notwordchar:
X	  mcnt = (int) Sword;
X	  goto matchnotsyntax;
X
X	case notsyntaxspec:
X	  mcnt = *p++;
X	matchnotsyntax:
X	  PREFETCH;
X	  if (SYNTAX (*d++) == (enum syntaxcode) mcnt) goto fail;
X	  break;
X#else
X	case wordchar:
X	  PREFETCH;
X	  if (SYNTAX (*d++) == 0) goto fail;
X	  break;
X	  
X	case notwordchar:
X	  PREFETCH;
X	  if (SYNTAX (*d++) != 0) goto fail;
X	  break;
X#endif /* not emacs */
X
X	case begbuf:
X	  if (d == string1)	/* Note, d cannot equal string2 */
X	    break;		/* unless string1 == string2.  */
X	  goto fail;
X
X	case endbuf:
X	  if (d == end2 || (d == end1 && size2 == 0))
X	    break;
X	  goto fail;
X
X	case exactn:
X	  /* Match the next few pattern characters exactly.
X	     mcnt is how many characters to match. */
X	  mcnt = *p++;
X	  if (translate)
X	    {
X	      do
X		{
X		  PREFETCH;
X		  if (translate[*d++] != *p++) goto fail;
X		}
X	      while (--mcnt);
X	    }
X	  else
X	    {
X	      do
X		{
X		  PREFETCH;
X		  if (*d++ != *p++) goto fail;
X		}
X	      while (--mcnt);
X	    }
X	  break;
X	}
X      continue;    /* Successfully matched one pattern command; keep matching */
X
X      /* Jump here if any matching operation fails. */
X    fail:
X      if (stackp != stackb)
X	/* A restart point is known.  Restart there and pop it. */
X	{
X	  if (!stackp[-2])
X	    {   /* If innermost failure point is dormant, flush it and keep looking */
X	      stackp -= 2;
X	      goto fail;
X	    }
X	  d = *--stackp;
X	  p = *--stackp;
X	  if (d >= string1 && d <= end1)
X	    dend = end_match_1;
X	}
X      else break;   /* Matching at this starting point really fails! */
X    }
X  return -1;         /* Failure to match */
X}
X
Xstatic int
Xbcmp_translate (s1, s2, len, translate)
X     unsigned char *s1, *s2;
X     register int len;
X     unsigned char *translate;
X{
X  register unsigned char *p1 = s1, *p2 = s2;
X  while (len)
X    {
X      if (translate [*p1++] != translate [*p2++]) return 1;
X      len--;
X    }
X  return 0;
X}
X
X/* Entry points compatible with bsd4.2 regex library */
X
X#ifndef emacs
X
Xstatic struct re_pattern_buffer re_comp_buf;
X
Xchar *
Xre_comp (s)
X     char *s;
X{
X  if (!s)
X    {
X      if (!re_comp_buf.buffer)
X	return "No previous regular expression";
X      return 0;
X    }
X
X  if (!re_comp_buf.buffer)
X    {
X      if (!(re_comp_buf.buffer = (char *) malloc (200)))
X	return "Memory exhausted";
X      re_comp_buf.allocated = 200;
X      if (!(re_comp_buf.fastmap = (char *) malloc (1 << BYTEWIDTH)))
X	return "Memory exhausted";
X    }
X  return re_compile_pattern (s, strlen (s), &re_comp_buf);
X}
X
Xint
Xre_exec (s)
X     char *s;
X{
X  int len = strlen (s);
X  return 0 <= re_search (&re_comp_buf, s, len, 0, len, 0);
X}
X
X#endif /* emacs */
X
X#ifdef test
X
X#include <stdio.h>
X
X/* Indexed by a character, gives the upper case equivalent of the character */
X
Xstatic char upcase[0400] = 
X  { 000, 001, 002, 003, 004, 005, 006, 007,
X    010, 011, 012, 013, 014, 015, 016, 017,
X    020, 021, 022, 023, 024, 025, 026, 027,
X    030, 031, 032, 033, 034, 035, 036, 037,
X    040, 041, 042, 043, 044, 045, 046, 047,
X    050, 051, 052, 053, 054, 055, 056, 057,
X    060, 061, 062, 063, 064, 065, 066, 067,
X    070, 071, 072, 073, 074, 075, 076, 077,
X    0100, 0101, 0102, 0103, 0104, 0105, 0106, 0107,
X    0110, 0111, 0112, 0113, 0114, 0115, 0116, 0117,
X    0120, 0121, 0122, 0123, 0124, 0125, 0126, 0127,
X    0130, 0131, 0132, 0133, 0134, 0135, 0136, 0137,
X    0140, 0101, 0102, 0103, 0104, 0105, 0106, 0107,
X    0110, 0111, 0112, 0113, 0114, 0115, 0116, 0117,
X    0120, 0121, 0122, 0123, 0124, 0125, 0126, 0127,
X    0130, 0131, 0132, 0173, 0174, 0175, 0176, 0177,
X    0200, 0201, 0202, 0203, 0204, 0205, 0206, 0207,
X    0210, 0211, 0212, 0213, 0214, 0215, 0216, 0217,
X    0220, 0221, 0222, 0223, 0224, 0225, 0226, 0227,
X    0230, 0231, 0232, 0233, 0234, 0235, 0236, 0237,
X    0240, 0241, 0242, 0243, 0244, 0245, 0246, 0247,
X    0250, 0251, 0252, 0253, 0254, 0255, 0256, 0257,
X    0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267,
X    0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277,
X    0300, 0301, 0302, 0303, 0304, 0305, 0306, 0307,
X    0310, 0311, 0312, 0313, 0314, 0315, 0316, 0317,
X    0320, 0321, 0322, 0323, 0324, 0325, 0326, 0327,
X    0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337,
X    0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347,
X    0350, 0351, 0352, 0353, 0354, 0355, 0356, 0357,
X    0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367,
X    0370, 0371, 0372, 0373, 0374, 0375, 0376, 0377
X  };
X
Xmain (argc, argv)
X     int argc;
X     char **argv;
X{
X  char pat[80];
X  struct re_pattern_buffer buf;
X  int i;
X  char c;
X  char fastmap[(1 << BYTEWIDTH)];
X
X  /* Allow a command argument to specify the style of syntax.  */
X  if (argc > 1)
X    obscure_syntax = atoi (argv[1]);
X
X  buf.allocated = 40;
X  buf.buffer = (char *) malloc (buf.allocated);
X  buf.fastmap = fastmap;
X  buf.translate = upcase;
X
X  while (1)
X    {
X      gets (pat);
X
X      if (*pat)
X	{
X          re_compile_pattern (pat, strlen(pat), &buf);
X
X	  for (i = 0; i < buf.used; i++)
X	    printchar (buf.buffer[i]);
X
X	  putchar ('\n');
X
X	  printf ("%d allocated, %d used.\n", buf.allocated, buf.used);
X
X	  re_compile_fastmap (&buf);
X	  printf ("Allowed by fastmap: ");
X	  for (i = 0; i < (1 << BYTEWIDTH); i++)
X	    if (fastmap[i]) printchar (i);
X	  putchar ('\n');
X	}
X
X      gets (pat);	/* Now read the string to match against */
X
X      i = re_match (&buf, pat, strlen (pat), 0, 0);
X      printf ("Match value %d.\n", i);
X    }
X}
X
X#ifdef NOTDEF
Xprint_buf (bufp)
X     struct re_pattern_buffer *bufp;
X{
X  int i;
X
X  printf ("buf is :\n----------------\n");
X  for (i = 0; i < bufp->used; i++)
X    printchar (bufp->buffer[i]);
X  
X  printf ("\n%d allocated, %d used.\n", bufp->allocated, bufp->used);
X  
X  printf ("Allowed by fastmap: ");
X  for (i = 0; i < (1 << BYTEWIDTH); i++)
X    if (bufp->fastmap[i])
X      printchar (i);
X  printf ("\nAllowed by translate: ");
X  if (bufp->translate)
X    for (i = 0; i < (1 << BYTEWIDTH); i++)
X      if (bufp->translate[i])
X	printchar (i);
X  printf ("\nfastmap is%s accurate\n", bufp->fastmap_accurate ? "" : "n't");
X  printf ("can %s be null\n----------", bufp->can_be_null ? "" : "not");
X}
X#endif
X
Xprintchar (c)
X     char c;
X{
X  if (c < 041 || c >= 0177)
X    {
X      putchar ('\\');
X      putchar (((c >> 6) & 3) + '0');
X      putchar (((c >> 3) & 7) + '0');
X      putchar ((c & 7) + '0');
X    }
X  else
X    putchar (c);
X}
X
Xerror (string)
X     char *string;
X{
X  puts (string);
X  exit (1);
X}
X
X#endif /* test */
SHAR_EOF
echo "End of archive 3 (of 14)"
# if you want to concatenate archives, remove anything after this line
exit