xref: /plan9/sys/src/cmd/diff/main.c (revision 56e2d73c64e38b03a72b5fdcfb50b0a26425b0f0)
13e12c5d1SDavid du Colombier #include <u.h>
23e12c5d1SDavid du Colombier #include <libc.h>
33e12c5d1SDavid du Colombier #include <bio.h>
43e12c5d1SDavid du Colombier #include "diff.h"
53e12c5d1SDavid du Colombier 
69a747e4fSDavid du Colombier #define	DIRECTORY(s)		((s)->qid.type&QTDIR)
79a747e4fSDavid du Colombier #define	REGULAR_FILE(s)		((s)->type == 'M' && !DIRECTORY(s))
83e12c5d1SDavid du Colombier 
93e12c5d1SDavid du Colombier Biobuf	stdout;
103e12c5d1SDavid du Colombier 
11756ec291SDavid du Colombier static char *tmp[] = {"/tmp/diff1XXXXXXXXXXX", "/tmp/diff2XXXXXXXXXXX"};
123e12c5d1SDavid du Colombier static int whichtmp;
133e12c5d1SDavid du Colombier static char *progname;
14754a2748SDavid du Colombier static char usage[] = "diff [-abcefmnrw] file1 ... file2\n";
153e12c5d1SDavid du Colombier 
163e12c5d1SDavid du Colombier static void
rmtmpfiles(void)173e12c5d1SDavid du Colombier rmtmpfiles(void)
183e12c5d1SDavid du Colombier {
193e12c5d1SDavid du Colombier 	while (whichtmp > 0) {
203e12c5d1SDavid du Colombier 		whichtmp--;
213e12c5d1SDavid du Colombier 		remove(tmp[whichtmp]);
223e12c5d1SDavid du Colombier 	}
233e12c5d1SDavid du Colombier }
243e12c5d1SDavid du Colombier 
253e12c5d1SDavid du Colombier void
done(int status)263e12c5d1SDavid du Colombier done(int status)
273e12c5d1SDavid du Colombier {
283e12c5d1SDavid du Colombier 	rmtmpfiles();
293e12c5d1SDavid du Colombier 	switch(status)
303e12c5d1SDavid du Colombier 	{
313e12c5d1SDavid du Colombier 	case 0:
323e12c5d1SDavid du Colombier 		exits("");
333e12c5d1SDavid du Colombier 	case 1:
343e12c5d1SDavid du Colombier 		exits("some");
353e12c5d1SDavid du Colombier 	default:
363e12c5d1SDavid du Colombier 		exits("error");
373e12c5d1SDavid du Colombier 	}
383e12c5d1SDavid du Colombier 	/*NOTREACHED*/
393e12c5d1SDavid du Colombier }
403e12c5d1SDavid du Colombier 
413e12c5d1SDavid du Colombier void
panic(int status,char * fmt,...)427dd7cddfSDavid du Colombier panic(int status, char *fmt, ...)
433e12c5d1SDavid du Colombier {
447dd7cddfSDavid du Colombier 	va_list arg;
453e12c5d1SDavid du Colombier 
463e12c5d1SDavid du Colombier 	Bflush(&stdout);
477dd7cddfSDavid du Colombier 
489a747e4fSDavid du Colombier 	fprint(2, "%s: ", progname);
497dd7cddfSDavid du Colombier 	va_start(arg, fmt);
509a747e4fSDavid du Colombier 	vfprint(2, fmt, arg);
517dd7cddfSDavid du Colombier 	va_end(arg);
523e12c5d1SDavid du Colombier 	if (status)
533e12c5d1SDavid du Colombier 		done(status);
543e12c5d1SDavid du Colombier 		/*NOTREACHED*/
553e12c5d1SDavid du Colombier }
563e12c5d1SDavid du Colombier 
573e12c5d1SDavid du Colombier static int
catch(void * a,char * msg)583e12c5d1SDavid du Colombier catch(void *a, char *msg)
593e12c5d1SDavid du Colombier {
603e12c5d1SDavid du Colombier 	USED(a);
613e12c5d1SDavid du Colombier 	panic(2, msg);
623e12c5d1SDavid du Colombier 	return 1;
633e12c5d1SDavid du Colombier }
643e12c5d1SDavid du Colombier 
653e12c5d1SDavid du Colombier int
mkpathname(char * pathname,char * path,char * name)663e12c5d1SDavid du Colombier mkpathname(char *pathname, char *path, char *name)
673e12c5d1SDavid du Colombier {
683e12c5d1SDavid du Colombier 	if (strlen(path) + strlen(name) > MAXPATHLEN) {
693e12c5d1SDavid du Colombier 		panic(0, "pathname %s/%s too long\n", path, name);
703e12c5d1SDavid du Colombier 		return 1;
713e12c5d1SDavid du Colombier 	}
723e12c5d1SDavid du Colombier 	sprint(pathname, "%s/%s", path, name);
733e12c5d1SDavid du Colombier 	return 0;
743e12c5d1SDavid du Colombier }
753e12c5d1SDavid du Colombier 
763e12c5d1SDavid du Colombier static char *
mktmpfile(int input,Dir ** sb)779a747e4fSDavid du Colombier mktmpfile(int input, Dir **sb)
783e12c5d1SDavid du Colombier {
793e12c5d1SDavid du Colombier 	int fd, i;
803e12c5d1SDavid du Colombier 	char *p;
813e12c5d1SDavid du Colombier 	char buf[8192];
823e12c5d1SDavid du Colombier 
833e12c5d1SDavid du Colombier 	atnotify(catch, 1);
84756ec291SDavid du Colombier 	p = mktemp(tmp[whichtmp++]);
853e12c5d1SDavid du Colombier 	fd = create(p, OWRITE, 0600);
863e12c5d1SDavid du Colombier 	if (fd < 0) {
87bd389b36SDavid du Colombier 		panic(mflag ? 0: 2, "cannot create %s: %r\n", p);
883e12c5d1SDavid du Colombier 		return 0;
893e12c5d1SDavid du Colombier 	}
903e12c5d1SDavid du Colombier 	while ((i = read(input, buf, sizeof(buf))) > 0) {
913e12c5d1SDavid du Colombier 		if ((i = write(fd, buf, i)) < 0)
923e12c5d1SDavid du Colombier 			break;
933e12c5d1SDavid du Colombier 	}
949a747e4fSDavid du Colombier 	*sb = dirfstat(fd);
953e12c5d1SDavid du Colombier 	close(fd);
963e12c5d1SDavid du Colombier 	if (i < 0) {
97bd389b36SDavid du Colombier 		panic(mflag ? 0: 2, "cannot read/write %s: %r\n", p);
983e12c5d1SDavid du Colombier 		return 0;
993e12c5d1SDavid du Colombier 	}
1003e12c5d1SDavid du Colombier 	return p;
1013e12c5d1SDavid du Colombier }
1023e12c5d1SDavid du Colombier 
1033e12c5d1SDavid du Colombier static char *
statfile(char * file,Dir ** sb)1049a747e4fSDavid du Colombier statfile(char *file, Dir **sb)
1053e12c5d1SDavid du Colombier {
1069a747e4fSDavid du Colombier 	Dir *dir;
1073e12c5d1SDavid du Colombier 	int input;
1083e12c5d1SDavid du Colombier 
1099a747e4fSDavid du Colombier 	dir = dirstat(file);
1109a747e4fSDavid du Colombier 	if(dir == nil) {
1119a747e4fSDavid du Colombier 		if (strcmp(file, "-") || (dir = dirfstat(0)) == nil) {
112bd389b36SDavid du Colombier 			panic(mflag ? 0: 2, "cannot stat %s: %r\n", file);
1133e12c5d1SDavid du Colombier 			return 0;
1143e12c5d1SDavid du Colombier 		}
1159a747e4fSDavid du Colombier 		free(dir);
1169a747e4fSDavid du Colombier 		return mktmpfile(0, sb);
1173e12c5d1SDavid du Colombier 	}
1189a747e4fSDavid du Colombier 	else if (!REGULAR_FILE(dir) && !DIRECTORY(dir)) {
1199a747e4fSDavid du Colombier 		free(dir);
1203e12c5d1SDavid du Colombier 		if ((input = open(file, OREAD)) == -1) {
121bd389b36SDavid du Colombier 			panic(mflag ? 0: 2, "cannot open %s: %r\n", file);
1223e12c5d1SDavid du Colombier 			return 0;
1233e12c5d1SDavid du Colombier 		}
1243e12c5d1SDavid du Colombier 		file = mktmpfile(input, sb);
1253e12c5d1SDavid du Colombier 		close(input);
1263e12c5d1SDavid du Colombier 	}
1279a747e4fSDavid du Colombier 	else
1289a747e4fSDavid du Colombier 		*sb = dir;
1293e12c5d1SDavid du Colombier 	return file;
1303e12c5d1SDavid du Colombier }
1313e12c5d1SDavid du Colombier 
1323e12c5d1SDavid du Colombier void
diff(char * f,char * t,int level)1333e12c5d1SDavid du Colombier diff(char *f, char *t, int level)
1343e12c5d1SDavid du Colombier {
1353e12c5d1SDavid du Colombier 	char *fp, *tp, *p, fb[MAXPATHLEN+1], tb[MAXPATHLEN+1];
1369a747e4fSDavid du Colombier 	Dir *fsb, *tsb;
1373e12c5d1SDavid du Colombier 
1383e12c5d1SDavid du Colombier 	if ((fp = statfile(f, &fsb)) == 0)
13915174232SDavid du Colombier 		goto Return;
1409a747e4fSDavid du Colombier 	if ((tp = statfile(t, &tsb)) == 0){
1419a747e4fSDavid du Colombier 		free(fsb);
14215174232SDavid du Colombier 		goto Return;
1439a747e4fSDavid du Colombier 	}
1443e12c5d1SDavid du Colombier 	if (DIRECTORY(fsb) && DIRECTORY(tsb)) {
1453e12c5d1SDavid du Colombier 		if (rflag || level == 0)
1463e12c5d1SDavid du Colombier 			diffdir(fp, tp, level);
1473e12c5d1SDavid du Colombier 		else
1483e12c5d1SDavid du Colombier 			Bprint(&stdout, "Common subdirectories: %s and %s\n",
1493e12c5d1SDavid du Colombier 				fp, tp);
1503e12c5d1SDavid du Colombier 	}
1513e12c5d1SDavid du Colombier 	else if (REGULAR_FILE(fsb) && REGULAR_FILE(tsb))
1523e12c5d1SDavid du Colombier 		diffreg(fp, tp);
1533e12c5d1SDavid du Colombier 	else {
1543e12c5d1SDavid du Colombier 		if (REGULAR_FILE(fsb)) {
1553e12c5d1SDavid du Colombier 			if ((p = utfrrune(f, '/')) == 0)
1563e12c5d1SDavid du Colombier 				p = f;
1573e12c5d1SDavid du Colombier 			else
1583e12c5d1SDavid du Colombier 				p++;
1599a747e4fSDavid du Colombier 			if (mkpathname(tb, tp, p) == 0)
1603e12c5d1SDavid du Colombier 				diffreg(fp, tb);
1613e12c5d1SDavid du Colombier 		}
1623e12c5d1SDavid du Colombier 		else {
1633e12c5d1SDavid du Colombier 			if ((p = utfrrune(t, '/')) == 0)
1643e12c5d1SDavid du Colombier 				p = t;
1653e12c5d1SDavid du Colombier 			else
1663e12c5d1SDavid du Colombier 				p++;
1679a747e4fSDavid du Colombier 			if (mkpathname(fb, fp, p) == 0)
1683e12c5d1SDavid du Colombier 				diffreg(fb, tp);
1693e12c5d1SDavid du Colombier 		}
1703e12c5d1SDavid du Colombier 	}
1719a747e4fSDavid du Colombier 	free(fsb);
1729a747e4fSDavid du Colombier 	free(tsb);
17315174232SDavid du Colombier Return:
17415174232SDavid du Colombier 	rmtmpfiles();
1753e12c5d1SDavid du Colombier }
1763e12c5d1SDavid du Colombier 
1773e12c5d1SDavid du Colombier void
main(int argc,char * argv[])1783e12c5d1SDavid du Colombier main(int argc, char *argv[])
1793e12c5d1SDavid du Colombier {
1803e12c5d1SDavid du Colombier 	char *p;
1813e12c5d1SDavid du Colombier 	int i;
1829a747e4fSDavid du Colombier 	Dir *fsb, *tsb;
1833e12c5d1SDavid du Colombier 
1843e12c5d1SDavid du Colombier 	Binit(&stdout, 1, OWRITE);
185*56e2d73cSDavid du Colombier 	progname = argv0 = *argv;
1863e12c5d1SDavid du Colombier 	while (--argc && (*++argv)[0] == '-' && (*argv)[1]) {
1873e12c5d1SDavid du Colombier 		for (p = *argv+1; *p; p++) {
1883e12c5d1SDavid du Colombier 			switch (*p) {
1893e12c5d1SDavid du Colombier 
1903e12c5d1SDavid du Colombier 			case 'e':
1913e12c5d1SDavid du Colombier 			case 'f':
1927dd7cddfSDavid du Colombier 			case 'n':
193a7534c1eSDavid du Colombier 			case 'c':
19427e10919SDavid du Colombier 			case 'a':
1953e12c5d1SDavid du Colombier 				mode = *p;
1963e12c5d1SDavid du Colombier 				break;
1973e12c5d1SDavid du Colombier 
1983e12c5d1SDavid du Colombier 			case 'w':
1993e12c5d1SDavid du Colombier 				bflag = 2;
2003e12c5d1SDavid du Colombier 				break;
2013e12c5d1SDavid du Colombier 
2023e12c5d1SDavid du Colombier 			case 'b':
2033e12c5d1SDavid du Colombier 				bflag = 1;
2043e12c5d1SDavid du Colombier 				break;
2053e12c5d1SDavid du Colombier 
2063e12c5d1SDavid du Colombier 			case 'r':
2073e12c5d1SDavid du Colombier 				rflag = 1;
2083e12c5d1SDavid du Colombier 				break;
2093e12c5d1SDavid du Colombier 
2107dd7cddfSDavid du Colombier 			case 'm':
2117dd7cddfSDavid du Colombier 				mflag = 1;
2127dd7cddfSDavid du Colombier 				break;
2137dd7cddfSDavid du Colombier 
2143e12c5d1SDavid du Colombier 			case 'h':
2153e12c5d1SDavid du Colombier 			default:
2163e12c5d1SDavid du Colombier 				progname = "Usage";
2173e12c5d1SDavid du Colombier 				panic(2, usage);
2183e12c5d1SDavid du Colombier 			}
2193e12c5d1SDavid du Colombier 		}
2203e12c5d1SDavid du Colombier 	}
2213e12c5d1SDavid du Colombier 	if (argc < 2)
2223e12c5d1SDavid du Colombier 		panic(2, usage, progname);
2239a747e4fSDavid du Colombier 	if ((tsb = dirstat(argv[argc-1])) == nil)
2243e12c5d1SDavid du Colombier 		panic(2, "can't stat %s\n", argv[argc-1]);
2253e12c5d1SDavid du Colombier 	if (argc > 2) {
2263e12c5d1SDavid du Colombier 		if (!DIRECTORY(tsb))
2273e12c5d1SDavid du Colombier 			panic(2, usage, progname);
2283e12c5d1SDavid du Colombier 		mflag = 1;
2293e12c5d1SDavid du Colombier 	}
2303e12c5d1SDavid du Colombier 	else {
2319a747e4fSDavid du Colombier 		if ((fsb = dirstat(argv[0])) == nil)
2323e12c5d1SDavid du Colombier 			panic(2, "can't stat %s\n", argv[0]);
2333e12c5d1SDavid du Colombier 		if (DIRECTORY(fsb) && DIRECTORY(tsb))
2343e12c5d1SDavid du Colombier 			mflag = 1;
2359a747e4fSDavid du Colombier 		free(fsb);
2363e12c5d1SDavid du Colombier 	}
2379a747e4fSDavid du Colombier 	free(tsb);
23815174232SDavid du Colombier 	for (i = 0; i < argc-1; i++)
2393e12c5d1SDavid du Colombier 		diff(argv[i], argv[argc-1], 0);
2403e12c5d1SDavid du Colombier 	done(anychange);
2413e12c5d1SDavid du Colombier 	/*NOTREACHED*/
2423e12c5d1SDavid du Colombier }
2433e12c5d1SDavid du Colombier 
2443e12c5d1SDavid du Colombier static char noroom[] = "out of memory - try diff -h\n";
2453e12c5d1SDavid du Colombier 
2463e12c5d1SDavid du Colombier void *
emalloc(unsigned n)2473e12c5d1SDavid du Colombier emalloc(unsigned n)
2483e12c5d1SDavid du Colombier {
2493e12c5d1SDavid du Colombier 	register void *p;
2503e12c5d1SDavid du Colombier 
2513e12c5d1SDavid du Colombier 	if ((p = malloc(n)) == 0)
2523e12c5d1SDavid du Colombier 		panic(2, noroom);
2533e12c5d1SDavid du Colombier 	return p;
2543e12c5d1SDavid du Colombier }
2553e12c5d1SDavid du Colombier 
2563e12c5d1SDavid du Colombier void *
erealloc(void * p,unsigned n)2573e12c5d1SDavid du Colombier erealloc(void *p, unsigned n)
2583e12c5d1SDavid du Colombier {
2593e12c5d1SDavid du Colombier 	register void *rp;
2603e12c5d1SDavid du Colombier 
2613e12c5d1SDavid du Colombier 	if ((rp = realloc(p, n)) == 0)
2623e12c5d1SDavid du Colombier 		panic(2, noroom);
2633e12c5d1SDavid du Colombier 	return rp;
2643e12c5d1SDavid du Colombier }
265