xref: /dflybsd-src/contrib/cvs-1.12/diff/context.c (revision 86d7f5d305c6adaa56ff4582ece9859d73106103)
1*86d7f5d3SJohn Marino /* Context-format output routines for GNU DIFF.
2*86d7f5d3SJohn Marino    Copyright (C) 1988,1989,1991,1992,1993,1994,1998 Free Software Foundation, Inc.
3*86d7f5d3SJohn Marino 
4*86d7f5d3SJohn Marino This file is part of GNU DIFF.
5*86d7f5d3SJohn Marino 
6*86d7f5d3SJohn Marino GNU DIFF is free software; you can redistribute it and/or modify
7*86d7f5d3SJohn Marino it under the terms of the GNU General Public License as published by
8*86d7f5d3SJohn Marino the Free Software Foundation; either version 2, or (at your option)
9*86d7f5d3SJohn Marino any later version.
10*86d7f5d3SJohn Marino 
11*86d7f5d3SJohn Marino GNU DIFF is distributed in the hope that it will be useful,
12*86d7f5d3SJohn Marino but WITHOUT ANY WARRANTY; without even the implied warranty of
13*86d7f5d3SJohn Marino MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14*86d7f5d3SJohn Marino GNU General Public License for more details.
15*86d7f5d3SJohn Marino 
16*86d7f5d3SJohn Marino */
17*86d7f5d3SJohn Marino 
18*86d7f5d3SJohn Marino #include "diff.h"
19*86d7f5d3SJohn Marino 
20*86d7f5d3SJohn Marino static struct change *find_hunk PARAMS((struct change *));
21*86d7f5d3SJohn Marino static void find_function PARAMS((struct file_data const *, int, char const **, size_t *));
22*86d7f5d3SJohn Marino static void mark_ignorable PARAMS((struct change *));
23*86d7f5d3SJohn Marino static void pr_context_hunk PARAMS((struct change *));
24*86d7f5d3SJohn Marino static void pr_unidiff_hunk PARAMS((struct change *));
25*86d7f5d3SJohn Marino static void print_context_label PARAMS ((char const *, struct file_data *, char const *));
26*86d7f5d3SJohn Marino static void print_context_number_range PARAMS((struct file_data const *, int, int));
27*86d7f5d3SJohn Marino static void print_unidiff_number_range PARAMS((struct file_data const *, int, int));
28*86d7f5d3SJohn Marino 
29*86d7f5d3SJohn Marino /* Last place find_function started searching from.  */
30*86d7f5d3SJohn Marino static int find_function_last_search;
31*86d7f5d3SJohn Marino 
32*86d7f5d3SJohn Marino /* The value find_function returned when it started searching there.  */
33*86d7f5d3SJohn Marino static int find_function_last_match;
34*86d7f5d3SJohn Marino 
35*86d7f5d3SJohn Marino /* Print a label for a context diff, with a file name and date or a label.  */
36*86d7f5d3SJohn Marino 
37*86d7f5d3SJohn Marino static void
print_context_label(mark,inf,label)38*86d7f5d3SJohn Marino print_context_label (mark, inf, label)
39*86d7f5d3SJohn Marino      char const *mark;
40*86d7f5d3SJohn Marino      struct file_data *inf;
41*86d7f5d3SJohn Marino      char const *label;
42*86d7f5d3SJohn Marino {
43*86d7f5d3SJohn Marino   if (label)
44*86d7f5d3SJohn Marino     printf_output ("%s %s\n", mark, label);
45*86d7f5d3SJohn Marino   else
46*86d7f5d3SJohn Marino     {
47*86d7f5d3SJohn Marino       char const *ct = ctime (&inf->stat.st_mtime);
48*86d7f5d3SJohn Marino       if (!ct)
49*86d7f5d3SJohn Marino 	ct = "?\n";
50*86d7f5d3SJohn Marino       /* See Posix.2 section 4.17.6.1.4 for this format.  */
51*86d7f5d3SJohn Marino       printf_output ("%s %s\t%s", mark, inf->name, ct);
52*86d7f5d3SJohn Marino     }
53*86d7f5d3SJohn Marino }
54*86d7f5d3SJohn Marino 
55*86d7f5d3SJohn Marino /* Print a header for a context diff, with the file names and dates.  */
56*86d7f5d3SJohn Marino 
57*86d7f5d3SJohn Marino void
print_context_header(inf,unidiff_flag)58*86d7f5d3SJohn Marino print_context_header (inf, unidiff_flag)
59*86d7f5d3SJohn Marino      struct file_data inf[];
60*86d7f5d3SJohn Marino      int unidiff_flag;
61*86d7f5d3SJohn Marino {
62*86d7f5d3SJohn Marino   if (unidiff_flag)
63*86d7f5d3SJohn Marino     {
64*86d7f5d3SJohn Marino       print_context_label ("---", &inf[0], file_label[0]);
65*86d7f5d3SJohn Marino       print_context_label ("+++", &inf[1], file_label[1]);
66*86d7f5d3SJohn Marino     }
67*86d7f5d3SJohn Marino   else
68*86d7f5d3SJohn Marino     {
69*86d7f5d3SJohn Marino       print_context_label ("***", &inf[0], file_label[0]);
70*86d7f5d3SJohn Marino       print_context_label ("---", &inf[1], file_label[1]);
71*86d7f5d3SJohn Marino     }
72*86d7f5d3SJohn Marino }
73*86d7f5d3SJohn Marino 
74*86d7f5d3SJohn Marino /* Print an edit script in context format.  */
75*86d7f5d3SJohn Marino 
76*86d7f5d3SJohn Marino void
print_context_script(script,unidiff_flag)77*86d7f5d3SJohn Marino print_context_script (script, unidiff_flag)
78*86d7f5d3SJohn Marino      struct change *script;
79*86d7f5d3SJohn Marino      int unidiff_flag;
80*86d7f5d3SJohn Marino {
81*86d7f5d3SJohn Marino   if (ignore_blank_lines_flag || ignore_regexp_list)
82*86d7f5d3SJohn Marino     mark_ignorable (script);
83*86d7f5d3SJohn Marino   else
84*86d7f5d3SJohn Marino     {
85*86d7f5d3SJohn Marino       struct change *e;
86*86d7f5d3SJohn Marino       for (e = script; e; e = e->link)
87*86d7f5d3SJohn Marino 	e->ignore = 0;
88*86d7f5d3SJohn Marino     }
89*86d7f5d3SJohn Marino 
90*86d7f5d3SJohn Marino   find_function_last_search = - files[0].prefix_lines;
91*86d7f5d3SJohn Marino   find_function_last_match = find_function_last_search - 1;
92*86d7f5d3SJohn Marino 
93*86d7f5d3SJohn Marino   if (unidiff_flag)
94*86d7f5d3SJohn Marino     print_script (script, find_hunk, pr_unidiff_hunk);
95*86d7f5d3SJohn Marino   else
96*86d7f5d3SJohn Marino     print_script (script, find_hunk, pr_context_hunk);
97*86d7f5d3SJohn Marino }
98*86d7f5d3SJohn Marino 
99*86d7f5d3SJohn Marino /* Print a pair of line numbers with a comma, translated for file FILE.
100*86d7f5d3SJohn Marino    If the second number is not greater, use the first in place of it.
101*86d7f5d3SJohn Marino 
102*86d7f5d3SJohn Marino    Args A and B are internal line numbers.
103*86d7f5d3SJohn Marino    We print the translated (real) line numbers.  */
104*86d7f5d3SJohn Marino 
105*86d7f5d3SJohn Marino static void
print_context_number_range(file,a,b)106*86d7f5d3SJohn Marino print_context_number_range (file, a, b)
107*86d7f5d3SJohn Marino      struct file_data const *file;
108*86d7f5d3SJohn Marino      int a, b;
109*86d7f5d3SJohn Marino {
110*86d7f5d3SJohn Marino   int trans_a, trans_b;
111*86d7f5d3SJohn Marino   translate_range (file, a, b, &trans_a, &trans_b);
112*86d7f5d3SJohn Marino 
113*86d7f5d3SJohn Marino   /* Note: we can have B < A in the case of a range of no lines.
114*86d7f5d3SJohn Marino      In this case, we should print the line number before the range,
115*86d7f5d3SJohn Marino      which is B.  */
116*86d7f5d3SJohn Marino   if (trans_b > trans_a)
117*86d7f5d3SJohn Marino     printf_output ("%d,%d", trans_a, trans_b);
118*86d7f5d3SJohn Marino   else
119*86d7f5d3SJohn Marino     printf_output ("%d", trans_b);
120*86d7f5d3SJohn Marino }
121*86d7f5d3SJohn Marino 
122*86d7f5d3SJohn Marino /* Print a portion of an edit script in context format.
123*86d7f5d3SJohn Marino    HUNK is the beginning of the portion to be printed.
124*86d7f5d3SJohn Marino    The end is marked by a `link' that has been nulled out.
125*86d7f5d3SJohn Marino 
126*86d7f5d3SJohn Marino    Prints out lines from both files, and precedes each
127*86d7f5d3SJohn Marino    line with the appropriate flag-character.  */
128*86d7f5d3SJohn Marino 
129*86d7f5d3SJohn Marino static void
pr_context_hunk(hunk)130*86d7f5d3SJohn Marino pr_context_hunk (hunk)
131*86d7f5d3SJohn Marino      struct change *hunk;
132*86d7f5d3SJohn Marino {
133*86d7f5d3SJohn Marino   int first0, last0, first1, last1, show_from, show_to, i;
134*86d7f5d3SJohn Marino   struct change *next;
135*86d7f5d3SJohn Marino   char const *prefix;
136*86d7f5d3SJohn Marino   char const *function;
137*86d7f5d3SJohn Marino   size_t function_length;
138*86d7f5d3SJohn Marino 
139*86d7f5d3SJohn Marino   /* Determine range of line numbers involved in each file.  */
140*86d7f5d3SJohn Marino 
141*86d7f5d3SJohn Marino   analyze_hunk (hunk, &first0, &last0, &first1, &last1, &show_from, &show_to);
142*86d7f5d3SJohn Marino 
143*86d7f5d3SJohn Marino   if (!show_from && !show_to)
144*86d7f5d3SJohn Marino     return;
145*86d7f5d3SJohn Marino 
146*86d7f5d3SJohn Marino   /* Include a context's width before and after.  */
147*86d7f5d3SJohn Marino 
148*86d7f5d3SJohn Marino   i = - files[0].prefix_lines;
149*86d7f5d3SJohn Marino   first0 = max (first0 - context, i);
150*86d7f5d3SJohn Marino   first1 = max (first1 - context, i);
151*86d7f5d3SJohn Marino   last0 = min (last0 + context, files[0].valid_lines - 1);
152*86d7f5d3SJohn Marino   last1 = min (last1 + context, files[1].valid_lines - 1);
153*86d7f5d3SJohn Marino 
154*86d7f5d3SJohn Marino   /* If desired, find the preceding function definition line in file 0.  */
155*86d7f5d3SJohn Marino   function = 0;
156*86d7f5d3SJohn Marino   if (function_regexp_list)
157*86d7f5d3SJohn Marino     find_function (&files[0], first0, &function, &function_length);
158*86d7f5d3SJohn Marino 
159*86d7f5d3SJohn Marino   begin_output ();
160*86d7f5d3SJohn Marino 
161*86d7f5d3SJohn Marino   /* If we looked for and found a function this is part of,
162*86d7f5d3SJohn Marino      include its name in the header of the diff section.  */
163*86d7f5d3SJohn Marino   printf_output ("***************");
164*86d7f5d3SJohn Marino 
165*86d7f5d3SJohn Marino   if (function)
166*86d7f5d3SJohn Marino     {
167*86d7f5d3SJohn Marino       printf_output (" ");
168*86d7f5d3SJohn Marino       write_output (function, min (function_length - 1, 40));
169*86d7f5d3SJohn Marino     }
170*86d7f5d3SJohn Marino 
171*86d7f5d3SJohn Marino   printf_output ("\n*** ");
172*86d7f5d3SJohn Marino   print_context_number_range (&files[0], first0, last0);
173*86d7f5d3SJohn Marino   printf_output (" ****\n");
174*86d7f5d3SJohn Marino 
175*86d7f5d3SJohn Marino   if (show_from)
176*86d7f5d3SJohn Marino     {
177*86d7f5d3SJohn Marino       next = hunk;
178*86d7f5d3SJohn Marino 
179*86d7f5d3SJohn Marino       for (i = first0; i <= last0; i++)
180*86d7f5d3SJohn Marino 	{
181*86d7f5d3SJohn Marino 	  /* Skip past changes that apply (in file 0)
182*86d7f5d3SJohn Marino 	     only to lines before line I.  */
183*86d7f5d3SJohn Marino 
184*86d7f5d3SJohn Marino 	  while (next && next->line0 + next->deleted <= i)
185*86d7f5d3SJohn Marino 	    next = next->link;
186*86d7f5d3SJohn Marino 
187*86d7f5d3SJohn Marino 	  /* Compute the marking for line I.  */
188*86d7f5d3SJohn Marino 
189*86d7f5d3SJohn Marino 	  prefix = " ";
190*86d7f5d3SJohn Marino 	  if (next && next->line0 <= i)
191*86d7f5d3SJohn Marino 	    /* The change NEXT covers this line.
192*86d7f5d3SJohn Marino 	       If lines were inserted here in file 1, this is "changed".
193*86d7f5d3SJohn Marino 	       Otherwise it is "deleted".  */
194*86d7f5d3SJohn Marino 	    prefix = (next->inserted > 0 ? "!" : "-");
195*86d7f5d3SJohn Marino 
196*86d7f5d3SJohn Marino 	  print_1_line (prefix, &files[0].linbuf[i]);
197*86d7f5d3SJohn Marino 	}
198*86d7f5d3SJohn Marino     }
199*86d7f5d3SJohn Marino 
200*86d7f5d3SJohn Marino   printf_output ("--- ");
201*86d7f5d3SJohn Marino   print_context_number_range (&files[1], first1, last1);
202*86d7f5d3SJohn Marino   printf_output (" ----\n");
203*86d7f5d3SJohn Marino 
204*86d7f5d3SJohn Marino   if (show_to)
205*86d7f5d3SJohn Marino     {
206*86d7f5d3SJohn Marino       next = hunk;
207*86d7f5d3SJohn Marino 
208*86d7f5d3SJohn Marino       for (i = first1; i <= last1; i++)
209*86d7f5d3SJohn Marino 	{
210*86d7f5d3SJohn Marino 	  /* Skip past changes that apply (in file 1)
211*86d7f5d3SJohn Marino 	     only to lines before line I.  */
212*86d7f5d3SJohn Marino 
213*86d7f5d3SJohn Marino 	  while (next && next->line1 + next->inserted <= i)
214*86d7f5d3SJohn Marino 	    next = next->link;
215*86d7f5d3SJohn Marino 
216*86d7f5d3SJohn Marino 	  /* Compute the marking for line I.  */
217*86d7f5d3SJohn Marino 
218*86d7f5d3SJohn Marino 	  prefix = " ";
219*86d7f5d3SJohn Marino 	  if (next && next->line1 <= i)
220*86d7f5d3SJohn Marino 	    /* The change NEXT covers this line.
221*86d7f5d3SJohn Marino 	       If lines were deleted here in file 0, this is "changed".
222*86d7f5d3SJohn Marino 	       Otherwise it is "inserted".  */
223*86d7f5d3SJohn Marino 	    prefix = (next->deleted > 0 ? "!" : "+");
224*86d7f5d3SJohn Marino 
225*86d7f5d3SJohn Marino 	  print_1_line (prefix, &files[1].linbuf[i]);
226*86d7f5d3SJohn Marino 	}
227*86d7f5d3SJohn Marino     }
228*86d7f5d3SJohn Marino }
229*86d7f5d3SJohn Marino 
230*86d7f5d3SJohn Marino /* Print a pair of line numbers with a comma, translated for file FILE.
231*86d7f5d3SJohn Marino    If the second number is smaller, use the first in place of it.
232*86d7f5d3SJohn Marino    If the numbers are equal, print just one number.
233*86d7f5d3SJohn Marino 
234*86d7f5d3SJohn Marino    Args A and B are internal line numbers.
235*86d7f5d3SJohn Marino    We print the translated (real) line numbers.  */
236*86d7f5d3SJohn Marino 
237*86d7f5d3SJohn Marino static void
print_unidiff_number_range(file,a,b)238*86d7f5d3SJohn Marino print_unidiff_number_range (file, a, b)
239*86d7f5d3SJohn Marino      struct file_data const *file;
240*86d7f5d3SJohn Marino      int a, b;
241*86d7f5d3SJohn Marino {
242*86d7f5d3SJohn Marino   int trans_a, trans_b;
243*86d7f5d3SJohn Marino   translate_range (file, a, b, &trans_a, &trans_b);
244*86d7f5d3SJohn Marino 
245*86d7f5d3SJohn Marino   /* Note: we can have B < A in the case of a range of no lines.
246*86d7f5d3SJohn Marino      In this case, we should print the line number before the range,
247*86d7f5d3SJohn Marino      which is B.  */
248*86d7f5d3SJohn Marino   if (trans_b <= trans_a)
249*86d7f5d3SJohn Marino     printf_output (trans_b == trans_a ? "%d" : "%d,0", trans_b);
250*86d7f5d3SJohn Marino   else
251*86d7f5d3SJohn Marino     printf_output ("%d,%d", trans_a, trans_b - trans_a + 1);
252*86d7f5d3SJohn Marino }
253*86d7f5d3SJohn Marino 
254*86d7f5d3SJohn Marino /* Print a portion of an edit script in unidiff format.
255*86d7f5d3SJohn Marino    HUNK is the beginning of the portion to be printed.
256*86d7f5d3SJohn Marino    The end is marked by a `link' that has been nulled out.
257*86d7f5d3SJohn Marino 
258*86d7f5d3SJohn Marino    Prints out lines from both files, and precedes each
259*86d7f5d3SJohn Marino    line with the appropriate flag-character.  */
260*86d7f5d3SJohn Marino 
261*86d7f5d3SJohn Marino static void
pr_unidiff_hunk(hunk)262*86d7f5d3SJohn Marino pr_unidiff_hunk (hunk)
263*86d7f5d3SJohn Marino      struct change *hunk;
264*86d7f5d3SJohn Marino {
265*86d7f5d3SJohn Marino   int first0, last0, first1, last1, show_from, show_to, i, j, k;
266*86d7f5d3SJohn Marino   struct change *next;
267*86d7f5d3SJohn Marino   char const *function;
268*86d7f5d3SJohn Marino   size_t function_length;
269*86d7f5d3SJohn Marino 
270*86d7f5d3SJohn Marino   /* Determine range of line numbers involved in each file.  */
271*86d7f5d3SJohn Marino 
272*86d7f5d3SJohn Marino   analyze_hunk (hunk, &first0, &last0, &first1, &last1, &show_from, &show_to);
273*86d7f5d3SJohn Marino 
274*86d7f5d3SJohn Marino   if (!show_from && !show_to)
275*86d7f5d3SJohn Marino     return;
276*86d7f5d3SJohn Marino 
277*86d7f5d3SJohn Marino   /* Include a context's width before and after.  */
278*86d7f5d3SJohn Marino 
279*86d7f5d3SJohn Marino   i = - files[0].prefix_lines;
280*86d7f5d3SJohn Marino   first0 = max (first0 - context, i);
281*86d7f5d3SJohn Marino   first1 = max (first1 - context, i);
282*86d7f5d3SJohn Marino   last0 = min (last0 + context, files[0].valid_lines - 1);
283*86d7f5d3SJohn Marino   last1 = min (last1 + context, files[1].valid_lines - 1);
284*86d7f5d3SJohn Marino 
285*86d7f5d3SJohn Marino   /* If desired, find the preceding function definition line in file 0.  */
286*86d7f5d3SJohn Marino   function = 0;
287*86d7f5d3SJohn Marino   if (function_regexp_list)
288*86d7f5d3SJohn Marino     find_function (&files[0], first0, &function, &function_length);
289*86d7f5d3SJohn Marino 
290*86d7f5d3SJohn Marino   begin_output ();
291*86d7f5d3SJohn Marino 
292*86d7f5d3SJohn Marino   printf_output ("@@ -");
293*86d7f5d3SJohn Marino   print_unidiff_number_range (&files[0], first0, last0);
294*86d7f5d3SJohn Marino   printf_output (" +");
295*86d7f5d3SJohn Marino   print_unidiff_number_range (&files[1], first1, last1);
296*86d7f5d3SJohn Marino   printf_output (" @@");
297*86d7f5d3SJohn Marino 
298*86d7f5d3SJohn Marino   /* If we looked for and found a function this is part of,
299*86d7f5d3SJohn Marino      include its name in the header of the diff section.  */
300*86d7f5d3SJohn Marino 
301*86d7f5d3SJohn Marino   if (function)
302*86d7f5d3SJohn Marino     {
303*86d7f5d3SJohn Marino       write_output (" ", 1);
304*86d7f5d3SJohn Marino       write_output (function, min (function_length - 1, 40));
305*86d7f5d3SJohn Marino     }
306*86d7f5d3SJohn Marino   write_output ("\n", 1);
307*86d7f5d3SJohn Marino 
308*86d7f5d3SJohn Marino   next = hunk;
309*86d7f5d3SJohn Marino   i = first0;
310*86d7f5d3SJohn Marino   j = first1;
311*86d7f5d3SJohn Marino 
312*86d7f5d3SJohn Marino   while (i <= last0 || j <= last1)
313*86d7f5d3SJohn Marino     {
314*86d7f5d3SJohn Marino 
315*86d7f5d3SJohn Marino       /* If the line isn't a difference, output the context from file 0. */
316*86d7f5d3SJohn Marino 
317*86d7f5d3SJohn Marino       if (!next || i < next->line0)
318*86d7f5d3SJohn Marino 	{
319*86d7f5d3SJohn Marino 	  write_output (tab_align_flag ? "\t" : " ", 1);
320*86d7f5d3SJohn Marino 	  print_1_line (0, &files[0].linbuf[i++]);
321*86d7f5d3SJohn Marino 	  j++;
322*86d7f5d3SJohn Marino 	}
323*86d7f5d3SJohn Marino       else
324*86d7f5d3SJohn Marino 	{
325*86d7f5d3SJohn Marino 	  /* For each difference, first output the deleted part. */
326*86d7f5d3SJohn Marino 
327*86d7f5d3SJohn Marino 	  k = next->deleted;
328*86d7f5d3SJohn Marino 	  while (k--)
329*86d7f5d3SJohn Marino 	    {
330*86d7f5d3SJohn Marino 	      write_output ("-", 1);
331*86d7f5d3SJohn Marino 	      if (tab_align_flag)
332*86d7f5d3SJohn Marino 		write_output ("\t", 1);
333*86d7f5d3SJohn Marino 	      print_1_line (0, &files[0].linbuf[i++]);
334*86d7f5d3SJohn Marino 	    }
335*86d7f5d3SJohn Marino 
336*86d7f5d3SJohn Marino 	  /* Then output the inserted part. */
337*86d7f5d3SJohn Marino 
338*86d7f5d3SJohn Marino 	  k = next->inserted;
339*86d7f5d3SJohn Marino 	  while (k--)
340*86d7f5d3SJohn Marino 	    {
341*86d7f5d3SJohn Marino 	      write_output ("+", 1);
342*86d7f5d3SJohn Marino 	      if (tab_align_flag)
343*86d7f5d3SJohn Marino 		write_output ("\t", 1);
344*86d7f5d3SJohn Marino 	      print_1_line (0, &files[1].linbuf[j++]);
345*86d7f5d3SJohn Marino 	    }
346*86d7f5d3SJohn Marino 
347*86d7f5d3SJohn Marino 	  /* We're done with this hunk, so on to the next! */
348*86d7f5d3SJohn Marino 
349*86d7f5d3SJohn Marino 	  next = next->link;
350*86d7f5d3SJohn Marino 	}
351*86d7f5d3SJohn Marino     }
352*86d7f5d3SJohn Marino }
353*86d7f5d3SJohn Marino 
354*86d7f5d3SJohn Marino /* Scan a (forward-ordered) edit script for the first place that more than
355*86d7f5d3SJohn Marino    2*CONTEXT unchanged lines appear, and return a pointer
356*86d7f5d3SJohn Marino    to the `struct change' for the last change before those lines.  */
357*86d7f5d3SJohn Marino 
358*86d7f5d3SJohn Marino static struct change *
find_hunk(start)359*86d7f5d3SJohn Marino find_hunk (start)
360*86d7f5d3SJohn Marino      struct change *start;
361*86d7f5d3SJohn Marino {
362*86d7f5d3SJohn Marino   struct change *prev;
363*86d7f5d3SJohn Marino   int top0, top1;
364*86d7f5d3SJohn Marino   int thresh;
365*86d7f5d3SJohn Marino 
366*86d7f5d3SJohn Marino   do
367*86d7f5d3SJohn Marino     {
368*86d7f5d3SJohn Marino       /* Compute number of first line in each file beyond this changed.  */
369*86d7f5d3SJohn Marino       top0 = start->line0 + start->deleted;
370*86d7f5d3SJohn Marino       top1 = start->line1 + start->inserted;
371*86d7f5d3SJohn Marino       prev = start;
372*86d7f5d3SJohn Marino       start = start->link;
373*86d7f5d3SJohn Marino       /* Threshold distance is 2*CONTEXT between two non-ignorable changes,
374*86d7f5d3SJohn Marino 	 but only CONTEXT if one is ignorable.  */
375*86d7f5d3SJohn Marino       thresh = ((prev->ignore || (start && start->ignore))
376*86d7f5d3SJohn Marino 		? context
377*86d7f5d3SJohn Marino 		: 2 * context + 1);
378*86d7f5d3SJohn Marino       /* It is not supposed to matter which file we check in the end-test.
379*86d7f5d3SJohn Marino 	 If it would matter, crash.  */
380*86d7f5d3SJohn Marino       if (start && start->line0 - top0 != start->line1 - top1)
381*86d7f5d3SJohn Marino 	abort ();
382*86d7f5d3SJohn Marino     } while (start
383*86d7f5d3SJohn Marino 	     /* Keep going if less than THRESH lines
384*86d7f5d3SJohn Marino 		elapse before the affected line.  */
385*86d7f5d3SJohn Marino 	     && start->line0 < top0 + thresh);
386*86d7f5d3SJohn Marino 
387*86d7f5d3SJohn Marino   return prev;
388*86d7f5d3SJohn Marino }
389*86d7f5d3SJohn Marino 
390*86d7f5d3SJohn Marino /* Set the `ignore' flag properly in each change in SCRIPT.
391*86d7f5d3SJohn Marino    It should be 1 if all the lines inserted or deleted in that change
392*86d7f5d3SJohn Marino    are ignorable lines.  */
393*86d7f5d3SJohn Marino 
394*86d7f5d3SJohn Marino static void
mark_ignorable(script)395*86d7f5d3SJohn Marino mark_ignorable (script)
396*86d7f5d3SJohn Marino      struct change *script;
397*86d7f5d3SJohn Marino {
398*86d7f5d3SJohn Marino   while (script)
399*86d7f5d3SJohn Marino     {
400*86d7f5d3SJohn Marino       struct change *next = script->link;
401*86d7f5d3SJohn Marino       int first0, last0, first1, last1, deletes, inserts;
402*86d7f5d3SJohn Marino 
403*86d7f5d3SJohn Marino       /* Turn this change into a hunk: detach it from the others.  */
404*86d7f5d3SJohn Marino       script->link = 0;
405*86d7f5d3SJohn Marino 
406*86d7f5d3SJohn Marino       /* Determine whether this change is ignorable.  */
407*86d7f5d3SJohn Marino       analyze_hunk (script, &first0, &last0, &first1, &last1, &deletes, &inserts);
408*86d7f5d3SJohn Marino       /* Reconnect the chain as before.  */
409*86d7f5d3SJohn Marino       script->link = next;
410*86d7f5d3SJohn Marino 
411*86d7f5d3SJohn Marino       /* If the change is ignorable, mark it.  */
412*86d7f5d3SJohn Marino       script->ignore = (!deletes && !inserts);
413*86d7f5d3SJohn Marino 
414*86d7f5d3SJohn Marino       /* Advance to the following change.  */
415*86d7f5d3SJohn Marino       script = next;
416*86d7f5d3SJohn Marino     }
417*86d7f5d3SJohn Marino }
418*86d7f5d3SJohn Marino 
419*86d7f5d3SJohn Marino /* Find the last function-header line in FILE prior to line number LINENUM.
420*86d7f5d3SJohn Marino    This is a line containing a match for the regexp in `function_regexp'.
421*86d7f5d3SJohn Marino    Store the address of the line text into LINEP and the length of the
422*86d7f5d3SJohn Marino    line into LENP.
423*86d7f5d3SJohn Marino    Do not store anything if no function-header is found.  */
424*86d7f5d3SJohn Marino 
425*86d7f5d3SJohn Marino static void
find_function(file,linenum,linep,lenp)426*86d7f5d3SJohn Marino find_function (file, linenum, linep, lenp)
427*86d7f5d3SJohn Marino      struct file_data const *file;
428*86d7f5d3SJohn Marino      int linenum;
429*86d7f5d3SJohn Marino      char const **linep;
430*86d7f5d3SJohn Marino      size_t *lenp;
431*86d7f5d3SJohn Marino {
432*86d7f5d3SJohn Marino   int i = linenum;
433*86d7f5d3SJohn Marino   int last = find_function_last_search;
434*86d7f5d3SJohn Marino   find_function_last_search = i;
435*86d7f5d3SJohn Marino 
436*86d7f5d3SJohn Marino   while (--i >= last)
437*86d7f5d3SJohn Marino     {
438*86d7f5d3SJohn Marino       /* See if this line is what we want.  */
439*86d7f5d3SJohn Marino       struct regexp_list *r;
440*86d7f5d3SJohn Marino       char const *line = file->linbuf[i];
441*86d7f5d3SJohn Marino       size_t len = file->linbuf[i + 1] - line;
442*86d7f5d3SJohn Marino 
443*86d7f5d3SJohn Marino       for (r = function_regexp_list; r; r = r->next)
444*86d7f5d3SJohn Marino 	if (0 <= re_search (&r->buf, line, len, 0, len, 0))
445*86d7f5d3SJohn Marino 	  {
446*86d7f5d3SJohn Marino 	    *linep = line;
447*86d7f5d3SJohn Marino 	    *lenp = len;
448*86d7f5d3SJohn Marino 	    find_function_last_match = i;
449*86d7f5d3SJohn Marino 	    return;
450*86d7f5d3SJohn Marino 	  }
451*86d7f5d3SJohn Marino     }
452*86d7f5d3SJohn Marino   /* If we search back to where we started searching the previous time,
453*86d7f5d3SJohn Marino      find the line we found last time.  */
454*86d7f5d3SJohn Marino   if (find_function_last_match >= - file->prefix_lines)
455*86d7f5d3SJohn Marino     {
456*86d7f5d3SJohn Marino       i = find_function_last_match;
457*86d7f5d3SJohn Marino       *linep = file->linbuf[i];
458*86d7f5d3SJohn Marino       *lenp = file->linbuf[i + 1] - *linep;
459*86d7f5d3SJohn Marino       return;
460*86d7f5d3SJohn Marino     }
461*86d7f5d3SJohn Marino   return;
462*86d7f5d3SJohn Marino }
463