1*59c8e88eSDag-Erling Smørgrav /* Implementation of the Patience Diff algorithm invented by Bram Cohen: 2*59c8e88eSDag-Erling Smørgrav * Divide a diff problem into smaller chunks by an LCS (Longest Common Sequence) 3*59c8e88eSDag-Erling Smørgrav * of common-unique lines. */ 4*59c8e88eSDag-Erling Smørgrav /* 5*59c8e88eSDag-Erling Smørgrav * Copyright (c) 2020 Neels Hofmeyr <neels@hofmeyr.de> 6*59c8e88eSDag-Erling Smørgrav * 7*59c8e88eSDag-Erling Smørgrav * Permission to use, copy, modify, and distribute this software for any 8*59c8e88eSDag-Erling Smørgrav * purpose with or without fee is hereby granted, provided that the above 9*59c8e88eSDag-Erling Smørgrav * copyright notice and this permission notice appear in all copies. 10*59c8e88eSDag-Erling Smørgrav * 11*59c8e88eSDag-Erling Smørgrav * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12*59c8e88eSDag-Erling Smørgrav * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13*59c8e88eSDag-Erling Smørgrav * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14*59c8e88eSDag-Erling Smørgrav * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15*59c8e88eSDag-Erling Smørgrav * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16*59c8e88eSDag-Erling Smørgrav * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17*59c8e88eSDag-Erling Smørgrav * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18*59c8e88eSDag-Erling Smørgrav */ 19*59c8e88eSDag-Erling Smørgrav 20*59c8e88eSDag-Erling Smørgrav #include <assert.h> 21*59c8e88eSDag-Erling Smørgrav #include <errno.h> 22*59c8e88eSDag-Erling Smørgrav #include <stdbool.h> 23*59c8e88eSDag-Erling Smørgrav #include <stdint.h> 24*59c8e88eSDag-Erling Smørgrav #include <stdio.h> 25*59c8e88eSDag-Erling Smørgrav #include <stdlib.h> 26*59c8e88eSDag-Erling Smørgrav 27*59c8e88eSDag-Erling Smørgrav #include <arraylist.h> 28*59c8e88eSDag-Erling Smørgrav #include <diff_main.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 /* Algorithm to find unique lines: 34*59c8e88eSDag-Erling Smørgrav * 0: stupidly iterate atoms 35*59c8e88eSDag-Erling Smørgrav * 1: qsort 36*59c8e88eSDag-Erling Smørgrav * 2: mergesort 37*59c8e88eSDag-Erling Smørgrav */ 38*59c8e88eSDag-Erling Smørgrav #define UNIQUE_STRATEGY 1 39*59c8e88eSDag-Erling Smørgrav 40*59c8e88eSDag-Erling Smørgrav /* Per-atom state for the Patience Diff algorithm */ 41*59c8e88eSDag-Erling Smørgrav struct atom_patience { 42*59c8e88eSDag-Erling Smørgrav #if UNIQUE_STRATEGY == 0 43*59c8e88eSDag-Erling Smørgrav bool unique_here; 44*59c8e88eSDag-Erling Smørgrav #endif 45*59c8e88eSDag-Erling Smørgrav bool unique_in_both; 46*59c8e88eSDag-Erling Smørgrav struct diff_atom *pos_in_other; 47*59c8e88eSDag-Erling Smørgrav struct diff_atom *prev_stack; 48*59c8e88eSDag-Erling Smørgrav struct diff_range identical_lines; 49*59c8e88eSDag-Erling Smørgrav }; 50*59c8e88eSDag-Erling Smørgrav 51*59c8e88eSDag-Erling Smørgrav /* A diff_atom has a backpointer to the root diff_data. That points to the 52*59c8e88eSDag-Erling Smørgrav * current diff_data, a possibly smaller section of the root. That current 53*59c8e88eSDag-Erling Smørgrav * diff_data->algo_data is a pointer to an array of struct atom_patience. The 54*59c8e88eSDag-Erling Smørgrav * atom's index in current diff_data gives the index in the atom_patience array. 55*59c8e88eSDag-Erling Smørgrav */ 56*59c8e88eSDag-Erling Smørgrav #define PATIENCE(ATOM) \ 57*59c8e88eSDag-Erling Smørgrav (((struct atom_patience*)((ATOM)->root->current->algo_data))\ 58*59c8e88eSDag-Erling Smørgrav [diff_atom_idx((ATOM)->root->current, ATOM)]) 59*59c8e88eSDag-Erling Smørgrav 60*59c8e88eSDag-Erling Smørgrav #if UNIQUE_STRATEGY == 0 61*59c8e88eSDag-Erling Smørgrav 62*59c8e88eSDag-Erling Smørgrav /* Stupid iteration and comparison of all atoms */ 63*59c8e88eSDag-Erling Smørgrav static int 64*59c8e88eSDag-Erling Smørgrav diff_atoms_mark_unique(struct diff_data *d, unsigned int *unique_count) 65*59c8e88eSDag-Erling Smørgrav { 66*59c8e88eSDag-Erling Smørgrav struct diff_atom *i; 67*59c8e88eSDag-Erling Smørgrav unsigned int count = 0; 68*59c8e88eSDag-Erling Smørgrav diff_data_foreach_atom(i, d) { 69*59c8e88eSDag-Erling Smørgrav PATIENCE(i).unique_here = true; 70*59c8e88eSDag-Erling Smørgrav PATIENCE(i).unique_in_both = true; 71*59c8e88eSDag-Erling Smørgrav count++; 72*59c8e88eSDag-Erling Smørgrav } 73*59c8e88eSDag-Erling Smørgrav diff_data_foreach_atom(i, d) { 74*59c8e88eSDag-Erling Smørgrav struct diff_atom *j; 75*59c8e88eSDag-Erling Smørgrav 76*59c8e88eSDag-Erling Smørgrav if (!PATIENCE(i).unique_here) 77*59c8e88eSDag-Erling Smørgrav continue; 78*59c8e88eSDag-Erling Smørgrav 79*59c8e88eSDag-Erling Smørgrav diff_data_foreach_atom_from(i + 1, j, d) { 80*59c8e88eSDag-Erling Smørgrav bool same; 81*59c8e88eSDag-Erling Smørgrav int r = diff_atom_same(&same, i, j); 82*59c8e88eSDag-Erling Smørgrav if (r) 83*59c8e88eSDag-Erling Smørgrav return r; 84*59c8e88eSDag-Erling Smørgrav if (!same) 85*59c8e88eSDag-Erling Smørgrav continue; 86*59c8e88eSDag-Erling Smørgrav if (PATIENCE(i).unique_here) { 87*59c8e88eSDag-Erling Smørgrav PATIENCE(i).unique_here = false; 88*59c8e88eSDag-Erling Smørgrav PATIENCE(i).unique_in_both = false; 89*59c8e88eSDag-Erling Smørgrav count--; 90*59c8e88eSDag-Erling Smørgrav } 91*59c8e88eSDag-Erling Smørgrav PATIENCE(j).unique_here = false; 92*59c8e88eSDag-Erling Smørgrav PATIENCE(j).unique_in_both = false; 93*59c8e88eSDag-Erling Smørgrav count--; 94*59c8e88eSDag-Erling Smørgrav } 95*59c8e88eSDag-Erling Smørgrav } 96*59c8e88eSDag-Erling Smørgrav if (unique_count) 97*59c8e88eSDag-Erling Smørgrav *unique_count = count; 98*59c8e88eSDag-Erling Smørgrav return 0; 99*59c8e88eSDag-Erling Smørgrav } 100*59c8e88eSDag-Erling Smørgrav 101*59c8e88eSDag-Erling Smørgrav /* Mark those lines as PATIENCE(atom).unique_in_both = true that appear exactly 102*59c8e88eSDag-Erling Smørgrav * once in each side. */ 103*59c8e88eSDag-Erling Smørgrav static int 104*59c8e88eSDag-Erling Smørgrav diff_atoms_mark_unique_in_both(struct diff_data *left, struct diff_data *right, 105*59c8e88eSDag-Erling Smørgrav unsigned int *unique_in_both_count) 106*59c8e88eSDag-Erling Smørgrav { 107*59c8e88eSDag-Erling Smørgrav /* Derive the final unique_in_both count without needing an explicit 108*59c8e88eSDag-Erling Smørgrav * iteration. So this is just some optimiziation to save one iteration 109*59c8e88eSDag-Erling Smørgrav * in the end. */ 110*59c8e88eSDag-Erling Smørgrav unsigned int unique_in_both; 111*59c8e88eSDag-Erling Smørgrav int r; 112*59c8e88eSDag-Erling Smørgrav 113*59c8e88eSDag-Erling Smørgrav r = diff_atoms_mark_unique(left, &unique_in_both); 114*59c8e88eSDag-Erling Smørgrav if (r) 115*59c8e88eSDag-Erling Smørgrav return r; 116*59c8e88eSDag-Erling Smørgrav r = diff_atoms_mark_unique(right, NULL); 117*59c8e88eSDag-Erling Smørgrav if (r) 118*59c8e88eSDag-Erling Smørgrav return r; 119*59c8e88eSDag-Erling Smørgrav 120*59c8e88eSDag-Erling Smørgrav debug("unique_in_both %u\n", unique_in_both); 121*59c8e88eSDag-Erling Smørgrav 122*59c8e88eSDag-Erling Smørgrav struct diff_atom *i; 123*59c8e88eSDag-Erling Smørgrav diff_data_foreach_atom(i, left) { 124*59c8e88eSDag-Erling Smørgrav if (!PATIENCE(i).unique_here) 125*59c8e88eSDag-Erling Smørgrav continue; 126*59c8e88eSDag-Erling Smørgrav struct diff_atom *j; 127*59c8e88eSDag-Erling Smørgrav int found_in_b = 0; 128*59c8e88eSDag-Erling Smørgrav diff_data_foreach_atom(j, right) { 129*59c8e88eSDag-Erling Smørgrav bool same; 130*59c8e88eSDag-Erling Smørgrav int r = diff_atom_same(&same, i, j); 131*59c8e88eSDag-Erling Smørgrav if (r) 132*59c8e88eSDag-Erling Smørgrav return r; 133*59c8e88eSDag-Erling Smørgrav if (!same) 134*59c8e88eSDag-Erling Smørgrav continue; 135*59c8e88eSDag-Erling Smørgrav if (!PATIENCE(j).unique_here) { 136*59c8e88eSDag-Erling Smørgrav found_in_b = 2; /* or more */ 137*59c8e88eSDag-Erling Smørgrav break; 138*59c8e88eSDag-Erling Smørgrav } else { 139*59c8e88eSDag-Erling Smørgrav found_in_b = 1; 140*59c8e88eSDag-Erling Smørgrav PATIENCE(j).pos_in_other = i; 141*59c8e88eSDag-Erling Smørgrav PATIENCE(i).pos_in_other = j; 142*59c8e88eSDag-Erling Smørgrav } 143*59c8e88eSDag-Erling Smørgrav } 144*59c8e88eSDag-Erling Smørgrav 145*59c8e88eSDag-Erling Smørgrav if (found_in_b == 0 || found_in_b > 1) { 146*59c8e88eSDag-Erling Smørgrav PATIENCE(i).unique_in_both = false; 147*59c8e88eSDag-Erling Smørgrav unique_in_both--; 148*59c8e88eSDag-Erling Smørgrav debug("unique_in_both %u (%d) ", unique_in_both, 149*59c8e88eSDag-Erling Smørgrav found_in_b); 150*59c8e88eSDag-Erling Smørgrav debug_dump_atom(left, NULL, i); 151*59c8e88eSDag-Erling Smørgrav } 152*59c8e88eSDag-Erling Smørgrav } 153*59c8e88eSDag-Erling Smørgrav 154*59c8e88eSDag-Erling Smørgrav /* Still need to unmark right[*]->patience.unique_in_both for atoms that 155*59c8e88eSDag-Erling Smørgrav * don't exist in left */ 156*59c8e88eSDag-Erling Smørgrav diff_data_foreach_atom(i, right) { 157*59c8e88eSDag-Erling Smørgrav if (!PATIENCE(i).unique_here 158*59c8e88eSDag-Erling Smørgrav || !PATIENCE(i).unique_in_both) 159*59c8e88eSDag-Erling Smørgrav continue; 160*59c8e88eSDag-Erling Smørgrav struct diff_atom *j; 161*59c8e88eSDag-Erling Smørgrav bool found_in_a = false; 162*59c8e88eSDag-Erling Smørgrav diff_data_foreach_atom(j, left) { 163*59c8e88eSDag-Erling Smørgrav bool same; 164*59c8e88eSDag-Erling Smørgrav int r; 165*59c8e88eSDag-Erling Smørgrav if (!PATIENCE(j).unique_in_both) 166*59c8e88eSDag-Erling Smørgrav continue; 167*59c8e88eSDag-Erling Smørgrav r = diff_atom_same(&same, i, j); 168*59c8e88eSDag-Erling Smørgrav if (r) 169*59c8e88eSDag-Erling Smørgrav return r; 170*59c8e88eSDag-Erling Smørgrav if (!same) 171*59c8e88eSDag-Erling Smørgrav continue; 172*59c8e88eSDag-Erling Smørgrav found_in_a = true; 173*59c8e88eSDag-Erling Smørgrav break; 174*59c8e88eSDag-Erling Smørgrav } 175*59c8e88eSDag-Erling Smørgrav 176*59c8e88eSDag-Erling Smørgrav if (!found_in_a) 177*59c8e88eSDag-Erling Smørgrav PATIENCE(i).unique_in_both = false; 178*59c8e88eSDag-Erling Smørgrav } 179*59c8e88eSDag-Erling Smørgrav 180*59c8e88eSDag-Erling Smørgrav if (unique_in_both_count) 181*59c8e88eSDag-Erling Smørgrav *unique_in_both_count = unique_in_both; 182*59c8e88eSDag-Erling Smørgrav return 0; 183*59c8e88eSDag-Erling Smørgrav } 184*59c8e88eSDag-Erling Smørgrav 185*59c8e88eSDag-Erling Smørgrav #else /* UNIQUE_STRATEGY != 0 */ 186*59c8e88eSDag-Erling Smørgrav 187*59c8e88eSDag-Erling Smørgrav /* Use an optimized sorting algorithm (qsort, mergesort) to find unique lines */ 188*59c8e88eSDag-Erling Smørgrav 189*59c8e88eSDag-Erling Smørgrav static int diff_atoms_compar(const void *_a, const void *_b) 190*59c8e88eSDag-Erling Smørgrav { 191*59c8e88eSDag-Erling Smørgrav const struct diff_atom *a = *(struct diff_atom**)_a; 192*59c8e88eSDag-Erling Smørgrav const struct diff_atom *b = *(struct diff_atom**)_b; 193*59c8e88eSDag-Erling Smørgrav int cmp; 194*59c8e88eSDag-Erling Smørgrav int rc = 0; 195*59c8e88eSDag-Erling Smørgrav 196*59c8e88eSDag-Erling Smørgrav /* If there's been an error (e.g. I/O error) in a previous compar, we 197*59c8e88eSDag-Erling Smørgrav * have no way to abort the sort but just report the rc and stop 198*59c8e88eSDag-Erling Smørgrav * comparing. Make sure to catch errors on either side. If atoms are 199*59c8e88eSDag-Erling Smørgrav * from more than one diff_data, make sure the error, if any, spreads 200*59c8e88eSDag-Erling Smørgrav * to all of them, so we can cut short all future comparisons. */ 201*59c8e88eSDag-Erling Smørgrav if (a->root->err) 202*59c8e88eSDag-Erling Smørgrav rc = a->root->err; 203*59c8e88eSDag-Erling Smørgrav if (b->root->err) 204*59c8e88eSDag-Erling Smørgrav rc = b->root->err; 205*59c8e88eSDag-Erling Smørgrav if (rc) { 206*59c8e88eSDag-Erling Smørgrav a->root->err = rc; 207*59c8e88eSDag-Erling Smørgrav b->root->err = rc; 208*59c8e88eSDag-Erling Smørgrav /* just return 'equal' to not swap more positions */ 209*59c8e88eSDag-Erling Smørgrav return 0; 210*59c8e88eSDag-Erling Smørgrav } 211*59c8e88eSDag-Erling Smørgrav 212*59c8e88eSDag-Erling Smørgrav /* Sort by the simplistic hash */ 213*59c8e88eSDag-Erling Smørgrav if (a->hash < b->hash) 214*59c8e88eSDag-Erling Smørgrav return -1; 215*59c8e88eSDag-Erling Smørgrav if (a->hash > b->hash) 216*59c8e88eSDag-Erling Smørgrav return 1; 217*59c8e88eSDag-Erling Smørgrav 218*59c8e88eSDag-Erling Smørgrav /* If hashes are the same, the lines may still differ. Do a full cmp. */ 219*59c8e88eSDag-Erling Smørgrav rc = diff_atom_cmp(&cmp, a, b); 220*59c8e88eSDag-Erling Smørgrav 221*59c8e88eSDag-Erling Smørgrav if (rc) { 222*59c8e88eSDag-Erling Smørgrav /* Mark the I/O error so that the caller can find out about it. 223*59c8e88eSDag-Erling Smørgrav * For the case atoms are from more than one diff_data, mark in 224*59c8e88eSDag-Erling Smørgrav * both. */ 225*59c8e88eSDag-Erling Smørgrav a->root->err = rc; 226*59c8e88eSDag-Erling Smørgrav if (a->root != b->root) 227*59c8e88eSDag-Erling Smørgrav b->root->err = rc; 228*59c8e88eSDag-Erling Smørgrav return 0; 229*59c8e88eSDag-Erling Smørgrav } 230*59c8e88eSDag-Erling Smørgrav 231*59c8e88eSDag-Erling Smørgrav return cmp; 232*59c8e88eSDag-Erling Smørgrav } 233*59c8e88eSDag-Erling Smørgrav 234*59c8e88eSDag-Erling Smørgrav /* Sort an array of struct diff_atom* in-place. */ 235*59c8e88eSDag-Erling Smørgrav static int diff_atoms_sort(struct diff_atom *atoms[], 236*59c8e88eSDag-Erling Smørgrav size_t atoms_count) 237*59c8e88eSDag-Erling Smørgrav { 238*59c8e88eSDag-Erling Smørgrav #if UNIQUE_STRATEGY == 1 239*59c8e88eSDag-Erling Smørgrav qsort(atoms, atoms_count, sizeof(struct diff_atom*), diff_atoms_compar); 240*59c8e88eSDag-Erling Smørgrav #else 241*59c8e88eSDag-Erling Smørgrav mergesort(atoms, atoms_count, sizeof(struct diff_atom*), 242*59c8e88eSDag-Erling Smørgrav diff_atoms_compar); 243*59c8e88eSDag-Erling Smørgrav #endif 244*59c8e88eSDag-Erling Smørgrav return atoms[0]->root->err; 245*59c8e88eSDag-Erling Smørgrav } 246*59c8e88eSDag-Erling Smørgrav 247*59c8e88eSDag-Erling Smørgrav static int 248*59c8e88eSDag-Erling Smørgrav diff_atoms_mark_unique_in_both(struct diff_data *left, struct diff_data *right, 249*59c8e88eSDag-Erling Smørgrav unsigned int *unique_in_both_count_p) 250*59c8e88eSDag-Erling Smørgrav { 251*59c8e88eSDag-Erling Smørgrav struct diff_atom *a; 252*59c8e88eSDag-Erling Smørgrav struct diff_atom *b; 253*59c8e88eSDag-Erling Smørgrav struct diff_atom **all_atoms; 254*59c8e88eSDag-Erling Smørgrav unsigned int len = 0; 255*59c8e88eSDag-Erling Smørgrav unsigned int i; 256*59c8e88eSDag-Erling Smørgrav unsigned int unique_in_both_count = 0; 257*59c8e88eSDag-Erling Smørgrav int rc; 258*59c8e88eSDag-Erling Smørgrav 259*59c8e88eSDag-Erling Smørgrav all_atoms = calloc(left->atoms.len + right->atoms.len, 260*59c8e88eSDag-Erling Smørgrav sizeof(struct diff_atom *)); 261*59c8e88eSDag-Erling Smørgrav if (all_atoms == NULL) 262*59c8e88eSDag-Erling Smørgrav return ENOMEM; 263*59c8e88eSDag-Erling Smørgrav 264*59c8e88eSDag-Erling Smørgrav left->err = 0; 265*59c8e88eSDag-Erling Smørgrav right->err = 0; 266*59c8e88eSDag-Erling Smørgrav left->root->err = 0; 267*59c8e88eSDag-Erling Smørgrav right->root->err = 0; 268*59c8e88eSDag-Erling Smørgrav diff_data_foreach_atom(a, left) { 269*59c8e88eSDag-Erling Smørgrav all_atoms[len++] = a; 270*59c8e88eSDag-Erling Smørgrav } 271*59c8e88eSDag-Erling Smørgrav diff_data_foreach_atom(b, right) { 272*59c8e88eSDag-Erling Smørgrav all_atoms[len++] = b; 273*59c8e88eSDag-Erling Smørgrav } 274*59c8e88eSDag-Erling Smørgrav 275*59c8e88eSDag-Erling Smørgrav rc = diff_atoms_sort(all_atoms, len); 276*59c8e88eSDag-Erling Smørgrav if (rc) 277*59c8e88eSDag-Erling Smørgrav goto free_and_exit; 278*59c8e88eSDag-Erling Smørgrav 279*59c8e88eSDag-Erling Smørgrav /* Now we have a sorted array of atom pointers. All similar lines are 280*59c8e88eSDag-Erling Smørgrav * adjacent. Walk through the array and mark those that are unique on 281*59c8e88eSDag-Erling Smørgrav * each side, but exist once in both sources. */ 282*59c8e88eSDag-Erling Smørgrav for (i = 0; i < len; i++) { 283*59c8e88eSDag-Erling Smørgrav bool same; 284*59c8e88eSDag-Erling Smørgrav unsigned int next_differing_i; 285*59c8e88eSDag-Erling Smørgrav unsigned int last_identical_i; 286*59c8e88eSDag-Erling Smørgrav unsigned int j; 287*59c8e88eSDag-Erling Smørgrav unsigned int count_first_side = 1; 288*59c8e88eSDag-Erling Smørgrav unsigned int count_other_side = 0; 289*59c8e88eSDag-Erling Smørgrav a = all_atoms[i]; 290*59c8e88eSDag-Erling Smørgrav debug("a: "); 291*59c8e88eSDag-Erling Smørgrav debug_dump_atom(a->root, NULL, a); 292*59c8e88eSDag-Erling Smørgrav 293*59c8e88eSDag-Erling Smørgrav /* Do as few diff_atom_cmp() as possible: first walk forward 294*59c8e88eSDag-Erling Smørgrav * only using the cheap hash as indicator for differing atoms; 295*59c8e88eSDag-Erling Smørgrav * then walk backwards until hitting an identical atom. */ 296*59c8e88eSDag-Erling Smørgrav for (next_differing_i = i + 1; next_differing_i < len; 297*59c8e88eSDag-Erling Smørgrav next_differing_i++) { 298*59c8e88eSDag-Erling Smørgrav b = all_atoms[next_differing_i]; 299*59c8e88eSDag-Erling Smørgrav if (a->hash != b->hash) 300*59c8e88eSDag-Erling Smørgrav break; 301*59c8e88eSDag-Erling Smørgrav } 302*59c8e88eSDag-Erling Smørgrav for (last_identical_i = next_differing_i - 1; 303*59c8e88eSDag-Erling Smørgrav last_identical_i > i; 304*59c8e88eSDag-Erling Smørgrav last_identical_i--) { 305*59c8e88eSDag-Erling Smørgrav b = all_atoms[last_identical_i]; 306*59c8e88eSDag-Erling Smørgrav rc = diff_atom_same(&same, a, b); 307*59c8e88eSDag-Erling Smørgrav if (rc) 308*59c8e88eSDag-Erling Smørgrav goto free_and_exit; 309*59c8e88eSDag-Erling Smørgrav if (same) 310*59c8e88eSDag-Erling Smørgrav break; 311*59c8e88eSDag-Erling Smørgrav } 312*59c8e88eSDag-Erling Smørgrav next_differing_i = last_identical_i + 1; 313*59c8e88eSDag-Erling Smørgrav 314*59c8e88eSDag-Erling Smørgrav for (j = i+1; j < next_differing_i; j++) { 315*59c8e88eSDag-Erling Smørgrav b = all_atoms[j]; 316*59c8e88eSDag-Erling Smørgrav /* A following atom is the same. See on which side the 317*59c8e88eSDag-Erling Smørgrav * repetition counts. */ 318*59c8e88eSDag-Erling Smørgrav if (a->root == b->root) 319*59c8e88eSDag-Erling Smørgrav count_first_side ++; 320*59c8e88eSDag-Erling Smørgrav else 321*59c8e88eSDag-Erling Smørgrav count_other_side ++; 322*59c8e88eSDag-Erling Smørgrav debug("b: "); 323*59c8e88eSDag-Erling Smørgrav debug_dump_atom(b->root, NULL, b); 324*59c8e88eSDag-Erling Smørgrav debug(" count_first_side=%d count_other_side=%d\n", 325*59c8e88eSDag-Erling Smørgrav count_first_side, count_other_side); 326*59c8e88eSDag-Erling Smørgrav } 327*59c8e88eSDag-Erling Smørgrav 328*59c8e88eSDag-Erling Smørgrav /* Counted a section of similar atoms, put the results back to 329*59c8e88eSDag-Erling Smørgrav * the atoms. */ 330*59c8e88eSDag-Erling Smørgrav if ((count_first_side == 1) 331*59c8e88eSDag-Erling Smørgrav && (count_other_side == 1)) { 332*59c8e88eSDag-Erling Smørgrav b = all_atoms[i+1]; 333*59c8e88eSDag-Erling Smørgrav PATIENCE(a).unique_in_both = true; 334*59c8e88eSDag-Erling Smørgrav PATIENCE(a).pos_in_other = b; 335*59c8e88eSDag-Erling Smørgrav PATIENCE(b).unique_in_both = true; 336*59c8e88eSDag-Erling Smørgrav PATIENCE(b).pos_in_other = a; 337*59c8e88eSDag-Erling Smørgrav unique_in_both_count++; 338*59c8e88eSDag-Erling Smørgrav } 339*59c8e88eSDag-Erling Smørgrav 340*59c8e88eSDag-Erling Smørgrav /* j now points at the first atom after 'a' that is not 341*59c8e88eSDag-Erling Smørgrav * identical to 'a'. j is always > i. */ 342*59c8e88eSDag-Erling Smørgrav i = j - 1; 343*59c8e88eSDag-Erling Smørgrav } 344*59c8e88eSDag-Erling Smørgrav *unique_in_both_count_p = unique_in_both_count; 345*59c8e88eSDag-Erling Smørgrav rc = 0; 346*59c8e88eSDag-Erling Smørgrav free_and_exit: 347*59c8e88eSDag-Erling Smørgrav free(all_atoms); 348*59c8e88eSDag-Erling Smørgrav return rc; 349*59c8e88eSDag-Erling Smørgrav } 350*59c8e88eSDag-Erling Smørgrav #endif /* UNIQUE_STRATEGY != 0 */ 351*59c8e88eSDag-Erling Smørgrav 352*59c8e88eSDag-Erling Smørgrav /* binary search to find the stack to put this atom "card" on. */ 353*59c8e88eSDag-Erling Smørgrav static int 354*59c8e88eSDag-Erling Smørgrav find_target_stack(struct diff_atom *atom, 355*59c8e88eSDag-Erling Smørgrav struct diff_atom **patience_stacks, 356*59c8e88eSDag-Erling Smørgrav unsigned int patience_stacks_count) 357*59c8e88eSDag-Erling Smørgrav { 358*59c8e88eSDag-Erling Smørgrav unsigned int lo = 0; 359*59c8e88eSDag-Erling Smørgrav unsigned int hi = patience_stacks_count; 360*59c8e88eSDag-Erling Smørgrav while (lo < hi) { 361*59c8e88eSDag-Erling Smørgrav unsigned int mid = (lo + hi) >> 1; 362*59c8e88eSDag-Erling Smørgrav 363*59c8e88eSDag-Erling Smørgrav if (PATIENCE(patience_stacks[mid]).pos_in_other 364*59c8e88eSDag-Erling Smørgrav < PATIENCE(atom).pos_in_other) 365*59c8e88eSDag-Erling Smørgrav lo = mid + 1; 366*59c8e88eSDag-Erling Smørgrav else 367*59c8e88eSDag-Erling Smørgrav hi = mid; 368*59c8e88eSDag-Erling Smørgrav } 369*59c8e88eSDag-Erling Smørgrav return lo; 370*59c8e88eSDag-Erling Smørgrav } 371*59c8e88eSDag-Erling Smørgrav 372*59c8e88eSDag-Erling Smørgrav /* Among the lines that appear exactly once in each side, find the longest 373*59c8e88eSDag-Erling Smørgrav * streak that appear in both files in the same order (with other stuff allowed 374*59c8e88eSDag-Erling Smørgrav * to interleave). Use patience sort for that, as in the Patience Diff 375*59c8e88eSDag-Erling Smørgrav * algorithm. 376*59c8e88eSDag-Erling Smørgrav * See https://bramcohen.livejournal.com/73318.html and, for a much more 377*59c8e88eSDag-Erling Smørgrav * detailed explanation, 378*59c8e88eSDag-Erling Smørgrav * https://blog.jcoglan.com/2017/09/19/the-patience-diff-algorithm/ */ 379*59c8e88eSDag-Erling Smørgrav int 380*59c8e88eSDag-Erling Smørgrav diff_algo_patience(const struct diff_algo_config *algo_config, 381*59c8e88eSDag-Erling Smørgrav struct diff_state *state) 382*59c8e88eSDag-Erling Smørgrav { 383*59c8e88eSDag-Erling Smørgrav int rc; 384*59c8e88eSDag-Erling Smørgrav struct diff_data *left = &state->left; 385*59c8e88eSDag-Erling Smørgrav struct diff_data *right = &state->right; 386*59c8e88eSDag-Erling Smørgrav struct atom_patience *atom_patience_left = 387*59c8e88eSDag-Erling Smørgrav calloc(left->atoms.len, sizeof(struct atom_patience)); 388*59c8e88eSDag-Erling Smørgrav struct atom_patience *atom_patience_right = 389*59c8e88eSDag-Erling Smørgrav calloc(right->atoms.len, sizeof(struct atom_patience)); 390*59c8e88eSDag-Erling Smørgrav unsigned int unique_in_both_count; 391*59c8e88eSDag-Erling Smørgrav struct diff_atom **lcs = NULL; 392*59c8e88eSDag-Erling Smørgrav 393*59c8e88eSDag-Erling Smørgrav debug("\n** %s\n", __func__); 394*59c8e88eSDag-Erling Smørgrav 395*59c8e88eSDag-Erling Smørgrav left->root->current = left; 396*59c8e88eSDag-Erling Smørgrav right->root->current = right; 397*59c8e88eSDag-Erling Smørgrav left->algo_data = atom_patience_left; 398*59c8e88eSDag-Erling Smørgrav right->algo_data = atom_patience_right; 399*59c8e88eSDag-Erling Smørgrav 400*59c8e88eSDag-Erling Smørgrav /* Find those lines that appear exactly once in 'left' and exactly once 401*59c8e88eSDag-Erling Smørgrav * in 'right'. */ 402*59c8e88eSDag-Erling Smørgrav rc = diff_atoms_mark_unique_in_both(left, right, &unique_in_both_count); 403*59c8e88eSDag-Erling Smørgrav if (rc) 404*59c8e88eSDag-Erling Smørgrav goto free_and_exit; 405*59c8e88eSDag-Erling Smørgrav 406*59c8e88eSDag-Erling Smørgrav debug("unique_in_both_count %u\n", unique_in_both_count); 407*59c8e88eSDag-Erling Smørgrav debug("left:\n"); 408*59c8e88eSDag-Erling Smørgrav debug_dump(left); 409*59c8e88eSDag-Erling Smørgrav debug("right:\n"); 410*59c8e88eSDag-Erling Smørgrav debug_dump(right); 411*59c8e88eSDag-Erling Smørgrav 412*59c8e88eSDag-Erling Smørgrav if (!unique_in_both_count) { 413*59c8e88eSDag-Erling Smørgrav /* Cannot apply Patience, tell the caller to use fallback_algo 414*59c8e88eSDag-Erling Smørgrav * instead. */ 415*59c8e88eSDag-Erling Smørgrav rc = DIFF_RC_USE_DIFF_ALGO_FALLBACK; 416*59c8e88eSDag-Erling Smørgrav goto free_and_exit; 417*59c8e88eSDag-Erling Smørgrav } 418*59c8e88eSDag-Erling Smørgrav 419*59c8e88eSDag-Erling Smørgrav rc = ENOMEM; 420*59c8e88eSDag-Erling Smørgrav 421*59c8e88eSDag-Erling Smørgrav /* An array of Longest Common Sequence is the result of the below 422*59c8e88eSDag-Erling Smørgrav * subscope: */ 423*59c8e88eSDag-Erling Smørgrav unsigned int lcs_count = 0; 424*59c8e88eSDag-Erling Smørgrav struct diff_atom *lcs_tail = NULL; 425*59c8e88eSDag-Erling Smørgrav 426*59c8e88eSDag-Erling Smørgrav { 427*59c8e88eSDag-Erling Smørgrav /* This subscope marks the lifetime of the atom_pointers 428*59c8e88eSDag-Erling Smørgrav * allocation */ 429*59c8e88eSDag-Erling Smørgrav 430*59c8e88eSDag-Erling Smørgrav /* One chunk of storage for atom pointers */ 431*59c8e88eSDag-Erling Smørgrav struct diff_atom **atom_pointers; 432*59c8e88eSDag-Erling Smørgrav atom_pointers = recallocarray(NULL, 0, unique_in_both_count * 2, 433*59c8e88eSDag-Erling Smørgrav sizeof(struct diff_atom*)); 434*59c8e88eSDag-Erling Smørgrav if (atom_pointers == NULL) 435*59c8e88eSDag-Erling Smørgrav return ENOMEM; 436*59c8e88eSDag-Erling Smørgrav /* Half for the list of atoms that still need to be put on 437*59c8e88eSDag-Erling Smørgrav * stacks */ 438*59c8e88eSDag-Erling Smørgrav struct diff_atom **uniques = atom_pointers; 439*59c8e88eSDag-Erling Smørgrav 440*59c8e88eSDag-Erling Smørgrav /* Half for the patience sort state's "card stacks" -- we 441*59c8e88eSDag-Erling Smørgrav * remember only each stack's topmost "card" */ 442*59c8e88eSDag-Erling Smørgrav struct diff_atom **patience_stacks; 443*59c8e88eSDag-Erling Smørgrav patience_stacks = atom_pointers + unique_in_both_count; 444*59c8e88eSDag-Erling Smørgrav unsigned int patience_stacks_count = 0; 445*59c8e88eSDag-Erling Smørgrav 446*59c8e88eSDag-Erling Smørgrav /* Take all common, unique items from 'left' ... */ 447*59c8e88eSDag-Erling Smørgrav 448*59c8e88eSDag-Erling Smørgrav struct diff_atom *atom; 449*59c8e88eSDag-Erling Smørgrav struct diff_atom **uniques_end = uniques; 450*59c8e88eSDag-Erling Smørgrav diff_data_foreach_atom(atom, left) { 451*59c8e88eSDag-Erling Smørgrav if (!PATIENCE(atom).unique_in_both) 452*59c8e88eSDag-Erling Smørgrav continue; 453*59c8e88eSDag-Erling Smørgrav *uniques_end = atom; 454*59c8e88eSDag-Erling Smørgrav uniques_end++; 455*59c8e88eSDag-Erling Smørgrav } 456*59c8e88eSDag-Erling Smørgrav 457*59c8e88eSDag-Erling Smørgrav /* ...and sort them to the order found in 'right'. 458*59c8e88eSDag-Erling Smørgrav * The idea is to find the leftmost stack that has a higher line 459*59c8e88eSDag-Erling Smørgrav * number and add it to the stack's top. 460*59c8e88eSDag-Erling Smørgrav * If there is no such stack, open a new one on the right. The 461*59c8e88eSDag-Erling Smørgrav * line number is derived from the atom*, which are array items 462*59c8e88eSDag-Erling Smørgrav * and hence reflect the relative position in the source file. 463*59c8e88eSDag-Erling Smørgrav * So we got the common-uniques from 'left' and sort them 464*59c8e88eSDag-Erling Smørgrav * according to PATIENCE(atom).pos_in_other. */ 465*59c8e88eSDag-Erling Smørgrav unsigned int i; 466*59c8e88eSDag-Erling Smørgrav for (i = 0; i < unique_in_both_count; i++) { 467*59c8e88eSDag-Erling Smørgrav atom = uniques[i]; 468*59c8e88eSDag-Erling Smørgrav unsigned int target_stack; 469*59c8e88eSDag-Erling Smørgrav target_stack = find_target_stack(atom, patience_stacks, 470*59c8e88eSDag-Erling Smørgrav patience_stacks_count); 471*59c8e88eSDag-Erling Smørgrav assert(target_stack <= patience_stacks_count); 472*59c8e88eSDag-Erling Smørgrav patience_stacks[target_stack] = atom; 473*59c8e88eSDag-Erling Smørgrav if (target_stack == patience_stacks_count) 474*59c8e88eSDag-Erling Smørgrav patience_stacks_count++; 475*59c8e88eSDag-Erling Smørgrav 476*59c8e88eSDag-Erling Smørgrav /* Record a back reference to the next stack on the 477*59c8e88eSDag-Erling Smørgrav * left, which will form the final longest sequence 478*59c8e88eSDag-Erling Smørgrav * later. */ 479*59c8e88eSDag-Erling Smørgrav PATIENCE(atom).prev_stack = target_stack ? 480*59c8e88eSDag-Erling Smørgrav patience_stacks[target_stack - 1] : NULL; 481*59c8e88eSDag-Erling Smørgrav 482*59c8e88eSDag-Erling Smørgrav { 483*59c8e88eSDag-Erling Smørgrav int xx; 484*59c8e88eSDag-Erling Smørgrav for (xx = 0; xx < patience_stacks_count; xx++) { 485*59c8e88eSDag-Erling Smørgrav debug(" %s%d", 486*59c8e88eSDag-Erling Smørgrav (xx == target_stack) ? ">" : "", 487*59c8e88eSDag-Erling Smørgrav diff_atom_idx(right, 488*59c8e88eSDag-Erling Smørgrav PATIENCE(patience_stacks[xx]).pos_in_other)); 489*59c8e88eSDag-Erling Smørgrav } 490*59c8e88eSDag-Erling Smørgrav debug("\n"); 491*59c8e88eSDag-Erling Smørgrav } 492*59c8e88eSDag-Erling Smørgrav } 493*59c8e88eSDag-Erling Smørgrav 494*59c8e88eSDag-Erling Smørgrav /* backtrace through prev_stack references to form the final 495*59c8e88eSDag-Erling Smørgrav * longest common sequence */ 496*59c8e88eSDag-Erling Smørgrav lcs_tail = patience_stacks[patience_stacks_count - 1]; 497*59c8e88eSDag-Erling Smørgrav lcs_count = patience_stacks_count; 498*59c8e88eSDag-Erling Smørgrav 499*59c8e88eSDag-Erling Smørgrav /* uniques and patience_stacks are no longer needed. 500*59c8e88eSDag-Erling Smørgrav * Backpointers are in PATIENCE(atom).prev_stack */ 501*59c8e88eSDag-Erling Smørgrav free(atom_pointers); 502*59c8e88eSDag-Erling Smørgrav } 503*59c8e88eSDag-Erling Smørgrav 504*59c8e88eSDag-Erling Smørgrav lcs = recallocarray(NULL, 0, lcs_count, sizeof(struct diff_atom*)); 505*59c8e88eSDag-Erling Smørgrav struct diff_atom **lcs_backtrace_pos = &lcs[lcs_count - 1]; 506*59c8e88eSDag-Erling Smørgrav struct diff_atom *atom; 507*59c8e88eSDag-Erling Smørgrav for (atom = lcs_tail; atom; atom = PATIENCE(atom).prev_stack, lcs_backtrace_pos--) { 508*59c8e88eSDag-Erling Smørgrav assert(lcs_backtrace_pos >= lcs); 509*59c8e88eSDag-Erling Smørgrav *lcs_backtrace_pos = atom; 510*59c8e88eSDag-Erling Smørgrav } 511*59c8e88eSDag-Erling Smørgrav 512*59c8e88eSDag-Erling Smørgrav unsigned int i; 513*59c8e88eSDag-Erling Smørgrav if (DEBUG) { 514*59c8e88eSDag-Erling Smørgrav debug("\npatience LCS:\n"); 515*59c8e88eSDag-Erling Smørgrav for (i = 0; i < lcs_count; i++) { 516*59c8e88eSDag-Erling Smørgrav debug("\n L "); debug_dump_atom(left, right, lcs[i]); 517*59c8e88eSDag-Erling Smørgrav debug(" R "); debug_dump_atom(right, left, 518*59c8e88eSDag-Erling Smørgrav PATIENCE(lcs[i]).pos_in_other); 519*59c8e88eSDag-Erling Smørgrav } 520*59c8e88eSDag-Erling Smørgrav } 521*59c8e88eSDag-Erling Smørgrav 522*59c8e88eSDag-Erling Smørgrav 523*59c8e88eSDag-Erling Smørgrav /* TODO: For each common-unique line found (now listed in lcs), swallow 524*59c8e88eSDag-Erling Smørgrav * lines upwards and downwards that are identical on each side. Requires 525*59c8e88eSDag-Erling Smørgrav * a way to represent atoms being glued to adjacent atoms. */ 526*59c8e88eSDag-Erling Smørgrav 527*59c8e88eSDag-Erling Smørgrav debug("\ntraverse LCS, possibly recursing:\n"); 528*59c8e88eSDag-Erling Smørgrav 529*59c8e88eSDag-Erling Smørgrav /* Now we have pinned positions in both files at which it makes sense to 530*59c8e88eSDag-Erling Smørgrav * divide the diff problem into smaller chunks. Go into the next round: 531*59c8e88eSDag-Erling Smørgrav * look at each section in turn, trying to again find common-unique 532*59c8e88eSDag-Erling Smørgrav * lines in those smaller sections. As soon as no more are found, the 533*59c8e88eSDag-Erling Smørgrav * remaining smaller sections are solved by Myers. */ 534*59c8e88eSDag-Erling Smørgrav /* left_pos and right_pos are indexes in left/right->atoms.head until 535*59c8e88eSDag-Erling Smørgrav * which the atoms are already handled (added to result chunks). */ 536*59c8e88eSDag-Erling Smørgrav unsigned int left_pos = 0; 537*59c8e88eSDag-Erling Smørgrav unsigned int right_pos = 0; 538*59c8e88eSDag-Erling Smørgrav for (i = 0; i <= lcs_count; i++) { 539*59c8e88eSDag-Erling Smørgrav struct diff_atom *atom; 540*59c8e88eSDag-Erling Smørgrav struct diff_atom *atom_r; 541*59c8e88eSDag-Erling Smørgrav /* left_idx and right_idx are indexes of the start of this 542*59c8e88eSDag-Erling Smørgrav * section of identical lines on both sides. 543*59c8e88eSDag-Erling Smørgrav * left_pos marks the index of the first still unhandled line, 544*59c8e88eSDag-Erling Smørgrav * left_idx is the start of an identical section some way 545*59c8e88eSDag-Erling Smørgrav * further down, and this loop adds an unsolved chunk of 546*59c8e88eSDag-Erling Smørgrav * [left_pos..left_idx[ and a solved chunk of 547*59c8e88eSDag-Erling Smørgrav * [left_idx..identical_lines.end[. */ 548*59c8e88eSDag-Erling Smørgrav unsigned int left_idx; 549*59c8e88eSDag-Erling Smørgrav unsigned int right_idx; 550*59c8e88eSDag-Erling Smørgrav 551*59c8e88eSDag-Erling Smørgrav debug("iteration %u of %u left_pos %u right_pos %u\n", 552*59c8e88eSDag-Erling Smørgrav i, lcs_count, left_pos, right_pos); 553*59c8e88eSDag-Erling Smørgrav 554*59c8e88eSDag-Erling Smørgrav if (i < lcs_count) { 555*59c8e88eSDag-Erling Smørgrav atom = lcs[i]; 556*59c8e88eSDag-Erling Smørgrav atom_r = PATIENCE(atom).pos_in_other; 557*59c8e88eSDag-Erling Smørgrav debug("lcs[%u] = left[%u] = right[%u]\n", i, 558*59c8e88eSDag-Erling Smørgrav diff_atom_idx(left, atom), diff_atom_idx(right, atom_r)); 559*59c8e88eSDag-Erling Smørgrav left_idx = diff_atom_idx(left, atom); 560*59c8e88eSDag-Erling Smørgrav right_idx = diff_atom_idx(right, atom_r); 561*59c8e88eSDag-Erling Smørgrav } else { 562*59c8e88eSDag-Erling Smørgrav /* There are no more identical lines until the end of 563*59c8e88eSDag-Erling Smørgrav * left and right. */ 564*59c8e88eSDag-Erling Smørgrav atom = NULL; 565*59c8e88eSDag-Erling Smørgrav atom_r = NULL; 566*59c8e88eSDag-Erling Smørgrav left_idx = left->atoms.len; 567*59c8e88eSDag-Erling Smørgrav right_idx = right->atoms.len; 568*59c8e88eSDag-Erling Smørgrav } 569*59c8e88eSDag-Erling Smørgrav 570*59c8e88eSDag-Erling Smørgrav /* 'atom' (if not NULL) now marks an atom that matches on both 571*59c8e88eSDag-Erling Smørgrav * sides according to patience-diff (a common-unique identical 572*59c8e88eSDag-Erling Smørgrav * atom in both files). 573*59c8e88eSDag-Erling Smørgrav * Handle the section before and the atom itself; the section 574*59c8e88eSDag-Erling Smørgrav * after will be handled by the next loop iteration -- note that 575*59c8e88eSDag-Erling Smørgrav * i loops to last element + 1 ("i <= lcs_count"), so that there 576*59c8e88eSDag-Erling Smørgrav * will be another final iteration to pick up the last remaining 577*59c8e88eSDag-Erling Smørgrav * items after the last LCS atom. 578*59c8e88eSDag-Erling Smørgrav */ 579*59c8e88eSDag-Erling Smørgrav 580*59c8e88eSDag-Erling Smørgrav debug("iteration %u left_pos %u left_idx %u" 581*59c8e88eSDag-Erling Smørgrav " right_pos %u right_idx %u\n", 582*59c8e88eSDag-Erling Smørgrav i, left_pos, left_idx, right_pos, right_idx); 583*59c8e88eSDag-Erling Smørgrav 584*59c8e88eSDag-Erling Smørgrav /* Section before the matching atom */ 585*59c8e88eSDag-Erling Smørgrav struct diff_atom *left_atom = &left->atoms.head[left_pos]; 586*59c8e88eSDag-Erling Smørgrav unsigned int left_section_len = left_idx - left_pos; 587*59c8e88eSDag-Erling Smørgrav 588*59c8e88eSDag-Erling Smørgrav struct diff_atom *right_atom = &(right->atoms.head[right_pos]); 589*59c8e88eSDag-Erling Smørgrav unsigned int right_section_len = right_idx - right_pos; 590*59c8e88eSDag-Erling Smørgrav 591*59c8e88eSDag-Erling Smørgrav if (left_section_len && right_section_len) { 592*59c8e88eSDag-Erling Smørgrav /* Record an unsolved chunk, the caller will apply 593*59c8e88eSDag-Erling Smørgrav * inner_algo() on this chunk. */ 594*59c8e88eSDag-Erling Smørgrav if (!diff_state_add_chunk(state, false, 595*59c8e88eSDag-Erling Smørgrav left_atom, left_section_len, 596*59c8e88eSDag-Erling Smørgrav right_atom, 597*59c8e88eSDag-Erling Smørgrav right_section_len)) 598*59c8e88eSDag-Erling Smørgrav goto free_and_exit; 599*59c8e88eSDag-Erling Smørgrav } else if (left_section_len && !right_section_len) { 600*59c8e88eSDag-Erling Smørgrav /* Only left atoms and none on the right, they form a 601*59c8e88eSDag-Erling Smørgrav * "minus" chunk, then. */ 602*59c8e88eSDag-Erling Smørgrav if (!diff_state_add_chunk(state, true, 603*59c8e88eSDag-Erling Smørgrav left_atom, left_section_len, 604*59c8e88eSDag-Erling Smørgrav right_atom, 0)) 605*59c8e88eSDag-Erling Smørgrav goto free_and_exit; 606*59c8e88eSDag-Erling Smørgrav } else if (!left_section_len && right_section_len) { 607*59c8e88eSDag-Erling Smørgrav /* No left atoms, only atoms on the right, they form a 608*59c8e88eSDag-Erling Smørgrav * "plus" chunk, then. */ 609*59c8e88eSDag-Erling Smørgrav if (!diff_state_add_chunk(state, true, 610*59c8e88eSDag-Erling Smørgrav left_atom, 0, 611*59c8e88eSDag-Erling Smørgrav right_atom, right_section_len)) 612*59c8e88eSDag-Erling Smørgrav goto free_and_exit; 613*59c8e88eSDag-Erling Smørgrav } 614*59c8e88eSDag-Erling Smørgrav /* else: left_section_len == 0 and right_section_len == 0, i.e. 615*59c8e88eSDag-Erling Smørgrav * nothing here. */ 616*59c8e88eSDag-Erling Smørgrav 617*59c8e88eSDag-Erling Smørgrav /* The atom found to match on both sides forms a chunk of equals 618*59c8e88eSDag-Erling Smørgrav * on each side. In the very last iteration of this loop, there 619*59c8e88eSDag-Erling Smørgrav * is no matching atom, we were just cleaning out the remaining 620*59c8e88eSDag-Erling Smørgrav * lines. */ 621*59c8e88eSDag-Erling Smørgrav if (atom) { 622*59c8e88eSDag-Erling Smørgrav void *ok; 623*59c8e88eSDag-Erling Smørgrav ok = diff_state_add_chunk(state, true, 624*59c8e88eSDag-Erling Smørgrav atom, 1, 625*59c8e88eSDag-Erling Smørgrav PATIENCE(atom).pos_in_other, 1); 626*59c8e88eSDag-Erling Smørgrav if (!ok) 627*59c8e88eSDag-Erling Smørgrav goto free_and_exit; 628*59c8e88eSDag-Erling Smørgrav } 629*59c8e88eSDag-Erling Smørgrav left_pos = left_idx + 1; 630*59c8e88eSDag-Erling Smørgrav right_pos = right_idx + 1; 631*59c8e88eSDag-Erling Smørgrav debug("end of iteration %u left_pos %u left_idx %u" 632*59c8e88eSDag-Erling Smørgrav " right_pos %u right_idx %u\n", 633*59c8e88eSDag-Erling Smørgrav i, left_pos, left_idx, right_pos, right_idx); 634*59c8e88eSDag-Erling Smørgrav } 635*59c8e88eSDag-Erling Smørgrav debug("** END %s\n", __func__); 636*59c8e88eSDag-Erling Smørgrav 637*59c8e88eSDag-Erling Smørgrav rc = DIFF_RC_OK; 638*59c8e88eSDag-Erling Smørgrav 639*59c8e88eSDag-Erling Smørgrav free_and_exit: 640*59c8e88eSDag-Erling Smørgrav left->root->current = NULL; 641*59c8e88eSDag-Erling Smørgrav right->root->current = NULL; 642*59c8e88eSDag-Erling Smørgrav free(atom_patience_left); 643*59c8e88eSDag-Erling Smørgrav free(atom_patience_right); 644*59c8e88eSDag-Erling Smørgrav if (lcs) 645*59c8e88eSDag-Erling Smørgrav free(lcs); 646*59c8e88eSDag-Erling Smørgrav return rc; 647*59c8e88eSDag-Erling Smørgrav } 648