[gnu.utils.bug] GNU diff 1.10 runtime and lint fixes

eggert@twinsun.com (Paul Eggert) (11/11/89)

We evaluated a test copy of Saber C by trying it out on GNU DIFF 1.10, and
found a few bugs.  We delinted DIFF first so that Saber C could focus on
runtime errors.  Here are many lint fixes and some runtime fixes to GNU DIFF
1.10.  Patches are relative to a previous bug report that sped up GNU DIFF
1.10.

The runtime fixes are:

	shift_boundaries() referenced one past the end of files[f].equivs when
	end==i_end.  Interchanging the order of tests fixed the problem
	(analyze.c:517 below).

	diff_2_files() did a free(script) followed by a return script?1:0; ANSI
	C doesn't let a program examine a pointer to freed storage.
	(analyze.c:816 below).

	line_cmp() referred to uninitialized storage when going one past the
	end of the input file.  (fix in io.c:122 below).

	find_equiv_class(n) referred to current->linbuf[n] even when n <
	current->prefix_lines, causing a reference to uninitialized storage.
	(fixes near io.c:499 below).

The lint fixes are:

	Adding procedure declarations.

	Removing code and variables that were never used.  In particular:

		Many routines took a struct file_data * parameter and never
		used it.

		The regex code permits obscure syntax, but this is never used.

	Casting ...alloc() size arguments to unsigned.

	Adding "" arguments to message routines.

	'preceeding' -> 'preceding'


===================================================================
RCS file: RCS/analyze.c,v
retrieving revision 1.1
diff -c -r1.1 analyze.c
*** /tmp/,RCSt1a21584	Fri Nov 10 11:48:13 1989
--- analyze.c	Thu Nov  9 22:00:31 1989
***************
*** 23,28 ****
--- 23,38 ----
  
  #include "diff.h"
  
+ void finish_output ();
+ void pr_forward_ed_script ();
+ void print_context_header ();
+ void print_context_script ();
+ void print_ed_script ();
+ void print_ifdef_script ();
+ void print_normal_script ();
+ void print_rcs_script ();
+ void setup_output ();
+ 
  extern int no_discards;
  
  static int *xvec, *yvec;	/* Vectors being compared. */
***************
*** 248,259 ****
        files[0].changed_flag[files[0].realindexes[xoff++]] = 1;
    else
      {
!       int c, d, f, b;
  
        /* Find a point of correspondence in the middle of the files.  */
  
        d = diag (xoff, xlim, yoff, ylim, &c);
-       f = fdiag[d];
        b = bdiag[d];
  
        if (c == 1)
--- 258,268 ----
        files[0].changed_flag[files[0].realindexes[xoff++]] = 1;
    else
      {
!       int c, d, b;
  
        /* Find a point of correspondence in the middle of the files.  */
  
        d = diag (xoff, xlim, yoff, ylim, &c);
        b = bdiag[d];
  
        if (c == 1)
***************
*** 276,285 ****
  	{
  	  /* Use that point to split this problem into two subproblems.  */
  	  compareseq (xoff, b, yoff, b - d);
- 	  /* This used to use f instead of b,
- 	     but that is incorrect!
- 	     It is not necessarily the case that diagonal d
- 	     has a snake from b to f.  */
  	  compareseq (b, xlim, b - d, ylim);
  	}
      }
--- 285,290 ----
***************
*** 301,307 ****
  discard_confusing_lines (filevec)
       struct file_data filevec[];
  {
!   int f, i, j, k;
    char *discarded[2];
    int *equiv_count[2];
  
--- 306,312 ----
  discard_confusing_lines (filevec)
       struct file_data filevec[];
  {
!   int f, i;
    char *discarded[2];
    int *equiv_count[2];
  
***************
*** 329,336 ****
  
    /* Set up tables of which lines are going to be discarded.  */
  
!   discarded[0] = (char *) xmalloc (filevec[0].buffered_lines);
!   discarded[1] = (char *) xmalloc (filevec[1].buffered_lines);
    bzero (discarded[0], filevec[0].buffered_lines);
    bzero (discarded[1], filevec[1].buffered_lines);
  
--- 334,341 ----
  
    /* Set up tables of which lines are going to be discarded.  */
  
!   discarded[0] = (char *) xmalloc ((unsigned) filevec[0].buffered_lines);
!   discarded[1] = (char *) xmalloc ((unsigned) filevec[1].buffered_lines);
    bzero (discarded[0], filevec[0].buffered_lines);
    bzero (discarded[1], filevec[1].buffered_lines);
  
***************
*** 421,427 ****
      {
        char *discards = discarded[f];
        int end = filevec[f].buffered_lines;
!       j = 0;
        for (i = 0; i < end; ++i)
  	if (no_discards || discards[i] == 0)
  	  {
--- 426,432 ----
      {
        char *discards = discarded[f];
        int end = filevec[f].buffered_lines;
!       int j = 0;
        for (i = 0; i < end; ++i)
  	if (no_discards || discards[i] == 0)
  	  {
***************
*** 468,476 ****
        int i = 0;
        int j = 0;
        int i_end = filevec[f].buffered_lines;
!       int j_end = filevec[1-f].buffered_lines;
!       int preceeding = -1;
!       int other_preceeding = -1;
  
        while (1)
  	{
--- 473,480 ----
        int i = 0;
        int j = 0;
        int i_end = filevec[f].buffered_lines;
!       int preceding = -1;
!       int other_preceding = -1;
  
        while (1)
  	{
***************
*** 483,490 ****
  	    {
  	      while (other_changed[j++])
  		/* Non-corresponding lines in the other file
! 		   will count as the preceeding batch of changes.  */
! 		other_preceeding = j;
  	      i++;
  	    }
  
--- 487,494 ----
  	    {
  	      while (other_changed[j++])
  		/* Non-corresponding lines in the other file
! 		   will count as the preceding batch of changes.  */
! 		other_preceding = j;
  	      i++;
  	    }
  
***************
*** 510,521 ****
  	      /* You might ask, how could this run follow right after another?
  		 Only because the previous run was shifted here.  */
  
! 	      if (files[f].equivs[start] == files[f].equivs[end]
  		  && !other_changed[j]
! 		  && end != i_end
! 		  && !((preceeding >= 0 && start == preceeding)
! 		       || (other_preceeding >= 0
! 			   && other_start == other_preceeding)))
  		{
  		  changed[end++] = 1;
  		  changed[start++] = 0;
--- 514,525 ----
  	      /* You might ask, how could this run follow right after another?
  		 Only because the previous run was shifted here.  */
  
! 	      if (end != i_end
! 		  && files[f].equivs[start] == files[f].equivs[end]
  		  && !other_changed[j]
! 		  && !((preceding >= 0 && start == preceding)
! 		       || (other_preceding >= 0
! 			   && other_start == other_preceding)))
  		{
  		  changed[end++] = 1;
  		  changed[start++] = 0;
***************
*** 529,536 ****
  		break;
  	    }
  
! 	  preceeding = i;
! 	  other_preceeding = j;
  	}
      }
  }
--- 533,540 ----
  		break;
  	    }
  
! 	  preceding = i;
! 	  other_preceding = j;
  	}
      }
  }
***************
*** 686,694 ****
        && output_style != OUTPUT_RCS)
      {
        if (filevec[0].missing_newline)
! 	message ("No newline at end of file %s\n", filevec[0].name);
        if (filevec[1].missing_newline)
! 	message ("No newline at end of file %s\n", filevec[1].name);
      }
  
    /* Allocate vectors for the results of comparison:
--- 690,698 ----
        && output_style != OUTPUT_RCS)
      {
        if (filevec[0].missing_newline)
! 	message ("No newline at end of file %s\n", filevec[0].name, "");
        if (filevec[1].missing_newline)
! 	message ("No newline at end of file %s\n", filevec[1].name, "");
      }
  
    /* Allocate vectors for the results of comparison:
***************
*** 696,703 ****
       is an insertion or deletion.
       Allocate an extra element, always zero, at each end of each vector.  */
  
!   filevec[0].changed_flag = (char *) xmalloc (filevec[0].buffered_lines + 2);
!   filevec[1].changed_flag = (char *) xmalloc (filevec[1].buffered_lines + 2);
    bzero (filevec[0].changed_flag, filevec[0].buffered_lines + 2);
    bzero (filevec[1].changed_flag, filevec[1].buffered_lines + 2);
    filevec[0].changed_flag++;
--- 700,707 ----
       is an insertion or deletion.
       Allocate an extra element, always zero, at each end of each vector.  */
  
!   filevec[0].changed_flag = (char *) xmalloc ((unsigned)filevec[0].buffered_lines + 2);
!   filevec[1].changed_flag = (char *) xmalloc ((unsigned)filevec[1].buffered_lines + 2);
    bzero (filevec[0].changed_flag, filevec[0].buffered_lines + 2);
    bzero (filevec[1].changed_flag, filevec[1].buffered_lines + 2);
    filevec[0].changed_flag++;
***************
*** 799,804 ****
--- 803,811 ----
        free (filevec[i].linbuf);
      }
  
+   if (!script)
+     return 0;
+ 
    for (e = script; e; e = p)
      {
        p = e->link;
***************
*** 805,809 ****
        free (e);
      }
  
!   return script ? 1 : 0;
  }
