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