Blob


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