Commit | Line | Data |
---|---|---|
da263a2e | 1 | static 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 |
15 | static int fd1, /* descriptor, file 1 */ |
16 | fd2, /* descriptor, file 2 */ | |
17 | silent = NO; /* if silent on error */ | |
18 | static short all = NO; /* if report all differences */ | |
19 | static u_char buf1[MAXBSIZE], /* read buffers */ | |
20 | buf2[MAXBSIZE]; | |
21 | static char *file1, /* name, file 1 */ | |
22 | *file2; /* name, file 2 */ | |
1b88b85d | 23 | |
34cbacef KB |
24 | main(argc,argv) |
25 | int argc; | |
26 | char **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 | */ | |
78 | static | |
79 | skip(dist,fd,fname) | |
80 | register u_long dist; /* length in bytes, to skip */ | |
81 | register int fd; /* file descriptor */ | |
82 | char *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 |
96 | static |
97 | cmp() | |
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 | */ | |
194 | static u_long | |
195 | otoi(C) | |
196 | register 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 | */ | |
211 | static | |
212 | usage() | |
1b88b85d | 213 | { |
da263a2e | 214 | fputs("usage: cmp [-ls] file1 file2 [skip1] [skip2]\n",stderr); |
34cbacef | 215 | exit(ERR); |
1b88b85d | 216 | } |