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
diff_atoms_mark_unique(struct diff_data * d,unsigned int * unique_count)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
diff_atoms_mark_unique_in_both(struct diff_data * left,struct diff_data * right,unsigned int * unique_in_both_count)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
diff_atoms_compar(const void * _a,const void * _b)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. */
diff_atoms_sort(struct diff_atom * atoms[],size_t atoms_count)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
diff_atoms_mark_unique_in_both(struct diff_data * left,struct diff_data * right,unsigned int * unique_in_both_count_p)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
find_target_stack(struct diff_atom * atom,struct diff_atom ** patience_stacks,unsigned int patience_stacks_count)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
diff_algo_patience(const struct diff_algo_config * algo_config,struct diff_state * state)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