Commit | Line | Data |
---|---|---|
94721995 KB |
1 | /* |
2 | * Copyright (c) 1987 Regents of the University of California. | |
cde75055 KB |
3 | * All rights reserved. |
4 | * | |
5 | * Redistribution and use in source and binary forms are permitted | |
b8c620d6 KB |
6 | * provided that the above copyright notice and this paragraph are |
7 | * duplicated in all such forms and that any documentation, | |
8 | * advertising materials, and other materials related to such | |
9 | * distribution and use acknowledge that the software was developed | |
10 | * by the University of California, Berkeley. The name of the | |
11 | * University may not be used to endorse or promote products derived | |
12 | * from this software without specific prior written permission. | |
13 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR | |
14 | * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED | |
15 | * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. | |
94721995 KB |
16 | */ |
17 | ||
18 | #ifndef lint | |
19 | char copyright[] = | |
20 | "@(#) Copyright (c) 1987 Regents of the University of California.\n\ | |
21 | All rights reserved.\n"; | |
b8c620d6 | 22 | #endif /* not lint */ |
94721995 KB |
23 | |
24 | #ifndef lint | |
1b7289a3 | 25 | static char sccsid[] = "@(#)cmp.c 5.1 (Berkeley) %G%"; |
b8c620d6 | 26 | #endif /* not lint */ |
34cbacef KB |
27 | |
28 | #include <sys/param.h> | |
29 | #include <sys/file.h> | |
30 | #include <sys/stat.h> | |
1b88b85d BJ |
31 | #include <stdio.h> |
32 | #include <ctype.h> | |
ec37e2d9 | 33 | #include <errno.h> |
1b88b85d | 34 | |
1b7289a3 KB |
35 | #define EXITNODIFF 0 |
36 | #define EXITDIFF 1 | |
37 | #define EXITERR 2 | |
1b88b85d | 38 | |
1b7289a3 KB |
39 | static int all, fd1, fd2, silent; |
40 | static u_char buf1[MAXBSIZE], buf2[MAXBSIZE]; | |
41 | static char *file1, *file2; | |
1b88b85d | 42 | |
ec37e2d9 | 43 | main(argc, argv) |
1b7289a3 KB |
44 | int argc; |
45 | char **argv; | |
1b88b85d | 46 | { |
1b7289a3 KB |
47 | extern char *optarg; |
48 | extern int optind; | |
49 | int ch; | |
50 | u_long otoi(); | |
34cbacef | 51 | |
1b7289a3 | 52 | while ((ch = getopt(argc, argv, "-ls")) != EOF) |
34cbacef | 53 | switch(ch) { |
ec37e2d9 | 54 | case 'l': /* print all differences */ |
1b7289a3 | 55 | all = 1; |
ec37e2d9 KB |
56 | break; |
57 | case 's': /* silent run */ | |
1b7289a3 | 58 | silent = 1; |
ec37e2d9 | 59 | break; |
1b7289a3 KB |
60 | case '-': /* must be after any flags */ |
61 | --optind; | |
62 | goto endargs; | |
ec37e2d9 KB |
63 | case '?': |
64 | default: | |
65 | usage(); | |
34cbacef | 66 | } |
1b7289a3 | 67 | endargs: |
34cbacef KB |
68 | argv += optind; |
69 | argc -= optind; | |
1b88b85d | 70 | |
34cbacef KB |
71 | if (argc < 2 || argc > 4) |
72 | usage(); | |
73 | ||
1b7289a3 KB |
74 | if (all && silent) { |
75 | fprintf(stderr, | |
76 | "cmp: only one of -l and -s may be specified.\n"); | |
77 | exit(EXITERR); | |
78 | } | |
79 | if (!strcmp(file1 = argv[0], "-")) | |
80 | fd1 = 0; | |
81 | else if ((fd1 = open(file1, O_RDONLY, 0)) < 0) | |
ec37e2d9 | 82 | error(file1); |
1b7289a3 KB |
83 | if (!strcmp(file2 = argv[1], "-")) |
84 | fd2 = 0; | |
85 | else if ((fd2 = open(file2, O_RDONLY, 0)) < 0) | |
ec37e2d9 | 86 | error(file2); |
1b7289a3 KB |
87 | if (fd1 == fd2) { |
88 | fprintf(stderr, | |
89 | "cmp: standard input may only be specified once.\n"); | |
90 | exit(EXITERR); | |
91 | } | |
34cbacef KB |
92 | |
93 | /* handle skip arguments */ | |
94 | if (argc > 2) { | |
ec37e2d9 | 95 | skip(otoi(argv[2]), fd1, file1); |
34cbacef | 96 | if (argc == 4) |
ec37e2d9 | 97 | skip(otoi(argv[3]), fd2, file2); |
1b88b85d | 98 | } |
34cbacef | 99 | cmp(); |
ec37e2d9 | 100 | /*NOTREACHED*/ |
34cbacef KB |
101 | } |
102 | ||
103 | /* | |
104 | * skip -- | |
105 | * skip first part of file | |
106 | */ | |
107 | static | |
ec37e2d9 | 108 | skip(dist, fd, fname) |
1b7289a3 KB |
109 | register u_long dist; |
110 | register int fd; | |
111 | char *fname; | |
34cbacef | 112 | { |
1b7289a3 | 113 | register int rlen, nread; |
ec37e2d9 KB |
114 | |
115 | for (; dist; dist -= rlen) { | |
116 | rlen = MIN(dist, sizeof(buf1)); | |
117 | if ((nread = read(fd, buf1, rlen)) != rlen) { | |
118 | if (nread < 0) | |
119 | error(fname); | |
120 | else | |
121 | endoffile(fname); | |
1b88b85d | 122 | } |
1b88b85d | 123 | } |
34cbacef | 124 | } |
1b88b85d | 125 | |
34cbacef KB |
126 | static |
127 | cmp() | |
128 | { | |
1b7289a3 KB |
129 | register u_char *C1, *C2; |
130 | register int cnt, len1, len2; | |
131 | register long byte, line; | |
132 | int dfound = 0; | |
34cbacef | 133 | |
ec37e2d9 KB |
134 | for (byte = 0, line = 1;;) { |
135 | switch(len1 = read(fd1, buf1, MAXBSIZE)) { | |
136 | case -1: | |
137 | error(file1); | |
138 | case 0: | |
139 | /* | |
140 | * read of file 1 just failed, find out | |
141 | * if there's anything left in file 2 | |
142 | */ | |
143 | switch(read(fd2, buf2, 1)) { | |
144 | case -1: | |
145 | error(file2); | |
146 | case 0: | |
1b7289a3 | 147 | exit(dfound ? EXITDIFF : EXITNODIFF); |
ec37e2d9 KB |
148 | default: |
149 | endoffile(file1); | |
150 | } | |
34cbacef KB |
151 | } |
152 | /* | |
153 | * file1 might be stdio, which means that a read of less than | |
154 | * MAXBSIZE might not mean an EOF. So, read whatever we read | |
155 | * from file1 from file2. | |
156 | */ | |
ec37e2d9 KB |
157 | if ((len2 = read(fd2, buf2, len1)) == -1) |
158 | error(file2); | |
159 | if (bcmp(buf1, buf2, len2)) { | |
34cbacef | 160 | if (silent) |
1b7289a3 | 161 | exit(EXITDIFF); |
34cbacef | 162 | if (all) { |
1b7289a3 | 163 | dfound = 1; |
ec37e2d9 | 164 | for (C1 = buf1, C2 = buf2, cnt = len2; cnt--; ++C1, ++C2) { |
34cbacef KB |
165 | ++byte; |
166 | if (*C1 != *C2) | |
ec37e2d9 | 167 | printf("%6ld %3o %3o\n", byte, *C1, *C2); |
34cbacef | 168 | } |
1b7289a3 | 169 | } else for (C1 = buf1, C2 = buf2;; ++C1, ++C2) { |
94721995 KB |
170 | ++byte; |
171 | if (*C1 != *C2) { | |
ec37e2d9 | 172 | printf("%s %s differ: char %ld, line %ld\n", file1, file2, byte, line); |
1b7289a3 | 173 | exit(EXITDIFF); |
34cbacef | 174 | } |
94721995 KB |
175 | if (*C1 == '\n') |
176 | ++line; | |
177 | } | |
1b7289a3 | 178 | } else { |
34cbacef KB |
179 | byte += len2; |
180 | /* | |
181 | * here's the real performance problem, we've got to | |
182 | * count the stupid lines, which means that -l is a | |
183 | * *much* faster version, i.e., unless you really | |
94721995 | 184 | * *want* to know the line number, run -s or -l. |
34cbacef | 185 | */ |
94721995 | 186 | if (!silent && !all) |
ec37e2d9 | 187 | for (C1 = buf1, cnt = len2; cnt--;) |
34cbacef KB |
188 | if (*C1++ == '\n') |
189 | ++line; | |
190 | } | |
191 | /* | |
192 | * couldn't read as much from file2 as from file1; checked | |
193 | * here because there might be a difference before we got | |
194 | * to this point, which would have precedence. | |
195 | */ | |
ec37e2d9 KB |
196 | if (len2 < len1) |
197 | endoffile(file2); | |
1b88b85d | 198 | } |
34cbacef | 199 | } |
1b88b85d | 200 | |
34cbacef KB |
201 | /* |
202 | * otoi -- | |
203 | * octal/decimal string to u_long | |
204 | */ | |
205 | static u_long | |
206 | otoi(C) | |
1b7289a3 | 207 | register char *C; |
34cbacef | 208 | { |
1b7289a3 KB |
209 | register u_long val; |
210 | register int base; | |
1b88b85d | 211 | |
34cbacef | 212 | base = (*C == '0') ? 8 : 10; |
ec37e2d9 | 213 | for (val = 0; isdigit(*C); ++C) |
34cbacef KB |
214 | val = val * base + *C - '0'; |
215 | return(val); | |
1b88b85d BJ |
216 | } |
217 | ||
ec37e2d9 KB |
218 | /* |
219 | * error -- | |
220 | * print I/O error message and die | |
221 | */ | |
222 | static | |
223 | error(filename) | |
224 | char *filename; | |
225 | { | |
226 | extern int errno; | |
1b7289a3 | 227 | char *strerror(); |
ec37e2d9 | 228 | |
1b7289a3 KB |
229 | if (!silent) |
230 | (void)fprintf(stderr, "cmp: %s: %s\n", | |
231 | filename, strerror(errno)); | |
232 | exit(EXITERR); | |
ec37e2d9 KB |
233 | } |
234 | ||
235 | /* | |
236 | * endoffile -- | |
237 | * print end-of-file message and exit indicating the files were different | |
238 | */ | |
239 | static | |
240 | endoffile(filename) | |
241 | char *filename; | |
242 | { | |
243 | /* 32V put this message on stdout, S5 does it on stderr. */ | |
244 | if (!silent) | |
245 | (void)fprintf(stderr, "cmp: EOF on %s\n", filename); | |
1b7289a3 | 246 | exit(EXITDIFF); |
ec37e2d9 KB |
247 | } |
248 | ||
34cbacef KB |
249 | /* |
250 | * usage -- | |
251 | * print usage and die | |
252 | */ | |
253 | static | |
254 | usage() | |
1b88b85d | 255 | { |
ec37e2d9 | 256 | fputs("usage: cmp [-ls] file1 file2 [skip1] [skip2]\n", stderr); |
1b7289a3 | 257 | exit(EXITERR); |
1b88b85d | 258 | } |