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 <inttypes.h>
20 e10a628a 2020-09-16 stsp #include <stdbool.h>
21 e10a628a 2020-09-16 stsp #include <stdio.h>
22 e10a628a 2020-09-16 stsp #include <stdlib.h>
23 4861c9da 2020-10-30 neels #include <assert.h>
24 e10a628a 2020-09-16 stsp
25 1dfba055 2020-10-07 stsp #include <arraylist.h>
26 1dfba055 2020-10-07 stsp #include <diff_main.h>
27 1dfba055 2020-10-07 stsp #include <diff_output.h>
28 3b0f3d61 2020-01-22 neels
29 85ab4559 2020-09-22 stsp #include "diff_internal.h"
30 2a1b94d0 2020-09-26 stsp #include "diff_debug.h"
31 3b0f3d61 2020-01-22 neels
32 2f26640c 2020-10-17 stsp bool
33 cbf93b70 2020-10-16 stsp diff_chunk_context_empty(const struct diff_chunk_context *cc)
34 3b0f3d61 2020-01-22 neels {
35 d362ea2e 2020-07-25 stsp return diff_range_empty(&cc->chunk);
36 3b0f3d61 2020-01-22 neels }
37 3b0f3d61 2020-01-22 neels
38 fe8af0d6 2020-10-06 stsp int
39 fe8af0d6 2020-10-06 stsp diff_chunk_get_left_start(const struct diff_chunk *c,
40 fe8af0d6 2020-10-06 stsp const struct diff_result *r, int context_lines)
41 fe8af0d6 2020-10-06 stsp {
42 c16dde50 2020-10-22 stsp int left_start = diff_atom_root_idx(r->left, c->left_start);
43 fe8af0d6 2020-10-06 stsp return MAX(0, left_start - context_lines);
44 fe8af0d6 2020-10-06 stsp }
45 fe8af0d6 2020-10-06 stsp
46 fe8af0d6 2020-10-06 stsp int
47 fe8af0d6 2020-10-06 stsp diff_chunk_get_left_end(const struct diff_chunk *c,
48 fe8af0d6 2020-10-06 stsp const struct diff_result *r, int context_lines)
49 fe8af0d6 2020-10-06 stsp {
50 fe8af0d6 2020-10-06 stsp int left_start = diff_chunk_get_left_start(c, r, 0);
51 c16dde50 2020-10-22 stsp return MIN(r->left->atoms.len,
52 fe8af0d6 2020-10-06 stsp left_start + c->left_count + context_lines);
53 fe8af0d6 2020-10-06 stsp }
54 fe8af0d6 2020-10-06 stsp
55 fe8af0d6 2020-10-06 stsp int
56 fe8af0d6 2020-10-06 stsp diff_chunk_get_right_start(const struct diff_chunk *c,
57 fe8af0d6 2020-10-06 stsp const struct diff_result *r, int context_lines)
58 fe8af0d6 2020-10-06 stsp {
59 c16dde50 2020-10-22 stsp int right_start = diff_atom_root_idx(r->right, c->right_start);
60 fe8af0d6 2020-10-06 stsp return MAX(0, right_start - context_lines);
61 fe8af0d6 2020-10-06 stsp }
62 fe8af0d6 2020-10-06 stsp
63 fe8af0d6 2020-10-06 stsp int
64 fe8af0d6 2020-10-06 stsp diff_chunk_get_right_end(const struct diff_chunk *c,
65 fe8af0d6 2020-10-06 stsp const struct diff_result *r, int context_lines)
66 fe8af0d6 2020-10-06 stsp {
67 fe8af0d6 2020-10-06 stsp int right_start = diff_chunk_get_right_start(c, r, 0);
68 c16dde50 2020-10-22 stsp return MIN(r->right->atoms.len,
69 fe8af0d6 2020-10-06 stsp right_start + c->right_count + context_lines);
70 fe8af0d6 2020-10-06 stsp }
71 fe8af0d6 2020-10-06 stsp
72 f374e913 2020-09-22 stsp void
73 f374e913 2020-09-22 stsp diff_chunk_context_get(struct diff_chunk_context *cc, const struct diff_result *r,
74 0d27172a 2020-05-06 neels int chunk_idx, int context_lines)
75 3b0f3d61 2020-01-22 neels {
76 3b0f3d61 2020-01-22 neels const struct diff_chunk *c = &r->chunks.head[chunk_idx];
77 fe8af0d6 2020-10-06 stsp int left_start = diff_chunk_get_left_start(c, r, context_lines);
78 fe8af0d6 2020-10-06 stsp int left_end = diff_chunk_get_left_end(c, r, context_lines);
79 fe8af0d6 2020-10-06 stsp int right_start = diff_chunk_get_right_start(c, r, context_lines);
80 fe8af0d6 2020-10-06 stsp int right_end = diff_chunk_get_right_end(c, r, context_lines);
81 0d27172a 2020-05-06 neels
82 f374e913 2020-09-22 stsp *cc = (struct diff_chunk_context){
83 3b0f3d61 2020-01-22 neels .chunk = {
84 3b0f3d61 2020-01-22 neels .start = chunk_idx,
85 3b0f3d61 2020-01-22 neels .end = chunk_idx + 1,
86 3b0f3d61 2020-01-22 neels },
87 3b0f3d61 2020-01-22 neels .left = {
88 0d27172a 2020-05-06 neels .start = left_start,
89 0d27172a 2020-05-06 neels .end = left_end,
90 3b0f3d61 2020-01-22 neels },
91 3b0f3d61 2020-01-22 neels .right = {
92 0d27172a 2020-05-06 neels .start = right_start,
93 0d27172a 2020-05-06 neels .end = right_end,
94 3b0f3d61 2020-01-22 neels },
95 3b0f3d61 2020-01-22 neels };
96 3b0f3d61 2020-01-22 neels }
97 3b0f3d61 2020-01-22 neels
98 2f26640c 2020-10-17 stsp bool
99 26595c7d 2020-10-15 stsp diff_chunk_contexts_touch(const struct diff_chunk_context *cc,
100 26595c7d 2020-10-15 stsp const struct diff_chunk_context *other)
101 3b0f3d61 2020-01-22 neels {
102 d362ea2e 2020-07-25 stsp return diff_ranges_touch(&cc->chunk, &other->chunk)
103 d362ea2e 2020-07-25 stsp || diff_ranges_touch(&cc->left, &other->left)
104 d362ea2e 2020-07-25 stsp || diff_ranges_touch(&cc->right, &other->right);
105 3b0f3d61 2020-01-22 neels }
106 3b0f3d61 2020-01-22 neels
107 26595c7d 2020-10-15 stsp void
108 26595c7d 2020-10-15 stsp diff_chunk_contexts_merge(struct diff_chunk_context *cc,
109 26595c7d 2020-10-15 stsp const struct diff_chunk_context *other)
110 3b0f3d61 2020-01-22 neels {
111 d362ea2e 2020-07-25 stsp diff_ranges_merge(&cc->chunk, &other->chunk);
112 d362ea2e 2020-07-25 stsp diff_ranges_merge(&cc->left, &other->left);
113 d362ea2e 2020-07-25 stsp diff_ranges_merge(&cc->right, &other->right);
114 7187fe97 2020-10-17 stsp }
115 7187fe97 2020-10-17 stsp
116 7187fe97 2020-10-17 stsp void
117 7187fe97 2020-10-17 stsp diff_chunk_context_load_change(struct diff_chunk_context *cc,
118 7187fe97 2020-10-17 stsp int *nchunks_used,
119 7187fe97 2020-10-17 stsp struct diff_result *result,
120 7187fe97 2020-10-17 stsp int start_chunk_idx,
121 7187fe97 2020-10-17 stsp int context_lines)
122 7187fe97 2020-10-17 stsp {
123 7187fe97 2020-10-17 stsp int i;
124 7187fe97 2020-10-17 stsp int seen_minus = 0, seen_plus = 0;
125 7187fe97 2020-10-17 stsp
126 7187fe97 2020-10-17 stsp if (nchunks_used)
127 7187fe97 2020-10-17 stsp *nchunks_used = 0;
128 7187fe97 2020-10-17 stsp
129 7187fe97 2020-10-17 stsp for (i = start_chunk_idx; i < result->chunks.len; i++) {
130 7187fe97 2020-10-17 stsp struct diff_chunk *chunk = &result->chunks.head[i];
131 7187fe97 2020-10-17 stsp enum diff_chunk_type t = diff_chunk_type(chunk);
132 7187fe97 2020-10-17 stsp struct diff_chunk_context next;
133 7187fe97 2020-10-17 stsp
134 7187fe97 2020-10-17 stsp if (t != CHUNK_MINUS && t != CHUNK_PLUS) {
135 7187fe97 2020-10-17 stsp if (nchunks_used)
136 7187fe97 2020-10-17 stsp (*nchunks_used)++;
137 f4867452 2020-10-17 stsp if (seen_minus || seen_plus)
138 7187fe97 2020-10-17 stsp break;
139 7187fe97 2020-10-17 stsp else
140 7187fe97 2020-10-17 stsp continue;
141 7187fe97 2020-10-17 stsp } else if (t == CHUNK_MINUS)
142 7187fe97 2020-10-17 stsp seen_minus = 1;
143 7187fe97 2020-10-17 stsp else if (t == CHUNK_PLUS)
144 7187fe97 2020-10-17 stsp seen_plus = 1;
145 7187fe97 2020-10-17 stsp
146 7187fe97 2020-10-17 stsp if (diff_chunk_context_empty(cc)) {
147 7187fe97 2020-10-17 stsp /* Note down the start point, any number of subsequent
148 7187fe97 2020-10-17 stsp * chunks may be joined up to this chunk by being
149 7187fe97 2020-10-17 stsp * directly adjacent. */
150 7187fe97 2020-10-17 stsp diff_chunk_context_get(cc, result, i, context_lines);
151 7187fe97 2020-10-17 stsp if (nchunks_used)
152 7187fe97 2020-10-17 stsp (*nchunks_used)++;
153 7187fe97 2020-10-17 stsp continue;
154 7187fe97 2020-10-17 stsp }
155 7187fe97 2020-10-17 stsp
156 7187fe97 2020-10-17 stsp /* There already is a previous chunk noted down for being
157 7187fe97 2020-10-17 stsp * printed. Does it join up with this one? */
158 7187fe97 2020-10-17 stsp diff_chunk_context_get(&next, result, i, context_lines);
159 7187fe97 2020-10-17 stsp
160 7187fe97 2020-10-17 stsp if (diff_chunk_contexts_touch(cc, &next)) {
161 7187fe97 2020-10-17 stsp /* This next context touches or overlaps the previous
162 7187fe97 2020-10-17 stsp * one, join. */
163 7187fe97 2020-10-17 stsp diff_chunk_contexts_merge(cc, &next);
164 7187fe97 2020-10-17 stsp if (nchunks_used)
165 7187fe97 2020-10-17 stsp (*nchunks_used)++;
166 7187fe97 2020-10-17 stsp continue;
167 7187fe97 2020-10-17 stsp } else
168 7187fe97 2020-10-17 stsp break;
169 7187fe97 2020-10-17 stsp }
170 3b0f3d61 2020-01-22 neels }
171 3b0f3d61 2020-01-22 neels
172 11caa5cc 2020-09-22 stsp struct diff_output_unidiff_state {
173 11caa5cc 2020-09-22 stsp bool header_printed;
174 11caa5cc 2020-09-22 stsp };
175 11caa5cc 2020-09-22 stsp
176 11caa5cc 2020-09-22 stsp struct diff_output_unidiff_state *
177 11caa5cc 2020-09-22 stsp diff_output_unidiff_state_alloc(void)
178 11caa5cc 2020-09-22 stsp {
179 11caa5cc 2020-09-22 stsp struct diff_output_unidiff_state *state;
180 11caa5cc 2020-09-22 stsp
181 11caa5cc 2020-09-22 stsp state = calloc(1, sizeof(struct diff_output_unidiff_state));
182 11caa5cc 2020-09-22 stsp if (state != NULL)
183 11caa5cc 2020-09-22 stsp diff_output_unidiff_state_reset(state);
184 11caa5cc 2020-09-22 stsp return state;
185 11caa5cc 2020-09-22 stsp }
186 11caa5cc 2020-09-22 stsp
187 f374e913 2020-09-22 stsp void
188 11caa5cc 2020-09-22 stsp diff_output_unidiff_state_reset(struct diff_output_unidiff_state *state)
189 11caa5cc 2020-09-22 stsp {
190 11caa5cc 2020-09-22 stsp state->header_printed = false;
191 11caa5cc 2020-09-22 stsp }
192 11caa5cc 2020-09-22 stsp
193 11caa5cc 2020-09-22 stsp void
194 11caa5cc 2020-09-22 stsp diff_output_unidiff_state_free(struct diff_output_unidiff_state *state)
195 11caa5cc 2020-09-22 stsp {
196 11caa5cc 2020-09-22 stsp free(state);
197 11caa5cc 2020-09-22 stsp }
198 11caa5cc 2020-09-22 stsp
199 2c20a3ed 2020-09-22 stsp static int
200 2c20a3ed 2020-09-22 stsp output_unidiff_chunk(struct diff_output_info *outinfo, FILE *dest,
201 2c20a3ed 2020-09-22 stsp struct diff_output_unidiff_state *state,
202 2c20a3ed 2020-09-22 stsp const struct diff_input_info *info,
203 2c20a3ed 2020-09-22 stsp const struct diff_result *result,
204 13e2caa3 2020-10-17 stsp bool print_header, bool show_function_prototypes,
205 2c20a3ed 2020-09-22 stsp const struct diff_chunk_context *cc)
206 3b0f3d61 2020-01-22 neels {
207 b6adedb6 2020-10-07 stsp int rc, left_start, left_len, right_start, right_len;
208 ab528e22 2020-09-22 stsp off_t outoff = 0, *offp;
209 13e2caa3 2020-10-17 stsp char *prototype = NULL;
210 2c20a3ed 2020-09-22 stsp
211 d362ea2e 2020-07-25 stsp if (diff_range_empty(&cc->left) && diff_range_empty(&cc->right))
212 2c20a3ed 2020-09-22 stsp return DIFF_RC_OK;
213 3b0f3d61 2020-01-22 neels
214 2c20a3ed 2020-09-22 stsp if (outinfo && outinfo->line_offsets.len > 0) {
215 2c20a3ed 2020-09-22 stsp unsigned int idx = outinfo->line_offsets.len - 1;
216 2c20a3ed 2020-09-22 stsp outoff = outinfo->line_offsets.head[idx];
217 2c20a3ed 2020-09-22 stsp }
218 2c20a3ed 2020-09-22 stsp
219 66ea8e5a 2020-10-17 stsp if (print_header && !(state->header_printed)) {
220 2c20a3ed 2020-09-22 stsp rc = fprintf(dest, "--- %s\n", info->left_path ? : "a");
221 2c20a3ed 2020-09-22 stsp if (rc < 0)
222 2c20a3ed 2020-09-22 stsp return errno;
223 2c20a3ed 2020-09-22 stsp if (outinfo) {
224 2c20a3ed 2020-09-22 stsp ARRAYLIST_ADD(offp, outinfo->line_offsets);
225 dabc1008 2020-09-22 stsp if (offp == NULL)
226 dabc1008 2020-09-22 stsp return ENOMEM;
227 2c20a3ed 2020-09-22 stsp outoff += rc;
228 2c20a3ed 2020-09-22 stsp *offp = outoff;
229 2c20a3ed 2020-09-22 stsp
230 2c20a3ed 2020-09-22 stsp }
231 2c20a3ed 2020-09-22 stsp rc = fprintf(dest, "+++ %s\n", info->right_path ? : "b");
232 2c20a3ed 2020-09-22 stsp if (rc < 0)
233 2c20a3ed 2020-09-22 stsp return errno;
234 2c20a3ed 2020-09-22 stsp if (outinfo) {
235 2c20a3ed 2020-09-22 stsp ARRAYLIST_ADD(offp, outinfo->line_offsets);
236 dabc1008 2020-09-22 stsp if (offp == NULL)
237 dabc1008 2020-09-22 stsp return ENOMEM;
238 2c20a3ed 2020-09-22 stsp outoff += rc;
239 2c20a3ed 2020-09-22 stsp *offp = outoff;
240 2c20a3ed 2020-09-22 stsp
241 2c20a3ed 2020-09-22 stsp }
242 11caa5cc 2020-09-22 stsp state->header_printed = true;
243 3b0f3d61 2020-01-22 neels }
244 3b0f3d61 2020-01-22 neels
245 b6adedb6 2020-10-07 stsp left_len = cc->left.end - cc->left.start;
246 c16dde50 2020-10-22 stsp if (result->left->atoms.len == 0)
247 11d9f2f7 2020-10-07 stsp left_start = 0;
248 11d9f2f7 2020-10-07 stsp else if (left_len == 0 && cc->left.start > 0)
249 b6adedb6 2020-10-07 stsp left_start = cc->left.start;
250 b6adedb6 2020-10-07 stsp else
251 b6adedb6 2020-10-07 stsp left_start = cc->left.start + 1;
252 b6adedb6 2020-10-07 stsp
253 b6adedb6 2020-10-07 stsp right_len = cc->right.end - cc->right.start;
254 c16dde50 2020-10-22 stsp if (result->right->atoms.len == 0)
255 11d9f2f7 2020-10-07 stsp right_start = 0;
256 11d9f2f7 2020-10-07 stsp else if (right_len == 0 && cc->right.start > 0)
257 b6adedb6 2020-10-07 stsp right_start = cc->right.start;
258 b6adedb6 2020-10-07 stsp else
259 b6adedb6 2020-10-07 stsp right_start = cc->right.start + 1;
260 13e2caa3 2020-10-17 stsp
261 13e2caa3 2020-10-17 stsp if (show_function_prototypes) {
262 13e2caa3 2020-10-17 stsp rc = diff_output_match_function_prototype(&prototype,
263 13e2caa3 2020-10-17 stsp result, cc);
264 13e2caa3 2020-10-17 stsp if (rc)
265 13e2caa3 2020-10-17 stsp return rc;
266 13e2caa3 2020-10-17 stsp }
267 b6adedb6 2020-10-07 stsp
268 d2dfa2ec 2020-10-07 stsp if (left_len == 1 && right_len == 1) {
269 13e2caa3 2020-10-17 stsp rc = fprintf(dest, "@@ -%d +%d @@%s%s\n",
270 13e2caa3 2020-10-17 stsp left_start, right_start,
271 13e2caa3 2020-10-17 stsp prototype ? " " : "",
272 13e2caa3 2020-10-17 stsp prototype ? : "");
273 d2dfa2ec 2020-10-07 stsp } else if (left_len == 1 && right_len != 1) {
274 13e2caa3 2020-10-17 stsp rc = fprintf(dest, "@@ -%d +%d,%d @@%s%s\n",
275 13e2caa3 2020-10-17 stsp left_start, right_start, right_len,
276 13e2caa3 2020-10-17 stsp prototype ? " " : "",
277 13e2caa3 2020-10-17 stsp prototype ? : "");
278 b6adedb6 2020-10-07 stsp } else if (left_len != 1 && right_len == 1) {
279 13e2caa3 2020-10-17 stsp rc = fprintf(dest, "@@ -%d,%d +%d @@%s%s\n",
280 13e2caa3 2020-10-17 stsp left_start, left_len, right_start,
281 13e2caa3 2020-10-17 stsp prototype ? " " : "",
282 13e2caa3 2020-10-17 stsp prototype ? : "");
283 b6adedb6 2020-10-07 stsp } else {
284 13e2caa3 2020-10-17 stsp rc = fprintf(dest, "@@ -%d,%d +%d,%d @@%s%s\n",
285 13e2caa3 2020-10-17 stsp left_start, left_len, right_start, right_len,
286 13e2caa3 2020-10-17 stsp prototype ? " " : "",
287 13e2caa3 2020-10-17 stsp prototype ? : "");
288 b6adedb6 2020-10-07 stsp }
289 13e2caa3 2020-10-17 stsp free(prototype);
290 2c20a3ed 2020-09-22 stsp if (rc < 0)
291 2c20a3ed 2020-09-22 stsp return errno;
292 2c20a3ed 2020-09-22 stsp if (outinfo) {
293 2c20a3ed 2020-09-22 stsp ARRAYLIST_ADD(offp, outinfo->line_offsets);
294 dabc1008 2020-09-22 stsp if (offp == NULL)
295 dabc1008 2020-09-22 stsp return ENOMEM;
296 2c20a3ed 2020-09-22 stsp outoff += rc;
297 2c20a3ed 2020-09-22 stsp *offp = outoff;
298 3b0f3d61 2020-01-22 neels
299 2c20a3ed 2020-09-22 stsp }
300 2c20a3ed 2020-09-22 stsp
301 0d27172a 2020-05-06 neels /* Got the absolute line numbers where to start printing, and the index
302 0d27172a 2020-05-06 neels * of the interesting (non-context) chunk.
303 0d27172a 2020-05-06 neels * To print context lines above the interesting chunk, nipping on the
304 0d27172a 2020-05-06 neels * previous chunk index may be necessary.
305 0d27172a 2020-05-06 neels * It is guaranteed to be only context lines where left == right, so it
306 0d27172a 2020-05-06 neels * suffices to look on the left. */
307 0d27172a 2020-05-06 neels const struct diff_chunk *first_chunk;
308 0d27172a 2020-05-06 neels int chunk_start_line;
309 0d27172a 2020-05-06 neels first_chunk = &result->chunks.head[cc->chunk.start];
310 c16dde50 2020-10-22 stsp chunk_start_line = diff_atom_root_idx(result->left,
311 0d27172a 2020-05-06 neels first_chunk->left_start);
312 2c20a3ed 2020-09-22 stsp if (cc->left.start < chunk_start_line) {
313 2c20a3ed 2020-09-22 stsp rc = diff_output_lines(outinfo, dest, " ",
314 c16dde50 2020-10-22 stsp &result->left->atoms.head[cc->left.start],
315 3b0f3d61 2020-01-22 neels chunk_start_line - cc->left.start);
316 2c20a3ed 2020-09-22 stsp if (rc)
317 2c20a3ed 2020-09-22 stsp return rc;
318 2c20a3ed 2020-09-22 stsp }
319 3b0f3d61 2020-01-22 neels
320 3b0f3d61 2020-01-22 neels /* Now write out all the joined chunks and contexts between them */
321 3b0f3d61 2020-01-22 neels int c_idx;
322 3b0f3d61 2020-01-22 neels for (c_idx = cc->chunk.start; c_idx < cc->chunk.end; c_idx++) {
323 3b0f3d61 2020-01-22 neels const struct diff_chunk *c = &result->chunks.head[c_idx];
324 3b0f3d61 2020-01-22 neels
325 3b0f3d61 2020-01-22 neels if (c->left_count && c->right_count)
326 2c20a3ed 2020-09-22 stsp rc = diff_output_lines(outinfo, dest,
327 0d27172a 2020-05-06 neels c->solved ? " " : "?",
328 0d27172a 2020-05-06 neels c->left_start, c->left_count);
329 3b0f3d61 2020-01-22 neels else if (c->left_count && !c->right_count)
330 2c20a3ed 2020-09-22 stsp rc = diff_output_lines(outinfo, dest,
331 0d27172a 2020-05-06 neels c->solved ? "-" : "?",
332 0d27172a 2020-05-06 neels c->left_start, c->left_count);
333 3b0f3d61 2020-01-22 neels else if (c->right_count && !c->left_count)
334 2c20a3ed 2020-09-22 stsp rc = diff_output_lines(outinfo, dest,
335 0d27172a 2020-05-06 neels c->solved ? "+" : "?",
336 0d27172a 2020-05-06 neels c->right_start, c->right_count);
337 2c20a3ed 2020-09-22 stsp if (rc)
338 2c20a3ed 2020-09-22 stsp return rc;
339 7021523c 2020-10-16 stsp
340 7021523c 2020-10-16 stsp if (cc->chunk.end == result->chunks.len) {
341 7021523c 2020-10-16 stsp rc = diff_output_trailing_newline_msg(outinfo, dest, c);
342 7021523c 2020-10-16 stsp if (rc != DIFF_RC_OK)
343 7021523c 2020-10-16 stsp return rc;
344 7021523c 2020-10-16 stsp }
345 3b0f3d61 2020-01-22 neels }
346 3b0f3d61 2020-01-22 neels
347 3b0f3d61 2020-01-22 neels /* Trailing context? */
348 0d27172a 2020-05-06 neels const struct diff_chunk *last_chunk;
349 0d27172a 2020-05-06 neels int chunk_end_line;
350 0d27172a 2020-05-06 neels last_chunk = &result->chunks.head[cc->chunk.end - 1];
351 c16dde50 2020-10-22 stsp chunk_end_line = diff_atom_root_idx(result->left,
352 0d27172a 2020-05-06 neels last_chunk->left_start
353 0d27172a 2020-05-06 neels + last_chunk->left_count);
354 2c20a3ed 2020-09-22 stsp if (cc->left.end > chunk_end_line) {
355 2c20a3ed 2020-09-22 stsp rc = diff_output_lines(outinfo, dest, " ",
356 c16dde50 2020-10-22 stsp &result->left->atoms.head[chunk_end_line],
357 3b0f3d61 2020-01-22 neels cc->left.end - chunk_end_line);
358 2c20a3ed 2020-09-22 stsp if (rc)
359 2c20a3ed 2020-09-22 stsp return rc;
360 2c20a3ed 2020-09-22 stsp }
361 2c20a3ed 2020-09-22 stsp
362 2c20a3ed 2020-09-22 stsp return DIFF_RC_OK;
363 3b0f3d61 2020-01-22 neels }
364 3b0f3d61 2020-01-22 neels
365 3e6cba3a 2020-08-13 stsp int
366 2c20a3ed 2020-09-22 stsp diff_output_unidiff_chunk(struct diff_output_info **output_info, FILE *dest,
367 2c20a3ed 2020-09-22 stsp struct diff_output_unidiff_state *state,
368 2c20a3ed 2020-09-22 stsp const struct diff_input_info *info,
369 2c20a3ed 2020-09-22 stsp const struct diff_result *result,
370 2c20a3ed 2020-09-22 stsp const struct diff_chunk_context *cc)
371 2c20a3ed 2020-09-22 stsp {
372 2c20a3ed 2020-09-22 stsp struct diff_output_info *outinfo = NULL;
373 c16dde50 2020-10-22 stsp int flags = (result->left->root->diff_flags |
374 c16dde50 2020-10-22 stsp result->right->root->diff_flags);
375 13e2caa3 2020-10-17 stsp bool show_function_prototypes = (flags & DIFF_FLAG_SHOW_PROTOTYPES);
376 2c20a3ed 2020-09-22 stsp
377 2c20a3ed 2020-09-22 stsp if (output_info) {
378 2c20a3ed 2020-09-22 stsp *output_info = diff_output_info_alloc();
379 2c20a3ed 2020-09-22 stsp if (*output_info == NULL)
380 2c20a3ed 2020-09-22 stsp return ENOMEM;
381 2c20a3ed 2020-09-22 stsp outinfo = *output_info;
382 2c20a3ed 2020-09-22 stsp }
383 2c20a3ed 2020-09-22 stsp
384 2c20a3ed 2020-09-22 stsp return output_unidiff_chunk(outinfo, dest, state, info,
385 13e2caa3 2020-10-17 stsp result, false, show_function_prototypes, cc);
386 2c20a3ed 2020-09-22 stsp }
387 2c20a3ed 2020-09-22 stsp
388 2c20a3ed 2020-09-22 stsp int
389 2c20a3ed 2020-09-22 stsp diff_output_unidiff(struct diff_output_info **output_info,
390 2c20a3ed 2020-09-22 stsp FILE *dest, const struct diff_input_info *info,
391 0d27172a 2020-05-06 neels const struct diff_result *result,
392 0d27172a 2020-05-06 neels unsigned int context_lines)
393 3b0f3d61 2020-01-22 neels {
394 11caa5cc 2020-09-22 stsp struct diff_output_unidiff_state *state;
395 11caa5cc 2020-09-22 stsp struct diff_chunk_context cc = {};
396 2c20a3ed 2020-09-22 stsp struct diff_output_info *outinfo = NULL;
397 c16dde50 2020-10-22 stsp int flags = (result->left->root->diff_flags |
398 c16dde50 2020-10-22 stsp result->right->root->diff_flags);
399 13e2caa3 2020-10-17 stsp bool show_function_prototypes = (flags & DIFF_FLAG_SHOW_PROTOTYPES);
400 11caa5cc 2020-09-22 stsp int i;
401 11caa5cc 2020-09-22 stsp
402 3b0f3d61 2020-01-22 neels if (!result)
403 3e6cba3a 2020-08-13 stsp return EINVAL;
404 3b0f3d61 2020-01-22 neels if (result->rc != DIFF_RC_OK)
405 3b0f3d61 2020-01-22 neels return result->rc;
406 3b0f3d61 2020-01-22 neels
407 2c20a3ed 2020-09-22 stsp if (output_info) {
408 2c20a3ed 2020-09-22 stsp *output_info = diff_output_info_alloc();
409 2c20a3ed 2020-09-22 stsp if (*output_info == NULL)
410 2c20a3ed 2020-09-22 stsp return ENOMEM;
411 2c20a3ed 2020-09-22 stsp outinfo = *output_info;
412 2c20a3ed 2020-09-22 stsp }
413 2c20a3ed 2020-09-22 stsp
414 11caa5cc 2020-09-22 stsp state = diff_output_unidiff_state_alloc();
415 2c20a3ed 2020-09-22 stsp if (state == NULL) {
416 2c20a3ed 2020-09-22 stsp if (output_info) {
417 2c20a3ed 2020-09-22 stsp diff_output_info_free(*output_info);
418 2c20a3ed 2020-09-22 stsp *output_info = NULL;
419 2c20a3ed 2020-09-22 stsp }
420 11caa5cc 2020-09-22 stsp return ENOMEM;
421 2c20a3ed 2020-09-22 stsp }
422 3b0f3d61 2020-01-22 neels
423 5ff75996 2020-10-11 neels #if DEBUG
424 e638575c 2020-11-06 neels unsigned int check_left_pos, check_right_pos;
425 4861c9da 2020-10-30 neels check_left_pos = 0;
426 4861c9da 2020-10-30 neels check_right_pos = 0;
427 5ff75996 2020-10-11 neels for (i = 0; i < result->chunks.len; i++) {
428 5ff75996 2020-10-11 neels struct diff_chunk *c = &result->chunks.head[i];
429 5ff75996 2020-10-11 neels enum diff_chunk_type t = diff_chunk_type(c);
430 2c20a3ed 2020-09-22 stsp
431 5ff75996 2020-10-11 neels debug("[%d] %s lines L%d R%d @L %d @R %d\n",
432 5ff75996 2020-10-11 neels i, (t == CHUNK_MINUS ? "minus" :
433 5ff75996 2020-10-11 neels (t == CHUNK_PLUS ? "plus" :
434 5ff75996 2020-10-11 neels (t == CHUNK_SAME ? "same" : "?"))),
435 5ff75996 2020-10-11 neels c->left_count,
436 5ff75996 2020-10-11 neels c->right_count,
437 9403a358 2020-10-24 neels c->left_start ? diff_atom_root_idx(result->left, c->left_start) : -1,
438 9403a358 2020-10-24 neels c->right_start ? diff_atom_root_idx(result->right, c->right_start) : -1);
439 4861c9da 2020-10-30 neels assert(check_left_pos == diff_atom_root_idx(result->left, c->left_start));
440 4861c9da 2020-10-30 neels assert(check_right_pos == diff_atom_root_idx(result->right, c->right_start));
441 4861c9da 2020-10-30 neels check_left_pos += c->left_count;
442 4861c9da 2020-10-30 neels check_right_pos += c->right_count;
443 4861c9da 2020-10-30 neels
444 5ff75996 2020-10-11 neels }
445 4861c9da 2020-10-30 neels assert(check_left_pos == result->left->atoms.len);
446 4861c9da 2020-10-30 neels assert(check_right_pos == result->right->atoms.len);
447 5ff75996 2020-10-11 neels #endif
448 5ff75996 2020-10-11 neels
449 3b0f3d61 2020-01-22 neels for (i = 0; i < result->chunks.len; i++) {
450 3b0f3d61 2020-01-22 neels struct diff_chunk *c = &result->chunks.head[i];
451 8546b045 2020-09-20 neels enum diff_chunk_type t = diff_chunk_type(c);
452 f374e913 2020-09-22 stsp struct diff_chunk_context next;
453 3b0f3d61 2020-01-22 neels
454 9cc49695 2020-05-05 neels if (t != CHUNK_MINUS && t != CHUNK_PLUS)
455 9cc49695 2020-05-05 neels continue;
456 9cc49695 2020-05-05 neels
457 cbf93b70 2020-10-16 stsp if (diff_chunk_context_empty(&cc)) {
458 9cc49695 2020-05-05 neels /* These are the first lines being printed.
459 0d27172a 2020-05-06 neels * Note down the start point, any number of subsequent
460 0d27172a 2020-05-06 neels * chunks may be joined up to this unidiff chunk by
461 0d27172a 2020-05-06 neels * context lines or by being directly adjacent. */
462 f374e913 2020-09-22 stsp diff_chunk_context_get(&cc, result, i, context_lines);
463 0d27172a 2020-05-06 neels debug("new chunk to be printed:"
464 0d27172a 2020-05-06 neels " chunk %d-%d left %d-%d right %d-%d\n",
465 9cc49695 2020-05-05 neels cc.chunk.start, cc.chunk.end,
466 9cc49695 2020-05-05 neels cc.left.start, cc.left.end,
467 9cc49695 2020-05-05 neels cc.right.start, cc.right.end);
468 9cc49695 2020-05-05 neels continue;
469 3b0f3d61 2020-01-22 neels }
470 3b0f3d61 2020-01-22 neels
471 0d27172a 2020-05-06 neels /* There already is a previous chunk noted down for being
472 0d27172a 2020-05-06 neels * printed. Does it join up with this one? */
473 f374e913 2020-09-22 stsp diff_chunk_context_get(&next, result, i, context_lines);
474 0d27172a 2020-05-06 neels debug("new chunk to be printed:"
475 0d27172a 2020-05-06 neels " chunk %d-%d left %d-%d right %d-%d\n",
476 9cc49695 2020-05-05 neels next.chunk.start, next.chunk.end,
477 9cc49695 2020-05-05 neels next.left.start, next.left.end,
478 9cc49695 2020-05-05 neels next.right.start, next.right.end);
479 9cc49695 2020-05-05 neels
480 26595c7d 2020-10-15 stsp if (diff_chunk_contexts_touch(&cc, &next)) {
481 0d27172a 2020-05-06 neels /* This next context touches or overlaps the previous
482 0d27172a 2020-05-06 neels * one, join. */
483 26595c7d 2020-10-15 stsp diff_chunk_contexts_merge(&cc, &next);
484 0d27172a 2020-05-06 neels debug("new chunk to be printed touches previous chunk,"
485 0d27172a 2020-05-06 neels " now: left %d-%d right %d-%d\n",
486 9cc49695 2020-05-05 neels cc.left.start, cc.left.end,
487 9cc49695 2020-05-05 neels cc.right.start, cc.right.end);
488 9cc49695 2020-05-05 neels continue;
489 9cc49695 2020-05-05 neels }
490 9cc49695 2020-05-05 neels
491 0d27172a 2020-05-06 neels /* No touching, so the previous context is complete with a gap
492 0d27172a 2020-05-06 neels * between it and this next one. Print the previous one and
493 0d27172a 2020-05-06 neels * start fresh here. */
494 0d27172a 2020-05-06 neels debug("new chunk to be printed does not touch previous chunk;"
495 0d27172a 2020-05-06 neels " print left %d-%d right %d-%d\n",
496 9cc49695 2020-05-05 neels cc.left.start, cc.left.end, cc.right.start, cc.right.end);
497 66ea8e5a 2020-10-17 stsp output_unidiff_chunk(outinfo, dest, state, info, result,
498 13e2caa3 2020-10-17 stsp true, show_function_prototypes, &cc);
499 9cc49695 2020-05-05 neels cc = next;
500 9cc49695 2020-05-05 neels debug("new unprinted chunk is left %d-%d right %d-%d\n",
501 9cc49695 2020-05-05 neels cc.left.start, cc.left.end, cc.right.start, cc.right.end);
502 3b0f3d61 2020-01-22 neels }
503 3b0f3d61 2020-01-22 neels
504 cbf93b70 2020-10-16 stsp if (!diff_chunk_context_empty(&cc))
505 66ea8e5a 2020-10-17 stsp output_unidiff_chunk(outinfo, dest, state, info, result,
506 13e2caa3 2020-10-17 stsp true, show_function_prototypes, &cc);
507 11caa5cc 2020-09-22 stsp diff_output_unidiff_state_free(state);
508 3b0f3d61 2020-01-22 neels return DIFF_RC_OK;
509 3b0f3d61 2020-01-22 neels }