273 lines · 4.6 KB · C
RawDownload
/*  * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #include <u.h>#include <libc.h>#include <bio.h>#include "diff.h" #define	DIRECTORY(s)		((s)->qid.type&QTDIR)#define	REGULAR_FILE(s)		((s)->type == 'M' && !DIRECTORY(s)) Biobuf	stdout; static char *tmp[] = {"/tmp/diff1XXXXXXXXXXX", "/tmp/diff2XXXXXXXXXXX"};static int whichtmp;static char *progname;static char usage[] = "diff [-abcefmnrw] file1 ... file2\n"; static voidrmtmpfiles(void){	while (whichtmp > 0) {		whichtmp--;		remove(tmp[whichtmp]);	}} void	done(int status){	rmtmpfiles();	switch(status)	{	case 0:		exits("");	case 1:		exits("some");	default:		exits("error");	}	/*NOTREACHED*/} voidpanic(int status, char *fmt, ...){	va_list arg; 	Bflush(&stdout); 	fprint(2, "%s: ", progname);	va_start(arg, fmt);	vfprint(2, fmt, arg);	va_end(arg);	if (status)		done(status);		/*NOTREACHED*/} static intcatch(void *a, char *msg){	USED(a);	panic(2, msg);	return 1;} intmkpathname(char *pathname, char *path, char *name){	if (strlen(path) + strlen(name) > MAXPATHLEN) {		panic(0, "pathname %s/%s too long\n", path, name);		return 1;	}	sprint(pathname, "%s/%s", path, name);	return 0;}	static char *mktmpfile(int input, Dir **sb){	int fd, i;	char *p;	char buf[8192]; 	atnotify(catch, 1);	p = mktemp(tmp[whichtmp++]);	fd = create(p, OWRITE, 0600);	if (fd < 0) {		panic(mflag ? 0: 2, "cannot create %s: %r\n", p);		return 0;	}	while ((i = read(input, buf, sizeof(buf))) > 0) {		if ((i = write(fd, buf, i)) < 0)			break;	}	*sb = dirfstat(fd);	close(fd);	if (i < 0) {		panic(mflag ? 0: 2, "cannot read/write %s: %r\n", p);		return 0;	}	return p;} static char *statfile(char *file, Dir **sb){	Dir *dir;	int input; 	dir = dirstat(file);	if(dir == nil) {		if (strcmp(file, "-") || (dir = dirfstat(0)) == nil) {			panic(mflag ? 0: 2, "cannot stat %s: %r\n", file);			return 0;		}		free(dir);		return mktmpfile(0, sb);	}	else if (!REGULAR_FILE(dir) && !DIRECTORY(dir)) {		free(dir);		if ((input = open(file, OREAD)) == -1) {			panic(mflag ? 0: 2, "cannot open %s: %r\n", file);			return 0;		}		file = mktmpfile(input, sb);		close(input);	}	else		*sb = dir;	return file;} voiddiff(char *f, char *t, int level){	char *fp, *tp, *p, fb[MAXPATHLEN+1], tb[MAXPATHLEN+1];	Dir *fsb, *tsb; 	if ((fp = statfile(f, &fsb)) == 0)		goto Return;	if ((tp = statfile(t, &tsb)) == 0){		free(fsb);		goto Return;	}	if (DIRECTORY(fsb) && DIRECTORY(tsb)) {		if (rflag || level == 0)			diffdir(fp, tp, level);		else			Bprint(&stdout, "Common subdirectories: %s and %s\n",				fp, tp);	}	else if (REGULAR_FILE(fsb) && REGULAR_FILE(tsb))		diffreg(fp, tp);	else {		if (REGULAR_FILE(fsb)) {			if ((p = utfrrune(f, '/')) == 0)				p = f;			else				p++;			if (mkpathname(tb, tp, p) == 0)				diffreg(fp, tb);		}		else {			if ((p = utfrrune(t, '/')) == 0)				p = t;			else				p++;			if (mkpathname(fb, fp, p) == 0)				diffreg(fb, tp);		}	}	free(fsb);	free(tsb);Return:	rmtmpfiles();} voidmain(int argc, char *argv[]){	char *p;	int i;	Dir *fsb, *tsb; 	Binit(&stdout, 1, OWRITE);	progname = argv0 = *argv;	while (--argc && (*++argv)[0] == '-' && (*argv)[1]) {		for (p = *argv+1; *p; p++) {			switch (*p) { 			case 'e':			case 'f':			case 'n':			case 'c':			case 'a':				mode = *p;				break; 			case 'w':				bflag = 2;				break; 			case 'b':				bflag = 1;				break; 			case 'r':				rflag = 1;				break; 			case 'm':				mflag = 1;					break; 			case 'h':			default:				progname = "Usage";				panic(2, usage);			}		}	}	if (argc < 2)		panic(2, usage, progname);	if ((tsb = dirstat(argv[argc-1])) == nil)		panic(2, "can't stat %s\n", argv[argc-1]);	if (argc > 2) {		if (!DIRECTORY(tsb))			panic(2, usage, progname);		mflag = 1;	}	else {		if ((fsb = dirstat(argv[0])) == nil)			panic(2, "can't stat %s\n", argv[0]);		if (DIRECTORY(fsb) && DIRECTORY(tsb))			mflag = 1;		free(fsb);	}	free(tsb);	for (i = 0; i < argc-1; i++)		diff(argv[i], argv[argc-1], 0);	done(anychange);	/*NOTREACHED*/} static char noroom[] = "out of memory - try diff -h\n"; void *emalloc(unsigned n){	register void *p; 	if ((p = malloc(n)) == 0)		panic(2, noroom);	return p;} void *erealloc(void *p, unsigned n){	register void *rp; 	if ((rp = realloc(p, n)) == 0)		panic(2, noroom);	return rp;}