--- 812,816 ----
        free (e);
      }
  
!   return 1;
  }
===================================================================
RCS file: RCS/context.c,v
retrieving revision 1.1
diff -c -r1.1 context.c
*** /tmp/,RCSt1a21584	Fri Nov 10 11:48:13 1989
--- context.c	Thu Nov  9 21:43:40 1989
***************
*** 20,29 ****
  #include "diff.h"
  #include "regex.h"
  
  static void pr_context_hunk ();
  static struct change *find_hunk ();
  static void mark_ignorable ();
! static int find_function ();
  
  /* Last place find_function started searching from.  */
  static int find_function_last_search;
--- 20,31 ----
  #include "diff.h"
  #include "regex.h"
  
+ void translate_range ();
+ 
  static void pr_context_hunk ();
  static struct change *find_hunk ();
  static void mark_ignorable ();
! static void find_function ();
  
  /* Last place find_function started searching from.  */
  static int find_function_last_search;
***************
*** 64,70 ****
    print_script (script, find_hunk, pr_context_hunk);
  }
  
! /* Print a pair of line numbers with a comma, translated for file FILE.
     If the second number is smaller, use the first in place of it.
  
     Args A and B are internal line numbers.
--- 66,72 ----
    print_script (script, find_hunk, pr_context_hunk);
  }
  
! /* Print a pair of line numbers with a comma.
     If the second number is smaller, use the first in place of it.
  
     Args A and B are internal line numbers.
***************
*** 71,82 ****
     We print the translated (real) line numbers.  */
  
  static void
! print_context_number_range (file, a, b)
!      struct file_data *file;
       int a, b;
  {
    int trans_a, trans_b;
!   translate_range (file, a, b, &trans_a, &trans_b);
  
    /* Note: we can have B < A in the case of a range of no lines.
       In this case, we should print the line number before the range,
--- 73,83 ----
     We print the translated (real) line numbers.  */
  
  static void
! print_context_number_range (a, b)
       int a, b;
  {
    int trans_a, trans_b;
!   translate_range (a, b, &trans_a, &trans_b);
  
    /* Note: we can have B < A in the case of a range of no lines.
       In this case, we should print the line number before the range,
***************
*** 101,107 ****
    int first0, last0, first1, last1, show_from, show_to, i;
    struct change *next;
    char *prefix;
-   int lastline;
    char *function;
    int function_length;
  
--- 102,107 ----
***************
*** 122,128 ****
    /* If desired, find the preceding function definition line in file 0.  */
    function = 0;
    if (function_regexp)
!     find_function (&files[0], first0, &function, &function_length);
  
    /* If we looked for and found a function this is part of,
       include its name in the header of the diff section.  */
--- 122,128 ----
    /* If desired, find the preceding function definition line in file 0.  */
    function = 0;
    if (function_regexp)
!     find_function (first0, &function, &function_length);
  
    /* If we looked for and found a function this is part of,
       include its name in the header of the diff section.  */
***************
*** 135,141 ****
      }
  
    fprintf (outfile, "\n*** ");
!   print_context_number_range (&files[0], first0, last0);
    fprintf (outfile, " ****\n");
  
    if (show_from)
--- 135,141 ----
      }
  
    fprintf (outfile, "\n*** ");
!   print_context_number_range (first0, last0);
    fprintf (outfile, " ****\n");
  
    if (show_from)
