xref: /src/contrib/libdiff/lib/diff_debug.h (revision 59c8e88e72633afbc47a4ace0d2170d00d51f7dc)
19eb461aaSDag-Erling Smørgrav /*
29eb461aaSDag-Erling Smørgrav  * Copyright (c) 2020 Neels Hofmeyr <neels@hofmeyr.de>
39eb461aaSDag-Erling Smørgrav  *
49eb461aaSDag-Erling Smørgrav  * Permission to use, copy, modify, and distribute this software for any
59eb461aaSDag-Erling Smørgrav  * purpose with or without fee is hereby granted, provided that the above
69eb461aaSDag-Erling Smørgrav  * copyright notice and this permission notice appear in all copies.
79eb461aaSDag-Erling Smørgrav  *
89eb461aaSDag-Erling Smørgrav  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
99eb461aaSDag-Erling Smørgrav  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
109eb461aaSDag-Erling Smørgrav  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
119eb461aaSDag-Erling Smørgrav  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
129eb461aaSDag-Erling Smørgrav  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
139eb461aaSDag-Erling Smørgrav  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
149eb461aaSDag-Erling Smørgrav  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
159eb461aaSDag-Erling Smørgrav  */
169eb461aaSDag-Erling Smørgrav 
179eb461aaSDag-Erling Smørgrav #define DEBUG 0
189eb461aaSDag-Erling Smørgrav 
199eb461aaSDag-Erling Smørgrav #if DEBUG
209eb461aaSDag-Erling Smørgrav #include <stdio.h>
219eb461aaSDag-Erling Smørgrav #include <unistd.h>
229eb461aaSDag-Erling Smørgrav #define print(args...) fprintf(stderr, ##args)
239eb461aaSDag-Erling Smørgrav #define debug print
249eb461aaSDag-Erling Smørgrav #define debug_dump dump
259eb461aaSDag-Erling Smørgrav #define debug_dump_atom dump_atom
269eb461aaSDag-Erling Smørgrav #define debug_dump_atoms dump_atoms
279eb461aaSDag-Erling Smørgrav 
289eb461aaSDag-Erling Smørgrav static inline void
print_atom_byte(unsigned char c)299eb461aaSDag-Erling Smørgrav print_atom_byte(unsigned char c) {
309eb461aaSDag-Erling Smørgrav 	if (c == '\r')
319eb461aaSDag-Erling Smørgrav 		print("\\r");
329eb461aaSDag-Erling Smørgrav 	else if (c == '\n')
339eb461aaSDag-Erling Smørgrav 		print("\\n");
349eb461aaSDag-Erling Smørgrav 	else if ((c < 32 || c >= 127) && (c != '\t'))
359eb461aaSDag-Erling Smørgrav 		print("\\x%02x", c);
369eb461aaSDag-Erling Smørgrav 	else
379eb461aaSDag-Erling Smørgrav 		print("%c", c);
389eb461aaSDag-Erling Smørgrav }
399eb461aaSDag-Erling Smørgrav 
409eb461aaSDag-Erling Smørgrav static inline void
dump_atom(const struct diff_data * left,const struct diff_data * right,const struct diff_atom * atom)419eb461aaSDag-Erling Smørgrav dump_atom(const struct diff_data *left, const struct diff_data *right,
429eb461aaSDag-Erling Smørgrav 	  const struct diff_atom *atom)
439eb461aaSDag-Erling Smørgrav {
449eb461aaSDag-Erling Smørgrav 	if (!atom) {
459eb461aaSDag-Erling Smørgrav 		print("NULL atom\n");
469eb461aaSDag-Erling Smørgrav 		return;
479eb461aaSDag-Erling Smørgrav 	}
489eb461aaSDag-Erling Smørgrav 	if (left)
499eb461aaSDag-Erling Smørgrav 		print(" %3u '", diff_atom_root_idx(left, atom));
509eb461aaSDag-Erling Smørgrav 
519eb461aaSDag-Erling Smørgrav 	if (atom->at == NULL) {
529eb461aaSDag-Erling Smørgrav 		off_t remain = atom->len;
539eb461aaSDag-Erling Smørgrav 		if (fseek(atom->root->f, atom->pos, SEEK_SET) == -1)
549eb461aaSDag-Erling Smørgrav 			abort(); /* cannot return error */
559eb461aaSDag-Erling Smørgrav 		while (remain > 0) {
569eb461aaSDag-Erling Smørgrav 			char buf[16];
579eb461aaSDag-Erling Smørgrav 			size_t r;
589eb461aaSDag-Erling Smørgrav 			int i;
599eb461aaSDag-Erling Smørgrav 			r = fread(buf, 1, MIN(remain, sizeof(buf)),
609eb461aaSDag-Erling Smørgrav 			    atom->root->f);
619eb461aaSDag-Erling Smørgrav 			if (r == 0)
629eb461aaSDag-Erling Smørgrav 				break;
639eb461aaSDag-Erling Smørgrav 			remain -= r;
649eb461aaSDag-Erling Smørgrav 			for (i = 0; i < r; i++)
659eb461aaSDag-Erling Smørgrav 				print_atom_byte(buf[i]);
669eb461aaSDag-Erling Smørgrav 		}
679eb461aaSDag-Erling Smørgrav 	} else {
689eb461aaSDag-Erling Smørgrav 		const char *s;
699eb461aaSDag-Erling Smørgrav 		for (s = atom->at; s < (const char*)(atom->at + atom->len); s++)
709eb461aaSDag-Erling Smørgrav 			print_atom_byte(*s);
719eb461aaSDag-Erling Smørgrav 	}
729eb461aaSDag-Erling Smørgrav 	print("'\n");
739eb461aaSDag-Erling Smørgrav }
749eb461aaSDag-Erling Smørgrav 
759eb461aaSDag-Erling Smørgrav static inline void
dump_atoms(const struct diff_data * d,struct diff_atom * atom,unsigned int count)769eb461aaSDag-Erling Smørgrav dump_atoms(const struct diff_data *d, struct diff_atom *atom,
779eb461aaSDag-Erling Smørgrav 	   unsigned int count)
789eb461aaSDag-Erling Smørgrav {
799eb461aaSDag-Erling Smørgrav 	if (count > 42) {
809eb461aaSDag-Erling Smørgrav 		dump_atoms(d, atom, 20);
819eb461aaSDag-Erling Smørgrav 		print("[%u lines skipped]\n", count - 20 - 20);
829eb461aaSDag-Erling Smørgrav 		dump_atoms(d, atom + count - 20, 20);
839eb461aaSDag-Erling Smørgrav 		return;
849eb461aaSDag-Erling Smørgrav 	} else {
859eb461aaSDag-Erling Smørgrav 		struct diff_atom *i;
869eb461aaSDag-Erling Smørgrav 		foreach_diff_atom(i, atom, count) {
879eb461aaSDag-Erling Smørgrav 			dump_atom(d, NULL, i);
889eb461aaSDag-Erling Smørgrav 		}
899eb461aaSDag-Erling Smørgrav 	}
909eb461aaSDag-Erling Smørgrav }
919eb461aaSDag-Erling Smørgrav 
929eb461aaSDag-Erling Smørgrav static inline void
dump(struct diff_data * d)939eb461aaSDag-Erling Smørgrav dump(struct diff_data *d)
949eb461aaSDag-Erling Smørgrav {
959eb461aaSDag-Erling Smørgrav 	dump_atoms(d, d->atoms.head, d->atoms.len);
969eb461aaSDag-Erling Smørgrav }
979eb461aaSDag-Erling Smørgrav 
989eb461aaSDag-Erling Smørgrav /* kd is a quadratic space myers matrix from the original Myers algorithm.
999eb461aaSDag-Erling Smørgrav  * kd_forward and kd_backward are linear slices of a myers matrix from the Myers
1009eb461aaSDag-Erling Smørgrav  * Divide algorithm.
1019eb461aaSDag-Erling Smørgrav  */
1029eb461aaSDag-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)1039eb461aaSDag-Erling Smørgrav dump_myers_graph(const struct diff_data *l, const struct diff_data *r,
1049eb461aaSDag-Erling Smørgrav 		 int *kd, int *kd_forward, int kd_forward_d,
1059eb461aaSDag-Erling Smørgrav 		 int *kd_backward, int kd_backward_d)
1069eb461aaSDag-Erling Smørgrav {
1079eb461aaSDag-Erling Smørgrav 	#define COLOR_YELLOW "\033[1;33m"
1089eb461aaSDag-Erling Smørgrav 	#define COLOR_GREEN "\033[1;32m"
1099eb461aaSDag-Erling Smørgrav 	#define COLOR_BLUE "\033[1;34m"
1109eb461aaSDag-Erling Smørgrav 	#define COLOR_RED "\033[1;31m"
1119eb461aaSDag-Erling Smørgrav 	#define COLOR_END "\033[0;m"
1129eb461aaSDag-Erling Smørgrav 	int x;
1139eb461aaSDag-Erling Smørgrav 	int y;
1149eb461aaSDag-Erling Smørgrav 	print("   ");
1159eb461aaSDag-Erling Smørgrav 	for (x = 0; x <= l->atoms.len; x++)
1169eb461aaSDag-Erling Smørgrav 		print("%2d", x % 100);
1179eb461aaSDag-Erling Smørgrav 	print("\n");
1189eb461aaSDag-Erling Smørgrav 
1199eb461aaSDag-Erling Smørgrav 	for (y = 0; y <= r->atoms.len; y++) {
1209eb461aaSDag-Erling Smørgrav 		print("%3d ", y);
1219eb461aaSDag-Erling Smørgrav 		for (x = 0; x <= l->atoms.len; x++) {
1229eb461aaSDag-Erling Smørgrav 
1239eb461aaSDag-Erling Smørgrav 			/* print d advancements from kd, if any. */
1249eb461aaSDag-Erling Smørgrav 			char label = 'o';
1259eb461aaSDag-Erling Smørgrav 			char *color = NULL;
1269eb461aaSDag-Erling Smørgrav 			if (kd) {
1279eb461aaSDag-Erling Smørgrav 				int max = l->atoms.len + r->atoms.len;
1289eb461aaSDag-Erling Smørgrav 				size_t kd_len = max + 1 + max;
1299eb461aaSDag-Erling Smørgrav 				int *kd_pos = kd;
1309eb461aaSDag-Erling Smørgrav 				int di;
1319eb461aaSDag-Erling Smørgrav #define xk_to_y(X, K) ((X) - (K))
1329eb461aaSDag-Erling Smørgrav 				for (di = 0; di < max; di++) {
1339eb461aaSDag-Erling Smørgrav 					int ki;
1349eb461aaSDag-Erling Smørgrav 					for (ki = di; ki >= -di; ki -= 2) {
1359eb461aaSDag-Erling Smørgrav 						if (x != kd_pos[ki]
1369eb461aaSDag-Erling Smørgrav 						    || y != xk_to_y(x, ki))
1379eb461aaSDag-Erling Smørgrav 							continue;
1389eb461aaSDag-Erling Smørgrav 						label = '0' + (di % 10);
1399eb461aaSDag-Erling Smørgrav 						color = COLOR_YELLOW;
1409eb461aaSDag-Erling Smørgrav 						break;
1419eb461aaSDag-Erling Smørgrav 					}
1429eb461aaSDag-Erling Smørgrav 					if (label != 'o')
1439eb461aaSDag-Erling Smørgrav 						break;
1449eb461aaSDag-Erling Smørgrav 					kd_pos += kd_len;
1459eb461aaSDag-Erling Smørgrav 				}
1469eb461aaSDag-Erling Smørgrav 			}
1479eb461aaSDag-Erling Smørgrav 			if (kd_forward && kd_forward_d >= 0) {
1489eb461aaSDag-Erling Smørgrav #define xc_to_y(X, C, DELTA) ((X) - (C) + (DELTA))
1499eb461aaSDag-Erling Smørgrav 				int ki;
1509eb461aaSDag-Erling Smørgrav 				for (ki = kd_forward_d;
1519eb461aaSDag-Erling Smørgrav 				     ki >= -kd_forward_d;
1529eb461aaSDag-Erling Smørgrav 				     ki -= 2) {
1539eb461aaSDag-Erling Smørgrav 					if (x != kd_forward[ki])
1549eb461aaSDag-Erling Smørgrav 						continue;
1559eb461aaSDag-Erling Smørgrav 					if (y != xk_to_y(x, ki))
1569eb461aaSDag-Erling Smørgrav 						continue;
1579eb461aaSDag-Erling Smørgrav 					label = 'F';
1589eb461aaSDag-Erling Smørgrav 					color = COLOR_GREEN;
1599eb461aaSDag-Erling Smørgrav 					break;
1609eb461aaSDag-Erling Smørgrav 				}
1619eb461aaSDag-Erling Smørgrav 			}
1629eb461aaSDag-Erling Smørgrav 			if (kd_backward && kd_backward_d >= 0) {
1639eb461aaSDag-Erling Smørgrav 				int delta = (int)r->atoms.len
1649eb461aaSDag-Erling Smørgrav 					    - (int)l->atoms.len;
1659eb461aaSDag-Erling Smørgrav 				int ki;
1669eb461aaSDag-Erling Smørgrav 				for (ki = kd_backward_d;
1679eb461aaSDag-Erling Smørgrav 				     ki >= -kd_backward_d;
1689eb461aaSDag-Erling Smørgrav 				     ki -= 2) {
1699eb461aaSDag-Erling Smørgrav 					if (x != kd_backward[ki])
1709eb461aaSDag-Erling Smørgrav 						continue;
1719eb461aaSDag-Erling Smørgrav 					if (y != xc_to_y(x, ki, delta))
1729eb461aaSDag-Erling Smørgrav 						continue;
1739eb461aaSDag-Erling Smørgrav 					if (label == 'o') {
1749eb461aaSDag-Erling Smørgrav 						label = 'B';
1759eb461aaSDag-Erling Smørgrav 						color = COLOR_BLUE;
1769eb461aaSDag-Erling Smørgrav 					} else {
1779eb461aaSDag-Erling Smørgrav 						label = 'X';
1789eb461aaSDag-Erling Smørgrav 						color = COLOR_RED;
1799eb461aaSDag-Erling Smørgrav 					}
1809eb461aaSDag-Erling Smørgrav 					break;
1819eb461aaSDag-Erling Smørgrav 				}
1829eb461aaSDag-Erling Smørgrav 			}
1839eb461aaSDag-Erling Smørgrav 			if (color)
1849eb461aaSDag-Erling Smørgrav 				print("%s", color);
1859eb461aaSDag-Erling Smørgrav 			print("%c", label);
1869eb461aaSDag-Erling Smørgrav 			if (color)
1879eb461aaSDag-Erling Smørgrav 				print("%s", COLOR_END);
1889eb461aaSDag-Erling Smørgrav 			if (x < l->atoms.len)
1899eb461aaSDag-Erling Smørgrav 				print("-");
1909eb461aaSDag-Erling Smørgrav 		}
1919eb461aaSDag-Erling Smørgrav 		print("\n");
1929eb461aaSDag-Erling Smørgrav 		if (y == r->atoms.len)
1939eb461aaSDag-Erling Smørgrav 			break;
1949eb461aaSDag-Erling Smørgrav 
1959eb461aaSDag-Erling Smørgrav 		print("    ");
1969eb461aaSDag-Erling Smørgrav 		for (x = 0; x < l->atoms.len; x++) {
1979eb461aaSDag-Erling Smørgrav 			bool same;
1989eb461aaSDag-Erling Smørgrav 			diff_atom_same(&same, &l->atoms.head[x],
1999eb461aaSDag-Erling Smørgrav 			    &r->atoms.head[y]);
2009eb461aaSDag-Erling Smørgrav 			if (same)
2019eb461aaSDag-Erling Smørgrav 				print("|\\");
2029eb461aaSDag-Erling Smørgrav 			else
2039eb461aaSDag-Erling Smørgrav 				print("| ");
2049eb461aaSDag-Erling Smørgrav 		}
2059eb461aaSDag-Erling Smørgrav 		print("|\n");
2069eb461aaSDag-Erling Smørgrav 	}
2079eb461aaSDag-Erling Smørgrav }
2089eb461aaSDag-Erling Smørgrav 
2099eb461aaSDag-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)2109eb461aaSDag-Erling Smørgrav debug_dump_myers_graph(const struct diff_data *l, const struct diff_data *r,
2119eb461aaSDag-Erling Smørgrav 		       int *kd, int *kd_forward, int kd_forward_d,
2129eb461aaSDag-Erling Smørgrav 		       int *kd_backward, int kd_backward_d)
2139eb461aaSDag-Erling Smørgrav {
2149eb461aaSDag-Erling Smørgrav 	if (l->atoms.len > 99 || r->atoms.len > 99)
2159eb461aaSDag-Erling Smørgrav 		return;
2169eb461aaSDag-Erling Smørgrav 	dump_myers_graph(l, r, kd, kd_forward, kd_forward_d,
2179eb461aaSDag-Erling Smørgrav 			 kd_backward, kd_backward_d);
2189eb461aaSDag-Erling Smørgrav }
2199eb461aaSDag-Erling Smørgrav 
2209eb461aaSDag-Erling Smørgrav #else
2219eb461aaSDag-Erling Smørgrav #define debug(args...)
2229eb461aaSDag-Erling Smørgrav #define debug_dump(args...)
2239eb461aaSDag-Erling Smørgrav #define debug_dump_atom(args...)
2249eb461aaSDag-Erling Smørgrav #define debug_dump_atoms(args...)
2259eb461aaSDag-Erling Smørgrav #define debug_dump_myers_graph(args...)
2269eb461aaSDag-Erling Smørgrav #endif
227