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