|
|
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: (1) source distributions retain this entire copyright
7: * notice and comment, and (2) distributions including binaries display
8: * the following acknowledgement: ``This product includes software
9: * developed by the University of California, Berkeley and its contributors''
10: * in the documentation or other materials provided with the distribution
11: * and in all advertising materials mentioning features or use of this
12: * software. Neither the name of the University nor the names of its
13: * contributors may be used to endorse or promote products derived
14: * from this software without specific prior written permission.
15: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
16: * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
17: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
18: */
19:
20: #ifndef lint
21: char copyright[] =
22: "@(#) Copyright (c) 1987, 1990 Regents of the University of California.\n\
23: All rights reserved.\n";
24: #endif /* not lint */
25:
26: #ifndef lint
27: static char sccsid[] = "@(#)cmp.c 5.3 (Berkeley) 6/1/90";
28: #endif /* not lint */
29:
30: #include <sys/param.h>
31: #include <sys/file.h>
32: #include <sys/stat.h>
33: #include <stdio.h>
34: #include <ctype.h>
35: #include <errno.h>
36:
37: #define EXITNODIFF 0
38: #define EXITDIFF 1
39: #define EXITERR 2
40:
41: int all, fd1, fd2, silent;
42: u_char buf1[MAXBSIZE], buf2[MAXBSIZE];
43: char *file1, *file2;
44:
45: main(argc, argv)
46: int argc;
47: char *argv[];
48: {
49: extern char *optarg;
50: extern int optind;
51: int ch;
52: u_long otoi();
53:
54: while ((ch = getopt(argc, argv, "-ls")) != EOF)
55: switch (ch) {
56: case 'l': /* print all differences */
57: all = 1;
58: break;
59: case 's': /* silent run */
60: silent = 1;
61: break;
62: case '-': /* must be after any flags */
63: --optind;
64: goto endargs;
65: case '?':
66: default:
67: usage();
68: }
69: endargs:
70: argv += optind;
71: argc -= optind;
72:
73: if (argc < 2 || argc > 4)
74: usage();
75:
76: if (all && silent) {
77: fprintf(stderr,
78: "cmp: only one of -l and -s may be specified.\n");
79: exit(EXITERR);
80: }
81: if (strcmp(file1 = argv[0], "-") == 0)
82: fd1 = 0;
83: else if ((fd1 = open(file1, O_RDONLY, 0)) < 0)
84: error(file1);
85: if (strcmp(file2 = argv[1], "-") == 0)
86: fd2 = 0;
87: else if ((fd2 = open(file2, O_RDONLY, 0)) < 0)
88: error(file2);
89: if (fd1 == fd2) {
90: fprintf(stderr,
91: "cmp: standard input may only be specified once.\n");
92: exit(EXITERR);
93: }
94:
95: /* handle skip arguments */
96: if (argc > 2) {
97: skip(otoi(argv[2]), fd1, file1);
98: if (argc == 4)
99: skip(otoi(argv[3]), fd2, file2);
100: }
101: cmp();
102: /*NOTREACHED*/
103: }
104:
105: /*
106: * skip --
107: * skip first part of file
108: */
109: skip(dist, fd, fname)
110: register u_long dist;
111: register int fd;
112: char *fname;
113: {
114: register int rlen, nread;
115:
116: for (; dist; dist -= rlen) {
117: rlen = MIN(dist, sizeof(buf1));
118: if ((nread = read(fd, buf1, rlen)) != rlen) {
119: if (nread < 0)
120: error(fname);
121: else
122: endoffile(fname);
123: }
124: }
125: }
126:
127: cmp()
128: {
129: register u_char *p1, *p2;
130: register int cnt, len1, len2;
131: register long byte, line;
132: int dfound = 0;
133:
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: /* NOTREACHED */
147: case 0:
148: exit(dfound ? EXITDIFF : EXITNODIFF);
149: /* NOTREACHED */
150: default:
151: endoffile(file1);
152: break;
153: }
154: }
155: /*
156: * file1 might be stdio, which means that a read of less than
157: * MAXBSIZE might not mean an EOF. So, read whatever we read
158: * from file1 from file2.
159: */
160: if ((len2 = read(fd2, buf2, len1)) == -1)
161: error(file2);
162: if (bcmp(buf1, buf2, len2)) {
163: if (silent)
164: exit(EXITDIFF);
165: if (all) {
166: dfound = 1;
167: for (p1 = buf1, p2 = buf2, cnt = len2; cnt--;
168: ++p1, ++p2) {
169: ++byte;
170: if (*p1 != *p2)
171: printf("%6ld %3o %3o\n",
172: byte, *p1, *p2);
173: }
174: } else for (p1 = buf1, p2 = buf2; ; ++p1, ++p2) {
175: ++byte;
176: if (*p1 != *p2) {
177: printf("%s %s differ: char %ld, line %ld\n", file1, file2, byte, line);
178: exit(EXITDIFF);
179: }
180: if (*p1 == '\n')
181: ++line;
182: }
183: } else {
184: byte += len2;
185: /*
186: * here's the real performance problem, we've got to
187: * count the stupid lines, which means that -l is a
188: * *much* faster version, i.e., unless you really
189: * *want* to know the line number, run -s or -l.
190: */
191: if (!silent && !all)
192: for (p1 = buf1, cnt = len2; cnt--; )
193: if (*p1++ == '\n')
194: ++line;
195: }
196: /*
197: * couldn't read as much from file2 as from file1; checked
198: * here because there might be a difference before we got
199: * to this point, which would have precedence.
200: */
201: if (len2 < len1)
202: endoffile(file2);
203: }
204: }
205:
206: /*
207: * otoi --
208: * octal/decimal string to u_long
209: */
210: u_long
211: otoi(s)
212: register char *s;
213: {
214: register u_long val;
215: register int base;
216:
217: base = (*s == '0') ? 8 : 10;
218: for (val = 0; isdigit(*s); ++s)
219: val = val * base + *s - '0';
220: return (val);
221: }
222:
223: /*
224: * error --
225: * print I/O error message and die
226: */
227: error(filename)
228: char *filename;
229: {
230: extern int errno;
231: char *strerror();
232:
233: if (!silent)
234: (void) fprintf(stderr, "cmp: %s: %s\n",
235: filename, strerror(errno));
236: exit(EXITERR);
237: }
238:
239: /*
240: * endoffile --
241: * print end-of-file message and exit indicating the files were different
242: */
243: endoffile(filename)
244: char *filename;
245: {
246: /* 32V put this message on stdout, S5 does it on stderr. */
247: /* POSIX.2 currently does it on stdout-- Hooray! */
248: if (!silent)
249: (void) printf("cmp: EOF on %s\n", filename);
250: exit(EXITDIFF);
251: }
252:
253: /*
254: * usage --
255: * print usage and die
256: */
257: usage()
258: {
259: fputs("usage: cmp [-ls] file1 file2 [skip1] [skip2]\n", stderr);
260: exit(EXITERR);
261: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.