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