date and time created 87/06/19 09:34:23 by minshall
[unix-history] / usr / src / usr.bin / cmp / cmp.c
CommitLineData
da263a2e 1static char *sccsid = "@(#)cmp.c 4.4 (Berkeley) %G%";
34cbacef
KB
2
3#include <sys/param.h>
4#include <sys/file.h>
5#include <sys/stat.h>
1b88b85d
BJ
6#include <stdio.h>
7#include <ctype.h>
8
34cbacef
KB
9#define DIFF 1 /* found differences */
10#define ERR 2 /* error during run */
11#define NO 0 /* no/false */
12#define OK 0 /* didn't find differences */
13#define YES 1 /* yes/true */
1b88b85d 14
34cbacef
KB
15static int fd1, /* descriptor, file 1 */
16 fd2, /* descriptor, file 2 */
17 silent = NO; /* if silent on error */
18static short all = NO; /* if report all differences */
19static u_char buf1[MAXBSIZE], /* read buffers */
20 buf2[MAXBSIZE];
21static char *file1, /* name, file 1 */
22 *file2; /* name, file 2 */
1b88b85d 23
34cbacef
KB
24main(argc,argv)
25int argc;
26char **argv;
1b88b85d 27{
34cbacef
KB
28 extern char *optarg; /* getopt externals */
29 extern int optind;
30 int ch; /* arguments */
31 u_long otoi();
32
33 while ((ch = getopt(argc,argv,"ls")) != EOF)
34 switch(ch) {
35 case 'l': /* print all differences */
36 all = YES;
37 break;
38 case 's': /* silent return */
39 silent = YES;
40 break;
41 case '?':
42 default:
43 usage();
44 }
45 argv += optind;
46 argc -= optind;
1b88b85d 47
34cbacef
KB
48 if (argc < 2 || argc > 4)
49 usage();
50
51 /* open up files; "-" is stdin */
52 file1 = argv[0];
53 if (strcmp(file1,"-") && (fd1 = open(file1,O_RDONLY)) < 0) {
54 if (!silent)
55 perror(file1);
56 exit(ERR);
1b88b85d 57 }
34cbacef
KB
58 file2 = argv[1];
59 if ((fd2 = open(file2,O_RDONLY)) < 0) {
60 if (!silent)
61 perror(file2);
62 exit(ERR);
1b88b85d 63 }
34cbacef
KB
64
65 /* handle skip arguments */
66 if (argc > 2) {
67 skip(otoi(argv[2]),fd1,file1);
68 if (argc == 4)
69 skip(otoi(argv[3]),fd2,file2);
1b88b85d 70 }
34cbacef
KB
71 cmp();
72}
73
74/*
75 * skip --
76 * skip first part of file
77 */
78static
79skip(dist,fd,fname)
80register u_long dist; /* length in bytes, to skip */
81register int fd; /* file descriptor */
82char *fname; /* file name for error */
83{
84 register int rlen; /* read length */
85
86 for (;dist;dist -= rlen) {
87 rlen = MIN(dist,sizeof(buf1));
88 if (read(fd,buf1,rlen) != rlen) {
89 if (!silent)
90 printf("cmp: EOF on %s\n",fname);
91 exit(DIFF);
1b88b85d 92 }
1b88b85d 93 }
34cbacef 94}
1b88b85d 95
34cbacef
KB
96static
97cmp()
98{
99 register u_char *C1, /* traveling pointers */
100 *C2;
101 register int cnt, /* counter */
102 len1, /* read length 1 */
103 len2; /* read length 2 */
104 register long byte, /* byte count */
105 line; /* line count */
106 short dfound = NO; /* if difference found */
107
108 for (byte = 0,line = 1;;) {
109 switch(len1 = read(fd1,buf1,MAXBSIZE)) {
110 case -1:
111 if (!silent)
112 perror(file1);
113 exit(ERR);
114 case 0:
115 /*
116 * read of file 1 just failed, find out
117 * if there's anything left in file 2
118 */
119 switch(read(fd2,buf2,1)) {
120 case -1:
121 if (!silent)
122 perror(file2);
123 exit(ERR);
124 case 0:
125 exit(dfound ? DIFF : OK);
126 default:
127 if (!silent)
128 printf("cmp: EOF on %s\n",file1);
129 exit(DIFF);
130 }
131 }
132 /*
133 * file1 might be stdio, which means that a read of less than
134 * MAXBSIZE might not mean an EOF. So, read whatever we read
135 * from file1 from file2.
136 */
137 if ((len2 = read(fd2,buf2,len1)) == -1) {
138 if (!silent)
139 perror(file2);
140 exit(ERR);
141 }
142 if (bcmp(buf1,buf2,len2)) {
143 if (silent)
144 exit(DIFF);
145 if (all) {
146 dfound = YES;
147 for (C1 = buf1,C2 = buf2,cnt = len2;cnt--;++C1,++C2) {
148 ++byte;
149 if (*C1 != *C2)
150 printf("%6ld %3o %3o\n",byte,*C1,*C2);
151 }
152 }
153 else
154 for (C1 = buf1,C2 = buf2;;++C1,++C2) {
155 ++byte;
156 if (*C1 != *C2) {
157 printf("%s %s differ: char %ld, line %ld\n",file1,file2,byte,line);
158 exit(DIFF);
159 }
160 if (*C1 == '\n')
161 ++line;
162 }
163 }
164 else {
165 byte += len2;
166 /*
167 * here's the real performance problem, we've got to
168 * count the stupid lines, which means that -l is a
169 * *much* faster version, i.e., unless you really
170 * *want* to know the line number, run -sl.
171 */
172 if (!all)
173 for (C1 = buf1,cnt = len2;cnt--;)
174 if (*C1++ == '\n')
175 ++line;
176 }
177 /*
178 * couldn't read as much from file2 as from file1; checked
179 * here because there might be a difference before we got
180 * to this point, which would have precedence.
181 */
182 if (len2 < len1) {
183 if (!silent)
184 printf("cmp: EOF on %s\n",file2);
185 exit(DIFF);
1b88b85d 186 }
1b88b85d 187 }
34cbacef 188}
1b88b85d 189
34cbacef
KB
190/*
191 * otoi --
192 * octal/decimal string to u_long
193 */
194static u_long
195otoi(C)
196register char *C; /* argument string */
197{
198 register u_long val; /* return value */
199 register int base; /* number base */
1b88b85d 200
34cbacef
KB
201 base = (*C == '0') ? 8 : 10;
202 for (val = 0;isdigit(*C);++C)
203 val = val * base + *C - '0';
204 return(val);
1b88b85d
BJ
205}
206
34cbacef
KB
207/*
208 * usage --
209 * print usage and die
210 */
211static
212usage()
1b88b85d 213{
da263a2e 214 fputs("usage: cmp [-ls] file1 file2 [skip1] [skip2]\n",stderr);
34cbacef 215 exit(ERR);
1b88b85d 216}