|
|
1.1 root 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
19: char copyright[] =
20: "@(#) Copyright (c) 1987 Regents of the University of California.\n\
21: All rights reserved.\n";
22: #endif /* not lint */
23:
24: #ifndef lint
25: static char sccsid[] = "@(#)cmp.c 4.9 (Berkeley) 6/18/88";
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 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 */
40:
41: static int fd1, fd2, /* file descriptors */
42: silent = NO; /* if silent run */
43: static short all = NO; /* if report all differences */
44: static u_char buf1[MAXBSIZE], /* read buffers */
45: buf2[MAXBSIZE];
46: static char *file1, *file2; /* file names */
47:
48: main(argc, argv)
49: int argc;
50: char **argv;
51: {
52: extern char *optarg;
53: extern int optind;
54: int ch;
55: u_long otoi();
56:
57: while ((ch = getopt(argc, argv, "ls")) != EOF)
58: switch(ch) {
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();
68: }
69: argv += optind;
70: argc -= optind;
71:
72: if (argc < 2 || argc > 4)
73: usage();
74:
75: /* open up files; "-" is stdin */
76: file1 = argv[0];
77: if (strcmp(file1, "-") && (fd1 = open(file1, O_RDONLY, 0)) < 0)
78: error(file1);
79: file2 = argv[1];
80: if ((fd2 = open(file2, O_RDONLY, 0)) < 0)
81: error(file2);
82:
83: /* handle skip arguments */
84: if (argc > 2) {
85: skip(otoi(argv[2]), fd1, file1);
86: if (argc == 4)
87: skip(otoi(argv[3]), fd2, file2);
88: }
89: cmp();
90: /*NOTREACHED*/
91: }
92:
93: /*
94: * skip --
95: * skip first part of file
96: */
97: static
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 */
102: {
103: register int rlen; /* read length */
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);
113: }
114: }
115: }
116:
117: static
118: cmp()
119: {
120: register u_char *C1, *C2; /* traveling pointers */
121: register int cnt, /* counter */
122: len1, len2; /* read lengths */
123: register long byte, /* byte count */
124: line; /* line count */
125: short dfound = NO; /* if difference found */
126:
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: }
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: */
150: if ((len2 = read(fd2, buf2, len1)) == -1)
151: error(file2);
152: if (bcmp(buf1, buf2, len2)) {
153: if (silent)
154: exit(DIFF);
155: if (all) {
156: dfound = YES;
157: for (C1 = buf1, C2 = buf2, cnt = len2; cnt--; ++C1, ++C2) {
158: ++byte;
159: if (*C1 != *C2)
160: printf("%6ld %3o %3o\n", byte, *C1, *C2);
161: }
162: }
163: else for (C1 = buf1, C2 = buf2;; ++C1, ++C2) {
164: ++byte;
165: if (*C1 != *C2) {
166: printf("%s %s differ: char %ld, line %ld\n", file1, file2, byte, line);
167: exit(DIFF);
168: }
169: if (*C1 == '\n')
170: ++line;
171: }
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
179: * *want* to know the line number, run -s or -l.
180: */
181: if (!silent && !all)
182: for (C1 = buf1, cnt = len2; cnt--;)
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: */
191: if (len2 < len1)
192: endoffile(file2);
193: }
194: }
195:
196: /*
197: * otoi --
198: * octal/decimal string to u_long
199: */
200: static u_long
201: otoi(C)
202: register char *C; /* argument string */
203: {
204: register u_long val; /* return value */
205: register int base; /* number base */
206:
207: base = (*C == '0') ? 8 : 10;
208: for (val = 0; isdigit(*C); ++C)
209: val = val * base + *C - '0';
210: return(val);
211: }
212:
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:
247: /*
248: * usage --
249: * print usage and die
250: */
251: static
252: usage()
253: {
254: fputs("usage: cmp [-ls] file1 file2 [skip1] [skip2]\n", stderr);
255: exit(ERR);
256: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.