1 | /* sdiff-format output routines for GNU DIFF.
|
---|
2 |
|
---|
3 | Copyright (C) 1991, 1992, 1993, 1998, 2001, 2002 Free Software
|
---|
4 | Foundation, Inc.
|
---|
5 |
|
---|
6 | This file is part of GNU DIFF.
|
---|
7 |
|
---|
8 | GNU DIFF is distributed in the hope that it will be useful,
|
---|
9 | but WITHOUT ANY WARRANTY. No author or distributor
|
---|
10 | accepts responsibility to anyone for the consequences of using it
|
---|
11 | or for whether it serves any particular purpose or works at all,
|
---|
12 | unless he says so in writing. Refer to the GNU DIFF General Public
|
---|
13 | License for full details.
|
---|
14 |
|
---|
15 | Everyone is granted permission to copy, modify and redistribute
|
---|
16 | GNU DIFF, but only under the conditions described in the
|
---|
17 | GNU DIFF General Public License. A copy of this license is
|
---|
18 | supposed to have been given to you along with GNU DIFF so you
|
---|
19 | can know your rights and responsibilities. It should be in a
|
---|
20 | file named COPYING. Among other things, the copyright notice
|
---|
21 | and this notice must be preserved on all copies. */
|
---|
22 |
|
---|
23 | #include "diff.h"
|
---|
24 |
|
---|
25 | static void print_sdiff_common_lines (lin, lin);
|
---|
26 | static void print_sdiff_hunk (struct change *);
|
---|
27 |
|
---|
28 | /* Next line number to be printed in the two input files. */
|
---|
29 | static lin next0, next1;
|
---|
30 |
|
---|
31 | /* Print the edit-script SCRIPT as a sdiff style output. */
|
---|
32 |
|
---|
33 | void
|
---|
34 | print_sdiff_script (struct change *script)
|
---|
35 | {
|
---|
36 | begin_output ();
|
---|
37 |
|
---|
38 | next0 = next1 = - files[0].prefix_lines;
|
---|
39 | print_script (script, find_change, print_sdiff_hunk);
|
---|
40 |
|
---|
41 | print_sdiff_common_lines (files[0].valid_lines, files[1].valid_lines);
|
---|
42 | }
|
---|
43 |
|
---|
44 | /* Tab from column FROM to column TO, where FROM <= TO. Yield TO. */
|
---|
45 |
|
---|
46 | static unsigned int
|
---|
47 | tab_from_to (unsigned int from, unsigned int to)
|
---|
48 | {
|
---|
49 | FILE *out = outfile;
|
---|
50 | unsigned int tab;
|
---|
51 |
|
---|
52 | if (!expand_tabs)
|
---|
53 | for (tab = from + TAB_WIDTH - from % TAB_WIDTH; tab <= to; tab += TAB_WIDTH)
|
---|
54 | {
|
---|
55 | putc ('\t', out);
|
---|
56 | from = tab;
|
---|
57 | }
|
---|
58 | while (from++ < to)
|
---|
59 | putc (' ', out);
|
---|
60 | return to;
|
---|
61 | }
|
---|
62 |
|
---|
63 | /*
|
---|
64 | * Print the text for half an sdiff line. This means truncate to width
|
---|
65 | * observing tabs, and trim a trailing newline. Returns the last column
|
---|
66 | * written (not the number of chars).
|
---|
67 | */
|
---|
68 | static unsigned int
|
---|
69 | print_half_line (char const *const *line, unsigned int indent,
|
---|
70 | unsigned int out_bound)
|
---|
71 | {
|
---|
72 | FILE *out = outfile;
|
---|
73 | register unsigned int in_position = 0;
|
---|
74 | register unsigned int out_position = 0;
|
---|
75 | register char const *text_pointer = line[0];
|
---|
76 | register char const *text_limit = line[1];
|
---|
77 |
|
---|
78 | while (text_pointer < text_limit)
|
---|
79 | {
|
---|
80 | register unsigned char c = *text_pointer++;
|
---|
81 |
|
---|
82 | switch (c)
|
---|
83 | {
|
---|
84 | case '\t':
|
---|
85 | {
|
---|
86 | unsigned int spaces = TAB_WIDTH - in_position % TAB_WIDTH;
|
---|
87 | if (in_position == out_position)
|
---|
88 | {
|
---|
89 | unsigned int tabstop = out_position + spaces;
|
---|
90 | if (expand_tabs)
|
---|
91 | {
|
---|
92 | if (out_bound < tabstop)
|
---|
93 | tabstop = out_bound;
|
---|
94 | for (; out_position < tabstop; out_position++)
|
---|
95 | putc (' ', out);
|
---|
96 | }
|
---|
97 | else
|
---|
98 | if (tabstop < out_bound)
|
---|
99 | {
|
---|
100 | out_position = tabstop;
|
---|
101 | putc (c, out);
|
---|
102 | }
|
---|
103 | }
|
---|
104 | in_position += spaces;
|
---|
105 | }
|
---|
106 | break;
|
---|
107 |
|
---|
108 | case '\r':
|
---|
109 | {
|
---|
110 | putc (c, out);
|
---|
111 | tab_from_to (0, indent);
|
---|
112 | in_position = out_position = 0;
|
---|
113 | }
|
---|
114 | break;
|
---|
115 |
|
---|
116 | case '\b':
|
---|
117 | if (in_position != 0 && --in_position < out_bound)
|
---|
118 | {
|
---|
119 | if (out_position <= in_position)
|
---|
120 | /* Add spaces to make up for suppressed tab past out_bound. */
|
---|
121 | for (; out_position < in_position; out_position++)
|
---|
122 | putc (' ', out);
|
---|
123 | else
|
---|
124 | {
|
---|
125 | out_position = in_position;
|
---|
126 | putc (c, out);
|
---|
127 | }
|
---|
128 | }
|
---|
129 | break;
|
---|
130 |
|
---|
131 | case '\f':
|
---|
132 | case '\v':
|
---|
133 | control_char:
|
---|
134 | if (in_position < out_bound)
|
---|
135 | putc (c, out);
|
---|
136 | break;
|
---|
137 |
|
---|
138 | default:
|
---|
139 | if (! ISPRINT (c))
|
---|
140 | goto control_char;
|
---|
141 | /* falls through */
|
---|
142 | case ' ':
|
---|
143 | if (in_position++ < out_bound)
|
---|
144 | {
|
---|
145 | out_position = in_position;
|
---|
146 | putc (c, out);
|
---|
147 | }
|
---|
148 | break;
|
---|
149 |
|
---|
150 | case '\n':
|
---|
151 | return out_position;
|
---|
152 | }
|
---|
153 | }
|
---|
154 |
|
---|
155 | return out_position;
|
---|
156 | }
|
---|
157 |
|
---|
158 | /*
|
---|
159 | * Print side by side lines with a separator in the middle.
|
---|
160 | * 0 parameters are taken to indicate white space text.
|
---|
161 | * Blank lines that can easily be caught are reduced to a single newline.
|
---|
162 | */
|
---|
163 |
|
---|
164 | static void
|
---|
165 | print_1sdiff_line (char const *const *left, char sep,
|
---|
166 | char const *const *right)
|
---|
167 | {
|
---|
168 | FILE *out = outfile;
|
---|
169 | unsigned int hw = sdiff_half_width, c2o = sdiff_column2_offset;
|
---|
170 | unsigned int col = 0;
|
---|
171 | bool put_newline = 0;
|
---|
172 |
|
---|
173 | if (left)
|
---|
174 | {
|
---|
175 | put_newline |= left[1][-1] == '\n';
|
---|
176 | col = print_half_line (left, 0, hw);
|
---|
177 | }
|
---|
178 |
|
---|
179 | if (sep != ' ')
|
---|
180 | {
|
---|
181 | col = tab_from_to (col, (hw + c2o - 1) / 2) + 1;
|
---|
182 | if (sep == '|' && put_newline != (right[1][-1] == '\n'))
|
---|
183 | sep = put_newline ? '/' : '\\';
|
---|
184 | putc (sep, out);
|
---|
185 | }
|
---|
186 |
|
---|
187 | if (right)
|
---|
188 | {
|
---|
189 | put_newline |= right[1][-1] == '\n';
|
---|
190 | if (**right != '\n')
|
---|
191 | {
|
---|
192 | col = tab_from_to (col, c2o);
|
---|
193 | print_half_line (right, col, hw);
|
---|
194 | }
|
---|
195 | }
|
---|
196 |
|
---|
197 | if (put_newline)
|
---|
198 | putc ('\n', out);
|
---|
199 | }
|
---|
200 |
|
---|
201 | /* Print lines common to both files in side-by-side format. */
|
---|
202 | static void
|
---|
203 | print_sdiff_common_lines (lin limit0, lin limit1)
|
---|
204 | {
|
---|
205 | lin i0 = next0, i1 = next1;
|
---|
206 |
|
---|
207 | if (!suppress_common_lines && (i0 != limit0 || i1 != limit1))
|
---|
208 | {
|
---|
209 | if (sdiff_merge_assist)
|
---|
210 | {
|
---|
211 | long len0 = limit0 - i0;
|
---|
212 | long len1 = limit1 - i1;
|
---|
213 | fprintf (outfile, "i%ld,%ld\n", len0, len1);
|
---|
214 | }
|
---|
215 |
|
---|
216 | if (!left_column)
|
---|
217 | {
|
---|
218 | while (i0 != limit0 && i1 != limit1)
|
---|
219 | print_1sdiff_line (&files[0].linbuf[i0++], ' ',
|
---|
220 | &files[1].linbuf[i1++]);
|
---|
221 | while (i1 != limit1)
|
---|
222 | print_1sdiff_line (0, ')', &files[1].linbuf[i1++]);
|
---|
223 | }
|
---|
224 | while (i0 != limit0)
|
---|
225 | print_1sdiff_line (&files[0].linbuf[i0++], '(', 0);
|
---|
226 | }
|
---|
227 |
|
---|
228 | next0 = limit0;
|
---|
229 | next1 = limit1;
|
---|
230 | }
|
---|
231 |
|
---|
232 | /* Print a hunk of an sdiff diff.
|
---|
233 | This is a contiguous portion of a complete edit script,
|
---|
234 | describing changes in consecutive lines. */
|
---|
235 |
|
---|
236 | static void
|
---|
237 | print_sdiff_hunk (struct change *hunk)
|
---|
238 | {
|
---|
239 | lin first0, last0, first1, last1;
|
---|
240 | register lin i, j;
|
---|
241 |
|
---|
242 | /* Determine range of line numbers involved in each file. */
|
---|
243 | enum changes changes =
|
---|
244 | analyze_hunk (hunk, &first0, &last0, &first1, &last1);
|
---|
245 | if (!changes)
|
---|
246 | return;
|
---|
247 |
|
---|
248 | /* Print out lines up to this change. */
|
---|
249 | print_sdiff_common_lines (first0, first1);
|
---|
250 |
|
---|
251 | if (sdiff_merge_assist)
|
---|
252 | {
|
---|
253 | long len0 = last0 - first0 + 1;
|
---|
254 | long len1 = last1 - first1 + 1;
|
---|
255 | fprintf (outfile, "c%ld,%ld\n", len0, len1);
|
---|
256 | }
|
---|
257 |
|
---|
258 | /* Print ``xxx | xxx '' lines */
|
---|
259 | if (changes == CHANGED)
|
---|
260 | {
|
---|
261 | for (i = first0, j = first1; i <= last0 && j <= last1; i++, j++)
|
---|
262 | print_1sdiff_line (&files[0].linbuf[i], '|', &files[1].linbuf[j]);
|
---|
263 | changes = (i <= last0 ? OLD : 0) + (j <= last1 ? NEW : 0);
|
---|
264 | next0 = first0 = i;
|
---|
265 | next1 = first1 = j;
|
---|
266 | }
|
---|
267 |
|
---|
268 | /* Print `` > xxx '' lines */
|
---|
269 | if (changes & NEW)
|
---|
270 | {
|
---|
271 | for (j = first1; j <= last1; ++j)
|
---|
272 | print_1sdiff_line (0, '>', &files[1].linbuf[j]);
|
---|
273 | next1 = j;
|
---|
274 | }
|
---|
275 |
|
---|
276 | /* Print ``xxx < '' lines */
|
---|
277 | if (changes & OLD)
|
---|
278 | {
|
---|
279 | for (i = first0; i <= last0; ++i)
|
---|
280 | print_1sdiff_line (&files[0].linbuf[i], '<', 0);
|
---|
281 | next0 = i;
|
---|
282 | }
|
---|
283 | }
|
---|