xref: /plan9-contrib/sys/src/cmd/diff/main.c (revision 7dd7cddf99dd7472612f1413b4da293630e6b1bc)
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 
63e12c5d1SDavid du Colombier #define	DIRECTORY(s)		((s).qid.path&CHDIR)
73e12c5d1SDavid du Colombier #define	REGULAR_FILE(s)		((s).type == 'M' && !DIRECTORY(s))
83e12c5d1SDavid du Colombier 
93e12c5d1SDavid du Colombier Biobuf	stdout;
103e12c5d1SDavid du Colombier 
113e12c5d1SDavid du Colombier static char *tmp[] = {"/tmp/diff1", "/tmp/diff2"};
123e12c5d1SDavid du Colombier static int whichtmp;
133e12c5d1SDavid du Colombier static char *progname;
14*7dd7cddfSDavid du Colombier static char usage[] = "diff [ -efmnbwr ] file1 ... file2\n";
153e12c5d1SDavid du Colombier 
163e12c5d1SDavid du Colombier static 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
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
42*7dd7cddfSDavid du Colombier panic(int status, char *fmt, ...)
433e12c5d1SDavid du Colombier {
44*7dd7cddfSDavid du Colombier 	va_list arg;
453e12c5d1SDavid du Colombier 	char buf[1024], *out;
463e12c5d1SDavid du Colombier 
473e12c5d1SDavid du Colombier 	Bflush(&stdout);
48*7dd7cddfSDavid du Colombier 
49*7dd7cddfSDavid du Colombier 	out = buf+snprint(buf, sizeof(buf), "%s: ", progname);
50*7dd7cddfSDavid du Colombier 	va_start(arg, fmt);
51*7dd7cddfSDavid du Colombier 	out = doprint(out, buf+sizeof(buf), fmt, arg);
52*7dd7cddfSDavid du Colombier 	va_end(arg);
533e12c5d1SDavid du Colombier 	write(2, buf, out-buf);
543e12c5d1SDavid du Colombier 	if (status)
553e12c5d1SDavid du Colombier 		done(status);
563e12c5d1SDavid du Colombier 		/*NOTREACHED*/
573e12c5d1SDavid du Colombier }
583e12c5d1SDavid du Colombier 
593e12c5d1SDavid du Colombier static int
603e12c5d1SDavid du Colombier catch(void *a, char *msg)
613e12c5d1SDavid du Colombier {
623e12c5d1SDavid du Colombier 	USED(a);
633e12c5d1SDavid du Colombier 	panic(2, msg);
643e12c5d1SDavid du Colombier 	return 1;
653e12c5d1SDavid du Colombier }
663e12c5d1SDavid du Colombier 
673e12c5d1SDavid du Colombier int
683e12c5d1SDavid du Colombier mkpathname(char *pathname, char *path, char *name)
693e12c5d1SDavid du Colombier {
703e12c5d1SDavid du Colombier 	if (strlen(path) + strlen(name) > MAXPATHLEN) {
713e12c5d1SDavid du Colombier 		panic(0, "pathname %s/%s too long\n", path, name);
723e12c5d1SDavid du Colombier 		return 1;
733e12c5d1SDavid du Colombier 	}
743e12c5d1SDavid du Colombier 	sprint(pathname, "%s/%s", path, name);
753e12c5d1SDavid du Colombier 	return 0;
763e12c5d1SDavid du Colombier }
773e12c5d1SDavid du Colombier 
783e12c5d1SDavid du Colombier static char *
793e12c5d1SDavid du Colombier mktmpfile(int input, Dir *sb)
803e12c5d1SDavid du Colombier {
813e12c5d1SDavid du Colombier 	int fd, i;
823e12c5d1SDavid du Colombier 	char *p;
833e12c5d1SDavid du Colombier 	char buf[8192];
843e12c5d1SDavid du Colombier 
853e12c5d1SDavid du Colombier 	atnotify(catch, 1);
863e12c5d1SDavid du Colombier 	p = tmp[whichtmp++];
873e12c5d1SDavid du Colombier 	fd = create(p, OWRITE, 0600);
883e12c5d1SDavid du Colombier 	if (fd < 0) {
89bd389b36SDavid du Colombier 		panic(mflag ? 0: 2, "cannot create %s: %r\n", p);
903e12c5d1SDavid du Colombier 		return 0;
913e12c5d1SDavid du Colombier 	}
923e12c5d1SDavid du Colombier 	while ((i = read(input, buf, sizeof(buf))) > 0) {
933e12c5d1SDavid du Colombier 		if ((i = write(fd, buf, i)) < 0)
943e12c5d1SDavid du Colombier 			break;
953e12c5d1SDavid du Colombier 	}
963e12c5d1SDavid du Colombier 	dirfstat(fd, sb);
973e12c5d1SDavid du Colombier 	close(fd);
983e12c5d1SDavid du Colombier 	if (i < 0) {
99bd389b36SDavid du Colombier 		panic(mflag ? 0: 2, "cannot read/write %s: %r\n", p);
1003e12c5d1SDavid du Colombier 		return 0;
1013e12c5d1SDavid du Colombier 	}
1023e12c5d1SDavid du Colombier 	return p;
1033e12c5d1SDavid du Colombier }
1043e12c5d1SDavid du Colombier 
1053e12c5d1SDavid du Colombier static char *
1063e12c5d1SDavid du Colombier statfile(char *file, Dir *sb)
1073e12c5d1SDavid du Colombier {
1083e12c5d1SDavid du Colombier 	int input;
1093e12c5d1SDavid du Colombier 
1103e12c5d1SDavid du Colombier 	if (dirstat(file, sb) == -1) {
1113e12c5d1SDavid du Colombier 		if (strcmp(file, "-") || dirfstat(0, sb) == -1) {
112bd389b36SDavid du Colombier 			panic(mflag ? 0: 2, "cannot stat %s: %r\n", file);
1133e12c5d1SDavid du Colombier 			return 0;
1143e12c5d1SDavid du Colombier 		}
1153e12c5d1SDavid du Colombier 		file = mktmpfile(0, sb);
1163e12c5d1SDavid du Colombier 	}
1173e12c5d1SDavid du Colombier 	else if (!REGULAR_FILE(*sb) && !DIRECTORY(*sb)) {
1183e12c5d1SDavid du Colombier 		if ((input = open(file, OREAD)) == -1) {
119bd389b36SDavid du Colombier 			panic(mflag ? 0: 2, "cannot open %s: %r\n", file);
1203e12c5d1SDavid du Colombier 			return 0;
1213e12c5d1SDavid du Colombier 		}
1223e12c5d1SDavid du Colombier 		file = mktmpfile(input, sb);
1233e12c5d1SDavid du Colombier 		close(input);
1243e12c5d1SDavid du Colombier 	}
1253e12c5d1SDavid du Colombier 	return file;
1263e12c5d1SDavid du Colombier }
1273e12c5d1SDavid du Colombier 
1283e12c5d1SDavid du Colombier void
1293e12c5d1SDavid du Colombier diff(char *f, char *t, int level)
1303e12c5d1SDavid du Colombier {
1313e12c5d1SDavid du Colombier 	char *fp, *tp, *p, fb[MAXPATHLEN+1], tb[MAXPATHLEN+1];
1323e12c5d1SDavid du Colombier 	Dir fsb, tsb;
1333e12c5d1SDavid du Colombier 
1343e12c5d1SDavid du Colombier 	if ((fp = statfile(f, &fsb)) == 0)
1353e12c5d1SDavid du Colombier 		return;
1363e12c5d1SDavid du Colombier 	if ((tp = statfile(t, &tsb)) == 0)
1373e12c5d1SDavid du Colombier 		return;
1383e12c5d1SDavid du Colombier 	if (DIRECTORY(fsb) && DIRECTORY(tsb)) {
1393e12c5d1SDavid du Colombier 		if (rflag || level == 0)
1403e12c5d1SDavid du Colombier 			diffdir(fp, tp, level);
1413e12c5d1SDavid du Colombier 		else
1423e12c5d1SDavid du Colombier 			Bprint(&stdout, "Common subdirectories: %s and %s\n",
1433e12c5d1SDavid du Colombier 				fp, tp);
1443e12c5d1SDavid du Colombier 	}
1453e12c5d1SDavid du Colombier 	else if (REGULAR_FILE(fsb) && REGULAR_FILE(tsb))
1463e12c5d1SDavid du Colombier 		diffreg(fp, tp);
1473e12c5d1SDavid du Colombier 	else {
1483e12c5d1SDavid du Colombier 		if (REGULAR_FILE(fsb)) {
1493e12c5d1SDavid du Colombier 			if ((p = utfrrune(f, '/')) == 0)
1503e12c5d1SDavid du Colombier 				p = f;
1513e12c5d1SDavid du Colombier 			else
1523e12c5d1SDavid du Colombier 				p++;
1533e12c5d1SDavid du Colombier 			if (mkpathname(tb, tp, p))
1543e12c5d1SDavid du Colombier 				return;
1553e12c5d1SDavid du Colombier 			diffreg(fp, tb);
1563e12c5d1SDavid du Colombier 		}
1573e12c5d1SDavid du Colombier 		else {
1583e12c5d1SDavid du Colombier 			if ((p = utfrrune(t, '/')) == 0)
1593e12c5d1SDavid du Colombier 				p = t;
1603e12c5d1SDavid du Colombier 			else
1613e12c5d1SDavid du Colombier 				p++;
1623e12c5d1SDavid du Colombier 			if (mkpathname(fb, fp, p))
1633e12c5d1SDavid du Colombier 				return;
1643e12c5d1SDavid du Colombier 			diffreg(fb, tp);
1653e12c5d1SDavid du Colombier 		}
1663e12c5d1SDavid du Colombier 	}
1673e12c5d1SDavid du Colombier }
1683e12c5d1SDavid du Colombier 
1693e12c5d1SDavid du Colombier void
1703e12c5d1SDavid du Colombier main(int argc, char *argv[])
1713e12c5d1SDavid du Colombier {
1723e12c5d1SDavid du Colombier 	char *p;
1733e12c5d1SDavid du Colombier 	int i;
1743e12c5d1SDavid du Colombier 	Dir fsb, tsb;
1753e12c5d1SDavid du Colombier 
1763e12c5d1SDavid du Colombier 	Binit(&stdout, 1, OWRITE);
1773e12c5d1SDavid du Colombier 	progname = *argv;
1783e12c5d1SDavid du Colombier 	while (--argc && (*++argv)[0] == '-' && (*argv)[1]) {
1793e12c5d1SDavid du Colombier 		for (p = *argv+1; *p; p++) {
1803e12c5d1SDavid du Colombier 			switch (*p) {
1813e12c5d1SDavid du Colombier 
1823e12c5d1SDavid du Colombier 			case 'e':
1833e12c5d1SDavid du Colombier 			case 'f':
184*7dd7cddfSDavid du Colombier 			case 'n':
1853e12c5d1SDavid du Colombier 				mode = *p;
1863e12c5d1SDavid du Colombier 				break;
1873e12c5d1SDavid du Colombier 
1883e12c5d1SDavid du Colombier 			case 'w':
1893e12c5d1SDavid du Colombier 				bflag = 2;
1903e12c5d1SDavid du Colombier 				break;
1913e12c5d1SDavid du Colombier 
1923e12c5d1SDavid du Colombier 			case 'b':
1933e12c5d1SDavid du Colombier 				bflag = 1;
1943e12c5d1SDavid du Colombier 				break;
1953e12c5d1SDavid du Colombier 
1963e12c5d1SDavid du Colombier 			case 'r':
1973e12c5d1SDavid du Colombier 				rflag = 1;
1983e12c5d1SDavid du Colombier 				break;
1993e12c5d1SDavid du Colombier 
200*7dd7cddfSDavid du Colombier 			case 'm':
201*7dd7cddfSDavid du Colombier 				mflag = 1;
202*7dd7cddfSDavid du Colombier 				break;
203*7dd7cddfSDavid du Colombier 
2043e12c5d1SDavid du Colombier 			case 'h':
2053e12c5d1SDavid du Colombier 			default:
2063e12c5d1SDavid du Colombier 				progname = "Usage";
2073e12c5d1SDavid du Colombier 				panic(2, usage);
2083e12c5d1SDavid du Colombier 			}
2093e12c5d1SDavid du Colombier 		}
2103e12c5d1SDavid du Colombier 	}
2113e12c5d1SDavid du Colombier 	if (argc < 2)
2123e12c5d1SDavid du Colombier 		panic(2, usage, progname);
2133e12c5d1SDavid du Colombier 	if (dirstat(argv[argc-1], &tsb) == -1)
2143e12c5d1SDavid du Colombier 		panic(2, "can't stat %s\n", argv[argc-1]);
2153e12c5d1SDavid du Colombier 	if (argc > 2) {
2163e12c5d1SDavid du Colombier 		if (!DIRECTORY(tsb))
2173e12c5d1SDavid du Colombier 			panic(2, usage, progname);
2183e12c5d1SDavid du Colombier 		mflag = 1;
2193e12c5d1SDavid du Colombier 	}
2203e12c5d1SDavid du Colombier 	else {
2213e12c5d1SDavid du Colombier 		if (dirstat(argv[0], &fsb) == -1)
2223e12c5d1SDavid du Colombier 			panic(2, "can't stat %s\n", argv[0]);
2233e12c5d1SDavid du Colombier 		if (DIRECTORY(fsb) && DIRECTORY(tsb))
2243e12c5d1SDavid du Colombier 			mflag = 1;
2253e12c5d1SDavid du Colombier 	}
2263e12c5d1SDavid du Colombier 	for (i = 0; i < argc-1; i++) {
2273e12c5d1SDavid du Colombier 		diff(argv[i], argv[argc-1], 0);
2283e12c5d1SDavid du Colombier 		rmtmpfiles();
2293e12c5d1SDavid du Colombier 	}
2303e12c5d1SDavid du Colombier 	done(anychange);
2313e12c5d1SDavid du Colombier 	/*NOTREACHED*/
2323e12c5d1SDavid du Colombier }
2333e12c5d1SDavid du Colombier 
2343e12c5d1SDavid du Colombier static char noroom[] = "out of memory - try diff -h\n";
2353e12c5d1SDavid du Colombier 
2363e12c5d1SDavid du Colombier void *
2373e12c5d1SDavid du Colombier emalloc(unsigned n)
2383e12c5d1SDavid du Colombier {
2393e12c5d1SDavid du Colombier 	register void *p;
2403e12c5d1SDavid du Colombier 
2413e12c5d1SDavid du Colombier 	if ((p = malloc(n)) == 0)
2423e12c5d1SDavid du Colombier 		panic(2, noroom);
2433e12c5d1SDavid du Colombier 	return p;
2443e12c5d1SDavid du Colombier }
2453e12c5d1SDavid du Colombier 
2463e12c5d1SDavid du Colombier void *
2473e12c5d1SDavid du Colombier erealloc(void *p, unsigned n)
2483e12c5d1SDavid du Colombier {
2493e12c5d1SDavid du Colombier 	register void *rp;
2503e12c5d1SDavid du Colombier 
2513e12c5d1SDavid du Colombier 	if ((rp = realloc(p, n)) == 0)
2523e12c5d1SDavid du Colombier 		panic(2, noroom);
2533e12c5d1SDavid du Colombier 	return rp;
2543e12c5d1SDavid du Colombier }
255