1*59c8e88eSDag-Erling Smørgrav /*
2*59c8e88eSDag-Erling Smørgrav * Copyright (c) 2020 Neels Hofmeyr <neels@hofmeyr.de>
3*59c8e88eSDag-Erling Smørgrav *
4*59c8e88eSDag-Erling Smørgrav * Permission to use, copy, modify, and distribute this software for any
5*59c8e88eSDag-Erling Smørgrav * purpose with or without fee is hereby granted, provided that the above
6*59c8e88eSDag-Erling Smørgrav * copyright notice and this permission notice appear in all copies.
7*59c8e88eSDag-Erling Smørgrav *
8*59c8e88eSDag-Erling Smørgrav * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9*59c8e88eSDag-Erling Smørgrav * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10*59c8e88eSDag-Erling Smørgrav * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11*59c8e88eSDag-Erling Smørgrav * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12*59c8e88eSDag-Erling Smørgrav * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13*59c8e88eSDag-Erling Smørgrav * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14*59c8e88eSDag-Erling Smørgrav * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15*59c8e88eSDag-Erling Smørgrav */
16*59c8e88eSDag-Erling Smørgrav
17*59c8e88eSDag-Erling Smørgrav #define DEBUG 0
18*59c8e88eSDag-Erling Smørgrav
19*59c8e88eSDag-Erling Smørgrav #if DEBUG
20*59c8e88eSDag-Erling Smørgrav #include <stdio.h>
21*59c8e88eSDag-Erling Smørgrav #include <unistd.h>
22*59c8e88eSDag-Erling Smørgrav #define print(args...) fprintf(stderr, ##args)
23*59c8e88eSDag-Erling Smørgrav #define debug print
24*59c8e88eSDag-Erling Smørgrav #define debug_dump dump
25*59c8e88eSDag-Erling Smørgrav #define debug_dump_atom dump_atom
26*59c8e88eSDag-Erling Smørgrav #define debug_dump_atoms dump_atoms
27*59c8e88eSDag-Erling Smørgrav
28*59c8e88eSDag-Erling Smørgrav static inline void
print_atom_byte(unsigned char c)29*59c8e88eSDag-Erling Smørgrav print_atom_byte(unsigned char c) {
30*59c8e88eSDag-Erling Smørgrav if (c == '\r')
31*59c8e88eSDag-Erling Smørgrav print("\\r");
32*59c8e88eSDag-Erling Smørgrav else if (c == '\n')
33*59c8e88eSDag-Erling Smørgrav print("\\n");
34*59c8e88eSDag-Erling Smørgrav else if ((c < 32 || c >= 127) && (c != '\t'))
35*59c8e88eSDag-Erling Smørgrav print("\\x%02x", c);
36*59c8e88eSDag-Erling Smørgrav else
37*59c8e88eSDag-Erling Smørgrav print("%c", c);
38*59c8e88eSDag-Erling Smørgrav }
39*59c8e88eSDag-Erling Smørgrav
40*59c8e88eSDag-Erling Smørgrav static inline void
dump_atom(const struct diff_data * left,const struct diff_data * right,const struct diff_atom * atom)41*59c8e88eSDag-Erling Smørgrav dump_atom(const struct diff_data *left, const struct diff_data *right,
42*59c8e88eSDag-Erling Smørgrav const struct diff_atom *atom)
43*59c8e88eSDag-Erling Smørgrav {
44*59c8e88eSDag-Erling Smørgrav if (!atom) {
45*59c8e88eSDag-Erling Smørgrav print("NULL atom\n");
46*59c8e88eSDag-Erling Smørgrav return;
47*59c8e88eSDag-Erling Smørgrav }
48*59c8e88eSDag-Erling Smørgrav if (left)
49*59c8e88eSDag-Erling Smørgrav print(" %3u '", diff_atom_root_idx(left, atom));
50*59c8e88eSDag-Erling Smørgrav
51*59c8e88eSDag-Erling Smørgrav if (atom->at == NULL) {
52*59c8e88eSDag-Erling Smørgrav off_t remain = atom->len;
53*59c8e88eSDag-Erling Smørgrav if (fseek(atom->root->f, atom->pos, SEEK_SET) == -1)
54*59c8e88eSDag-Erling Smørgrav abort(); /* cannot return error */
55*59c8e88eSDag-Erling Smørgrav while (remain > 0) {
56*59c8e88eSDag-Erling Smørgrav char buf[16];
57*59c8e88eSDag-Erling Smørgrav size_t r;
58*59c8e88eSDag-Erling Smørgrav int i;
59*59c8e88eSDag-Erling Smørgrav r = fread(buf, 1, MIN(remain, sizeof(buf)),
60*59c8e88eSDag-Erling Smørgrav atom->root->f);
61*59c8e88eSDag-Erling Smørgrav if (r == 0)
62*59c8e88eSDag-Erling Smørgrav break;
63*59c8e88eSDag-Erling Smørgrav remain -= r;
64*59c8e88eSDag-Erling Smørgrav for (i = 0; i < r; i++)
65*59c8e88eSDag-Erling Smørgrav print_atom_byte(buf[i]);
66*59c8e88eSDag-Erling Smørgrav }
67*59c8e88eSDag-Erling Smørgrav } else {
68*59c8e88eSDag-Erling Smørgrav const char *s;
69*59c8e88eSDag-Erling Smørgrav for (s = atom->at; s < (const char*)(atom->at + atom->len); s++)
70*59c8e88eSDag-Erling Smørgrav print_atom_byte(*s);
71*59c8e88eSDag-Erling Smørgrav }
72*59c8e88eSDag-Erling Smørgrav print("'\n");
73*59c8e88eSDag-Erling Smørgrav }
74*59c8e88eSDag-Erling Smørgrav
75*59c8e88eSDag-Erling Smørgrav static inline void
dump_atoms(const struct diff_data * d,struct diff_atom * atom,unsigned int count)76*59c8e88eSDag-Erling Smørgrav dump_atoms(const struct diff_data *d, struct diff_atom *atom,
77*59c8e88eSDag-Erling Smørgrav unsigned int count)
78*59c8e88eSDag-Erling Smørgrav {
79*59c8e88eSDag-Erling Smørgrav if (count > 42) {
80*59c8e88eSDag-Erling Smørgrav dump_atoms(d, atom, 20);
81*59c8e88eSDag-Erling Smørgrav print("[%u lines skipped]\n", count - 20 - 20);
82*59c8e88eSDag-Erling Smørgrav dump_atoms(d, atom + count - 20, 20);
83*59c8e88eSDag-Erling Smørgrav return;
84*59c8e88eSDag-Erling Smørgrav } else {
85*59c8e88eSDag-Erling Smørgrav struct diff_atom *i;
86*59c8e88eSDag-Erling Smørgrav foreach_diff_atom(i, atom, count) {
87*59c8e88eSDag-Erling Smørgrav dump_atom(d, NULL, i);
88*59c8e88eSDag-Erling Smørgrav }
89*59c8e88eSDag-Erling Smørgrav }
90*59c8e88eSDag-Erling Smørgrav }
91*59c8e88eSDag-Erling Smørgrav
92*59c8e88eSDag-Erling Smørgrav static inline void
dump(struct diff_data * d)93*59c8e88eSDag-Erling Smørgrav dump(struct diff_data *d)
94*59c8e88eSDag-Erling Smørgrav {
95*59c8e88eSDag-Erling Smørgrav dump_atoms(d, d->atoms.head, d->atoms.len);
96*59c8e88eSDag-Erling Smørgrav }
97*59c8e88eSDag-Erling Smørgrav
98*59c8e88eSDag-Erling Smørgrav /* kd is a quadratic space myers matrix from the original Myers algorithm.
99*59c8e88eSDag-Erling Smørgrav * kd_forward and kd_backward are linear slices of a myers matrix from the Myers
100*59c8e88eSDag-Erling Smørgrav * Divide algorithm.
101*59c8e88eSDag-Erling Smørgrav */
102*59c8e88eSDag-Erling Smørgrav static inline void
dump_myers_graph(const struct diff_data * l,const struct diff_data * r,int * kd,int * kd_forward,int kd_forward_d,int * kd_backward,int kd_backward_d)103*59c8e88eSDag-Erling Smørgrav dump_myers_graph(const struct diff_data *l, const struct diff_data *r,
104*59c8e88eSDag-Erling Smørgrav int *kd, int *kd_forward, int kd_forward_d,
105*59c8e88eSDag-Erling Smørgrav int *kd_backward, int kd_backward_d)
106*59c8e88eSDag-Erling Smørgrav {
107*59c8e88eSDag-Erling Smørgrav #define COLOR_YELLOW "\033[1;33m"
108*59c8e88eSDag-Erling Smørgrav #define COLOR_GREEN "\033[1;32m"
109*59c8e88eSDag-Erling Smørgrav #define COLOR_BLUE "\033[1;34m"
110*59c8e88eSDag-Erling Smørgrav #define COLOR_RED "\033[1;31m"
111*59c8e88eSDag-Erling Smørgrav #define COLOR_END "\033[0;m"
112*59c8e88eSDag-Erling Smørgrav int x;
113*59c8e88eSDag-Erling Smørgrav int y;
114*59c8e88eSDag-Erling Smørgrav print(" ");
115*59c8e88eSDag-Erling Smørgrav for (x = 0; x <= l->atoms.len; x++)
116*59c8e88eSDag-Erling Smørgrav print("%2d", x % 100);
117*59c8e88eSDag-Erling Smørgrav print("\n");
118*59c8e88eSDag-Erling Smørgrav
119*59c8e88eSDag-Erling Smørgrav for (y = 0; y <= r->atoms.len; y++) {
120*59c8e88eSDag-Erling Smørgrav print("%3d ", y);
121*59c8e88eSDag-Erling Smørgrav for (x = 0; x <= l->atoms.len; x++) {
122*59c8e88eSDag-Erling Smørgrav
123*59c8e88eSDag-Erling Smørgrav /* print d advancements from kd, if any. */
124*59c8e88eSDag-Erling Smørgrav char label = 'o';
125*59c8e88eSDag-Erling Smørgrav char *color = NULL;
126*59c8e88eSDag-Erling Smørgrav if (kd) {
127*59c8e88eSDag-Erling Smørgrav int max = l->atoms.len + r->atoms.len;
128*59c8e88eSDag-Erling Smørgrav size_t kd_len = max + 1 + max;
129*59c8e88eSDag-Erling Smørgrav int *kd_pos = kd;
130*59c8e88eSDag-Erling Smørgrav int di;
131*59c8e88eSDag-Erling Smørgrav #define xk_to_y(X, K) ((X) - (K))
132*59c8e88eSDag-Erling Smørgrav for (di = 0; di < max; di++) {
133*59c8e88eSDag-Erling Smørgrav int ki;
134*59c8e88eSDag-Erling Smørgrav for (ki = di; ki >= -di; ki -= 2) {
135*59c8e88eSDag-Erling Smørgrav if (x != kd_pos[ki]
136*59c8e88eSDag-Erling Smørgrav || y != xk_to_y(x, ki))
137*59c8e88eSDag-Erling Smørgrav continue;
138*59c8e88eSDag-Erling Smørgrav label = '0' + (di % 10);
139*59c8e88eSDag-Erling Smørgrav color = COLOR_YELLOW;
140*59c8e88eSDag-Erling Smørgrav break;
141*59c8e88eSDag-Erling Smørgrav }
142*59c8e88eSDag-Erling Smørgrav if (label != 'o')
143*59c8e88eSDag-Erling Smørgrav break;
144*59c8e88eSDag-Erling Smørgrav kd_pos += kd_len;
145*59c8e88eSDag-Erling Smørgrav }
146*59c8e88eSDag-Erling Smørgrav }
147*59c8e88eSDag-Erling Smørgrav if (kd_forward && kd_forward_d >= 0) {
148*59c8e88eSDag-Erling Smørgrav #define xc_to_y(X, C, DELTA) ((X) - (C) + (DELTA))
149*59c8e88eSDag-Erling Smørgrav int ki;
150*59c8e88eSDag-Erling Smørgrav for (ki = kd_forward_d;
151*59c8e88eSDag-Erling Smørgrav ki >= -kd_forward_d;
152*59c8e88eSDag-Erling Smørgrav ki -= 2) {
153*59c8e88eSDag-Erling Smørgrav if (x != kd_forward[ki])
154*59c8e88eSDag-Erling Smørgrav continue;
155*59c8e88eSDag-Erling Smørgrav if (y != xk_to_y(x, ki))
156*59c8e88eSDag-Erling Smørgrav continue;
157*59c8e88eSDag-Erling Smørgrav label = 'F';
158*59c8e88eSDag-Erling Smørgrav color = COLOR_GREEN;
159*59c8e88eSDag-Erling Smørgrav break;
160*59c8e88eSDag-Erling Smørgrav }
161*59c8e88eSDag-Erling Smørgrav }
162*59c8e88eSDag-Erling Smørgrav if (kd_backward && kd_backward_d >= 0) {
163*59c8e88eSDag-Erling Smørgrav int delta = (int)r->atoms.len
164*59c8e88eSDag-Erling Smørgrav - (int)l->atoms.len;
165*59c8e88eSDag-Erling Smørgrav int ki;
166*59c8e88eSDag-Erling Smørgrav for (ki = kd_backward_d;
167*59c8e88eSDag-Erling Smørgrav ki >= -kd_backward_d;
168*59c8e88eSDag-Erling Smørgrav ki -= 2) {
169*59c8e88eSDag-Erling Smørgrav if (x != kd_backward[ki])
170*59c8e88eSDag-Erling Smørgrav continue;
171*59c8e88eSDag-Erling Smørgrav if (y != xc_to_y(x, ki, delta))
172*59c8e88eSDag-Erling Smørgrav continue;
173*59c8e88eSDag-Erling Smørgrav if (label == 'o') {
174*59c8e88eSDag-Erling Smørgrav label = 'B';
175*59c8e88eSDag-Erling Smørgrav color = COLOR_BLUE;
176*59c8e88eSDag-Erling Smørgrav } else {
177*59c8e88eSDag-Erling Smørgrav label = 'X';
178*59c8e88eSDag-Erling Smørgrav color = COLOR_RED;
179*59c8e88eSDag-Erling Smørgrav }
180*59c8e88eSDag-Erling Smørgrav break;
181*59c8e88eSDag-Erling Smørgrav }
182*59c8e88eSDag-Erling Smørgrav }
183*59c8e88eSDag-Erling Smørgrav if (color)
184*59c8e88eSDag-Erling Smørgrav print("%s", color);
185*59c8e88eSDag-Erling Smørgrav print("%c", label);
186*59c8e88eSDag-Erling Smørgrav if (color)
187*59c8e88eSDag-Erling Smørgrav print("%s", COLOR_END);
188*59c8e88eSDag-Erling Smørgrav if (x < l->atoms.len)
189*59c8e88eSDag-Erling Smørgrav print("-");
190*59c8e88eSDag-Erling Smørgrav }
191*59c8e88eSDag-Erling Smørgrav print("\n");
192*59c8e88eSDag-Erling Smørgrav if (y == r->atoms.len)
193*59c8e88eSDag-Erling Smørgrav break;
194*59c8e88eSDag-Erling Smørgrav
195*59c8e88eSDag-Erling Smørgrav print(" ");
196*59c8e88eSDag-Erling Smørgrav for (x = 0; x < l->atoms.len; x++) {
197*59c8e88eSDag-Erling Smørgrav bool same;
198*59c8e88eSDag-Erling Smørgrav diff_atom_same(&same, &l->atoms.head[x],
199*59c8e88eSDag-Erling Smørgrav &r->atoms.head[y]);
200*59c8e88eSDag-Erling Smørgrav if (same)
201*59c8e88eSDag-Erling Smørgrav print("|\\");
202*59c8e88eSDag-Erling Smørgrav else
203*59c8e88eSDag-Erling Smørgrav print("| ");
204*59c8e88eSDag-Erling Smørgrav }
205*59c8e88eSDag-Erling Smørgrav print("|\n");
206*59c8e88eSDag-Erling Smørgrav }
207*59c8e88eSDag-Erling Smørgrav }
208*59c8e88eSDag-Erling Smørgrav
209*59c8e88eSDag-Erling Smørgrav static inline void
debug_dump_myers_graph(const struct diff_data * l,const struct diff_data * r,int * kd,int * kd_forward,int kd_forward_d,int * kd_backward,int kd_backward_d)210*59c8e88eSDag-Erling Smørgrav debug_dump_myers_graph(const struct diff_data *l, const struct diff_data *r,
211*59c8e88eSDag-Erling Smørgrav int *kd, int *kd_forward, int kd_forward_d,
212*59c8e88eSDag-Erling Smørgrav int *kd_backward, int kd_backward_d)
213*59c8e88eSDag-Erling Smørgrav {
214*59c8e88eSDag-Erling Smørgrav if (l->atoms.len > 99 || r->atoms.len > 99)
215*59c8e88eSDag-Erling Smørgrav return;
216*59c8e88eSDag-Erling Smørgrav dump_myers_graph(l, r, kd, kd_forward, kd_forward_d,
217*59c8e88eSDag-Erling Smørgrav kd_backward, kd_backward_d);
218*59c8e88eSDag-Erling Smørgrav }
219*59c8e88eSDag-Erling Smørgrav
220*59c8e88eSDag-Erling Smørgrav #else
221*59c8e88eSDag-Erling Smørgrav #define debug(args...)
222*59c8e88eSDag-Erling Smørgrav #define debug_dump(args...)
223*59c8e88eSDag-Erling Smørgrav #define debug_dump_atom(args...)
224*59c8e88eSDag-Erling Smørgrav #define debug_dump_atoms(args...)
225*59c8e88eSDag-Erling Smørgrav #define debug_dump_myers_graph(args...)
226*59c8e88eSDag-Erling Smørgrav #endif
227