Path: blob/main/contrib/libdiff/lib/diff_output_edscript.c
35065 views
/* Produce ed(1) script output from a diff_result. */1/*2* Copyright (c) 2020 Neels Hofmeyr <[email protected]>3* Copyright (c) 2020 Stefan Sperling <[email protected]>4*5* Permission to use, copy, modify, and distribute this software for any6* purpose with or without fee is hereby granted, provided that the above7* copyright notice and this permission notice appear in all copies.8*9* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES10* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF11* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR12* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES13* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN14* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF15* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.16*/1718#include <errno.h>19#include <stdint.h>20#include <stdio.h>21#include <stdlib.h>22#include <stdbool.h>2324#include <arraylist.h>25#include <diff_main.h>26#include <diff_output.h>2728#include "diff_internal.h"2930static int31output_edscript_chunk(struct diff_output_info *outinfo,32FILE *dest, const struct diff_input_info *info,33const struct diff_result *result,34struct diff_chunk_context *cc)35{36off_t outoff = 0, *offp;37int left_start, left_len, right_start, right_len;38int rc;3940left_len = cc->left.end - cc->left.start;41if (left_len < 0)42return EINVAL;43else if (result->left->atoms.len == 0)44left_start = 0;45else if (left_len == 0 && cc->left.start > 0)46left_start = cc->left.start;47else if (cc->left.end > 0)48left_start = cc->left.start + 1;49else50left_start = cc->left.start;5152right_len = cc->right.end - cc->right.start;53if (right_len < 0)54return EINVAL;55else if (result->right->atoms.len == 0)56right_start = 0;57else if (right_len == 0 && cc->right.start > 0)58right_start = cc->right.start;59else if (cc->right.end > 0)60right_start = cc->right.start + 1;61else62right_start = cc->right.start;6364if (left_len == 0) {65/* addition */66if (right_len == 1) {67rc = fprintf(dest, "%da%d\n", left_start, right_start);68} else {69rc = fprintf(dest, "%da%d,%d\n", left_start,70right_start, cc->right.end);71}72} else if (right_len == 0) {73/* deletion */74if (left_len == 1) {75rc = fprintf(dest, "%dd%d\n", left_start,76right_start);77} else {78rc = fprintf(dest, "%d,%dd%d\n", left_start,79cc->left.end, right_start);80}81} else {82/* change */83if (left_len == 1 && right_len == 1) {84rc = fprintf(dest, "%dc%d\n", left_start, right_start);85} else if (left_len == 1) {86rc = fprintf(dest, "%dc%d,%d\n", left_start,87right_start, cc->right.end);88} else if (right_len == 1) {89rc = fprintf(dest, "%d,%dc%d\n", left_start,90cc->left.end, right_start);91} else {92rc = fprintf(dest, "%d,%dc%d,%d\n", left_start,93cc->left.end, right_start, cc->right.end);94}95}96if (rc < 0)97return errno;98if (outinfo) {99ARRAYLIST_ADD(offp, outinfo->line_offsets);100if (offp == NULL)101return ENOMEM;102outoff += rc;103*offp = outoff;104}105106return DIFF_RC_OK;107}108109int110diff_output_edscript(struct diff_output_info **output_info,111FILE *dest, const struct diff_input_info *info,112const struct diff_result *result)113{114struct diff_output_info *outinfo = NULL;115struct diff_chunk_context cc = {};116int atomizer_flags = (result->left->atomizer_flags|117result->right->atomizer_flags);118int flags = (result->left->root->diff_flags |119result->right->root->diff_flags);120bool force_text = (flags & DIFF_FLAG_FORCE_TEXT_DATA);121bool have_binary = (atomizer_flags & DIFF_ATOMIZER_FOUND_BINARY_DATA);122int i, rc;123124if (!result)125return EINVAL;126if (result->rc != DIFF_RC_OK)127return result->rc;128129if (output_info) {130*output_info = diff_output_info_alloc();131if (*output_info == NULL)132return ENOMEM;133outinfo = *output_info;134}135136if (have_binary && !force_text) {137for (i = 0; i < result->chunks.len; i++) {138struct diff_chunk *c = &result->chunks.head[i];139enum diff_chunk_type t = diff_chunk_type(c);140141if (t != CHUNK_MINUS && t != CHUNK_PLUS)142continue;143144fprintf(dest, "Binary files %s and %s differ\n",145diff_output_get_label_left(info),146diff_output_get_label_right(info));147break;148}149150return DIFF_RC_OK;151}152153for (i = 0; i < result->chunks.len; i++) {154struct diff_chunk *chunk = &result->chunks.head[i];155enum diff_chunk_type t = diff_chunk_type(chunk);156struct diff_chunk_context next;157158if (t != CHUNK_MINUS && t != CHUNK_PLUS)159continue;160161if (diff_chunk_context_empty(&cc)) {162/* Note down the start point, any number of subsequent163* chunks may be joined up to this chunk by being164* directly adjacent. */165diff_chunk_context_get(&cc, result, i, 0);166continue;167}168169/* There already is a previous chunk noted down for being170* printed. Does it join up with this one? */171diff_chunk_context_get(&next, result, i, 0);172173if (diff_chunk_contexts_touch(&cc, &next)) {174/* This next context touches or overlaps the previous175* one, join. */176diff_chunk_contexts_merge(&cc, &next);177continue;178}179180rc = output_edscript_chunk(outinfo, dest, info, result, &cc);181if (rc != DIFF_RC_OK)182return rc;183cc = next;184}185186if (!diff_chunk_context_empty(&cc))187return output_edscript_chunk(outinfo, dest, info, result, &cc);188return DIFF_RC_OK;189}190191192