xref: /plan9/sys/src/cmd/diff/main.c (revision 3e12c5d1bb89fc02707907988834ef147769ddaf)
1*3e12c5d1SDavid du Colombier #include <u.h>
2*3e12c5d1SDavid du Colombier #include <libc.h>
3*3e12c5d1SDavid du Colombier #include <bio.h>
4*3e12c5d1SDavid du Colombier #include "diff.h"
5*3e12c5d1SDavid du Colombier 
6*3e12c5d1SDavid du Colombier #define	DIRECTORY(s)		((s).qid.path&CHDIR)
7*3e12c5d1SDavid du Colombier #define	REGULAR_FILE(s)		((s).type == 'M' && !DIRECTORY(s))
8*3e12c5d1SDavid du Colombier 
9*3e12c5d1SDavid du Colombier Biobuf	stdout;
10*3e12c5d1SDavid du Colombier 
11*3e12c5d1SDavid du Colombier static char *tmp[] = {"/tmp/diff1", "/tmp/diff2"};
12*3e12c5d1SDavid du Colombier static int whichtmp;
13*3e12c5d1SDavid du Colombier static char *progname;
14*3e12c5d1SDavid du Colombier static char usage[] = "diff [ -efbwr ] file1 ... file2\n";
15*3e12c5d1SDavid du Colombier 
16*3e12c5d1SDavid du Colombier static void
17*3e12c5d1SDavid du Colombier rmtmpfiles(void)
18*3e12c5d1SDavid du Colombier {
19*3e12c5d1SDavid du Colombier 	while (whichtmp > 0) {
20*3e12c5d1SDavid du Colombier 		whichtmp--;
21*3e12c5d1SDavid du Colombier 		remove(tmp[whichtmp]);
22*3e12c5d1SDavid du Colombier 	}
23*3e12c5d1SDavid du Colombier }
24*3e12c5d1SDavid du Colombier 
25*3e12c5d1SDavid du Colombier void
26*3e12c5d1SDavid du Colombier done(int status)
27*3e12c5d1SDavid du Colombier {
28*3e12c5d1SDavid du Colombier 	rmtmpfiles();
29*3e12c5d1SDavid du Colombier 	switch(status)
30*3e12c5d1SDavid du Colombier 	{
31*3e12c5d1SDavid du Colombier 	case 0:
32*3e12c5d1SDavid du Colombier 		exits("");
33*3e12c5d1SDavid du Colombier 	case 1:
34*3e12c5d1SDavid du Colombier 		exits("some");
35*3e12c5d1SDavid du Colombier 	default:
36*3e12c5d1SDavid du Colombier 		exits("error");
37*3e12c5d1SDavid du Colombier 	}
38*3e12c5d1SDavid du Colombier 	/*NOTREACHED*/
39*3e12c5d1SDavid du Colombier }
40*3e12c5d1SDavid du Colombier 
41*3e12c5d1SDavid du Colombier void
42*3e12c5d1SDavid du Colombier panic(int status, char *format, ...)
43*3e12c5d1SDavid du Colombier {
44*3e12c5d1SDavid du Colombier 	char buf[1024], *out;
45*3e12c5d1SDavid du Colombier 
46*3e12c5d1SDavid du Colombier 	Bflush(&stdout);
47*3e12c5d1SDavid du Colombier 	out = doprint(buf, buf+sizeof(buf), "%s: ", &progname);
48*3e12c5d1SDavid du Colombier 	out = doprint(out, buf+sizeof(buf), format, ((long*)&format)+1);
49*3e12c5d1SDavid du Colombier 	write(2, buf, out-buf);
50*3e12c5d1SDavid du Colombier 	if (status)
51*3e12c5d1SDavid du Colombier 		done(status);
52*3e12c5d1SDavid du Colombier 		/*NOTREACHED*/
53*3e12c5d1SDavid du Colombier }
54*3e12c5d1SDavid du Colombier 
55*3e12c5d1SDavid du Colombier static int
56*3e12c5d1SDavid du Colombier catch(void *a, char *msg)
57*3e12c5d1SDavid du Colombier {
58*3e12c5d1SDavid du Colombier 	USED(a);
59*3e12c5d1SDavid du Colombier 	panic(2, msg);
60*3e12c5d1SDavid du Colombier 	return 1;
61*3e12c5d1SDavid du Colombier }
62*3e12c5d1SDavid du Colombier 
63*3e12c5d1SDavid du Colombier int
64*3e12c5d1SDavid du Colombier mkpathname(char *pathname, char *path, char *name)
65*3e12c5d1SDavid du Colombier {
66*3e12c5d1SDavid du Colombier 	if (strlen(path) + strlen(name) > MAXPATHLEN) {
67*3e12c5d1SDavid du Colombier 		panic(0, "pathname %s/%s too long\n", path, name);
68*3e12c5d1SDavid du Colombier 		return 1;
69*3e12c5d1SDavid du Colombier 	}
70*3e12c5d1SDavid du Colombier 	sprint(pathname, "%s/%s", path, name);
71*3e12c5d1SDavid du Colombier 	return 0;
72*3e12c5d1SDavid du Colombier }
73*3e12c5d1SDavid du Colombier 
74*3e12c5d1SDavid du Colombier static char *
75*3e12c5d1SDavid du Colombier mktmpfile(int input, Dir *sb)
76*3e12c5d1SDavid du Colombier {
77*3e12c5d1SDavid du Colombier 	int fd, i;
78*3e12c5d1SDavid du Colombier 	char *p;
79*3e12c5d1SDavid du Colombier 	char buf[8192];
80*3e12c5d1SDavid du Colombier 
81*3e12c5d1SDavid du Colombier 	atnotify(catch, 1);
82*3e12c5d1SDavid du Colombier 	p = tmp[whichtmp++];
83*3e12c5d1SDavid du Colombier 	fd = create(p, OWRITE, 0600);
84*3e12c5d1SDavid du Colombier 	if (fd < 0) {
85*3e12c5d1SDavid du Colombier 		panic(mflag ? 0: 2, "cannot create %s\n", p);
86*3e12c5d1SDavid du Colombier 		return 0;
87*3e12c5d1SDavid du Colombier 	}
88*3e12c5d1SDavid du Colombier 	while ((i = read(input, buf, sizeof(buf))) > 0) {
89*3e12c5d1SDavid du Colombier 		if ((i = write(fd, buf, i)) < 0)
90*3e12c5d1SDavid du Colombier 			break;
91*3e12c5d1SDavid du Colombier 	}
92*3e12c5d1SDavid du Colombier 	dirfstat(fd, sb);
93*3e12c5d1SDavid du Colombier 	close(fd);
94*3e12c5d1SDavid du Colombier 	if (i < 0) {
95*3e12c5d1SDavid du Colombier 		panic(mflag ? 0: 2, "cannot read/write %s\n", p);
96*3e12c5d1SDavid du Colombier 		return 0;
97*3e12c5d1SDavid du Colombier 	}
98*3e12c5d1SDavid du Colombier 	return p;
99*3e12c5d1SDavid du Colombier }
100*3e12c5d1SDavid du Colombier 
101*3e12c5d1SDavid du Colombier static char *
102*3e12c5d1SDavid du Colombier statfile(char *file, Dir *sb)
103*3e12c5d1SDavid du Colombier {
104*3e12c5d1SDavid du Colombier 	int input;
105*3e12c5d1SDavid du Colombier 
106*3e12c5d1SDavid du Colombier 	if (dirstat(file, sb) == -1) {
107*3e12c5d1SDavid du Colombier 		if (strcmp(file, "-") || dirfstat(0, sb) == -1) {
108*3e12c5d1SDavid du Colombier 			panic(mflag ? 0: 2, "cannot stat %s\n", file);
109*3e12c5d1SDavid du Colombier 			return 0;
110*3e12c5d1SDavid du Colombier 		}
111*3e12c5d1SDavid du Colombier 		file = mktmpfile(0, sb);
112*3e12c5d1SDavid du Colombier 	}
113*3e12c5d1SDavid du Colombier 	else if (!REGULAR_FILE(*sb) && !DIRECTORY(*sb)) {
114*3e12c5d1SDavid du Colombier 		if ((input = open(file, OREAD)) == -1) {
115*3e12c5d1SDavid du Colombier 			panic(mflag ? 0: 2, "cannot open %s\n", file);
116*3e12c5d1SDavid du Colombier 			return 0;
117*3e12c5d1SDavid du Colombier 		}
118*3e12c5d1SDavid du Colombier 		file = mktmpfile(input, sb);
119*3e12c5d1SDavid du Colombier 		close(input);
120*3e12c5d1SDavid du Colombier 	}
121*3e12c5d1SDavid du Colombier 	return file;
122*3e12c5d1SDavid du Colombier }
123*3e12c5d1SDavid du Colombier 
124*3e12c5d1SDavid du Colombier void
125*3e12c5d1SDavid du Colombier diff(char *f, char *t, int level)
126*3e12c5d1SDavid du Colombier {
127*3e12c5d1SDavid du Colombier 	char *fp, *tp, *p, fb[MAXPATHLEN+1], tb[MAXPATHLEN+1];
128*3e12c5d1SDavid du Colombier 	Dir fsb, tsb;
129*3e12c5d1SDavid du Colombier 
130*3e12c5d1SDavid du Colombier 	if ((fp = statfile(f, &fsb)) == 0)
131*3e12c5d1SDavid du Colombier 		return;
132*3e12c5d1SDavid du Colombier 	if ((tp = statfile(t, &tsb)) == 0)
133*3e12c5d1SDavid du Colombier 		return;
134*3e12c5d1SDavid du Colombier 	if (DIRECTORY(fsb) && DIRECTORY(tsb)) {
135*3e12c5d1SDavid du Colombier 		if (rflag || level == 0)
136*3e12c5d1SDavid du Colombier 			diffdir(fp, tp, level);
137*3e12c5d1SDavid du Colombier 		else
138*3e12c5d1SDavid du Colombier 			Bprint(&stdout, "Common subdirectories: %s and %s\n",
139*3e12c5d1SDavid du Colombier 				fp, tp);
140*3e12c5d1SDavid du Colombier 	}
141*3e12c5d1SDavid du Colombier 	else if (REGULAR_FILE(fsb) && REGULAR_FILE(tsb))
142*3e12c5d1SDavid du Colombier 		diffreg(fp, tp);
143*3e12c5d1SDavid du Colombier 	else {
144*3e12c5d1SDavid du Colombier 		if (REGULAR_FILE(fsb)) {
145*3e12c5d1SDavid du Colombier 			if ((p = utfrrune(f, '/')) == 0)
146*3e12c5d1SDavid du Colombier 				p = f;
147*3e12c5d1SDavid du Colombier 			else
148*3e12c5d1SDavid du Colombier 				p++;
149*3e12c5d1SDavid du Colombier 			if (mkpathname(tb, tp, p))
150*3e12c5d1SDavid du Colombier 				return;
151*3e12c5d1SDavid du Colombier 			diffreg(fp, tb);
152*3e12c5d1SDavid du Colombier 		}
153*3e12c5d1SDavid du Colombier 		else {
154*3e12c5d1SDavid du Colombier 			if ((p = utfrrune(t, '/')) == 0)
155*3e12c5d1SDavid du Colombier 				p = t;
156*3e12c5d1SDavid du Colombier 			else
157*3e12c5d1SDavid du Colombier 				p++;
158*3e12c5d1SDavid du Colombier 			if (mkpathname(fb, fp, p))
159*3e12c5d1SDavid du Colombier 				return;
160*3e12c5d1SDavid du Colombier 			diffreg(fb, tp);
161*3e12c5d1SDavid du Colombier 		}
162*3e12c5d1SDavid du Colombier 	}
163*3e12c5d1SDavid du Colombier }
164*3e12c5d1SDavid du Colombier 
165*3e12c5d1SDavid du Colombier void
166*3e12c5d1SDavid du Colombier main(int argc, char *argv[])
167*3e12c5d1SDavid du Colombier {
168*3e12c5d1SDavid du Colombier 	char *p;
169*3e12c5d1SDavid du Colombier 	int i;
170*3e12c5d1SDavid du Colombier 	Dir fsb, tsb;
171*3e12c5d1SDavid du Colombier 
172*3e12c5d1SDavid du Colombier 	Binit(&stdout, 1, OWRITE);
173*3e12c5d1SDavid du Colombier 	progname = *argv;
174*3e12c5d1SDavid du Colombier 	while (--argc && (*++argv)[0] == '-' && (*argv)[1]) {
175*3e12c5d1SDavid du Colombier 		for (p = *argv+1; *p; p++) {
176*3e12c5d1SDavid du Colombier 			switch (*p) {
177*3e12c5d1SDavid du Colombier 
178*3e12c5d1SDavid du Colombier 			case 'e':
179*3e12c5d1SDavid du Colombier 			case 'f':
180*3e12c5d1SDavid du Colombier 				mode = *p;
181*3e12c5d1SDavid du Colombier 				break;
182*3e12c5d1SDavid du Colombier 
183*3e12c5d1SDavid du Colombier 			case 'w':
184*3e12c5d1SDavid du Colombier 				bflag = 2;
185*3e12c5d1SDavid du Colombier 				break;
186*3e12c5d1SDavid du Colombier 
187*3e12c5d1SDavid du Colombier 			case 'b':
188*3e12c5d1SDavid du Colombier 				bflag = 1;
189*3e12c5d1SDavid du Colombier 				break;
190*3e12c5d1SDavid du Colombier 
191*3e12c5d1SDavid du Colombier 			case 'r':
192*3e12c5d1SDavid du Colombier 				rflag = 1;
193*3e12c5d1SDavid du Colombier 				break;
194*3e12c5d1SDavid du Colombier 
195*3e12c5d1SDavid du Colombier 			case 'h':
196*3e12c5d1SDavid du Colombier 			default:
197*3e12c5d1SDavid du Colombier 				progname = "Usage";
198*3e12c5d1SDavid du Colombier 				panic(2, usage);
199*3e12c5d1SDavid du Colombier 			}
200*3e12c5d1SDavid du Colombier 		}
201*3e12c5d1SDavid du Colombier 	}
202*3e12c5d1SDavid du Colombier 	if (argc < 2)
203*3e12c5d1SDavid du Colombier 		panic(2, usage, progname);
204*3e12c5d1SDavid du Colombier 	if (dirstat(argv[argc-1], &tsb) == -1)
205*3e12c5d1SDavid du Colombier 		panic(2, "can't stat %s\n", argv[argc-1]);
206*3e12c5d1SDavid du Colombier 	if (argc > 2) {
207*3e12c5d1SDavid du Colombier 		if (!DIRECTORY(tsb))
208*3e12c5d1SDavid du Colombier 			panic(2, usage, progname);
209*3e12c5d1SDavid du Colombier 		mflag = 1;
210*3e12c5d1SDavid du Colombier 	}
211*3e12c5d1SDavid du Colombier 	else {
212*3e12c5d1SDavid du Colombier 		if (dirstat(argv[0], &fsb) == -1)
213*3e12c5d1SDavid du Colombier 			panic(2, "can't stat %s\n", argv[0]);
214*3e12c5d1SDavid du Colombier 		if (DIRECTORY(fsb) && DIRECTORY(tsb))
215*3e12c5d1SDavid du Colombier 			mflag = 1;
216*3e12c5d1SDavid du Colombier 	}
217*3e12c5d1SDavid du Colombier 	for (i = 0; i < argc-1; i++) {
218*3e12c5d1SDavid du Colombier 		diff(argv[i], argv[argc-1], 0);
219*3e12c5d1SDavid du Colombier 		rmtmpfiles();
220*3e12c5d1SDavid du Colombier 	}
221*3e12c5d1SDavid du Colombier 	done(anychange);
222*3e12c5d1SDavid du Colombier 	/*NOTREACHED*/
223*3e12c5d1SDavid du Colombier }
224*3e12c5d1SDavid du Colombier 
225*3e12c5d1SDavid du Colombier static char noroom[] = "out of memory - try diff -h\n";
226*3e12c5d1SDavid du Colombier 
227*3e12c5d1SDavid du Colombier void *
228*3e12c5d1SDavid du Colombier emalloc(unsigned n)
229*3e12c5d1SDavid du Colombier {
230*3e12c5d1SDavid du Colombier 	register void *p;
231*3e12c5d1SDavid du Colombier 
232*3e12c5d1SDavid du Colombier 	if ((p = malloc(n)) == 0)
233*3e12c5d1SDavid du Colombier 		panic(2, noroom);
234*3e12c5d1SDavid du Colombier 	return p;
235*3e12c5d1SDavid du Colombier }
236*3e12c5d1SDavid du Colombier 
237*3e12c5d1SDavid du Colombier void *
238*3e12c5d1SDavid du Colombier erealloc(void *p, unsigned n)
239*3e12c5d1SDavid du Colombier {
240*3e12c5d1SDavid du Colombier 	register void *rp;
241*3e12c5d1SDavid du Colombier 
242*3e12c5d1SDavid du Colombier 	if ((rp = realloc(p, n)) == 0)
243*3e12c5d1SDavid du Colombier 		panic(2, noroom);
244*3e12c5d1SDavid du Colombier 	return rp;
245*3e12c5d1SDavid du Colombier }
246