159c8e88eSDag-Erling Smørgrav /* Produce a unidiff output from a diff_result. */
259c8e88eSDag-Erling Smørgrav /*
359c8e88eSDag-Erling Smørgrav * Copyright (c) 2020 Neels Hofmeyr <neels@hofmeyr.de>
459c8e88eSDag-Erling Smørgrav *
559c8e88eSDag-Erling Smørgrav * Permission to use, copy, modify, and distribute this software for any
659c8e88eSDag-Erling Smørgrav * purpose with or without fee is hereby granted, provided that the above
759c8e88eSDag-Erling Smørgrav * copyright notice and this permission notice appear in all copies.
859c8e88eSDag-Erling Smørgrav *
959c8e88eSDag-Erling Smørgrav * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1059c8e88eSDag-Erling Smørgrav * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1159c8e88eSDag-Erling Smørgrav * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1259c8e88eSDag-Erling Smørgrav * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1359c8e88eSDag-Erling Smørgrav * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1459c8e88eSDag-Erling Smørgrav * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1559c8e88eSDag-Erling Smørgrav * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1659c8e88eSDag-Erling Smørgrav */
1759c8e88eSDag-Erling Smørgrav
1859c8e88eSDag-Erling Smørgrav #include <errno.h>
1959c8e88eSDag-Erling Smørgrav #include <stdbool.h>
2059c8e88eSDag-Erling Smørgrav #include <stdint.h>
2159c8e88eSDag-Erling Smørgrav #include <stdio.h>
2259c8e88eSDag-Erling Smørgrav #include <stdlib.h>
2359c8e88eSDag-Erling Smørgrav #include <string.h>
2459c8e88eSDag-Erling Smørgrav #include <assert.h>
2559c8e88eSDag-Erling Smørgrav
2659c8e88eSDag-Erling Smørgrav #include <arraylist.h>
2759c8e88eSDag-Erling Smørgrav #include <diff_main.h>
2859c8e88eSDag-Erling Smørgrav #include <diff_output.h>
2959c8e88eSDag-Erling Smørgrav
3059c8e88eSDag-Erling Smørgrav #include "diff_internal.h"
3159c8e88eSDag-Erling Smørgrav #include "diff_debug.h"
3259c8e88eSDag-Erling Smørgrav
3359c8e88eSDag-Erling Smørgrav off_t
diff_chunk_get_left_start_pos(const struct diff_chunk * c)3459c8e88eSDag-Erling Smørgrav diff_chunk_get_left_start_pos(const struct diff_chunk *c)
3559c8e88eSDag-Erling Smørgrav {
3659c8e88eSDag-Erling Smørgrav return c->left_start->pos;
3759c8e88eSDag-Erling Smørgrav }
3859c8e88eSDag-Erling Smørgrav
3959c8e88eSDag-Erling Smørgrav off_t
diff_chunk_get_right_start_pos(const struct diff_chunk * c)4059c8e88eSDag-Erling Smørgrav diff_chunk_get_right_start_pos(const struct diff_chunk *c)
4159c8e88eSDag-Erling Smørgrav {
4259c8e88eSDag-Erling Smørgrav return c->right_start->pos;
4359c8e88eSDag-Erling Smørgrav }
4459c8e88eSDag-Erling Smørgrav
4559c8e88eSDag-Erling Smørgrav bool
diff_chunk_context_empty(const struct diff_chunk_context * cc)4659c8e88eSDag-Erling Smørgrav diff_chunk_context_empty(const struct diff_chunk_context *cc)
4759c8e88eSDag-Erling Smørgrav {
4859c8e88eSDag-Erling Smørgrav return diff_range_empty(&cc->chunk);
4959c8e88eSDag-Erling Smørgrav }
5059c8e88eSDag-Erling Smørgrav
5159c8e88eSDag-Erling Smørgrav int
diff_chunk_get_left_start(const struct diff_chunk * c,const struct diff_result * r,int context_lines)5259c8e88eSDag-Erling Smørgrav diff_chunk_get_left_start(const struct diff_chunk *c,
5359c8e88eSDag-Erling Smørgrav const struct diff_result *r, int context_lines)
5459c8e88eSDag-Erling Smørgrav {
5559c8e88eSDag-Erling Smørgrav int left_start = diff_atom_root_idx(r->left, c->left_start);
5659c8e88eSDag-Erling Smørgrav return MAX(0, left_start - context_lines);
5759c8e88eSDag-Erling Smørgrav }
5859c8e88eSDag-Erling Smørgrav
5959c8e88eSDag-Erling Smørgrav int
diff_chunk_get_left_end(const struct diff_chunk * c,const struct diff_result * r,int context_lines)6059c8e88eSDag-Erling Smørgrav diff_chunk_get_left_end(const struct diff_chunk *c,
6159c8e88eSDag-Erling Smørgrav const struct diff_result *r, int context_lines)
6259c8e88eSDag-Erling Smørgrav {
6359c8e88eSDag-Erling Smørgrav int left_start = diff_chunk_get_left_start(c, r, 0);
6459c8e88eSDag-Erling Smørgrav return MIN(r->left->atoms.len,
6559c8e88eSDag-Erling Smørgrav left_start + c->left_count + context_lines);
6659c8e88eSDag-Erling Smørgrav }
6759c8e88eSDag-Erling Smørgrav
6859c8e88eSDag-Erling Smørgrav int
diff_chunk_get_right_start(const struct diff_chunk * c,const struct diff_result * r,int context_lines)6959c8e88eSDag-Erling Smørgrav diff_chunk_get_right_start(const struct diff_chunk *c,
7059c8e88eSDag-Erling Smørgrav const struct diff_result *r, int context_lines)
7159c8e88eSDag-Erling Smørgrav {
7259c8e88eSDag-Erling Smørgrav int right_start = diff_atom_root_idx(r->right, c->right_start);
7359c8e88eSDag-Erling Smørgrav return MAX(0, right_start - context_lines);
7459c8e88eSDag-Erling Smørgrav }
7559c8e88eSDag-Erling Smørgrav
7659c8e88eSDag-Erling Smørgrav int
diff_chunk_get_right_end(const struct diff_chunk * c,const struct diff_result * r,int context_lines)7759c8e88eSDag-Erling Smørgrav diff_chunk_get_right_end(const struct diff_chunk *c,
7859c8e88eSDag-Erling Smørgrav const struct diff_result *r, int context_lines)
7959c8e88eSDag-Erling Smørgrav {
8059c8e88eSDag-Erling Smørgrav int right_start = diff_chunk_get_right_start(c, r, 0);
8159c8e88eSDag-Erling Smørgrav return MIN(r->right->atoms.len,
8259c8e88eSDag-Erling Smørgrav right_start + c->right_count + context_lines);
8359c8e88eSDag-Erling Smørgrav }
8459c8e88eSDag-Erling Smørgrav
8559c8e88eSDag-Erling Smørgrav struct diff_chunk *
diff_chunk_get(const struct diff_result * r,int chunk_idx)8659c8e88eSDag-Erling Smørgrav diff_chunk_get(const struct diff_result *r, int chunk_idx)
8759c8e88eSDag-Erling Smørgrav {
8859c8e88eSDag-Erling Smørgrav return &r->chunks.head[chunk_idx];
8959c8e88eSDag-Erling Smørgrav }
9059c8e88eSDag-Erling Smørgrav
9159c8e88eSDag-Erling Smørgrav int
diff_chunk_get_left_count(struct diff_chunk * c)9259c8e88eSDag-Erling Smørgrav diff_chunk_get_left_count(struct diff_chunk *c)
9359c8e88eSDag-Erling Smørgrav {
9459c8e88eSDag-Erling Smørgrav return c->left_count;
9559c8e88eSDag-Erling Smørgrav }
9659c8e88eSDag-Erling Smørgrav
9759c8e88eSDag-Erling Smørgrav int
diff_chunk_get_right_count(struct diff_chunk * c)9859c8e88eSDag-Erling Smørgrav diff_chunk_get_right_count(struct diff_chunk *c)
9959c8e88eSDag-Erling Smørgrav {
10059c8e88eSDag-Erling Smørgrav return c->right_count;
10159c8e88eSDag-Erling Smørgrav }
10259c8e88eSDag-Erling Smørgrav
10359c8e88eSDag-Erling Smørgrav void
diff_chunk_context_get(struct diff_chunk_context * cc,const struct diff_result * r,int chunk_idx,int context_lines)10459c8e88eSDag-Erling Smørgrav diff_chunk_context_get(struct diff_chunk_context *cc, const struct diff_result *r,
10559c8e88eSDag-Erling Smørgrav int chunk_idx, int context_lines)
10659c8e88eSDag-Erling Smørgrav {
10759c8e88eSDag-Erling Smørgrav const struct diff_chunk *c = &r->chunks.head[chunk_idx];
10859c8e88eSDag-Erling Smørgrav int left_start = diff_chunk_get_left_start(c, r, context_lines);
10959c8e88eSDag-Erling Smørgrav int left_end = diff_chunk_get_left_end(c, r, context_lines);
11059c8e88eSDag-Erling Smørgrav int right_start = diff_chunk_get_right_start(c, r, context_lines);
11159c8e88eSDag-Erling Smørgrav int right_end = diff_chunk_get_right_end(c, r, context_lines);
11259c8e88eSDag-Erling Smørgrav
11359c8e88eSDag-Erling Smørgrav *cc = (struct diff_chunk_context){
11459c8e88eSDag-Erling Smørgrav .chunk = {
11559c8e88eSDag-Erling Smørgrav .start = chunk_idx,
11659c8e88eSDag-Erling Smørgrav .end = chunk_idx + 1,
11759c8e88eSDag-Erling Smørgrav },
11859c8e88eSDag-Erling Smørgrav .left = {
11959c8e88eSDag-Erling Smørgrav .start = left_start,
12059c8e88eSDag-Erling Smørgrav .end = left_end,
12159c8e88eSDag-Erling Smørgrav },
12259c8e88eSDag-Erling Smørgrav .right = {
12359c8e88eSDag-Erling Smørgrav .start = right_start,
12459c8e88eSDag-Erling Smørgrav .end = right_end,
12559c8e88eSDag-Erling Smørgrav },
12659c8e88eSDag-Erling Smørgrav };
12759c8e88eSDag-Erling Smørgrav }
12859c8e88eSDag-Erling Smørgrav
12959c8e88eSDag-Erling Smørgrav bool
diff_chunk_contexts_touch(const struct diff_chunk_context * cc,const struct diff_chunk_context * other)13059c8e88eSDag-Erling Smørgrav diff_chunk_contexts_touch(const struct diff_chunk_context *cc,
13159c8e88eSDag-Erling Smørgrav const struct diff_chunk_context *other)
13259c8e88eSDag-Erling Smørgrav {
13359c8e88eSDag-Erling Smørgrav return diff_ranges_touch(&cc->chunk, &other->chunk)
13459c8e88eSDag-Erling Smørgrav || diff_ranges_touch(&cc->left, &other->left)
13559c8e88eSDag-Erling Smørgrav || diff_ranges_touch(&cc->right, &other->right);
13659c8e88eSDag-Erling Smørgrav }
13759c8e88eSDag-Erling Smørgrav
13859c8e88eSDag-Erling Smørgrav void
diff_chunk_contexts_merge(struct diff_chunk_context * cc,const struct diff_chunk_context * other)13959c8e88eSDag-Erling Smørgrav diff_chunk_contexts_merge(struct diff_chunk_context *cc,
14059c8e88eSDag-Erling Smørgrav const struct diff_chunk_context *other)
14159c8e88eSDag-Erling Smørgrav {
14259c8e88eSDag-Erling Smørgrav diff_ranges_merge(&cc->chunk, &other->chunk);
14359c8e88eSDag-Erling Smørgrav diff_ranges_merge(&cc->left, &other->left);
14459c8e88eSDag-Erling Smørgrav diff_ranges_merge(&cc->right, &other->right);
14559c8e88eSDag-Erling Smørgrav }
14659c8e88eSDag-Erling Smørgrav
14759c8e88eSDag-Erling Smørgrav void
diff_chunk_context_load_change(struct diff_chunk_context * cc,int * nchunks_used,struct diff_result * result,int start_chunk_idx,int context_lines)14859c8e88eSDag-Erling Smørgrav diff_chunk_context_load_change(struct diff_chunk_context *cc,
14959c8e88eSDag-Erling Smørgrav int *nchunks_used,
15059c8e88eSDag-Erling Smørgrav struct diff_result *result,
15159c8e88eSDag-Erling Smørgrav int start_chunk_idx,
15259c8e88eSDag-Erling Smørgrav int context_lines)
15359c8e88eSDag-Erling Smørgrav {
15459c8e88eSDag-Erling Smørgrav int i;
15559c8e88eSDag-Erling Smørgrav int seen_minus = 0, seen_plus = 0;
15659c8e88eSDag-Erling Smørgrav
15759c8e88eSDag-Erling Smørgrav if (nchunks_used)
15859c8e88eSDag-Erling Smørgrav *nchunks_used = 0;
15959c8e88eSDag-Erling Smørgrav
16059c8e88eSDag-Erling Smørgrav for (i = start_chunk_idx; i < result->chunks.len; i++) {
16159c8e88eSDag-Erling Smørgrav struct diff_chunk *chunk = &result->chunks.head[i];
16259c8e88eSDag-Erling Smørgrav enum diff_chunk_type t = diff_chunk_type(chunk);
16359c8e88eSDag-Erling Smørgrav struct diff_chunk_context next;
16459c8e88eSDag-Erling Smørgrav
16559c8e88eSDag-Erling Smørgrav if (t != CHUNK_MINUS && t != CHUNK_PLUS) {
16659c8e88eSDag-Erling Smørgrav if (nchunks_used)
16759c8e88eSDag-Erling Smørgrav (*nchunks_used)++;
16859c8e88eSDag-Erling Smørgrav if (seen_minus || seen_plus)
16959c8e88eSDag-Erling Smørgrav break;
17059c8e88eSDag-Erling Smørgrav else
17159c8e88eSDag-Erling Smørgrav continue;
17259c8e88eSDag-Erling Smørgrav } else if (t == CHUNK_MINUS)
17359c8e88eSDag-Erling Smørgrav seen_minus = 1;
17459c8e88eSDag-Erling Smørgrav else if (t == CHUNK_PLUS)
17559c8e88eSDag-Erling Smørgrav seen_plus = 1;
17659c8e88eSDag-Erling Smørgrav
17759c8e88eSDag-Erling Smørgrav if (diff_chunk_context_empty(cc)) {
17859c8e88eSDag-Erling Smørgrav /* Note down the start point, any number of subsequent
17959c8e88eSDag-Erling Smørgrav * chunks may be joined up to this chunk by being
18059c8e88eSDag-Erling Smørgrav * directly adjacent. */
18159c8e88eSDag-Erling Smørgrav diff_chunk_context_get(cc, result, i, context_lines);
18259c8e88eSDag-Erling Smørgrav if (nchunks_used)
18359c8e88eSDag-Erling Smørgrav (*nchunks_used)++;
18459c8e88eSDag-Erling Smørgrav continue;
18559c8e88eSDag-Erling Smørgrav }
18659c8e88eSDag-Erling Smørgrav
18759c8e88eSDag-Erling Smørgrav /* There already is a previous chunk noted down for being
18859c8e88eSDag-Erling Smørgrav * printed. Does it join up with this one? */
18959c8e88eSDag-Erling Smørgrav diff_chunk_context_get(&next, result, i, context_lines);
19059c8e88eSDag-Erling Smørgrav
19159c8e88eSDag-Erling Smørgrav if (diff_chunk_contexts_touch(cc, &next)) {
19259c8e88eSDag-Erling Smørgrav /* This next context touches or overlaps the previous
19359c8e88eSDag-Erling Smørgrav * one, join. */
19459c8e88eSDag-Erling Smørgrav diff_chunk_contexts_merge(cc, &next);
19559c8e88eSDag-Erling Smørgrav if (nchunks_used)
19659c8e88eSDag-Erling Smørgrav (*nchunks_used)++;
19759c8e88eSDag-Erling Smørgrav continue;
19859c8e88eSDag-Erling Smørgrav } else
19959c8e88eSDag-Erling Smørgrav break;
20059c8e88eSDag-Erling Smørgrav }
20159c8e88eSDag-Erling Smørgrav }
20259c8e88eSDag-Erling Smørgrav
20359c8e88eSDag-Erling Smørgrav struct diff_output_unidiff_state {
20459c8e88eSDag-Erling Smørgrav bool header_printed;
20559c8e88eSDag-Erling Smørgrav char prototype[DIFF_FUNCTION_CONTEXT_SIZE];
20659c8e88eSDag-Erling Smørgrav int last_prototype_idx;
20759c8e88eSDag-Erling Smørgrav };
20859c8e88eSDag-Erling Smørgrav
20959c8e88eSDag-Erling Smørgrav struct diff_output_unidiff_state *
diff_output_unidiff_state_alloc(void)21059c8e88eSDag-Erling Smørgrav diff_output_unidiff_state_alloc(void)
21159c8e88eSDag-Erling Smørgrav {
21259c8e88eSDag-Erling Smørgrav struct diff_output_unidiff_state *state;
21359c8e88eSDag-Erling Smørgrav
21459c8e88eSDag-Erling Smørgrav state = calloc(1, sizeof(struct diff_output_unidiff_state));
21559c8e88eSDag-Erling Smørgrav if (state != NULL)
21659c8e88eSDag-Erling Smørgrav diff_output_unidiff_state_reset(state);
21759c8e88eSDag-Erling Smørgrav return state;
21859c8e88eSDag-Erling Smørgrav }
21959c8e88eSDag-Erling Smørgrav
22059c8e88eSDag-Erling Smørgrav void
diff_output_unidiff_state_reset(struct diff_output_unidiff_state * state)22159c8e88eSDag-Erling Smørgrav diff_output_unidiff_state_reset(struct diff_output_unidiff_state *state)
22259c8e88eSDag-Erling Smørgrav {
22359c8e88eSDag-Erling Smørgrav state->header_printed = false;
22459c8e88eSDag-Erling Smørgrav memset(state->prototype, 0, sizeof(state->prototype));
22559c8e88eSDag-Erling Smørgrav state->last_prototype_idx = 0;
22659c8e88eSDag-Erling Smørgrav }
22759c8e88eSDag-Erling Smørgrav
22859c8e88eSDag-Erling Smørgrav void
diff_output_unidiff_state_free(struct diff_output_unidiff_state * state)22959c8e88eSDag-Erling Smørgrav diff_output_unidiff_state_free(struct diff_output_unidiff_state *state)
23059c8e88eSDag-Erling Smørgrav {
23159c8e88eSDag-Erling Smørgrav free(state);
23259c8e88eSDag-Erling Smørgrav }
23359c8e88eSDag-Erling Smørgrav
23459c8e88eSDag-Erling Smørgrav static int
output_unidiff_chunk(struct diff_output_info * outinfo,FILE * dest,struct diff_output_unidiff_state * state,const struct diff_input_info * info,const struct diff_result * result,bool print_header,bool show_function_prototypes,const struct diff_chunk_context * cc)23559c8e88eSDag-Erling Smørgrav output_unidiff_chunk(struct diff_output_info *outinfo, FILE *dest,
23659c8e88eSDag-Erling Smørgrav struct diff_output_unidiff_state *state,
23759c8e88eSDag-Erling Smørgrav const struct diff_input_info *info,
23859c8e88eSDag-Erling Smørgrav const struct diff_result *result,
23959c8e88eSDag-Erling Smørgrav bool print_header, bool show_function_prototypes,
24059c8e88eSDag-Erling Smørgrav const struct diff_chunk_context *cc)
24159c8e88eSDag-Erling Smørgrav {
24259c8e88eSDag-Erling Smørgrav int rc, left_start, left_len, right_start, right_len;
24359c8e88eSDag-Erling Smørgrav off_t outoff = 0, *offp;
24459c8e88eSDag-Erling Smørgrav uint8_t *typep;
24559c8e88eSDag-Erling Smørgrav
24659c8e88eSDag-Erling Smørgrav if (diff_range_empty(&cc->left) && diff_range_empty(&cc->right))
24759c8e88eSDag-Erling Smørgrav return DIFF_RC_OK;
24859c8e88eSDag-Erling Smørgrav
24959c8e88eSDag-Erling Smørgrav if (outinfo && outinfo->line_offsets.len > 0) {
25059c8e88eSDag-Erling Smørgrav unsigned int idx = outinfo->line_offsets.len - 1;
25159c8e88eSDag-Erling Smørgrav outoff = outinfo->line_offsets.head[idx];
25259c8e88eSDag-Erling Smørgrav }
25359c8e88eSDag-Erling Smørgrav
25459c8e88eSDag-Erling Smørgrav if (print_header && !(state->header_printed)) {
25559c8e88eSDag-Erling Smørgrav rc = fprintf(dest, "--- %s\n",
25659c8e88eSDag-Erling Smørgrav diff_output_get_label_left(info));
25759c8e88eSDag-Erling Smørgrav if (rc < 0)
25859c8e88eSDag-Erling Smørgrav return errno;
25959c8e88eSDag-Erling Smørgrav if (outinfo) {
26059c8e88eSDag-Erling Smørgrav ARRAYLIST_ADD(offp, outinfo->line_offsets);
26159c8e88eSDag-Erling Smørgrav if (offp == NULL)
26259c8e88eSDag-Erling Smørgrav return ENOMEM;
26359c8e88eSDag-Erling Smørgrav outoff += rc;
26459c8e88eSDag-Erling Smørgrav *offp = outoff;
26559c8e88eSDag-Erling Smørgrav ARRAYLIST_ADD(typep, outinfo->line_types);
26659c8e88eSDag-Erling Smørgrav if (typep == NULL)
26759c8e88eSDag-Erling Smørgrav return ENOMEM;
26859c8e88eSDag-Erling Smørgrav *typep = DIFF_LINE_MINUS;
26959c8e88eSDag-Erling Smørgrav }
27059c8e88eSDag-Erling Smørgrav rc = fprintf(dest, "+++ %s\n",
27159c8e88eSDag-Erling Smørgrav diff_output_get_label_right(info));
27259c8e88eSDag-Erling Smørgrav if (rc < 0)
27359c8e88eSDag-Erling Smørgrav return errno;
27459c8e88eSDag-Erling Smørgrav if (outinfo) {
27559c8e88eSDag-Erling Smørgrav ARRAYLIST_ADD(offp, outinfo->line_offsets);
27659c8e88eSDag-Erling Smørgrav if (offp == NULL)
27759c8e88eSDag-Erling Smørgrav return ENOMEM;
27859c8e88eSDag-Erling Smørgrav outoff += rc;
27959c8e88eSDag-Erling Smørgrav *offp = outoff;
28059c8e88eSDag-Erling Smørgrav ARRAYLIST_ADD(typep, outinfo->line_types);
28159c8e88eSDag-Erling Smørgrav if (typep == NULL)
28259c8e88eSDag-Erling Smørgrav return ENOMEM;
28359c8e88eSDag-Erling Smørgrav *typep = DIFF_LINE_PLUS;
28459c8e88eSDag-Erling Smørgrav }
28559c8e88eSDag-Erling Smørgrav state->header_printed = true;
28659c8e88eSDag-Erling Smørgrav }
28759c8e88eSDag-Erling Smørgrav
28859c8e88eSDag-Erling Smørgrav left_len = cc->left.end - cc->left.start;
28959c8e88eSDag-Erling Smørgrav if (result->left->atoms.len == 0)
29059c8e88eSDag-Erling Smørgrav left_start = 0;
29159c8e88eSDag-Erling Smørgrav else if (left_len == 0 && cc->left.start > 0)
29259c8e88eSDag-Erling Smørgrav left_start = cc->left.start;
29359c8e88eSDag-Erling Smørgrav else
29459c8e88eSDag-Erling Smørgrav left_start = cc->left.start + 1;
29559c8e88eSDag-Erling Smørgrav
29659c8e88eSDag-Erling Smørgrav right_len = cc->right.end - cc->right.start;
29759c8e88eSDag-Erling Smørgrav if (result->right->atoms.len == 0)
29859c8e88eSDag-Erling Smørgrav right_start = 0;
29959c8e88eSDag-Erling Smørgrav else if (right_len == 0 && cc->right.start > 0)
30059c8e88eSDag-Erling Smørgrav right_start = cc->right.start;
30159c8e88eSDag-Erling Smørgrav else
30259c8e88eSDag-Erling Smørgrav right_start = cc->right.start + 1;
30359c8e88eSDag-Erling Smørgrav
3045fbe8912SDag-Erling Smørgrav /* Got the absolute line numbers where to start printing, and the index
3055fbe8912SDag-Erling Smørgrav * of the interesting (non-context) chunk.
3065fbe8912SDag-Erling Smørgrav * To print context lines above the interesting chunk, nipping on the
3075fbe8912SDag-Erling Smørgrav * previous chunk index may be necessary.
3085fbe8912SDag-Erling Smørgrav * It is guaranteed to be only context lines where left == right, so it
3095fbe8912SDag-Erling Smørgrav * suffices to look on the left. */
3105fbe8912SDag-Erling Smørgrav const struct diff_chunk *first_chunk;
3115fbe8912SDag-Erling Smørgrav int chunk_start_line;
3125fbe8912SDag-Erling Smørgrav first_chunk = &result->chunks.head[cc->chunk.start];
3135fbe8912SDag-Erling Smørgrav chunk_start_line = diff_atom_root_idx(result->left,
3145fbe8912SDag-Erling Smørgrav first_chunk->left_start);
31559c8e88eSDag-Erling Smørgrav if (show_function_prototypes) {
31659c8e88eSDag-Erling Smørgrav rc = diff_output_match_function_prototype(state->prototype,
31759c8e88eSDag-Erling Smørgrav sizeof(state->prototype), &state->last_prototype_idx,
3185fbe8912SDag-Erling Smørgrav result, chunk_start_line);
31959c8e88eSDag-Erling Smørgrav if (rc)
32059c8e88eSDag-Erling Smørgrav return rc;
32159c8e88eSDag-Erling Smørgrav }
32259c8e88eSDag-Erling Smørgrav
32359c8e88eSDag-Erling Smørgrav if (left_len == 1 && right_len == 1) {
32459c8e88eSDag-Erling Smørgrav rc = fprintf(dest, "@@ -%d +%d @@%s%s\n",
32559c8e88eSDag-Erling Smørgrav left_start, right_start,
32659c8e88eSDag-Erling Smørgrav state->prototype[0] ? " " : "",
32759c8e88eSDag-Erling Smørgrav state->prototype[0] ? state->prototype : "");
32859c8e88eSDag-Erling Smørgrav } else if (left_len == 1 && right_len != 1) {
32959c8e88eSDag-Erling Smørgrav rc = fprintf(dest, "@@ -%d +%d,%d @@%s%s\n",
33059c8e88eSDag-Erling Smørgrav left_start, right_start, right_len,
33159c8e88eSDag-Erling Smørgrav state->prototype[0] ? " " : "",
33259c8e88eSDag-Erling Smørgrav state->prototype[0] ? state->prototype : "");
33359c8e88eSDag-Erling Smørgrav } else if (left_len != 1 && right_len == 1) {
33459c8e88eSDag-Erling Smørgrav rc = fprintf(dest, "@@ -%d,%d +%d @@%s%s\n",
33559c8e88eSDag-Erling Smørgrav left_start, left_len, right_start,
33659c8e88eSDag-Erling Smørgrav state->prototype[0] ? " " : "",
33759c8e88eSDag-Erling Smørgrav state->prototype[0] ? state->prototype : "");
33859c8e88eSDag-Erling Smørgrav } else {
33959c8e88eSDag-Erling Smørgrav rc = fprintf(dest, "@@ -%d,%d +%d,%d @@%s%s\n",
34059c8e88eSDag-Erling Smørgrav left_start, left_len, right_start, right_len,
34159c8e88eSDag-Erling Smørgrav state->prototype[0] ? " " : "",
34259c8e88eSDag-Erling Smørgrav state->prototype[0] ? state->prototype : "");
34359c8e88eSDag-Erling Smørgrav }
34459c8e88eSDag-Erling Smørgrav if (rc < 0)
34559c8e88eSDag-Erling Smørgrav return errno;
34659c8e88eSDag-Erling Smørgrav if (outinfo) {
34759c8e88eSDag-Erling Smørgrav ARRAYLIST_ADD(offp, outinfo->line_offsets);
34859c8e88eSDag-Erling Smørgrav if (offp == NULL)
34959c8e88eSDag-Erling Smørgrav return ENOMEM;
35059c8e88eSDag-Erling Smørgrav outoff += rc;
35159c8e88eSDag-Erling Smørgrav *offp = outoff;
35259c8e88eSDag-Erling Smørgrav ARRAYLIST_ADD(typep, outinfo->line_types);
35359c8e88eSDag-Erling Smørgrav if (typep == NULL)
35459c8e88eSDag-Erling Smørgrav return ENOMEM;
35559c8e88eSDag-Erling Smørgrav *typep = DIFF_LINE_HUNK;
35659c8e88eSDag-Erling Smørgrav }
35759c8e88eSDag-Erling Smørgrav
35859c8e88eSDag-Erling Smørgrav if (cc->left.start < chunk_start_line) {
35959c8e88eSDag-Erling Smørgrav rc = diff_output_lines(outinfo, dest, " ",
36059c8e88eSDag-Erling Smørgrav &result->left->atoms.head[cc->left.start],
36159c8e88eSDag-Erling Smørgrav chunk_start_line - cc->left.start);
36259c8e88eSDag-Erling Smørgrav if (rc)
36359c8e88eSDag-Erling Smørgrav return rc;
36459c8e88eSDag-Erling Smørgrav }
36559c8e88eSDag-Erling Smørgrav
36659c8e88eSDag-Erling Smørgrav /* Now write out all the joined chunks and contexts between them */
36759c8e88eSDag-Erling Smørgrav int c_idx;
36859c8e88eSDag-Erling Smørgrav for (c_idx = cc->chunk.start; c_idx < cc->chunk.end; c_idx++) {
36959c8e88eSDag-Erling Smørgrav const struct diff_chunk *c = &result->chunks.head[c_idx];
37059c8e88eSDag-Erling Smørgrav
37159c8e88eSDag-Erling Smørgrav if (c->left_count && c->right_count)
37259c8e88eSDag-Erling Smørgrav rc = diff_output_lines(outinfo, dest,
37359c8e88eSDag-Erling Smørgrav c->solved ? " " : "?",
37459c8e88eSDag-Erling Smørgrav c->left_start, c->left_count);
37559c8e88eSDag-Erling Smørgrav else if (c->left_count && !c->right_count)
37659c8e88eSDag-Erling Smørgrav rc = diff_output_lines(outinfo, dest,
37759c8e88eSDag-Erling Smørgrav c->solved ? "-" : "?",
37859c8e88eSDag-Erling Smørgrav c->left_start, c->left_count);
37959c8e88eSDag-Erling Smørgrav else if (c->right_count && !c->left_count)
38059c8e88eSDag-Erling Smørgrav rc = diff_output_lines(outinfo, dest,
38159c8e88eSDag-Erling Smørgrav c->solved ? "+" : "?",
38259c8e88eSDag-Erling Smørgrav c->right_start, c->right_count);
38359c8e88eSDag-Erling Smørgrav if (rc)
38459c8e88eSDag-Erling Smørgrav return rc;
38559c8e88eSDag-Erling Smørgrav
38659c8e88eSDag-Erling Smørgrav if (cc->chunk.end == result->chunks.len) {
38759c8e88eSDag-Erling Smørgrav rc = diff_output_trailing_newline_msg(outinfo, dest, c);
38859c8e88eSDag-Erling Smørgrav if (rc != DIFF_RC_OK)
38959c8e88eSDag-Erling Smørgrav return rc;
39059c8e88eSDag-Erling Smørgrav }
39159c8e88eSDag-Erling Smørgrav }
39259c8e88eSDag-Erling Smørgrav
39359c8e88eSDag-Erling Smørgrav /* Trailing context? */
39459c8e88eSDag-Erling Smørgrav const struct diff_chunk *last_chunk;
39559c8e88eSDag-Erling Smørgrav int chunk_end_line;
39659c8e88eSDag-Erling Smørgrav last_chunk = &result->chunks.head[cc->chunk.end - 1];
39759c8e88eSDag-Erling Smørgrav chunk_end_line = diff_atom_root_idx(result->left,
39859c8e88eSDag-Erling Smørgrav last_chunk->left_start
39959c8e88eSDag-Erling Smørgrav + last_chunk->left_count);
40059c8e88eSDag-Erling Smørgrav if (cc->left.end > chunk_end_line) {
40159c8e88eSDag-Erling Smørgrav rc = diff_output_lines(outinfo, dest, " ",
40259c8e88eSDag-Erling Smørgrav &result->left->atoms.head[chunk_end_line],
40359c8e88eSDag-Erling Smørgrav cc->left.end - chunk_end_line);
40459c8e88eSDag-Erling Smørgrav if (rc)
40559c8e88eSDag-Erling Smørgrav return rc;
40659c8e88eSDag-Erling Smørgrav
40759c8e88eSDag-Erling Smørgrav if (cc->left.end == result->left->atoms.len) {
40859c8e88eSDag-Erling Smørgrav rc = diff_output_trailing_newline_msg(outinfo, dest,
40959c8e88eSDag-Erling Smørgrav &result->chunks.head[result->chunks.len - 1]);
41059c8e88eSDag-Erling Smørgrav if (rc != DIFF_RC_OK)
41159c8e88eSDag-Erling Smørgrav return rc;
41259c8e88eSDag-Erling Smørgrav }
41359c8e88eSDag-Erling Smørgrav }
41459c8e88eSDag-Erling Smørgrav
41559c8e88eSDag-Erling Smørgrav return DIFF_RC_OK;
41659c8e88eSDag-Erling Smørgrav }
41759c8e88eSDag-Erling Smørgrav
41859c8e88eSDag-Erling Smørgrav int
diff_output_unidiff_chunk(struct diff_output_info ** output_info,FILE * dest,struct diff_output_unidiff_state * state,const struct diff_input_info * info,const struct diff_result * result,const struct diff_chunk_context * cc)41959c8e88eSDag-Erling Smørgrav diff_output_unidiff_chunk(struct diff_output_info **output_info, FILE *dest,
42059c8e88eSDag-Erling Smørgrav struct diff_output_unidiff_state *state,
42159c8e88eSDag-Erling Smørgrav const struct diff_input_info *info,
42259c8e88eSDag-Erling Smørgrav const struct diff_result *result,
42359c8e88eSDag-Erling Smørgrav const struct diff_chunk_context *cc)
42459c8e88eSDag-Erling Smørgrav {
42559c8e88eSDag-Erling Smørgrav struct diff_output_info *outinfo = NULL;
42659c8e88eSDag-Erling Smørgrav int flags = (result->left->root->diff_flags |
42759c8e88eSDag-Erling Smørgrav result->right->root->diff_flags);
42859c8e88eSDag-Erling Smørgrav bool show_function_prototypes = (flags & DIFF_FLAG_SHOW_PROTOTYPES);
42959c8e88eSDag-Erling Smørgrav
43059c8e88eSDag-Erling Smørgrav if (output_info) {
43159c8e88eSDag-Erling Smørgrav *output_info = diff_output_info_alloc();
43259c8e88eSDag-Erling Smørgrav if (*output_info == NULL)
43359c8e88eSDag-Erling Smørgrav return ENOMEM;
43459c8e88eSDag-Erling Smørgrav outinfo = *output_info;
43559c8e88eSDag-Erling Smørgrav }
43659c8e88eSDag-Erling Smørgrav
43759c8e88eSDag-Erling Smørgrav return output_unidiff_chunk(outinfo, dest, state, info,
43859c8e88eSDag-Erling Smørgrav result, false, show_function_prototypes, cc);
43959c8e88eSDag-Erling Smørgrav }
44059c8e88eSDag-Erling Smørgrav
44159c8e88eSDag-Erling Smørgrav int
diff_output_unidiff(struct diff_output_info ** output_info,FILE * dest,const struct diff_input_info * info,const struct diff_result * result,unsigned int context_lines)44259c8e88eSDag-Erling Smørgrav diff_output_unidiff(struct diff_output_info **output_info,
44359c8e88eSDag-Erling Smørgrav FILE *dest, const struct diff_input_info *info,
44459c8e88eSDag-Erling Smørgrav const struct diff_result *result,
44559c8e88eSDag-Erling Smørgrav unsigned int context_lines)
44659c8e88eSDag-Erling Smørgrav {
44759c8e88eSDag-Erling Smørgrav struct diff_output_unidiff_state *state;
44859c8e88eSDag-Erling Smørgrav struct diff_chunk_context cc = {};
44959c8e88eSDag-Erling Smørgrav struct diff_output_info *outinfo = NULL;
45059c8e88eSDag-Erling Smørgrav int atomizer_flags = (result->left->atomizer_flags|
45159c8e88eSDag-Erling Smørgrav result->right->atomizer_flags);
45259c8e88eSDag-Erling Smørgrav int flags = (result->left->root->diff_flags |
45359c8e88eSDag-Erling Smørgrav result->right->root->diff_flags);
45459c8e88eSDag-Erling Smørgrav bool show_function_prototypes = (flags & DIFF_FLAG_SHOW_PROTOTYPES);
45559c8e88eSDag-Erling Smørgrav bool force_text = (flags & DIFF_FLAG_FORCE_TEXT_DATA);
45659c8e88eSDag-Erling Smørgrav bool have_binary = (atomizer_flags & DIFF_ATOMIZER_FOUND_BINARY_DATA);
45759c8e88eSDag-Erling Smørgrav off_t outoff = 0, *offp;
45859c8e88eSDag-Erling Smørgrav uint8_t *typep;
45959c8e88eSDag-Erling Smørgrav int rc, i;
46059c8e88eSDag-Erling Smørgrav
46159c8e88eSDag-Erling Smørgrav if (!result)
46259c8e88eSDag-Erling Smørgrav return EINVAL;
46359c8e88eSDag-Erling Smørgrav if (result->rc != DIFF_RC_OK)
46459c8e88eSDag-Erling Smørgrav return result->rc;
46559c8e88eSDag-Erling Smørgrav
46659c8e88eSDag-Erling Smørgrav if (output_info) {
46759c8e88eSDag-Erling Smørgrav *output_info = diff_output_info_alloc();
46859c8e88eSDag-Erling Smørgrav if (*output_info == NULL)
46959c8e88eSDag-Erling Smørgrav return ENOMEM;
47059c8e88eSDag-Erling Smørgrav outinfo = *output_info;
47159c8e88eSDag-Erling Smørgrav }
47259c8e88eSDag-Erling Smørgrav
47359c8e88eSDag-Erling Smørgrav if (have_binary && !force_text) {
47459c8e88eSDag-Erling Smørgrav for (i = 0; i < result->chunks.len; i++) {
47559c8e88eSDag-Erling Smørgrav struct diff_chunk *c = &result->chunks.head[i];
47659c8e88eSDag-Erling Smørgrav enum diff_chunk_type t = diff_chunk_type(c);
47759c8e88eSDag-Erling Smørgrav
47859c8e88eSDag-Erling Smørgrav if (t != CHUNK_MINUS && t != CHUNK_PLUS)
47959c8e88eSDag-Erling Smørgrav continue;
48059c8e88eSDag-Erling Smørgrav
48159c8e88eSDag-Erling Smørgrav if (outinfo && outinfo->line_offsets.len > 0) {
48259c8e88eSDag-Erling Smørgrav unsigned int idx =
48359c8e88eSDag-Erling Smørgrav outinfo->line_offsets.len - 1;
48459c8e88eSDag-Erling Smørgrav outoff = outinfo->line_offsets.head[idx];
48559c8e88eSDag-Erling Smørgrav }
48659c8e88eSDag-Erling Smørgrav
48759c8e88eSDag-Erling Smørgrav rc = fprintf(dest, "Binary files %s and %s differ\n",
48859c8e88eSDag-Erling Smørgrav diff_output_get_label_left(info),
48959c8e88eSDag-Erling Smørgrav diff_output_get_label_right(info));
49059c8e88eSDag-Erling Smørgrav if (outinfo) {
49159c8e88eSDag-Erling Smørgrav ARRAYLIST_ADD(offp, outinfo->line_offsets);
49259c8e88eSDag-Erling Smørgrav if (offp == NULL)
49359c8e88eSDag-Erling Smørgrav return ENOMEM;
49459c8e88eSDag-Erling Smørgrav outoff += rc;
49559c8e88eSDag-Erling Smørgrav *offp = outoff;
49659c8e88eSDag-Erling Smørgrav ARRAYLIST_ADD(typep, outinfo->line_types);
49759c8e88eSDag-Erling Smørgrav if (typep == NULL)
49859c8e88eSDag-Erling Smørgrav return ENOMEM;
49959c8e88eSDag-Erling Smørgrav *typep = DIFF_LINE_NONE;
50059c8e88eSDag-Erling Smørgrav }
50159c8e88eSDag-Erling Smørgrav break;
50259c8e88eSDag-Erling Smørgrav }
50359c8e88eSDag-Erling Smørgrav
50459c8e88eSDag-Erling Smørgrav return DIFF_RC_OK;
50559c8e88eSDag-Erling Smørgrav }
50659c8e88eSDag-Erling Smørgrav
50759c8e88eSDag-Erling Smørgrav state = diff_output_unidiff_state_alloc();
50859c8e88eSDag-Erling Smørgrav if (state == NULL) {
50959c8e88eSDag-Erling Smørgrav if (output_info) {
51059c8e88eSDag-Erling Smørgrav diff_output_info_free(*output_info);
51159c8e88eSDag-Erling Smørgrav *output_info = NULL;
51259c8e88eSDag-Erling Smørgrav }
51359c8e88eSDag-Erling Smørgrav return ENOMEM;
51459c8e88eSDag-Erling Smørgrav }
51559c8e88eSDag-Erling Smørgrav
51659c8e88eSDag-Erling Smørgrav #if DEBUG
51759c8e88eSDag-Erling Smørgrav unsigned int check_left_pos, check_right_pos;
51859c8e88eSDag-Erling Smørgrav check_left_pos = 0;
51959c8e88eSDag-Erling Smørgrav check_right_pos = 0;
52059c8e88eSDag-Erling Smørgrav for (i = 0; i < result->chunks.len; i++) {
52159c8e88eSDag-Erling Smørgrav struct diff_chunk *c = &result->chunks.head[i];
52259c8e88eSDag-Erling Smørgrav enum diff_chunk_type t = diff_chunk_type(c);
52359c8e88eSDag-Erling Smørgrav
52459c8e88eSDag-Erling Smørgrav debug("[%d] %s lines L%d R%d @L %d @R %d\n",
52559c8e88eSDag-Erling Smørgrav i, (t == CHUNK_MINUS ? "minus" :
52659c8e88eSDag-Erling Smørgrav (t == CHUNK_PLUS ? "plus" :
52759c8e88eSDag-Erling Smørgrav (t == CHUNK_SAME ? "same" : "?"))),
52859c8e88eSDag-Erling Smørgrav c->left_count,
52959c8e88eSDag-Erling Smørgrav c->right_count,
53059c8e88eSDag-Erling Smørgrav c->left_start ? diff_atom_root_idx(result->left, c->left_start) : -1,
53159c8e88eSDag-Erling Smørgrav c->right_start ? diff_atom_root_idx(result->right, c->right_start) : -1);
53259c8e88eSDag-Erling Smørgrav assert(check_left_pos == diff_atom_root_idx(result->left, c->left_start));
53359c8e88eSDag-Erling Smørgrav assert(check_right_pos == diff_atom_root_idx(result->right, c->right_start));
53459c8e88eSDag-Erling Smørgrav check_left_pos += c->left_count;
53559c8e88eSDag-Erling Smørgrav check_right_pos += c->right_count;
53659c8e88eSDag-Erling Smørgrav
53759c8e88eSDag-Erling Smørgrav }
53859c8e88eSDag-Erling Smørgrav assert(check_left_pos == result->left->atoms.len);
53959c8e88eSDag-Erling Smørgrav assert(check_right_pos == result->right->atoms.len);
54059c8e88eSDag-Erling Smørgrav #endif
54159c8e88eSDag-Erling Smørgrav
54259c8e88eSDag-Erling Smørgrav for (i = 0; i < result->chunks.len; i++) {
54359c8e88eSDag-Erling Smørgrav struct diff_chunk *c = &result->chunks.head[i];
54459c8e88eSDag-Erling Smørgrav enum diff_chunk_type t = diff_chunk_type(c);
54559c8e88eSDag-Erling Smørgrav struct diff_chunk_context next;
54659c8e88eSDag-Erling Smørgrav
54759c8e88eSDag-Erling Smørgrav if (t != CHUNK_MINUS && t != CHUNK_PLUS)
54859c8e88eSDag-Erling Smørgrav continue;
54959c8e88eSDag-Erling Smørgrav
55059c8e88eSDag-Erling Smørgrav if (diff_chunk_context_empty(&cc)) {
55159c8e88eSDag-Erling Smørgrav /* These are the first lines being printed.
55259c8e88eSDag-Erling Smørgrav * Note down the start point, any number of subsequent
55359c8e88eSDag-Erling Smørgrav * chunks may be joined up to this unidiff chunk by
55459c8e88eSDag-Erling Smørgrav * context lines or by being directly adjacent. */
55559c8e88eSDag-Erling Smørgrav diff_chunk_context_get(&cc, result, i, context_lines);
55659c8e88eSDag-Erling Smørgrav debug("new chunk to be printed:"
55759c8e88eSDag-Erling Smørgrav " chunk %d-%d left %d-%d right %d-%d\n",
55859c8e88eSDag-Erling Smørgrav cc.chunk.start, cc.chunk.end,
55959c8e88eSDag-Erling Smørgrav cc.left.start, cc.left.end,
56059c8e88eSDag-Erling Smørgrav cc.right.start, cc.right.end);
56159c8e88eSDag-Erling Smørgrav continue;
56259c8e88eSDag-Erling Smørgrav }
56359c8e88eSDag-Erling Smørgrav
56459c8e88eSDag-Erling Smørgrav /* There already is a previous chunk noted down for being
56559c8e88eSDag-Erling Smørgrav * printed. Does it join up with this one? */
56659c8e88eSDag-Erling Smørgrav diff_chunk_context_get(&next, result, i, context_lines);
56759c8e88eSDag-Erling Smørgrav debug("new chunk to be printed:"
56859c8e88eSDag-Erling Smørgrav " chunk %d-%d left %d-%d right %d-%d\n",
56959c8e88eSDag-Erling Smørgrav next.chunk.start, next.chunk.end,
57059c8e88eSDag-Erling Smørgrav next.left.start, next.left.end,
57159c8e88eSDag-Erling Smørgrav next.right.start, next.right.end);
57259c8e88eSDag-Erling Smørgrav
57359c8e88eSDag-Erling Smørgrav if (diff_chunk_contexts_touch(&cc, &next)) {
57459c8e88eSDag-Erling Smørgrav /* This next context touches or overlaps the previous
57559c8e88eSDag-Erling Smørgrav * one, join. */
57659c8e88eSDag-Erling Smørgrav diff_chunk_contexts_merge(&cc, &next);
57759c8e88eSDag-Erling Smørgrav debug("new chunk to be printed touches previous chunk,"
57859c8e88eSDag-Erling Smørgrav " now: left %d-%d right %d-%d\n",
57959c8e88eSDag-Erling Smørgrav cc.left.start, cc.left.end,
58059c8e88eSDag-Erling Smørgrav cc.right.start, cc.right.end);
58159c8e88eSDag-Erling Smørgrav continue;
58259c8e88eSDag-Erling Smørgrav }
58359c8e88eSDag-Erling Smørgrav
58459c8e88eSDag-Erling Smørgrav /* No touching, so the previous context is complete with a gap
58559c8e88eSDag-Erling Smørgrav * between it and this next one. Print the previous one and
58659c8e88eSDag-Erling Smørgrav * start fresh here. */
58759c8e88eSDag-Erling Smørgrav debug("new chunk to be printed does not touch previous chunk;"
58859c8e88eSDag-Erling Smørgrav " print left %d-%d right %d-%d\n",
58959c8e88eSDag-Erling Smørgrav cc.left.start, cc.left.end, cc.right.start, cc.right.end);
59059c8e88eSDag-Erling Smørgrav output_unidiff_chunk(outinfo, dest, state, info, result,
59159c8e88eSDag-Erling Smørgrav true, show_function_prototypes, &cc);
59259c8e88eSDag-Erling Smørgrav cc = next;
59359c8e88eSDag-Erling Smørgrav debug("new unprinted chunk is left %d-%d right %d-%d\n",
59459c8e88eSDag-Erling Smørgrav cc.left.start, cc.left.end, cc.right.start, cc.right.end);
59559c8e88eSDag-Erling Smørgrav }
59659c8e88eSDag-Erling Smørgrav
59759c8e88eSDag-Erling Smørgrav if (!diff_chunk_context_empty(&cc))
59859c8e88eSDag-Erling Smørgrav output_unidiff_chunk(outinfo, dest, state, info, result,
59959c8e88eSDag-Erling Smørgrav true, show_function_prototypes, &cc);
60059c8e88eSDag-Erling Smørgrav diff_output_unidiff_state_free(state);
60159c8e88eSDag-Erling Smørgrav return DIFF_RC_OK;
60259c8e88eSDag-Erling Smørgrav }
603