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