man page in the right palce
[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[] =
152df645 20"@(#) Copyright (c) 1987, 1990 Regents of the University of California.\n\
94721995 21 All rights reserved.\n";
b8c620d6 22#endif /* not lint */
94721995
KB
23
24#ifndef lint
152df645 25static char sccsid[] = "@(#)cmp.c 5.2 (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
152df645
MK
39int all, fd1, fd2, silent;
40u_char buf1[MAXBSIZE], buf2[MAXBSIZE];
41char *file1, *file2;
1b88b85d 42
ec37e2d9 43main(argc, argv)
1b7289a3 44 int argc;
152df645 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)
152df645 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 }
152df645 79 if (strcmp(file1 = argv[0], "-") == 0)
1b7289a3
KB
80 fd1 = 0;
81 else if ((fd1 = open(file1, O_RDONLY, 0)) < 0)
ec37e2d9 82 error(file1);
152df645 83 if (strcmp(file2 = argv[1], "-") == 0)
1b7289a3
KB
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 */
ec37e2d9 107skip(dist, fd, fname)
1b7289a3
KB
108 register u_long dist;
109 register int fd;
110 char *fname;
34cbacef 111{
1b7289a3 112 register int rlen, nread;
ec37e2d9
KB
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);
1b88b85d 121 }
1b88b85d 122 }
34cbacef 123}
1b88b85d 124
34cbacef
KB
125cmp()
126{
152df645 127 register u_char *p1, *p2;
1b7289a3
KB
128 register int cnt, len1, len2;
129 register long byte, line;
130 int dfound = 0;
34cbacef 131
152df645
MK
132 for (byte = 0, line = 1; ; ) {
133 switch (len1 = read(fd1, buf1, MAXBSIZE)) {
ec37e2d9
KB
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 */
152df645 141 switch (read(fd2, buf2, 1)) {
ec37e2d9
KB
142 case -1:
143 error(file2);
152df645 144 /* NOTREACHED */
ec37e2d9 145 case 0:
1b7289a3 146 exit(dfound ? EXITDIFF : EXITNODIFF);
152df645 147 /* NOTREACHED */
ec37e2d9
KB
148 default:
149 endoffile(file1);
152df645 150 break;
ec37e2d9 151 }
34cbacef
KB
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 */
ec37e2d9
KB
158 if ((len2 = read(fd2, buf2, len1)) == -1)
159 error(file2);
160 if (bcmp(buf1, buf2, len2)) {
34cbacef 161 if (silent)
1b7289a3 162 exit(EXITDIFF);
34cbacef 163 if (all) {
1b7289a3 164 dfound = 1;
152df645
MK
165 for (p1 = buf1, p2 = buf2, cnt = len2; cnt--;
166 ++p1, ++p2) {
34cbacef 167 ++byte;
152df645
MK
168 if (*p1 != *p2)
169 printf("%6ld %3o %3o\n",
170 byte, *p1, *p2);
34cbacef 171 }
152df645 172 } else for (p1 = buf1, p2 = buf2; ; ++p1, ++p2) {
94721995 173 ++byte;
152df645 174 if (*p1 != *p2) {
ec37e2d9 175 printf("%s %s differ: char %ld, line %ld\n", file1, file2, byte, line);
1b7289a3 176 exit(EXITDIFF);
34cbacef 177 }
152df645 178 if (*p1 == '\n')
94721995
KB
179 ++line;
180 }
1b7289a3 181 } else {
34cbacef
KB
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
94721995 187 * *want* to know the line number, run -s or -l.
34cbacef 188 */
94721995 189 if (!silent && !all)
152df645
MK
190 for (p1 = buf1, cnt = len2; cnt--; )
191 if (*p1++ == '\n')
34cbacef
KB
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 */
ec37e2d9
KB
199 if (len2 < len1)
200 endoffile(file2);
1b88b85d 201 }
34cbacef 202}
1b88b85d 203
34cbacef
KB
204/*
205 * otoi --
206 * octal/decimal string to u_long
207 */
152df645
MK
208u_long
209otoi(s)
210 register char *s;
34cbacef 211{
1b7289a3
KB
212 register u_long val;
213 register int base;
1b88b85d 214
152df645
MK
215 base = (*s == '0') ? 8 : 10;
216 for (val = 0; isdigit(*s); ++s)
217 val = val * base + *s - '0';
218 return (val);
1b88b85d
BJ
219}
220
ec37e2d9
KB
221/*
222 * error --
223 * print I/O error message and die
224 */
ec37e2d9
KB
225error(filename)
226 char *filename;
227{
228 extern int errno;
1b7289a3 229 char *strerror();
ec37e2d9 230
1b7289a3 231 if (!silent)
152df645 232 (void) fprintf(stderr, "cmp: %s: %s\n",
1b7289a3
KB
233 filename, strerror(errno));
234 exit(EXITERR);
ec37e2d9
KB
235}
236
237/*
238 * endoffile --
239 * print end-of-file message and exit indicating the files were different
240 */
ec37e2d9
KB
241endoffile(filename)
242 char *filename;
243{
244 /* 32V put this message on stdout, S5 does it on stderr. */
152df645 245 /* POSIX.2 currently does it on stdout-- Hooray! */
ec37e2d9 246 if (!silent)
152df645 247 (void) printf("cmp: EOF on %s\n", filename);
1b7289a3 248 exit(EXITDIFF);
ec37e2d9
KB
249}
250
34cbacef
KB
251/*
252 * usage --
253 * print usage and die
254 */
34cbacef 255usage()
1b88b85d 256{
ec37e2d9 257 fputs("usage: cmp [-ls] file1 file2 [skip1] [skip2]\n", stderr);
1b7289a3 258 exit(EXITERR);
1b88b85d 259}