1*59c8e88eSDag-Erling Smørgrav /* Generic infrastructure to implement various diff algorithms (implementation). */ 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 19*59c8e88eSDag-Erling Smørgrav #include <sys/queue.h> 20*59c8e88eSDag-Erling Smørgrav #include <ctype.h> 21*59c8e88eSDag-Erling Smørgrav #include <errno.h> 22*59c8e88eSDag-Erling Smørgrav #include <stdint.h> 23*59c8e88eSDag-Erling Smørgrav #include <stdlib.h> 24*59c8e88eSDag-Erling Smørgrav #include <stdbool.h> 25*59c8e88eSDag-Erling Smørgrav #include <stdio.h> 26*59c8e88eSDag-Erling Smørgrav #include <string.h> 27*59c8e88eSDag-Erling Smørgrav #include <limits.h> 28*59c8e88eSDag-Erling Smørgrav #include <unistd.h> 29*59c8e88eSDag-Erling Smørgrav 30*59c8e88eSDag-Erling Smørgrav #include <assert.h> 31*59c8e88eSDag-Erling Smørgrav 32*59c8e88eSDag-Erling Smørgrav #include <arraylist.h> 33*59c8e88eSDag-Erling Smørgrav #include <diff_main.h> 34*59c8e88eSDag-Erling Smørgrav 35*59c8e88eSDag-Erling Smørgrav #include "diff_internal.h" 36*59c8e88eSDag-Erling Smørgrav #include "diff_debug.h" 37*59c8e88eSDag-Erling Smørgrav 38*59c8e88eSDag-Erling Smørgrav inline enum diff_chunk_type 39*59c8e88eSDag-Erling Smørgrav diff_chunk_type(const struct diff_chunk *chunk) 40*59c8e88eSDag-Erling Smørgrav { 41*59c8e88eSDag-Erling Smørgrav if (!chunk->left_count && !chunk->right_count) 42*59c8e88eSDag-Erling Smørgrav return CHUNK_EMPTY; 43*59c8e88eSDag-Erling Smørgrav if (!chunk->solved) 44*59c8e88eSDag-Erling Smørgrav return CHUNK_ERROR; 45*59c8e88eSDag-Erling Smørgrav if (!chunk->right_count) 46*59c8e88eSDag-Erling Smørgrav return CHUNK_MINUS; 47*59c8e88eSDag-Erling Smørgrav if (!chunk->left_count) 48*59c8e88eSDag-Erling Smørgrav return CHUNK_PLUS; 49*59c8e88eSDag-Erling Smørgrav if (chunk->left_count != chunk->right_count) 50*59c8e88eSDag-Erling Smørgrav return CHUNK_ERROR; 51*59c8e88eSDag-Erling Smørgrav return CHUNK_SAME; 52*59c8e88eSDag-Erling Smørgrav } 53*59c8e88eSDag-Erling Smørgrav 54*59c8e88eSDag-Erling Smørgrav static int 55*59c8e88eSDag-Erling Smørgrav read_at(FILE *f, off_t at_pos, unsigned char *buf, size_t len) 56*59c8e88eSDag-Erling Smørgrav { 57*59c8e88eSDag-Erling Smørgrav int r; 58*59c8e88eSDag-Erling Smørgrav if (fseeko(f, at_pos, SEEK_SET) == -1) 59*59c8e88eSDag-Erling Smørgrav return errno; 60*59c8e88eSDag-Erling Smørgrav r = fread(buf, sizeof(char), len, f); 61*59c8e88eSDag-Erling Smørgrav if ((r == 0 || r < len) && ferror(f)) 62*59c8e88eSDag-Erling Smørgrav return EIO; 63*59c8e88eSDag-Erling Smørgrav if (r != len) 64*59c8e88eSDag-Erling Smørgrav return EIO; 65*59c8e88eSDag-Erling Smørgrav return 0; 66*59c8e88eSDag-Erling Smørgrav } 67*59c8e88eSDag-Erling Smørgrav 68*59c8e88eSDag-Erling Smørgrav static int 69*59c8e88eSDag-Erling Smørgrav buf_cmp(const unsigned char *left, size_t left_len, 70*59c8e88eSDag-Erling Smørgrav const unsigned char *right, size_t right_len, 71*59c8e88eSDag-Erling Smørgrav bool ignore_whitespace) 72*59c8e88eSDag-Erling Smørgrav { 73*59c8e88eSDag-Erling Smørgrav int cmp; 74*59c8e88eSDag-Erling Smørgrav 75*59c8e88eSDag-Erling Smørgrav if (ignore_whitespace) { 76*59c8e88eSDag-Erling Smørgrav int il = 0, ir = 0; 77*59c8e88eSDag-Erling Smørgrav while (il < left_len && ir < right_len) { 78*59c8e88eSDag-Erling Smørgrav unsigned char cl = left[il]; 79*59c8e88eSDag-Erling Smørgrav unsigned char cr = right[ir]; 80*59c8e88eSDag-Erling Smørgrav 81*59c8e88eSDag-Erling Smørgrav if (isspace((unsigned char)cl) && il < left_len) { 82*59c8e88eSDag-Erling Smørgrav il++; 83*59c8e88eSDag-Erling Smørgrav continue; 84*59c8e88eSDag-Erling Smørgrav } 85*59c8e88eSDag-Erling Smørgrav if (isspace((unsigned char)cr) && ir < right_len) { 86*59c8e88eSDag-Erling Smørgrav ir++; 87*59c8e88eSDag-Erling Smørgrav continue; 88*59c8e88eSDag-Erling Smørgrav } 89*59c8e88eSDag-Erling Smørgrav 90*59c8e88eSDag-Erling Smørgrav if (cl > cr) 91*59c8e88eSDag-Erling Smørgrav return 1; 92*59c8e88eSDag-Erling Smørgrav if (cr > cl) 93*59c8e88eSDag-Erling Smørgrav return -1; 94*59c8e88eSDag-Erling Smørgrav il++; 95*59c8e88eSDag-Erling Smørgrav ir++; 96*59c8e88eSDag-Erling Smørgrav } 97*59c8e88eSDag-Erling Smørgrav while (il < left_len) { 98*59c8e88eSDag-Erling Smørgrav unsigned char cl = left[il++]; 99*59c8e88eSDag-Erling Smørgrav if (!isspace((unsigned char)cl)) 100*59c8e88eSDag-Erling Smørgrav return 1; 101*59c8e88eSDag-Erling Smørgrav } 102*59c8e88eSDag-Erling Smørgrav while (ir < right_len) { 103*59c8e88eSDag-Erling Smørgrav unsigned char cr = right[ir++]; 104*59c8e88eSDag-Erling Smørgrav if (!isspace((unsigned char)cr)) 105*59c8e88eSDag-Erling Smørgrav return -1; 106*59c8e88eSDag-Erling Smørgrav } 107*59c8e88eSDag-Erling Smørgrav 108*59c8e88eSDag-Erling Smørgrav return 0; 109*59c8e88eSDag-Erling Smørgrav } 110*59c8e88eSDag-Erling Smørgrav 111*59c8e88eSDag-Erling Smørgrav cmp = memcmp(left, right, MIN(left_len, right_len)); 112*59c8e88eSDag-Erling Smørgrav if (cmp) 113*59c8e88eSDag-Erling Smørgrav return cmp; 114*59c8e88eSDag-Erling Smørgrav if (left_len == right_len) 115*59c8e88eSDag-Erling Smørgrav return 0; 116*59c8e88eSDag-Erling Smørgrav return (left_len > right_len) ? 1 : -1; 117*59c8e88eSDag-Erling Smørgrav } 118*59c8e88eSDag-Erling Smørgrav 119*59c8e88eSDag-Erling Smørgrav int 120*59c8e88eSDag-Erling Smørgrav diff_atom_cmp(int *cmp, 121*59c8e88eSDag-Erling Smørgrav const struct diff_atom *left, 122*59c8e88eSDag-Erling Smørgrav const struct diff_atom *right) 123*59c8e88eSDag-Erling Smørgrav { 124*59c8e88eSDag-Erling Smørgrav off_t remain_left, remain_right; 125*59c8e88eSDag-Erling Smørgrav int flags = (left->root->diff_flags | right->root->diff_flags); 126*59c8e88eSDag-Erling Smørgrav bool ignore_whitespace = (flags & DIFF_FLAG_IGNORE_WHITESPACE); 127*59c8e88eSDag-Erling Smørgrav 128*59c8e88eSDag-Erling Smørgrav if (!left->len && !right->len) { 129*59c8e88eSDag-Erling Smørgrav *cmp = 0; 130*59c8e88eSDag-Erling Smørgrav return 0; 131*59c8e88eSDag-Erling Smørgrav } 132*59c8e88eSDag-Erling Smørgrav if (!ignore_whitespace) { 133*59c8e88eSDag-Erling Smørgrav if (!right->len) { 134*59c8e88eSDag-Erling Smørgrav *cmp = 1; 135*59c8e88eSDag-Erling Smørgrav return 0; 136*59c8e88eSDag-Erling Smørgrav } 137*59c8e88eSDag-Erling Smørgrav if (!left->len) { 138*59c8e88eSDag-Erling Smørgrav *cmp = -1; 139*59c8e88eSDag-Erling Smørgrav return 0; 140*59c8e88eSDag-Erling Smørgrav } 141*59c8e88eSDag-Erling Smørgrav } 142*59c8e88eSDag-Erling Smørgrav 143*59c8e88eSDag-Erling Smørgrav if (left->at != NULL && right->at != NULL) { 144*59c8e88eSDag-Erling Smørgrav *cmp = buf_cmp(left->at, left->len, right->at, right->len, 145*59c8e88eSDag-Erling Smørgrav ignore_whitespace); 146*59c8e88eSDag-Erling Smørgrav return 0; 147*59c8e88eSDag-Erling Smørgrav } 148*59c8e88eSDag-Erling Smørgrav 149*59c8e88eSDag-Erling Smørgrav remain_left = left->len; 150*59c8e88eSDag-Erling Smørgrav remain_right = right->len; 151*59c8e88eSDag-Erling Smørgrav while (remain_left > 0 || remain_right > 0) { 152*59c8e88eSDag-Erling Smørgrav const size_t chunksz = 8192; 153*59c8e88eSDag-Erling Smørgrav unsigned char buf_left[chunksz], buf_right[chunksz]; 154*59c8e88eSDag-Erling Smørgrav const uint8_t *p_left, *p_right; 155*59c8e88eSDag-Erling Smørgrav off_t n_left, n_right; 156*59c8e88eSDag-Erling Smørgrav ssize_t r; 157*59c8e88eSDag-Erling Smørgrav 158*59c8e88eSDag-Erling Smørgrav if (!remain_right) { 159*59c8e88eSDag-Erling Smørgrav *cmp = 1; 160*59c8e88eSDag-Erling Smørgrav return 0; 161*59c8e88eSDag-Erling Smørgrav } 162*59c8e88eSDag-Erling Smørgrav if (!remain_left) { 163*59c8e88eSDag-Erling Smørgrav *cmp = -1; 164*59c8e88eSDag-Erling Smørgrav return 0; 165*59c8e88eSDag-Erling Smørgrav } 166*59c8e88eSDag-Erling Smørgrav 167*59c8e88eSDag-Erling Smørgrav n_left = MIN(chunksz, remain_left); 168*59c8e88eSDag-Erling Smørgrav n_right = MIN(chunksz, remain_right); 169*59c8e88eSDag-Erling Smørgrav 170*59c8e88eSDag-Erling Smørgrav if (left->at == NULL) { 171*59c8e88eSDag-Erling Smørgrav r = read_at(left->root->f, 172*59c8e88eSDag-Erling Smørgrav left->pos + (left->len - remain_left), 173*59c8e88eSDag-Erling Smørgrav buf_left, n_left); 174*59c8e88eSDag-Erling Smørgrav if (r) { 175*59c8e88eSDag-Erling Smørgrav *cmp = 0; 176*59c8e88eSDag-Erling Smørgrav return r; 177*59c8e88eSDag-Erling Smørgrav } 178*59c8e88eSDag-Erling Smørgrav p_left = buf_left; 179*59c8e88eSDag-Erling Smørgrav } else { 180*59c8e88eSDag-Erling Smørgrav p_left = left->at + (left->len - remain_left); 181*59c8e88eSDag-Erling Smørgrav } 182*59c8e88eSDag-Erling Smørgrav 183*59c8e88eSDag-Erling Smørgrav if (right->at == NULL) { 184*59c8e88eSDag-Erling Smørgrav r = read_at(right->root->f, 185*59c8e88eSDag-Erling Smørgrav right->pos + (right->len - remain_right), 186*59c8e88eSDag-Erling Smørgrav buf_right, n_right); 187*59c8e88eSDag-Erling Smørgrav if (r) { 188*59c8e88eSDag-Erling Smørgrav *cmp = 0; 189*59c8e88eSDag-Erling Smørgrav return r; 190*59c8e88eSDag-Erling Smørgrav } 191*59c8e88eSDag-Erling Smørgrav p_right = buf_right; 192*59c8e88eSDag-Erling Smørgrav } else { 193*59c8e88eSDag-Erling Smørgrav p_right = right->at + (right->len - remain_right); 194*59c8e88eSDag-Erling Smørgrav } 195*59c8e88eSDag-Erling Smørgrav 196*59c8e88eSDag-Erling Smørgrav r = buf_cmp(p_left, n_left, p_right, n_right, 197*59c8e88eSDag-Erling Smørgrav ignore_whitespace); 198*59c8e88eSDag-Erling Smørgrav if (r) { 199*59c8e88eSDag-Erling Smørgrav *cmp = r; 200*59c8e88eSDag-Erling Smørgrav return 0; 201*59c8e88eSDag-Erling Smørgrav } 202*59c8e88eSDag-Erling Smørgrav 203*59c8e88eSDag-Erling Smørgrav remain_left -= n_left; 204*59c8e88eSDag-Erling Smørgrav remain_right -= n_right; 205*59c8e88eSDag-Erling Smørgrav } 206*59c8e88eSDag-Erling Smørgrav 207*59c8e88eSDag-Erling Smørgrav *cmp = 0; 208*59c8e88eSDag-Erling Smørgrav return 0; 209*59c8e88eSDag-Erling Smørgrav } 210*59c8e88eSDag-Erling Smørgrav 211*59c8e88eSDag-Erling Smørgrav int 212*59c8e88eSDag-Erling Smørgrav diff_atom_same(bool *same, 213*59c8e88eSDag-Erling Smørgrav const struct diff_atom *left, 214*59c8e88eSDag-Erling Smørgrav const struct diff_atom *right) 215*59c8e88eSDag-Erling Smørgrav { 216*59c8e88eSDag-Erling Smørgrav int cmp; 217*59c8e88eSDag-Erling Smørgrav int r; 218*59c8e88eSDag-Erling Smørgrav if (left->hash != right->hash) { 219*59c8e88eSDag-Erling Smørgrav *same = false; 220*59c8e88eSDag-Erling Smørgrav return 0; 221*59c8e88eSDag-Erling Smørgrav } 222*59c8e88eSDag-Erling Smørgrav r = diff_atom_cmp(&cmp, left, right); 223*59c8e88eSDag-Erling Smørgrav if (r) { 224*59c8e88eSDag-Erling Smørgrav *same = true; 225*59c8e88eSDag-Erling Smørgrav return r; 226*59c8e88eSDag-Erling Smørgrav } 227*59c8e88eSDag-Erling Smørgrav *same = (cmp == 0); 228*59c8e88eSDag-Erling Smørgrav return 0; 229*59c8e88eSDag-Erling Smørgrav } 230*59c8e88eSDag-Erling Smørgrav 231*59c8e88eSDag-Erling Smørgrav static struct diff_chunk * 232*59c8e88eSDag-Erling Smørgrav diff_state_add_solved_chunk(struct diff_state *state, 233*59c8e88eSDag-Erling Smørgrav const struct diff_chunk *chunk) 234*59c8e88eSDag-Erling Smørgrav { 235*59c8e88eSDag-Erling Smørgrav diff_chunk_arraylist_t *result; 236*59c8e88eSDag-Erling Smørgrav struct diff_chunk *new_chunk; 237*59c8e88eSDag-Erling Smørgrav enum diff_chunk_type last_t; 238*59c8e88eSDag-Erling Smørgrav enum diff_chunk_type new_t; 239*59c8e88eSDag-Erling Smørgrav struct diff_chunk *last; 240*59c8e88eSDag-Erling Smørgrav 241*59c8e88eSDag-Erling Smørgrav /* Append to solved chunks; make sure that adjacent chunks of same type are combined, and that a minus chunk 242*59c8e88eSDag-Erling Smørgrav * never directly follows a plus chunk. */ 243*59c8e88eSDag-Erling Smørgrav result = &state->result->chunks; 244*59c8e88eSDag-Erling Smørgrav 245*59c8e88eSDag-Erling Smørgrav last_t = result->len ? diff_chunk_type(&result->head[result->len - 1]) 246*59c8e88eSDag-Erling Smørgrav : CHUNK_EMPTY; 247*59c8e88eSDag-Erling Smørgrav new_t = diff_chunk_type(chunk); 248*59c8e88eSDag-Erling Smørgrav 249*59c8e88eSDag-Erling Smørgrav debug("ADD %s chunk #%u:\n", chunk->solved ? "solved" : "UNSOLVED", 250*59c8e88eSDag-Erling Smørgrav result->len); 251*59c8e88eSDag-Erling Smørgrav debug("L\n"); 252*59c8e88eSDag-Erling Smørgrav debug_dump_atoms(&state->left, chunk->left_start, chunk->left_count); 253*59c8e88eSDag-Erling Smørgrav debug("R\n"); 254*59c8e88eSDag-Erling Smørgrav debug_dump_atoms(&state->right, chunk->right_start, chunk->right_count); 255*59c8e88eSDag-Erling Smørgrav 256*59c8e88eSDag-Erling Smørgrav if (result->len) { 257*59c8e88eSDag-Erling Smørgrav last = &result->head[result->len - 1]; 258*59c8e88eSDag-Erling Smørgrav assert(chunk->left_start 259*59c8e88eSDag-Erling Smørgrav == last->left_start + last->left_count); 260*59c8e88eSDag-Erling Smørgrav assert(chunk->right_start 261*59c8e88eSDag-Erling Smørgrav == last->right_start + last->right_count); 262*59c8e88eSDag-Erling Smørgrav } 263*59c8e88eSDag-Erling Smørgrav 264*59c8e88eSDag-Erling Smørgrav if (new_t == last_t) { 265*59c8e88eSDag-Erling Smørgrav new_chunk = &result->head[result->len - 1]; 266*59c8e88eSDag-Erling Smørgrav new_chunk->left_count += chunk->left_count; 267*59c8e88eSDag-Erling Smørgrav new_chunk->right_count += chunk->right_count; 268*59c8e88eSDag-Erling Smørgrav debug(" - added chunk touches previous one of same type, joined:\n"); 269*59c8e88eSDag-Erling Smørgrav debug("L\n"); 270*59c8e88eSDag-Erling Smørgrav debug_dump_atoms(&state->left, new_chunk->left_start, new_chunk->left_count); 271*59c8e88eSDag-Erling Smørgrav debug("R\n"); 272*59c8e88eSDag-Erling Smørgrav debug_dump_atoms(&state->right, new_chunk->right_start, new_chunk->right_count); 273*59c8e88eSDag-Erling Smørgrav } else if (last_t == CHUNK_PLUS && new_t == CHUNK_MINUS) { 274*59c8e88eSDag-Erling Smørgrav enum diff_chunk_type prev_last_t = 275*59c8e88eSDag-Erling Smørgrav result->len > 1 ? 276*59c8e88eSDag-Erling Smørgrav diff_chunk_type(&result->head[result->len - 2]) 277*59c8e88eSDag-Erling Smørgrav : CHUNK_EMPTY; 278*59c8e88eSDag-Erling Smørgrav /* If a minus-chunk follows a plus-chunk, place it above the plus-chunk-> 279*59c8e88eSDag-Erling Smørgrav * Is the one before that also a minus? combine. */ 280*59c8e88eSDag-Erling Smørgrav if (prev_last_t == CHUNK_MINUS) { 281*59c8e88eSDag-Erling Smørgrav new_chunk = &result->head[result->len - 2]; 282*59c8e88eSDag-Erling Smørgrav new_chunk->left_count += chunk->left_count; 283*59c8e88eSDag-Erling Smørgrav new_chunk->right_count += chunk->right_count; 284*59c8e88eSDag-Erling Smørgrav 285*59c8e88eSDag-Erling Smørgrav debug(" - added minus-chunk follows plus-chunk," 286*59c8e88eSDag-Erling Smørgrav " put before that plus-chunk and joined" 287*59c8e88eSDag-Erling Smørgrav " with preceding minus-chunk:\n"); 288*59c8e88eSDag-Erling Smørgrav debug("L\n"); 289*59c8e88eSDag-Erling Smørgrav debug_dump_atoms(&state->left, new_chunk->left_start, new_chunk->left_count); 290*59c8e88eSDag-Erling Smørgrav debug("R\n"); 291*59c8e88eSDag-Erling Smørgrav debug_dump_atoms(&state->right, new_chunk->right_start, new_chunk->right_count); 292*59c8e88eSDag-Erling Smørgrav } else { 293*59c8e88eSDag-Erling Smørgrav ARRAYLIST_INSERT(new_chunk, *result, result->len - 1); 294*59c8e88eSDag-Erling Smørgrav if (!new_chunk) 295*59c8e88eSDag-Erling Smørgrav return NULL; 296*59c8e88eSDag-Erling Smørgrav *new_chunk = *chunk; 297*59c8e88eSDag-Erling Smørgrav 298*59c8e88eSDag-Erling Smørgrav /* The new minus chunk indicates to which position on 299*59c8e88eSDag-Erling Smørgrav * the right it corresponds, even though it doesn't add 300*59c8e88eSDag-Erling Smørgrav * any lines on the right. By moving above a plus chunk, 301*59c8e88eSDag-Erling Smørgrav * that position on the right has shifted. */ 302*59c8e88eSDag-Erling Smørgrav last = &result->head[result->len - 1]; 303*59c8e88eSDag-Erling Smørgrav new_chunk->right_start = last->right_start; 304*59c8e88eSDag-Erling Smørgrav 305*59c8e88eSDag-Erling Smørgrav debug(" - added minus-chunk follows plus-chunk," 306*59c8e88eSDag-Erling Smørgrav " put before that plus-chunk\n"); 307*59c8e88eSDag-Erling Smørgrav } 308*59c8e88eSDag-Erling Smørgrav 309*59c8e88eSDag-Erling Smørgrav /* That last_t == CHUNK_PLUS indicates to which position on the 310*59c8e88eSDag-Erling Smørgrav * left it corresponds, even though it doesn't add any lines on 311*59c8e88eSDag-Erling Smørgrav * the left. By inserting/extending the prev_last_t == 312*59c8e88eSDag-Erling Smørgrav * CHUNK_MINUS, that position on the left has shifted. */ 313*59c8e88eSDag-Erling Smørgrav last = &result->head[result->len - 1]; 314*59c8e88eSDag-Erling Smørgrav last->left_start = new_chunk->left_start 315*59c8e88eSDag-Erling Smørgrav + new_chunk->left_count; 316*59c8e88eSDag-Erling Smørgrav 317*59c8e88eSDag-Erling Smørgrav } else { 318*59c8e88eSDag-Erling Smørgrav ARRAYLIST_ADD(new_chunk, *result); 319*59c8e88eSDag-Erling Smørgrav if (!new_chunk) 320*59c8e88eSDag-Erling Smørgrav return NULL; 321*59c8e88eSDag-Erling Smørgrav *new_chunk = *chunk; 322*59c8e88eSDag-Erling Smørgrav } 323*59c8e88eSDag-Erling Smørgrav return new_chunk; 324*59c8e88eSDag-Erling Smørgrav } 325*59c8e88eSDag-Erling Smørgrav 326*59c8e88eSDag-Erling Smørgrav /* Even if a left or right side is empty, diff output may need to know the 327*59c8e88eSDag-Erling Smørgrav * position in that file. 328*59c8e88eSDag-Erling Smørgrav * So left_start or right_start must never be NULL -- pass left_count or 329*59c8e88eSDag-Erling Smørgrav * right_count as zero to indicate staying at that position without consuming 330*59c8e88eSDag-Erling Smørgrav * any lines. */ 331*59c8e88eSDag-Erling Smørgrav struct diff_chunk * 332*59c8e88eSDag-Erling Smørgrav diff_state_add_chunk(struct diff_state *state, bool solved, 333*59c8e88eSDag-Erling Smørgrav struct diff_atom *left_start, unsigned int left_count, 334*59c8e88eSDag-Erling Smørgrav struct diff_atom *right_start, unsigned int right_count) 335*59c8e88eSDag-Erling Smørgrav { 336*59c8e88eSDag-Erling Smørgrav struct diff_chunk *new_chunk; 337*59c8e88eSDag-Erling Smørgrav struct diff_chunk chunk = { 338*59c8e88eSDag-Erling Smørgrav .solved = solved, 339*59c8e88eSDag-Erling Smørgrav .left_start = left_start, 340*59c8e88eSDag-Erling Smørgrav .left_count = left_count, 341*59c8e88eSDag-Erling Smørgrav .right_start = right_start, 342*59c8e88eSDag-Erling Smørgrav .right_count = right_count, 343*59c8e88eSDag-Erling Smørgrav }; 344*59c8e88eSDag-Erling Smørgrav 345*59c8e88eSDag-Erling Smørgrav /* An unsolved chunk means store as intermediate result for later 346*59c8e88eSDag-Erling Smørgrav * re-iteration. 347*59c8e88eSDag-Erling Smørgrav * If there already are intermediate results, that means even a 348*59c8e88eSDag-Erling Smørgrav * following solved chunk needs to go to intermediate results, so that 349*59c8e88eSDag-Erling Smørgrav * it is later put in the final correct position in solved chunks. 350*59c8e88eSDag-Erling Smørgrav */ 351*59c8e88eSDag-Erling Smørgrav if (!solved || state->temp_result.len) { 352*59c8e88eSDag-Erling Smørgrav /* Append to temp_result */ 353*59c8e88eSDag-Erling Smørgrav debug("ADD %s chunk to temp result:\n", 354*59c8e88eSDag-Erling Smørgrav chunk.solved ? "solved" : "UNSOLVED"); 355*59c8e88eSDag-Erling Smørgrav debug("L\n"); 356*59c8e88eSDag-Erling Smørgrav debug_dump_atoms(&state->left, left_start, left_count); 357*59c8e88eSDag-Erling Smørgrav debug("R\n"); 358*59c8e88eSDag-Erling Smørgrav debug_dump_atoms(&state->right, right_start, right_count); 359*59c8e88eSDag-Erling Smørgrav ARRAYLIST_ADD(new_chunk, state->temp_result); 360*59c8e88eSDag-Erling Smørgrav if (!new_chunk) 361*59c8e88eSDag-Erling Smørgrav return NULL; 362*59c8e88eSDag-Erling Smørgrav *new_chunk = chunk; 363*59c8e88eSDag-Erling Smørgrav return new_chunk; 364*59c8e88eSDag-Erling Smørgrav } 365*59c8e88eSDag-Erling Smørgrav 366*59c8e88eSDag-Erling Smørgrav return diff_state_add_solved_chunk(state, &chunk); 367*59c8e88eSDag-Erling Smørgrav } 368*59c8e88eSDag-Erling Smørgrav 369*59c8e88eSDag-Erling Smørgrav static void 370*59c8e88eSDag-Erling Smørgrav diff_data_init_root(struct diff_data *d, FILE *f, const uint8_t *data, 371*59c8e88eSDag-Erling Smørgrav unsigned long long len, int diff_flags) 372*59c8e88eSDag-Erling Smørgrav { 373*59c8e88eSDag-Erling Smørgrav *d = (struct diff_data){ 374*59c8e88eSDag-Erling Smørgrav .f = f, 375*59c8e88eSDag-Erling Smørgrav .pos = 0, 376*59c8e88eSDag-Erling Smørgrav .data = data, 377*59c8e88eSDag-Erling Smørgrav .len = len, 378*59c8e88eSDag-Erling Smørgrav .root = d, 379*59c8e88eSDag-Erling Smørgrav .diff_flags = diff_flags, 380*59c8e88eSDag-Erling Smørgrav }; 381*59c8e88eSDag-Erling Smørgrav } 382*59c8e88eSDag-Erling Smørgrav 383*59c8e88eSDag-Erling Smørgrav void 384*59c8e88eSDag-Erling Smørgrav diff_data_init_subsection(struct diff_data *d, struct diff_data *parent, 385*59c8e88eSDag-Erling Smørgrav struct diff_atom *from_atom, unsigned int atoms_count) 386*59c8e88eSDag-Erling Smørgrav { 387*59c8e88eSDag-Erling Smørgrav struct diff_atom *last_atom; 388*59c8e88eSDag-Erling Smørgrav 389*59c8e88eSDag-Erling Smørgrav debug("diff_data %p parent %p from_atom %p atoms_count %u\n", 390*59c8e88eSDag-Erling Smørgrav d, parent, from_atom, atoms_count); 391*59c8e88eSDag-Erling Smørgrav debug(" from_atom "); 392*59c8e88eSDag-Erling Smørgrav debug_dump_atom(parent, NULL, from_atom); 393*59c8e88eSDag-Erling Smørgrav 394*59c8e88eSDag-Erling Smørgrav if (atoms_count == 0) { 395*59c8e88eSDag-Erling Smørgrav *d = (struct diff_data){ 396*59c8e88eSDag-Erling Smørgrav .f = NULL, 397*59c8e88eSDag-Erling Smørgrav .pos = 0, 398*59c8e88eSDag-Erling Smørgrav .data = NULL, 399*59c8e88eSDag-Erling Smørgrav .len = 0, 400*59c8e88eSDag-Erling Smørgrav .root = parent->root, 401*59c8e88eSDag-Erling Smørgrav .atoms.head = NULL, 402*59c8e88eSDag-Erling Smørgrav .atoms.len = atoms_count, 403*59c8e88eSDag-Erling Smørgrav }; 404*59c8e88eSDag-Erling Smørgrav 405*59c8e88eSDag-Erling Smørgrav return; 406*59c8e88eSDag-Erling Smørgrav } 407*59c8e88eSDag-Erling Smørgrav 408*59c8e88eSDag-Erling Smørgrav last_atom = from_atom + atoms_count - 1; 409*59c8e88eSDag-Erling Smørgrav *d = (struct diff_data){ 410*59c8e88eSDag-Erling Smørgrav .f = NULL, 411*59c8e88eSDag-Erling Smørgrav .pos = from_atom->pos, 412*59c8e88eSDag-Erling Smørgrav .data = from_atom->at, 413*59c8e88eSDag-Erling Smørgrav .len = (last_atom->pos + last_atom->len) - from_atom->pos, 414*59c8e88eSDag-Erling Smørgrav .root = parent->root, 415*59c8e88eSDag-Erling Smørgrav .atoms.head = from_atom, 416*59c8e88eSDag-Erling Smørgrav .atoms.len = atoms_count, 417*59c8e88eSDag-Erling Smørgrav }; 418*59c8e88eSDag-Erling Smørgrav 419*59c8e88eSDag-Erling Smørgrav debug("subsection:\n"); 420*59c8e88eSDag-Erling Smørgrav debug_dump(d); 421*59c8e88eSDag-Erling Smørgrav } 422*59c8e88eSDag-Erling Smørgrav 423*59c8e88eSDag-Erling Smørgrav void 424*59c8e88eSDag-Erling Smørgrav diff_data_free(struct diff_data *diff_data) 425*59c8e88eSDag-Erling Smørgrav { 426*59c8e88eSDag-Erling Smørgrav if (!diff_data) 427*59c8e88eSDag-Erling Smørgrav return; 428*59c8e88eSDag-Erling Smørgrav if (diff_data->atoms.allocated) 429*59c8e88eSDag-Erling Smørgrav ARRAYLIST_FREE(diff_data->atoms); 430*59c8e88eSDag-Erling Smørgrav } 431*59c8e88eSDag-Erling Smørgrav 432*59c8e88eSDag-Erling Smørgrav int 433*59c8e88eSDag-Erling Smørgrav diff_algo_none(const struct diff_algo_config *algo_config, 434*59c8e88eSDag-Erling Smørgrav struct diff_state *state) 435*59c8e88eSDag-Erling Smørgrav { 436*59c8e88eSDag-Erling Smørgrav debug("\n** %s\n", __func__); 437*59c8e88eSDag-Erling Smørgrav debug("left:\n"); 438*59c8e88eSDag-Erling Smørgrav debug_dump(&state->left); 439*59c8e88eSDag-Erling Smørgrav debug("right:\n"); 440*59c8e88eSDag-Erling Smørgrav debug_dump(&state->right); 441*59c8e88eSDag-Erling Smørgrav debug_dump_myers_graph(&state->left, &state->right, NULL, NULL, 0, NULL, 442*59c8e88eSDag-Erling Smørgrav 0); 443*59c8e88eSDag-Erling Smørgrav 444*59c8e88eSDag-Erling Smørgrav /* Add a chunk of equal lines, if any */ 445*59c8e88eSDag-Erling Smørgrav struct diff_atom *l = state->left.atoms.head; 446*59c8e88eSDag-Erling Smørgrav unsigned int l_len = state->left.atoms.len; 447*59c8e88eSDag-Erling Smørgrav struct diff_atom *r = state->right.atoms.head; 448*59c8e88eSDag-Erling Smørgrav unsigned int r_len = state->right.atoms.len; 449*59c8e88eSDag-Erling Smørgrav unsigned int equal_atoms_start = 0; 450*59c8e88eSDag-Erling Smørgrav unsigned int equal_atoms_end = 0; 451*59c8e88eSDag-Erling Smørgrav unsigned int l_idx = 0; 452*59c8e88eSDag-Erling Smørgrav unsigned int r_idx = 0; 453*59c8e88eSDag-Erling Smørgrav 454*59c8e88eSDag-Erling Smørgrav while (equal_atoms_start < l_len 455*59c8e88eSDag-Erling Smørgrav && equal_atoms_start < r_len) { 456*59c8e88eSDag-Erling Smørgrav int err; 457*59c8e88eSDag-Erling Smørgrav bool same; 458*59c8e88eSDag-Erling Smørgrav err = diff_atom_same(&same, &l[equal_atoms_start], 459*59c8e88eSDag-Erling Smørgrav &r[equal_atoms_start]); 460*59c8e88eSDag-Erling Smørgrav if (err) 461*59c8e88eSDag-Erling Smørgrav return err; 462*59c8e88eSDag-Erling Smørgrav if (!same) 463*59c8e88eSDag-Erling Smørgrav break; 464*59c8e88eSDag-Erling Smørgrav equal_atoms_start++; 465*59c8e88eSDag-Erling Smørgrav } 466*59c8e88eSDag-Erling Smørgrav while (equal_atoms_end < (l_len - equal_atoms_start) 467*59c8e88eSDag-Erling Smørgrav && equal_atoms_end < (r_len - equal_atoms_start)) { 468*59c8e88eSDag-Erling Smørgrav int err; 469*59c8e88eSDag-Erling Smørgrav bool same; 470*59c8e88eSDag-Erling Smørgrav err = diff_atom_same(&same, &l[l_len - 1 - equal_atoms_end], 471*59c8e88eSDag-Erling Smørgrav &r[r_len - 1 - equal_atoms_end]); 472*59c8e88eSDag-Erling Smørgrav if (err) 473*59c8e88eSDag-Erling Smørgrav return err; 474*59c8e88eSDag-Erling Smørgrav if (!same) 475*59c8e88eSDag-Erling Smørgrav break; 476*59c8e88eSDag-Erling Smørgrav equal_atoms_end++; 477*59c8e88eSDag-Erling Smørgrav } 478*59c8e88eSDag-Erling Smørgrav 479*59c8e88eSDag-Erling Smørgrav /* Add a chunk of equal lines at the start */ 480*59c8e88eSDag-Erling Smørgrav if (equal_atoms_start) { 481*59c8e88eSDag-Erling Smørgrav if (!diff_state_add_chunk(state, true, 482*59c8e88eSDag-Erling Smørgrav l, equal_atoms_start, 483*59c8e88eSDag-Erling Smørgrav r, equal_atoms_start)) 484*59c8e88eSDag-Erling Smørgrav return ENOMEM; 485*59c8e88eSDag-Erling Smørgrav l_idx += equal_atoms_start; 486*59c8e88eSDag-Erling Smørgrav r_idx += equal_atoms_start; 487*59c8e88eSDag-Erling Smørgrav } 488*59c8e88eSDag-Erling Smørgrav 489*59c8e88eSDag-Erling Smørgrav /* Add a "minus" chunk with all lines from the left. */ 490*59c8e88eSDag-Erling Smørgrav if (equal_atoms_start + equal_atoms_end < l_len) { 491*59c8e88eSDag-Erling Smørgrav unsigned int add_len = l_len - equal_atoms_start - equal_atoms_end; 492*59c8e88eSDag-Erling Smørgrav if (!diff_state_add_chunk(state, true, 493*59c8e88eSDag-Erling Smørgrav &l[l_idx], add_len, 494*59c8e88eSDag-Erling Smørgrav &r[r_idx], 0)) 495*59c8e88eSDag-Erling Smørgrav return ENOMEM; 496*59c8e88eSDag-Erling Smørgrav l_idx += add_len; 497*59c8e88eSDag-Erling Smørgrav } 498*59c8e88eSDag-Erling Smørgrav 499*59c8e88eSDag-Erling Smørgrav /* Add a "plus" chunk with all lines from the right. */ 500*59c8e88eSDag-Erling Smørgrav if (equal_atoms_start + equal_atoms_end < r_len) { 501*59c8e88eSDag-Erling Smørgrav unsigned int add_len = r_len - equal_atoms_start - equal_atoms_end; 502*59c8e88eSDag-Erling Smørgrav if (!diff_state_add_chunk(state, true, 503*59c8e88eSDag-Erling Smørgrav &l[l_idx], 0, 504*59c8e88eSDag-Erling Smørgrav &r[r_idx], add_len)) 505*59c8e88eSDag-Erling Smørgrav return ENOMEM; 506*59c8e88eSDag-Erling Smørgrav r_idx += add_len; 507*59c8e88eSDag-Erling Smørgrav } 508*59c8e88eSDag-Erling Smørgrav 509*59c8e88eSDag-Erling Smørgrav /* Add a chunk of equal lines at the end */ 510*59c8e88eSDag-Erling Smørgrav if (equal_atoms_end) { 511*59c8e88eSDag-Erling Smørgrav if (!diff_state_add_chunk(state, true, 512*59c8e88eSDag-Erling Smørgrav &l[l_idx], equal_atoms_end, 513*59c8e88eSDag-Erling Smørgrav &r[r_idx], equal_atoms_end)) 514*59c8e88eSDag-Erling Smørgrav return ENOMEM; 515*59c8e88eSDag-Erling Smørgrav } 516*59c8e88eSDag-Erling Smørgrav 517*59c8e88eSDag-Erling Smørgrav return DIFF_RC_OK; 518*59c8e88eSDag-Erling Smørgrav } 519*59c8e88eSDag-Erling Smørgrav 520*59c8e88eSDag-Erling Smørgrav static int 521*59c8e88eSDag-Erling Smørgrav diff_run_algo(const struct diff_algo_config *algo_config, 522*59c8e88eSDag-Erling Smørgrav struct diff_state *state) 523*59c8e88eSDag-Erling Smørgrav { 524*59c8e88eSDag-Erling Smørgrav int rc; 525*59c8e88eSDag-Erling Smørgrav 526*59c8e88eSDag-Erling Smørgrav if (!algo_config || !algo_config->impl 527*59c8e88eSDag-Erling Smørgrav || !state->recursion_depth_left 528*59c8e88eSDag-Erling Smørgrav || !state->left.atoms.len || !state->right.atoms.len) { 529*59c8e88eSDag-Erling Smørgrav debug("Fall back to diff_algo_none():%s%s%s\n", 530*59c8e88eSDag-Erling Smørgrav (!algo_config || !algo_config->impl) ? " no-cfg" : "", 531*59c8e88eSDag-Erling Smørgrav (!state->recursion_depth_left) ? " max-depth" : "", 532*59c8e88eSDag-Erling Smørgrav (!state->left.atoms.len || !state->right.atoms.len)? 533*59c8e88eSDag-Erling Smørgrav " trivial" : ""); 534*59c8e88eSDag-Erling Smørgrav return diff_algo_none(algo_config, state); 535*59c8e88eSDag-Erling Smørgrav } 536*59c8e88eSDag-Erling Smørgrav 537*59c8e88eSDag-Erling Smørgrav ARRAYLIST_FREE(state->temp_result); 538*59c8e88eSDag-Erling Smørgrav ARRAYLIST_INIT(state->temp_result, DIFF_RESULT_ALLOC_BLOCKSIZE); 539*59c8e88eSDag-Erling Smørgrav rc = algo_config->impl(algo_config, state); 540*59c8e88eSDag-Erling Smørgrav switch (rc) { 541*59c8e88eSDag-Erling Smørgrav case DIFF_RC_USE_DIFF_ALGO_FALLBACK: 542*59c8e88eSDag-Erling Smørgrav debug("Got DIFF_RC_USE_DIFF_ALGO_FALLBACK (%p)\n", 543*59c8e88eSDag-Erling Smørgrav algo_config->fallback_algo); 544*59c8e88eSDag-Erling Smørgrav rc = diff_run_algo(algo_config->fallback_algo, state); 545*59c8e88eSDag-Erling Smørgrav goto return_rc; 546*59c8e88eSDag-Erling Smørgrav 547*59c8e88eSDag-Erling Smørgrav case DIFF_RC_OK: 548*59c8e88eSDag-Erling Smørgrav /* continue below */ 549*59c8e88eSDag-Erling Smørgrav break; 550*59c8e88eSDag-Erling Smørgrav 551*59c8e88eSDag-Erling Smørgrav default: 552*59c8e88eSDag-Erling Smørgrav /* some error happened */ 553*59c8e88eSDag-Erling Smørgrav goto return_rc; 554*59c8e88eSDag-Erling Smørgrav } 555*59c8e88eSDag-Erling Smørgrav 556*59c8e88eSDag-Erling Smørgrav /* Pick up any diff chunks that are still unsolved and feed to 557*59c8e88eSDag-Erling Smørgrav * inner_algo. inner_algo will solve unsolved chunks and append to 558*59c8e88eSDag-Erling Smørgrav * result, and subsequent solved chunks on this level are then appended 559*59c8e88eSDag-Erling Smørgrav * to result afterwards. */ 560*59c8e88eSDag-Erling Smørgrav int i; 561*59c8e88eSDag-Erling Smørgrav for (i = 0; i < state->temp_result.len; i++) { 562*59c8e88eSDag-Erling Smørgrav struct diff_chunk *c = &state->temp_result.head[i]; 563*59c8e88eSDag-Erling Smørgrav if (c->solved) { 564*59c8e88eSDag-Erling Smørgrav diff_state_add_solved_chunk(state, c); 565*59c8e88eSDag-Erling Smørgrav continue; 566*59c8e88eSDag-Erling Smørgrav } 567*59c8e88eSDag-Erling Smørgrav 568*59c8e88eSDag-Erling Smørgrav /* c is an unsolved chunk, feed to inner_algo */ 569*59c8e88eSDag-Erling Smørgrav struct diff_state inner_state = { 570*59c8e88eSDag-Erling Smørgrav .result = state->result, 571*59c8e88eSDag-Erling Smørgrav .recursion_depth_left = state->recursion_depth_left - 1, 572*59c8e88eSDag-Erling Smørgrav .kd_buf = state->kd_buf, 573*59c8e88eSDag-Erling Smørgrav .kd_buf_size = state->kd_buf_size, 574*59c8e88eSDag-Erling Smørgrav }; 575*59c8e88eSDag-Erling Smørgrav diff_data_init_subsection(&inner_state.left, &state->left, 576*59c8e88eSDag-Erling Smørgrav c->left_start, c->left_count); 577*59c8e88eSDag-Erling Smørgrav diff_data_init_subsection(&inner_state.right, &state->right, 578*59c8e88eSDag-Erling Smørgrav c->right_start, c->right_count); 579*59c8e88eSDag-Erling Smørgrav 580*59c8e88eSDag-Erling Smørgrav rc = diff_run_algo(algo_config->inner_algo, &inner_state); 581*59c8e88eSDag-Erling Smørgrav state->kd_buf = inner_state.kd_buf; 582*59c8e88eSDag-Erling Smørgrav state->kd_buf_size = inner_state.kd_buf_size; 583*59c8e88eSDag-Erling Smørgrav if (rc != DIFF_RC_OK) 584*59c8e88eSDag-Erling Smørgrav goto return_rc; 585*59c8e88eSDag-Erling Smørgrav } 586*59c8e88eSDag-Erling Smørgrav 587*59c8e88eSDag-Erling Smørgrav rc = DIFF_RC_OK; 588*59c8e88eSDag-Erling Smørgrav return_rc: 589*59c8e88eSDag-Erling Smørgrav ARRAYLIST_FREE(state->temp_result); 590*59c8e88eSDag-Erling Smørgrav return rc; 591*59c8e88eSDag-Erling Smørgrav } 592*59c8e88eSDag-Erling Smørgrav 593*59c8e88eSDag-Erling Smørgrav int 594*59c8e88eSDag-Erling Smørgrav diff_atomize_file(struct diff_data *d, 595*59c8e88eSDag-Erling Smørgrav const struct diff_config *config, 596*59c8e88eSDag-Erling Smørgrav FILE *f, const uint8_t *data, off_t len, int diff_flags) 597*59c8e88eSDag-Erling Smørgrav { 598*59c8e88eSDag-Erling Smørgrav if (!config->atomize_func) 599*59c8e88eSDag-Erling Smørgrav return EINVAL; 600*59c8e88eSDag-Erling Smørgrav 601*59c8e88eSDag-Erling Smørgrav diff_data_init_root(d, f, data, len, diff_flags); 602*59c8e88eSDag-Erling Smørgrav 603*59c8e88eSDag-Erling Smørgrav return config->atomize_func(config->atomize_func_data, d); 604*59c8e88eSDag-Erling Smørgrav 605*59c8e88eSDag-Erling Smørgrav } 606*59c8e88eSDag-Erling Smørgrav 607*59c8e88eSDag-Erling Smørgrav struct diff_result * 608*59c8e88eSDag-Erling Smørgrav diff_main(const struct diff_config *config, struct diff_data *left, 609*59c8e88eSDag-Erling Smørgrav struct diff_data *right) 610*59c8e88eSDag-Erling Smørgrav { 611*59c8e88eSDag-Erling Smørgrav struct diff_result *result = malloc(sizeof(struct diff_result)); 612*59c8e88eSDag-Erling Smørgrav if (!result) 613*59c8e88eSDag-Erling Smørgrav return NULL; 614*59c8e88eSDag-Erling Smørgrav 615*59c8e88eSDag-Erling Smørgrav *result = (struct diff_result){}; 616*59c8e88eSDag-Erling Smørgrav result->left = left; 617*59c8e88eSDag-Erling Smørgrav result->right = right; 618*59c8e88eSDag-Erling Smørgrav 619*59c8e88eSDag-Erling Smørgrav struct diff_state state = { 620*59c8e88eSDag-Erling Smørgrav .result = result, 621*59c8e88eSDag-Erling Smørgrav .recursion_depth_left = config->max_recursion_depth ? 622*59c8e88eSDag-Erling Smørgrav config->max_recursion_depth : UINT_MAX, 623*59c8e88eSDag-Erling Smørgrav .kd_buf = NULL, 624*59c8e88eSDag-Erling Smørgrav .kd_buf_size = 0, 625*59c8e88eSDag-Erling Smørgrav }; 626*59c8e88eSDag-Erling Smørgrav diff_data_init_subsection(&state.left, left, 627*59c8e88eSDag-Erling Smørgrav left->atoms.head, 628*59c8e88eSDag-Erling Smørgrav left->atoms.len); 629*59c8e88eSDag-Erling Smørgrav diff_data_init_subsection(&state.right, right, 630*59c8e88eSDag-Erling Smørgrav right->atoms.head, 631*59c8e88eSDag-Erling Smørgrav right->atoms.len); 632*59c8e88eSDag-Erling Smørgrav 633*59c8e88eSDag-Erling Smørgrav result->rc = diff_run_algo(config->algo, &state); 634*59c8e88eSDag-Erling Smørgrav free(state.kd_buf); 635*59c8e88eSDag-Erling Smørgrav 636*59c8e88eSDag-Erling Smørgrav return result; 637*59c8e88eSDag-Erling Smørgrav } 638*59c8e88eSDag-Erling Smørgrav 639*59c8e88eSDag-Erling Smørgrav void 640*59c8e88eSDag-Erling Smørgrav diff_result_free(struct diff_result *result) 641*59c8e88eSDag-Erling Smørgrav { 642*59c8e88eSDag-Erling Smørgrav if (!result) 643*59c8e88eSDag-Erling Smørgrav return; 644*59c8e88eSDag-Erling Smørgrav ARRAYLIST_FREE(result->chunks); 645*59c8e88eSDag-Erling Smørgrav free(result); 646*59c8e88eSDag-Erling Smørgrav } 647*59c8e88eSDag-Erling Smørgrav 648*59c8e88eSDag-Erling Smørgrav int 649*59c8e88eSDag-Erling Smørgrav diff_result_contains_printable_chunks(struct diff_result *result) 650*59c8e88eSDag-Erling Smørgrav { 651*59c8e88eSDag-Erling Smørgrav struct diff_chunk *c; 652*59c8e88eSDag-Erling Smørgrav enum diff_chunk_type t; 653*59c8e88eSDag-Erling Smørgrav int i; 654*59c8e88eSDag-Erling Smørgrav 655*59c8e88eSDag-Erling Smørgrav for (i = 0; i < result->chunks.len; i++) { 656*59c8e88eSDag-Erling Smørgrav c = &result->chunks.head[i]; 657*59c8e88eSDag-Erling Smørgrav t = diff_chunk_type(c); 658*59c8e88eSDag-Erling Smørgrav if (t == CHUNK_MINUS || t == CHUNK_PLUS) 659*59c8e88eSDag-Erling Smørgrav return 1; 660*59c8e88eSDag-Erling Smørgrav } 661*59c8e88eSDag-Erling Smørgrav 662*59c8e88eSDag-Erling Smørgrav return 0; 663*59c8e88eSDag-Erling Smørgrav } 664