Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/diff/src/side.c
39530 views
1
/* sdiff-format output routines for GNU DIFF.
2
3
Copyright (C) 1991, 1992, 1993, 1998, 2001, 2002, 2004 Free
4
Software 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 size_t
47
tab_from_to (size_t from, size_t to)
48
{
49
FILE *out = outfile;
50
size_t tab;
51
size_t tab_size = tabsize;
52
53
if (!expand_tabs)
54
for (tab = from + tab_size - from % tab_size; tab <= to; tab += tab_size)
55
{
56
putc ('\t', out);
57
from = tab;
58
}
59
while (from++ < to)
60
putc (' ', out);
61
return to;
62
}
63
64
/* Print the text for half an sdiff line. This means truncate to
65
width observing tabs, and trim a trailing newline. Return the
66
last column written (not the number of chars). */
67
68
static size_t
69
print_half_line (char const *const *line, size_t indent, size_t out_bound)
70
{
71
FILE *out = outfile;
72
register size_t in_position = 0;
73
register size_t out_position = 0;
74
register char const *text_pointer = line[0];
75
register char const *text_limit = line[1];
76
77
while (text_pointer < text_limit)
78
{
79
register unsigned char c = *text_pointer++;
80
81
switch (c)
82
{
83
case '\t':
84
{
85
size_t spaces = tabsize - in_position % tabsize;
86
if (in_position == out_position)
87
{
88
size_t tabstop = out_position + spaces;
89
if (expand_tabs)
90
{
91
if (out_bound < tabstop)
92
tabstop = out_bound;
93
for (; out_position < tabstop; out_position++)
94
putc (' ', out);
95
}
96
else
97
if (tabstop < out_bound)
98
{
99
out_position = tabstop;
100
putc (c, out);
101
}
102
}
103
in_position += spaces;
104
}
105
break;
106
107
case '\r':
108
{
109
putc (c, out);
110
tab_from_to (0, indent);
111
in_position = out_position = 0;
112
}
113
break;
114
115
case '\b':
116
if (in_position != 0 && --in_position < out_bound)
117
{
118
if (out_position <= in_position)
119
/* Add spaces to make up for suppressed tab past out_bound. */
120
for (; out_position < in_position; out_position++)
121
putc (' ', out);
122
else
123
{
124
out_position = in_position;
125
putc (c, out);
126
}
127
}
128
break;
129
130
case '\f':
131
case '\v':
132
control_char:
133
if (in_position < out_bound)
134
putc (c, out);
135
break;
136
137
default:
138
if (! isprint (c))
139
goto control_char;
140
/* falls through */
141
case ' ':
142
if (in_position++ < out_bound)
143
{
144
out_position = in_position;
145
putc (c, out);
146
}
147
break;
148
149
case '\n':
150
return out_position;
151
}
152
}
153
154
return out_position;
155
}
156
157
/* Print side by side lines with a separator in the middle.
158
0 parameters are taken to indicate white space text.
159
Blank lines that can easily be caught are reduced to a single newline. */
160
161
static void
162
print_1sdiff_line (char const *const *left, char sep,
163
char const *const *right)
164
{
165
FILE *out = outfile;
166
size_t hw = sdiff_half_width;
167
size_t c2o = sdiff_column2_offset;
168
size_t col = 0;
169
bool put_newline = false;
170
171
if (left)
172
{
173
put_newline |= left[1][-1] == '\n';
174
col = print_half_line (left, 0, hw);
175
}
176
177
if (sep != ' ')
178
{
179
col = tab_from_to (col, (hw + c2o - 1) / 2) + 1;
180
if (sep == '|' && put_newline != (right[1][-1] == '\n'))
181
sep = put_newline ? '/' : '\\';
182
putc (sep, out);
183
}
184
185
if (right)
186
{
187
put_newline |= right[1][-1] == '\n';
188
if (**right != '\n')
189
{
190
col = tab_from_to (col, c2o);
191
print_half_line (right, col, hw);
192
}
193
}
194
195
if (put_newline)
196
putc ('\n', out);
197
}
198
199
/* Print lines common to both files in side-by-side format. */
200
static void
201
print_sdiff_common_lines (lin limit0, lin limit1)
202
{
203
lin i0 = next0, i1 = next1;
204
205
if (!suppress_common_lines && (i0 != limit0 || i1 != limit1))
206
{
207
if (sdiff_merge_assist)
208
{
209
long int len0 = limit0 - i0;
210
long int len1 = limit1 - i1;
211
fprintf (outfile, "i%ld,%ld\n", len0, len1);
212
}
213
214
if (!left_column)
215
{
216
while (i0 != limit0 && i1 != limit1)
217
print_1sdiff_line (&files[0].linbuf[i0++], ' ',
218
&files[1].linbuf[i1++]);
219
while (i1 != limit1)
220
print_1sdiff_line (0, ')', &files[1].linbuf[i1++]);
221
}
222
while (i0 != limit0)
223
print_1sdiff_line (&files[0].linbuf[i0++], '(', 0);
224
}
225
226
next0 = limit0;
227
next1 = limit1;
228
}
229
230
/* Print a hunk of an sdiff diff.
231
This is a contiguous portion of a complete edit script,
232
describing changes in consecutive lines. */
233
234
static void
235
print_sdiff_hunk (struct change *hunk)
236
{
237
lin first0, last0, first1, last1;
238
register lin i, j;
239
240
/* Determine range of line numbers involved in each file. */
241
enum changes changes =
242
analyze_hunk (hunk, &first0, &last0, &first1, &last1);
243
if (!changes)
244
return;
245
246
/* Print out lines up to this change. */
247
print_sdiff_common_lines (first0, first1);
248
249
if (sdiff_merge_assist)
250
{
251
long int len0 = last0 - first0 + 1;
252
long int len1 = last1 - first1 + 1;
253
fprintf (outfile, "c%ld,%ld\n", len0, len1);
254
}
255
256
/* Print ``xxx | xxx '' lines */
257
if (changes == CHANGED)
258
{
259
for (i = first0, j = first1; i <= last0 && j <= last1; i++, j++)
260
print_1sdiff_line (&files[0].linbuf[i], '|', &files[1].linbuf[j]);
261
changes = (i <= last0 ? OLD : 0) + (j <= last1 ? NEW : 0);
262
next0 = first0 = i;
263
next1 = first1 = j;
264
}
265
266
/* Print `` > xxx '' lines */
267
if (changes & NEW)
268
{
269
for (j = first1; j <= last1; ++j)
270
print_1sdiff_line (0, '>', &files[1].linbuf[j]);
271
next1 = j;
272
}
273
274
/* Print ``xxx < '' lines */
275
if (changes & OLD)
276
{
277
for (i = first0; i <= last0; ++i)
278
print_1sdiff_line (&files[0].linbuf[i], '<', 0);
279
next0 = i;
280
}
281
}
282
283