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