***************
*** 164,170 ****
      }
  
    fprintf (outfile, "--- ");
!   print_context_number_range (&files[1], first1, last1);
    fprintf (outfile, " ----\n");
  
    if (show_to)
--- 164,170 ----
      }
  
    fprintf (outfile, "--- ");
!   print_context_number_range (first1, last1);
    fprintf (outfile, " ----\n");
  
    if (show_to)
***************
*** 258,272 ****
      }
  }
  
! /* Find the last function-header line in FILE prior to line number LINENUM.
     This is a line containing a match for the regexp in `function_regexp'.
     Store the address of the line text into LINEP and the length of the
     line into LENP.
     Do not store anything if no function-header is found.  */
  
! static int
! find_function (file, linenum, linep, lenp)
!      struct file_data *file;
       int linenum;
       char **linep;
       int *lenp;
--- 258,271 ----
      }
  }
  
! /* Find the last function-header line prior to line number LINENUM.
     This is a line containing a match for the regexp in `function_regexp'.
     Store the address of the line text into LINEP and the length of the
     line into LENP.
     Do not store anything if no function-header is found.  */
  
! static void
! find_function (linenum, linep, lenp)
       int linenum;
       char **linep;
       int *lenp;
***************
*** 288,294 ****
  	  *linep = files[0].linbuf[i].text;
  	  *lenp = files[0].linbuf[i].length;
  	  find_function_last_match = i;
! 	  return 1;
  	}
      }
    /* If we search back to where we started searching the previous time,
--- 287,293 ----
  	  *linep = files[0].linbuf[i].text;
  	  *lenp = files[0].linbuf[i].length;
  	  find_function_last_match = i;
! 	  return;
  	}
      }
    /* If we search back to where we started searching the previous time,
***************
*** 298,304 ****
        i = find_function_last_match;
        *linep = files[0].linbuf[i].text;
        *lenp = files[0].linbuf[i].length;
-       return 1;
      }
-   return 0;
  }
--- 297,301 ----
===================================================================
RCS file: RCS/diff.c,v
retrieving revision 1.2
diff -c -r1.2 diff.c
*** /tmp/,RCSt1a21584	Fri Nov 10 11:48:14 1989
--- diff.c	Thu Nov  9 21:40:50 1989
***************
*** 48,54 ****
       int count;
  {
    int i;
!   int length = 0;
    char *result;
  
    for (i = 0; i < count; i++)
--- 48,54 ----
       int count;
  {
    int i;
!   unsigned length = 0;
    char *result;
  
    for (i = 0; i < count; i++)
***************
*** 300,307 ****
        val = re_compile_pattern (ignore_regexp, strlen (ignore_regexp),
  				&ignore_regexp_compiled);
        if (val != 0)
! 	error ("-I option: ", val);
!       ignore_regexp_compiled.fastmap = (char *) xmalloc (256);
      }
  
    if (function_regexp)
--- 300,307 ----
        val = re_compile_pattern (ignore_regexp, strlen (ignore_regexp),
  				&ignore_regexp_compiled);
        if (val != 0)
! 	error ("-I option: ", "", "");
!       ignore_regexp_compiled.fastmap = (char *) xmalloc ((unsigned)256);
      }
  
    if (function_regexp)
***************
*** 311,318 ****
        val = re_compile_pattern (function_regexp, strlen (function_regexp),
  				&function_regexp_compiled);
        if (val != 0)
! 	error ("-F option: ", val);
!       function_regexp_compiled.fastmap = (char *) xmalloc (256);
      }
  
    if (output_style != OUTPUT_CONTEXT)
--- 311,318 ----
        val = re_compile_pattern (function_regexp, strlen (function_regexp),
  				&function_regexp_compiled);
        if (val != 0)
! 	error ("-F option: ", "", "");
!       function_regexp_compiled.fastmap = (char *) xmalloc ((unsigned)256);
      }
  
    if (output_style != OUTPUT_CONTEXT)
***************
*** 323,329 ****
  
    switch_string = option_list (argv + 1, optind - 1);
  
!   val = compare_files (0, argv[optind], 0, argv[optind + 1], 0);
  
    /* Print any messages that were saved up for last.  */
    print_message_queue ();
--- 323,329 ----
  
    switch_string = option_list (argv + 1, optind - 1);
  
!   val = compare_files ((char *)0, argv[optind], (char *)0, argv[optind + 1], 0);
  
    /* Print any messages that were saved up for last.  */
    print_message_queue ();
***************
*** 345,351 ****
  {
    if (output_style != OUTPUT_NORMAL
        && output_style != style)
!     error ("conflicting specifications of output style");
    output_style = style;
  }
  
--- 345,351 ----
  {
    if (output_style != OUTPUT_NORMAL
        && output_style != style)
!     error ("conflicting specifications of output style", "", "");
    output_style = style;
  }
  
===================================================================
RCS file: RCS/diff.h,v
retrieving revision 1.1
diff -c -r1.1 diff.h
*** /tmp/,RCSt1a21584	Fri Nov 10 11:48:15 1989
--- diff.h	Thu Nov  9 21:23:55 1989
***************
*** 321,331 ****
  
  void *xmalloc ();
  void *xrealloc ();
- void *xcalloc();
  char *concat ();
  void free ();
  char *rindex ();
  char *index ();
  
  void message ();
  void print_message_queue ();
--- 321,337 ----
  
  void *xmalloc ();
  void *xrealloc ();
  char *concat ();
  void free ();
  char *rindex ();
  char *index ();
  
+ void analyze_hunk ();
+ void error ();
+ void fatal ();
  void message ();
+ void perror_with_name ();
+ void pfatal_with_name ();
+ void print_1_line ();
  void print_message_queue ();
+ void print_script ();
===================================================================
RCS file: RCS/dir.c,v
retrieving revision 1.1
diff -c -r1.1 dir.c
*** /tmp/,RCSt1a21584	Fri Nov 10 11:48:15 1989
--- dir.c	Thu Nov  9 21:47:29 1989
***************
*** 39,45 ****
    register DIR *reading;
    register struct direct *next;
    struct dirdata dirdata;
-   int compare_names ();
  
    /* Address of block containing the files that are described.  */
    char **files;
