1 /* Commandline diff utility to test diff implementations. */
3 * Copyright (c) 2018 Martin Pieuchot
4 * Copyright (c) 2020 Neels Hofmeyr <neels@hofmeyr.de>
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
29 #include <diff/diff_main.h>
30 #include <diff/diff_output.h>
33 /* stupid shims to compile and test on linux */
36 static const char *getprogname()
42 __dead void usage(void);
43 int diffreg(char *, char *, int);
44 char *mmapfile(const char *, struct stat *);
50 "usage: %s [-p] file1 file2\n"
52 " -p Use Patience Diff (slower but often nicer)\n"
57 static bool do_patience = false;
60 main(int argc, char *argv[])
64 while ((ch = getopt(argc, argv, "p")) != -1) {
80 return diffreg(argv[0], argv[1], 0);
83 const struct diff_algo_config myers_then_patience, myers_then_myers_divide, patience, myers_divide;
85 const struct diff_algo_config myers_then_patience = (struct diff_algo_config){
86 .impl = diff_algo_myers,
87 .permitted_state_size = 1024 * 1024 * sizeof(int),
88 .fallback_algo = &patience,
91 const struct diff_algo_config myers_then_myers_divide = (struct diff_algo_config){
92 .impl = diff_algo_myers,
93 .permitted_state_size = 1024 * 1024 * sizeof(int),
94 .fallback_algo = &myers_divide,
97 const struct diff_algo_config patience = (struct diff_algo_config){
98 .impl = diff_algo_patience,
99 .inner_algo = &patience, // After subdivision, do Patience again.
100 .fallback_algo = &myers_then_myers_divide, // If subdivision failed, do Myers Divide et Impera.
103 const struct diff_algo_config myers_divide = (struct diff_algo_config){
104 .impl = diff_algo_myers_divide,
105 .inner_algo = &myers_then_myers_divide, // When division succeeded, start from the top.
106 // (fallback_algo = NULL implies diff_algo_none).
109 const struct diff_config diff_config = {
110 .atomize_func = diff_atomize_text_by_line,
111 .algo = &myers_then_myers_divide,
114 const struct diff_config diff_config_patience = {
115 .atomize_func = diff_atomize_text_by_line,
116 .algo = &myers_then_patience,
120 diffreg(char *file1, char *file2, int flags)
123 struct stat st1, st2;
124 struct diff_input_info info = {
128 struct diff_result *result;
130 const struct diff_config *cfg = do_patience ? &diff_config_patience : &diff_config;
132 str1 = mmapfile(file1, &st1);
133 str2 = mmapfile(file2, &st2);
135 result = diff_main(cfg, str1, st1.st_size, str2, st2.st_size);
137 rc = diff_output_plain(stdout, &info, result);
139 rc = diff_output_unidiff(stdout, &info, result, 3);
141 diff_result_free(result);
143 munmap(str1, st1.st_size);
144 munmap(str2, st2.st_size);
150 mmapfile(const char *path, struct stat *st)
155 fd = open(path, O_RDONLY);
159 if (fstat(fd, st) == -1)
162 if ((uintmax_t)st->st_size > SIZE_MAX)
163 errx(2, "%s: file too big to fit memory", path);
165 p = mmap(NULL, st->st_size, PROT_READ, MAP_PRIVATE, fd, 0);