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