--- 39,44 ----
===================================================================
RCS file: RCS/ed.c,v
retrieving revision 1.1
diff -c -r1.1 ed.c
*** /tmp/,RCSt1a21584	Fri Nov 10 11:48:16 1989
--- ed.c	Thu Nov  9 21:21:01 1989
***************
*** 22,28 ****
  static void print_rcs_hunk ();
  static void print_ed_hunk ();
  static void pr_forward_ed_hunk ();
! static void print_range_length ();
  void translate_range ();
  struct change *find_change ();
  struct change *find_reverse_change ();
--- 22,28 ----
  static void print_rcs_hunk ();
  static void print_ed_hunk ();
  static void pr_forward_ed_hunk ();
! void print_number_range ();
  void translate_range ();
  struct change *find_change ();
  struct change *find_reverse_change ();
***************
*** 58,64 ****
      return;
  
    /* Print out the line number header for this hunk */
!   print_number_range (',', &files[0], f0, l0);
    fprintf (outfile, "%c\n", change_letter (inserts, deletes));
  
    /* Print new/changed lines from second file, if needed */
--- 58,64 ----
      return;
  
    /* Print out the line number header for this hunk */
!   print_number_range (',', f0, l0);
    fprintf (outfile, "%c\n", change_letter (inserts, deletes));
  
    /* Print new/changed lines from second file, if needed */
***************
*** 71,77 ****
  	  /* Resume the insert, if we stopped.  */
  	  if (! inserting)
  	    fprintf (outfile, "%da\n",
! 		     i - f1 + translate_line_number (&files[0], f0) - 1);
  	  inserting = 1;
  
  	  /* If the file's line is just a dot, it would confuse `ed'.
--- 71,77 ----
  	  /* Resume the insert, if we stopped.  */
  	  if (! inserting)
  	    fprintf (outfile, "%da\n",
! 		     i - f1 + translate_line_number (f0) - 1);
  	  inserting = 1;
  
  	  /* If the file's line is just a dot, it would confuse `ed'.
***************
*** 86,92 ****
  	      fprintf (outfile, ".\n");
  	      /* Now change that double dot to the desired single dot.  */
  	      fprintf (outfile, "%ds/^\\.\\././\n",
! 		       i - f1 + translate_line_number (&files[0], f0));
  	      inserting = 0;
  	    }
  	  else
--- 86,92 ----
  	      fprintf (outfile, ".\n");
  	      /* Now change that double dot to the desired single dot.  */
  	      fprintf (outfile, "%ds/^\\.\\././\n",
! 		       i - f1 + translate_line_number (f0));
  	      inserting = 0;
  	    }
  	  else
***************
*** 125,131 ****
      return;
  
    fprintf (outfile, "%c", change_letter (inserts, deletes));
!   print_number_range (' ', files, f0, l0);
    fprintf (outfile, "\n");
  
    /* If deletion only, print just the number range.  */
--- 125,131 ----
      return;
  
    fprintf (outfile, "%c", change_letter (inserts, deletes));
!   print_number_range (' ', f0, l0);
    fprintf (outfile, "\n");
  
    /* If deletion only, print just the number range.  */
***************
*** 169,175 ****
    if (!deletes && !inserts)
      return;
  
