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