Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

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