BSD 2 development
[unix-history] / src / diffdir.c
CommitLineData
783c5c09
BJ
1/* Copyright (c) 1979 Regents of the University of California */
2#include <retrofit.h>
3#include <stdio.h>
4
5/*
6 * Diffdir - a (first) directory difference program
7 * Bill Joy UCB March 16, 1978
8 *
9 * This is a difference program which operates on the entire contents of
10 * a directory. It reports common files which are different, running
11 * diff if the files are ASCII files. It also reports files which are
12 * unique to one of the two directories.
13 *
14 * An option "h" (for header) causes diffdir to print each difference
15 * on a new page (using an appropriate "pr") and to summarize missing
16 * files and differences in binary files on a final page.
17 *
18 * Option "s" causes files which are the same to be reported also.
19 *
20 * It would be nice if this were "difftree", and if it knew a few
21 * more things, e.g to "size" objects which are different or some
22 * such or at least to not say that "directories are different" calling
23 * them files, i.e. "Files ex-1.1/temp and ex-1.2/temp are different".
24 */
25
26typedef char bool;
27
28struct entry {
29 char *name;
30 int flags;
31} *dir1, *dir2;
32
33#define ONLY 1
34#define DIFFER 2
35
36bool hflg;
37bool vflg;
38bool sflg;
39
40#define vprintf if (vflg) printf
41
42main(argc, argv)
43 int argc;
44 char *argv[];
45{
46 register struct entry *d1, *d2;
47 register char *cp;
48
49 while (argc > 1) {
50 cp = argv[1];
51 if (*cp++ != '-')
52 break;
53 while (*cp) switch (*cp++) {
54
55 case 'h':
56 hflg++;
57 continue;
58
59 case 'v':
60 vflg++;
61 continue;
62
63 case 's':
64 sflg++;
65 continue;
66
67 default:
68usage:
69 panic("Usage: diffdir [ -h ] dir1 dir2");
70 }
71 argc--, argv++;
72 }
73 if (argc != 3)
74 goto usage;
75 setupdir(argv[1], &dir1);
76 setupdir(argv[2], &dir2);
77 d1 = dir1; d2 = dir2;
78 while (d1->name != 0 || d2->name != 0) {
79 if (useless(d1->name)) {
80 d1++;
81 continue;
82 }
83 if (useless(d2->name)) {
84 d2++;
85 continue;
86 }
87 if (d1->name != 0 && d2->name != 0)
88 switch (sgn(strcmp(d1->name, d2->name))) {
89
90 case -1:
91onlyin1:
92 if (hflg)
93 d1->flags =| ONLY;
94 else
95 printf("Only in %s: %s\n", argv[1], d1->name);
96 d1++;
97 continue;
98
99 case 0:
100 vprintf("In both: %s\n", d1->name);
101 compare(d1, argv[1], argv[2]);
102 d1++;
103 d2++;
104 continue;
105
106 case 1:
107onlyin2: if (hflg)
108 d2->flags =| ONLY;
109 else
110 printf("Only in %s: %s\n", argv[2], d2->name);
111 d2++;
112 continue;
113 }
114 if (d1->name != 0)
115 goto onlyin1;
116 else
117 goto onlyin2;
118 }
119 if (hflg) {
120 int header = 0;
121
122 for (d1 = dir1; d1->name; d1++)
123 if (d1->flags & ONLY) {
124 if (header == 0) {
125 printf("\fOnly in %s\n", argv[1]);
126 header = 1;
127 }
128 printf("\t%s\n", d1->name);
129 }
130 for (d2 = dir2; d2->name != 0; d2++) {
131 if (d2->flags & ONLY) {
132 if (header == 0)
133 printf("\f");
134 if ((header & 2) == 0) {
135 printf("Only in %s\n", argv[2]);
136 header =| 2;
137 }
138 printf("\t%s\n", d2->name);
139 }
140 }
141 for (d1 = dir1; d1->name; d1++)
142 if (d1->flags & DIFFER) {
143 if (header == 0) {
144 printf("\f");
145 header = 1;
146 }
147 if ((header & 4) == 0) {
148 printf("Non-ascii files which differ:\n");
149 header =| 4;
150 }
151 printf("\t%s\n", d1->name);
152 }
153 }
154 exit(0);
155}
156
157int entcmp();
158setupdir(cp, head)
159 char *cp;
160 struct entry **head;
161{
162 int count = 1;
163 struct dirent0 {
164 short ino;
165 char fname[14];
166 };
167
168 struct dirent1 {
169 short ino;
170 char fname1[16];
171 } dirent;
172 register struct entry *hp;
173
174 close(0);
175 if (open(cp, 0) < 0) {
176 perror(cp);
177 exit(1);
178 }
179 while (read(0, &dirent, sizeof (struct dirent0)) == sizeof (struct dirent0))
180 if (dirent.ino)
181 count++;
182 lseek(0, (long) 0, 0);
183 hp = *head = Calloc(count, sizeof **head);
184 while (read(0, &dirent, sizeof (struct dirent0)) == sizeof (struct dirent0))
185 if (dirent.ino) {
186 hp->name = savestr(dirent.fname);
187 hp++;
188 }
189 qsort(*head, count - 1, sizeof **head, entcmp);
190}
191
192entcmp(ep, ep2)
193 struct entry *ep, *ep2;
194{
195
196 return (strcmp(ep->name, ep2->name));
197}
198
199Calloc(i, n)
200 int i, n;
201{
202 register unsigned mem;
203
204 mem = calloc(i, n);
205 if (mem == 0)
206 panic("Ran out of memory");
207 return (mem);
208}
209
210savestr(cp)
211 register char *cp;
212{
213
214 return (strcpy(calloc(strlen(cp)+1, sizeof (char)), cp));
215}
216
217panic(cp)
218 char *cp;
219{
220
221 fprintf(stderr, "%s\n", cp);
222 exit(1);
223}
224
225sgn(i)
226 int i;
227{
228 if (i > 0)
229 return (1);
230 else if (i < 0)
231 return (-1);
232 return (0);
233}
234
235compare(dp, d1, d2)
236 struct entry *dp;
237 char *d1, *d2;
238{
239 register int i;
240 char path1[100], path2[100];
241 int t1, t2;
242 char header[250];
243 char *name = dp->name;
244
245 if (max(strlen(d1), strlen(d2)) + strlen(name) + 2 >= 100)
246 panic("Path names too long");
247 strcat(strcat(strcpy(path1, d1), "/"), name);
248 strcat(strcat(strcpy(path2, d2), "/"), name);
249 i = callit("/usr/bin/cmp", "cmp", "-s", path1, path2, 0);
250 if (i == 0) {
251 if (sflg)
252 printf("Files %s and %s same\n", path1, path2);
253 return;
254 }
255 if (!ascii(path1) || !ascii(path2)) {
256 if (hflg)
257 dp->flags =| DIFFER;
258 else
259 printf("Files %s and %s differ\n", path1, path2);
260 return;
261 }
262 if (hflg) {
263 sprintf(header, "diff %s %s", path1, path2);
264 prcallit(header, "/usr/bin/diff", "diff", path1, path2, 0);
265 } else {
266 printf("diff %s %s\n", path1, path2);
267 callit("/usr/bin/diff", "diff", path1, path2, 0);
268 }
269}
270
271prcallit(header, path, av)
272 char *header, *path;
273{
274 int status;
275 int pid;
276 int pv[2];
277
278 fflush(stdout);
279 pipe(pv);
280 pid = fork();
281 if (pid == -1)
282 panic("No more processes");
283 if (pid == 0) {
284 close(0);
285 dup(pv[0]);
286 close(pv[0]);
287 close(pv[1]);
288 execl("/bin/pr", "pr", "-h", header, 0);
289 execl("/usr/bin/pr", "pr", "-h", header, 0);
290 perror("/usr/bin/pr");
291 exit(1);
292 }
293 pid = fork();
294 if (pid == -1)
295 panic("No more processes");
296 if (pid == 0) {
297 close(1);
298 dup(pv[1]);
299 close(pv[0]);
300 close(pv[1]);
301 execv(path+4, &av);
302 execv(path, &av);
303 perror(path);
304 exit(1);
305 }
306 close(pv[0]);
307 close(pv[1]);
308 while (wait(&status) != -1)
309 continue;
310}
311
312callit(path, av)
313 char *path;
314{
315 int status;
316 int pid;
317
318 fflush(stdout);
319 pid = fork();
320 if (pid == -1)
321 panic("No more processes");
322 if (pid == 0) {
323 execv(path+4, &av);
324 execv(path, &av);
325 perror(path);
326 exit(1);
327 }
328 wait(&status);
329 return (((status >> 8) & 0377) | (status & 0377));
330}
331
332max(a,b)
333 int a,b;
334{
335
336 return (a > b ? a : b);
337}
338
339ascii(cp)
340 char *cp;
341{
342 int f;
343 short w;
344
345 f = open(cp, 0);
346 if (f < 0)
347 return (0);
348 if (read(f, &w, sizeof w) != sizeof w) {
349 close(f);
350 return (1);
351 }
352 close(f);
353 switch (w) {
354
355 case 0405: /* Overlay executable */
356 case 0407: /* Executable */
357 case 0410: /* Pure executable */
358 case 0411: /* Separate executable */
359 case 0177545: /* Archive */
360 case 0177555: /* Old archive */
361 return (0);
362 default:
363 if (w & 0100200)
364 return (0);
365 return (1);
366 }
367}
368
369useless(cp)
370 char *cp;
371{
372
373 if (strcmp(cp, ".") == 0 || strcmp(cp, "..") == 0)
374 return (1);
375 if (cp[0] == '.')
376 return (1); /* For now */
377 return (0);
378}