Blame


1 3b0f3d61 2020-01-22 neels /* Produce a unidiff output from a diff_result. */
2 3b0f3d61 2020-01-22 neels /*
3 3b0f3d61 2020-01-22 neels * Copyright (c) 2020 Neels Hofmeyr <neels@hofmeyr.de>
4 3b0f3d61 2020-01-22 neels *
5 3b0f3d61 2020-01-22 neels * Permission to use, copy, modify, and distribute this software for any
6 3b0f3d61 2020-01-22 neels * purpose with or without fee is hereby granted, provided that the above
7 3b0f3d61 2020-01-22 neels * copyright notice and this permission notice appear in all copies.
8 3b0f3d61 2020-01-22 neels *
9 3b0f3d61 2020-01-22 neels * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 3b0f3d61 2020-01-22 neels * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 3b0f3d61 2020-01-22 neels * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 3b0f3d61 2020-01-22 neels * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 3b0f3d61 2020-01-22 neels * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 3b0f3d61 2020-01-22 neels * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 3b0f3d61 2020-01-22 neels * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 3b0f3d61 2020-01-22 neels */
17 3b0f3d61 2020-01-22 neels
18 e10a628a 2020-09-16 stsp #include <errno.h>
19 e10a628a 2020-09-16 stsp #include <stdbool.h>
20 fe6d58fb 2020-11-14 naddy #include <stdint.h>
21 e10a628a 2020-09-16 stsp #include <stdio.h>
22 e10a628a 2020-09-16 stsp #include <stdlib.h>
23 b3fd1fa2 2020-12-10 stsp #include <string.h>
24 4861c9da 2020-10-30 neels #include <assert.h>
25 e10a628a 2020-09-16 stsp
26 1dfba055 2020-10-07 stsp #include <arraylist.h>
27 1dfba055 2020-10-07 stsp #include <diff_main.h>
28 1dfba055 2020-10-07 stsp #include <diff_output.h>
29 3b0f3d61 2020-01-22 neels
30 85ab4559 2020-09-22 stsp #include "diff_internal.h"
31 2a1b94d0 2020-09-26 stsp #include "diff_debug.h"
32 3b0f3d61 2020-01-22 neels
33 2f26640c 2020-10-17 stsp bool
34 cbf93b70 2020-10-16 stsp diff_chunk_context_empty(const struct diff_chunk_context *cc)
35 3b0f3d61 2020-01-22 neels {
36 d362ea2e 2020-07-25 stsp return diff_range_empty(&cc->chunk);
37 3b0f3d61 2020-01-22 neels }
38 3b0f3d61 2020-01-22 neels
39 fe8af0d6 2020-10-06 stsp int
40 fe8af0d6 2020-10-06 stsp diff_chunk_get_left_start(const struct diff_chunk *c,
41 fe8af0d6 2020-10-06 stsp const struct diff_result *r, int context_lines)
42 fe8af0d6 2020-10-06 stsp {
43 c16dde50 2020-10-22 stsp int left_start = diff_atom_root_idx(r->left, c->left_start);
44 fe8af0d6 2020-10-06 stsp return MAX(0, left_start - context_lines);
45 fe8af0d6 2020-10-06 stsp }
46 fe8af0d6 2020-10-06 stsp
47 fe8af0d6 2020-10-06 stsp int
48 fe8af0d6 2020-10-06 stsp diff_chunk_get_left_end(const struct diff_chunk *c,
49 fe8af0d6 2020-10-06 stsp const struct diff_result *r, int context_lines)
50 fe8af0d6 2020-10-06 stsp {
51 fe8af0d6 2020-10-06 stsp int left_start = diff_chunk_get_left_start(c, r, 0);
52 c16dde50 2020-10-22 stsp return MIN(r->left->atoms.len,
53 fe8af0d6 2020-10-06 stsp left_start + c->left_count + context_lines);
54 fe8af0d6 2020-10-06 stsp }
55 fe8af0d6 2020-10-06 stsp
56 fe8af0d6 2020-10-06 stsp int
57 fe8af0d6 2020-10-06 stsp diff_chunk_get_right_start(const struct diff_chunk *c,
58 fe8af0d6 2020-10-06 stsp const struct diff_result *r, int context_lines)
59 fe8af0d6 2020-10-06 stsp {
60 c16dde50 2020-10-22 stsp int right_start = diff_atom_root_idx(r->right, c->right_start);
61 fe8af0d6 2020-10-06 stsp return MAX(0, right_start - context_lines);
62 fe8af0d6 2020-10-06 stsp }
63 fe8af0d6 2020-10-06 stsp
64 fe8af0d6 2020-10-06 stsp int
65 fe8af0d6 2020-10-06 stsp diff_chunk_get_right_end(const struct diff_chunk *c,
66 fe8af0d6 2020-10-06 stsp const struct diff_result *r, int context_lines)
67 fe8af0d6 2020-10-06 stsp {
68 fe8af0d6 2020-10-06 stsp int right_start = diff_chunk_get_right_start(c, r, 0);
69 c16dde50 2020-10-22 stsp return MIN(r->right->atoms.len,
70 fe8af0d6 2020-10-06 stsp right_start + c->right_count + context_lines);
71 e8eedebc 2020-11-06 stsp }
72 e8eedebc 2020-11-06 stsp
73 e8eedebc 2020-11-06 stsp struct diff_chunk *
74 e8eedebc 2020-11-06 stsp diff_chunk_get(const struct diff_result *r, int chunk_idx)
75 e8eedebc 2020-11-06 stsp {
76 e8eedebc 2020-11-06 stsp return &r->chunks.head[chunk_idx];
77 e8eedebc 2020-11-06 stsp }
78 e8eedebc 2020-11-06 stsp
79 e8eedebc 2020-11-06 stsp int
80 e8eedebc 2020-11-06 stsp diff_chunk_get_left_count(struct diff_chunk *c)
81 e8eedebc 2020-11-06 stsp {
82 e8eedebc 2020-11-06 stsp return c->left_count;
83 e8eedebc 2020-11-06 stsp }
84 e8eedebc 2020-11-06 stsp
85 e8eedebc 2020-11-06 stsp int
86 e8eedebc 2020-11-06 stsp diff_chunk_get_right_count(struct diff_chunk *c)
87 e8eedebc 2020-11-06 stsp {
88 e8eedebc 2020-11-06 stsp return c->right_count;
89 fe8af0d6 2020-10-06 stsp }
90 fe8af0d6 2020-10-06 stsp
91 f374e913 2020-09-22 stsp void
92 f374e913 2020-09-22 stsp diff_chunk_context_get(struct diff_chunk_context *cc, const struct diff_result *r,
93 0d27172a 2020-05-06 neels int chunk_idx, int context_lines)
94 3b0f3d61 2020-01-22 neels {
95 3b0f3d61 2020-01-22 neels const struct diff_chunk *c = &r->chunks.head[chunk_idx];
96 fe8af0d6 2020-10-06 stsp int left_start = diff_chunk_get_left_start(c, r, context_lines);
97 fe8af0d6 2020-10-06 stsp int left_end = diff_chunk_get_left_end(c, r, context_lines);
98 fe8af0d6 2020-10-06 stsp int right_start = diff_chunk_get_right_start(c, r, context_lines);
99 fe8af0d6 2020-10-06 stsp int right_end = diff_chunk_get_right_end(c, r, context_lines);
100 0d27172a 2020-05-06 neels
101 f374e913 2020-09-22 stsp *cc = (struct diff_chunk_context){
102 3b0f3d61 2020-01-22 neels .chunk = {
103 3b0f3d61 2020-01-22 neels .start = chunk_idx,
104 3b0f3d61 2020-01-22 neels .end = chunk_idx + 1,
105 3b0f3d61 2020-01-22 neels },
106 3b0f3d61 2020-01-22 neels .left = {
107 0d27172a 2020-05-06 neels .start = left_start,
108 0d27172a 2020-05-06 neels .end = left_end,
109 3b0f3d61 2020-01-22 neels },
110 3b0f3d61 2020-01-22 neels .right = {
111 0d27172a 2020-05-06 neels .start = right_start,
112 0d27172a 2020-05-06 neels .end = right_end,
113 3b0f3d61 2020-01-22 neels },
114 3b0f3d61 2020-01-22 neels };
115 3b0f3d61 2020-01-22 neels }
116 3b0f3d61 2020-01-22 neels
117 2f26640c 2020-10-17 stsp bool
118 26595c7d 2020-10-15 stsp diff_chunk_contexts_touch(const struct diff_chunk_context *cc,
119 26595c7d 2020-10-15 stsp const struct diff_chunk_context *other)
120 3b0f3d61 2020-01-22 neels {
121 d362ea2e 2020-07-25 stsp return diff_ranges_touch(&cc->chunk, &other->chunk)
122 d362ea2e 2020-07-25 stsp || diff_ranges_touch(&cc->left, &other->left)
123 d362ea2e 2020-07-25 stsp || diff_ranges_touch(&cc->right, &other->right);
124 3b0f3d61 2020-01-22 neels }
125 3b0f3d61 2020-01-22 neels
126 26595c7d 2020-10-15 stsp void
127 26595c7d 2020-10-15 stsp diff_chunk_contexts_merge(struct diff_chunk_context *cc,
128 26595c7d 2020-10-15 stsp const struct diff_chunk_context *other)
129 3b0f3d61 2020-01-22 neels {
130 d362ea2e 2020-07-25 stsp diff_ranges_merge(&cc->chunk, &other->chunk);
131 d362ea2e 2020-07-25 stsp diff_ranges_merge(&cc->left, &other->left);
132 d362ea2e 2020-07-25 stsp diff_ranges_merge(&cc->right, &other->right);
133 7187fe97 2020-10-17 stsp }
134 7187fe97 2020-10-17 stsp
135 7187fe97 2020-10-17 stsp void
136 7187fe97 2020-10-17 stsp diff_chunk_context_load_change(struct diff_chunk_context *cc,
137 7187fe97 2020-10-17 stsp int *nchunks_used,
138 7187fe97 2020-10-17 stsp struct diff_result *result,
139 7187fe97 2020-10-17 stsp int start_chunk_idx,
140 7187fe97 2020-10-17 stsp int context_lines)
141 7187fe97 2020-10-17 stsp {
142 7187fe97 2020-10-17 stsp int i;
143 7187fe97 2020-10-17 stsp int seen_minus = 0, seen_plus = 0;
144 7187fe97 2020-10-17 stsp
145 7187fe97 2020-10-17 stsp if (nchunks_used)
146 7187fe97 2020-10-17 stsp *nchunks_used = 0;
147 7187fe97 2020-10-17 stsp
148 7187fe97 2020-10-17 stsp for (i = start_chunk_idx; i < result->chunks.len; i++) {
149 7187fe97 2020-10-17 stsp struct diff_chunk *chunk = &result->chunks.head[i];
150 7187fe97 2020-10-17 stsp enum diff_chunk_type t = diff_chunk_type(chunk);
151 7187fe97 2020-10-17 stsp struct diff_chunk_context next;
152 7187fe97 2020-10-17 stsp
153 7187fe97 2020-10-17 stsp if (t != CHUNK_MINUS && t != CHUNK_PLUS) {
154 7187fe97 2020-10-17 stsp if (nchunks_used)
155 7187fe97 2020-10-17 stsp (*nchunks_used)++;
156 f4867452 2020-10-17 stsp if (seen_minus || seen_plus)
157 7187fe97 2020-10-17 stsp break;
158 7187fe97 2020-10-17 stsp else
159 7187fe97 2020-10-17 stsp continue;
160 7187fe97 2020-10-17 stsp } else if (t == CHUNK_MINUS)
161 7187fe97 2020-10-17 stsp seen_minus = 1;
162 7187fe97 2020-10-17 stsp else if (t == CHUNK_PLUS)
163 7187fe97 2020-10-17 stsp seen_plus = 1;
164 7187fe97 2020-10-17 stsp
165 7187fe97 2020-10-17 stsp if (diff_chunk_context_empty(cc)) {
166 7187fe97 2020-10-17 stsp /* Note down the start point, any number of subsequent
167 7187fe97 2020-10-17 stsp * chunks may be joined up to this chunk by being
168 7187fe97 2020-10-17 stsp * directly adjacent. */
169 7187fe97 2020-10-17 stsp diff_chunk_context_get(cc, result, i, context_lines);
170 7187fe97 2020-10-17 stsp if (nchunks_used)
171 7187fe97 2020-10-17 stsp (*nchunks_used)++;
172 7187fe97 2020-10-17 stsp continue;
173 7187fe97 2020-10-17 stsp }
174 7187fe97 2020-10-17 stsp
175 7187fe97 2020-10-17 stsp /* There already is a previous chunk noted down for being
176 7187fe97 2020-10-17 stsp * printed. Does it join up with this one? */
177 7187fe97 2020-10-17 stsp diff_chunk_context_get(&next, result, i, context_lines);
178 7187fe97 2020-10-17 stsp
179 7187fe97 2020-10-17 stsp if (diff_chunk_contexts_touch(cc, &next)) {
180 7187fe97 2020-10-17 stsp /* This next context touches or overlaps the previous
181 7187fe97 2020-10-17 stsp * one, join. */
182 7187fe97 2020-10-17 stsp diff_chunk_contexts_merge(cc, &next);
183 7187fe97 2020-10-17 stsp if (nchunks_used)
184 7187fe97 2020-10-17 stsp (*nchunks_used)++;
185 7187fe97 2020-10-17 stsp continue;
186 7187fe97 2020-10-17 stsp } else
187 7187fe97 2020-10-17 stsp break;
188 7187fe97 2020-10-17 stsp }
189 3b0f3d61 2020-01-22 neels }
190 3b0f3d61 2020-01-22 neels
191 11caa5cc 2020-09-22 stsp struct diff_output_unidiff_state {
192 11caa5cc 2020-09-22 stsp bool header_printed;
193 b3fd1fa2 2020-12-10 stsp char prototype[DIFF_FUNCTION_CONTEXT_SIZE];
194 b3fd1fa2 2020-12-10 stsp int last_prototype_idx;
195 11caa5cc 2020-09-22 stsp };
196 11caa5cc 2020-09-22 stsp
197 11caa5cc 2020-09-22 stsp struct diff_output_unidiff_state *
198 11caa5cc 2020-09-22 stsp diff_output_unidiff_state_alloc(void)
199 11caa5cc 2020-09-22 stsp {
200 11caa5cc 2020-09-22 stsp struct diff_output_unidiff_state *state;
201 11caa5cc 2020-09-22 stsp
202 11caa5cc 2020-09-22 stsp state = calloc(1, sizeof(struct diff_output_unidiff_state));
203 11caa5cc 2020-09-22 stsp if (state != NULL)
204 11caa5cc 2020-09-22 stsp diff_output_unidiff_state_reset(state);
205 11caa5cc 2020-09-22 stsp return state;
206 11caa5cc 2020-09-22 stsp }
207 11caa5cc 2020-09-22 stsp
208 f374e913 2020-09-22 stsp void
209 11caa5cc 2020-09-22 stsp diff_output_unidiff_state_reset(struct diff_output_unidiff_state *state)
210 11caa5cc 2020-09-22 stsp {
211 11caa5cc 2020-09-22 stsp state->header_printed = false;
212 b3fd1fa2 2020-12-10 stsp memset(state->prototype, 0, sizeof(state->prototype));
213 b3fd1fa2 2020-12-10 stsp state->last_prototype_idx = 0;
214 11caa5cc 2020-09-22 stsp }
215 11caa5cc 2020-09-22 stsp
216 11caa5cc 2020-09-22 stsp void
217 11caa5cc 2020-09-22 stsp diff_output_unidiff_state_free(struct diff_output_unidiff_state *state)
218 11caa5cc 2020-09-22 stsp {
219 11caa5cc 2020-09-22 stsp free(state);
220 11caa5cc 2020-09-22 stsp }
221 11caa5cc 2020-09-22 stsp
222 2c20a3ed 2020-09-22 stsp static int
223 2c20a3ed 2020-09-22 stsp output_unidiff_chunk(struct diff_output_info *outinfo, FILE *dest,
224 2c20a3ed 2020-09-22 stsp struct diff_output_unidiff_state *state,
225 2c20a3ed 2020-09-22 stsp const struct diff_input_info *info,
226 2c20a3ed 2020-09-22 stsp const struct diff_result *result,
227 13e2caa3 2020-10-17 stsp bool print_header, bool show_function_prototypes,
228 8993f425 2022-09-23 mark const struct diff_chunk_context *cc, unsigned int ncontext)
229 3b0f3d61 2020-01-22 neels {
230 b6adedb6 2020-10-07 stsp int rc, left_start, left_len, right_start, right_len;
231 ab528e22 2020-09-22 stsp off_t outoff = 0, *offp;
232 9343b925 2022-08-04 mark uint8_t *typep;
233 2c20a3ed 2020-09-22 stsp
234 d362ea2e 2020-07-25 stsp if (diff_range_empty(&cc->left) && diff_range_empty(&cc->right))
235 2c20a3ed 2020-09-22 stsp return DIFF_RC_OK;
236 3b0f3d61 2020-01-22 neels
237 2c20a3ed 2020-09-22 stsp if (outinfo && outinfo->line_offsets.len > 0) {
238 2c20a3ed 2020-09-22 stsp unsigned int idx = outinfo->line_offsets.len - 1;
239 2c20a3ed 2020-09-22 stsp outoff = outinfo->line_offsets.head[idx];
240 2c20a3ed 2020-09-22 stsp }
241 2c20a3ed 2020-09-22 stsp
242 66ea8e5a 2020-10-17 stsp if (print_header && !(state->header_printed)) {
243 e4c510c1 2020-11-21 stsp rc = fprintf(dest, "--- %s\n",
244 e4c510c1 2020-11-21 stsp diff_output_get_label_left(info));
245 2c20a3ed 2020-09-22 stsp if (rc < 0)
246 2c20a3ed 2020-09-22 stsp return errno;
247 2c20a3ed 2020-09-22 stsp if (outinfo) {
248 2c20a3ed 2020-09-22 stsp ARRAYLIST_ADD(offp, outinfo->line_offsets);
249 dabc1008 2020-09-22 stsp if (offp == NULL)
250 dabc1008 2020-09-22 stsp return ENOMEM;
251 2c20a3ed 2020-09-22 stsp outoff += rc;
252 2c20a3ed 2020-09-22 stsp *offp = outoff;
253 9343b925 2022-08-04 mark ARRAYLIST_ADD(typep, outinfo->line_types);
254 9343b925 2022-08-04 mark if (typep == NULL)
255 9343b925 2022-08-04 mark return ENOMEM;
256 9343b925 2022-08-04 mark *typep = DIFF_LINE_MINUS;
257 2c20a3ed 2020-09-22 stsp }
258 e4c510c1 2020-11-21 stsp rc = fprintf(dest, "+++ %s\n",
259 e4c510c1 2020-11-21 stsp diff_output_get_label_right(info));
260 2c20a3ed 2020-09-22 stsp if (rc < 0)
261 2c20a3ed 2020-09-22 stsp return errno;
262 2c20a3ed 2020-09-22 stsp if (outinfo) {
263 2c20a3ed 2020-09-22 stsp ARRAYLIST_ADD(offp, outinfo->line_offsets);
264 dabc1008 2020-09-22 stsp if (offp == NULL)
265 dabc1008 2020-09-22 stsp return ENOMEM;
266 2c20a3ed 2020-09-22 stsp outoff += rc;
267 2c20a3ed 2020-09-22 stsp *offp = outoff;
268 9343b925 2022-08-04 mark ARRAYLIST_ADD(typep, outinfo->line_types);
269 9343b925 2022-08-04 mark if (typep == NULL)
270 9343b925 2022-08-04 mark return ENOMEM;
271 9343b925 2022-08-04 mark *typep = DIFF_LINE_PLUS;
272 2c20a3ed 2020-09-22 stsp }
273 11caa5cc 2020-09-22 stsp state->header_printed = true;
274 3b0f3d61 2020-01-22 neels }
275 3b0f3d61 2020-01-22 neels
276 b6adedb6 2020-10-07 stsp left_len = cc->left.end - cc->left.start;
277 c16dde50 2020-10-22 stsp if (result->left->atoms.len == 0)
278 11d9f2f7 2020-10-07 stsp left_start = 0;
279 11d9f2f7 2020-10-07 stsp else if (left_len == 0 && cc->left.start > 0)
280 b6adedb6 2020-10-07 stsp left_start = cc->left.start;
281 b6adedb6 2020-10-07 stsp else
282 b6adedb6 2020-10-07 stsp left_start = cc->left.start + 1;
283 b6adedb6 2020-10-07 stsp
284 b6adedb6 2020-10-07 stsp right_len = cc->right.end - cc->right.start;
285 c16dde50 2020-10-22 stsp if (result->right->atoms.len == 0)
286 11d9f2f7 2020-10-07 stsp right_start = 0;
287 11d9f2f7 2020-10-07 stsp else if (right_len == 0 && cc->right.start > 0)
288 b6adedb6 2020-10-07 stsp right_start = cc->right.start;
289 b6adedb6 2020-10-07 stsp else
290 b6adedb6 2020-10-07 stsp right_start = cc->right.start + 1;
291 13e2caa3 2020-10-17 stsp
292 13e2caa3 2020-10-17 stsp if (show_function_prototypes) {
293 b3fd1fa2 2020-12-10 stsp rc = diff_output_match_function_prototype(state->prototype,
294 b3fd1fa2 2020-12-10 stsp sizeof(state->prototype), &state->last_prototype_idx,
295 8993f425 2022-09-23 mark result, cc, ncontext);
296 13e2caa3 2020-10-17 stsp if (rc)
297 13e2caa3 2020-10-17 stsp return rc;
298 13e2caa3 2020-10-17 stsp }
299 b6adedb6 2020-10-07 stsp
300 d2dfa2ec 2020-10-07 stsp if (left_len == 1 && right_len == 1) {
301 13e2caa3 2020-10-17 stsp rc = fprintf(dest, "@@ -%d +%d @@%s%s\n",
302 13e2caa3 2020-10-17 stsp left_start, right_start,
303 b3fd1fa2 2020-12-10 stsp state->prototype[0] ? " " : "",
304 b3fd1fa2 2020-12-10 stsp state->prototype[0] ? state->prototype : "");
305 d2dfa2ec 2020-10-07 stsp } else if (left_len == 1 && right_len != 1) {
306 13e2caa3 2020-10-17 stsp rc = fprintf(dest, "@@ -%d +%d,%d @@%s%s\n",
307 13e2caa3 2020-10-17 stsp left_start, right_start, right_len,
308 b3fd1fa2 2020-12-10 stsp state->prototype[0] ? " " : "",
309 b3fd1fa2 2020-12-10 stsp state->prototype[0] ? state->prototype : "");
310 b6adedb6 2020-10-07 stsp } else if (left_len != 1 && right_len == 1) {
311 13e2caa3 2020-10-17 stsp rc = fprintf(dest, "@@ -%d,%d +%d @@%s%s\n",
312 13e2caa3 2020-10-17 stsp left_start, left_len, right_start,
313 b3fd1fa2 2020-12-10 stsp state->prototype[0] ? " " : "",
314 b3fd1fa2 2020-12-10 stsp state->prototype[0] ? state->prototype : "");
315 b6adedb6 2020-10-07 stsp } else {
316 13e2caa3 2020-10-17 stsp rc = fprintf(dest, "@@ -%d,%d +%d,%d @@%s%s\n",
317 13e2caa3 2020-10-17 stsp left_start, left_len, right_start, right_len,
318 b3fd1fa2 2020-12-10 stsp state->prototype[0] ? " " : "",
319 b3fd1fa2 2020-12-10 stsp state->prototype[0] ? state->prototype : "");
320 b6adedb6 2020-10-07 stsp }
321 2c20a3ed 2020-09-22 stsp if (rc < 0)
322 2c20a3ed 2020-09-22 stsp return errno;
323 2c20a3ed 2020-09-22 stsp if (outinfo) {
324 2c20a3ed 2020-09-22 stsp ARRAYLIST_ADD(offp, outinfo->line_offsets);
325 dabc1008 2020-09-22 stsp if (offp == NULL)
326 dabc1008 2020-09-22 stsp return ENOMEM;
327 2c20a3ed 2020-09-22 stsp outoff += rc;
328 2c20a3ed 2020-09-22 stsp *offp = outoff;
329 9343b925 2022-08-04 mark ARRAYLIST_ADD(typep, outinfo->line_types);
330 9343b925 2022-08-04 mark if (typep == NULL)
331 9343b925 2022-08-04 mark return ENOMEM;
332 9343b925 2022-08-04 mark *typep = DIFF_LINE_HUNK;
333 2c20a3ed 2020-09-22 stsp }
334 2c20a3ed 2020-09-22 stsp
335 0d27172a 2020-05-06 neels /* Got the absolute line numbers where to start printing, and the index
336 0d27172a 2020-05-06 neels * of the interesting (non-context) chunk.
337 0d27172a 2020-05-06 neels * To print context lines above the interesting chunk, nipping on the
338 0d27172a 2020-05-06 neels * previous chunk index may be necessary.
339 0d27172a 2020-05-06 neels * It is guaranteed to be only context lines where left == right, so it
340 0d27172a 2020-05-06 neels * suffices to look on the left. */
341 0d27172a 2020-05-06 neels const struct diff_chunk *first_chunk;
342 0d27172a 2020-05-06 neels int chunk_start_line;
343 0d27172a 2020-05-06 neels first_chunk = &result->chunks.head[cc->chunk.start];
344 c16dde50 2020-10-22 stsp chunk_start_line = diff_atom_root_idx(result->left,
345 0d27172a 2020-05-06 neels first_chunk->left_start);
346 2c20a3ed 2020-09-22 stsp if (cc->left.start < chunk_start_line) {
347 2c20a3ed 2020-09-22 stsp rc = diff_output_lines(outinfo, dest, " ",
348 c16dde50 2020-10-22 stsp &result->left->atoms.head[cc->left.start],
349 3b0f3d61 2020-01-22 neels chunk_start_line - cc->left.start);
350 2c20a3ed 2020-09-22 stsp if (rc)
351 2c20a3ed 2020-09-22 stsp return rc;
352 2c20a3ed 2020-09-22 stsp }
353 3b0f3d61 2020-01-22 neels
354 3b0f3d61 2020-01-22 neels /* Now write out all the joined chunks and contexts between them */
355 3b0f3d61 2020-01-22 neels int c_idx;
356 3b0f3d61 2020-01-22 neels for (c_idx = cc->chunk.start; c_idx < cc->chunk.end; c_idx++) {
357 3b0f3d61 2020-01-22 neels const struct diff_chunk *c = &result->chunks.head[c_idx];
358 3b0f3d61 2020-01-22 neels
359 3b0f3d61 2020-01-22 neels if (c->left_count && c->right_count)
360 2c20a3ed 2020-09-22 stsp rc = diff_output_lines(outinfo, dest,
361 0d27172a 2020-05-06 neels c->solved ? " " : "?",
362 0d27172a 2020-05-06 neels c->left_start, c->left_count);
363 3b0f3d61 2020-01-22 neels else if (c->left_count && !c->right_count)
364 2c20a3ed 2020-09-22 stsp rc = diff_output_lines(outinfo, dest,
365 0d27172a 2020-05-06 neels c->solved ? "-" : "?",
366 0d27172a 2020-05-06 neels c->left_start, c->left_count);
367 3b0f3d61 2020-01-22 neels else if (c->right_count && !c->left_count)
368 2c20a3ed 2020-09-22 stsp rc = diff_output_lines(outinfo, dest,
369 0d27172a 2020-05-06 neels c->solved ? "+" : "?",
370 0d27172a 2020-05-06 neels c->right_start, c->right_count);
371 2c20a3ed 2020-09-22 stsp if (rc)
372 2c20a3ed 2020-09-22 stsp return rc;
373 7021523c 2020-10-16 stsp
374 7021523c 2020-10-16 stsp if (cc->chunk.end == result->chunks.len) {
375 7021523c 2020-10-16 stsp rc = diff_output_trailing_newline_msg(outinfo, dest, c);
376 7021523c 2020-10-16 stsp if (rc != DIFF_RC_OK)
377 7021523c 2020-10-16 stsp return rc;
378 7021523c 2020-10-16 stsp }
379 3b0f3d61 2020-01-22 neels }
380 3b0f3d61 2020-01-22 neels
381 3b0f3d61 2020-01-22 neels /* Trailing context? */
382 0d27172a 2020-05-06 neels const struct diff_chunk *last_chunk;
383 0d27172a 2020-05-06 neels int chunk_end_line;
384 0d27172a 2020-05-06 neels last_chunk = &result->chunks.head[cc->chunk.end - 1];
385 c16dde50 2020-10-22 stsp chunk_end_line = diff_atom_root_idx(result->left,
386 0d27172a 2020-05-06 neels last_chunk->left_start
387 0d27172a 2020-05-06 neels + last_chunk->left_count);
388 2c20a3ed 2020-09-22 stsp if (cc->left.end > chunk_end_line) {
389 2c20a3ed 2020-09-22 stsp rc = diff_output_lines(outinfo, dest, " ",
390 c16dde50 2020-10-22 stsp &result->left->atoms.head[chunk_end_line],
391 3b0f3d61 2020-01-22 neels cc->left.end - chunk_end_line);
392 2c20a3ed 2020-09-22 stsp if (rc)
393 2c20a3ed 2020-09-22 stsp return rc;
394 4125b1ef 2022-10-10 tj
395 4125b1ef 2022-10-10 tj rc = diff_output_trailing_newline_msg(outinfo, dest,
396 4125b1ef 2022-10-10 tj &result->chunks.head[result->chunks.len - 1]);
397 4125b1ef 2022-10-10 tj if (rc != DIFF_RC_OK)
398 4125b1ef 2022-10-10 tj return rc;
399 2c20a3ed 2020-09-22 stsp }
400 2c20a3ed 2020-09-22 stsp
401 2c20a3ed 2020-09-22 stsp return DIFF_RC_OK;
402 3b0f3d61 2020-01-22 neels }
403 3b0f3d61 2020-01-22 neels
404 3e6cba3a 2020-08-13 stsp int
405 2c20a3ed 2020-09-22 stsp diff_output_unidiff_chunk(struct diff_output_info **output_info, FILE *dest,
406 2c20a3ed 2020-09-22 stsp struct diff_output_unidiff_state *state,
407 2c20a3ed 2020-09-22 stsp const struct diff_input_info *info,
408 2c20a3ed 2020-09-22 stsp const struct diff_result *result,
409 2c20a3ed 2020-09-22 stsp const struct diff_chunk_context *cc)
410 2c20a3ed 2020-09-22 stsp {
411 2c20a3ed 2020-09-22 stsp struct diff_output_info *outinfo = NULL;
412 c16dde50 2020-10-22 stsp int flags = (result->left->root->diff_flags |
413 c16dde50 2020-10-22 stsp result->right->root->diff_flags);
414 13e2caa3 2020-10-17 stsp bool show_function_prototypes = (flags & DIFF_FLAG_SHOW_PROTOTYPES);
415 2c20a3ed 2020-09-22 stsp
416 2c20a3ed 2020-09-22 stsp if (output_info) {
417 2c20a3ed 2020-09-22 stsp *output_info = diff_output_info_alloc();
418 2c20a3ed 2020-09-22 stsp if (*output_info == NULL)
419 2c20a3ed 2020-09-22 stsp return ENOMEM;
420 2c20a3ed 2020-09-22 stsp outinfo = *output_info;
421 2c20a3ed 2020-09-22 stsp }
422 2c20a3ed 2020-09-22 stsp
423 2c20a3ed 2020-09-22 stsp return output_unidiff_chunk(outinfo, dest, state, info,
424 8993f425 2022-09-23 mark result, false, show_function_prototypes, cc, 0);
425 2c20a3ed 2020-09-22 stsp }
426 2c20a3ed 2020-09-22 stsp
427 2c20a3ed 2020-09-22 stsp int
428 2c20a3ed 2020-09-22 stsp diff_output_unidiff(struct diff_output_info **output_info,
429 2c20a3ed 2020-09-22 stsp FILE *dest, const struct diff_input_info *info,
430 0d27172a 2020-05-06 neels const struct diff_result *result,
431 0d27172a 2020-05-06 neels unsigned int context_lines)
432 3b0f3d61 2020-01-22 neels {
433 11caa5cc 2020-09-22 stsp struct diff_output_unidiff_state *state;
434 11caa5cc 2020-09-22 stsp struct diff_chunk_context cc = {};
435 2c20a3ed 2020-09-22 stsp struct diff_output_info *outinfo = NULL;
436 e51ebd83 2020-11-21 stsp int atomizer_flags = (result->left->atomizer_flags|
437 e51ebd83 2020-11-21 stsp result->right->atomizer_flags);
438 c16dde50 2020-10-22 stsp int flags = (result->left->root->diff_flags |
439 c16dde50 2020-10-22 stsp result->right->root->diff_flags);
440 13e2caa3 2020-10-17 stsp bool show_function_prototypes = (flags & DIFF_FLAG_SHOW_PROTOTYPES);
441 e51ebd83 2020-11-21 stsp bool force_text = (flags & DIFF_FLAG_FORCE_TEXT_DATA);
442 e51ebd83 2020-11-21 stsp bool have_binary = (atomizer_flags & DIFF_ATOMIZER_FOUND_BINARY_DATA);
443 b72f51ff 2022-01-06 stsp off_t outoff = 0, *offp;
444 9343b925 2022-08-04 mark uint8_t *typep;
445 b72f51ff 2022-01-06 stsp int rc, i;
446 11caa5cc 2020-09-22 stsp
447 3b0f3d61 2020-01-22 neels if (!result)
448 3e6cba3a 2020-08-13 stsp return EINVAL;
449 3b0f3d61 2020-01-22 neels if (result->rc != DIFF_RC_OK)
450 3b0f3d61 2020-01-22 neels return result->rc;
451 3b0f3d61 2020-01-22 neels
452 2c20a3ed 2020-09-22 stsp if (output_info) {
453 2c20a3ed 2020-09-22 stsp *output_info = diff_output_info_alloc();
454 2c20a3ed 2020-09-22 stsp if (*output_info == NULL)
455 2c20a3ed 2020-09-22 stsp return ENOMEM;
456 2c20a3ed 2020-09-22 stsp outinfo = *output_info;
457 2c20a3ed 2020-09-22 stsp }
458 e51ebd83 2020-11-21 stsp
459 e51ebd83 2020-11-21 stsp if (have_binary && !force_text) {
460 e51ebd83 2020-11-21 stsp for (i = 0; i < result->chunks.len; i++) {
461 e51ebd83 2020-11-21 stsp struct diff_chunk *c = &result->chunks.head[i];
462 e51ebd83 2020-11-21 stsp enum diff_chunk_type t = diff_chunk_type(c);
463 2c20a3ed 2020-09-22 stsp
464 e51ebd83 2020-11-21 stsp if (t != CHUNK_MINUS && t != CHUNK_PLUS)
465 e51ebd83 2020-11-21 stsp continue;
466 e51ebd83 2020-11-21 stsp
467 b72f51ff 2022-01-06 stsp if (outinfo && outinfo->line_offsets.len > 0) {
468 b72f51ff 2022-01-06 stsp unsigned int idx =
469 b72f51ff 2022-01-06 stsp outinfo->line_offsets.len - 1;
470 b72f51ff 2022-01-06 stsp outoff = outinfo->line_offsets.head[idx];
471 b72f51ff 2022-01-06 stsp }
472 b72f51ff 2022-01-06 stsp
473 b72f51ff 2022-01-06 stsp rc = fprintf(dest, "Binary files %s and %s differ\n",
474 e4c510c1 2020-11-21 stsp diff_output_get_label_left(info),
475 e4c510c1 2020-11-21 stsp diff_output_get_label_right(info));
476 b72f51ff 2022-01-06 stsp if (outinfo) {
477 b72f51ff 2022-01-06 stsp ARRAYLIST_ADD(offp, outinfo->line_offsets);
478 b72f51ff 2022-01-06 stsp if (offp == NULL)
479 b72f51ff 2022-01-06 stsp return ENOMEM;
480 b72f51ff 2022-01-06 stsp outoff += rc;
481 b72f51ff 2022-01-06 stsp *offp = outoff;
482 9343b925 2022-08-04 mark ARRAYLIST_ADD(typep, outinfo->line_types);
483 9343b925 2022-08-04 mark if (typep == NULL)
484 9343b925 2022-08-04 mark return ENOMEM;
485 9343b925 2022-08-04 mark *typep = DIFF_LINE_NONE;
486 b72f51ff 2022-01-06 stsp }
487 e51ebd83 2020-11-21 stsp break;
488 e51ebd83 2020-11-21 stsp }
489 e51ebd83 2020-11-21 stsp
490 e51ebd83 2020-11-21 stsp return DIFF_RC_OK;
491 e51ebd83 2020-11-21 stsp }
492 e51ebd83 2020-11-21 stsp
493 11caa5cc 2020-09-22 stsp state = diff_output_unidiff_state_alloc();
494 2c20a3ed 2020-09-22 stsp if (state == NULL) {
495 2c20a3ed 2020-09-22 stsp if (output_info) {
496 2c20a3ed 2020-09-22 stsp diff_output_info_free(*output_info);
497 2c20a3ed 2020-09-22 stsp *output_info = NULL;
498 2c20a3ed 2020-09-22 stsp }
499 11caa5cc 2020-09-22 stsp return ENOMEM;
500 2c20a3ed 2020-09-22 stsp }
501 3b0f3d61 2020-01-22 neels
502 5ff75996 2020-10-11 neels #if DEBUG
503 e638575c 2020-11-06 neels unsigned int check_left_pos, check_right_pos;
504 4861c9da 2020-10-30 neels check_left_pos = 0;
505 4861c9da 2020-10-30 neels check_right_pos = 0;
506 5ff75996 2020-10-11 neels for (i = 0; i < result->chunks.len; i++) {
507 5ff75996 2020-10-11 neels struct diff_chunk *c = &result->chunks.head[i];
508 5ff75996 2020-10-11 neels enum diff_chunk_type t = diff_chunk_type(c);
509 2c20a3ed 2020-09-22 stsp
510 5ff75996 2020-10-11 neels debug("[%d] %s lines L%d R%d @L %d @R %d\n",
511 5ff75996 2020-10-11 neels i, (t == CHUNK_MINUS ? "minus" :
512 5ff75996 2020-10-11 neels (t == CHUNK_PLUS ? "plus" :
513 5ff75996 2020-10-11 neels (t == CHUNK_SAME ? "same" : "?"))),
514 5ff75996 2020-10-11 neels c->left_count,
515 5ff75996 2020-10-11 neels c->right_count,
516 9403a358 2020-10-24 neels c->left_start ? diff_atom_root_idx(result->left, c->left_start) : -1,
517 9403a358 2020-10-24 neels c->right_start ? diff_atom_root_idx(result->right, c->right_start) : -1);
518 4861c9da 2020-10-30 neels assert(check_left_pos == diff_atom_root_idx(result->left, c->left_start));
519 4861c9da 2020-10-30 neels assert(check_right_pos == diff_atom_root_idx(result->right, c->right_start));
520 4861c9da 2020-10-30 neels check_left_pos += c->left_count;
521 4861c9da 2020-10-30 neels check_right_pos += c->right_count;
522 4861c9da 2020-10-30 neels
523 5ff75996 2020-10-11 neels }
524 4861c9da 2020-10-30 neels assert(check_left_pos == result->left->atoms.len);
525 4861c9da 2020-10-30 neels assert(check_right_pos == result->right->atoms.len);
526 5ff75996 2020-10-11 neels #endif
527 5ff75996 2020-10-11 neels
528 3b0f3d61 2020-01-22 neels for (i = 0; i < result->chunks.len; i++) {
529 3b0f3d61 2020-01-22 neels struct diff_chunk *c = &result->chunks.head[i];
530 8546b045 2020-09-20 neels enum diff_chunk_type t = diff_chunk_type(c);
531 f374e913 2020-09-22 stsp struct diff_chunk_context next;
532 3b0f3d61 2020-01-22 neels
533 9cc49695 2020-05-05 neels if (t != CHUNK_MINUS && t != CHUNK_PLUS)
534 9cc49695 2020-05-05 neels continue;
535 9cc49695 2020-05-05 neels
536 cbf93b70 2020-10-16 stsp if (diff_chunk_context_empty(&cc)) {
537 9cc49695 2020-05-05 neels /* These are the first lines being printed.
538 0d27172a 2020-05-06 neels * Note down the start point, any number of subsequent
539 0d27172a 2020-05-06 neels * chunks may be joined up to this unidiff chunk by
540 0d27172a 2020-05-06 neels * context lines or by being directly adjacent. */
541 f374e913 2020-09-22 stsp diff_chunk_context_get(&cc, result, i, context_lines);
542 0d27172a 2020-05-06 neels debug("new chunk to be printed:"
543 0d27172a 2020-05-06 neels " chunk %d-%d left %d-%d right %d-%d\n",
544 9cc49695 2020-05-05 neels cc.chunk.start, cc.chunk.end,
545 9cc49695 2020-05-05 neels cc.left.start, cc.left.end,
546 9cc49695 2020-05-05 neels cc.right.start, cc.right.end);
547 9cc49695 2020-05-05 neels continue;
548 3b0f3d61 2020-01-22 neels }
549 3b0f3d61 2020-01-22 neels
550 0d27172a 2020-05-06 neels /* There already is a previous chunk noted down for being
551 0d27172a 2020-05-06 neels * printed. Does it join up with this one? */
552 f374e913 2020-09-22 stsp diff_chunk_context_get(&next, result, i, context_lines);
553 0d27172a 2020-05-06 neels debug("new chunk to be printed:"
554 0d27172a 2020-05-06 neels " chunk %d-%d left %d-%d right %d-%d\n",
555 9cc49695 2020-05-05 neels next.chunk.start, next.chunk.end,
556 9cc49695 2020-05-05 neels next.left.start, next.left.end,
557 9cc49695 2020-05-05 neels next.right.start, next.right.end);
558 9cc49695 2020-05-05 neels
559 26595c7d 2020-10-15 stsp if (diff_chunk_contexts_touch(&cc, &next)) {
560 0d27172a 2020-05-06 neels /* This next context touches or overlaps the previous
561 0d27172a 2020-05-06 neels * one, join. */
562 26595c7d 2020-10-15 stsp diff_chunk_contexts_merge(&cc, &next);
563 0d27172a 2020-05-06 neels debug("new chunk to be printed touches previous chunk,"
564 0d27172a 2020-05-06 neels " now: left %d-%d right %d-%d\n",
565 9cc49695 2020-05-05 neels cc.left.start, cc.left.end,
566 9cc49695 2020-05-05 neels cc.right.start, cc.right.end);
567 9cc49695 2020-05-05 neels continue;
568 9cc49695 2020-05-05 neels }
569 9cc49695 2020-05-05 neels
570 0d27172a 2020-05-06 neels /* No touching, so the previous context is complete with a gap
571 0d27172a 2020-05-06 neels * between it and this next one. Print the previous one and
572 0d27172a 2020-05-06 neels * start fresh here. */
573 0d27172a 2020-05-06 neels debug("new chunk to be printed does not touch previous chunk;"
574 0d27172a 2020-05-06 neels " print left %d-%d right %d-%d\n",
575 9cc49695 2020-05-05 neels cc.left.start, cc.left.end, cc.right.start, cc.right.end);
576 66ea8e5a 2020-10-17 stsp output_unidiff_chunk(outinfo, dest, state, info, result,
577 8993f425 2022-09-23 mark true, show_function_prototypes, &cc, context_lines);
578 9cc49695 2020-05-05 neels cc = next;
579 9cc49695 2020-05-05 neels debug("new unprinted chunk is left %d-%d right %d-%d\n",
580 9cc49695 2020-05-05 neels cc.left.start, cc.left.end, cc.right.start, cc.right.end);
581 3b0f3d61 2020-01-22 neels }
582 3b0f3d61 2020-01-22 neels
583 cbf93b70 2020-10-16 stsp if (!diff_chunk_context_empty(&cc))
584 66ea8e5a 2020-10-17 stsp output_unidiff_chunk(outinfo, dest, state, info, result,
585 8993f425 2022-09-23 mark true, show_function_prototypes, &cc, context_lines);
586 11caa5cc 2020-09-22 stsp diff_output_unidiff_state_free(state);
587 3b0f3d61 2020-01-22 neels return DIFF_RC_OK;
588 3b0f3d61 2020-01-22 neels }