Commit | Line | Data |
---|---|---|
390caa6e | 1 | static char *sccsid = "@(#)diffdir.c 4.9 (Berkeley) %G%"; |
c1df85d7 BJ |
2 | |
3 | #include "diff.h" | |
4 | /* | |
5 | * diff - directory comparison | |
6 | */ | |
7 | #define d_flags d_ino | |
8 | ||
9 | #define ONLY 1 /* Only in this directory */ | |
10 | #define SAME 2 /* Both places and same */ | |
11 | #define DIFFER 4 /* Both places and different */ | |
12 | #define DIRECT 8 /* Directory */ | |
13 | ||
9299bded SL |
14 | struct dir { |
15 | u_long d_ino; | |
16 | short d_reclen; | |
17 | short d_namlen; | |
18 | char *d_entry; | |
19 | }; | |
20 | ||
21 | struct dir *setupdir(); | |
c1df85d7 BJ |
22 | int header; |
23 | char title[2*BUFSIZ], *etitle; | |
24 | ||
25 | diffdir(argv) | |
26 | char **argv; | |
27 | { | |
9299bded SL |
28 | register struct dir *d1, *d2; |
29 | struct dir *dir1, *dir2; | |
c1df85d7 BJ |
30 | register int i; |
31 | int cmp; | |
32 | ||
33 | if (opt == D_IFDEF) { | |
34 | fprintf(stderr, "diff: can't specify -I with directories\n"); | |
35 | done(); | |
36 | } | |
37 | if (opt == D_EDIT && (sflag || lflag)) | |
38 | fprintf(stderr, | |
39 | "diff: warning: shouldn't give -s or -l with -e\n"); | |
40 | title[0] = 0; | |
41 | strcpy(title, "diff "); | |
42 | for (i = 1; diffargv[i+2]; i++) { | |
43 | if (!strcmp(diffargv[i], "-")) | |
44 | continue; /* was -S, dont look silly */ | |
45 | strcat(title, diffargv[i]); | |
46 | strcat(title, " "); | |
47 | } | |
48 | for (etitle = title; *etitle; etitle++) | |
49 | ; | |
50 | setfile(&file1, &efile1, file1); | |
51 | setfile(&file2, &efile2, file2); | |
52 | argv[0] = file1; | |
53 | argv[1] = file2; | |
54 | dir1 = setupdir(file1); | |
55 | dir2 = setupdir(file2); | |
56 | d1 = dir1; d2 = dir2; | |
9299bded SL |
57 | while (d1->d_entry != 0 || d2->d_entry != 0) { |
58 | if (d1->d_entry && useless(d1->d_entry)) { | |
c1df85d7 BJ |
59 | d1++; |
60 | continue; | |
61 | } | |
9299bded | 62 | if (d2->d_entry && useless(d2->d_entry)) { |
c1df85d7 BJ |
63 | d2++; |
64 | continue; | |
65 | } | |
9299bded | 66 | if (d1->d_entry == 0) |
c1df85d7 | 67 | cmp = 1; |
9299bded | 68 | else if (d2->d_entry == 0) |
c1df85d7 BJ |
69 | cmp = -1; |
70 | else | |
9299bded | 71 | cmp = strcmp(d1->d_entry, d2->d_entry); |
c1df85d7 BJ |
72 | if (cmp < 0) { |
73 | if (lflag) | |
74 | d1->d_flags |= ONLY; | |
9299bded | 75 | else if (opt == 0 || opt == 2) |
c1df85d7 | 76 | only(d1, 1); |
c1df85d7 BJ |
77 | d1++; |
78 | } else if (cmp == 0) { | |
79 | compare(d1); | |
80 | d1++; | |
81 | d2++; | |
82 | } else { | |
83 | if (lflag) | |
84 | d2->d_flags |= ONLY; | |
9299bded | 85 | else if (opt == 0 || opt == 2) |
c1df85d7 | 86 | only(d2, 2); |
c1df85d7 BJ |
87 | d2++; |
88 | } | |
89 | } | |
90 | if (lflag) { | |
f8377f45 SL |
91 | scanpr(dir1, ONLY, "Only in %.*s", file1, efile1, 0, 0); |
92 | scanpr(dir2, ONLY, "Only in %.*s", file2, efile2, 0, 0); | |
93 | scanpr(dir1, SAME, "Common identical files in %.*s and %.*s", | |
94 | file1, efile1, file2, efile2); | |
95 | scanpr(dir1, DIFFER, "Binary files which differ in %.*s and %.*s", | |
96 | file1, efile1, file2, efile2); | |
97 | scanpr(dir1, DIRECT, "Common subdirectories of %.*s and %.*s", | |
98 | file1, efile1, file2, efile2); | |
c1df85d7 BJ |
99 | } |
100 | if (rflag) { | |
101 | if (header && lflag) | |
102 | printf("\f"); | |
9299bded | 103 | for (d1 = dir1; d1->d_entry; d1++) { |
c1df85d7 BJ |
104 | if ((d1->d_flags & DIRECT) == 0) |
105 | continue; | |
9299bded SL |
106 | strcpy(efile1, d1->d_entry); |
107 | strcpy(efile2, d1->d_entry); | |
c1df85d7 BJ |
108 | calldiff(0); |
109 | } | |
110 | } | |
111 | } | |
112 | ||
113 | setfile(fpp, epp, file) | |
114 | char **fpp, **epp; | |
115 | char *file; | |
116 | { | |
117 | register char *cp; | |
118 | ||
119 | *fpp = malloc(BUFSIZ); | |
120 | if (*fpp == 0) { | |
121 | fprintf(stderr, "diff: ran out of memory\n"); | |
122 | exit(1); | |
123 | } | |
124 | strcpy(*fpp, file); | |
125 | for (cp = *fpp; *cp; cp++) | |
126 | continue; | |
127 | *cp++ = '/'; | |
128 | *epp = cp; | |
129 | } | |
130 | ||
f8377f45 | 131 | scanpr(dp, test, title, file1, efile1, file2, efile2) |
9299bded | 132 | register struct dir *dp; |
c1df85d7 | 133 | int test; |
f8377f45 | 134 | char *title, *file1, *efile1, *file2, *efile2; |
c1df85d7 BJ |
135 | { |
136 | int titled = 0; | |
137 | ||
9299bded SL |
138 | for (; dp->d_entry; dp++) { |
139 | if ((dp->d_flags & test) == 0) | |
140 | continue; | |
141 | if (titled == 0) { | |
f8377f45 | 142 | if (header == 0) |
9299bded | 143 | header = 1; |
f8377f45 | 144 | else |
9299bded | 145 | printf("\n"); |
f8377f45 SL |
146 | printf(title, |
147 | efile1 - file1 - 1, file1, | |
148 | efile2 - file2 - 1, file2); | |
9299bded SL |
149 | printf(":\n"); |
150 | titled = 1; | |
c1df85d7 | 151 | } |
9299bded SL |
152 | printf("\t%s\n", dp->d_entry); |
153 | } | |
c1df85d7 BJ |
154 | } |
155 | ||
156 | only(dp, which) | |
9299bded | 157 | struct dir *dp; |
c1df85d7 BJ |
158 | int which; |
159 | { | |
160 | char *file = which == 1 ? file1 : file2; | |
161 | char *efile = which == 1 ? efile1 : efile2; | |
162 | ||
9299bded | 163 | printf("Only in %.*s: %s\n", efile - file - 1, file, dp->d_entry); |
c1df85d7 BJ |
164 | } |
165 | ||
166 | int entcmp(); | |
167 | ||
9299bded | 168 | struct dir * |
c1df85d7 BJ |
169 | setupdir(cp) |
170 | char *cp; | |
171 | { | |
9299bded SL |
172 | register struct dir *dp = 0, *ep; |
173 | register struct direct *rp; | |
174 | register int nitems, n; | |
175 | DIR *dirp; | |
c1df85d7 | 176 | |
9299bded SL |
177 | dirp = opendir(cp); |
178 | if (dirp == NULL) { | |
c1df85d7 BJ |
179 | fprintf(stderr, "diff: "); |
180 | perror(cp); | |
181 | done(); | |
182 | } | |
9299bded SL |
183 | nitems = 0; |
184 | dp = (struct dir *)malloc(sizeof (struct dir)); | |
c1df85d7 BJ |
185 | if (dp == 0) { |
186 | fprintf(stderr, "diff: ran out of memory\n"); | |
187 | done(); | |
188 | } | |
9299bded SL |
189 | while (rp = readdir(dirp)) { |
190 | ep = &dp[nitems++]; | |
191 | ep->d_reclen = rp->d_reclen; | |
192 | ep->d_namlen = rp->d_namlen; | |
193 | ep->d_entry = 0; | |
c1df85d7 | 194 | ep->d_flags = 0; |
9299bded SL |
195 | if (ep->d_namlen > 0) { |
196 | ep->d_entry = malloc(ep->d_namlen + 1); | |
197 | if (ep->d_entry == 0) { | |
198 | fprintf(stderr, "diff: out of memory\n"); | |
199 | done(); | |
200 | } | |
201 | strcpy(ep->d_entry, rp->d_name); | |
202 | } | |
203 | dp = (struct dir *)realloc((char *)dp, | |
204 | (nitems + 1) * sizeof (struct dir)); | |
205 | if (dp == 0) { | |
206 | fprintf(stderr, "diff: ran out of memory\n"); | |
207 | done(); | |
208 | } | |
209 | } | |
210 | dp[nitems].d_entry = 0; /* delimiter */ | |
211 | closedir(dirp); | |
212 | qsort(dp, nitems, sizeof (struct dir), entcmp); | |
c1df85d7 BJ |
213 | return (dp); |
214 | } | |
215 | ||
216 | entcmp(d1, d2) | |
9299bded | 217 | struct dir *d1, *d2; |
c1df85d7 | 218 | { |
9299bded | 219 | return (strcmp(d1->d_entry, d2->d_entry)); |
c1df85d7 BJ |
220 | } |
221 | ||
222 | compare(dp) | |
9299bded | 223 | register struct dir *dp; |
c1df85d7 BJ |
224 | { |
225 | register int i, j; | |
226 | int f1, f2, fmt1, fmt2; | |
227 | struct stat stb1, stb2; | |
228 | int flag = 0; | |
229 | char buf1[BUFSIZ], buf2[BUFSIZ]; | |
230 | ||
9299bded SL |
231 | strcpy(efile1, dp->d_entry); |
232 | strcpy(efile2, dp->d_entry); | |
c1df85d7 BJ |
233 | f1 = open(file1, 0); |
234 | if (f1 < 0) { | |
235 | perror(file1); | |
236 | return; | |
237 | } | |
238 | f2 = open(file2, 0); | |
239 | if (f2 < 0) { | |
240 | perror(file2); | |
241 | close(f1); | |
242 | return; | |
243 | } | |
244 | fstat(f1, &stb1); fstat(f2, &stb2); | |
245 | fmt1 = stb1.st_mode & S_IFMT; | |
246 | fmt2 = stb2.st_mode & S_IFMT; | |
247 | if (fmt1 != S_IFREG || fmt2 != S_IFREG) { | |
248 | if (fmt1 == fmt2) { | |
249 | if (fmt1 != S_IFDIR && stb1.st_rdev == stb2.st_rdev) | |
250 | goto same; | |
251 | if (fmt1 == S_IFDIR) { | |
252 | dp->d_flags = DIRECT; | |
253 | if (lflag || opt == D_EDIT) | |
254 | goto closem; | |
255 | printf("Common subdirectories: %s and %s\n", | |
256 | file1, file2); | |
257 | goto closem; | |
258 | } | |
259 | } | |
260 | goto notsame; | |
261 | } | |
262 | if (stb1.st_size != stb2.st_size) | |
263 | goto notsame; | |
264 | for (;;) { | |
265 | i = read(f1, buf1, BUFSIZ); | |
266 | j = read(f2, buf2, BUFSIZ); | |
267 | if (i < 0 || j < 0 || i != j) | |
268 | goto notsame; | |
269 | if (i == 0 && j == 0) | |
270 | goto same; | |
271 | for (j = 0; j < i; j++) | |
272 | if (buf1[j] != buf2[j]) | |
273 | goto notsame; | |
274 | } | |
275 | same: | |
276 | if (sflag == 0) | |
277 | goto closem; | |
278 | if (lflag) | |
279 | dp->d_flags = SAME; | |
280 | else | |
281 | printf("Files %s and %s are identical\n", file1, file2); | |
282 | goto closem; | |
283 | notsame: | |
284 | if (!ascii(f1) || !ascii(f2)) { | |
285 | if (lflag) | |
286 | dp->d_flags |= DIFFER; | |
287 | else if (opt == D_NORMAL || opt == D_CONTEXT) | |
288 | printf("Binary files %s and %s differ\n", | |
289 | file1, file2); | |
290 | goto closem; | |
291 | } | |
292 | close(f1); close(f2); | |
293 | anychange = 1; | |
294 | if (lflag) | |
295 | calldiff(title); | |
296 | else { | |
297 | if (opt == D_EDIT) { | |
9299bded | 298 | printf("ed - %s << '-*-END-*-'\n", dp->d_entry); |
c1df85d7 BJ |
299 | calldiff(0); |
300 | } else { | |
301 | printf("%s%s %s\n", title, file1, file2); | |
302 | calldiff(0); | |
303 | } | |
304 | if (opt == D_EDIT) | |
305 | printf("w\nq\n-*-END-*-\n"); | |
306 | } | |
307 | return; | |
308 | closem: | |
309 | close(f1); close(f2); | |
310 | } | |
311 | ||
eaeea298 | 312 | char *prargs[] = { "pr", "-h", 0, "-f", 0, 0 }; |
c1df85d7 BJ |
313 | |
314 | calldiff(wantpr) | |
315 | char *wantpr; | |
316 | { | |
317 | int pid, status, status2, pv[2]; | |
318 | ||
eaeea298 | 319 | prargs[2] = wantpr; |
c1df85d7 BJ |
320 | fflush(stdout); |
321 | if (wantpr) { | |
322 | sprintf(etitle, "%s %s", file1, file2); | |
323 | pipe(pv); | |
324 | pid = fork(); | |
325 | if (pid == -1) { | |
326 | fprintf(stderr, "No more processes"); | |
327 | done(); | |
328 | } | |
329 | if (pid == 0) { | |
330 | close(0); | |
331 | dup(pv[0]); | |
332 | close(pv[0]); | |
333 | close(pv[1]); | |
334 | execv(pr+4, prargs); | |
eaeea298 | 335 | execv(pr, prargs); |
c1df85d7 BJ |
336 | perror(pr); |
337 | done(); | |
338 | } | |
339 | } | |
340 | pid = fork(); | |
341 | if (pid == -1) { | |
342 | fprintf(stderr, "diff: No more processes\n"); | |
343 | done(); | |
344 | } | |
345 | if (pid == 0) { | |
346 | if (wantpr) { | |
347 | close(1); | |
348 | dup(pv[1]); | |
349 | close(pv[0]); | |
350 | close(pv[1]); | |
351 | } | |
352 | execv(diff+4, diffargv); | |
353 | execv(diff, diffargv); | |
354 | perror(diff); | |
355 | done(); | |
356 | } | |
390caa6e RC |
357 | if (wantpr) { |
358 | close(pv[0]); | |
359 | close(pv[1]); | |
360 | } | |
c1df85d7 BJ |
361 | while (wait(&status) != pid) |
362 | continue; | |
363 | while (wait(&status2) != -1) | |
364 | continue; | |
365 | /* | |
366 | if ((status >> 8) >= 2) | |
367 | done(); | |
368 | */ | |
369 | } | |
370 | ||
f01de581 BJ |
371 | #include <a.out.h> |
372 | ||
c1df85d7 BJ |
373 | ascii(f) |
374 | int f; | |
375 | { | |
376 | char buf[BUFSIZ]; | |
377 | register int cnt; | |
378 | register char *cp; | |
379 | ||
380 | lseek(f, (long)0, 0); | |
381 | cnt = read(f, buf, BUFSIZ); | |
f01de581 BJ |
382 | if (cnt >= sizeof (struct exec)) { |
383 | struct exec hdr; | |
384 | hdr = *(struct exec *)buf; | |
385 | if (!N_BADMAG(hdr)) | |
386 | return (0); | |
387 | } | |
c1df85d7 BJ |
388 | cp = buf; |
389 | while (--cnt >= 0) | |
390 | if (*cp++ & 0200) | |
391 | return (0); | |
392 | return (1); | |
393 | } | |
394 | ||
395 | /* | |
396 | * THIS IS CRUDE. | |
397 | */ | |
398 | useless(cp) | |
399 | register char *cp; | |
400 | { | |
401 | ||
22742b62 RC |
402 | if (cp[0] == '.') { |
403 | if (cp[1] == '\0') | |
404 | return (1); /* directory "." */ | |
405 | if (cp[1] == '.' && cp[2] == '\0') | |
406 | return (1); /* directory ".." */ | |
407 | } | |
c1df85d7 BJ |
408 | if (start && strcmp(start, cp) > 0) |
409 | return (1); | |
410 | return (0); | |
411 | } |