!   translate_range (&files[0], f0, l0, &tf0, &tl0);
  
    if (deletes)
      {
--- 169,175 ----
    if (!deletes && !inserts)
      return;
  
!   translate_range (f0, l0, &tf0, &tl0);
  
    if (deletes)
      {
***************
*** 186,192 ****
        fprintf (outfile, "a");
  
        /* Take last-line-number from file 0 and # lines from file 1.  */
!       translate_range (&files[1], f1, l1, &tf1, &tl1);
        fprintf (outfile, "%d %d\n",
  	       tl0,
  	       (tl1 >= tf1 ? tl1 - tf1 + 1 : 1));	     
--- 186,192 ----
        fprintf (outfile, "a");
  
        /* Take last-line-number from file 0 and # lines from file 1.  */
!       translate_range (f1, l1, &tf1, &tl1);
        fprintf (outfile, "%d %d\n",
  	       tl0,
  	       (tl1 >= tf1 ? tl1 - tf1 + 1 : 1));	     
===================================================================
RCS file: RCS/io.c,v
retrieving revision 1.1
diff -c -r1.1 io.c
*** /tmp/,RCSt1a21584	Fri Nov 10 11:48:17 1989
--- io.c	Thu Nov  9 22:43:22 1989
***************
*** 69,75 ****
    else if ((current->stat.st_mode & S_IFMT) == S_IFREG)
      {
        current->bufsize = current->stat.st_size;
!       current->buffer = (char *) xmalloc (current->bufsize + 2);
        current->buffered_chars
  	= read (current->desc, current->buffer, current->bufsize);
        if (current->buffered_chars < 0)
--- 69,75 ----
    else if ((current->stat.st_mode & S_IFMT) == S_IFREG)
      {
        current->bufsize = current->stat.st_size;
!       current->buffer = (char *) xmalloc ((unsigned)current->bufsize + 2);
        current->buffered_chars
  	= read (current->desc, current->buffer, current->bufsize);
        if (current->buffered_chars < 0)
***************
*** 80,86 ****
        int cc;
  
        current->bufsize = 4096;
!       current->buffer = (char *) xmalloc (current->bufsize + 2);
        current->buffered_chars = 0;
        
        /* Not a regular file; read it in a little at a time, growing the
--- 80,86 ----
        int cc;
  
        current->bufsize = 4096;
!       current->buffer = (char *) xmalloc ((unsigned)current->bufsize + 2);
        current->buffered_chars = 0;
        
        /* Not a regular file; read it in a little at a time, growing the
***************
*** 95,101 ****
  	    {
  	      current->bufsize = current->bufsize * 2;
  	      current->buffer = (char *) xrealloc (current->buffer,
! 						   current->bufsize + 2);
  	    }
  	}
        if (cc < 0)
--- 95,101 ----
  	    {
  	      current->bufsize = current->bufsize * 2;
  	      current->buffer = (char *) xrealloc (current->buffer,
! 						   (unsigned)current->bufsize + 2);
  	    }
  	}
        if (cc < 0)
***************
*** 119,124 ****
--- 119,127 ----
    else
      current->missing_newline = 0;
  
+   /* Don't use uninitialized storage. */
+   current->buffer[current->buffered_chars] = '\0';
+ 
    return 0;
  }
  
***************
*** 487,494 ****
  find_equiv_class (n)
       int n;
  {
!   int bucket = current->linbuf[n].hash % nbuckets;
!   struct equivclass *b = buckets[bucket], *p = NULL;
  
    /* Equivalence class 0 is permanently allocated to lines that were
       not hashed because they were parts of identical prefixes or
--- 490,497 ----
  find_equiv_class (n)
       int n;
  {
!   int bucket;
!   struct equivclass *b, *p = NULL;
  
    /* Equivalence class 0 is permanently allocated to lines that were
       not hashed because they were parts of identical prefixes or
***************
*** 497,506 ****
        || current->linbuf[n].text >= current->suffix_begin)
      return 0;
  
    /* Check through the appropriate bucket to see if there isn't already
       an equivalence class for this line. */
!   while (b)
!     {
        if (b->line.hash == current->linbuf[n].hash
  	  && (b->line.length == current->linbuf[n].length
  	      /* Lines of different lengths can match with certain options.  */
--- 500,510 ----
        || current->linbuf[n].text >= current->suffix_begin)
      return 0;
  
+   bucket = current->linbuf[n].hash % nbuckets;
+ 
    /* Check through the appropriate bucket to see if there isn't already
       an equivalence class for this line. */
!   for (b = buckets[bucket];  b;  p = b, b = b->next)
        if (b->line.hash == current->linbuf[n].hash
  	  && (b->line.length == current->linbuf[n].length
  	      /* Lines of different lengths can match with certain options.  */
***************
*** 507,514 ****
  	      || length_varies)
  	  && !line_cmp (&b->line, &current->linbuf[n]))
  	return b - equivs;
-       p = b, b = b->next;
-     }
  
    /* Create a new equivalence class in this bucket. */
  
--- 511,516 ----
***************
*** 529,535 ****
       struct file_data filevec[];
  {
    int i, j;
-   struct equivclass *b, *f;
    int binary = 0;
    int this_binary;
  
--- 531,536 ----
===================================================================
RCS file: RCS/normal.c,v
retrieving revision 1.1
diff -c -r1.1 normal.c
*** /tmp/,RCSt1a21584	Fri Nov 10 11:48:18 1989
--- normal.c	Thu Nov  9 20:36:56 1989
***************
*** 51,59 ****
      return;
  
    /* Print out the line number header for this hunk */
!   print_number_range (',', &files[0], first0, last0);
    fprintf (outfile, "%c", change_letter (inserts, deletes));
!   print_number_range (',', &files[1], first1, last1);
    fprintf (outfile, "\n");
  
    /* Print the lines that the first file has.  */
--- 51,59 ----
      return;
  
    /* Print out the line number header for this hunk */
!   print_number_range (',', first0, last0);
    fprintf (outfile, "%c", change_letter (inserts, deletes));
!   print_number_range (',', first1, last1);
    fprintf (outfile, "\n");
  
    /* Print the lines that the first file has.  */
===================================================================
RCS file: RCS/regex.c,v
retrieving revision 1.1
diff -c -r1.1 regex.c
*** /tmp/,RCSt1a21584	Fri Nov 10 11:48:18 1989
--- regex.c	Thu Nov  9 21:44:02 1989
***************
*** 53,58 ****
--- 53,61 ----
  #ifdef sparc
  #include <alloca.h>
  #endif
+ 
+ void *malloc();
+ void *realloc();
  #endif
  
  /*
***************
*** 117,122 ****
--- 120,130 ----
  #define SIGN_EXTEND_CHAR(x) (x)
  #endif
  
+ #ifdef diff
+ #define obscurable 0
+ #else
+ #define obscurable 1
+ 
  static int obscure_syntax = 0;
  
  /* Specify the precise syntax of regexp for compilation.
***************
*** 135,140 ****
--- 143,149 ----
    obscure_syntax = syntax;
    return ret;
  }
+ #endif
  
  /* re_compile_pattern takes a regular-expression string
     and converts it into a buffer full of byte commands for matching.
***************
*** 280,285 ****
--- 289,295 ----
        switch (c)
  	{
  	case '$':
+ #if obscurable
  	  if (obscure_syntax & RE_TIGHT_VBAR)
  	    {
  	      if (! (obscure_syntax & RE_CONTEXT_INDEP_OPS) && p != pend)
***************
*** 291,307 ****
  	      PATPUSH (endline);
  	      break;
  	    }
  
  	  /* $ means succeed if at end of line, but only in special contexts.
  	    If randomly in the middle of a pattern, it is a normal character. */
  	  if (p == pend || *p == '\n'
! 	      || (obscure_syntax & RE_CONTEXT_INDEP_OPS)
  	      || (obscure_syntax & RE_NO_BK_PARENS
  		  ? *p == ')'
! 		  : *p == '\\' && p[1] == ')')
! 	      || (obscure_syntax & RE_NO_BK_VBAR
  		  ? *p == '|'
! 		  : *p == '\\' && p[1] == '|'))
  	    {
  	      PATPUSH (endline);
  	      break;
--- 301,326 ----
  	      PATPUSH (endline);
  	      break;
  	    }
+ #endif
  
  	  /* $ means succeed if at end of line, but only in special contexts.
  	    If randomly in the middle of a pattern, it is a normal character. */
  	  if (p == pend || *p == '\n'
! 	      || (
! #if obscurable
! 	          obscure_syntax & RE_CONTEXT_INDEP_OPS)
  	      || (obscure_syntax & RE_NO_BK_PARENS
  		  ? *p == ')'
! 		  :
! #endif
! 		    *p == '\\' && p[1] == ')')
! 	      || (
! #if obscurable
! 		  obscure_syntax & RE_NO_BK_VBAR
  		  ? *p == '|'
! 		  :
! #endif
! 		    *p == '\\' && p[1] == '|'))
  	    {
  	      PATPUSH (endline);
  	      break;
***************
*** 312,319 ****
  	  /* ^ means succeed if at beg of line, but only if no preceding pattern. */
  
  	  if (laststart && p[-2] != '\n'
! 	      && ! (obscure_syntax & RE_CONTEXT_INDEP_OPS))
  	    goto normal_char;
  	  if (obscure_syntax & RE_TIGHT_VBAR)
  	    {
  	      if (p != pattern + 1
--- 331,342 ----
  	  /* ^ means succeed if at beg of line, but only if no preceding pattern. */
  
  	  if (laststart && p[-2] != '\n'
! #if obscurable
! 	      && ! (obscure_syntax & RE_CONTEXT_INDEP_OPS)
! #endif
! 	      )
  	    goto normal_char;
+ #if obscurable
  	  if (obscure_syntax & RE_TIGHT_VBAR)
  	    {
  	      if (p != pattern + 1
***************
*** 323,339 ****
  	      begalt = b;
  	    }
  	  else
  	    PATPUSH (begline);
  	  break;
  
  	case '+':
  	case '?':
  	  if (obscure_syntax & RE_BK_PLUS_QM)
  	    goto normal_char;
  	handle_plus:
  	case '*':
  	  /* If there is no previous pattern, char not special. */
! 	  if (!laststart && ! (obscure_syntax & RE_CONTEXT_INDEP_OPS))
  	    goto normal_char;
  	  /* If there is a sequence of repetition chars,
  	     collapse it down to equivalent to just one.  */
--- 346,369 ----
  	      begalt = b;
  	    }
  	  else
+ #endif
  	    PATPUSH (begline);
  	  break;
  
  	case '+':
  	case '?':
+ #if obscurable
  	  if (obscure_syntax & RE_BK_PLUS_QM)
  	    goto normal_char;
  	handle_plus:
+ #endif
  	case '*':
  	  /* If there is no previous pattern, char not special. */
! 	  if (!laststart
! #if obscurable
! 		&& ! (obscure_syntax & RE_CONTEXT_INDEP_OPS)
! #endif
! 		)
  	    goto normal_char;
  	  /* If there is a sequence of repetition chars,
  	     collapse it down to equivalent to just one.  */
***************
*** 348,356 ****
  	      PATFETCH (c);
  	      if (c == '*')
  		;
! 	      else if (!(obscure_syntax & RE_BK_PLUS_QM)
! 		       && (c == '+' || c == '?'))
  		;
  	      else if ((obscure_syntax & RE_BK_PLUS_QM)
  		       && c == '\\')
  		{
--- 378,391 ----
  	      PATFETCH (c);
  	      if (c == '*')
  		;
! 	      else if (
! #if obscurable
! 			  !(obscure_syntax & RE_BK_PLUS_QM)
! 		       &&
! #endif
! 			  (c == '+' || c == '?'))
  		;
+ #if obscurable
  	      else if ((obscure_syntax & RE_BK_PLUS_QM)
  		       && c == '\\')
  		{
***************
*** 364,369 ****
--- 399,405 ----
  		    }
  		  c = c1;
  		}
+ #endif
  	      else
  		{
  		  PATUNFETCH;
***************
*** 423,428 ****
--- 459,465 ----
  	    {
  	      PATFETCH (c);
  
+ #if obscurable
  	      /* If awk, \ escapes characters when inside [...].  */
  	      if ((obscure_syntax & RE_AWK_CLASS_HACK) && c == '\\')
  	        {
***************
*** 430,435 ****
--- 467,473 ----
  	          b[c1 / BYTEWIDTH] |= 1 << (c1 % BYTEWIDTH);
  	          continue;
  	        }
+ #endif
  
  	      if (c == ']' && p != p1 + 1) break;
  	      if (*p == '-' && p[1] != ']')
***************
*** 452,479 ****
  	  break;
  
  	case '(':
! 	  if (! (obscure_syntax & RE_NO_BK_PARENS))
! 	    goto normal_char;
! 	  else
  	    goto handle_open;
  
  	case ')':
! 	  if (! (obscure_syntax & RE_NO_BK_PARENS))
! 	    goto normal_char;
! 	  else
  	    goto handle_close;
  
  	case '\n':
! 	  if (! (obscure_syntax & RE_NEWLINE_OR))
! 	    goto normal_char;
! 	  else
  	    goto handle_bar;
  
  	case '|':
! 	  if (! (obscure_syntax & RE_NO_BK_VBAR))
! 	    goto normal_char;
! 	  else
  	    goto handle_bar;
  
          case '\\':
  	  if (p == pend) goto invalid_pattern;
--- 490,525 ----
  	  break;
  
  	case '(':
! #if obscurable
! 	  if (obscure_syntax & RE_NO_BK_PARENS)
  	    goto handle_open;
+ 	  else
+ #endif
+ 	    goto normal_char;
  
  	case ')':
! #if obscurable
! 	  if (obscure_syntax & RE_NO_BK_PARENS)
  	    goto handle_close;
+ 	  else
+ #endif
+ 	    goto normal_char;
  
  	case '\n':
! #if obscurable
! 	  if (obscure_syntax & RE_NEWLINE_OR)
  	    goto handle_bar;
+ 	  else
+ #endif
+ 	    goto normal_char;
  
  	case '|':
! #if obscurable
! 	  if (obscure_syntax & RE_NO_BK_VBAR)
  	    goto handle_bar;
+ 	  else
+ #endif
+ 	    goto normal_char;
  
          case '\\':
  	  if (p == pend) goto invalid_pattern;
***************
*** 481,489 ****
--- 527,537 ----
  	  switch (c)
  	    {
  	    case '(':
+ #if obscurable
  	      if (obscure_syntax & RE_NO_BK_PARENS)
  		goto normal_backsl;
  	    handle_open:
+ #endif
  	      if (stackp == stacke) goto nesting_too_deep;
  	      if (regnum < RE_NREGS)
  	        {
***************
*** 500,508 ****
--- 548,558 ----
  	      break;
  
  	    case ')':
+ #if obscurable
  	      if (obscure_syntax & RE_NO_BK_PARENS)
  		goto normal_backsl;
  	    handle_close:
+ #endif
  	      if (stackp == stackb) goto unmatched_close;
  	      begalt = *--stackp + bufp->buffer;
  	      if (fixup_jump)
***************
*** 520,528 ****
--- 570,580 ----
  	      break;
  
  	    case '|':
+ #if obscurable
  	      if (obscure_syntax & RE_NO_BK_VBAR)
  		goto normal_backsl;
  	    handle_bar:
+ #endif
  	      insert_jump (on_failure_jump, begalt, b + 6, b);
  	      pending_exact = 0;
  	      b += 3;
***************
*** 608,620 ****
  	      PATPUSH (c1);
  	      break;
  
  	    case '+':
  	    case '?':
  	      if (obscure_syntax & RE_BK_PLUS_QM)
  		goto handle_plus;
  
- 	    default:
  	    normal_backsl:
  	      /* You might think it would be useful for \ to mean
  		 not to translate; but if we don't translate it
  		 it will never match anything.  */
--- 660,675 ----
  	      PATPUSH (c1);
  	      break;
  
+ #if obscurable
  	    case '+':
  	    case '?':
  	      if (obscure_syntax & RE_BK_PLUS_QM)
  		goto handle_plus;
  
  	    normal_backsl:
+ #endif
+ 
+ 	    default:
  	      /* You might think it would be useful for \ to mean
  		 not to translate; but if we don't translate it
  		 it will never match anything.  */
***************
*** 627,635 ****
  	normal_char:
  	  if (!pending_exact || pending_exact + *pending_exact + 1 != b
  	      || *pending_exact == 0177 || *p == '*' || *p == '^'
! 	      || ((obscure_syntax & RE_BK_PLUS_QM)
  		  ? *p == '\\' && (p[1] == '+' || p[1] == '?')
! 		  : (*p == '+' || *p == '?')))
  	    {
  	      laststart = b;
  	      PATPUSH (exactn);
--- 682,694 ----
  	normal_char:
  	  if (!pending_exact || pending_exact + *pending_exact + 1 != b
  	      || *pending_exact == 0177 || *p == '*' || *p == '^'
! 	      || (
! #if obscurable
! 		  (obscure_syntax & RE_BK_PLUS_QM)
  		  ? *p == '\\' && (p[1] == '+' || p[1] == '?')
! 		  :
! #endif
! 		    (*p == '+' || *p == '?')))
  	    {
  	      laststart = b;
  	      PATPUSH (exactn);
***************
*** 677,683 ****
  static int
  store_jump (from, opcode, to)
       char *from, *to;
!      char opcode;
  {
    from[0] = opcode;
    from[1] = (to - (from + 3)) & 0377;
--- 736,742 ----
  static int
  store_jump (from, opcode, to)
       char *from, *to;
!      enum regexpcode opcode;
  {
    from[0] = opcode;
    from[1] = (to - (from + 3)) & 0377;
***************
*** 693,699 ****
  
  static int
  insert_jump (op, from, to, current_end)
!      char op;
       char *from, *to, *current_end;
  {
    register char *pto = current_end + 3;
--- 752,758 ----
  
  static int
  insert_jump (op, from, to, current_end)
!      enum regexpcode op;
       char *from, *to, *current_end;
  {
    register char *pto = current_end + 3;
***************
*** 717,727 ****
       struct re_pattern_buffer *bufp;
  {
    unsigned char *pattern = (unsigned char *) bufp->buffer;
-   int size = bufp->used;
    register char *fastmap = bufp->fastmap;
    register unsigned char *p = pattern;
!   register unsigned char *pend = pattern + size;
!   register int j, k;
    unsigned char *translate = (unsigned char *) bufp->translate;
  
    unsigned char *stackb[NFAILURES];
--- 776,785 ----
       struct re_pattern_buffer *bufp;
  {
    unsigned char *pattern = (unsigned char *) bufp->buffer;
    register char *fastmap = bufp->fastmap;
    register unsigned char *p = pattern;
!   register unsigned char *pend = pattern + bufp->used;
!   register int j;
    unsigned char *translate = (unsigned char *) bufp->translate;
  
    unsigned char *stackb[NFAILURES];
***************
*** 900,906 ****
       int size, startpos, range;
       struct re_registers *regs;
  {
!   return re_search_2 (pbufp, 0, 0, string, size, startpos, range, regs, size);
  }
  
  /* Like re_match_2 but tries first a match starting at index STARTPOS,
--- 958,964 ----
       int size, startpos, range;
       struct re_registers *regs;
  {
!   return re_search_2 (pbufp, (char *)0, 0, string, size, startpos, range, regs, size);
  }
  
  /* Like re_match_2 but tries first a match starting at index STARTPOS,
***************
*** 1012,1018 ****
    return -1;
  }
  
! #ifndef emacs   /* emacs never uses this */
  int
  re_match (pbufp, string, size, pos, regs)
       struct re_pattern_buffer *pbufp;
--- 1070,1076 ----
    return -1;
  }
  
! #if !defined (emacs) && !defined (diff)
  int
  re_match (pbufp, string, size, pos, regs)
       struct re_pattern_buffer *pbufp;
***************
*** 1572,1578 ****
  
  /* Entry points compatible with bsd4.2 regex library */
  
! #ifndef emacs
  
  static struct re_pattern_buffer re_comp_buf;
  
--- 1630,1636 ----
  
  /* Entry points compatible with bsd4.2 regex library */
  
! #if !defined (emacs) && !defined (diff)
  
  static struct re_pattern_buffer re_comp_buf;
  
===================================================================
RCS file: RCS/regex.h,v
retrieving revision 1.1
diff -c -r1.1 regex.h
*** /tmp/,RCSt1a21584	Fri Nov 10 11:48:19 1989
--- regex.h	Thu Nov  9 21:23:35 1989
***************
*** 183,189 ****
  /* Is this really advertised? */
  extern void re_compile_fastmap ();
  extern int re_search (), re_search_2 ();
! extern int re_match (), re_match_2 ();
  
  /* 4.2 bsd compatibility (yuck) */
  extern char *re_comp ();
--- 183,192 ----
  /* Is this really advertised? */
  extern void re_compile_fastmap ();
  extern int re_search (), re_search_2 ();
! #ifndef diff
! extern int re_match ();
! #endif
! extern int re_match_2 ();
  
  /* 4.2 bsd compatibility (yuck) */
  extern char *re_comp ();
===================================================================
RCS file: RCS/util.c,v
retrieving revision 1.2
diff -c -r1.2 util.c
*** /tmp/,RCSt1a21584	Fri Nov 10 11:48:20 1989
--- util.c	Thu Nov  9 21:41:06 1989
***************
*** 19,24 ****
--- 19,26 ----
  
  #include "diff.h"
  
+ void perror ();
+ 
  /* Use when a system call returns non-zero status.
     TEXT should normally be the file name.  */
  
***************
*** 65,71 ****
       char *text;
  {
    print_message_queue ();
!   error ("%s", text);
    exit (2);
  }
  
--- 67,73 ----
       char *text;
  {
    print_message_queue ();
!   error ("%s", text, "");
    exit (2);
  }
  
***************
*** 448,454 ****
  
  /* Translate an internal line number (an index into diff's table of lines)
     into an actual line number in the input file.
!    The internal line number is LNUM.  FILE points to the data on the file.
  
     Internal line numbers count from 0 within the current chunk.
     Actual line numbers count from 1 within the entire file;
--- 450,456 ----
  
  /* Translate an internal line number (an index into diff's table of lines)
     into an actual line number in the input file.
!    The internal line number is LNUM.
  
     Internal line numbers count from 0 within the current chunk.
     Actual line numbers count from 1 within the entire file;
***************
*** 457,464 ****
     The `ltran' feature is no longer in use.  */
  
  int
! translate_line_number (file, lnum)
!      struct file_data *file;
       int lnum;
  {
    return lnum + 1;
--- 459,465 ----
     The `ltran' feature is no longer in use.  */
  
  int
! translate_line_number (lnum)
       int lnum;
  {
    return lnum + 1;
***************
*** 465,480 ****
  }
  
  void
! translate_range (file, a, b, aptr, bptr)
!      struct file_data *file;
       int a, b;
       int *aptr, *bptr;
  {
!   *aptr = translate_line_number (file, a - 1) + 1;
!   *bptr = translate_line_number (file, b + 1) - 1;
  }
  
! /* Print a pair of line numbers with SEPCHAR, translated for file FILE.
     If the two numbers are identical, print just one number.
  
     Args A and B are internal line numbers.
--- 466,480 ----
  }
  
  void
! translate_range (a, b, aptr, bptr)
       int a, b;
       int *aptr, *bptr;
  {
!   *aptr = translate_line_number (a - 1) + 1;
!   *bptr = translate_line_number (b + 1) - 1;
  }
  
! /* Print a pair of line numbers with SEPCHAR.
     If the two numbers are identical, print just one number.
  
     Args A and B are internal line numbers.
***************
*** 481,493 ****
     We print the translated (real) line numbers.  */
  
  void
! print_number_range (sepchar, file, a, b)
       char sepchar;
-      struct file_data *file;
       int a, b;
  {
    int trans_a, trans_b;
!   translate_range (file, a, b, &trans_a, &trans_b);
  
    /* Note: we can have B < A in the case of a range of no lines.
       In this case, we should print the line number before the range,
--- 481,492 ----
     We print the translated (real) line numbers.  */
  
  void
! print_number_range (sepchar, a, b)
       char sepchar;
       int a, b;
  {
    int trans_a, trans_b;
!   translate_range (a, b, &trans_a, &trans_b);
  
    /* Note: we can have B < A in the case of a range of no lines.
       In this case, we should print the line number before the range,
***************
*** 540,546 ****
  		|| 0 > re_search (&ignore_regexp_compiled,
  				  files[0].linbuf[i].text,
  				  files[0].linbuf[i].length, 0,
! 				  files[0].linbuf[i].length, 0)))
  	  nontrivial = 1;
  
        for (i = next->line1; i <= l1 && ! nontrivial; i++)
--- 539,545 ----
  		|| 0 > re_search (&ignore_regexp_compiled,
  				  files[0].linbuf[i].text,
  				  files[0].linbuf[i].length, 0,
! 				  files[0].linbuf[i].length, (struct re_registers *)0)))
  	  nontrivial = 1;
  
        for (i = next->line1; i <= l1 && ! nontrivial; i++)
***************
*** 549,555 ****
  		|| 0 > re_search (&ignore_regexp_compiled,
  				  files[1].linbuf[i].text,
  				  files[1].linbuf[i].length, 0,
! 				  files[1].linbuf[i].length, 0)))
  	  nontrivial = 1;
      }
  
--- 548,554 ----
  		|| 0 > re_search (&ignore_regexp_compiled,
  				  files[1].linbuf[i].text,
  				  files[1].linbuf[i].length, 0,
! 				  files[1].linbuf[i].length, (struct re_registers *)0)))
  	  nontrivial = 1;
      }
  
***************
*** 574,580 ****
  xmalloc (size)
       unsigned size;
  {
!   register void *value = (void *) malloc (size);
  
    if (!value)
      fatal ("virtual memory exhausted");
--- 573,580 ----
  xmalloc (size)
       unsigned size;
  {
!   extern void *malloc();
!   register void *value = malloc (size);
  
    if (!value)
      fatal ("virtual memory exhausted");
***************
*** 588,594 ****
       void *old;
       unsigned int size;
  {
!   register void *value = (void *) realloc (old, size);
  
    if (!value)
      fatal ("virtual memory exhausted");
--- 588,595 ----
       void *old;
       unsigned int size;
  {
!   extern void *realloc();
!   register void *value = realloc (old, size);
  
    if (!value)
      fatal ("virtual memory exhausted");
***************
*** 595,611 ****
    return value;
  }
  
- void *
- xcalloc (nitems, size)
-      int nitems, size;
- {
-   void *value = (void *) calloc (nitems, size);
- 
-   if (! value)
-     fatal ("virtual memory exhausted");
-   return value;
- }
- 
  /* Concatenate three strings, returning a newly malloc'd string.  */
  
  char *
--- 596,601 ----
***************
*** 612,618 ****
  concat (s1, s2, s3)
       char *s1, *s2, *s3;
  {
!   int len = strlen (s1) + strlen (s2) + strlen (s3);
    char *new = (char *) xmalloc (len + 1);
    strcpy (new, s1);
    strcat (new, s2);
--- 602,608 ----
  concat (s1, s2, s3)
       char *s1, *s2, *s3;
  {
!   unsigned len = strlen (s1) + strlen (s2) + strlen (s3);
    char *new = (char *) xmalloc (len + 1);
    strcpy (new, s1);
    strcat (new, s2);
***************
*** 620,625 ****
--- 610,616 ----
    return new;
  }
  
+ #ifdef DEBUG
  debug_script (sp)
       struct change *sp;
  {
***************
*** 629,631 ****
--- 620,623 ----
  	     sp->line0, sp->line1, sp->deleted, sp->inserted);
    fflush (stderr);
  }
+ #endif