ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/src/vendor/FreeBSD/dist/contrib/diff/context.c
Revision: 9647
Committed: Sun Oct 22 19:53:04 2017 UTC (6 years, 6 months ago) by laffer1
Content type: text/plain
File size: 13241 byte(s)
Log Message:
tag freebsd 6.1

File Contents

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

Properties

Name Value
cvs2svn:cvs-rev 1.1.1.1