cmp.c revision 1.6 1 /*
2 * Copyright (c) 1987 Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 #ifndef lint
35 char copyright[] =
36 "@(#) Copyright (c) 1987, 1990 Regents of the University of California.\n\
37 All rights reserved.\n";
38 #endif /* not lint */
39
40 #ifndef lint
41 /*static char sccsid[] = "from: @(#)cmp.c 5.3 (Berkeley) 6/1/90";*/
42 static char rcsid[] = "$Id: cmp.c,v 1.6 1994/03/25 17:07:02 mycroft Exp $";
43 #endif /* not lint */
44
45 #include <sys/param.h>
46 #include <sys/file.h>
47 #include <sys/stat.h>
48 #include <stdio.h>
49 #include <stdlib.h>
50 #include <string.h>
51 #include <ctype.h>
52 #include <errno.h>
53 #include <locale.h>
54 #include <unistd.h>
55
56 #define EXITNODIFF 0
57 #define EXITDIFF 1
58 #define EXITERR 2
59
60 void skip __P(());
61 __dead void cmp __P(());
62 __dead void error __P(());
63 __dead void endoffile __P(());
64 __dead void usage __P(());
65
66 int all, fd1, fd2, silent;
67 u_char buffer1[MAXBSIZE], buffer2[MAXBSIZE];
68 char *file1, *file2;
69
70 int
71 main(argc, argv)
72 int argc;
73 char **argv;
74 {
75 int ch;
76
77 setlocale(LC_ALL, "");
78
79 while ((ch = getopt(argc, argv, "ls")) != -1)
80 switch (ch) {
81 case 'l': /* print all differences */
82 all = 1;
83 break;
84 case 's': /* silent run */
85 silent = 1;
86 break;
87 case '?':
88 default:
89 usage();
90 }
91 argv += optind;
92 argc -= optind;
93
94 if (argc < 2 || argc > 4)
95 usage();
96
97 if (all && silent)
98 usage ();
99
100 if (strcmp(file1 = argv[0], "-") == 0)
101 fd1 = 0;
102 else if ((fd1 = open(file1, O_RDONLY, 0)) < 0)
103 error(file1);
104 if (strcmp(file2 = argv[1], "-") == 0)
105 fd2 = 0;
106 else if ((fd2 = open(file2, O_RDONLY, 0)) < 0)
107 error(file2);
108 if (fd1 == fd2) {
109 fprintf(stderr,
110 "cmp: standard input may only be specified once.\n");
111 exit(EXITERR);
112 }
113
114 /* handle skip arguments */
115 if (argc > 2) {
116 skip(strtoul(argv[2], NULL, 0), fd1, file1);
117 if (argc == 4)
118 skip(strtoul(argv[3], NULL, 0), fd2, file2);
119 }
120 cmp();
121 /*NOTREACHED*/
122 }
123
124 /*
125 * skip --
126 * skip first part of file
127 */
128 void
129 skip(dist, fd, fname)
130 register u_long dist;
131 register int fd;
132 char *fname;
133 {
134 register int rlen, nread;
135
136 for (; dist; dist -= rlen) {
137 rlen = MIN(dist, sizeof(buffer1));
138 if ((nread = read(fd, buffer1, rlen)) != rlen) {
139 if (nread < 0)
140 error(fname);
141 else
142 endoffile(fname);
143 }
144 }
145 }
146
147 void
148 cmp()
149 {
150 register u_char *p1, *p2;
151 u_char *buf1, *buf2;
152 register int cnt;
153 int len = 0, len1 = 0, len2 = 0;
154 register long byte, line;
155 int dfound = 0;
156
157 for (byte = 0, line = 1; ; ) {
158 len1 -= len;
159 len2 -= len;
160 if (len1)
161 buf1 += len;
162 else
163 switch (len1 = read(fd1, buf1 = buffer1, MAXBSIZE)) {
164 case -1:
165 error(file1);
166 case 0:
167 if (len2)
168 endoffile(file1);
169 /*
170 * read of file 1 just failed, find out
171 * if there's anything left in file 2
172 */
173 switch (read(fd2, buf2 = buffer2, 1)) {
174 case -1:
175 error(file2);
176 /* NOTREACHED */
177 case 0:
178 exit(dfound ? EXITDIFF : EXITNODIFF);
179 /* NOTREACHED */
180 default:
181 endoffile(file1);
182 break;
183 }
184 }
185 if (len2)
186 buf2 += len;
187 else
188 switch (len2 = read(fd2, buf2 = buffer2, MAXBSIZE)) {
189 case -1:
190 error(file2);
191 case 0:
192 /*
193 * read of file 2 just failed; we know there is
194 * data left in file 1 if we got this far
195 */
196 endoffile(file2);
197 break;
198 }
199 /*
200 * Either file might be stdio. We compare only the minimum
201 * number of bytes we know are common, then loop back to the
202 * top. This avoids blocking on input if a difference is
203 * found early.
204 */
205 if (len1 < len2)
206 len = len1;
207 else
208 len = len2;
209 if (memcmp(buf1, buf2, len)) {
210 if (silent)
211 exit(EXITDIFF);
212 if (all) {
213 dfound = 1;
214 for (p1 = buf1, p2 = buf2, cnt = len; cnt--;
215 ++p1, ++p2) {
216 ++byte;
217 if (*p1 != *p2)
218 printf("%6ld %3o %3o\n",
219 byte, *p1, *p2);
220 }
221 } else for (p1 = buf1, p2 = buf2; ; ++p1, ++p2) {
222 ++byte;
223 if (*p1 != *p2) {
224 printf("%s %s differ: char %ld, line %ld\n", file1, file2, byte, line);
225 exit(EXITDIFF);
226 }
227 if (*p1 == '\n')
228 ++line;
229 }
230 } else {
231 byte += len;
232 /*
233 * here's the real performance problem, we've got to
234 * count the stupid lines, which means that -l is a
235 * *much* faster version, i.e., unless you really
236 * *want* to know the line number, run -s or -l.
237 */
238 if (!silent && !all)
239 for (p1 = buf1, cnt = len; cnt--; )
240 if (*p1++ == '\n')
241 ++line;
242 }
243 }
244 }
245
246 /*
247 * error --
248 * print I/O error message and die
249 */
250 void
251 error(filename)
252 char *filename;
253 {
254 extern int errno;
255 char *strerror();
256
257 if (!silent)
258 (void) fprintf(stderr, "cmp: %s: %s\n",
259 filename, strerror(errno));
260 exit(EXITERR);
261 }
262
263 /*
264 * endoffile --
265 * print end-of-file message and exit indicating the files were different
266 */
267 void
268 endoffile(filename)
269 char *filename;
270 {
271 if (!silent)
272 (void) fprintf(stderr, "cmp: EOF on %s\n", filename);
273 exit(EXITDIFF);
274 }
275
276 /*
277 * usage --
278 * print usage and die
279 */
280 void
281 usage()
282 {
283 fputs("usage: cmp [-l | -s] file1 file2 [skip1] [skip2]\n", stderr);
284 exit(EXITERR);
285 }
286