1 /* sdiff-format output routines for GNU DIFF.
2 Copyright (C) 1991, 1992, 1993, 1998 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 __RCSID("$MirOS: src/gnu/usr.bin/cvs/diff/side.c,v 1.5 2010/09/19 19:42:51 tg Exp $");
25
26 static unsigned print_half_line PARAMS((char const * const *, unsigned, unsigned));
27 static unsigned tab_from_to PARAMS((unsigned, unsigned));
28 static void print_1sdiff_line PARAMS((char const * const *, int, char const * const *));
29 static void print_sdiff_common_lines PARAMS((int, int));
30 static void print_sdiff_hunk PARAMS((struct change *));
31
32 /* Next line number to be printed in the two input files. */
33 static int next0, next1;
34
35 /* Print the edit-script SCRIPT as a sdiff style output. */
36
37 void
print_sdiff_script(script)38 print_sdiff_script (script)
39 struct change *script;
40 {
41 begin_output ();
42
43 next0 = next1 = - files[0].prefix_lines;
44 print_script (script, find_change, print_sdiff_hunk);
45
46 print_sdiff_common_lines (files[0].valid_lines, files[1].valid_lines);
47 }
48
49 /* Tab from column FROM to column TO, where FROM <= TO. Yield TO. */
50
51 static unsigned
tab_from_to(from,to)52 tab_from_to (from, to)
53 unsigned from, to;
54 {
55 unsigned tab;
56
57 if (! tab_expand_flag)
58 for (tab = from + TAB_WIDTH - from % TAB_WIDTH; tab <= to; tab += TAB_WIDTH)
59 {
60 write_output ("\t", 1);
61 from = tab;
62 }
63 while (from++ < to)
64 write_output (" ", 1);
65 return to;
66 }
67
68 /*
69 * Print the text for half an sdiff line. This means truncate to width
70 * observing tabs, and trim a trailing newline. Returns the last column
71 * written (not the number of chars).
72 */
73 static unsigned
print_half_line(line,indent,out_bound)74 print_half_line (line, indent, out_bound)
75 char const * const *line;
76 unsigned indent, out_bound;
77 {
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 /* We use CC to avoid taking the address of the register
87 variable C. */
88 char cc;
89
90 switch (c)
91 {
92 case '\t':
93 {
94 unsigned spaces = TAB_WIDTH - in_position % TAB_WIDTH;
95 if (in_position == out_position)
96 {
97 unsigned tabstop = out_position + spaces;
98 if (tab_expand_flag)
99 {
100 if (out_bound < tabstop)
101 tabstop = out_bound;
102 for (; out_position < tabstop; out_position++)
103 write_output (" ", 1);
104 }
105 else
106 if (tabstop < out_bound)
107 {
108 out_position = tabstop;
109 cc = c;
110 write_output (&cc, 1);
111 }
112 }
113 in_position += spaces;
114 }
115 break;
116
117 case '\r':
118 {
119 cc = c;
120 write_output (&cc, 1);
121 tab_from_to (0, indent);
122 in_position = out_position = 0;
123 }
124 break;
125
126 case '\b':
127 if (in_position != 0 && --in_position < out_bound) {
128 if (out_position <= in_position)
129 /* Add spaces to make up for suppressed tab past out_bound. */
130 for (; out_position < in_position; out_position++)
131 write_output (" ", 1);
132 else
133 {
134 out_position = in_position;
135 cc = c;
136 write_output (&cc, 1);
137 }
138 }
139 break;
140
141 case '\f':
142 case '\v':
143 control_char:
144 if (in_position < out_bound)
145 {
146 cc = c;
147 write_output (&cc, 1);
148 }
149 break;
150
151 default:
152 if (! ISPRINT (c))
153 goto control_char;
154 /* falls through */
155 case ' ':
156 if (in_position++ < out_bound)
157 {
158 out_position = in_position;
159 cc = c;
160 write_output (&cc, 1);
161 }
162 break;
163
164 case '\n':
165 return out_position;
166 }
167 }
168
169 return out_position;
170 }
171
172 /*
173 * Print side by side lines with a separator in the middle.
174 * 0 parameters are taken to indicate white space text.
175 * Blank lines that can easily be caught are reduced to a single newline.
176 */
177
178 static void
print_1sdiff_line(left,sep,right)179 print_1sdiff_line (left, sep, right)
180 char const * const *left;
181 int sep;
182 char const * const *right;
183 {
184 unsigned hw = sdiff_half_width, c2o = sdiff_column2_offset;
185 unsigned col = 0;
186 int put_newline = 0;
187
188 if (left)
189 {
190 if (left[1][-1] == '\n')
191 put_newline = 1;
192 col = print_half_line (left, 0, hw);
193 }
194
195 if (sep != ' ')
196 {
197 char cc;
198
199 col = tab_from_to (col, (hw + c2o - 1) / 2) + 1;
200 if (sep == '|' && put_newline != (right[1][-1] == '\n'))
201 sep = put_newline ? '/' : '\\';
202 cc = sep;
203 write_output (&cc, 1);
204 }
205
206 if (right)
207 {
208 if (right[1][-1] == '\n')
209 put_newline = 1;
210 if (**right != '\n')
211 {
212 col = tab_from_to (col, c2o);
213 print_half_line (right, col, hw);
214 }
215 }
216
217 if (put_newline)
218 write_output ("\n", 1);
219 }
220
221 /* Print lines common to both files in side-by-side format. */
222 static void
print_sdiff_common_lines(limit0,limit1)223 print_sdiff_common_lines (limit0, limit1)
224 int limit0, limit1;
225 {
226 int i0 = next0, i1 = next1;
227
228 if (! sdiff_skip_common_lines && (i0 != limit0 || i1 != limit1))
229 {
230 if (sdiff_help_sdiff)
231 printf_output ("i%d,%d\n", limit0 - i0, limit1 - i1);
232
233 if (! sdiff_left_only)
234 {
235 while (i0 != limit0 && i1 != limit1)
236 print_1sdiff_line (&files[0].linbuf[i0++], ' ', &files[1].linbuf[i1++]);
237 while (i1 != limit1)
238 print_1sdiff_line (0, ')', &files[1].linbuf[i1++]);
239 }
240 while (i0 != limit0)
241 print_1sdiff_line (&files[0].linbuf[i0++], '(', 0);
242 }
243
244 next0 = limit0;
245 next1 = limit1;
246 }
247
248 /* Print a hunk of an sdiff diff.
249 This is a contiguous portion of a complete edit script,
250 describing changes in consecutive lines. */
251
252 static void
print_sdiff_hunk(hunk)253 print_sdiff_hunk (hunk)
254 struct change *hunk;
255 {
256 int first0, last0, first1, last1, deletes, inserts;
257 register int i, j;
258
259 /* Determine range of line numbers involved in each file. */
260 analyze_hunk (hunk, &first0, &last0, &first1, &last1, &deletes, &inserts);
261 if (!deletes && !inserts)
262 return;
263
264 /* Print out lines up to this change. */
265 print_sdiff_common_lines (first0, first1);
266
267 if (sdiff_help_sdiff)
268 printf_output ("c%d,%d\n", last0 - first0 + 1, last1 - first1 + 1);
269
270 /* Print ``xxx | xxx '' lines */
271 if (inserts && deletes)
272 {
273 for (i = first0, j = first1; i <= last0 && j <= last1; ++i, ++j)
274 print_1sdiff_line (&files[0].linbuf[i], '|', &files[1].linbuf[j]);
275 deletes = i <= last0;
276 inserts = j <= last1;
277 next0 = first0 = i;
278 next1 = first1 = j;
279 }
280
281
282 /* Print `` > xxx '' lines */
283 if (inserts)
284 {
285 for (j = first1; j <= last1; ++j)
286 print_1sdiff_line (0, '>', &files[1].linbuf[j]);
287 next1 = j;
288 }
289
290 /* Print ``xxx < '' lines */
291 if (deletes)
292 {
293 for (i = first0; i <= last0; ++i)
294 print_1sdiff_line (&files[0].linbuf[i], '<', 0);
295 next0 = i;
296 }
297 }
298