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 | |
b8c620d6 KB |
25 | static char sccsid[] = "@(#)cmp.c 4.9 (Berkeley) %G%"; |
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 | |
34cbacef KB |
35 | #define DIFF 1 /* found differences */ |
36 | #define ERR 2 /* error during run */ | |
37 | #define NO 0 /* no/false */ | |
38 | #define OK 0 /* didn't find differences */ | |
39 | #define YES 1 /* yes/true */ | |
1b88b85d | 40 | |
f10a0ae9 | 41 | static int fd1, fd2, /* file descriptors */ |
94721995 | 42 | silent = NO; /* if silent run */ |
34cbacef | 43 | static short all = NO; /* if report all differences */ |
ec37e2d9 | 44 | static u_char buf1[MAXBSIZE], /* read buffers */ |
34cbacef | 45 | buf2[MAXBSIZE]; |
ec37e2d9 | 46 | static char *file1, *file2; /* file names */ |
1b88b85d | 47 | |
ec37e2d9 KB |
48 | main(argc, argv) |
49 | int argc; | |
50 | char **argv; | |
1b88b85d | 51 | { |
ec37e2d9 | 52 | extern char *optarg; |
34cbacef | 53 | extern int optind; |
ec37e2d9 | 54 | int ch; |
34cbacef KB |
55 | u_long otoi(); |
56 | ||
ec37e2d9 | 57 | while ((ch = getopt(argc, argv, "ls")) != EOF) |
34cbacef | 58 | switch(ch) { |
ec37e2d9 KB |
59 | case 'l': /* print all differences */ |
60 | all = YES; | |
61 | break; | |
62 | case 's': /* silent run */ | |
63 | silent = YES; | |
64 | break; | |
65 | case '?': | |
66 | default: | |
67 | usage(); | |
34cbacef KB |
68 | } |
69 | argv += optind; | |
70 | argc -= optind; | |
1b88b85d | 71 | |
34cbacef KB |
72 | if (argc < 2 || argc > 4) |
73 | usage(); | |
74 | ||
75 | /* open up files; "-" is stdin */ | |
76 | file1 = argv[0]; | |
ec37e2d9 KB |
77 | if (strcmp(file1, "-") && (fd1 = open(file1, O_RDONLY, 0)) < 0) |
78 | error(file1); | |
34cbacef | 79 | file2 = argv[1]; |
ec37e2d9 KB |
80 | if ((fd2 = open(file2, O_RDONLY, 0)) < 0) |
81 | error(file2); | |
34cbacef KB |
82 | |
83 | /* handle skip arguments */ | |
84 | if (argc > 2) { | |
ec37e2d9 | 85 | skip(otoi(argv[2]), fd1, file1); |
34cbacef | 86 | if (argc == 4) |
ec37e2d9 | 87 | skip(otoi(argv[3]), fd2, file2); |
1b88b85d | 88 | } |
34cbacef | 89 | cmp(); |
ec37e2d9 | 90 | /*NOTREACHED*/ |
34cbacef KB |
91 | } |
92 | ||
93 | /* | |
94 | * skip -- | |
95 | * skip first part of file | |
96 | */ | |
97 | static | |
ec37e2d9 KB |
98 | skip(dist, fd, fname) |
99 | register u_long dist; /* length in bytes, to skip */ | |
100 | register int fd; /* file descriptor */ | |
101 | char *fname; /* file name for error */ | |
34cbacef KB |
102 | { |
103 | register int rlen; /* read length */ | |
ec37e2d9 KB |
104 | register int nread; |
105 | ||
106 | for (; dist; dist -= rlen) { | |
107 | rlen = MIN(dist, sizeof(buf1)); | |
108 | if ((nread = read(fd, buf1, rlen)) != rlen) { | |
109 | if (nread < 0) | |
110 | error(fname); | |
111 | else | |
112 | endoffile(fname); | |
1b88b85d | 113 | } |
1b88b85d | 114 | } |
34cbacef | 115 | } |
1b88b85d | 116 | |
34cbacef KB |
117 | static |
118 | cmp() | |
119 | { | |
ec37e2d9 | 120 | register u_char *C1, *C2; /* traveling pointers */ |
34cbacef | 121 | register int cnt, /* counter */ |
ec37e2d9 | 122 | len1, len2; /* read lengths */ |
34cbacef KB |
123 | register long byte, /* byte count */ |
124 | line; /* line count */ | |
125 | short dfound = NO; /* if difference found */ | |
126 | ||
ec37e2d9 KB |
127 | for (byte = 0, line = 1;;) { |
128 | switch(len1 = read(fd1, buf1, MAXBSIZE)) { | |
129 | case -1: | |
130 | error(file1); | |
131 | case 0: | |
132 | /* | |
133 | * read of file 1 just failed, find out | |
134 | * if there's anything left in file 2 | |
135 | */ | |
136 | switch(read(fd2, buf2, 1)) { | |
137 | case -1: | |
138 | error(file2); | |
139 | case 0: | |
140 | exit(dfound ? DIFF : OK); | |
141 | default: | |
142 | endoffile(file1); | |
143 | } | |
34cbacef KB |
144 | } |
145 | /* | |
146 | * file1 might be stdio, which means that a read of less than | |
147 | * MAXBSIZE might not mean an EOF. So, read whatever we read | |
148 | * from file1 from file2. | |
149 | */ | |
ec37e2d9 KB |
150 | if ((len2 = read(fd2, buf2, len1)) == -1) |
151 | error(file2); | |
152 | if (bcmp(buf1, buf2, len2)) { | |
34cbacef KB |
153 | if (silent) |
154 | exit(DIFF); | |
155 | if (all) { | |
156 | dfound = YES; | |
ec37e2d9 | 157 | for (C1 = buf1, C2 = buf2, cnt = len2; cnt--; ++C1, ++C2) { |
34cbacef KB |
158 | ++byte; |
159 | if (*C1 != *C2) | |
ec37e2d9 | 160 | printf("%6ld %3o %3o\n", byte, *C1, *C2); |
34cbacef KB |
161 | } |
162 | } | |
ec37e2d9 | 163 | else for (C1 = buf1, C2 = buf2;; ++C1, ++C2) { |
94721995 KB |
164 | ++byte; |
165 | if (*C1 != *C2) { | |
ec37e2d9 | 166 | printf("%s %s differ: char %ld, line %ld\n", file1, file2, byte, line); |
94721995 | 167 | exit(DIFF); |
34cbacef | 168 | } |
94721995 KB |
169 | if (*C1 == '\n') |
170 | ++line; | |
171 | } | |
34cbacef KB |
172 | } |
173 | else { | |
174 | byte += len2; | |
175 | /* | |
176 | * here's the real performance problem, we've got to | |
177 | * count the stupid lines, which means that -l is a | |
178 | * *much* faster version, i.e., unless you really | |
94721995 | 179 | * *want* to know the line number, run -s or -l. |
34cbacef | 180 | */ |
94721995 | 181 | if (!silent && !all) |
ec37e2d9 | 182 | for (C1 = buf1, cnt = len2; cnt--;) |
34cbacef KB |
183 | if (*C1++ == '\n') |
184 | ++line; | |
185 | } | |
186 | /* | |
187 | * couldn't read as much from file2 as from file1; checked | |
188 | * here because there might be a difference before we got | |
189 | * to this point, which would have precedence. | |
190 | */ | |
ec37e2d9 KB |
191 | if (len2 < len1) |
192 | endoffile(file2); | |
1b88b85d | 193 | } |
34cbacef | 194 | } |
1b88b85d | 195 | |
34cbacef KB |
196 | /* |
197 | * otoi -- | |
198 | * octal/decimal string to u_long | |
199 | */ | |
200 | static u_long | |
201 | otoi(C) | |
ec37e2d9 | 202 | register char *C; /* argument string */ |
34cbacef | 203 | { |
ec37e2d9 KB |
204 | register u_long val; /* return value */ |
205 | register int base; /* number base */ | |
1b88b85d | 206 | |
34cbacef | 207 | base = (*C == '0') ? 8 : 10; |
ec37e2d9 | 208 | for (val = 0; isdigit(*C); ++C) |
34cbacef KB |
209 | val = val * base + *C - '0'; |
210 | return(val); | |
1b88b85d BJ |
211 | } |
212 | ||
ec37e2d9 KB |
213 | /* |
214 | * error -- | |
215 | * print I/O error message and die | |
216 | */ | |
217 | static | |
218 | error(filename) | |
219 | char *filename; | |
220 | { | |
221 | extern int errno; | |
222 | int sverrno; | |
223 | ||
224 | if (!silent) { | |
225 | sverrno = errno; | |
226 | (void)fprintf(stderr, "cmp: %s: ", filename); | |
227 | errno = sverrno; | |
228 | perror((char *)NULL); | |
229 | } | |
230 | exit(ERR); | |
231 | } | |
232 | ||
233 | /* | |
234 | * endoffile -- | |
235 | * print end-of-file message and exit indicating the files were different | |
236 | */ | |
237 | static | |
238 | endoffile(filename) | |
239 | char *filename; | |
240 | { | |
241 | /* 32V put this message on stdout, S5 does it on stderr. */ | |
242 | if (!silent) | |
243 | (void)fprintf(stderr, "cmp: EOF on %s\n", filename); | |
244 | exit(DIFF); | |
245 | } | |
246 | ||
34cbacef KB |
247 | /* |
248 | * usage -- | |
249 | * print usage and die | |
250 | */ | |
251 | static | |
252 | usage() | |
1b88b85d | 253 | { |
ec37e2d9 | 254 | fputs("usage: cmp [-ls] file1 file2 [skip1] [skip2]\n", stderr); |
34cbacef | 255 | exit(ERR); |
1b88b85d | 256 | } |