1 3b0f3d61 2020-01-22 neels /* Generic infrastructure to implement various diff algorithms (implementation). */
3 3b0f3d61 2020-01-22 neels * Copyright (c) 2020 Neels Hofmeyr <neels@hofmeyr.de>
5 3b0f3d61 2020-01-22 neels * Permission to use, copy, modify, and distribute this software for any
6 3b0f3d61 2020-01-22 neels * purpose with or without fee is hereby granted, provided that the above
7 3b0f3d61 2020-01-22 neels * copyright notice and this permission notice appear in all copies.
9 3b0f3d61 2020-01-22 neels * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 3b0f3d61 2020-01-22 neels * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 3b0f3d61 2020-01-22 neels * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 3b0f3d61 2020-01-22 neels * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 3b0f3d61 2020-01-22 neels * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 3b0f3d61 2020-01-22 neels * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 3b0f3d61 2020-01-22 neels * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 3b0f3d61 2020-01-22 neels #include <sys/queue.h>
20 732e8ee0 2020-09-20 stsp #include <ctype.h>
21 e10a628a 2020-09-16 stsp #include <errno.h>
22 3b0f3d61 2020-01-22 neels #include <stdint.h>
23 3b0f3d61 2020-01-22 neels #include <stdlib.h>
24 3b0f3d61 2020-01-22 neels #include <stdbool.h>
25 3b0f3d61 2020-01-22 neels #include <stdio.h>
26 3b0f3d61 2020-01-22 neels #include <string.h>
27 3b0f3d61 2020-01-22 neels #include <limits.h>
28 c6eecea3 2020-07-26 stsp #include <unistd.h>
30 3b0f3d61 2020-01-22 neels #include <assert.h>
32 1dfba055 2020-10-07 stsp #include <arraylist.h>
33 1dfba055 2020-10-07 stsp #include <diff_main.h>
35 85ab4559 2020-09-22 stsp #include "diff_internal.h"
36 2a1b94d0 2020-09-26 stsp #include "diff_debug.h"
39 7a54ad3a 2020-09-20 stsp read_at(FILE *f, off_t at_pos, unsigned char *buf, size_t len)
42 7a54ad3a 2020-09-20 stsp if (fseeko(f, at_pos, SEEK_SET) == -1)
43 b3fb4686 2020-09-20 neels return errno;
44 7a54ad3a 2020-09-20 stsp r = fread(buf, sizeof(char), len, f);
45 7a54ad3a 2020-09-20 stsp if ((r == 0 || r < len) && ferror(f))
46 b3fb4686 2020-09-20 neels return errno;
47 b3fb4686 2020-09-20 neels if (r != len)
48 b3fb4686 2020-09-20 neels return EIO;
53 b3fb4686 2020-09-20 neels buf_cmp(const unsigned char *left, size_t left_len,
54 732e8ee0 2020-09-20 stsp const unsigned char *right, size_t right_len,
55 732e8ee0 2020-09-20 stsp bool ignore_whitespace)
59 732e8ee0 2020-09-20 stsp if (ignore_whitespace) {
60 732e8ee0 2020-09-20 stsp int il = 0, ir = 0;
61 732e8ee0 2020-09-20 stsp while (il < left_len && ir < right_len) {
62 732e8ee0 2020-09-20 stsp unsigned char cl = left[il];
63 732e8ee0 2020-09-20 stsp unsigned char cr = right[ir];
65 732e8ee0 2020-09-20 stsp if (isspace(cl) && il < left_len) {
69 732e8ee0 2020-09-20 stsp if (isspace(cr) && ir < right_len) {
74 732e8ee0 2020-09-20 stsp if (cl > cr)
76 732e8ee0 2020-09-20 stsp if (cr > cl)
81 732e8ee0 2020-09-20 stsp while (il < left_len) {
82 732e8ee0 2020-09-20 stsp unsigned char cl = left[il++];
83 732e8ee0 2020-09-20 stsp if (!isspace(cl))
86 732e8ee0 2020-09-20 stsp while (ir < right_len) {
87 732e8ee0 2020-09-20 stsp unsigned char cr = right[ir++];
88 732e8ee0 2020-09-20 stsp if (!isspace(cr))
95 732e8ee0 2020-09-20 stsp cmp = memcmp(left, right, MIN(left_len, right_len));
97 b3fb4686 2020-09-20 neels return cmp;
98 b3fb4686 2020-09-20 neels if (left_len == right_len)
100 b3fb4686 2020-09-20 neels return (left_len > right_len) ? 1 : -1;
104 b3fb4686 2020-09-20 neels diff_atom_cmp(int *cmp,
105 b3fb4686 2020-09-20 neels const struct diff_atom *left,
106 b3fb4686 2020-09-20 neels const struct diff_atom *right)
108 c6eecea3 2020-07-26 stsp off_t remain_left, remain_right;
109 00d5652b 2020-09-22 stsp int flags = (left->d->root->diff_flags | right->d->root->diff_flags);
110 00d5652b 2020-09-22 stsp bool ignore_whitespace = (flags & DIFF_FLAG_IGNORE_WHITESPACE);
112 732e8ee0 2020-09-20 stsp if (!ignore_whitespace) {
113 732e8ee0 2020-09-20 stsp if (!left->len && !right->len) {
117 732e8ee0 2020-09-20 stsp if (!right->len) {
121 732e8ee0 2020-09-20 stsp if (!left->len) {
127 b3fb4686 2020-09-20 neels if (left->at != NULL && right->at != NULL) {
128 732e8ee0 2020-09-20 stsp *cmp = buf_cmp(left->at, left->len, right->at, right->len,
129 732e8ee0 2020-09-20 stsp ignore_whitespace);
133 c6eecea3 2020-07-26 stsp remain_left = left->len;
134 c6eecea3 2020-07-26 stsp remain_right = right->len;
135 c6eecea3 2020-07-26 stsp while (remain_left > 0 || remain_right > 0) {
136 c6eecea3 2020-07-26 stsp const size_t chunksz = 8192;
137 c6eecea3 2020-07-26 stsp unsigned char buf_left[chunksz], buf_right[chunksz];
138 c6eecea3 2020-07-26 stsp const uint8_t *p_left, *p_right;
139 c6eecea3 2020-07-26 stsp off_t n_left, n_right;
142 b3fb4686 2020-09-20 neels if (!remain_right) {
146 b3fb4686 2020-09-20 neels if (!remain_left) {
147 b3fb4686 2020-09-20 neels *cmp = -1;
151 c6eecea3 2020-07-26 stsp n_left = MIN(chunksz, remain_left);
152 c6eecea3 2020-07-26 stsp n_right = MIN(chunksz, remain_right);
154 c6eecea3 2020-07-26 stsp if (left->at == NULL) {
155 7a54ad3a 2020-09-20 stsp r = read_at(left->d->root->f,
156 b3fb4686 2020-09-20 neels left->pos + (left->len - remain_left),
157 b3fb4686 2020-09-20 neels buf_left, n_left);
162 c6eecea3 2020-07-26 stsp p_left = buf_left;
164 c6eecea3 2020-07-26 stsp p_left = left->at + (left->len - remain_left);
167 c6eecea3 2020-07-26 stsp if (right->at == NULL) {
168 7a54ad3a 2020-09-20 stsp r = read_at(right->d->root->f,
169 b3fb4686 2020-09-20 neels right->pos + (right->len - remain_right),
170 b3fb4686 2020-09-20 neels buf_right, n_right);
175 c6eecea3 2020-07-26 stsp p_right = buf_right;
177 c6eecea3 2020-07-26 stsp p_right = right->at + (right->len - remain_right);
180 732e8ee0 2020-09-20 stsp r = buf_cmp(p_left, n_left, p_right, n_right,
181 732e8ee0 2020-09-20 stsp ignore_whitespace);
187 c6eecea3 2020-07-26 stsp remain_left -= n_left;
188 c6eecea3 2020-07-26 stsp remain_right -= n_right;
196 b3fb4686 2020-09-20 neels diff_atom_same(bool *same,
197 b3fb4686 2020-09-20 neels const struct diff_atom *left,
198 b3fb4686 2020-09-20 neels const struct diff_atom *right)
201 b3fb4686 2020-09-20 neels int r = diff_atom_cmp(&cmp, left, right);
203 b3fb4686 2020-09-20 neels *same = true;
206 b3fb4686 2020-09-20 neels *same = (cmp == 0);
210 0d27172a 2020-05-06 neels /* Even if a left or right side is empty, diff output may need to know the
211 0d27172a 2020-05-06 neels * position in that file.
212 0d27172a 2020-05-06 neels * So left_start or right_start must never be NULL -- pass left_count or
213 0d27172a 2020-05-06 neels * right_count as zero to indicate staying at that position without consuming
214 0d27172a 2020-05-06 neels * any lines. */
215 61a7b578 2020-05-06 neels struct diff_chunk *
216 61a7b578 2020-05-06 neels diff_state_add_chunk(struct diff_state *state, bool solved,
217 61a7b578 2020-05-06 neels struct diff_atom *left_start, unsigned int left_count,
218 61a7b578 2020-05-06 neels struct diff_atom *right_start, unsigned int right_count)
220 8546b045 2020-09-20 neels diff_chunk_arraylist_t *result = NULL;
221 8546b045 2020-09-20 neels struct diff_chunk *new_chunk;
222 8546b045 2020-09-20 neels struct diff_chunk chunk = {
223 3b0f3d61 2020-01-22 neels .solved = solved,
224 3b0f3d61 2020-01-22 neels .left_start = left_start,
225 3b0f3d61 2020-01-22 neels .left_count = left_count,
226 3b0f3d61 2020-01-22 neels .right_start = right_start,
227 3b0f3d61 2020-01-22 neels .right_count = right_count,
229 8546b045 2020-09-20 neels enum diff_chunk_type last_t;
230 8546b045 2020-09-20 neels enum diff_chunk_type prev_last_t;
231 8546b045 2020-09-20 neels enum diff_chunk_type new_t;
233 8546b045 2020-09-20 neels if (!solved || state->temp_result.len) {
234 8546b045 2020-09-20 neels /* Append to temp_result */
235 8546b045 2020-09-20 neels result = &state->temp_result;
236 8546b045 2020-09-20 neels } else if (!state->result->chunks.len) {
237 8546b045 2020-09-20 neels /* Append to final result */
238 8546b045 2020-09-20 neels result = &state->result->chunks;
240 8546b045 2020-09-20 neels if (result) {
241 8546b045 2020-09-20 neels ARRAYLIST_ADD(new_chunk, *result);
242 8546b045 2020-09-20 neels if (!new_chunk)
243 8546b045 2020-09-20 neels return NULL;
244 8546b045 2020-09-20 neels *new_chunk = chunk;
245 8546b045 2020-09-20 neels goto chunk_added;
248 8546b045 2020-09-20 neels /* Append to solved chunks; make sure that adjacent chunks of same type are combined, and that a minus chunk
249 8546b045 2020-09-20 neels * never directly follows a plus chunk. */
250 8546b045 2020-09-20 neels result = &state->result->chunks;
252 8546b045 2020-09-20 neels prev_last_t = result->len > 1 ?
253 8546b045 2020-09-20 neels diff_chunk_type(&result->head[result->len - 2]) : CHUNK_EMPTY;
254 8546b045 2020-09-20 neels last_t = diff_chunk_type(&result->head[result->len - 1]);
255 8546b045 2020-09-20 neels new_t = diff_chunk_type(&chunk);
257 8546b045 2020-09-20 neels if (new_t == last_t) {
258 8546b045 2020-09-20 neels new_chunk = &result->head[result->len - 1];
259 8546b045 2020-09-20 neels new_chunk->left_count += chunk.left_count;
260 8546b045 2020-09-20 neels new_chunk->right_count += chunk.right_count;
261 8546b045 2020-09-20 neels } else if (last_t == CHUNK_PLUS && new_t == CHUNK_MINUS) {
262 8546b045 2020-09-20 neels /* If a minus-chunk follows a plus-chunk, place it above the plus-chunk.
263 8546b045 2020-09-20 neels * Is the one before that also a minus? combine. */
264 8546b045 2020-09-20 neels if (prev_last_t == CHUNK_MINUS) {
265 8546b045 2020-09-20 neels new_chunk = &result->head[result->len - 2];
266 8546b045 2020-09-20 neels new_chunk->left_count += chunk.left_count;
267 8546b045 2020-09-20 neels new_chunk->right_count += chunk.right_count;
269 8546b045 2020-09-20 neels ARRAYLIST_INSERT(new_chunk, *result, result->len - 2);
270 8546b045 2020-09-20 neels if (!new_chunk)
271 8546b045 2020-09-20 neels return NULL;
272 8546b045 2020-09-20 neels *new_chunk = chunk;
275 8546b045 2020-09-20 neels ARRAYLIST_ADD(new_chunk, *result);
276 8546b045 2020-09-20 neels if (!new_chunk)
277 8546b045 2020-09-20 neels return NULL;
278 8546b045 2020-09-20 neels *new_chunk = chunk;
279 8546b045 2020-09-20 neels goto chunk_added;
282 8546b045 2020-09-20 neels chunk_added:
283 8546b045 2020-09-20 neels debug("Add %s chunk:\n", new_chunk->solved ? "solved" : "UNSOLVED");
284 8546b045 2020-09-20 neels debug("L\n");
285 8546b045 2020-09-20 neels debug_dump_atoms(&state->left, new_chunk->left_start, new_chunk->left_count);
286 3b0f3d61 2020-01-22 neels debug("R\n");
287 8546b045 2020-09-20 neels debug_dump_atoms(&state->right, new_chunk->right_start, new_chunk->right_count);
288 8546b045 2020-09-20 neels return new_chunk;
292 7a54ad3a 2020-09-20 stsp diff_data_init_root(struct diff_data *d, FILE *f, const uint8_t *data,
293 00d5652b 2020-09-22 stsp unsigned long long len, int diff_flags)
295 3b0f3d61 2020-01-22 neels *d = (struct diff_data){
298 3b0f3d61 2020-01-22 neels .data = data,
299 3b0f3d61 2020-01-22 neels .len = len,
300 3b0f3d61 2020-01-22 neels .root = d,
301 00d5652b 2020-09-22 stsp .diff_flags = diff_flags,
306 61a7b578 2020-05-06 neels diff_data_init_subsection(struct diff_data *d, struct diff_data *parent,
307 61a7b578 2020-05-06 neels struct diff_atom *from_atom, unsigned int atoms_count)
309 05b5f01f 2020-09-21 stsp struct diff_atom *last_atom;
311 05b5f01f 2020-09-21 stsp if (atoms_count == 0) {
312 05b5f01f 2020-09-21 stsp *d = (struct diff_data){
315 05b5f01f 2020-09-21 stsp .data = "",
317 05b5f01f 2020-09-21 stsp .root = parent->root,
318 05b5f01f 2020-09-21 stsp .atoms.head = NULL,
319 05b5f01f 2020-09-21 stsp .atoms.len = atoms_count,
325 05b5f01f 2020-09-21 stsp last_atom = from_atom + atoms_count - 1;
326 3b0f3d61 2020-01-22 neels *d = (struct diff_data){
328 c6eecea3 2020-07-26 stsp .pos = from_atom->pos,
329 3b0f3d61 2020-01-22 neels .data = from_atom->at,
330 c6eecea3 2020-07-26 stsp .len = (last_atom->pos + last_atom->len) - from_atom->pos,
331 3b0f3d61 2020-01-22 neels .root = parent->root,
332 3b0f3d61 2020-01-22 neels .atoms.head = from_atom,
333 3b0f3d61 2020-01-22 neels .atoms.len = atoms_count,
336 3b0f3d61 2020-01-22 neels debug("subsection:\n");
337 3b0f3d61 2020-01-22 neels debug_dump(d);
341 61a7b578 2020-05-06 neels diff_data_free(struct diff_data *diff_data)
343 3b0f3d61 2020-01-22 neels if (!diff_data)
345 3b0f3d61 2020-01-22 neels if (diff_data->atoms.allocated)
346 3b0f3d61 2020-01-22 neels ARRAYLIST_FREE(diff_data->atoms);
350 0d27172a 2020-05-06 neels diff_algo_none(const struct diff_algo_config *algo_config,
351 0d27172a 2020-05-06 neels struct diff_state *state)
353 3b0f3d61 2020-01-22 neels debug("\n** %s\n", __func__);
354 3b0f3d61 2020-01-22 neels debug("left:\n");
355 3b0f3d61 2020-01-22 neels debug_dump(&state->left);
356 3b0f3d61 2020-01-22 neels debug("right:\n");
357 3b0f3d61 2020-01-22 neels debug_dump(&state->right);
358 0d27172a 2020-05-06 neels debug_dump_myers_graph(&state->left, &state->right, NULL, NULL, 0, NULL,
361 3b0f3d61 2020-01-22 neels /* Add a chunk of equal lines, if any */
362 3b0f3d61 2020-01-22 neels unsigned int equal_atoms = 0;
363 0d27172a 2020-05-06 neels while (equal_atoms < state->left.atoms.len
364 b3fb4686 2020-09-20 neels && equal_atoms < state->right.atoms.len) {
366 b3fb4686 2020-09-20 neels bool same;
367 b3fb4686 2020-09-20 neels r = diff_atom_same(&same, &state->left.atoms.head[equal_atoms],
368 b3fb4686 2020-09-20 neels &state->right.atoms.head[equal_atoms]);
371 b3fb4686 2020-09-20 neels if (!same)
373 3b0f3d61 2020-01-22 neels equal_atoms++;
375 3b0f3d61 2020-01-22 neels if (equal_atoms) {
376 3b0f3d61 2020-01-22 neels if (!diff_state_add_chunk(state, true,
377 0d27172a 2020-05-06 neels &state->left.atoms.head[0],
378 0d27172a 2020-05-06 neels equal_atoms,
379 0d27172a 2020-05-06 neels &state->right.atoms.head[0],
380 0d27172a 2020-05-06 neels equal_atoms))
381 3e6cba3a 2020-08-13 stsp return ENOMEM;
384 3b0f3d61 2020-01-22 neels /* Add a "minus" chunk with all lines from the left. */
385 3b0f3d61 2020-01-22 neels if (equal_atoms < state->left.atoms.len) {
386 3b0f3d61 2020-01-22 neels if (!diff_state_add_chunk(state, true,
387 3b0f3d61 2020-01-22 neels &state->left.atoms.head[equal_atoms],
388 3b0f3d61 2020-01-22 neels state->left.atoms.len - equal_atoms,
390 3e6cba3a 2020-08-13 stsp return ENOMEM;
393 3b0f3d61 2020-01-22 neels /* Add a "plus" chunk with all lines from the right. */
394 3b0f3d61 2020-01-22 neels if (equal_atoms < state->right.atoms.len) {
395 3b0f3d61 2020-01-22 neels if (!diff_state_add_chunk(state, true,
397 3b0f3d61 2020-01-22 neels &state->right.atoms.head[equal_atoms],
398 3b0f3d61 2020-01-22 neels state->right.atoms.len - equal_atoms))
399 3e6cba3a 2020-08-13 stsp return ENOMEM;
401 3b0f3d61 2020-01-22 neels return DIFF_RC_OK;
405 0d27172a 2020-05-06 neels diff_run_algo(const struct diff_algo_config *algo_config,
406 0d27172a 2020-05-06 neels struct diff_state *state)
409 3b0f3d61 2020-01-22 neels ARRAYLIST_FREE(state->temp_result);
411 0d27172a 2020-05-06 neels if (!algo_config || !algo_config->impl
412 0d27172a 2020-05-06 neels || !state->recursion_depth_left) {
413 3b0f3d61 2020-01-22 neels debug("MAX RECURSION REACHED, just dumping diff chunks\n");
414 3b0f3d61 2020-01-22 neels return diff_algo_none(algo_config, state);
417 3b0f3d61 2020-01-22 neels ARRAYLIST_INIT(state->temp_result, DIFF_RESULT_ALLOC_BLOCKSIZE);
418 3b0f3d61 2020-01-22 neels rc = algo_config->impl(algo_config, state);
419 3b0f3d61 2020-01-22 neels switch (rc) {
420 3b0f3d61 2020-01-22 neels case DIFF_RC_USE_DIFF_ALGO_FALLBACK:
421 0d27172a 2020-05-06 neels debug("Got DIFF_RC_USE_DIFF_ALGO_FALLBACK (%p)\n",
422 0d27172a 2020-05-06 neels algo_config->fallback_algo);
423 3b0f3d61 2020-01-22 neels rc = diff_run_algo(algo_config->fallback_algo, state);
424 3b0f3d61 2020-01-22 neels goto return_rc;
426 3b0f3d61 2020-01-22 neels case DIFF_RC_OK:
427 3b0f3d61 2020-01-22 neels /* continue below */
431 3b0f3d61 2020-01-22 neels /* some error happened */
432 3b0f3d61 2020-01-22 neels goto return_rc;
435 0d27172a 2020-05-06 neels /* Pick up any diff chunks that are still unsolved and feed to
436 0d27172a 2020-05-06 neels * inner_algo. inner_algo will solve unsolved chunks and append to
437 0d27172a 2020-05-06 neels * result, and subsequent solved chunks on this level are then appended
438 0d27172a 2020-05-06 neels * to result afterwards. */
440 3b0f3d61 2020-01-22 neels for (i = 0; i < state->temp_result.len; i++) {
441 3b0f3d61 2020-01-22 neels struct diff_chunk *c = &state->temp_result.head[i];
442 3b0f3d61 2020-01-22 neels if (c->solved) {
443 3b0f3d61 2020-01-22 neels struct diff_chunk *final_c;
444 3b0f3d61 2020-01-22 neels ARRAYLIST_ADD(final_c, state->result->chunks);
445 3b0f3d61 2020-01-22 neels if (!final_c) {
446 3e6cba3a 2020-08-13 stsp rc = ENOMEM;
447 3b0f3d61 2020-01-22 neels goto return_rc;
449 3b0f3d61 2020-01-22 neels *final_c = *c;
453 3b0f3d61 2020-01-22 neels /* c is an unsolved chunk, feed to inner_algo */
454 3b0f3d61 2020-01-22 neels struct diff_state inner_state = {
455 3b0f3d61 2020-01-22 neels .result = state->result,
456 3b0f3d61 2020-01-22 neels .recursion_depth_left = state->recursion_depth_left - 1,
458 0d27172a 2020-05-06 neels diff_data_init_subsection(&inner_state.left, &state->left,
459 0d27172a 2020-05-06 neels c->left_start, c->left_count);
460 0d27172a 2020-05-06 neels diff_data_init_subsection(&inner_state.right, &state->right,
461 0d27172a 2020-05-06 neels c->right_start, c->right_count);
463 3b0f3d61 2020-01-22 neels rc = diff_run_algo(algo_config->inner_algo, &inner_state);
465 3b0f3d61 2020-01-22 neels if (rc != DIFF_RC_OK)
466 3b0f3d61 2020-01-22 neels goto return_rc;
469 3b0f3d61 2020-01-22 neels rc = DIFF_RC_OK;
470 3b0f3d61 2020-01-22 neels return_rc:
471 3b0f3d61 2020-01-22 neels ARRAYLIST_FREE(state->temp_result);
472 3b0f3d61 2020-01-22 neels return rc;
475 61a7b578 2020-05-06 neels struct diff_result *
476 61a7b578 2020-05-06 neels diff_main(const struct diff_config *config,
477 7a54ad3a 2020-09-20 stsp FILE *left_f, const uint8_t *left_data, off_t left_len,
478 7a54ad3a 2020-09-20 stsp FILE *right_f, const uint8_t *right_data, off_t right_len,
479 00d5652b 2020-09-22 stsp int diff_flags)
481 3b0f3d61 2020-01-22 neels struct diff_result *result = malloc(sizeof(struct diff_result));
482 3b0f3d61 2020-01-22 neels if (!result)
483 3b0f3d61 2020-01-22 neels return NULL;
485 3b0f3d61 2020-01-22 neels *result = (struct diff_result){};
486 7a54ad3a 2020-09-20 stsp diff_data_init_root(&result->left, left_f, left_data, left_len,
487 00d5652b 2020-09-22 stsp diff_flags);
488 7a54ad3a 2020-09-20 stsp diff_data_init_root(&result->right, right_f, right_data, right_len,
489 00d5652b 2020-09-22 stsp diff_flags);
491 3b0f3d61 2020-01-22 neels if (!config->atomize_func) {
492 3e6cba3a 2020-08-13 stsp result->rc = EINVAL;
493 3b0f3d61 2020-01-22 neels return result;
496 0d27172a 2020-05-06 neels result->rc = config->atomize_func(config->atomize_func_data,
497 0d27172a 2020-05-06 neels &result->left, &result->right);
498 3b0f3d61 2020-01-22 neels if (result->rc != DIFF_RC_OK)
499 3b0f3d61 2020-01-22 neels return result;
501 3b0f3d61 2020-01-22 neels struct diff_state state = {
502 3b0f3d61 2020-01-22 neels .result = result,
503 00961134 2020-09-20 stsp .recursion_depth_left = config->max_recursion_depth ? : 32,
505 0d27172a 2020-05-06 neels diff_data_init_subsection(&state.left, &result->left,
506 0d27172a 2020-05-06 neels result->left.atoms.head,
507 0d27172a 2020-05-06 neels result->left.atoms.len);
508 0d27172a 2020-05-06 neels diff_data_init_subsection(&state.right, &result->right,
509 0d27172a 2020-05-06 neels result->right.atoms.head,
510 0d27172a 2020-05-06 neels result->right.atoms.len);
512 3b0f3d61 2020-01-22 neels result->rc = diff_run_algo(config->algo, &state);
514 3b0f3d61 2020-01-22 neels return result;
518 61a7b578 2020-05-06 neels diff_result_free(struct diff_result *result)
520 3b0f3d61 2020-01-22 neels if (!result)
522 3b0f3d61 2020-01-22 neels diff_data_free(&result->left);
523 3b0f3d61 2020-01-22 neels diff_data_free(&result->right);
524 3b0f3d61 2020-01-22 neels ARRAYLIST_FREE(result->chunks);
525 3b0f3d61 2020-01-22 neels free(result);