Blame


1 3b0f3d61 2020-01-22 neels /* Commandline diff utility to test diff implementations. */
2 3b0f3d61 2020-01-22 neels /*
3 3b0f3d61 2020-01-22 neels * Copyright (c) 2018 Martin Pieuchot
4 3b0f3d61 2020-01-22 neels * Copyright (c) 2020 Neels Hofmeyr <neels@hofmeyr.de>
5 3b0f3d61 2020-01-22 neels *
6 3b0f3d61 2020-01-22 neels * Permission to use, copy, modify, and distribute this software for any
7 3b0f3d61 2020-01-22 neels * purpose with or without fee is hereby granted, provided that the above
8 3b0f3d61 2020-01-22 neels * copyright notice and this permission notice appear in all copies.
9 3b0f3d61 2020-01-22 neels *
10 3b0f3d61 2020-01-22 neels * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 3b0f3d61 2020-01-22 neels * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 3b0f3d61 2020-01-22 neels * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 3b0f3d61 2020-01-22 neels * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 3b0f3d61 2020-01-22 neels * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 3b0f3d61 2020-01-22 neels * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 3b0f3d61 2020-01-22 neels * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 3b0f3d61 2020-01-22 neels */
18 3b0f3d61 2020-01-22 neels
19 3b0f3d61 2020-01-22 neels #include <sys/mman.h>
20 3b0f3d61 2020-01-22 neels #include <sys/stat.h>
21 3b0f3d61 2020-01-22 neels
22 3b0f3d61 2020-01-22 neels #include <err.h>
23 3b0f3d61 2020-01-22 neels #include <fcntl.h>
24 3b0f3d61 2020-01-22 neels #include <inttypes.h>
25 3b0f3d61 2020-01-22 neels #include <stdio.h>
26 3b0f3d61 2020-01-22 neels #include <stdlib.h>
27 e10a628a 2020-09-16 stsp #include <stdbool.h>
28 3e6cba3a 2020-08-13 stsp #include <string.h>
29 3b0f3d61 2020-01-22 neels #include <unistd.h>
30 3b0f3d61 2020-01-22 neels
31 e10a628a 2020-09-16 stsp #include <diff/arraylist.h>
32 8ad022d2 2020-05-05 neels #include <diff/diff_main.h>
33 8ad022d2 2020-05-05 neels #include <diff/diff_output.h>
34 8ad022d2 2020-05-05 neels
35 3b0f3d61 2020-01-22 neels #ifdef __linux__
36 3b0f3d61 2020-01-22 neels /* stupid shims to compile and test on linux */
37 3b0f3d61 2020-01-22 neels #define __dead
38 3b0f3d61 2020-01-22 neels
39 3b0f3d61 2020-01-22 neels static const char *getprogname()
40 3b0f3d61 2020-01-22 neels {
41 3b0f3d61 2020-01-22 neels return "diff";
42 3b0f3d61 2020-01-22 neels }
43 3b0f3d61 2020-01-22 neels #endif
44 3b0f3d61 2020-01-22 neels
45 3b0f3d61 2020-01-22 neels __dead void usage(void);
46 527f2c8a 2020-09-20 stsp int diffreg(char *, char *, bool, bool, int);
47 c6eecea3 2020-07-26 stsp int openfile(const char *, char **, struct stat *);
48 3b0f3d61 2020-01-22 neels
49 3b0f3d61 2020-01-22 neels __dead void
50 3b0f3d61 2020-01-22 neels usage(void)
51 3b0f3d61 2020-01-22 neels {
52 760fe30e 2020-05-05 neels fprintf(stderr,
53 527f2c8a 2020-09-20 stsp "usage: %s [-pw] [-C n] file1 file2\n"
54 760fe30e 2020-05-05 neels "\n"
55 760fe30e 2020-05-05 neels " -p Use Patience Diff (slower but often nicer)\n"
56 732e8ee0 2020-09-20 stsp " -w Ignore Whitespace\n"
57 527f2c8a 2020-09-20 stsp " -C n Number of Context Lines\n"
58 760fe30e 2020-05-05 neels , getprogname());
59 3b0f3d61 2020-01-22 neels exit(1);
60 3b0f3d61 2020-01-22 neels }
61 3b0f3d61 2020-01-22 neels
62 3b0f3d61 2020-01-22 neels int
63 3b0f3d61 2020-01-22 neels main(int argc, char *argv[])
64 3b0f3d61 2020-01-22 neels {
65 3e6cba3a 2020-08-13 stsp int ch, rc;
66 732e8ee0 2020-09-20 stsp bool do_patience = false, ignore_whitespace = false;
67 527f2c8a 2020-09-20 stsp int context_lines = 3;
68 3b0f3d61 2020-01-22 neels
69 527f2c8a 2020-09-20 stsp while ((ch = getopt(argc, argv, "pwC:")) != -1) {
70 3b0f3d61 2020-01-22 neels switch (ch) {
71 760fe30e 2020-05-05 neels case 'p':
72 760fe30e 2020-05-05 neels do_patience = true;
73 760fe30e 2020-05-05 neels break;
74 732e8ee0 2020-09-20 stsp case 'w':
75 732e8ee0 2020-09-20 stsp ignore_whitespace = true;
76 732e8ee0 2020-09-20 stsp break;
77 527f2c8a 2020-09-20 stsp case 'C':
78 527f2c8a 2020-09-20 stsp context_lines = atoi(optarg);
79 527f2c8a 2020-09-20 stsp break;
80 3b0f3d61 2020-01-22 neels default:
81 3b0f3d61 2020-01-22 neels usage();
82 3b0f3d61 2020-01-22 neels }
83 3b0f3d61 2020-01-22 neels }
84 3b0f3d61 2020-01-22 neels
85 3b0f3d61 2020-01-22 neels argc -= optind;
86 3b0f3d61 2020-01-22 neels argv += optind;
87 3b0f3d61 2020-01-22 neels
88 3b0f3d61 2020-01-22 neels if (argc != 2)
89 3b0f3d61 2020-01-22 neels usage();
90 3b0f3d61 2020-01-22 neels
91 527f2c8a 2020-09-20 stsp rc = diffreg(argv[0], argv[1], do_patience, ignore_whitespace,
92 527f2c8a 2020-09-20 stsp context_lines);
93 3e6cba3a 2020-08-13 stsp if (rc != DIFF_RC_OK) {
94 3e6cba3a 2020-08-13 stsp fprintf(stderr, "diff: %s\n", strerror(rc));
95 3e6cba3a 2020-08-13 stsp return 1;
96 3e6cba3a 2020-08-13 stsp }
97 3e6cba3a 2020-08-13 stsp return 0;
98 3b0f3d61 2020-01-22 neels }
99 3b0f3d61 2020-01-22 neels
100 0d27172a 2020-05-06 neels const struct diff_algo_config myers_then_patience;
101 0d27172a 2020-05-06 neels const struct diff_algo_config myers_then_myers_divide;
102 0d27172a 2020-05-06 neels const struct diff_algo_config patience;
103 0d27172a 2020-05-06 neels const struct diff_algo_config myers_divide;
104 3b0f3d61 2020-01-22 neels
105 760fe30e 2020-05-05 neels const struct diff_algo_config myers_then_patience = (struct diff_algo_config){
106 3b0f3d61 2020-01-22 neels .impl = diff_algo_myers,
107 9e668157 2020-01-27 neels .permitted_state_size = 1024 * 1024 * sizeof(int),
108 3b0f3d61 2020-01-22 neels .fallback_algo = &patience,
109 3b0f3d61 2020-01-22 neels };
110 3b0f3d61 2020-01-22 neels
111 0d27172a 2020-05-06 neels const struct diff_algo_config myers_then_myers_divide =
112 0d27172a 2020-05-06 neels (struct diff_algo_config){
113 760fe30e 2020-05-05 neels .impl = diff_algo_myers,
114 760fe30e 2020-05-05 neels .permitted_state_size = 1024 * 1024 * sizeof(int),
115 760fe30e 2020-05-05 neels .fallback_algo = &myers_divide,
116 760fe30e 2020-05-05 neels };
117 760fe30e 2020-05-05 neels
118 3b0f3d61 2020-01-22 neels const struct diff_algo_config patience = (struct diff_algo_config){
119 3b0f3d61 2020-01-22 neels .impl = diff_algo_patience,
120 0d27172a 2020-05-06 neels /* After subdivision, do Patience again: */
121 0d27172a 2020-05-06 neels .inner_algo = &patience,
122 0d27172a 2020-05-06 neels /* If subdivision failed, do Myers Divide et Impera: */
123 0d27172a 2020-05-06 neels .fallback_algo = &myers_then_myers_divide,
124 3b0f3d61 2020-01-22 neels };
125 3b0f3d61 2020-01-22 neels
126 3b0f3d61 2020-01-22 neels const struct diff_algo_config myers_divide = (struct diff_algo_config){
127 3b0f3d61 2020-01-22 neels .impl = diff_algo_myers_divide,
128 0d27172a 2020-05-06 neels /* When division succeeded, start from the top: */
129 0d27172a 2020-05-06 neels .inner_algo = &myers_then_myers_divide,
130 0d27172a 2020-05-06 neels /* (fallback_algo = NULL implies diff_algo_none). */
131 3b0f3d61 2020-01-22 neels };
132 3b0f3d61 2020-01-22 neels
133 3b0f3d61 2020-01-22 neels const struct diff_config diff_config = {
134 3b0f3d61 2020-01-22 neels .atomize_func = diff_atomize_text_by_line,
135 760fe30e 2020-05-05 neels .algo = &myers_then_myers_divide,
136 3b0f3d61 2020-01-22 neels };
137 3b0f3d61 2020-01-22 neels
138 760fe30e 2020-05-05 neels const struct diff_config diff_config_patience = {
139 760fe30e 2020-05-05 neels .atomize_func = diff_atomize_text_by_line,
140 760fe30e 2020-05-05 neels .algo = &myers_then_patience,
141 760fe30e 2020-05-05 neels };
142 760fe30e 2020-05-05 neels
143 3b0f3d61 2020-01-22 neels int
144 527f2c8a 2020-09-20 stsp diffreg(char *file1, char *file2, bool do_patience, bool ignore_whitespace,
145 527f2c8a 2020-09-20 stsp int context_lines)
146 3b0f3d61 2020-01-22 neels {
147 3b0f3d61 2020-01-22 neels char *str1, *str2;
148 c6eecea3 2020-07-26 stsp int fd1, fd2;
149 3b0f3d61 2020-01-22 neels struct stat st1, st2;
150 3b0f3d61 2020-01-22 neels struct diff_input_info info = {
151 3b0f3d61 2020-01-22 neels .left_path = file1,
152 3b0f3d61 2020-01-22 neels .right_path = file2,
153 3b0f3d61 2020-01-22 neels };
154 f8cbb8fe 2020-05-05 neels struct diff_result *result;
155 3e6cba3a 2020-08-13 stsp int rc;
156 0d27172a 2020-05-06 neels const struct diff_config *cfg;
157 0d27172a 2020-05-06 neels
158 0d27172a 2020-05-06 neels cfg = do_patience ? &diff_config_patience : &diff_config;
159 3b0f3d61 2020-01-22 neels
160 c6eecea3 2020-07-26 stsp fd1 = openfile(file1, &str1, &st1);
161 c6eecea3 2020-07-26 stsp fd2 = openfile(file2, &str2, &st2);
162 3b0f3d61 2020-01-22 neels
163 732e8ee0 2020-09-20 stsp result = diff_main(cfg, fd1, str1, st1.st_size, fd2, str2, st2.st_size,
164 732e8ee0 2020-09-20 stsp ignore_whitespace);
165 f8cbb8fe 2020-05-05 neels #if 0
166 f8cbb8fe 2020-05-05 neels rc = diff_output_plain(stdout, &info, result);
167 f8cbb8fe 2020-05-05 neels #else
168 527f2c8a 2020-09-20 stsp rc = diff_output_unidiff(stdout, &info, result, context_lines);
169 f8cbb8fe 2020-05-05 neels #endif
170 f8cbb8fe 2020-05-05 neels diff_result_free(result);
171 3b0f3d61 2020-01-22 neels
172 c6eecea3 2020-07-26 stsp if (str1)
173 c6eecea3 2020-07-26 stsp munmap(str1, st1.st_size);
174 c6eecea3 2020-07-26 stsp if (str2)
175 c6eecea3 2020-07-26 stsp munmap(str2, st2.st_size);
176 c6eecea3 2020-07-26 stsp close(fd1);
177 c6eecea3 2020-07-26 stsp close(fd2);
178 3b0f3d61 2020-01-22 neels
179 f8cbb8fe 2020-05-05 neels return rc;
180 3b0f3d61 2020-01-22 neels }
181 3b0f3d61 2020-01-22 neels
182 c6eecea3 2020-07-26 stsp int
183 c6eecea3 2020-07-26 stsp openfile(const char *path, char **p, struct stat *st)
184 3b0f3d61 2020-01-22 neels {
185 3b0f3d61 2020-01-22 neels int fd;
186 3b0f3d61 2020-01-22 neels
187 3b0f3d61 2020-01-22 neels fd = open(path, O_RDONLY);
188 3b0f3d61 2020-01-22 neels if (fd == -1)
189 3b0f3d61 2020-01-22 neels err(2, "%s", path);
190 3b0f3d61 2020-01-22 neels
191 3b0f3d61 2020-01-22 neels if (fstat(fd, st) == -1)
192 3b0f3d61 2020-01-22 neels err(2, "%s", path);
193 3b0f3d61 2020-01-22 neels
194 c6eecea3 2020-07-26 stsp #ifndef DIFF_NO_MMAP
195 c6eecea3 2020-07-26 stsp *p = mmap(NULL, st->st_size, PROT_READ, MAP_PRIVATE, fd, 0);
196 c6eecea3 2020-07-26 stsp if (*p == MAP_FAILED)
197 c6eecea3 2020-07-26 stsp #endif
198 c6eecea3 2020-07-26 stsp *p = NULL; /* fall back on file I/O */
199 3b0f3d61 2020-01-22 neels
200 c6eecea3 2020-07-26 stsp return fd;
201 3b0f3d61 2020-01-22 neels }