xref: /freebsd/contrib/diff/src/context.c (revision 416ba5c74546f32a993436a99516d35008e9f384)
118fd37a7SXin LI /* Context-format output routines for GNU DIFF.
218fd37a7SXin LI 
318fd37a7SXin LI    Copyright (C) 1988, 1989, 1991, 1992, 1993, 1994, 1995, 1998, 2001,
418fd37a7SXin LI    2002, 2004 Free Software Foundation, Inc.
518fd37a7SXin LI 
618fd37a7SXin LI    This file is part of GNU DIFF.
718fd37a7SXin LI 
818fd37a7SXin LI    GNU DIFF is free software; you can redistribute it and/or modify
918fd37a7SXin LI    it under the terms of the GNU General Public License as published by
1018fd37a7SXin LI    the Free Software Foundation; either version 2, or (at your option)
1118fd37a7SXin LI    any later version.
1218fd37a7SXin LI 
1318fd37a7SXin LI    GNU DIFF is distributed in the hope that it will be useful,
1418fd37a7SXin LI    but WITHOUT ANY WARRANTY; without even the implied warranty of
1518fd37a7SXin LI    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1618fd37a7SXin LI    GNU General Public License for more details.
1718fd37a7SXin LI 
1818fd37a7SXin LI    You should have received a copy of the GNU General Public License
1918fd37a7SXin LI    along with this program; see the file COPYING.
2018fd37a7SXin LI    If not, write to the Free Software Foundation,
2118fd37a7SXin LI    59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
2218fd37a7SXin LI 
2318fd37a7SXin LI #include "diff.h"
2418fd37a7SXin LI #include <inttostr.h>
2518fd37a7SXin LI 
2618fd37a7SXin LI #ifdef ST_MTIM_NSEC
2718fd37a7SXin LI # define TIMESPEC_NS(timespec) ((timespec).ST_MTIM_NSEC)
2818fd37a7SXin LI #else
2918fd37a7SXin LI # define TIMESPEC_NS(timespec) 0
3018fd37a7SXin LI #endif
3118fd37a7SXin LI 
326f5e3243SDavid E. O'Brien size_t nstrftime (char *, size_t, char const *, struct tm const *, int, long);
3318fd37a7SXin LI 
3418fd37a7SXin LI static char const *find_function (char const * const *, lin);
3518fd37a7SXin LI static struct change *find_hunk (struct change *);
3618fd37a7SXin LI static void mark_ignorable (struct change *);
3718fd37a7SXin LI static void pr_context_hunk (struct change *);
3818fd37a7SXin LI static void pr_unidiff_hunk (struct change *);
3918fd37a7SXin LI 
4018fd37a7SXin LI /* Last place find_function started searching from.  */
4118fd37a7SXin LI static lin find_function_last_search;
4218fd37a7SXin LI 
4318fd37a7SXin LI /* The value find_function returned when it started searching there.  */
4418fd37a7SXin LI static lin find_function_last_match;
4518fd37a7SXin LI 
4618fd37a7SXin LI /* Print a label for a context diff, with a file name and date or a label.  */
4718fd37a7SXin LI 
4818fd37a7SXin LI static void
print_context_label(char const * mark,struct file_data * inf,char const * label)4918fd37a7SXin LI print_context_label (char const *mark,
5018fd37a7SXin LI 		     struct file_data *inf,
5118fd37a7SXin LI 		     char const *label)
5218fd37a7SXin LI {
5318fd37a7SXin LI   if (label)
5418fd37a7SXin LI     fprintf (outfile, "%s %s\n", mark, label);
5518fd37a7SXin LI   else
5618fd37a7SXin LI     {
5718fd37a7SXin LI       char buf[MAX (INT_STRLEN_BOUND (int) + 32,
5818fd37a7SXin LI 		    INT_STRLEN_BOUND (time_t) + 11)];
5918fd37a7SXin LI       struct tm const *tm = localtime (&inf->stat.st_mtime);
606f5e3243SDavid E. O'Brien       long nsec = TIMESPEC_NS (inf->stat.st_mtim);
6118fd37a7SXin LI       if (! (tm && nstrftime (buf, sizeof buf, time_format, tm, 0, nsec)))
6218fd37a7SXin LI 	{
636f5e3243SDavid E. O'Brien 	  time_t sec = inf->stat.st_mtime;
6418fd37a7SXin LI 	  verify (info_preserved, sizeof inf->stat.st_mtime <= sizeof sec);
65*9310c7d5SMarcelo Araujo 	  sprintf (buf, "%jd.%.9ld", (intmax_t)sec, nsec);
6618fd37a7SXin LI 	}
6718fd37a7SXin LI       fprintf (outfile, "%s %s\t%s\n", mark, inf->name, buf);
6818fd37a7SXin LI     }
6918fd37a7SXin LI }
7018fd37a7SXin LI 
7118fd37a7SXin LI /* Print a header for a context diff, with the file names and dates.  */
7218fd37a7SXin LI 
7318fd37a7SXin LI void
print_context_header(struct file_data inf[],bool unidiff)7418fd37a7SXin LI print_context_header (struct file_data inf[], bool unidiff)
7518fd37a7SXin LI {
7618fd37a7SXin LI   if (unidiff)
7718fd37a7SXin LI     {
7818fd37a7SXin LI       print_context_label ("---", &inf[0], file_label[0]);
7918fd37a7SXin LI       print_context_label ("+++", &inf[1], file_label[1]);
8018fd37a7SXin LI     }
8118fd37a7SXin LI   else
8218fd37a7SXin LI     {
8318fd37a7SXin LI       print_context_label ("***", &inf[0], file_label[0]);
8418fd37a7SXin LI       print_context_label ("---", &inf[1], file_label[1]);
8518fd37a7SXin LI     }
8618fd37a7SXin LI }
8718fd37a7SXin LI 
8818fd37a7SXin LI /* Print an edit script in context format.  */
8918fd37a7SXin LI 
9018fd37a7SXin LI void
print_context_script(struct change * script,bool unidiff)9118fd37a7SXin LI print_context_script (struct change *script, bool unidiff)
9218fd37a7SXin LI {
9318fd37a7SXin LI   if (ignore_blank_lines || ignore_regexp.fastmap)
9418fd37a7SXin LI     mark_ignorable (script);
9518fd37a7SXin LI   else
9618fd37a7SXin LI     {
9718fd37a7SXin LI       struct change *e;
9818fd37a7SXin LI       for (e = script; e; e = e->link)
9918fd37a7SXin LI 	e->ignore = false;
10018fd37a7SXin LI     }
10118fd37a7SXin LI 
10218fd37a7SXin LI   find_function_last_search = - files[0].prefix_lines;
10318fd37a7SXin LI   find_function_last_match = LIN_MAX;
10418fd37a7SXin LI 
10518fd37a7SXin LI   if (unidiff)
10618fd37a7SXin LI     print_script (script, find_hunk, pr_unidiff_hunk);
10718fd37a7SXin LI   else
10818fd37a7SXin LI     print_script (script, find_hunk, pr_context_hunk);
10918fd37a7SXin LI }
11018fd37a7SXin LI 
11118fd37a7SXin LI /* Print a pair of line numbers with a comma, translated for file FILE.
11218fd37a7SXin LI    If the second number is not greater, use the first in place of it.
11318fd37a7SXin LI 
11418fd37a7SXin LI    Args A and B are internal line numbers.
11518fd37a7SXin LI    We print the translated (real) line numbers.  */
11618fd37a7SXin LI 
11718fd37a7SXin LI static void
print_context_number_range(struct file_data const * file,lin a,lin b)11818fd37a7SXin LI print_context_number_range (struct file_data const *file, lin a, lin b)
11918fd37a7SXin LI {
12018fd37a7SXin LI   long int trans_a, trans_b;
12118fd37a7SXin LI   translate_range (file, a, b, &trans_a, &trans_b);
12218fd37a7SXin LI 
12318fd37a7SXin LI   /* We can have B <= A in the case of a range of no lines.
12418fd37a7SXin LI      In this case, we should print the line number before the range,
12518fd37a7SXin LI      which is B.
12618fd37a7SXin LI 
12718fd37a7SXin LI      POSIX 1003.1-2001 requires two line numbers separated by a comma
12818fd37a7SXin LI      even if the line numbers are the same.  However, this does not
12918fd37a7SXin LI      match existing practice and is surely an error in the
13018fd37a7SXin LI      specification.  */
13118fd37a7SXin LI 
13218fd37a7SXin LI   if (trans_b <= trans_a)
13318fd37a7SXin LI     fprintf (outfile, "%ld", trans_b);
13418fd37a7SXin LI   else
13518fd37a7SXin LI     fprintf (outfile, "%ld,%ld", trans_a, trans_b);
13618fd37a7SXin LI }
13718fd37a7SXin LI 
13818fd37a7SXin LI /* Print FUNCTION in a context header.  */
13918fd37a7SXin LI static void
print_context_function(FILE * out,char const * function)14018fd37a7SXin LI print_context_function (FILE *out, char const *function)
14118fd37a7SXin LI {
14218fd37a7SXin LI   int i;
14318fd37a7SXin LI   putc (' ', out);
14418fd37a7SXin LI   for (i = 0; i < 40 && function[i] != '\n'; i++)
14518fd37a7SXin LI     continue;
14618fd37a7SXin LI   fwrite (function, sizeof (char), i, out);
14718fd37a7SXin LI }
14818fd37a7SXin LI 
14918fd37a7SXin LI /* Print a portion of an edit script in context format.
15018fd37a7SXin LI    HUNK is the beginning of the portion to be printed.
15118fd37a7SXin LI    The end is marked by a `link' that has been nulled out.
15218fd37a7SXin LI 
15318fd37a7SXin LI    Prints out lines from both files, and precedes each
15418fd37a7SXin LI    line with the appropriate flag-character.  */
15518fd37a7SXin LI 
15618fd37a7SXin LI static void
pr_context_hunk(struct change * hunk)15718fd37a7SXin LI pr_context_hunk (struct change *hunk)
15818fd37a7SXin LI {
15918fd37a7SXin LI   lin first0, last0, first1, last1, i;
16018fd37a7SXin LI   char const *prefix;
16118fd37a7SXin LI   char const *function;
16218fd37a7SXin LI   FILE *out;
16318fd37a7SXin LI 
16418fd37a7SXin LI   /* Determine range of line numbers involved in each file.  */
16518fd37a7SXin LI 
16618fd37a7SXin LI   enum changes changes = analyze_hunk (hunk, &first0, &last0, &first1, &last1);
16718fd37a7SXin LI   if (! changes)
16818fd37a7SXin LI     return;
16918fd37a7SXin LI 
17018fd37a7SXin LI   /* Include a context's width before and after.  */
17118fd37a7SXin LI 
17218fd37a7SXin LI   i = - files[0].prefix_lines;
17318fd37a7SXin LI   first0 = MAX (first0 - context, i);
17418fd37a7SXin LI   first1 = MAX (first1 - context, i);
17518fd37a7SXin LI   if (last0 < files[0].valid_lines - context)
17618fd37a7SXin LI     last0 += context;
17718fd37a7SXin LI   else
17818fd37a7SXin LI     last0 = files[0].valid_lines - 1;
17918fd37a7SXin LI   if (last1 < files[1].valid_lines - context)
18018fd37a7SXin LI     last1 += context;
18118fd37a7SXin LI   else
18218fd37a7SXin LI     last1 = files[1].valid_lines - 1;
18318fd37a7SXin LI 
18418fd37a7SXin LI   /* If desired, find the preceding function definition line in file 0.  */
18518fd37a7SXin LI   function = 0;
18618fd37a7SXin LI   if (function_regexp.fastmap)
18718fd37a7SXin LI     function = find_function (files[0].linbuf, first0);
18818fd37a7SXin LI 
18918fd37a7SXin LI   begin_output ();
19018fd37a7SXin LI   out = outfile;
19118fd37a7SXin LI 
19218fd37a7SXin LI   fprintf (out, "***************");
19318fd37a7SXin LI 
19418fd37a7SXin LI   if (function)
19518fd37a7SXin LI     print_context_function (out, function);
19618fd37a7SXin LI 
19718fd37a7SXin LI   fprintf (out, "\n*** ");
19818fd37a7SXin LI   print_context_number_range (&files[0], first0, last0);
19918fd37a7SXin LI   fprintf (out, " ****\n");
20018fd37a7SXin LI 
20118fd37a7SXin LI   if (changes & OLD)
20218fd37a7SXin LI     {
20318fd37a7SXin LI       struct change *next = hunk;
20418fd37a7SXin LI 
20518fd37a7SXin LI       for (i = first0; i <= last0; i++)
20618fd37a7SXin LI 	{
20718fd37a7SXin LI 	  /* Skip past changes that apply (in file 0)
20818fd37a7SXin LI 	     only to lines before line I.  */
20918fd37a7SXin LI 
21018fd37a7SXin LI 	  while (next && next->line0 + next->deleted <= i)
21118fd37a7SXin LI 	    next = next->link;
21218fd37a7SXin LI 
21318fd37a7SXin LI 	  /* Compute the marking for line I.  */
21418fd37a7SXin LI 
21518fd37a7SXin LI 	  prefix = " ";
21618fd37a7SXin LI 	  if (next && next->line0 <= i)
21718fd37a7SXin LI 	    /* The change NEXT covers this line.
21818fd37a7SXin LI 	       If lines were inserted here in file 1, this is "changed".
21918fd37a7SXin LI 	       Otherwise it is "deleted".  */
22018fd37a7SXin LI 	    prefix = (next->inserted > 0 ? "!" : "-");
22118fd37a7SXin LI 
22218fd37a7SXin LI 	  print_1_line (prefix, &files[0].linbuf[i]);
22318fd37a7SXin LI 	}
22418fd37a7SXin LI     }
22518fd37a7SXin LI 
22618fd37a7SXin LI   fprintf (out, "--- ");
22718fd37a7SXin LI   print_context_number_range (&files[1], first1, last1);
22818fd37a7SXin LI   fprintf (out, " ----\n");
22918fd37a7SXin LI 
23018fd37a7SXin LI   if (changes & NEW)
23118fd37a7SXin LI     {
23218fd37a7SXin LI       struct change *next = hunk;
23318fd37a7SXin LI 
23418fd37a7SXin LI       for (i = first1; i <= last1; i++)
23518fd37a7SXin LI 	{
23618fd37a7SXin LI 	  /* Skip past changes that apply (in file 1)
23718fd37a7SXin LI 	     only to lines before line I.  */
23818fd37a7SXin LI 
23918fd37a7SXin LI 	  while (next && next->line1 + next->inserted <= i)
24018fd37a7SXin LI 	    next = next->link;
24118fd37a7SXin LI 
24218fd37a7SXin LI 	  /* Compute the marking for line I.  */
24318fd37a7SXin LI 
24418fd37a7SXin LI 	  prefix = " ";
24518fd37a7SXin LI 	  if (next && next->line1 <= i)
24618fd37a7SXin LI 	    /* The change NEXT covers this line.
24718fd37a7SXin LI 	       If lines were deleted here in file 0, this is "changed".
24818fd37a7SXin LI 	       Otherwise it is "inserted".  */
24918fd37a7SXin LI 	    prefix = (next->deleted > 0 ? "!" : "+");
25018fd37a7SXin LI 
25118fd37a7SXin LI 	  print_1_line (prefix, &files[1].linbuf[i]);
25218fd37a7SXin LI 	}
25318fd37a7SXin LI     }
25418fd37a7SXin LI }
25518fd37a7SXin LI 
25618fd37a7SXin LI /* Print a pair of line numbers with a comma, translated for file FILE.
25718fd37a7SXin LI    If the second number is smaller, use the first in place of it.
25818fd37a7SXin LI    If the numbers are equal, print just one number.
25918fd37a7SXin LI 
26018fd37a7SXin LI    Args A and B are internal line numbers.
26118fd37a7SXin LI    We print the translated (real) line numbers.  */
26218fd37a7SXin LI 
26318fd37a7SXin LI static void
print_unidiff_number_range(struct file_data const * file,lin a,lin b)26418fd37a7SXin LI print_unidiff_number_range (struct file_data const *file, lin a, lin b)
26518fd37a7SXin LI {
26618fd37a7SXin LI   long int trans_a, trans_b;
26718fd37a7SXin LI   translate_range (file, a, b, &trans_a, &trans_b);
26818fd37a7SXin LI 
26918fd37a7SXin LI   /* We can have B < A in the case of a range of no lines.
27018fd37a7SXin LI      In this case, we print the line number before the range,
27118fd37a7SXin LI      which is B.  It would be more logical to print A, but
27218fd37a7SXin LI      'patch' expects B in order to detect diffs against empty files.  */
27318fd37a7SXin LI   if (trans_b <= trans_a)
27418fd37a7SXin LI     fprintf (outfile, trans_b < trans_a ? "%ld,0" : "%ld", trans_b);
27518fd37a7SXin LI   else
27618fd37a7SXin LI     fprintf (outfile, "%ld,%ld", trans_a, trans_b - trans_a + 1);
27718fd37a7SXin LI }
27818fd37a7SXin LI 
27918fd37a7SXin LI /* Print a portion of an edit script in unidiff format.
28018fd37a7SXin LI    HUNK is the beginning of the portion to be printed.
28118fd37a7SXin LI    The end is marked by a `link' that has been nulled out.
28218fd37a7SXin LI 
28318fd37a7SXin LI    Prints out lines from both files, and precedes each
28418fd37a7SXin LI    line with the appropriate flag-character.  */
28518fd37a7SXin LI 
28618fd37a7SXin LI static void
pr_unidiff_hunk(struct change * hunk)28718fd37a7SXin LI pr_unidiff_hunk (struct change *hunk)
28818fd37a7SXin LI {
28918fd37a7SXin LI   lin first0, last0, first1, last1;
29018fd37a7SXin LI   lin i, j, k;
29118fd37a7SXin LI   struct change *next;
29218fd37a7SXin LI   char const *function;
29318fd37a7SXin LI   FILE *out;
29418fd37a7SXin LI 
29518fd37a7SXin LI   /* Determine range of line numbers involved in each file.  */
29618fd37a7SXin LI 
29718fd37a7SXin LI   if (! analyze_hunk (hunk, &first0, &last0, &first1, &last1))
29818fd37a7SXin LI     return;
29918fd37a7SXin LI 
30018fd37a7SXin LI   /* Include a context's width before and after.  */
30118fd37a7SXin LI 
30218fd37a7SXin LI   i = - files[0].prefix_lines;
30318fd37a7SXin LI   first0 = MAX (first0 - context, i);
30418fd37a7SXin LI   first1 = MAX (first1 - context, i);
30518fd37a7SXin LI   if (last0 < files[0].valid_lines - context)
30618fd37a7SXin LI     last0 += context;
30718fd37a7SXin LI   else
30818fd37a7SXin LI     last0 = files[0].valid_lines - 1;
30918fd37a7SXin LI   if (last1 < files[1].valid_lines - context)
31018fd37a7SXin LI     last1 += context;
31118fd37a7SXin LI   else
31218fd37a7SXin LI     last1 = files[1].valid_lines - 1;
31318fd37a7SXin LI 
31418fd37a7SXin LI   /* If desired, find the preceding function definition line in file 0.  */
31518fd37a7SXin LI   function = 0;
31618fd37a7SXin LI   if (function_regexp.fastmap)
31718fd37a7SXin LI     function = find_function (files[0].linbuf, first0);
31818fd37a7SXin LI 
31918fd37a7SXin LI   begin_output ();
32018fd37a7SXin LI   out = outfile;
32118fd37a7SXin LI 
32218fd37a7SXin LI   fprintf (out, "@@ -");
32318fd37a7SXin LI   print_unidiff_number_range (&files[0], first0, last0);
32418fd37a7SXin LI   fprintf (out, " +");
32518fd37a7SXin LI   print_unidiff_number_range (&files[1], first1, last1);
32618fd37a7SXin LI   fprintf (out, " @@");
32718fd37a7SXin LI 
32818fd37a7SXin LI   if (function)
32918fd37a7SXin LI     print_context_function (out, function);
33018fd37a7SXin LI 
33118fd37a7SXin LI   putc ('\n', out);
33218fd37a7SXin LI 
33318fd37a7SXin LI   next = hunk;
33418fd37a7SXin LI   i = first0;
33518fd37a7SXin LI   j = first1;
33618fd37a7SXin LI 
33718fd37a7SXin LI   while (i <= last0 || j <= last1)
33818fd37a7SXin LI     {
33918fd37a7SXin LI 
34018fd37a7SXin LI       /* If the line isn't a difference, output the context from file 0. */
34118fd37a7SXin LI 
34218fd37a7SXin LI       if (!next || i < next->line0)
34318fd37a7SXin LI 	{
34418fd37a7SXin LI 	  putc (initial_tab ? '\t' : ' ', out);
34518fd37a7SXin LI 	  print_1_line (0, &files[0].linbuf[i++]);
34618fd37a7SXin LI 	  j++;
34718fd37a7SXin LI 	}
34818fd37a7SXin LI       else
34918fd37a7SXin LI 	{
35018fd37a7SXin LI 	  /* For each difference, first output the deleted part. */
35118fd37a7SXin LI 
35218fd37a7SXin LI 	  k = next->deleted;
35318fd37a7SXin LI 	  while (k--)
35418fd37a7SXin LI 	    {
35518fd37a7SXin LI 	      putc ('-', out);
35618fd37a7SXin LI 	      if (initial_tab)
35718fd37a7SXin LI 		putc ('\t', out);
35818fd37a7SXin LI 	      print_1_line (0, &files[0].linbuf[i++]);
35918fd37a7SXin LI 	    }
36018fd37a7SXin LI 
36118fd37a7SXin LI 	  /* Then output the inserted part. */
36218fd37a7SXin LI 
36318fd37a7SXin LI 	  k = next->inserted;
36418fd37a7SXin LI 	  while (k--)
36518fd37a7SXin LI 	    {
36618fd37a7SXin LI 	      putc ('+', out);
36718fd37a7SXin LI 	      if (initial_tab)
36818fd37a7SXin LI 		putc ('\t', out);
36918fd37a7SXin LI 	      print_1_line (0, &files[1].linbuf[j++]);
37018fd37a7SXin LI 	    }
37118fd37a7SXin LI 
37218fd37a7SXin LI 	  /* We're done with this hunk, so on to the next! */
37318fd37a7SXin LI 
37418fd37a7SXin LI 	  next = next->link;
37518fd37a7SXin LI 	}
37618fd37a7SXin LI     }
37718fd37a7SXin LI }
37818fd37a7SXin LI 
37918fd37a7SXin LI /* Scan a (forward-ordered) edit script for the first place that more than
38018fd37a7SXin LI    2*CONTEXT unchanged lines appear, and return a pointer
38118fd37a7SXin LI    to the `struct change' for the last change before those lines.  */
38218fd37a7SXin LI 
38318fd37a7SXin LI static struct change *
find_hunk(struct change * start)38418fd37a7SXin LI find_hunk (struct change *start)
38518fd37a7SXin LI {
38618fd37a7SXin LI   struct change *prev;
38718fd37a7SXin LI   lin top0, top1;
38818fd37a7SXin LI   lin thresh;
38918fd37a7SXin LI 
39018fd37a7SXin LI   /* Threshold distance is 2 * CONTEXT + 1 between two non-ignorable
39118fd37a7SXin LI      changes, but only CONTEXT if one is ignorable.  Watch out for
39218fd37a7SXin LI      integer overflow, though.  */
39318fd37a7SXin LI   lin non_ignorable_threshold =
39418fd37a7SXin LI     (LIN_MAX - 1) / 2 < context ? LIN_MAX : 2 * context + 1;
39518fd37a7SXin LI   lin ignorable_threshold = context;
39618fd37a7SXin LI 
39718fd37a7SXin LI   do
39818fd37a7SXin LI     {
39918fd37a7SXin LI       /* Compute number of first line in each file beyond this changed.  */
40018fd37a7SXin LI       top0 = start->line0 + start->deleted;
40118fd37a7SXin LI       top1 = start->line1 + start->inserted;
40218fd37a7SXin LI       prev = start;
40318fd37a7SXin LI       start = start->link;
40418fd37a7SXin LI       thresh = (prev->ignore || (start && start->ignore)
40518fd37a7SXin LI 		? ignorable_threshold
40618fd37a7SXin LI 		: non_ignorable_threshold);
40718fd37a7SXin LI       /* It is not supposed to matter which file we check in the end-test.
40818fd37a7SXin LI 	 If it would matter, crash.  */
40918fd37a7SXin LI       if (start && start->line0 - top0 != start->line1 - top1)
41018fd37a7SXin LI 	abort ();
41118fd37a7SXin LI     } while (start
41218fd37a7SXin LI 	     /* Keep going if less than THRESH lines
41318fd37a7SXin LI 		elapse before the affected line.  */
41418fd37a7SXin LI 	     && start->line0 - top0 < thresh);
41518fd37a7SXin LI 
41618fd37a7SXin LI   return prev;
41718fd37a7SXin LI }
41818fd37a7SXin LI 
41918fd37a7SXin LI /* Set the `ignore' flag properly in each change in SCRIPT.
42018fd37a7SXin LI    It should be 1 if all the lines inserted or deleted in that change
42118fd37a7SXin LI    are ignorable lines.  */
42218fd37a7SXin LI 
42318fd37a7SXin LI static void
mark_ignorable(struct change * script)42418fd37a7SXin LI mark_ignorable (struct change *script)
42518fd37a7SXin LI {
42618fd37a7SXin LI   while (script)
42718fd37a7SXin LI     {
42818fd37a7SXin LI       struct change *next = script->link;
42918fd37a7SXin LI       lin first0, last0, first1, last1;
43018fd37a7SXin LI 
43118fd37a7SXin LI       /* Turn this change into a hunk: detach it from the others.  */
43218fd37a7SXin LI       script->link = 0;
43318fd37a7SXin LI 
43418fd37a7SXin LI       /* Determine whether this change is ignorable.  */
43518fd37a7SXin LI       script->ignore = ! analyze_hunk (script,
43618fd37a7SXin LI 				       &first0, &last0, &first1, &last1);
43718fd37a7SXin LI 
43818fd37a7SXin LI       /* Reconnect the chain as before.  */
43918fd37a7SXin LI       script->link = next;
44018fd37a7SXin LI 
44118fd37a7SXin LI       /* Advance to the following change.  */
44218fd37a7SXin LI       script = next;
44318fd37a7SXin LI     }
44418fd37a7SXin LI }
44518fd37a7SXin LI 
44618fd37a7SXin LI /* Find the last function-header line in LINBUF prior to line number LINENUM.
44718fd37a7SXin LI    This is a line containing a match for the regexp in `function_regexp'.
44818fd37a7SXin LI    Return the address of the text, or 0 if no function-header is found.  */
44918fd37a7SXin LI 
45018fd37a7SXin LI static char const *
find_function(char const * const * linbuf,lin linenum)45118fd37a7SXin LI find_function (char const * const *linbuf, lin linenum)
45218fd37a7SXin LI {
45318fd37a7SXin LI   lin i = linenum;
45418fd37a7SXin LI   lin last = find_function_last_search;
45518fd37a7SXin LI   find_function_last_search = i;
45618fd37a7SXin LI 
45718fd37a7SXin LI   while (last <= --i)
45818fd37a7SXin LI     {
45918fd37a7SXin LI       /* See if this line is what we want.  */
46018fd37a7SXin LI       char const *line = linbuf[i];
46118fd37a7SXin LI       size_t linelen = linbuf[i + 1] - line - 1;
46218fd37a7SXin LI 
46318fd37a7SXin LI       /* FIXME: re_search's size args should be size_t, not int.  */
46418fd37a7SXin LI       int len = MIN (linelen, INT_MAX);
46518fd37a7SXin LI 
46618fd37a7SXin LI       if (0 <= re_search (&function_regexp, line, len, 0, len, 0))
46718fd37a7SXin LI 	{
46818fd37a7SXin LI 	  find_function_last_match = i;
46918fd37a7SXin LI 	  return line;
47018fd37a7SXin LI 	}
47118fd37a7SXin LI     }
47218fd37a7SXin LI   /* If we search back to where we started searching the previous time,
47318fd37a7SXin LI      find the line we found last time.  */
47418fd37a7SXin LI   if (find_function_last_match != LIN_MAX)
47518fd37a7SXin LI     return linbuf[find_function_last_match];
47618fd37a7SXin LI 
47718fd37a7SXin LI   return 0;
47818fd37a7SXin LI }
479