xref: /dflybsd-src/contrib/cvs-1.12/diff/context.c (revision 86d7f5d305c6adaa56ff4582ece9859d73106103)
186d7f5d3SJohn Marino /* Context-format output routines for GNU DIFF.
286d7f5d3SJohn Marino    Copyright (C) 1988,1989,1991,1992,1993,1994,1998 Free Software Foundation, Inc.
386d7f5d3SJohn Marino 
486d7f5d3SJohn Marino This file is part of GNU DIFF.
586d7f5d3SJohn Marino 
686d7f5d3SJohn Marino GNU DIFF is free software; you can redistribute it and/or modify
786d7f5d3SJohn Marino it under the terms of the GNU General Public License as published by
886d7f5d3SJohn Marino the Free Software Foundation; either version 2, or (at your option)
986d7f5d3SJohn Marino any later version.
1086d7f5d3SJohn Marino 
1186d7f5d3SJohn Marino GNU DIFF is distributed in the hope that it will be useful,
1286d7f5d3SJohn Marino but WITHOUT ANY WARRANTY; without even the implied warranty of
1386d7f5d3SJohn Marino MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1486d7f5d3SJohn Marino GNU General Public License for more details.
1586d7f5d3SJohn Marino 
1686d7f5d3SJohn Marino */
1786d7f5d3SJohn Marino 
1886d7f5d3SJohn Marino #include "diff.h"
1986d7f5d3SJohn Marino 
2086d7f5d3SJohn Marino static struct change *find_hunk PARAMS((struct change *));
2186d7f5d3SJohn Marino static void find_function PARAMS((struct file_data const *, int, char const **, size_t *));
2286d7f5d3SJohn Marino static void mark_ignorable PARAMS((struct change *));
2386d7f5d3SJohn Marino static void pr_context_hunk PARAMS((struct change *));
2486d7f5d3SJohn Marino static void pr_unidiff_hunk PARAMS((struct change *));
2586d7f5d3SJohn Marino static void print_context_label PARAMS ((char const *, struct file_data *, char const *));
2686d7f5d3SJohn Marino static void print_context_number_range PARAMS((struct file_data const *, int, int));
2786d7f5d3SJohn Marino static void print_unidiff_number_range PARAMS((struct file_data const *, int, int));
2886d7f5d3SJohn Marino 
2986d7f5d3SJohn Marino /* Last place find_function started searching from.  */
3086d7f5d3SJohn Marino static int find_function_last_search;
3186d7f5d3SJohn Marino 
3286d7f5d3SJohn Marino /* The value find_function returned when it started searching there.  */
3386d7f5d3SJohn Marino static int find_function_last_match;
3486d7f5d3SJohn Marino 
3586d7f5d3SJohn Marino /* Print a label for a context diff, with a file name and date or a label.  */
3686d7f5d3SJohn Marino 
3786d7f5d3SJohn Marino static void
print_context_label(mark,inf,label)3886d7f5d3SJohn Marino print_context_label (mark, inf, label)
3986d7f5d3SJohn Marino      char const *mark;
4086d7f5d3SJohn Marino      struct file_data *inf;
4186d7f5d3SJohn Marino      char const *label;
4286d7f5d3SJohn Marino {
4386d7f5d3SJohn Marino   if (label)
4486d7f5d3SJohn Marino     printf_output ("%s %s\n", mark, label);
4586d7f5d3SJohn Marino   else
4686d7f5d3SJohn Marino     {
4786d7f5d3SJohn Marino       char const *ct = ctime (&inf->stat.st_mtime);
4886d7f5d3SJohn Marino       if (!ct)
4986d7f5d3SJohn Marino 	ct = "?\n";
5086d7f5d3SJohn Marino       /* See Posix.2 section 4.17.6.1.4 for this format.  */
5186d7f5d3SJohn Marino       printf_output ("%s %s\t%s", mark, inf->name, ct);
5286d7f5d3SJohn Marino     }
5386d7f5d3SJohn Marino }
5486d7f5d3SJohn Marino 
5586d7f5d3SJohn Marino /* Print a header for a context diff, with the file names and dates.  */
5686d7f5d3SJohn Marino 
5786d7f5d3SJohn Marino void
print_context_header(inf,unidiff_flag)5886d7f5d3SJohn Marino print_context_header (inf, unidiff_flag)
5986d7f5d3SJohn Marino      struct file_data inf[];
6086d7f5d3SJohn Marino      int unidiff_flag;
6186d7f5d3SJohn Marino {
6286d7f5d3SJohn Marino   if (unidiff_flag)
6386d7f5d3SJohn Marino     {
6486d7f5d3SJohn Marino       print_context_label ("---", &inf[0], file_label[0]);
6586d7f5d3SJohn Marino       print_context_label ("+++", &inf[1], file_label[1]);
6686d7f5d3SJohn Marino     }
6786d7f5d3SJohn Marino   else
6886d7f5d3SJohn Marino     {
6986d7f5d3SJohn Marino       print_context_label ("***", &inf[0], file_label[0]);
7086d7f5d3SJohn Marino       print_context_label ("---", &inf[1], file_label[1]);
7186d7f5d3SJohn Marino     }
7286d7f5d3SJohn Marino }
7386d7f5d3SJohn Marino 
7486d7f5d3SJohn Marino /* Print an edit script in context format.  */
7586d7f5d3SJohn Marino 
7686d7f5d3SJohn Marino void
print_context_script(script,unidiff_flag)7786d7f5d3SJohn Marino print_context_script (script, unidiff_flag)
7886d7f5d3SJohn Marino      struct change *script;
7986d7f5d3SJohn Marino      int unidiff_flag;
8086d7f5d3SJohn Marino {
8186d7f5d3SJohn Marino   if (ignore_blank_lines_flag || ignore_regexp_list)
8286d7f5d3SJohn Marino     mark_ignorable (script);
8386d7f5d3SJohn Marino   else
8486d7f5d3SJohn Marino     {
8586d7f5d3SJohn Marino       struct change *e;
8686d7f5d3SJohn Marino       for (e = script; e; e = e->link)
8786d7f5d3SJohn Marino 	e->ignore = 0;
8886d7f5d3SJohn Marino     }
8986d7f5d3SJohn Marino 
9086d7f5d3SJohn Marino   find_function_last_search = - files[0].prefix_lines;
9186d7f5d3SJohn Marino   find_function_last_match = find_function_last_search - 1;
9286d7f5d3SJohn Marino 
9386d7f5d3SJohn Marino   if (unidiff_flag)
9486d7f5d3SJohn Marino     print_script (script, find_hunk, pr_unidiff_hunk);
9586d7f5d3SJohn Marino   else
9686d7f5d3SJohn Marino     print_script (script, find_hunk, pr_context_hunk);
9786d7f5d3SJohn Marino }
9886d7f5d3SJohn Marino 
9986d7f5d3SJohn Marino /* Print a pair of line numbers with a comma, translated for file FILE.
10086d7f5d3SJohn Marino    If the second number is not greater, use the first in place of it.
10186d7f5d3SJohn Marino 
10286d7f5d3SJohn Marino    Args A and B are internal line numbers.
10386d7f5d3SJohn Marino    We print the translated (real) line numbers.  */
10486d7f5d3SJohn Marino 
10586d7f5d3SJohn Marino static void
print_context_number_range(file,a,b)10686d7f5d3SJohn Marino print_context_number_range (file, a, b)
10786d7f5d3SJohn Marino      struct file_data const *file;
10886d7f5d3SJohn Marino      int a, b;
10986d7f5d3SJohn Marino {
11086d7f5d3SJohn Marino   int trans_a, trans_b;
11186d7f5d3SJohn Marino   translate_range (file, a, b, &trans_a, &trans_b);
11286d7f5d3SJohn Marino 
11386d7f5d3SJohn Marino   /* Note: we can have B < A in the case of a range of no lines.
11486d7f5d3SJohn Marino      In this case, we should print the line number before the range,
11586d7f5d3SJohn Marino      which is B.  */
11686d7f5d3SJohn Marino   if (trans_b > trans_a)
11786d7f5d3SJohn Marino     printf_output ("%d,%d", trans_a, trans_b);
11886d7f5d3SJohn Marino   else
11986d7f5d3SJohn Marino     printf_output ("%d", trans_b);
12086d7f5d3SJohn Marino }
12186d7f5d3SJohn Marino 
12286d7f5d3SJohn Marino /* Print a portion of an edit script in context format.
12386d7f5d3SJohn Marino    HUNK is the beginning of the portion to be printed.
12486d7f5d3SJohn Marino    The end is marked by a `link' that has been nulled out.
12586d7f5d3SJohn Marino 
12686d7f5d3SJohn Marino    Prints out lines from both files, and precedes each
12786d7f5d3SJohn Marino    line with the appropriate flag-character.  */
12886d7f5d3SJohn Marino 
12986d7f5d3SJohn Marino static void
pr_context_hunk(hunk)13086d7f5d3SJohn Marino pr_context_hunk (hunk)
13186d7f5d3SJohn Marino      struct change *hunk;
13286d7f5d3SJohn Marino {
13386d7f5d3SJohn Marino   int first0, last0, first1, last1, show_from, show_to, i;
13486d7f5d3SJohn Marino   struct change *next;
13586d7f5d3SJohn Marino   char const *prefix;
13686d7f5d3SJohn Marino   char const *function;
13786d7f5d3SJohn Marino   size_t function_length;
13886d7f5d3SJohn Marino 
13986d7f5d3SJohn Marino   /* Determine range of line numbers involved in each file.  */
14086d7f5d3SJohn Marino 
14186d7f5d3SJohn Marino   analyze_hunk (hunk, &first0, &last0, &first1, &last1, &show_from, &show_to);
14286d7f5d3SJohn Marino 
14386d7f5d3SJohn Marino   if (!show_from && !show_to)
14486d7f5d3SJohn Marino     return;
14586d7f5d3SJohn Marino 
14686d7f5d3SJohn Marino   /* Include a context's width before and after.  */
14786d7f5d3SJohn Marino 
14886d7f5d3SJohn Marino   i = - files[0].prefix_lines;
14986d7f5d3SJohn Marino   first0 = max (first0 - context, i);
15086d7f5d3SJohn Marino   first1 = max (first1 - context, i);
15186d7f5d3SJohn Marino   last0 = min (last0 + context, files[0].valid_lines - 1);
15286d7f5d3SJohn Marino   last1 = min (last1 + context, files[1].valid_lines - 1);
15386d7f5d3SJohn Marino 
15486d7f5d3SJohn Marino   /* If desired, find the preceding function definition line in file 0.  */
15586d7f5d3SJohn Marino   function = 0;
15686d7f5d3SJohn Marino   if (function_regexp_list)
15786d7f5d3SJohn Marino     find_function (&files[0], first0, &function, &function_length);
15886d7f5d3SJohn Marino 
15986d7f5d3SJohn Marino   begin_output ();
16086d7f5d3SJohn Marino 
16186d7f5d3SJohn Marino   /* If we looked for and found a function this is part of,
16286d7f5d3SJohn Marino      include its name in the header of the diff section.  */
16386d7f5d3SJohn Marino   printf_output ("***************");
16486d7f5d3SJohn Marino 
16586d7f5d3SJohn Marino   if (function)
16686d7f5d3SJohn Marino     {
16786d7f5d3SJohn Marino       printf_output (" ");
16886d7f5d3SJohn Marino       write_output (function, min (function_length - 1, 40));
16986d7f5d3SJohn Marino     }
17086d7f5d3SJohn Marino 
17186d7f5d3SJohn Marino   printf_output ("\n*** ");
17286d7f5d3SJohn Marino   print_context_number_range (&files[0], first0, last0);
17386d7f5d3SJohn Marino   printf_output (" ****\n");
17486d7f5d3SJohn Marino 
17586d7f5d3SJohn Marino   if (show_from)
17686d7f5d3SJohn Marino     {
17786d7f5d3SJohn Marino       next = hunk;
17886d7f5d3SJohn Marino 
17986d7f5d3SJohn Marino       for (i = first0; i <= last0; i++)
18086d7f5d3SJohn Marino 	{
18186d7f5d3SJohn Marino 	  /* Skip past changes that apply (in file 0)
18286d7f5d3SJohn Marino 	     only to lines before line I.  */
18386d7f5d3SJohn Marino 
18486d7f5d3SJohn Marino 	  while (next && next->line0 + next->deleted <= i)
18586d7f5d3SJohn Marino 	    next = next->link;
18686d7f5d3SJohn Marino 
18786d7f5d3SJohn Marino 	  /* Compute the marking for line I.  */
18886d7f5d3SJohn Marino 
18986d7f5d3SJohn Marino 	  prefix = " ";
19086d7f5d3SJohn Marino 	  if (next && next->line0 <= i)
19186d7f5d3SJohn Marino 	    /* The change NEXT covers this line.
19286d7f5d3SJohn Marino 	       If lines were inserted here in file 1, this is "changed".
19386d7f5d3SJohn Marino 	       Otherwise it is "deleted".  */
19486d7f5d3SJohn Marino 	    prefix = (next->inserted > 0 ? "!" : "-");
19586d7f5d3SJohn Marino 
19686d7f5d3SJohn Marino 	  print_1_line (prefix, &files[0].linbuf[i]);
19786d7f5d3SJohn Marino 	}
19886d7f5d3SJohn Marino     }
19986d7f5d3SJohn Marino 
20086d7f5d3SJohn Marino   printf_output ("--- ");
20186d7f5d3SJohn Marino   print_context_number_range (&files[1], first1, last1);
20286d7f5d3SJohn Marino   printf_output (" ----\n");
20386d7f5d3SJohn Marino 
20486d7f5d3SJohn Marino   if (show_to)
20586d7f5d3SJohn Marino     {
20686d7f5d3SJohn Marino       next = hunk;
20786d7f5d3SJohn Marino 
20886d7f5d3SJohn Marino       for (i = first1; i <= last1; i++)
20986d7f5d3SJohn Marino 	{
21086d7f5d3SJohn Marino 	  /* Skip past changes that apply (in file 1)
21186d7f5d3SJohn Marino 	     only to lines before line I.  */
21286d7f5d3SJohn Marino 
21386d7f5d3SJohn Marino 	  while (next && next->line1 + next->inserted <= i)
21486d7f5d3SJohn Marino 	    next = next->link;
21586d7f5d3SJohn Marino 
21686d7f5d3SJohn Marino 	  /* Compute the marking for line I.  */
21786d7f5d3SJohn Marino 
21886d7f5d3SJohn Marino 	  prefix = " ";
21986d7f5d3SJohn Marino 	  if (next && next->line1 <= i)
22086d7f5d3SJohn Marino 	    /* The change NEXT covers this line.
22186d7f5d3SJohn Marino 	       If lines were deleted here in file 0, this is "changed".
22286d7f5d3SJohn Marino 	       Otherwise it is "inserted".  */
22386d7f5d3SJohn Marino 	    prefix = (next->deleted > 0 ? "!" : "+");
22486d7f5d3SJohn Marino 
22586d7f5d3SJohn Marino 	  print_1_line (prefix, &files[1].linbuf[i]);
22686d7f5d3SJohn Marino 	}
22786d7f5d3SJohn Marino     }
22886d7f5d3SJohn Marino }
22986d7f5d3SJohn Marino 
23086d7f5d3SJohn Marino /* Print a pair of line numbers with a comma, translated for file FILE.
23186d7f5d3SJohn Marino    If the second number is smaller, use the first in place of it.
23286d7f5d3SJohn Marino    If the numbers are equal, print just one number.
23386d7f5d3SJohn Marino 
23486d7f5d3SJohn Marino    Args A and B are internal line numbers.
23586d7f5d3SJohn Marino    We print the translated (real) line numbers.  */
23686d7f5d3SJohn Marino 
23786d7f5d3SJohn Marino static void
print_unidiff_number_range(file,a,b)23886d7f5d3SJohn Marino print_unidiff_number_range (file, a, b)
23986d7f5d3SJohn Marino      struct file_data const *file;
24086d7f5d3SJohn Marino      int a, b;
24186d7f5d3SJohn Marino {
24286d7f5d3SJohn Marino   int trans_a, trans_b;
24386d7f5d3SJohn Marino   translate_range (file, a, b, &trans_a, &trans_b);
24486d7f5d3SJohn Marino 
24586d7f5d3SJohn Marino   /* Note: we can have B < A in the case of a range of no lines.
24686d7f5d3SJohn Marino      In this case, we should print the line number before the range,
24786d7f5d3SJohn Marino      which is B.  */
24886d7f5d3SJohn Marino   if (trans_b <= trans_a)
24986d7f5d3SJohn Marino     printf_output (trans_b == trans_a ? "%d" : "%d,0", trans_b);
25086d7f5d3SJohn Marino   else
25186d7f5d3SJohn Marino     printf_output ("%d,%d", trans_a, trans_b - trans_a + 1);
25286d7f5d3SJohn Marino }
25386d7f5d3SJohn Marino 
25486d7f5d3SJohn Marino /* Print a portion of an edit script in unidiff format.
25586d7f5d3SJohn Marino    HUNK is the beginning of the portion to be printed.
25686d7f5d3SJohn Marino    The end is marked by a `link' that has been nulled out.
25786d7f5d3SJohn Marino 
25886d7f5d3SJohn Marino    Prints out lines from both files, and precedes each
25986d7f5d3SJohn Marino    line with the appropriate flag-character.  */
26086d7f5d3SJohn Marino 
26186d7f5d3SJohn Marino static void
pr_unidiff_hunk(hunk)26286d7f5d3SJohn Marino pr_unidiff_hunk (hunk)
26386d7f5d3SJohn Marino      struct change *hunk;
26486d7f5d3SJohn Marino {
26586d7f5d3SJohn Marino   int first0, last0, first1, last1, show_from, show_to, i, j, k;
26686d7f5d3SJohn Marino   struct change *next;
26786d7f5d3SJohn Marino   char const *function;
26886d7f5d3SJohn Marino   size_t function_length;
26986d7f5d3SJohn Marino 
27086d7f5d3SJohn Marino   /* Determine range of line numbers involved in each file.  */
27186d7f5d3SJohn Marino 
27286d7f5d3SJohn Marino   analyze_hunk (hunk, &first0, &last0, &first1, &last1, &show_from, &show_to);
27386d7f5d3SJohn Marino 
27486d7f5d3SJohn Marino   if (!show_from && !show_to)
27586d7f5d3SJohn Marino     return;
27686d7f5d3SJohn Marino 
27786d7f5d3SJohn Marino   /* Include a context's width before and after.  */
27886d7f5d3SJohn Marino 
27986d7f5d3SJohn Marino   i = - files[0].prefix_lines;
28086d7f5d3SJohn Marino   first0 = max (first0 - context, i);
28186d7f5d3SJohn Marino   first1 = max (first1 - context, i);
28286d7f5d3SJohn Marino   last0 = min (last0 + context, files[0].valid_lines - 1);
28386d7f5d3SJohn Marino   last1 = min (last1 + context, files[1].valid_lines - 1);
28486d7f5d3SJohn Marino 
28586d7f5d3SJohn Marino   /* If desired, find the preceding function definition line in file 0.  */
28686d7f5d3SJohn Marino   function = 0;
28786d7f5d3SJohn Marino   if (function_regexp_list)
28886d7f5d3SJohn Marino     find_function (&files[0], first0, &function, &function_length);
28986d7f5d3SJohn Marino 
29086d7f5d3SJohn Marino   begin_output ();
29186d7f5d3SJohn Marino 
29286d7f5d3SJohn Marino   printf_output ("@@ -");
29386d7f5d3SJohn Marino   print_unidiff_number_range (&files[0], first0, last0);
29486d7f5d3SJohn Marino   printf_output (" +");
29586d7f5d3SJohn Marino   print_unidiff_number_range (&files[1], first1, last1);
29686d7f5d3SJohn Marino   printf_output (" @@");
29786d7f5d3SJohn Marino 
29886d7f5d3SJohn Marino   /* If we looked for and found a function this is part of,
29986d7f5d3SJohn Marino      include its name in the header of the diff section.  */
30086d7f5d3SJohn Marino 
30186d7f5d3SJohn Marino   if (function)
30286d7f5d3SJohn Marino     {
30386d7f5d3SJohn Marino       write_output (" ", 1);
30486d7f5d3SJohn Marino       write_output (function, min (function_length - 1, 40));
30586d7f5d3SJohn Marino     }
30686d7f5d3SJohn Marino   write_output ("\n", 1);
30786d7f5d3SJohn Marino 
30886d7f5d3SJohn Marino   next = hunk;
30986d7f5d3SJohn Marino   i = first0;
31086d7f5d3SJohn Marino   j = first1;
31186d7f5d3SJohn Marino 
31286d7f5d3SJohn Marino   while (i <= last0 || j <= last1)
31386d7f5d3SJohn Marino     {
31486d7f5d3SJohn Marino 
31586d7f5d3SJohn Marino       /* If the line isn't a difference, output the context from file 0. */
31686d7f5d3SJohn Marino 
31786d7f5d3SJohn Marino       if (!next || i < next->line0)
31886d7f5d3SJohn Marino 	{
31986d7f5d3SJohn Marino 	  write_output (tab_align_flag ? "\t" : " ", 1);
32086d7f5d3SJohn Marino 	  print_1_line (0, &files[0].linbuf[i++]);
32186d7f5d3SJohn Marino 	  j++;
32286d7f5d3SJohn Marino 	}
32386d7f5d3SJohn Marino       else
32486d7f5d3SJohn Marino 	{
32586d7f5d3SJohn Marino 	  /* For each difference, first output the deleted part. */
32686d7f5d3SJohn Marino 
32786d7f5d3SJohn Marino 	  k = next->deleted;
32886d7f5d3SJohn Marino 	  while (k--)
32986d7f5d3SJohn Marino 	    {
33086d7f5d3SJohn Marino 	      write_output ("-", 1);
33186d7f5d3SJohn Marino 	      if (tab_align_flag)
33286d7f5d3SJohn Marino 		write_output ("\t", 1);
33386d7f5d3SJohn Marino 	      print_1_line (0, &files[0].linbuf[i++]);
33486d7f5d3SJohn Marino 	    }
33586d7f5d3SJohn Marino 
33686d7f5d3SJohn Marino 	  /* Then output the inserted part. */
33786d7f5d3SJohn Marino 
33886d7f5d3SJohn Marino 	  k = next->inserted;
33986d7f5d3SJohn Marino 	  while (k--)
34086d7f5d3SJohn Marino 	    {
34186d7f5d3SJohn Marino 	      write_output ("+", 1);
34286d7f5d3SJohn Marino 	      if (tab_align_flag)
34386d7f5d3SJohn Marino 		write_output ("\t", 1);
34486d7f5d3SJohn Marino 	      print_1_line (0, &files[1].linbuf[j++]);
34586d7f5d3SJohn Marino 	    }
34686d7f5d3SJohn Marino 
34786d7f5d3SJohn Marino 	  /* We're done with this hunk, so on to the next! */
34886d7f5d3SJohn Marino 
34986d7f5d3SJohn Marino 	  next = next->link;
35086d7f5d3SJohn Marino 	}
35186d7f5d3SJohn Marino     }
35286d7f5d3SJohn Marino }
35386d7f5d3SJohn Marino 
35486d7f5d3SJohn Marino /* Scan a (forward-ordered) edit script for the first place that more than
35586d7f5d3SJohn Marino    2*CONTEXT unchanged lines appear, and return a pointer
35686d7f5d3SJohn Marino    to the `struct change' for the last change before those lines.  */
35786d7f5d3SJohn Marino 
35886d7f5d3SJohn Marino static struct change *
find_hunk(start)35986d7f5d3SJohn Marino find_hunk (start)
36086d7f5d3SJohn Marino      struct change *start;
36186d7f5d3SJohn Marino {
36286d7f5d3SJohn Marino   struct change *prev;
36386d7f5d3SJohn Marino   int top0, top1;
36486d7f5d3SJohn Marino   int thresh;
36586d7f5d3SJohn Marino 
36686d7f5d3SJohn Marino   do
36786d7f5d3SJohn Marino     {
36886d7f5d3SJohn Marino       /* Compute number of first line in each file beyond this changed.  */
36986d7f5d3SJohn Marino       top0 = start->line0 + start->deleted;
37086d7f5d3SJohn Marino       top1 = start->line1 + start->inserted;
37186d7f5d3SJohn Marino       prev = start;
37286d7f5d3SJohn Marino       start = start->link;
37386d7f5d3SJohn Marino       /* Threshold distance is 2*CONTEXT between two non-ignorable changes,
37486d7f5d3SJohn Marino 	 but only CONTEXT if one is ignorable.  */
37586d7f5d3SJohn Marino       thresh = ((prev->ignore || (start && start->ignore))
37686d7f5d3SJohn Marino 		? context
37786d7f5d3SJohn Marino 		: 2 * context + 1);
37886d7f5d3SJohn Marino       /* It is not supposed to matter which file we check in the end-test.
37986d7f5d3SJohn Marino 	 If it would matter, crash.  */
38086d7f5d3SJohn Marino       if (start && start->line0 - top0 != start->line1 - top1)
38186d7f5d3SJohn Marino 	abort ();
38286d7f5d3SJohn Marino     } while (start
38386d7f5d3SJohn Marino 	     /* Keep going if less than THRESH lines
38486d7f5d3SJohn Marino 		elapse before the affected line.  */
38586d7f5d3SJohn Marino 	     && start->line0 < top0 + thresh);
38686d7f5d3SJohn Marino 
38786d7f5d3SJohn Marino   return prev;
38886d7f5d3SJohn Marino }
38986d7f5d3SJohn Marino 
39086d7f5d3SJohn Marino /* Set the `ignore' flag properly in each change in SCRIPT.
39186d7f5d3SJohn Marino    It should be 1 if all the lines inserted or deleted in that change
39286d7f5d3SJohn Marino    are ignorable lines.  */
39386d7f5d3SJohn Marino 
39486d7f5d3SJohn Marino static void
mark_ignorable(script)39586d7f5d3SJohn Marino mark_ignorable (script)
39686d7f5d3SJohn Marino      struct change *script;
39786d7f5d3SJohn Marino {
39886d7f5d3SJohn Marino   while (script)
39986d7f5d3SJohn Marino     {
40086d7f5d3SJohn Marino       struct change *next = script->link;
40186d7f5d3SJohn Marino       int first0, last0, first1, last1, deletes, inserts;
40286d7f5d3SJohn Marino 
40386d7f5d3SJohn Marino       /* Turn this change into a hunk: detach it from the others.  */
40486d7f5d3SJohn Marino       script->link = 0;
40586d7f5d3SJohn Marino 
40686d7f5d3SJohn Marino       /* Determine whether this change is ignorable.  */
40786d7f5d3SJohn Marino       analyze_hunk (script, &first0, &last0, &first1, &last1, &deletes, &inserts);
40886d7f5d3SJohn Marino       /* Reconnect the chain as before.  */
40986d7f5d3SJohn Marino       script->link = next;
41086d7f5d3SJohn Marino 
41186d7f5d3SJohn Marino       /* If the change is ignorable, mark it.  */
41286d7f5d3SJohn Marino       script->ignore = (!deletes && !inserts);
41386d7f5d3SJohn Marino 
41486d7f5d3SJohn Marino       /* Advance to the following change.  */
41586d7f5d3SJohn Marino       script = next;
41686d7f5d3SJohn Marino     }
41786d7f5d3SJohn Marino }
41886d7f5d3SJohn Marino 
41986d7f5d3SJohn Marino /* Find the last function-header line in FILE prior to line number LINENUM.
42086d7f5d3SJohn Marino    This is a line containing a match for the regexp in `function_regexp'.
42186d7f5d3SJohn Marino    Store the address of the line text into LINEP and the length of the
42286d7f5d3SJohn Marino    line into LENP.
42386d7f5d3SJohn Marino    Do not store anything if no function-header is found.  */
42486d7f5d3SJohn Marino 
42586d7f5d3SJohn Marino static void
find_function(file,linenum,linep,lenp)42686d7f5d3SJohn Marino find_function (file, linenum, linep, lenp)
42786d7f5d3SJohn Marino      struct file_data const *file;
42886d7f5d3SJohn Marino      int linenum;
42986d7f5d3SJohn Marino      char const **linep;
43086d7f5d3SJohn Marino      size_t *lenp;
43186d7f5d3SJohn Marino {
43286d7f5d3SJohn Marino   int i = linenum;
43386d7f5d3SJohn Marino   int last = find_function_last_search;
43486d7f5d3SJohn Marino   find_function_last_search = i;
43586d7f5d3SJohn Marino 
43686d7f5d3SJohn Marino   while (--i >= last)
43786d7f5d3SJohn Marino     {
43886d7f5d3SJohn Marino       /* See if this line is what we want.  */
43986d7f5d3SJohn Marino       struct regexp_list *r;
44086d7f5d3SJohn Marino       char const *line = file->linbuf[i];
44186d7f5d3SJohn Marino       size_t len = file->linbuf[i + 1] - line;
44286d7f5d3SJohn Marino 
44386d7f5d3SJohn Marino       for (r = function_regexp_list; r; r = r->next)
44486d7f5d3SJohn Marino 	if (0 <= re_search (&r->buf, line, len, 0, len, 0))
44586d7f5d3SJohn Marino 	  {
44686d7f5d3SJohn Marino 	    *linep = line;
44786d7f5d3SJohn Marino 	    *lenp = len;
44886d7f5d3SJohn Marino 	    find_function_last_match = i;
44986d7f5d3SJohn Marino 	    return;
45086d7f5d3SJohn Marino 	  }
45186d7f5d3SJohn Marino     }
45286d7f5d3SJohn Marino   /* If we search back to where we started searching the previous time,
45386d7f5d3SJohn Marino      find the line we found last time.  */
45486d7f5d3SJohn Marino   if (find_function_last_match >= - file->prefix_lines)
45586d7f5d3SJohn Marino     {
45686d7f5d3SJohn Marino       i = find_function_last_match;
45786d7f5d3SJohn Marino       *linep = file->linbuf[i];
45886d7f5d3SJohn Marino       *lenp = file->linbuf[i + 1] - *linep;
45986d7f5d3SJohn Marino       return;
46086d7f5d3SJohn Marino     }
46186d7f5d3SJohn Marino   return;
46286d7f5d3SJohn Marino }
463