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