fix '-' parsing; make -l, -s mutually exclusive, KNF cleanups
[unix-history] / usr / src / usr.bin / cmp / cmp.c
CommitLineData
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
19char 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 25static 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
39static int all, fd1, fd2, silent;
40static u_char buf1[MAXBSIZE], buf2[MAXBSIZE];
41static char *file1, *file2;
1b88b85d 42
ec37e2d9 43main(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 67endargs:
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 */
107static
ec37e2d9 108skip(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
126static
127cmp()
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 */
205static u_long
206otoi(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 */
222static
223error(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 */
239static
240endoffile(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 */
253static
254usage()
1b88b85d 255{
ec37e2d9 256 fputs("usage: cmp [-ls] file1 file2 [skip1] [skip2]\n", stderr);
1b7289a3 257 exit(EXITERR);
1b88b85d 258}