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.
31 #include <diff/arraylist.h>
32 #include <diff/diff_main.h>
33 #include <diff/diff_output.h>
36 /* stupid shims to compile and test on linux */
39 static const char *getprogname()
45 __dead void usage(void);
46 int diffreg(char *, char *, bool, bool);
47 int openfile(const char *, char **, struct stat *);
53 "usage: %s [-pw] file1 file2\n"
55 " -p Use Patience Diff (slower but often nicer)\n"
56 " -w Ignore Whitespace\n"
62 main(int argc, char *argv[])
65 bool do_patience = false, ignore_whitespace = false;
67 while ((ch = getopt(argc, argv, "pw")) != -1) {
73 ignore_whitespace = true;
86 rc = diffreg(argv[0], argv[1], do_patience, ignore_whitespace);
87 if (rc != DIFF_RC_OK) {
88 fprintf(stderr, "diff: %s\n", strerror(rc));
94 const struct diff_algo_config myers_then_patience;
95 const struct diff_algo_config myers_then_myers_divide;
96 const struct diff_algo_config patience;
97 const struct diff_algo_config myers_divide;
99 const struct diff_algo_config myers_then_patience = (struct diff_algo_config){
100 .impl = diff_algo_myers,
101 .permitted_state_size = 1024 * 1024 * sizeof(int),
102 .fallback_algo = &patience,
105 const struct diff_algo_config myers_then_myers_divide =
106 (struct diff_algo_config){
107 .impl = diff_algo_myers,
108 .permitted_state_size = 1024 * 1024 * sizeof(int),
109 .fallback_algo = &myers_divide,
112 const struct diff_algo_config patience = (struct diff_algo_config){
113 .impl = diff_algo_patience,
114 /* After subdivision, do Patience again: */
115 .inner_algo = &patience,
116 /* If subdivision failed, do Myers Divide et Impera: */
117 .fallback_algo = &myers_then_myers_divide,
120 const struct diff_algo_config myers_divide = (struct diff_algo_config){
121 .impl = diff_algo_myers_divide,
122 /* When division succeeded, start from the top: */
123 .inner_algo = &myers_then_myers_divide,
124 /* (fallback_algo = NULL implies diff_algo_none). */
127 const struct diff_config diff_config = {
128 .atomize_func = diff_atomize_text_by_line,
129 .algo = &myers_then_myers_divide,
132 const struct diff_config diff_config_patience = {
133 .atomize_func = diff_atomize_text_by_line,
134 .algo = &myers_then_patience,
138 diffreg(char *file1, char *file2, bool do_patience, bool ignore_whitespace)
142 struct stat st1, st2;
143 struct diff_input_info info = {
147 struct diff_result *result;
149 const struct diff_config *cfg;
151 cfg = do_patience ? &diff_config_patience : &diff_config;
153 fd1 = openfile(file1, &str1, &st1);
154 fd2 = openfile(file2, &str2, &st2);
156 result = diff_main(cfg, fd1, str1, st1.st_size, fd2, str2, st2.st_size,
159 rc = diff_output_plain(stdout, &info, result);
161 rc = diff_output_unidiff(stdout, &info, result, 3);
163 diff_result_free(result);
166 munmap(str1, st1.st_size);
168 munmap(str2, st2.st_size);
176 openfile(const char *path, char **p, struct stat *st)
180 fd = open(path, O_RDONLY);
184 if (fstat(fd, st) == -1)
188 *p = mmap(NULL, st->st_size, PROT_READ, MAP_PRIVATE, fd, 0);
189 if (*p == MAP_FAILED)
191 *p = NULL; /* fall back on file I/O */