source: vendor/diffutils/2.8.1/src/context.c@ 2603

Last change on this file since 2603 was 2556, checked in by bird, 20 years ago

diffutils 2.8.1

File size: 13.0 KB
RevLine 
[2556]1/* Context-format output routines for GNU DIFF.
2
3 Copyright (C) 1988, 1989, 1991, 1992, 1993, 1994, 1995, 1998, 2001,
4 2002 Free Software Foundation, Inc.
5
6 This file is part of GNU DIFF.
7
8 GNU DIFF is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2, or (at your option)
11 any later version.
12
13 GNU DIFF is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; see the file COPYING.
20 If not, write to the Free Software Foundation,
21 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
22
23#include "diff.h"
24#include <inttostr.h>
25#include <regex.h>
26
27#ifdef ST_MTIM_NSEC
28# define TIMESPEC_NS(timespec) ((timespec).ST_MTIM_NSEC)
29#else
30# define TIMESPEC_NS(timespec) 0
31#endif
32
33size_t nstrftime (char *, size_t, char const *, struct tm const *, int, int);
34
35static char const *find_function (char const * const *, lin);
36static struct change *find_hunk (struct change *);
37static void mark_ignorable (struct change *);
38static void pr_context_hunk (struct change *);
39static void pr_unidiff_hunk (struct change *);
40
41/* Last place find_function started searching from. */
42static lin find_function_last_search;
43
44/* The value find_function returned when it started searching there. */
45static lin find_function_last_match;
46
47
48/* Print a label for a context diff, with a file name and date or a label. */
49
50static void
51print_context_label (char const *mark,
52 struct file_data *inf,
53 char const *label)
54{
55 if (label)
56 fprintf (outfile, "%s %s\n", mark, label);
57 else
58 {
59 char buf[MAX (INT_STRLEN_BOUND (int) + 32,
60 INT_STRLEN_BOUND (time_t) + 11)];
61 struct tm const *tm = localtime (&inf->stat.st_mtime);
62 int nsec = TIMESPEC_NS (inf->stat.st_mtim);
63 if (! (tm && nstrftime (buf, sizeof buf, time_format, tm, 0, nsec)))
64 {
65 long sec = inf->stat.st_mtime;
66 verify (info_preserved, sizeof inf->stat.st_mtime <= sizeof sec);
67 sprintf (buf, "%ld.%.9d", sec, nsec);
68 }
69 fprintf (outfile, "%s %s\t%s\n", mark, inf->name, buf);
70 }
71}
72
73/* Print a header for a context diff, with the file names and dates. */
74
75void
76print_context_header (struct file_data inf[], bool unidiff)
77{
78 if (unidiff)
79 {
80 print_context_label ("---", &inf[0], file_label[0]);
81 print_context_label ("+++", &inf[1], file_label[1]);
82 }
83 else
84 {
85 print_context_label ("***", &inf[0], file_label[0]);
86 print_context_label ("---", &inf[1], file_label[1]);
87 }
88}
89
90/* Print an edit script in context format. */
91
92void
93print_context_script (struct change *script, bool unidiff)
94{
95 if (ignore_blank_lines || ignore_regexp.fastmap)
96 mark_ignorable (script);
97 else
98 {
99 struct change *e;
100 for (e = script; e; e = e->link)
101 e->ignore = 0;
102 }
103
104 find_function_last_search = - files[0].prefix_lines;
105 find_function_last_match = LIN_MAX;
106
107 if (unidiff)
108 print_script (script, find_hunk, pr_unidiff_hunk);
109 else
110 print_script (script, find_hunk, pr_context_hunk);
111}
112
113
114/* Print a pair of line numbers with a comma, translated for file FILE.
115 If the second number is not greater, use the first in place of it.
116
117 Args A and B are internal line numbers.
118 We print the translated (real) line numbers. */
119
120static void
121print_context_number_range (struct file_data const *file, lin a, lin b)
122{
123 long trans_a, trans_b;
124 translate_range (file, a, b, &trans_a, &trans_b);
125
126 /* We can have B <= A in the case of a range of no lines.
127 In this case, we should print the line number before the range,
128 which is B.
129
130 POSIX 1003.1-2001 requires two line numbers separated by a comma
131 even if the line numbers are the same. However, this does not
132 match existing practice and is surely an error in the
133 specification. */
134
135 if (trans_b <= trans_a)
136 fprintf (outfile, "%ld", trans_b);
137 else
138 fprintf (outfile, "%ld,%ld", trans_a, trans_b);
139}
140
141/* Print FUNCTION in a context header. */
142static void
143print_context_function (FILE *out, char const *function)
144{
145 int i;
146 putc (' ', out);
147 for (i = 0; i < 40 && function[i] != '\n'; i++)
148 continue;
149 fwrite (function, 1, i, out);
150}
151
152
153/* Print a portion of an edit script in context format.
154 HUNK is the beginning of the portion to be printed.
155 The end is marked by a `link' that has been nulled out.
156
157 Prints out lines from both files, and precedes each
158 line with the appropriate flag-character. */
159
160static void
161pr_context_hunk (struct change *hunk)
162{
163 lin first0, last0, first1, last1, i;
164 char const *prefix;
165 char const *function;
166 FILE *out;
167
168 /* Determine range of line numbers involved in each file. */
169
170 enum changes changes = analyze_hunk (hunk, &first0, &last0, &first1, &last1);
171 if (! changes)
172 return;
173
174 /* Include a context's width before and after. */
175
176 i = - files[0].prefix_lines;
177 first0 = MAX (first0 - context, i);
178 first1 = MAX (first1 - context, i);
179 if (last0 < files[0].valid_lines - context)
180 last0 += context;
181 else
182 last0 = files[0].valid_lines - 1;
183 if (last1 < files[1].valid_lines - context)
184 last1 += context;
185 else
186 last1 = files[1].valid_lines - 1;
187
188 /* If desired, find the preceding function definition line in file 0. */
189 function = 0;